From 910ee1116888e5e1015e6e44a617e16302001dc6 Mon Sep 17 00:00:00 2001 From: "TOKISAKIX\\21168" <2116884726@qq.com> Date: Mon, 11 Dec 2023 21:50:22 +0800 Subject: [PATCH] init repo --- LICENSE | 201 ++ README.md | 1 + lab1/.gitignore | 358 +++ lab1/Makefile | 47 + lab1/build.sbt | 24 + lab1/coremark/yatcpu/core_portme.c | 169 ++ lab1/coremark/yatcpu/core_portme.h | 211 ++ lab1/coremark/yatcpu/core_portme.mak | 92 + lab1/coremark/yatcpu/cvt.c | 127 ++ lab1/coremark/yatcpu/div.s | 71 + lab1/coremark/yatcpu/ee_printf.c | 687 ++++++ lab1/coremark/yatcpu/init.s | 16 + lab1/coremark/yatcpu/link.ld | 12 + lab1/csrc/CMakeLists.txt | 43 + lab1/csrc/build.bat | 3 + lab1/csrc/build.sh | 3 + lab1/csrc/fibonacci.c | 22 + lab1/csrc/hdmi_test.c | 29 + lab1/csrc/hello.c | 175 ++ lab1/csrc/init.S | 107 + lab1/csrc/link.lds | 11 + lab1/csrc/mmio.S | 24 + lab1/csrc/mmio.h | 23 + lab1/csrc/quicksort.c | 50 + lab1/csrc/sb.S | 25 + lab1/csrc/tetris.c | 498 ++++ lab1/csrc/toolchain.cmake | 20 + lab1/project/build.properties | 1 + lab1/project/plugins.sbt | 1 + lab1/riscv-target/yatcpu/Makefile.include | 7 + .../yatcpu/device/rv32i_m/I/Makefile.include | 54 + lab1/riscv-target/yatcpu/link.ld | 12 + lab1/riscv-target/yatcpu/model_test.h | 46 + lab1/src/main/resources/fibonacci.asmbin | Bin 0 -> 520 bytes lab1/src/main/resources/hello.asmbin | Bin 0 -> 4344 bytes lab1/src/main/resources/litenes.asmbin | Bin 0 -> 70484 bytes lab1/src/main/resources/mmio.asmbin | Bin 0 -> 32 bytes lab1/src/main/resources/quicksort.asmbin | Bin 0 -> 1012 bytes lab1/src/main/resources/sb.asmbin | Bin 0 -> 36 bytes lab1/src/main/resources/tetris.asmbin | Bin 0 -> 8300 bytes lab1/src/main/resources/vga_font_8x16.bmp | Bin 0 -> 17462 bytes .../scala/board/basys3/BCD2Segments.scala | 54 + .../board/basys3/OnboardDigitDisplay.scala | 32 + .../main/scala/board/basys3/SYSULogo.scala | 34 + .../main/scala/board/basys3/SegmentMux.scala | 42 + lab1/src/main/scala/board/basys3/Top.scala | 123 + lab1/src/main/scala/board/pynq/Top.scala | 93 + lab1/src/main/scala/board/verilator/Top.scala | 43 + .../scala/peripheral/CharacterDisplay.scala | 84 + lab1/src/main/scala/peripheral/Dummy.scala | 29 + lab1/src/main/scala/peripheral/FontROM.scala | 64 + .../main/scala/peripheral/HDMIDisplay.scala | 394 ++++ .../scala/peripheral/InstructionROM.scala | 68 + lab1/src/main/scala/peripheral/Memory.scala | 77 + .../src/main/scala/peripheral/ROMLoader.scala | 50 + .../main/scala/peripheral/VGADisplay.scala | 116 + lab1/src/main/scala/riscv/CPUBundle.scala | 28 + lab1/src/main/scala/riscv/Parameters.scala | 58 + lab1/src/main/scala/riscv/core/ALU.scala | 70 + .../main/scala/riscv/core/ALUControl.scala | 86 + lab1/src/main/scala/riscv/core/CPU.scala | 77 + lab1/src/main/scala/riscv/core/Execute.scala | 75 + .../scala/riscv/core/InstructionDecode.scala | 193 ++ .../scala/riscv/core/InstructionFetch.scala | 50 + .../main/scala/riscv/core/MemoryAccess.scala | 106 + .../main/scala/riscv/core/RegisterFile.scala | 70 + .../src/main/scala/riscv/core/WriteBack.scala | 37 + .../test/scala/riscv/TestAnnotations.scala | 52 + .../scala/riscv/singlecycle/CPUTest.scala | 125 + .../scala/riscv/singlecycle/ExecuteTest.scala | 72 + .../singlecycle/InstructionDecoderTest.scala | 46 + .../singlecycle/InstructionFetchTest.scala | 58 + .../riscv/singlecycle/RegisterFileTest.scala | 69 + lab1/verilog/basys3/test.v | 35 + lab1/verilog/pynq/TMDS_PLLVR.v | 221 ++ lab1/verilog/pynq/design_1_wrapper.v | 136 ++ lab1/verilog/pynq/test.v | 35 + lab1/verilog/verilator/sim_main.cpp | 245 ++ lab1/vivado/basys3/basys3.xdc | 307 +++ lab1/vivado/basys3/generate_and_program.tcl | 17 + lab1/vivado/basys3/generate_bitstream.tcl | 55 + lab1/vivado/basys3/open_project.tcl | 39 + lab1/vivado/basys3/program_device.tcl | 24 + lab1/vivado/basys3/run.ps1 | 4 + lab1/vivado/basys3/run_simulation.tcl | 24 + lab1/vivado/pynq/generate_and_program.tcl | 17 + lab1/vivado/pynq/generate_bitstream.tcl | 56 + lab1/vivado/pynq/open_project.tcl | 40 + lab1/vivado/pynq/program_device.tcl | 22 + lab1/vivado/pynq/pynq.xdc | 189 ++ lab1/vivado/pynq/run.ps1 | 4 + lab1/vivado/pynq/run_simulation.tcl | 28 + lab2/.gitignore | 358 +++ lab2/Makefile | 47 + lab2/build.sbt | 24 + lab2/coremark/yatcpu/core_portme.c | 169 ++ lab2/coremark/yatcpu/core_portme.h | 211 ++ lab2/coremark/yatcpu/core_portme.mak | 92 + lab2/coremark/yatcpu/cvt.c | 127 ++ lab2/coremark/yatcpu/div.s | 71 + lab2/coremark/yatcpu/ee_printf.c | 687 ++++++ lab2/coremark/yatcpu/init.s | 16 + lab2/coremark/yatcpu/link.ld | 12 + lab2/csrc/CMakeLists.txt | 43 + lab2/csrc/build.bat | 3 + lab2/csrc/build.sh | 3 + lab2/csrc/fibonacci.c | 22 + lab2/csrc/hello.c | 175 ++ lab2/csrc/init.S | 107 + lab2/csrc/link.lds | 11 + lab2/csrc/mmio.S | 24 + lab2/csrc/mmio.h | 23 + lab2/csrc/quicksort.c | 50 + lab2/csrc/sb.S | 25 + lab2/csrc/simpletest.c | 12 + lab2/csrc/tetris.S | 2023 +++++++++++++++++ lab2/csrc/tetris.c | 498 ++++ lab2/csrc/toolchain.cmake | 20 + lab2/project/build.properties | 1 + lab2/project/plugins.sbt | 1 + lab2/riscv-target/yatcpu/Makefile.include | 7 + .../yatcpu/device/rv32i_m/I/Makefile.include | 54 + lab2/riscv-target/yatcpu/link.ld | 12 + lab2/riscv-target/yatcpu/model_test.h | 46 + lab2/src/main/resources/fibonacci.asmbin | Bin 0 -> 520 bytes lab2/src/main/resources/hdmi_test.asmbin | Bin 0 -> 4109 bytes lab2/src/main/resources/hello.asmbin | Bin 0 -> 4344 bytes lab2/src/main/resources/mmio.asmbin | Bin 0 -> 32 bytes lab2/src/main/resources/quicksort.asmbin | Bin 0 -> 1012 bytes lab2/src/main/resources/sb.asmbin | Bin 0 -> 36 bytes lab2/src/main/resources/simpletest.asmbin | Bin 0 -> 432 bytes lab2/src/main/resources/tetris.asmbin | Bin 0 -> 8300 bytes lab2/src/main/resources/vga_font_8x16.bmp | Bin 0 -> 17462 bytes .../scala/board/basys3/BCD2Segments.scala | 54 + .../board/basys3/OnboardDigitDisplay.scala | 32 + .../main/scala/board/basys3/SYSULogo.scala | 34 + .../main/scala/board/basys3/SegmentMux.scala | 42 + lab2/src/main/scala/board/basys3/Top.scala | 138 ++ lab2/src/main/scala/board/pynq/Top.scala | 109 + lab2/src/main/scala/board/verilator/Top.scala | 45 + .../scala/peripheral/CharacterDisplay.scala | 84 + lab2/src/main/scala/peripheral/Dummy.scala | 29 + lab2/src/main/scala/peripheral/FontROM.scala | 64 + .../main/scala/peripheral/HDMIDisplay.scala | 394 ++++ .../scala/peripheral/InstructionROM.scala | 68 + lab2/src/main/scala/peripheral/Memory.scala | 77 + .../src/main/scala/peripheral/ROMLoader.scala | 50 + lab2/src/main/scala/peripheral/Timer.scala | 38 + lab2/src/main/scala/peripheral/UART.scala | 204 ++ .../main/scala/peripheral/VGADisplay.scala | 116 + lab2/src/main/scala/riscv/CPUBundle.scala | 31 + lab2/src/main/scala/riscv/Parameters.scala | 58 + lab2/src/main/scala/riscv/core/ALU.scala | 70 + .../main/scala/riscv/core/ALUControl.scala | 86 + lab2/src/main/scala/riscv/core/CLINT.scala | 107 + lab2/src/main/scala/riscv/core/CPU.scala | 96 + lab2/src/main/scala/riscv/core/CSR.scala | 107 + lab2/src/main/scala/riscv/core/Execute.scala | 79 + .../scala/riscv/core/InstructionDecode.scala | 208 ++ .../scala/riscv/core/InstructionFetch.scala | 53 + .../main/scala/riscv/core/MemoryAccess.scala | 105 + .../main/scala/riscv/core/RegisterFile.scala | 95 + .../src/main/scala/riscv/core/WriteBack.scala | 39 + .../test/scala/riscv/TestAnnotations.scala | 52 + .../riscv/singlecycle/CLINTCSRTest.scala | 142 ++ .../scala/riscv/singlecycle/CPUTest.scala | 162 ++ .../scala/riscv/singlecycle/ExecuteTest.scala | 49 + .../scala/riscv/singlecycle/TimerTest.scala | 61 + lab2/verilog/basys3/test.v | 35 + lab2/verilog/pynq/TMDS_PLLVR.v | 221 ++ lab2/verilog/pynq/test.v | 35 + lab2/verilog/verilator/sim_main.cpp | 246 ++ lab2/vivado/basys3/basys3.xdc | 307 +++ lab2/vivado/basys3/generate_and_program.tcl | 17 + lab2/vivado/basys3/generate_bitstream.tcl | 55 + lab2/vivado/basys3/open_project.tcl | 39 + lab2/vivado/basys3/program_device.tcl | 24 + lab2/vivado/basys3/run.ps1 | 4 + lab2/vivado/basys3/run_simulation.tcl | 24 + lab2/vivado/pynq/generate_and_program.tcl | 17 + lab2/vivado/pynq/generate_bitstream.tcl | 57 + lab2/vivado/pynq/open_project.tcl | 40 + lab2/vivado/pynq/program_device.tcl | 22 + lab2/vivado/pynq/pynq.xdc | 191 ++ lab2/vivado/pynq/run.ps1 | 4 + lab2/vivado/pynq/run_simulation.tcl | 28 + lab3/.gitignore | 358 +++ lab3/Makefile | 55 + lab3/build.sbt | 24 + lab3/coremark/yatcpu/core_portme.c | 169 ++ lab3/coremark/yatcpu/core_portme.h | 211 ++ lab3/coremark/yatcpu/core_portme.mak | 92 + lab3/coremark/yatcpu/cvt.c | 127 ++ lab3/coremark/yatcpu/div.s | 71 + lab3/coremark/yatcpu/ee_printf.c | 687 ++++++ lab3/coremark/yatcpu/init.s | 16 + lab3/coremark/yatcpu/link.ld | 12 + lab3/csrc/CMakeLists.txt | 43 + lab3/csrc/build.bat | 3 + lab3/csrc/build.sh | 3 + lab3/csrc/fibonacci.c | 22 + lab3/csrc/hazard.S | 48 + lab3/csrc/hello.c | 175 ++ lab3/csrc/init.S | 107 + lab3/csrc/link.lds | 11 + lab3/csrc/mmio.S | 24 + lab3/csrc/mmio.h | 23 + lab3/csrc/quicksort.c | 50 + lab3/csrc/sb.S | 25 + lab3/csrc/tetris.c | 495 ++++ lab3/csrc/toolchain.cmake | 20 + lab3/project/build.properties | 1 + lab3/project/plugins.sbt | 1 + lab3/riscv-target/yatcpu/Makefile.include | 7 + .../yatcpu/device/rv32i_m/I/Makefile.include | 54 + lab3/riscv-target/yatcpu/link.ld | 12 + lab3/riscv-target/yatcpu/model_test.h | 46 + lab3/src/main/resources/fibonacci.asmbin | Bin 0 -> 520 bytes lab3/src/main/resources/hazard.asmbin | Bin 0 -> 100 bytes lab3/src/main/resources/hello.asmbin | Bin 0 -> 4344 bytes lab3/src/main/resources/mmio.asmbin | Bin 0 -> 32 bytes lab3/src/main/resources/quicksort.asmbin | Bin 0 -> 1028 bytes lab3/src/main/resources/sb.asmbin | Bin 0 -> 36 bytes lab3/src/main/resources/tetris.asmbin | Bin 0 -> 8196 bytes lab3/src/main/resources/vga_font_8x16.bmp | Bin 0 -> 17462 bytes .../scala/board/basys3/BCD2Segments.scala | 54 + .../board/basys3/OnboardDigitDisplay.scala | 32 + .../main/scala/board/basys3/SYSULogo.scala | 34 + .../main/scala/board/basys3/SegmentMux.scala | 42 + lab3/src/main/scala/board/basys3/Top.scala | 128 ++ lab3/src/main/scala/board/pynq/Top.scala | 103 + lab3/src/main/scala/board/verilator/Top.scala | 42 + lab3/src/main/scala/peripheral/Dummy.scala | 29 + lab3/src/main/scala/peripheral/FontROM.scala | 64 + .../main/scala/peripheral/HDMIDisplay.scala | 403 ++++ .../scala/peripheral/InstructionROM.scala | 68 + lab3/src/main/scala/peripheral/Memory.scala | 77 + .../src/main/scala/peripheral/ROMLoader.scala | 50 + lab3/src/main/scala/peripheral/Timer.scala | 60 + lab3/src/main/scala/peripheral/UART.scala | 204 ++ .../main/scala/peripheral/VGADisplay.scala | 164 ++ lab3/src/main/scala/riscv/Parameters.scala | 60 + lab3/src/main/scala/riscv/core/ALU.scala | 69 + .../main/scala/riscv/core/ALUControl.scala | 87 + lab3/src/main/scala/riscv/core/CPU.scala | 40 + .../src/main/scala/riscv/core/CPUBundle.scala | 30 + lab3/src/main/scala/riscv/core/CSR.scala | 99 + .../scala/riscv/core/PipelineRegister.scala | 30 + .../main/scala/riscv/core/RegisterFile.scala | 78 + .../riscv/core/fivestage_final/CLINT.scala | 101 + .../riscv/core/fivestage_final/CPU.scala | 169 ++ .../riscv/core/fivestage_final/Control.scala | 43 + .../riscv/core/fivestage_final/EX2MEM.scala | 108 + .../riscv/core/fivestage_final/Execute.scala | 93 + .../core/fivestage_final/Forwarding.scala | 49 + .../riscv/core/fivestage_final/ID2EX.scala | 163 ++ .../riscv/core/fivestage_final/IF2ID.scala | 51 + .../fivestage_final/InstructionDecode.scala | 229 ++ .../fivestage_final/InstructionFetch.scala | 48 + .../riscv/core/fivestage_final/MEM2WB.scala | 83 + .../core/fivestage_final/MemoryAccess.scala | 109 + .../core/fivestage_final/WriteBack.scala | 40 + .../riscv/core/fivestage_forward/CLINT.scala | 103 + .../riscv/core/fivestage_forward/CPU.scala | 158 ++ .../core/fivestage_forward/Control.scala | 40 + .../riscv/core/fivestage_forward/EX2MEM.scala | 108 + .../core/fivestage_forward/Execute.scala | 111 + .../core/fivestage_forward/Forwarding.scala | 44 + .../riscv/core/fivestage_forward/ID2EX.scala | 164 ++ .../riscv/core/fivestage_forward/IF2ID.scala | 51 + .../fivestage_forward/InstructionDecode.scala | 207 ++ .../fivestage_forward/InstructionFetch.scala | 48 + .../riscv/core/fivestage_forward/MEM2WB.scala | 83 + .../core/fivestage_forward/MemoryAccess.scala | 109 + .../core/fivestage_forward/WriteBack.scala | 40 + .../riscv/core/fivestage_stall/CLINT.scala | 103 + .../riscv/core/fivestage_stall/CPU.scala | 148 ++ .../riscv/core/fivestage_stall/Control.scala | 43 + .../riscv/core/fivestage_stall/EX2MEM.scala | 108 + .../riscv/core/fivestage_stall/Execute.scala | 101 + .../riscv/core/fivestage_stall/ID2EX.scala | 164 ++ .../riscv/core/fivestage_stall/IF2ID.scala | 51 + .../fivestage_stall/InstructionDecode.scala | 207 ++ .../fivestage_stall/InstructionFetch.scala | 48 + .../riscv/core/fivestage_stall/MEM2WB.scala | 83 + .../core/fivestage_stall/MemoryAccess.scala | 106 + .../core/fivestage_stall/WriteBack.scala | 40 + .../scala/riscv/core/threestage/CLINT.scala | 88 + .../scala/riscv/core/threestage/CPU.scala | 104 + .../scala/riscv/core/threestage/Control.scala | 21 + .../scala/riscv/core/threestage/Execute.scala | 191 ++ .../scala/riscv/core/threestage/ID2EX.scala | 148 ++ .../scala/riscv/core/threestage/IF2ID.scala | 52 + .../core/threestage/InstructionDecode.scala | 207 ++ .../core/threestage/InstructionFetch.scala | 47 + .../scala/riscv/FiveStageCPUFinalTest.scala | 73 + .../scala/riscv/FiveStageCPUForwardTest.scala | 73 + .../scala/riscv/FiveStageCPUStallTest.scala | 73 + .../scala/riscv/PipelineRegisterTest.scala | 58 + .../test/scala/riscv/TestAnnotations.scala | 52 + lab3/src/test/scala/riscv/TestTopModule.scala | 66 + .../test/scala/riscv/ThreeStageCPUTest.scala | 73 + lab3/verilog/basys3/test.v | 35 + lab3/verilog/pynq/TMDS_PLLVR.v | 221 ++ lab3/verilog/pynq/test.v | 35 + lab3/verilog/verilator/sim_main.cpp | 251 ++ lab3/vivado/basys3/basys3.xdc | 307 +++ lab3/vivado/basys3/generate_and_program.tcl | 17 + lab3/vivado/basys3/generate_bitstream.tcl | 55 + lab3/vivado/basys3/open_project.tcl | 39 + lab3/vivado/basys3/program_device.tcl | 24 + lab3/vivado/basys3/run.ps1 | 4 + lab3/vivado/basys3/run_simulation.tcl | 24 + lab3/vivado/pynq/generate_and_program.tcl | 17 + lab3/vivado/pynq/generate_bitstream.tcl | 56 + lab3/vivado/pynq/open_project.tcl | 40 + lab3/vivado/pynq/program_device.tcl | 22 + lab3/vivado/pynq/pynq.xdc | 189 ++ lab3/vivado/pynq/run.ps1 | 4 + lab3/vivado/pynq/run_simulation.tcl | 28 + lab4/.gitignore | 358 +++ lab4/Makefile | 47 + lab4/build.sbt | 24 + lab4/coremark/yatcpu/core_portme.c | 169 ++ lab4/coremark/yatcpu/core_portme.h | 211 ++ lab4/coremark/yatcpu/core_portme.mak | 92 + lab4/coremark/yatcpu/cvt.c | 127 ++ lab4/coremark/yatcpu/div.s | 71 + lab4/coremark/yatcpu/ee_printf.c | 687 ++++++ lab4/coremark/yatcpu/init.s | 16 + lab4/coremark/yatcpu/link.ld | 12 + lab4/csrc/CMakeLists.txt | 66 + lab4/csrc/build.bat | 3 + lab4/csrc/build.sh | 3 + lab4/csrc/fibonacci.c | 22 + lab4/csrc/hello.c | 175 ++ lab4/csrc/init.S | 117 + lab4/csrc/link.lds | 12 + lab4/csrc/mm.h | 43 + lab4/csrc/mmio.S | 24 + lab4/csrc/mmio.h | 33 + lab4/csrc/paging.c | 191 ++ lab4/csrc/quicksort.c | 50 + lab4/csrc/say_goodbye.c | 44 + lab4/csrc/sb.S | 25 + lab4/csrc/tetris.c | 498 ++++ lab4/csrc/tetris_mmu.c | 568 +++++ lab4/csrc/toolchain.cmake | 20 + lab4/project/build.properties | 1 + lab4/project/plugins.sbt | 1 + lab4/riscv-target/yatcpu/Makefile.include | 7 + .../yatcpu/device/rv32i_m/I/Makefile.include | 54 + lab4/riscv-target/yatcpu/link.ld | 12 + lab4/riscv-target/yatcpu/model_test.h | 46 + lab4/src/main/resources/fibonacci.asmbin | Bin 0 -> 520 bytes lab4/src/main/resources/hello.asmbin | Bin 0 -> 4344 bytes lab4/src/main/resources/mmio.asmbin | Bin 0 -> 32 bytes lab4/src/main/resources/quicksort.asmbin | Bin 0 -> 1012 bytes lab4/src/main/resources/sb.asmbin | Bin 0 -> 36 bytes lab4/src/main/resources/tetris.asmbin | Bin 0 -> 8300 bytes lab4/src/main/resources/vga_font_8x16.bmp | Bin 0 -> 17462 bytes .../scala/board/basys3/BCD2Segments.scala | 54 + .../board/basys3/OnboardDigitDisplay.scala | 32 + .../main/scala/board/basys3/SYSULogo.scala | 34 + .../main/scala/board/basys3/SegmentMux.scala | 42 + lab4/src/main/scala/board/basys3/Top.scala | 143 ++ lab4/src/main/scala/board/pynq/Top.scala | 149 ++ lab4/src/main/scala/board/verilator/Top.scala | 71 + lab4/src/main/scala/bus/AXI4Lite.scala | 197 ++ lab4/src/main/scala/bus/BusArbiter.scala | 40 + lab4/src/main/scala/bus/BusSwitch.scala | 33 + .../scala/peripheral/CharacterDisplay.scala | 89 + .../main/scala/peripheral/DummyMaster.scala | 33 + .../main/scala/peripheral/DummySlave.scala | 32 + lab4/src/main/scala/peripheral/FontROM.scala | 65 + .../main/scala/peripheral/HDMIDisplay.scala | 398 ++++ .../scala/peripheral/InstructionROM.scala | 68 + .../peripheral/InterruptController.scala | 26 + lab4/src/main/scala/peripheral/Memory.scala | 72 + .../main/scala/peripheral/PixelDisplay.scala | 56 + .../src/main/scala/peripheral/ROMLoader.scala | 80 + lab4/src/main/scala/peripheral/SPI.scala | 24 + lab4/src/main/scala/peripheral/Timer.scala | 67 + lab4/src/main/scala/peripheral/UART.scala | 211 ++ .../main/scala/peripheral/VGADisplay.scala | 129 ++ lab4/src/main/scala/riscv/Parameters.scala | 58 + .../src/main/scala/riscv/core/BusBundle.scala | 32 + lab4/src/main/scala/riscv/core/CPU.scala | 32 + .../src/main/scala/riscv/core/CPUBundle.scala | 32 + .../main/scala/riscv/core/fivestage/ALU.scala | 70 + .../riscv/core/fivestage/ALUControl.scala | 86 + .../scala/riscv/core/fivestage/CLINT.scala | 183 ++ .../main/scala/riscv/core/fivestage/CPU.scala | 217 ++ .../main/scala/riscv/core/fivestage/CSR.scala | 126 + .../scala/riscv/core/fivestage/Cache.scala | 23 + .../scala/riscv/core/fivestage/Control.scala | 48 + .../scala/riscv/core/fivestage/EX2MEM.scala | 115 + .../scala/riscv/core/fivestage/Execute.scala | 91 + .../riscv/core/fivestage/Forwarding.scala | 53 + .../scala/riscv/core/fivestage/ID2EX.scala | 147 ++ .../scala/riscv/core/fivestage/IF2ID.scala | 52 + .../core/fivestage/InstructionDecode.scala | 238 ++ .../core/fivestage/InstructionFetch.scala | 68 + .../scala/riscv/core/fivestage/MEM2WB.scala | 82 + .../riscv/core/fivestage/MemoryAccess.scala | 151 ++ .../core/fivestage/PipelineRegister.scala | 35 + .../riscv/core/fivestage/RegisterFile.scala | 78 + .../riscv/core/fivestage/WriteBack.scala | 40 + .../scala/riscv/core/threestage/ALU.scala | 67 + .../riscv/core/threestage/ALUControl.scala | 77 + .../scala/riscv/core/threestage/CLINT.scala | 183 ++ .../scala/riscv/core/threestage/CPU.scala | 167 ++ .../scala/riscv/core/threestage/CSR.scala | 126 + .../scala/riscv/core/threestage/Cache.scala | 23 + .../scala/riscv/core/threestage/Control.scala | 55 + .../scala/riscv/core/threestage/Execute.scala | 315 +++ .../scala/riscv/core/threestage/ID2EX.scala | 132 ++ .../scala/riscv/core/threestage/IF2ID.scala | 53 + .../core/threestage/InstructionDecode.scala | 317 +++ .../core/threestage/InstructionFetch.scala | 69 + .../core/threestage/PipelineRegister.scala | 35 + .../riscv/core/threestage/RegisterFile.scala | 78 + .../main/scala/riscv/debug/DebugModule.scala | 33 + .../riscv/debug/DebugTransportModule.scala | 35 + lab4/src/test/scala/riscv/BusTest.scala | 164 ++ .../test/scala/riscv/TestAnnotations.scala | 52 + .../test/scala/riscv/fivestage/CPUTest.scala | 184 ++ .../test/scala/riscv/threestage/CPUTest.scala | 185 ++ lab4/verilog/basys3/test.v | 35 + lab4/verilog/pynq/TMDS_PLLVR.v | 221 ++ lab4/verilog/pynq/design_1_wrapper.v | 136 ++ lab4/verilog/pynq/test.v | 35 + lab4/verilog/verilator/sim_main.cpp | 230 ++ lab4/vivado/basys3/basys3.xdc | 307 +++ lab4/vivado/basys3/generate_and_program.tcl | 17 + lab4/vivado/basys3/generate_bitstream.tcl | 55 + lab4/vivado/basys3/open_project.tcl | 39 + lab4/vivado/basys3/program_device.tcl | 24 + lab4/vivado/basys3/run.ps1 | 4 + lab4/vivado/basys3/run_simulation.tcl | 24 + lab4/vivado/pynq/generate_and_program.tcl | 17 + lab4/vivado/pynq/generate_bitstream.tcl | 57 + lab4/vivado/pynq/open_project.tcl | 29 + lab4/vivado/pynq/program_device.tcl | 22 + lab4/vivado/pynq/pynq.xdc | 189 ++ lab4/vivado/pynq/riscv-pynq.tcl | 1602 +++++++++++++ lab4/vivado/pynq/run.ps1 | 4 + lab4/vivado/pynq/run_simulation.tcl | 28 + start_cpu.bat | 1 + 449 files changed, 41705 insertions(+) create mode 100644 LICENSE create mode 100644 README.md create mode 100644 lab1/.gitignore create mode 100644 lab1/Makefile create mode 100644 lab1/build.sbt create mode 100644 lab1/coremark/yatcpu/core_portme.c create mode 100644 lab1/coremark/yatcpu/core_portme.h create mode 100644 lab1/coremark/yatcpu/core_portme.mak create mode 100644 lab1/coremark/yatcpu/cvt.c create mode 100644 lab1/coremark/yatcpu/div.s create mode 100644 lab1/coremark/yatcpu/ee_printf.c create mode 100644 lab1/coremark/yatcpu/init.s create mode 100644 lab1/coremark/yatcpu/link.ld create mode 100644 lab1/csrc/CMakeLists.txt create mode 100644 lab1/csrc/build.bat create mode 100644 lab1/csrc/build.sh create mode 100644 lab1/csrc/fibonacci.c create mode 100644 lab1/csrc/hdmi_test.c create mode 100644 lab1/csrc/hello.c create mode 100644 lab1/csrc/init.S create mode 100644 lab1/csrc/link.lds create mode 100644 lab1/csrc/mmio.S create mode 100644 lab1/csrc/mmio.h create mode 100644 lab1/csrc/quicksort.c create mode 100644 lab1/csrc/sb.S create mode 100644 lab1/csrc/tetris.c create mode 100644 lab1/csrc/toolchain.cmake create mode 100644 lab1/project/build.properties create mode 100644 lab1/project/plugins.sbt create mode 100644 lab1/riscv-target/yatcpu/Makefile.include create mode 100644 lab1/riscv-target/yatcpu/device/rv32i_m/I/Makefile.include create mode 100644 lab1/riscv-target/yatcpu/link.ld create mode 100644 lab1/riscv-target/yatcpu/model_test.h create mode 100644 lab1/src/main/resources/fibonacci.asmbin create mode 100644 lab1/src/main/resources/hello.asmbin create mode 100644 lab1/src/main/resources/litenes.asmbin create mode 100644 lab1/src/main/resources/mmio.asmbin create mode 100644 lab1/src/main/resources/quicksort.asmbin create mode 100644 lab1/src/main/resources/sb.asmbin create mode 100644 lab1/src/main/resources/tetris.asmbin create mode 100644 lab1/src/main/resources/vga_font_8x16.bmp create mode 100644 lab1/src/main/scala/board/basys3/BCD2Segments.scala create mode 100644 lab1/src/main/scala/board/basys3/OnboardDigitDisplay.scala create mode 100644 lab1/src/main/scala/board/basys3/SYSULogo.scala create mode 100644 lab1/src/main/scala/board/basys3/SegmentMux.scala create mode 100644 lab1/src/main/scala/board/basys3/Top.scala create mode 100644 lab1/src/main/scala/board/pynq/Top.scala create mode 100644 lab1/src/main/scala/board/verilator/Top.scala create mode 100644 lab1/src/main/scala/peripheral/CharacterDisplay.scala create mode 100644 lab1/src/main/scala/peripheral/Dummy.scala create mode 100644 lab1/src/main/scala/peripheral/FontROM.scala create mode 100644 lab1/src/main/scala/peripheral/HDMIDisplay.scala create mode 100644 lab1/src/main/scala/peripheral/InstructionROM.scala create mode 100644 lab1/src/main/scala/peripheral/Memory.scala create mode 100644 lab1/src/main/scala/peripheral/ROMLoader.scala create mode 100644 lab1/src/main/scala/peripheral/VGADisplay.scala create mode 100644 lab1/src/main/scala/riscv/CPUBundle.scala create mode 100644 lab1/src/main/scala/riscv/Parameters.scala create mode 100644 lab1/src/main/scala/riscv/core/ALU.scala create mode 100644 lab1/src/main/scala/riscv/core/ALUControl.scala create mode 100644 lab1/src/main/scala/riscv/core/CPU.scala create mode 100644 lab1/src/main/scala/riscv/core/Execute.scala create mode 100644 lab1/src/main/scala/riscv/core/InstructionDecode.scala create mode 100644 lab1/src/main/scala/riscv/core/InstructionFetch.scala create mode 100644 lab1/src/main/scala/riscv/core/MemoryAccess.scala create mode 100644 lab1/src/main/scala/riscv/core/RegisterFile.scala create mode 100644 lab1/src/main/scala/riscv/core/WriteBack.scala create mode 100644 lab1/src/test/scala/riscv/TestAnnotations.scala create mode 100644 lab1/src/test/scala/riscv/singlecycle/CPUTest.scala create mode 100644 lab1/src/test/scala/riscv/singlecycle/ExecuteTest.scala create mode 100644 lab1/src/test/scala/riscv/singlecycle/InstructionDecoderTest.scala create mode 100644 lab1/src/test/scala/riscv/singlecycle/InstructionFetchTest.scala create mode 100644 lab1/src/test/scala/riscv/singlecycle/RegisterFileTest.scala create mode 100644 lab1/verilog/basys3/test.v create mode 100644 lab1/verilog/pynq/TMDS_PLLVR.v create mode 100644 lab1/verilog/pynq/design_1_wrapper.v create mode 100644 lab1/verilog/pynq/test.v create mode 100644 lab1/verilog/verilator/sim_main.cpp create mode 100644 lab1/vivado/basys3/basys3.xdc create mode 100644 lab1/vivado/basys3/generate_and_program.tcl create mode 100644 lab1/vivado/basys3/generate_bitstream.tcl create mode 100644 lab1/vivado/basys3/open_project.tcl create mode 100644 lab1/vivado/basys3/program_device.tcl create mode 100644 lab1/vivado/basys3/run.ps1 create mode 100644 lab1/vivado/basys3/run_simulation.tcl create mode 100644 lab1/vivado/pynq/generate_and_program.tcl create mode 100644 lab1/vivado/pynq/generate_bitstream.tcl create mode 100644 lab1/vivado/pynq/open_project.tcl create mode 100644 lab1/vivado/pynq/program_device.tcl create mode 100644 lab1/vivado/pynq/pynq.xdc create mode 100644 lab1/vivado/pynq/run.ps1 create mode 100644 lab1/vivado/pynq/run_simulation.tcl create mode 100644 lab2/.gitignore create mode 100644 lab2/Makefile create mode 100644 lab2/build.sbt create mode 100644 lab2/coremark/yatcpu/core_portme.c create mode 100644 lab2/coremark/yatcpu/core_portme.h create mode 100644 lab2/coremark/yatcpu/core_portme.mak create mode 100644 lab2/coremark/yatcpu/cvt.c create mode 100644 lab2/coremark/yatcpu/div.s create mode 100644 lab2/coremark/yatcpu/ee_printf.c create mode 100644 lab2/coremark/yatcpu/init.s create mode 100644 lab2/coremark/yatcpu/link.ld create mode 100644 lab2/csrc/CMakeLists.txt create mode 100644 lab2/csrc/build.bat create mode 100644 lab2/csrc/build.sh create mode 100644 lab2/csrc/fibonacci.c create mode 100644 lab2/csrc/hello.c create mode 100644 lab2/csrc/init.S create mode 100644 lab2/csrc/link.lds create mode 100644 lab2/csrc/mmio.S create mode 100644 lab2/csrc/mmio.h create mode 100644 lab2/csrc/quicksort.c create mode 100644 lab2/csrc/sb.S create mode 100644 lab2/csrc/simpletest.c create mode 100644 lab2/csrc/tetris.S create mode 100644 lab2/csrc/tetris.c create mode 100644 lab2/csrc/toolchain.cmake create mode 100644 lab2/project/build.properties create mode 100644 lab2/project/plugins.sbt create mode 100644 lab2/riscv-target/yatcpu/Makefile.include create mode 100644 lab2/riscv-target/yatcpu/device/rv32i_m/I/Makefile.include create mode 100644 lab2/riscv-target/yatcpu/link.ld create mode 100644 lab2/riscv-target/yatcpu/model_test.h create mode 100644 lab2/src/main/resources/fibonacci.asmbin create mode 100644 lab2/src/main/resources/hdmi_test.asmbin create mode 100644 lab2/src/main/resources/hello.asmbin create mode 100644 lab2/src/main/resources/mmio.asmbin create mode 100644 lab2/src/main/resources/quicksort.asmbin create mode 100644 lab2/src/main/resources/sb.asmbin create mode 100644 lab2/src/main/resources/simpletest.asmbin create mode 100644 lab2/src/main/resources/tetris.asmbin create mode 100644 lab2/src/main/resources/vga_font_8x16.bmp create mode 100644 lab2/src/main/scala/board/basys3/BCD2Segments.scala create mode 100644 lab2/src/main/scala/board/basys3/OnboardDigitDisplay.scala create mode 100644 lab2/src/main/scala/board/basys3/SYSULogo.scala create mode 100644 lab2/src/main/scala/board/basys3/SegmentMux.scala create mode 100644 lab2/src/main/scala/board/basys3/Top.scala create mode 100644 lab2/src/main/scala/board/pynq/Top.scala create mode 100644 lab2/src/main/scala/board/verilator/Top.scala create mode 100644 lab2/src/main/scala/peripheral/CharacterDisplay.scala create mode 100644 lab2/src/main/scala/peripheral/Dummy.scala create mode 100644 lab2/src/main/scala/peripheral/FontROM.scala create mode 100644 lab2/src/main/scala/peripheral/HDMIDisplay.scala create mode 100644 lab2/src/main/scala/peripheral/InstructionROM.scala create mode 100644 lab2/src/main/scala/peripheral/Memory.scala create mode 100644 lab2/src/main/scala/peripheral/ROMLoader.scala create mode 100644 lab2/src/main/scala/peripheral/Timer.scala create mode 100644 lab2/src/main/scala/peripheral/UART.scala create mode 100644 lab2/src/main/scala/peripheral/VGADisplay.scala create mode 100644 lab2/src/main/scala/riscv/CPUBundle.scala create mode 100644 lab2/src/main/scala/riscv/Parameters.scala create mode 100644 lab2/src/main/scala/riscv/core/ALU.scala create mode 100644 lab2/src/main/scala/riscv/core/ALUControl.scala create mode 100644 lab2/src/main/scala/riscv/core/CLINT.scala create mode 100644 lab2/src/main/scala/riscv/core/CPU.scala create mode 100644 lab2/src/main/scala/riscv/core/CSR.scala create mode 100644 lab2/src/main/scala/riscv/core/Execute.scala create mode 100644 lab2/src/main/scala/riscv/core/InstructionDecode.scala create mode 100644 lab2/src/main/scala/riscv/core/InstructionFetch.scala create mode 100644 lab2/src/main/scala/riscv/core/MemoryAccess.scala create mode 100644 lab2/src/main/scala/riscv/core/RegisterFile.scala create mode 100644 lab2/src/main/scala/riscv/core/WriteBack.scala create mode 100644 lab2/src/test/scala/riscv/TestAnnotations.scala create mode 100644 lab2/src/test/scala/riscv/singlecycle/CLINTCSRTest.scala create mode 100644 lab2/src/test/scala/riscv/singlecycle/CPUTest.scala create mode 100644 lab2/src/test/scala/riscv/singlecycle/ExecuteTest.scala create mode 100644 lab2/src/test/scala/riscv/singlecycle/TimerTest.scala create mode 100644 lab2/verilog/basys3/test.v create mode 100644 lab2/verilog/pynq/TMDS_PLLVR.v create mode 100644 lab2/verilog/pynq/test.v create mode 100644 lab2/verilog/verilator/sim_main.cpp create mode 100644 lab2/vivado/basys3/basys3.xdc create mode 100644 lab2/vivado/basys3/generate_and_program.tcl create mode 100644 lab2/vivado/basys3/generate_bitstream.tcl create mode 100644 lab2/vivado/basys3/open_project.tcl create mode 100644 lab2/vivado/basys3/program_device.tcl create mode 100644 lab2/vivado/basys3/run.ps1 create mode 100644 lab2/vivado/basys3/run_simulation.tcl create mode 100644 lab2/vivado/pynq/generate_and_program.tcl create mode 100644 lab2/vivado/pynq/generate_bitstream.tcl create mode 100644 lab2/vivado/pynq/open_project.tcl create mode 100644 lab2/vivado/pynq/program_device.tcl create mode 100644 lab2/vivado/pynq/pynq.xdc create mode 100644 lab2/vivado/pynq/run.ps1 create mode 100644 lab2/vivado/pynq/run_simulation.tcl create mode 100644 lab3/.gitignore create mode 100644 lab3/Makefile create mode 100644 lab3/build.sbt create mode 100644 lab3/coremark/yatcpu/core_portme.c create mode 100644 lab3/coremark/yatcpu/core_portme.h create mode 100644 lab3/coremark/yatcpu/core_portme.mak create mode 100644 lab3/coremark/yatcpu/cvt.c create mode 100644 lab3/coremark/yatcpu/div.s create mode 100644 lab3/coremark/yatcpu/ee_printf.c create mode 100644 lab3/coremark/yatcpu/init.s create mode 100644 lab3/coremark/yatcpu/link.ld create mode 100644 lab3/csrc/CMakeLists.txt create mode 100644 lab3/csrc/build.bat create mode 100644 lab3/csrc/build.sh create mode 100644 lab3/csrc/fibonacci.c create mode 100644 lab3/csrc/hazard.S create mode 100644 lab3/csrc/hello.c create mode 100644 lab3/csrc/init.S create mode 100644 lab3/csrc/link.lds create mode 100644 lab3/csrc/mmio.S create mode 100644 lab3/csrc/mmio.h create mode 100644 lab3/csrc/quicksort.c create mode 100644 lab3/csrc/sb.S create mode 100644 lab3/csrc/tetris.c create mode 100644 lab3/csrc/toolchain.cmake create mode 100644 lab3/project/build.properties create mode 100644 lab3/project/plugins.sbt create mode 100644 lab3/riscv-target/yatcpu/Makefile.include create mode 100644 lab3/riscv-target/yatcpu/device/rv32i_m/I/Makefile.include create mode 100644 lab3/riscv-target/yatcpu/link.ld create mode 100644 lab3/riscv-target/yatcpu/model_test.h create mode 100644 lab3/src/main/resources/fibonacci.asmbin create mode 100644 lab3/src/main/resources/hazard.asmbin create mode 100644 lab3/src/main/resources/hello.asmbin create mode 100644 lab3/src/main/resources/mmio.asmbin create mode 100644 lab3/src/main/resources/quicksort.asmbin create mode 100644 lab3/src/main/resources/sb.asmbin create mode 100644 lab3/src/main/resources/tetris.asmbin create mode 100644 lab3/src/main/resources/vga_font_8x16.bmp create mode 100644 lab3/src/main/scala/board/basys3/BCD2Segments.scala create mode 100644 lab3/src/main/scala/board/basys3/OnboardDigitDisplay.scala create mode 100644 lab3/src/main/scala/board/basys3/SYSULogo.scala create mode 100644 lab3/src/main/scala/board/basys3/SegmentMux.scala create mode 100644 lab3/src/main/scala/board/basys3/Top.scala create mode 100644 lab3/src/main/scala/board/pynq/Top.scala create mode 100644 lab3/src/main/scala/board/verilator/Top.scala create mode 100644 lab3/src/main/scala/peripheral/Dummy.scala create mode 100644 lab3/src/main/scala/peripheral/FontROM.scala create mode 100644 lab3/src/main/scala/peripheral/HDMIDisplay.scala create mode 100644 lab3/src/main/scala/peripheral/InstructionROM.scala create mode 100644 lab3/src/main/scala/peripheral/Memory.scala create mode 100644 lab3/src/main/scala/peripheral/ROMLoader.scala create mode 100644 lab3/src/main/scala/peripheral/Timer.scala create mode 100644 lab3/src/main/scala/peripheral/UART.scala create mode 100644 lab3/src/main/scala/peripheral/VGADisplay.scala create mode 100644 lab3/src/main/scala/riscv/Parameters.scala create mode 100644 lab3/src/main/scala/riscv/core/ALU.scala create mode 100644 lab3/src/main/scala/riscv/core/ALUControl.scala create mode 100644 lab3/src/main/scala/riscv/core/CPU.scala create mode 100644 lab3/src/main/scala/riscv/core/CPUBundle.scala create mode 100644 lab3/src/main/scala/riscv/core/CSR.scala create mode 100644 lab3/src/main/scala/riscv/core/PipelineRegister.scala create mode 100644 lab3/src/main/scala/riscv/core/RegisterFile.scala create mode 100644 lab3/src/main/scala/riscv/core/fivestage_final/CLINT.scala create mode 100644 lab3/src/main/scala/riscv/core/fivestage_final/CPU.scala create mode 100644 lab3/src/main/scala/riscv/core/fivestage_final/Control.scala create mode 100644 lab3/src/main/scala/riscv/core/fivestage_final/EX2MEM.scala create mode 100644 lab3/src/main/scala/riscv/core/fivestage_final/Execute.scala create mode 100644 lab3/src/main/scala/riscv/core/fivestage_final/Forwarding.scala create mode 100644 lab3/src/main/scala/riscv/core/fivestage_final/ID2EX.scala create mode 100644 lab3/src/main/scala/riscv/core/fivestage_final/IF2ID.scala create mode 100644 lab3/src/main/scala/riscv/core/fivestage_final/InstructionDecode.scala create mode 100644 lab3/src/main/scala/riscv/core/fivestage_final/InstructionFetch.scala create mode 100644 lab3/src/main/scala/riscv/core/fivestage_final/MEM2WB.scala create mode 100644 lab3/src/main/scala/riscv/core/fivestage_final/MemoryAccess.scala create mode 100644 lab3/src/main/scala/riscv/core/fivestage_final/WriteBack.scala create mode 100644 lab3/src/main/scala/riscv/core/fivestage_forward/CLINT.scala create mode 100644 lab3/src/main/scala/riscv/core/fivestage_forward/CPU.scala create mode 100644 lab3/src/main/scala/riscv/core/fivestage_forward/Control.scala create mode 100644 lab3/src/main/scala/riscv/core/fivestage_forward/EX2MEM.scala create mode 100644 lab3/src/main/scala/riscv/core/fivestage_forward/Execute.scala create mode 100644 lab3/src/main/scala/riscv/core/fivestage_forward/Forwarding.scala create mode 100644 lab3/src/main/scala/riscv/core/fivestage_forward/ID2EX.scala create mode 100644 lab3/src/main/scala/riscv/core/fivestage_forward/IF2ID.scala create mode 100644 lab3/src/main/scala/riscv/core/fivestage_forward/InstructionDecode.scala create mode 100644 lab3/src/main/scala/riscv/core/fivestage_forward/InstructionFetch.scala create mode 100644 lab3/src/main/scala/riscv/core/fivestage_forward/MEM2WB.scala create mode 100644 lab3/src/main/scala/riscv/core/fivestage_forward/MemoryAccess.scala create mode 100644 lab3/src/main/scala/riscv/core/fivestage_forward/WriteBack.scala create mode 100644 lab3/src/main/scala/riscv/core/fivestage_stall/CLINT.scala create mode 100644 lab3/src/main/scala/riscv/core/fivestage_stall/CPU.scala create mode 100644 lab3/src/main/scala/riscv/core/fivestage_stall/Control.scala create mode 100644 lab3/src/main/scala/riscv/core/fivestage_stall/EX2MEM.scala create mode 100644 lab3/src/main/scala/riscv/core/fivestage_stall/Execute.scala create mode 100644 lab3/src/main/scala/riscv/core/fivestage_stall/ID2EX.scala create mode 100644 lab3/src/main/scala/riscv/core/fivestage_stall/IF2ID.scala create mode 100644 lab3/src/main/scala/riscv/core/fivestage_stall/InstructionDecode.scala create mode 100644 lab3/src/main/scala/riscv/core/fivestage_stall/InstructionFetch.scala create mode 100644 lab3/src/main/scala/riscv/core/fivestage_stall/MEM2WB.scala create mode 100644 lab3/src/main/scala/riscv/core/fivestage_stall/MemoryAccess.scala create mode 100644 lab3/src/main/scala/riscv/core/fivestage_stall/WriteBack.scala create mode 100644 lab3/src/main/scala/riscv/core/threestage/CLINT.scala create mode 100644 lab3/src/main/scala/riscv/core/threestage/CPU.scala create mode 100644 lab3/src/main/scala/riscv/core/threestage/Control.scala create mode 100644 lab3/src/main/scala/riscv/core/threestage/Execute.scala create mode 100644 lab3/src/main/scala/riscv/core/threestage/ID2EX.scala create mode 100644 lab3/src/main/scala/riscv/core/threestage/IF2ID.scala create mode 100644 lab3/src/main/scala/riscv/core/threestage/InstructionDecode.scala create mode 100644 lab3/src/main/scala/riscv/core/threestage/InstructionFetch.scala create mode 100644 lab3/src/test/scala/riscv/FiveStageCPUFinalTest.scala create mode 100644 lab3/src/test/scala/riscv/FiveStageCPUForwardTest.scala create mode 100644 lab3/src/test/scala/riscv/FiveStageCPUStallTest.scala create mode 100644 lab3/src/test/scala/riscv/PipelineRegisterTest.scala create mode 100644 lab3/src/test/scala/riscv/TestAnnotations.scala create mode 100644 lab3/src/test/scala/riscv/TestTopModule.scala create mode 100644 lab3/src/test/scala/riscv/ThreeStageCPUTest.scala create mode 100644 lab3/verilog/basys3/test.v create mode 100644 lab3/verilog/pynq/TMDS_PLLVR.v create mode 100644 lab3/verilog/pynq/test.v create mode 100644 lab3/verilog/verilator/sim_main.cpp create mode 100644 lab3/vivado/basys3/basys3.xdc create mode 100644 lab3/vivado/basys3/generate_and_program.tcl create mode 100644 lab3/vivado/basys3/generate_bitstream.tcl create mode 100644 lab3/vivado/basys3/open_project.tcl create mode 100644 lab3/vivado/basys3/program_device.tcl create mode 100644 lab3/vivado/basys3/run.ps1 create mode 100644 lab3/vivado/basys3/run_simulation.tcl create mode 100644 lab3/vivado/pynq/generate_and_program.tcl create mode 100644 lab3/vivado/pynq/generate_bitstream.tcl create mode 100644 lab3/vivado/pynq/open_project.tcl create mode 100644 lab3/vivado/pynq/program_device.tcl create mode 100644 lab3/vivado/pynq/pynq.xdc create mode 100644 lab3/vivado/pynq/run.ps1 create mode 100644 lab3/vivado/pynq/run_simulation.tcl create mode 100644 lab4/.gitignore create mode 100644 lab4/Makefile create mode 100644 lab4/build.sbt create mode 100644 lab4/coremark/yatcpu/core_portme.c create mode 100644 lab4/coremark/yatcpu/core_portme.h create mode 100644 lab4/coremark/yatcpu/core_portme.mak create mode 100644 lab4/coremark/yatcpu/cvt.c create mode 100644 lab4/coremark/yatcpu/div.s create mode 100644 lab4/coremark/yatcpu/ee_printf.c create mode 100644 lab4/coremark/yatcpu/init.s create mode 100644 lab4/coremark/yatcpu/link.ld create mode 100644 lab4/csrc/CMakeLists.txt create mode 100644 lab4/csrc/build.bat create mode 100644 lab4/csrc/build.sh create mode 100644 lab4/csrc/fibonacci.c create mode 100644 lab4/csrc/hello.c create mode 100644 lab4/csrc/init.S create mode 100644 lab4/csrc/link.lds create mode 100644 lab4/csrc/mm.h create mode 100644 lab4/csrc/mmio.S create mode 100644 lab4/csrc/mmio.h create mode 100644 lab4/csrc/paging.c create mode 100644 lab4/csrc/quicksort.c create mode 100644 lab4/csrc/say_goodbye.c create mode 100644 lab4/csrc/sb.S create mode 100644 lab4/csrc/tetris.c create mode 100644 lab4/csrc/tetris_mmu.c create mode 100644 lab4/csrc/toolchain.cmake create mode 100644 lab4/project/build.properties create mode 100644 lab4/project/plugins.sbt create mode 100644 lab4/riscv-target/yatcpu/Makefile.include create mode 100644 lab4/riscv-target/yatcpu/device/rv32i_m/I/Makefile.include create mode 100644 lab4/riscv-target/yatcpu/link.ld create mode 100644 lab4/riscv-target/yatcpu/model_test.h create mode 100644 lab4/src/main/resources/fibonacci.asmbin create mode 100644 lab4/src/main/resources/hello.asmbin create mode 100644 lab4/src/main/resources/mmio.asmbin create mode 100644 lab4/src/main/resources/quicksort.asmbin create mode 100644 lab4/src/main/resources/sb.asmbin create mode 100644 lab4/src/main/resources/tetris.asmbin create mode 100644 lab4/src/main/resources/vga_font_8x16.bmp create mode 100644 lab4/src/main/scala/board/basys3/BCD2Segments.scala create mode 100644 lab4/src/main/scala/board/basys3/OnboardDigitDisplay.scala create mode 100644 lab4/src/main/scala/board/basys3/SYSULogo.scala create mode 100644 lab4/src/main/scala/board/basys3/SegmentMux.scala create mode 100644 lab4/src/main/scala/board/basys3/Top.scala create mode 100644 lab4/src/main/scala/board/pynq/Top.scala create mode 100644 lab4/src/main/scala/board/verilator/Top.scala create mode 100644 lab4/src/main/scala/bus/AXI4Lite.scala create mode 100644 lab4/src/main/scala/bus/BusArbiter.scala create mode 100644 lab4/src/main/scala/bus/BusSwitch.scala create mode 100644 lab4/src/main/scala/peripheral/CharacterDisplay.scala create mode 100644 lab4/src/main/scala/peripheral/DummyMaster.scala create mode 100644 lab4/src/main/scala/peripheral/DummySlave.scala create mode 100644 lab4/src/main/scala/peripheral/FontROM.scala create mode 100644 lab4/src/main/scala/peripheral/HDMIDisplay.scala create mode 100644 lab4/src/main/scala/peripheral/InstructionROM.scala create mode 100644 lab4/src/main/scala/peripheral/InterruptController.scala create mode 100644 lab4/src/main/scala/peripheral/Memory.scala create mode 100644 lab4/src/main/scala/peripheral/PixelDisplay.scala create mode 100644 lab4/src/main/scala/peripheral/ROMLoader.scala create mode 100644 lab4/src/main/scala/peripheral/SPI.scala create mode 100644 lab4/src/main/scala/peripheral/Timer.scala create mode 100644 lab4/src/main/scala/peripheral/UART.scala create mode 100644 lab4/src/main/scala/peripheral/VGADisplay.scala create mode 100644 lab4/src/main/scala/riscv/Parameters.scala create mode 100644 lab4/src/main/scala/riscv/core/BusBundle.scala create mode 100644 lab4/src/main/scala/riscv/core/CPU.scala create mode 100644 lab4/src/main/scala/riscv/core/CPUBundle.scala create mode 100644 lab4/src/main/scala/riscv/core/fivestage/ALU.scala create mode 100644 lab4/src/main/scala/riscv/core/fivestage/ALUControl.scala create mode 100644 lab4/src/main/scala/riscv/core/fivestage/CLINT.scala create mode 100644 lab4/src/main/scala/riscv/core/fivestage/CPU.scala create mode 100644 lab4/src/main/scala/riscv/core/fivestage/CSR.scala create mode 100644 lab4/src/main/scala/riscv/core/fivestage/Cache.scala create mode 100644 lab4/src/main/scala/riscv/core/fivestage/Control.scala create mode 100644 lab4/src/main/scala/riscv/core/fivestage/EX2MEM.scala create mode 100644 lab4/src/main/scala/riscv/core/fivestage/Execute.scala create mode 100644 lab4/src/main/scala/riscv/core/fivestage/Forwarding.scala create mode 100644 lab4/src/main/scala/riscv/core/fivestage/ID2EX.scala create mode 100644 lab4/src/main/scala/riscv/core/fivestage/IF2ID.scala create mode 100644 lab4/src/main/scala/riscv/core/fivestage/InstructionDecode.scala create mode 100644 lab4/src/main/scala/riscv/core/fivestage/InstructionFetch.scala create mode 100644 lab4/src/main/scala/riscv/core/fivestage/MEM2WB.scala create mode 100644 lab4/src/main/scala/riscv/core/fivestage/MemoryAccess.scala create mode 100644 lab4/src/main/scala/riscv/core/fivestage/PipelineRegister.scala create mode 100644 lab4/src/main/scala/riscv/core/fivestage/RegisterFile.scala create mode 100644 lab4/src/main/scala/riscv/core/fivestage/WriteBack.scala create mode 100644 lab4/src/main/scala/riscv/core/threestage/ALU.scala create mode 100644 lab4/src/main/scala/riscv/core/threestage/ALUControl.scala create mode 100644 lab4/src/main/scala/riscv/core/threestage/CLINT.scala create mode 100644 lab4/src/main/scala/riscv/core/threestage/CPU.scala create mode 100644 lab4/src/main/scala/riscv/core/threestage/CSR.scala create mode 100644 lab4/src/main/scala/riscv/core/threestage/Cache.scala create mode 100644 lab4/src/main/scala/riscv/core/threestage/Control.scala create mode 100644 lab4/src/main/scala/riscv/core/threestage/Execute.scala create mode 100644 lab4/src/main/scala/riscv/core/threestage/ID2EX.scala create mode 100644 lab4/src/main/scala/riscv/core/threestage/IF2ID.scala create mode 100644 lab4/src/main/scala/riscv/core/threestage/InstructionDecode.scala create mode 100644 lab4/src/main/scala/riscv/core/threestage/InstructionFetch.scala create mode 100644 lab4/src/main/scala/riscv/core/threestage/PipelineRegister.scala create mode 100644 lab4/src/main/scala/riscv/core/threestage/RegisterFile.scala create mode 100644 lab4/src/main/scala/riscv/debug/DebugModule.scala create mode 100644 lab4/src/main/scala/riscv/debug/DebugTransportModule.scala create mode 100644 lab4/src/test/scala/riscv/BusTest.scala create mode 100644 lab4/src/test/scala/riscv/TestAnnotations.scala create mode 100644 lab4/src/test/scala/riscv/fivestage/CPUTest.scala create mode 100644 lab4/src/test/scala/riscv/threestage/CPUTest.scala create mode 100644 lab4/verilog/basys3/test.v create mode 100644 lab4/verilog/pynq/TMDS_PLLVR.v create mode 100644 lab4/verilog/pynq/design_1_wrapper.v create mode 100644 lab4/verilog/pynq/test.v create mode 100644 lab4/verilog/verilator/sim_main.cpp create mode 100644 lab4/vivado/basys3/basys3.xdc create mode 100644 lab4/vivado/basys3/generate_and_program.tcl create mode 100644 lab4/vivado/basys3/generate_bitstream.tcl create mode 100644 lab4/vivado/basys3/open_project.tcl create mode 100644 lab4/vivado/basys3/program_device.tcl create mode 100644 lab4/vivado/basys3/run.ps1 create mode 100644 lab4/vivado/basys3/run_simulation.tcl create mode 100644 lab4/vivado/pynq/generate_and_program.tcl create mode 100644 lab4/vivado/pynq/generate_bitstream.tcl create mode 100644 lab4/vivado/pynq/open_project.tcl create mode 100644 lab4/vivado/pynq/program_device.tcl create mode 100644 lab4/vivado/pynq/pynq.xdc create mode 100644 lab4/vivado/pynq/riscv-pynq.tcl create mode 100644 lab4/vivado/pynq/run.ps1 create mode 100644 lab4/vivado/pynq/run_simulation.tcl create mode 100644 start_cpu.bat diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..8317c59 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [Tokisakix] [name of copyright owner] + + 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. diff --git a/README.md b/README.md new file mode 100644 index 0000000..f53c9de --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +# YatCPU diff --git a/lab1/.gitignore b/lab1/.gitignore new file mode 100644 index 0000000..946816b --- /dev/null +++ b/lab1/.gitignore @@ -0,0 +1,358 @@ +### Project Specific stuff +test_run_dir/* +### XilinxISE template +# intermediate build files +*.bgn +*.bit +*.bld +*.cmd_log +*.drc +*.ll +*.lso +*.msd +*.msk +*.ncd +*.ngc +*.ngd +*.ngr +*.pad +*.par +*.pcf +*.prj +*.ptwx +*.rbb +*.rbd +*.stx +*.syr +*.twr +*.twx +*.unroutes +*.ut +*.xpi +*.xst +*_bitgen.xwbt +*_envsettings.html +*_map.map +*_map.mrp +*_map.ngm +*_map.xrpt +*_ngdbuild.xrpt +*_pad.csv +*_pad.txt +*_par.xrpt +*_summary.html +*_summary.xml +*_usage.xml +*_xst.xrpt + +# project-wide generated files +*.gise +par_usage_statistics.html +usage_statistics_webtalk.html +webtalk.log +webtalk_pn.xml + +# generated folders +iseconfig/ +xlnx_auto_0_xdb/ +xst/ +_ngo/ +_xmsgs/ +### Eclipse template +*.pydevproject +.metadata +.gradle +bin/ +tmp/ +*.tmp +*.bak +*.swp +*~.nib +local.properties +.settings/ +.loadpath + +# Eclipse Core +.project + +# External tool builders +.externalToolBuilders/ + +# Locally stored "Eclipse launch configurations" +*.launch + +# CDT-specific +.cproject + +# JDT-specific (Eclipse Java Development Tools) +.classpath + +# Java annotation processor (APT) +.factorypath + +# PDT-specific +.buildpath + +# sbteclipse plugin +.target + +# TeXlipse plugin +.texlipse +### C template +# Object files +*.o +*.ko +*.obj +*.elf + +# Precompiled Headers +*.gch +*.pch + +# Libraries +*.lib +*.a +*.la +*.lo + +# Shared objects (inc. Windows DLLs) +*.dll +*.so +*.so.* +*.dylib + +# Executables +*.exe +*.out +*.app +*.i*86 +*.x86_64 +*.hex + +# Debug files +*.dSYM/ +### SBT template +# Simple Build Tool +# http://www.scala-sbt.org/release/docs/Getting-Started/Directories.html#configuring-version-control + +target/ +lib_managed/ +src_managed/ +project/boot/ +.history +.cache +### Emacs template +# -*- mode: gitignore; -*- +*~ +\#*\# +/.emacs.desktop +/.emacs.desktop.lock +*.elc +auto-save-list +tramp +.\#* + +# Org-mode +.org-id-locations +*_archive + +# flymake-mode +*_flymake.* + +# eshell files +/eshell/history +/eshell/lastdir + +# elpa packages +/elpa/ + +# reftex files +*.rel + +# AUCTeX auto folder +/auto/ + +# cask packages +.cask/ +### Vim template +[._]*.s[a-w][a-z] +[._]s[a-w][a-z] +*.un~ +Session.vim +.netrwhist +*~ +### JetBrains template +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio + +*.iml + +## Directory-based project format: +.idea/ +# if you remove the above rule, at least ignore the following: + +# User-specific stuff: +# .idea/workspace.xml +# .idea/tasks.xml +# .idea/dictionaries + +# Sensitive or high-churn files: +# .idea/dataSources.ids +# .idea/dataSources.xml +# .idea/sqlDataSources.xml +# .idea/dynamic.xml +# .idea/uiDesigner.xml + +# Gradle: +# .idea/gradle.xml +# .idea/libraries + +# Mongo Explorer plugin: +# .idea/mongoSettings.xml + +## File-based project format: +*.ipr +*.iws + +## Plugin-specific files: + +# IntelliJ +/out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +### C++ template +# Compiled Object files +*.slo +*.lo +*.o +*.obj + +# Precompiled Headers +*.gch +*.pch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app +### OSX template +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk +### Xcode template +# Xcode +# +# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore + +## Build generated +build/ +DerivedData + +## Various settings +*.pbxuser +!default.pbxuser +*.mode1v3 +!default.mode1v3 +*.mode2v3 +!default.mode2v3 +*.perspectivev3 +!default.perspectivev3 +xcuserdata + +## Other +*.xccheckout +*.moved-aside +*.xcuserstate +### Scala template +*.class +*.log +/.bsp + +# sbt specific +.cache +.history +.lib/ +dist/* +target/ +lib_managed/ +src_managed/ +project/boot/ +project/plugins/project/ + +# Scala-IDE specific +.scala_dependencies +.worksheet +### Java template +*.class + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.ear + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* + +verilog/*.txt +verilog/basys3/* +verilog/pynq/* +verilog/verilator/* +!verilog/basys3/test.v +!verilog/pynq/design_1_wrapper.v +!verilog/pynq/test.v +!verilog/pynq/TMDS_PLLVR.v +!verilog/verilator/sim_main.cpp +*.jou +*.log +.Xil +vivado/basys3/riscv-basys3 +vivado/pynq/riscv-pynq +vivado/pynq/NA +.vscode +.metals diff --git a/lab1/Makefile b/lab1/Makefile new file mode 100644 index 0000000..1bffd0a --- /dev/null +++ b/lab1/Makefile @@ -0,0 +1,47 @@ +# 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. + +test: + sbt test + +verilator: + sbt "runMain board.verilator.VerilogGenerator" + cd verilog/verilator && verilator --trace --exe --cc sim_main.cpp Top.v && make -C obj_dir -f VTop.mk + +verilator-sim: verilator + cd verilog/verilator && obj_dir/VTop $(SIM_TIME) + +basys3: + sbt "runMain board.basys3.VerilogGenerator" +pynq: + sbt "runMain board.pynq.VerilogGenerator" + +bitstream-basys3: basys3 + cd vivado/basys3 && vivado -mode batch -source generate_bitstream.tcl + +program-basys3: bitstream-basys3 + cd vivado/basys3 && vivado -mode batch -source program_device.tcl + +vivado-sim-basys3: basys3 + cd vivado/basys3 && vivado -mode batch -source run_simulation.tcl +bitstream-pynq: pynq + cd vivado/pynq && vivado -mode batch -source generate_bitstream.tcl + +program-pynq: bitstream-pynq + cd vivado/pynq && vivado -mode batch -source program_device.tcl + +vivado-sim-pynq: pynq + cd vivado/pynq && vivado -mode batch -source run_simulation.tcl + +.PHONY: basys3 verilator test bitstream program verilator-sim vivado-sim diff --git a/lab1/build.sbt b/lab1/build.sbt new file mode 100644 index 0000000..75f138e --- /dev/null +++ b/lab1/build.sbt @@ -0,0 +1,24 @@ +import sbt.Keys.libraryDependencies +// See README.md for license details. + +ThisBuild / scalaVersion := "2.13.10" +ThisBuild / version := "0.1.0" +ThisBuild / organization := "io.github.howardlau1999" + +val chiselVersion = "3.6.0" + +lazy val root = (project in file(".")) + .settings( + name := "yatcpu", + libraryDependencies ++= Seq( + "edu.berkeley.cs" %% "chisel3" % chiselVersion, + "edu.berkeley.cs" %% "chiseltest" % "0.6.0" % "test", + ), + scalacOptions ++= Seq( + "-language:reflectiveCalls", + "-deprecation", + "-feature", + "-Xcheckinit", + ), + addCompilerPlugin("edu.berkeley.cs" % "chisel3-plugin" % chiselVersion cross CrossVersion.full), + ) diff --git a/lab1/coremark/yatcpu/core_portme.c b/lab1/coremark/yatcpu/core_portme.c new file mode 100644 index 0000000..3d7ae3b --- /dev/null +++ b/lab1/coremark/yatcpu/core_portme.c @@ -0,0 +1,169 @@ +/* +Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) + +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. + +Original Author: Shay Gal-on +*/ +#include "coremark.h" +#include "core_portme.h" + +#if VALIDATION_RUN +volatile ee_s32 seed1_volatile = 0x3415; +volatile ee_s32 seed2_volatile = 0x3415; +volatile ee_s32 seed3_volatile = 0x66; +#endif +#if PERFORMANCE_RUN +volatile ee_s32 seed1_volatile = 0x0; +volatile ee_s32 seed2_volatile = 0x0; +volatile ee_s32 seed3_volatile = 0x66; +#endif +#if PROFILE_RUN +volatile ee_s32 seed1_volatile = 0x8; +volatile ee_s32 seed2_volatile = 0x8; +volatile ee_s32 seed3_volatile = 0x8; +#endif +volatile ee_s32 seed4_volatile = ITERATIONS; +volatile ee_s32 seed5_volatile = 0; +/* Porting : Timing functions + How to capture time and convert to seconds must be ported to whatever is + supported by the platform. e.g. Read value from on board RTC, read value from + cpu clock cycles performance counter etc. Sample implementation for standard + time.h and windows.h definitions included. +*/ +CORETIMETYPE +barebones_clock() +{ + ee_u32 cyclel; + __asm__ __volatile__ ( + "rdcycle %0" : "=r"(cyclel) : : + ); + return cyclel; +} +/* Define : TIMER_RES_DIVIDER + Divider to trade off timer resolution and total time that can be + measured. + + Use lower values to increase resolution, but make sure that overflow + does not occur. If there are issues with the return value overflowing, + increase this value. + */ +#define GETMYTIME(_t) (*_t = barebones_clock()) +#define MYTIMEDIFF(fin, ini) ((fin) - (ini)) +#define TIMER_RES_DIVIDER 1 +#define SAMPLE_TIME_IMPLEMENTATION 1 +#define EE_TICKS_PER_SEC (CLOCKS_PER_SEC / TIMER_RES_DIVIDER) + +/** Define Host specific (POSIX), or target specific global time variables. */ +static CORETIMETYPE start_time_val, stop_time_val; + +/* Function : start_time + This function will be called right before starting the timed portion of + the benchmark. + + Implementation may be capturing a system timer (as implemented in the + example code) or zeroing some system parameters - e.g. setting the cpu clocks + cycles to 0. +*/ +void +start_time(void) +{ + GETMYTIME(&start_time_val); +} +/* Function : stop_time + This function will be called right after ending the timed portion of the + benchmark. + + Implementation may be capturing a system timer (as implemented in the + example code) or other system parameters - e.g. reading the current value of + cpu cycles counter. +*/ +void +stop_time(void) +{ + GETMYTIME(&stop_time_val); +} +/* Function : get_time + Return an abstract "ticks" number that signifies time on the system. + + Actual value returned may be cpu cycles, milliseconds or any other + value, as long as it can be converted to seconds by . This + methodology is taken to accommodate any hardware or simulated platform. The + sample implementation returns millisecs by default, and the resolution is + controlled by +*/ +CORE_TICKS +get_time(void) +{ + CORE_TICKS elapsed + = (CORE_TICKS)(MYTIMEDIFF(stop_time_val, start_time_val)); + return elapsed; +} +/* Function : time_in_secs + Convert the value returned by get_time to seconds. + + The type is used to accommodate systems with no support for + floating point. Default implementation implemented by the EE_TICKS_PER_SEC + macro above. +*/ +secs_ret +time_in_secs(CORE_TICKS ticks) +{ + secs_ret retval = ((secs_ret)ticks) / (secs_ret)EE_TICKS_PER_SEC; + return retval; +} + +ee_u32 default_num_contexts = 1; + +/* Function : portable_init + Target specific initialization code + Test for some common mistakes. +*/ +void +portable_init(core_portable *p, int *argc, char *argv[]) +{ + if (sizeof(ee_ptr_int) != sizeof(ee_u8 *)) + { + ee_printf( + "ERROR! Please define ee_ptr_int to a type that holds a " + "pointer!\n"); + } + if (sizeof(ee_u32) != 4) + { + ee_printf("ERROR! Please define ee_u32 to a 32b unsigned type!\n"); + } + p->portable_id = 1; +} +/* Function : portable_fini + Target specific final code +*/ +void +portable_fini(core_portable *p) +{ + p->portable_id = 0; +} + +unsigned int +__mulsi3 (unsigned int a, unsigned int b) +{ + unsigned int r = 0; + + while (a) + { + if (a & 1) + r += b; + a >>= 1; + b <<= 1; + } + return r; +} \ No newline at end of file diff --git a/lab1/coremark/yatcpu/core_portme.h b/lab1/coremark/yatcpu/core_portme.h new file mode 100644 index 0000000..7b0d646 --- /dev/null +++ b/lab1/coremark/yatcpu/core_portme.h @@ -0,0 +1,211 @@ +/* +Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) + +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. + +Original Author: Shay Gal-on +*/ +/* Topic : Description + This file contains configuration constants required to execute on + different platforms +*/ +#ifndef CORE_PORTME_H +#define CORE_PORTME_H +/************************/ +/* Data types and settings */ +/************************/ +/* Configuration : HAS_FLOAT + Define to 1 if the platform supports floating point. +*/ +#ifndef HAS_FLOAT +#define HAS_FLOAT 0 +#endif +/* Configuration : HAS_TIME_H + Define to 1 if platform has the time.h header file, + and implementation of functions thereof. +*/ +#ifndef HAS_TIME_H +#define HAS_TIME_H 0 +#define CLOCKS_PER_SEC 100000000 +#endif +/* Configuration : USE_CLOCK + Define to 1 if platform has the time.h header file, + and implementation of functions thereof. +*/ +#ifndef USE_CLOCK +#define USE_CLOCK 0 +#endif +/* Configuration : HAS_STDIO + Define to 1 if the platform has stdio.h. +*/ +#ifndef HAS_STDIO +#define HAS_STDIO 0 +#endif +/* Configuration : HAS_PRINTF + Define to 1 if the platform has stdio.h and implements the printf + function. +*/ +#ifndef HAS_PRINTF +#define HAS_PRINTF 0 +#endif + +/* Definitions : COMPILER_VERSION, COMPILER_FLAGS, MEM_LOCATION + Initialize these strings per platform +*/ +#ifndef COMPILER_VERSION +#ifdef __GNUC__ +#define COMPILER_VERSION "GCC"__VERSION__ +#else +#define COMPILER_VERSION "Please put compiler version here (e.g. gcc 4.1)" +#endif +#endif +#ifndef COMPILER_FLAGS +#define COMPILER_FLAGS \ + FLAGS_STR /* "Please put compiler flags here (e.g. -o3)" */ +#endif +#ifndef MEM_LOCATION +#define MEM_LOCATION "STACK" +#endif + +/* Data Types : + To avoid compiler issues, define the data types that need ot be used for + 8b, 16b and 32b in . + + *Imprtant* : + ee_ptr_int needs to be the data type used to hold pointers, otherwise + coremark may fail!!! +*/ +typedef signed short ee_s16; +typedef unsigned short ee_u16; +typedef signed int ee_s32; +typedef double ee_f32; +typedef unsigned char ee_u8; +typedef unsigned int ee_u32; +typedef ee_u32 ee_ptr_int; +typedef ee_u32 ee_size_t; +#define NULL ((void *)0) +/* align_mem : + This macro is used to align an offset to point to a 32b value. It is + used in the Matrix algorithm to initialize the input memory blocks. +*/ +#define align_mem(x) (void *)(4 + (((ee_ptr_int)(x)-1) & ~3)) + +/* Configuration : CORE_TICKS + Define type of return from the timing functions. + */ +#define CORETIMETYPE ee_u32 +typedef ee_u32 CORE_TICKS; + +/* Configuration : SEED_METHOD + Defines method to get seed values that cannot be computed at compile + time. + + Valid values : + SEED_ARG - from command line. + SEED_FUNC - from a system function. + SEED_VOLATILE - from volatile variables. +*/ +#ifndef SEED_METHOD +#define SEED_METHOD SEED_VOLATILE +#endif + +/* Configuration : MEM_METHOD + Defines method to get a block of memry. + + Valid values : + MEM_MALLOC - for platforms that implement malloc and have malloc.h. + MEM_STATIC - to use a static memory array. + MEM_STACK - to allocate the data block on the stack (NYI). +*/ +#ifndef MEM_METHOD +#define MEM_METHOD MEM_STATIC +#endif + +/* Configuration : MULTITHREAD + Define for parallel execution + + Valid values : + 1 - only one context (default). + N>1 - will execute N copies in parallel. + + Note : + If this flag is defined to more then 1, an implementation for launching + parallel contexts must be defined. + + Two sample implementations are provided. Use or + to enable them. + + It is valid to have a different implementation of + and in , to fit a particular architecture. +*/ +#ifndef MULTITHREAD +#define MULTITHREAD 1 +#define USE_PTHREAD 0 +#define USE_FORK 0 +#define USE_SOCKET 0 +#endif + +/* Configuration : MAIN_HAS_NOARGC + Needed if platform does not support getting arguments to main. + + Valid values : + 0 - argc/argv to main is supported + 1 - argc/argv to main is not supported + + Note : + This flag only matters if MULTITHREAD has been defined to a value + greater then 1. +*/ +#ifndef MAIN_HAS_NOARGC +#define MAIN_HAS_NOARGC 1 +#endif + +/* Configuration : MAIN_HAS_NORETURN + Needed if platform does not support returning a value from main. + + Valid values : + 0 - main returns an int, and return value will be 0. + 1 - platform does not support returning a value from main +*/ +#ifndef MAIN_HAS_NORETURN +#define MAIN_HAS_NORETURN 0 +#endif + +/* Variable : default_num_contexts + Not used for this simple port, must contain the value 1. +*/ +extern ee_u32 default_num_contexts; + +typedef struct CORE_PORTABLE_S +{ + ee_u8 portable_id; +} core_portable; + +/* target specific init/fini */ +void portable_init(core_portable *p, int *argc, char *argv[]); +void portable_fini(core_portable *p); + +#if !defined(PROFILE_RUN) && !defined(PERFORMANCE_RUN) \ + && !defined(VALIDATION_RUN) +#if (TOTAL_DATA_SIZE == 1200) +#define PROFILE_RUN 1 +#elif (TOTAL_DATA_SIZE == 2000) +#define PERFORMANCE_RUN 1 +#else +#define VALIDATION_RUN 1 +#endif +#endif + +int ee_printf(const char *fmt, ...); + +#endif /* CORE_PORTME_H */ diff --git a/lab1/coremark/yatcpu/core_portme.mak b/lab1/coremark/yatcpu/core_portme.mak new file mode 100644 index 0000000..e26c689 --- /dev/null +++ b/lab1/coremark/yatcpu/core_portme.mak @@ -0,0 +1,92 @@ +# Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) +# +# 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. +# +# Original Author: Shay Gal-on + +#File : core_portme.mak + +# Flag : OUTFLAG +# Use this flag to define how to to get an executable (e.g -o) +OUTFLAG= -o +# Flag : CC +# Use this flag to define compiler to use +CC = clang +# Flag : LD +# Use this flag to define compiler to use +LD = ld.lld +# Flag : AS +# Use this flag to define compiler to use +AS = clang +# Flag : CFLAGS +# Use this flag to define compiler options. Note, you can add compiler options from the command line using XCFLAGS="other flags" +PORT_CFLAGS = -O0 -g --target=riscv32-unknown-elf -march=rv32i -mabi=ilp32 +FLAGS_STR = "$(PORT_CFLAGS) $(XCFLAGS) $(XLFLAGS) $(LFLAGS_END)" +CFLAGS = $(PORT_CFLAGS) -I$(PORT_DIR) -I. -DFLAGS_STR=\"$(FLAGS_STR)\" +#Flag : LFLAGS_END +# Define any libraries needed for linking or other flags that should come at the end of the link line (e.g. linker scripts). +# Note : On certain platforms, the default clock_gettime implementation is supported but requires linking of librt. +SEPARATE_COMPILE=1 +# Flag : SEPARATE_COMPILE +# You must also define below how to create an object file, and how to link. +OBJOUT = -o +LFLAGS = -T $(PORT_DIR)/link.ld +ASFLAGS = -c --target=riscv32-unknown-elf -march=rv32i -mabi=ilp32 +OFLAG = -o +COUT = -c + +LFLAGS_END = +# Flag : PORT_SRCS +# Port specific source files can be added here +# You may also need cvt.c if the fcvt functions are not provided as intrinsics by your compiler! +PORT_SRCS = $(PORT_DIR)/core_portme.c $(PORT_DIR)/ee_printf.c $(PORT_DIR)/div.s $(PORT_DIR)/init.s +vpath %.c $(PORT_DIR) +vpath %.s $(PORT_DIR) + +PORT_OBJS = $(PORT_DIR)/init$(OEXT) $(PORT_DIR)/core_portme$(OEXT) $(PORT_DIR)/ee_printf$(OEXT) $(PORT_DIR)/div$(OEXT) +PORT_CLEAN = *$(OEXT) $(OUTFILE).asmbin + +# Flag : LOAD +# For a simple port, we assume self hosted compile and run, no load needed. + +# Flag : RUN +# For a simple port, we assume self hosted compile and run, simple invocation of the executable + +LOAD = echo "Please set LOAD to the process of loading the executable to the flash" +RUN = echo "Please set LOAD to the process of running the executable (e.g. via jtag, or board reset)" + +OEXT = .o +EXE = .bin + +$(OPATH)$(PORT_DIR)/%$(OEXT) : %.c + $(CC) $(CFLAGS) $(XCFLAGS) $(COUT) $< $(OBJOUT) $@ + +$(OPATH)%$(OEXT) : %.c + $(CC) $(CFLAGS) $(XCFLAGS) $(COUT) $< $(OBJOUT) $@ + +$(OPATH)$(PORT_DIR)/%$(OEXT) : %.s + $(AS) $(ASFLAGS) $< $(OBJOUT) $@ + +# Target : port_pre% and port_post% +# For the purpose of this simple port, no pre or post steps needed. + +.PHONY : port_prebuild port_postbuild port_prerun port_postrun port_preload port_postload +port_postbuild: $(OUTFILE) + llvm-objcopy -O binary -j .text -j .data $(OUTFILE) $(OUTFILE).asmbin +port_pre% port_post% : + +# FLAG : OPATH +# Path to the output folder. Default - current folder. +OPATH = ./ +MKDIR = mkdir -p + diff --git a/lab1/coremark/yatcpu/cvt.c b/lab1/coremark/yatcpu/cvt.c new file mode 100644 index 0000000..333e8ea --- /dev/null +++ b/lab1/coremark/yatcpu/cvt.c @@ -0,0 +1,127 @@ +/* +Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) + +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. +*/ +#include +#define CVTBUFSIZE 80 +static char CVTBUF[CVTBUFSIZE]; + +static char * +cvt(double arg, int ndigits, int *decpt, int *sign, char *buf, int eflag) +{ + int r2; + double fi, fj; + char * p, *p1; + + if (ndigits < 0) + ndigits = 0; + if (ndigits >= CVTBUFSIZE - 1) + ndigits = CVTBUFSIZE - 2; + r2 = 0; + *sign = 0; + p = &buf[0]; + if (arg < 0) + { + *sign = 1; + arg = -arg; + } + arg = modf(arg, &fi); + p1 = &buf[CVTBUFSIZE]; + + if (fi != 0) + { + p1 = &buf[CVTBUFSIZE]; + while (fi != 0) + { + fj = modf(fi / 10, &fi); + *--p1 = (int)((fj + .03) * 10) + '0'; + r2++; + } + while (p1 < &buf[CVTBUFSIZE]) + *p++ = *p1++; + } + else if (arg > 0) + { + while ((fj = arg * 10) < 1) + { + arg = fj; + r2--; + } + } + p1 = &buf[ndigits]; + if (eflag == 0) + p1 += r2; + *decpt = r2; + if (p1 < &buf[0]) + { + buf[0] = '\0'; + return buf; + } + while (p <= p1 && p < &buf[CVTBUFSIZE]) + { + arg *= 10; + arg = modf(arg, &fj); + *p++ = (int)fj + '0'; + } + if (p1 >= &buf[CVTBUFSIZE]) + { + buf[CVTBUFSIZE - 1] = '\0'; + return buf; + } + p = p1; + *p1 += 5; + while (*p1 > '9') + { + *p1 = '0'; + if (p1 > buf) + ++*--p1; + else + { + *p1 = '1'; + (*decpt)++; + if (eflag == 0) + { + if (p > buf) + *p = '0'; + p++; + } + } + } + *p = '\0'; + return buf; +} + +char * +ecvt(double arg, int ndigits, int *decpt, int *sign) +{ + return cvt(arg, ndigits, decpt, sign, CVTBUF, 1); +} + +char * +ecvtbuf(double arg, int ndigits, int *decpt, int *sign, char *buf) +{ + return cvt(arg, ndigits, decpt, sign, buf, 1); +} + +char * +fcvt(double arg, int ndigits, int *decpt, int *sign) +{ + return cvt(arg, ndigits, decpt, sign, CVTBUF, 0); +} + +char * +fcvtbuf(double arg, int ndigits, int *decpt, int *sign, char *buf) +{ + return cvt(arg, ndigits, decpt, sign, buf, 0); +} diff --git a/lab1/coremark/yatcpu/div.s b/lab1/coremark/yatcpu/div.s new file mode 100644 index 0000000..6725293 --- /dev/null +++ b/lab1/coremark/yatcpu/div.s @@ -0,0 +1,71 @@ +.text +.globl __divsi3 +__divsi3: + bltz a0, .L10 + bltz a1, .L11 + +.globl __udivsi3 +__udivsi3: + mv a2, a1 + mv a1, a0 + li a0, -1 + beqz a2, .L5 + li a3, 1 + bgeu a2, a1, .L2 +.L1: + blez a2, .L2 + slli a2, a2, 1 + slli a3, a3, 1 + bgtu a1, a2, .L1 +.L2: + li a0, 0 +.L3: + bltu a1, a2, .L4 + sub a1, a1, a2 + or a0, a0, a3 +.L4: + srli a3, a3, 1 + srli a2, a2, 1 + bnez a3, .L3 +.L5: + ret + +.globl __umodsi3 +__umodsi3: + move t0, ra + jal __udivsi3 + move a0, a1 + jr t0 + +.L10: + neg a0, a0 + bgtz a1, .L12 + + neg a1, a1 + j __udivsi3 +.L11: + neg a1, a1 +.L12: + move t0, ra + jal __udivsi3 + neg a0, a0 + jr t0 + +.globl __modsi3 +__modsi3: + move t0, ra + bltz a1, .L31 + bltz a0, .L32 +.L30: + jal __udivsi3 + move a0, a1 + jr t0 +.L31: + neg a1, a1 + bgez a0, .L30 +.L32: + neg a0, a0 + jal __udivsi3 + neg a0, a1 + jr t0 + diff --git a/lab1/coremark/yatcpu/ee_printf.c b/lab1/coremark/yatcpu/ee_printf.c new file mode 100644 index 0000000..9dde21a --- /dev/null +++ b/lab1/coremark/yatcpu/ee_printf.c @@ -0,0 +1,687 @@ +/* +Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) + +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. +*/ + +#include +#include + +#define ZEROPAD (1 << 0) /* Pad with zero */ +#define SIGN (1 << 1) /* Unsigned/signed long */ +#define PLUS (1 << 2) /* Show plus */ +#define SPACE (1 << 3) /* Spacer */ +#define LEFT (1 << 4) /* Left justified */ +#define HEX_PREP (1 << 5) /* 0x */ +#define UPPERCASE (1 << 6) /* 'ABCDEF' */ + +#define is_digit(c) ((c) >= '0' && (c) <= '9') + +static char * digits = "0123456789abcdefghijklmnopqrstuvwxyz"; +static char * upper_digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; +static ee_size_t strnlen(const char *s, ee_size_t count); + +static ee_size_t +strnlen(const char *s, ee_size_t count) +{ + const char *sc; + for (sc = s; *sc != '\0' && count--; ++sc) + ; + return sc - s; +} + +static int +skip_atoi(const char **s) +{ + int i = 0; + while (is_digit(**s)) + i = i * 10 + *((*s)++) - '0'; + return i; +} + +static char * +number(char *str, long num, int base, int size, int precision, int type) +{ + char c, sign, tmp[66]; + char *dig = digits; + int i; + + if (type & UPPERCASE) + dig = upper_digits; + if (type & LEFT) + type &= ~ZEROPAD; + if (base < 2 || base > 36) + return 0; + + c = (type & ZEROPAD) ? '0' : ' '; + sign = 0; + if (type & SIGN) + { + if (num < 0) + { + sign = '-'; + num = -num; + size--; + } + else if (type & PLUS) + { + sign = '+'; + size--; + } + else if (type & SPACE) + { + sign = ' '; + size--; + } + } + + if (type & HEX_PREP) + { + if (base == 16) + size -= 2; + else if (base == 8) + size--; + } + + i = 0; + + if (num == 0) + tmp[i++] = '0'; + else + { + while (num != 0) + { + tmp[i++] = dig[((unsigned long)num) % (unsigned)base]; + num = ((unsigned long)num) / (unsigned)base; + } + } + + if (i > precision) + precision = i; + size -= precision; + if (!(type & (ZEROPAD | LEFT))) + while (size-- > 0) + *str++ = ' '; + if (sign) + *str++ = sign; + + if (type & HEX_PREP) + { + if (base == 8) + *str++ = '0'; + else if (base == 16) + { + *str++ = '0'; + *str++ = digits[33]; + } + } + + if (!(type & LEFT)) + while (size-- > 0) + *str++ = c; + while (i < precision--) + *str++ = '0'; + while (i-- > 0) + *str++ = tmp[i]; + while (size-- > 0) + *str++ = ' '; + + return str; +} + +static char * +eaddr(char *str, unsigned char *addr, int size, int precision, int type) +{ + char tmp[24]; + char *dig = digits; + int i, len; + + if (type & UPPERCASE) + dig = upper_digits; + len = 0; + for (i = 0; i < 6; i++) + { + if (i != 0) + tmp[len++] = ':'; + tmp[len++] = dig[addr[i] >> 4]; + tmp[len++] = dig[addr[i] & 0x0F]; + } + + if (!(type & LEFT)) + while (len < size--) + *str++ = ' '; + for (i = 0; i < len; ++i) + *str++ = tmp[i]; + while (len < size--) + *str++ = ' '; + + return str; +} + +static char * +iaddr(char *str, unsigned char *addr, int size, int precision, int type) +{ + char tmp[24]; + int i, n, len; + + len = 0; + for (i = 0; i < 4; i++) + { + if (i != 0) + tmp[len++] = '.'; + n = addr[i]; + + if (n == 0) + tmp[len++] = digits[0]; + else + { + if (n >= 100) + { + tmp[len++] = digits[n / 100]; + n = n % 100; + tmp[len++] = digits[n / 10]; + n = n % 10; + } + else if (n >= 10) + { + tmp[len++] = digits[n / 10]; + n = n % 10; + } + + tmp[len++] = digits[n]; + } + } + + if (!(type & LEFT)) + while (len < size--) + *str++ = ' '; + for (i = 0; i < len; ++i) + *str++ = tmp[i]; + while (len < size--) + *str++ = ' '; + + return str; +} + +#if HAS_FLOAT + +char * ecvtbuf(double arg, int ndigits, int *decpt, int *sign, char *buf); +char * fcvtbuf(double arg, int ndigits, int *decpt, int *sign, char *buf); +static void ee_bufcpy(char *d, char *s, int count); + +void +ee_bufcpy(char *pd, char *ps, int count) +{ + char *pe = ps + count; + while (ps != pe) + *pd++ = *ps++; +} + +static void +parse_float(double value, char *buffer, char fmt, int precision) +{ + int decpt, sign, exp, pos; + char *digits = NULL; + char cvtbuf[80]; + int capexp = 0; + int magnitude; + + if (fmt == 'G' || fmt == 'E') + { + capexp = 1; + fmt += 'a' - 'A'; + } + + if (fmt == 'g') + { + digits = ecvtbuf(value, precision, &decpt, &sign, cvtbuf); + magnitude = decpt - 1; + if (magnitude < -4 || magnitude > precision - 1) + { + fmt = 'e'; + precision -= 1; + } + else + { + fmt = 'f'; + precision -= decpt; + } + } + + if (fmt == 'e') + { + digits = ecvtbuf(value, precision + 1, &decpt, &sign, cvtbuf); + + if (sign) + *buffer++ = '-'; + *buffer++ = *digits; + if (precision > 0) + *buffer++ = '.'; + ee_bufcpy(buffer, digits + 1, precision); + buffer += precision; + *buffer++ = capexp ? 'E' : 'e'; + + if (decpt == 0) + { + if (value == 0.0) + exp = 0; + else + exp = -1; + } + else + exp = decpt - 1; + + if (exp < 0) + { + *buffer++ = '-'; + exp = -exp; + } + else + *buffer++ = '+'; + + buffer[2] = (exp % 10) + '0'; + exp = exp / 10; + buffer[1] = (exp % 10) + '0'; + exp = exp / 10; + buffer[0] = (exp % 10) + '0'; + buffer += 3; + } + else if (fmt == 'f') + { + digits = fcvtbuf(value, precision, &decpt, &sign, cvtbuf); + if (sign) + *buffer++ = '-'; + if (*digits) + { + if (decpt <= 0) + { + *buffer++ = '0'; + *buffer++ = '.'; + for (pos = 0; pos < -decpt; pos++) + *buffer++ = '0'; + while (*digits) + *buffer++ = *digits++; + } + else + { + pos = 0; + while (*digits) + { + if (pos++ == decpt) + *buffer++ = '.'; + *buffer++ = *digits++; + } + } + } + else + { + *buffer++ = '0'; + if (precision > 0) + { + *buffer++ = '.'; + for (pos = 0; pos < precision; pos++) + *buffer++ = '0'; + } + } + } + + *buffer = '\0'; +} + +static void +decimal_point(char *buffer) +{ + while (*buffer) + { + if (*buffer == '.') + return; + if (*buffer == 'e' || *buffer == 'E') + break; + buffer++; + } + + if (*buffer) + { + int n = strnlen(buffer, 256); + while (n > 0) + { + buffer[n + 1] = buffer[n]; + n--; + } + + *buffer = '.'; + } + else + { + *buffer++ = '.'; + *buffer = '\0'; + } +} + +static void +cropzeros(char *buffer) +{ + char *stop; + + while (*buffer && *buffer != '.') + buffer++; + if (*buffer++) + { + while (*buffer && *buffer != 'e' && *buffer != 'E') + buffer++; + stop = buffer--; + while (*buffer == '0') + buffer--; + if (*buffer == '.') + buffer--; + while (buffer != stop) + *++buffer = 0; + } +} + +static char * +flt(char *str, double num, int size, int precision, char fmt, int flags) +{ + char tmp[80]; + char c, sign; + int n, i; + + // Left align means no zero padding + if (flags & LEFT) + flags &= ~ZEROPAD; + + // Determine padding and sign char + c = (flags & ZEROPAD) ? '0' : ' '; + sign = 0; + if (flags & SIGN) + { + if (num < 0.0) + { + sign = '-'; + num = -num; + size--; + } + else if (flags & PLUS) + { + sign = '+'; + size--; + } + else if (flags & SPACE) + { + sign = ' '; + size--; + } + } + + // Compute the precision value + if (precision < 0) + precision = 6; // Default precision: 6 + + // Convert floating point number to text + parse_float(num, tmp, fmt, precision); + + if ((flags & HEX_PREP) && precision == 0) + decimal_point(tmp); + if (fmt == 'g' && !(flags & HEX_PREP)) + cropzeros(tmp); + + n = strnlen(tmp, 256); + + // Output number with alignment and padding + size -= n; + if (!(flags & (ZEROPAD | LEFT))) + while (size-- > 0) + *str++ = ' '; + if (sign) + *str++ = sign; + if (!(flags & LEFT)) + while (size-- > 0) + *str++ = c; + for (i = 0; i < n; i++) + *str++ = tmp[i]; + while (size-- > 0) + *str++ = ' '; + + return str; +} + +#endif + +static int +ee_vsprintf(char *buf, const char *fmt, va_list args) +{ + int len; + unsigned long num; + int i, base; + char * str; + char * s; + + int flags; // Flags to number() + + int field_width; // Width of output field + int precision; // Min. # of digits for integers; max number of chars for + // from string + int qualifier; // 'h', 'l', or 'L' for integer fields + + for (str = buf; *fmt; fmt++) + { + if (*fmt != '%') + { + *str++ = *fmt; + continue; + } + + // Process flags + flags = 0; + repeat: + fmt++; // This also skips first '%' + switch (*fmt) + { + case '-': + flags |= LEFT; + goto repeat; + case '+': + flags |= PLUS; + goto repeat; + case ' ': + flags |= SPACE; + goto repeat; + case '#': + flags |= HEX_PREP; + goto repeat; + case '0': + flags |= ZEROPAD; + goto repeat; + } + + // Get field width + field_width = -1; + if (is_digit(*fmt)) + field_width = skip_atoi(&fmt); + else if (*fmt == '*') + { + fmt++; + field_width = va_arg(args, int); + if (field_width < 0) + { + field_width = -field_width; + flags |= LEFT; + } + } + + // Get the precision + precision = -1; + if (*fmt == '.') + { + ++fmt; + if (is_digit(*fmt)) + precision = skip_atoi(&fmt); + else if (*fmt == '*') + { + ++fmt; + precision = va_arg(args, int); + } + if (precision < 0) + precision = 0; + } + + // Get the conversion qualifier + qualifier = -1; + if (*fmt == 'l' || *fmt == 'L') + { + qualifier = *fmt; + fmt++; + } + + // Default base + base = 10; + + switch (*fmt) + { + case 'c': + if (!(flags & LEFT)) + while (--field_width > 0) + *str++ = ' '; + *str++ = (unsigned char)va_arg(args, int); + while (--field_width > 0) + *str++ = ' '; + continue; + + case 's': + s = va_arg(args, char *); + if (!s) + s = ""; + len = strnlen(s, precision); + if (!(flags & LEFT)) + while (len < field_width--) + *str++ = ' '; + for (i = 0; i < len; ++i) + *str++ = *s++; + while (len < field_width--) + *str++ = ' '; + continue; + + case 'p': + if (field_width == -1) + { + field_width = 2 * sizeof(void *); + flags |= ZEROPAD; + } + str = number(str, + (unsigned long)va_arg(args, void *), + 16, + field_width, + precision, + flags); + continue; + + case 'A': + flags |= UPPERCASE; + + case 'a': + if (qualifier == 'l') + str = eaddr(str, + va_arg(args, unsigned char *), + field_width, + precision, + flags); + else + str = iaddr(str, + va_arg(args, unsigned char *), + field_width, + precision, + flags); + continue; + + // Integer number formats - set up the flags and "break" + case 'o': + base = 8; + break; + + case 'X': + flags |= UPPERCASE; + + case 'x': + base = 16; + break; + + case 'd': + case 'i': + flags |= SIGN; + + case 'u': + break; + +#if HAS_FLOAT + + case 'f': + str = flt(str, + va_arg(args, double), + field_width, + precision, + *fmt, + flags | SIGN); + continue; + +#endif + + default: + if (*fmt != '%') + *str++ = '%'; + if (*fmt) + *str++ = *fmt; + else + --fmt; + continue; + } + + if (qualifier == 'l') + num = va_arg(args, unsigned long); + else if (flags & SIGN) + num = va_arg(args, int); + else + num = va_arg(args, unsigned int); + + str = number(str, num, base, field_width, precision, flags); + } + + *str = '\0'; + return str - buf; +} + +void +uart_send_char(char c) +{ + *((volatile unsigned int *) (0x40000010)) = c; +} + +int +ee_printf(const char *fmt, ...) +{ + char buf[1024], *p; + va_list args; + int n = 0; + + va_start(args, fmt); + ee_vsprintf(buf, fmt, args); + va_end(args); + p = buf; + while (*p) + { + uart_send_char(*p); + n++; + p++; + } + + return n; +} diff --git a/lab1/coremark/yatcpu/init.s b/lab1/coremark/yatcpu/init.s new file mode 100644 index 0000000..0efae64 --- /dev/null +++ b/lab1/coremark/yatcpu/init.s @@ -0,0 +1,16 @@ +.section .text.init +.globl _start +_start: + li sp, 4092 + call main + li x1, 0xBABECAFE +write_tohost: + sw x1, tohost, x0 +loop: + j loop + +.pushsection .tohost,"aw",@progbits + .align 4 + .global tohost + tohost: .word 0 +.popsection \ No newline at end of file diff --git a/lab1/coremark/yatcpu/link.ld b/lab1/coremark/yatcpu/link.ld new file mode 100644 index 0000000..2ae1500 --- /dev/null +++ b/lab1/coremark/yatcpu/link.ld @@ -0,0 +1,12 @@ +OUTPUT_ARCH( "riscv" ) +ENTRY(_start) + +SECTIONS +{ + . = 0x00001000; + .text : { *(.text.init) *(.text.startup) *(.text) } + .data ALIGN(0x1000) : { *(.data*) *(.rodata*) *(.sdata*) } + .tohost ALIGN(0x1000) : { *(.tohost) } + .bss : { *(.bss) } + _end = .; +} diff --git a/lab1/csrc/CMakeLists.txt b/lab1/csrc/CMakeLists.txt new file mode 100644 index 0000000..a1c1c7c --- /dev/null +++ b/lab1/csrc/CMakeLists.txt @@ -0,0 +1,43 @@ +# Make CMake happy +cmake_minimum_required(VERSION 3.18) +project(yatcpu-programs C CXX ASM) + +# Setting variables +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O0 --target=riscv32-unknown-elf -march=rv32i -mabi=ilp32") +set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -O0 --target=riscv32-unknown-elf -march=rv32i -mabi=ilp32") +set(C_PROGRAMS tetris hello fibonacci quicksort) +set(ASM_PROGRAMS mmio sb) +set(LINKER_SCRIPT ${CMAKE_SOURCE_DIR}/link.lds) +set(LINKER_FLAGS -T ${LINKER_SCRIPT}) +set(OBJCOPY_ARGS -O binary -j .text -j .data) +if(NOT DEST_DIR) + set(DEST_DIR "../src/main/resources") +endif() + +# Let CMake know that there exists header files +include_directories("${CMAKE_SOURCE_DIR}") + +add_library(prelude init.S) +set_target_properties(prelude PROPERTIES LINK_DEPENDS ${LINKER_SCRIPT}) + +# Let's build our executables +foreach(program IN LISTS C_PROGRAMS) + add_executable(${program} ${program}.c) + set_target_properties(${program} PROPERTIES LINK_DEPENDS ${LINKER_SCRIPT}) + target_link_libraries(${program} prelude ${LINKER_FLAGS}) +endforeach() + +foreach(program IN LISTS ASM_PROGRAMS) + add_executable(${program} ${program}.S) + set_target_properties(${program} PROPERTIES LINK_DEPENDS ${LINKER_SCRIPT}) +endforeach() + +# Copy the .text section to .asmbin files +foreach(program IN LISTS C_PROGRAMS ASM_PROGRAMS) + add_custom_command( + TARGET ${program} + POST_BUILD + COMMAND ${CMAKE_OBJCOPY} ARGS ${OBJCOPY_ARGS} $ ${CMAKE_SOURCE_DIR}/${DEST_DIR}/${program}.asmbin + ) +endforeach() + diff --git a/lab1/csrc/build.bat b/lab1/csrc/build.bat new file mode 100644 index 0000000..b5a522b --- /dev/null +++ b/lab1/csrc/build.bat @@ -0,0 +1,3 @@ +rmdir /Q /S build +cmake -DCMAKE_TOOLCHAIN_FILE=toolchain.cmake -G"NMake Makefiles" -B build . +cmake --build build \ No newline at end of file diff --git a/lab1/csrc/build.sh b/lab1/csrc/build.sh new file mode 100644 index 0000000..e48a4ba --- /dev/null +++ b/lab1/csrc/build.sh @@ -0,0 +1,3 @@ +#!/bin/sh +rm -rf build +cmake -DCMAKE_TOOLCHAIN_FILE=toolchain.cmake -B build . && cmake --build build --parallel `nproc` diff --git a/lab1/csrc/fibonacci.c b/lab1/csrc/fibonacci.c new file mode 100644 index 0000000..9905dde --- /dev/null +++ b/lab1/csrc/fibonacci.c @@ -0,0 +1,22 @@ +// 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. + +int fib(int a) { + if (a == 1 || a == 2) return 1; + return fib(a - 1) + fib(a - 2); +} + +int main() { + *(int *)(4) = fib(10); +} \ No newline at end of file diff --git a/lab1/csrc/hdmi_test.c b/lab1/csrc/hdmi_test.c new file mode 100644 index 0000000..e439af3 --- /dev/null +++ b/lab1/csrc/hdmi_test.c @@ -0,0 +1,29 @@ +// Copyright 2022 hrpccs +// +// 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. + + +#include "mmio.h" + + + +int main(){ + int *vram = ((int *) VRAM_BASE); + for (int i = 0; i < 600; ++i) vram[i] = 0x20202020; + + for(int i = 0;i < 12;i++){ + VRAM[i] = "hello world!"[i]; + } + + while(1); +} \ No newline at end of file diff --git a/lab1/csrc/hello.c b/lab1/csrc/hello.c new file mode 100644 index 0000000..3e79635 --- /dev/null +++ b/lab1/csrc/hello.c @@ -0,0 +1,175 @@ +// 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. + +#include "mmio.h" + +#define MUL80(x) (((x) << 6) + ((x) << 4)) + +struct screen { + unsigned char row, col; +} scr; + +void copy_line(int prev, int cur) { + int *prev_vram_start = ((int *) (MUL80(prev) + VRAM_BASE)); + int *cur_vram_start = ((int *) (MUL80(cur) + VRAM_BASE)); + for (int i = 0; i < 20; ++i) { + prev_vram_start[i] = cur_vram_start[i]; + } +} + +void write_char(int row, int col, unsigned char ch) { + VRAM[MUL80(row) + col] = ch; +} + +void move_to(int row, int col) { + scr.row = row; + scr.col = col; +} + +void new_line() { + scr.col = 0; + if (scr.row == 29) { + for (int i = 0; i < 29; ++i) { + copy_line(i, i + 1); + } + int *vram = (int *) (MUL80(29) + VRAM_BASE); + for (int i = 0; i < 20; ++i) { + vram[i] = 0x20202020; + } + } else { + ++scr.row; + } +} + +void putch(unsigned char ch) { + if (ch == '\n') { + new_line(); + } else if (ch == '\r') { + scr.col = 0; + } else { + if (scr.col == 79) { + new_line(); + } + write_char(scr.row, scr.col, ch); + ++scr.col; + } +} + +void clear_screen() { + scr.row = 0; + scr.col = 0; + int *vram = ((int *) VRAM_BASE); + for (int i = 0; i < 600; ++i) vram[i] = 0x20202020; +} + +void print_hex(unsigned int counter) { + putch('0'); putch('x'); + for (int i = 7; i >= 0; --i) { + unsigned int num = (counter >> (i << 2)) & 0xF; + if (num < 10) { + putch('0' + num); + } else { + putch('A' + num - 10); + } + } +} + +void putstr(const char *s) { + while (*s) { + putch(*(s++)); + } +} + +int hc = 1; +int fast = 0; + +void print_timer() { + putstr("Hardware timer count limit = "); + print_hex(*TIMER_LIMIT); + putstr(", enabled = "); + print_hex(*TIMER_ENABLED); + putch('\n'); +} + +void print_uart() { + putstr("UART Baud rate = "); + print_hex(*UART_BAUDRATE); + putch('\n'); +} + +void handle_timer() { + putstr("Timer trigger times = "); + print_hex(hc++); + putch('\n'); + int mode = ((hc & 0x10) >> 4); + if (hc == 0x40) { + putstr("Disable timer!\n"); + *TIMER_ENABLED = 0; + print_timer(); + return; + } + if (fast ^ mode) { + putstr("Switch timer frequency\n"); + if (fast == 0) { + *TIMER_LIMIT = 25000000; + } else { + + *TIMER_LIMIT = 100000000; + } + fast = mode; + print_timer(); + } +} + +void handle_uart() { + unsigned int ch = *UART_RECV; + *UART_SEND = ch; + putstr("UART Recv hex = "); print_hex(ch); putstr(", ch = "); putch(ch); putch('\n'); +} + +void trap_handler(void *epc, unsigned int cause) { + putstr("Interrupt! EPC = "); + print_hex((unsigned int) epc); + putstr(", CAUSE = "); + print_hex(cause); + putch('\n'); + switch (cause) { + case 0x8000000B: + handle_uart(); + break; + default: + handle_timer(); + break; + } +} +extern void enable_interrupt(); +extern unsigned int get_epc(); +int main() { + clear_screen(); + hc = 0; + *TIMER_ENABLED = 1; + putstr("YatCPU Demo Program "); + putch(137); + putstr("2021 Howard Lau\n"); + putstr("Hello, world!\n"); + putstr("Last EPC = "); + print_hex(get_epc()); + putch('\n'); + print_timer(); + print_uart(); + *((int *) 0x4) = 0xDEADBEEF; + unsigned int i = 0; + enable_interrupt(); + for (;;) ; +} diff --git a/lab1/csrc/init.S b/lab1/csrc/init.S new file mode 100644 index 0000000..4534c78 --- /dev/null +++ b/lab1/csrc/init.S @@ -0,0 +1,107 @@ +# 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. + +.section .text.init +.globl _start +_start: + li sp, 4096 # Initialize stack pointer + call main # Jump to main function +loop: + j loop # Loop forever +.globl enable_interrupt +enable_interrupt: + la t0, __trap_entry + csrrw t1, mtvec, t0 # setup trap vector base + li t0, 0x1888 + csrrw t1, mstatus, t0 # enable interrupt + ret +.globl get_epc +get_epc: + csrr a0, mepc + ret +.weak trap_handler +tran_handler: + ret +__trap_entry: + csrw mscratch, sp + addi sp, sp, -128 + sw ra, 4(sp) + + sw gp, 12(sp) + sw tp, 16(sp) + sw t0, 20(sp) + sw t1, 24(sp) + sw t2, 28(sp) + sw tp, 32(sp) + sw s1, 36(sp) + sw a0, 40(sp) + sw a1, 44(sp) + sw a2, 48(sp) + sw a3, 52(sp) + sw a4, 56(sp) + sw a5, 60(sp) + sw a6, 64(sp) + sw a7, 68(sp) + sw s2, 72(sp) + sw s3, 76(sp) + sw s4, 80(sp) + sw s5, 84(sp) + sw s6, 88(sp) + sw s7, 92(sp) + sw s8, 96(sp) + sw s9, 100(sp) + sw s10, 104(sp) + sw s11, 108(sp) + sw t3, 112(sp) + sw t4, 116(sp) + sw t5, 120(sp) + sw t6, 124(sp) + + csrr a0, mepc + csrr a1, mcause + call trap_handler + + lw ra, 4(sp) + + lw gp, 12(sp) + lw tp, 16(sp) + lw t0, 20(sp) + lw t1, 24(sp) + lw t2, 28(sp) + lw tp, 32(sp) + lw s1, 36(sp) + lw a0, 40(sp) + lw a1, 44(sp) + lw a2, 48(sp) + lw a3, 52(sp) + lw a4, 56(sp) + lw a5, 60(sp) + lw a6, 64(sp) + lw a7, 68(sp) + lw s2, 72(sp) + lw s3, 76(sp) + lw s4, 80(sp) + lw s5, 84(sp) + lw s6, 88(sp) + lw s7, 92(sp) + lw s8, 96(sp) + lw s9, 100(sp) + lw s10, 104(sp) + lw s11, 108(sp) + lw t3, 112(sp) + lw t4, 116(sp) + lw t5, 120(sp) + lw t6, 124(sp) + csrr sp, mscratch + mret diff --git a/lab1/csrc/link.lds b/lab1/csrc/link.lds new file mode 100644 index 0000000..b5d8366 --- /dev/null +++ b/lab1/csrc/link.lds @@ -0,0 +1,11 @@ +OUTPUT_ARCH( "riscv" ) +ENTRY(_start) + +SECTIONS +{ + . = 0x00001000; + .text : { *(.text.init) *(.text.startup) *(.text) } + .data ALIGN(0x1000) : { *(.data*) *(.rodata*) *(.sdata*) } + .bss : { *(.bss) } + _end = .; +} diff --git a/lab1/csrc/mmio.S b/lab1/csrc/mmio.S new file mode 100644 index 0000000..7b49530 --- /dev/null +++ b/lab1/csrc/mmio.S @@ -0,0 +1,24 @@ +# 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. + +.globl _start +_start: + li a0, 0x80000000 + lw t0, 4(a0) + li a1, 0xBEEF + sw a1, 4(a0) + nop + lw t1, 4(a0) +loop: + j loop diff --git a/lab1/csrc/mmio.h b/lab1/csrc/mmio.h new file mode 100644 index 0000000..b1222dd --- /dev/null +++ b/lab1/csrc/mmio.h @@ -0,0 +1,23 @@ +// 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. + +#define VRAM_BASE 0x20000000 +#define VRAM ((volatile unsigned char *) VRAM_BASE) +#define TIMER_BASE 0x80000000 +#define TIMER_LIMIT ((volatile unsigned int *) (TIMER_BASE + 4)) +#define TIMER_ENABLED ((volatile unsigned int *) (TIMER_BASE + 8)) +#define UART_BASE 0x40000000 +#define UART_BAUDRATE ((volatile unsigned int *) (UART_BASE + 4)) +#define UART_RECV ((volatile unsigned int *) (UART_BASE + 12)) +#define UART_SEND ((volatile unsigned int *) (UART_BASE + 16)) diff --git a/lab1/csrc/quicksort.c b/lab1/csrc/quicksort.c new file mode 100644 index 0000000..5105ef1 --- /dev/null +++ b/lab1/csrc/quicksort.c @@ -0,0 +1,50 @@ +// 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. + +void quicksort(int *arr, int l, int r) { + if (l >= r) return; + int pivot = arr[l]; + int i = l, j = r; + while (i < j) { + while(arr[j] >= pivot && i < j) --j; + arr[i] = arr[j]; + while(arr[i] < pivot && i < j) ++i; + arr[j] = arr[i]; + } + arr[i] = pivot; + quicksort(arr, l, i - 1); + quicksort(arr, i + 1, r); +} + +int main() { + int nums[10]; + + nums[0] = 6; + nums[1] = 2; + nums[2] = 4; + nums[3] = 5; + nums[4] = 3; + nums[5] = 1; + nums[6] = 0; + nums[7] = 9; + nums[8] = 7; + nums[9] = 8; + + + quicksort(nums, 0, 9); + + for (int i = 1; i <= 10; ++i) { + *(int *)(i * 4) = nums[i - 1]; + } +} \ No newline at end of file diff --git a/lab1/csrc/sb.S b/lab1/csrc/sb.S new file mode 100644 index 0000000..ed71a72 --- /dev/null +++ b/lab1/csrc/sb.S @@ -0,0 +1,25 @@ +# 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. + +.globl _start +_start: + li a0, 0x4 + li t0, 0xDEADBEEF + sb t0, 0(a0) + lw t1, 0(a0) + li s2, 0x15 + sb s2, 1(a0) + lw ra, 0(a0) +loop: + j loop diff --git a/lab1/csrc/tetris.c b/lab1/csrc/tetris.c new file mode 100644 index 0000000..2b37550 --- /dev/null +++ b/lab1/csrc/tetris.c @@ -0,0 +1,498 @@ +// 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. + +#ifdef DEBUG +#include +#endif + +#include "mmio.h" + +#define FALL_TIMER_LIMIT 50000000 +#define ROWS 22 +#define COLS 10 +#define OFFSET_X 28 +#define OFFSET_Y 3 +#define SCREEN_COLS 80 +#define SCREEN_ROWS 30 + +struct block { + unsigned int shape[3]; + unsigned int xywh; +}; + +struct block current; + +unsigned int score; + +unsigned char *board; + +#ifdef DEBUG +unsigned char screen[SCREEN_COLS * SCREEN_ROWS]; +#endif + +int wk_mul(int a, int b) { + int r = 0; + for (; b; a <<= 1, b >>= 1) + if (b & 1) + r += a; + return r; +} + +unsigned int make_xywh(unsigned int x, unsigned int y, unsigned int w, unsigned int h) { + return (x << 12) | (y << 4) | (w << 2) | h; +} + +void init_block(struct block *block, int type, int x, int y) { + int w = 0; int h = 0; + block->shape[0] = block->shape[1] = block->shape[2] = 0; + switch(type) { + case 0: // I + block->shape[0] = 0xF; + w = 3; h = 0; + break; + case 1: // O + block->shape[0] = 0x3; + block->shape[1] = 0x3; + w = 1; h = 1; + break; + case 2: // J + block->shape[0] = 0x4; + block->shape[1] = 0x7; + w = 2; h = 1; + break; + case 3: // T + block->shape[0] = 0x2; + block->shape[1] = 0x7; + w = 2; h = 1; + break; + case 4: // L + block->shape[0] = 0x1; + block->shape[1] = 0x7; + w = 2; h = 1; + break; + case 5: // Z + block->shape[0] = 0x6; + block->shape[1] = 0x3; + w = 2; h = 1; + break; + case 6: // S + block->shape[0] = 0x3; + block->shape[1] = 0x6; + w = 2; h = 1; + break; + } + block->xywh = make_xywh(x, y, w, h); +} + +unsigned int get_shape(struct block *block, unsigned int r, unsigned int c) { + return (block->shape[r] & (1 << c)) >> c; +} + +unsigned int check_bounds(struct block *block) { + unsigned int xywh = block->xywh; + unsigned int h = xywh & 0x3; + unsigned int w = (xywh & 0xC) >> 2; + unsigned int y = (xywh & 0xFF0) >> 4; + unsigned int x = (xywh & 0xF000) >> 12; + if (x < 0 || x + w >= COLS) return 0; + if (y < 0 || y + h >= ROWS) return 0; + return 1; +} + +void copy_block(struct block *dst, struct block *src) { + dst->xywh = src->xywh; + dst->shape[0] = src->shape[0]; + dst->shape[1] = src->shape[1]; + dst->shape[2] = src->shape[2]; +} + +unsigned int check_collision(struct block *block) { + unsigned int xywh = block->xywh; + unsigned int h = xywh & 0x3; + unsigned int w = (xywh & 0xC) >> 2; + unsigned int y = (xywh & 0xFF0) >> 4; + unsigned int x = (xywh & 0xF000) >> 12; + for (int r = 0; r <= h; ++r) { + for (int c = 0; c <= w; ++c) { + if (get_shape(block, r, c) && + board[wk_mul(y + r, COLS) + x + c]) + return 0; + } + } + return 1; +} + +void putch_at(int x, int y, unsigned char ch) { +#ifdef DEBUG + screen[wk_mul(OFFSET_Y + y, SCREEN_COLS) + x + OFFSET_X] = ch; +#else + VRAM[wk_mul(OFFSET_Y + y, SCREEN_COLS) + x + OFFSET_X] = ch; +#endif +} + +void block_move(struct block *block, int dir) { + unsigned int xywh = block->xywh; + unsigned int h = xywh & 0x3; + unsigned int w = (xywh & 0xC) >> 2; + unsigned int y = (xywh & 0xFF0) >> 4; + unsigned int x = (xywh & 0xF000) >> 12; + switch(dir) { + case 0: // Left + x--; + break; + case 1: // Right + x++; + break; + case 2: // Down + y++; + break; + default: + break; + } + block->xywh = (x << 12) | (y << 4) | (w << 2) | h; +} + +unsigned int move(struct block *block, int dir) { + struct block moved; + copy_block(&moved, block); + block_move(&moved, dir); + if (check_bounds(&moved) && check_collision(&moved)) { + copy_block(block, &moved); + return 1; + } + return 0; +} + +void block_rotate(struct block *block, unsigned int clock) { + unsigned int xywh = block->xywh; + unsigned int h = xywh & 0x3; + unsigned int w = (xywh & 0xC) >> 2; + unsigned int y = (xywh & 0xFF0) >> 4; + unsigned int x = (xywh & 0xF000) >> 12; + unsigned int xyhw = make_xywh(x, y, h, w); + unsigned int shape[3] = {0, 0, 0}; + if (clock) { + for (int r = 0; r <= h; ++r) { + for (int c = 0; c <= w; ++c) { + shape[c] = shape[c] | (get_shape(block, r, c) << (h - r)); + } + } + + } else { + for (int r = 0; r <= h; ++r) { + for (int c = 0; c <= w; ++c) { + shape[w - c] = shape[w - c] | (get_shape(block, r, c) << r); + } + } + } + block->shape[0] = shape[0]; + block->shape[1] = shape[1]; + block->shape[2] = shape[2]; + block->xywh = xyhw; +} + + +void rotate(struct block *block, int clock) { + struct block rotated; + copy_block(&rotated, block); + block_rotate(&rotated, clock); + if (check_bounds(&rotated) && check_collision(&rotated)) { + copy_block(block, &rotated); + return; + } + unsigned int xywh = rotated.xywh; + unsigned int h = xywh & 0x3; + unsigned int w = (xywh & 0xc) >> 2; + unsigned int y = (xywh & 0xff0) >> 4; + unsigned int x = (xywh & 0xf000) >> 12; + if (x + w >= COLS) { + x = COLS - w - 1; + } + rotated.xywh = make_xywh(x, y, w, h); + if (check_bounds(&rotated) && check_collision(&rotated)) { + copy_block(block, &rotated); + } +} + +void clear_board() { + for (int i = 0, s = wk_mul(ROWS, COLS); i < s; ++i) { + board[i] = 0; + } +} + +void fix_block(struct block *block) { + unsigned int xywh = block->xywh; + unsigned int h = xywh & 0x3; + unsigned int w = (xywh & 0xc) >> 2; + unsigned int y = (xywh & 0xff0) >> 4; + unsigned int x = (xywh & 0xf000) >> 12; +#ifdef DEBUG + printf("%d %d %d %d\n", x, y, w, h); +#endif + for (int r = 0; r <= h; ++r) { + for (int c = 0; c <= w; ++c) { + if (get_shape(block, r, c)) { + board[wk_mul(y + r, COLS) + x + c] = 1; + } + } + } +} + +void print_score() { + int c = 8; + putch_at(c++, -2, 'S'); + putch_at(c++, -2, 'C'); + putch_at(c++, -2, 'O'); + putch_at(c++, -2, 'R'); + putch_at(c++, -2, 'E'); + for (int i = 0; i < 5; ++i) { + unsigned int mask = 0xF << (i * 4); + unsigned int num = (score & mask) >> (i * 4); + putch_at(12 - i, -1, num + '0'); + } +} + +void draw_board() { + for (int r = 0; r < ROWS; ++r) { + for (int c = 0; c < COLS; ++c) { + if (board[wk_mul(r , COLS) + c] == 1) { + putch_at((c << 1) + 1, r, '['); + putch_at((c << 1) + 2, r, ']'); + } else { + putch_at((c << 1) + 1, r, ' '); + putch_at((c << 1)+ 2, r, ' '); + } + } + } + unsigned int xywh = current.xywh; + unsigned int h = xywh & 0x3; + unsigned int w = (xywh & 0xc) >> 2; + unsigned int y = (xywh & 0xff0) >> 4; + unsigned int x = (xywh & 0xf000) >> 12; + for (int r = 0; r <= h; ++r) { + for (int c = 0; c <= w; ++c) { + if (get_shape(¤t, r, c)) { + putch_at(((c + x) << 1) + 1, r + y, '['); + putch_at(((c + x) << 1) + 2, r + y, ']'); + } + } + } + print_score(); +} + + +void add_score(unsigned int delta) { + score += delta; + for (unsigned int i = 0, carry = 0; i < 32; i += 4) { + unsigned int mask = 0xF << i; + unsigned int num = (score & mask) >> i; + num += carry; + if (num >= 10) { + carry = 1; + num -= 10; + } else { + carry = 0; + } + score &= ~(mask); + score |= (num << i); + } +} + +void check_clear() { + unsigned int y = (current.xywh & 0xff0) >> 4; + unsigned int h = current.xywh & 0x3; + for (int r = y + h; r >= y; --r) { + unsigned int count = 0; + for (int c = 0; c < COLS; ++c) { + if (board[wk_mul(r , COLS) + c]) ++count; + } + if (count == COLS) { + add_score(1); + for (int nr = r - 1; nr > 0; --nr) { + for (int c = 0; c < COLS; ++c) { + board[wk_mul(nr + 1, COLS) + c] = board[wk_mul(nr, COLS) + c]; + } + } + ++r; ++y; + } + } +} + +unsigned int rand() { + static unsigned int seed = 990315; + seed = (wk_mul(1103515245 , seed) + 12345) & 0x7FFFFFFF; + return seed; +} + +unsigned int rand_type() { + unsigned int type = rand() & 0x7; + while (type == 7) { + type = rand() & 0x7; + } + return type; +} + +void fall() { + if (move(¤t, 2) == 0) { + fix_block(¤t); + check_clear(); + init_block(¤t, rand_type(), 4, 0); + } +} + +#ifdef DEBUG +void print_screen() { + for (int r = 0; r < SCREEN_ROWS; ++r) { + for (int c = 0; c < SCREEN_COLS; ++c) { + printf("%c", screen[wk_mul(r, SCREEN_COLS) + c]); + } + printf("\n"); + } + printf("\n"); +} +#endif + +void on_input(unsigned int ch) { + switch (ch) { + case 's': + fall(); + break; + case 'a': + move(¤t, 0); + break; + case 'd': + move(¤t, 1); + break; + case 'j': + rotate(¤t, 0); + break; + case 'k': + rotate(¤t, 1); + break; + } + draw_board(); +#ifdef DEBUG + print_screen(); +#endif +} + +void on_timer() { + fall(); + draw_board(); +} + +void trap_handler(void *epc, unsigned int cause) { + if (cause == 0x80000007) { + on_timer(); + } else { + unsigned int ch = *UART_RECV; + *UART_SEND = ch; + on_input(ch); + } +} + +void init() { + clear_board(); + // Draw border + for (int r = 0; r < ROWS; ++r) { + putch_at(0, r, '|'); + putch_at(COLS << 1 | 1, r, '|'); + } + for (int c = 0; c <= (COLS << 1 | 1); ++c) { + putch_at(c, ROWS, '-'); + } + int c = 8; + putch_at(c++, ROWS + 1, 'T'); + putch_at(c++, ROWS + 1, 'E'); + putch_at(c++, ROWS + 1, 'T'); + putch_at(c++, ROWS + 1, 'R'); + putch_at(c++, ROWS + 1, 'I'); + putch_at(c++, ROWS + 1, 'S'); + c = 6; + putch_at(c++, ROWS + 3, 'H'); + putch_at(c++, ROWS + 3, 'o'); + putch_at(c++, ROWS + 3, 'w'); + putch_at(c++, ROWS + 3, 'a'); + putch_at(c++, ROWS + 3, 'r'); + putch_at(c++, ROWS + 3, 'd'); + c++; + putch_at(c++, ROWS + 3, 'L'); + putch_at(c++, ROWS + 3, 'a'); + putch_at(c++, ROWS + 3, 'u'); + c = 9; + putch_at(c++, ROWS + 4, '2'); + putch_at(c++, ROWS + 4, '0'); + putch_at(c++, ROWS + 4, '2'); + putch_at(c++, ROWS + 4, '1'); + init_block(¤t, rand_type(), 4, 0); + score = 0; + draw_board(); +} + +void clear_screen() { + int *vram = ((int *) VRAM_BASE); + for (int i = 0; i < 600; ++i) vram[i] = 0x20202020; +} + +extern void enable_interrupt(); + +int main() { +#ifdef DEBUG + unsigned char b[ROWS * COLS] = {0}; + board = b; + for (int i = 0; i < SCREEN_ROWS * SCREEN_COLS; ++i) screen[i] = '%'; + init(); +#else + board = (unsigned char *) 16384; + for (int i = 0; i < 16384; i += 4) { + *((int*) (board + i)) = 0; + } + clear_screen(); + init(); + *((unsigned int *) 4) = 0xDEADBEEF; + enable_interrupt(); + *TIMER_ENABLED = 1; + *TIMER_LIMIT = FALL_TIMER_LIMIT; + for (;;); +#endif +#ifdef DEBUG + on_input('a'); + on_input('a'); + on_input('s'); + on_input('s'); + on_input('s'); + for (int i = 21; i >= 0; --i) { + on_timer(); + } + on_input('d'); + on_input('d'); + on_input('d'); + on_input('d'); + for (int i = 21; i >= 0; --i) { + on_timer(); + } + on_input('d'); + on_input('d'); + on_input('d'); + on_input('d'); + on_input('d'); + for (int i = 21; i >= 0; --i) { + on_timer(); + add_score(10); + } + print_score(); + print_screen(); + return 0; +#endif +} diff --git a/lab1/csrc/toolchain.cmake b/lab1/csrc/toolchain.cmake new file mode 100644 index 0000000..60bc5a9 --- /dev/null +++ b/lab1/csrc/toolchain.cmake @@ -0,0 +1,20 @@ +set(CMAKE_SYSTEM_NAME Generic) +set(CMAKE_SYSTEM_PROCESSOR riscv32) + +set(triple riscv32-unknown-elf) + +set(CMAKE_C_COMPILER clang) +set(CMAKE_C_COMPILER_TARGET ${triple}) +set(CMAKE_CXX_COMPILER clang++) +set(CMAKE_CXX_COMPILER_TARGET ${triple}) +set(CMAKE_ASM_COMPILER clang) +set(CMAKE_ASM_COMPILER_TARGET ${triple}) +set(CMAKE_AR llvm-ar CACHE FILEPATH "Archiver") +set(CMAKE_OBJCOPY llvm-objcopy) + +set(CMAKE_C_FLAGS_INIT "-mno-relax") +set(CMAKE_CXX_FLAGS_INIT "-mno-relax") +set(CMAKE_ASM_FLAGS_INIT "-mno-relax") +set(CMAKE_EXE_LINKER_FLAGS_INIT "-fuse-ld=lld -nostdlib -static -mno-relax") +set(CMAKE_MODULE_LINKER_FLAGS_INIT "-fuse-ld=lld -nostdlib -static -mno-relax") +set(CMAKE_SHARED_LINKER_FLAGS_INIT "-fuse-ld=lld -nostdlib -static -mno-relax") diff --git a/lab1/project/build.properties b/lab1/project/build.properties new file mode 100644 index 0000000..303541e --- /dev/null +++ b/lab1/project/build.properties @@ -0,0 +1 @@ +sbt.version = 1.9.6 diff --git a/lab1/project/plugins.sbt b/lab1/project/plugins.sbt new file mode 100644 index 0000000..5708f81 --- /dev/null +++ b/lab1/project/plugins.sbt @@ -0,0 +1 @@ +logLevel := Level.Warn diff --git a/lab1/riscv-target/yatcpu/Makefile.include b/lab1/riscv-target/yatcpu/Makefile.include new file mode 100644 index 0000000..e209499 --- /dev/null +++ b/lab1/riscv-target/yatcpu/Makefile.include @@ -0,0 +1,7 @@ +export TARGETDIR ?= riscv-target +export XLEN = 32 +export RISCV_TARGET = yatcpu +export RISCV_DEVICE = +export RISCV_TARGET_FLAGS = +export RISCV_ASSERT = 0 +JOBS = -j1 \ No newline at end of file diff --git a/lab1/riscv-target/yatcpu/device/rv32i_m/I/Makefile.include b/lab1/riscv-target/yatcpu/device/rv32i_m/I/Makefile.include new file mode 100644 index 0000000..d17e055 --- /dev/null +++ b/lab1/riscv-target/yatcpu/device/rv32i_m/I/Makefile.include @@ -0,0 +1,54 @@ +TARGET_SIM ?= verilog/verilator/obj_dir/VTop +TARGET_FLAGS ?= $(RISCV_TARGET_FLAGS) +ifeq ($(shell command -v $(TARGET_SIM) 2> /dev/null),) + $(error Target simulator executable '$(TARGET_SIM)` not found) +endif + +RISCV_PREFIX ?= riscv64-unknown-elf- +RISCV_GCC ?= $(RISCV_PREFIX)gcc +RISCV_OBJDUMP ?= $(RISCV_PREFIX)objdump +RISCV_OBJCOPY ?= $(RISCV_PREFIX)objcopy +RISCV_GCC_OPTS ?= -g -static -mcmodel=medany -fvisibility=hidden -nostdlib -nostartfiles $(RVTEST_DEFINES) + +COMPILE_CMD = $$(RISCV_GCC) $(1) $$(RISCV_GCC_OPTS) \ + -I$(ROOTDIR)/riscv-test-suite/env/ \ + -I$(TARGETDIR)/$(RISCV_TARGET)/ \ + -T$(TARGETDIR)/$(RISCV_TARGET)/link.ld \ + $$(<) -o $$@ + +OBJDUMP_CMD = $$(RISCV_OBJDUMP) $$@ -D > $$@.objdump; \ + $$(RISCV_OBJDUMP) $$@ --source > $$@.debug; \ + $$(RISCV_OBJDUMP) -t $$@ | grep " begin_signature$$$$" | awk '{ print $$$$1 }' > $$@.begin_signature; \ + $$(RISCV_OBJDUMP) -t $$@ | grep " end_signature$$$$" | awk '{ print $$$$1 }' > $$@.end_signature; \ + $$(RISCV_OBJDUMP) -t $$@ | grep " tohost$$$$" | awk '{ print $$$$1 }' > $$@.halt \ + + +OBJCOPY_CMD = $$(RISCV_OBJCOPY) $$@ -O binary -j .text -j .data -j .tohost $$@.asmbin + +COMPILE_TARGET=\ + $(COMPILE_CMD); \ + if [ $$$$? -ne 0 ] ; \ + then \ + echo "\e[31m$$(RISCV_GCC) failed for target $$(@) \e[39m" ; \ + exit 1 ; \ + fi ; \ + $(OBJDUMP_CMD); \ + if [ $$$$? -ne 0 ] ; \ + then \ + echo "\e[31m $$(RISCV_OBJDUMP) failed for target $$(@) \e[39m" ; \ + exit 1 ; \ + fi ; \ + $(OBJCOPY_CMD); \ + if [ $$$$? -ne 0 ] ; \ + then \ + echo "\e[31m $$(RISCV_OBJCOPY) failed for target $$(@) \e[39m" ; \ + exit 1 ; \ + fi ; \ + +RUN_CMD = $(TARGET_SIM) $(TARGET_FLAGS) \ + -signature 0x$(shell cat $(<).begin_signature) 0x$(shell cat $(<).end_signature) $(*).signature.output \ + -halt 0x$(shell cat $(<).halt) \ + -time 1000000 \ + -instruction $(<).asmbin +RUN_TARGET = \ + $(RUN_CMD) diff --git a/lab1/riscv-target/yatcpu/link.ld b/lab1/riscv-target/yatcpu/link.ld new file mode 100644 index 0000000..6afe7d6 --- /dev/null +++ b/lab1/riscv-target/yatcpu/link.ld @@ -0,0 +1,12 @@ +OUTPUT_ARCH( "riscv" ) +ENTRY(rvtest_entry_point) + +SECTIONS +{ + . = 0x00001000; + .text : { *(.text.init) *(.text.startup) *(.text) } + .data ALIGN(0x1000) : { *(.data*) *(.rodata*) *(.sdata*) } + .tohost ALIGN(0x1000) : { *(.tohost) } + .bss : { *(.bss) } + _end = .; +} diff --git a/lab1/riscv-target/yatcpu/model_test.h b/lab1/riscv-target/yatcpu/model_test.h new file mode 100644 index 0000000..ca8f8c6 --- /dev/null +++ b/lab1/riscv-target/yatcpu/model_test.h @@ -0,0 +1,46 @@ +#ifndef _COMPLIANCE_MODEL_H_ +#define _COMPLIANCE_MODEL_H_ + +#define ALIGNMENT 2 + +#define RVMODEL_DATA_SECTION \ + .pushsection .tohost,"aw",@progbits; \ + .align 4; .global tohost; tohost: .word 0; \ + .popsection; + +#define RVMODEL_BOOT + +#define RVMODEL_HALT \ + li x1, 0xBABECAFE; \ + write_tohost: \ + sw x1, tohost, x0; \ + loop: j loop + +//RV_COMPLIANCE_DATA_BEGIN +#define RVMODEL_DATA_BEGIN \ + .align 4; .global begin_signature; begin_signature: + +//RV_COMPLIANCE_DATA_END +#define RVMODEL_DATA_END \ + .align 4; .global end_signature; end_signature: \ + RVMODEL_DATA_SECTION \ + +//RVTEST_IO_INIT +#define RVMODEL_IO_INIT +//RVTEST_IO_WRITE_STR +#define RVMODEL_IO_WRITE_STR(_R, _STR) +//RVTEST_IO_CHECK +#define RVMODEL_IO_CHECK() +//RVTEST_IO_ASSERT_GPR_EQ +#define RVMODEL_IO_ASSERT_GPR_EQ(_S, _R, _I) +//RVTEST_IO_ASSERT_SFPR_EQ +#define RVMODEL_IO_ASSERT_SFPR_EQ(_F, _R, _I) +//RVTEST_IO_ASSERT_DFPR_EQ +#define RVMODEL_IO_ASSERT_DFPR_EQ(_D, _R, _I) + +#define RVMODEL_SET_MSW_INT +#define RVMODEL_CLEAR_MSW_INT +#define RVMODEL_CLEAR_MTIMER_INT +#define RVMODEL_CLEAR_MEXT_INT + +#endif diff --git a/lab1/src/main/resources/fibonacci.asmbin b/lab1/src/main/resources/fibonacci.asmbin new file mode 100644 index 0000000000000000000000000000000000000000..45e994fece092de67f03a039ffd50b31c5605514 GIT binary patch literal 520 zcmXxhv1;5v5CG7b9nEc%;*2^&K&O%9vn(0FM8`tx(s^&e;7^3D2d z*PGerB|uk>=R@4A$2dfte(}gdREVpd8^*4x9Y8WtKO=&>g`a=OPS4gwL{1pgh>R-5ku~f z#AA?%nwwBKL!~#NjD{+tP&uLlPvIaEO)&{mm(Zb4!eLCPMh>-OI`SNjB2$B-(6|vD z`%yTKBWlrx)>%67Hk?G;O<>+ZHq%+Gq}5q89?}H0-iza+nclmXP}%;Int2lEg9^?6_b literal 0 HcmV?d00001 diff --git a/lab1/src/main/resources/hello.asmbin b/lab1/src/main/resources/hello.asmbin new file mode 100644 index 0000000000000000000000000000000000000000..8e9a27dbdeb1d15cac9a16186fdaba132d4bba84 GIT binary patch literal 4344 zcmeHJUu;uV7(e%(o?aZvhE0v}LC$)1OBrPhnCX*AE9-)W7zFm>9wYyYA8k z0-AP1gw_%f-aa4F*8qs`CB;lhQiauvU-A8*h z=JX~Q-B@JK#yX=>&F@4Le!8jXcQ)1iv`;gfzJx(H7Y%1~-N<#5fgIuez(rH^0TZglC#G>}v&r`$*u4A+R-EyXcu|1{fhC zG}FwGH~~ED`!(yus*ZbV9z~zczQRROP@T;Wl9I>93 zHsq(wFb41gd}c_ExtzfnO$NcX=v(e5eg*Szb87&Xke}P1jUb^z`Id@x(E*KUDG2-q zmEXARDbV#Uy_V&VeqBwVUQc7}b^`;2W}A$+(OUY zox?qE4sxKfmiUzbvkkene}lNvkNbuoCh%sxQ1!doK#zKPY#XkUKw-(%6Lk-;cZv0? z*9*936zrYSFS!i7Yt+40xZ~XZ3H?gnSi@3F*6{v~hj}+%PBh6tN61t6;>*59PSK_` z`vJJQbsuh)=_7k%SW|ib6Jx~2w?NIL@?&3>cN%`>_iuc=)GT>+;P8aE{`TSGJ)^WB ze?Yu=J67#-+gI)Dhx0Y1w2c2A3&T8#z^pQdU?$+3o?Rnzj$dl~jemvn#xawfOveAbhaQ(1GeL*nfP=vfV3)jq?yuIA*Y6|WZPEjYio=a=aUKH{_jv)|Qn zuq8gKz>LDTm|U$m`5t|%^;v0SkEnXTqsiO0xi)w9?0?1e=DXtHQRVNOb}ai#X)8P? zZME~Lhg#3KW7R&xbL662s@^sG?CbEK#Ov8h58z|j3~;rBS&aFqSXF$VbHIuCxUvT0 z1X!1=uj0bf`3$`ERjQ5;rOi}Y5LL?sChepl?Ipz{nLobRYAx9DNfmSUj`~i@v-lZh zJL~4t_~c@_v~*2`K6mGm#M}F^M*JVP@>^kGg@F|YRv1`e;QwUcWoD3&+@8!>>3L`w5%BS&U&*8DW zwO`%dmrWlmq$jO6I>?Un_;@DD4`;IDBi$V&%F~mn*T&N$h}rA9&S%F)Mif(0>7T%kB#R literal 0 HcmV?d00001 diff --git a/lab1/src/main/resources/litenes.asmbin b/lab1/src/main/resources/litenes.asmbin new file mode 100644 index 0000000000000000000000000000000000000000..b868250eec8b661d7eb730c409ec7a8b24e1003f GIT binary patch literal 70484 zcmeFae_T{m{y%>1++V{0Gou3oisHx}hMy8TD5R#K;_tU>ZPIRT8-|e9yREj=+V)eU z!v*{SsS_%iE%8eRh1EAIvPNMELO)#IpLg1(*1Bu{s@A3wEj8xzJonBB_@jFFeZT+t zJ{r5+dtc|A*YEQ>uXFCXw^W80Hxfe5IvnATlAEHG>!PPzn&gKa zggg~(OrdAx+Q_7s80H%(Y5#G{cwo4<$ z9?(ef|EZA@|DlnRzSKw-hDTdovJU6bo=1Bg?Rm84(Vmwq%SE&o(OyJ*5$#2^7tvls zdy(?;b+jc#<(=H)v}6$H@B@U6Vi;#s2E$6r8K-oB!M(<5&CsyX%QepE0~*%GuufYB z%f>8coiPVkHkRR>u^Aj2x14jv9pKn_hIhti@NB|z-kETKXA>F0nV2E4BbE!!5eEb| zi4mPi86tbfa?yFm0r9EfB;_e$Nro=Gk`21BE+;0AVWjw~p2tZ#VWX#bU3|A!ir?Mi z;t9zS_7Dnx-1Da%7ImGL0|adus#Bb=0tW{i9B}X^fk3ARd!*Q^9?7=5CzUq>e-+Mz zk)o=4*y#Ko$>OKO^*E!a^yECfM?>*Dqq!av=tH-xv$`#XwN3fXWHysVxs6C` z{d`mUq3|p4<9YD1p9cj-`S(0{F;!;3GyjN+uk~!I3|;bVMwQ3b8tCep3-lFzCLX+E z;sv7CP1m}39x~-$l`OljNl8^#eEPVWI-26_egisD^a=f4>*e#{)tmVQjPglwc!ph5 zX_LJ^9-666VQ&uh=3r;uXYYPKQyB<52k!2v)E(?$Gw=19=8Y!OAlR8-=rx6oCaxv? z^K7WqYtMzgDLnIOz-0<|^n=f{dT-%d-$RSy;TdPus8gE3hmn=K7anB>Qe{5V{Q38ls8vtC`lEJlvizk-{!oE&rrEMfB#C+ zQzl3CWNd_v6q(DbsSPyn8x8!1y_MfkJ(_52sJ*2wd!!`9r9>qzAqK<8Vs}${U=!kS z$xBGiU^OPG{5#MGS{an3v(@N_KHUMg8b_>%tCj-{c+vQH>1Qj2XJ722HbTE=bLQ+3 z)P99~=z`k634PQhw{i5^$ww0@V0Vu*6MYeVi2AhR5du zr#9B9JhVR0YvU^8ets;P-p|PT_N&{Gl&a^pUmoD>`nX&ui&8>h}lgL#9%mQTz-#f__vx!R9EV zw$bOLUmp*d8|H9vvNFVP+oS-tPK11Ww!S75PXdG&T9(mwCsMwK?%T#Bm z57|-2tm>oxc6SWE{6UGqiaz`KdNRRS>dPVWd#JssFQD(H(>U$(?{t?un)(beEeRzq z*d#~m?}tjvS9A-wFV?0)-ZT%qg7 zVY`8@#YeXf{5suRlqqz5aKGMibOQW7OuOX(aFlEd+_0Ka34O-VX4qop=QatjS*x?N3HH>7QBU6v&g*g#(F;gJs;?c$>eMHh?O|!p$xfLV=jC*^Ou87!s&Yvi@Z56 zwdtLu3yJGUCUJFl6Si{-NxifVd?v#$_MXVeKSFZW^FcHZaB+c5&Oo;&75z4KDjjDz zvN2uB*FR2eQ(+k6iBewBulz)6?m%MF@kMOr{pfqV;2LzE*jJ`7CO*KA<9Mo#kfwN= zW1}sF&!xCYrxR^Vf<=MneBP$9%ZnM8tYhrl9`Ix&sf&S|_w&+vl+FBgkt;uh*tvU| zQ=h0Ym`%W3AU=bz@rY4z2M8O-Fiz<3#{P)>L&;}1dc0oHerBVE^5CfT@$wy&gPoUK zMB|7GbA%&rQRZ4YVxr*q4-}1b%39=w3T-hjBV?Kwxx!R2T%(CnEXz!9`x1E+-Fvj$mQ!4i4`IRc} z)|o!KADklmH>tp5;xo&9GS5)U93Pwt=Pw~2y^Ois3r*3(fV-_(iTlXU6ki8C)iw;a zZU?;WdR$UtZM8RSGS#oMRK0KW-@l~ZpZ4Fol)SZoKjxfjgCC*a6{26B7K{>ehWKps zykEc6MoRsB{upvWwLX8z;N!WH<*ktAv{z!PZkn^u+yMBGv2rwcM*m-O$zaOmjneWq zADy?J>|Y1x5;kBl$C8(RN zwDHy7O6jdF3M1Idz zr7N&Z)VCj>V=+-GtlrVjswC;$aIK zJ5*ac+02E+*_M9{{fTvT^Fj90=%*}fVMUy~As4$XugDL6EU&l4fxP6$;^-@HUs>mDuZ8!tyCf-i7r8jF+bkP4Gciff@Qds_3&4ebUrTeGst%a^EO(Us{T8p-<$- z(3k4#l)ekPHpx`4e!Ap$N}W*n*pkx*wtXQ<#X1tk^(Yz#X%0o(vGdxFN!H!ROiPc7 z_B`0rdGIE^tFgwJdJ`YiZ+td(-3z-e_1o6ZLu)RzEnOEvUV%QhTkUhqOTB##^4`kM zH_`IT3>vqQ_dzFg;+M&F1afyHK0!8hTyi8(eK^~o2VV?O<{XHtE=Bj4lQ@4QFFv`Q z@NFue>m|_g_jA?ezi9jfHpQBneN5?%{&26-ru!DL=qKvMFE{l8B_5PwUIe-O^OQc7 z)>HbHwF+h6tp@Q@?&~wHGo6{eI_%Y5YuNvk?j*}_hT2H=8*dwNe!3k#UagGL z|DCqdil5%L@>XpTbDH1-&bHCV)Y$UYmwuU5c%~0N+0!3B&tLxnh0`(1nK_!U7_0m- zwXxvHb(tj%#waSYZ;a|~lX=@V%D8sRHn*o!d0RU3egYlL_5Zu_@R>xycjS9uww$ea0B(r{j5|4<5(0pN=QH4<7Q( zPsh_&F2~n7;Xh43{q;<~_^EhILO=a{`qT0B)6bb7!lU#z_(T)>7uJN1-RM)-^N&#O z80P61Ppyct-CmR2ZD_(;l1oVfQ{G;gI(HQwbad4M|JIXin{$wY-s?&yVCd@%MV^67y>*}$=Evu3y>XmX>!|UYuG6r#f@6(zzSMTnYdYG^n7CXTyZZL+1E#$pxTkB? z{;{(44O2Jgo9|(~2mD4o_+)IkJ^f5&o#;ofJ&H6at?gzGe75Ob7-Ny?ht1O4lbxn8fg4mAGj@|556M zVt#-*uw-pUj_jKUb95do_nQazodc`=AbmQ^uRP|IG0#IgI(KqGH;uHNjQn58tFi7x z`vT(gt#Wl5_o@6%IMf^+Yb$N&8yI67yW6l{E-ULSsRCV>y5yzL1XWu)({I@hxif9& zv-gC)w)Bt9{`nxC+tcy*`aD>*=Qzb4{@mG?fBU$r=+LpaU))h(>5G0a?wnHQSGnNt z)@x?Ic@*VE^>TgguJBEM(a-Kj{QAWDhhld}1kG8LI#~a37GNHY zbx?aD`m-pK#x|_MB97S$+Liuo&)tSNa0K(l-I!JZSNu9xe8WGNQh7{nqP|>>Smax`Fs)jM zSgKQV7gg5LEG<{o1fEsmtFk6g)n`or^*1VY9ix;r0o>EI3l)|=(%(;{0qf zjc*M-pwAk*N;AgJxj{=^L%)HaM5RA~r|(@qzs^&7+>h-OKjOI*_K{)lQsQ##wONOK zkHc9!2V|jR7S92(muLZt{f!LDu}5$nBgMXo=Y+eM)M`9W(LRBF1AKGSX!=Yp^LT2_ zFx>C`#<#v0p1O_RH>EYrLwRv#ViVd(4SSw#+J|Q}1p9wV!uPp^wq_HXO{9uEtcRkW zn0c3rYyVcNxTvm=a`T3m#6x#VQH3NGcuWTQQBy(Nvr^O5>2l@bdf+a*R~(I?8M zvZ^d{tW>^RqslQaLb5br|L0y-;(&{_fY+rO@Q3}Pg&KuciJT}!9c3#~E>$f>JE{*k zL#o=1eOralCE8*vH|f*CXFCf%p=)2;HT+~Legj*H=RDGmJPmkb!4r-RtRzyNmU1dj zd^>pJRGvzQfG19&E%Woi8|NzGvBtQINLsY1$l|~s2maJLD>Ii!QDgW@T2|N2gFXlP zN||XjKSqkr<12LveGc@or?n7A9xnwd^aYiE+h?FJsPx-Rpf7-~Ck!B+y|D;oHUPO>)PKph_UwWuFk zh+{*bB;dXd<#lKik2die0^uXzFHZ-WfuN&Rlj5*sLgY zu#_kc@cDNF@C{V;cqAP71_IAOv`WSA7Y%>+INfiNvgQ0z~P&b&|^6IK{)gn?&EU=+70%#qkQ6; z%E> z_=l+YW!is+pxqF(8-n^nP=5&OBmONL>f`5Y)Q|M>1N%2cqCVw267?fdKN9taq5d#h zANnkX{)W@~ru-w6ABzGn;x|dPoC0^PK7#(XY&dj09PO2I*wG3)Q7WAy!$BuXrQh~4 z&qLY9lI@{CEDS>7b>O=t+1zw}U zqZMV*D2qm!6=hbG`S4{{f{x9{7nR?JHZf>p^YP~ff4=h4aPVgXo*3X!%1vuB*Gc91 zaZ3BuZK0B7S)8hmww35dD!fppJ`}6slw#YM3g0>ED>dQpezYx zccAPJlqI1o31tdDrhJ)$-jXT*rZqC;DjccsUnpOcDlR62w`BNVGKHCnWa{H;x!h)k z+@nxulqxSj9C9Jn=Z`}DQK)D4!CO!-1@%$@PXTdN|2x&TGGgcMwA2*v#BnC@KQ`6syROO~i@IY`K30v%g?|RF z@wgxFi_u@ZfC z45oDp%t~1U;7Ncd*}^IffY&S?r0S#Xd9(?q^i9RnppR{X&?XXXA#>I++z&%}BydN9 z4&=`pDkW_j3i?C9#}M#?dSiy7-cZyV0=z>jMOtq|1nNbg-eA-lj7>OzT^a-!@b32@C(?b0f5~F*hKJa1i$c$ zGZZ!vdDTR;9ROXzXKV)KSb92lk#_8zASGU&AT{jOLx*_3DGTE`>Ka1zQq5ky3wb>B zh&Fk_Xpj8<3O=jm_;3^`8&^4BEftqoaP zv_V_sVj}9)Eah^qcdxN)lf`Fo+G zH0X#PV{ttm=kYj0p4}6aKAPV)5d9wS6XYX@%IBo2d;w>A1mRkbGd+wrLU3=!nI7Rd zhTuLD=ScKnj3xOgxF3TvJ;vjD0?wd8pQG@hQhd{dCd5fs{y~hV8xd#PCnCqyBYsSj zqWonq4U?=Wt7xBy+*ptNZ=%|ULq4|A*ZzI86tyuKdD{f!*m~sJcfmg6rP#ue$nVA@ z7uO>vzYFxnOYx{z*M1jrchDJg7wFJ>cI0#8k=Nk1TB=sH~Gs3f!;XepL*n>v`rf5ja6eo81lT! zh;Jz8QEuHkPK8ekm8^hALGG%hW0Bi}*Q4XW>sas)T`V1o9GL0?u#G8zQNG3^M+RS) zFt^)?IS7s&S!u|@!4F{ZO=;i}F?Z^n$ko9MV6la1sxDtb{sq0%PQ4SkK4_f*4%APi zwDQt0M*yv(cj7(;#~9E`gRcj{=Tjl89Wo<+n^Vz0g3xDDp@&h>j~#NS!k$6UR}k7@ z%xF)A4Ut3dO@)p}L*EoW1~vn(ywR{h3T!eO?NeYg;K~~fJ0ZVrAB~tYOyxBMacHAO zN>Yv}Tw8HX51X$%46s<-(<2_&i8#|ENiDyZmM7z$9;0xbf^!PaV{je=T6Wkf2)43A zmm{ImAlSza`vk#0n8Pd`1^(@@%P80-2zIf<7MKeFZfhE=`t}j<2>oHMj$BP$tpg1n$tzBCE=F}6<~2|Ixgz=BYxqWuooXC&+cnrB9$ zkK6&>0-l!)`#`5hM}ns$@OTGsB*Q+K&t%;p1>;eFSU@`gtQ@d*pM%P|zPCQCO@3iv|q26Y6OJiyAWm`mw@CAY&Hn zhwCKhD+;kW3gb!n(nR%;Cm_LU-}7C!I@D*ianNuxUJOtAjlf;0tl^1s&+Zr%+}Ce>V844KZZL z)Hv7=bWtY?V?k6_80;4Z`$0AZHVm*B*e_0E0J9#AgB^9C2_FSK33jp}XR;yg#bS)A z$cu$dLH8(fM%*XjC|?>2`(a*fLynAbHxWl&mJRmRLXH@;Lw=5ZgGqn|RBfyd%a}xYEiN=^qSmOfjSm25}Y61-jHp05X(FnYWdx6y$7h8@=g67iUp45X4Oz&=Fy;{2 zb}807mJS5|fzW9<{F%Z+a3FuhSXB;~A(Vq&IbTji;UjU3#&IVO^s79K4|$-KXN0b? zmX?RL1mwkmxTg0tuvHEGt_J<30b@=>9&*6Eu{bb4KyId^b@n13#8I=C=4%rmKL`DA z&@~60anL^popVyH8TpPG`HmU+jv2aC4&*y#5O3819`FB>B7m16^~_4+p(*&?g5QaLDZh zf?DK!TI6?H=Hdz;%G@0M`K?1b7hOG}jCQJP7$<5Xyp3rbn5+ zlE)$92*44DBN&H)*Gn4Yh}bhL;e7;&=8$^jT7zp1t~Ds6e~ z;kCFA!hI0#gK(|KHS*|pN?_U$O|#J6r%_Pg9}e+{Ag|689>`L6c*+N`+U9v3PPTg@MLR%agf z$$kBOTkwl@^x=4(FcNF-8F-#>H)8Dq%r~B7a^{u?(LJ1WKWFMy9C%jX3TS&)dCs6~ zYi_!NXSR?}fd{sI`#5oM>id0}jPjmh_1njlebm+5akgg4ak{79mDQbLZ^B+l;b=Pc z%BQ0|U8=1*Ce ze{04SYcZU+DLqV_$!eu%DjV zjfG8o^zU_IUliSgBUx+U7nHXj-VfNP{ak8;>+ieJ{Q*-2;xu!|q?&4FkBMZ(-Y*&P zeQNwx6!T_XO|`J(k|=O>`QjvV+l3HWb=kAWX*x4wQxZ7I;QJBi)3~s}k zC$7t6LdQ!NhrK=l#AxSN68n-;vawZp_j9Rl3|(g8Lhw#+iuZfp8_ha`J!6ogqg|6D z2!e7w@F@NE&n@3IRb^$J9=zNY3QM)1eGc<`^;gL3d6i5Nhi zE%LBcca=|%js@tCtkO>Dqv&FDTdR+qk|y>*GfRKPU%31+XvG=PUhv$4Bp1px3{>8ao20zNtQa_RqpSb2FXv z`RaE>u$S#e#CJSrg@56|9xY#dIBKG@&CAEPTd>CGv-OR*RR4bKznbu6eOig>iLqR)uIO6MnZw1p>%GOLh;o{*dqM4+E4#i_KA4N>5QT$k{ICDbnn{Vk- z_c)N3p?t|`-+OJDDc8T*Gtc+_um7EAe_hzpMR`^FW9z>ZTKL{b&P$*Pe{|j=-@Z-< zy6A07J~f55{XqTnzV*-kaQ(S`>wn_ojZt}X^rO|wllpFgPbVi;_>oS^Cw-U87u){s zhf`mtWxo0!^}L2TctFrm(f7lCGW$@MipckIqhwkK~z3_hgzuyEq zVGh)(eA@u~I{WbYAuTf%P}v{@=703tSSGwv<)_tK4q0w4Khj$cnQksezwqOSY&Vzx zXKy)Vyt(|Zz2%Vg=JNM?%OUg4`(`g3_^!j9tty?< z(9^B>oZQx1ek(pFztvlQD?TS5aLtq9TliMeCy0qzrO_x}<1ITbhJE#B4W z_EMSf9OvDBF^|5_PUTp1lygB28as2=s&X_z4p)Kjg-PVSuCTMj6ecpJ`(haTSzOcj zy7UlY6qVx$$yszpkwc-yU-G8z1x-N!t+wmm8^CyY1$*r{?4`s0t92aq+Ns|Xv}WMj zf_L-SYe&B&h`nFSvBtTM#a=t?#oNWweT+>yhBWO)tZRF})3s99)07F`R^vl=zP{`m zTV8d|4kf0Dm5}#frxf+7hMfXCg}Sk3{wmF_v8Ipn=JC{5{%Dee{4sF9NeDy^S)}SG zcn>j^{*iHob~5(GcxUgiS&T~{##9md6Nx63J`Xcwrnra)581TjD9p( zE2D9(8A43K!GE*|oX38`VvIk=M{XzWyvMRQ~+Nv!`5a2^E4Y{Khq8$xdLA}s`zvc-q~(Ey##W!0`GpRPkis^ z0O+;hUS`;Xh*|J`+E;z!k4*JQ?=ey3dBWVFqcuT!`}l(kQ%78dqFWz60bsx|eAbz~?2Q z2j_HCCFH$?HjTh>D4&>;F6mw70_?L8jCSrlV%ji`Y2-T7>9_n$<|cLDvE@rmW65{v ztc@XdLmU0Z8l%kNxO_un{zB%|iqWU-{2TaQ0Z&fl3q5S9mNbg<;7_#gK(~2eoN3-^ zG%uR5pWcSOQ_v^*mdm=~r=r(n?n67b z24e}O-KNsc1MRbvHl=x0q3NebZD5yQC#GoLi295~-Y2Jm_zP^bj@a|g;n)BhMiVw> zxrV-DgSBb+J)OVT;ai%+{^cBTK*Nr}T45sA3en%Oe#Bz^h{O63zUjG~=J)u}Uo>?iPORZOXk2V+M&DkIJSw2o;F1&YeVJVvf4oE=#j~~p z_(qw4=We^M#|hxXHQFJj(!Hk?AFls~wxEH2UVwh?`__w;cmR7|cWLN%K7d2x|3(aO zX#Babl(dWPL&mz`lhocC$`ihCs$rG2)(nR7=CtBlewYX6d}Y0Z=D$jRn1cRL9jG}q zMeZ@3PEldA0Bh^KK8|kOsm#58;lj5_@jV;#Kj20i^ht86qxy;o_c^oc0G|un8}U9! zhDL4UxW{zbN*Z=m^J82pEE8-|(EA~xbt$I%gZ1yS#x$sUVzR{%cmHt~(5TW|OI{=6UG_DVw#h60J zBGxq{u2ciQoY-|(Q;N@8egZ>pQ66lY!=e?)sntt1keovQv>qD}jzY8Mp6EU?P^wpst}mR@ z@}IJ8!T8pf{Hcr2zQM=R6KNaFb1?5QD)|Cp#5u$W4l#m9jKFt&5d-M=eG?eL8J{5_ zMhJ)z0%C;dM88Lj5S^9-B4UHq7bE&TC&>A2Io6f1#=`l(^OBBlmEyZlZ|C=*{SU7v z!Y^Fh!A`b~WAJS#jqh73%X6^roW_)#AZl--X<9-M1NPiyAH9bt?=~a0C^89q-e#*Y zw$T_^UZr6(Z`56SXbzs?P+UITkI}i9dfoc(sWkUd+N1*?>ZtvBU=DIH3m$`i*dED>}9#&qS_>d9YG%@=(~Z zpZz3!r-R00Q(;>to3%}e;piVeguPy&AHWvff{RB#((S>ToCS8r z`lfkL2<4xh0zGhu^DC_?&*;a!e77PGfp7MMIW*Enjz}&}S#zxv z#@fuyc~%qRgsXt&-N<2RoLGeO^%&tmJVN}U{^rl|ftUIdwG-RkeS)qnR2I~nz&aYK zEaXAUq2`*%7ft>(0X3d~4jl+Df3dIzw{)Su=z_Q&Qh~ojQue_|8GM`2%w~4O2lybme$EPKPMDC}+4J@) z{wBHF-$s88qHQV-6mP4EUb9oXJ6(bqup@X69r*#z!$vjKb^~ZR-q%440N)%hROasm zJY7)QMQ6Ta&)kMF4RIaMFHBlGHxvR)S!b9gErVDf2y||EE4#W1zUgaI&Lpsi`)!ma zCxHfipOETP;%mTjdH|J268E0)!z%%&{zLnArPv0$644}ogItmNM6NQvxU|%7LK(^{ zWO~;wAh*scM6AVH@#g}o*fap`!6i6ustNHFd`L|jirBj3gM3ZKXM z$UVeG&)z6pPa>`tC=6xK((@?d!r65MWmj;Pwdk8#;(C7>ab3i>4L@^{O8r8w=~5VJ zeDpA>ELq|;9eEf&8%pe-HxS8??=^jZ{AF1fu|NC;kzPFA<2rgD#$YpPJo9(>&HFvB z_hS@XjSI_2<%^{~rlZsFjK@suXF8#;gWw@m#g|)$Z(vrFN>W8C9morrm+(D>Bczh~ z1n*zUjHG#*kyhj)?*}b>bFopL$DDfk;ft;nkVT8RYEcn6we}$on|OdY@$8jN$iVa0 z<#_&j0MB2MH^yb)`Rj5#f9?GibrbdRcAt;Gc%;K0hm^hzUT8cHt5n{Voj~i-HBPCn zn%XAa9$JIFv}zrHd{*Y+axUgG7!NQnW^4G-Cfny13zovXAS(UfuA+-vj%?Fz|R`^|C0tbl$9-x!mpsnydZLb`5yxY zY$!7iC|Ig`?3MF{MMclNQdWj@!81iTj8Mi}9OXD1 z4hJFoQ^_0oq-H;Pq=`f}60*)lo=YHP0wL3b$@nO8M;>bO%CDoNgZ$b%WxTh^{;t)hDWc+g^GC!1*=8^n^U?V{JdA(jz>U})ld*pGiciFq%$IHCW{o1?k zL2re<<_&W9hmZW*kp}XiH!m+QSoxuT{u|!?`@LQJz1}xI^}g}0_h6Iv-3IT674QC| ztl>ga-Q^377rY;R^bttlHwXW}4GqJ9KlS&_-`vJxVyWSC{0yiIf)ibK=gLNQ~pSXNjDm0WmQtbaxf za9I9TGW$LUQ`Pagkz{1dP8mPt-bH_`edFUV*fnd`6tgT_-1{TxXcG5AG5$OcKI)$p z3!+hU z4=8>?tdLq9qKEz1A--+wJ`+$u%EkI^Vw^@M^|d%PT zu#@RZtN*>&$##vbUnY9E!^_0%`fEa*(K85*;v8Lr-3i6ZL|oT)l9b(rQxS&I9Wjy-&KZrA!;y;L%Xy@$xD;gdZ&#j6R ziysv&dS}bT6)@|$lR|R$jt9k#H5}_E#n%MOrw!HmPN8cG?w$~fe=inCiSWbh9iZ^J zZmm%N9c^r3U%v2wcwwP<;Xd)g6Jq@}vG@@YEl|BetO$e0d<2_c$u53SEY1_5qinI{ zVKG~bn&CWbwZadYhdRp$TV%Wp4m~=zwHV|N7Yl4Q}uTgshK zt_S1`w3dHswT%37w&#MX?%jXg>1=UcaxTbkh!D>eq`0;6wb^qD%Sry|>c`qrx`gV2 z&g`A+nb94aEN6Ds4;I@}Jm&gEV)$Z5@gmX9EGD&{^v8Jt4DhlW!KLTyQbF< z5lu3S;Dg)<7(Ad2qi8CAi~ zZjy*Qmo=Ci7-p#K3UNJ%N_+h|plGb?88|-m-`% zR%=q6)cQi5^d|GEcldjv)f#8TZ}_YLU&UB!RM0f5bb|Q{id8I8K_YE#jU3bq3Jfsn z016+bkMKt4hg$GSf^ggq4Yyi!5reE!c$hxH7R^{~BXEpntT7)>t&90bW}P=Qa-eY_ z$7+a`w-T)=AO(ntnL6j!3x4;z>AKohZf#Jjb}ifiL5>ckJqR!@_Y`(|Jz^Qdp6lrP z%1v;wsIHUSIpggvss4U+e5O;kRy?mO|I->RTO6Pmcuk06+BIhQ2Eye~c-z}u0Xv?c zHq*>tX08n^=bHajSjN$Snth(r>FPk}tHQD&Ac9|O(AqEEiL)mb)R$ubLAP*=uqah> zy-kc`WPV3F3mXj=%O0}K&AdZ>A=yEl+HDs5tbqd>oznN?mSIu|ntC^WQ2iaKqZ+7xZdS{r*s{e3LFV1ky z-?BVg_APscoFO&Lxs$nBDhGsI@HR3J907sp_z+YWu}5au4;;>nxPS85}dK+TefTp>t-O{%&p(DR6FNR zifcbqiK#vu6B83AhD{9OkPCW=K^$l>h+*^?f`e2C#ED&ZqbHsmxpQW1bLUF*$8#O9 zGwtNG-`CF(b-LQ-|6JLx_rEVRzqJy5w4ShPH^1<{Q2)NrDXitu%ib5VGc%_tzx#gm z>-(t}+wd#TaI+0_#4e4Svus?Ya%XvL)dl2KpR?I+QqFb~Pe?iG{FO)FdACQ`(fNRf z@4UyubZpu|*bcNQ!kD6i4-Lpnu)d>ZWapd6|k3a}R!w^5w6-{`wnlEcwgQ{eSt( z{{5NLRJ+mh?!9}O==sKf6xWSEN}v9=@2GEh;I|L__JH+(wY}p|=iBeT^Im*>db(0L z%{py`GhepiOy#2TQ2tTYt4r&h*0I)c*6{#l*fJD7?%eesjmw^0_Utd`-J3;^>TNZ( zZytQB?Y>|C>i*~c&mW(kNGyiXfzgJsgAImccz4V|WqdOjlVc2K9EM~gp>^U=J_eqj zJREg!#u#WA?5{H>%vUGCFn$QFGX!;pD0POQ5ycZUeuz>B=qO48l)RCG*pke+f2X~VI3T)A2O8IqS61)B>Gf@MUU3{ zA^NbP3O$`QOm9)E{h8Qi1`moHGQbKlL&L+Yfy7oc0K>!(eB>!;s8wfG#vP)oT_kgh zWWHk;CkynC`0oP21cgrKjBy@J=iFAyh!VGjj*tX@D!B4ib)1vN7GlL^InXJcNIbX&%%3ffa%V!bmc)40y4c(Bu#! zTAZO%*f|9wB8`xiR)TmIg{awlu>@&Mb9V{y7?~~5EUIfEFQ$FlT~b@4Y5qV&_&nFq z&URfyI)lq|=Spa9gvlN8m@%JDVZxvNKuk7cRz0Zf1F`6B#;Mlm%LcPTV8pwBCwoKYxzk0_5%?!vrB9B=Q?nQ#)#j-+Kbs-^7QOy*4DQE z?VRl}gQU>9#v+zG)(pp>pwktX3x|`%!z0DRqeSF)k)kE)<@!g&E+d^1 zAYJGZ>wkk3axHt|T>)r4JknH5rXBKC*#2oH|Hs9BV)4B+fxTZWUO;DEPm8q(!W~^# zkm401hm589emRS2%N#5NFpnfXBU=8o)}2;-N^nmv{-@ynRq;Or%xzzLQJKqLE@zwH zc@Z;GWDk}>zZI#r{v_`B73N+TorhKs%gPqFNB*FKFDDkM z8Ju>pmcS;rDC@Jc(sQ54OIQA7=RQFQ(p;!FiW=bB;rm5nAntyTRJfSVupSh3b+A^P z#>1R@tz{i9XKvcbQJ0T1yf+vt4r?{2K3}w~SU-E=dUf7uUH`D0x*p*1bYAV&$k#xE zsv00H_R!@CtU@45yOWYc%e5xZDgF*@=s+1+8zl`Fgn0MT$v4_f6ETI6^^`G&mZs4h zad`a#F?k3Q#TiWTFU1O><$iH`%K~xh{o{N?V4d?(I!jB z`op+oEsw0s#_a0&`i7#0qH8Yy`GQTP`J$mqD7J|gqQwj4LVdXqHw;dlO_H-+gbWxs z&_u}H_xw_^E@3npR=rxc9;Hf2#-zy#Xx;jag+(jNa6Mq4sj9lVx@O}hOz>DzRb4~z zP(*mun_@s|jZ#mA;qqm&x(+|ITuoknnO0*}(uCC2y1LlHKB`lKQz1OrRKl6cF=z3E|RhAQ6D2B5k29ONk=|I`=jn8 z@d(u})x;1q*nX z%OUlTYo)URTztrt?u3_Dk#zzRO=B(1-#^MW-d)sMp()V9Ipf3~iQ=xao!@z8wIqwi zsU5q{>edF2Vo!P%D?bM@F#EMu! zi5K6C7S{@v($d*amR^VxEh|g0j*u)SvmYnJtJl;cHv2zzs?@YE_sN(oa(P_Y6>U0w#QN z4bP^YLxW4K2#v|wY_)=iHhs?~cKy9RQQSI$N?VQ8oUVMF-ju#EY4e25UzN?>{Oir9 zH%;F1myOSs{juzYvir&wl|5S4RrW!du&HVD_DwI98Mn}X?3M`SpBaB2-!y3Re{Ei| z>6Nm8&HByE=C3vcZw%g;p#00+(6#}p0_)RZj)9Bdp~W#sD3U2N#goMBMR9bf;<07| zhBGiqaPUBn_8gqCsEawbs`#jYr2==b#k{dzqVY!(vuQ$6!RnxY z=njM5x@XU>+vpAlz|ycKUsxN2`ZKqV5#56Ta!0&|){!k^L|H)n!Ki;w=t?~2{snD0 z_guMQ_6u8T#Bzeuq>RbHP)>G=9YBFWr@3ik@vDeynVFe*3NdXe$(%7`1|q{un#j+Z zHVt<(X5bF@v*}ZW%~E66+(773$o=pOXH@U#tOj~iN0z6Xj5^mkR2LANND8HA)&)9!<33Z zP*jx914+J6!=G#Z(V2Em?`R|*mgd$j= zoB`Y5W)nJq09@G>Bz%v-!=F3JcU{Vcaoh#P+XbX>jJpuk-E5*;oDT4!I(I7&WxE9c z65RnlSRh4SPTV=D3#=6y_hYn`6-KRKus|0L@!Si55zMBY*UD?43BPZ?P&RwYWoQ-rquJSlE7P*7aao2dxYFBgFV zg`nuc>qRYF7S)KVP{6m4idmGbcju}XygLspHax;X-CLJ&5NhkA97NpuB!{K`we)et zBV4v93OrIT?387(gn#-A&_Fgi8lZU~8dlB`L`Ul|8=*@x(zeV_+Jd{+1YG7LWQ=wGQ@}T3bCqt*tu)Tkl1`nyU<*7^8LyJ4Pd+|G%{RpyP!b zc^Y8SvJv-aI9Efzp_VR>QCiv6$_Wb|*`$l-r_)GS+x(9$GQy%E{Mo;6k%jDmWAu9c zs8OSIwsec><>I+wTsFqY_~JQubn>9sy!++w$Fd>sYcFTl&lN2JFW2IPA?_Dq^GOu_ z0!5#^ET3-{w#uJUlgDmVfr(q?v(0n1%5Y^Gko!emgyu9FlZ{}bHJlO)Rl~Ltu%};- z*uGLc3FC_=)1Yk^tIvin*2rh8&n+hMxopDg^ro-~OLSbTEju=jiFwF6+L99$myx(2 zex&W8Bxyvp9ngizqlV`W6NZo{HtzhpZrHD%-{S6KhK;}bxj&Y>4}W>(>geo}y2iip z_UtFOY{l;t_4lVfzjEdGD*X|5&=4WB_0hwrs|J;PJ^j5=-pzD(2V}u zvwt?esCoQKLqkIqP5)|Ywr#7WKeyXmw|)Ee9Xoc^ze<;HDwlq=fA*(CBi_w=z`V76 z=$NgYL%HKKhUQ0fK2TI@&?e7*W<*Ww+C5$an-$R+VGzee)J04$HR$3a<_A490tJC< zX3bvq;AcTC#|Ld)GW7q<|8VGCAC(QYZM{EXRpQ$bmeS{bb9{EhyW`&V;R#$bZs_Wv z+k=h|HL$ruAC2I*21f8(0*9^+idgeR=yO5GgA7_<)fo4zAoz!{EW!|&9Xe}`Le9XJ zT))5MxV|U%b3^c)+)KPnqR84 ztS6^0m*!T3_s7&#_Z$Wow7k`&o&By~>Bl$4d<2ef)F$ z7Ds}7l{Zixd2iC2dH)<>5H$k~K?4VP^>5a0C;LktUGXs~w--znChRVMM`IA5pH$=2 z77v>|$?n;|qvPxe= z_UqdmUlVWSo8(bpbwN&(foBCtnANnO%x}7yI<5&^q)j}LBf5D zV$a8(c3NK?Q#+sa8Z^(OPe1(4Ti?885TBde-ep+TG1n^>1Ue$f@ziCG&r*95ED4V1 z(zfqgR?suaGNWL%u*LCQ$^51*`u+MX4sW0%JI%PSb=>ii^nISR=Ss@=weGu0%J(Jj zzc8uD5SXBUSnt)<>0{&dBa6I;oFA~0Ui<^gS3P5`iT)&dmh%*@S6cU21FCYZomPWZ zj`qG+y{A^JT^jptbZ(W~dfGau${?1;p27KpIJ5g#aU0{nG!zP@dc6rNwx@kO>7Nn% zJ{x!3v3g&`imUscb6g!i|F!4#MU=dwk0>z&Cyd*_@3R%N_U%s_*R)?_Fh!7e9FM-{ zea_K99IH#t@!uAN6`18Y36AY0h4Nec>J?iw+co*1u75}Wt-h$BMmVn7TjJe*_~S{f?;M_A5^;Ez z{BWj0Od!w68?hR;UPCouor(Xigg3&mKW)})pN%tc31oZPX9P$c+xI;R*0=1R|JqgZ z=)S9I-oS#v!g1l_H#MGd`yHPNfd%+r!<_~pdtXFBd2>@tOH6|ERh!#(Av!Q-H*^wt zNA}6F)!U9c#;sTl-WENvKYCkY%zxOLZCf0*EB3^^7PE8zxD|yd7os2aMpo;RVq=o* zhYW0Fx|o!F*1$(vrx?V@s7I2d?S_EJj75?0tMGrBNgDO3cU)m!%)2ocMiyR>wv8)1 zE_w}2QglL6^sG72?>s7QoOZr&+Mz#)M-M$CrWJ0Vc1qk*Xb4y|?f9W_hrH9aydz#2 zTCinoVU}1FA#P2|^?0|4{3yXLrW|HZ+g3b9=Y>~vhlNkbIbDw~Y2}>2dvzhJ z4(d`?Jue*6F();;X}aavD|Cl+`oiZm+cb@u4>YGV;tG>yg7CbiLF~~5AAE1};ed|= zKbq8|dEn4@^L+$yR^STWq-8r@PBgq#uXCAt^fZL^=IK}=_PSwayMsjaxC(`4+S?niz zHi>y&cwO_ca1(jId_5#)SMI1Kx+h7~NbM)#3nRJv#_iXIt%@1@l(N?QC6Ni~X$v1Ge
?$CAS92R@Tq~&>&9+~v4?sd|!@SBC&Pm;vv*;mBZ*^ePF zTOB-wO8n8Jj{_BnuagvlmfxxS4YN|WgZWT*jY)EDW17ez=3`xtW{&gzQ8~KBy5}_) z*ej#hRROxl>sKL@A~nzJUIFT)g5T;&gx7T!#0me8vo{ZHs#yQV&z78|Yq}Dk%jrUC zplKK#!G^cNumlNED3ql^XpbTw z%2H%ksHbceDDC^1q;Me%$!~U-WkPZ7SKr z18q$2fjN_3oH8jWrl?@Zg29WPowQ=nvmX}~Pgyg$YC!F?Ui2%|2MqO_25fvdxhicF zb1rCT(X@f@4cwN|ka70eXSU=I1d505)OjX1D$hRKSaKHK0Z^Ea(RDE;LzzkF>2?2K zRR2Ti8%mS>Hlc^J<_EG_A3pc&Ic3bUP09mlksY>$9ZW}2AfGkAdcngDAE6J1=Y95qzAF2>uI_}BVwpDqpibhtbGU}%H>C;hXZzSr~1HS0sphj)Z5+P5ydNqA)59GsN0 z>f`JVee$PcvisLfoL}GTaPNfTG~rcx;ncDz6_YoLyXltfF?BOTKF&U;Z<`Xdf0O>y z)T>j|z8Tbe1b39aIzM2^(Ck3JNqUU$?5m|6`m76MsF`A^XcOxPbPSlaZ%_80!lUtV z!NP2P{;k#Y=TyLw&-ELIAJzwQEX~sibZ`0wTXVafeebt5BSzg`Fk;lh1tU^h4O2%^ z6XRZ`Kbn`-dV?`6`FY9>IxsLe^DuuiFM8kWNsnHL3r_kbe$d1D!cxAJSuGr%&$TKC zWX*kf?$!B&tfRP+k1o%>Iv}koYp#9n@dVYaFhy@>^xSvexi)Xc?TWcqg*)^98qm#} zCS=W>pS)X<)%yP24RQ6#RaPVr&dh zyo46gONCNltMHvrPamd^3#Wt`)`fg&{Iw}}r$-en&h%C~HjZC1Dsdt;70Eqw3vOMV z|M^4Z(pTwI@mDGKo41&)@fYc<{3z>0J-f{nIWu>XTOe`+%4|yw8K+>o^pNi z1M&H-rBlD8znj`H<@Ds=#jMuSILu@K{(9!DecvWMGJD5iAM6nPI($pE->2R68R27x z7e)46oj80~_zr6Si2AUeYi5KVh?ubN$Kj#-Qo@YgdVbm?dsNuc;opP>t@>u_cT*2e zKQaAmo)1}@vd?4Wq0rfy|LOMaz@MjFo6+{=?Q7?_yIR!D_l}+0{ z;HQ!81BPsVZ`$%q|1W!_X(uO7&JthCYY7S75xs9{_S+bhq|fw!34C!k;raA>_Aqli zzW2qf$yevUdTAo{*8EY{3CgMQ-^_2HANEz6Vnp1l^Xe0hvI`&9Fj=kN%sCSFu`I71>-AYF!enZ!Ds#~Aq&~cCdg_*50y?vC4mOAuLAAV%PWD8^(=0z>ZoEND0 zJiUC%*TPn1y>OJhzbbV}?vz0FpsAzSiE+!BgYO?6a6crg)gJQpw&T+;PG7WdZ_*=b zpMkpbd?3SQk9dCk{&UnT`=2}f$UH7MsYT3gnuGBiC~%$^)t8v2?3>+q=Z*pN}7>m!avG=(VYVk5FbKZ;x&Qlu{r zJs%Nypj-G0q5q0ZUeicFy>C+XO5xGxXhVml@23+(|0lF=_+MfF_;jZKuFx$x-B-`0 zx~=&rd~wL?;d>+6!#YEru#C+f7n&cwA@tYKo~v_4d>CpP{atv^HKUOp&qLXLPehCe zeKu@i*xI~^eP0c)5AC44h>@2@JQL7rpf^5wI=w|uZ5=dl1UDvbg76XjdE9sWmrJf@ zzrOYJsWr^O;iH@LC%-$*IDO3sdvN#GK1#dpaKeqP;Wt3t*kpdU%51S z-e>x&^ONdIKm2icR%^qp&o6$RaFw~p-;N)2@k?qqec7=Zpb3E~6_NiV8#fZDuee!!B{F#=zBxl--)2C0r zv0zlu1jW?2DZ@XD|6=%2*1amLb!yU#-p7^gwDz~t{BBXB#mD{HsrT&A~jYXC1RP5GQsp-=fys>n~>KSL|8w$4y9{+mP@h8qusf7k=Id#1M z&AfK%)K@oXL*dIIKZpFHA!NBCGa$M>L~XeKh}CXxXY|nyYb&RlKen z-&+_R@+IAXcQo}*I?n$5!6&PJ#sXpwQMXP_oRRqRl;l-?G%v-?;okROPOXVs|Kt-p zp5C`O>5;N)aw&zx=byA@2orKn2q%T~ujY?lAgmF#2|o#Ug#LvuXJg8JHUQI@?IAAA zK0q~0abGyDJjLIi9I#}}<`tWF)0f6xM>x>0ctrWUz<}UP?^2Z;97IoIzM*!{@6nt! zIe*H+sh>~XG36xRHl_Q8cgC0KOUGKquO4BGJ2?KN{*-W8d1c&C(He0$Wo;Gm*@qkIE<6MZfi1KS7UZn~XLEgC+4 z3^$`!LE_BBo!N)EbN*XOJDAi9sdH!03#n3i1=T{|V^|~3mWqpHdNci*vU!JvQ~afO zd22Ui?g#G*<@4UZP&NfC%KS5Q+Z0s#TM#vynJ+9%Sjw#yHc=gZK}A_}tLG8kVdX&F zbKDQzxTMj&Q_iP#Fwflkh+d)GJE|r4xx+z41s^;HkPf1$SB5G_=8Vdj@XRLqd>$Sz zpx?A+n=$1NSVMsFGW^;nyJ z!`Q9kw(GweTR-7(p8ib6s6pcgj~>_p4ZU^3^>In{z0;mxvMJ~I4m!}2 zFmS-Q^6`P5m$Ro%m@y!Hf5w2)3EeKHOx8^qqRJlhvi{BN3cY9Ysi|2%OfNU=-?Reu9Nsp{xLN=H^fv!s^+hUmUt?mTx6>I8L!X6>L?0Av)j5UvU7pJPIk-&Whqq_#ei@P(70}^&k#&6uc->IusO~A7JQ*rq{w7C?_g>2Ua)XQL7P# zGC!CSU}_WOp6)0<^M1P1SmN$MRLrw%0jD#ZUMtZ=Wci8}DGkjyqTu`2X^QTurYA4j zf?x<4uu} z)~+OW>^h?#xv=OWTmp>#DV!W+ipx)6=Y_MI zTgC(VE^mu2nFD~1eBR0yM+2YmxfstI!nVLamf8a70QX5Htd+!a%1Xfv2LCPE>5axl z5s0@k1oc77#}oH?6z%n-7lF%(R@znqD>`eOSWUdkMQon%w86>$#Vwu#81eJBcw=NI z?`e<|4A-4fSdBlAk^=b_e;)XPN$myrA0U_POv7^&K8h!uDiLQ!;9$viyMzZ>f7?F*MEhTf}rzu!NK=~ z4&2`0&Alj?VP-bnJ$rq)Rt-QDH%K2zJtx&`FRXC7^PDQkSwJ zMFr#Jp69l$z>CaPd-ArGtk=q(jr>|^NkB03b4d_Ade+8wt#~pC4a!Km%2NaViQrr70ST^W|FYC+3yNvnB=ninU?Zy{WjBB z4qXMGSa>as*k*c(tD@YawwV~>{X+A$w1XpMWe~&nr+JZK6_}wYLvThkcr;GBfzYDG zvXH`}LgJpl@`i&hk|NOQZ%Z?d1k4jn3f{fkMNkTidngRiiSlSof{x8I$2b&N7#Qq7 z;%yUW(Y$fuv6nbqg5xF5IME<%$J5N4T~BX%pN{1;3ddMH^-vnc=uY^;nJ9D>*(P8f zK^iQlVaPt=XjG=q8(oP~FG5NM5JRb_cNRoo(skMyOJYp`zdVF5TfT&EX;gw7ezLui z#t$LCVZ_x!xW8Sc7vy~?0m z2`?#O;OUl^fq#&*2e!suF6j=)S<6YKVV#Fya*$~e2eK+X0eAYjoc8^NoRM+=lar%n zQby41%=>dW+pPQlZYrAo-rkS**$q__nUhgyo(T+g+It^pCp=L)- zFztSJ$DXk}eEW3J!9l|IR^jDVVf)35Tc%%?by)ixzbcLE?RwA!OsgQClv{jF$UaF*3v`r# z(%U&x3EvU~U$-YLkr)8M?swrF;9f~tO5LX@OH)lbE3u}v?6Qh4*p_nai!pYHIuX|Y z0z4@LuX1{fTMi~`n^|r938?(3rGh0ajLMuts@vWQhrS_~8jhlzzZ^fXDFL#kY|j_0 zu+9U=MpHR!@+B9{-QX5MTYCy^7ps^$$*J0`#HdMHg)K>9F!4E*-zHPa6)cUzpsqQp z%-ZYrz=5@zjD?|YkU-USs$vmmh}}sLmTC{e4W6Mfb2&6-AqR&7_&Rv~HS#PmcJ(PI80V3*emdRySnq)--HQ28-VFL*Pbx0>)@CJcBVv|4knZ{dUW zT~qNZWth7Q4{CpB@x+F0Cw_k3r#1!~5PqfX4=ZXgZ7TLtXn?T;q>$a+lFN%$6&fk? zWp!{Lfq&z7O0iOfPVFPVgk6k6!%oBfUEBJU${A%;78=($VfmyFhzd zCh?9*yk{C%Z^|_3@yW7L+ToYs3AJ!L&-Ocu2On+4~!Ny52R; zcdaxox6{U5u2aNUs&GD;;ae!hWE9?KKu|x>bxl zVU^MzU@GR}P45*FFo3~L&<$8e-j{c$$d*&vlIlV*mH0h|!dk&v>u6y|)20?yB&1b^ z1S`D@&%0}XhlF6+0||8xumir=BCZ|6fn;@9s%;8DXdY1RQJb0T3h_Wf{iou2j^tu<#ug_tm{FzW5T^vGb2tUz=nNJbklP#)8m> zy{D*#UVDQzJ`!^F*gH^DiCnO>m(Uo+GFeUfLzP zR<3Pj?XpF*OtC+(RNLDv8{x<`gj+k5bG>VM&$ZIB%5{pYq^HSa(Ul~>mJ*y>jp3@^ zSSF_lcCv2cj@jr7VhI;ph1yo(l^X@y_Q<+iyL{rbld+t3o$|;9X2BVSbblxM`487A zcqb|foM5WZ2p}s-B*MFcW~I2=8>}2vdxbSBv4-%qmsqr+_8JTDCocn#H`pVZ6XG>5 z-{56Rhi-IDB$L)iyCxFP8PID+EfWzLOc5Arrk29GNw1~gH`yomO;^cu%2MK*HJ!1{ zD!_UQ4=gf#6@RE8&2-E zE=Gb-J0o${SUXotT@$vTm7-Ebc45=@e5~13dkG=KYD;>U&fOMy&910R!BAGCD8P&& znSyHXtQWE0g3~Taq{xJEXX@PJkKlC@aBRum(pLOcRCC8`a-=d%eGnABxjrj|0!He zy@-N=1bXm}p58!D9&V{5rVm-VpW@*#Ys%tHgL!w`zf7s%mPYdOBzQteFI)Y~bT7c! z^Yq+0=`PAU{ZXBC)7E&pv`$I@OF~J}#1~m9CA6GYw)~=W{Gx>H65}|HiyRDYo;;MV z2%pvoSrV%HMQJ*%#C0U^IHr^}KBfR;Ee3v|hSdEvS^Vbfo=ynHQTvIntQ-V?FTaM( z*Heah`pdNFh=#^Qmm(WUL%=^NkpWMMd+}4mz4$41BoEs8XJV;4sf1$P2^F1Aqa(=1n5=Fupbksr#|ejusu?D_ zn2xdd!TO_?LajPi(^{I-FxKYscbX8#5@w3AJ8@)gUe4!9hfP^Cnkl3M?^YS^3srIg)G(nE;my&N9C1NCqPefrkj}D)z9#~t(x?ee9Nq05j$N)=|tCU^O63U8N=(8Q<4_SA?%F2TW91aAb8YWKzi1QRS7(R4#G zb%}Bodz)Z{RD*@a3T5L&nYVLw(Pr8&mk2wQuL*pu9UDW86bLq5?Ot~P{X~Olm?(u- zQ4l0#e^?InT%{GI z;14aq727FSQ$-UcnhWQcJ89DNI~XRmM{36SsHT7={ohX>Abj-$96d22Wfto*@ZrS( zM5}7|*9Re55vn7=50=mz;JDWz^m^v?An^U(AeeewYYH+mTRXGBU6^>g&1jzBgF&0EPgo>E$sWdyJRQk%CPT`sD*4!k=~;Y5-c zs=7e?{-8s^BjK)RyPrPvZ@DAiuCiD~njsstuoCFZV+GMV$IqV>|27eKCpNRrH?UFs z8{V@K@DcJ%qu7G>*B)~`2d?@v-67K78(l(qq6nIvNNAB`N zm=0*G7i7b{{pg1}g)SjgtE4|gTZbCbid`jDTY;@XxgO5xpNsuNgiKnQf@0e0 z#IRtjbBZZo78}c>c_WJlc>rwrab;yEoPC}BKt=zu(UwRosIzUX1%q8{1gi<+&)6VA z`Y;NL+IUu-2i^%e91>2{Y^M3i$hCBR>%|!FDLUlx$psVN8SY zT7zLg0}hG6sOhv=4R18qW$y^GSRost29Bgv1++m?iHZOI+y*l9-(S#RnJq$wvs2q5 z>mtl-`Sox#^Gd^0p4Wan)8PAi&hy`YXBz(L`Om)zo(Z0Q(z4xS-DeuU`f=xuGYwVW zoduQmDhwc7f^HvVyX4K{YeXRMoEM(_1u{Vmcs1;&^B5rFMxtKWv%3Dyc@`a6`TdZi zgFR!9jy<~F^WO2!BZ}|)elIsJIx^VvE0pG2fA}vEHv6QIeGKJvMZWNxu;^DJfy}xo zM4$Y3{D;2@qkbhUA}f@6$n&Pl-pVttC!+ob$NzPr+sSSxn@-$6p*V@o2)0C8VsM-Z zR-3iGXfy*fM6CS`dS~I$eo!-YA#j`$tX7ic=swW?`CeTVb&b-h+5+zQ#BIYLM_fbX zekX@`Wp(Mz+DcaHM%J*OJm_5){iCf}zY z@M|Ejb9Ri)H96o)V~7&f731gB5m=>vkb31r7)-FO#HoX#fTZy-asW9S2CPGW8Hh9R z;GSLixf-USLHqtm4+bW`x4@F`#Y+s}QG+HBMTB?0HZ-_@K@t&#AtSWrYLue{`qz0x z;d2t_vPP$KQW$2NtLZGwfu~hN_rTn15?xIv^3AN_gT01#_6pB_FTC|VtRY174C!iE zXECTWRu<5Hdl30CTKkwy>_pD;M{NQB12#5i;HHDG>y}nqPH8}tt zOA#RCX)h9_S*Gu$&}DgMu4<$c2R1>w0`UW>FMsc9%6yd0c?2_KY1)=kCIw+S zy_5fV9Ti=rnRmT+*Fj@N!z#27bq*qp$|ZnB6i6Yp=^Rvf7&=(N88p=@7D(ZUgwD?! zDe?ELb_QdL;8a#Yjpg*=V`jj?Mzf58X%z{u;PpS>Yrh7X!SB@*Ec)2b zXE?nR*jcJd4fSUfIo`%?hoNrcy)o=KQJg*LviXrO;}_%ErpHVkv*bg z1&R-jjEd{kJDF04_KfSD`h<@1kBEgk@1RU7K%3a_$)|?usi2<81E0#y$)$p0`(!Lem1b-!XXOjZc%i0Y>_`mi>==5FVvtX|)hU{RpSP6Th zk-~6j(DzE5igvTHg2qDn7noiPNET)eE&2V;4T7c++C!1K=m>cl43Xlb#{wDEkm2 zg{}*cLd#EBL9DE@@?^d%U(%Obtgx&PA=@fpW0)u>I^Mx9!3Ntz7_C$YdtlCQK+aH! z0}HBjSwS!ciP+`@XNfqpPX?g7fEgl@eV z_HY;~u{+z4B?+tc8b?-v%IEQ*E zX{M|6*c+@A;N@wn-6@jkj1shN7AQpNwwyXz?q==Gy!i(Em{XyTox!1Z%crv_UP=ZM z2$QIQMuU)LveE(eLUYvL#i2q&$PbWj)hC-sb2}_nk^`IJJql-Uhnbh+0l%3i@D~Do zx(i^pL7jcPwwbp_p!q`a4_1vUhnS9Jut}wuqF~{Pgrfrc?ur3t=E|wap=_$$O-)K{ zGwuhetoVllqY6qg)0?c=@+K>sZGbZUuH6qT64(>Ngr5s_y23&TLp3wlmKm&L28)C6 zX0YyxAH1q=oqY}ggRz?-(h%ZG`G_n1n7HmHB=hvw2W6#p5r}*fs17Qqw~xaZWPlFB zycQMHAVbhsd1pUP9-?Sa=I4Vj* zm`^Dj4*LI_AjW|7!kUWr^3M*9sy-#_rFlR4z>CS8 z;bnf#f-CjMF!pk#hC@I-_);Z7?x7PvE6D~8{~6I9Bs@pBR1y&dr3F+Tu;5lvItAD% z`NVaYZI^%LO-WMVket0FmzM!05xhMNy!4q9qL6Tsl#Ji3lVqfI$G{_m#0$(jR&cvW zF0(?++r>{8);(+h4$Eez$AsczqV`M&Yaf8aNwij9wH_*b+Q`iQM!+Lh1 zYm^id8p133fgo(4UBMdvl;DkINtOd}8wq~rpIDyzH7@0(Dd=ZQK4=G7TgcAZj8jmg z3U#cLQ9}qPi|Ym&io-N;i5W1X4uo>FKZ*zhKut5XAlwPffH+nyATdKwEJ5h5BceBr zK?SPWDH6+l26`#*BrEmz!k$Fi#FpT=yd)lT5;~@^G zgh!l^cUsh5%WP1!5tQE%Mx1db5M;*K;0+;Zy;u(wUO3|g%&D$j#iewtUB!uLQh$&k z>Sy9esWezl`6)T_kd8*?m+f@)Dh|o&Lgg_SARpHS$RE_D$=P)g&UwW0J&TBr=_s5q zQK`V2Qtm}?0=cvh%4+@>_wzp!Er@njF}M3O=q;SA`_rF+IMKFV$4GD4!%=@YkjYPP z1kHQZu?l)7$2!=yFJ0OD0|`X}7n-l;$s8V3Z2qIitJn9H5KDY84K=s^o5-G&v0Y9^8OA zfCKSDWJQCAm!jP>P6J9;POdPhxqxU7(Hb(6?2nA=MR3Q_DbOofsWmY;=rZgVJR)r! zhqfASpAJ;pp`&Xl<{ZWF23y4=LCY$l;&=aa8jBHuN$hG`%F zx_@|QTCi;JCdfg8Y$O;;5@h}7?5d*8f-9yw4Dp3hhdYb^Fq&NE(`?LEe~OVK~P`#Niep-lJiA;Fwq(yduMC)fq&V zW~dnQT{)v!OAZbvS_`%Sgfhhyqw9riiG-kR6ej;lCPMf!;iWUKCL^^BqRz#Fjb>KZ zgVMd6+#qBmX`X-)kOGVK!Wqcw@oonZ?-fYx?2a(b@vU%h?r*(;Z^;=uCy;%E3Ne{C zk(6_);4jC4e_!uF)O|!LojozcyV;0Vt*@-8OObTLF0(zrT!oU{&KR1Gbh5wjw9ZG(ZD4+OPDc6!&8b_ znL15oQU>(TqLm?jWdTI^yA2&@JV{^zVN8d82kK;)a@SY=K`L{Kf_#w_ z5T1(w1W_YRm>799;y?fb&k2?1okObD>oPqDK?fqw2?x)~sWmY0CZIN@nYWEJQiciV zg`?-}axb`B3i7!wAB=g7VcbxcSDq{_WV;;pbB$0 zB*SC$hevX%@mNxzr@t3Tb(2W~){t?Iz&TO4d=8Q$0LU}&=c=OXC}}9X`Sp{DP2A;U+bJ5sWNIVBu6a%{( zOgE0_VsJc{U2B{OzXn+Q4bLsR&v#PV_^}0MZ?m~NKXj8P5mok*vQVHxhRxBK){?;E zhLdCMX*g4d$fS92+O0&tnu7VW1I{_wBU0OnVB(V#WH6ueBw-`~DNZtcgJ8do2F8e2 zBaAFJqj>m1l1@vjO7r>BXx~pg2cCvlCVTSQ_xqnS&JsPZ%Zx`930A^zG#h-n+Ti8| zf0Gg%sRj=&&kR}NDbPxErbv8uhQK+E_GqNBaG^biw5S@i9MT@VgHK|wcnXX2 zN6E3;X5}@H)r>RKZk3iTf1Tg6?aSKTj_=}p!We0>E z=g+P_FDA}fc8CPmofkd(Wu>QHX0&APc8Jy9Gp#n3i!{z0V-yx}+Gso>i1RaZoK71Y;Ivepd^C+D2P=H>Vh}9c|T6qC#jQbcqu@Dk_5OuEoJup(qBTR?1#-i6pcJHD$VD zs{Np5h*9ee+y(c(^OhLkN-)P-BQenau>FBj0?=~vMNG@u3zF*49}RU{^Huov$xxI7 z3rL1F+@l~;7v$*&hNq7hGJl2I^>PWMpxKvaiCBKNL)0!LWM;MJ~UR5NQeP|zs%cyFQU{m+G3}y5eD-`5VRnS z3qOntW!D^VoxmC8aYEHaXjf2pH`fN8)-_lPM-3Z*w85?uDQ%V$MB*MS62_J^MPyV# z0vjGEFyTQ0qYlEWLbXbY5&|iRTSOLDa(*f{ATXR_G!YyZ5Cu7i-)M!uB?9V=IBTuy zH^Y_RthvRM^%=t}zgblXK-Ej8uMyn-%^ti?si0-3>dO25z^(-o(A`k{+coSwIpXPX z2BH*tBl^%=3b=!6duN4{tJus{Y~d=la$*VP-T}83w*v*yoi#hj>i`sWej0zWQ+9`CNLh&XfT^yTN#kruW{pn(gOxAkh@MXjS*#(lq)o4h& zuMET ztdvl_KoM08Z_%mvD}M?fFZj5lVPE zI!2RD5jt*1ifBY2)e$m5cGdtAq_&_jtXZ09*DZI^D>c3oy^H!UB9B`K&(%r z_#ZDyu>XZd!yi_`7!F(!Cr_D*o`O3o<2>a0)z`tk9w7sYhtiVtSnVfQ8cs!2)DO?h7&{E+rRkNmuuVGSFTvGvc281 zW{su2{mhy3=g*uud-mM9_Vz7Xx4GKew{QIpzjNl!o8R6(d-mIJx3|xlMSkCYd-iPd zJ8M>Z`<**??>_#$d-u+r_IBTId;6b%x_9i_xqEkedu{FR-5-4T%dbEGeC$|bV^h?=R+&V}sVZ_$KRGzclB&N_6YT7XVcSNONv8%k~ zjcmc*3*t9xcJ7sW*PG2!C`kx@b|qnUnaa-$Lw~pZ37Jk) z$Cv{uUjc0J2(A413S+zB;iQ<#c~=+`2TJzF6$WqzRKDOXfva40h^bN`uL7XoloL}_ z@@tjbq^RaxS?m6csL;nW50L`V=A0`G`7`K9O-gwXn6xx#A)fGPoqeI3h>$eCx4t-| zD=Wbp-;g3~>a0cA@Q#F=DOQ3Sq6<}S^tLdF0BcrR>E&whv^T2$5H@%Hd&w1^st6DI zheJ)vPrDgLUD!YDc7;6~YfCd@eu`wsK$R(9lWE+w`XCix z0OjzlLCvuIyZuPaU6QPAbjXP z?DiqAu&JbKfBFNNPy7LThi12;e{Lut3u8d2>?LFc!XkH##kS5wduan!jxz829FE9z z-Ub!g=UushC^UR2+UEF)&4o0j!b*hI2a5s58@Zv#f&>>NcqG3A)qz4L;uU2tMrEW> zo7xYblsX0Ft)dK|k_BQjSs-d#SufW}W!~J(PN%#Kgrk-v3tRx>*ur8pwc*(o-?Lx> zg7Dl8{CZa(6k~(ep_^q+^Njg#xWwJ9O2;vVBdRyyh{_t zA(r<2z!zb-6Upjq{|6cSPzHEsKo_?ZOqdzMD-fQ^TS_;^)wD4erVwl`6AoU6X}oZw z?~W|@-sKyEDfiz92loG?FR&b^Fy6iZ;=;+!45FP89LI^DLigP*N{5pm!m*1W#lCQ4}TPKw)Db4iK) zfKKnJv1Aj6+TEQww!1~q{8Nx+M+h(X zg2rVDe=LOTgmh|6Av|6q=1pXUnO_kg(>THW;GfW*fhNGh1pVP9yopVV`J6+6foiyn z4Hv3vvO6-Lro>L{s;jmAXX-4{f#SMc$}z5J3q$Ls@8m zjNGOZO0=RjrUjEew#CcjNUb8-jVF(XkzyzoFtX!T8VAot=-T43FX0K<7mkFLm;f0> zcANT{d)h|!N|PcQgmSq4m;y;dM8Hrk8)nMB>)WzbVOuYsBXJ94NOR>f_VES=;tf7F zKR>6^5y%@($#&N8u1qL{FjLM2cHoQ>z?+uvcnTp9udai@kKzkNf^p(%qN;{h5BX#8 z&rpy5Y68K+r@+0S0ZJ$Z_6Pg(*l$jBg#qrbWos}9%=-Wl1^8{Ws%yWNCB{kTi zjt_I3P~w2q7|#y5ho?@C^fX9`gw7B1(fO2NpmmXqy9bHs!MI~^MNA9>84y?+4Igpg z+g2+}LKF!x!h0a6P+F23C8DA1p$%`f!ZgAOZ?#^#W>+_qK;J`c^d)pPR_tJ1UJX}; zgY}hq_;FbVgu2Q{sH@1st$ZXz<@ak^H$nx3!uNR#_Z12o;<;8rRuvTVm({T4ODw>F zgzXz#2K}wY!(xMZmZl2pn&r0kj!r(9FX4a`oc3_H1Tt+8{_dtB2O8 z?U_cn{t63j)&AbPf%8xj-q$3Flqw*|TM)#pPRd)v&|8^z8*vypeb=?;saxI>hTQU& zAfN<}lrZqt;}U)ljX1;|?mqzlEd{Sga5B>s8{x;4muI8Q0a$|If&hY~m;7)+Sb;I2 z=n|D|M9Kl}#cO;Xzjlqh4hT%XcdT5yCOYQ8y%6uEgi7AjP49h0rQ;CxSJ)n4w7=%q z0;R3(f&7MP3vW6^_9R5;jjhI8#@oJ^S@tpQ;_c61R_x-T*i?C9-@= zPi{Bv!rRBZxlj_8WN4Ut#caXGa3SiBu;{K(a8Iz@gJS3*(GMCsjUC2E#s@WZyzNd3 z+-6(qc$|NsESK5FI#33^xSZCnp!A|pbi0zOcGI1*|5`@xraINCwX9xT!RePP@YH&{ zl9QS%RnnRD|0@5?0&gJm7oS^Je~K-vfOv|q{B~u9)XSa(4V<>J$odUng<^9TPa4uo zQdYihy(g(Wf|OF3Yu$~yB*Ct*R!AHySF0=6kun01g``%ZQM*jEUJ|Q1WudrLw=t*F zNxnbfn~HB9zKikQgKwd&Rqm$yBG37Go^yYmvuB=jNS<>>o^yMiGZ)5alxzL6a-BU1 zW!LQD-J5TlC_Ok-UxGN$tr;~zq^K+ck#LuKyv^9c%e~AE38%aS1Q*_OYJ%z zJe6#o^W+ifLACp*I~XF1rAu}VP)u53Uu;t7F_ic4Eqi#!9zL)7Xf4bG_O&KX@4kOW z*mzqs%)Uzp1qJ#m1A_h3Y@jMo8Gx*NdBViN3vh>?VLx>Bl!B;Zp+F%=K;JmRm1@H6;fRp?1umTZo^Z5+1eq$JjAyA z&Aj4{)FPTTgGH5;LiHVC-rWs%RvaWJLLA_W?|Af*u2Qw)0PJp%j94UqhW#*kx|uiL zL7t$N!+gzQ_!CG0))46uG?RZdye+fB z={A##$8>jWQ@SEkg-y3N?ci6qc~aJFP}w^vescF^o=|5n ziGk;<9q(VU$D+tiWW(dz^0>yGD7MDQw>WtKt#a(+fp4jWK)aI%r11aN;mxFi9FU@s zwf3k=)~c04aSg!L&wHPb0yVzTwmeubZhUhY&J$1JwbSKU2e9wsjZX1#^&E!Mos>lY zM1?%bWZ*x3=Kc)66W(X;FFHkcCGK8+VcN?>20S}+QqJ=kri^FtQnt6>dHX~1T~fLP zcdIK_uP0w}N3N>*?Y*^v`+ol(dSP?>({aMV_F>W5&_~dkM?at_+r!mUG@g#caBWU| zOt@;oBkP<3)%XrWqLz8kFKUN2?|~3HNBi!Bo|mG#oMQQ6F^wZ>P&pZeZ9HxEn zAR;hMoAgkt`9N!U*gg0K?K=-+Li=jxKa2_PSDc!fTEwMt##DsR_#&*?q(a~%0|K*zK60I>wSIi~pO2Uotsl{A;YMgXH8h|fl1T`#9>Qj`Q#FfUU z4=&Pk8O4Lsi&AyQKGbV3J{QsbvxpNH|LC`&Z|^VHy=(;KERKmU5@NX0sMPeL3{IC0 zAd>nREYxpWX!#H8vd#kMWZzBR>PuB$9w^W{2YczkiHF{TLc#{4_&G;UhS zw8tq2ZQnl97#>xGgky@v6pulf#(_p%Nh(Jvsub%KYmLR>#>C`QB#00Hy8)!cRKUxn zquP>qs;XD7s+7v;FD*r>sela)N#{6kZ1q%_9D5We8so!@1B%j%)6vZ0^pe3GWsQro z#`RTvU8F76YKyd5u4Hih05ksP4ltX|6w;=mg^5K;8C*t55>?atwdi&IYStUWi-h9% z)EKl1i$^KmgQp*yQPc&;#lQag>uzgJ?{#a9+M<}^_&)LRNEXkPa7BGkOld~Cw`Ekp zn{SP*9N=ud`3C{Igfqq$#h1n>^(jt`F9{!K9uPtm#wW)o#V6vMj8aJWf87g7LL$D& zU0)LZulrwn!-+??5O&7L!F&g{oma_hb6y1x6~y9?f3FmJ)*YjKaI zTA?^*X;gAjRF9~lRE~@1xZ0Aa^oI&MOO{>b?@WzI`>VoPwpXs}#Pd1mG&81?5Oym0J za5*`sqBy>kQwD@b#h0WaBnE}|NGwTBEXAHNZA@|rTxO?H$4;ERc=PTqc*y;F`R47~ ztv{STf4%juy>KH-2e(>E@}f6kB`GDD2O@}Ak~^bRhXPWI!c(UtX_5=Me+N`CleA(F z#P|Xw+|nM}$l~xG+Ms~QrQt#hkWiY~BUCdb2swmZseB4m+1QIe9`?&bW7v^jvhRCaM9o;`XX-0;F64tjG~MsgAvXs zNiRz3ld&W{-I%_lPf03OY<3op9qXisZ}^(e^7HebdG(p~Uw`$r@$2Rd2?y4%U2k0f zBLc3?-x@c6>o8i@Rc?Iq&3{f>Tg-6)DZVH?J~cGH4}PQKQ~xupjqejFB;yxPeZP1b zK+>d##_Kfk{UhVkwMiL~Ng3fu8KLnRug0eb#K$j*i80132`vd<0(ydfV=A|#e_{;& zjs3YL1C!(NZyZ>P_7o4MUVXtp{-dH^#b?q>W5|C@%p`oKyfT*j$Hz~(di82wlonnX zjvstVB9}xKM&bvbCCTwU$bVsS@{;6IP{Lx}Qm!~)=@dQURyl^r4 zTyw&WcNWNZ?)^TX-_p=N2KTBufEaz@CPqk6MQ)j6ksDso_>RZZ&vrgCGon1?*kEq$y0;+%-L%mAnQ{$;T zDw`TgWl#gC-ju*avk}Z5rkp-OO~LpS^jcj2UN@-Kg(j*VUlSQ6hZhj4deRD39T=(% z#r6`VI)E#$_~Kt?7zZq{8JJgn`swP`tJiox7Vqb?|NXI8)~t?*jO+%*O!po=qN1Z? zVz3It;>9_*;upgeYMcLlUQ|dG%AIU*Y;06w(i;>$vBQQfZmuhAFRY^kZ0@Aw_Kps5 zj+PIO9kzJ!;#i)F8Me6nBZ`9j*w)_OR=0n~6N45n?(F3G;NZm{wI(-WPHwL2(2Ka&=%}`i zur!^P1B`$zmREJ_Mrl4CN>O#qot+&W?ag}YFvOG3pxz0PZIN3B82B7TMV)gf6@EM9 zxpt=z7hN#n`{XoF5SSs>~Cj>77n&l1@ zR3{2L)K5OKPdxDigkschhI|~=-lie-HP; z53OkF>>NU*`eAVbst)1-2x%`cGpBR$u%NoS=H}q_O$f#WQH2d1*8qwJDa1KU&*{) zvy{vRgF=)gp@D1;)yj5QS1cmtzQm<)M9gH*=g7q39+M3>)ley?hpae#1(>*PsMO>3 zILyp!PKPrQRGA3(u>=NY!t9l2&#`!KXHGI%qa&FKGQTT{#!!8)i?`Q7q8)JwquK6g zi%HNI)WS$_3>;7_w`9qzfXQq&UL~E%icG`5C7@{MTE$2(d+pk9H7(6P+iAGh2$ewj zu)11PsnLMhv(^M*5<7;$i6h5*Wry1Zywh)UyC5G}0ZAqkb>S16upI~C&5l4Uj}H<) z91i2in4)RZWC5L1nXfaMNLY@?Vv>Y?T>z! z4S%abs7%VKX~u%-U@#PFxeKWr2>3-50dNt(N?l^(>Lvt*!Jt%E&+R^u4Du3D@hBMx zyWKCw6jUI~j;<~QjO5-tDyqaNzJ7h`qNYs@KXtbR=bDQ}MJdO$;XQk(No=^ccUXhH zI?Uwv3XquwX~1S;<#7B+Y5bTANTfi67GIczQ279KN%6N=ZU3j%4bGaZcd8W(&k)kTRc7^mfqE zwRo`$Nl7TQWqFw-#Yxa{iSviM=IMi>A^XH<0xg-`)wLlfFv(1;m%4-r0%f{rgT87it-Q5a0n3j z(HE#=*_gb!uKst|aw@CY(6V94urG_g;#?eL$ z!5}@f03=*4##mmGX%wJ{B2BXe#AN`!Zuy;xp~Av`c$*~*^Marq2I9^v6`(R2@7mtg zh4wUV@9O5de!8DK+r7unz9q#K&5JMJ+LoKm6Qb<4#lGYk)ocTOP-y(RMsG7^br5Wk23*EpH zV{w^vkO!K}8_`Q155f2Jpk0ZBKYw=;eGPAY z7@DtH4mw4NNN~=q#H?lqfJ!7z?EYIPX5~a&>5)AL4lLZacYo?)XXkj@-Z^#cS~iks z?wXpuc0Fp}cJ2y7`2JaSJ$0DpE`r#EApk#aHqUo5aq8lwFaCJq#MlY%0_SqSUsxi` zQOWD=6#c<>&D+wC91g^C*=#ZxP9{t*Xql`Mj~dKgDYn>P#)!iDB0B)7CD@7GR+T3C zIK<^WaKN>1|DNITNF)vVY*un*LC^XrWK%#t=dy7zBYF*n;I671o)|YeYPLQkxjpGW zR<&HxFeX<%+Hz@1Fe1Wdk)ydB!Zz7)myzU6fg#2vc>)A~@IQl?e7XNwHs*s<0iYoO zO3DAAMV=b?A2-rW6mRf6b}YaWF8>cOXEOr?0p?J+iC%IB6T{R_MhyE*X zfm10b!=lL2ti+hn3qdiXW*Fc3#LAUk-JpR(%PW8ASLB){FbS_B!~Gm}ojG$fok#@J z@OyY)j>%$iI`w%*^D@Vrii$Zl!Rxfmo_!m7yBI$cV|QZVJ%9e}5=RIt-X=u1n4hlf zTCqrsscJp^9AhF%kzeRmv}wvSF^I$2Bx*rDxdG}u+S4J+zsstsc?tRFAs<`{0u9k$ zl~1v33P%uQgWS2+wI3g*&&A^b*hhmk=q$06uw>-u*I#`DKb8nuY}UPO%&CoO+BL*i zf*{m>AHg(*#SB$ab&T#*Y6wr3)%XMf`Ju~C^uU1`hu+xq=pFT5ESK$ek0%hoonbIv z$^rn7$6jJ`mN-q!`hUvD@bZ~q1@gtpB=;b#aBu~)IW(I}!K>iRgf%*9D#Kbm5~e&! znDUfD)DWH%DZ*X9(*k7%yxjj_g$F95111SD+984&Q2p?&fUX}GE^R$D@77iOu6|X> z|KjDBU;gHsCDn!eSNryTI&a?9bA|lYL+c;@&7o(v7V<(XK}0CzZ%(&efEV6ARlNMb zrcIk3IMc7^W1^m#EKFRRN~Ipk=W*2~(zC*F+j)qk>{2wHcel6}x4ERU6l9hMxAe$y zl@=;_$R%@SGx1V5nM=(mucjbfENBZ519B!FnRuBkT0k@L5vV1VD(1nA{uT4mwq!E7 zO)BQI$I+kT*iC&V z_Us2m`Y?wZ@=IM()zdThr7m1iM?bj1AN>W~kS98qLW7I^2tRs!cQFtA2Q%x79#6)~ zX3*>Hbrs7K_nG{WxfBy&!+A)hPOIvr8|@)%Y(^edBtZa$;!L%>#mEeMC?fJF2%R|m zf7c86LW*+OgqaBl%$LGJ<)KiH4=NmJb%N#;8>A6Jn;6pIr4xuoaYQJMDOphhZVYEJ zMj+CXg2pjk3}drl31c*tmX}l9S9sr;A@4wWwPrD?r!xEkAnn%uaXP0Z^#2HH;L$34 zlL?>Eee9ty{Dcm0(q0ACn=MWjhL1L4o{{Azt{P1)__x(hW4`}d9URk=f^)7lN;(Nv0C(W&=bt7?CGzrNn6fzJo3B~sE`Hk> ze6f~UTw-qUfsg4r$|}8iD3qhHh(Jjs`k#LWqF0pd+fhz47&J6MD+K<$GQB=xqkx3t z3w(3|qiOjIs==_Zssb~krd`D17wmK>l$TKjfgBDdi8s$+okiz~-Udm}UJwYMAN8`~Xu4GO0OfnkBAujP+!H?Fx=ue?}8u}US?CeyO#K2Q{h zRSl&><2!d=#@-zMDOzuDqPKS-q2ZLb`0~(D@6bC24RqAfgrZlZfsR*&S&joo4iwQO zF9V7c&?g>z=taiZ*A6pO~2HCULhDnA9@koDqyN&+$WJxASl!74=FaJ zjYeFj;33ED02?J7uq{FQo*3%wC4E)DI03d>= z?HJlq()r-1%b#hz+}miXB3DsKT~E`$`GB+A`~Dl8VC+9SxsrTs|J;=aqVJl)r@)xd zghQT}1RaeB;!EQ}6`~3sugvEQ5tx2<{aXUYD@-Kfq7Nac0cc*M;rc)B&13YW1Uok@ zn1H0pEbvIl^78uf>GE=`$@KQuU*qlTeNHca&b~+{15?OE zJ$G(sXwQN8j>f;Ib%drG9Y2kPh1-qV<;PBpVKB&5b=_0@)o-V#uU^HzF$Wr^R6UMd zKv0iL0*08Wqg7+$aP2#zYVT31-1|MJq( zcfNuCO?`cb@$2i0L?T!uMk2ZuVI<^17bXoZ9V}1(^i*40r_39m9z!5xcGxN_D+x=V zg23cSTkhy1J|olL-w#w}C1k+IH@p~7*m};Sf$Hz~`@@%K&7vl24s0F)(#T{epVspZ zdIJH?Y%~v3f9Ra*rgQiN-V8dY`Mhu)Z!9QENN@FxfQI}CQITJvbu&(JLG~2Z)#NXT znEVB;!*NQUAR021R{y?aZ&WD=1XKj0TefW3`GB%z%NRf#8iRYv3?AsEDM4=8sc2ia zU?S+Cc~Q&^G9kq0k+%Gc&nbT=83?d|igWZ~P@ zfT!d0&p)3$H<8hH?b;RTi75*1j9yutva36G>~IXqdB4Eo*pH2)ss<)CJon;@&tYEA z11eueIWBq3z5=Pm@d?TnZJ3?yC%*b6--)3_f;w!miy>{_8fFGzU-kfH$Y3sM2t z2uLw)AR5%iJI1sQ`SD)N)2s|0H^)~+dgzmLoS|eBHcX*h`dC(9al#a%~YrB1+ z!~7LhG z`wUIO{`R|tpBdH&FTb~1c=Nq`gjcL5Pn|h4dg|mSqo;(F^}qjTWMt&yk+UOX!UgMx zAAR`o$hi+c8A)W<^#P^7O418-x#_$_C|7opn|6Jrp8%NUo@&u(9CTe}J&}CvU^5Ms| zXa|xHKfdUDXMTr%cmL3#XZxdv{*97n`w#8*eQ7^oxW!Vsc){!iRrUoHuIhU$42u`e zvsT+H7dx%TgBSe zwy<^ULacRdD_h&Nku@~7v4-YVtg&?yYh2sN?rB@c*0ro<4fnUPHO-q?TSFsjZlSUv z{2{-pi8ZfkTf`cEw1zeQ2#C-|*3{U_npQP}K@)3OcP|SyH?j7OZLIa~5SY;QHK;Iz zN;cx%8SB8jk*#ZQV{PprwyI?v%C+KrBWnk*HO(7Y3mVwax)x>Dur^!^wXJ3CZNRlP zpaG36)YOP{4Qt;N0u43%e$>B_-GlZtG=evHHmqp}&rN7Yh^<524Xf@$nN8R``s+er qaQ?MY^!^Kk1ExnA``5=9Yel*le=+>I=^Fl+fPKWJ>^3^H;_$!t(WiL; literal 0 HcmV?d00001 diff --git a/lab1/src/main/resources/mmio.asmbin b/lab1/src/main/resources/mmio.asmbin new file mode 100644 index 0000000000000000000000000000000000000000..22cc8f4b9b5d3ab1ce53f87b27cbafea18e571e6 GIT binary patch literal 32 mcmXqKWoT$ta%I?ll!0M#>(_V6N?RF(85kItm0cO~fiwV{qzDB7 literal 0 HcmV?d00001 diff --git a/lab1/src/main/resources/quicksort.asmbin b/lab1/src/main/resources/quicksort.asmbin new file mode 100644 index 0000000000000000000000000000000000000000..d9a007a1184f4594d2440eb2e2b0adff9465c30d GIT binary patch literal 1012 zcmZvbF>ljQ5XbMm=NB&wsjM)t;QC@WO+y-JB-UE07#I-n0SYJsV?hyn+}BEspa^xO zNa+VaG-9^oegI}BBoG@aLLh`(hySx1D5!&V_UZob{qFwf>kCACMD%$?*R~M%B++<# zTMox}dvAmC{poNldk;rM!?51Bv3#$Kz9+;_4i<=`tHiCCxP6DX^MJVfnAndc2hSxp zUrCN$OKzo-+wUZIK1l9)&UhF(Ljq1VuB=r#L^3%v`y3%v`y3%v`y3%zSu zzJ-4Ol%0$plUYnj1wxo07K#&LI2HJorWs2WCenndRFP07ij`VQlvzrZY6-`*Vn;0} zj#*9})fU>cW35&aZB|mPI-+JeaZO!GYUWB>Q(fVjZtSYn#5Jp_J6xpxko+EIal+98 z`c0(g2*vG5!L7rBqpVP&Gc#dU3~o$mi`MbbB^7QU=gh`0LR!;PQlTbpPRd#iY|IMw zCxxv?ZGqZiusN+)`Z8zr#aX=xcM7jYn17ZJZdG^9wQJ!N`AJ@#mz{V|8Z_2KgA4OI zr||UmS$XI2y$b@a-Oyd@9-~yo(XN**zlOKPY>_`QX?%pQ8hg&H4FN4<$!u z&arb22ky`fV$5Lc4+nDpaDeM9$MNMa3cZ)i|1nm4&a7mw{g_qzGWt~I!M)oc1&>bm z=wmq_cxe1o!c%2;9Wm!FyzP|UI(BZ{J_P4|?EWP8w2%F_aUFRZZ{t6(u~*LA({*nWNkWfLEB literal 0 HcmV?d00001 diff --git a/lab1/src/main/resources/sb.asmbin b/lab1/src/main/resources/sb.asmbin new file mode 100644 index 0000000000000000000000000000000000000000..fde0216ff6947c0b66cb85c21d84af9f23f2a4a1 GIT binary patch literal 36 scmWe;bzs95pR$yhwXJB9e0NFnYLI3~& literal 0 HcmV?d00001 diff --git a/lab1/src/main/resources/tetris.asmbin b/lab1/src/main/resources/tetris.asmbin new file mode 100644 index 0000000000000000000000000000000000000000..fc07ed8ffc0d7c774a931a061b00a4325e3a99ac GIT binary patch literal 8300 zcmeHMUx-|1760y^@6Hm^W|P|uQpDWsotbRY?RLv1Zt-bGW~-DUZ81Lh;BFby6qRfw z?o&}_b7w;zL{f$tAH+txDS{|UcCu7TnU$Gf#Y)sBC`Hp^X~cq#O*W>x^T*#g-}lY` zBz=fJB{1y0-@kLt@0{N`=ewESF2u<|h|4+g+PuKCEkxniG5cuY$;s7Getzy~!Ja&n z6XIxMcpv@c=V5D~Z&}yF(d{BkJ|x1iv+_&gP_pQ0kUQ0%M)6%(rQAYQ#NoU;hqVcrnJh13R53G64gcXY> z(lO`3#aQ&F)vcWNx01d-m^nR zm)~dHroS*Ec)*l$3HNV3deA6_0k5dcjB-& zShJvqP5!x&K4G%l2;*7wGe_ zUY)l^&0`$rImrzCg|(w+d)B3f)H>|zSyzyB<_g;n{iIqq*CBiI2C{{t)?!}ULih~U zlVYh1eDe+H*ocyD<0QCyIVawsGs2glJN$!qun`B&t>VGK9`XtMUSm(O;CsVjYUf!o zwNMdL2R=e9ARZl@<0L8^yQHJPuwR668mH%q@DC&yOL|`&VShKL7K#|3VIT0i5o!4c zDpokLj2Ho5hELmy1LZpGV{R1WDUtn(;taVaKFJTJq z_2bq=yu$|OwPoVn*xACH?N;&1F~RRMt=L!Vm()8r0XYKxA)Z>=Ki$0gA7L4eFV|F_ z$=4mkPxi~jt@N%j)N>ikWg6h-kiy+Xd|-VtQ&(}8d#gZxv5OwfPlLDcIdb%J4R#Xd zb%psUq1XScASKqgIHO!Yvs58&@n7cpj8r*rORqn3j*_3L`;v2CZN55tO^xN%7}-;u zz48(KI50oI6e~9zc@;TP#jY>+lP*&8=_RFio_N+Iy{A19_})2-p2Hmbu{ZB_`%%{c zj;-6s3yLT5CHuiGYJTMF1?0YL*Lz^z9dHYntt0nR4CGJ~=^ePLcZ+<-?<#L{J>oSZ z70TJD4KunnWcunviwFJu>Ba+b9VS;0BQElGz79Us6xOBJff4v!*14?oKE3O?SJ=+G zm7TOt`{xZFw~hT&U(H;p+>QwWo(ry>I-Umcd;|5{Mg4YB*St2*krQsK-zbNrCyI=Gc}42+Jh(*Kzb{U??;XfOP~$@-%T<;^KsNfpo| zupP+`JI0J1u8E`PamI$S!-XAgtwVocj~NJGq<8hwRW(+w z0jH+U@l=nv=YY=YnQ}YwACJGx`9UJjOXPV^=lL4q41F;7Pp*kGTJKAj@{qCPdpHNO z+@^~4)J1yNe0YxIev9EltNwqV$8|3Woxle(S1P~{cRAn}@g0BbT$_K(NF8SbGGcZ3yTo&BQ1)YLTc%Ng_! zydU{q*+RbJdW8P_#o8@vIrr=tl}B`4XY64+alF+R=^E6BJ$hbVXRr?lGvqVQ+sql% z>oV2rc0TB@^SYLkon`pJ_@MM9#&(OklNh@xF9Q?g>2k}z3bWEfswQS|hTBlJJkPaU z;e?)8J2k2PM_?=DdOz2=<_-})JSP)+?!2BW9fV$PYreHt;5$OOrf|q* zQ4kR=nF;;~CRl{yp7M$H6Vq1(>Kl`>?8Y z@Hyv4qm#BLUg+qx9j-HqlWlBipUYfqW1M=TZ!Kfpxz=Ew`&=8djN&HgSluwUsBd1S`@v~Bgc?qF+aVKkA@ZNX0e+NK3-yEZm*Rou4S1pAka&}C z@rLfBA@U+|33fIp{^*^a`EEF8Y9sOy5m?W^jC32I?reh?xGxaQw|!RMhV;@b|U6HuX$#@A_^C92J#ujAJ+t~52_Zi zO)VYEur<>}j=z`WGlsxM*~75}`@r2tdhTSZzB48|o-XJ+4aFMAOq;v7(`{8XoG~Gu zKt@MwKnBJL!|JXNX$@ojF_TM%^?k2&$$?+^u7O&meT;XU|M?Ccbkr}_{V~M@!U{eE zzj3ETUkRSGoG`v(`2RZfwGsNE0{5%P1$)YM^r`~Aop3yl^1s@z@1&%+w!eb-s;mBx zdJ%95d(3@K`L?S*X%4t;dvM=W_5lkOTkV|E%01eC@?UlK-2q(b>QC5a@FhwtdD92Z zrG0tfJ+1FAb-is)f0E+nyAJ7!duY!0u5k>7@gnlqk_Q>R-xRuJ=-%Ee*85$4-s#o|~`sBeo}{uP|>we>f0OZT8( zcH85KZPlatSnssQTkAiK^;UblwLVSyYgxx{g`>veA9{T>V0~YXC40%vRVi|Xr3I0_ zx6_v?+^cdn=2FgS(%jEsw5uI0^-Q=^odMflPpY6Qg&sn~A-d1Obzo|1Q7vl`> zhc4mHhJI1oS)g%zZ$OM&bgxEi;r|;y`)S>K@I2Q#gK=g* zXxa1~=fnVip0dJ#`v1TQCyWi^SHQPNzHqetCHNEfay8#0|1~q-_UEwPS9(=*@+Xv^ z48Ki|3P%wWZ_{12bQpQEu}ZZIJ%W;1`V9En+aq=5&Vf^Os`!;? literal 0 HcmV?d00001 diff --git a/lab1/src/main/resources/vga_font_8x16.bmp b/lab1/src/main/resources/vga_font_8x16.bmp new file mode 100644 index 0000000000000000000000000000000000000000..1aa58b97adc06ca07e07f83dc762bdce4b963d68 GIT binary patch literal 17462 zcmeHJJF?`)5riUS=om0{0@?_LT;2gk!BJo+bPm`$gA5#jK8;mYW@UFZ1~c!y;kO72JFBA zoVv<=hFyRa*nk~4fK%6e%&-fv0voUc2XOKcEawcn04uNoJ8%H!wBh{QGy`$+6^K7O zZ~*7D;r!b?0}HSM8?XZhaO$xwGwcGazy|EV0i1fI>kPX9E3g4OZ~&(sH->E60<6FW z?7#t>dKLB=b^%sk19sp5PQ50_47&g;umL-804HCe?VMp3U3;#}EzJv$hPoyIL zKl^dlw|kC*egEI9A+KuO841{@iMAiu_KTJmr5qqe=XLMhJK*M<&PN3Lx!vCGp-w05 z`IC&^oC=d(?SJC4Ejpqu%cDG@KTXHPoEj>WdrHnxK~f((cx=Zvy)Q-8$1b>}zT^j` zvBELC`r{_d7_%9bHn=aTy@ND!ul6z~pFd5Mcw3zl-6;oStzHj4ABqJ!%jByq&2(9h zC3IlTZ$;LaA4;h+<`6Lv%ZQ6Gs@!)TuS|75^<|LM-ys`;=}nIeX5CSP$9qb}u5(FP z&uUq=$-YZfS)VyCqyFdTk8A=^b%inUqRcSn z1Ggn*vz>b=G{$6TzE)19t5T0k>)-}YgNAfuGu`x^ATfegNjGy&(_&G4m3RE=cG@I3 zZ}8%pZqM;7@A;p$-axsn;#S7{{Aj*?9B;LkuHwGcbzA?c{?b(3Tm3ha9})0{U2MBX z=lvlduHRqyF^(hUu$660y0LW)kEireL=re*>$Q)B{&peG%?;LC`i-ayLzX|=9z-T# zH+ws$h*6;P^FHEYa@$R$w6_yg807M`G$Z z%~1R&^VM`jMv1$t`OufEbz|1ZvfBn{>6A& z7&aTM_zlSq1krih{j~4_@pn?c>HN40?OnGLmlL-WYsqJp`Ap|UvV~|e%OFp%rV7z$5Ja>G2v!@_RwIt9A+5ru}wI8Ti)>p z=DUR!%gg!Db4_N=$wl<&R! zANnTXurW_7PS#_6kr_8ei}U}-(X4*HD2S35lCh_-FVD+CEX0o6sP0SXF_wrM7^$(e9nGgDvJMAfKBB)qIxN%H%N1ZJwP1;>0wKOsl{t)v6}>+9%giV^b_8*Zlae zdDc?Y0~HS6U#7gbp)cC{{9s0zi_+R5*31pIaEJV$qe>`L?UuzDn|`ky!OXSjj>>FI0IhgQC?_=-f5cDS zSmo-W*9Li~7t`r>G`X81aJ7c+KyTg%1w9Fe_5+4LZsLzv5kFC(giO^J1 zv&9enCGnf)w?T4p8+=ZFpscWf#Sfqnn?Mvx-+2Cqt7s={{o$nQT`o#7A~|NJ)eDsz zP#nuP>C896FsQMHtOs#;T!|7jEq)G9!(1apgn)6e$_`YuaG$(?#iF!+I6ZHVR)rzO zUQJ3$*YRn(Rn0w@C_-s#{;i&#lN3Z&k9&)4W2%!qOjSP^j;m)P3r@sLyTBYX zS#W}apUdYBe9Iencw@h%_&c>}Iz?+qEzkzK`YOiv=E6SBjdX31*uFyH(nlxuFn z+QtJhrInAJGcnSVV>3)va^xdw2{~Mu9-14A{Jghlj-SV6*y9}8>Tn8M5feqm@yP6L z^4i#5s8iC{PU?PI9~m4A1&h$;QoHK58%IrAZ)Qho)L;f9vl13T#Ln3|-xXAmLaZP8 z)m`NIJrve%ZbHJD_s)f(sY-khRV=TmkVLOdmH$EiI)B_v5&K5- LisBRZyA1jtmw literal 0 HcmV?d00001 diff --git a/lab1/src/main/scala/board/basys3/BCD2Segments.scala b/lab1/src/main/scala/board/basys3/BCD2Segments.scala new file mode 100644 index 0000000..65b79b8 --- /dev/null +++ b/lab1/src/main/scala/board/basys3/BCD2Segments.scala @@ -0,0 +1,54 @@ +// 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 board.basys3 + +import chisel3._ +import chisel3.util._ + +class BCD2Segments extends Module { + val io = IO(new Bundle { + val bcd = Input(UInt(4.W)) + val segs = Output(UInt(8.W)) + }) + + val bcd = io.bcd + val segs = Wire(UInt(8.W)) + + segs := MuxLookup( + bcd, + 0xFF.U, + IndexedSeq( + 0.U -> "b10000001".U, + 1.U -> "b11001111".U, + 2.U -> "b10010010".U, + 3.U -> "b10000110".U, + 4.U -> "b11001100".U, + 5.U -> "b10100100".U, + 6.U -> "b10100000".U, + 7.U -> "b10001111".U, + 8.U -> "b10000000".U, + 9.U -> "b10000100".U, + 10.U -> "b00001000".U, + 11.U -> "b01100000".U, + 12.U -> "b00110001".U, + 13.U -> "b01000010".U, + 14.U -> "b00110000".U, + 15.U -> "b00111000".U, + ) + ) + + io.segs := segs +} + diff --git a/lab1/src/main/scala/board/basys3/OnboardDigitDisplay.scala b/lab1/src/main/scala/board/basys3/OnboardDigitDisplay.scala new file mode 100644 index 0000000..a07819b --- /dev/null +++ b/lab1/src/main/scala/board/basys3/OnboardDigitDisplay.scala @@ -0,0 +1,32 @@ +// 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 board.basys3 + +import chisel3._ + +class OnboardDigitDisplay extends Module { + val io = IO(new Bundle { + val digit_mask = Output(UInt(4.W)) + }) + + val counter = RegInit(UInt(16.W), 0.U) + val digit_mask = RegInit(UInt(4.W), "b0111".U) + + counter := counter + 1.U + when(counter === 0.U) { + digit_mask := (digit_mask << 1.U).asUInt + digit_mask(3) + } + io.digit_mask := digit_mask +} diff --git a/lab1/src/main/scala/board/basys3/SYSULogo.scala b/lab1/src/main/scala/board/basys3/SYSULogo.scala new file mode 100644 index 0000000..c41f4e6 --- /dev/null +++ b/lab1/src/main/scala/board/basys3/SYSULogo.scala @@ -0,0 +1,34 @@ +// 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 board.basys3 + +import chisel3._ +import chisel3.util._ + +class SYSULogo extends Module { + val io = IO(new Bundle { + val digit_mask = Input(UInt(4.W)) + val segs = Output(UInt(8.W)) + }) + + io.segs := MuxLookup( + io.digit_mask, + "b00100100".U, // "b0111".U, "b1101".U -> S + IndexedSeq( + "b1011".U -> "b01000100".U, // Y + "b1110".U -> "b01000001".U, // U + ) + ) +} diff --git a/lab1/src/main/scala/board/basys3/SegmentMux.scala b/lab1/src/main/scala/board/basys3/SegmentMux.scala new file mode 100644 index 0000000..9bb1bf7 --- /dev/null +++ b/lab1/src/main/scala/board/basys3/SegmentMux.scala @@ -0,0 +1,42 @@ +// 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 board.basys3 + +import chisel3._ +import chisel3.util._ + +class SegmentMux extends Module { + val io = IO(new Bundle { + val digit_mask = Input(UInt(4.W)) + val numbers = Input(UInt(16.W)) + val segs = Output(UInt(8.W)) + }) + + + val digit = RegInit(UInt(4.W), 0.U) + val bcd2segs = Module(new BCD2Segments) + + bcd2segs.io.bcd := digit + io.segs := bcd2segs.io.segs + digit := MuxLookup( + io.digit_mask, + io.numbers(3, 0), // "b1110".U + IndexedSeq( + "b1101".U -> io.numbers(7, 4), + "b1011".U -> io.numbers(11, 8), + "b0111".U -> io.numbers(15, 12) + ) + ) +} diff --git a/lab1/src/main/scala/board/basys3/Top.scala b/lab1/src/main/scala/board/basys3/Top.scala new file mode 100644 index 0000000..a4d809b --- /dev/null +++ b/lab1/src/main/scala/board/basys3/Top.scala @@ -0,0 +1,123 @@ +// 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 board.basys3 + +import chisel3._ +import chisel3.experimental.ChiselEnum +import chisel3.stage.{ChiselGeneratorAnnotation, ChiselStage} +import chisel3.util._ +import peripheral.{CharacterDisplay, Dummy, InstructionROM, Memory, ROMLoader, VGADisplay} +import riscv._ +import riscv.core.{CPU, ProgramCounter} + +object BootStates extends ChiselEnum { + val Init, Loading, Finished = Value +} + +class Top extends Module { + val binaryFilename = "tetris.asmbin" + val io = IO(new Bundle { + val switch = Input(UInt(16.W)) + + val segs = Output(UInt(8.W)) + val digit_mask = Output(UInt(4.W)) + + val hsync = Output(Bool()) + val vsync = Output(Bool()) + val rgb = Output(UInt(12.W)) + val led = Output(UInt(16.W)) + + }) + val vga_display = Module(new VGADisplay) + val display = Module(new CharacterDisplay) + + val mem = Module(new Memory(Parameters.MemorySizeInWords)) + val dummy = Module(new Dummy) + + display.io.bundle <> dummy.io.bundle + mem.io.bundle <> dummy.io.bundle + mem.io.debug_read_address := 0.U + + val instruction_rom = Module(new InstructionROM(binaryFilename)) + val rom_loader = Module(new ROMLoader(instruction_rom.capacity)) + + rom_loader.io.rom_data := instruction_rom.io.data + rom_loader.io.load_address := Parameters.EntryAddress + instruction_rom.io.address := rom_loader.io.rom_address + + val CPU_clkdiv = RegInit(UInt(2.W), 0.U) + val CPU_tick = Wire(Bool()) + val CPU_next = Wire(UInt(2.W)) + CPU_next := Mux(CPU_clkdiv === 3.U, 0.U, CPU_clkdiv + 1.U) + CPU_tick := CPU_clkdiv === 0.U + CPU_clkdiv := CPU_next + + withClock(CPU_tick.asClock) { + val cpu = Module(new CPU) + cpu.io.debug_read_address := 0.U + cpu.io.instruction_valid := rom_loader.io.load_finished + mem.io.instruction_address := cpu.io.instruction_address + cpu.io.instruction := mem.io.instruction + + when(!rom_loader.io.load_finished) { + rom_loader.io.bundle <> mem.io.bundle + cpu.io.memory_bundle.read_data := 0.U + }.otherwise { + rom_loader.io.bundle.read_data := 0.U + when(cpu.io.deviceSelect === 1.U) { + cpu.io.memory_bundle <> display.io.bundle + }.otherwise { + cpu.io.memory_bundle <> mem.io.bundle + } + } + } + io.hsync := vga_display.io.hsync + io.vsync := vga_display.io.vsync + + display.io.x := vga_display.io.x + display.io.y := vga_display.io.y + display.io.video_on := vga_display.io.video_on + + io.rgb := display.io.rgb + + mem.io.debug_read_address := io.switch(15, 1).asUInt << 2 + io.led := Mux( + io.switch(0), + mem.io.debug_read_data(31, 16).asUInt, + mem.io.debug_read_data(15, 0).asUInt, + ) + + val onboard_display = Module(new OnboardDigitDisplay) + io.digit_mask := onboard_display.io.digit_mask + + val sysu_logo = Module(new SYSULogo) + sysu_logo.io.digit_mask := io.digit_mask + + val seg_mux = Module(new SegmentMux) + seg_mux.io.digit_mask := io.digit_mask + seg_mux.io.numbers := io.led + + io.segs := MuxLookup( + io.switch, + seg_mux.io.segs, + IndexedSeq( + 0.U -> sysu_logo.io.segs + ) + ) +} + +object VerilogGenerator extends App { + (new ChiselStage).execute(Array("-X", "verilog", "-td", "verilog/basys3"), Seq(ChiselGeneratorAnnotation(() => new Top))) +} \ No newline at end of file diff --git a/lab1/src/main/scala/board/pynq/Top.scala b/lab1/src/main/scala/board/pynq/Top.scala new file mode 100644 index 0000000..51f7989 --- /dev/null +++ b/lab1/src/main/scala/board/pynq/Top.scala @@ -0,0 +1,93 @@ +// Copyright 2022 Canbin Huang +// +// 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 board.pynq + +import chisel3._ +import chisel3.stage.{ChiselGeneratorAnnotation, ChiselStage} +import peripheral._ +import riscv.Parameters +import riscv.core.{CPU, ProgramCounter} + +class Top extends Module { + val binaryFilename = "hello.asmbin" + val io = IO(new Bundle() { + val hdmi_clk_n = Output(Bool()) + val hdmi_clk_p = Output(Bool()) + val hdmi_data_n = Output(UInt(3.W)) + val hdmi_data_p = Output(UInt(3.W)) + val hdmi_hpdn = Output(Bool()) + + val led = Output(UInt(4.W)) + }) + val hdmi_display = Module(new HDMIDisplay) + val display = Module(new CharacterDisplay) + val mem = Module(new Memory(Parameters.MemorySizeInWords)) + val dummy = Module(new Dummy) + + display.io.bundle <> dummy.io.bundle + mem.io.bundle <> dummy.io.bundle + mem.io.debug_read_address := 0.U + + val instruction_rom = Module(new InstructionROM(binaryFilename)) + val rom_loader = Module(new ROMLoader(instruction_rom.capacity)) + + rom_loader.io.rom_data := instruction_rom.io.data + rom_loader.io.load_address := Parameters.EntryAddress + instruction_rom.io.address := rom_loader.io.rom_address + + val CPU_clkdiv = RegInit(UInt(2.W),0.U) + val CPU_tick = Wire(Bool()) + val CPU_next = Wire(UInt(2.W)) + CPU_next := Mux(CPU_clkdiv === 3.U, 0.U, CPU_clkdiv + 1.U) + CPU_tick := CPU_clkdiv === 0.U + CPU_clkdiv := CPU_next + + withClock(CPU_tick.asClock) { + val cpu = Module(new CPU) + cpu.io.debug_read_address := 0.U + cpu.io.instruction_valid := rom_loader.io.load_finished + mem.io.instruction_address := cpu.io.instruction_address + cpu.io.instruction := mem.io.instruction + + when(!rom_loader.io.load_finished) { + rom_loader.io.bundle <> mem.io.bundle + cpu.io.memory_bundle.read_data := 0.U + }.otherwise { + rom_loader.io.bundle.read_data := 0.U + when(cpu.io.deviceSelect === 1.U) { + cpu.io.memory_bundle <> display.io.bundle + }.otherwise { + cpu.io.memory_bundle <> mem.io.bundle + } + } + } + + io.led := 15.U(4.W) + + display.io.x := hdmi_display.io.x + display.io.y := hdmi_display.io.y + display.io.video_on := hdmi_display.io.video_on + hdmi_display.io.rgb := display.io.rgb + + io.hdmi_hpdn := 1.U + io.hdmi_data_n := hdmi_display.io.TMDSdata_n + io.hdmi_data_p := hdmi_display.io.TMDSdata_p + io.hdmi_clk_n := hdmi_display.io.TMDSclk_n + io.hdmi_clk_p := hdmi_display.io.TMDSclk_p +} + +object VerilogGenerator extends App { + (new ChiselStage).execute(Array("-X", "verilog", "-td", "verilog/pynq"), Seq(ChiselGeneratorAnnotation(() => new Top))) +} \ No newline at end of file diff --git a/lab1/src/main/scala/board/verilator/Top.scala b/lab1/src/main/scala/board/verilator/Top.scala new file mode 100644 index 0000000..d4bcf06 --- /dev/null +++ b/lab1/src/main/scala/board/verilator/Top.scala @@ -0,0 +1,43 @@ +// Copyright 2022 Canbin Huang +// +// 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 board.verilator + +import chisel3._ +import chisel3.stage.{ChiselGeneratorAnnotation, ChiselStage} +import peripheral._ +import riscv.{CPUBundle, Parameters} +import riscv.core.CPU + +class Top extends Module { + val io = IO(new CPUBundle) + + val cpu = Module(new CPU) + + io.deviceSelect := 0.U + cpu.io.debug_read_address := io.debug_read_address + io.debug_read_data := cpu.io.debug_read_data + + io.memory_bundle <> cpu.io.memory_bundle + io.instruction_address := cpu.io.instruction_address + cpu.io.instruction := io.instruction + + cpu.io.instruction_valid := io.instruction_valid + +} + +object VerilogGenerator extends App { + (new ChiselStage).execute(Array("-X", "verilog", "-td", "verilog/verilator"), Seq(ChiselGeneratorAnnotation(() => + new Top()))) +} \ No newline at end of file diff --git a/lab1/src/main/scala/peripheral/CharacterDisplay.scala b/lab1/src/main/scala/peripheral/CharacterDisplay.scala new file mode 100644 index 0000000..1c4bc8e --- /dev/null +++ b/lab1/src/main/scala/peripheral/CharacterDisplay.scala @@ -0,0 +1,84 @@ +// 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 peripheral + +import chisel3.util.{MuxLookup, log2Up} +import chisel3.{Bool, Bundle, Module, Mux, Output, UInt, Wire, _} +import peripheral.ScreenInfo.{DisplayHorizontal, DisplayVertical} +import riscv.Parameters + +object GlyphInfo { + val glyphWidth = 8 + val glyphHeight = 16 + // ASCII printable characters start from here + val spaceIndex = 1 +} + +object ScreenInfo { + val DisplayHorizontal = 640 + val DisplayVertical = 480 +} + +object CharacterBufferInfo { + val CharCols = DisplayHorizontal / GlyphInfo.glyphWidth + val CharRows = DisplayVertical / GlyphInfo.glyphHeight + val Chars = CharCols * CharRows +} + +class CharacterDisplay extends Module { + val io = IO(new Bundle() { + val bundle = new RAMBundle() + + val x = Input(UInt(16.W)) + val y = Input(UInt(16.W)) + val video_on = Input(Bool()) + + val rgb = Output(UInt(24.W)) + }) + + val mem = Module(new BlockRAM(CharacterBufferInfo.Chars / Parameters.WordSize)) + mem.io.write_enable := io.bundle.write_enable + mem.io.write_data := io.bundle.write_data + mem.io.write_address := io.bundle.address + mem.io.write_strobe := io.bundle.write_strobe + mem.io.read_address := io.bundle.address + io.bundle.read_data := mem.io.read_data + + + val font_rom = Module(new FontROM) + val row = (io.y >> log2Up(GlyphInfo.glyphHeight)).asUInt + val col = (io.x >> log2Up(GlyphInfo.glyphWidth)).asUInt + val char_index = (row * CharacterBufferInfo.CharCols.U) + col + val offset = char_index(1, 0) + val ch = Wire(UInt(8.W)) + + mem.io.debug_read_address := char_index + ch := MuxLookup( + offset, + 0.U, + IndexedSeq( + 0.U -> mem.io.debug_read_data(7, 0).asUInt, + 1.U -> mem.io.debug_read_data(15, 8).asUInt, + 2.U -> mem.io.debug_read_data(23, 16).asUInt, + 3.U -> mem.io.debug_read_data(31, 24).asUInt + ) + ) + font_rom.io.glyph_index := Mux(ch >= 32.U, ch - 31.U, 0.U) + font_rom.io.glyph_y := io.y(log2Up(GlyphInfo.glyphHeight) - 1, 0) + + // White if pixel_on and glyph pixel on + val glyph_x = io.x(log2Up(GlyphInfo.glyphWidth) - 1, 0) + io.rgb := Mux(io.video_on && font_rom.io.glyph_pixel_byte(glyph_x), 0xFFFFFF.U, 0.U) +} diff --git a/lab1/src/main/scala/peripheral/Dummy.scala b/lab1/src/main/scala/peripheral/Dummy.scala new file mode 100644 index 0000000..fe4cb04 --- /dev/null +++ b/lab1/src/main/scala/peripheral/Dummy.scala @@ -0,0 +1,29 @@ +// 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 peripheral + +import chisel3._ +import riscv.Parameters + +// A dummy master that never initiates reads or writes +class Dummy extends Module { + val io = IO(new Bundle { + val bundle = Flipped(new RAMBundle) + }) + io.bundle.write_strobe := VecInit(Seq.fill(Parameters.WordSize)(false.B)) + io.bundle.write_data := 0.U + io.bundle.write_enable := false.B + io.bundle.address := 0.U +} diff --git a/lab1/src/main/scala/peripheral/FontROM.scala b/lab1/src/main/scala/peripheral/FontROM.scala new file mode 100644 index 0000000..b9b0d3b --- /dev/null +++ b/lab1/src/main/scala/peripheral/FontROM.scala @@ -0,0 +1,64 @@ +package peripheral + +import chisel3.experimental.{ChiselAnnotation, annotate} +import chisel3.util.experimental.loadMemoryFromFileInline +import chisel3.{Bundle, Input, Module, Output, SyncReadMem, UInt, _} +import firrtl.annotations.MemorySynthInit + +import java.io.FileWriter +import java.nio.file.Paths +import javax.imageio.ImageIO + +class FontROM(fontBitmapFilename: String = "vga_font_8x16.bmp") extends Module { + val glyphWidth = GlyphInfo.glyphWidth + val glyphHeight = GlyphInfo.glyphHeight + + val io = IO(new Bundle { + val glyph_index = Input(UInt(7.W)) + val glyph_y = Input(UInt(4.W)) + + val glyph_pixel_byte = Output(UInt(8.W)) + }) + + annotate(new ChiselAnnotation { + override def toFirrtl = + MemorySynthInit + }) + + val (hexTxtPath, glyphCount) = readFontBitmap() + val mem = SyncReadMem(glyphCount, UInt(8.W)) + loadMemoryFromFileInline(mem, hexTxtPath.toString.replaceAll("\\\\", "/")) + io.glyph_pixel_byte := mem.read(io.glyph_index * GlyphInfo.glyphHeight.U + io.glyph_y, true.B) + + def readFontBitmap() = { + val inputStream = getClass.getClassLoader.getResourceAsStream(fontBitmapFilename) + val image = ImageIO.read(inputStream) + + val glyphColumns = image.getWidth() / glyphWidth + val glyphRows = image.getHeight / glyphHeight + val glyphCount = glyphColumns * glyphRows + val glyphs = new Array[UInt](glyphCount * GlyphInfo.glyphHeight) + + for (row <- 0 until glyphRows) { + for (col <- 0 until glyphColumns) { + for (i <- 0 until glyphHeight) { + var lineInt = 0 + for (j <- 0 until glyphWidth) { + if (image.getRGB(col * glyphWidth + j, row * glyphHeight + i) != 0xFFFFFFFF) { + lineInt |= (1 << j) + } + } + glyphs((row * glyphColumns + col) * GlyphInfo.glyphHeight + i) = lineInt.U(8.W) + } + } + } + val currentDir = System.getProperty("user.dir") + val hexTxtPath = Paths.get(currentDir, "verilog", f"${fontBitmapFilename}.txt") + val writer = new FileWriter(hexTxtPath.toString) + for (i <- glyphs.indices) { + writer.write(f"@$i%x\n${glyphs(i).litValue}%02x\n") + } + writer.close() + (hexTxtPath, glyphs.length) + } +} diff --git a/lab1/src/main/scala/peripheral/HDMIDisplay.scala b/lab1/src/main/scala/peripheral/HDMIDisplay.scala new file mode 100644 index 0000000..d575fda --- /dev/null +++ b/lab1/src/main/scala/peripheral/HDMIDisplay.scala @@ -0,0 +1,394 @@ +// Copyright 2022 hrpccs +// +// 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 peripheral + +import chisel3._ +import chisel3.util._ + +class HDMISync extends Module { + val io = IO(new Bundle { + val hsync = Output(Bool()) + val vsync = Output(Bool()) + val video_on = Output(Bool()) + val p_tick = Output(Bool()) + val f_tick = Output(Bool()) + val x = Output(UInt(10.W)) + val y = Output(UInt(10.W)) + val x_next = Output(UInt(10.W)) + val y_next = Output(UInt(10.W)) + }) + + val DisplayHorizontal = ScreenInfo.DisplayHorizontal + val DisplayVertical = ScreenInfo.DisplayVertical + + val BorderLeft = 48 + val BorderRight = 16 + val BorderTop = 10 + val BorderBottom = 33 + + val RetraceHorizontal = 96 + val RetraceVertical = 2 + + val MaxHorizontal = DisplayHorizontal + BorderLeft + BorderRight + RetraceHorizontal - 1 + val MaxVertical = DisplayVertical + BorderTop + BorderBottom + RetraceVertical - 1 + + val RetraceHorizontalStart = DisplayHorizontal + BorderRight + val RetraceHorizontalEnd = RetraceHorizontalStart + RetraceHorizontal - 1 + + val RetraceVerticalStart = DisplayVertical + BorderBottom + val RetraceVerticalEnd = RetraceVerticalStart + RetraceVertical - 1 + + val pixel = RegInit(UInt(3.W), 0.U) + val pixel_next = Wire(UInt(3.W)) + val pixel_tick = Wire(Bool()) + + val v_count_reg = RegInit(UInt(10.W), 0.U) + val h_count_reg = RegInit(UInt(10.W), 0.U) + + val v_count_next = Wire(UInt(10.W)) + val h_count_next = Wire(UInt(10.W)) + + val vsync_reg = RegInit(Bool(), false.B) + val hsync_reg = RegInit(Bool(), false.B) + + val vsync_next = Wire(Bool()) + val hsync_next = Wire(Bool()) + + pixel_next := Mux(pixel === 4.U, 0.U, pixel + 1.U) + pixel_tick := pixel === 0.U + + h_count_next := Mux( + pixel_tick, + Mux(h_count_reg === MaxHorizontal.U, 0.U, h_count_reg + 1.U), + h_count_reg + ) + + v_count_next := Mux( + pixel_tick && h_count_reg === MaxHorizontal.U, + Mux(v_count_reg === MaxVertical.U, 0.U, v_count_reg + 1.U), + v_count_reg + ) + + hsync_next := h_count_reg >= RetraceHorizontalStart.U && h_count_reg <= RetraceHorizontalEnd.U + vsync_next := v_count_reg >= RetraceVerticalStart.U && v_count_reg <= RetraceVerticalEnd.U + + pixel := pixel_next + hsync_reg := hsync_next + vsync_reg := vsync_next + v_count_reg := v_count_next + h_count_reg := h_count_next + + io.video_on := h_count_reg < DisplayHorizontal.U && v_count_reg < DisplayVertical.U + io.hsync := hsync_reg + io.vsync := vsync_reg + io.x := h_count_reg + io.y := v_count_reg + io.x_next := h_count_next + io.y_next := v_count_next + io.p_tick := pixel_tick + io.f_tick := io.x === 0.U && io.y === 0.U +} + +class TMDS_encoder extends Module { + val io = IO(new Bundle() { + val video_data = Input(UInt(8.W)) //r,g,b,8bit + val control_data = Input(UInt(2.W)) + val video_on = Input(Bool()) + val TMDS = Output(UInt(10.W)) + }) + val Nb1s = PopCount(io.video_data) + val xored = xorfct(io.video_data) + val xnored = xnorfct(io.video_data) + val XNOR = (Nb1s > 4.U(4.W)) || (Nb1s === 4.U(4.W) && io.video_data(0) === 0.U) + val q_m = RegInit(0.U(9.W)) + val diffSize = 4 + val diff = RegInit(0.S(diffSize.W)) + q_m := Mux( + XNOR, + xnored, + xored + ) + val disparitySize = 4 + val disparityReg = RegInit(0.S(disparitySize.W)) + diff := PopCount(q_m).asSInt - 4.S + val doutReg = RegInit("b1010101011".U(10.W)) + + def xorfct(value: UInt): UInt = { + val vin = VecInit(value.asBools) + val res = VecInit(511.U.asBools) + res(0) := vin(0) + for (i <- 1 to 7) { + res(i) := res(i - 1) ^ vin(i) + } + res(8) := 1.U + res.asUInt + } + + def xnorfct(value: UInt): UInt = { + val vin = VecInit(value.asBools) + val res = VecInit(511.U.asBools) + res(0) := vin(0) + for (i <- 1 to 7) { + res(i) := !(res(i - 1) ^ vin(i)) + } + res(8) := 0.U + res.asUInt + } + + when(io.video_on === false.B) { + disparityReg := 0.S + doutReg := "b1010101011".U(10.W) + switch(io.control_data) { + is("b00".U(2.W)) { + doutReg := "b1101010100".U(10.W) + } + is("b01".U(2.W)) { + doutReg := "b0010101011".U(10.W) + } + is("b10".U(2.W)) { + doutReg := "b0101010100".U(10.W) + } + } + }.otherwise { + when(disparityReg === 0.S || diff === 0.S) { + when(q_m(8) === false.B) { + doutReg := "b10".U(2.W) ## ~q_m(7, 0) + disparityReg := disparityReg - diff + }.otherwise { + doutReg := "b01".U(2.W) ## q_m(7, 0) + disparityReg := disparityReg + diff + } + }.elsewhen((!diff(diffSize - 1) && !disparityReg(disparitySize - 1)) + || (diff(diffSize - 1) && disparityReg(disparitySize - 1))) { + doutReg := 1.U(1.W) ## q_m(8) ## ~q_m(7, 0) + when(q_m(8)) { + disparityReg := disparityReg + 1.S - diff + }.otherwise { + disparityReg := disparityReg - diff + } + }.otherwise { + doutReg := 0.U(1.W) ## q_m + when(q_m(8)) { + disparityReg := disparityReg + diff + }.otherwise { + disparityReg := disparityReg - 1.S + diff + } + } + } + + io.TMDS := doutReg +} + +class HDMIDisplay extends Module { + val io = IO(new Bundle() { + val rgb = Input(UInt(24.W)) + val x = Output(UInt(16.W)) + val y = Output(UInt(16.W)) + val x_next = Output(UInt(16.W)) + val y_next = Output(UInt(16.W)) + val video_on = Output(Bool()) + + val TMDSclk_p = Output(Bool()) + val TMDSdata_p = Output(UInt(3.W)) + val TMDSclk_n = Output(Bool()) + val TMDSdata_n = Output(UInt(3.W)) + }) + val rgb = io.rgb + val pixel_clk = Wire(Bool()) + val hsync = Wire(Bool()) + val vsync = Wire(Bool()) + val sync = Module(new HDMISync) + + io.x := sync.io.x + io.y := sync.io.y + io.x_next := sync.io.x_next + io.y_next := sync.io.y_next + io.video_on := sync.io.video_on + + hsync := sync.io.hsync + vsync := sync.io.vsync + pixel_clk := sync.io.p_tick + + // TMDS_PLLVR is a vivado IP core, check it in /verilog/pynq/TMDS_PLLVR.v + val serial_clk = Wire(Clock()) + val pll_lock = Wire(Bool()) + val tmdspll = Module(new TMDS_PLLVR) + val rst = Wire(Reset()) + tmdspll.io.clkin := pixel_clk.asClock + serial_clk := tmdspll.io.clkout + pll_lock := tmdspll.io.lock + tmdspll.io.reset := reset + rst := ~pll_lock + + val tmds = Wire(UInt(3.W)) + val tmds_clk = Wire(Bool()) + withClockAndReset(pixel_clk.asClock, rst) { + val tmds_channel1 = Wire(UInt(10.W)) + val tmds_channel2 = Wire(UInt(10.W)) + val tmds_channel0 = Wire(UInt(10.W)) + + val tmds_green = Module(new TMDS_encoder) + val tmds_red = Module(new TMDS_encoder) + val tmds_blue = Module(new TMDS_encoder) + + tmds_red.io.video_on := sync.io.video_on + tmds_blue.io.video_on := sync.io.video_on + tmds_green.io.video_on := sync.io.video_on + + tmds_blue.io.control_data := sync.io.vsync ## sync.io.hsync + tmds_green.io.control_data := 0.U + tmds_red.io.control_data := 0.U + + tmds_red.io.video_data := rgb(23, 16) + tmds_blue.io.video_data := rgb(7, 0) + tmds_green.io.video_data := rgb(15, 8) + + tmds_channel0 := tmds_blue.io.TMDS + tmds_channel1 := tmds_green.io.TMDS + tmds_channel2 := tmds_red.io.TMDS + + val serdesBlue = Module(new Oser10Module()) + serdesBlue.io.data := tmds_channel0 + serdesBlue.io.fclk := serial_clk + + val serdesGreen = Module(new Oser10Module()) + serdesGreen.io.data := tmds_channel1 + serdesGreen.io.fclk := serial_clk + + val serdesRed = Module(new Oser10Module()) + serdesRed.io.data := tmds_channel2 + serdesRed.io.fclk := serial_clk + + tmds := serdesRed.io.q ## serdesGreen.io.q ## serdesBlue.io.q + + //serdesCLk : 25Mhz ,Why not directly use p_tick? + //cause Duty Ratio of p_tick is 10% , while which of serdesCLk is 50% + val serdesClk = Module(new Oser10Module()) + serdesClk.io.data := "b1111100000".U(10.W) + serdesClk.io.fclk := serial_clk + + tmds_clk := serdesClk.io.q + + val buffDiffBlue = Module(new OBUFDS) + buffDiffBlue.io.I := tmds(0) + val buffDiffGreen = Module(new OBUFDS) + buffDiffGreen.io.I := tmds(1) + val buffDiffRed = Module(new OBUFDS) + buffDiffRed.io.I := tmds(2) + val buffDiffClk = Module(new OBUFDS) + buffDiffClk.io.I := tmds_clk + + io.TMDSclk_p := buffDiffClk.io.O + io.TMDSclk_n := buffDiffClk.io.OB + io.TMDSdata_p := buffDiffRed.io.O ## buffDiffGreen.io.O ## buffDiffBlue.io.O + io.TMDSdata_n := buffDiffRed.io.OB ## buffDiffGreen.io.OB ## buffDiffBlue.io.OB + } +} + +//---------------------------------------- +//PLL frequency multiplier using BlackBox +class TMDS_PLLVR extends BlackBox { + val io = IO(new Bundle { + val clkin = Input(Clock()) + val reset = Input(Reset()) + val clkout = Output(Clock()) + val clkoutd = Output(Clock()) + val lock = Output(Bool()) + }) +} + +/* OSER10 : serializer 10:1*/ +class OSER10 extends Module { + val io = IO(new Bundle { + val Q = Output(Bool()) // OSER10 data output signal + val D0 = Input(Bool()) + val D1 = Input(Bool()) + val D2 = Input(Bool()) + val D3 = Input(Bool()) + val D4 = Input(Bool()) + val D5 = Input(Bool()) + val D6 = Input(Bool()) + val D7 = Input(Bool()) + val D8 = Input(Bool()) + val D9 = Input(Bool()) // OSER10 data input signal + val PCLK = Input(Clock()) // Primary clock input signal + val FCLK = Input(Clock()) // High speed clock input signal + val RESET = Input(Reset()) // Asynchronous reset input signal, + //active-high. + }) + withClockAndReset(io.FCLK, io.RESET) { + val count = RegInit(0.U(4.W)) + val countnext = Wire(UInt(4.W)) + io.Q := MuxLookup( + count, + 0.U, + IndexedSeq( + 0.U -> io.D0.asBool, + 1.U -> io.D1.asBool, + 2.U -> io.D2.asBool, + 3.U -> io.D3.asBool, + 4.U -> io.D4.asBool, + 5.U -> io.D5.asBool, + 6.U -> io.D6.asBool, + 7.U -> io.D7.asBool, + 8.U -> io.D8.asBool, + 9.U -> io.D9.asBool + ) + ) + countnext := Mux( + count === 9.U, 0.U, count + 1.U + ) + count := countnext + } +} + +class Oser10Module extends Module { + val io = IO(new Bundle { + val q = Output(Bool()) + val data = Input(UInt(10.W)) + val fclk = Input(Clock()) // Fast clock + }) + + val osr10 = Module(new OSER10()) + io.q := osr10.io.Q + osr10.io.D0 := io.data(0) + osr10.io.D1 := io.data(1) + osr10.io.D2 := io.data(2) + osr10.io.D3 := io.data(3) + osr10.io.D4 := io.data(4) + osr10.io.D5 := io.data(5) + osr10.io.D6 := io.data(6) + osr10.io.D7 := io.data(7) + osr10.io.D8 := io.data(8) + osr10.io.D9 := io.data(9) + osr10.io.PCLK := clock + osr10.io.FCLK := io.fclk + osr10.io.RESET := reset +} + +/* lvds output */ +class OBUFDS extends BlackBox { + val io = IO(new Bundle { + val O = Output(Bool()) + val OB = Output(Bool()) + val I = Input(Bool()) + }) +} +//----------------------------------------- + + +//----------------------------------------- + + diff --git a/lab1/src/main/scala/peripheral/InstructionROM.scala b/lab1/src/main/scala/peripheral/InstructionROM.scala new file mode 100644 index 0000000..4d7ed12 --- /dev/null +++ b/lab1/src/main/scala/peripheral/InstructionROM.scala @@ -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 peripheral + +import chisel3._ +import chisel3.experimental.{ChiselAnnotation, annotate} +import chisel3.util.experimental.loadMemoryFromFileInline +import firrtl.annotations.MemorySynthInit +import riscv.Parameters + +import java.io.FileWriter +import java.nio.file.{Files, Paths} +import java.nio.{ByteBuffer, ByteOrder} + +class InstructionROM(instructionFilename: String) extends Module { + val io = IO(new Bundle { + val address = Input(UInt(Parameters.AddrWidth)) + val data = Output(UInt(Parameters.InstructionWidth)) + }) + + val (instructionsInitFile, capacity) = readAsmBinary(instructionFilename) + val mem = Mem(capacity, UInt(Parameters.InstructionWidth)) + annotate(new ChiselAnnotation { + override def toFirrtl = + MemorySynthInit + }) + loadMemoryFromFileInline(mem, instructionsInitFile.toString.replaceAll("\\\\", "/")) + io.data := mem.read(io.address) + + def readAsmBinary(filename: String) = { + val inputStream = if (Files.exists(Paths.get(filename))) { + Files.newInputStream(Paths.get(filename)) + } else { + 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 + } + instructions = instructions :+ BigInt(0x00000013L) + instructions = instructions :+ BigInt(0x00000013L) + instructions = instructions :+ BigInt(0x00000013L) + val currentDir = System.getProperty("user.dir") + val exeTxtPath = Paths.get(currentDir, "verilog", f"${instructionFilename}.txt") + val writer = new FileWriter(exeTxtPath.toString) + for (i <- instructions.indices) { + writer.write(f"@$i%x\n${instructions(i)}%08x\n") + } + writer.close() + (exeTxtPath, instructions.length) + } +} diff --git a/lab1/src/main/scala/peripheral/Memory.scala b/lab1/src/main/scala/peripheral/Memory.scala new file mode 100644 index 0000000..4c10bca --- /dev/null +++ b/lab1/src/main/scala/peripheral/Memory.scala @@ -0,0 +1,77 @@ +// 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 peripheral + +import chisel3._ +import chisel3.util._ +import riscv.Parameters + +class RAMBundle extends Bundle { + val address = Input(UInt(Parameters.AddrWidth)) + val write_data = Input(UInt(Parameters.DataWidth)) + val write_enable = Input(Bool()) + val write_strobe = Input(Vec(Parameters.WordSize, Bool())) + val read_data = Output(UInt(Parameters.DataWidth)) +} +// The purpose of this module is to help the synthesis tool recognize +// our memory as a Block RAM template +class BlockRAM(capacity: Int) extends Module { + val io = IO(new Bundle { + val read_address = Input(UInt(Parameters.AddrWidth)) + val write_address = Input(UInt(Parameters.AddrWidth)) + val write_data = Input(UInt(Parameters.DataWidth)) + val write_enable = Input(Bool()) + val write_strobe = Input(Vec(Parameters.WordSize, Bool())) + + val debug_read_address = Input(UInt(Parameters.AddrWidth)) + + val read_data = Output(UInt(Parameters.DataWidth)) + val debug_read_data = Output(UInt(Parameters.DataWidth)) + }) + val mem = SyncReadMem(capacity, Vec(Parameters.WordSize, UInt(Parameters.ByteWidth))) + when(io.write_enable) { + val write_data_vec = Wire(Vec(Parameters.WordSize, UInt(Parameters.ByteWidth))) + for (i <- 0 until Parameters.WordSize) { + write_data_vec(i) := io.write_data((i + 1) * Parameters.ByteBits - 1, i * Parameters.ByteBits) + } + mem.write((io.write_address >> 2.U).asUInt, write_data_vec, io.write_strobe) + } + io.read_data := mem.read((io.read_address >> 2.U).asUInt, true.B).asUInt + io.debug_read_data := mem.read((io.debug_read_address >> 2.U).asUInt, true.B).asUInt +} + +class Memory(capacity: Int) extends Module { + val io = IO(new Bundle { + val bundle = new RAMBundle + + val instruction = Output(UInt(Parameters.DataWidth)) + val instruction_address = Input(UInt(Parameters.AddrWidth)) + + val debug_read_address = Input(UInt(Parameters.AddrWidth)) + val debug_read_data = Output(UInt(Parameters.DataWidth)) + }) + + val mem = SyncReadMem(capacity, Vec(Parameters.WordSize, UInt(Parameters.ByteWidth))) + when(io.bundle.write_enable) { + val write_data_vec = Wire(Vec(Parameters.WordSize, UInt(Parameters.ByteWidth))) + for (i <- 0 until Parameters.WordSize) { + write_data_vec(i) := io.bundle.write_data((i + 1) * Parameters.ByteBits - 1, i * Parameters.ByteBits) + } + mem.write((io.bundle.address >> 2.U).asUInt, write_data_vec, io.bundle.write_strobe) + } + io.bundle.read_data := mem.read((io.bundle.address >> 2.U).asUInt, true.B).asUInt + io.debug_read_data := mem.read((io.debug_read_address >> 2.U).asUInt, true.B).asUInt + io.instruction := mem.read((io.instruction_address >> 2.U).asUInt, true.B).asUInt +} \ No newline at end of file diff --git a/lab1/src/main/scala/peripheral/ROMLoader.scala b/lab1/src/main/scala/peripheral/ROMLoader.scala new file mode 100644 index 0000000..d3313e5 --- /dev/null +++ b/lab1/src/main/scala/peripheral/ROMLoader.scala @@ -0,0 +1,50 @@ +// 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 peripheral + +import chisel3._ +import riscv.Parameters + +class ROMLoader(capacity: Int) extends Module { + val io = IO(new Bundle { + val bundle = Flipped(new RAMBundle) + + val rom_address = Output(UInt(Parameters.AddrWidth)) + val rom_data = Input(UInt(Parameters.InstructionWidth)) + + val load_address = Input(UInt(Parameters.AddrWidth)) + val load_finished = Output(Bool()) + }) + + val address = RegInit(0.U(32.W)) + val valid = RegInit(false.B) + + io.bundle.write_strobe := VecInit(Seq.fill(Parameters.WordSize)(false.B)) + io.bundle.address := 0.U + io.bundle.write_data := 0.U + io.bundle.write_enable := false.B + when(address <= (capacity - 1).U) { + io.bundle.write_enable := true.B + io.bundle.write_data := io.rom_data + io.bundle.address := (address << 2.U).asUInt + io.load_address + io.bundle.write_strobe := VecInit(Seq.fill(Parameters.WordSize)(true.B)) + address := address + 1.U + when(address === (capacity - 1).U) { + valid := true.B + } + } + io.load_finished := valid + io.rom_address := address +} diff --git a/lab1/src/main/scala/peripheral/VGADisplay.scala b/lab1/src/main/scala/peripheral/VGADisplay.scala new file mode 100644 index 0000000..268c38c --- /dev/null +++ b/lab1/src/main/scala/peripheral/VGADisplay.scala @@ -0,0 +1,116 @@ +// 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 peripheral + +import chisel3._ + + +class VGASync extends Module { + val io = IO(new Bundle { + val hsync = Output(Bool()) + val vsync = Output(Bool()) + val video_on = Output(Bool()) + val p_tick = Output(Bool()) + val f_tick = Output(Bool()) + val x = Output(UInt(10.W)) + val y = Output(UInt(10.W)) + }) + + val DisplayHorizontal = ScreenInfo.DisplayHorizontal + val DisplayVertical = ScreenInfo.DisplayVertical + + val BorderLeft = 48 + val BorderRight = 16 + val BorderTop = 10 + val BorderBottom = 33 + + val RetraceHorizontal = 96 + val RetraceVertical = 2 + + val MaxHorizontal = DisplayHorizontal + BorderLeft + BorderRight + RetraceHorizontal - 1 + val MaxVertical = DisplayVertical + BorderTop + BorderBottom + RetraceVertical - 1 + + val RetraceHorizontalStart = DisplayHorizontal + BorderRight + val RetraceHorizontalEnd = RetraceHorizontalStart + RetraceHorizontal - 1 + + val RetraceVerticalStart = DisplayVertical + BorderBottom + val RetraceVerticalEnd = RetraceVerticalStart + RetraceVertical - 1 + + val pixel = RegInit(UInt(2.W), 0.U) + val pixel_next = Wire(UInt(2.W)) + val pixel_tick = Wire(Bool()) + + val v_count_reg = RegInit(UInt(10.W), 0.U) + val h_count_reg = RegInit(UInt(10.W), 0.U) + + val v_count_next = Wire(UInt(10.W)) + val h_count_next = Wire(UInt(10.W)) + + val vsync_reg = RegInit(Bool(), false.B) + val hsync_reg = RegInit(Bool(), false.B) + + val vsync_next = Wire(Bool()) + val hsync_next = Wire(Bool()) + + pixel_next := pixel + 1.U + pixel_tick := pixel === 0.U + + h_count_next := Mux( + pixel_tick, + Mux(h_count_reg === MaxHorizontal.U, 0.U, h_count_reg + 1.U), + h_count_reg + ) + + v_count_next := Mux( + pixel_tick && h_count_reg === MaxHorizontal.U, + Mux(v_count_reg === MaxVertical.U, 0.U, v_count_reg + 1.U), + v_count_reg + ) + + hsync_next := h_count_reg >= RetraceHorizontalStart.U && h_count_reg <= RetraceHorizontalEnd.U + vsync_next := v_count_reg >= RetraceVerticalStart.U && v_count_reg <= RetraceVerticalEnd.U + + pixel := pixel_next + hsync_reg := hsync_next + vsync_reg := vsync_next + v_count_reg := v_count_next + h_count_reg := h_count_next + + io.video_on := h_count_reg < DisplayHorizontal.U && v_count_reg < DisplayVertical.U + io.hsync := hsync_reg + io.vsync := vsync_reg + io.x := h_count_reg + io.y := v_count_reg + io.p_tick := pixel_tick + io.f_tick := io.x === 0.U && io.y === 0.U +} + +class VGADisplay extends Module { + val io = IO(new Bundle() { + val x = Output(UInt(16.W)) + val y = Output(UInt(16.W)) + val video_on = Output(Bool()) + + val hsync = Output(Bool()) + val vsync = Output(Bool()) + }) + + val sync = Module(new VGASync) + io.hsync := sync.io.hsync + io.vsync := sync.io.vsync + io.x := sync.io.x + io.y := sync.io.y + io.video_on := sync.io.y +} diff --git a/lab1/src/main/scala/riscv/CPUBundle.scala b/lab1/src/main/scala/riscv/CPUBundle.scala new file mode 100644 index 0000000..2da57c3 --- /dev/null +++ b/lab1/src/main/scala/riscv/CPUBundle.scala @@ -0,0 +1,28 @@ +// 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 chisel3._ +import peripheral.RAMBundle + +class CPUBundle extends Bundle { + val instruction_address = Output(UInt(Parameters.AddrWidth)) + val instruction = Input(UInt(Parameters.DataWidth)) + val memory_bundle = Flipped(new RAMBundle) + val instruction_valid = Input(Bool()) + val deviceSelect = Output(UInt(Parameters.SlaveDeviceCountBits.W)) + val debug_read_address = Input(UInt(Parameters.PhysicalRegisterAddrWidth)) + val debug_read_data = Output(UInt(Parameters.DataWidth)) +} diff --git a/lab1/src/main/scala/riscv/Parameters.scala b/lab1/src/main/scala/riscv/Parameters.scala new file mode 100644 index 0000000..b319498 --- /dev/null +++ b/lab1/src/main/scala/riscv/Parameters.scala @@ -0,0 +1,58 @@ +// 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 chisel3._ +import chisel3.util._ + +object ImplementationType { + val ThreeStage = 0 + val FiveStage = 1 +} + +object Parameters { + val AddrBits = 32 + val AddrWidth = AddrBits.W + + val InstructionBits = 32 + val InstructionWidth = InstructionBits.W + val DataBits = 32 + val DataWidth = DataBits.W + val ByteBits = 8 + val ByteWidth = ByteBits.W + val WordSize = Math.ceil(DataBits / ByteBits).toInt + + val PhysicalRegisters = 32 + val PhysicalRegisterAddrBits = log2Up(PhysicalRegisters) + val PhysicalRegisterAddrWidth = PhysicalRegisterAddrBits.W + + val CSRRegisterAddrBits = 12 + val CSRRegisterAddrWidth = CSRRegisterAddrBits.W + + val InterruptFlagBits = 32 + val InterruptFlagWidth = InterruptFlagBits.W + + val HoldStateBits = 3 + val StallStateWidth = HoldStateBits.W + + val MemorySizeInBytes = 32768 + val MemorySizeInWords = MemorySizeInBytes / 4 + + val EntryAddress = 0x1000.U(Parameters.AddrWidth) + + val MasterDeviceCount = 1 + val SlaveDeviceCount = 8 + val SlaveDeviceCountBits = log2Up(Parameters.SlaveDeviceCount) +} diff --git a/lab1/src/main/scala/riscv/core/ALU.scala b/lab1/src/main/scala/riscv/core/ALU.scala new file mode 100644 index 0000000..a92869e --- /dev/null +++ b/lab1/src/main/scala/riscv/core/ALU.scala @@ -0,0 +1,70 @@ +// 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.core + +import chisel3._ +import chisel3.experimental.ChiselEnum +import chisel3.util._ +import riscv.Parameters + +object ALUFunctions extends ChiselEnum { + val zero, add, sub, sll, slt, xor, or, and, srl, sra, sltu = Value +} + +class ALU extends Module { + val io = IO(new Bundle { + val func = Input(ALUFunctions()) + + val op1 = Input(UInt(Parameters.DataWidth)) + val op2 = Input(UInt(Parameters.DataWidth)) + + val result = Output(UInt(Parameters.DataWidth)) + }) + + io.result := 0.U + switch(io.func) { + is(ALUFunctions.add) { + io.result := io.op1 + io.op2 + } + is(ALUFunctions.sub) { + io.result := io.op1 - io.op2 + } + is(ALUFunctions.sll) { + io.result := io.op1 << io.op2(4, 0) + } + is(ALUFunctions.slt) { + io.result := io.op1.asSInt < io.op2.asSInt + } + is(ALUFunctions.xor) { + io.result := io.op1 ^ io.op2 + } + is(ALUFunctions.or) { + io.result := io.op1 | io.op2 + } + is(ALUFunctions.and) { + io.result := io.op1 & io.op2 + } + is(ALUFunctions.srl) { + io.result := io.op1 >> io.op2(4, 0) + } + is(ALUFunctions.sra) { + io.result := (io.op1.asSInt >> io.op2(4, 0)).asUInt + } + is(ALUFunctions.sltu) { + io.result := io.op1 < io.op2 + } + } + +} diff --git a/lab1/src/main/scala/riscv/core/ALUControl.scala b/lab1/src/main/scala/riscv/core/ALUControl.scala new file mode 100644 index 0000000..ac273f5 --- /dev/null +++ b/lab1/src/main/scala/riscv/core/ALUControl.scala @@ -0,0 +1,86 @@ +// 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.core + +import chisel3._ +import chisel3.util._ + +class ALUControl extends Module { + val io = IO(new Bundle { + val opcode = Input(UInt(7.W)) + val funct3 = Input(UInt(3.W)) + val funct7 = Input(UInt(7.W)) + + val alu_funct = Output(ALUFunctions()) + }) + + io.alu_funct := ALUFunctions.zero + + switch(io.opcode) { + is(InstructionTypes.I) { + io.alu_funct := MuxLookup( + io.funct3, + ALUFunctions.zero, + IndexedSeq( + InstructionsTypeI.addi -> ALUFunctions.add, + InstructionsTypeI.slli -> ALUFunctions.sll, + InstructionsTypeI.slti -> ALUFunctions.slt, + InstructionsTypeI.sltiu -> ALUFunctions.sltu, + InstructionsTypeI.xori -> ALUFunctions.xor, + InstructionsTypeI.ori -> ALUFunctions.or, + InstructionsTypeI.andi -> ALUFunctions.and, + InstructionsTypeI.sri -> Mux(io.funct7(5), ALUFunctions.sra, ALUFunctions.srl) + ), + ) + } + is(InstructionTypes.RM) { + io.alu_funct := MuxLookup( + io.funct3, + ALUFunctions.zero, + IndexedSeq( + InstructionsTypeR.add_sub -> Mux(io.funct7(5), ALUFunctions.sub, ALUFunctions.add), + InstructionsTypeR.sll -> ALUFunctions.sll, + InstructionsTypeR.slt -> ALUFunctions.slt, + InstructionsTypeR.sltu -> ALUFunctions.sltu, + InstructionsTypeR.xor -> ALUFunctions.xor, + InstructionsTypeR.or -> ALUFunctions.or, + InstructionsTypeR.and -> ALUFunctions.and, + InstructionsTypeR.sr -> Mux(io.funct7(5), ALUFunctions.sra, ALUFunctions.srl) + ), + ) + } + is(InstructionTypes.B) { + io.alu_funct := ALUFunctions.add + } + is(InstructionTypes.L) { + io.alu_funct := ALUFunctions.add + } + is(InstructionTypes.S) { + io.alu_funct := ALUFunctions.add + } + is(Instructions.jal) { + io.alu_funct := ALUFunctions.add + } + is(Instructions.jalr) { + io.alu_funct := ALUFunctions.add + } + is(Instructions.lui) { + io.alu_funct := ALUFunctions.add + } + is(Instructions.auipc) { + io.alu_funct := ALUFunctions.add + } + } +} diff --git a/lab1/src/main/scala/riscv/core/CPU.scala b/lab1/src/main/scala/riscv/core/CPU.scala new file mode 100644 index 0000000..5d16bfc --- /dev/null +++ b/lab1/src/main/scala/riscv/core/CPU.scala @@ -0,0 +1,77 @@ +// 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.core + +import chisel3._ +import chisel3.util.Cat +import riscv.{CPUBundle, Parameters} + +class CPU extends Module { + val io = IO(new CPUBundle) + + val regs = Module(new RegisterFile) + val inst_fetch = Module(new InstructionFetch) + val id = Module(new InstructionDecode) + val ex = Module(new Execute) + val mem = Module(new MemoryAccess) + val wb = Module(new WriteBack) + + + io.deviceSelect := mem.io.memory_bundle.address(Parameters.AddrBits - 1, Parameters.AddrBits - Parameters.SlaveDeviceCountBits) + + inst_fetch.io.jump_address_id := ex.io.if_jump_address + inst_fetch.io.jump_flag_id := ex.io.if_jump_flag + inst_fetch.io.instruction_valid := io.instruction_valid + inst_fetch.io.instruction_read_data := io.instruction + io.instruction_address := inst_fetch.io.instruction_address + + regs.io.write_enable := id.io.reg_write_enable + regs.io.write_address := id.io.reg_write_address + regs.io.write_data := wb.io.regs_write_data + regs.io.read_address1 := id.io.regs_reg1_read_address + regs.io.read_address2 := id.io.regs_reg2_read_address + + regs.io.debug_read_address := io.debug_read_address + io.debug_read_data := regs.io.debug_read_data + + id.io.instruction := inst_fetch.io.instruction + + // lab1(cpu) + + + + + + + // lab1(cpu) end + + + mem.io.alu_result := ex.io.mem_alu_result + mem.io.reg2_data := regs.io.read_data2 + mem.io.memory_read_enable := id.io.memory_read_enable + mem.io.memory_write_enable := id.io.memory_write_enable + mem.io.funct3 := inst_fetch.io.instruction(14, 12) + + io.memory_bundle.address := Cat(0.U(Parameters.SlaveDeviceCountBits.W),mem.io.memory_bundle.address(Parameters.AddrBits - 1 - Parameters.SlaveDeviceCountBits, 0)) + io.memory_bundle.write_enable := mem.io.memory_bundle.write_enable + io.memory_bundle.write_data := mem.io.memory_bundle.write_data + io.memory_bundle.write_strobe := mem.io.memory_bundle.write_strobe + mem.io.memory_bundle.read_data := io.memory_bundle.read_data + + wb.io.instruction_address := inst_fetch.io.instruction_address + wb.io.alu_result := ex.io.mem_alu_result + wb.io.memory_read_data := mem.io.wb_memory_read_data + wb.io.regs_write_source := id.io.wb_reg_write_source +} diff --git a/lab1/src/main/scala/riscv/core/Execute.scala b/lab1/src/main/scala/riscv/core/Execute.scala new file mode 100644 index 0000000..d51dc46 --- /dev/null +++ b/lab1/src/main/scala/riscv/core/Execute.scala @@ -0,0 +1,75 @@ +// 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.core + +import chisel3._ +import chisel3.util.{Cat, MuxLookup} +import riscv.Parameters + +class Execute extends Module { + val io = IO(new Bundle { + val instruction = Input(UInt(Parameters.InstructionWidth)) + val instruction_address = Input(UInt(Parameters.AddrWidth)) + val reg1_data = Input(UInt(Parameters.DataWidth)) + val reg2_data = Input(UInt(Parameters.DataWidth)) + val immediate = Input(UInt(Parameters.DataWidth)) + val aluop1_source = Input(UInt(1.W)) + val aluop2_source = Input(UInt(1.W)) + + val mem_alu_result = Output(UInt(Parameters.DataWidth)) + val if_jump_flag = Output(Bool()) + val if_jump_address = Output(UInt(Parameters.DataWidth)) + }) + + val opcode = io.instruction(6, 0) + val funct3 = io.instruction(14, 12) + val funct7 = io.instruction(31, 25) + val rd = io.instruction(11, 7) + val uimm = io.instruction(19, 15) + + val alu = Module(new ALU) + val alu_ctrl = Module(new ALUControl) + + alu_ctrl.io.opcode := opcode + alu_ctrl.io.funct3 := funct3 + alu_ctrl.io.funct7 := funct7 + + // lab1(Execute) + + + + + + + + // lab1(Execute) end + + io.mem_alu_result := alu.io.result + io.if_jump_flag := opcode === Instructions.jal || + (opcode === Instructions.jalr) || + (opcode === InstructionTypes.B) && MuxLookup( + funct3, + false.B, + IndexedSeq( + InstructionsTypeB.beq -> (io.reg1_data === io.reg2_data), + InstructionsTypeB.bne -> (io.reg1_data =/= io.reg2_data), + InstructionsTypeB.blt -> (io.reg1_data.asSInt < io.reg2_data.asSInt), + InstructionsTypeB.bge -> (io.reg1_data.asSInt >= io.reg2_data.asSInt), + InstructionsTypeB.bltu -> (io.reg1_data.asUInt < io.reg2_data.asUInt), + InstructionsTypeB.bgeu -> (io.reg1_data.asUInt >= io.reg2_data.asUInt) + ) + ) + io.if_jump_address := io.immediate + Mux(opcode === Instructions.jalr, io.reg1_data, io.instruction_address) +} diff --git a/lab1/src/main/scala/riscv/core/InstructionDecode.scala b/lab1/src/main/scala/riscv/core/InstructionDecode.scala new file mode 100644 index 0000000..14868a7 --- /dev/null +++ b/lab1/src/main/scala/riscv/core/InstructionDecode.scala @@ -0,0 +1,193 @@ +// 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.core + +import chisel3._ +import chisel3.util._ +import riscv.Parameters + +object InstructionTypes { + val L = "b0000011".U + val I = "b0010011".U + val S = "b0100011".U + val RM = "b0110011".U + val B = "b1100011".U +} + +object Instructions { + val lui = "b0110111".U + val nop = "b0000001".U + val jal = "b1101111".U + val jalr = "b1100111".U + val auipc = "b0010111".U + val csr = "b1110011".U + val fence = "b0001111".U +} + +object InstructionsTypeL { + val lb = "b000".U + val lh = "b001".U + val lw = "b010".U + val lbu = "b100".U + val lhu = "b101".U +} + +object InstructionsTypeI { + val addi = 0.U + val slli = 1.U + val slti = 2.U + val sltiu = 3.U + val xori = 4.U + val sri = 5.U + val ori = 6.U + val andi = 7.U +} + +object InstructionsTypeS { + val sb = "b000".U + val sh = "b001".U + val sw = "b010".U +} + +object InstructionsTypeR { + val add_sub = 0.U + val sll = 1.U + val slt = 2.U + val sltu = 3.U + val xor = 4.U + val sr = 5.U + val or = 6.U + val and = 7.U +} + +object InstructionsTypeM { + val mul = 0.U + val mulh = 1.U + val mulhsu = 2.U + val mulhum = 3.U + val div = 4.U + val divu = 5.U + val rem = 6.U + val remu = 7.U +} + +object InstructionsTypeB { + val beq = "b000".U + val bne = "b001".U + val blt = "b100".U + val bge = "b101".U + val bltu = "b110".U + val bgeu = "b111".U +} + +object InstructionsTypeCSR { + val csrrw = "b001".U + val csrrs = "b010".U + val csrrc = "b011".U + val csrrwi = "b101".U + val csrrsi = "b110".U + val csrrci = "b111".U +} + +object InstructionsNop { + val nop = 0x00000013L.U(Parameters.DataWidth) +} + +object InstructionsRet { + val mret = 0x30200073L.U(Parameters.DataWidth) + val ret = 0x00008067L.U(Parameters.DataWidth) +} + +object InstructionsEnv { + val ecall = 0x00000073L.U(Parameters.DataWidth) + val ebreak = 0x00100073L.U(Parameters.DataWidth) +} + +object ALUOp1Source { + val Register = 0.U(1.W) + val InstructionAddress = 1.U(1.W) +} + +object ALUOp2Source { + val Register = 0.U(1.W) + val Immediate = 1.U(1.W) +} + +object RegWriteSource { + val ALUResult = 0.U(2.W) + val Memory = 1.U(2.W) + //val CSR = 2.U(2.W) + val NextInstructionAddress = 3.U(2.W) +} + +class InstructionDecode extends Module { + val io = IO(new Bundle { + val instruction = Input(UInt(Parameters.InstructionWidth)) + + val regs_reg1_read_address = Output(UInt(Parameters.PhysicalRegisterAddrWidth)) + val regs_reg2_read_address = Output(UInt(Parameters.PhysicalRegisterAddrWidth)) + val ex_immediate = Output(UInt(Parameters.DataWidth)) + val ex_aluop1_source = Output(UInt(1.W)) + val ex_aluop2_source = Output(UInt(1.W)) + val memory_read_enable = Output(Bool()) + val memory_write_enable = Output(Bool()) + val wb_reg_write_source = Output(UInt(2.W)) + val reg_write_enable = Output(Bool()) + val reg_write_address = Output(UInt(Parameters.PhysicalRegisterAddrWidth)) + }) + val opcode = io.instruction(6, 0) + val funct3 = io.instruction(14, 12) + val funct7 = io.instruction(31, 25) + val rd = io.instruction(11, 7) + val rs1 = io.instruction(19, 15) + val rs2 = io.instruction(24, 20) + + io.regs_reg1_read_address := Mux(opcode === Instructions.lui, 0.U(Parameters.PhysicalRegisterAddrWidth), rs1) + io.regs_reg2_read_address := rs2 + val immediate = MuxLookup( + opcode, + Cat(Fill(20, io.instruction(31)), io.instruction(31, 20)), + IndexedSeq( + InstructionTypes.I -> Cat(Fill(21, io.instruction(31)), io.instruction(30, 20)), + InstructionTypes.L -> Cat(Fill(21, io.instruction(31)), io.instruction(30, 20)), + Instructions.jalr -> Cat(Fill(21, io.instruction(31)), io.instruction(30, 20)), + InstructionTypes.S -> Cat(Fill(21, io.instruction(31)), io.instruction(30, 25), io.instruction(11, 7)), + InstructionTypes.B -> Cat(Fill(20, io.instruction(31)), io.instruction(7), io.instruction(30, 25), io.instruction(11, 8), 0.U(1.W)), + Instructions.lui -> Cat(io.instruction(31, 12), 0.U(12.W)), + Instructions.auipc -> Cat(io.instruction(31, 12), 0.U(12.W)), + Instructions.jal -> Cat(Fill(12, io.instruction(31)), io.instruction(19, 12), io.instruction(20), io.instruction(30, 21), 0.U(1.W)) + ) + ) + io.ex_immediate := immediate + io.ex_aluop1_source := Mux( + opcode === Instructions.auipc || opcode === InstructionTypes.B || opcode === Instructions.jal, + ALUOp1Source.InstructionAddress, + ALUOp1Source.Register + ) + + // lab1(InstructionDecode) + + + + + + + + // lab1(InstructionDecode) end + io.reg_write_enable := (opcode === InstructionTypes.RM) || (opcode === InstructionTypes.I) || + (opcode === InstructionTypes.L) || (opcode === Instructions.auipc) || (opcode === Instructions.lui) || + (opcode === Instructions.jal) || (opcode === Instructions.jalr) + io.reg_write_address := io.instruction(11, 7) +} diff --git a/lab1/src/main/scala/riscv/core/InstructionFetch.scala b/lab1/src/main/scala/riscv/core/InstructionFetch.scala new file mode 100644 index 0000000..67ae55c --- /dev/null +++ b/lab1/src/main/scala/riscv/core/InstructionFetch.scala @@ -0,0 +1,50 @@ +// 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.core + +import chisel3._ +import riscv.Parameters + +object ProgramCounter { + val EntryAddress = Parameters.EntryAddress +} + +class InstructionFetch extends Module { + val io = IO(new Bundle { + val jump_flag_id = Input(Bool()) + val jump_address_id = Input(UInt(Parameters.AddrWidth)) + val instruction_read_data = Input(UInt(Parameters.DataWidth)) + val instruction_valid = Input(Bool()) + + val instruction_address = Output(UInt(Parameters.AddrWidth)) + val instruction = Output(UInt(Parameters.InstructionWidth)) + }) + val pc = RegInit(ProgramCounter.EntryAddress) + + when(io.instruction_valid) { + io.instruction := io.instruction_read_data + // lab1(InstructionFetch) + + + + // la1(InstructionFetch) end + + + }.otherwise{ + pc := pc + io.instruction := 0x00000013.U + } + io.instruction_address := pc +} diff --git a/lab1/src/main/scala/riscv/core/MemoryAccess.scala b/lab1/src/main/scala/riscv/core/MemoryAccess.scala new file mode 100644 index 0000000..139c1e3 --- /dev/null +++ b/lab1/src/main/scala/riscv/core/MemoryAccess.scala @@ -0,0 +1,106 @@ +// Copyright 2022 Canbin Huang +// +// 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.core + +import chisel3._ +import chisel3.util._ +import peripheral.RAMBundle +import riscv.Parameters + +class MemoryAccess extends Module { + val io = IO(new Bundle() { + val alu_result = Input(UInt(Parameters.DataWidth)) + val reg2_data = Input(UInt(Parameters.DataWidth)) + val memory_read_enable = Input(Bool()) + val memory_write_enable = Input(Bool()) + val funct3 = Input(UInt(3.W)) + + val wb_memory_read_data = Output(UInt(Parameters.DataWidth)) + + val memory_bundle = Flipped(new RAMBundle) + }) + val mem_address_index = io.alu_result(log2Up(Parameters.WordSize) - 1, 0).asUInt + + io.memory_bundle.write_enable := false.B + io.memory_bundle.write_data := 0.U + io.memory_bundle.address := io.alu_result + io.memory_bundle.write_strobe := VecInit(Seq.fill(Parameters.WordSize)(false.B)) + io.wb_memory_read_data := 0.U + + when(io.memory_read_enable) { + val data = io.memory_bundle.read_data + io.wb_memory_read_data := MuxLookup( + io.funct3, + 0.U, + IndexedSeq( + InstructionsTypeL.lb -> MuxLookup( + mem_address_index, + Cat(Fill(24, data(31)), data(31, 24)), + IndexedSeq( + 0.U -> Cat(Fill(24, data(7)), data(7, 0)), + 1.U -> Cat(Fill(24, data(15)), data(15, 8)), + 2.U -> Cat(Fill(24, data(23)), data(23, 16)) + ) + ), + InstructionsTypeL.lbu -> MuxLookup( + mem_address_index, + Cat(Fill(24, 0.U), data(31, 24)), + IndexedSeq( + 0.U -> Cat(Fill(24, 0.U), data(7, 0)), + 1.U -> Cat(Fill(24, 0.U), data(15, 8)), + 2.U -> Cat(Fill(24, 0.U), data(23, 16)) + ) + ), + InstructionsTypeL.lh -> Mux( + mem_address_index === 0.U, + Cat(Fill(16, data(15)), data(15, 0)), + Cat(Fill(16, data(31)), data(31, 16)) + + ), + InstructionsTypeL.lhu -> Mux( + mem_address_index === 0.U, + Cat(Fill(16, 0.U), data(15, 0)), + Cat(Fill(16, 0.U), data(31, 16)) + ), + InstructionsTypeL.lw -> data + ) + ) + }.elsewhen(io.memory_write_enable) { + io.memory_bundle.write_data := io.reg2_data + io.memory_bundle.write_enable := true.B + io.memory_bundle.write_strobe := VecInit(Seq.fill(Parameters.WordSize)(false.B)) + when(io.funct3 === InstructionsTypeS.sb) { + io.memory_bundle.write_strobe(mem_address_index) := true.B + io.memory_bundle.write_data := io.reg2_data(Parameters.ByteBits, 0) << (mem_address_index << log2Up(Parameters.ByteBits).U) + }.elsewhen(io.funct3 === InstructionsTypeS.sh) { + when(mem_address_index === 0.U) { + for (i <- 0 until Parameters.WordSize / 2) { + io.memory_bundle.write_strobe(i) := true.B + } + io.memory_bundle.write_data := io.reg2_data(Parameters.WordSize / 2 * Parameters.ByteBits, 0) + }.otherwise { + for (i <- Parameters.WordSize / 2 until Parameters.WordSize) { + io.memory_bundle.write_strobe(i) := true.B + } + io.memory_bundle.write_data := io.reg2_data(Parameters.WordSize / 2 * Parameters.ByteBits, 0) << (Parameters + .WordSize / 2 * Parameters.ByteBits) + } + }.elsewhen(io.funct3 === InstructionsTypeS.sw) { + for (i <- 0 until Parameters.WordSize) { + io.memory_bundle.write_strobe(i) := true.B + } + } + } +} diff --git a/lab1/src/main/scala/riscv/core/RegisterFile.scala b/lab1/src/main/scala/riscv/core/RegisterFile.scala new file mode 100644 index 0000000..c59d526 --- /dev/null +++ b/lab1/src/main/scala/riscv/core/RegisterFile.scala @@ -0,0 +1,70 @@ +// 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.core + +import chisel3._ +import riscv.Parameters + +object Registers extends Enumeration { + type Register = Value + val zero, + ra, sp, gp, tp, + t0, t1, t2, fp, + s1, + a0, a1, a2, a3, a4, a5, a6, a7, + s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, + t3, t4, t5, t6 = Value +} + +class RegisterFile extends Module { + val io = IO(new Bundle { + val write_enable = Input(Bool()) + val write_address = Input(UInt(Parameters.PhysicalRegisterAddrWidth)) + val write_data = Input(UInt(Parameters.DataWidth)) + + val read_address1 = Input(UInt(Parameters.PhysicalRegisterAddrWidth)) + val read_address2 = Input(UInt(Parameters.PhysicalRegisterAddrWidth)) + val read_data1 = Output(UInt(Parameters.DataWidth)) + val read_data2 = Output(UInt(Parameters.DataWidth)) + + val debug_read_address = Input(UInt(Parameters.PhysicalRegisterAddrWidth)) + val debug_read_data = Output(UInt(Parameters.DataWidth)) + }) + val registers = RegInit(VecInit(Seq.fill(Parameters.PhysicalRegisters)(0.U(Parameters.DataWidth)))) + + when(!reset.asBool) { + when(io.write_enable && io.write_address =/= 0.U) { + registers(io.write_address) := io.write_data + } + } + + io.read_data1 := Mux( + io.read_address1 === 0.U, + 0.U, + registers(io.read_address1) + ) + + io.read_data2 := Mux( + io.read_address2 === 0.U, + 0.U, + registers(io.read_address2) + ) + + io.debug_read_data := Mux( + io.debug_read_address === 0.U, + 0.U, + registers(io.debug_read_address) + ) +} diff --git a/lab1/src/main/scala/riscv/core/WriteBack.scala b/lab1/src/main/scala/riscv/core/WriteBack.scala new file mode 100644 index 0000000..0401d6c --- /dev/null +++ b/lab1/src/main/scala/riscv/core/WriteBack.scala @@ -0,0 +1,37 @@ +// Copyright 2022 Canbin Huang +// +// 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.core + +import chisel3._ +import chisel3.util._ +import riscv.Parameters + +class WriteBack extends Module { + val io = IO(new Bundle() { + val instruction_address = Input(UInt(Parameters.AddrWidth)) + val alu_result = Input(UInt(Parameters.DataWidth)) + val memory_read_data = Input(UInt(Parameters.DataWidth)) + val regs_write_source = Input(UInt(2.W)) + val regs_write_data = Output(UInt(Parameters.DataWidth)) + }) + io.regs_write_data := MuxLookup( + io.regs_write_source, + io.alu_result, + IndexedSeq( + RegWriteSource.Memory -> io.memory_read_data, + RegWriteSource.NextInstructionAddress -> (io.instruction_address + 4.U) + ) + ) +} diff --git a/lab1/src/test/scala/riscv/TestAnnotations.scala b/lab1/src/test/scala/riscv/TestAnnotations.scala new file mode 100644 index 0000000..1dca602 --- /dev/null +++ b/lab1/src/test/scala/riscv/TestAnnotations.scala @@ -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 +} diff --git a/lab1/src/test/scala/riscv/singlecycle/CPUTest.scala b/lab1/src/test/scala/riscv/singlecycle/CPUTest.scala new file mode 100644 index 0000000..2fda3a2 --- /dev/null +++ b/lab1/src/test/scala/riscv/singlecycle/CPUTest.scala @@ -0,0 +1,125 @@ +// 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.singlecycle + + +import chisel3._ +import chiseltest._ +import org.scalatest.flatspec.AnyFlatSpec +import peripheral.{InstructionROM, Memory, ROMLoader} +import riscv.core.{CPU, ProgramCounter} +import riscv.{Parameters, TestAnnotations} + +import java.nio.{ByteBuffer, ByteOrder} + + +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 mem = Module(new Memory(8192)) + val instruction_rom = Module(new InstructionROM(exeFilename)) + val rom_loader = Module(new ROMLoader(instruction_rom.capacity)) + + rom_loader.io.rom_data := instruction_rom.io.data + rom_loader.io.load_address := Parameters.EntryAddress + instruction_rom.io.address := rom_loader.io.rom_address + + val CPU_clkdiv = RegInit(UInt(2.W), 0.U) + val CPU_tick = Wire(Bool()) + val CPU_next = Wire(UInt(2.W)) + CPU_next := Mux(CPU_clkdiv === 3.U, 0.U, CPU_clkdiv + 1.U) + CPU_tick := CPU_clkdiv === 0.U + CPU_clkdiv := CPU_next + + withClock(CPU_tick.asClock) { + val cpu = Module(new CPU) + cpu.io.debug_read_address := 0.U + cpu.io.instruction_valid := rom_loader.io.load_finished + mem.io.instruction_address := cpu.io.instruction_address + cpu.io.instruction := mem.io.instruction + + + when(!rom_loader.io.load_finished) { + rom_loader.io.bundle <> mem.io.bundle + cpu.io.memory_bundle.read_data := 0.U + }.otherwise { + rom_loader.io.bundle.read_data := 0.U + cpu.io.memory_bundle <> mem.io.bundle + } + + cpu.io.debug_read_address := io.regs_debug_read_address + io.regs_debug_read_data := cpu.io.debug_read_data + } + + mem.io.debug_read_address := io.mem_debug_read_address + io.mem_debug_read_data := mem.io.debug_read_data +} + + +class FibonacciTest extends AnyFlatSpec with ChiselScalatestTester { + behavior of "Single Cycle CPU" + it should "calculate recursively fibonacci(10)" in { + test(new TestTopModule("fibonacci.asmbin")).withAnnotations(TestAnnotations.annos) { c => + 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 "Single Cycle CPU" + it should "quicksort 10 numbers" in { + test(new TestTopModule("quicksort.asmbin")).withAnnotations(TestAnnotations.annos) { c => + 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 ByteAccessTest extends AnyFlatSpec with ChiselScalatestTester { + behavior of "Single Cycle CPU" + it should "store and load single byte" in { + test(new TestTopModule("sb.asmbin")).withAnnotations(TestAnnotations.annos) { c => + 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) + } + } +} diff --git a/lab1/src/test/scala/riscv/singlecycle/ExecuteTest.scala b/lab1/src/test/scala/riscv/singlecycle/ExecuteTest.scala new file mode 100644 index 0000000..68b1a61 --- /dev/null +++ b/lab1/src/test/scala/riscv/singlecycle/ExecuteTest.scala @@ -0,0 +1,72 @@ +// Copyright 2022 hrpccs +// +// 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.singlecycle + +import chisel3._ +import chiseltest._ +import org.scalatest.flatspec.AnyFlatSpec +import riscv.TestAnnotations +import riscv.core.{ALUOp1Source, ALUOp2Source, Execute, InstructionTypes} + +class ExecuteTest extends AnyFlatSpec with ChiselScalatestTester{ + behavior of "Exxecute of Single Cycle CPU" + it should "execute correctly" in { + test(new Execute).withAnnotations(TestAnnotations.annos) { c => + + // add test + c.io.instruction.poke(0x001101b3L.U) //x3 = x2 + x1 + //c.io.immediate.poke(0.U) + //c.io.aluop1_source.poke(0.U) + //c.io.aluop2_source.poke(0.U) + + var x = 0 + for (x <- 0 to 100) { + val op1 = scala.util.Random.nextInt(429496729) + val op2 = scala.util.Random.nextInt(429496729) + val result = op1 + op2 + val addr = scala.util.Random.nextInt(32) + + c.io.reg1_data.poke(op1.U) + c.io.reg2_data.poke(op2.U) + + c.clock.step() + c.io.mem_alu_result.expect(result.U) + c.io.if_jump_flag.expect(0.U) + } + + // beq test + c.io.instruction.poke(0x00208163L.U) //pc + 2 if x1 === x2 + c.io.instruction_address.poke(2.U) + c.io.immediate.poke(2.U) + c.io.aluop1_source.poke(1.U) + c.io.aluop2_source.poke(1.U) + c.clock.step() + + // equ + c.io.reg1_data.poke(9.U) + c.io.reg2_data.poke(9.U) + c.clock.step()//add + c.io.if_jump_flag.expect(1.U) + c.io.if_jump_address.expect(4.U) + + // not equ + c.io.reg1_data.poke(9.U) + c.io.reg2_data.poke(19.U) + c.clock.step() + c.io.if_jump_flag.expect(0.U) + c.io.if_jump_address.expect(4.U) + } + } +} diff --git a/lab1/src/test/scala/riscv/singlecycle/InstructionDecoderTest.scala b/lab1/src/test/scala/riscv/singlecycle/InstructionDecoderTest.scala new file mode 100644 index 0000000..bed90a3 --- /dev/null +++ b/lab1/src/test/scala/riscv/singlecycle/InstructionDecoderTest.scala @@ -0,0 +1,46 @@ +// Copyright 2022 hrpccs +// +// 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.singlecycle + +import chisel3._ +import chiseltest._ +import org.scalatest.flatspec.AnyFlatSpec +import riscv.TestAnnotations +import riscv.core.{ALUOp1Source, ALUOp2Source, InstructionDecode, InstructionTypes} + +class InstructionDecoderTest extends AnyFlatSpec with ChiselScalatestTester{ + behavior of "InstructionDecoder of Single Cycle CPU" + it should "produce correct control signal" in { + test(new InstructionDecode).withAnnotations(TestAnnotations.annos) { c => + c.io.instruction.poke(0x00a02223L.U) //S-type + c.io.ex_aluop1_source.expect(ALUOp1Source.Register) + c.io.ex_aluop2_source.expect(ALUOp2Source.Immediate) + c.io.regs_reg1_read_address.expect(0.U) + c.io.regs_reg2_read_address.expect(10.U) + c.clock.step() + + c.io.instruction.poke(0x000022b7L.U) //lui + c.io.regs_reg1_read_address.expect(0.U) + c.io.ex_aluop1_source.expect(ALUOp1Source.Register) + c.io.ex_aluop2_source.expect(ALUOp2Source.Immediate) + c.clock.step() + + c.io.instruction.poke(0x002081b3L.U) //add + c.io.ex_aluop1_source.expect(ALUOp1Source.Register) + c.io.ex_aluop2_source.expect(ALUOp2Source.Register) + c.clock.step() + } + } +} diff --git a/lab1/src/test/scala/riscv/singlecycle/InstructionFetchTest.scala b/lab1/src/test/scala/riscv/singlecycle/InstructionFetchTest.scala new file mode 100644 index 0000000..691fcc3 --- /dev/null +++ b/lab1/src/test/scala/riscv/singlecycle/InstructionFetchTest.scala @@ -0,0 +1,58 @@ +// Copyright 2022 hrpccs +// +// 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.singlecycle + +import chisel3._ +import chiseltest._ +import org.scalatest.flatspec.AnyFlatSpec +import riscv.TestAnnotations +import riscv.Parameters +import riscv.core.{ALUOp1Source, ALUOp2Source, InstructionFetch, InstructionTypes,ProgramCounter} + + +import scala.math.pow +import scala.util.Random + + + +class InstructionFetchTest extends AnyFlatSpec with ChiselScalatestTester{ + behavior of "InstructionFetch of Single Cycle CPU" + it should "fetch instruction" in { + test(new InstructionFetch).withAnnotations(TestAnnotations.annos) { c => + val entry = 0x1000 + var pre = entry + var cur = pre + c.io.instruction_valid.poke(true.B) + var x = 0 + for (x <- 0 to 100) { + Random.nextInt(2) match { + case 0 => // no jump + cur = pre + 4 + c.io.jump_flag_id.poke(false.B) + c.clock.step() + c.io.instruction_address.expect(cur) + pre = pre + 4 + case 1 => // jump + c.io.jump_flag_id.poke(true.B) + c.io.jump_address_id.poke(entry) + c.clock.step() + c.io.instruction_address.expect(entry) + pre = entry + } + } + + } + } +} diff --git a/lab1/src/test/scala/riscv/singlecycle/RegisterFileTest.scala b/lab1/src/test/scala/riscv/singlecycle/RegisterFileTest.scala new file mode 100644 index 0000000..1f50048 --- /dev/null +++ b/lab1/src/test/scala/riscv/singlecycle/RegisterFileTest.scala @@ -0,0 +1,69 @@ +// 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.singlecycle + +import chisel3._ +import chiseltest._ +import org.scalatest.flatspec.AnyFlatSpec +import riscv.TestAnnotations +import riscv.core.RegisterFile + +class RegisterFileTest extends AnyFlatSpec with ChiselScalatestTester { + behavior of "Register File of Single Cycle 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.clock.step() + 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) + } + } + +} diff --git a/lab1/verilog/basys3/test.v b/lab1/verilog/basys3/test.v new file mode 100644 index 0000000..9f3f6a6 --- /dev/null +++ b/lab1/verilog/basys3/test.v @@ -0,0 +1,35 @@ +`timescale 1ns / 1ps +////////////////////////////////////////////////////////////////////////////////// +// Company: +// Engineer: +// +// Create Date: 2021/12/17 16:31:05 +// Design Name: +// Module Name: test +// Project Name: +// Target Devices: +// Tool Versions: +// Description: +// +// Dependencies: +// +// Revision: +// Revision 0.01 - File Created +// Additional Comments: +// +////////////////////////////////////////////////////////////////////////////////// + + +module test(); +reg clock; +reg reset; +initial begin +clock = 0; +forever #1 clock = ~clock; +end +initial begin +reset = 1; +#2 reset = 0; +end +Top top(clock, reset); +endmodule diff --git a/lab1/verilog/pynq/TMDS_PLLVR.v b/lab1/verilog/pynq/TMDS_PLLVR.v new file mode 100644 index 0000000..1bc4dfb --- /dev/null +++ b/lab1/verilog/pynq/TMDS_PLLVR.v @@ -0,0 +1,221 @@ + +// file: TMDS_PLLVR.v +// +// (c) Copyright 2008 - 2013 Xilinx, Inc. All rights reserved. +// +// This file contains confidential and proprietary information +// of Xilinx, Inc. and is protected under U.S. and +// international copyright and other intellectual property +// laws. +// +// DISCLAIMER +// This disclaimer is not a license and does not grant any +// rights to the materials distributed herewith. Except as +// otherwise provided in a valid license issued to you by +// Xilinx, and to the maximum extent permitted by applicable +// law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND +// WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES +// AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING +// BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON- +// INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and +// (2) Xilinx shall not be liable (whether in contract or tort, +// including negligence, or under any other theory of +// liability) for any loss or damage of any kind or nature +// related to, arising under or in connection with these +// materials, including for any direct, or any indirect, +// special, incidental, or consequential loss or damage +// (including loss of data, profits, goodwill, or any type of +// loss or damage suffered as a result of any action brought +// by a third party) even if such damage or loss was +// reasonably foreseeable or Xilinx had been advised of the +// possibility of the same. +// +// CRITICAL APPLICATIONS +// Xilinx products are not designed or intended to be fail- +// safe, or for use in any application requiring fail-safe +// performance, such as life-support or safety devices or +// systems, Class III medical devices, nuclear facilities, +// applications related to the deployment of airbags, or any +// other applications that could lead to death, personal +// injury, or severe property or environmental damage +// (individually and collectively, "Critical +// Applications"). Customer assumes the sole risk and +// liability of any use of Xilinx products in Critical +// Applications, subject only to applicable laws and +// regulations governing limitations on product liability. +// +// THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS +// PART OF THIS FILE AT ALL TIMES. +// +//---------------------------------------------------------------------------- +// User entered comments +//---------------------------------------------------------------------------- +// None +// +//---------------------------------------------------------------------------- +// Output Output Phase Duty Cycle Pk-to-Pk Phase +// Clock Freq (MHz) (degrees) (%) Jitter (ps) Error (ps) +//---------------------------------------------------------------------------- +// __clkout__250.00000______0.000______50.0______200.536____237.727 +// _clkoutd__100.00000______0.000______50.0______226.965____237.727 +// +//---------------------------------------------------------------------------- +// Input Clock Freq (MHz) Input Jitter (UI) +//---------------------------------------------------------------------------- +// __primary__________25.000____________0.010 + +`timescale 1ps/1ps + +(* CORE_GENERATION_INFO = "TMDS_PLLVR,clk_wiz_v6_0_5_0_0,{component_name=TMDS_PLLVR,use_phase_alignment=true,use_min_o_jitter=false,use_max_i_jitter=false,use_dyn_phase_shift=false,use_inclk_switchover=false,use_dyn_reconfig=false,enable_axi=0,feedback_source=FDBK_AUTO,PRIMITIVE=PLL,num_out_clk=2,clkin1_period=40.000,clkin2_period=10.0,use_power_down=false,use_reset=true,use_locked=true,use_inclk_stopped=false,feedback_type=SINGLE,CLOCK_MGR_TYPE=NA,manual_override=true}" *) + +module TMDS_PLLVR + ( + // Clock out ports + output clkout, + output clkoutd, + // Status and control signals + input reset, + output lock, + // Clock in ports + input clkin + ); + + TMDS_PLLVR_clk_wiz inst + ( + // Clock out ports + .clkout(clkout), + .clkoutd(clkoutd), + // Status and control signals + .reset(reset), + .lock(lock), + // Clock in ports + .clk_in1(clkin) + ); + +endmodule + + +module TMDS_PLLVR_clk_wiz + + (// Clock in ports + // Clock out ports + output clkout, + output clkoutd, + // Status and control signals + input reset, + output lock, + input clk_in1 + ); + // Input buffering + //------------------------------------ +wire clk_in1_TMDS_PLLVR; +wire clk_in2_TMDS_PLLVR; + IBUF clkin1_ibufg + (.O (clk_in1_TMDS_PLLVR), + .I (clk_in1)); + + + + + // Clocking PRIMITIVE + //------------------------------------ + + // Instantiation of the MMCM PRIMITIVE + // * Unused inputs are tied off + // * Unused outputs are labeled unused + + wire clkout_TMDS_PLLVR; + wire clkoutd_TMDS_PLLVR; + wire clk_out3_TMDS_PLLVR; + wire clk_out4_TMDS_PLLVR; + wire clk_out5_TMDS_PLLVR; + wire clk_out6_TMDS_PLLVR; + wire clk_out7_TMDS_PLLVR; + + wire [15:0] do_unused; + wire drdy_unused; + wire psdone_unused; + wire lock_int; + wire clkfbout_TMDS_PLLVR; + wire clkfbout_buf_TMDS_PLLVR; + wire clkfboutb_unused; + wire clkout2_unused; + wire clkout3_unused; + wire clkout4_unused; + wire clkout5_unused; + wire clkout6_unused; + wire clkfbstopped_unused; + wire clkinstopped_unused; + wire reset_high; + + PLLE2_ADV + #(.BANDWIDTH ("OPTIMIZED"), + .COMPENSATION ("ZHOLD"), + .STARTUP_WAIT ("FALSE"), + .DIVCLK_DIVIDE (1), + .CLKFBOUT_MULT (40), + .CLKFBOUT_PHASE (0.000), + .CLKOUT0_DIVIDE (4), + .CLKOUT0_PHASE (0.000), + .CLKOUT0_DUTY_CYCLE (0.500), + .CLKOUT1_DIVIDE (10), + .CLKOUT1_PHASE (0.000), + .CLKOUT1_DUTY_CYCLE (0.500), + .CLKIN1_PERIOD (40.000)) + plle2_adv_inst + // Output clocks + ( + .CLKFBOUT (clkfbout_TMDS_PLLVR), + .CLKOUT0 (clkout_TMDS_PLLVR), + .CLKOUT1 (clkoutd_TMDS_PLLVR), + .CLKOUT2 (clkout2_unused), + .CLKOUT3 (clkout3_unused), + .CLKOUT4 (clkout4_unused), + .CLKOUT5 (clkout5_unused), + // Input clock control + .CLKFBIN (clkfbout_buf_TMDS_PLLVR), + .CLKIN1 (clk_in1_TMDS_PLLVR), + .CLKIN2 (1'b0), + // Tied to always select the primary input clock + .CLKINSEL (1'b1), + // Ports for dynamic reconfiguration + .DADDR (7'h0), + .DCLK (1'b0), + .DEN (1'b0), + .DI (16'h0), + .DO (do_unused), + .DRDY (drdy_unused), + .DWE (1'b0), + // Other control and status signals + .LOCKED (lock_int), + .PWRDWN (1'b0), + .RST (reset_high)); + assign reset_high = reset; + + assign lock = lock_int; +// Clock Monitor clock assigning +//-------------------------------------- + // Output buffering + //----------------------------------- + + BUFG clkf_buf + (.O (clkfbout_buf_TMDS_PLLVR), + .I (clkfbout_TMDS_PLLVR)); + + + + + + + BUFG clkout1_buf + (.O (clkout), + .I (clkout_TMDS_PLLVR)); + + + BUFG clkout2_buf + (.O (clkoutd), + .I (clkoutd_TMDS_PLLVR)); + + + +endmodule diff --git a/lab1/verilog/pynq/design_1_wrapper.v b/lab1/verilog/pynq/design_1_wrapper.v new file mode 100644 index 0000000..5e2092d --- /dev/null +++ b/lab1/verilog/pynq/design_1_wrapper.v @@ -0,0 +1,136 @@ +//Copyright 1986-2020 Xilinx, Inc. All Rights Reserved. +//-------------------------------------------------------------------------------- +//Tool Version: Vivado v.2020.1 (win64) Build 2902540 Wed May 27 19:54:49 MDT 2020 +//Date : Thu Jun 9 10:53:21 2022 +//Host : DESKTOP-UR8AHA2 running 64-bit major release (build 9200) +//Command : generate_target design_1_wrapper.bd +//Design : design_1_wrapper +//Purpose : IP block netlist +//-------------------------------------------------------------------------------- +`timescale 1 ps / 1 ps + +module design_1_wrapper + (DDR_addr, + DDR_ba, + DDR_cas_n, + DDR_ck_n, + DDR_ck_p, + DDR_cke, + DDR_cs_n, + DDR_dm, + DDR_dq, + DDR_dqs_n, + DDR_dqs_p, + DDR_odt, + DDR_ras_n, + DDR_reset_n, + DDR_we_n, + FIXED_IO_ddr_vrn, + FIXED_IO_ddr_vrp, + FIXED_IO_mio, + FIXED_IO_ps_clk, + FIXED_IO_ps_porb, + FIXED_IO_ps_srstb, + io_hdmi_clk_n, + io_hdmi_clk_p, + io_hdmi_data_n, + io_hdmi_data_p, + io_hdmi_hpdn, + io_led, + io_rx, + io_tx, + reset); + inout [14:0]DDR_addr; + inout [2:0]DDR_ba; + inout DDR_cas_n; + inout DDR_ck_n; + inout DDR_ck_p; + inout DDR_cke; + inout DDR_cs_n; + inout [3:0]DDR_dm; + inout [31:0]DDR_dq; + inout [3:0]DDR_dqs_n; + inout [3:0]DDR_dqs_p; + inout DDR_odt; + inout DDR_ras_n; + inout DDR_reset_n; + inout DDR_we_n; + inout FIXED_IO_ddr_vrn; + inout FIXED_IO_ddr_vrp; + inout [53:0]FIXED_IO_mio; + inout FIXED_IO_ps_clk; + inout FIXED_IO_ps_porb; + inout FIXED_IO_ps_srstb; + output io_hdmi_clk_n; + output io_hdmi_clk_p; + output [2:0]io_hdmi_data_n; + output [2:0]io_hdmi_data_p; + output io_hdmi_hpdn; + output [3:0]io_led; + input io_rx; + output io_tx; + input reset; + + wire [14:0]DDR_addr; + wire [2:0]DDR_ba; + wire DDR_cas_n; + wire DDR_ck_n; + wire DDR_ck_p; + wire DDR_cke; + wire DDR_cs_n; + wire [3:0]DDR_dm; + wire [31:0]DDR_dq; + wire [3:0]DDR_dqs_n; + wire [3:0]DDR_dqs_p; + wire DDR_odt; + wire DDR_ras_n; + wire DDR_reset_n; + wire DDR_we_n; + wire FIXED_IO_ddr_vrn; + wire FIXED_IO_ddr_vrp; + wire [53:0]FIXED_IO_mio; + wire FIXED_IO_ps_clk; + wire FIXED_IO_ps_porb; + wire FIXED_IO_ps_srstb; + wire io_hdmi_clk_n; + wire io_hdmi_clk_p; + wire [2:0]io_hdmi_data_n; + wire [2:0]io_hdmi_data_p; + wire io_hdmi_hpdn; + wire [3:0]io_led; + wire io_rx; + wire io_tx; + wire reset; + + design_1 design_1_i + (.DDR_addr(DDR_addr), + .DDR_ba(DDR_ba), + .DDR_cas_n(DDR_cas_n), + .DDR_ck_n(DDR_ck_n), + .DDR_ck_p(DDR_ck_p), + .DDR_cke(DDR_cke), + .DDR_cs_n(DDR_cs_n), + .DDR_dm(DDR_dm), + .DDR_dq(DDR_dq), + .DDR_dqs_n(DDR_dqs_n), + .DDR_dqs_p(DDR_dqs_p), + .DDR_odt(DDR_odt), + .DDR_ras_n(DDR_ras_n), + .DDR_reset_n(DDR_reset_n), + .DDR_we_n(DDR_we_n), + .FIXED_IO_ddr_vrn(FIXED_IO_ddr_vrn), + .FIXED_IO_ddr_vrp(FIXED_IO_ddr_vrp), + .FIXED_IO_mio(FIXED_IO_mio), + .FIXED_IO_ps_clk(FIXED_IO_ps_clk), + .FIXED_IO_ps_porb(FIXED_IO_ps_porb), + .FIXED_IO_ps_srstb(FIXED_IO_ps_srstb), + .io_hdmi_clk_n(io_hdmi_clk_n), + .io_hdmi_clk_p(io_hdmi_clk_p), + .io_hdmi_data_n(io_hdmi_data_n), + .io_hdmi_data_p(io_hdmi_data_p), + .io_hdmi_hpdn(io_hdmi_hpdn), + .io_led(io_led), + .io_rx(io_rx), + .io_tx(io_tx), + .reset(reset)); +endmodule diff --git a/lab1/verilog/pynq/test.v b/lab1/verilog/pynq/test.v new file mode 100644 index 0000000..9f3f6a6 --- /dev/null +++ b/lab1/verilog/pynq/test.v @@ -0,0 +1,35 @@ +`timescale 1ns / 1ps +////////////////////////////////////////////////////////////////////////////////// +// Company: +// Engineer: +// +// Create Date: 2021/12/17 16:31:05 +// Design Name: +// Module Name: test +// Project Name: +// Target Devices: +// Tool Versions: +// Description: +// +// Dependencies: +// +// Revision: +// Revision 0.01 - File Created +// Additional Comments: +// +////////////////////////////////////////////////////////////////////////////////// + + +module test(); +reg clock; +reg reset; +initial begin +clock = 0; +forever #1 clock = ~clock; +end +initial begin +reset = 1; +#2 reset = 0; +end +Top top(clock, reset); +endmodule diff --git a/lab1/verilog/verilator/sim_main.cpp b/lab1/verilog/verilator/sim_main.cpp new file mode 100644 index 0000000..78c9df5 --- /dev/null +++ b/lab1/verilog/verilator/sim_main.cpp @@ -0,0 +1,245 @@ +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "VTop.h" // From Verilating "top.v" + + +class Memory { + std::vector memory; + + public: + Memory(size_t size) : memory(size, 0) {} + uint32_t read(size_t address) { + address = address / 4; + if (address >= memory.size()) { +// printf("invalid read address 0x%08x\n", address * 4); + return 0; + } + + return memory[address]; + } + + uint32_t readInst(size_t address) { + address = address / 4; + if (address >= memory.size()) { +// printf("invalid read Inst address 0x%08x\n", address * 4); + return 0; + } + + return memory[address]; + } + + void write(size_t address, uint32_t value, bool write_strobe[4]) { + address = address / 4; + uint32_t write_mask = 0; + if (write_strobe[0]) write_mask |= 0x000000FF; + if (write_strobe[1]) write_mask |= 0x0000FF00; + if (write_strobe[2]) write_mask |= 0x00FF0000; + if (write_strobe[3]) write_mask |= 0xFF000000; + if (address >= memory.size()) { +// printf("invalid write address 0x%08x\n", address * 4); + return; + } + memory[address] = (memory[address] & ~write_mask) | (value & write_mask); + } + + void load_binary(std::string const& filename, size_t load_address = 0x1000) { + std::ifstream file(filename, std::ios::binary); + if (!file) { + throw std::runtime_error("Could not open file " + filename); + } + file.seekg(0, std::ios::end); + size_t size = file.tellg(); + if (load_address + size > memory.size() * 4) { + throw std::runtime_error("File " + filename + " is too large (File is " + + std::to_string(size) + " bytes. Memory is " + + std::to_string(memory.size() * 4 - load_address) + " bytes.)"); + } + file.seekg(0, std::ios::beg); + for (int i = 0; i < size / 4; ++i) { + file.read(reinterpret_cast(&memory[i + load_address / 4]), + sizeof(uint32_t)); + } + } +}; + +class VCDTracer { + VerilatedVcdC* tfp = nullptr; + + public: + void enable(std::string const& filename, VTop& top) { + Verilated::traceEverOn(true); + tfp = new VerilatedVcdC; + top.trace(tfp, 99); + tfp->open(filename.c_str()); + tfp->set_time_resolution("1ps"); + tfp->set_time_unit("1ns"); + if (!tfp->isOpen()) { + throw std::runtime_error("Failed to open VCD dump file " + filename); + } + } + + void dump(vluint64_t time) { + if (tfp) { + tfp->dump(time); + } + } + + ~VCDTracer() { + if (tfp) { + tfp->close(); + delete tfp; + } + } +}; + +uint32_t parse_number(std::string const& str) { + if (str.size() > 2) { + auto&& prefix = str.substr(0, 2); + if (prefix == "0x" || prefix == "0X") { + return std::stoul(str.substr(2), nullptr, 16); + } + } + return std::stoul(str); +} + +class Simulator { + vluint64_t main_time = 0; + vluint64_t max_sim_time = 10000; + uint32_t halt_address = 0; + size_t memory_words = 1024 * 1024; // 4MB + bool dump_vcd = false; + std::unique_ptr top; + std::unique_ptr vcd_tracer; + std::unique_ptr memory; + bool dump_signature = false; + unsigned long signature_begin, signature_end; + std::string signature_filename; + std::string instruction_filename; + + public: + void parse_args(std::vector const& args) { + if (auto it = std::find(args.begin(), args.end(), "-halt"); + it != args.end()) { + halt_address = parse_number(*(it + 1)); + } + + if (auto it = std::find(args.begin(), args.end(), "-memory"); + it != args.end()) { + memory_words = std::stoul(*(it + 1)); + } + + if (auto it = std::find(args.begin(), args.end(), "-time"); + it != args.end()) { + max_sim_time = std::stoul(*(it + 1)); + } + + if (auto it = std::find(args.begin(), args.end(), "-vcd"); + it != args.end()) { + vcd_tracer->enable(*(it + 1), *top); + } + + if (auto it = std::find(args.begin(), args.end(), "-signature"); + it != args.end()) { + dump_signature = true; + signature_begin = parse_number(*(it + 1)); + signature_end = parse_number(*(it + 2)); + signature_filename = *(it + 3); + } + + if (auto it = std::find(args.begin(), args.end(), "-instruction"); + it != args.end()) { + instruction_filename = *(it + 1); + } + } + + Simulator(std::vector const& args) + : top(std::make_unique()), + vcd_tracer(std::make_unique()) { + parse_args(args); + memory = std::make_unique(memory_words); + if (!instruction_filename.empty()) { + memory->load_binary(instruction_filename); + } + } + + void run() { + top->reset = 1; + top->clock = 0; + top->eval(); + vcd_tracer->dump(main_time); + uint32_t data_memory_read_word = 0; + uint32_t inst_memory_read_word = 0; + uint32_t counter = 0; + uint32_t clocktime = 1; + bool memory_write_strobe[4] = {false}; + while (main_time < max_sim_time && !Verilated::gotFinish()) { + ++main_time; + ++counter; + if(counter > clocktime){ + top->clock = !top->clock; + counter = 0; + } + if (main_time > 2) { + top->reset = 0; + } +// top->io_mem_slave_read_data = memory_read_word; + top->io_instruction_valid = 1; + top->io_memory_bundle_read_data = data_memory_read_word; + top->io_instruction = inst_memory_read_word; + top->clock = !top->clock; + top->eval(); + + + data_memory_read_word = memory->read(top->io_memory_bundle_address); + + + inst_memory_read_word = memory->readInst(top->io_instruction_address); + + if (top->io_memory_bundle_write_enable) { + memory_write_strobe[0] = top->io_memory_bundle_write_strobe_0; + memory_write_strobe[1] = top->io_memory_bundle_write_strobe_1; + memory_write_strobe[2] = top->io_memory_bundle_write_strobe_2; + memory_write_strobe[3] = top->io_memory_bundle_write_strobe_3; + memory->write(top->io_memory_bundle_address, top->io_memory_bundle_write_data, + memory_write_strobe); + } + vcd_tracer->dump(main_time); + if (halt_address) { + if (memory->read(halt_address) == 0xBABECAFE) { + break; + } + } + } + + if (dump_signature) { + char data[9] = {0}; + std::ofstream signature_file(signature_filename); + for (size_t addr = signature_begin; addr < signature_end; addr += 4) { + snprintf(data, 9, "%08x", memory->read(addr)); + signature_file << data << std::endl; + } + } + } + + ~Simulator() { + if (top) { + top->final(); + } + } +}; + +int main(int argc, char** argv) { + Verilated::commandArgs(argc, argv); + std::vector args(argv, argv + argc); + Simulator simulator(args); + simulator.run(); + return 0; +} diff --git a/lab1/vivado/basys3/basys3.xdc b/lab1/vivado/basys3/basys3.xdc new file mode 100644 index 0000000..9864546 --- /dev/null +++ b/lab1/vivado/basys3/basys3.xdc @@ -0,0 +1,307 @@ +# 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. + +## Clock signal +set_property PACKAGE_PIN W5 [get_ports clock] + set_property IOSTANDARD LVCMOS33 [get_ports clock] + create_clock -add -name sys_clk_pin -period 20.00 -waveform {0 5} [get_ports clock] + +## Switches +set_property PACKAGE_PIN V17 [get_ports {io_switch[0]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_switch[0]}] +set_property PACKAGE_PIN V16 [get_ports {io_switch[1]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_switch[1]}] +set_property PACKAGE_PIN W16 [get_ports {io_switch[2]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_switch[2]}] +set_property PACKAGE_PIN W17 [get_ports {io_switch[3]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_switch[3]}] +set_property PACKAGE_PIN W15 [get_ports {io_switch[4]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_switch[4]}] +set_property PACKAGE_PIN V15 [get_ports {io_switch[5]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_switch[5]}] +set_property PACKAGE_PIN W14 [get_ports {io_switch[6]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_switch[6]}] +set_property PACKAGE_PIN W13 [get_ports {io_switch[7]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_switch[7]}] +set_property PACKAGE_PIN V2 [get_ports {io_switch[8]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_switch[8]}] +set_property PACKAGE_PIN T3 [get_ports {io_switch[9]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_switch[9]}] +set_property PACKAGE_PIN T2 [get_ports {io_switch[10]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_switch[10]}] +set_property PACKAGE_PIN R3 [get_ports {io_switch[11]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_switch[11]}] +set_property PACKAGE_PIN W2 [get_ports {io_switch[12]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_switch[12]}] +set_property PACKAGE_PIN U1 [get_ports {io_switch[13]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_switch[13]}] +set_property PACKAGE_PIN T1 [get_ports {io_switch[14]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_switch[14]}] +set_property PACKAGE_PIN R2 [get_ports {io_switch[15]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_switch[15]}] + + +## LEDs +set_property PACKAGE_PIN U16 [get_ports {io_led[0]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_led[0]}] +set_property PACKAGE_PIN E19 [get_ports {io_led[1]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_led[1]}] +set_property PACKAGE_PIN U19 [get_ports {io_led[2]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_led[2]}] +set_property PACKAGE_PIN V19 [get_ports {io_led[3]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_led[3]}] +set_property PACKAGE_PIN W18 [get_ports {io_led[4]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_led[4]}] +set_property PACKAGE_PIN U15 [get_ports {io_led[5]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_led[5]}] +set_property PACKAGE_PIN U14 [get_ports {io_led[6]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_led[6]}] +set_property PACKAGE_PIN V14 [get_ports {io_led[7]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_led[7]}] +set_property PACKAGE_PIN V13 [get_ports {io_led[8]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_led[8]}] +set_property PACKAGE_PIN V3 [get_ports {io_led[9]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_led[9]}] +set_property PACKAGE_PIN W3 [get_ports {io_led[10]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_led[10]}] +set_property PACKAGE_PIN U3 [get_ports {io_led[11]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_led[11]}] +set_property PACKAGE_PIN P3 [get_ports {io_led[12]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_led[12]}] +set_property PACKAGE_PIN N3 [get_ports {io_led[13]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_led[13]}] +set_property PACKAGE_PIN P1 [get_ports {io_led[14]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_led[14]}] +set_property PACKAGE_PIN L1 [get_ports {io_led[15]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_led[15]}] + + +##7 segment display +set_property PACKAGE_PIN U7 [get_ports io_segs[0]] + set_property IOSTANDARD LVCMOS33 [get_ports io_segs[0]] +set_property PACKAGE_PIN V5 [get_ports io_segs[1]] + set_property IOSTANDARD LVCMOS33 [get_ports io_segs[1]] +set_property PACKAGE_PIN U5 [get_ports io_segs[2]] + set_property IOSTANDARD LVCMOS33 [get_ports io_segs[2]] +set_property PACKAGE_PIN V8 [get_ports io_segs[3]] + set_property IOSTANDARD LVCMOS33 [get_ports io_segs[3]] +set_property PACKAGE_PIN U8 [get_ports io_segs[4]] + set_property IOSTANDARD LVCMOS33 [get_ports io_segs[4]] +set_property PACKAGE_PIN W6 [get_ports io_segs[5]] + set_property IOSTANDARD LVCMOS33 [get_ports io_segs[5]] +set_property PACKAGE_PIN W7 [get_ports io_segs[6]] + set_property IOSTANDARD LVCMOS33 [get_ports io_segs[6]] +set_property PACKAGE_PIN V7 [get_ports io_segs[7]] + set_property IOSTANDARD LVCMOS33 [get_ports io_segs[7]] + +set_property PACKAGE_PIN U2 [get_ports {io_digit_mask[0]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_digit_mask[0]}] +set_property PACKAGE_PIN U4 [get_ports {io_digit_mask[1]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_digit_mask[1]}] +set_property PACKAGE_PIN V4 [get_ports {io_digit_mask[2]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_digit_mask[2]}] +set_property PACKAGE_PIN W4 [get_ports {io_digit_mask[3]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_digit_mask[3]}] + + +##Buttons +set_property PACKAGE_PIN U18 [get_ports reset] + set_property IOSTANDARD LVCMOS33 [get_ports reset] +#set_property PACKAGE_PIN T18 [get_ports io_freqIncrease] + #set_property IOSTANDARD LVCMOS33 [get_ports io_freqIncrease] +#set_property PACKAGE_PIN W19 [get_ports io_widthIncrease] + #set_property IOSTANDARD LVCMOS33 [get_ports io_widthIncrease] +#set_property PACKAGE_PIN T17 [get_ports io_widthDecrease] + #set_property IOSTANDARD LVCMOS33 [get_ports io_widthDecrease] +#set_property PACKAGE_PIN U17 [get_ports io_freqDecrease] + #set_property IOSTANDARD LVCMOS33 [get_ports io_freqDecrease] + + + +##Pmod Header JA +##Sch name = JA1 +#set_property PACKAGE_PIN J1 [get_ports {JA[0]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JA[0]}] +##Sch name = JA2 +#set_property PACKAGE_PIN L2 [get_ports {JA[1]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JA[1]}] +##Sch name = JA3 +#set_property PACKAGE_PIN J2 [get_ports {JA[2]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JA[2]}] +##Sch name = JA4 +#set_property PACKAGE_PIN G2 [get_ports {JA[3]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JA[3]}] +##Sch name = JA7 +#set_property PACKAGE_PIN H1 [get_ports {JA[4]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JA[4]}] +##Sch name = JA8 +#set_property PACKAGE_PIN K2 [get_ports {JA[5]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JA[5]}] +##Sch name = JA9 +#set_property PACKAGE_PIN H2 [get_ports {JA[6]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JA[6]}] +##Sch name = JA10 +#set_property PACKAGE_PIN G3 [get_ports {JA[7]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JA[7]}] + + + +##Pmod Header JB +##Sch name = JB1 +#set_property PACKAGE_PIN A14 [get_ports {JB[0]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JB[0]}] +##Sch name = JB2 +#set_property PACKAGE_PIN A16 [get_ports {JB[1]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JB[1]}] +##Sch name = JB3 +#set_property PACKAGE_PIN B15 [get_ports {JB[2]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JB[2]}] +##Sch name = JB4 +#set_property PACKAGE_PIN B16 [get_ports {JB[3]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JB[3]}] +##Sch name = JB7 +#set_property PACKAGE_PIN A15 [get_ports {JB[4]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JB[4]}] +##Sch name = JB8 +#set_property PACKAGE_PIN A17 [get_ports {JB[5]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JB[5]}] +##Sch name = JB9 +#set_property PACKAGE_PIN C15 [get_ports {JB[6]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JB[6]}] +##Sch name = JB10 +#set_property PACKAGE_PIN C16 [get_ports {JB[7]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JB[7]}] + + + +##Pmod Header JC +##Sch name = JC1 +#set_property PACKAGE_PIN K17 [get_ports {JC[0]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JC[0]}] +##Sch name = JC2 +#set_property PACKAGE_PIN M18 [get_ports {JC[1]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JC[1]}] +##Sch name = JC3 +#set_property PACKAGE_PIN N17 [get_ports {JC[2]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JC[2]}] +##Sch name = JC4 +#set_property PACKAGE_PIN P18 [get_ports {JC[3]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JC[3]}] +##Sch name = JC7 +#set_property PACKAGE_PIN L17 [get_ports {JC[4]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JC[4]}] +##Sch name = JC8 +#set_property PACKAGE_PIN M19 [get_ports {JC[5]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JC[5]}] +##Sch name = JC9 +#set_property PACKAGE_PIN P17 [get_ports {JC[6]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JC[6]}] +##Sch name = JC10 +#set_property PACKAGE_PIN R18 [get_ports {JC[7]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JC[7]}] + + +##Pmod Header JXADC +##Sch name = XA1_P +#set_property PACKAGE_PIN J3 [get_ports {JXADC[0]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JXADC[0]}] +##Sch name = XA2_P +#set_property PACKAGE_PIN L3 [get_ports {JXADC[1]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JXADC[1]}] +##Sch name = XA3_P +#set_property PACKAGE_PIN M2 [get_ports {JXADC[2]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JXADC[2]}] +##Sch name = XA4_P +#set_property PACKAGE_PIN N2 [get_ports {JXADC[3]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JXADC[3]}] +##Sch name = XA1_N +#set_property PACKAGE_PIN K3 [get_ports {JXADC[4]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JXADC[4]}] +##Sch name = XA2_N +#set_property PACKAGE_PIN M3 [get_ports {JXADC[5]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JXADC[5]}] +##Sch name = XA3_N +#set_property PACKAGE_PIN M1 [get_ports {JXADC[6]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JXADC[6]}] +##Sch name = XA4_N +#set_property PACKAGE_PIN N1 [get_ports {JXADC[7]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JXADC[7]}] + + + +##VGA Connector +set_property PACKAGE_PIN G19 [get_ports {io_rgb[8]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_rgb[8]}] +set_property PACKAGE_PIN H19 [get_ports {io_rgb[9]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_rgb[9]}] +set_property PACKAGE_PIN J19 [get_ports {io_rgb[10]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_rgb[10]}] +set_property PACKAGE_PIN N19 [get_ports {io_rgb[11]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_rgb[11]}] +set_property PACKAGE_PIN N18 [get_ports {io_rgb[0]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_rgb[0]}] +set_property PACKAGE_PIN L18 [get_ports {io_rgb[1]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_rgb[1]}] +set_property PACKAGE_PIN K18 [get_ports {io_rgb[2]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_rgb[2]}] +set_property PACKAGE_PIN J18 [get_ports {io_rgb[3]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_rgb[3]}] +set_property PACKAGE_PIN J17 [get_ports {io_rgb[4]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_rgb[4]}] +set_property PACKAGE_PIN H17 [get_ports {io_rgb[5]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_rgb[5]}] +set_property PACKAGE_PIN G17 [get_ports {io_rgb[6]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_rgb[6]}] +set_property PACKAGE_PIN D17 [get_ports {io_rgb[7]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_rgb[7]}] +set_property PACKAGE_PIN P19 [get_ports io_hsync] + set_property IOSTANDARD LVCMOS33 [get_ports io_hsync] +set_property PACKAGE_PIN R19 [get_ports io_vsync] + set_property IOSTANDARD LVCMOS33 [get_ports io_vsync] + + +##USB-RS232 Interface +set_property PACKAGE_PIN B18 [get_ports io_rx] + set_property IOSTANDARD LVCMOS33 [get_ports io_rx] +set_property PACKAGE_PIN A18 [get_ports io_tx] + set_property IOSTANDARD LVCMOS33 [get_ports io_tx] + + +##USB HID (PS/2) +#set_property PACKAGE_PIN C17 [get_ports PS2Clk] + #set_property IOSTANDARD LVCMOS33 [get_ports PS2Clk] + #set_property PULLUP true [get_ports PS2Clk] +#set_property PACKAGE_PIN B17 [get_ports PS2Data] + #set_property IOSTANDARD LVCMOS33 [get_ports PS2Data] + #set_property PULLUP true [get_ports PS2Data] + + +##Quad SPI Flash +##Note that CCLK_0 cannot be placed in 7 series devices. You can access it using the +##STARTUPE2 primitive. +#set_property PACKAGE_PIN D18 [get_ports {QspiDB[0]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {QspiDB[0]}] +#set_property PACKAGE_PIN D19 [get_ports {QspiDB[1]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {QspiDB[1]}] +#set_property PACKAGE_PIN G18 [get_ports {QspiDB[2]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {QspiDB[2]}] +#set_property PACKAGE_PIN F18 [get_ports {QspiDB[3]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {QspiDB[3]}] +#set_property PACKAGE_PIN K19 [get_ports QspiCSn] + #set_property IOSTANDARD LVCMOS33 [get_ports QspiCSn] + + +## Configuration options, can be used for all designs +set_property CONFIG_VOLTAGE 3.3 [current_design] +set_property CFGBVS VCCO [current_design] diff --git a/lab1/vivado/basys3/generate_and_program.tcl b/lab1/vivado/basys3/generate_and_program.tcl new file mode 100644 index 0000000..71df1af --- /dev/null +++ b/lab1/vivado/basys3/generate_and_program.tcl @@ -0,0 +1,17 @@ +# 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. + +# Only tested on Vivado 2020.1 on Windows 10 +source generate_bitstream.tcl +source program_device.tcl \ No newline at end of file diff --git a/lab1/vivado/basys3/generate_bitstream.tcl b/lab1/vivado/basys3/generate_bitstream.tcl new file mode 100644 index 0000000..e1a26fb --- /dev/null +++ b/lab1/vivado/basys3/generate_bitstream.tcl @@ -0,0 +1,55 @@ +# 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. + +source open_project.tcl + +while 1 { + if { [catch {launch_runs synth_1 -jobs 4 } ] } { + regexp {ERROR: \[Common (\d+-\d+)]} $errorInfo -> code + if { [string equal $code "12-978"] } { + puts "Already generated and up-to-date" + break + } elseif { [string equal $code "17-69"] } { + puts "Out of date, reset runs" + reset_runs synth_1 + continue + } else { + puts "UNKNOWN ERROR!!! $errorInfo" + exit + } + } + break +} + +wait_on_run synth_1 + +while 1 { + if { [catch {launch_runs impl_1 -jobs 4 -to_step write_bitstream } ] } { + regexp {ERROR: \[Vivado (\d+-\d+)]} $errorInfo -> code + if { [string equal $code "12-978"] } { + puts "Already generated and up-to-date" + break + } elseif { [string equal $code "12-1088"] } { + puts "Out of date, reset runs" + reset_runs impl_1 + continue + } else { + puts "UNKNOWN ERROR!!! $errorInfo" + exit + } + } + break +} + +wait_on_run impl_1 diff --git a/lab1/vivado/basys3/open_project.tcl b/lab1/vivado/basys3/open_project.tcl new file mode 100644 index 0000000..b20931a --- /dev/null +++ b/lab1/vivado/basys3/open_project.tcl @@ -0,0 +1,39 @@ +# 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. + +# Only tested on Vivado 2020.1 on Windows 10 + +# set variables +set project_dir riscv-basys3 +set project_name riscv-basys3 +set part xc7a35tcpg236-1 +set sources {../../verilog/basys3/Top.v} +set test_sources {../../verilog/basys3/test.v} + +# open the project. will create one if it doesn't exist +if {[file exist $project_dir]} { + # check that it's a directory + if {! [file isdirectory $project_dir]} { + puts "$project_dir exists, but it's a file" + } + open_project $project_dir/$project_name.xpr -part $part +} else { + create_project $project_name $project_dir -part $part +} + +add_files -norecurse $sources +update_compile_order -fileset sources_1 +add_files -fileset constrs_1 -norecurse basys3.xdc +add_files -fileset sim_1 -norecurse $test_sources +update_compile_order -fileset sim_1 diff --git a/lab1/vivado/basys3/program_device.tcl b/lab1/vivado/basys3/program_device.tcl new file mode 100644 index 0000000..12fe648 --- /dev/null +++ b/lab1/vivado/basys3/program_device.tcl @@ -0,0 +1,24 @@ +# 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. + +# Only tested on Vivado 2020.1 on Windows 10 +open_hw_manager +connect_hw_server -allow_non_jtag +open_hw_target +current_hw_device [get_hw_devices xc7a35t_0] +refresh_hw_server [current_hw_server] +open_hw_target [lindex [get_hw_targets] 0] +set_property PROGRAM.FILE {./riscv-basys3/riscv-basys3.runs/impl_1/Top.bit} [get_hw_devices xc7a35t_0] +program_hw_devices [get_hw_devices xc7a35t_0] +close_hw_target diff --git a/lab1/vivado/basys3/run.ps1 b/lab1/vivado/basys3/run.ps1 new file mode 100644 index 0000000..178feab --- /dev/null +++ b/lab1/vivado/basys3/run.ps1 @@ -0,0 +1,4 @@ +cd .. +sbt run +cd vivado +C:\Xilinx\Vivado\2020.1\bin\vivado -mode batch -source .\generate_and_program.tcl \ No newline at end of file diff --git a/lab1/vivado/basys3/run_simulation.tcl b/lab1/vivado/basys3/run_simulation.tcl new file mode 100644 index 0000000..7c1a23c --- /dev/null +++ b/lab1/vivado/basys3/run_simulation.tcl @@ -0,0 +1,24 @@ +# 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. + +source open_project.tcl + +launch_simulation +restart +open_vcd +log_wave -recursive [get_object /test/top/cpu/*] +log_vcd [get_object /test/top/cpu/*] +run 1000ns +close_vcd +close_sim diff --git a/lab1/vivado/pynq/generate_and_program.tcl b/lab1/vivado/pynq/generate_and_program.tcl new file mode 100644 index 0000000..71df1af --- /dev/null +++ b/lab1/vivado/pynq/generate_and_program.tcl @@ -0,0 +1,17 @@ +# 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. + +# Only tested on Vivado 2020.1 on Windows 10 +source generate_bitstream.tcl +source program_device.tcl \ No newline at end of file diff --git a/lab1/vivado/pynq/generate_bitstream.tcl b/lab1/vivado/pynq/generate_bitstream.tcl new file mode 100644 index 0000000..69d54c1 --- /dev/null +++ b/lab1/vivado/pynq/generate_bitstream.tcl @@ -0,0 +1,56 @@ +# 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. + +source open_project.tcl +set_param general.maxThreads 16 + +while 1 { + if { [catch {launch_runs synth_1 -jobs 16 } ] } { + regexp {ERROR: \[Common (\d+-\d+)]} $errorInfo -> code + if { [string equal $code "12-978"] } { + puts "Already generated and up-to-date" + break + } elseif { [string equal $code "17-69"] } { + puts "Out of date, reset runs" + reset_runs synth_1 + continue + } else { + puts "UNKNOWN ERROR!!! $errorInfo" + exit + } + } + break +} + +wait_on_run synth_1 + +while 1 { + if { [catch {launch_runs impl_1 -jobs 16 -to_step write_bitstream } ] } { + regexp {ERROR: \[Vivado (\d+-\d+)]} $errorInfo -> code + if { [string equal $code "12-978"] } { + puts "Already generated and up-to-date" + break + } elseif { [string equal $code "12-1088"] } { + puts "Out of date, reset runs" + reset_runs impl_1 + continue + } else { + puts "UNKNOWN ERROR!!! $errorInfo" + exit + } + } + break +} + +wait_on_run impl_1 diff --git a/lab1/vivado/pynq/open_project.tcl b/lab1/vivado/pynq/open_project.tcl new file mode 100644 index 0000000..52d029f --- /dev/null +++ b/lab1/vivado/pynq/open_project.tcl @@ -0,0 +1,40 @@ +# 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. + +# Only tested on Vivado 2020.1 on Windows 10 + +# set variables +set project_dir riscv-pynq +set project_name riscv-pynq +set part xc7z020clg400-1 +set sources {../../verilog/pynq/Top.v} +set test_sources {../../verilog/pynq/test.v} + +# open the project. will create one if it doesn't exist +if {[file exist $project_dir]} { + # check that it's a directory + if {! [file isdirectory $project_dir]} { + puts "$project_dir exists, but it's a file" + } + open_project $project_dir/$project_name.xpr -part $part +} else { + create_project $project_name $project_dir -part $part +} + +add_files -norecurse $sources +add_files -norecurse ../../verilog/pynq/TMDS_PLLVR.v +update_compile_order -fileset sources_1 +add_files -fileset constrs_1 -norecurse pynq.xdc +add_files -fileset sim_1 -norecurse $test_sources +update_compile_order -fileset sim_1 diff --git a/lab1/vivado/pynq/program_device.tcl b/lab1/vivado/pynq/program_device.tcl new file mode 100644 index 0000000..8da4e29 --- /dev/null +++ b/lab1/vivado/pynq/program_device.tcl @@ -0,0 +1,22 @@ +# 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. + +# Only tested on Vivado 2020.1 on Windows 10 +open_hw_manager +connect_hw_server -allow_non_jtag +refresh_hw_server [current_hw_server] +open_hw_target [lindex [get_hw_targets] 0] +set_property PROGRAM.FILE {riscv-pynq/riscv-pynq.runs/impl_1/Top.bit} [get_hw_devices xc7z020_1] +program_hw_devices [get_hw_devices xc7z020_1] +close_hw_target diff --git a/lab1/vivado/pynq/pynq.xdc b/lab1/vivado/pynq/pynq.xdc new file mode 100644 index 0000000..bdcd6b9 --- /dev/null +++ b/lab1/vivado/pynq/pynq.xdc @@ -0,0 +1,189 @@ +## This file is a general .xdc for the PYNQ-Z1 board Rev. C +## To use it in a project: +## - uncomment the lines corresponding to used pins +## - rename the used ports (in each line, after get_ports) according to the top level signal names in the project + +## Clock signal 125 MHz + +set_property -dict { PACKAGE_PIN H16 IOSTANDARD LVCMOS33 } [get_ports { clock }]; #IO_L13P_T2_MRCC_35 Sch=sysclk +create_clock -add -name sys_clk_pin -period 8.00 -waveform {0 4} [get_ports { clock }]; + +##Switches + +set_property -dict { PACKAGE_PIN M20 IOSTANDARD LVCMOS33 } [get_ports { io_debug_step }]; #IO_L7N_T1_AD2N_35 Sch=sw[0] +#set_property -dict { PACKAGE_PIN M19 IOSTANDARD LVCMOS33 } [get_ports { sw[1] }]; #IO_L7P_T1_AD2P_35 Sch=sw[1] + +##RGB LEDs + +#set_property -dict { PACKAGE_PIN L15 IOSTANDARD LVCMOS33 } [get_ports { led4_b }]; #IO_L22N_T3_AD7N_35 Sch=led4_b +#set_property -dict { PACKAGE_PIN G17 IOSTANDARD LVCMOS33 } [get_ports { led4_g }]; #IO_L16P_T2_35 Sch=led4_g +#set_property -dict { PACKAGE_PIN N15 IOSTANDARD LVCMOS33 } [get_ports { led4_r }]; #IO_L21P_T3_DQS_AD14P_35 Sch=led4_r +#set_property -dict { PACKAGE_PIN G14 IOSTANDARD LVCMOS33 } [get_ports { led5_b }]; #IO_0_35 Sch=led5_b +#set_property -dict { PACKAGE_PIN L14 IOSTANDARD LVCMOS33 } [get_ports { led5_g }]; #IO_L22P_T3_AD7P_35 Sch=led5_g +#set_property -dict { PACKAGE_PIN M15 IOSTANDARD LVCMOS33 } [get_ports { led5_r }]; #IO_L23N_T3_35 Sch=led5_r + +##LEDs + +set_property -dict { PACKAGE_PIN R14 IOSTANDARD LVCMOS33 } [get_ports { io_led[0] }]; #IO_L6N_T0_VREF_34 Sch=led[0] +set_property -dict { PACKAGE_PIN P14 IOSTANDARD LVCMOS33 } [get_ports { io_led[1] }]; #IO_L6P_T0_34 Sch=led[1] +set_property -dict { PACKAGE_PIN N16 IOSTANDARD LVCMOS33 } [get_ports { io_led[2] }]; #IO_L21N_T3_DQS_AD14N_35 Sch=led[2] +set_property -dict { PACKAGE_PIN M14 IOSTANDARD LVCMOS33 } [get_ports { io_led[3] }]; #IO_L23P_T3_35 Sch=led[3] + +##Buttons + +set_property -dict { PACKAGE_PIN D19 IOSTANDARD LVCMOS33 } [get_ports { reset }]; #IO_L4P_T0_35 Sch=btn[0] +set_property -dict { PACKAGE_PIN D20 IOSTANDARD LVCMOS33 } [get_ports { io_debug_clk }]; #IO_L4N_T0_35 Sch=btn[1] +#set_property -dict { PACKAGE_PIN L20 IOSTANDARD LVCMOS33 } [get_ports { btn[2] }]; #IO_L9N_T1_DQS_AD3N_35 Sch=btn[2] +#set_property -dict { PACKAGE_PIN L19 IOSTANDARD LVCMOS33 } [get_ports { btn[3] }]; #IO_L9P_T1_DQS_AD3P_35 Sch=btn[3] + +##Pmod Header JA + +#set_property -dict { PACKAGE_PIN Y18 IOSTANDARD LVCMOS33 } [get_ports { io_rx }]; #IO_L17P_T2_34 Sch=ja_p[1] +#set_property -dict { PACKAGE_PIN Y19 IOSTANDARD LVCMOS33 } [get_ports { io_tx }]; #IO_L17N_T2_34 Sch=ja_n[1] +set_property -dict { PACKAGE_PIN Y16 IOSTANDARD LVCMOS33 } [get_ports { io_rx }]; #IO_L7P_T1_34 Sch=ja_p[2] +set_property -dict { PACKAGE_PIN Y17 IOSTANDARD LVCMOS33 } [get_ports { io_tx }]; #IO_L7N_T1_34 Sch=ja_n[2] +#set_property -dict { PACKAGE_PIN U18 IOSTANDARD LVCMOS33 } [get_ports { ja[4] }]; #IO_L12P_T1_MRCC_34 Sch=ja_p[3] +#set_property -dict { PACKAGE_PIN U19 IOSTANDARD LVCMOS33 } [get_ports { ja[5] }]; #IO_L12N_T1_MRCC_34 Sch=ja_n[3] +#set_property -dict { PACKAGE_PIN W18 IOSTANDARD LVCMOS33 } [get_ports { ja[6] }]; #IO_L22P_T3_34 Sch=ja_p[4] +#set_property -dict { PACKAGE_PIN W19 IOSTANDARD LVCMOS33 } [get_ports { ja[7] }]; #IO_L22N_T3_34 Sch=ja_n[4] + +##Pmod Header JB + +#set_property -dict { PACKAGE_PIN W14 IOSTANDARD LVCMOS33 } [get_ports { jb[0] }]; #IO_L8P_T1_34 Sch=jb_p[1] +#set_property -dict { PACKAGE_PIN Y14 IOSTANDARD LVCMOS33 } [get_ports { jb[1] }]; #IO_L8N_T1_34 Sch=jb_n[1] +#set_property -dict { PACKAGE_PIN T11 IOSTANDARD LVCMOS33 } [get_ports { jb[2] }]; #IO_L1P_T0_34 Sch=jb_p[2] +#set_property -dict { PACKAGE_PIN T10 IOSTANDARD LVCMOS33 } [get_ports { jb[3] }]; #IO_L1N_T0_34 Sch=jb_n[2] +#set_property -dict { PACKAGE_PIN V16 IOSTANDARD LVCMOS33 } [get_ports { jb[4] }]; #IO_L18P_T2_34 Sch=jb_p[3] +#set_property -dict { PACKAGE_PIN W16 IOSTANDARD LVCMOS33 } [get_ports { jb[5] }]; #IO_L18N_T2_34 Sch=jb_n[3] +#set_property -dict { PACKAGE_PIN V12 IOSTANDARD LVCMOS33 } [get_ports { jb[6] }]; #IO_L4P_T0_34 Sch=jb_p[4] +#set_property -dict { PACKAGE_PIN W13 IOSTANDARD LVCMOS33 } [get_ports { jb[7] }]; #IO_L4N_T0_34 Sch=jb_n[4] + +##Audio Out + +#set_property -dict { PACKAGE_PIN R18 IOSTANDARD LVCMOS33 } [get_ports { aud_pwm }]; #IO_L20N_T3_34 Sch=aud_pwm +#set_property -dict { PACKAGE_PIN T17 IOSTANDARD LVCMOS33 } [get_ports { aud_sd }]; #IO_L20P_T3_34 Sch=aud_sd + +##Mic input + +#set_property -dict { PACKAGE_PIN F17 IOSTANDARD LVCMOS33 } [get_ports { m_clk }]; #IO_L6N_T0_VREF_35 Sch=m_clk +#set_property -dict { PACKAGE_PIN G18 IOSTANDARD LVCMOS33 } [get_ports { m_data }]; #IO_L16N_T2_35 Sch=m_data + +##ChipKit Single Ended Analog Inputs +##NOTE: The ck_an_p pins can be used as single ended analog inputs with voltages from 0-3.3V (Chipkit Analog pins A0-A5). +## These signals should only be connected to the XADC core. When using these pins as digital I/O, use pins ck_io[14-19]. + +#set_property -dict { PACKAGE_PIN D18 IOSTANDARD LVCMOS33 } [get_ports { ck_an_n[0] }]; #IO_L3N_T0_DQS_AD1N_35 Sch=ck_an_n[0] +#set_property -dict { PACKAGE_PIN E17 IOSTANDARD LVCMOS33 } [get_ports { ck_an_p[0] }]; #IO_L3P_T0_DQS_AD1P_35 Sch=ck_an_p[0] +#set_property -dict { PACKAGE_PIN E19 IOSTANDARD LVCMOS33 } [get_ports { ck_an_n[1] }]; #IO_L5N_T0_AD9N_35 Sch=ck_an_n[1] +#set_property -dict { PACKAGE_PIN E18 IOSTANDARD LVCMOS33 } [get_ports { ck_an_p[1] }]; #IO_L5P_T0_AD9P_35 Sch=ck_an_p[1] +#set_property -dict { PACKAGE_PIN J14 IOSTANDARD LVCMOS33 } [get_ports { ck_an_n[2] }]; #IO_L20N_T3_AD6N_35 Sch=ck_an_n[2] +#set_property -dict { PACKAGE_PIN K14 IOSTANDARD LVCMOS33 } [get_ports { ck_an_p[2] }]; #IO_L20P_T3_AD6P_35 Sch=ck_an_p[2] +#set_property -dict { PACKAGE_PIN J16 IOSTANDARD LVCMOS33 } [get_ports { ck_an_n[3] }]; #IO_L24N_T3_AD15N_35 Sch=ck_an_n[3] +#set_property -dict { PACKAGE_PIN K16 IOSTANDARD LVCMOS33 } [get_ports { ck_an_p[3] }]; #IO_L24P_T3_AD15P_35 Sch=ck_an_p[3] +#set_property -dict { PACKAGE_PIN H20 IOSTANDARD LVCMOS33 } [get_ports { ck_an_n[4] }]; #IO_L17N_T2_AD5N_35 Sch=ck_an_n[4] +#set_property -dict { PACKAGE_PIN J20 IOSTANDARD LVCMOS33 } [get_ports { ck_an_p[4] }]; #IO_L17P_T2_AD5P_35 Sch=ck_an_p[4] +#set_property -dict { PACKAGE_PIN G20 IOSTANDARD LVCMOS33 } [get_ports { ck_an_n[5] }]; #IO_L18N_T2_AD13N_35 Sch=ck_an_n[5] +#set_property -dict { PACKAGE_PIN G19 IOSTANDARD LVCMOS33 } [get_ports { ck_an_p[5] }]; #IO_L18P_T2_AD13P_35 Sch=ck_an_p[5] + +##ChipKit Digital I/O Low + +#set_property -dict { PACKAGE_PIN T14 IOSTANDARD LVCMOS33 } [get_ports { ck_io[0] }]; #IO_L5P_T0_34 Sch=ck_io[0] +#set_property -dict { PACKAGE_PIN U12 IOSTANDARD LVCMOS33 } [get_ports { ck_io[1] }]; #IO_L2N_T0_34 Sch=ck_io[1] +#set_property -dict { PACKAGE_PIN U13 IOSTANDARD LVCMOS33 } [get_ports { ck_io[2] }]; #IO_L3P_T0_DQS_PUDC_B_34 Sch=ck_io[2] +#set_property -dict { PACKAGE_PIN V13 IOSTANDARD LVCMOS33 } [get_ports { ck_io[3] }]; #IO_L3N_T0_DQS_34 Sch=ck_io[3] +#set_property -dict { PACKAGE_PIN V15 IOSTANDARD LVCMOS33 } [get_ports { ck_io[4] }]; #IO_L10P_T1_34 Sch=ck_io[4] +#set_property -dict { PACKAGE_PIN T15 IOSTANDARD LVCMOS33 } [get_ports { ck_io[5] }]; #IO_L5N_T0_34 Sch=ck_io[5] +#set_property -dict { PACKAGE_PIN R16 IOSTANDARD LVCMOS33 } [get_ports { ck_io[6] }]; #IO_L19P_T3_34 Sch=ck_io[6] +#set_property -dict { PACKAGE_PIN U17 IOSTANDARD LVCMOS33 } [get_ports { ck_io[7] }]; #IO_L9N_T1_DQS_34 Sch=ck_io[7] +#set_property -dict { PACKAGE_PIN V17 IOSTANDARD LVCMOS33 } [get_ports { ck_io[8] }]; #IO_L21P_T3_DQS_34 Sch=ck_io[8] +#set_property -dict { PACKAGE_PIN V18 IOSTANDARD LVCMOS33 } [get_ports { ck_io[9] }]; #IO_L21N_T3_DQS_34 Sch=ck_io[9] +#set_property -dict { PACKAGE_PIN T16 IOSTANDARD LVCMOS33 } [get_ports { ck_io[10] }]; #IO_L9P_T1_DQS_34 Sch=ck_io[10] +#set_property -dict { PACKAGE_PIN R17 IOSTANDARD LVCMOS33 } [get_ports { ck_io[11] }]; #IO_L19N_T3_VREF_34 Sch=ck_io[11] +#set_property -dict { PACKAGE_PIN P18 IOSTANDARD LVCMOS33 } [get_ports { ck_io[12] }]; #IO_L23N_T3_34 Sch=ck_io[12] +#set_property -dict { PACKAGE_PIN N17 IOSTANDARD LVCMOS33 } [get_ports { ck_io[13] }]; #IO_L23P_T3_34 Sch=ck_io[13] + +##ChipKit Digital I/O On Outer Analog Header +##NOTE: These pins should be used when using the analog header signals A0-A5 as digital I/O (Chipkit digital pins 14-19) + +#set_property -dict { PACKAGE_PIN Y11 IOSTANDARD LVCMOS33 } [get_ports { ck_io[14] }]; #IO_L18N_T2_13 Sch=ck_a[0] +#set_property -dict { PACKAGE_PIN Y12 IOSTANDARD LVCMOS33 } [get_ports { ck_io[15] }]; #IO_L20P_T3_13 Sch=ck_a[1] +#set_property -dict { PACKAGE_PIN W11 IOSTANDARD LVCMOS33 } [get_ports { ck_io[16] }]; #IO_L18P_T2_13 Sch=ck_a[2] +#set_property -dict { PACKAGE_PIN V11 IOSTANDARD LVCMOS33 } [get_ports { ck_io[17] }]; #IO_L21P_T3_DQS_13 Sch=ck_a[3] +#set_property -dict { PACKAGE_PIN T5 IOSTANDARD LVCMOS33 } [get_ports { ck_io[18] }]; #IO_L19P_T3_13 Sch=ck_a[4] +#set_property -dict { PACKAGE_PIN U10 IOSTANDARD LVCMOS33 } [get_ports { ck_io[19] }]; #IO_L12N_T1_MRCC_13 Sch=ck_a[5] + +##ChipKit Digital I/O On Inner Analog Header +##NOTE: These pins will need to be connected to the XADC core when used as differential analog inputs (Chipkit analog pins A6-A11) + +#set_property -dict { PACKAGE_PIN B20 IOSTANDARD LVCMOS33 } [get_ports { ck_io[20] }]; #IO_L1N_T0_AD0N_35 Sch=ad_n[0] +#set_property -dict { PACKAGE_PIN C20 IOSTANDARD LVCMOS33 } [get_ports { ck_io[21] }]; #IO_L1P_T0_AD0P_35 Sch=ad_p[0] +#set_property -dict { PACKAGE_PIN F20 IOSTANDARD LVCMOS33 } [get_ports { ck_io[22] }]; #IO_L15N_T2_DQS_AD12N_35 Sch=ad_n[12] +#set_property -dict { PACKAGE_PIN F19 IOSTANDARD LVCMOS33 } [get_ports { ck_io[23] }]; #IO_L15P_T2_DQS_AD12P_35 Sch=ad_p[12] +#set_property -dict { PACKAGE_PIN A20 IOSTANDARD LVCMOS33 } [get_ports { ck_io[24] }]; #IO_L2N_T0_AD8N_35 Sch=ad_n[8] +#set_property -dict { PACKAGE_PIN B19 IOSTANDARD LVCMOS33 } [get_ports { ck_io[25] }]; #IO_L2P_T0_AD8P_35 Sch=ad_p[8] + +##ChipKit Digital I/O High + +#set_property -dict { PACKAGE_PIN U5 IOSTANDARD LVCMOS33 } [get_ports { ck_io[26] }]; #IO_L19N_T3_VREF_13 Sch=ck_io[26] +#set_property -dict { PACKAGE_PIN V5 IOSTANDARD LVCMOS33 } [get_ports { ck_io[27] }]; #IO_L6N_T0_VREF_13 Sch=ck_io[27] +#set_property -dict { PACKAGE_PIN V6 IOSTANDARD LVCMOS33 } [get_ports { ck_io[28] }]; #IO_L22P_T3_13 Sch=ck_io[28] +#set_property -dict { PACKAGE_PIN U7 IOSTANDARD LVCMOS33 } [get_ports { ck_io[29] }]; #IO_L11P_T1_SRCC_13 Sch=ck_io[29] +#set_property -dict { PACKAGE_PIN V7 IOSTANDARD LVCMOS33 } [get_ports { ck_io[30] }]; #IO_L11N_T1_SRCC_13 Sch=ck_io[30] +#set_property -dict { PACKAGE_PIN U8 IOSTANDARD LVCMOS33 } [get_ports { ck_io[31] }]; #IO_L17N_T2_13 Sch=ck_io[31] +#set_property -dict { PACKAGE_PIN V8 IOSTANDARD LVCMOS33 } [get_ports { ck_io[32] }]; #IO_L15P_T2_DQS_13 Sch=ck_io[32] +#set_property -dict { PACKAGE_PIN V10 IOSTANDARD LVCMOS33 } [get_ports { ck_io[33] }]; #IO_L21N_T3_DQS_13 Sch=ck_io[33] +#set_property -dict { PACKAGE_PIN W10 IOSTANDARD LVCMOS33 } [get_ports { ck_io[34] }]; #IO_L16P_T2_13 Sch=ck_io[34] +#set_property -dict { PACKAGE_PIN W6 IOSTANDARD LVCMOS33 } [get_ports { ck_io[35] }]; #IO_L22N_T3_13 Sch=ck_io[35] +#set_property -dict { PACKAGE_PIN Y6 IOSTANDARD LVCMOS33 } [get_ports { ck_io[36] }]; #IO_L13N_T2_MRCC_13 Sch=ck_io[36] +#set_property -dict { PACKAGE_PIN Y7 IOSTANDARD LVCMOS33 } [get_ports { ck_io[37] }]; #IO_L13P_T2_MRCC_13 Sch=ck_io[37] +#set_property -dict { PACKAGE_PIN W8 IOSTANDARD LVCMOS33 } [get_ports { ck_io[38] }]; #IO_L15N_T2_DQS_13 Sch=ck_io[38] +#set_property -dict { PACKAGE_PIN Y8 IOSTANDARD LVCMOS33 } [get_ports { ck_io[39] }]; #IO_L14N_T2_SRCC_13 Sch=ck_io[39] +#set_property -dict { PACKAGE_PIN W9 IOSTANDARD LVCMOS33 } [get_ports { ck_io[40] }]; #IO_L16N_T2_13 Sch=ck_io[40] +#set_property -dict { PACKAGE_PIN Y9 IOSTANDARD LVCMOS33 } [get_ports { ck_io[41] }]; #IO_L14P_T2_SRCC_13 Sch=ck_io[41] +#set_property -dict { PACKAGE_PIN Y13 IOSTANDARD LVCMOS33 } [get_ports { ck_io[42] }]; #IO_L20N_T3_13 Sch=ck_ioa + +## ChipKit SPI + +#set_property -dict { PACKAGE_PIN W15 IOSTANDARD LVCMOS33 } [get_ports { ck_miso }]; #IO_L10N_T1_34 Sch=ck_miso +#set_property -dict { PACKAGE_PIN T12 IOSTANDARD LVCMOS33 } [get_ports { ck_mosi }]; #IO_L2P_T0_34 Sch=ck_mosi +#set_property -dict { PACKAGE_PIN H15 IOSTANDARD LVCMOS33 } [get_ports { ck_sck }]; #IO_L19P_T3_35 Sch=ck_sck +#set_property -dict { PACKAGE_PIN F16 IOSTANDARD LVCMOS33 } [get_ports { ck_ss }]; #IO_L6P_T0_35 Sch=ck_ss + +## ChipKit I2C + +#set_property -dict { PACKAGE_PIN P16 IOSTANDARD LVCMOS33 } [get_ports { ck_scl }]; #IO_L24N_T3_34 Sch=ck_scl +#set_property -dict { PACKAGE_PIN P15 IOSTANDARD LVCMOS33 } [get_ports { ck_sda }]; #IO_L24P_T3_34 Sch=ck_sda + +##HDMI Rx + +#set_property -dict { PACKAGE_PIN H17 IOSTANDARD LVCMOS33 } [get_ports { hdmi_rx_cec }]; #IO_L13N_T2_MRCC_35 Sch=hdmi_rx_cec +set_property -dict { PACKAGE_PIN P19 IOSTANDARD TMDS_33 } [get_ports { io_debug_hdmi_clk_n }]; #IO_L13N_T2_MRCC_34 Sch=hdmi_rx_clk_n +set_property -dict { PACKAGE_PIN N18 IOSTANDARD TMDS_33 } [get_ports { io_debug_hdmi_clk_p }]; #IO_L13P_T2_MRCC_34 Sch=hdmi_rx_clk_p +set_property -dict { PACKAGE_PIN W20 IOSTANDARD TMDS_33 } [get_ports { io_debug_hdmi_data_n[0] }]; #IO_L16N_T2_34 Sch=hdmi_rx_d_n[0] +set_property -dict { PACKAGE_PIN V20 IOSTANDARD TMDS_33 } [get_ports { io_debug_hdmi_data_p[0] }]; #IO_L16P_T2_34 Sch=hdmi_rx_d_p[0] +set_property -dict { PACKAGE_PIN U20 IOSTANDARD TMDS_33 } [get_ports { io_debug_hdmi_data_n[1] }]; #IO_L15N_T2_DQS_34 Sch=hdmi_rx_d_n[1] +set_property -dict { PACKAGE_PIN T20 IOSTANDARD TMDS_33 } [get_ports { io_debug_hdmi_data_p[1] }]; #IO_L15P_T2_DQS_34 Sch=hdmi_rx_d_p[1] +set_property -dict { PACKAGE_PIN P20 IOSTANDARD TMDS_33 } [get_ports { io_debug_hdmi_data_n[2] }]; #IO_L14N_T2_SRCC_34 Sch=hdmi_rx_d_n[2] +set_property -dict { PACKAGE_PIN N20 IOSTANDARD TMDS_33 } [get_ports { io_debug_hdmi_data_p[2] }]; #IO_L14P_T2_SRCC_34 Sch=hdmi_rx_d_p[2] +set_property -dict { PACKAGE_PIN T19 IOSTANDARD LVCMOS33 } [get_ports { io_debug_hdmi_hpdn }]; #IO_25_34 Sch=hdmi_rx_hpd +#set_property -dict { PACKAGE_PIN U14 IOSTANDARD LVCMOS33 } [get_ports { hdmi_rx_scl }]; #IO_L11P_T1_SRCC_34 Sch=hdmi_rx_scl +#set_property -dict { PACKAGE_PIN U15 IOSTANDARD LVCMOS33 } [get_ports { hdmi_rx_sda }]; #IO_L11N_T1_SRCC_34 Sch=hdmi_rx_sda + +##HDMI Tx + +#set_property -dict { PACKAGE_PIN G15 IOSTANDARD LVCMOS33 } [get_ports { hdmi_tx_cec }]; #IO_L19N_T3_VREF_35 Sch=hdmi_tx_cec +set_property -dict { PACKAGE_PIN L17 IOSTANDARD TMDS_33 } [get_ports { io_hdmi_clk_n }]; #IO_L11N_T1_SRCC_35 Sch=hdmi_tx_clk_n +set_property -dict { PACKAGE_PIN L16 IOSTANDARD TMDS_33 } [get_ports { io_hdmi_clk_p }]; #IO_L11P_T1_SRCC_35 Sch=hdmi_tx_clk_p +set_property -dict { PACKAGE_PIN K18 IOSTANDARD TMDS_33 } [get_ports { io_hdmi_data_n[0] }]; #IO_L12N_T1_MRCC_35 Sch=hdmi_tx_d_n[0] +set_property -dict { PACKAGE_PIN K17 IOSTANDARD TMDS_33 } [get_ports { io_hdmi_data_p[0] }]; #IO_L12P_T1_MRCC_35 Sch=hdmi_tx_d_p[0] +set_property -dict { PACKAGE_PIN J19 IOSTANDARD TMDS_33 } [get_ports { io_hdmi_data_n[1] }]; #IO_L10N_T1_AD11N_35 Sch=hdmi_tx_d_n[1] +set_property -dict { PACKAGE_PIN K19 IOSTANDARD TMDS_33 } [get_ports { io_hdmi_data_p[1] }]; #IO_L10P_T1_AD11P_35 Sch=hdmi_tx_d_p[1] +set_property -dict { PACKAGE_PIN H18 IOSTANDARD TMDS_33 } [get_ports { io_hdmi_data_n[2] }]; #IO_L14N_T2_AD4N_SRCC_35 Sch=hdmi_tx_d_n[2] +set_property -dict { PACKAGE_PIN J18 IOSTANDARD TMDS_33 } [get_ports { io_hdmi_data_p[2] }]; #IO_L14P_T2_AD4P_SRCC_35 Sch=hdmi_tx_d_p[2] +set_property -dict { PACKAGE_PIN R19 IOSTANDARD LVCMOS33 } [get_ports { io_hdmi_hpdn }]; #IO_0_34 Sch=hdmi_tx_hpdn +#set_property -dict { PACKAGE_PIN M17 IOSTANDARD LVCMOS33 } [get_ports { hdmi_tx_scl }]; #IO_L8P_T1_AD10P_35 Sch=hdmi_tx_scl +#set_property -dict { PACKAGE_PIN M18 IOSTANDARD LVCMOS33 } [get_ports { hdmi_tx_sda }]; #IO_L8N_T1_AD10N_35 Sch=hdmi_tx_sda + +##Crypto SDA + +#set_property -dict { PACKAGE_PIN J15 IOSTANDARD LVCMOS33 } [get_ports { crypto_sda }]; #IO_25_35 Sch=crypto_sda \ No newline at end of file diff --git a/lab1/vivado/pynq/run.ps1 b/lab1/vivado/pynq/run.ps1 new file mode 100644 index 0000000..178feab --- /dev/null +++ b/lab1/vivado/pynq/run.ps1 @@ -0,0 +1,4 @@ +cd .. +sbt run +cd vivado +C:\Xilinx\Vivado\2020.1\bin\vivado -mode batch -source .\generate_and_program.tcl \ No newline at end of file diff --git a/lab1/vivado/pynq/run_simulation.tcl b/lab1/vivado/pynq/run_simulation.tcl new file mode 100644 index 0000000..f1f021a --- /dev/null +++ b/lab1/vivado/pynq/run_simulation.tcl @@ -0,0 +1,28 @@ +# 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. + +source open_project.tcl + +launch_simulation +restart +open_vcd +#log_wave -recursive [get_object /test/top/hdmi_display/*] +#log_vcd [get_object /test/top/hdmi_display/*] +#log_wave -recursive [get_object /test/top/*] +#log_vcd [get_object /test/top/*] +log_wave -recursive [get_object /test/top/hdmi_display/serdesBlue/osr10/*] +log_vcd [get_object /test/top/hdmi_display/serdesBlue/osr10/*] +run 1000000ns +close_vcd +close_sim diff --git a/lab2/.gitignore b/lab2/.gitignore new file mode 100644 index 0000000..946816b --- /dev/null +++ b/lab2/.gitignore @@ -0,0 +1,358 @@ +### Project Specific stuff +test_run_dir/* +### XilinxISE template +# intermediate build files +*.bgn +*.bit +*.bld +*.cmd_log +*.drc +*.ll +*.lso +*.msd +*.msk +*.ncd +*.ngc +*.ngd +*.ngr +*.pad +*.par +*.pcf +*.prj +*.ptwx +*.rbb +*.rbd +*.stx +*.syr +*.twr +*.twx +*.unroutes +*.ut +*.xpi +*.xst +*_bitgen.xwbt +*_envsettings.html +*_map.map +*_map.mrp +*_map.ngm +*_map.xrpt +*_ngdbuild.xrpt +*_pad.csv +*_pad.txt +*_par.xrpt +*_summary.html +*_summary.xml +*_usage.xml +*_xst.xrpt + +# project-wide generated files +*.gise +par_usage_statistics.html +usage_statistics_webtalk.html +webtalk.log +webtalk_pn.xml + +# generated folders +iseconfig/ +xlnx_auto_0_xdb/ +xst/ +_ngo/ +_xmsgs/ +### Eclipse template +*.pydevproject +.metadata +.gradle +bin/ +tmp/ +*.tmp +*.bak +*.swp +*~.nib +local.properties +.settings/ +.loadpath + +# Eclipse Core +.project + +# External tool builders +.externalToolBuilders/ + +# Locally stored "Eclipse launch configurations" +*.launch + +# CDT-specific +.cproject + +# JDT-specific (Eclipse Java Development Tools) +.classpath + +# Java annotation processor (APT) +.factorypath + +# PDT-specific +.buildpath + +# sbteclipse plugin +.target + +# TeXlipse plugin +.texlipse +### C template +# Object files +*.o +*.ko +*.obj +*.elf + +# Precompiled Headers +*.gch +*.pch + +# Libraries +*.lib +*.a +*.la +*.lo + +# Shared objects (inc. Windows DLLs) +*.dll +*.so +*.so.* +*.dylib + +# Executables +*.exe +*.out +*.app +*.i*86 +*.x86_64 +*.hex + +# Debug files +*.dSYM/ +### SBT template +# Simple Build Tool +# http://www.scala-sbt.org/release/docs/Getting-Started/Directories.html#configuring-version-control + +target/ +lib_managed/ +src_managed/ +project/boot/ +.history +.cache +### Emacs template +# -*- mode: gitignore; -*- +*~ +\#*\# +/.emacs.desktop +/.emacs.desktop.lock +*.elc +auto-save-list +tramp +.\#* + +# Org-mode +.org-id-locations +*_archive + +# flymake-mode +*_flymake.* + +# eshell files +/eshell/history +/eshell/lastdir + +# elpa packages +/elpa/ + +# reftex files +*.rel + +# AUCTeX auto folder +/auto/ + +# cask packages +.cask/ +### Vim template +[._]*.s[a-w][a-z] +[._]s[a-w][a-z] +*.un~ +Session.vim +.netrwhist +*~ +### JetBrains template +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio + +*.iml + +## Directory-based project format: +.idea/ +# if you remove the above rule, at least ignore the following: + +# User-specific stuff: +# .idea/workspace.xml +# .idea/tasks.xml +# .idea/dictionaries + +# Sensitive or high-churn files: +# .idea/dataSources.ids +# .idea/dataSources.xml +# .idea/sqlDataSources.xml +# .idea/dynamic.xml +# .idea/uiDesigner.xml + +# Gradle: +# .idea/gradle.xml +# .idea/libraries + +# Mongo Explorer plugin: +# .idea/mongoSettings.xml + +## File-based project format: +*.ipr +*.iws + +## Plugin-specific files: + +# IntelliJ +/out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +### C++ template +# Compiled Object files +*.slo +*.lo +*.o +*.obj + +# Precompiled Headers +*.gch +*.pch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app +### OSX template +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk +### Xcode template +# Xcode +# +# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore + +## Build generated +build/ +DerivedData + +## Various settings +*.pbxuser +!default.pbxuser +*.mode1v3 +!default.mode1v3 +*.mode2v3 +!default.mode2v3 +*.perspectivev3 +!default.perspectivev3 +xcuserdata + +## Other +*.xccheckout +*.moved-aside +*.xcuserstate +### Scala template +*.class +*.log +/.bsp + +# sbt specific +.cache +.history +.lib/ +dist/* +target/ +lib_managed/ +src_managed/ +project/boot/ +project/plugins/project/ + +# Scala-IDE specific +.scala_dependencies +.worksheet +### Java template +*.class + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.ear + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* + +verilog/*.txt +verilog/basys3/* +verilog/pynq/* +verilog/verilator/* +!verilog/basys3/test.v +!verilog/pynq/design_1_wrapper.v +!verilog/pynq/test.v +!verilog/pynq/TMDS_PLLVR.v +!verilog/verilator/sim_main.cpp +*.jou +*.log +.Xil +vivado/basys3/riscv-basys3 +vivado/pynq/riscv-pynq +vivado/pynq/NA +.vscode +.metals diff --git a/lab2/Makefile b/lab2/Makefile new file mode 100644 index 0000000..1bffd0a --- /dev/null +++ b/lab2/Makefile @@ -0,0 +1,47 @@ +# 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. + +test: + sbt test + +verilator: + sbt "runMain board.verilator.VerilogGenerator" + cd verilog/verilator && verilator --trace --exe --cc sim_main.cpp Top.v && make -C obj_dir -f VTop.mk + +verilator-sim: verilator + cd verilog/verilator && obj_dir/VTop $(SIM_TIME) + +basys3: + sbt "runMain board.basys3.VerilogGenerator" +pynq: + sbt "runMain board.pynq.VerilogGenerator" + +bitstream-basys3: basys3 + cd vivado/basys3 && vivado -mode batch -source generate_bitstream.tcl + +program-basys3: bitstream-basys3 + cd vivado/basys3 && vivado -mode batch -source program_device.tcl + +vivado-sim-basys3: basys3 + cd vivado/basys3 && vivado -mode batch -source run_simulation.tcl +bitstream-pynq: pynq + cd vivado/pynq && vivado -mode batch -source generate_bitstream.tcl + +program-pynq: bitstream-pynq + cd vivado/pynq && vivado -mode batch -source program_device.tcl + +vivado-sim-pynq: pynq + cd vivado/pynq && vivado -mode batch -source run_simulation.tcl + +.PHONY: basys3 verilator test bitstream program verilator-sim vivado-sim diff --git a/lab2/build.sbt b/lab2/build.sbt new file mode 100644 index 0000000..75f138e --- /dev/null +++ b/lab2/build.sbt @@ -0,0 +1,24 @@ +import sbt.Keys.libraryDependencies +// See README.md for license details. + +ThisBuild / scalaVersion := "2.13.10" +ThisBuild / version := "0.1.0" +ThisBuild / organization := "io.github.howardlau1999" + +val chiselVersion = "3.6.0" + +lazy val root = (project in file(".")) + .settings( + name := "yatcpu", + libraryDependencies ++= Seq( + "edu.berkeley.cs" %% "chisel3" % chiselVersion, + "edu.berkeley.cs" %% "chiseltest" % "0.6.0" % "test", + ), + scalacOptions ++= Seq( + "-language:reflectiveCalls", + "-deprecation", + "-feature", + "-Xcheckinit", + ), + addCompilerPlugin("edu.berkeley.cs" % "chisel3-plugin" % chiselVersion cross CrossVersion.full), + ) diff --git a/lab2/coremark/yatcpu/core_portme.c b/lab2/coremark/yatcpu/core_portme.c new file mode 100644 index 0000000..3d7ae3b --- /dev/null +++ b/lab2/coremark/yatcpu/core_portme.c @@ -0,0 +1,169 @@ +/* +Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) + +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. + +Original Author: Shay Gal-on +*/ +#include "coremark.h" +#include "core_portme.h" + +#if VALIDATION_RUN +volatile ee_s32 seed1_volatile = 0x3415; +volatile ee_s32 seed2_volatile = 0x3415; +volatile ee_s32 seed3_volatile = 0x66; +#endif +#if PERFORMANCE_RUN +volatile ee_s32 seed1_volatile = 0x0; +volatile ee_s32 seed2_volatile = 0x0; +volatile ee_s32 seed3_volatile = 0x66; +#endif +#if PROFILE_RUN +volatile ee_s32 seed1_volatile = 0x8; +volatile ee_s32 seed2_volatile = 0x8; +volatile ee_s32 seed3_volatile = 0x8; +#endif +volatile ee_s32 seed4_volatile = ITERATIONS; +volatile ee_s32 seed5_volatile = 0; +/* Porting : Timing functions + How to capture time and convert to seconds must be ported to whatever is + supported by the platform. e.g. Read value from on board RTC, read value from + cpu clock cycles performance counter etc. Sample implementation for standard + time.h and windows.h definitions included. +*/ +CORETIMETYPE +barebones_clock() +{ + ee_u32 cyclel; + __asm__ __volatile__ ( + "rdcycle %0" : "=r"(cyclel) : : + ); + return cyclel; +} +/* Define : TIMER_RES_DIVIDER + Divider to trade off timer resolution and total time that can be + measured. + + Use lower values to increase resolution, but make sure that overflow + does not occur. If there are issues with the return value overflowing, + increase this value. + */ +#define GETMYTIME(_t) (*_t = barebones_clock()) +#define MYTIMEDIFF(fin, ini) ((fin) - (ini)) +#define TIMER_RES_DIVIDER 1 +#define SAMPLE_TIME_IMPLEMENTATION 1 +#define EE_TICKS_PER_SEC (CLOCKS_PER_SEC / TIMER_RES_DIVIDER) + +/** Define Host specific (POSIX), or target specific global time variables. */ +static CORETIMETYPE start_time_val, stop_time_val; + +/* Function : start_time + This function will be called right before starting the timed portion of + the benchmark. + + Implementation may be capturing a system timer (as implemented in the + example code) or zeroing some system parameters - e.g. setting the cpu clocks + cycles to 0. +*/ +void +start_time(void) +{ + GETMYTIME(&start_time_val); +} +/* Function : stop_time + This function will be called right after ending the timed portion of the + benchmark. + + Implementation may be capturing a system timer (as implemented in the + example code) or other system parameters - e.g. reading the current value of + cpu cycles counter. +*/ +void +stop_time(void) +{ + GETMYTIME(&stop_time_val); +} +/* Function : get_time + Return an abstract "ticks" number that signifies time on the system. + + Actual value returned may be cpu cycles, milliseconds or any other + value, as long as it can be converted to seconds by . This + methodology is taken to accommodate any hardware or simulated platform. The + sample implementation returns millisecs by default, and the resolution is + controlled by +*/ +CORE_TICKS +get_time(void) +{ + CORE_TICKS elapsed + = (CORE_TICKS)(MYTIMEDIFF(stop_time_val, start_time_val)); + return elapsed; +} +/* Function : time_in_secs + Convert the value returned by get_time to seconds. + + The type is used to accommodate systems with no support for + floating point. Default implementation implemented by the EE_TICKS_PER_SEC + macro above. +*/ +secs_ret +time_in_secs(CORE_TICKS ticks) +{ + secs_ret retval = ((secs_ret)ticks) / (secs_ret)EE_TICKS_PER_SEC; + return retval; +} + +ee_u32 default_num_contexts = 1; + +/* Function : portable_init + Target specific initialization code + Test for some common mistakes. +*/ +void +portable_init(core_portable *p, int *argc, char *argv[]) +{ + if (sizeof(ee_ptr_int) != sizeof(ee_u8 *)) + { + ee_printf( + "ERROR! Please define ee_ptr_int to a type that holds a " + "pointer!\n"); + } + if (sizeof(ee_u32) != 4) + { + ee_printf("ERROR! Please define ee_u32 to a 32b unsigned type!\n"); + } + p->portable_id = 1; +} +/* Function : portable_fini + Target specific final code +*/ +void +portable_fini(core_portable *p) +{ + p->portable_id = 0; +} + +unsigned int +__mulsi3 (unsigned int a, unsigned int b) +{ + unsigned int r = 0; + + while (a) + { + if (a & 1) + r += b; + a >>= 1; + b <<= 1; + } + return r; +} \ No newline at end of file diff --git a/lab2/coremark/yatcpu/core_portme.h b/lab2/coremark/yatcpu/core_portme.h new file mode 100644 index 0000000..7b0d646 --- /dev/null +++ b/lab2/coremark/yatcpu/core_portme.h @@ -0,0 +1,211 @@ +/* +Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) + +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. + +Original Author: Shay Gal-on +*/ +/* Topic : Description + This file contains configuration constants required to execute on + different platforms +*/ +#ifndef CORE_PORTME_H +#define CORE_PORTME_H +/************************/ +/* Data types and settings */ +/************************/ +/* Configuration : HAS_FLOAT + Define to 1 if the platform supports floating point. +*/ +#ifndef HAS_FLOAT +#define HAS_FLOAT 0 +#endif +/* Configuration : HAS_TIME_H + Define to 1 if platform has the time.h header file, + and implementation of functions thereof. +*/ +#ifndef HAS_TIME_H +#define HAS_TIME_H 0 +#define CLOCKS_PER_SEC 100000000 +#endif +/* Configuration : USE_CLOCK + Define to 1 if platform has the time.h header file, + and implementation of functions thereof. +*/ +#ifndef USE_CLOCK +#define USE_CLOCK 0 +#endif +/* Configuration : HAS_STDIO + Define to 1 if the platform has stdio.h. +*/ +#ifndef HAS_STDIO +#define HAS_STDIO 0 +#endif +/* Configuration : HAS_PRINTF + Define to 1 if the platform has stdio.h and implements the printf + function. +*/ +#ifndef HAS_PRINTF +#define HAS_PRINTF 0 +#endif + +/* Definitions : COMPILER_VERSION, COMPILER_FLAGS, MEM_LOCATION + Initialize these strings per platform +*/ +#ifndef COMPILER_VERSION +#ifdef __GNUC__ +#define COMPILER_VERSION "GCC"__VERSION__ +#else +#define COMPILER_VERSION "Please put compiler version here (e.g. gcc 4.1)" +#endif +#endif +#ifndef COMPILER_FLAGS +#define COMPILER_FLAGS \ + FLAGS_STR /* "Please put compiler flags here (e.g. -o3)" */ +#endif +#ifndef MEM_LOCATION +#define MEM_LOCATION "STACK" +#endif + +/* Data Types : + To avoid compiler issues, define the data types that need ot be used for + 8b, 16b and 32b in . + + *Imprtant* : + ee_ptr_int needs to be the data type used to hold pointers, otherwise + coremark may fail!!! +*/ +typedef signed short ee_s16; +typedef unsigned short ee_u16; +typedef signed int ee_s32; +typedef double ee_f32; +typedef unsigned char ee_u8; +typedef unsigned int ee_u32; +typedef ee_u32 ee_ptr_int; +typedef ee_u32 ee_size_t; +#define NULL ((void *)0) +/* align_mem : + This macro is used to align an offset to point to a 32b value. It is + used in the Matrix algorithm to initialize the input memory blocks. +*/ +#define align_mem(x) (void *)(4 + (((ee_ptr_int)(x)-1) & ~3)) + +/* Configuration : CORE_TICKS + Define type of return from the timing functions. + */ +#define CORETIMETYPE ee_u32 +typedef ee_u32 CORE_TICKS; + +/* Configuration : SEED_METHOD + Defines method to get seed values that cannot be computed at compile + time. + + Valid values : + SEED_ARG - from command line. + SEED_FUNC - from a system function. + SEED_VOLATILE - from volatile variables. +*/ +#ifndef SEED_METHOD +#define SEED_METHOD SEED_VOLATILE +#endif + +/* Configuration : MEM_METHOD + Defines method to get a block of memry. + + Valid values : + MEM_MALLOC - for platforms that implement malloc and have malloc.h. + MEM_STATIC - to use a static memory array. + MEM_STACK - to allocate the data block on the stack (NYI). +*/ +#ifndef MEM_METHOD +#define MEM_METHOD MEM_STATIC +#endif + +/* Configuration : MULTITHREAD + Define for parallel execution + + Valid values : + 1 - only one context (default). + N>1 - will execute N copies in parallel. + + Note : + If this flag is defined to more then 1, an implementation for launching + parallel contexts must be defined. + + Two sample implementations are provided. Use or + to enable them. + + It is valid to have a different implementation of + and in , to fit a particular architecture. +*/ +#ifndef MULTITHREAD +#define MULTITHREAD 1 +#define USE_PTHREAD 0 +#define USE_FORK 0 +#define USE_SOCKET 0 +#endif + +/* Configuration : MAIN_HAS_NOARGC + Needed if platform does not support getting arguments to main. + + Valid values : + 0 - argc/argv to main is supported + 1 - argc/argv to main is not supported + + Note : + This flag only matters if MULTITHREAD has been defined to a value + greater then 1. +*/ +#ifndef MAIN_HAS_NOARGC +#define MAIN_HAS_NOARGC 1 +#endif + +/* Configuration : MAIN_HAS_NORETURN + Needed if platform does not support returning a value from main. + + Valid values : + 0 - main returns an int, and return value will be 0. + 1 - platform does not support returning a value from main +*/ +#ifndef MAIN_HAS_NORETURN +#define MAIN_HAS_NORETURN 0 +#endif + +/* Variable : default_num_contexts + Not used for this simple port, must contain the value 1. +*/ +extern ee_u32 default_num_contexts; + +typedef struct CORE_PORTABLE_S +{ + ee_u8 portable_id; +} core_portable; + +/* target specific init/fini */ +void portable_init(core_portable *p, int *argc, char *argv[]); +void portable_fini(core_portable *p); + +#if !defined(PROFILE_RUN) && !defined(PERFORMANCE_RUN) \ + && !defined(VALIDATION_RUN) +#if (TOTAL_DATA_SIZE == 1200) +#define PROFILE_RUN 1 +#elif (TOTAL_DATA_SIZE == 2000) +#define PERFORMANCE_RUN 1 +#else +#define VALIDATION_RUN 1 +#endif +#endif + +int ee_printf(const char *fmt, ...); + +#endif /* CORE_PORTME_H */ diff --git a/lab2/coremark/yatcpu/core_portme.mak b/lab2/coremark/yatcpu/core_portme.mak new file mode 100644 index 0000000..e26c689 --- /dev/null +++ b/lab2/coremark/yatcpu/core_portme.mak @@ -0,0 +1,92 @@ +# Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) +# +# 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. +# +# Original Author: Shay Gal-on + +#File : core_portme.mak + +# Flag : OUTFLAG +# Use this flag to define how to to get an executable (e.g -o) +OUTFLAG= -o +# Flag : CC +# Use this flag to define compiler to use +CC = clang +# Flag : LD +# Use this flag to define compiler to use +LD = ld.lld +# Flag : AS +# Use this flag to define compiler to use +AS = clang +# Flag : CFLAGS +# Use this flag to define compiler options. Note, you can add compiler options from the command line using XCFLAGS="other flags" +PORT_CFLAGS = -O0 -g --target=riscv32-unknown-elf -march=rv32i -mabi=ilp32 +FLAGS_STR = "$(PORT_CFLAGS) $(XCFLAGS) $(XLFLAGS) $(LFLAGS_END)" +CFLAGS = $(PORT_CFLAGS) -I$(PORT_DIR) -I. -DFLAGS_STR=\"$(FLAGS_STR)\" +#Flag : LFLAGS_END +# Define any libraries needed for linking or other flags that should come at the end of the link line (e.g. linker scripts). +# Note : On certain platforms, the default clock_gettime implementation is supported but requires linking of librt. +SEPARATE_COMPILE=1 +# Flag : SEPARATE_COMPILE +# You must also define below how to create an object file, and how to link. +OBJOUT = -o +LFLAGS = -T $(PORT_DIR)/link.ld +ASFLAGS = -c --target=riscv32-unknown-elf -march=rv32i -mabi=ilp32 +OFLAG = -o +COUT = -c + +LFLAGS_END = +# Flag : PORT_SRCS +# Port specific source files can be added here +# You may also need cvt.c if the fcvt functions are not provided as intrinsics by your compiler! +PORT_SRCS = $(PORT_DIR)/core_portme.c $(PORT_DIR)/ee_printf.c $(PORT_DIR)/div.s $(PORT_DIR)/init.s +vpath %.c $(PORT_DIR) +vpath %.s $(PORT_DIR) + +PORT_OBJS = $(PORT_DIR)/init$(OEXT) $(PORT_DIR)/core_portme$(OEXT) $(PORT_DIR)/ee_printf$(OEXT) $(PORT_DIR)/div$(OEXT) +PORT_CLEAN = *$(OEXT) $(OUTFILE).asmbin + +# Flag : LOAD +# For a simple port, we assume self hosted compile and run, no load needed. + +# Flag : RUN +# For a simple port, we assume self hosted compile and run, simple invocation of the executable + +LOAD = echo "Please set LOAD to the process of loading the executable to the flash" +RUN = echo "Please set LOAD to the process of running the executable (e.g. via jtag, or board reset)" + +OEXT = .o +EXE = .bin + +$(OPATH)$(PORT_DIR)/%$(OEXT) : %.c + $(CC) $(CFLAGS) $(XCFLAGS) $(COUT) $< $(OBJOUT) $@ + +$(OPATH)%$(OEXT) : %.c + $(CC) $(CFLAGS) $(XCFLAGS) $(COUT) $< $(OBJOUT) $@ + +$(OPATH)$(PORT_DIR)/%$(OEXT) : %.s + $(AS) $(ASFLAGS) $< $(OBJOUT) $@ + +# Target : port_pre% and port_post% +# For the purpose of this simple port, no pre or post steps needed. + +.PHONY : port_prebuild port_postbuild port_prerun port_postrun port_preload port_postload +port_postbuild: $(OUTFILE) + llvm-objcopy -O binary -j .text -j .data $(OUTFILE) $(OUTFILE).asmbin +port_pre% port_post% : + +# FLAG : OPATH +# Path to the output folder. Default - current folder. +OPATH = ./ +MKDIR = mkdir -p + diff --git a/lab2/coremark/yatcpu/cvt.c b/lab2/coremark/yatcpu/cvt.c new file mode 100644 index 0000000..333e8ea --- /dev/null +++ b/lab2/coremark/yatcpu/cvt.c @@ -0,0 +1,127 @@ +/* +Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) + +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. +*/ +#include +#define CVTBUFSIZE 80 +static char CVTBUF[CVTBUFSIZE]; + +static char * +cvt(double arg, int ndigits, int *decpt, int *sign, char *buf, int eflag) +{ + int r2; + double fi, fj; + char * p, *p1; + + if (ndigits < 0) + ndigits = 0; + if (ndigits >= CVTBUFSIZE - 1) + ndigits = CVTBUFSIZE - 2; + r2 = 0; + *sign = 0; + p = &buf[0]; + if (arg < 0) + { + *sign = 1; + arg = -arg; + } + arg = modf(arg, &fi); + p1 = &buf[CVTBUFSIZE]; + + if (fi != 0) + { + p1 = &buf[CVTBUFSIZE]; + while (fi != 0) + { + fj = modf(fi / 10, &fi); + *--p1 = (int)((fj + .03) * 10) + '0'; + r2++; + } + while (p1 < &buf[CVTBUFSIZE]) + *p++ = *p1++; + } + else if (arg > 0) + { + while ((fj = arg * 10) < 1) + { + arg = fj; + r2--; + } + } + p1 = &buf[ndigits]; + if (eflag == 0) + p1 += r2; + *decpt = r2; + if (p1 < &buf[0]) + { + buf[0] = '\0'; + return buf; + } + while (p <= p1 && p < &buf[CVTBUFSIZE]) + { + arg *= 10; + arg = modf(arg, &fj); + *p++ = (int)fj + '0'; + } + if (p1 >= &buf[CVTBUFSIZE]) + { + buf[CVTBUFSIZE - 1] = '\0'; + return buf; + } + p = p1; + *p1 += 5; + while (*p1 > '9') + { + *p1 = '0'; + if (p1 > buf) + ++*--p1; + else + { + *p1 = '1'; + (*decpt)++; + if (eflag == 0) + { + if (p > buf) + *p = '0'; + p++; + } + } + } + *p = '\0'; + return buf; +} + +char * +ecvt(double arg, int ndigits, int *decpt, int *sign) +{ + return cvt(arg, ndigits, decpt, sign, CVTBUF, 1); +} + +char * +ecvtbuf(double arg, int ndigits, int *decpt, int *sign, char *buf) +{ + return cvt(arg, ndigits, decpt, sign, buf, 1); +} + +char * +fcvt(double arg, int ndigits, int *decpt, int *sign) +{ + return cvt(arg, ndigits, decpt, sign, CVTBUF, 0); +} + +char * +fcvtbuf(double arg, int ndigits, int *decpt, int *sign, char *buf) +{ + return cvt(arg, ndigits, decpt, sign, buf, 0); +} diff --git a/lab2/coremark/yatcpu/div.s b/lab2/coremark/yatcpu/div.s new file mode 100644 index 0000000..6725293 --- /dev/null +++ b/lab2/coremark/yatcpu/div.s @@ -0,0 +1,71 @@ +.text +.globl __divsi3 +__divsi3: + bltz a0, .L10 + bltz a1, .L11 + +.globl __udivsi3 +__udivsi3: + mv a2, a1 + mv a1, a0 + li a0, -1 + beqz a2, .L5 + li a3, 1 + bgeu a2, a1, .L2 +.L1: + blez a2, .L2 + slli a2, a2, 1 + slli a3, a3, 1 + bgtu a1, a2, .L1 +.L2: + li a0, 0 +.L3: + bltu a1, a2, .L4 + sub a1, a1, a2 + or a0, a0, a3 +.L4: + srli a3, a3, 1 + srli a2, a2, 1 + bnez a3, .L3 +.L5: + ret + +.globl __umodsi3 +__umodsi3: + move t0, ra + jal __udivsi3 + move a0, a1 + jr t0 + +.L10: + neg a0, a0 + bgtz a1, .L12 + + neg a1, a1 + j __udivsi3 +.L11: + neg a1, a1 +.L12: + move t0, ra + jal __udivsi3 + neg a0, a0 + jr t0 + +.globl __modsi3 +__modsi3: + move t0, ra + bltz a1, .L31 + bltz a0, .L32 +.L30: + jal __udivsi3 + move a0, a1 + jr t0 +.L31: + neg a1, a1 + bgez a0, .L30 +.L32: + neg a0, a0 + jal __udivsi3 + neg a0, a1 + jr t0 + diff --git a/lab2/coremark/yatcpu/ee_printf.c b/lab2/coremark/yatcpu/ee_printf.c new file mode 100644 index 0000000..9dde21a --- /dev/null +++ b/lab2/coremark/yatcpu/ee_printf.c @@ -0,0 +1,687 @@ +/* +Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) + +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. +*/ + +#include +#include + +#define ZEROPAD (1 << 0) /* Pad with zero */ +#define SIGN (1 << 1) /* Unsigned/signed long */ +#define PLUS (1 << 2) /* Show plus */ +#define SPACE (1 << 3) /* Spacer */ +#define LEFT (1 << 4) /* Left justified */ +#define HEX_PREP (1 << 5) /* 0x */ +#define UPPERCASE (1 << 6) /* 'ABCDEF' */ + +#define is_digit(c) ((c) >= '0' && (c) <= '9') + +static char * digits = "0123456789abcdefghijklmnopqrstuvwxyz"; +static char * upper_digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; +static ee_size_t strnlen(const char *s, ee_size_t count); + +static ee_size_t +strnlen(const char *s, ee_size_t count) +{ + const char *sc; + for (sc = s; *sc != '\0' && count--; ++sc) + ; + return sc - s; +} + +static int +skip_atoi(const char **s) +{ + int i = 0; + while (is_digit(**s)) + i = i * 10 + *((*s)++) - '0'; + return i; +} + +static char * +number(char *str, long num, int base, int size, int precision, int type) +{ + char c, sign, tmp[66]; + char *dig = digits; + int i; + + if (type & UPPERCASE) + dig = upper_digits; + if (type & LEFT) + type &= ~ZEROPAD; + if (base < 2 || base > 36) + return 0; + + c = (type & ZEROPAD) ? '0' : ' '; + sign = 0; + if (type & SIGN) + { + if (num < 0) + { + sign = '-'; + num = -num; + size--; + } + else if (type & PLUS) + { + sign = '+'; + size--; + } + else if (type & SPACE) + { + sign = ' '; + size--; + } + } + + if (type & HEX_PREP) + { + if (base == 16) + size -= 2; + else if (base == 8) + size--; + } + + i = 0; + + if (num == 0) + tmp[i++] = '0'; + else + { + while (num != 0) + { + tmp[i++] = dig[((unsigned long)num) % (unsigned)base]; + num = ((unsigned long)num) / (unsigned)base; + } + } + + if (i > precision) + precision = i; + size -= precision; + if (!(type & (ZEROPAD | LEFT))) + while (size-- > 0) + *str++ = ' '; + if (sign) + *str++ = sign; + + if (type & HEX_PREP) + { + if (base == 8) + *str++ = '0'; + else if (base == 16) + { + *str++ = '0'; + *str++ = digits[33]; + } + } + + if (!(type & LEFT)) + while (size-- > 0) + *str++ = c; + while (i < precision--) + *str++ = '0'; + while (i-- > 0) + *str++ = tmp[i]; + while (size-- > 0) + *str++ = ' '; + + return str; +} + +static char * +eaddr(char *str, unsigned char *addr, int size, int precision, int type) +{ + char tmp[24]; + char *dig = digits; + int i, len; + + if (type & UPPERCASE) + dig = upper_digits; + len = 0; + for (i = 0; i < 6; i++) + { + if (i != 0) + tmp[len++] = ':'; + tmp[len++] = dig[addr[i] >> 4]; + tmp[len++] = dig[addr[i] & 0x0F]; + } + + if (!(type & LEFT)) + while (len < size--) + *str++ = ' '; + for (i = 0; i < len; ++i) + *str++ = tmp[i]; + while (len < size--) + *str++ = ' '; + + return str; +} + +static char * +iaddr(char *str, unsigned char *addr, int size, int precision, int type) +{ + char tmp[24]; + int i, n, len; + + len = 0; + for (i = 0; i < 4; i++) + { + if (i != 0) + tmp[len++] = '.'; + n = addr[i]; + + if (n == 0) + tmp[len++] = digits[0]; + else + { + if (n >= 100) + { + tmp[len++] = digits[n / 100]; + n = n % 100; + tmp[len++] = digits[n / 10]; + n = n % 10; + } + else if (n >= 10) + { + tmp[len++] = digits[n / 10]; + n = n % 10; + } + + tmp[len++] = digits[n]; + } + } + + if (!(type & LEFT)) + while (len < size--) + *str++ = ' '; + for (i = 0; i < len; ++i) + *str++ = tmp[i]; + while (len < size--) + *str++ = ' '; + + return str; +} + +#if HAS_FLOAT + +char * ecvtbuf(double arg, int ndigits, int *decpt, int *sign, char *buf); +char * fcvtbuf(double arg, int ndigits, int *decpt, int *sign, char *buf); +static void ee_bufcpy(char *d, char *s, int count); + +void +ee_bufcpy(char *pd, char *ps, int count) +{ + char *pe = ps + count; + while (ps != pe) + *pd++ = *ps++; +} + +static void +parse_float(double value, char *buffer, char fmt, int precision) +{ + int decpt, sign, exp, pos; + char *digits = NULL; + char cvtbuf[80]; + int capexp = 0; + int magnitude; + + if (fmt == 'G' || fmt == 'E') + { + capexp = 1; + fmt += 'a' - 'A'; + } + + if (fmt == 'g') + { + digits = ecvtbuf(value, precision, &decpt, &sign, cvtbuf); + magnitude = decpt - 1; + if (magnitude < -4 || magnitude > precision - 1) + { + fmt = 'e'; + precision -= 1; + } + else + { + fmt = 'f'; + precision -= decpt; + } + } + + if (fmt == 'e') + { + digits = ecvtbuf(value, precision + 1, &decpt, &sign, cvtbuf); + + if (sign) + *buffer++ = '-'; + *buffer++ = *digits; + if (precision > 0) + *buffer++ = '.'; + ee_bufcpy(buffer, digits + 1, precision); + buffer += precision; + *buffer++ = capexp ? 'E' : 'e'; + + if (decpt == 0) + { + if (value == 0.0) + exp = 0; + else + exp = -1; + } + else + exp = decpt - 1; + + if (exp < 0) + { + *buffer++ = '-'; + exp = -exp; + } + else + *buffer++ = '+'; + + buffer[2] = (exp % 10) + '0'; + exp = exp / 10; + buffer[1] = (exp % 10) + '0'; + exp = exp / 10; + buffer[0] = (exp % 10) + '0'; + buffer += 3; + } + else if (fmt == 'f') + { + digits = fcvtbuf(value, precision, &decpt, &sign, cvtbuf); + if (sign) + *buffer++ = '-'; + if (*digits) + { + if (decpt <= 0) + { + *buffer++ = '0'; + *buffer++ = '.'; + for (pos = 0; pos < -decpt; pos++) + *buffer++ = '0'; + while (*digits) + *buffer++ = *digits++; + } + else + { + pos = 0; + while (*digits) + { + if (pos++ == decpt) + *buffer++ = '.'; + *buffer++ = *digits++; + } + } + } + else + { + *buffer++ = '0'; + if (precision > 0) + { + *buffer++ = '.'; + for (pos = 0; pos < precision; pos++) + *buffer++ = '0'; + } + } + } + + *buffer = '\0'; +} + +static void +decimal_point(char *buffer) +{ + while (*buffer) + { + if (*buffer == '.') + return; + if (*buffer == 'e' || *buffer == 'E') + break; + buffer++; + } + + if (*buffer) + { + int n = strnlen(buffer, 256); + while (n > 0) + { + buffer[n + 1] = buffer[n]; + n--; + } + + *buffer = '.'; + } + else + { + *buffer++ = '.'; + *buffer = '\0'; + } +} + +static void +cropzeros(char *buffer) +{ + char *stop; + + while (*buffer && *buffer != '.') + buffer++; + if (*buffer++) + { + while (*buffer && *buffer != 'e' && *buffer != 'E') + buffer++; + stop = buffer--; + while (*buffer == '0') + buffer--; + if (*buffer == '.') + buffer--; + while (buffer != stop) + *++buffer = 0; + } +} + +static char * +flt(char *str, double num, int size, int precision, char fmt, int flags) +{ + char tmp[80]; + char c, sign; + int n, i; + + // Left align means no zero padding + if (flags & LEFT) + flags &= ~ZEROPAD; + + // Determine padding and sign char + c = (flags & ZEROPAD) ? '0' : ' '; + sign = 0; + if (flags & SIGN) + { + if (num < 0.0) + { + sign = '-'; + num = -num; + size--; + } + else if (flags & PLUS) + { + sign = '+'; + size--; + } + else if (flags & SPACE) + { + sign = ' '; + size--; + } + } + + // Compute the precision value + if (precision < 0) + precision = 6; // Default precision: 6 + + // Convert floating point number to text + parse_float(num, tmp, fmt, precision); + + if ((flags & HEX_PREP) && precision == 0) + decimal_point(tmp); + if (fmt == 'g' && !(flags & HEX_PREP)) + cropzeros(tmp); + + n = strnlen(tmp, 256); + + // Output number with alignment and padding + size -= n; + if (!(flags & (ZEROPAD | LEFT))) + while (size-- > 0) + *str++ = ' '; + if (sign) + *str++ = sign; + if (!(flags & LEFT)) + while (size-- > 0) + *str++ = c; + for (i = 0; i < n; i++) + *str++ = tmp[i]; + while (size-- > 0) + *str++ = ' '; + + return str; +} + +#endif + +static int +ee_vsprintf(char *buf, const char *fmt, va_list args) +{ + int len; + unsigned long num; + int i, base; + char * str; + char * s; + + int flags; // Flags to number() + + int field_width; // Width of output field + int precision; // Min. # of digits for integers; max number of chars for + // from string + int qualifier; // 'h', 'l', or 'L' for integer fields + + for (str = buf; *fmt; fmt++) + { + if (*fmt != '%') + { + *str++ = *fmt; + continue; + } + + // Process flags + flags = 0; + repeat: + fmt++; // This also skips first '%' + switch (*fmt) + { + case '-': + flags |= LEFT; + goto repeat; + case '+': + flags |= PLUS; + goto repeat; + case ' ': + flags |= SPACE; + goto repeat; + case '#': + flags |= HEX_PREP; + goto repeat; + case '0': + flags |= ZEROPAD; + goto repeat; + } + + // Get field width + field_width = -1; + if (is_digit(*fmt)) + field_width = skip_atoi(&fmt); + else if (*fmt == '*') + { + fmt++; + field_width = va_arg(args, int); + if (field_width < 0) + { + field_width = -field_width; + flags |= LEFT; + } + } + + // Get the precision + precision = -1; + if (*fmt == '.') + { + ++fmt; + if (is_digit(*fmt)) + precision = skip_atoi(&fmt); + else if (*fmt == '*') + { + ++fmt; + precision = va_arg(args, int); + } + if (precision < 0) + precision = 0; + } + + // Get the conversion qualifier + qualifier = -1; + if (*fmt == 'l' || *fmt == 'L') + { + qualifier = *fmt; + fmt++; + } + + // Default base + base = 10; + + switch (*fmt) + { + case 'c': + if (!(flags & LEFT)) + while (--field_width > 0) + *str++ = ' '; + *str++ = (unsigned char)va_arg(args, int); + while (--field_width > 0) + *str++ = ' '; + continue; + + case 's': + s = va_arg(args, char *); + if (!s) + s = ""; + len = strnlen(s, precision); + if (!(flags & LEFT)) + while (len < field_width--) + *str++ = ' '; + for (i = 0; i < len; ++i) + *str++ = *s++; + while (len < field_width--) + *str++ = ' '; + continue; + + case 'p': + if (field_width == -1) + { + field_width = 2 * sizeof(void *); + flags |= ZEROPAD; + } + str = number(str, + (unsigned long)va_arg(args, void *), + 16, + field_width, + precision, + flags); + continue; + + case 'A': + flags |= UPPERCASE; + + case 'a': + if (qualifier == 'l') + str = eaddr(str, + va_arg(args, unsigned char *), + field_width, + precision, + flags); + else + str = iaddr(str, + va_arg(args, unsigned char *), + field_width, + precision, + flags); + continue; + + // Integer number formats - set up the flags and "break" + case 'o': + base = 8; + break; + + case 'X': + flags |= UPPERCASE; + + case 'x': + base = 16; + break; + + case 'd': + case 'i': + flags |= SIGN; + + case 'u': + break; + +#if HAS_FLOAT + + case 'f': + str = flt(str, + va_arg(args, double), + field_width, + precision, + *fmt, + flags | SIGN); + continue; + +#endif + + default: + if (*fmt != '%') + *str++ = '%'; + if (*fmt) + *str++ = *fmt; + else + --fmt; + continue; + } + + if (qualifier == 'l') + num = va_arg(args, unsigned long); + else if (flags & SIGN) + num = va_arg(args, int); + else + num = va_arg(args, unsigned int); + + str = number(str, num, base, field_width, precision, flags); + } + + *str = '\0'; + return str - buf; +} + +void +uart_send_char(char c) +{ + *((volatile unsigned int *) (0x40000010)) = c; +} + +int +ee_printf(const char *fmt, ...) +{ + char buf[1024], *p; + va_list args; + int n = 0; + + va_start(args, fmt); + ee_vsprintf(buf, fmt, args); + va_end(args); + p = buf; + while (*p) + { + uart_send_char(*p); + n++; + p++; + } + + return n; +} diff --git a/lab2/coremark/yatcpu/init.s b/lab2/coremark/yatcpu/init.s new file mode 100644 index 0000000..0efae64 --- /dev/null +++ b/lab2/coremark/yatcpu/init.s @@ -0,0 +1,16 @@ +.section .text.init +.globl _start +_start: + li sp, 4092 + call main + li x1, 0xBABECAFE +write_tohost: + sw x1, tohost, x0 +loop: + j loop + +.pushsection .tohost,"aw",@progbits + .align 4 + .global tohost + tohost: .word 0 +.popsection \ No newline at end of file diff --git a/lab2/coremark/yatcpu/link.ld b/lab2/coremark/yatcpu/link.ld new file mode 100644 index 0000000..2ae1500 --- /dev/null +++ b/lab2/coremark/yatcpu/link.ld @@ -0,0 +1,12 @@ +OUTPUT_ARCH( "riscv" ) +ENTRY(_start) + +SECTIONS +{ + . = 0x00001000; + .text : { *(.text.init) *(.text.startup) *(.text) } + .data ALIGN(0x1000) : { *(.data*) *(.rodata*) *(.sdata*) } + .tohost ALIGN(0x1000) : { *(.tohost) } + .bss : { *(.bss) } + _end = .; +} diff --git a/lab2/csrc/CMakeLists.txt b/lab2/csrc/CMakeLists.txt new file mode 100644 index 0000000..32a8ca4 --- /dev/null +++ b/lab2/csrc/CMakeLists.txt @@ -0,0 +1,43 @@ +# Make CMake happy +cmake_minimum_required(VERSION 3.18) +project(yatcpu-programs C CXX ASM) + +# Setting variables +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O0 --target=riscv32-unknown-elf -march=rv32i -mabi=ilp32") +set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -O0 --target=riscv32-unknown-elf -march=rv32i -mabi=ilp32") +set(C_PROGRAMS tetris hello fibonacci quicksort simpletest) +set(ASM_PROGRAMS mmio sb) +set(LINKER_SCRIPT ${CMAKE_SOURCE_DIR}/link.lds) +set(LINKER_FLAGS -T ${LINKER_SCRIPT}) +set(OBJCOPY_ARGS -O binary -j .text -j .data) +if(NOT DEST_DIR) + set(DEST_DIR "../src/main/resources") +endif() + +# Let CMake know that there exists header files +include_directories("${CMAKE_SOURCE_DIR}") + +add_library(prelude init.S) +set_target_properties(prelude PROPERTIES LINK_DEPENDS ${LINKER_SCRIPT}) + +# Let's build our executables +foreach(program IN LISTS C_PROGRAMS) + add_executable(${program} ${program}.c) + set_target_properties(${program} PROPERTIES LINK_DEPENDS ${LINKER_SCRIPT}) + target_link_libraries(${program} prelude ${LINKER_FLAGS}) +endforeach() + +foreach(program IN LISTS ASM_PROGRAMS) + add_executable(${program} ${program}.S) + set_target_properties(${program} PROPERTIES LINK_DEPENDS ${LINKER_SCRIPT}) +endforeach() + +# Copy the .text section to .asmbin files +foreach(program IN LISTS C_PROGRAMS ASM_PROGRAMS) + add_custom_command( + TARGET ${program} + POST_BUILD + COMMAND ${CMAKE_OBJCOPY} ARGS ${OBJCOPY_ARGS} $ ${CMAKE_SOURCE_DIR}/${DEST_DIR}/${program}.asmbin + ) +endforeach() + diff --git a/lab2/csrc/build.bat b/lab2/csrc/build.bat new file mode 100644 index 0000000..b5a522b --- /dev/null +++ b/lab2/csrc/build.bat @@ -0,0 +1,3 @@ +rmdir /Q /S build +cmake -DCMAKE_TOOLCHAIN_FILE=toolchain.cmake -G"NMake Makefiles" -B build . +cmake --build build \ No newline at end of file diff --git a/lab2/csrc/build.sh b/lab2/csrc/build.sh new file mode 100644 index 0000000..e48a4ba --- /dev/null +++ b/lab2/csrc/build.sh @@ -0,0 +1,3 @@ +#!/bin/sh +rm -rf build +cmake -DCMAKE_TOOLCHAIN_FILE=toolchain.cmake -B build . && cmake --build build --parallel `nproc` diff --git a/lab2/csrc/fibonacci.c b/lab2/csrc/fibonacci.c new file mode 100644 index 0000000..9905dde --- /dev/null +++ b/lab2/csrc/fibonacci.c @@ -0,0 +1,22 @@ +// 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. + +int fib(int a) { + if (a == 1 || a == 2) return 1; + return fib(a - 1) + fib(a - 2); +} + +int main() { + *(int *)(4) = fib(10); +} \ No newline at end of file diff --git a/lab2/csrc/hello.c b/lab2/csrc/hello.c new file mode 100644 index 0000000..3e79635 --- /dev/null +++ b/lab2/csrc/hello.c @@ -0,0 +1,175 @@ +// 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. + +#include "mmio.h" + +#define MUL80(x) (((x) << 6) + ((x) << 4)) + +struct screen { + unsigned char row, col; +} scr; + +void copy_line(int prev, int cur) { + int *prev_vram_start = ((int *) (MUL80(prev) + VRAM_BASE)); + int *cur_vram_start = ((int *) (MUL80(cur) + VRAM_BASE)); + for (int i = 0; i < 20; ++i) { + prev_vram_start[i] = cur_vram_start[i]; + } +} + +void write_char(int row, int col, unsigned char ch) { + VRAM[MUL80(row) + col] = ch; +} + +void move_to(int row, int col) { + scr.row = row; + scr.col = col; +} + +void new_line() { + scr.col = 0; + if (scr.row == 29) { + for (int i = 0; i < 29; ++i) { + copy_line(i, i + 1); + } + int *vram = (int *) (MUL80(29) + VRAM_BASE); + for (int i = 0; i < 20; ++i) { + vram[i] = 0x20202020; + } + } else { + ++scr.row; + } +} + +void putch(unsigned char ch) { + if (ch == '\n') { + new_line(); + } else if (ch == '\r') { + scr.col = 0; + } else { + if (scr.col == 79) { + new_line(); + } + write_char(scr.row, scr.col, ch); + ++scr.col; + } +} + +void clear_screen() { + scr.row = 0; + scr.col = 0; + int *vram = ((int *) VRAM_BASE); + for (int i = 0; i < 600; ++i) vram[i] = 0x20202020; +} + +void print_hex(unsigned int counter) { + putch('0'); putch('x'); + for (int i = 7; i >= 0; --i) { + unsigned int num = (counter >> (i << 2)) & 0xF; + if (num < 10) { + putch('0' + num); + } else { + putch('A' + num - 10); + } + } +} + +void putstr(const char *s) { + while (*s) { + putch(*(s++)); + } +} + +int hc = 1; +int fast = 0; + +void print_timer() { + putstr("Hardware timer count limit = "); + print_hex(*TIMER_LIMIT); + putstr(", enabled = "); + print_hex(*TIMER_ENABLED); + putch('\n'); +} + +void print_uart() { + putstr("UART Baud rate = "); + print_hex(*UART_BAUDRATE); + putch('\n'); +} + +void handle_timer() { + putstr("Timer trigger times = "); + print_hex(hc++); + putch('\n'); + int mode = ((hc & 0x10) >> 4); + if (hc == 0x40) { + putstr("Disable timer!\n"); + *TIMER_ENABLED = 0; + print_timer(); + return; + } + if (fast ^ mode) { + putstr("Switch timer frequency\n"); + if (fast == 0) { + *TIMER_LIMIT = 25000000; + } else { + + *TIMER_LIMIT = 100000000; + } + fast = mode; + print_timer(); + } +} + +void handle_uart() { + unsigned int ch = *UART_RECV; + *UART_SEND = ch; + putstr("UART Recv hex = "); print_hex(ch); putstr(", ch = "); putch(ch); putch('\n'); +} + +void trap_handler(void *epc, unsigned int cause) { + putstr("Interrupt! EPC = "); + print_hex((unsigned int) epc); + putstr(", CAUSE = "); + print_hex(cause); + putch('\n'); + switch (cause) { + case 0x8000000B: + handle_uart(); + break; + default: + handle_timer(); + break; + } +} +extern void enable_interrupt(); +extern unsigned int get_epc(); +int main() { + clear_screen(); + hc = 0; + *TIMER_ENABLED = 1; + putstr("YatCPU Demo Program "); + putch(137); + putstr("2021 Howard Lau\n"); + putstr("Hello, world!\n"); + putstr("Last EPC = "); + print_hex(get_epc()); + putch('\n'); + print_timer(); + print_uart(); + *((int *) 0x4) = 0xDEADBEEF; + unsigned int i = 0; + enable_interrupt(); + for (;;) ; +} diff --git a/lab2/csrc/init.S b/lab2/csrc/init.S new file mode 100644 index 0000000..4534c78 --- /dev/null +++ b/lab2/csrc/init.S @@ -0,0 +1,107 @@ +# 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. + +.section .text.init +.globl _start +_start: + li sp, 4096 # Initialize stack pointer + call main # Jump to main function +loop: + j loop # Loop forever +.globl enable_interrupt +enable_interrupt: + la t0, __trap_entry + csrrw t1, mtvec, t0 # setup trap vector base + li t0, 0x1888 + csrrw t1, mstatus, t0 # enable interrupt + ret +.globl get_epc +get_epc: + csrr a0, mepc + ret +.weak trap_handler +tran_handler: + ret +__trap_entry: + csrw mscratch, sp + addi sp, sp, -128 + sw ra, 4(sp) + + sw gp, 12(sp) + sw tp, 16(sp) + sw t0, 20(sp) + sw t1, 24(sp) + sw t2, 28(sp) + sw tp, 32(sp) + sw s1, 36(sp) + sw a0, 40(sp) + sw a1, 44(sp) + sw a2, 48(sp) + sw a3, 52(sp) + sw a4, 56(sp) + sw a5, 60(sp) + sw a6, 64(sp) + sw a7, 68(sp) + sw s2, 72(sp) + sw s3, 76(sp) + sw s4, 80(sp) + sw s5, 84(sp) + sw s6, 88(sp) + sw s7, 92(sp) + sw s8, 96(sp) + sw s9, 100(sp) + sw s10, 104(sp) + sw s11, 108(sp) + sw t3, 112(sp) + sw t4, 116(sp) + sw t5, 120(sp) + sw t6, 124(sp) + + csrr a0, mepc + csrr a1, mcause + call trap_handler + + lw ra, 4(sp) + + lw gp, 12(sp) + lw tp, 16(sp) + lw t0, 20(sp) + lw t1, 24(sp) + lw t2, 28(sp) + lw tp, 32(sp) + lw s1, 36(sp) + lw a0, 40(sp) + lw a1, 44(sp) + lw a2, 48(sp) + lw a3, 52(sp) + lw a4, 56(sp) + lw a5, 60(sp) + lw a6, 64(sp) + lw a7, 68(sp) + lw s2, 72(sp) + lw s3, 76(sp) + lw s4, 80(sp) + lw s5, 84(sp) + lw s6, 88(sp) + lw s7, 92(sp) + lw s8, 96(sp) + lw s9, 100(sp) + lw s10, 104(sp) + lw s11, 108(sp) + lw t3, 112(sp) + lw t4, 116(sp) + lw t5, 120(sp) + lw t6, 124(sp) + csrr sp, mscratch + mret diff --git a/lab2/csrc/link.lds b/lab2/csrc/link.lds new file mode 100644 index 0000000..b5d8366 --- /dev/null +++ b/lab2/csrc/link.lds @@ -0,0 +1,11 @@ +OUTPUT_ARCH( "riscv" ) +ENTRY(_start) + +SECTIONS +{ + . = 0x00001000; + .text : { *(.text.init) *(.text.startup) *(.text) } + .data ALIGN(0x1000) : { *(.data*) *(.rodata*) *(.sdata*) } + .bss : { *(.bss) } + _end = .; +} diff --git a/lab2/csrc/mmio.S b/lab2/csrc/mmio.S new file mode 100644 index 0000000..7b49530 --- /dev/null +++ b/lab2/csrc/mmio.S @@ -0,0 +1,24 @@ +# 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. + +.globl _start +_start: + li a0, 0x80000000 + lw t0, 4(a0) + li a1, 0xBEEF + sw a1, 4(a0) + nop + lw t1, 4(a0) +loop: + j loop diff --git a/lab2/csrc/mmio.h b/lab2/csrc/mmio.h new file mode 100644 index 0000000..b1222dd --- /dev/null +++ b/lab2/csrc/mmio.h @@ -0,0 +1,23 @@ +// 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. + +#define VRAM_BASE 0x20000000 +#define VRAM ((volatile unsigned char *) VRAM_BASE) +#define TIMER_BASE 0x80000000 +#define TIMER_LIMIT ((volatile unsigned int *) (TIMER_BASE + 4)) +#define TIMER_ENABLED ((volatile unsigned int *) (TIMER_BASE + 8)) +#define UART_BASE 0x40000000 +#define UART_BAUDRATE ((volatile unsigned int *) (UART_BASE + 4)) +#define UART_RECV ((volatile unsigned int *) (UART_BASE + 12)) +#define UART_SEND ((volatile unsigned int *) (UART_BASE + 16)) diff --git a/lab2/csrc/quicksort.c b/lab2/csrc/quicksort.c new file mode 100644 index 0000000..5105ef1 --- /dev/null +++ b/lab2/csrc/quicksort.c @@ -0,0 +1,50 @@ +// 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. + +void quicksort(int *arr, int l, int r) { + if (l >= r) return; + int pivot = arr[l]; + int i = l, j = r; + while (i < j) { + while(arr[j] >= pivot && i < j) --j; + arr[i] = arr[j]; + while(arr[i] < pivot && i < j) ++i; + arr[j] = arr[i]; + } + arr[i] = pivot; + quicksort(arr, l, i - 1); + quicksort(arr, i + 1, r); +} + +int main() { + int nums[10]; + + nums[0] = 6; + nums[1] = 2; + nums[2] = 4; + nums[3] = 5; + nums[4] = 3; + nums[5] = 1; + nums[6] = 0; + nums[7] = 9; + nums[8] = 7; + nums[9] = 8; + + + quicksort(nums, 0, 9); + + for (int i = 1; i <= 10; ++i) { + *(int *)(i * 4) = nums[i - 1]; + } +} \ No newline at end of file diff --git a/lab2/csrc/sb.S b/lab2/csrc/sb.S new file mode 100644 index 0000000..ed71a72 --- /dev/null +++ b/lab2/csrc/sb.S @@ -0,0 +1,25 @@ +# 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. + +.globl _start +_start: + li a0, 0x4 + li t0, 0xDEADBEEF + sb t0, 0(a0) + lw t1, 0(a0) + li s2, 0x15 + sb s2, 1(a0) + lw ra, 0(a0) +loop: + j loop diff --git a/lab2/csrc/simpletest.c b/lab2/csrc/simpletest.c new file mode 100644 index 0000000..3993a24 --- /dev/null +++ b/lab2/csrc/simpletest.c @@ -0,0 +1,12 @@ + +extern void enable_interrupt(); + +void trap_handler(void *epc, unsigned int cause){ + *((int*)0x4) = 0x2022; +} + +int main(){ + *((int*)0x4) = 0xDEADBEEF; + enable_interrupt(); + for(;;); +} \ No newline at end of file diff --git a/lab2/csrc/tetris.S b/lab2/csrc/tetris.S new file mode 100644 index 0000000..53b41cb --- /dev/null +++ b/lab2/csrc/tetris.S @@ -0,0 +1,2023 @@ + +build/tetris: file format elf32-littleriscv + + +Disassembly of section .text: + +00001000 <_start>: + 1000: 00001137 lui sp,0x1 + 1004: 00002097 auipc ra,0x2 + 1008: be4080e7 jalr -1052(ra) # 2be8
+ +0000100c : + 100c: 0000006f j 100c + +00001010 : + 1010: 00000297 auipc t0,0x0 + 1014: 02828293 addi t0,t0,40 # 1038 <__trap_entry> + 1018: 30529373 csrrw t1,mtvec,t0 + 101c: 000022b7 lui t0,0x2 + 1020: 88828293 addi t0,t0,-1912 # 1888 + 1024: 30029373 csrrw t1,mstatus,t0 + 1028: 00008067 ret + +0000102c : + 102c: 34102573 csrr a0,mepc + 1030: 00008067 ret + +00001034 : + 1034: 00008067 ret + +00001038 <__trap_entry>: + 1038: 34011073 csrw mscratch,sp + 103c: f8010113 addi sp,sp,-128 # f80 <_start-0x80> + 1040: 00112223 sw ra,4(sp) + 1044: 00312623 sw gp,12(sp) + 1048: 00412823 sw tp,16(sp) + 104c: 00512a23 sw t0,20(sp) + 1050: 00612c23 sw t1,24(sp) + 1054: 00712e23 sw t2,28(sp) + 1058: 02412023 sw tp,32(sp) + 105c: 02912223 sw s1,36(sp) + 1060: 02a12423 sw a0,40(sp) + 1064: 02b12623 sw a1,44(sp) + 1068: 02c12823 sw a2,48(sp) + 106c: 02d12a23 sw a3,52(sp) + 1070: 02e12c23 sw a4,56(sp) + 1074: 02f12e23 sw a5,60(sp) + 1078: 05012023 sw a6,64(sp) + 107c: 05112223 sw a7,68(sp) + 1080: 05212423 sw s2,72(sp) + 1084: 05312623 sw s3,76(sp) + 1088: 05412823 sw s4,80(sp) + 108c: 05512a23 sw s5,84(sp) + 1090: 05612c23 sw s6,88(sp) + 1094: 05712e23 sw s7,92(sp) + 1098: 07812023 sw s8,96(sp) + 109c: 07912223 sw s9,100(sp) + 10a0: 07a12423 sw s10,104(sp) + 10a4: 07b12623 sw s11,108(sp) + 10a8: 07c12823 sw t3,112(sp) + 10ac: 07d12a23 sw t4,116(sp) + 10b0: 07e12c23 sw t5,120(sp) + 10b4: 07f12e23 sw t6,124(sp) + 10b8: 34102573 csrr a0,mepc + 10bc: 342025f3 csrr a1,mcause + 10c0: 00001097 auipc ra,0x1 + 10c4: 6f0080e7 jalr 1776(ra) # 27b0 + 10c8: 00412083 lw ra,4(sp) + 10cc: 00c12183 lw gp,12(sp) + 10d0: 01012203 lw tp,16(sp) + 10d4: 01412283 lw t0,20(sp) + 10d8: 01812303 lw t1,24(sp) + 10dc: 01c12383 lw t2,28(sp) + 10e0: 02012203 lw tp,32(sp) + 10e4: 02412483 lw s1,36(sp) + 10e8: 02812503 lw a0,40(sp) + 10ec: 02c12583 lw a1,44(sp) + 10f0: 03012603 lw a2,48(sp) + 10f4: 03412683 lw a3,52(sp) + 10f8: 03812703 lw a4,56(sp) + 10fc: 03c12783 lw a5,60(sp) + 1100: 04012803 lw a6,64(sp) + 1104: 04412883 lw a7,68(sp) + 1108: 04812903 lw s2,72(sp) + 110c: 04c12983 lw s3,76(sp) + 1110: 05012a03 lw s4,80(sp) + 1114: 05412a83 lw s5,84(sp) + 1118: 05812b03 lw s6,88(sp) + 111c: 05c12b83 lw s7,92(sp) + 1120: 06012c03 lw s8,96(sp) + 1124: 06412c83 lw s9,100(sp) + 1128: 06812d03 lw s10,104(sp) + 112c: 06c12d83 lw s11,108(sp) + 1130: 07012e03 lw t3,112(sp) + 1134: 07412e83 lw t4,116(sp) + 1138: 07812f03 lw t5,120(sp) + 113c: 07c12f83 lw t6,124(sp) + 1140: 34002173 csrr sp,mscratch + 1144: 30200073 mret + +00001148 : + 1148: fe010113 addi sp,sp,-32 + 114c: 00112e23 sw ra,28(sp) + 1150: 00812c23 sw s0,24(sp) + 1154: 02010413 addi s0,sp,32 + 1158: fea42a23 sw a0,-12(s0) + 115c: feb42823 sw a1,-16(s0) + 1160: 00000513 li a0,0 + 1164: fea42623 sw a0,-20(s0) + 1168: 0040006f j 116c + 116c: ff042503 lw a0,-16(s0) + 1170: 00000593 li a1,0 + 1174: 04b50863 beq a0,a1,11c4 + 1178: 0040006f j 117c + 117c: ff044503 lbu a0,-16(s0) + 1180: 00157513 andi a0,a0,1 + 1184: 00000593 li a1,0 + 1188: 00b50e63 beq a0,a1,11a4 + 118c: 0040006f j 1190 + 1190: ff442583 lw a1,-12(s0) + 1194: fec42503 lw a0,-20(s0) + 1198: 00b50533 add a0,a0,a1 + 119c: fea42623 sw a0,-20(s0) + 11a0: 0040006f j 11a4 + 11a4: 0040006f j 11a8 + 11a8: ff442503 lw a0,-12(s0) + 11ac: 00151513 slli a0,a0,0x1 + 11b0: fea42a23 sw a0,-12(s0) + 11b4: ff042503 lw a0,-16(s0) + 11b8: 40155513 srai a0,a0,0x1 + 11bc: fea42823 sw a0,-16(s0) + 11c0: fadff06f j 116c + 11c4: fec42503 lw a0,-20(s0) + 11c8: 01812403 lw s0,24(sp) + 11cc: 01c12083 lw ra,28(sp) + 11d0: 02010113 addi sp,sp,32 + 11d4: 00008067 ret + +000011d8 : + 11d8: fe010113 addi sp,sp,-32 + 11dc: 00112e23 sw ra,28(sp) + 11e0: 00812c23 sw s0,24(sp) + 11e4: 02010413 addi s0,sp,32 + 11e8: fea42a23 sw a0,-12(s0) + 11ec: feb42823 sw a1,-16(s0) + 11f0: fec42623 sw a2,-20(s0) + 11f4: fed42423 sw a3,-24(s0) + 11f8: ff442503 lw a0,-12(s0) + 11fc: 00c51513 slli a0,a0,0xc + 1200: ff042583 lw a1,-16(s0) + 1204: 00459593 slli a1,a1,0x4 + 1208: 00b56533 or a0,a0,a1 + 120c: fec42583 lw a1,-20(s0) + 1210: 00259593 slli a1,a1,0x2 + 1214: 00b56533 or a0,a0,a1 + 1218: fe842583 lw a1,-24(s0) + 121c: 00b56533 or a0,a0,a1 + 1220: 01812403 lw s0,24(sp) + 1224: 01c12083 lw ra,28(sp) + 1228: 02010113 addi sp,sp,32 + 122c: 00008067 ret + +00001230 : + 1230: fd010113 addi sp,sp,-48 + 1234: 02112623 sw ra,44(sp) + 1238: 02812423 sw s0,40(sp) + 123c: 03010413 addi s0,sp,48 + 1240: fea42a23 sw a0,-12(s0) + 1244: feb42823 sw a1,-16(s0) + 1248: fec42623 sw a2,-20(s0) + 124c: fed42423 sw a3,-24(s0) + 1250: 00000513 li a0,0 + 1254: fea42223 sw a0,-28(s0) + 1258: fea42023 sw a0,-32(s0) + 125c: ff442583 lw a1,-12(s0) + 1260: 00a5a423 sw a0,8(a1) + 1264: ff442583 lw a1,-12(s0) + 1268: 00a5a223 sw a0,4(a1) + 126c: ff442583 lw a1,-12(s0) + 1270: 00a5a023 sw a0,0(a1) + 1274: ff042583 lw a1,-16(s0) + 1278: fcb42e23 sw a1,-36(s0) + 127c: 00600513 li a0,6 + 1280: 12b56c63 bltu a0,a1,13b8 <.LBB2_8+0x2c> + 1284: fdc42503 lw a0,-36(s0) + 1288: 00251513 slli a0,a0,0x2 + 128c: 000035b7 lui a1,0x3 + 1290: 00058593 mv a1,a1 + 1294: 00b50533 add a0,a0,a1 + 1298: 00052503 lw a0,0(a0) + 129c: 00050067 jr a0 + +000012a0 <.LBB2_2>: + 12a0: ff442583 lw a1,-12(s0) + 12a4: 00f00513 li a0,15 + 12a8: 00a5a023 sw a0,0(a1) # 3000 <.LJTI2_0> + 12ac: 00300513 li a0,3 + 12b0: fea42223 sw a0,-28(s0) + 12b4: 00000513 li a0,0 + 12b8: fea42023 sw a0,-32(s0) + 12bc: 0fc0006f j 13b8 <.LBB2_8+0x2c> + +000012c0 <.LBB2_3>: + 12c0: ff442583 lw a1,-12(s0) + 12c4: 00300513 li a0,3 + 12c8: 00a5a023 sw a0,0(a1) + 12cc: ff442583 lw a1,-12(s0) + 12d0: 00a5a223 sw a0,4(a1) + 12d4: 00100513 li a0,1 + 12d8: fea42223 sw a0,-28(s0) + 12dc: fea42023 sw a0,-32(s0) + 12e0: 0d80006f j 13b8 <.LBB2_8+0x2c> + +000012e4 <.LBB2_4>: + 12e4: ff442583 lw a1,-12(s0) + 12e8: 00400513 li a0,4 + 12ec: 00a5a023 sw a0,0(a1) + 12f0: ff442583 lw a1,-12(s0) + 12f4: 00700513 li a0,7 + 12f8: 00a5a223 sw a0,4(a1) + 12fc: 00200513 li a0,2 + 1300: fea42223 sw a0,-28(s0) + 1304: 00100513 li a0,1 + 1308: fea42023 sw a0,-32(s0) + 130c: 0ac0006f j 13b8 <.LBB2_8+0x2c> + +00001310 <.LBB2_5>: + 1310: ff442583 lw a1,-12(s0) + 1314: 00200513 li a0,2 + 1318: 00a5a023 sw a0,0(a1) + 131c: ff442603 lw a2,-12(s0) + 1320: 00700593 li a1,7 + 1324: 00b62223 sw a1,4(a2) + 1328: fea42223 sw a0,-28(s0) + 132c: 00100513 li a0,1 + 1330: fea42023 sw a0,-32(s0) + 1334: 0840006f j 13b8 <.LBB2_8+0x2c> + +00001338 <.LBB2_6>: + 1338: ff442583 lw a1,-12(s0) + 133c: 00100513 li a0,1 + 1340: 00a5a023 sw a0,0(a1) + 1344: ff442603 lw a2,-12(s0) + 1348: 00700593 li a1,7 + 134c: 00b62223 sw a1,4(a2) + 1350: 00200593 li a1,2 + 1354: feb42223 sw a1,-28(s0) + 1358: fea42023 sw a0,-32(s0) + 135c: 05c0006f j 13b8 <.LBB2_8+0x2c> + +00001360 <.LBB2_7>: + 1360: ff442583 lw a1,-12(s0) + 1364: 00600513 li a0,6 + 1368: 00a5a023 sw a0,0(a1) + 136c: ff442583 lw a1,-12(s0) + 1370: 00300513 li a0,3 + 1374: 00a5a223 sw a0,4(a1) + 1378: 00200513 li a0,2 + 137c: fea42223 sw a0,-28(s0) + 1380: 00100513 li a0,1 + 1384: fea42023 sw a0,-32(s0) + 1388: 0300006f j 13b8 <.LBB2_8+0x2c> + +0000138c <.LBB2_8>: + 138c: ff442583 lw a1,-12(s0) + 1390: 00300513 li a0,3 + 1394: 00a5a023 sw a0,0(a1) + 1398: ff442583 lw a1,-12(s0) + 139c: 00600513 li a0,6 + 13a0: 00a5a223 sw a0,4(a1) + 13a4: 00200513 li a0,2 + 13a8: fea42223 sw a0,-28(s0) + 13ac: 00100513 li a0,1 + 13b0: fea42023 sw a0,-32(s0) + 13b4: 0040006f j 13b8 <.LBB2_8+0x2c> + 13b8: fec42503 lw a0,-20(s0) + 13bc: fe842583 lw a1,-24(s0) + 13c0: fe442603 lw a2,-28(s0) + 13c4: fe042683 lw a3,-32(s0) + 13c8: 00000097 auipc ra,0x0 + 13cc: e10080e7 jalr -496(ra) # 11d8 + 13d0: ff442583 lw a1,-12(s0) + 13d4: 00a5a623 sw a0,12(a1) + 13d8: 02812403 lw s0,40(sp) + 13dc: 02c12083 lw ra,44(sp) + 13e0: 03010113 addi sp,sp,48 + 13e4: 00008067 ret + +000013e8 : + 13e8: fe010113 addi sp,sp,-32 + 13ec: 00112e23 sw ra,28(sp) + 13f0: 00812c23 sw s0,24(sp) + 13f4: 02010413 addi s0,sp,32 + 13f8: fea42a23 sw a0,-12(s0) + 13fc: feb42823 sw a1,-16(s0) + 1400: fec42623 sw a2,-20(s0) + 1404: ff442503 lw a0,-12(s0) + 1408: ff042583 lw a1,-16(s0) + 140c: 00259593 slli a1,a1,0x2 + 1410: 00b50533 add a0,a0,a1 + 1414: 00052503 lw a0,0(a0) + 1418: fec42583 lw a1,-20(s0) + 141c: 00100613 li a2,1 + 1420: 00b61633 sll a2,a2,a1 + 1424: 00c57533 and a0,a0,a2 + 1428: 00b55533 srl a0,a0,a1 + 142c: 01812403 lw s0,24(sp) + 1430: 01c12083 lw ra,28(sp) + 1434: 02010113 addi sp,sp,32 + 1438: 00008067 ret + +0000143c : + 143c: fd010113 addi sp,sp,-48 + 1440: 02112623 sw ra,44(sp) + 1444: 02812423 sw s0,40(sp) + 1448: 03010413 addi s0,sp,48 + 144c: fea42823 sw a0,-16(s0) + 1450: ff042503 lw a0,-16(s0) + 1454: 00c52503 lw a0,12(a0) + 1458: fea42623 sw a0,-20(s0) + 145c: fec42503 lw a0,-20(s0) + 1460: 00357513 andi a0,a0,3 + 1464: fea42423 sw a0,-24(s0) + 1468: fec42503 lw a0,-20(s0) + 146c: 00c57513 andi a0,a0,12 + 1470: 00255513 srli a0,a0,0x2 + 1474: fea42223 sw a0,-28(s0) + 1478: fec42503 lw a0,-20(s0) + 147c: 000015b7 lui a1,0x1 + 1480: ff058593 addi a1,a1,-16 # ff0 <_start-0x10> + 1484: 00b57533 and a0,a0,a1 + 1488: 00455513 srli a0,a0,0x4 + 148c: fea42023 sw a0,-32(s0) + 1490: fec42503 lw a0,-20(s0) + 1494: 01051513 slli a0,a0,0x10 + 1498: 01c55513 srli a0,a0,0x1c + 149c: fca42e23 sw a0,-36(s0) + 14a0: 00000513 li a0,0 + 14a4: 02a51063 bne a0,a0,14c4 + 14a8: 0040006f j 14ac + 14ac: fdc42503 lw a0,-36(s0) + 14b0: fe442583 lw a1,-28(s0) + 14b4: 00b50533 add a0,a0,a1 + 14b8: 00a00593 li a1,10 + 14bc: 00b56a63 bltu a0,a1,14d0 + 14c0: 0040006f j 14c4 + 14c4: 00000513 li a0,0 + 14c8: fea42a23 sw a0,-12(s0) + 14cc: 0400006f j 150c + 14d0: 00000513 li a0,0 + 14d4: 02a51063 bne a0,a0,14f4 + 14d8: 0040006f j 14dc + 14dc: fe042503 lw a0,-32(s0) + 14e0: fe842583 lw a1,-24(s0) + 14e4: 00b50533 add a0,a0,a1 + 14e8: 01600593 li a1,22 + 14ec: 00b56a63 bltu a0,a1,1500 + 14f0: 0040006f j 14f4 + 14f4: 00000513 li a0,0 + 14f8: fea42a23 sw a0,-12(s0) + 14fc: 0100006f j 150c + 1500: 00100513 li a0,1 + 1504: fea42a23 sw a0,-12(s0) + 1508: 0040006f j 150c + 150c: ff442503 lw a0,-12(s0) + 1510: 02812403 lw s0,40(sp) + 1514: 02c12083 lw ra,44(sp) + 1518: 03010113 addi sp,sp,48 + 151c: 00008067 ret + +00001520 : + 1520: ff010113 addi sp,sp,-16 + 1524: 00112623 sw ra,12(sp) + 1528: 00812423 sw s0,8(sp) + 152c: 01010413 addi s0,sp,16 + 1530: fea42a23 sw a0,-12(s0) + 1534: feb42823 sw a1,-16(s0) + 1538: ff042503 lw a0,-16(s0) + 153c: 00c52503 lw a0,12(a0) + 1540: ff442583 lw a1,-12(s0) + 1544: 00a5a623 sw a0,12(a1) + 1548: ff042503 lw a0,-16(s0) + 154c: 00052503 lw a0,0(a0) + 1550: ff442583 lw a1,-12(s0) + 1554: 00a5a023 sw a0,0(a1) + 1558: ff042503 lw a0,-16(s0) + 155c: 00452503 lw a0,4(a0) + 1560: ff442583 lw a1,-12(s0) + 1564: 00a5a223 sw a0,4(a1) + 1568: ff042503 lw a0,-16(s0) + 156c: 00852503 lw a0,8(a0) + 1570: ff442583 lw a1,-12(s0) + 1574: 00a5a423 sw a0,8(a1) + 1578: 00812403 lw s0,8(sp) + 157c: 00c12083 lw ra,12(sp) + 1580: 01010113 addi sp,sp,16 + 1584: 00008067 ret + +00001588 : + 1588: fd010113 addi sp,sp,-48 + 158c: 02112623 sw ra,44(sp) + 1590: 02812423 sw s0,40(sp) + 1594: 03010413 addi s0,sp,48 + 1598: fea42823 sw a0,-16(s0) + 159c: ff042503 lw a0,-16(s0) + 15a0: 00c52503 lw a0,12(a0) + 15a4: fea42623 sw a0,-20(s0) + 15a8: fec42503 lw a0,-20(s0) + 15ac: 00357513 andi a0,a0,3 + 15b0: fea42423 sw a0,-24(s0) + 15b4: fec42503 lw a0,-20(s0) + 15b8: 00c57513 andi a0,a0,12 + 15bc: 00255513 srli a0,a0,0x2 + 15c0: fea42223 sw a0,-28(s0) + 15c4: fec42503 lw a0,-20(s0) + 15c8: 000015b7 lui a1,0x1 + 15cc: ff058593 addi a1,a1,-16 # ff0 <_start-0x10> + 15d0: 00b57533 and a0,a0,a1 + 15d4: 00455513 srli a0,a0,0x4 + 15d8: fea42023 sw a0,-32(s0) + 15dc: fec42503 lw a0,-20(s0) + 15e0: 01051513 slli a0,a0,0x10 + 15e4: 01c55513 srli a0,a0,0x1c + 15e8: fca42e23 sw a0,-36(s0) + 15ec: 00000513 li a0,0 + 15f0: fca42c23 sw a0,-40(s0) + 15f4: 0040006f j 15f8 + 15f8: fd842583 lw a1,-40(s0) + 15fc: fe842503 lw a0,-24(s0) + 1600: 0cb56463 bltu a0,a1,16c8 + 1604: 0040006f j 1608 + 1608: 00000513 li a0,0 + 160c: fca42a23 sw a0,-44(s0) + 1610: 0040006f j 1614 + 1614: fd442583 lw a1,-44(s0) + 1618: fe442503 lw a0,-28(s0) + 161c: 08b56c63 bltu a0,a1,16b4 + 1620: 0040006f j 1624 + 1624: ff042503 lw a0,-16(s0) + 1628: fd842583 lw a1,-40(s0) + 162c: fd442603 lw a2,-44(s0) + 1630: 00000097 auipc ra,0x0 + 1634: db8080e7 jalr -584(ra) # 13e8 + 1638: 00000593 li a1,0 + 163c: 06b50263 beq a0,a1,16a0 + 1640: 0040006f j 1644 + 1644: 00003537 lui a0,0x3 + 1648: 07c52503 lw a0,124(a0) # 307c <_end> + 164c: fca42823 sw a0,-48(s0) + 1650: fe042503 lw a0,-32(s0) + 1654: fd842583 lw a1,-40(s0) + 1658: 00b50533 add a0,a0,a1 + 165c: 00a00593 li a1,10 + 1660: 00000097 auipc ra,0x0 + 1664: ae8080e7 jalr -1304(ra) # 1148 + 1668: 00050593 mv a1,a0 + 166c: fd042503 lw a0,-48(s0) + 1670: fdc42603 lw a2,-36(s0) + 1674: 00c585b3 add a1,a1,a2 + 1678: fd442603 lw a2,-44(s0) + 167c: 00c585b3 add a1,a1,a2 + 1680: 00b50533 add a0,a0,a1 + 1684: 00054503 lbu a0,0(a0) + 1688: 00000593 li a1,0 + 168c: 00b50a63 beq a0,a1,16a0 + 1690: 0040006f j 1694 + 1694: 00000513 li a0,0 + 1698: fea42a23 sw a0,-12(s0) + 169c: 0380006f j 16d4 + 16a0: 0040006f j 16a4 + 16a4: fd442503 lw a0,-44(s0) + 16a8: 00150513 addi a0,a0,1 + 16ac: fca42a23 sw a0,-44(s0) + 16b0: f65ff06f j 1614 + 16b4: 0040006f j 16b8 + 16b8: fd842503 lw a0,-40(s0) + 16bc: 00150513 addi a0,a0,1 + 16c0: fca42c23 sw a0,-40(s0) + 16c4: f35ff06f j 15f8 + 16c8: 00100513 li a0,1 + 16cc: fea42a23 sw a0,-12(s0) + 16d0: 0040006f j 16d4 + 16d4: ff442503 lw a0,-12(s0) + 16d8: 02812403 lw s0,40(sp) + 16dc: 02c12083 lw ra,44(sp) + 16e0: 03010113 addi sp,sp,48 + 16e4: 00008067 ret + +000016e8 : + 16e8: fe010113 addi sp,sp,-32 + 16ec: 00112e23 sw ra,28(sp) + 16f0: 00812c23 sw s0,24(sp) + 16f4: 02010413 addi s0,sp,32 + 16f8: fea42a23 sw a0,-12(s0) + 16fc: feb42823 sw a1,-16(s0) + 1700: fec407a3 sb a2,-17(s0) + 1704: fef40503 lb a0,-17(s0) + 1708: fea42423 sw a0,-24(s0) + 170c: ff042503 lw a0,-16(s0) + 1710: 00350513 addi a0,a0,3 + 1714: 05000593 li a1,80 + 1718: 00000097 auipc ra,0x0 + 171c: a30080e7 jalr -1488(ra) # 1148 + 1720: 00050593 mv a1,a0 + 1724: fe842503 lw a0,-24(s0) + 1728: ff442603 lw a2,-12(s0) + 172c: 00c585b3 add a1,a1,a2 + 1730: 20000637 lui a2,0x20000 + 1734: 01c60613 addi a2,a2,28 # 2000001c + 1738: 00c585b3 add a1,a1,a2 + 173c: 00a58023 sb a0,0(a1) + 1740: 01812403 lw s0,24(sp) + 1744: 01c12083 lw ra,28(sp) + 1748: 02010113 addi sp,sp,32 + 174c: 00008067 ret + +00001750 : + 1750: fd010113 addi sp,sp,-48 + 1754: 02112623 sw ra,44(sp) + 1758: 02812423 sw s0,40(sp) + 175c: 03010413 addi s0,sp,48 + 1760: fea42a23 sw a0,-12(s0) + 1764: feb42823 sw a1,-16(s0) + 1768: ff442503 lw a0,-12(s0) + 176c: 00c52503 lw a0,12(a0) + 1770: fea42623 sw a0,-20(s0) + 1774: fec42503 lw a0,-20(s0) + 1778: 00357513 andi a0,a0,3 + 177c: fea42423 sw a0,-24(s0) + 1780: fec42503 lw a0,-20(s0) + 1784: 00c57513 andi a0,a0,12 + 1788: 00255513 srli a0,a0,0x2 + 178c: fea42223 sw a0,-28(s0) + 1790: fec42503 lw a0,-20(s0) + 1794: 000015b7 lui a1,0x1 + 1798: ff058593 addi a1,a1,-16 # ff0 <_start-0x10> + 179c: 00b57533 and a0,a0,a1 + 17a0: 00455513 srli a0,a0,0x4 + 17a4: fea42023 sw a0,-32(s0) + 17a8: fec42503 lw a0,-20(s0) + 17ac: 01051513 slli a0,a0,0x10 + 17b0: 01c55513 srli a0,a0,0x1c + 17b4: fca42e23 sw a0,-36(s0) + 17b8: ff042503 lw a0,-16(s0) + 17bc: fca42c23 sw a0,-40(s0) + 17c0: 00000593 li a1,0 + 17c4: 02b50463 beq a0,a1,17ec + 17c8: 0040006f j 17cc + 17cc: fd842503 lw a0,-40(s0) + 17d0: 00100593 li a1,1 + 17d4: 02b50463 beq a0,a1,17fc + 17d8: 0040006f j 17dc + 17dc: fd842503 lw a0,-40(s0) + 17e0: 00200593 li a1,2 + 17e4: 02b50463 beq a0,a1,180c + 17e8: 0340006f j 181c + 17ec: fdc42503 lw a0,-36(s0) + 17f0: fff50513 addi a0,a0,-1 + 17f4: fca42e23 sw a0,-36(s0) + 17f8: 0280006f j 1820 + 17fc: fdc42503 lw a0,-36(s0) + 1800: 00150513 addi a0,a0,1 + 1804: fca42e23 sw a0,-36(s0) + 1808: 0180006f j 1820 + 180c: fe042503 lw a0,-32(s0) + 1810: 00150513 addi a0,a0,1 + 1814: fea42023 sw a0,-32(s0) + 1818: 0080006f j 1820 + 181c: 0040006f j 1820 + 1820: fdc42503 lw a0,-36(s0) + 1824: 00c51513 slli a0,a0,0xc + 1828: fe042583 lw a1,-32(s0) + 182c: 00459593 slli a1,a1,0x4 + 1830: 00b56533 or a0,a0,a1 + 1834: fe442583 lw a1,-28(s0) + 1838: 00259593 slli a1,a1,0x2 + 183c: 00b56533 or a0,a0,a1 + 1840: fe842583 lw a1,-24(s0) + 1844: 00b56533 or a0,a0,a1 + 1848: ff442583 lw a1,-12(s0) + 184c: 00a5a623 sw a0,12(a1) + 1850: 02812403 lw s0,40(sp) + 1854: 02c12083 lw ra,44(sp) + 1858: 03010113 addi sp,sp,48 + 185c: 00008067 ret + +00001860 : + 1860: fd010113 addi sp,sp,-48 + 1864: 02112623 sw ra,44(sp) + 1868: 02812423 sw s0,40(sp) + 186c: 03010413 addi s0,sp,48 + 1870: fea42823 sw a0,-16(s0) + 1874: feb42623 sw a1,-20(s0) + 1878: ff042583 lw a1,-16(s0) + 187c: fd840513 addi a0,s0,-40 + 1880: fca42a23 sw a0,-44(s0) + 1884: 00000097 auipc ra,0x0 + 1888: c9c080e7 jalr -868(ra) # 1520 + 188c: fd442503 lw a0,-44(s0) + 1890: fec42583 lw a1,-20(s0) + 1894: 00000097 auipc ra,0x0 + 1898: ebc080e7 jalr -324(ra) # 1750 + 189c: fd442503 lw a0,-44(s0) + 18a0: 00000097 auipc ra,0x0 + 18a4: b9c080e7 jalr -1124(ra) # 143c + 18a8: 00000593 li a1,0 + 18ac: 02b50e63 beq a0,a1,18e8 + 18b0: 0040006f j 18b4 + 18b4: fd840513 addi a0,s0,-40 + 18b8: 00000097 auipc ra,0x0 + 18bc: cd0080e7 jalr -816(ra) # 1588 + 18c0: 00000593 li a1,0 + 18c4: 02b50263 beq a0,a1,18e8 + 18c8: 0040006f j 18cc + 18cc: ff042503 lw a0,-16(s0) + 18d0: fd840593 addi a1,s0,-40 + 18d4: 00000097 auipc ra,0x0 + 18d8: c4c080e7 jalr -948(ra) # 1520 + 18dc: 00100513 li a0,1 + 18e0: fea42a23 sw a0,-12(s0) + 18e4: 0100006f j 18f4 + 18e8: 00000513 li a0,0 + 18ec: fea42a23 sw a0,-12(s0) + 18f0: 0040006f j 18f4 + 18f4: ff442503 lw a0,-12(s0) + 18f8: 02812403 lw s0,40(sp) + 18fc: 02c12083 lw ra,44(sp) + 1900: 03010113 addi sp,sp,48 + 1904: 00008067 ret + +00001908 : + 1908: fa010113 addi sp,sp,-96 + 190c: 04112e23 sw ra,92(sp) + 1910: 04812c23 sw s0,88(sp) + 1914: 06010413 addi s0,sp,96 + 1918: fea42a23 sw a0,-12(s0) + 191c: feb42823 sw a1,-16(s0) + 1920: ff442503 lw a0,-12(s0) + 1924: 00c52503 lw a0,12(a0) + 1928: fea42623 sw a0,-20(s0) + 192c: fec42503 lw a0,-20(s0) + 1930: 00357513 andi a0,a0,3 + 1934: fea42423 sw a0,-24(s0) + 1938: fec42503 lw a0,-20(s0) + 193c: 00c57513 andi a0,a0,12 + 1940: 00255513 srli a0,a0,0x2 + 1944: fea42223 sw a0,-28(s0) + 1948: fec42503 lw a0,-20(s0) + 194c: 000015b7 lui a1,0x1 + 1950: ff058593 addi a1,a1,-16 # ff0 <_start-0x10> + 1954: 00b57533 and a0,a0,a1 + 1958: 00455513 srli a0,a0,0x4 + 195c: fea42023 sw a0,-32(s0) + 1960: fec42503 lw a0,-20(s0) + 1964: 01051513 slli a0,a0,0x10 + 1968: 01c55513 srli a0,a0,0x1c + 196c: fca42e23 sw a0,-36(s0) + 1970: fdc42503 lw a0,-36(s0) + 1974: fe042583 lw a1,-32(s0) + 1978: fe842603 lw a2,-24(s0) + 197c: fe442683 lw a3,-28(s0) + 1980: 00000097 auipc ra,0x0 + 1984: 858080e7 jalr -1960(ra) # 11d8 + 1988: fca42c23 sw a0,-40(s0) + 198c: 00000593 li a1,0 + 1990: fcb42a23 sw a1,-44(s0) + 1994: fcb42823 sw a1,-48(s0) + 1998: fcb42623 sw a1,-52(s0) + 199c: ff042503 lw a0,-16(s0) + 19a0: 0cb50463 beq a0,a1,1a68 + 19a4: 0040006f j 19a8 + 19a8: 00000513 li a0,0 + 19ac: fca42423 sw a0,-56(s0) + 19b0: 0040006f j 19b4 + 19b4: fc842583 lw a1,-56(s0) + 19b8: fe842503 lw a0,-24(s0) + 19bc: 0ab56463 bltu a0,a1,1a64 + 19c0: 0040006f j 19c4 + 19c4: 00000513 li a0,0 + 19c8: fca42223 sw a0,-60(s0) + 19cc: 0040006f j 19d0 + 19d0: fc442583 lw a1,-60(s0) + 19d4: fe442503 lw a0,-28(s0) + 19d8: 06b56c63 bltu a0,a1,1a50 + 19dc: 0040006f j 19e0 + 19e0: fc442603 lw a2,-60(s0) + 19e4: 00261593 slli a1,a2,0x2 + 19e8: fcc40513 addi a0,s0,-52 + 19ec: faa42a23 sw a0,-76(s0) + 19f0: 00b50533 add a0,a0,a1 + 19f4: 00052503 lw a0,0(a0) + 19f8: faa42c23 sw a0,-72(s0) + 19fc: ff442503 lw a0,-12(s0) + 1a00: fc842583 lw a1,-56(s0) + 1a04: 00000097 auipc ra,0x0 + 1a08: 9e4080e7 jalr -1564(ra) # 13e8 + 1a0c: fb442583 lw a1,-76(s0) + 1a10: 00050613 mv a2,a0 + 1a14: fb842503 lw a0,-72(s0) + 1a18: fe842683 lw a3,-24(s0) + 1a1c: fc842703 lw a4,-56(s0) + 1a20: 40e686b3 sub a3,a3,a4 + 1a24: 00d61633 sll a2,a2,a3 + 1a28: 00c56533 or a0,a0,a2 + 1a2c: fc442603 lw a2,-60(s0) + 1a30: 00261613 slli a2,a2,0x2 + 1a34: 00c585b3 add a1,a1,a2 + 1a38: 00a5a023 sw a0,0(a1) + 1a3c: 0040006f j 1a40 + 1a40: fc442503 lw a0,-60(s0) + 1a44: 00150513 addi a0,a0,1 + 1a48: fca42223 sw a0,-60(s0) + 1a4c: f85ff06f j 19d0 + 1a50: 0040006f j 1a54 + 1a54: fc842503 lw a0,-56(s0) + 1a58: 00150513 addi a0,a0,1 + 1a5c: fca42423 sw a0,-56(s0) + 1a60: f55ff06f j 19b4 + 1a64: 0cc0006f j 1b30 + 1a68: 00000513 li a0,0 + 1a6c: fca42023 sw a0,-64(s0) + 1a70: 0040006f j 1a74 + 1a74: fc042583 lw a1,-64(s0) + 1a78: fe842503 lw a0,-24(s0) + 1a7c: 0ab56863 bltu a0,a1,1b2c + 1a80: 0040006f j 1a84 + 1a84: 00000513 li a0,0 + 1a88: faa42e23 sw a0,-68(s0) + 1a8c: 0040006f j 1a90 + 1a90: fbc42583 lw a1,-68(s0) + 1a94: fe442503 lw a0,-28(s0) + 1a98: 08b56063 bltu a0,a1,1b18 + 1a9c: 0040006f j 1aa0 + 1aa0: fe442503 lw a0,-28(s0) + 1aa4: fbc42603 lw a2,-68(s0) + 1aa8: 40c50533 sub a0,a0,a2 + 1aac: 00251593 slli a1,a0,0x2 + 1ab0: fcc40513 addi a0,s0,-52 + 1ab4: faa42623 sw a0,-84(s0) + 1ab8: 00b50533 add a0,a0,a1 + 1abc: 00052503 lw a0,0(a0) + 1ac0: faa42823 sw a0,-80(s0) + 1ac4: ff442503 lw a0,-12(s0) + 1ac8: fc042583 lw a1,-64(s0) + 1acc: 00000097 auipc ra,0x0 + 1ad0: 91c080e7 jalr -1764(ra) # 13e8 + 1ad4: fac42583 lw a1,-84(s0) + 1ad8: 00050613 mv a2,a0 + 1adc: fb042503 lw a0,-80(s0) + 1ae0: fc042683 lw a3,-64(s0) + 1ae4: 00d61633 sll a2,a2,a3 + 1ae8: 00c56533 or a0,a0,a2 + 1aec: fe442603 lw a2,-28(s0) + 1af0: fbc42683 lw a3,-68(s0) + 1af4: 40d60633 sub a2,a2,a3 + 1af8: 00261613 slli a2,a2,0x2 + 1afc: 00c585b3 add a1,a1,a2 + 1b00: 00a5a023 sw a0,0(a1) + 1b04: 0040006f j 1b08 + 1b08: fbc42503 lw a0,-68(s0) + 1b0c: 00150513 addi a0,a0,1 + 1b10: faa42e23 sw a0,-68(s0) + 1b14: f7dff06f j 1a90 + 1b18: 0040006f j 1b1c + 1b1c: fc042503 lw a0,-64(s0) + 1b20: 00150513 addi a0,a0,1 + 1b24: fca42023 sw a0,-64(s0) + 1b28: f4dff06f j 1a74 + 1b2c: 0040006f j 1b30 + 1b30: fcc42503 lw a0,-52(s0) + 1b34: ff442583 lw a1,-12(s0) + 1b38: 00a5a023 sw a0,0(a1) + 1b3c: fd042503 lw a0,-48(s0) + 1b40: ff442583 lw a1,-12(s0) + 1b44: 00a5a223 sw a0,4(a1) + 1b48: fd442503 lw a0,-44(s0) + 1b4c: ff442583 lw a1,-12(s0) + 1b50: 00a5a423 sw a0,8(a1) + 1b54: fd842503 lw a0,-40(s0) + 1b58: ff442583 lw a1,-12(s0) + 1b5c: 00a5a623 sw a0,12(a1) + 1b60: 05812403 lw s0,88(sp) + 1b64: 05c12083 lw ra,92(sp) + 1b68: 06010113 addi sp,sp,96 + 1b6c: 00008067 ret + +00001b70 : + 1b70: fc010113 addi sp,sp,-64 + 1b74: 02112e23 sw ra,60(sp) + 1b78: 02812c23 sw s0,56(sp) + 1b7c: 04010413 addi s0,sp,64 + 1b80: fea42a23 sw a0,-12(s0) + 1b84: feb42823 sw a1,-16(s0) + 1b88: ff442583 lw a1,-12(s0) + 1b8c: fe040513 addi a0,s0,-32 + 1b90: fca42423 sw a0,-56(s0) + 1b94: 00000097 auipc ra,0x0 + 1b98: 98c080e7 jalr -1652(ra) # 1520 + 1b9c: fc842503 lw a0,-56(s0) + 1ba0: ff042583 lw a1,-16(s0) + 1ba4: 00000097 auipc ra,0x0 + 1ba8: d64080e7 jalr -668(ra) # 1908 + 1bac: fc842503 lw a0,-56(s0) + 1bb0: 00000097 auipc ra,0x0 + 1bb4: 88c080e7 jalr -1908(ra) # 143c + 1bb8: 00000593 li a1,0 + 1bbc: 02b50a63 beq a0,a1,1bf0 + 1bc0: 0040006f j 1bc4 + 1bc4: fe040513 addi a0,s0,-32 + 1bc8: 00000097 auipc ra,0x0 + 1bcc: 9c0080e7 jalr -1600(ra) # 1588 + 1bd0: 00000593 li a1,0 + 1bd4: 00b50e63 beq a0,a1,1bf0 + 1bd8: 0040006f j 1bdc + 1bdc: ff442503 lw a0,-12(s0) + 1be0: fe040593 addi a1,s0,-32 + 1be4: 00000097 auipc ra,0x0 + 1be8: 93c080e7 jalr -1732(ra) # 1520 + 1bec: 0dc0006f j 1cc8 + 1bf0: fec42503 lw a0,-20(s0) + 1bf4: fca42e23 sw a0,-36(s0) + 1bf8: fdc42503 lw a0,-36(s0) + 1bfc: 00357513 andi a0,a0,3 + 1c00: fca42c23 sw a0,-40(s0) + 1c04: fdc42503 lw a0,-36(s0) + 1c08: 00c57513 andi a0,a0,12 + 1c0c: 00255513 srli a0,a0,0x2 + 1c10: fca42a23 sw a0,-44(s0) + 1c14: fdc42503 lw a0,-36(s0) + 1c18: 000015b7 lui a1,0x1 + 1c1c: ff058593 addi a1,a1,-16 # ff0 <_start-0x10> + 1c20: 00b57533 and a0,a0,a1 + 1c24: 00455513 srli a0,a0,0x4 + 1c28: fca42823 sw a0,-48(s0) + 1c2c: fdc42503 lw a0,-36(s0) + 1c30: 01051513 slli a0,a0,0x10 + 1c34: 01c55513 srli a0,a0,0x1c + 1c38: fca42623 sw a0,-52(s0) + 1c3c: fcc42503 lw a0,-52(s0) + 1c40: fd442583 lw a1,-44(s0) + 1c44: 00b50533 add a0,a0,a1 + 1c48: 00a00593 li a1,10 + 1c4c: 00b56e63 bltu a0,a1,1c68 + 1c50: 0040006f j 1c54 + 1c54: fd442583 lw a1,-44(s0) + 1c58: 00900513 li a0,9 + 1c5c: 40b50533 sub a0,a0,a1 + 1c60: fca42623 sw a0,-52(s0) + 1c64: 0040006f j 1c68 + 1c68: fcc42503 lw a0,-52(s0) + 1c6c: fd042583 lw a1,-48(s0) + 1c70: fd442603 lw a2,-44(s0) + 1c74: fd842683 lw a3,-40(s0) + 1c78: fffff097 auipc ra,0xfffff + 1c7c: 560080e7 jalr 1376(ra) # 11d8 + 1c80: fea42623 sw a0,-20(s0) + 1c84: fe040513 addi a0,s0,-32 + 1c88: fffff097 auipc ra,0xfffff + 1c8c: 7b4080e7 jalr 1972(ra) # 143c + 1c90: 00000593 li a1,0 + 1c94: 02b50a63 beq a0,a1,1cc8 + 1c98: 0040006f j 1c9c + 1c9c: fe040513 addi a0,s0,-32 + 1ca0: 00000097 auipc ra,0x0 + 1ca4: 8e8080e7 jalr -1816(ra) # 1588 + 1ca8: 00000593 li a1,0 + 1cac: 00b50e63 beq a0,a1,1cc8 + 1cb0: 0040006f j 1cb4 + 1cb4: ff442503 lw a0,-12(s0) + 1cb8: fe040593 addi a1,s0,-32 + 1cbc: 00000097 auipc ra,0x0 + 1cc0: 864080e7 jalr -1948(ra) # 1520 + 1cc4: 0040006f j 1cc8 + 1cc8: 03812403 lw s0,56(sp) + 1ccc: 03c12083 lw ra,60(sp) + 1cd0: 04010113 addi sp,sp,64 + 1cd4: 00008067 ret + +00001cd8 : + 1cd8: ff010113 addi sp,sp,-16 + 1cdc: 00112623 sw ra,12(sp) + 1ce0: 00812423 sw s0,8(sp) + 1ce4: 01010413 addi s0,sp,16 + 1ce8: 00000513 li a0,0 + 1cec: fea42a23 sw a0,-12(s0) + 1cf0: 01600513 li a0,22 + 1cf4: 00a00593 li a1,10 + 1cf8: fffff097 auipc ra,0xfffff + 1cfc: 450080e7 jalr 1104(ra) # 1148 + 1d00: fea42823 sw a0,-16(s0) + 1d04: 0040006f j 1d08 + 1d08: ff442503 lw a0,-12(s0) + 1d0c: ff042583 lw a1,-16(s0) + 1d10: 02b55a63 bge a0,a1,1d44 + 1d14: 0040006f j 1d18 + 1d18: 00003537 lui a0,0x3 + 1d1c: 07c52503 lw a0,124(a0) # 307c <_end> + 1d20: ff442583 lw a1,-12(s0) + 1d24: 00b505b3 add a1,a0,a1 + 1d28: 00000513 li a0,0 + 1d2c: 00a58023 sb a0,0(a1) + 1d30: 0040006f j 1d34 + 1d34: ff442503 lw a0,-12(s0) + 1d38: 00150513 addi a0,a0,1 + 1d3c: fea42a23 sw a0,-12(s0) + 1d40: fc9ff06f j 1d08 + 1d44: 00812403 lw s0,8(sp) + 1d48: 00c12083 lw ra,12(sp) + 1d4c: 01010113 addi sp,sp,16 + 1d50: 00008067 ret + +00001d54 : + 1d54: fd010113 addi sp,sp,-48 + 1d58: 02112623 sw ra,44(sp) + 1d5c: 02812423 sw s0,40(sp) + 1d60: 03010413 addi s0,sp,48 + 1d64: fea42a23 sw a0,-12(s0) + 1d68: ff442503 lw a0,-12(s0) + 1d6c: 00c52503 lw a0,12(a0) + 1d70: fea42823 sw a0,-16(s0) + 1d74: ff042503 lw a0,-16(s0) + 1d78: 00357513 andi a0,a0,3 + 1d7c: fea42623 sw a0,-20(s0) + 1d80: ff042503 lw a0,-16(s0) + 1d84: 00c57513 andi a0,a0,12 + 1d88: 00255513 srli a0,a0,0x2 + 1d8c: fea42423 sw a0,-24(s0) + 1d90: ff042503 lw a0,-16(s0) + 1d94: 000015b7 lui a1,0x1 + 1d98: ff058593 addi a1,a1,-16 # ff0 <_start-0x10> + 1d9c: 00b57533 and a0,a0,a1 + 1da0: 00455513 srli a0,a0,0x4 + 1da4: fea42223 sw a0,-28(s0) + 1da8: ff042503 lw a0,-16(s0) + 1dac: 01051513 slli a0,a0,0x10 + 1db0: 01c55513 srli a0,a0,0x1c + 1db4: fea42023 sw a0,-32(s0) + 1db8: 00000513 li a0,0 + 1dbc: fca42e23 sw a0,-36(s0) + 1dc0: 0040006f j 1dc4 + 1dc4: fdc42583 lw a1,-36(s0) + 1dc8: fec42503 lw a0,-20(s0) + 1dcc: 0ab56c63 bltu a0,a1,1e84 + 1dd0: 0040006f j 1dd4 + 1dd4: 00000513 li a0,0 + 1dd8: fca42c23 sw a0,-40(s0) + 1ddc: 0040006f j 1de0 + 1de0: fd842583 lw a1,-40(s0) + 1de4: fe842503 lw a0,-24(s0) + 1de8: 08b56463 bltu a0,a1,1e70 + 1dec: 0040006f j 1df0 + 1df0: ff442503 lw a0,-12(s0) + 1df4: fdc42583 lw a1,-36(s0) + 1df8: fd842603 lw a2,-40(s0) + 1dfc: fffff097 auipc ra,0xfffff + 1e00: 5ec080e7 jalr 1516(ra) # 13e8 + 1e04: 00000593 li a1,0 + 1e08: 04b50a63 beq a0,a1,1e5c + 1e0c: 0040006f j 1e10 + 1e10: 00003537 lui a0,0x3 + 1e14: 07c52503 lw a0,124(a0) # 307c <_end> + 1e18: fca42a23 sw a0,-44(s0) + 1e1c: fe442503 lw a0,-28(s0) + 1e20: fdc42583 lw a1,-36(s0) + 1e24: 00b50533 add a0,a0,a1 + 1e28: 00a00593 li a1,10 + 1e2c: fffff097 auipc ra,0xfffff + 1e30: 31c080e7 jalr 796(ra) # 1148 + 1e34: 00050593 mv a1,a0 + 1e38: fd442503 lw a0,-44(s0) + 1e3c: fe042603 lw a2,-32(s0) + 1e40: 00c585b3 add a1,a1,a2 + 1e44: fd842603 lw a2,-40(s0) + 1e48: 00c585b3 add a1,a1,a2 + 1e4c: 00b505b3 add a1,a0,a1 + 1e50: 00100513 li a0,1 + 1e54: 00a58023 sb a0,0(a1) + 1e58: 0040006f j 1e5c + 1e5c: 0040006f j 1e60 + 1e60: fd842503 lw a0,-40(s0) + 1e64: 00150513 addi a0,a0,1 + 1e68: fca42c23 sw a0,-40(s0) + 1e6c: f75ff06f j 1de0 + 1e70: 0040006f j 1e74 + 1e74: fdc42503 lw a0,-36(s0) + 1e78: 00150513 addi a0,a0,1 + 1e7c: fca42e23 sw a0,-36(s0) + 1e80: f45ff06f j 1dc4 + 1e84: 02812403 lw s0,40(sp) + 1e88: 02c12083 lw ra,44(sp) + 1e8c: 03010113 addi sp,sp,48 + 1e90: 00008067 ret + +00001e94 : + 1e94: fe010113 addi sp,sp,-32 + 1e98: 00112e23 sw ra,28(sp) + 1e9c: 00812c23 sw s0,24(sp) + 1ea0: 02010413 addi s0,sp,32 + 1ea4: 00800513 li a0,8 + 1ea8: fea42a23 sw a0,-12(s0) + 1eac: ff442503 lw a0,-12(s0) + 1eb0: 00150593 addi a1,a0,1 + 1eb4: feb42a23 sw a1,-12(s0) + 1eb8: ffe00593 li a1,-2 + 1ebc: feb42223 sw a1,-28(s0) + 1ec0: 05300613 li a2,83 + 1ec4: 00000097 auipc ra,0x0 + 1ec8: 824080e7 jalr -2012(ra) # 16e8 + 1ecc: fe442583 lw a1,-28(s0) + 1ed0: ff442503 lw a0,-12(s0) + 1ed4: 00150613 addi a2,a0,1 + 1ed8: fec42a23 sw a2,-12(s0) + 1edc: 04300613 li a2,67 + 1ee0: 00000097 auipc ra,0x0 + 1ee4: 808080e7 jalr -2040(ra) # 16e8 + 1ee8: fe442583 lw a1,-28(s0) + 1eec: ff442503 lw a0,-12(s0) + 1ef0: 00150613 addi a2,a0,1 + 1ef4: fec42a23 sw a2,-12(s0) + 1ef8: 04f00613 li a2,79 + 1efc: fffff097 auipc ra,0xfffff + 1f00: 7ec080e7 jalr 2028(ra) # 16e8 + 1f04: fe442583 lw a1,-28(s0) + 1f08: ff442503 lw a0,-12(s0) + 1f0c: 00150613 addi a2,a0,1 + 1f10: fec42a23 sw a2,-12(s0) + 1f14: 05200613 li a2,82 + 1f18: fffff097 auipc ra,0xfffff + 1f1c: 7d0080e7 jalr 2000(ra) # 16e8 + 1f20: fe442583 lw a1,-28(s0) + 1f24: ff442503 lw a0,-12(s0) + 1f28: 00150613 addi a2,a0,1 + 1f2c: fec42a23 sw a2,-12(s0) + 1f30: 04500613 li a2,69 + 1f34: fffff097 auipc ra,0xfffff + 1f38: 7b4080e7 jalr 1972(ra) # 16e8 + 1f3c: 00000513 li a0,0 + 1f40: fea42823 sw a0,-16(s0) + 1f44: 0040006f j 1f48 + 1f48: ff042583 lw a1,-16(s0) + 1f4c: 00400513 li a0,4 + 1f50: 06b54a63 blt a0,a1,1fc4 + 1f54: 0040006f j 1f58 + 1f58: ff042503 lw a0,-16(s0) + 1f5c: 00251593 slli a1,a0,0x2 + 1f60: 00f00513 li a0,15 + 1f64: 00b51533 sll a0,a0,a1 + 1f68: fea42623 sw a0,-20(s0) + 1f6c: 00003537 lui a0,0x3 + 1f70: 08052503 lw a0,128(a0) # 3080 + 1f74: fec42583 lw a1,-20(s0) + 1f78: 00b57533 and a0,a0,a1 + 1f7c: ff042583 lw a1,-16(s0) + 1f80: 00259593 slli a1,a1,0x2 + 1f84: 00b55533 srl a0,a0,a1 + 1f88: fea42423 sw a0,-24(s0) + 1f8c: ff042583 lw a1,-16(s0) + 1f90: 00c00513 li a0,12 + 1f94: 40b50533 sub a0,a0,a1 + 1f98: fe842583 lw a1,-24(s0) + 1f9c: 03058593 addi a1,a1,48 + 1fa0: 0ff5f613 andi a2,a1,255 + 1fa4: fff00593 li a1,-1 + 1fa8: fffff097 auipc ra,0xfffff + 1fac: 740080e7 jalr 1856(ra) # 16e8 + 1fb0: 0040006f j 1fb4 + 1fb4: ff042503 lw a0,-16(s0) + 1fb8: 00150513 addi a0,a0,1 + 1fbc: fea42823 sw a0,-16(s0) + 1fc0: f89ff06f j 1f48 + 1fc4: 01812403 lw s0,24(sp) + 1fc8: 01c12083 lw ra,28(sp) + 1fcc: 02010113 addi sp,sp,32 + 1fd0: 00008067 ret + +00001fd4 : + 1fd4: fc010113 addi sp,sp,-64 + 1fd8: 02112e23 sw ra,60(sp) + 1fdc: 02812c23 sw s0,56(sp) + 1fe0: 04010413 addi s0,sp,64 + 1fe4: 00000513 li a0,0 + 1fe8: fea42a23 sw a0,-12(s0) + 1fec: 0040006f j 1ff0 + 1ff0: ff442583 lw a1,-12(s0) + 1ff4: 01500513 li a0,21 + 1ff8: 10b54463 blt a0,a1,2100 + 1ffc: 0040006f j 2000 + 2000: 00000513 li a0,0 + 2004: fea42823 sw a0,-16(s0) + 2008: 0040006f j 200c + 200c: ff042583 lw a1,-16(s0) + 2010: 00900513 li a0,9 + 2014: 0cb54c63 blt a0,a1,20ec + 2018: 0040006f j 201c + 201c: 00003537 lui a0,0x3 + 2020: 07c52503 lw a0,124(a0) # 307c <_end> + 2024: fca42823 sw a0,-48(s0) + 2028: ff442503 lw a0,-12(s0) + 202c: 00a00593 li a1,10 + 2030: fffff097 auipc ra,0xfffff + 2034: 118080e7 jalr 280(ra) # 1148 + 2038: 00050593 mv a1,a0 + 203c: fd042503 lw a0,-48(s0) + 2040: ff042603 lw a2,-16(s0) + 2044: 00c585b3 add a1,a1,a2 + 2048: 00b50533 add a0,a0,a1 + 204c: 00054503 lbu a0,0(a0) + 2050: 00100593 li a1,1 + 2054: 04b51263 bne a0,a1,2098 + 2058: 0040006f j 205c + 205c: ff042503 lw a0,-16(s0) + 2060: 00151513 slli a0,a0,0x1 + 2064: 00156513 ori a0,a0,1 + 2068: ff442583 lw a1,-12(s0) + 206c: 05b00613 li a2,91 + 2070: fffff097 auipc ra,0xfffff + 2074: 678080e7 jalr 1656(ra) # 16e8 + 2078: ff042503 lw a0,-16(s0) + 207c: 00151513 slli a0,a0,0x1 + 2080: 00250513 addi a0,a0,2 + 2084: ff442583 lw a1,-12(s0) + 2088: 05d00613 li a2,93 + 208c: fffff097 auipc ra,0xfffff + 2090: 65c080e7 jalr 1628(ra) # 16e8 + 2094: 0440006f j 20d8 + 2098: ff042503 lw a0,-16(s0) + 209c: 00151513 slli a0,a0,0x1 + 20a0: 00156513 ori a0,a0,1 + 20a4: ff442583 lw a1,-12(s0) + 20a8: 02000613 li a2,32 + 20ac: fcc42623 sw a2,-52(s0) + 20b0: fffff097 auipc ra,0xfffff + 20b4: 638080e7 jalr 1592(ra) # 16e8 + 20b8: fcc42603 lw a2,-52(s0) + 20bc: ff042503 lw a0,-16(s0) + 20c0: 00151513 slli a0,a0,0x1 + 20c4: 00250513 addi a0,a0,2 + 20c8: ff442583 lw a1,-12(s0) + 20cc: fffff097 auipc ra,0xfffff + 20d0: 61c080e7 jalr 1564(ra) # 16e8 + 20d4: 0040006f j 20d8 + 20d8: 0040006f j 20dc + 20dc: ff042503 lw a0,-16(s0) + 20e0: 00150513 addi a0,a0,1 + 20e4: fea42823 sw a0,-16(s0) + 20e8: f25ff06f j 200c + 20ec: 0040006f j 20f0 + 20f0: ff442503 lw a0,-12(s0) + 20f4: 00150513 addi a0,a0,1 + 20f8: fea42a23 sw a0,-12(s0) + 20fc: ef5ff06f j 1ff0 + 2100: 00003537 lui a0,0x3 + 2104: 06c50513 addi a0,a0,108 # 306c + 2108: 00c52503 lw a0,12(a0) + 210c: fea42623 sw a0,-20(s0) + 2110: fec42503 lw a0,-20(s0) + 2114: 00357513 andi a0,a0,3 + 2118: fea42423 sw a0,-24(s0) + 211c: fec42503 lw a0,-20(s0) + 2120: 00c57513 andi a0,a0,12 + 2124: 00255513 srli a0,a0,0x2 + 2128: fea42223 sw a0,-28(s0) + 212c: fec42503 lw a0,-20(s0) + 2130: 000015b7 lui a1,0x1 + 2134: ff058593 addi a1,a1,-16 # ff0 <_start-0x10> + 2138: 00b57533 and a0,a0,a1 + 213c: 00455513 srli a0,a0,0x4 + 2140: fea42023 sw a0,-32(s0) + 2144: fec42503 lw a0,-20(s0) + 2148: 01051513 slli a0,a0,0x10 + 214c: 01c55513 srli a0,a0,0x1c + 2150: fca42e23 sw a0,-36(s0) + 2154: 00000513 li a0,0 + 2158: fca42c23 sw a0,-40(s0) + 215c: 0040006f j 2160 + 2160: fd842583 lw a1,-40(s0) + 2164: fe842503 lw a0,-24(s0) + 2168: 0cb56663 bltu a0,a1,2234 + 216c: 0040006f j 2170 + 2170: 00000513 li a0,0 + 2174: fca42a23 sw a0,-44(s0) + 2178: 0040006f j 217c + 217c: fd442583 lw a1,-44(s0) + 2180: fe442503 lw a0,-28(s0) + 2184: 08b56e63 bltu a0,a1,2220 + 2188: 0040006f j 218c + 218c: fd842583 lw a1,-40(s0) + 2190: fd442603 lw a2,-44(s0) + 2194: 00003537 lui a0,0x3 + 2198: 06c50513 addi a0,a0,108 # 306c + 219c: fffff097 auipc ra,0xfffff + 21a0: 24c080e7 jalr 588(ra) # 13e8 + 21a4: 00000593 li a1,0 + 21a8: 06b50263 beq a0,a1,220c + 21ac: 0040006f j 21b0 + 21b0: fd442503 lw a0,-44(s0) + 21b4: fdc42583 lw a1,-36(s0) + 21b8: 00b50533 add a0,a0,a1 + 21bc: 00151513 slli a0,a0,0x1 + 21c0: 00156513 ori a0,a0,1 + 21c4: fd842583 lw a1,-40(s0) + 21c8: fe042603 lw a2,-32(s0) + 21cc: 00c585b3 add a1,a1,a2 + 21d0: 05b00613 li a2,91 + 21d4: fffff097 auipc ra,0xfffff + 21d8: 514080e7 jalr 1300(ra) # 16e8 + 21dc: fd442503 lw a0,-44(s0) + 21e0: fdc42583 lw a1,-36(s0) + 21e4: 00b50533 add a0,a0,a1 + 21e8: 00151513 slli a0,a0,0x1 + 21ec: 00250513 addi a0,a0,2 + 21f0: fd842583 lw a1,-40(s0) + 21f4: fe042603 lw a2,-32(s0) + 21f8: 00c585b3 add a1,a1,a2 + 21fc: 05d00613 li a2,93 + 2200: fffff097 auipc ra,0xfffff + 2204: 4e8080e7 jalr 1256(ra) # 16e8 + 2208: 0040006f j 220c + 220c: 0040006f j 2210 + 2210: fd442503 lw a0,-44(s0) + 2214: 00150513 addi a0,a0,1 + 2218: fca42a23 sw a0,-44(s0) + 221c: f61ff06f j 217c + 2220: 0040006f j 2224 + 2224: fd842503 lw a0,-40(s0) + 2228: 00150513 addi a0,a0,1 + 222c: fca42c23 sw a0,-40(s0) + 2230: f31ff06f j 2160 + 2234: 00000097 auipc ra,0x0 + 2238: c60080e7 jalr -928(ra) # 1e94 + 223c: 03812403 lw s0,56(sp) + 2240: 03c12083 lw ra,60(sp) + 2244: 04010113 addi sp,sp,64 + 2248: 00008067 ret + +0000224c : + 224c: fe010113 addi sp,sp,-32 + 2250: 00112e23 sw ra,28(sp) + 2254: 00812c23 sw s0,24(sp) + 2258: 02010413 addi s0,sp,32 + 225c: fea42a23 sw a0,-12(s0) + 2260: ff442603 lw a2,-12(s0) + 2264: 000035b7 lui a1,0x3 + 2268: 0805a503 lw a0,128(a1) # 3080 + 226c: 00c50533 add a0,a0,a2 + 2270: 08a5a023 sw a0,128(a1) + 2274: 00000513 li a0,0 + 2278: fea42823 sw a0,-16(s0) + 227c: fea42623 sw a0,-20(s0) + 2280: 0040006f j 2284 + 2284: ff042583 lw a1,-16(s0) + 2288: 01f00513 li a0,31 + 228c: 0ab56e63 bltu a0,a1,2348 + 2290: 0040006f j 2294 + 2294: ff042583 lw a1,-16(s0) + 2298: 00f00513 li a0,15 + 229c: 00b51533 sll a0,a0,a1 + 22a0: fea42423 sw a0,-24(s0) + 22a4: 00003537 lui a0,0x3 + 22a8: 08052503 lw a0,128(a0) # 3080 + 22ac: fe842583 lw a1,-24(s0) + 22b0: 00b57533 and a0,a0,a1 + 22b4: ff042583 lw a1,-16(s0) + 22b8: 00b55533 srl a0,a0,a1 + 22bc: fea42223 sw a0,-28(s0) + 22c0: fec42583 lw a1,-20(s0) + 22c4: fe442503 lw a0,-28(s0) + 22c8: 00b50533 add a0,a0,a1 + 22cc: fea42223 sw a0,-28(s0) + 22d0: fe442503 lw a0,-28(s0) + 22d4: 00a00593 li a1,10 + 22d8: 02b56063 bltu a0,a1,22f8 + 22dc: 0040006f j 22e0 + 22e0: 00100513 li a0,1 + 22e4: fea42623 sw a0,-20(s0) + 22e8: fe442503 lw a0,-28(s0) + 22ec: ff650513 addi a0,a0,-10 + 22f0: fea42223 sw a0,-28(s0) + 22f4: 0100006f j 2304 + 22f8: 00000513 li a0,0 + 22fc: fea42623 sw a0,-20(s0) + 2300: 0040006f j 2304 + 2304: fe842503 lw a0,-24(s0) + 2308: fff54613 not a2,a0 + 230c: 000035b7 lui a1,0x3 + 2310: 0805a503 lw a0,128(a1) # 3080 + 2314: 00c57533 and a0,a0,a2 + 2318: 08a5a023 sw a0,128(a1) + 231c: fe442503 lw a0,-28(s0) + 2320: ff042603 lw a2,-16(s0) + 2324: 00c51633 sll a2,a0,a2 + 2328: 0805a503 lw a0,128(a1) + 232c: 00c56533 or a0,a0,a2 + 2330: 08a5a023 sw a0,128(a1) + 2334: 0040006f j 2338 + 2338: ff042503 lw a0,-16(s0) + 233c: 00450513 addi a0,a0,4 + 2340: fea42823 sw a0,-16(s0) + 2344: f41ff06f j 2284 + 2348: 01812403 lw s0,24(sp) + 234c: 01c12083 lw ra,28(sp) + 2350: 02010113 addi sp,sp,32 + 2354: 00008067 ret + +00002358 : + 2358: fc010113 addi sp,sp,-64 + 235c: 02112e23 sw ra,60(sp) + 2360: 02812c23 sw s0,56(sp) + 2364: 04010413 addi s0,sp,64 + 2368: 00003537 lui a0,0x3 + 236c: 06c50513 addi a0,a0,108 # 306c + 2370: 00c52583 lw a1,12(a0) + 2374: 00001637 lui a2,0x1 + 2378: ff060613 addi a2,a2,-16 # ff0 <_start-0x10> + 237c: 00c5f5b3 and a1,a1,a2 + 2380: 0045d593 srli a1,a1,0x4 + 2384: feb42a23 sw a1,-12(s0) + 2388: 00c52503 lw a0,12(a0) + 238c: 00357513 andi a0,a0,3 + 2390: fea42823 sw a0,-16(s0) + 2394: ff442503 lw a0,-12(s0) + 2398: ff042583 lw a1,-16(s0) + 239c: 00b50533 add a0,a0,a1 + 23a0: fea42623 sw a0,-20(s0) + 23a4: 0040006f j 23a8 + 23a8: fec42503 lw a0,-20(s0) + 23ac: ff442583 lw a1,-12(s0) + 23b0: 1ab56c63 bltu a0,a1,2568 + 23b4: 0040006f j 23b8 + 23b8: 00000513 li a0,0 + 23bc: fea42423 sw a0,-24(s0) + 23c0: fea42223 sw a0,-28(s0) + 23c4: 0040006f j 23c8 + 23c8: fe442583 lw a1,-28(s0) + 23cc: 00900513 li a0,9 + 23d0: 06b54663 blt a0,a1,243c + 23d4: 0040006f j 23d8 + 23d8: 00003537 lui a0,0x3 + 23dc: 07c52503 lw a0,124(a0) # 307c <_end> + 23e0: fca42c23 sw a0,-40(s0) + 23e4: fec42503 lw a0,-20(s0) + 23e8: 00a00593 li a1,10 + 23ec: fffff097 auipc ra,0xfffff + 23f0: d5c080e7 jalr -676(ra) # 1148 + 23f4: 00050593 mv a1,a0 + 23f8: fd842503 lw a0,-40(s0) + 23fc: fe442603 lw a2,-28(s0) + 2400: 00c585b3 add a1,a1,a2 + 2404: 00b50533 add a0,a0,a1 + 2408: 00054503 lbu a0,0(a0) + 240c: 00000593 li a1,0 + 2410: 00b50c63 beq a0,a1,2428 + 2414: 0040006f j 2418 + 2418: fe842503 lw a0,-24(s0) + 241c: 00150513 addi a0,a0,1 + 2420: fea42423 sw a0,-24(s0) + 2424: 0040006f j 2428 + 2428: 0040006f j 242c + 242c: fe442503 lw a0,-28(s0) + 2430: 00150513 addi a0,a0,1 + 2434: fea42223 sw a0,-28(s0) + 2438: f91ff06f j 23c8 + 243c: fe842503 lw a0,-24(s0) + 2440: 00a00593 li a1,10 + 2444: 10b51863 bne a0,a1,2554 + 2448: 0040006f j 244c + 244c: 00100513 li a0,1 + 2450: 00000097 auipc ra,0x0 + 2454: dfc080e7 jalr -516(ra) # 224c + 2458: fec42503 lw a0,-20(s0) + 245c: fff50513 addi a0,a0,-1 + 2460: fea42023 sw a0,-32(s0) + 2464: 0040006f j 2468 + 2468: fe042583 lw a1,-32(s0) + 246c: 00000513 li a0,0 + 2470: 0cb55463 bge a0,a1,2538 + 2474: 0040006f j 2478 + 2478: 00000513 li a0,0 + 247c: fca42e23 sw a0,-36(s0) + 2480: 0040006f j 2484 + 2484: fdc42583 lw a1,-36(s0) + 2488: 00900513 li a0,9 + 248c: 08b54c63 blt a0,a1,2524 + 2490: 0040006f j 2494 + 2494: 00003537 lui a0,0x3 + 2498: fca42623 sw a0,-52(s0) + 249c: 07c52503 lw a0,124(a0) # 307c <_end> + 24a0: fca42223 sw a0,-60(s0) + 24a4: fe042503 lw a0,-32(s0) + 24a8: 00a00593 li a1,10 + 24ac: fcb42423 sw a1,-56(s0) + 24b0: fffff097 auipc ra,0xfffff + 24b4: c98080e7 jalr -872(ra) # 1148 + 24b8: fc442603 lw a2,-60(s0) + 24bc: fc842583 lw a1,-56(s0) + 24c0: 00050693 mv a3,a0 + 24c4: fcc42503 lw a0,-52(s0) + 24c8: fdc42703 lw a4,-36(s0) + 24cc: 00e686b3 add a3,a3,a4 + 24d0: 00d60633 add a2,a2,a3 + 24d4: 00060603 lb a2,0(a2) + 24d8: fcc42a23 sw a2,-44(s0) + 24dc: 07c52503 lw a0,124(a0) + 24e0: fca42823 sw a0,-48(s0) + 24e4: fe042503 lw a0,-32(s0) + 24e8: 00150513 addi a0,a0,1 + 24ec: fffff097 auipc ra,0xfffff + 24f0: c5c080e7 jalr -932(ra) # 1148 + 24f4: fd042583 lw a1,-48(s0) + 24f8: 00050613 mv a2,a0 + 24fc: fd442503 lw a0,-44(s0) + 2500: fdc42683 lw a3,-36(s0) + 2504: 00d60633 add a2,a2,a3 + 2508: 00c585b3 add a1,a1,a2 + 250c: 00a58023 sb a0,0(a1) + 2510: 0040006f j 2514 + 2514: fdc42503 lw a0,-36(s0) + 2518: 00150513 addi a0,a0,1 + 251c: fca42e23 sw a0,-36(s0) + 2520: f65ff06f j 2484 + 2524: 0040006f j 2528 + 2528: fe042503 lw a0,-32(s0) + 252c: fff50513 addi a0,a0,-1 + 2530: fea42023 sw a0,-32(s0) + 2534: f35ff06f j 2468 + 2538: fec42503 lw a0,-20(s0) + 253c: 00150513 addi a0,a0,1 + 2540: fea42623 sw a0,-20(s0) + 2544: ff442503 lw a0,-12(s0) + 2548: 00150513 addi a0,a0,1 + 254c: fea42a23 sw a0,-12(s0) + 2550: 0040006f j 2554 + 2554: 0040006f j 2558 + 2558: fec42503 lw a0,-20(s0) + 255c: fff50513 addi a0,a0,-1 + 2560: fea42623 sw a0,-20(s0) + 2564: e45ff06f j 23a8 + 2568: 03812403 lw s0,56(sp) + 256c: 03c12083 lw ra,60(sp) + 2570: 04010113 addi sp,sp,64 + 2574: 00008067 ret + +00002578 : + 2578: ff010113 addi sp,sp,-16 + 257c: 00112623 sw ra,12(sp) + 2580: 00812423 sw s0,8(sp) + 2584: 01010413 addi s0,sp,16 + 2588: 00003537 lui a0,0x3 + 258c: fea42a23 sw a0,-12(s0) + 2590: 06852583 lw a1,104(a0) # 3068 + 2594: 41c65537 lui a0,0x41c65 + 2598: e6d50513 addi a0,a0,-403 # 41c64e6d + 259c: fffff097 auipc ra,0xfffff + 25a0: bac080e7 jalr -1108(ra) # 1148 + 25a4: 00050593 mv a1,a0 + 25a8: ff442503 lw a0,-12(s0) + 25ac: 00003637 lui a2,0x3 + 25b0: 03960613 addi a2,a2,57 # 3039 <.LJTI21_0+0x1d> + 25b4: 00c585b3 add a1,a1,a2 + 25b8: 80000637 lui a2,0x80000 + 25bc: fff60613 addi a2,a2,-1 # 7fffffff + 25c0: 00c5f5b3 and a1,a1,a2 + 25c4: 06b52423 sw a1,104(a0) + 25c8: 06852503 lw a0,104(a0) + 25cc: 00812403 lw s0,8(sp) + 25d0: 00c12083 lw ra,12(sp) + 25d4: 01010113 addi sp,sp,16 + 25d8: 00008067 ret + +000025dc : + 25dc: ff010113 addi sp,sp,-16 + 25e0: 00112623 sw ra,12(sp) + 25e4: 00812423 sw s0,8(sp) + 25e8: 01010413 addi s0,sp,16 + 25ec: 00000097 auipc ra,0x0 + 25f0: f8c080e7 jalr -116(ra) # 2578 + 25f4: 00757513 andi a0,a0,7 + 25f8: fea42a23 sw a0,-12(s0) + 25fc: 0040006f j 2600 + 2600: ff442503 lw a0,-12(s0) + 2604: 00700593 li a1,7 + 2608: 00b51e63 bne a0,a1,2624 + 260c: 0040006f j 2610 + 2610: 00000097 auipc ra,0x0 + 2614: f68080e7 jalr -152(ra) # 2578 + 2618: 00757513 andi a0,a0,7 + 261c: fea42a23 sw a0,-12(s0) + 2620: fe1ff06f j 2600 + 2624: ff442503 lw a0,-12(s0) + 2628: 00812403 lw s0,8(sp) + 262c: 00c12083 lw ra,12(sp) + 2630: 01010113 addi sp,sp,16 + 2634: 00008067 ret + +00002638 : + 2638: ff010113 addi sp,sp,-16 + 263c: 00112623 sw ra,12(sp) + 2640: 00812423 sw s0,8(sp) + 2644: 01010413 addi s0,sp,16 + 2648: 00003537 lui a0,0x3 + 264c: 06c50513 addi a0,a0,108 # 306c + 2650: 00200593 li a1,2 + 2654: fffff097 auipc ra,0xfffff + 2658: 20c080e7 jalr 524(ra) # 1860 + 265c: 00000593 li a1,0 + 2660: 04b51463 bne a0,a1,26a8 + 2664: 0040006f j 2668 + 2668: 00003537 lui a0,0x3 + 266c: 06c50513 addi a0,a0,108 # 306c + 2670: fea42a23 sw a0,-12(s0) + 2674: fffff097 auipc ra,0xfffff + 2678: 6e0080e7 jalr 1760(ra) # 1d54 + 267c: 00000097 auipc ra,0x0 + 2680: cdc080e7 jalr -804(ra) # 2358 + 2684: 00000097 auipc ra,0x0 + 2688: f58080e7 jalr -168(ra) # 25dc + 268c: 00050593 mv a1,a0 + 2690: ff442503 lw a0,-12(s0) + 2694: 00400613 li a2,4 + 2698: 00000693 li a3,0 + 269c: fffff097 auipc ra,0xfffff + 26a0: b94080e7 jalr -1132(ra) # 1230 + 26a4: 0040006f j 26a8 + 26a8: 00812403 lw s0,8(sp) + 26ac: 00c12083 lw ra,12(sp) + 26b0: 01010113 addi sp,sp,16 + 26b4: 00008067 ret + +000026b8 : + 26b8: ff010113 addi sp,sp,-16 + 26bc: 00112623 sw ra,12(sp) + 26c0: 00812423 sw s0,8(sp) + 26c4: 01010413 addi s0,sp,16 + 26c8: fea42a23 sw a0,-12(s0) + 26cc: ff442503 lw a0,-12(s0) + 26d0: f9f50593 addi a1,a0,-97 + 26d4: feb42823 sw a1,-16(s0) + 26d8: 01200513 li a0,18 + 26dc: 08b56663 bltu a0,a1,2768 <.LBB21_7> + 26e0: ff042503 lw a0,-16(s0) + 26e4: 00251513 slli a0,a0,0x2 + 26e8: 000035b7 lui a1,0x3 + 26ec: 01c58593 addi a1,a1,28 # 301c <.LJTI21_0> + 26f0: 00b50533 add a0,a0,a1 + 26f4: 00052503 lw a0,0(a0) + 26f8: 00050067 jr a0 + +000026fc <.LBB21_2>: + 26fc: 00000097 auipc ra,0x0 + 2700: f3c080e7 jalr -196(ra) # 2638 + 2704: 0640006f j 2768 <.LBB21_7> + +00002708 <.LBB21_3>: + 2708: 00003537 lui a0,0x3 + 270c: 06c50513 addi a0,a0,108 # 306c + 2710: 00000593 li a1,0 + 2714: fffff097 auipc ra,0xfffff + 2718: 14c080e7 jalr 332(ra) # 1860 + 271c: 04c0006f j 2768 <.LBB21_7> + +00002720 <.LBB21_4>: + 2720: 00003537 lui a0,0x3 + 2724: 06c50513 addi a0,a0,108 # 306c + 2728: 00100593 li a1,1 + 272c: fffff097 auipc ra,0xfffff + 2730: 134080e7 jalr 308(ra) # 1860 + 2734: 0340006f j 2768 <.LBB21_7> + +00002738 <.LBB21_5>: + 2738: 00003537 lui a0,0x3 + 273c: 06c50513 addi a0,a0,108 # 306c + 2740: 00000593 li a1,0 + 2744: fffff097 auipc ra,0xfffff + 2748: 42c080e7 jalr 1068(ra) # 1b70 + 274c: 01c0006f j 2768 <.LBB21_7> + +00002750 <.LBB21_6>: + 2750: 00003537 lui a0,0x3 + 2754: 06c50513 addi a0,a0,108 # 306c + 2758: 00100593 li a1,1 + 275c: fffff097 auipc ra,0xfffff + 2760: 414080e7 jalr 1044(ra) # 1b70 + 2764: 0040006f j 2768 <.LBB21_7> + +00002768 <.LBB21_7>: + 2768: 00000097 auipc ra,0x0 + 276c: 86c080e7 jalr -1940(ra) # 1fd4 + 2770: 00812403 lw s0,8(sp) + 2774: 00c12083 lw ra,12(sp) + 2778: 01010113 addi sp,sp,16 + 277c: 00008067 ret + +00002780 : + 2780: ff010113 addi sp,sp,-16 + 2784: 00112623 sw ra,12(sp) + 2788: 00812423 sw s0,8(sp) + 278c: 01010413 addi s0,sp,16 + 2790: 00000097 auipc ra,0x0 + 2794: ea8080e7 jalr -344(ra) # 2638 + 2798: 00000097 auipc ra,0x0 + 279c: 83c080e7 jalr -1988(ra) # 1fd4 + 27a0: 00812403 lw s0,8(sp) + 27a4: 00c12083 lw ra,12(sp) + 27a8: 01010113 addi sp,sp,16 + 27ac: 00008067 ret + +000027b0 : + 27b0: fe010113 addi sp,sp,-32 + 27b4: 00112e23 sw ra,28(sp) + 27b8: 00812c23 sw s0,24(sp) + 27bc: 02010413 addi s0,sp,32 + 27c0: fea42a23 sw a0,-12(s0) + 27c4: feb42823 sw a1,-16(s0) + 27c8: ff042503 lw a0,-16(s0) + 27cc: 800005b7 lui a1,0x80000 + 27d0: 00758593 addi a1,a1,7 # 80000007 + 27d4: 00b51a63 bne a0,a1,27e8 + 27d8: 0040006f j 27dc + 27dc: 00000097 auipc ra,0x0 + 27e0: fa4080e7 jalr -92(ra) # 2780 + 27e4: 0280006f j 280c + 27e8: 400005b7 lui a1,0x40000 + 27ec: 00c5a503 lw a0,12(a1) # 4000000c + 27f0: fea42623 sw a0,-20(s0) + 27f4: fec42503 lw a0,-20(s0) + 27f8: 00a5a823 sw a0,16(a1) + 27fc: fec42503 lw a0,-20(s0) + 2800: 00000097 auipc ra,0x0 + 2804: eb8080e7 jalr -328(ra) # 26b8 + 2808: 0040006f j 280c + 280c: 01812403 lw s0,24(sp) + 2810: 01c12083 lw ra,28(sp) + 2814: 02010113 addi sp,sp,32 + 2818: 00008067 ret + +0000281c : + 281c: fc010113 addi sp,sp,-64 + 2820: 02112e23 sw ra,60(sp) + 2824: 02812c23 sw s0,56(sp) + 2828: 04010413 addi s0,sp,64 + 282c: fffff097 auipc ra,0xfffff + 2830: 4ac080e7 jalr 1196(ra) # 1cd8 + 2834: 00000513 li a0,0 + 2838: fea42a23 sw a0,-12(s0) + 283c: 0040006f j 2840 + 2840: ff442583 lw a1,-12(s0) + 2844: 01500513 li a0,21 + 2848: 04b54463 blt a0,a1,2890 + 284c: 0040006f j 2850 + 2850: ff442583 lw a1,-12(s0) + 2854: 00000513 li a0,0 + 2858: 07c00613 li a2,124 + 285c: fec42423 sw a2,-24(s0) + 2860: fffff097 auipc ra,0xfffff + 2864: e88080e7 jalr -376(ra) # 16e8 + 2868: fe842603 lw a2,-24(s0) + 286c: ff442583 lw a1,-12(s0) + 2870: 01500513 li a0,21 + 2874: fffff097 auipc ra,0xfffff + 2878: e74080e7 jalr -396(ra) # 16e8 + 287c: 0040006f j 2880 + 2880: ff442503 lw a0,-12(s0) + 2884: 00150513 addi a0,a0,1 + 2888: fea42a23 sw a0,-12(s0) + 288c: fb5ff06f j 2840 + 2890: 00000513 li a0,0 + 2894: fea42823 sw a0,-16(s0) + 2898: 0040006f j 289c + 289c: ff042583 lw a1,-16(s0) + 28a0: 00001537 lui a0,0x1 + 28a4: 80150513 addi a0,a0,-2047 # 801 <_start-0x7ff> + 28a8: 02b54863 blt a0,a1,28d8 + 28ac: 0040006f j 28b0 + 28b0: ff042503 lw a0,-16(s0) + 28b4: 01600593 li a1,22 + 28b8: 02d00613 li a2,45 + 28bc: fffff097 auipc ra,0xfffff + 28c0: e2c080e7 jalr -468(ra) # 16e8 + 28c4: 0040006f j 28c8 + 28c8: ff042503 lw a0,-16(s0) + 28cc: 00150513 addi a0,a0,1 + 28d0: fea42823 sw a0,-16(s0) + 28d4: fc9ff06f j 289c + 28d8: 00800513 li a0,8 + 28dc: fea42623 sw a0,-20(s0) + 28e0: fec42503 lw a0,-20(s0) + 28e4: 00150593 addi a1,a0,1 + 28e8: feb42623 sw a1,-20(s0) + 28ec: 01700593 li a1,23 + 28f0: fcb42823 sw a1,-48(s0) + 28f4: 05400613 li a2,84 + 28f8: fcc42623 sw a2,-52(s0) + 28fc: fffff097 auipc ra,0xfffff + 2900: dec080e7 jalr -532(ra) # 16e8 + 2904: fd042583 lw a1,-48(s0) + 2908: fec42503 lw a0,-20(s0) + 290c: 00150613 addi a2,a0,1 + 2910: fec42623 sw a2,-20(s0) + 2914: 04500613 li a2,69 + 2918: fffff097 auipc ra,0xfffff + 291c: dd0080e7 jalr -560(ra) # 16e8 + 2920: fcc42603 lw a2,-52(s0) + 2924: fd042583 lw a1,-48(s0) + 2928: fec42503 lw a0,-20(s0) + 292c: 00150693 addi a3,a0,1 + 2930: fed42623 sw a3,-20(s0) + 2934: fffff097 auipc ra,0xfffff + 2938: db4080e7 jalr -588(ra) # 16e8 + 293c: fd042583 lw a1,-48(s0) + 2940: fec42503 lw a0,-20(s0) + 2944: 00150613 addi a2,a0,1 + 2948: fec42623 sw a2,-20(s0) + 294c: 05200613 li a2,82 + 2950: fffff097 auipc ra,0xfffff + 2954: d98080e7 jalr -616(ra) # 16e8 + 2958: fd042583 lw a1,-48(s0) + 295c: fec42503 lw a0,-20(s0) + 2960: 00150613 addi a2,a0,1 + 2964: fec42623 sw a2,-20(s0) + 2968: 04900613 li a2,73 + 296c: fffff097 auipc ra,0xfffff + 2970: d7c080e7 jalr -644(ra) # 16e8 + 2974: fd042583 lw a1,-48(s0) + 2978: fec42503 lw a0,-20(s0) + 297c: 00150613 addi a2,a0,1 + 2980: fec42623 sw a2,-20(s0) + 2984: 05300613 li a2,83 + 2988: fffff097 auipc ra,0xfffff + 298c: d60080e7 jalr -672(ra) # 16e8 + 2990: 00600513 li a0,6 + 2994: fea42623 sw a0,-20(s0) + 2998: fec42503 lw a0,-20(s0) + 299c: 00150593 addi a1,a0,1 + 29a0: feb42623 sw a1,-20(s0) + 29a4: 01900593 li a1,25 + 29a8: fcb42c23 sw a1,-40(s0) + 29ac: 04800613 li a2,72 + 29b0: fffff097 auipc ra,0xfffff + 29b4: d38080e7 jalr -712(ra) # 16e8 + 29b8: fd842583 lw a1,-40(s0) + 29bc: fec42503 lw a0,-20(s0) + 29c0: 00150613 addi a2,a0,1 + 29c4: fec42623 sw a2,-20(s0) + 29c8: 06f00613 li a2,111 + 29cc: fffff097 auipc ra,0xfffff + 29d0: d1c080e7 jalr -740(ra) # 16e8 + 29d4: fd842583 lw a1,-40(s0) + 29d8: fec42503 lw a0,-20(s0) + 29dc: 00150613 addi a2,a0,1 + 29e0: fec42623 sw a2,-20(s0) + 29e4: 07700613 li a2,119 + 29e8: fffff097 auipc ra,0xfffff + 29ec: d00080e7 jalr -768(ra) # 16e8 + 29f0: fd842583 lw a1,-40(s0) + 29f4: fec42503 lw a0,-20(s0) + 29f8: 00150613 addi a2,a0,1 + 29fc: fec42623 sw a2,-20(s0) + 2a00: 06100613 li a2,97 + 2a04: fcc42a23 sw a2,-44(s0) + 2a08: fffff097 auipc ra,0xfffff + 2a0c: ce0080e7 jalr -800(ra) # 16e8 + 2a10: fd842583 lw a1,-40(s0) + 2a14: fec42503 lw a0,-20(s0) + 2a18: 00150613 addi a2,a0,1 + 2a1c: fec42623 sw a2,-20(s0) + 2a20: 07200613 li a2,114 + 2a24: fffff097 auipc ra,0xfffff + 2a28: cc4080e7 jalr -828(ra) # 16e8 + 2a2c: fd842583 lw a1,-40(s0) + 2a30: fec42503 lw a0,-20(s0) + 2a34: 00150613 addi a2,a0,1 + 2a38: fec42623 sw a2,-20(s0) + 2a3c: 06400613 li a2,100 + 2a40: fffff097 auipc ra,0xfffff + 2a44: ca8080e7 jalr -856(ra) # 16e8 + 2a48: fd842583 lw a1,-40(s0) + 2a4c: fec42503 lw a0,-20(s0) + 2a50: 00150513 addi a0,a0,1 + 2a54: fea42623 sw a0,-20(s0) + 2a58: fec42503 lw a0,-20(s0) + 2a5c: 00150613 addi a2,a0,1 + 2a60: fec42623 sw a2,-20(s0) + 2a64: 04c00613 li a2,76 + 2a68: fffff097 auipc ra,0xfffff + 2a6c: c80080e7 jalr -896(ra) # 16e8 + 2a70: fd442603 lw a2,-44(s0) + 2a74: fd842583 lw a1,-40(s0) + 2a78: fec42503 lw a0,-20(s0) + 2a7c: 00150693 addi a3,a0,1 + 2a80: fed42623 sw a3,-20(s0) + 2a84: fffff097 auipc ra,0xfffff + 2a88: c64080e7 jalr -924(ra) # 16e8 + 2a8c: fd842583 lw a1,-40(s0) + 2a90: fec42503 lw a0,-20(s0) + 2a94: 00150613 addi a2,a0,1 + 2a98: fec42623 sw a2,-20(s0) + 2a9c: 07500613 li a2,117 + 2aa0: fffff097 auipc ra,0xfffff + 2aa4: c48080e7 jalr -952(ra) # 16e8 + 2aa8: 00900513 li a0,9 + 2aac: fea42623 sw a0,-20(s0) + 2ab0: fec42503 lw a0,-20(s0) + 2ab4: 00150593 addi a1,a0,1 + 2ab8: feb42623 sw a1,-20(s0) + 2abc: 01a00593 li a1,26 + 2ac0: feb42023 sw a1,-32(s0) + 2ac4: 03200613 li a2,50 + 2ac8: fcc42e23 sw a2,-36(s0) + 2acc: fffff097 auipc ra,0xfffff + 2ad0: c1c080e7 jalr -996(ra) # 16e8 + 2ad4: fe042583 lw a1,-32(s0) + 2ad8: fec42503 lw a0,-20(s0) + 2adc: 00150613 addi a2,a0,1 + 2ae0: fec42623 sw a2,-20(s0) + 2ae4: 03000613 li a2,48 + 2ae8: fffff097 auipc ra,0xfffff + 2aec: c00080e7 jalr -1024(ra) # 16e8 + 2af0: fdc42603 lw a2,-36(s0) + 2af4: fe042583 lw a1,-32(s0) + 2af8: fec42503 lw a0,-20(s0) + 2afc: 00150693 addi a3,a0,1 + 2b00: fed42623 sw a3,-20(s0) + 2b04: fffff097 auipc ra,0xfffff + 2b08: be4080e7 jalr -1052(ra) # 16e8 + 2b0c: fe042583 lw a1,-32(s0) + 2b10: fec42503 lw a0,-20(s0) + 2b14: 00150613 addi a2,a0,1 + 2b18: fec42623 sw a2,-20(s0) + 2b1c: 03100613 li a2,49 + 2b20: fffff097 auipc ra,0xfffff + 2b24: bc8080e7 jalr -1080(ra) # 16e8 + 2b28: 00000097 auipc ra,0x0 + 2b2c: ab4080e7 jalr -1356(ra) # 25dc + 2b30: 00050593 mv a1,a0 + 2b34: 00003537 lui a0,0x3 + 2b38: 06c50513 addi a0,a0,108 # 306c + 2b3c: 00400613 li a2,4 + 2b40: 00000693 li a3,0 + 2b44: fed42223 sw a3,-28(s0) + 2b48: ffffe097 auipc ra,0xffffe + 2b4c: 6e8080e7 jalr 1768(ra) # 1230 + 2b50: fe442503 lw a0,-28(s0) + 2b54: 000035b7 lui a1,0x3 + 2b58: 08a5a023 sw a0,128(a1) # 3080 + 2b5c: fffff097 auipc ra,0xfffff + 2b60: 478080e7 jalr 1144(ra) # 1fd4 + 2b64: 03812403 lw s0,56(sp) + 2b68: 03c12083 lw ra,60(sp) + 2b6c: 04010113 addi sp,sp,64 + 2b70: 00008067 ret + +00002b74 : + 2b74: ff010113 addi sp,sp,-16 + 2b78: 00112623 sw ra,12(sp) + 2b7c: 00812423 sw s0,8(sp) + 2b80: 01010413 addi s0,sp,16 + 2b84: 20000537 lui a0,0x20000 + 2b88: fea42a23 sw a0,-12(s0) + 2b8c: 00000513 li a0,0 + 2b90: fea42823 sw a0,-16(s0) + 2b94: 0040006f j 2b98 + 2b98: ff042583 lw a1,-16(s0) + 2b9c: 25700513 li a0,599 + 2ba0: 02b54c63 blt a0,a1,2bd8 + 2ba4: 0040006f j 2ba8 + 2ba8: ff442503 lw a0,-12(s0) + 2bac: ff042583 lw a1,-16(s0) + 2bb0: 00259593 slli a1,a1,0x2 + 2bb4: 00b505b3 add a1,a0,a1 + 2bb8: 20202537 lui a0,0x20202 + 2bbc: 02050513 addi a0,a0,32 # 20202020 + 2bc0: 00a5a023 sw a0,0(a1) + 2bc4: 0040006f j 2bc8 + 2bc8: ff042503 lw a0,-16(s0) + 2bcc: 00150513 addi a0,a0,1 + 2bd0: fea42823 sw a0,-16(s0) + 2bd4: fc5ff06f j 2b98 + 2bd8: 00812403 lw s0,8(sp) + 2bdc: 00c12083 lw ra,12(sp) + 2be0: 01010113 addi sp,sp,16 + 2be4: 00008067 ret + +00002be8
: + 2be8: ff010113 addi sp,sp,-16 + 2bec: 00112623 sw ra,12(sp) + 2bf0: 00812423 sw s0,8(sp) + 2bf4: 01010413 addi s0,sp,16 + 2bf8: 00000513 li a0,0 + 2bfc: fea42a23 sw a0,-12(s0) + 2c00: 000035b7 lui a1,0x3 + 2c04: 00004537 lui a0,0x4 + 2c08: 06a5ae23 sw a0,124(a1) # 307c <_end> + 2c0c: 00000097 auipc ra,0x0 + 2c10: f68080e7 jalr -152(ra) # 2b74 + 2c14: 00000097 auipc ra,0x0 + 2c18: c08080e7 jalr -1016(ra) # 281c + 2c1c: deadc537 lui a0,0xdeadc + 2c20: eef50513 addi a0,a0,-273 # deadbeef + 2c24: 00a02223 sw a0,4(zero) # 4 <_start-0xffc> + 2c28: ffffe097 auipc ra,0xffffe + 2c2c: 3e8080e7 jalr 1000(ra) # 1010 + 2c30: 800005b7 lui a1,0x80000 + 2c34: 00100513 li a0,1 + 2c38: 00a5a423 sw a0,8(a1) # 80000008 + 2c3c: 02faf537 lui a0,0x2faf + 2c40: 08050513 addi a0,a0,128 # 2faf080 + 2c44: 00a5a223 sw a0,4(a1) + 2c48: 0040006f j 2c4c + 2c4c: 0000006f j 2c4c + +Disassembly of section .data: + +00003000 <.LJTI2_0>: + 3000: 12a0 addi s0,sp,360 + 3002: 0000 unimp + 3004: 12c0 addi s0,sp,356 + 3006: 0000 unimp + 3008: 12e4 addi s1,sp,364 + 300a: 0000 unimp + 300c: 1310 addi a2,sp,416 + 300e: 0000 unimp + 3010: 1338 addi a4,sp,424 + 3012: 0000 unimp + 3014: 1360 addi s0,sp,428 + 3016: 0000 unimp + 3018: 138c addi a1,sp,480 + ... + +0000301c <.LJTI21_0>: + 301c: 2708 fld fa0,8(a4) + 301e: 0000 unimp + 3020: 2768 fld fa0,200(a4) + 3022: 0000 unimp + 3024: 2768 fld fa0,200(a4) + 3026: 0000 unimp + 3028: 2720 fld fs0,72(a4) + 302a: 0000 unimp + 302c: 2768 fld fa0,200(a4) + 302e: 0000 unimp + 3030: 2768 fld fa0,200(a4) + 3032: 0000 unimp + 3034: 2768 fld fa0,200(a4) + 3036: 0000 unimp + 3038: 2768 fld fa0,200(a4) + 303a: 0000 unimp + 303c: 2768 fld fa0,200(a4) + 303e: 0000 unimp + 3040: 2738 fld fa4,72(a4) + 3042: 0000 unimp + 3044: 2750 fld fa2,136(a4) + 3046: 0000 unimp + 3048: 2768 fld fa0,200(a4) + 304a: 0000 unimp + 304c: 2768 fld fa0,200(a4) + 304e: 0000 unimp + 3050: 2768 fld fa0,200(a4) + 3052: 0000 unimp + 3054: 2768 fld fa0,200(a4) + 3056: 0000 unimp + 3058: 2768 fld fa0,200(a4) + 305a: 0000 unimp + 305c: 2768 fld fa0,200(a4) + 305e: 0000 unimp + 3060: 2768 fld fa0,200(a4) + 3062: 0000 unimp + 3064: 26fc fld fa5,200(a3) + ... + +00003068 : + 3068: 000f1c6b 0xf1c6b + +Disassembly of section .bss: + +0000306c : + ... + +Disassembly of section .sbss: + +0000307c : + 307c: 0000 unimp + ... + +00003080 : + 3080: 0000 unimp + ... + +Disassembly of section .comment: + +00000000 <.comment>: + 0: 6e616c63 bltu sp,t1,6f8 <_start-0x908> + 4: 65762067 0x65762067 + 8: 7372 flw ft6,60(sp) + a: 6f69 lui t5,0x1a + c: 206e fld ft0,216(sp) + e: 3331 jal fffffd1a + 10: 302e fld ft0,232(sp) + 12: 312e fld ft2,232(sp) + 14: 4c00 lw s0,24(s0) + 16: 6e69 lui t3,0x1a + 18: 3a72656b 0x3a72656b + 1c: 4c20 lw s0,88(s0) + 1e: 444c lw a1,12(s0) + 20: 3120 fld fs0,96(a0) + 22: 2e302e33 0x2e302e33 + 26: 0031 c.nop 12 + ... + +Disassembly of section .riscv.attributes: + +00000000 <.riscv.attributes>: + 0: 1b41 addi s6,s6,-16 + 2: 0000 unimp + 4: 7200 flw fs0,32(a2) + 6: 7369 lui t1,0xffffa + 8: 01007663 bgeu zero,a6,14 <_start-0xfec> + c: 0011 c.nop 4 + e: 0000 unimp + 10: 1004 addi s1,sp,32 + 12: 7205 lui tp,0xfffe1 + 14: 3376 fld ft6,376(sp) + 16: 6932 flw fs2,12(sp) + 18: 7032 flw ft0,44(sp) + 1a: 0030 addi a2,sp,8 diff --git a/lab2/csrc/tetris.c b/lab2/csrc/tetris.c new file mode 100644 index 0000000..2b37550 --- /dev/null +++ b/lab2/csrc/tetris.c @@ -0,0 +1,498 @@ +// 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. + +#ifdef DEBUG +#include +#endif + +#include "mmio.h" + +#define FALL_TIMER_LIMIT 50000000 +#define ROWS 22 +#define COLS 10 +#define OFFSET_X 28 +#define OFFSET_Y 3 +#define SCREEN_COLS 80 +#define SCREEN_ROWS 30 + +struct block { + unsigned int shape[3]; + unsigned int xywh; +}; + +struct block current; + +unsigned int score; + +unsigned char *board; + +#ifdef DEBUG +unsigned char screen[SCREEN_COLS * SCREEN_ROWS]; +#endif + +int wk_mul(int a, int b) { + int r = 0; + for (; b; a <<= 1, b >>= 1) + if (b & 1) + r += a; + return r; +} + +unsigned int make_xywh(unsigned int x, unsigned int y, unsigned int w, unsigned int h) { + return (x << 12) | (y << 4) | (w << 2) | h; +} + +void init_block(struct block *block, int type, int x, int y) { + int w = 0; int h = 0; + block->shape[0] = block->shape[1] = block->shape[2] = 0; + switch(type) { + case 0: // I + block->shape[0] = 0xF; + w = 3; h = 0; + break; + case 1: // O + block->shape[0] = 0x3; + block->shape[1] = 0x3; + w = 1; h = 1; + break; + case 2: // J + block->shape[0] = 0x4; + block->shape[1] = 0x7; + w = 2; h = 1; + break; + case 3: // T + block->shape[0] = 0x2; + block->shape[1] = 0x7; + w = 2; h = 1; + break; + case 4: // L + block->shape[0] = 0x1; + block->shape[1] = 0x7; + w = 2; h = 1; + break; + case 5: // Z + block->shape[0] = 0x6; + block->shape[1] = 0x3; + w = 2; h = 1; + break; + case 6: // S + block->shape[0] = 0x3; + block->shape[1] = 0x6; + w = 2; h = 1; + break; + } + block->xywh = make_xywh(x, y, w, h); +} + +unsigned int get_shape(struct block *block, unsigned int r, unsigned int c) { + return (block->shape[r] & (1 << c)) >> c; +} + +unsigned int check_bounds(struct block *block) { + unsigned int xywh = block->xywh; + unsigned int h = xywh & 0x3; + unsigned int w = (xywh & 0xC) >> 2; + unsigned int y = (xywh & 0xFF0) >> 4; + unsigned int x = (xywh & 0xF000) >> 12; + if (x < 0 || x + w >= COLS) return 0; + if (y < 0 || y + h >= ROWS) return 0; + return 1; +} + +void copy_block(struct block *dst, struct block *src) { + dst->xywh = src->xywh; + dst->shape[0] = src->shape[0]; + dst->shape[1] = src->shape[1]; + dst->shape[2] = src->shape[2]; +} + +unsigned int check_collision(struct block *block) { + unsigned int xywh = block->xywh; + unsigned int h = xywh & 0x3; + unsigned int w = (xywh & 0xC) >> 2; + unsigned int y = (xywh & 0xFF0) >> 4; + unsigned int x = (xywh & 0xF000) >> 12; + for (int r = 0; r <= h; ++r) { + for (int c = 0; c <= w; ++c) { + if (get_shape(block, r, c) && + board[wk_mul(y + r, COLS) + x + c]) + return 0; + } + } + return 1; +} + +void putch_at(int x, int y, unsigned char ch) { +#ifdef DEBUG + screen[wk_mul(OFFSET_Y + y, SCREEN_COLS) + x + OFFSET_X] = ch; +#else + VRAM[wk_mul(OFFSET_Y + y, SCREEN_COLS) + x + OFFSET_X] = ch; +#endif +} + +void block_move(struct block *block, int dir) { + unsigned int xywh = block->xywh; + unsigned int h = xywh & 0x3; + unsigned int w = (xywh & 0xC) >> 2; + unsigned int y = (xywh & 0xFF0) >> 4; + unsigned int x = (xywh & 0xF000) >> 12; + switch(dir) { + case 0: // Left + x--; + break; + case 1: // Right + x++; + break; + case 2: // Down + y++; + break; + default: + break; + } + block->xywh = (x << 12) | (y << 4) | (w << 2) | h; +} + +unsigned int move(struct block *block, int dir) { + struct block moved; + copy_block(&moved, block); + block_move(&moved, dir); + if (check_bounds(&moved) && check_collision(&moved)) { + copy_block(block, &moved); + return 1; + } + return 0; +} + +void block_rotate(struct block *block, unsigned int clock) { + unsigned int xywh = block->xywh; + unsigned int h = xywh & 0x3; + unsigned int w = (xywh & 0xC) >> 2; + unsigned int y = (xywh & 0xFF0) >> 4; + unsigned int x = (xywh & 0xF000) >> 12; + unsigned int xyhw = make_xywh(x, y, h, w); + unsigned int shape[3] = {0, 0, 0}; + if (clock) { + for (int r = 0; r <= h; ++r) { + for (int c = 0; c <= w; ++c) { + shape[c] = shape[c] | (get_shape(block, r, c) << (h - r)); + } + } + + } else { + for (int r = 0; r <= h; ++r) { + for (int c = 0; c <= w; ++c) { + shape[w - c] = shape[w - c] | (get_shape(block, r, c) << r); + } + } + } + block->shape[0] = shape[0]; + block->shape[1] = shape[1]; + block->shape[2] = shape[2]; + block->xywh = xyhw; +} + + +void rotate(struct block *block, int clock) { + struct block rotated; + copy_block(&rotated, block); + block_rotate(&rotated, clock); + if (check_bounds(&rotated) && check_collision(&rotated)) { + copy_block(block, &rotated); + return; + } + unsigned int xywh = rotated.xywh; + unsigned int h = xywh & 0x3; + unsigned int w = (xywh & 0xc) >> 2; + unsigned int y = (xywh & 0xff0) >> 4; + unsigned int x = (xywh & 0xf000) >> 12; + if (x + w >= COLS) { + x = COLS - w - 1; + } + rotated.xywh = make_xywh(x, y, w, h); + if (check_bounds(&rotated) && check_collision(&rotated)) { + copy_block(block, &rotated); + } +} + +void clear_board() { + for (int i = 0, s = wk_mul(ROWS, COLS); i < s; ++i) { + board[i] = 0; + } +} + +void fix_block(struct block *block) { + unsigned int xywh = block->xywh; + unsigned int h = xywh & 0x3; + unsigned int w = (xywh & 0xc) >> 2; + unsigned int y = (xywh & 0xff0) >> 4; + unsigned int x = (xywh & 0xf000) >> 12; +#ifdef DEBUG + printf("%d %d %d %d\n", x, y, w, h); +#endif + for (int r = 0; r <= h; ++r) { + for (int c = 0; c <= w; ++c) { + if (get_shape(block, r, c)) { + board[wk_mul(y + r, COLS) + x + c] = 1; + } + } + } +} + +void print_score() { + int c = 8; + putch_at(c++, -2, 'S'); + putch_at(c++, -2, 'C'); + putch_at(c++, -2, 'O'); + putch_at(c++, -2, 'R'); + putch_at(c++, -2, 'E'); + for (int i = 0; i < 5; ++i) { + unsigned int mask = 0xF << (i * 4); + unsigned int num = (score & mask) >> (i * 4); + putch_at(12 - i, -1, num + '0'); + } +} + +void draw_board() { + for (int r = 0; r < ROWS; ++r) { + for (int c = 0; c < COLS; ++c) { + if (board[wk_mul(r , COLS) + c] == 1) { + putch_at((c << 1) + 1, r, '['); + putch_at((c << 1) + 2, r, ']'); + } else { + putch_at((c << 1) + 1, r, ' '); + putch_at((c << 1)+ 2, r, ' '); + } + } + } + unsigned int xywh = current.xywh; + unsigned int h = xywh & 0x3; + unsigned int w = (xywh & 0xc) >> 2; + unsigned int y = (xywh & 0xff0) >> 4; + unsigned int x = (xywh & 0xf000) >> 12; + for (int r = 0; r <= h; ++r) { + for (int c = 0; c <= w; ++c) { + if (get_shape(¤t, r, c)) { + putch_at(((c + x) << 1) + 1, r + y, '['); + putch_at(((c + x) << 1) + 2, r + y, ']'); + } + } + } + print_score(); +} + + +void add_score(unsigned int delta) { + score += delta; + for (unsigned int i = 0, carry = 0; i < 32; i += 4) { + unsigned int mask = 0xF << i; + unsigned int num = (score & mask) >> i; + num += carry; + if (num >= 10) { + carry = 1; + num -= 10; + } else { + carry = 0; + } + score &= ~(mask); + score |= (num << i); + } +} + +void check_clear() { + unsigned int y = (current.xywh & 0xff0) >> 4; + unsigned int h = current.xywh & 0x3; + for (int r = y + h; r >= y; --r) { + unsigned int count = 0; + for (int c = 0; c < COLS; ++c) { + if (board[wk_mul(r , COLS) + c]) ++count; + } + if (count == COLS) { + add_score(1); + for (int nr = r - 1; nr > 0; --nr) { + for (int c = 0; c < COLS; ++c) { + board[wk_mul(nr + 1, COLS) + c] = board[wk_mul(nr, COLS) + c]; + } + } + ++r; ++y; + } + } +} + +unsigned int rand() { + static unsigned int seed = 990315; + seed = (wk_mul(1103515245 , seed) + 12345) & 0x7FFFFFFF; + return seed; +} + +unsigned int rand_type() { + unsigned int type = rand() & 0x7; + while (type == 7) { + type = rand() & 0x7; + } + return type; +} + +void fall() { + if (move(¤t, 2) == 0) { + fix_block(¤t); + check_clear(); + init_block(¤t, rand_type(), 4, 0); + } +} + +#ifdef DEBUG +void print_screen() { + for (int r = 0; r < SCREEN_ROWS; ++r) { + for (int c = 0; c < SCREEN_COLS; ++c) { + printf("%c", screen[wk_mul(r, SCREEN_COLS) + c]); + } + printf("\n"); + } + printf("\n"); +} +#endif + +void on_input(unsigned int ch) { + switch (ch) { + case 's': + fall(); + break; + case 'a': + move(¤t, 0); + break; + case 'd': + move(¤t, 1); + break; + case 'j': + rotate(¤t, 0); + break; + case 'k': + rotate(¤t, 1); + break; + } + draw_board(); +#ifdef DEBUG + print_screen(); +#endif +} + +void on_timer() { + fall(); + draw_board(); +} + +void trap_handler(void *epc, unsigned int cause) { + if (cause == 0x80000007) { + on_timer(); + } else { + unsigned int ch = *UART_RECV; + *UART_SEND = ch; + on_input(ch); + } +} + +void init() { + clear_board(); + // Draw border + for (int r = 0; r < ROWS; ++r) { + putch_at(0, r, '|'); + putch_at(COLS << 1 | 1, r, '|'); + } + for (int c = 0; c <= (COLS << 1 | 1); ++c) { + putch_at(c, ROWS, '-'); + } + int c = 8; + putch_at(c++, ROWS + 1, 'T'); + putch_at(c++, ROWS + 1, 'E'); + putch_at(c++, ROWS + 1, 'T'); + putch_at(c++, ROWS + 1, 'R'); + putch_at(c++, ROWS + 1, 'I'); + putch_at(c++, ROWS + 1, 'S'); + c = 6; + putch_at(c++, ROWS + 3, 'H'); + putch_at(c++, ROWS + 3, 'o'); + putch_at(c++, ROWS + 3, 'w'); + putch_at(c++, ROWS + 3, 'a'); + putch_at(c++, ROWS + 3, 'r'); + putch_at(c++, ROWS + 3, 'd'); + c++; + putch_at(c++, ROWS + 3, 'L'); + putch_at(c++, ROWS + 3, 'a'); + putch_at(c++, ROWS + 3, 'u'); + c = 9; + putch_at(c++, ROWS + 4, '2'); + putch_at(c++, ROWS + 4, '0'); + putch_at(c++, ROWS + 4, '2'); + putch_at(c++, ROWS + 4, '1'); + init_block(¤t, rand_type(), 4, 0); + score = 0; + draw_board(); +} + +void clear_screen() { + int *vram = ((int *) VRAM_BASE); + for (int i = 0; i < 600; ++i) vram[i] = 0x20202020; +} + +extern void enable_interrupt(); + +int main() { +#ifdef DEBUG + unsigned char b[ROWS * COLS] = {0}; + board = b; + for (int i = 0; i < SCREEN_ROWS * SCREEN_COLS; ++i) screen[i] = '%'; + init(); +#else + board = (unsigned char *) 16384; + for (int i = 0; i < 16384; i += 4) { + *((int*) (board + i)) = 0; + } + clear_screen(); + init(); + *((unsigned int *) 4) = 0xDEADBEEF; + enable_interrupt(); + *TIMER_ENABLED = 1; + *TIMER_LIMIT = FALL_TIMER_LIMIT; + for (;;); +#endif +#ifdef DEBUG + on_input('a'); + on_input('a'); + on_input('s'); + on_input('s'); + on_input('s'); + for (int i = 21; i >= 0; --i) { + on_timer(); + } + on_input('d'); + on_input('d'); + on_input('d'); + on_input('d'); + for (int i = 21; i >= 0; --i) { + on_timer(); + } + on_input('d'); + on_input('d'); + on_input('d'); + on_input('d'); + on_input('d'); + for (int i = 21; i >= 0; --i) { + on_timer(); + add_score(10); + } + print_score(); + print_screen(); + return 0; +#endif +} diff --git a/lab2/csrc/toolchain.cmake b/lab2/csrc/toolchain.cmake new file mode 100644 index 0000000..60bc5a9 --- /dev/null +++ b/lab2/csrc/toolchain.cmake @@ -0,0 +1,20 @@ +set(CMAKE_SYSTEM_NAME Generic) +set(CMAKE_SYSTEM_PROCESSOR riscv32) + +set(triple riscv32-unknown-elf) + +set(CMAKE_C_COMPILER clang) +set(CMAKE_C_COMPILER_TARGET ${triple}) +set(CMAKE_CXX_COMPILER clang++) +set(CMAKE_CXX_COMPILER_TARGET ${triple}) +set(CMAKE_ASM_COMPILER clang) +set(CMAKE_ASM_COMPILER_TARGET ${triple}) +set(CMAKE_AR llvm-ar CACHE FILEPATH "Archiver") +set(CMAKE_OBJCOPY llvm-objcopy) + +set(CMAKE_C_FLAGS_INIT "-mno-relax") +set(CMAKE_CXX_FLAGS_INIT "-mno-relax") +set(CMAKE_ASM_FLAGS_INIT "-mno-relax") +set(CMAKE_EXE_LINKER_FLAGS_INIT "-fuse-ld=lld -nostdlib -static -mno-relax") +set(CMAKE_MODULE_LINKER_FLAGS_INIT "-fuse-ld=lld -nostdlib -static -mno-relax") +set(CMAKE_SHARED_LINKER_FLAGS_INIT "-fuse-ld=lld -nostdlib -static -mno-relax") diff --git a/lab2/project/build.properties b/lab2/project/build.properties new file mode 100644 index 0000000..303541e --- /dev/null +++ b/lab2/project/build.properties @@ -0,0 +1 @@ +sbt.version = 1.9.6 diff --git a/lab2/project/plugins.sbt b/lab2/project/plugins.sbt new file mode 100644 index 0000000..5708f81 --- /dev/null +++ b/lab2/project/plugins.sbt @@ -0,0 +1 @@ +logLevel := Level.Warn diff --git a/lab2/riscv-target/yatcpu/Makefile.include b/lab2/riscv-target/yatcpu/Makefile.include new file mode 100644 index 0000000..e209499 --- /dev/null +++ b/lab2/riscv-target/yatcpu/Makefile.include @@ -0,0 +1,7 @@ +export TARGETDIR ?= riscv-target +export XLEN = 32 +export RISCV_TARGET = yatcpu +export RISCV_DEVICE = +export RISCV_TARGET_FLAGS = +export RISCV_ASSERT = 0 +JOBS = -j1 \ No newline at end of file diff --git a/lab2/riscv-target/yatcpu/device/rv32i_m/I/Makefile.include b/lab2/riscv-target/yatcpu/device/rv32i_m/I/Makefile.include new file mode 100644 index 0000000..d17e055 --- /dev/null +++ b/lab2/riscv-target/yatcpu/device/rv32i_m/I/Makefile.include @@ -0,0 +1,54 @@ +TARGET_SIM ?= verilog/verilator/obj_dir/VTop +TARGET_FLAGS ?= $(RISCV_TARGET_FLAGS) +ifeq ($(shell command -v $(TARGET_SIM) 2> /dev/null),) + $(error Target simulator executable '$(TARGET_SIM)` not found) +endif + +RISCV_PREFIX ?= riscv64-unknown-elf- +RISCV_GCC ?= $(RISCV_PREFIX)gcc +RISCV_OBJDUMP ?= $(RISCV_PREFIX)objdump +RISCV_OBJCOPY ?= $(RISCV_PREFIX)objcopy +RISCV_GCC_OPTS ?= -g -static -mcmodel=medany -fvisibility=hidden -nostdlib -nostartfiles $(RVTEST_DEFINES) + +COMPILE_CMD = $$(RISCV_GCC) $(1) $$(RISCV_GCC_OPTS) \ + -I$(ROOTDIR)/riscv-test-suite/env/ \ + -I$(TARGETDIR)/$(RISCV_TARGET)/ \ + -T$(TARGETDIR)/$(RISCV_TARGET)/link.ld \ + $$(<) -o $$@ + +OBJDUMP_CMD = $$(RISCV_OBJDUMP) $$@ -D > $$@.objdump; \ + $$(RISCV_OBJDUMP) $$@ --source > $$@.debug; \ + $$(RISCV_OBJDUMP) -t $$@ | grep " begin_signature$$$$" | awk '{ print $$$$1 }' > $$@.begin_signature; \ + $$(RISCV_OBJDUMP) -t $$@ | grep " end_signature$$$$" | awk '{ print $$$$1 }' > $$@.end_signature; \ + $$(RISCV_OBJDUMP) -t $$@ | grep " tohost$$$$" | awk '{ print $$$$1 }' > $$@.halt \ + + +OBJCOPY_CMD = $$(RISCV_OBJCOPY) $$@ -O binary -j .text -j .data -j .tohost $$@.asmbin + +COMPILE_TARGET=\ + $(COMPILE_CMD); \ + if [ $$$$? -ne 0 ] ; \ + then \ + echo "\e[31m$$(RISCV_GCC) failed for target $$(@) \e[39m" ; \ + exit 1 ; \ + fi ; \ + $(OBJDUMP_CMD); \ + if [ $$$$? -ne 0 ] ; \ + then \ + echo "\e[31m $$(RISCV_OBJDUMP) failed for target $$(@) \e[39m" ; \ + exit 1 ; \ + fi ; \ + $(OBJCOPY_CMD); \ + if [ $$$$? -ne 0 ] ; \ + then \ + echo "\e[31m $$(RISCV_OBJCOPY) failed for target $$(@) \e[39m" ; \ + exit 1 ; \ + fi ; \ + +RUN_CMD = $(TARGET_SIM) $(TARGET_FLAGS) \ + -signature 0x$(shell cat $(<).begin_signature) 0x$(shell cat $(<).end_signature) $(*).signature.output \ + -halt 0x$(shell cat $(<).halt) \ + -time 1000000 \ + -instruction $(<).asmbin +RUN_TARGET = \ + $(RUN_CMD) diff --git a/lab2/riscv-target/yatcpu/link.ld b/lab2/riscv-target/yatcpu/link.ld new file mode 100644 index 0000000..6afe7d6 --- /dev/null +++ b/lab2/riscv-target/yatcpu/link.ld @@ -0,0 +1,12 @@ +OUTPUT_ARCH( "riscv" ) +ENTRY(rvtest_entry_point) + +SECTIONS +{ + . = 0x00001000; + .text : { *(.text.init) *(.text.startup) *(.text) } + .data ALIGN(0x1000) : { *(.data*) *(.rodata*) *(.sdata*) } + .tohost ALIGN(0x1000) : { *(.tohost) } + .bss : { *(.bss) } + _end = .; +} diff --git a/lab2/riscv-target/yatcpu/model_test.h b/lab2/riscv-target/yatcpu/model_test.h new file mode 100644 index 0000000..ca8f8c6 --- /dev/null +++ b/lab2/riscv-target/yatcpu/model_test.h @@ -0,0 +1,46 @@ +#ifndef _COMPLIANCE_MODEL_H_ +#define _COMPLIANCE_MODEL_H_ + +#define ALIGNMENT 2 + +#define RVMODEL_DATA_SECTION \ + .pushsection .tohost,"aw",@progbits; \ + .align 4; .global tohost; tohost: .word 0; \ + .popsection; + +#define RVMODEL_BOOT + +#define RVMODEL_HALT \ + li x1, 0xBABECAFE; \ + write_tohost: \ + sw x1, tohost, x0; \ + loop: j loop + +//RV_COMPLIANCE_DATA_BEGIN +#define RVMODEL_DATA_BEGIN \ + .align 4; .global begin_signature; begin_signature: + +//RV_COMPLIANCE_DATA_END +#define RVMODEL_DATA_END \ + .align 4; .global end_signature; end_signature: \ + RVMODEL_DATA_SECTION \ + +//RVTEST_IO_INIT +#define RVMODEL_IO_INIT +//RVTEST_IO_WRITE_STR +#define RVMODEL_IO_WRITE_STR(_R, _STR) +//RVTEST_IO_CHECK +#define RVMODEL_IO_CHECK() +//RVTEST_IO_ASSERT_GPR_EQ +#define RVMODEL_IO_ASSERT_GPR_EQ(_S, _R, _I) +//RVTEST_IO_ASSERT_SFPR_EQ +#define RVMODEL_IO_ASSERT_SFPR_EQ(_F, _R, _I) +//RVTEST_IO_ASSERT_DFPR_EQ +#define RVMODEL_IO_ASSERT_DFPR_EQ(_D, _R, _I) + +#define RVMODEL_SET_MSW_INT +#define RVMODEL_CLEAR_MSW_INT +#define RVMODEL_CLEAR_MTIMER_INT +#define RVMODEL_CLEAR_MEXT_INT + +#endif diff --git a/lab2/src/main/resources/fibonacci.asmbin b/lab2/src/main/resources/fibonacci.asmbin new file mode 100644 index 0000000000000000000000000000000000000000..45e994fece092de67f03a039ffd50b31c5605514 GIT binary patch literal 520 zcmXxhv1;5v5CG7b9nEc%;*2^&K&O%9vn(0FM8`tx(s^&e;7^3D2d z*PGerB|uk>=R@4A$2dfte(}gdREVpd8^*4x9Y8WtKO=&>g`a=OPS4gwL{1pgh>R-5ku~f z#AA?%nwwBKL!~#NjD{+tP&uLlPvIaEO)&{mm(Zb4!eLCPMh>-OI`SNjB2$B-(6|vD z`%yTKBWlrx)>%67Hk?G;O<>+ZHq%+Gq}5q89?}H0-iza+nclmXP}%;Int2lEg9^?6_b literal 0 HcmV?d00001 diff --git a/lab2/src/main/resources/hdmi_test.asmbin b/lab2/src/main/resources/hdmi_test.asmbin new file mode 100644 index 0000000000000000000000000000000000000000..fc484475f6d9dcabccd03371e89837aaf3946e6b GIT binary patch literal 4109 zcmeH^v2GMG5QfK|^}0>8P~+P}?sq7?; zzDufpNUDEHGD0z{XgE;JE9MpRih0GnBGYQ-HS?Nz&Aet_Gq0J~;Vr+dnXKOq;Ee-6 z=m2veeC`BND?D|Ad+CQxqHU$Ooy0<*FC5}li+-y^EJfl=m*94r`0Xyikx+i*6z;Uj z?{o?)k^0J|xZ9?Fw@a}W+Sg9wUaS3Hr<(yx8Zcva(NoPXsur?D$V>tIIPEVL7%IQ? zRGjv6*avUF_L+KV5AI*c(4$TMhPCB;3+L(rrq-BDDM=sBV7(vC-)6_mUp>BFof&(e*6t+ag!Gq&I=h=cdo-7;oswk2BLvzAR34U gqJd~28i)p>foLEa_`eOjcs85O&71k_+0z011A%sd;s5{u literal 0 HcmV?d00001 diff --git a/lab2/src/main/resources/hello.asmbin b/lab2/src/main/resources/hello.asmbin new file mode 100644 index 0000000000000000000000000000000000000000..8e9a27dbdeb1d15cac9a16186fdaba132d4bba84 GIT binary patch literal 4344 zcmeHJUu;uV7(e%(o?aZvhE0v}LC$)1OBrPhnCX*AE9-)W7zFm>9wYyYA8k z0-AP1gw_%f-aa4F*8qs`CB;lhQiauvU-A8*h z=JX~Q-B@JK#yX=>&F@4Le!8jXcQ)1iv`;gfzJx(H7Y%1~-N<#5fgIuez(rH^0TZglC#G>}v&r`$*u4A+R-EyXcu|1{fhC zG}FwGH~~ED`!(yus*ZbV9z~zczQRROP@T;Wl9I>93 zHsq(wFb41gd}c_ExtzfnO$NcX=v(e5eg*Szb87&Xke}P1jUb^z`Id@x(E*KUDG2-q zmEXARDbV#Uy_V&VeqBwVUQc7}b^`;2W}A$+(OUY zox?qE4sxKfmiUzbvkkene}lNvkNbuoCh%sxQ1!doK#zKPY#XkUKw-(%6Lk-;cZv0? z*9*936zrYSFS!i7Yt+40xZ~XZ3H?gnSi@3F*6{v~hj}+%PBh6tN61t6;>*59PSK_` z`vJJQbsuh)=_7k%SW|ib6Jx~2w?NIL@?&3>cN%`>_iuc=)GT>+;P8aE{`TSGJ)^WB ze?Yu=J67#-+gI)Dhx0Y1w2c2A3&T8#z^pQdU?$+3o?Rnzj$dl~jemvn#xawfOveAbhaQ(1GeL*nfP=vfV3)jq?yuIA*Y6|WZPEjYio=a=aUKH{_jv)|Qn zuq8gKz>LDTm|U$m`5t|%^;v0SkEnXTqsiO0xi)w9?0?1e=DXtHQRVNOb}ai#X)8P? zZME~Lhg#3KW7R&xbL662s@^sG?CbEK#Ov8h58z|j3~;rBS&aFqSXF$VbHIuCxUvT0 z1X!1=uj0bf`3$`ERjQ5;rOi}Y5LL?sChepl?Ipz{nLobRYAx9DNfmSUj`~i@v-lZh zJL~4t_~c@_v~*2`K6mGm#M}F^M*JVP@>^kGg@F|YRv1`e;QwUcWoD3&+@8!>>3L`w5%BS&U&*8DW zwO`%dmrWlmq$jO6I>?Un_;@DD4`;IDBi$V&%F~mn*T&N$h}rA9&S%F)Mif(0>7T%kB#R literal 0 HcmV?d00001 diff --git a/lab2/src/main/resources/mmio.asmbin b/lab2/src/main/resources/mmio.asmbin new file mode 100644 index 0000000000000000000000000000000000000000..b67851b84c88cfa6dbedcc7154c6db3633e89bcd GIT binary patch literal 32 mcmXqKWoT$ta%I?lbnU&#tzX|MD{W;EW?*1oR(55`2hsq%xCxK| literal 0 HcmV?d00001 diff --git a/lab2/src/main/resources/quicksort.asmbin b/lab2/src/main/resources/quicksort.asmbin new file mode 100644 index 0000000000000000000000000000000000000000..d9a007a1184f4594d2440eb2e2b0adff9465c30d GIT binary patch literal 1012 zcmZvbF>ljQ5XbMm=NB&wsjM)t;QC@WO+y-JB-UE07#I-n0SYJsV?hyn+}BEspa^xO zNa+VaG-9^oegI}BBoG@aLLh`(hySx1D5!&V_UZob{qFwf>kCACMD%$?*R~M%B++<# zTMox}dvAmC{poNldk;rM!?51Bv3#$Kz9+;_4i<=`tHiCCxP6DX^MJVfnAndc2hSxp zUrCN$OKzo-+wUZIK1l9)&UhF(Ljq1VuB=r#L^3%v`y3%v`y3%v`y3%zSu zzJ-4Ol%0$plUYnj1wxo07K#&LI2HJorWs2WCenndRFP07ij`VQlvzrZY6-`*Vn;0} zj#*9})fU>cW35&aZB|mPI-+JeaZO!GYUWB>Q(fVjZtSYn#5Jp_J6xpxko+EIal+98 z`c0(g2*vG5!L7rBqpVP&Gc#dU3~o$mi`MbbB^7QU=gh`0LR!;PQlTbpPRd#iY|IMw zCxxv?ZGqZiusN+)`Z8zr#aX=xcM7jYn17ZJZdG^9wQJ!N`AJ@#mz{V|8Z_2KgA4OI zr||UmS$XI2y$b@a-Oyd@9-~yo(XN**zlOKPY>_`QX?%pQ8hg&H4FN4<$!u z&arb22ky`fV$5Lc4+nDpaDeM9$MNMa3cZ)i|1nm4&a7mw{g_qzGWt~I!M)oc1&>bm z=wmq_cxe1o!c%2;9Wm!FyzP|UI(BZ{J_P4|?EWP8w2%F_aUFRZZ{t6(u~*LA({*nWNkWfLEB literal 0 HcmV?d00001 diff --git a/lab2/src/main/resources/sb.asmbin b/lab2/src/main/resources/sb.asmbin new file mode 100644 index 0000000000000000000000000000000000000000..fde0216ff6947c0b66cb85c21d84af9f23f2a4a1 GIT binary patch literal 36 scmWe;bzs95pR$yhwXJB9e0NFnYLI3~& literal 0 HcmV?d00001 diff --git a/lab2/src/main/resources/simpletest.asmbin b/lab2/src/main/resources/simpletest.asmbin new file mode 100644 index 0000000000000000000000000000000000000000..4cf3ded9c12a43e0f16bb3709dbfa8675bd1c6d5 GIT binary patch literal 432 zcmZ9}u}T9$5C-6xo!hKs!WFico7{OhV-g{d)_nwh11rlQ_X1g`v6U3I3bq!4V7-M8 z;0p*=c7ljt6`hM#Rx``;!N32`djOXJ@VZ=XFLYiSfYsTVX;w$mhkUc2H!CweSpqag zch=6$-o;sp_{Dh-xZDS>JaByoJURv*p8{vzaDHKUaBaA}Gh9W(^^@Vzi{bIR;S8-> z%Y(jEZ`E7%R=rhkISWp`Q}5I}^-jH0@6@|C%SVyT{<3dL=0W-qC`XjsBXL0Ch+Dq=<$}Bq=@7P9WKdL=`4d`Gkfckzq`zMk}?qv>UAKMoS~?$jEnSFLY!tc4&-F z#@^8+IGIG(^kLROHq|b^xzsKO0n!AK>zg%K_v?89klI4KxB|&EUwe;;ZHNC&YC$`^ XSx^T*#g-}lY` zBz=fJB{1y0-@kLt@0{N`=ewESF2u<|h|4+g+PuKCEkxniG5cuY$;s7Getzy~!Ja&n z6XIxMcpv@c=V5D~Z&}yF(d{BkJ|x1iv+_&gP_pQ0kUQ0%M)6%(rQAYQ#NoU;hqVcrnJh13R53G64gcXY> z(lO`3#aQ&F)vcWNx01d-m^nR zm)~dHroS*Ec)*l$3HNV3deA6_0k5dcjB-& zShJvqP5!x&K4G%l2;*7wGe_ zUY)l^&0`$rImrzCg|(w+d)B3f)H>|zSyzyB<_g;n{iIqq*CBiI2C{{t)?!}ULih~U zlVYh1eDe+H*ocyD<0QCyIVawsGs2glJN$!qun`B&t>VGK9`XtMUSm(O;CsVjYUf!o zwNMdL2R=e9ARZl@<0L8^yQHJPuwR668mH%q@DC&yOL|`&VShKL7K#|3VIT0i5o!4c zDpokLj2Ho5hELmy1LZpGV{R1WDUtn(;taVaKFJTJq z_2bq=yu$|OwPoVn*xACH?N;&1F~RRMt=L!Vm()8r0XYKxA)Z>=Ki$0gA7L4eFV|F_ z$=4mkPxi~jt@N%j)N>ikWg6h-kiy+Xd|-VtQ&(}8d#gZxv5OwfPlLDcIdb%J4R#Xd zb%psUq1XScASKqgIHO!Yvs58&@n7cpj8r*rORqn3j*_3L`;v2CZN55tO^xN%7}-;u zz48(KI50oI6e~9zc@;TP#jY>+lP*&8=_RFio_N+Iy{A19_})2-p2Hmbu{ZB_`%%{c zj;-6s3yLT5CHuiGYJTMF1?0YL*Lz^z9dHYntt0nR4CGJ~=^ePLcZ+<-?<#L{J>oSZ z70TJD4KunnWcunviwFJu>Ba+b9VS;0BQElGz79Us6xOBJff4v!*14?oKE3O?SJ=+G zm7TOt`{xZFw~hT&U(H;p+>QwWo(ry>I-Umcd;|5{Mg4YB*St2*krQsK-zbNrCyI=Gc}42+Jh(*Kzb{U??;XfOP~$@-%T<;^KsNfpo| zupP+`JI0J1u8E`PamI$S!-XAgtwVocj~NJGq<8hwRW(+w z0jH+U@l=nv=YY=YnQ}YwACJGx`9UJjOXPV^=lL4q41F;7Pp*kGTJKAj@{qCPdpHNO z+@^~4)J1yNe0YxIev9EltNwqV$8|3Woxle(S1P~{cRAn}@g0BbT$_K(NF8SbGGcZ3yTo&BQ1)YLTc%Ng_! zydU{q*+RbJdW8P_#o8@vIrr=tl}B`4XY64+alF+R=^E6BJ$hbVXRr?lGvqVQ+sql% z>oV2rc0TB@^SYLkon`pJ_@MM9#&(OklNh@xF9Q?g>2k}z3bWEfswQS|hTBlJJkPaU z;e?)8J2k2PM_?=DdOz2=<_-})JSP)+?!2BW9fV$PYreHt;5$OOrf|q* zQ4kR=nF;;~CRl{yp7M$H6Vq1(>Kl`>?8Y z@Hyv4qm#BLUg+qx9j-HqlWlBipUYfqW1M=TZ!Kfpxz=Ew`&=8djN&HgSluwUsBd1S`@v~Bgc?qF+aVKkA@ZNX0e+NK3-yEZm*Rou4S1pAka&}C z@rLfBA@U+|33fIp{^*^a`EEF8Y9sOy5m?W^jC32I?reh?xGxaQw|!RMhV;@b|U6HuX$#@A_^C92J#ujAJ+t~52_Zi zO)VYEur<>}j=z`WGlsxM*~75}`@r2tdhTSZzB48|o-XJ+4aFMAOq;v7(`{8XoG~Gu zKt@MwKnBJL!|JXNX$@ojF_TM%^?k2&$$?+^u7O&meT;XU|M?Ccbkr}_{V~M@!U{eE zzj3ETUkRSGoG`v(`2RZfwGsNE0{5%P1$)YM^r`~Aop3yl^1s@z@1&%+w!eb-s;mBx zdJ%95d(3@K`L?S*X%4t;dvM=W_5lkOTkV|E%01eC@?UlK-2q(b>QC5a@FhwtdD92Z zrG0tfJ+1FAb-is)f0E+nyAJ7!duY!0u5k>7@gnlqk_Q>R-xRuJ=-%Ee*85$4-s#o|~`sBeo}{uP|>we>f0OZT8( zcH85KZPlatSnssQTkAiK^;UblwLVSyYgxx{g`>veA9{T>V0~YXC40%vRVi|Xr3I0_ zx6_v?+^cdn=2FgS(%jEsw5uI0^-Q=^odMflPpY6Qg&sn~A-d1Obzo|1Q7vl`> zhc4mHhJI1oS)g%zZ$OM&bgxEi;r|;y`)S>K@I2Q#gK=g* zXxa1~=fnVip0dJ#`v1TQCyWi^SHQPNzHqetCHNEfay8#0|1~q-_UEwPS9(=*@+Xv^ z48Ki|3P%wWZ_{12bQpQEu}ZZIJ%W;1`V9En+aq=5&Vf^Os`!;? literal 0 HcmV?d00001 diff --git a/lab2/src/main/resources/vga_font_8x16.bmp b/lab2/src/main/resources/vga_font_8x16.bmp new file mode 100644 index 0000000000000000000000000000000000000000..1aa58b97adc06ca07e07f83dc762bdce4b963d68 GIT binary patch literal 17462 zcmeHJJF?`)5riUS=om0{0@?_LT;2gk!BJo+bPm`$gA5#jK8;mYW@UFZ1~c!y;kO72JFBA zoVv<=hFyRa*nk~4fK%6e%&-fv0voUc2XOKcEawcn04uNoJ8%H!wBh{QGy`$+6^K7O zZ~*7D;r!b?0}HSM8?XZhaO$xwGwcGazy|EV0i1fI>kPX9E3g4OZ~&(sH->E60<6FW z?7#t>dKLB=b^%sk19sp5PQ50_47&g;umL-804HCe?VMp3U3;#}EzJv$hPoyIL zKl^dlw|kC*egEI9A+KuO841{@iMAiu_KTJmr5qqe=XLMhJK*M<&PN3Lx!vCGp-w05 z`IC&^oC=d(?SJC4Ejpqu%cDG@KTXHPoEj>WdrHnxK~f((cx=Zvy)Q-8$1b>}zT^j` zvBELC`r{_d7_%9bHn=aTy@ND!ul6z~pFd5Mcw3zl-6;oStzHj4ABqJ!%jByq&2(9h zC3IlTZ$;LaA4;h+<`6Lv%ZQ6Gs@!)TuS|75^<|LM-ys`;=}nIeX5CSP$9qb}u5(FP z&uUq=$-YZfS)VyCqyFdTk8A=^b%inUqRcSn z1Ggn*vz>b=G{$6TzE)19t5T0k>)-}YgNAfuGu`x^ATfegNjGy&(_&G4m3RE=cG@I3 zZ}8%pZqM;7@A;p$-axsn;#S7{{Aj*?9B;LkuHwGcbzA?c{?b(3Tm3ha9})0{U2MBX z=lvlduHRqyF^(hUu$660y0LW)kEireL=re*>$Q)B{&peG%?;LC`i-ayLzX|=9z-T# zH+ws$h*6;P^FHEYa@$R$w6_yg807M`G$Z z%~1R&^VM`jMv1$t`OufEbz|1ZvfBn{>6A& z7&aTM_zlSq1krih{j~4_@pn?c>HN40?OnGLmlL-WYsqJp`Ap|UvV~|e%OFp%rV7z$5Ja>G2v!@_RwIt9A+5ru}wI8Ti)>p z=DUR!%gg!Db4_N=$wl<&R! zANnTXurW_7PS#_6kr_8ei}U}-(X4*HD2S35lCh_-FVD+CEX0o6sP0SXF_wrM7^$(e9nGgDvJMAfKBB)qIxN%H%N1ZJwP1;>0wKOsl{t)v6}>+9%giV^b_8*Zlae zdDc?Y0~HS6U#7gbp)cC{{9s0zi_+R5*31pIaEJV$qe>`L?UuzDn|`ky!OXSjj>>FI0IhgQC?_=-f5cDS zSmo-W*9Li~7t`r>G`X81aJ7c+KyTg%1w9Fe_5+4LZsLzv5kFC(giO^J1 zv&9enCGnf)w?T4p8+=ZFpscWf#Sfqnn?Mvx-+2Cqt7s={{o$nQT`o#7A~|NJ)eDsz zP#nuP>C896FsQMHtOs#;T!|7jEq)G9!(1apgn)6e$_`YuaG$(?#iF!+I6ZHVR)rzO zUQJ3$*YRn(Rn0w@C_-s#{;i&#lN3Z&k9&)4W2%!qOjSP^j;m)P3r@sLyTBYX zS#W}apUdYBe9Iencw@h%_&c>}Iz?+qEzkzK`YOiv=E6SBjdX31*uFyH(nlxuFn z+QtJhrInAJGcnSVV>3)va^xdw2{~Mu9-14A{Jghlj-SV6*y9}8>Tn8M5feqm@yP6L z^4i#5s8iC{PU?PI9~m4A1&h$;QoHK58%IrAZ)Qho)L;f9vl13T#Ln3|-xXAmLaZP8 z)m`NIJrve%ZbHJD_s)f(sY-khRV=TmkVLOdmH$EiI)B_v5&K5- LisBRZyA1jtmw literal 0 HcmV?d00001 diff --git a/lab2/src/main/scala/board/basys3/BCD2Segments.scala b/lab2/src/main/scala/board/basys3/BCD2Segments.scala new file mode 100644 index 0000000..65b79b8 --- /dev/null +++ b/lab2/src/main/scala/board/basys3/BCD2Segments.scala @@ -0,0 +1,54 @@ +// 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 board.basys3 + +import chisel3._ +import chisel3.util._ + +class BCD2Segments extends Module { + val io = IO(new Bundle { + val bcd = Input(UInt(4.W)) + val segs = Output(UInt(8.W)) + }) + + val bcd = io.bcd + val segs = Wire(UInt(8.W)) + + segs := MuxLookup( + bcd, + 0xFF.U, + IndexedSeq( + 0.U -> "b10000001".U, + 1.U -> "b11001111".U, + 2.U -> "b10010010".U, + 3.U -> "b10000110".U, + 4.U -> "b11001100".U, + 5.U -> "b10100100".U, + 6.U -> "b10100000".U, + 7.U -> "b10001111".U, + 8.U -> "b10000000".U, + 9.U -> "b10000100".U, + 10.U -> "b00001000".U, + 11.U -> "b01100000".U, + 12.U -> "b00110001".U, + 13.U -> "b01000010".U, + 14.U -> "b00110000".U, + 15.U -> "b00111000".U, + ) + ) + + io.segs := segs +} + diff --git a/lab2/src/main/scala/board/basys3/OnboardDigitDisplay.scala b/lab2/src/main/scala/board/basys3/OnboardDigitDisplay.scala new file mode 100644 index 0000000..a07819b --- /dev/null +++ b/lab2/src/main/scala/board/basys3/OnboardDigitDisplay.scala @@ -0,0 +1,32 @@ +// 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 board.basys3 + +import chisel3._ + +class OnboardDigitDisplay extends Module { + val io = IO(new Bundle { + val digit_mask = Output(UInt(4.W)) + }) + + val counter = RegInit(UInt(16.W), 0.U) + val digit_mask = RegInit(UInt(4.W), "b0111".U) + + counter := counter + 1.U + when(counter === 0.U) { + digit_mask := (digit_mask << 1.U).asUInt + digit_mask(3) + } + io.digit_mask := digit_mask +} diff --git a/lab2/src/main/scala/board/basys3/SYSULogo.scala b/lab2/src/main/scala/board/basys3/SYSULogo.scala new file mode 100644 index 0000000..c41f4e6 --- /dev/null +++ b/lab2/src/main/scala/board/basys3/SYSULogo.scala @@ -0,0 +1,34 @@ +// 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 board.basys3 + +import chisel3._ +import chisel3.util._ + +class SYSULogo extends Module { + val io = IO(new Bundle { + val digit_mask = Input(UInt(4.W)) + val segs = Output(UInt(8.W)) + }) + + io.segs := MuxLookup( + io.digit_mask, + "b00100100".U, // "b0111".U, "b1101".U -> S + IndexedSeq( + "b1011".U -> "b01000100".U, // Y + "b1110".U -> "b01000001".U, // U + ) + ) +} diff --git a/lab2/src/main/scala/board/basys3/SegmentMux.scala b/lab2/src/main/scala/board/basys3/SegmentMux.scala new file mode 100644 index 0000000..9bb1bf7 --- /dev/null +++ b/lab2/src/main/scala/board/basys3/SegmentMux.scala @@ -0,0 +1,42 @@ +// 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 board.basys3 + +import chisel3._ +import chisel3.util._ + +class SegmentMux extends Module { + val io = IO(new Bundle { + val digit_mask = Input(UInt(4.W)) + val numbers = Input(UInt(16.W)) + val segs = Output(UInt(8.W)) + }) + + + val digit = RegInit(UInt(4.W), 0.U) + val bcd2segs = Module(new BCD2Segments) + + bcd2segs.io.bcd := digit + io.segs := bcd2segs.io.segs + digit := MuxLookup( + io.digit_mask, + io.numbers(3, 0), // "b1110".U + IndexedSeq( + "b1101".U -> io.numbers(7, 4), + "b1011".U -> io.numbers(11, 8), + "b0111".U -> io.numbers(15, 12) + ) + ) +} diff --git a/lab2/src/main/scala/board/basys3/Top.scala b/lab2/src/main/scala/board/basys3/Top.scala new file mode 100644 index 0000000..f3af2ca --- /dev/null +++ b/lab2/src/main/scala/board/basys3/Top.scala @@ -0,0 +1,138 @@ +// 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 board.basys3 + +import chisel3._ +import chisel3.experimental.ChiselEnum +import chisel3.stage.{ChiselGeneratorAnnotation, ChiselStage} +import chisel3.util._ +import peripheral.{CharacterDisplay, Dummy, InstructionROM, Memory, ROMLoader, Uart, VGADisplay, Timer} +import riscv._ +import riscv.core.{CPU, ProgramCounter} + +object BootStates extends ChiselEnum { + val Init, Loading, Finished = Value +} + +class Top extends Module { + val binaryFilename = "tetris.asmbin" + val io = IO(new Bundle { + val switch = Input(UInt(16.W)) + + val segs = Output(UInt(8.W)) + val digit_mask = Output(UInt(4.W)) + + val hsync = Output(Bool()) + val vsync = Output(Bool()) + val rgb = Output(UInt(12.W)) + val led = Output(UInt(16.W)) + + val tx = Output(Bool()) + val rx = Input(Bool()) + + }) + + val mem = Module(new Memory(Parameters.MemorySizeInWords)) + val vga_display = Module(new VGADisplay) + val display = Module(new CharacterDisplay) + val timer = Module(new Timer) + val uart = Module(new Uart(frequency = 100000000, baudRate = 115200)) + val dummy = Module(new Dummy) + + display.io.bundle <> dummy.io.bundle + mem.io.bundle <> dummy.io.bundle + mem.io.debug_read_address := 0.U + timer.io.bundle <> dummy.io.bundle + uart.io.bundle <> dummy.io.bundle + io.tx := uart.io.txd + uart.io.rxd := io.rx + + val instruction_rom = Module(new InstructionROM(binaryFilename)) + val rom_loader = Module(new ROMLoader(instruction_rom.capacity)) + + rom_loader.io.rom_data := instruction_rom.io.data + rom_loader.io.load_address := Parameters.EntryAddress + instruction_rom.io.address := rom_loader.io.rom_address + + val CPU_clkdiv = RegInit(UInt(2.W), 0.U) + val CPU_tick = Wire(Bool()) + val CPU_next = Wire(UInt(2.W)) + CPU_next := Mux(CPU_clkdiv === 3.U, 0.U, CPU_clkdiv + 1.U) + CPU_tick := CPU_clkdiv === 0.U + CPU_clkdiv := CPU_next + + withClock(CPU_tick.asClock) { + val cpu = Module(new CPU) + cpu.io.interrupt_flag := Cat(uart.io.signal_interrupt, timer.io.signal_interrupt) + cpu.io.csr_regs_debug_read_address := 0.U + cpu.io.regs_debug_read_address := 0.U + cpu.io.instruction_valid := rom_loader.io.load_finished + mem.io.instruction_address := cpu.io.instruction_address + cpu.io.instruction := mem.io.instruction + + when(!rom_loader.io.load_finished) { + rom_loader.io.bundle <> mem.io.bundle + cpu.io.memory_bundle.read_data := 0.U + }.otherwise { + rom_loader.io.bundle.read_data := 0.U + when(cpu.io.deviceSelect === 4.U) { + cpu.io.memory_bundle <> timer.io.bundle + }.elsewhen(cpu.io.deviceSelect === 2.U) { + cpu.io.memory_bundle <> uart.io.bundle + }.elsewhen(cpu.io.deviceSelect === 1.U) { + cpu.io.memory_bundle <> display.io.bundle + }.otherwise { + cpu.io.memory_bundle <> mem.io.bundle + } + } + } + + display.io.x := vga_display.io.x + display.io.y := vga_display.io.y + + io.hsync := vga_display.io.hsync + io.vsync := vga_display.io.vsync + + io.rgb := display.io.rgb + + mem.io.debug_read_address := io.switch(15, 1).asUInt << 2 + io.led := Mux( + io.switch(0), + mem.io.debug_read_data(31, 16).asUInt, + mem.io.debug_read_data(15, 0).asUInt, + ) + + val onboard_display = Module(new OnboardDigitDisplay) + io.digit_mask := onboard_display.io.digit_mask + + val sysu_logo = Module(new SYSULogo) + sysu_logo.io.digit_mask := io.digit_mask + + val seg_mux = Module(new SegmentMux) + seg_mux.io.digit_mask := io.digit_mask + seg_mux.io.numbers := io.led + + io.segs := MuxLookup( + io.switch, + seg_mux.io.segs, + IndexedSeq( + 0.U -> sysu_logo.io.segs + ) + ) +} + +object VerilogGenerator extends App { + (new ChiselStage).execute(Array("-X", "verilog", "-td", "verilog/basys3"), Seq(ChiselGeneratorAnnotation(() => new Top))) +} \ No newline at end of file diff --git a/lab2/src/main/scala/board/pynq/Top.scala b/lab2/src/main/scala/board/pynq/Top.scala new file mode 100644 index 0000000..57f39cb --- /dev/null +++ b/lab2/src/main/scala/board/pynq/Top.scala @@ -0,0 +1,109 @@ +// Copyright 2022 Canbin Huang +// +// 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 board.pynq + +import chisel3._ +import chisel3.stage.{ChiselGeneratorAnnotation, ChiselStage} +import chisel3.util.Cat +import peripheral._ +import riscv.Parameters +import riscv.core.{CPU, ProgramCounter} + +class Top extends Module { + val binaryFilename = "hello.asmbin" + val io = IO(new Bundle() { + val hdmi_clk_n = Output(Bool()) + val hdmi_clk_p = Output(Bool()) + val hdmi_data_n = Output(UInt(3.W)) + val hdmi_data_p = Output(UInt(3.W)) + val hdmi_hpdn = Output(Bool()) + + val tx = Output(Bool()) + val rx = Input(Bool()) + + val led = Output(UInt(4.W)) + }) + val mem = Module(new Memory(Parameters.MemorySizeInWords)) + val hdmi_display = Module(new HDMIDisplay) + val display = Module(new CharacterDisplay) + val timer = Module(new Timer) + val uart = Module(new Uart(frequency = 125000000, baudRate = 115200)) + val dummy = Module(new Dummy) + + display.io.bundle <> dummy.io.bundle + mem.io.bundle <> dummy.io.bundle + mem.io.debug_read_address := 0.U + timer.io.bundle <> dummy.io.bundle + uart.io.bundle <> dummy.io.bundle + io.tx := uart.io.txd + uart.io.rxd := io.rx + + val instruction_rom = Module(new InstructionROM(binaryFilename)) + val rom_loader = Module(new ROMLoader(instruction_rom.capacity)) + + rom_loader.io.rom_data := instruction_rom.io.data + rom_loader.io.load_address := Parameters.EntryAddress + instruction_rom.io.address := rom_loader.io.rom_address + + val CPU_clkdiv = RegInit(UInt(2.W),0.U) + val CPU_tick = Wire(Bool()) + val CPU_next = Wire(UInt(2.W)) + CPU_next := Mux(CPU_clkdiv === 3.U, 0.U, CPU_clkdiv + 1.U) + CPU_tick := CPU_clkdiv === 0.U + CPU_clkdiv := CPU_next + + withClock(CPU_tick.asClock) { + val cpu = Module(new CPU) + cpu.io.interrupt_flag := Cat(uart.io.signal_interrupt, timer.io.signal_interrupt) + cpu.io.csr_regs_debug_read_address := 0.U + cpu.io.regs_debug_read_address := 0.U + cpu.io.instruction_valid := rom_loader.io.load_finished + mem.io.instruction_address := cpu.io.instruction_address + cpu.io.instruction := mem.io.instruction + + when(!rom_loader.io.load_finished) { + rom_loader.io.bundle <> mem.io.bundle + cpu.io.memory_bundle.read_data := 0.U + }.otherwise { + rom_loader.io.bundle.read_data := 0.U + when(cpu.io.deviceSelect === 4.U) { + cpu.io.memory_bundle <> timer.io.bundle + }.elsewhen(cpu.io.deviceSelect === 2.U) { + cpu.io.memory_bundle <> uart.io.bundle + }.elsewhen(cpu.io.deviceSelect === 1.U) { + cpu.io.memory_bundle <> display.io.bundle + }.otherwise { + cpu.io.memory_bundle <> mem.io.bundle + } + } + } + + io.led := 15.U(4.W) + + display.io.x := hdmi_display.io.x + display.io.y := hdmi_display.io.y + display.io.video_on := hdmi_display.io.video_on + hdmi_display.io.rgb := display.io.rgb + + io.hdmi_hpdn := 1.U + io.hdmi_data_n := hdmi_display.io.TMDSdata_n + io.hdmi_data_p := hdmi_display.io.TMDSdata_p + io.hdmi_clk_n := hdmi_display.io.TMDSclk_n + io.hdmi_clk_p := hdmi_display.io.TMDSclk_p +} + +object VerilogGenerator extends App { + (new ChiselStage).execute(Array("-X", "verilog", "-td", "verilog/pynq"), Seq(ChiselGeneratorAnnotation(() => new Top))) +} \ No newline at end of file diff --git a/lab2/src/main/scala/board/verilator/Top.scala b/lab2/src/main/scala/board/verilator/Top.scala new file mode 100644 index 0000000..7f353e4 --- /dev/null +++ b/lab2/src/main/scala/board/verilator/Top.scala @@ -0,0 +1,45 @@ +// Copyright 2022 Canbin Huang +// +// 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 board.verilator + +import chisel3._ +import chisel3.stage.{ChiselGeneratorAnnotation, ChiselStage} +import peripheral._ +import riscv.{CPUBundle, Parameters} +import riscv.core.CPU + +class Top extends Module { + val io = IO(new CPUBundle) + + val cpu = Module(new CPU) + + io.deviceSelect := 0.U + cpu.io.regs_debug_read_address := io.regs_debug_read_address + cpu.io.csr_regs_debug_read_address := io.csr_regs_debug_read_address + io.csr_regs_debug_read_data := cpu.io.csr_regs_debug_read_data + io.regs_debug_read_data := cpu.io.regs_debug_read_data + + io.memory_bundle <> cpu.io.memory_bundle + io.instruction_address := cpu.io.instruction_address + cpu.io.instruction := io.instruction + + cpu.io.interrupt_flag := io.interrupt_flag + cpu.io.instruction_valid := io.instruction_valid +} + +object VerilogGenerator extends App { + (new ChiselStage).execute(Array("-X", "verilog", "-td", "verilog/verilator"), Seq(ChiselGeneratorAnnotation(() => + new Top()))) +} \ No newline at end of file diff --git a/lab2/src/main/scala/peripheral/CharacterDisplay.scala b/lab2/src/main/scala/peripheral/CharacterDisplay.scala new file mode 100644 index 0000000..1c4bc8e --- /dev/null +++ b/lab2/src/main/scala/peripheral/CharacterDisplay.scala @@ -0,0 +1,84 @@ +// 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 peripheral + +import chisel3.util.{MuxLookup, log2Up} +import chisel3.{Bool, Bundle, Module, Mux, Output, UInt, Wire, _} +import peripheral.ScreenInfo.{DisplayHorizontal, DisplayVertical} +import riscv.Parameters + +object GlyphInfo { + val glyphWidth = 8 + val glyphHeight = 16 + // ASCII printable characters start from here + val spaceIndex = 1 +} + +object ScreenInfo { + val DisplayHorizontal = 640 + val DisplayVertical = 480 +} + +object CharacterBufferInfo { + val CharCols = DisplayHorizontal / GlyphInfo.glyphWidth + val CharRows = DisplayVertical / GlyphInfo.glyphHeight + val Chars = CharCols * CharRows +} + +class CharacterDisplay extends Module { + val io = IO(new Bundle() { + val bundle = new RAMBundle() + + val x = Input(UInt(16.W)) + val y = Input(UInt(16.W)) + val video_on = Input(Bool()) + + val rgb = Output(UInt(24.W)) + }) + + val mem = Module(new BlockRAM(CharacterBufferInfo.Chars / Parameters.WordSize)) + mem.io.write_enable := io.bundle.write_enable + mem.io.write_data := io.bundle.write_data + mem.io.write_address := io.bundle.address + mem.io.write_strobe := io.bundle.write_strobe + mem.io.read_address := io.bundle.address + io.bundle.read_data := mem.io.read_data + + + val font_rom = Module(new FontROM) + val row = (io.y >> log2Up(GlyphInfo.glyphHeight)).asUInt + val col = (io.x >> log2Up(GlyphInfo.glyphWidth)).asUInt + val char_index = (row * CharacterBufferInfo.CharCols.U) + col + val offset = char_index(1, 0) + val ch = Wire(UInt(8.W)) + + mem.io.debug_read_address := char_index + ch := MuxLookup( + offset, + 0.U, + IndexedSeq( + 0.U -> mem.io.debug_read_data(7, 0).asUInt, + 1.U -> mem.io.debug_read_data(15, 8).asUInt, + 2.U -> mem.io.debug_read_data(23, 16).asUInt, + 3.U -> mem.io.debug_read_data(31, 24).asUInt + ) + ) + font_rom.io.glyph_index := Mux(ch >= 32.U, ch - 31.U, 0.U) + font_rom.io.glyph_y := io.y(log2Up(GlyphInfo.glyphHeight) - 1, 0) + + // White if pixel_on and glyph pixel on + val glyph_x = io.x(log2Up(GlyphInfo.glyphWidth) - 1, 0) + io.rgb := Mux(io.video_on && font_rom.io.glyph_pixel_byte(glyph_x), 0xFFFFFF.U, 0.U) +} diff --git a/lab2/src/main/scala/peripheral/Dummy.scala b/lab2/src/main/scala/peripheral/Dummy.scala new file mode 100644 index 0000000..fe4cb04 --- /dev/null +++ b/lab2/src/main/scala/peripheral/Dummy.scala @@ -0,0 +1,29 @@ +// 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 peripheral + +import chisel3._ +import riscv.Parameters + +// A dummy master that never initiates reads or writes +class Dummy extends Module { + val io = IO(new Bundle { + val bundle = Flipped(new RAMBundle) + }) + io.bundle.write_strobe := VecInit(Seq.fill(Parameters.WordSize)(false.B)) + io.bundle.write_data := 0.U + io.bundle.write_enable := false.B + io.bundle.address := 0.U +} diff --git a/lab2/src/main/scala/peripheral/FontROM.scala b/lab2/src/main/scala/peripheral/FontROM.scala new file mode 100644 index 0000000..b9b0d3b --- /dev/null +++ b/lab2/src/main/scala/peripheral/FontROM.scala @@ -0,0 +1,64 @@ +package peripheral + +import chisel3.experimental.{ChiselAnnotation, annotate} +import chisel3.util.experimental.loadMemoryFromFileInline +import chisel3.{Bundle, Input, Module, Output, SyncReadMem, UInt, _} +import firrtl.annotations.MemorySynthInit + +import java.io.FileWriter +import java.nio.file.Paths +import javax.imageio.ImageIO + +class FontROM(fontBitmapFilename: String = "vga_font_8x16.bmp") extends Module { + val glyphWidth = GlyphInfo.glyphWidth + val glyphHeight = GlyphInfo.glyphHeight + + val io = IO(new Bundle { + val glyph_index = Input(UInt(7.W)) + val glyph_y = Input(UInt(4.W)) + + val glyph_pixel_byte = Output(UInt(8.W)) + }) + + annotate(new ChiselAnnotation { + override def toFirrtl = + MemorySynthInit + }) + + val (hexTxtPath, glyphCount) = readFontBitmap() + val mem = SyncReadMem(glyphCount, UInt(8.W)) + loadMemoryFromFileInline(mem, hexTxtPath.toString.replaceAll("\\\\", "/")) + io.glyph_pixel_byte := mem.read(io.glyph_index * GlyphInfo.glyphHeight.U + io.glyph_y, true.B) + + def readFontBitmap() = { + val inputStream = getClass.getClassLoader.getResourceAsStream(fontBitmapFilename) + val image = ImageIO.read(inputStream) + + val glyphColumns = image.getWidth() / glyphWidth + val glyphRows = image.getHeight / glyphHeight + val glyphCount = glyphColumns * glyphRows + val glyphs = new Array[UInt](glyphCount * GlyphInfo.glyphHeight) + + for (row <- 0 until glyphRows) { + for (col <- 0 until glyphColumns) { + for (i <- 0 until glyphHeight) { + var lineInt = 0 + for (j <- 0 until glyphWidth) { + if (image.getRGB(col * glyphWidth + j, row * glyphHeight + i) != 0xFFFFFFFF) { + lineInt |= (1 << j) + } + } + glyphs((row * glyphColumns + col) * GlyphInfo.glyphHeight + i) = lineInt.U(8.W) + } + } + } + val currentDir = System.getProperty("user.dir") + val hexTxtPath = Paths.get(currentDir, "verilog", f"${fontBitmapFilename}.txt") + val writer = new FileWriter(hexTxtPath.toString) + for (i <- glyphs.indices) { + writer.write(f"@$i%x\n${glyphs(i).litValue}%02x\n") + } + writer.close() + (hexTxtPath, glyphs.length) + } +} diff --git a/lab2/src/main/scala/peripheral/HDMIDisplay.scala b/lab2/src/main/scala/peripheral/HDMIDisplay.scala new file mode 100644 index 0000000..d575fda --- /dev/null +++ b/lab2/src/main/scala/peripheral/HDMIDisplay.scala @@ -0,0 +1,394 @@ +// Copyright 2022 hrpccs +// +// 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 peripheral + +import chisel3._ +import chisel3.util._ + +class HDMISync extends Module { + val io = IO(new Bundle { + val hsync = Output(Bool()) + val vsync = Output(Bool()) + val video_on = Output(Bool()) + val p_tick = Output(Bool()) + val f_tick = Output(Bool()) + val x = Output(UInt(10.W)) + val y = Output(UInt(10.W)) + val x_next = Output(UInt(10.W)) + val y_next = Output(UInt(10.W)) + }) + + val DisplayHorizontal = ScreenInfo.DisplayHorizontal + val DisplayVertical = ScreenInfo.DisplayVertical + + val BorderLeft = 48 + val BorderRight = 16 + val BorderTop = 10 + val BorderBottom = 33 + + val RetraceHorizontal = 96 + val RetraceVertical = 2 + + val MaxHorizontal = DisplayHorizontal + BorderLeft + BorderRight + RetraceHorizontal - 1 + val MaxVertical = DisplayVertical + BorderTop + BorderBottom + RetraceVertical - 1 + + val RetraceHorizontalStart = DisplayHorizontal + BorderRight + val RetraceHorizontalEnd = RetraceHorizontalStart + RetraceHorizontal - 1 + + val RetraceVerticalStart = DisplayVertical + BorderBottom + val RetraceVerticalEnd = RetraceVerticalStart + RetraceVertical - 1 + + val pixel = RegInit(UInt(3.W), 0.U) + val pixel_next = Wire(UInt(3.W)) + val pixel_tick = Wire(Bool()) + + val v_count_reg = RegInit(UInt(10.W), 0.U) + val h_count_reg = RegInit(UInt(10.W), 0.U) + + val v_count_next = Wire(UInt(10.W)) + val h_count_next = Wire(UInt(10.W)) + + val vsync_reg = RegInit(Bool(), false.B) + val hsync_reg = RegInit(Bool(), false.B) + + val vsync_next = Wire(Bool()) + val hsync_next = Wire(Bool()) + + pixel_next := Mux(pixel === 4.U, 0.U, pixel + 1.U) + pixel_tick := pixel === 0.U + + h_count_next := Mux( + pixel_tick, + Mux(h_count_reg === MaxHorizontal.U, 0.U, h_count_reg + 1.U), + h_count_reg + ) + + v_count_next := Mux( + pixel_tick && h_count_reg === MaxHorizontal.U, + Mux(v_count_reg === MaxVertical.U, 0.U, v_count_reg + 1.U), + v_count_reg + ) + + hsync_next := h_count_reg >= RetraceHorizontalStart.U && h_count_reg <= RetraceHorizontalEnd.U + vsync_next := v_count_reg >= RetraceVerticalStart.U && v_count_reg <= RetraceVerticalEnd.U + + pixel := pixel_next + hsync_reg := hsync_next + vsync_reg := vsync_next + v_count_reg := v_count_next + h_count_reg := h_count_next + + io.video_on := h_count_reg < DisplayHorizontal.U && v_count_reg < DisplayVertical.U + io.hsync := hsync_reg + io.vsync := vsync_reg + io.x := h_count_reg + io.y := v_count_reg + io.x_next := h_count_next + io.y_next := v_count_next + io.p_tick := pixel_tick + io.f_tick := io.x === 0.U && io.y === 0.U +} + +class TMDS_encoder extends Module { + val io = IO(new Bundle() { + val video_data = Input(UInt(8.W)) //r,g,b,8bit + val control_data = Input(UInt(2.W)) + val video_on = Input(Bool()) + val TMDS = Output(UInt(10.W)) + }) + val Nb1s = PopCount(io.video_data) + val xored = xorfct(io.video_data) + val xnored = xnorfct(io.video_data) + val XNOR = (Nb1s > 4.U(4.W)) || (Nb1s === 4.U(4.W) && io.video_data(0) === 0.U) + val q_m = RegInit(0.U(9.W)) + val diffSize = 4 + val diff = RegInit(0.S(diffSize.W)) + q_m := Mux( + XNOR, + xnored, + xored + ) + val disparitySize = 4 + val disparityReg = RegInit(0.S(disparitySize.W)) + diff := PopCount(q_m).asSInt - 4.S + val doutReg = RegInit("b1010101011".U(10.W)) + + def xorfct(value: UInt): UInt = { + val vin = VecInit(value.asBools) + val res = VecInit(511.U.asBools) + res(0) := vin(0) + for (i <- 1 to 7) { + res(i) := res(i - 1) ^ vin(i) + } + res(8) := 1.U + res.asUInt + } + + def xnorfct(value: UInt): UInt = { + val vin = VecInit(value.asBools) + val res = VecInit(511.U.asBools) + res(0) := vin(0) + for (i <- 1 to 7) { + res(i) := !(res(i - 1) ^ vin(i)) + } + res(8) := 0.U + res.asUInt + } + + when(io.video_on === false.B) { + disparityReg := 0.S + doutReg := "b1010101011".U(10.W) + switch(io.control_data) { + is("b00".U(2.W)) { + doutReg := "b1101010100".U(10.W) + } + is("b01".U(2.W)) { + doutReg := "b0010101011".U(10.W) + } + is("b10".U(2.W)) { + doutReg := "b0101010100".U(10.W) + } + } + }.otherwise { + when(disparityReg === 0.S || diff === 0.S) { + when(q_m(8) === false.B) { + doutReg := "b10".U(2.W) ## ~q_m(7, 0) + disparityReg := disparityReg - diff + }.otherwise { + doutReg := "b01".U(2.W) ## q_m(7, 0) + disparityReg := disparityReg + diff + } + }.elsewhen((!diff(diffSize - 1) && !disparityReg(disparitySize - 1)) + || (diff(diffSize - 1) && disparityReg(disparitySize - 1))) { + doutReg := 1.U(1.W) ## q_m(8) ## ~q_m(7, 0) + when(q_m(8)) { + disparityReg := disparityReg + 1.S - diff + }.otherwise { + disparityReg := disparityReg - diff + } + }.otherwise { + doutReg := 0.U(1.W) ## q_m + when(q_m(8)) { + disparityReg := disparityReg + diff + }.otherwise { + disparityReg := disparityReg - 1.S + diff + } + } + } + + io.TMDS := doutReg +} + +class HDMIDisplay extends Module { + val io = IO(new Bundle() { + val rgb = Input(UInt(24.W)) + val x = Output(UInt(16.W)) + val y = Output(UInt(16.W)) + val x_next = Output(UInt(16.W)) + val y_next = Output(UInt(16.W)) + val video_on = Output(Bool()) + + val TMDSclk_p = Output(Bool()) + val TMDSdata_p = Output(UInt(3.W)) + val TMDSclk_n = Output(Bool()) + val TMDSdata_n = Output(UInt(3.W)) + }) + val rgb = io.rgb + val pixel_clk = Wire(Bool()) + val hsync = Wire(Bool()) + val vsync = Wire(Bool()) + val sync = Module(new HDMISync) + + io.x := sync.io.x + io.y := sync.io.y + io.x_next := sync.io.x_next + io.y_next := sync.io.y_next + io.video_on := sync.io.video_on + + hsync := sync.io.hsync + vsync := sync.io.vsync + pixel_clk := sync.io.p_tick + + // TMDS_PLLVR is a vivado IP core, check it in /verilog/pynq/TMDS_PLLVR.v + val serial_clk = Wire(Clock()) + val pll_lock = Wire(Bool()) + val tmdspll = Module(new TMDS_PLLVR) + val rst = Wire(Reset()) + tmdspll.io.clkin := pixel_clk.asClock + serial_clk := tmdspll.io.clkout + pll_lock := tmdspll.io.lock + tmdspll.io.reset := reset + rst := ~pll_lock + + val tmds = Wire(UInt(3.W)) + val tmds_clk = Wire(Bool()) + withClockAndReset(pixel_clk.asClock, rst) { + val tmds_channel1 = Wire(UInt(10.W)) + val tmds_channel2 = Wire(UInt(10.W)) + val tmds_channel0 = Wire(UInt(10.W)) + + val tmds_green = Module(new TMDS_encoder) + val tmds_red = Module(new TMDS_encoder) + val tmds_blue = Module(new TMDS_encoder) + + tmds_red.io.video_on := sync.io.video_on + tmds_blue.io.video_on := sync.io.video_on + tmds_green.io.video_on := sync.io.video_on + + tmds_blue.io.control_data := sync.io.vsync ## sync.io.hsync + tmds_green.io.control_data := 0.U + tmds_red.io.control_data := 0.U + + tmds_red.io.video_data := rgb(23, 16) + tmds_blue.io.video_data := rgb(7, 0) + tmds_green.io.video_data := rgb(15, 8) + + tmds_channel0 := tmds_blue.io.TMDS + tmds_channel1 := tmds_green.io.TMDS + tmds_channel2 := tmds_red.io.TMDS + + val serdesBlue = Module(new Oser10Module()) + serdesBlue.io.data := tmds_channel0 + serdesBlue.io.fclk := serial_clk + + val serdesGreen = Module(new Oser10Module()) + serdesGreen.io.data := tmds_channel1 + serdesGreen.io.fclk := serial_clk + + val serdesRed = Module(new Oser10Module()) + serdesRed.io.data := tmds_channel2 + serdesRed.io.fclk := serial_clk + + tmds := serdesRed.io.q ## serdesGreen.io.q ## serdesBlue.io.q + + //serdesCLk : 25Mhz ,Why not directly use p_tick? + //cause Duty Ratio of p_tick is 10% , while which of serdesCLk is 50% + val serdesClk = Module(new Oser10Module()) + serdesClk.io.data := "b1111100000".U(10.W) + serdesClk.io.fclk := serial_clk + + tmds_clk := serdesClk.io.q + + val buffDiffBlue = Module(new OBUFDS) + buffDiffBlue.io.I := tmds(0) + val buffDiffGreen = Module(new OBUFDS) + buffDiffGreen.io.I := tmds(1) + val buffDiffRed = Module(new OBUFDS) + buffDiffRed.io.I := tmds(2) + val buffDiffClk = Module(new OBUFDS) + buffDiffClk.io.I := tmds_clk + + io.TMDSclk_p := buffDiffClk.io.O + io.TMDSclk_n := buffDiffClk.io.OB + io.TMDSdata_p := buffDiffRed.io.O ## buffDiffGreen.io.O ## buffDiffBlue.io.O + io.TMDSdata_n := buffDiffRed.io.OB ## buffDiffGreen.io.OB ## buffDiffBlue.io.OB + } +} + +//---------------------------------------- +//PLL frequency multiplier using BlackBox +class TMDS_PLLVR extends BlackBox { + val io = IO(new Bundle { + val clkin = Input(Clock()) + val reset = Input(Reset()) + val clkout = Output(Clock()) + val clkoutd = Output(Clock()) + val lock = Output(Bool()) + }) +} + +/* OSER10 : serializer 10:1*/ +class OSER10 extends Module { + val io = IO(new Bundle { + val Q = Output(Bool()) // OSER10 data output signal + val D0 = Input(Bool()) + val D1 = Input(Bool()) + val D2 = Input(Bool()) + val D3 = Input(Bool()) + val D4 = Input(Bool()) + val D5 = Input(Bool()) + val D6 = Input(Bool()) + val D7 = Input(Bool()) + val D8 = Input(Bool()) + val D9 = Input(Bool()) // OSER10 data input signal + val PCLK = Input(Clock()) // Primary clock input signal + val FCLK = Input(Clock()) // High speed clock input signal + val RESET = Input(Reset()) // Asynchronous reset input signal, + //active-high. + }) + withClockAndReset(io.FCLK, io.RESET) { + val count = RegInit(0.U(4.W)) + val countnext = Wire(UInt(4.W)) + io.Q := MuxLookup( + count, + 0.U, + IndexedSeq( + 0.U -> io.D0.asBool, + 1.U -> io.D1.asBool, + 2.U -> io.D2.asBool, + 3.U -> io.D3.asBool, + 4.U -> io.D4.asBool, + 5.U -> io.D5.asBool, + 6.U -> io.D6.asBool, + 7.U -> io.D7.asBool, + 8.U -> io.D8.asBool, + 9.U -> io.D9.asBool + ) + ) + countnext := Mux( + count === 9.U, 0.U, count + 1.U + ) + count := countnext + } +} + +class Oser10Module extends Module { + val io = IO(new Bundle { + val q = Output(Bool()) + val data = Input(UInt(10.W)) + val fclk = Input(Clock()) // Fast clock + }) + + val osr10 = Module(new OSER10()) + io.q := osr10.io.Q + osr10.io.D0 := io.data(0) + osr10.io.D1 := io.data(1) + osr10.io.D2 := io.data(2) + osr10.io.D3 := io.data(3) + osr10.io.D4 := io.data(4) + osr10.io.D5 := io.data(5) + osr10.io.D6 := io.data(6) + osr10.io.D7 := io.data(7) + osr10.io.D8 := io.data(8) + osr10.io.D9 := io.data(9) + osr10.io.PCLK := clock + osr10.io.FCLK := io.fclk + osr10.io.RESET := reset +} + +/* lvds output */ +class OBUFDS extends BlackBox { + val io = IO(new Bundle { + val O = Output(Bool()) + val OB = Output(Bool()) + val I = Input(Bool()) + }) +} +//----------------------------------------- + + +//----------------------------------------- + + diff --git a/lab2/src/main/scala/peripheral/InstructionROM.scala b/lab2/src/main/scala/peripheral/InstructionROM.scala new file mode 100644 index 0000000..4d7ed12 --- /dev/null +++ b/lab2/src/main/scala/peripheral/InstructionROM.scala @@ -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 peripheral + +import chisel3._ +import chisel3.experimental.{ChiselAnnotation, annotate} +import chisel3.util.experimental.loadMemoryFromFileInline +import firrtl.annotations.MemorySynthInit +import riscv.Parameters + +import java.io.FileWriter +import java.nio.file.{Files, Paths} +import java.nio.{ByteBuffer, ByteOrder} + +class InstructionROM(instructionFilename: String) extends Module { + val io = IO(new Bundle { + val address = Input(UInt(Parameters.AddrWidth)) + val data = Output(UInt(Parameters.InstructionWidth)) + }) + + val (instructionsInitFile, capacity) = readAsmBinary(instructionFilename) + val mem = Mem(capacity, UInt(Parameters.InstructionWidth)) + annotate(new ChiselAnnotation { + override def toFirrtl = + MemorySynthInit + }) + loadMemoryFromFileInline(mem, instructionsInitFile.toString.replaceAll("\\\\", "/")) + io.data := mem.read(io.address) + + def readAsmBinary(filename: String) = { + val inputStream = if (Files.exists(Paths.get(filename))) { + Files.newInputStream(Paths.get(filename)) + } else { + 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 + } + instructions = instructions :+ BigInt(0x00000013L) + instructions = instructions :+ BigInt(0x00000013L) + instructions = instructions :+ BigInt(0x00000013L) + val currentDir = System.getProperty("user.dir") + val exeTxtPath = Paths.get(currentDir, "verilog", f"${instructionFilename}.txt") + val writer = new FileWriter(exeTxtPath.toString) + for (i <- instructions.indices) { + writer.write(f"@$i%x\n${instructions(i)}%08x\n") + } + writer.close() + (exeTxtPath, instructions.length) + } +} diff --git a/lab2/src/main/scala/peripheral/Memory.scala b/lab2/src/main/scala/peripheral/Memory.scala new file mode 100644 index 0000000..4c10bca --- /dev/null +++ b/lab2/src/main/scala/peripheral/Memory.scala @@ -0,0 +1,77 @@ +// 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 peripheral + +import chisel3._ +import chisel3.util._ +import riscv.Parameters + +class RAMBundle extends Bundle { + val address = Input(UInt(Parameters.AddrWidth)) + val write_data = Input(UInt(Parameters.DataWidth)) + val write_enable = Input(Bool()) + val write_strobe = Input(Vec(Parameters.WordSize, Bool())) + val read_data = Output(UInt(Parameters.DataWidth)) +} +// The purpose of this module is to help the synthesis tool recognize +// our memory as a Block RAM template +class BlockRAM(capacity: Int) extends Module { + val io = IO(new Bundle { + val read_address = Input(UInt(Parameters.AddrWidth)) + val write_address = Input(UInt(Parameters.AddrWidth)) + val write_data = Input(UInt(Parameters.DataWidth)) + val write_enable = Input(Bool()) + val write_strobe = Input(Vec(Parameters.WordSize, Bool())) + + val debug_read_address = Input(UInt(Parameters.AddrWidth)) + + val read_data = Output(UInt(Parameters.DataWidth)) + val debug_read_data = Output(UInt(Parameters.DataWidth)) + }) + val mem = SyncReadMem(capacity, Vec(Parameters.WordSize, UInt(Parameters.ByteWidth))) + when(io.write_enable) { + val write_data_vec = Wire(Vec(Parameters.WordSize, UInt(Parameters.ByteWidth))) + for (i <- 0 until Parameters.WordSize) { + write_data_vec(i) := io.write_data((i + 1) * Parameters.ByteBits - 1, i * Parameters.ByteBits) + } + mem.write((io.write_address >> 2.U).asUInt, write_data_vec, io.write_strobe) + } + io.read_data := mem.read((io.read_address >> 2.U).asUInt, true.B).asUInt + io.debug_read_data := mem.read((io.debug_read_address >> 2.U).asUInt, true.B).asUInt +} + +class Memory(capacity: Int) extends Module { + val io = IO(new Bundle { + val bundle = new RAMBundle + + val instruction = Output(UInt(Parameters.DataWidth)) + val instruction_address = Input(UInt(Parameters.AddrWidth)) + + val debug_read_address = Input(UInt(Parameters.AddrWidth)) + val debug_read_data = Output(UInt(Parameters.DataWidth)) + }) + + val mem = SyncReadMem(capacity, Vec(Parameters.WordSize, UInt(Parameters.ByteWidth))) + when(io.bundle.write_enable) { + val write_data_vec = Wire(Vec(Parameters.WordSize, UInt(Parameters.ByteWidth))) + for (i <- 0 until Parameters.WordSize) { + write_data_vec(i) := io.bundle.write_data((i + 1) * Parameters.ByteBits - 1, i * Parameters.ByteBits) + } + mem.write((io.bundle.address >> 2.U).asUInt, write_data_vec, io.bundle.write_strobe) + } + io.bundle.read_data := mem.read((io.bundle.address >> 2.U).asUInt, true.B).asUInt + io.debug_read_data := mem.read((io.debug_read_address >> 2.U).asUInt, true.B).asUInt + io.instruction := mem.read((io.instruction_address >> 2.U).asUInt, true.B).asUInt +} \ No newline at end of file diff --git a/lab2/src/main/scala/peripheral/ROMLoader.scala b/lab2/src/main/scala/peripheral/ROMLoader.scala new file mode 100644 index 0000000..d3313e5 --- /dev/null +++ b/lab2/src/main/scala/peripheral/ROMLoader.scala @@ -0,0 +1,50 @@ +// 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 peripheral + +import chisel3._ +import riscv.Parameters + +class ROMLoader(capacity: Int) extends Module { + val io = IO(new Bundle { + val bundle = Flipped(new RAMBundle) + + val rom_address = Output(UInt(Parameters.AddrWidth)) + val rom_data = Input(UInt(Parameters.InstructionWidth)) + + val load_address = Input(UInt(Parameters.AddrWidth)) + val load_finished = Output(Bool()) + }) + + val address = RegInit(0.U(32.W)) + val valid = RegInit(false.B) + + io.bundle.write_strobe := VecInit(Seq.fill(Parameters.WordSize)(false.B)) + io.bundle.address := 0.U + io.bundle.write_data := 0.U + io.bundle.write_enable := false.B + when(address <= (capacity - 1).U) { + io.bundle.write_enable := true.B + io.bundle.write_data := io.rom_data + io.bundle.address := (address << 2.U).asUInt + io.load_address + io.bundle.write_strobe := VecInit(Seq.fill(Parameters.WordSize)(true.B)) + address := address + 1.U + when(address === (capacity - 1).U) { + valid := true.B + } + } + io.load_finished := valid + io.rom_address := address +} diff --git a/lab2/src/main/scala/peripheral/Timer.scala b/lab2/src/main/scala/peripheral/Timer.scala new file mode 100644 index 0000000..bca60cb --- /dev/null +++ b/lab2/src/main/scala/peripheral/Timer.scala @@ -0,0 +1,38 @@ +// 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 peripheral + +import chisel3._ +import chisel3.util._ +import riscv.Parameters + +class Timer extends Module { + val io = IO(new Bundle { + val bundle = new RAMBundle + val signal_interrupt = Output(Bool()) + + val debug_limit = Output(UInt(Parameters.DataWidth)) + val debug_enabled = Output(Bool()) + }) + + val count = RegInit(0.U(32.W)) + val limit = RegInit(100000000.U(32.W)) + io.debug_limit := limit + val enabled = RegInit(true.B) + io.debug_enabled := enabled + + //lab2(CLINTCSR) + //finish the read-write for count,limit,enabled. And produce appropriate signal_interrupt +} diff --git a/lab2/src/main/scala/peripheral/UART.scala b/lab2/src/main/scala/peripheral/UART.scala new file mode 100644 index 0000000..2d47c57 --- /dev/null +++ b/lab2/src/main/scala/peripheral/UART.scala @@ -0,0 +1,204 @@ +// 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 peripheral + +import chisel3._ +import chisel3.util._ + +class UartIO extends DecoupledIO(UInt(8.W)) { +} + + +/** + * Transmit part of the UART. + * A minimal version without any additional buffering. + * Use a ready/valid handshaking. + */ +class Tx(frequency: Int, baudRate: Int) extends Module { + val io = IO(new Bundle { + val txd = Output(UInt(1.W)) + val channel = Flipped(new UartIO()) + + }) + + val BIT_CNT = ((frequency + baudRate / 2) / baudRate - 1).U + + val shiftReg = RegInit(0x7ff.U) + val cntReg = RegInit(0.U(20.W)) + val bitsReg = RegInit(0.U(4.W)) + + io.channel.ready := (cntReg === 0.U) && (bitsReg === 0.U) + io.txd := shiftReg(0) + + when(cntReg === 0.U) { + + cntReg := BIT_CNT + when(bitsReg =/= 0.U) { + val shift = shiftReg >> 1 + shiftReg := Cat(1.U, shift(9, 0)) + bitsReg := bitsReg - 1.U + }.otherwise { + when(io.channel.valid) { + shiftReg := Cat(Cat(3.U, io.channel.bits), 0.U) // two stop bits, data, one start bit + bitsReg := 11.U + }.otherwise { + shiftReg := 0x7ff.U + } + } + + }.otherwise { + cntReg := cntReg - 1.U + } +} + +/** + * Receive part of the UART. + * A minimal version without any additional buffering. + * Use a ready/valid handshaking. + * + * The following code is inspired by Tommy's receive code at: + * https://github.com/tommythorn/yarvi + */ +class Rx(frequency: Int, baudRate: Int) extends Module { + val io = IO(new Bundle { + val rxd = Input(UInt(1.W)) + val channel = new UartIO() + + }) + + val BIT_CNT = ((frequency + baudRate / 2) / baudRate - 1).U + val START_CNT = ((3 * frequency / 2 + baudRate / 2) / baudRate - 1).U + + // Sync in the asynchronous RX data, reset to 1 to not start reading after a reset + val rxReg = RegNext(RegNext(io.rxd, 1.U), 1.U) + + val shiftReg = RegInit(0.U(8.W)) + val cntReg = RegInit(0.U(20.W)) + val bitsReg = RegInit(0.U(4.W)) + val valReg = RegInit(false.B) + + when(cntReg =/= 0.U) { + cntReg := cntReg - 1.U + }.elsewhen(bitsReg =/= 0.U) { + cntReg := BIT_CNT + shiftReg := Cat(rxReg, shiftReg >> 1) + bitsReg := bitsReg - 1.U + // the last shifted in + when(bitsReg === 1.U) { + valReg := true.B + } + }.elsewhen(rxReg === 0.U) { // wait 1.5 bits after falling edge of start + cntReg := START_CNT + bitsReg := 8.U + } + + when(valReg && io.channel.ready) { + valReg := false.B + } + + io.channel.bits := shiftReg + io.channel.valid := valReg +} + +/** + * A single byte buffer with a ready/valid interface + */ +class Buffer extends Module { + val io = IO(new Bundle { + val in = Flipped(new UartIO()) + val out = new UartIO() + }) + + val empty :: full :: Nil = Enum(2) + val stateReg = RegInit(empty) + val dataReg = RegInit(0.U(8.W)) + + io.in.ready := stateReg === empty + io.out.valid := stateReg === full + + when(stateReg === empty) { + when(io.in.valid) { + dataReg := io.in.bits + stateReg := full + } + }.otherwise { // full + when(io.out.ready) { + stateReg := empty + } + } + io.out.bits := dataReg +} + +/** + * A transmitter with a single buffer. + */ +class BufferedTx(frequency: Int, baudRate: Int) extends Module { + val io = IO(new Bundle { + val txd = Output(UInt(1.W)) + val channel = Flipped(new UartIO()) + + }) + val tx = Module(new Tx(frequency, baudRate)) + val buf = Module(new Buffer) + + buf.io.in <> io.channel + tx.io.channel <> buf.io.out + io.txd <> tx.io.txd +} + +class Uart(frequency: Int, baudRate: Int) extends Module { + val io = IO(new Bundle { + val bundle = new RAMBundle + val rxd = Input(UInt(1.W)) + val txd = Output(UInt(1.W)) + + val signal_interrupt = Output(Bool()) + }) + val interrupt = RegInit(false.B) + val rxData = RegInit(0.U) + + val tx = Module(new BufferedTx(frequency, baudRate)) + val rx = Module(new Rx(frequency, baudRate)) + + io.bundle.read_data := 0.U + when(io.bundle.address === 0x4.U) { + io.bundle.read_data := baudRate.U + }.elsewhen(io.bundle.address === 0xC.U) { + io.bundle.read_data := rxData + interrupt := false.B + } + + tx.io.channel.valid := false.B + tx.io.channel.bits := 0.U + when(io.bundle.write_enable) { + when(io.bundle.address === 0x8.U) { + interrupt := io.bundle.write_data =/= 0.U + }.elsewhen(io.bundle.address === 0x10.U) { + tx.io.channel.valid := true.B + tx.io.channel.bits := io.bundle.write_data + } + } + + io.txd := tx.io.txd + rx.io.rxd := io.rxd + + io.signal_interrupt := interrupt + rx.io.channel.ready := false.B + when(rx.io.channel.valid) { + rx.io.channel.ready := true.B + rxData := rx.io.channel.bits + interrupt := true.B + } +} diff --git a/lab2/src/main/scala/peripheral/VGADisplay.scala b/lab2/src/main/scala/peripheral/VGADisplay.scala new file mode 100644 index 0000000..268c38c --- /dev/null +++ b/lab2/src/main/scala/peripheral/VGADisplay.scala @@ -0,0 +1,116 @@ +// 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 peripheral + +import chisel3._ + + +class VGASync extends Module { + val io = IO(new Bundle { + val hsync = Output(Bool()) + val vsync = Output(Bool()) + val video_on = Output(Bool()) + val p_tick = Output(Bool()) + val f_tick = Output(Bool()) + val x = Output(UInt(10.W)) + val y = Output(UInt(10.W)) + }) + + val DisplayHorizontal = ScreenInfo.DisplayHorizontal + val DisplayVertical = ScreenInfo.DisplayVertical + + val BorderLeft = 48 + val BorderRight = 16 + val BorderTop = 10 + val BorderBottom = 33 + + val RetraceHorizontal = 96 + val RetraceVertical = 2 + + val MaxHorizontal = DisplayHorizontal + BorderLeft + BorderRight + RetraceHorizontal - 1 + val MaxVertical = DisplayVertical + BorderTop + BorderBottom + RetraceVertical - 1 + + val RetraceHorizontalStart = DisplayHorizontal + BorderRight + val RetraceHorizontalEnd = RetraceHorizontalStart + RetraceHorizontal - 1 + + val RetraceVerticalStart = DisplayVertical + BorderBottom + val RetraceVerticalEnd = RetraceVerticalStart + RetraceVertical - 1 + + val pixel = RegInit(UInt(2.W), 0.U) + val pixel_next = Wire(UInt(2.W)) + val pixel_tick = Wire(Bool()) + + val v_count_reg = RegInit(UInt(10.W), 0.U) + val h_count_reg = RegInit(UInt(10.W), 0.U) + + val v_count_next = Wire(UInt(10.W)) + val h_count_next = Wire(UInt(10.W)) + + val vsync_reg = RegInit(Bool(), false.B) + val hsync_reg = RegInit(Bool(), false.B) + + val vsync_next = Wire(Bool()) + val hsync_next = Wire(Bool()) + + pixel_next := pixel + 1.U + pixel_tick := pixel === 0.U + + h_count_next := Mux( + pixel_tick, + Mux(h_count_reg === MaxHorizontal.U, 0.U, h_count_reg + 1.U), + h_count_reg + ) + + v_count_next := Mux( + pixel_tick && h_count_reg === MaxHorizontal.U, + Mux(v_count_reg === MaxVertical.U, 0.U, v_count_reg + 1.U), + v_count_reg + ) + + hsync_next := h_count_reg >= RetraceHorizontalStart.U && h_count_reg <= RetraceHorizontalEnd.U + vsync_next := v_count_reg >= RetraceVerticalStart.U && v_count_reg <= RetraceVerticalEnd.U + + pixel := pixel_next + hsync_reg := hsync_next + vsync_reg := vsync_next + v_count_reg := v_count_next + h_count_reg := h_count_next + + io.video_on := h_count_reg < DisplayHorizontal.U && v_count_reg < DisplayVertical.U + io.hsync := hsync_reg + io.vsync := vsync_reg + io.x := h_count_reg + io.y := v_count_reg + io.p_tick := pixel_tick + io.f_tick := io.x === 0.U && io.y === 0.U +} + +class VGADisplay extends Module { + val io = IO(new Bundle() { + val x = Output(UInt(16.W)) + val y = Output(UInt(16.W)) + val video_on = Output(Bool()) + + val hsync = Output(Bool()) + val vsync = Output(Bool()) + }) + + val sync = Module(new VGASync) + io.hsync := sync.io.hsync + io.vsync := sync.io.vsync + io.x := sync.io.x + io.y := sync.io.y + io.video_on := sync.io.y +} diff --git a/lab2/src/main/scala/riscv/CPUBundle.scala b/lab2/src/main/scala/riscv/CPUBundle.scala new file mode 100644 index 0000000..0c36cc9 --- /dev/null +++ b/lab2/src/main/scala/riscv/CPUBundle.scala @@ -0,0 +1,31 @@ +// 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 chisel3._ +import peripheral.RAMBundle + +class CPUBundle extends Bundle { + val instruction_address = Output(UInt(Parameters.AddrWidth)) + val instruction = Input(UInt(Parameters.DataWidth)) + val instruction_valid = Input(Bool()) + val interrupt_flag = Input(UInt(Parameters.InterruptFlagWidth)) + val memory_bundle = Flipped(new RAMBundle) + val deviceSelect = Output(UInt(Parameters.SlaveDeviceCountBits.W)) + val regs_debug_read_address = Input(UInt(Parameters.PhysicalRegisterAddrWidth)) + val regs_debug_read_data = Output(UInt(Parameters.DataWidth)) + val csr_regs_debug_read_address = Input(UInt(Parameters.CSRRegisterAddrWidth)) + val csr_regs_debug_read_data = Output(UInt(Parameters.DataWidth)) +} diff --git a/lab2/src/main/scala/riscv/Parameters.scala b/lab2/src/main/scala/riscv/Parameters.scala new file mode 100644 index 0000000..b319498 --- /dev/null +++ b/lab2/src/main/scala/riscv/Parameters.scala @@ -0,0 +1,58 @@ +// 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 chisel3._ +import chisel3.util._ + +object ImplementationType { + val ThreeStage = 0 + val FiveStage = 1 +} + +object Parameters { + val AddrBits = 32 + val AddrWidth = AddrBits.W + + val InstructionBits = 32 + val InstructionWidth = InstructionBits.W + val DataBits = 32 + val DataWidth = DataBits.W + val ByteBits = 8 + val ByteWidth = ByteBits.W + val WordSize = Math.ceil(DataBits / ByteBits).toInt + + val PhysicalRegisters = 32 + val PhysicalRegisterAddrBits = log2Up(PhysicalRegisters) + val PhysicalRegisterAddrWidth = PhysicalRegisterAddrBits.W + + val CSRRegisterAddrBits = 12 + val CSRRegisterAddrWidth = CSRRegisterAddrBits.W + + val InterruptFlagBits = 32 + val InterruptFlagWidth = InterruptFlagBits.W + + val HoldStateBits = 3 + val StallStateWidth = HoldStateBits.W + + val MemorySizeInBytes = 32768 + val MemorySizeInWords = MemorySizeInBytes / 4 + + val EntryAddress = 0x1000.U(Parameters.AddrWidth) + + val MasterDeviceCount = 1 + val SlaveDeviceCount = 8 + val SlaveDeviceCountBits = log2Up(Parameters.SlaveDeviceCount) +} diff --git a/lab2/src/main/scala/riscv/core/ALU.scala b/lab2/src/main/scala/riscv/core/ALU.scala new file mode 100644 index 0000000..a92869e --- /dev/null +++ b/lab2/src/main/scala/riscv/core/ALU.scala @@ -0,0 +1,70 @@ +// 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.core + +import chisel3._ +import chisel3.experimental.ChiselEnum +import chisel3.util._ +import riscv.Parameters + +object ALUFunctions extends ChiselEnum { + val zero, add, sub, sll, slt, xor, or, and, srl, sra, sltu = Value +} + +class ALU extends Module { + val io = IO(new Bundle { + val func = Input(ALUFunctions()) + + val op1 = Input(UInt(Parameters.DataWidth)) + val op2 = Input(UInt(Parameters.DataWidth)) + + val result = Output(UInt(Parameters.DataWidth)) + }) + + io.result := 0.U + switch(io.func) { + is(ALUFunctions.add) { + io.result := io.op1 + io.op2 + } + is(ALUFunctions.sub) { + io.result := io.op1 - io.op2 + } + is(ALUFunctions.sll) { + io.result := io.op1 << io.op2(4, 0) + } + is(ALUFunctions.slt) { + io.result := io.op1.asSInt < io.op2.asSInt + } + is(ALUFunctions.xor) { + io.result := io.op1 ^ io.op2 + } + is(ALUFunctions.or) { + io.result := io.op1 | io.op2 + } + is(ALUFunctions.and) { + io.result := io.op1 & io.op2 + } + is(ALUFunctions.srl) { + io.result := io.op1 >> io.op2(4, 0) + } + is(ALUFunctions.sra) { + io.result := (io.op1.asSInt >> io.op2(4, 0)).asUInt + } + is(ALUFunctions.sltu) { + io.result := io.op1 < io.op2 + } + } + +} diff --git a/lab2/src/main/scala/riscv/core/ALUControl.scala b/lab2/src/main/scala/riscv/core/ALUControl.scala new file mode 100644 index 0000000..ac273f5 --- /dev/null +++ b/lab2/src/main/scala/riscv/core/ALUControl.scala @@ -0,0 +1,86 @@ +// 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.core + +import chisel3._ +import chisel3.util._ + +class ALUControl extends Module { + val io = IO(new Bundle { + val opcode = Input(UInt(7.W)) + val funct3 = Input(UInt(3.W)) + val funct7 = Input(UInt(7.W)) + + val alu_funct = Output(ALUFunctions()) + }) + + io.alu_funct := ALUFunctions.zero + + switch(io.opcode) { + is(InstructionTypes.I) { + io.alu_funct := MuxLookup( + io.funct3, + ALUFunctions.zero, + IndexedSeq( + InstructionsTypeI.addi -> ALUFunctions.add, + InstructionsTypeI.slli -> ALUFunctions.sll, + InstructionsTypeI.slti -> ALUFunctions.slt, + InstructionsTypeI.sltiu -> ALUFunctions.sltu, + InstructionsTypeI.xori -> ALUFunctions.xor, + InstructionsTypeI.ori -> ALUFunctions.or, + InstructionsTypeI.andi -> ALUFunctions.and, + InstructionsTypeI.sri -> Mux(io.funct7(5), ALUFunctions.sra, ALUFunctions.srl) + ), + ) + } + is(InstructionTypes.RM) { + io.alu_funct := MuxLookup( + io.funct3, + ALUFunctions.zero, + IndexedSeq( + InstructionsTypeR.add_sub -> Mux(io.funct7(5), ALUFunctions.sub, ALUFunctions.add), + InstructionsTypeR.sll -> ALUFunctions.sll, + InstructionsTypeR.slt -> ALUFunctions.slt, + InstructionsTypeR.sltu -> ALUFunctions.sltu, + InstructionsTypeR.xor -> ALUFunctions.xor, + InstructionsTypeR.or -> ALUFunctions.or, + InstructionsTypeR.and -> ALUFunctions.and, + InstructionsTypeR.sr -> Mux(io.funct7(5), ALUFunctions.sra, ALUFunctions.srl) + ), + ) + } + is(InstructionTypes.B) { + io.alu_funct := ALUFunctions.add + } + is(InstructionTypes.L) { + io.alu_funct := ALUFunctions.add + } + is(InstructionTypes.S) { + io.alu_funct := ALUFunctions.add + } + is(Instructions.jal) { + io.alu_funct := ALUFunctions.add + } + is(Instructions.jalr) { + io.alu_funct := ALUFunctions.add + } + is(Instructions.lui) { + io.alu_funct := ALUFunctions.add + } + is(Instructions.auipc) { + io.alu_funct := ALUFunctions.add + } + } +} diff --git a/lab2/src/main/scala/riscv/core/CLINT.scala b/lab2/src/main/scala/riscv/core/CLINT.scala new file mode 100644 index 0000000..183fd0b --- /dev/null +++ b/lab2/src/main/scala/riscv/core/CLINT.scala @@ -0,0 +1,107 @@ +// 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.core + +import chisel3._ +import chisel3.util.MuxLookup +import riscv.Parameters + +object InterruptStatus { + val None = 0x0.U(8.W) + val Timer0 = 0x1.U(8.W) + val Ret = 0xFF.U(8.W) +} + +object InterruptEntry { + val Timer0 = 0x4.U(8.W) +} + +object InterruptState { + val Idle = 0x0.U + val SyncAssert = 0x1.U + val AsyncAssert = 0x2.U + val MRET = 0x3.U +} + +object CSRState { + val Idle = 0x0.U + val Traping = 0x1.U + val Mret = 0x2.U +} + +class CSRDirectAccessBundle extends Bundle { + val mstatus = Input(UInt(Parameters.DataWidth)) + val mepc = Input(UInt(Parameters.DataWidth)) + val mcause = Input(UInt(Parameters.DataWidth)) + val mtvec = Input(UInt(Parameters.DataWidth)) + + val mstatus_write_data= Output(UInt(Parameters.DataWidth)) + val mepc_write_data= Output(UInt(Parameters.DataWidth)) + val mcause_write_data= Output(UInt(Parameters.DataWidth)) + + val direct_write_enable = Output(Bool()) +} + +// Core Local Interrupt Controller +class CLINT extends Module { + val io = IO(new Bundle { + // Interrupt signals from peripherals + val interrupt_flag = Input(UInt(Parameters.InterruptFlagWidth)) + + val instruction = Input(UInt(Parameters.InstructionWidth)) + val instruction_address = Input(UInt(Parameters.AddrWidth)) + + val jump_flag = Input(Bool()) + val jump_address = Input(UInt(Parameters.AddrWidth)) + + val interrupt_handler_address = Output(UInt(Parameters.AddrWidth)) + val interrupt_assert = Output(Bool()) + + val csr_bundle = new CSRDirectAccessBundle + }) + val interrupt_enable = io.csr_bundle.mstatus(3) + val instruction_address = Mux( + io.jump_flag, + io.jump_address, + io.instruction_address + 4.U, + ) + //lab2(CLINTCSR) + /* + val interrupt_enable = + + when(io.interrupt_flag =/= InterruptStatus.None && interrupt_enable) { + io.csr_bundle.mstatus_write_data := + io.csr_bundle.mepc_write_data := + io.csr_bundle.mcause_write_data := + io.csr_bundle.direct_write_enable := + io.interrupt_assert := + io.interrupt_handler_address := + }.elsewhen(io.instruction === InstructionsRet.mret) { + io.csr_bundle.mstatus_write_data := + io.csr_bundle.mepc_write_data := + io.csr_bundle.mcause_write_data := + io.csr_bundle.direct_write_enable := + io.interrupt_assert := + io.interrupt_handler_address := + }.otherwise { + io.csr_bundle.mstatus_write_data := + io.csr_bundle.mepc_write_data := + io.csr_bundle.mcause_write_data := + io.csr_bundle.direct_write_enable := + io.interrupt_assert := + io.interrupt_handler_address := + } + */ +} diff --git a/lab2/src/main/scala/riscv/core/CPU.scala b/lab2/src/main/scala/riscv/core/CPU.scala new file mode 100644 index 0000000..57eaeb4 --- /dev/null +++ b/lab2/src/main/scala/riscv/core/CPU.scala @@ -0,0 +1,96 @@ +// 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.core + +import chisel3._ +import chisel3.util.Cat +import riscv.{CPUBundle, Parameters} + +class CPU extends Module { + val io = IO(new CPUBundle) + + val regs = Module(new RegisterFile) + val inst_fetch = Module(new InstructionFetch) + val id = Module(new InstructionDecode) + val ex = Module(new Execute) + val mem = Module(new MemoryAccess) + val wb = Module(new WriteBack) + val csr_regs = Module(new CSR) + val clint = Module(new CLINT) + + io.regs_debug_read_data := regs.io.debug_read_data + io.csr_regs_debug_read_data := csr_regs.io.debug_reg_read_data + regs.io.debug_read_address := io.regs_debug_read_address + csr_regs.io.debug_reg_read_address := io.csr_regs_debug_read_address + + io.deviceSelect := mem.io.memory_bundle.address(Parameters.AddrBits - 1, Parameters.AddrBits - Parameters.SlaveDeviceCountBits) + + inst_fetch.io.jump_address_id := ex.io.if_jump_address + inst_fetch.io.jump_flag_id := ex.io.if_jump_flag + inst_fetch.io.interrupt_assert := clint.io.interrupt_assert + inst_fetch.io.interrupt_handler_address := clint.io.interrupt_handler_address + inst_fetch.io.instruction_valid := io.instruction_valid + inst_fetch.io.instruction_read_data := io.instruction + io.instruction_address := inst_fetch.io.instruction_address + + regs.io.write_enable := id.io.reg_write_enable + regs.io.write_address := id.io.reg_write_address + regs.io.write_data := wb.io.regs_write_data + regs.io.read_address1 := id.io.regs_reg1_read_address + regs.io.read_address2 := id.io.regs_reg2_read_address + + + id.io.instruction := inst_fetch.io.instruction + + csr_regs.io.clint_access_bundle <> clint.io.csr_bundle + csr_regs.io.reg_read_address_id := id.io.csr_reg_address + csr_regs.io.reg_write_data_ex := ex.io.csr_reg_write_data + csr_regs.io.reg_write_address_id := id.io.csr_reg_address + csr_regs.io.reg_write_enable_id := id.io.csr_reg_write_enable + + ex.io.instruction := inst_fetch.io.instruction + ex.io.instruction_address := inst_fetch.io.instruction_address + ex.io.reg1_data := regs.io.read_data1 + ex.io.reg2_data := regs.io.read_data2 + ex.io.immediate := id.io.ex_immediate + ex.io.aluop1_source := id.io.ex_aluop1_source + ex.io.aluop2_source := id.io.ex_aluop2_source + ex.io.csr_reg_read_data := csr_regs.io.reg_read_data + + mem.io.alu_result := ex.io.mem_alu_result + mem.io.reg2_data := regs.io.read_data2 + mem.io.memory_read_enable := id.io.memory_read_enable + mem.io.memory_write_enable := id.io.memory_write_enable + mem.io.funct3 := inst_fetch.io.instruction(14, 12) + + io.memory_bundle.address := Cat(0.U(Parameters.SlaveDeviceCountBits.W),mem.io.memory_bundle.address(Parameters.AddrBits - 1 - Parameters.SlaveDeviceCountBits, 0)) + io.memory_bundle.write_enable := mem.io.memory_bundle.write_enable + io.memory_bundle.write_data := mem.io.memory_bundle.write_data + io.memory_bundle.write_strobe := mem.io.memory_bundle.write_strobe + mem.io.memory_bundle.read_data := io.memory_bundle.read_data + + wb.io.instruction_address := inst_fetch.io.instruction_address + wb.io.alu_result := ex.io.mem_alu_result + wb.io.memory_read_data := mem.io.wb_memory_read_data + wb.io.regs_write_source := id.io.wb_reg_write_source + wb.io.csr_read_data := csr_regs.io.reg_read_data + + clint.io.instruction := inst_fetch.io.instruction + clint.io.instruction_address := inst_fetch.io.instruction_address + clint.io.interrupt_flag := io.interrupt_flag + clint.io.jump_flag := ex.io.if_jump_flag + clint.io.jump_address := ex.io.if_jump_address + +} diff --git a/lab2/src/main/scala/riscv/core/CSR.scala b/lab2/src/main/scala/riscv/core/CSR.scala new file mode 100644 index 0000000..8533b4c --- /dev/null +++ b/lab2/src/main/scala/riscv/core/CSR.scala @@ -0,0 +1,107 @@ +// 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.core + +import chisel3._ +import chisel3.util._ +import riscv.Parameters + + +object CSRRegister { + // Refer to Spec. Vol.II Page 8-10 + val MSTATUS = 0x300.U(Parameters.CSRRegisterAddrWidth) + val MIE = 0x304.U(Parameters.CSRRegisterAddrWidth) + val MTVEC = 0x305.U(Parameters.CSRRegisterAddrWidth) + val MSCRATCH = 0x340.U(Parameters.CSRRegisterAddrWidth) + val MEPC = 0x341.U(Parameters.CSRRegisterAddrWidth) + val MCAUSE = 0x342.U(Parameters.CSRRegisterAddrWidth) + val CycleL = 0xc00.U(Parameters.CSRRegisterAddrWidth) + val CycleH = 0xc80.U(Parameters.CSRRegisterAddrWidth) +} + +class CSR extends Module { + val io = IO(new Bundle { + val reg_read_address_id = Input(UInt(Parameters.CSRRegisterAddrWidth)) + val reg_write_enable_id= Input(Bool()) + val reg_write_address_id = Input(UInt(Parameters.CSRRegisterAddrWidth)) + val reg_write_data_ex= Input(UInt(Parameters.DataWidth)) + val debug_reg_read_address = Input(UInt(Parameters.CSRRegisterAddrWidth)) + + val debug_reg_read_data = Output(UInt(Parameters.DataWidth)) + val reg_read_data = Output(UInt(Parameters.DataWidth)) + + val clint_access_bundle = Flipped(new CSRDirectAccessBundle) + }) + + val mstatus = RegInit(UInt(Parameters.DataWidth), 0.U) + val mie = RegInit(UInt(Parameters.DataWidth), 0.U) + val mtvec = RegInit(UInt(Parameters.DataWidth), 0.U) + val mscratch = RegInit(UInt(Parameters.DataWidth), 0.U) + val mepc = RegInit(UInt(Parameters.DataWidth), 0.U) + val mcause = RegInit(UInt(Parameters.DataWidth), 0.U) + val cycles = RegInit(UInt(64.W), 0.U) + val regLUT = + IndexedSeq( + CSRRegister.MSTATUS -> mstatus, + CSRRegister.MIE -> mie, + CSRRegister.MTVEC -> mtvec, + CSRRegister.MSCRATCH -> mscratch, + CSRRegister.MEPC -> mepc, + CSRRegister.MCAUSE -> mcause, + CSRRegister.CycleL -> cycles(31, 0), + CSRRegister.CycleH -> cycles(63, 32), + ) + cycles := cycles + 1.U + + // If the pipeline and the CLINT are going to read and write the CSR at the same time, let the pipeline write first. + // This is implemented in a single cycle by passing reg_write_data_ex to clint and writing the data from the CLINT to the CSR. + io.reg_read_data := MuxLookup(io.reg_read_address_id, 0.U, regLUT) + io.debug_reg_read_data := MuxLookup(io.debug_reg_read_address, 0.U,regLUT) + + //lab2(CLINTCSR) + //what data should be passed from csr to clint (Note: what should clint see is the next state of the CPU) + /* + io.clint_access_bundle.mstatus := + io.clint_access_bundle.mtvec := + io.clint_access_bundle.mcause := + io.clint_access_bundle.mepc := + */ + + when(io.clint_access_bundle.direct_write_enable) { + mstatus := io.clint_access_bundle.mstatus_write_data + mepc := io.clint_access_bundle.mepc_write_data + mcause := io.clint_access_bundle.mcause_write_data + }.elsewhen(io.reg_write_enable_id) { + when(io.reg_write_address_id === CSRRegister.MSTATUS) { + mstatus := io.reg_write_data_ex + }.elsewhen(io.reg_write_address_id === CSRRegister.MEPC) { + mepc := io.reg_write_data_ex + }.elsewhen(io.reg_write_address_id === CSRRegister.MCAUSE) { + mcause := io.reg_write_data_ex + } + } + + when(io.reg_write_enable_id) { + when(io.reg_write_address_id === CSRRegister.MIE) { + mie := io.reg_write_data_ex + }.elsewhen(io.reg_write_address_id === CSRRegister.MTVEC){ + mtvec := io.reg_write_data_ex + }.elsewhen(io.reg_write_address_id === CSRRegister.MSCRATCH) { + mscratch := io.reg_write_data_ex + } + } + + +} diff --git a/lab2/src/main/scala/riscv/core/Execute.scala b/lab2/src/main/scala/riscv/core/Execute.scala new file mode 100644 index 0000000..702bb14 --- /dev/null +++ b/lab2/src/main/scala/riscv/core/Execute.scala @@ -0,0 +1,79 @@ +// 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.core + +import chisel3._ +import chisel3.util.{Cat, MuxLookup} +import riscv.Parameters + +class Execute extends Module { + val io = IO(new Bundle { + val instruction = Input(UInt(Parameters.InstructionWidth)) + val instruction_address = Input(UInt(Parameters.AddrWidth)) + val reg1_data = Input(UInt(Parameters.DataWidth)) + val reg2_data = Input(UInt(Parameters.DataWidth)) + val immediate = Input(UInt(Parameters.DataWidth)) + val aluop1_source = Input(UInt(1.W)) + val aluop2_source = Input(UInt(1.W)) + val csr_reg_read_data = Input(UInt(Parameters.DataWidth)) + + val mem_alu_result = Output(UInt(Parameters.DataWidth)) + val csr_reg_write_data = Output(UInt(Parameters.DataWidth)) + val if_jump_flag = Output(Bool()) + val if_jump_address = Output(UInt(Parameters.DataWidth)) + }) + + val opcode = io.instruction(6, 0) + val funct3 = io.instruction(14, 12) + val funct7 = io.instruction(31, 25) + + val alu = Module(new ALU) + val alu_ctrl = Module(new ALUControl) + + alu_ctrl.io.opcode := opcode + alu_ctrl.io.funct3 := funct3 + alu_ctrl.io.funct7 := funct7 + alu.io.func := alu_ctrl.io.alu_funct + alu.io.op1 := Mux( + io.aluop1_source === ALUOp1Source.InstructionAddress, + io.instruction_address, + io.reg1_data, + ) + alu.io.op2 := Mux( + io.aluop2_source === ALUOp2Source.Immediate, + io.immediate, + io.reg2_data, + ) + io.if_jump_flag := opcode === Instructions.jal || + (opcode === Instructions.jalr) || + (opcode === InstructionTypes.B) && MuxLookup( + funct3, + false.B, + IndexedSeq( + InstructionsTypeB.beq -> (io.reg1_data === io.reg2_data), + InstructionsTypeB.bne -> (io.reg1_data =/= io.reg2_data), + InstructionsTypeB.blt -> (io.reg1_data.asSInt < io.reg2_data.asSInt), + InstructionsTypeB.bge -> (io.reg1_data.asSInt >= io.reg2_data.asSInt), + InstructionsTypeB.bltu -> (io.reg1_data.asUInt < io.reg2_data.asUInt), + InstructionsTypeB.bgeu -> (io.reg1_data.asUInt >= io.reg2_data.asUInt) + ) + ) + io.if_jump_address := io.immediate + Mux(opcode === Instructions.jalr, io.reg1_data, io.instruction_address) + io.mem_alu_result := alu.io.result + // lab2(CLINTCSR) + /* + io.csr_reg_write_data := + */ +} diff --git a/lab2/src/main/scala/riscv/core/InstructionDecode.scala b/lab2/src/main/scala/riscv/core/InstructionDecode.scala new file mode 100644 index 0000000..a5d1efe --- /dev/null +++ b/lab2/src/main/scala/riscv/core/InstructionDecode.scala @@ -0,0 +1,208 @@ +// 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.core + +import chisel3._ +import chisel3.util._ +import riscv.Parameters + +object InstructionTypes { + val L = "b0000011".U + val I = "b0010011".U + val S = "b0100011".U + val RM = "b0110011".U + val B = "b1100011".U +} + +object Instructions { + val lui = "b0110111".U + val nop = "b0000001".U + val jal = "b1101111".U + val jalr = "b1100111".U + val auipc = "b0010111".U + val csr = "b1110011".U + val fence = "b0001111".U +} + +object InstructionsTypeL { + val lb = "b000".U + val lh = "b001".U + val lw = "b010".U + val lbu = "b100".U + val lhu = "b101".U +} + +object InstructionsTypeI { + val addi = 0.U + val slli = 1.U + val slti = 2.U + val sltiu = 3.U + val xori = 4.U + val sri = 5.U + val ori = 6.U + val andi = 7.U +} + +object InstructionsTypeS { + val sb = "b000".U + val sh = "b001".U + val sw = "b010".U +} + +object InstructionsTypeR { + val add_sub = 0.U + val sll = 1.U + val slt = 2.U + val sltu = 3.U + val xor = 4.U + val sr = 5.U + val or = 6.U + val and = 7.U +} + +object InstructionsTypeM { + val mul = 0.U + val mulh = 1.U + val mulhsu = 2.U + val mulhum = 3.U + val div = 4.U + val divu = 5.U + val rem = 6.U + val remu = 7.U +} + +object InstructionsTypeB { + val beq = "b000".U + val bne = "b001".U + val blt = "b100".U + val bge = "b101".U + val bltu = "b110".U + val bgeu = "b111".U +} + +object InstructionsTypeCSR { + val csrrw = "b001".U + val csrrs = "b010".U + val csrrc = "b011".U + val csrrwi = "b101".U + val csrrsi = "b110".U + val csrrci = "b111".U +} + +object InstructionsNop { + val nop = 0x00000013L.U(Parameters.DataWidth) +} + +object InstructionsRet { + val mret = 0x30200073L.U(Parameters.DataWidth) + val ret = 0x00008067L.U(Parameters.DataWidth) +} + +object InstructionsEnv { + val ecall = 0x00000073L.U(Parameters.DataWidth) + val ebreak = 0x00100073L.U(Parameters.DataWidth) +} + +object ALUOp1Source { + val Register = 0.U(1.W) + val InstructionAddress = 1.U(1.W) +} + +object ALUOp2Source { + val Register = 0.U(1.W) + val Immediate = 1.U(1.W) +} + +object RegWriteSource { + val ALUResult = 0.U(2.W) + val Memory = 1.U(2.W) + val CSR = 2.U(2.W) + val NextInstructionAddress = 3.U(2.W) +} + +class InstructionDecode extends Module { + val io = IO(new Bundle { + val instruction = Input(UInt(Parameters.InstructionWidth)) + + val regs_reg1_read_address = Output(UInt(Parameters.PhysicalRegisterAddrWidth)) + val regs_reg2_read_address = Output(UInt(Parameters.PhysicalRegisterAddrWidth)) + val ex_immediate = Output(UInt(Parameters.DataWidth)) + val ex_aluop1_source = Output(UInt(1.W)) + val ex_aluop2_source = Output(UInt(1.W)) + val memory_read_enable = Output(Bool()) + val memory_write_enable = Output(Bool()) + val wb_reg_write_source = Output(UInt(2.W)) + val reg_write_enable = Output(Bool()) + val reg_write_address = Output(UInt(Parameters.PhysicalRegisterAddrWidth)) + val csr_reg_write_enable = Output(Bool()) + val csr_reg_address = Output(UInt(Parameters.DataWidth)) + }) + val opcode = io.instruction(6, 0) + val funct3 = io.instruction(14, 12) + val funct7 = io.instruction(31, 25) + val rd = io.instruction(11, 7) + val rs1 = io.instruction(19, 15) + val rs2 = io.instruction(24, 20) + + io.regs_reg1_read_address := Mux(opcode === Instructions.lui, 0.U(Parameters.PhysicalRegisterAddrWidth), rs1) + io.regs_reg2_read_address := rs2 + val immediate = MuxLookup( + opcode, + Cat(Fill(20, io.instruction(31)), io.instruction(31, 20)), + IndexedSeq( + InstructionTypes.I -> Cat(Fill(21, io.instruction(31)), io.instruction(30, 20)), + InstructionTypes.L -> Cat(Fill(21, io.instruction(31)), io.instruction(30, 20)), + Instructions.jalr -> Cat(Fill(21, io.instruction(31)), io.instruction(30, 20)), + InstructionTypes.S -> Cat(Fill(21, io.instruction(31)), io.instruction(30, 25), io.instruction(11, 7)), + InstructionTypes.B -> Cat(Fill(20, io.instruction(31)), io.instruction(7), io.instruction(30, 25), io.instruction(11, 8), 0.U(1.W)), + Instructions.lui -> Cat(io.instruction(31, 12), 0.U(12.W)), + Instructions.auipc -> Cat(io.instruction(31, 12), 0.U(12.W)), + Instructions.jal -> Cat(Fill(12, io.instruction(31)), io.instruction(19, 12), io.instruction(20), io.instruction(30, 21), 0.U(1.W)) + ) + ) + io.ex_immediate := immediate + io.ex_aluop1_source := Mux( + opcode === Instructions.auipc || opcode === InstructionTypes.B || opcode === Instructions.jal, + ALUOp1Source.InstructionAddress, + ALUOp1Source.Register + ) + io.ex_aluop2_source := Mux( + opcode === InstructionTypes.RM, + ALUOp2Source.Register, + ALUOp2Source.Immediate + ) + io.memory_read_enable := opcode === InstructionTypes.L + io.memory_write_enable := opcode === InstructionTypes.S + io.wb_reg_write_source := MuxLookup( + opcode, + RegWriteSource.ALUResult, + IndexedSeq( + InstructionTypes.L -> RegWriteSource.Memory, + Instructions.jal -> RegWriteSource.NextInstructionAddress, + Instructions.jalr -> RegWriteSource.NextInstructionAddress, + Instructions.csr -> RegWriteSource.CSR + ) + ) + io.reg_write_enable := (opcode === InstructionTypes.RM) || (opcode === InstructionTypes.I) || + (opcode === InstructionTypes.L) || (opcode === Instructions.auipc) || (opcode === Instructions.lui) || + (opcode === Instructions.jal) || (opcode === Instructions.jalr) || (opcode === Instructions.csr) + io.reg_write_address := io.instruction(11, 7) + io.csr_reg_address := io.instruction(31,20) + io.csr_reg_write_enable := (opcode === Instructions.csr) && ( + funct3 === InstructionsTypeCSR.csrrw || funct3 === InstructionsTypeCSR.csrrwi || + funct3 === InstructionsTypeCSR.csrrs || funct3 === InstructionsTypeCSR.csrrsi || + funct3 === InstructionsTypeCSR.csrrc || funct3 === InstructionsTypeCSR.csrrci + ) +} diff --git a/lab2/src/main/scala/riscv/core/InstructionFetch.scala b/lab2/src/main/scala/riscv/core/InstructionFetch.scala new file mode 100644 index 0000000..9cecb67 --- /dev/null +++ b/lab2/src/main/scala/riscv/core/InstructionFetch.scala @@ -0,0 +1,53 @@ +// 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.core + +import chisel3._ +import riscv.Parameters + +object ProgramCounter { + val EntryAddress = Parameters.EntryAddress +} + +class InstructionFetch extends Module { + val io = IO(new Bundle { + val jump_flag_id = Input(Bool()) + val jump_address_id = Input(UInt(Parameters.AddrWidth)) + val instruction_read_data = Input(UInt(Parameters.DataWidth)) + val interrupt_assert = Input(Bool()) + val interrupt_handler_address = Input(UInt(Parameters.AddrWidth)) + val instruction_valid = Input(Bool()) + + val instruction_address = Output(UInt(Parameters.AddrWidth)) + val instruction = Output(UInt(Parameters.InstructionWidth)) + + }) + val pc = RegInit(ProgramCounter.EntryAddress) + + when(io.instruction_valid) { + when(io.interrupt_assert){ + pc := io.interrupt_handler_address + }.elsewhen(io.jump_flag_id){ + pc := io.jump_address_id + }.otherwise { + pc := pc + 4.U + } + io.instruction := io.instruction_read_data + }.otherwise{ + pc := pc + io.instruction := 0x00000013.U + } + io.instruction_address := pc +} diff --git a/lab2/src/main/scala/riscv/core/MemoryAccess.scala b/lab2/src/main/scala/riscv/core/MemoryAccess.scala new file mode 100644 index 0000000..b54444d --- /dev/null +++ b/lab2/src/main/scala/riscv/core/MemoryAccess.scala @@ -0,0 +1,105 @@ +// Copyright 2022 Canbin Huang +// +// 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.core + +import chisel3._ +import chisel3.util._ +import peripheral.RAMBundle +import riscv.Parameters + +class MemoryAccess extends Module { + val io = IO(new Bundle() { + val alu_result = Input(UInt(Parameters.DataWidth)) + val reg2_data = Input(UInt(Parameters.DataWidth)) + val memory_read_enable = Input(Bool()) + val memory_write_enable = Input(Bool()) + val funct3 = Input(UInt(3.W)) + + val wb_memory_read_data = Output(UInt(Parameters.DataWidth)) + + val memory_bundle = Flipped(new RAMBundle) + }) + val mem_address_index = io.alu_result(log2Up(Parameters.WordSize) - 1, 0).asUInt + + io.memory_bundle.write_enable := false.B + io.memory_bundle.write_data := 0.U + io.memory_bundle.address := io.alu_result + io.memory_bundle.write_strobe := VecInit(Seq.fill(Parameters.WordSize)(false.B)) + io.wb_memory_read_data := 0.U + + when(io.memory_read_enable) { + val data = io.memory_bundle.read_data + io.wb_memory_read_data := MuxLookup( + io.funct3, + 0.U, + IndexedSeq( + InstructionsTypeL.lb -> MuxLookup( + mem_address_index, + Cat(Fill(24, data(31)), data(31, 24)), + IndexedSeq( + 0.U -> Cat(Fill(24, data(7)), data(7, 0)), + 1.U -> Cat(Fill(24, data(15)), data(15, 8)), + 2.U -> Cat(Fill(24, data(23)), data(23, 16)) + ) + ), + InstructionsTypeL.lbu -> MuxLookup( + mem_address_index, + Cat(Fill(24, 0.U), data(31, 24)), + IndexedSeq( + 0.U -> Cat(Fill(24, 0.U), data(7, 0)), + 1.U -> Cat(Fill(24, 0.U), data(15, 8)), + 2.U -> Cat(Fill(24, 0.U), data(23, 16)) + ) + ), + InstructionsTypeL.lh -> Mux( + mem_address_index === 0.U, + Cat(Fill(16, data(15)), data(15, 0)), + Cat(Fill(16, data(31)), data(31, 16)) + ), + InstructionsTypeL.lhu -> Mux( + mem_address_index === 0.U, + Cat(Fill(16, 0.U), data(15, 0)), + Cat(Fill(16, 0.U), data(31, 16)) + ), + InstructionsTypeL.lw -> data + ) + ) + }.elsewhen(io.memory_write_enable) { + io.memory_bundle.write_data := io.reg2_data + io.memory_bundle.write_enable := true.B + io.memory_bundle.write_strobe := VecInit(Seq.fill(Parameters.WordSize)(false.B)) + when(io.funct3 === InstructionsTypeS.sb) { + io.memory_bundle.write_strobe(mem_address_index) := true.B + io.memory_bundle.write_data := io.reg2_data(Parameters.ByteBits, 0) << (mem_address_index << log2Up(Parameters.ByteBits).U) + }.elsewhen(io.funct3 === InstructionsTypeS.sh) { + when(mem_address_index === 0.U) { + for (i <- 0 until Parameters.WordSize / 2) { + io.memory_bundle.write_strobe(i) := true.B + } + io.memory_bundle.write_data := io.reg2_data(Parameters.WordSize / 2 * Parameters.ByteBits, 0) + }.otherwise { + for (i <- Parameters.WordSize / 2 until Parameters.WordSize) { + io.memory_bundle.write_strobe(i) := true.B + } + io.memory_bundle.write_data := io.reg2_data(Parameters.WordSize / 2 * Parameters.ByteBits, 0) << (Parameters + .WordSize / 2 * Parameters.ByteBits) + } + }.elsewhen(io.funct3 === InstructionsTypeS.sw) { + for (i <- 0 until Parameters.WordSize) { + io.memory_bundle.write_strobe(i) := true.B + } + } + } +} diff --git a/lab2/src/main/scala/riscv/core/RegisterFile.scala b/lab2/src/main/scala/riscv/core/RegisterFile.scala new file mode 100644 index 0000000..9eb90c0 --- /dev/null +++ b/lab2/src/main/scala/riscv/core/RegisterFile.scala @@ -0,0 +1,95 @@ +// 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.core + +import chisel3._ +import chisel3.util._ +import riscv.Parameters + +object Registers extends Enumeration { + type Register = Value + val zero, + ra, sp, gp, tp, + t0, t1, t2, fp, + s1, + a0, a1, a2, a3, a4, a5, a6, a7, + s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, + t3, t4, t5, t6 = Value +} + +class RegisterFile extends Module { + val io = IO(new Bundle { + val write_enable = Input(Bool()) + val write_address = Input(UInt(Parameters.PhysicalRegisterAddrWidth)) + val write_data = Input(UInt(Parameters.DataWidth)) + + val read_address1 = Input(UInt(Parameters.PhysicalRegisterAddrWidth)) + val read_address2 = Input(UInt(Parameters.PhysicalRegisterAddrWidth)) + val read_data1 = Output(UInt(Parameters.DataWidth)) + val read_data2 = Output(UInt(Parameters.DataWidth)) + + val debug_read_address = Input(UInt(Parameters.PhysicalRegisterAddrWidth)) + val debug_read_data = Output(UInt(Parameters.DataWidth)) + }) + val registers = RegInit(VecInit(Seq.fill(Parameters.PhysicalRegisters)(0.U(Parameters.DataWidth)))) + + when(!reset.asBool) { + when(io.write_enable && io.write_address =/= 0.U) { + registers(io.write_address) := io.write_data + } + } + + io.read_data1 := Mux( + io.read_address1 === 0.U, + 0.U, + registers(io.read_address1) + ) + + io.read_data2 := Mux( + io.read_address2 === 0.U, + 0.U, + registers(io.read_address2) + ) + + io.debug_read_data := Mux( + io.debug_read_address === 0.U, + 0.U, + registers(io.debug_read_address) + ) +// io.read_data1 := MuxCase( +// registers(io.read_address1), +// IndexedSeq( +// (io.read_address1 === 0.U) -> 0.U, +// (io.read_address1 === io.write_address && io.write_enable) -> io.write_data +// ) +// ) +// +// io.read_data2 := MuxCase( +// registers(io.read_address2), +// IndexedSeq( +// (io.read_address2 === 0.U) -> 0.U, +// (io.read_address2 === io.write_address && io.write_enable) -> io.write_data +// ) +// ) +// +// io.debug_read_data := MuxCase( +// registers(io.debug_read_address), +// IndexedSeq( +// (io.debug_read_address === 0.U) -> 0.U, +// (io.debug_read_address === io.write_address && io.write_enable) -> io.write_data +// ) +// ) + +} diff --git a/lab2/src/main/scala/riscv/core/WriteBack.scala b/lab2/src/main/scala/riscv/core/WriteBack.scala new file mode 100644 index 0000000..13291e2 --- /dev/null +++ b/lab2/src/main/scala/riscv/core/WriteBack.scala @@ -0,0 +1,39 @@ +// Copyright 2022 Canbin Huang +// +// 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.core + +import chisel3._ +import chisel3.util._ +import riscv.Parameters + +class WriteBack extends Module { + val io = IO(new Bundle() { + val instruction_address = Input(UInt(Parameters.AddrWidth)) + val alu_result = Input(UInt(Parameters.DataWidth)) + val memory_read_data = Input(UInt(Parameters.DataWidth)) + val regs_write_source = Input(UInt(2.W)) + val csr_read_data = Input(UInt(Parameters.DataWidth)) + val regs_write_data = Output(UInt(Parameters.DataWidth)) + }) + io.regs_write_data := MuxLookup( + io.regs_write_source, + io.alu_result, + IndexedSeq( + RegWriteSource.Memory -> io.memory_read_data, + RegWriteSource.CSR -> io.csr_read_data, + RegWriteSource.NextInstructionAddress -> (io.instruction_address + 4.U), + ) + ) +} diff --git a/lab2/src/test/scala/riscv/TestAnnotations.scala b/lab2/src/test/scala/riscv/TestAnnotations.scala new file mode 100644 index 0000000..7842a95 --- /dev/null +++ b/lab2/src/test/scala/riscv/TestAnnotations.scala @@ -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 +} diff --git a/lab2/src/test/scala/riscv/singlecycle/CLINTCSRTest.scala b/lab2/src/test/scala/riscv/singlecycle/CLINTCSRTest.scala new file mode 100644 index 0000000..8eb90ee --- /dev/null +++ b/lab2/src/test/scala/riscv/singlecycle/CLINTCSRTest.scala @@ -0,0 +1,142 @@ +// Copyright 2022 hrpccs +// +// 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.singlecycle + +import chisel3._ +import chiseltest._ +import org.scalatest.flatspec.AnyFlatSpec +import riscv.{Parameters, TestAnnotations} +import riscv.core.{ALUOp1Source, ALUOp2Source, CLINT, CSR, CSRRegister, InstructionDecode, InstructionsNop, InstructionsRet} + +class CLINTCSRTestTopModule extends Module { + val io = IO( new Bundle{ + val csr_regs_debug_read_address = Input(UInt(Parameters.CSRRegisterAddrWidth)) + val csr_regs_write_address = Input(UInt(Parameters.CSRRegisterAddrWidth)) + val csr_regs_write_data = Input(UInt(Parameters.DataWidth)) + val csr_regs_write_enable = Input(Bool()) + val interrupt_flag = Input(UInt(Parameters.InterruptFlagWidth)) + val instruction = Input(UInt(Parameters.DataWidth)) + val instruction_address = Input(UInt(Parameters.AddrWidth)) + + val jump_flag = Input(Bool()) + val jump_address = Input(UInt(Parameters.AddrWidth)) + + val interrupt_assert = Output(Bool()) + val interrupt_handler_address = Output(UInt(Parameters.DataWidth)) + val csr_regs_read_data = Output(UInt(Parameters.DataWidth)) + val csr_regs_debug_read_data = Output(UInt(Parameters.DataWidth)) + }) + val csr_regs = Module(new CSR) + val clint = Module(new CLINT) + + clint.io.instruction := io.instruction + clint.io.instruction_address := io.instruction_address + clint.io.interrupt_flag := io.interrupt_flag + clint.io.jump_flag := io.jump_flag + clint.io.jump_address := io.jump_address + + io.interrupt_handler_address := clint.io.interrupt_handler_address + io.interrupt_assert := clint.io.interrupt_assert + io.csr_regs_read_data := csr_regs.io.reg_read_data + csr_regs.io.reg_write_address_id := io.csr_regs_write_address + csr_regs.io.debug_reg_read_address := io.csr_regs_debug_read_address + csr_regs.io.reg_write_data_ex := io.csr_regs_write_data + csr_regs.io.reg_write_enable_id := io.csr_regs_write_enable + csr_regs.io.reg_read_address_id := io.csr_regs_write_address + io.csr_regs_debug_read_data := csr_regs.io.debug_reg_read_data + + csr_regs.io.clint_access_bundle <> clint.io.csr_bundle + +} + +class CLINTCSRTest extends AnyFlatSpec with ChiselScalatestTester{ + behavior of "CLINTCSRTest of Single Cycle CPU" + it should "process " in { + test(new CLINTCSRTestTopModule).withAnnotations(TestAnnotations.annos) { c => + + // + c.io.jump_flag.poke(false.B) + c.io.csr_regs_write_enable.poke(false.B) + c.io.interrupt_flag.poke(0.U) + c.clock.step() + c.io.csr_regs_write_enable.poke(true.B) + c.io.csr_regs_write_address.poke(CSRRegister.MTVEC) + c.io.csr_regs_write_data.poke(0x1144L.U) + c.clock.step() + c.io.csr_regs_write_address.poke(CSRRegister.MSTATUS) + c.io.csr_regs_write_data.poke(0x1888L.U) + c.clock.step() + c.io.csr_regs_write_enable.poke(false.B) + //handle interrupt when not jumping + c.io.jump_flag.poke(false.B) + c.io.instruction_address.poke(0x1900L.U) + c.io.instruction.poke(InstructionsNop.nop) + c.io.interrupt_flag.poke(1.U) + c.io.interrupt_assert.expect(true.B) + c.io.interrupt_handler_address.expect(0x1144L.U) + c.clock.step() + c.io.interrupt_flag.poke(0.U) + c.io.csr_regs_debug_read_address.poke(CSRRegister.MEPC) + c.io.csr_regs_debug_read_data.expect(0x1904L.U) + c.io.csr_regs_debug_read_address.poke(CSRRegister.MCAUSE) + c.io.csr_regs_debug_read_data.expect(0x80000007L.U) + c.io.csr_regs_debug_read_address.poke(CSRRegister.MSTATUS) + c.io.csr_regs_debug_read_data.expect(0x1880L.U) + + c.clock.step(25) + + //mret from interrupt handler + c.io.instruction.poke(InstructionsRet.mret) + c.io.interrupt_assert.expect(true.B) + c.io.interrupt_handler_address.expect(0x1904L.U) + c.clock.step() + c.io.csr_regs_debug_read_address.poke(CSRRegister.MSTATUS) + c.io.csr_regs_debug_read_data.expect(0x1888L.U) + + //handle interrupt when jumping + c.io.jump_flag.poke(true.B) + c.io.jump_address.poke(0x1990L.U) + c.io.interrupt_flag.poke(2.U) + c.io.interrupt_assert.expect(true.B) + c.io.interrupt_handler_address.expect(0x1144L.U) + c.clock.step() + c.io.interrupt_flag.poke(0.U) + c.io.csr_regs_debug_read_address.poke(CSRRegister.MEPC) + c.io.csr_regs_debug_read_data.expect(0x1990L.U) + c.io.csr_regs_debug_read_address.poke(CSRRegister.MCAUSE) + c.io.csr_regs_debug_read_data.expect(0x8000000BL.U) + c.io.csr_regs_debug_read_address.poke(CSRRegister.MSTATUS) + c.io.csr_regs_debug_read_data.expect(0x1880L.U) + + c.clock.step(25) + + //mret from interrupt handler + c.io.instruction.poke(InstructionsRet.mret) + c.io.interrupt_assert.expect(true.B) + c.io.interrupt_handler_address.expect(0x1990L.U) + c.clock.step() + c.io.csr_regs_debug_read_address.poke(CSRRegister.MSTATUS) + c.io.csr_regs_debug_read_data.expect(0x1888L.U) + c.io.instruction.poke(InstructionsNop.nop) + + //don't handle interrupt under certain situation + c.io.csr_regs_write_enable.poke(true.B) + c.io.csr_regs_write_address.poke(CSRRegister.MSTATUS) + c.io.csr_regs_write_data.poke(0x1880L.U) + c.io.interrupt_flag.poke(1.U) + c.io.interrupt_assert.expect(false.B) + } + } +} diff --git a/lab2/src/test/scala/riscv/singlecycle/CPUTest.scala b/lab2/src/test/scala/riscv/singlecycle/CPUTest.scala new file mode 100644 index 0000000..ab9e232 --- /dev/null +++ b/lab2/src/test/scala/riscv/singlecycle/CPUTest.scala @@ -0,0 +1,162 @@ +// 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.singlecycle + +import board.basys3.BootStates +import chisel3._ +import chiseltest._ +import org.scalatest.flatspec.AnyFlatSpec +import peripheral.{InstructionROM, Memory, ROMLoader} +import riscv.core.{CPU, CSRRegister, ProgramCounter} +import riscv.{Parameters, TestAnnotations} + +import java.nio.{ByteBuffer, ByteOrder} + + +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 csr_regs_debug_read_address = Input(UInt(Parameters.CSRRegisterAddrWidth)) + val interrupt_flag = Input(UInt(Parameters.InterruptFlagWidth)) + + + val regs_debug_read_data = Output(UInt(Parameters.DataWidth)) + val mem_debug_read_data = Output(UInt(Parameters.DataWidth)) + val csr_regs_debug_read_data = Output(UInt(Parameters.DataWidth)) + val pc_debug_read = Output(UInt(Parameters.AddrWidth)); + }) + + val mem = Module(new Memory(8192)) + val instruction_rom = Module(new InstructionROM(exeFilename)) + val rom_loader = Module(new ROMLoader(instruction_rom.capacity)) + + rom_loader.io.rom_data := instruction_rom.io.data + rom_loader.io.load_address := Parameters.EntryAddress + instruction_rom.io.address := rom_loader.io.rom_address + + val CPU_clkdiv = RegInit(UInt(2.W), 0.U) + val CPU_tick = Wire(Bool()) + val CPU_next = Wire(UInt(2.W)) + CPU_next := Mux(CPU_clkdiv === 3.U, 0.U, CPU_clkdiv + 1.U) + CPU_tick := CPU_clkdiv === 0.U + CPU_clkdiv := CPU_next + + withClock(CPU_tick.asClock) { + val cpu = Module(new CPU) + cpu.io.instruction_valid := rom_loader.io.load_finished + mem.io.instruction_address := cpu.io.instruction_address + cpu.io.instruction := mem.io.instruction + cpu.io.interrupt_flag := io.interrupt_flag + + when(!rom_loader.io.load_finished) { + rom_loader.io.bundle <> mem.io.bundle + cpu.io.memory_bundle.read_data := 0.U + }.otherwise { + rom_loader.io.bundle.read_data := 0.U + cpu.io.memory_bundle <> mem.io.bundle + } + + cpu.io.regs_debug_read_address := io.regs_debug_read_address + cpu.io.csr_regs_debug_read_address := io.csr_regs_debug_read_address + io.regs_debug_read_data := cpu.io.regs_debug_read_data + io.csr_regs_debug_read_data := cpu.io.csr_regs_debug_read_data + io.pc_debug_read := cpu.io.instruction_address + } + + mem.io.debug_read_address := io.mem_debug_read_address + io.mem_debug_read_data := mem.io.debug_read_data +} + + +class FibonacciTest extends AnyFlatSpec with ChiselScalatestTester { + behavior of "Single Cycle CPU with CSR and CLINT" + it should "calculate recursively fibonacci(10)" in { + test(new TestTopModule("fibonacci.asmbin")).withAnnotations(TestAnnotations.annos) { c => + 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 "Single Cycle CPU with CSR and CLINT" + it should "quicksort 10 numbers" in { + test(new TestTopModule("quicksort.asmbin")).withAnnotations(TestAnnotations.annos) { c => + 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 ByteAccessTest extends AnyFlatSpec with ChiselScalatestTester { + behavior of "Single Cycle CPU with CSR and CLINT" + it should "store and load single byte" in { + test(new TestTopModule("sb.asmbin")).withAnnotations(TestAnnotations.annos) { c => + 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) + } + } +} + +class SimpleTrapTest extends AnyFlatSpec with ChiselScalatestTester { + behavior of "Single Cycle CPU with CSR and CLINT" + it should "jump to trap handler and then return" in { + test(new TestTopModule("simpletest.asmbin")).withAnnotations(TestAnnotations.annos) { c => + for (i <- 1 to 1000) { + c.clock.step() + 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(0xDEADBEEFL.U) + c.io.interrupt_flag.poke(0x1.U) + c.clock.step(5) + c.io.interrupt_flag.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.csr_regs_debug_read_address.poke(CSRRegister.MSTATUS) + c.io.csr_regs_debug_read_data.expect(0x1888.U) + c.io.csr_regs_debug_read_address.poke(CSRRegister.MCAUSE) + c.io.csr_regs_debug_read_data.expect(0x80000007L.U) + c.io.mem_debug_read_address.poke(0x4.U) + c.clock.step() + c.io.mem_debug_read_data.expect(0x2022L.U) + } + } +} diff --git a/lab2/src/test/scala/riscv/singlecycle/ExecuteTest.scala b/lab2/src/test/scala/riscv/singlecycle/ExecuteTest.scala new file mode 100644 index 0000000..d82189b --- /dev/null +++ b/lab2/src/test/scala/riscv/singlecycle/ExecuteTest.scala @@ -0,0 +1,49 @@ +// Copyright 2022 hrpccs +// +// 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.singlecycle + +import chisel3._ +import chiseltest._ +import org.scalatest.flatspec.AnyFlatSpec +import riscv.TestAnnotations +import riscv.core.Execute + +class ExecuteTest extends AnyFlatSpec with ChiselScalatestTester{ + behavior of "CLINTCSRTest of Single Cycle CPU" + it should "produce correct data for csr write" in { + test(new Execute).withAnnotations(TestAnnotations.annos) { c => + c.io.instruction.poke(0x30047073L.U) // csrc mstatus,3 + c.io.csr_reg_read_data.poke(0x1888L.U) + c.io.reg1_data.poke(0x1880L.U) + c.io.csr_reg_write_data.expect(0x1880.U) + c.clock.step() + c.io.instruction.poke(0x30046073L.U) //csrs mastatus,3 + c.io.csr_reg_read_data.poke(0x1880L.U) + c.io.reg1_data.poke(0x1880L.U) + c.io.csr_reg_write_data.expect(0x1888.U) + c.clock.step() + c.io.instruction.poke(0x30051073L.U) //csrw mstatus, a0 + c.io.csr_reg_read_data.poke(0.U) + c.io.reg1_data.poke(0x1888L.U) + c.io.csr_reg_write_data.expect(0x1888.U) + c.clock.step() + c.io.instruction.poke(0x30002573L.U) //csrr a0, mstatus + c.io.csr_reg_read_data.poke(0x1888.U) + c.io.reg1_data.poke(0x0L.U) + c.io.csr_reg_write_data.expect(0x1888.U) + c.clock.step() + } + } +} diff --git a/lab2/src/test/scala/riscv/singlecycle/TimerTest.scala b/lab2/src/test/scala/riscv/singlecycle/TimerTest.scala new file mode 100644 index 0000000..5d1ced2 --- /dev/null +++ b/lab2/src/test/scala/riscv/singlecycle/TimerTest.scala @@ -0,0 +1,61 @@ +// Copyright 2022 hrpccs +// +// 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.singlecycle + +import chisel3._ +import chiseltest._ +import org.scalatest.flatspec.AnyFlatSpec +import riscv.{Parameters, TestAnnotations} +import peripheral.{RAMBundle, Timer} + +class TimerTest extends AnyFlatSpec with ChiselScalatestTester { + + class TestTimer extends Module { + val io = IO(new Bundle { + val debug_limit = Output(UInt(Parameters.DataWidth)) + val debug_enabled = Output(Bool()) + val bundle = new RAMBundle + + val write_strobe = Input(UInt(4.W)) + }) + val timer = Module(new Timer) + io.debug_limit := timer.io.debug_limit + io.debug_enabled := timer.io.debug_enabled + + timer.io.bundle <> io.bundle + timer.io.bundle.write_strobe := VecInit(io.write_strobe.asBools) + } + + behavior of "Timer" + it should "read and write the limit" in { + test(new TestTimer).withAnnotations(TestAnnotations.annos) {c => + c.io.write_strobe.poke(0xF.U) + c.io.bundle.write_enable.poke(true.B) + c.io.bundle.address.poke(0x4.U) + c.io.bundle.write_data.poke(0x990315.U) + c.clock.step() + c.io.bundle.write_enable.poke(false.B) + c.clock.step() + c.io.debug_limit.expect(0x990315.U) + c.io.bundle.write_enable.poke(true.B) + c.io.bundle.address.poke(0x8.U) + c.io.bundle.write_data.poke(0.U) + c.clock.step() + c.io.bundle.write_enable.poke(false.B) + c.io.debug_enabled.expect(false.B) + } + } +} + diff --git a/lab2/verilog/basys3/test.v b/lab2/verilog/basys3/test.v new file mode 100644 index 0000000..9f3f6a6 --- /dev/null +++ b/lab2/verilog/basys3/test.v @@ -0,0 +1,35 @@ +`timescale 1ns / 1ps +////////////////////////////////////////////////////////////////////////////////// +// Company: +// Engineer: +// +// Create Date: 2021/12/17 16:31:05 +// Design Name: +// Module Name: test +// Project Name: +// Target Devices: +// Tool Versions: +// Description: +// +// Dependencies: +// +// Revision: +// Revision 0.01 - File Created +// Additional Comments: +// +////////////////////////////////////////////////////////////////////////////////// + + +module test(); +reg clock; +reg reset; +initial begin +clock = 0; +forever #1 clock = ~clock; +end +initial begin +reset = 1; +#2 reset = 0; +end +Top top(clock, reset); +endmodule diff --git a/lab2/verilog/pynq/TMDS_PLLVR.v b/lab2/verilog/pynq/TMDS_PLLVR.v new file mode 100644 index 0000000..1bc4dfb --- /dev/null +++ b/lab2/verilog/pynq/TMDS_PLLVR.v @@ -0,0 +1,221 @@ + +// file: TMDS_PLLVR.v +// +// (c) Copyright 2008 - 2013 Xilinx, Inc. All rights reserved. +// +// This file contains confidential and proprietary information +// of Xilinx, Inc. and is protected under U.S. and +// international copyright and other intellectual property +// laws. +// +// DISCLAIMER +// This disclaimer is not a license and does not grant any +// rights to the materials distributed herewith. Except as +// otherwise provided in a valid license issued to you by +// Xilinx, and to the maximum extent permitted by applicable +// law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND +// WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES +// AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING +// BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON- +// INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and +// (2) Xilinx shall not be liable (whether in contract or tort, +// including negligence, or under any other theory of +// liability) for any loss or damage of any kind or nature +// related to, arising under or in connection with these +// materials, including for any direct, or any indirect, +// special, incidental, or consequential loss or damage +// (including loss of data, profits, goodwill, or any type of +// loss or damage suffered as a result of any action brought +// by a third party) even if such damage or loss was +// reasonably foreseeable or Xilinx had been advised of the +// possibility of the same. +// +// CRITICAL APPLICATIONS +// Xilinx products are not designed or intended to be fail- +// safe, or for use in any application requiring fail-safe +// performance, such as life-support or safety devices or +// systems, Class III medical devices, nuclear facilities, +// applications related to the deployment of airbags, or any +// other applications that could lead to death, personal +// injury, or severe property or environmental damage +// (individually and collectively, "Critical +// Applications"). Customer assumes the sole risk and +// liability of any use of Xilinx products in Critical +// Applications, subject only to applicable laws and +// regulations governing limitations on product liability. +// +// THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS +// PART OF THIS FILE AT ALL TIMES. +// +//---------------------------------------------------------------------------- +// User entered comments +//---------------------------------------------------------------------------- +// None +// +//---------------------------------------------------------------------------- +// Output Output Phase Duty Cycle Pk-to-Pk Phase +// Clock Freq (MHz) (degrees) (%) Jitter (ps) Error (ps) +//---------------------------------------------------------------------------- +// __clkout__250.00000______0.000______50.0______200.536____237.727 +// _clkoutd__100.00000______0.000______50.0______226.965____237.727 +// +//---------------------------------------------------------------------------- +// Input Clock Freq (MHz) Input Jitter (UI) +//---------------------------------------------------------------------------- +// __primary__________25.000____________0.010 + +`timescale 1ps/1ps + +(* CORE_GENERATION_INFO = "TMDS_PLLVR,clk_wiz_v6_0_5_0_0,{component_name=TMDS_PLLVR,use_phase_alignment=true,use_min_o_jitter=false,use_max_i_jitter=false,use_dyn_phase_shift=false,use_inclk_switchover=false,use_dyn_reconfig=false,enable_axi=0,feedback_source=FDBK_AUTO,PRIMITIVE=PLL,num_out_clk=2,clkin1_period=40.000,clkin2_period=10.0,use_power_down=false,use_reset=true,use_locked=true,use_inclk_stopped=false,feedback_type=SINGLE,CLOCK_MGR_TYPE=NA,manual_override=true}" *) + +module TMDS_PLLVR + ( + // Clock out ports + output clkout, + output clkoutd, + // Status and control signals + input reset, + output lock, + // Clock in ports + input clkin + ); + + TMDS_PLLVR_clk_wiz inst + ( + // Clock out ports + .clkout(clkout), + .clkoutd(clkoutd), + // Status and control signals + .reset(reset), + .lock(lock), + // Clock in ports + .clk_in1(clkin) + ); + +endmodule + + +module TMDS_PLLVR_clk_wiz + + (// Clock in ports + // Clock out ports + output clkout, + output clkoutd, + // Status and control signals + input reset, + output lock, + input clk_in1 + ); + // Input buffering + //------------------------------------ +wire clk_in1_TMDS_PLLVR; +wire clk_in2_TMDS_PLLVR; + IBUF clkin1_ibufg + (.O (clk_in1_TMDS_PLLVR), + .I (clk_in1)); + + + + + // Clocking PRIMITIVE + //------------------------------------ + + // Instantiation of the MMCM PRIMITIVE + // * Unused inputs are tied off + // * Unused outputs are labeled unused + + wire clkout_TMDS_PLLVR; + wire clkoutd_TMDS_PLLVR; + wire clk_out3_TMDS_PLLVR; + wire clk_out4_TMDS_PLLVR; + wire clk_out5_TMDS_PLLVR; + wire clk_out6_TMDS_PLLVR; + wire clk_out7_TMDS_PLLVR; + + wire [15:0] do_unused; + wire drdy_unused; + wire psdone_unused; + wire lock_int; + wire clkfbout_TMDS_PLLVR; + wire clkfbout_buf_TMDS_PLLVR; + wire clkfboutb_unused; + wire clkout2_unused; + wire clkout3_unused; + wire clkout4_unused; + wire clkout5_unused; + wire clkout6_unused; + wire clkfbstopped_unused; + wire clkinstopped_unused; + wire reset_high; + + PLLE2_ADV + #(.BANDWIDTH ("OPTIMIZED"), + .COMPENSATION ("ZHOLD"), + .STARTUP_WAIT ("FALSE"), + .DIVCLK_DIVIDE (1), + .CLKFBOUT_MULT (40), + .CLKFBOUT_PHASE (0.000), + .CLKOUT0_DIVIDE (4), + .CLKOUT0_PHASE (0.000), + .CLKOUT0_DUTY_CYCLE (0.500), + .CLKOUT1_DIVIDE (10), + .CLKOUT1_PHASE (0.000), + .CLKOUT1_DUTY_CYCLE (0.500), + .CLKIN1_PERIOD (40.000)) + plle2_adv_inst + // Output clocks + ( + .CLKFBOUT (clkfbout_TMDS_PLLVR), + .CLKOUT0 (clkout_TMDS_PLLVR), + .CLKOUT1 (clkoutd_TMDS_PLLVR), + .CLKOUT2 (clkout2_unused), + .CLKOUT3 (clkout3_unused), + .CLKOUT4 (clkout4_unused), + .CLKOUT5 (clkout5_unused), + // Input clock control + .CLKFBIN (clkfbout_buf_TMDS_PLLVR), + .CLKIN1 (clk_in1_TMDS_PLLVR), + .CLKIN2 (1'b0), + // Tied to always select the primary input clock + .CLKINSEL (1'b1), + // Ports for dynamic reconfiguration + .DADDR (7'h0), + .DCLK (1'b0), + .DEN (1'b0), + .DI (16'h0), + .DO (do_unused), + .DRDY (drdy_unused), + .DWE (1'b0), + // Other control and status signals + .LOCKED (lock_int), + .PWRDWN (1'b0), + .RST (reset_high)); + assign reset_high = reset; + + assign lock = lock_int; +// Clock Monitor clock assigning +//-------------------------------------- + // Output buffering + //----------------------------------- + + BUFG clkf_buf + (.O (clkfbout_buf_TMDS_PLLVR), + .I (clkfbout_TMDS_PLLVR)); + + + + + + + BUFG clkout1_buf + (.O (clkout), + .I (clkout_TMDS_PLLVR)); + + + BUFG clkout2_buf + (.O (clkoutd), + .I (clkoutd_TMDS_PLLVR)); + + + +endmodule diff --git a/lab2/verilog/pynq/test.v b/lab2/verilog/pynq/test.v new file mode 100644 index 0000000..620909f --- /dev/null +++ b/lab2/verilog/pynq/test.v @@ -0,0 +1,35 @@ +`timescale 1ns / 1ps +////////////////////////////////////////////////////////////////////////////////// +// Company: +// Engineer: +// +// Create Date: 2021/12/17 16:31:05 +// Design Name: +// Module Name: test +// Project Name: +// Target Devices: +// Tool Versions: +// Description: +// +// Dependencies: +// +// Revision: +// Revision 0.01 - File Created +// Additional Comments: +// +////////////////////////////////////////////////////////////////////////////////// + + +module test(); +reg clock; +reg reset; +initial begin +clock = 0; +forever #100 clock = ~clock; +end +initial begin +reset = 1; +#200 reset = 0; +end +Top top(clock, reset); +endmodule diff --git a/lab2/verilog/verilator/sim_main.cpp b/lab2/verilog/verilator/sim_main.cpp new file mode 100644 index 0000000..aa1dcab --- /dev/null +++ b/lab2/verilog/verilator/sim_main.cpp @@ -0,0 +1,246 @@ +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "VTop.h" // From Verilating "top.v" + + +class Memory { + std::vector memory; + + public: + Memory(size_t size) : memory(size, 0) {} + uint32_t read(size_t address) { + address = address / 4; + if (address >= memory.size()) { +// printf("invalid read address 0x%08x\n", address * 4); + return 0; + } + + return memory[address]; + } + + uint32_t readInst(size_t address) { + address = address / 4; + if (address >= memory.size()) { +// printf("invalid read Inst address 0x%08x\n", address * 4); + return 0; + } + + return memory[address]; + } + + void write(size_t address, uint32_t value, bool write_strobe[4]) { + address = address / 4; + uint32_t write_mask = 0; + if (write_strobe[0]) write_mask |= 0x000000FF; + if (write_strobe[1]) write_mask |= 0x0000FF00; + if (write_strobe[2]) write_mask |= 0x00FF0000; + if (write_strobe[3]) write_mask |= 0xFF000000; + if (address >= memory.size()) { +// printf("invalid write address 0x%08x\n", address * 4); + return; + } + memory[address] = (memory[address] & ~write_mask) | (value & write_mask); + } + + void load_binary(std::string const& filename, size_t load_address = 0x1000) { + std::ifstream file(filename, std::ios::binary); + if (!file) { + throw std::runtime_error("Could not open file " + filename); + } + file.seekg(0, std::ios::end); + size_t size = file.tellg(); + if (load_address + size > memory.size() * 4) { + throw std::runtime_error("File " + filename + " is too large (File is " + + std::to_string(size) + " bytes. Memory is " + + std::to_string(memory.size() * 4 - load_address) + " bytes.)"); + } + file.seekg(0, std::ios::beg); + for (int i = 0; i < size / 4; ++i) { + file.read(reinterpret_cast(&memory[i + load_address / 4]), + sizeof(uint32_t)); + } + } +}; + +class VCDTracer { + VerilatedVcdC* tfp = nullptr; + + public: + void enable(std::string const& filename, VTop& top) { + Verilated::traceEverOn(true); + tfp = new VerilatedVcdC; + top.trace(tfp, 99); + tfp->open(filename.c_str()); + tfp->set_time_resolution("1ps"); + tfp->set_time_unit("1ns"); + if (!tfp->isOpen()) { + throw std::runtime_error("Failed to open VCD dump file " + filename); + } + } + + void dump(vluint64_t time) { + if (tfp) { + tfp->dump(time); + } + } + + ~VCDTracer() { + if (tfp) { + tfp->close(); + delete tfp; + } + } +}; + +uint32_t parse_number(std::string const& str) { + if (str.size() > 2) { + auto&& prefix = str.substr(0, 2); + if (prefix == "0x" || prefix == "0X") { + return std::stoul(str.substr(2), nullptr, 16); + } + } + return std::stoul(str); +} + +class Simulator { + vluint64_t main_time = 0; + vluint64_t max_sim_time = 10000; + uint32_t halt_address = 0; + size_t memory_words = 1024 * 1024; // 4MB + bool dump_vcd = false; + std::unique_ptr top; + std::unique_ptr vcd_tracer; + std::unique_ptr memory; + bool dump_signature = false; + unsigned long signature_begin, signature_end; + std::string signature_filename; + std::string instruction_filename; + + public: + void parse_args(std::vector const& args) { + if (auto it = std::find(args.begin(), args.end(), "-halt"); + it != args.end()) { + halt_address = parse_number(*(it + 1)); + } + + if (auto it = std::find(args.begin(), args.end(), "-memory"); + it != args.end()) { + memory_words = std::stoul(*(it + 1)); + } + + if (auto it = std::find(args.begin(), args.end(), "-time"); + it != args.end()) { + max_sim_time = std::stoul(*(it + 1)); + } + + if (auto it = std::find(args.begin(), args.end(), "-vcd"); + it != args.end()) { + vcd_tracer->enable(*(it + 1), *top); + } + + if (auto it = std::find(args.begin(), args.end(), "-signature"); + it != args.end()) { + dump_signature = true; + signature_begin = parse_number(*(it + 1)); + signature_end = parse_number(*(it + 2)); + signature_filename = *(it + 3); + } + + if (auto it = std::find(args.begin(), args.end(), "-instruction"); + it != args.end()) { + instruction_filename = *(it + 1); + } + } + + Simulator(std::vector const& args) + : top(std::make_unique()), + vcd_tracer(std::make_unique()) { + parse_args(args); + memory = std::make_unique(memory_words); + if (!instruction_filename.empty()) { + memory->load_binary(instruction_filename); + } + } + + void run() { + top->reset = 1; + top->clock = 0; + top->io_instruction_valid = 1; + top->eval(); + vcd_tracer->dump(main_time); + uint32_t data_memory_read_word = 0; + uint32_t inst_memory_read_word = 0; + uint32_t timer_interrupt = 0; + uint32_t counter = 0; + uint32_t clocktime = 1; + bool memory_write_strobe[4] = {false}; + while (main_time < max_sim_time && !Verilated::gotFinish()) { + ++main_time; + ++counter; + if(counter > clocktime){ + top->clock = !top->clock; + counter = 0; + } + if (main_time > 2) { + top->reset = 0; + } +// top->io_mem_slave_read_data = memory_read_word; + top->io_memory_bundle_read_data = data_memory_read_word; + top->io_instruction = inst_memory_read_word; + top->clock = !top->clock; + top->eval(); + top->io_interrupt_flag = 0; + + data_memory_read_word = memory->read(top->io_memory_bundle_address); + + + inst_memory_read_word = memory->readInst(top->io_instruction_address); + + if (top->io_memory_bundle_write_enable) { + memory_write_strobe[0] = top->io_memory_bundle_write_strobe_0; + memory_write_strobe[1] = top->io_memory_bundle_write_strobe_1; + memory_write_strobe[2] = top->io_memory_bundle_write_strobe_2; + memory_write_strobe[3] = top->io_memory_bundle_write_strobe_3; + memory->write(top->io_memory_bundle_address, top->io_memory_bundle_write_data, + memory_write_strobe); + } + vcd_tracer->dump(main_time); + if (halt_address) { + if (memory->read(halt_address) == 0xBABECAFE) { + break; + } + } + } + + if (dump_signature) { + char data[9] = {0}; + std::ofstream signature_file(signature_filename); + for (size_t addr = signature_begin; addr < signature_end; addr += 4) { + snprintf(data, 9, "%08x", memory->read(addr)); + signature_file << data << std::endl; + } + } + } + + ~Simulator() { + if (top) { + top->final(); + } + } +}; + +int main(int argc, char** argv) { + Verilated::commandArgs(argc, argv); + std::vector args(argv, argv + argc); + Simulator simulator(args); + simulator.run(); + return 0; +} diff --git a/lab2/vivado/basys3/basys3.xdc b/lab2/vivado/basys3/basys3.xdc new file mode 100644 index 0000000..9864546 --- /dev/null +++ b/lab2/vivado/basys3/basys3.xdc @@ -0,0 +1,307 @@ +# 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. + +## Clock signal +set_property PACKAGE_PIN W5 [get_ports clock] + set_property IOSTANDARD LVCMOS33 [get_ports clock] + create_clock -add -name sys_clk_pin -period 20.00 -waveform {0 5} [get_ports clock] + +## Switches +set_property PACKAGE_PIN V17 [get_ports {io_switch[0]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_switch[0]}] +set_property PACKAGE_PIN V16 [get_ports {io_switch[1]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_switch[1]}] +set_property PACKAGE_PIN W16 [get_ports {io_switch[2]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_switch[2]}] +set_property PACKAGE_PIN W17 [get_ports {io_switch[3]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_switch[3]}] +set_property PACKAGE_PIN W15 [get_ports {io_switch[4]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_switch[4]}] +set_property PACKAGE_PIN V15 [get_ports {io_switch[5]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_switch[5]}] +set_property PACKAGE_PIN W14 [get_ports {io_switch[6]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_switch[6]}] +set_property PACKAGE_PIN W13 [get_ports {io_switch[7]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_switch[7]}] +set_property PACKAGE_PIN V2 [get_ports {io_switch[8]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_switch[8]}] +set_property PACKAGE_PIN T3 [get_ports {io_switch[9]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_switch[9]}] +set_property PACKAGE_PIN T2 [get_ports {io_switch[10]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_switch[10]}] +set_property PACKAGE_PIN R3 [get_ports {io_switch[11]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_switch[11]}] +set_property PACKAGE_PIN W2 [get_ports {io_switch[12]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_switch[12]}] +set_property PACKAGE_PIN U1 [get_ports {io_switch[13]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_switch[13]}] +set_property PACKAGE_PIN T1 [get_ports {io_switch[14]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_switch[14]}] +set_property PACKAGE_PIN R2 [get_ports {io_switch[15]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_switch[15]}] + + +## LEDs +set_property PACKAGE_PIN U16 [get_ports {io_led[0]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_led[0]}] +set_property PACKAGE_PIN E19 [get_ports {io_led[1]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_led[1]}] +set_property PACKAGE_PIN U19 [get_ports {io_led[2]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_led[2]}] +set_property PACKAGE_PIN V19 [get_ports {io_led[3]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_led[3]}] +set_property PACKAGE_PIN W18 [get_ports {io_led[4]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_led[4]}] +set_property PACKAGE_PIN U15 [get_ports {io_led[5]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_led[5]}] +set_property PACKAGE_PIN U14 [get_ports {io_led[6]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_led[6]}] +set_property PACKAGE_PIN V14 [get_ports {io_led[7]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_led[7]}] +set_property PACKAGE_PIN V13 [get_ports {io_led[8]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_led[8]}] +set_property PACKAGE_PIN V3 [get_ports {io_led[9]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_led[9]}] +set_property PACKAGE_PIN W3 [get_ports {io_led[10]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_led[10]}] +set_property PACKAGE_PIN U3 [get_ports {io_led[11]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_led[11]}] +set_property PACKAGE_PIN P3 [get_ports {io_led[12]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_led[12]}] +set_property PACKAGE_PIN N3 [get_ports {io_led[13]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_led[13]}] +set_property PACKAGE_PIN P1 [get_ports {io_led[14]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_led[14]}] +set_property PACKAGE_PIN L1 [get_ports {io_led[15]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_led[15]}] + + +##7 segment display +set_property PACKAGE_PIN U7 [get_ports io_segs[0]] + set_property IOSTANDARD LVCMOS33 [get_ports io_segs[0]] +set_property PACKAGE_PIN V5 [get_ports io_segs[1]] + set_property IOSTANDARD LVCMOS33 [get_ports io_segs[1]] +set_property PACKAGE_PIN U5 [get_ports io_segs[2]] + set_property IOSTANDARD LVCMOS33 [get_ports io_segs[2]] +set_property PACKAGE_PIN V8 [get_ports io_segs[3]] + set_property IOSTANDARD LVCMOS33 [get_ports io_segs[3]] +set_property PACKAGE_PIN U8 [get_ports io_segs[4]] + set_property IOSTANDARD LVCMOS33 [get_ports io_segs[4]] +set_property PACKAGE_PIN W6 [get_ports io_segs[5]] + set_property IOSTANDARD LVCMOS33 [get_ports io_segs[5]] +set_property PACKAGE_PIN W7 [get_ports io_segs[6]] + set_property IOSTANDARD LVCMOS33 [get_ports io_segs[6]] +set_property PACKAGE_PIN V7 [get_ports io_segs[7]] + set_property IOSTANDARD LVCMOS33 [get_ports io_segs[7]] + +set_property PACKAGE_PIN U2 [get_ports {io_digit_mask[0]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_digit_mask[0]}] +set_property PACKAGE_PIN U4 [get_ports {io_digit_mask[1]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_digit_mask[1]}] +set_property PACKAGE_PIN V4 [get_ports {io_digit_mask[2]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_digit_mask[2]}] +set_property PACKAGE_PIN W4 [get_ports {io_digit_mask[3]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_digit_mask[3]}] + + +##Buttons +set_property PACKAGE_PIN U18 [get_ports reset] + set_property IOSTANDARD LVCMOS33 [get_ports reset] +#set_property PACKAGE_PIN T18 [get_ports io_freqIncrease] + #set_property IOSTANDARD LVCMOS33 [get_ports io_freqIncrease] +#set_property PACKAGE_PIN W19 [get_ports io_widthIncrease] + #set_property IOSTANDARD LVCMOS33 [get_ports io_widthIncrease] +#set_property PACKAGE_PIN T17 [get_ports io_widthDecrease] + #set_property IOSTANDARD LVCMOS33 [get_ports io_widthDecrease] +#set_property PACKAGE_PIN U17 [get_ports io_freqDecrease] + #set_property IOSTANDARD LVCMOS33 [get_ports io_freqDecrease] + + + +##Pmod Header JA +##Sch name = JA1 +#set_property PACKAGE_PIN J1 [get_ports {JA[0]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JA[0]}] +##Sch name = JA2 +#set_property PACKAGE_PIN L2 [get_ports {JA[1]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JA[1]}] +##Sch name = JA3 +#set_property PACKAGE_PIN J2 [get_ports {JA[2]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JA[2]}] +##Sch name = JA4 +#set_property PACKAGE_PIN G2 [get_ports {JA[3]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JA[3]}] +##Sch name = JA7 +#set_property PACKAGE_PIN H1 [get_ports {JA[4]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JA[4]}] +##Sch name = JA8 +#set_property PACKAGE_PIN K2 [get_ports {JA[5]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JA[5]}] +##Sch name = JA9 +#set_property PACKAGE_PIN H2 [get_ports {JA[6]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JA[6]}] +##Sch name = JA10 +#set_property PACKAGE_PIN G3 [get_ports {JA[7]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JA[7]}] + + + +##Pmod Header JB +##Sch name = JB1 +#set_property PACKAGE_PIN A14 [get_ports {JB[0]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JB[0]}] +##Sch name = JB2 +#set_property PACKAGE_PIN A16 [get_ports {JB[1]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JB[1]}] +##Sch name = JB3 +#set_property PACKAGE_PIN B15 [get_ports {JB[2]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JB[2]}] +##Sch name = JB4 +#set_property PACKAGE_PIN B16 [get_ports {JB[3]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JB[3]}] +##Sch name = JB7 +#set_property PACKAGE_PIN A15 [get_ports {JB[4]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JB[4]}] +##Sch name = JB8 +#set_property PACKAGE_PIN A17 [get_ports {JB[5]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JB[5]}] +##Sch name = JB9 +#set_property PACKAGE_PIN C15 [get_ports {JB[6]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JB[6]}] +##Sch name = JB10 +#set_property PACKAGE_PIN C16 [get_ports {JB[7]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JB[7]}] + + + +##Pmod Header JC +##Sch name = JC1 +#set_property PACKAGE_PIN K17 [get_ports {JC[0]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JC[0]}] +##Sch name = JC2 +#set_property PACKAGE_PIN M18 [get_ports {JC[1]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JC[1]}] +##Sch name = JC3 +#set_property PACKAGE_PIN N17 [get_ports {JC[2]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JC[2]}] +##Sch name = JC4 +#set_property PACKAGE_PIN P18 [get_ports {JC[3]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JC[3]}] +##Sch name = JC7 +#set_property PACKAGE_PIN L17 [get_ports {JC[4]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JC[4]}] +##Sch name = JC8 +#set_property PACKAGE_PIN M19 [get_ports {JC[5]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JC[5]}] +##Sch name = JC9 +#set_property PACKAGE_PIN P17 [get_ports {JC[6]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JC[6]}] +##Sch name = JC10 +#set_property PACKAGE_PIN R18 [get_ports {JC[7]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JC[7]}] + + +##Pmod Header JXADC +##Sch name = XA1_P +#set_property PACKAGE_PIN J3 [get_ports {JXADC[0]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JXADC[0]}] +##Sch name = XA2_P +#set_property PACKAGE_PIN L3 [get_ports {JXADC[1]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JXADC[1]}] +##Sch name = XA3_P +#set_property PACKAGE_PIN M2 [get_ports {JXADC[2]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JXADC[2]}] +##Sch name = XA4_P +#set_property PACKAGE_PIN N2 [get_ports {JXADC[3]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JXADC[3]}] +##Sch name = XA1_N +#set_property PACKAGE_PIN K3 [get_ports {JXADC[4]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JXADC[4]}] +##Sch name = XA2_N +#set_property PACKAGE_PIN M3 [get_ports {JXADC[5]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JXADC[5]}] +##Sch name = XA3_N +#set_property PACKAGE_PIN M1 [get_ports {JXADC[6]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JXADC[6]}] +##Sch name = XA4_N +#set_property PACKAGE_PIN N1 [get_ports {JXADC[7]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JXADC[7]}] + + + +##VGA Connector +set_property PACKAGE_PIN G19 [get_ports {io_rgb[8]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_rgb[8]}] +set_property PACKAGE_PIN H19 [get_ports {io_rgb[9]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_rgb[9]}] +set_property PACKAGE_PIN J19 [get_ports {io_rgb[10]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_rgb[10]}] +set_property PACKAGE_PIN N19 [get_ports {io_rgb[11]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_rgb[11]}] +set_property PACKAGE_PIN N18 [get_ports {io_rgb[0]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_rgb[0]}] +set_property PACKAGE_PIN L18 [get_ports {io_rgb[1]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_rgb[1]}] +set_property PACKAGE_PIN K18 [get_ports {io_rgb[2]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_rgb[2]}] +set_property PACKAGE_PIN J18 [get_ports {io_rgb[3]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_rgb[3]}] +set_property PACKAGE_PIN J17 [get_ports {io_rgb[4]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_rgb[4]}] +set_property PACKAGE_PIN H17 [get_ports {io_rgb[5]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_rgb[5]}] +set_property PACKAGE_PIN G17 [get_ports {io_rgb[6]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_rgb[6]}] +set_property PACKAGE_PIN D17 [get_ports {io_rgb[7]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_rgb[7]}] +set_property PACKAGE_PIN P19 [get_ports io_hsync] + set_property IOSTANDARD LVCMOS33 [get_ports io_hsync] +set_property PACKAGE_PIN R19 [get_ports io_vsync] + set_property IOSTANDARD LVCMOS33 [get_ports io_vsync] + + +##USB-RS232 Interface +set_property PACKAGE_PIN B18 [get_ports io_rx] + set_property IOSTANDARD LVCMOS33 [get_ports io_rx] +set_property PACKAGE_PIN A18 [get_ports io_tx] + set_property IOSTANDARD LVCMOS33 [get_ports io_tx] + + +##USB HID (PS/2) +#set_property PACKAGE_PIN C17 [get_ports PS2Clk] + #set_property IOSTANDARD LVCMOS33 [get_ports PS2Clk] + #set_property PULLUP true [get_ports PS2Clk] +#set_property PACKAGE_PIN B17 [get_ports PS2Data] + #set_property IOSTANDARD LVCMOS33 [get_ports PS2Data] + #set_property PULLUP true [get_ports PS2Data] + + +##Quad SPI Flash +##Note that CCLK_0 cannot be placed in 7 series devices. You can access it using the +##STARTUPE2 primitive. +#set_property PACKAGE_PIN D18 [get_ports {QspiDB[0]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {QspiDB[0]}] +#set_property PACKAGE_PIN D19 [get_ports {QspiDB[1]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {QspiDB[1]}] +#set_property PACKAGE_PIN G18 [get_ports {QspiDB[2]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {QspiDB[2]}] +#set_property PACKAGE_PIN F18 [get_ports {QspiDB[3]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {QspiDB[3]}] +#set_property PACKAGE_PIN K19 [get_ports QspiCSn] + #set_property IOSTANDARD LVCMOS33 [get_ports QspiCSn] + + +## Configuration options, can be used for all designs +set_property CONFIG_VOLTAGE 3.3 [current_design] +set_property CFGBVS VCCO [current_design] diff --git a/lab2/vivado/basys3/generate_and_program.tcl b/lab2/vivado/basys3/generate_and_program.tcl new file mode 100644 index 0000000..71df1af --- /dev/null +++ b/lab2/vivado/basys3/generate_and_program.tcl @@ -0,0 +1,17 @@ +# 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. + +# Only tested on Vivado 2020.1 on Windows 10 +source generate_bitstream.tcl +source program_device.tcl \ No newline at end of file diff --git a/lab2/vivado/basys3/generate_bitstream.tcl b/lab2/vivado/basys3/generate_bitstream.tcl new file mode 100644 index 0000000..e1a26fb --- /dev/null +++ b/lab2/vivado/basys3/generate_bitstream.tcl @@ -0,0 +1,55 @@ +# 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. + +source open_project.tcl + +while 1 { + if { [catch {launch_runs synth_1 -jobs 4 } ] } { + regexp {ERROR: \[Common (\d+-\d+)]} $errorInfo -> code + if { [string equal $code "12-978"] } { + puts "Already generated and up-to-date" + break + } elseif { [string equal $code "17-69"] } { + puts "Out of date, reset runs" + reset_runs synth_1 + continue + } else { + puts "UNKNOWN ERROR!!! $errorInfo" + exit + } + } + break +} + +wait_on_run synth_1 + +while 1 { + if { [catch {launch_runs impl_1 -jobs 4 -to_step write_bitstream } ] } { + regexp {ERROR: \[Vivado (\d+-\d+)]} $errorInfo -> code + if { [string equal $code "12-978"] } { + puts "Already generated and up-to-date" + break + } elseif { [string equal $code "12-1088"] } { + puts "Out of date, reset runs" + reset_runs impl_1 + continue + } else { + puts "UNKNOWN ERROR!!! $errorInfo" + exit + } + } + break +} + +wait_on_run impl_1 diff --git a/lab2/vivado/basys3/open_project.tcl b/lab2/vivado/basys3/open_project.tcl new file mode 100644 index 0000000..b20931a --- /dev/null +++ b/lab2/vivado/basys3/open_project.tcl @@ -0,0 +1,39 @@ +# 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. + +# Only tested on Vivado 2020.1 on Windows 10 + +# set variables +set project_dir riscv-basys3 +set project_name riscv-basys3 +set part xc7a35tcpg236-1 +set sources {../../verilog/basys3/Top.v} +set test_sources {../../verilog/basys3/test.v} + +# open the project. will create one if it doesn't exist +if {[file exist $project_dir]} { + # check that it's a directory + if {! [file isdirectory $project_dir]} { + puts "$project_dir exists, but it's a file" + } + open_project $project_dir/$project_name.xpr -part $part +} else { + create_project $project_name $project_dir -part $part +} + +add_files -norecurse $sources +update_compile_order -fileset sources_1 +add_files -fileset constrs_1 -norecurse basys3.xdc +add_files -fileset sim_1 -norecurse $test_sources +update_compile_order -fileset sim_1 diff --git a/lab2/vivado/basys3/program_device.tcl b/lab2/vivado/basys3/program_device.tcl new file mode 100644 index 0000000..12fe648 --- /dev/null +++ b/lab2/vivado/basys3/program_device.tcl @@ -0,0 +1,24 @@ +# 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. + +# Only tested on Vivado 2020.1 on Windows 10 +open_hw_manager +connect_hw_server -allow_non_jtag +open_hw_target +current_hw_device [get_hw_devices xc7a35t_0] +refresh_hw_server [current_hw_server] +open_hw_target [lindex [get_hw_targets] 0] +set_property PROGRAM.FILE {./riscv-basys3/riscv-basys3.runs/impl_1/Top.bit} [get_hw_devices xc7a35t_0] +program_hw_devices [get_hw_devices xc7a35t_0] +close_hw_target diff --git a/lab2/vivado/basys3/run.ps1 b/lab2/vivado/basys3/run.ps1 new file mode 100644 index 0000000..178feab --- /dev/null +++ b/lab2/vivado/basys3/run.ps1 @@ -0,0 +1,4 @@ +cd .. +sbt run +cd vivado +C:\Xilinx\Vivado\2020.1\bin\vivado -mode batch -source .\generate_and_program.tcl \ No newline at end of file diff --git a/lab2/vivado/basys3/run_simulation.tcl b/lab2/vivado/basys3/run_simulation.tcl new file mode 100644 index 0000000..7c1a23c --- /dev/null +++ b/lab2/vivado/basys3/run_simulation.tcl @@ -0,0 +1,24 @@ +# 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. + +source open_project.tcl + +launch_simulation +restart +open_vcd +log_wave -recursive [get_object /test/top/cpu/*] +log_vcd [get_object /test/top/cpu/*] +run 1000ns +close_vcd +close_sim diff --git a/lab2/vivado/pynq/generate_and_program.tcl b/lab2/vivado/pynq/generate_and_program.tcl new file mode 100644 index 0000000..71df1af --- /dev/null +++ b/lab2/vivado/pynq/generate_and_program.tcl @@ -0,0 +1,17 @@ +# 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. + +# Only tested on Vivado 2020.1 on Windows 10 +source generate_bitstream.tcl +source program_device.tcl \ No newline at end of file diff --git a/lab2/vivado/pynq/generate_bitstream.tcl b/lab2/vivado/pynq/generate_bitstream.tcl new file mode 100644 index 0000000..8e7055a --- /dev/null +++ b/lab2/vivado/pynq/generate_bitstream.tcl @@ -0,0 +1,57 @@ +# 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. + +source open_project.tcl +set_param general.maxThreads 16 +set_param pwropt.maxFaninFanoutToNetRatio 5000 + +while 1 { + if { [catch {launch_runs synth_1 -jobs 16 } ] } { + regexp {ERROR: \[Common (\d+-\d+)]} $errorInfo -> code + if { [string equal $code "12-978"] } { + puts "Already generated and up-to-date" + break + } elseif { [string equal $code "17-69"] } { + puts "Out of date, reset runs" + reset_runs synth_1 + continue + } else { + puts "UNKNOWN ERROR!!! $errorInfo" + exit + } + } + break +} + +wait_on_run synth_1 + +while 1 { + if { [catch {launch_runs impl_1 -jobs 16 -to_step write_bitstream } ] } { + regexp {ERROR: \[Vivado (\d+-\d+)]} $errorInfo -> code + if { [string equal $code "12-978"] } { + puts "Already generated and up-to-date" + break + } elseif { [string equal $code "12-1088"] } { + puts "Out of date, reset runs" + reset_runs impl_1 + continue + } else { + puts "UNKNOWN ERROR!!! $errorInfo" + exit + } + } + break +} + +wait_on_run impl_1 diff --git a/lab2/vivado/pynq/open_project.tcl b/lab2/vivado/pynq/open_project.tcl new file mode 100644 index 0000000..52d029f --- /dev/null +++ b/lab2/vivado/pynq/open_project.tcl @@ -0,0 +1,40 @@ +# 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. + +# Only tested on Vivado 2020.1 on Windows 10 + +# set variables +set project_dir riscv-pynq +set project_name riscv-pynq +set part xc7z020clg400-1 +set sources {../../verilog/pynq/Top.v} +set test_sources {../../verilog/pynq/test.v} + +# open the project. will create one if it doesn't exist +if {[file exist $project_dir]} { + # check that it's a directory + if {! [file isdirectory $project_dir]} { + puts "$project_dir exists, but it's a file" + } + open_project $project_dir/$project_name.xpr -part $part +} else { + create_project $project_name $project_dir -part $part +} + +add_files -norecurse $sources +add_files -norecurse ../../verilog/pynq/TMDS_PLLVR.v +update_compile_order -fileset sources_1 +add_files -fileset constrs_1 -norecurse pynq.xdc +add_files -fileset sim_1 -norecurse $test_sources +update_compile_order -fileset sim_1 diff --git a/lab2/vivado/pynq/program_device.tcl b/lab2/vivado/pynq/program_device.tcl new file mode 100644 index 0000000..8da4e29 --- /dev/null +++ b/lab2/vivado/pynq/program_device.tcl @@ -0,0 +1,22 @@ +# 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. + +# Only tested on Vivado 2020.1 on Windows 10 +open_hw_manager +connect_hw_server -allow_non_jtag +refresh_hw_server [current_hw_server] +open_hw_target [lindex [get_hw_targets] 0] +set_property PROGRAM.FILE {riscv-pynq/riscv-pynq.runs/impl_1/Top.bit} [get_hw_devices xc7z020_1] +program_hw_devices [get_hw_devices xc7z020_1] +close_hw_target diff --git a/lab2/vivado/pynq/pynq.xdc b/lab2/vivado/pynq/pynq.xdc new file mode 100644 index 0000000..8c22de7 --- /dev/null +++ b/lab2/vivado/pynq/pynq.xdc @@ -0,0 +1,191 @@ +## This file is a general .xdc for the PYNQ-Z1 board Rev. C +## To use it in a project: +## - uncomment the lines corresponding to used pins +## - rename the used ports (in each line, after get_ports) according to the top level signal names in the project + +## Clock signal 125 MHz + +set_property -dict {PACKAGE_PIN H16 IOSTANDARD LVCMOS33} [get_ports clock] +create_clock -period 8.000 -name sys_clk_pin -waveform {0.000 4.000} -add [get_ports clock] + +##Switches + +set_property -dict { PACKAGE_PIN M20 IOSTANDARD LVCMOS33 } [get_ports { io_debug_step }]; #IO_L7N_T1_AD2N_35 Sch=sw[0] +#set_property -dict { PACKAGE_PIN M19 IOSTANDARD LVCMOS33 } [get_ports { sw[1] }]; #IO_L7P_T1_AD2P_35 Sch=sw[1] + +##RGB LEDs + +#set_property -dict { PACKAGE_PIN L15 IOSTANDARD LVCMOS33 } [get_ports { led4_b }]; #IO_L22N_T3_AD7N_35 Sch=led4_b +#set_property -dict { PACKAGE_PIN G17 IOSTANDARD LVCMOS33 } [get_ports { led4_g }]; #IO_L16P_T2_35 Sch=led4_g +#set_property -dict { PACKAGE_PIN N15 IOSTANDARD LVCMOS33 } [get_ports { led4_r }]; #IO_L21P_T3_DQS_AD14P_35 Sch=led4_r +#set_property -dict { PACKAGE_PIN G14 IOSTANDARD LVCMOS33 } [get_ports { led5_b }]; #IO_0_35 Sch=led5_b +#set_property -dict { PACKAGE_PIN L14 IOSTANDARD LVCMOS33 } [get_ports { led5_g }]; #IO_L22P_T3_AD7P_35 Sch=led5_g +#set_property -dict { PACKAGE_PIN M15 IOSTANDARD LVCMOS33 } [get_ports { led5_r }]; #IO_L23N_T3_35 Sch=led5_r + +##LEDs + +set_property -dict {PACKAGE_PIN R14 IOSTANDARD LVCMOS33} [get_ports {io_led[0]}] +set_property -dict {PACKAGE_PIN P14 IOSTANDARD LVCMOS33} [get_ports {io_led[1]}] +set_property -dict {PACKAGE_PIN N16 IOSTANDARD LVCMOS33} [get_ports {io_led[2]}] +set_property -dict {PACKAGE_PIN M14 IOSTANDARD LVCMOS33} [get_ports {io_led[3]}] + +##Buttons + +set_property -dict {PACKAGE_PIN D19 IOSTANDARD LVCMOS33} [get_ports reset] +set_property -dict { PACKAGE_PIN D20 IOSTANDARD LVCMOS33 } [get_ports { io_debug_clk }]; #IO_L4N_T0_35 Sch=btn[1] +#set_property -dict { PACKAGE_PIN L20 IOSTANDARD LVCMOS33 } [get_ports { btn[2] }]; #IO_L9N_T1_DQS_AD3N_35 Sch=btn[2] +#set_property -dict { PACKAGE_PIN L19 IOSTANDARD LVCMOS33 } [get_ports { btn[3] }]; #IO_L9P_T1_DQS_AD3P_35 Sch=btn[3] + +##Pmod Header JA + +#set_property -dict { PACKAGE_PIN Y18 IOSTANDARD LVCMOS33 } [get_ports { io_rx }]; #IO_L17P_T2_34 Sch=ja_p[1] +#set_property -dict { PACKAGE_PIN Y19 IOSTANDARD LVCMOS33 } [get_ports { io_tx }]; #IO_L17N_T2_34 Sch=ja_n[1] +set_property -dict {PACKAGE_PIN Y16 IOSTANDARD LVCMOS33} [get_ports io_rx] +set_property -dict {PACKAGE_PIN Y17 IOSTANDARD LVCMOS33} [get_ports io_tx] +#set_property -dict { PACKAGE_PIN U18 IOSTANDARD LVCMOS33 } [get_ports { ja[4] }]; #IO_L12P_T1_MRCC_34 Sch=ja_p[3] +#set_property -dict { PACKAGE_PIN U19 IOSTANDARD LVCMOS33 } [get_ports { ja[5] }]; #IO_L12N_T1_MRCC_34 Sch=ja_n[3] +#set_property -dict { PACKAGE_PIN W18 IOSTANDARD LVCMOS33 } [get_ports { ja[6] }]; #IO_L22P_T3_34 Sch=ja_p[4] +#set_property -dict { PACKAGE_PIN W19 IOSTANDARD LVCMOS33 } [get_ports { ja[7] }]; #IO_L22N_T3_34 Sch=ja_n[4] + +##Pmod Header JB + +#set_property -dict { PACKAGE_PIN W14 IOSTANDARD LVCMOS33 } [get_ports { jb[0] }]; #IO_L8P_T1_34 Sch=jb_p[1] +#set_property -dict { PACKAGE_PIN Y14 IOSTANDARD LVCMOS33 } [get_ports { jb[1] }]; #IO_L8N_T1_34 Sch=jb_n[1] +#set_property -dict { PACKAGE_PIN T11 IOSTANDARD LVCMOS33 } [get_ports { jb[2] }]; #IO_L1P_T0_34 Sch=jb_p[2] +#set_property -dict { PACKAGE_PIN T10 IOSTANDARD LVCMOS33 } [get_ports { jb[3] }]; #IO_L1N_T0_34 Sch=jb_n[2] +#set_property -dict { PACKAGE_PIN V16 IOSTANDARD LVCMOS33 } [get_ports { jb[4] }]; #IO_L18P_T2_34 Sch=jb_p[3] +#set_property -dict { PACKAGE_PIN W16 IOSTANDARD LVCMOS33 } [get_ports { jb[5] }]; #IO_L18N_T2_34 Sch=jb_n[3] +#set_property -dict { PACKAGE_PIN V12 IOSTANDARD LVCMOS33 } [get_ports { jb[6] }]; #IO_L4P_T0_34 Sch=jb_p[4] +#set_property -dict { PACKAGE_PIN W13 IOSTANDARD LVCMOS33 } [get_ports { jb[7] }]; #IO_L4N_T0_34 Sch=jb_n[4] + +##Audio Out + +#set_property -dict { PACKAGE_PIN R18 IOSTANDARD LVCMOS33 } [get_ports { aud_pwm }]; #IO_L20N_T3_34 Sch=aud_pwm +#set_property -dict { PACKAGE_PIN T17 IOSTANDARD LVCMOS33 } [get_ports { aud_sd }]; #IO_L20P_T3_34 Sch=aud_sd + +##Mic input + +#set_property -dict { PACKAGE_PIN F17 IOSTANDARD LVCMOS33 } [get_ports { m_clk }]; #IO_L6N_T0_VREF_35 Sch=m_clk +#set_property -dict { PACKAGE_PIN G18 IOSTANDARD LVCMOS33 } [get_ports { m_data }]; #IO_L16N_T2_35 Sch=m_data + +##ChipKit Single Ended Analog Inputs +##NOTE: The ck_an_p pins can be used as single ended analog inputs with voltages from 0-3.3V (Chipkit Analog pins A0-A5). +## These signals should only be connected to the XADC core. When using these pins as digital I/O, use pins ck_io[14-19]. + +#set_property -dict { PACKAGE_PIN D18 IOSTANDARD LVCMOS33 } [get_ports { ck_an_n[0] }]; #IO_L3N_T0_DQS_AD1N_35 Sch=ck_an_n[0] +#set_property -dict { PACKAGE_PIN E17 IOSTANDARD LVCMOS33 } [get_ports { ck_an_p[0] }]; #IO_L3P_T0_DQS_AD1P_35 Sch=ck_an_p[0] +#set_property -dict { PACKAGE_PIN E19 IOSTANDARD LVCMOS33 } [get_ports { ck_an_n[1] }]; #IO_L5N_T0_AD9N_35 Sch=ck_an_n[1] +#set_property -dict { PACKAGE_PIN E18 IOSTANDARD LVCMOS33 } [get_ports { ck_an_p[1] }]; #IO_L5P_T0_AD9P_35 Sch=ck_an_p[1] +#set_property -dict { PACKAGE_PIN J14 IOSTANDARD LVCMOS33 } [get_ports { ck_an_n[2] }]; #IO_L20N_T3_AD6N_35 Sch=ck_an_n[2] +#set_property -dict { PACKAGE_PIN K14 IOSTANDARD LVCMOS33 } [get_ports { ck_an_p[2] }]; #IO_L20P_T3_AD6P_35 Sch=ck_an_p[2] +#set_property -dict { PACKAGE_PIN J16 IOSTANDARD LVCMOS33 } [get_ports { ck_an_n[3] }]; #IO_L24N_T3_AD15N_35 Sch=ck_an_n[3] +#set_property -dict { PACKAGE_PIN K16 IOSTANDARD LVCMOS33 } [get_ports { ck_an_p[3] }]; #IO_L24P_T3_AD15P_35 Sch=ck_an_p[3] +#set_property -dict { PACKAGE_PIN H20 IOSTANDARD LVCMOS33 } [get_ports { ck_an_n[4] }]; #IO_L17N_T2_AD5N_35 Sch=ck_an_n[4] +#set_property -dict { PACKAGE_PIN J20 IOSTANDARD LVCMOS33 } [get_ports { ck_an_p[4] }]; #IO_L17P_T2_AD5P_35 Sch=ck_an_p[4] +#set_property -dict { PACKAGE_PIN G20 IOSTANDARD LVCMOS33 } [get_ports { ck_an_n[5] }]; #IO_L18N_T2_AD13N_35 Sch=ck_an_n[5] +#set_property -dict { PACKAGE_PIN G19 IOSTANDARD LVCMOS33 } [get_ports { ck_an_p[5] }]; #IO_L18P_T2_AD13P_35 Sch=ck_an_p[5] + +##ChipKit Digital I/O Low + +#set_property -dict { PACKAGE_PIN T14 IOSTANDARD LVCMOS33 } [get_ports { ck_io[0] }]; #IO_L5P_T0_34 Sch=ck_io[0] +#set_property -dict { PACKAGE_PIN U12 IOSTANDARD LVCMOS33 } [get_ports { ck_io[1] }]; #IO_L2N_T0_34 Sch=ck_io[1] +#set_property -dict { PACKAGE_PIN U13 IOSTANDARD LVCMOS33 } [get_ports { ck_io[2] }]; #IO_L3P_T0_DQS_PUDC_B_34 Sch=ck_io[2] +#set_property -dict { PACKAGE_PIN V13 IOSTANDARD LVCMOS33 } [get_ports { ck_io[3] }]; #IO_L3N_T0_DQS_34 Sch=ck_io[3] +#set_property -dict { PACKAGE_PIN V15 IOSTANDARD LVCMOS33 } [get_ports { ck_io[4] }]; #IO_L10P_T1_34 Sch=ck_io[4] +#set_property -dict { PACKAGE_PIN T15 IOSTANDARD LVCMOS33 } [get_ports { ck_io[5] }]; #IO_L5N_T0_34 Sch=ck_io[5] +#set_property -dict { PACKAGE_PIN R16 IOSTANDARD LVCMOS33 } [get_ports { ck_io[6] }]; #IO_L19P_T3_34 Sch=ck_io[6] +#set_property -dict { PACKAGE_PIN U17 IOSTANDARD LVCMOS33 } [get_ports { ck_io[7] }]; #IO_L9N_T1_DQS_34 Sch=ck_io[7] +#set_property -dict { PACKAGE_PIN V17 IOSTANDARD LVCMOS33 } [get_ports { ck_io[8] }]; #IO_L21P_T3_DQS_34 Sch=ck_io[8] +#set_property -dict { PACKAGE_PIN V18 IOSTANDARD LVCMOS33 } [get_ports { ck_io[9] }]; #IO_L21N_T3_DQS_34 Sch=ck_io[9] +#set_property -dict { PACKAGE_PIN T16 IOSTANDARD LVCMOS33 } [get_ports { ck_io[10] }]; #IO_L9P_T1_DQS_34 Sch=ck_io[10] +#set_property -dict { PACKAGE_PIN R17 IOSTANDARD LVCMOS33 } [get_ports { ck_io[11] }]; #IO_L19N_T3_VREF_34 Sch=ck_io[11] +#set_property -dict { PACKAGE_PIN P18 IOSTANDARD LVCMOS33 } [get_ports { ck_io[12] }]; #IO_L23N_T3_34 Sch=ck_io[12] +#set_property -dict { PACKAGE_PIN N17 IOSTANDARD LVCMOS33 } [get_ports { ck_io[13] }]; #IO_L23P_T3_34 Sch=ck_io[13] + +##ChipKit Digital I/O On Outer Analog Header +##NOTE: These pins should be used when using the analog header signals A0-A5 as digital I/O (Chipkit digital pins 14-19) + +#set_property -dict { PACKAGE_PIN Y11 IOSTANDARD LVCMOS33 } [get_ports { ck_io[14] }]; #IO_L18N_T2_13 Sch=ck_a[0] +#set_property -dict { PACKAGE_PIN Y12 IOSTANDARD LVCMOS33 } [get_ports { ck_io[15] }]; #IO_L20P_T3_13 Sch=ck_a[1] +#set_property -dict { PACKAGE_PIN W11 IOSTANDARD LVCMOS33 } [get_ports { ck_io[16] }]; #IO_L18P_T2_13 Sch=ck_a[2] +#set_property -dict { PACKAGE_PIN V11 IOSTANDARD LVCMOS33 } [get_ports { ck_io[17] }]; #IO_L21P_T3_DQS_13 Sch=ck_a[3] +#set_property -dict { PACKAGE_PIN T5 IOSTANDARD LVCMOS33 } [get_ports { ck_io[18] }]; #IO_L19P_T3_13 Sch=ck_a[4] +#set_property -dict { PACKAGE_PIN U10 IOSTANDARD LVCMOS33 } [get_ports { ck_io[19] }]; #IO_L12N_T1_MRCC_13 Sch=ck_a[5] + +##ChipKit Digital I/O On Inner Analog Header +##NOTE: These pins will need to be connected to the XADC core when used as differential analog inputs (Chipkit analog pins A6-A11) + +#set_property -dict { PACKAGE_PIN B20 IOSTANDARD LVCMOS33 } [get_ports { ck_io[20] }]; #IO_L1N_T0_AD0N_35 Sch=ad_n[0] +#set_property -dict { PACKAGE_PIN C20 IOSTANDARD LVCMOS33 } [get_ports { ck_io[21] }]; #IO_L1P_T0_AD0P_35 Sch=ad_p[0] +#set_property -dict { PACKAGE_PIN F20 IOSTANDARD LVCMOS33 } [get_ports { ck_io[22] }]; #IO_L15N_T2_DQS_AD12N_35 Sch=ad_n[12] +#set_property -dict { PACKAGE_PIN F19 IOSTANDARD LVCMOS33 } [get_ports { ck_io[23] }]; #IO_L15P_T2_DQS_AD12P_35 Sch=ad_p[12] +#set_property -dict { PACKAGE_PIN A20 IOSTANDARD LVCMOS33 } [get_ports { ck_io[24] }]; #IO_L2N_T0_AD8N_35 Sch=ad_n[8] +#set_property -dict { PACKAGE_PIN B19 IOSTANDARD LVCMOS33 } [get_ports { ck_io[25] }]; #IO_L2P_T0_AD8P_35 Sch=ad_p[8] + +##ChipKit Digital I/O High + +#set_property -dict { PACKAGE_PIN U5 IOSTANDARD LVCMOS33 } [get_ports { ck_io[26] }]; #IO_L19N_T3_VREF_13 Sch=ck_io[26] +#set_property -dict { PACKAGE_PIN V5 IOSTANDARD LVCMOS33 } [get_ports { ck_io[27] }]; #IO_L6N_T0_VREF_13 Sch=ck_io[27] +#set_property -dict { PACKAGE_PIN V6 IOSTANDARD LVCMOS33 } [get_ports { ck_io[28] }]; #IO_L22P_T3_13 Sch=ck_io[28] +#set_property -dict { PACKAGE_PIN U7 IOSTANDARD LVCMOS33 } [get_ports { ck_io[29] }]; #IO_L11P_T1_SRCC_13 Sch=ck_io[29] +#set_property -dict { PACKAGE_PIN V7 IOSTANDARD LVCMOS33 } [get_ports { ck_io[30] }]; #IO_L11N_T1_SRCC_13 Sch=ck_io[30] +#set_property -dict { PACKAGE_PIN U8 IOSTANDARD LVCMOS33 } [get_ports { ck_io[31] }]; #IO_L17N_T2_13 Sch=ck_io[31] +#set_property -dict { PACKAGE_PIN V8 IOSTANDARD LVCMOS33 } [get_ports { ck_io[32] }]; #IO_L15P_T2_DQS_13 Sch=ck_io[32] +#set_property -dict { PACKAGE_PIN V10 IOSTANDARD LVCMOS33 } [get_ports { ck_io[33] }]; #IO_L21N_T3_DQS_13 Sch=ck_io[33] +#set_property -dict { PACKAGE_PIN W10 IOSTANDARD LVCMOS33 } [get_ports { ck_io[34] }]; #IO_L16P_T2_13 Sch=ck_io[34] +#set_property -dict { PACKAGE_PIN W6 IOSTANDARD LVCMOS33 } [get_ports { ck_io[35] }]; #IO_L22N_T3_13 Sch=ck_io[35] +#set_property -dict { PACKAGE_PIN Y6 IOSTANDARD LVCMOS33 } [get_ports { ck_io[36] }]; #IO_L13N_T2_MRCC_13 Sch=ck_io[36] +#set_property -dict { PACKAGE_PIN Y7 IOSTANDARD LVCMOS33 } [get_ports { ck_io[37] }]; #IO_L13P_T2_MRCC_13 Sch=ck_io[37] +#set_property -dict { PACKAGE_PIN W8 IOSTANDARD LVCMOS33 } [get_ports { ck_io[38] }]; #IO_L15N_T2_DQS_13 Sch=ck_io[38] +#set_property -dict { PACKAGE_PIN Y8 IOSTANDARD LVCMOS33 } [get_ports { ck_io[39] }]; #IO_L14N_T2_SRCC_13 Sch=ck_io[39] +#set_property -dict { PACKAGE_PIN W9 IOSTANDARD LVCMOS33 } [get_ports { ck_io[40] }]; #IO_L16N_T2_13 Sch=ck_io[40] +#set_property -dict { PACKAGE_PIN Y9 IOSTANDARD LVCMOS33 } [get_ports { ck_io[41] }]; #IO_L14P_T2_SRCC_13 Sch=ck_io[41] +#set_property -dict { PACKAGE_PIN Y13 IOSTANDARD LVCMOS33 } [get_ports { ck_io[42] }]; #IO_L20N_T3_13 Sch=ck_ioa + +## ChipKit SPI + +#set_property -dict { PACKAGE_PIN W15 IOSTANDARD LVCMOS33 } [get_ports { ck_miso }]; #IO_L10N_T1_34 Sch=ck_miso +#set_property -dict { PACKAGE_PIN T12 IOSTANDARD LVCMOS33 } [get_ports { ck_mosi }]; #IO_L2P_T0_34 Sch=ck_mosi +#set_property -dict { PACKAGE_PIN H15 IOSTANDARD LVCMOS33 } [get_ports { ck_sck }]; #IO_L19P_T3_35 Sch=ck_sck +#set_property -dict { PACKAGE_PIN F16 IOSTANDARD LVCMOS33 } [get_ports { ck_ss }]; #IO_L6P_T0_35 Sch=ck_ss + +## ChipKit I2C + +#set_property -dict { PACKAGE_PIN P16 IOSTANDARD LVCMOS33 } [get_ports { ck_scl }]; #IO_L24N_T3_34 Sch=ck_scl +#set_property -dict { PACKAGE_PIN P15 IOSTANDARD LVCMOS33 } [get_ports { ck_sda }]; #IO_L24P_T3_34 Sch=ck_sda + +##HDMI Rx + +#set_property -dict { PACKAGE_PIN H17 IOSTANDARD LVCMOS33 } [get_ports { hdmi_rx_cec }]; #IO_L13N_T2_MRCC_35 Sch=hdmi_rx_cec +#set_property -dict { PACKAGE_PIN P19 IOSTANDARD TMDS_33 } [get_ports { io_debug_hdmi_clk_n }]; #IO_L13N_T2_MRCC_34 Sch=hdmi_rx_clk_n +#set_property -dict { PACKAGE_PIN N18 IOSTANDARD TMDS_33 } [get_ports { io_debug_hdmi_clk_p }]; #IO_L13P_T2_MRCC_34 Sch=hdmi_rx_clk_p +#set_property -dict { PACKAGE_PIN W20 IOSTANDARD TMDS_33 } [get_ports { io_debug_hdmi_data_n[0] }]; #IO_L16N_T2_34 Sch=hdmi_rx_d_n[0] +#set_property -dict { PACKAGE_PIN V20 IOSTANDARD TMDS_33 } [get_ports { io_debug_hdmi_data_p[0] }]; #IO_L16P_T2_34 Sch=hdmi_rx_d_p[0] +#set_property -dict { PACKAGE_PIN U20 IOSTANDARD TMDS_33 } [get_ports { io_debug_hdmi_data_n[1] }]; #IO_L15N_T2_DQS_34 Sch=hdmi_rx_d_n[1] +#set_property -dict { PACKAGE_PIN T20 IOSTANDARD TMDS_33 } [get_ports { io_debug_hdmi_data_p[1] }]; #IO_L15P_T2_DQS_34 Sch=hdmi_rx_d_p[1] +#set_property -dict { PACKAGE_PIN P20 IOSTANDARD TMDS_33 } [get_ports { io_debug_hdmi_data_n[2] }]; #IO_L14N_T2_SRCC_34 Sch=hdmi_rx_d_n[2] +#set_property -dict { PACKAGE_PIN N20 IOSTANDARD TMDS_33 } [get_ports { io_debug_hdmi_data_p[2] }]; #IO_L14P_T2_SRCC_34 Sch=hdmi_rx_d_p[2] +#set_property -dict { PACKAGE_PIN T19 IOSTANDARD LVCMOS33 } [get_ports { io_debug_hdmi_hpdn }]; #IO_25_34 Sch=hdmi_rx_hpd +#set_property -dict { PACKAGE_PIN U14 IOSTANDARD LVCMOS33 } [get_ports { hdmi_rx_scl }]; #IO_L11P_T1_SRCC_34 Sch=hdmi_rx_scl +#set_property -dict { PACKAGE_PIN U15 IOSTANDARD LVCMOS33 } [get_ports { hdmi_rx_sda }]; #IO_L11N_T1_SRCC_34 Sch=hdmi_rx_sda + +##HDMI Tx + +#set_property -dict { PACKAGE_PIN G15 IOSTANDARD LVCMOS33 } [get_ports { hdmi_tx_cec }]; #IO_L19N_T3_VREF_35 Sch=hdmi_tx_cec +set_property -dict {PACKAGE_PIN L17 IOSTANDARD TMDS_33} [get_ports io_hdmi_clk_n] +set_property -dict {PACKAGE_PIN L16 IOSTANDARD TMDS_33} [get_ports io_hdmi_clk_p] +set_property -dict {PACKAGE_PIN K18 IOSTANDARD TMDS_33} [get_ports {io_hdmi_data_n[0]}] +set_property -dict {PACKAGE_PIN K17 IOSTANDARD TMDS_33} [get_ports {io_hdmi_data_p[0]}] +set_property -dict {PACKAGE_PIN J19 IOSTANDARD TMDS_33} [get_ports {io_hdmi_data_n[1]}] +set_property -dict {PACKAGE_PIN K19 IOSTANDARD TMDS_33} [get_ports {io_hdmi_data_p[1]}] +set_property -dict {PACKAGE_PIN H18 IOSTANDARD TMDS_33} [get_ports {io_hdmi_data_n[2]}] +set_property -dict {PACKAGE_PIN J18 IOSTANDARD TMDS_33} [get_ports {io_hdmi_data_p[2]}] +set_property -dict {PACKAGE_PIN R19 IOSTANDARD LVCMOS33} [get_ports io_hdmi_hpdn] +#set_property -dict { PACKAGE_PIN M17 IOSTANDARD LVCMOS33 } [get_ports { hdmi_tx_scl }]; #IO_L8P_T1_AD10P_35 Sch=hdmi_tx_scl +#set_property -dict { PACKAGE_PIN M18 IOSTANDARD LVCMOS33 } [get_ports { hdmi_tx_sda }]; #IO_L8N_T1_AD10N_35 Sch=hdmi_tx_sda + +##Crypto SDA + +#set_property -dict { PACKAGE_PIN J15 IOSTANDARD LVCMOS33 } [get_ports { crypto_sda }]; #IO_25_35 Sch=crypto_sda + + diff --git a/lab2/vivado/pynq/run.ps1 b/lab2/vivado/pynq/run.ps1 new file mode 100644 index 0000000..178feab --- /dev/null +++ b/lab2/vivado/pynq/run.ps1 @@ -0,0 +1,4 @@ +cd .. +sbt run +cd vivado +C:\Xilinx\Vivado\2020.1\bin\vivado -mode batch -source .\generate_and_program.tcl \ No newline at end of file diff --git a/lab2/vivado/pynq/run_simulation.tcl b/lab2/vivado/pynq/run_simulation.tcl new file mode 100644 index 0000000..f1f021a --- /dev/null +++ b/lab2/vivado/pynq/run_simulation.tcl @@ -0,0 +1,28 @@ +# 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. + +source open_project.tcl + +launch_simulation +restart +open_vcd +#log_wave -recursive [get_object /test/top/hdmi_display/*] +#log_vcd [get_object /test/top/hdmi_display/*] +#log_wave -recursive [get_object /test/top/*] +#log_vcd [get_object /test/top/*] +log_wave -recursive [get_object /test/top/hdmi_display/serdesBlue/osr10/*] +log_vcd [get_object /test/top/hdmi_display/serdesBlue/osr10/*] +run 1000000ns +close_vcd +close_sim diff --git a/lab3/.gitignore b/lab3/.gitignore new file mode 100644 index 0000000..946816b --- /dev/null +++ b/lab3/.gitignore @@ -0,0 +1,358 @@ +### Project Specific stuff +test_run_dir/* +### XilinxISE template +# intermediate build files +*.bgn +*.bit +*.bld +*.cmd_log +*.drc +*.ll +*.lso +*.msd +*.msk +*.ncd +*.ngc +*.ngd +*.ngr +*.pad +*.par +*.pcf +*.prj +*.ptwx +*.rbb +*.rbd +*.stx +*.syr +*.twr +*.twx +*.unroutes +*.ut +*.xpi +*.xst +*_bitgen.xwbt +*_envsettings.html +*_map.map +*_map.mrp +*_map.ngm +*_map.xrpt +*_ngdbuild.xrpt +*_pad.csv +*_pad.txt +*_par.xrpt +*_summary.html +*_summary.xml +*_usage.xml +*_xst.xrpt + +# project-wide generated files +*.gise +par_usage_statistics.html +usage_statistics_webtalk.html +webtalk.log +webtalk_pn.xml + +# generated folders +iseconfig/ +xlnx_auto_0_xdb/ +xst/ +_ngo/ +_xmsgs/ +### Eclipse template +*.pydevproject +.metadata +.gradle +bin/ +tmp/ +*.tmp +*.bak +*.swp +*~.nib +local.properties +.settings/ +.loadpath + +# Eclipse Core +.project + +# External tool builders +.externalToolBuilders/ + +# Locally stored "Eclipse launch configurations" +*.launch + +# CDT-specific +.cproject + +# JDT-specific (Eclipse Java Development Tools) +.classpath + +# Java annotation processor (APT) +.factorypath + +# PDT-specific +.buildpath + +# sbteclipse plugin +.target + +# TeXlipse plugin +.texlipse +### C template +# Object files +*.o +*.ko +*.obj +*.elf + +# Precompiled Headers +*.gch +*.pch + +# Libraries +*.lib +*.a +*.la +*.lo + +# Shared objects (inc. Windows DLLs) +*.dll +*.so +*.so.* +*.dylib + +# Executables +*.exe +*.out +*.app +*.i*86 +*.x86_64 +*.hex + +# Debug files +*.dSYM/ +### SBT template +# Simple Build Tool +# http://www.scala-sbt.org/release/docs/Getting-Started/Directories.html#configuring-version-control + +target/ +lib_managed/ +src_managed/ +project/boot/ +.history +.cache +### Emacs template +# -*- mode: gitignore; -*- +*~ +\#*\# +/.emacs.desktop +/.emacs.desktop.lock +*.elc +auto-save-list +tramp +.\#* + +# Org-mode +.org-id-locations +*_archive + +# flymake-mode +*_flymake.* + +# eshell files +/eshell/history +/eshell/lastdir + +# elpa packages +/elpa/ + +# reftex files +*.rel + +# AUCTeX auto folder +/auto/ + +# cask packages +.cask/ +### Vim template +[._]*.s[a-w][a-z] +[._]s[a-w][a-z] +*.un~ +Session.vim +.netrwhist +*~ +### JetBrains template +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio + +*.iml + +## Directory-based project format: +.idea/ +# if you remove the above rule, at least ignore the following: + +# User-specific stuff: +# .idea/workspace.xml +# .idea/tasks.xml +# .idea/dictionaries + +# Sensitive or high-churn files: +# .idea/dataSources.ids +# .idea/dataSources.xml +# .idea/sqlDataSources.xml +# .idea/dynamic.xml +# .idea/uiDesigner.xml + +# Gradle: +# .idea/gradle.xml +# .idea/libraries + +# Mongo Explorer plugin: +# .idea/mongoSettings.xml + +## File-based project format: +*.ipr +*.iws + +## Plugin-specific files: + +# IntelliJ +/out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +### C++ template +# Compiled Object files +*.slo +*.lo +*.o +*.obj + +# Precompiled Headers +*.gch +*.pch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app +### OSX template +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk +### Xcode template +# Xcode +# +# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore + +## Build generated +build/ +DerivedData + +## Various settings +*.pbxuser +!default.pbxuser +*.mode1v3 +!default.mode1v3 +*.mode2v3 +!default.mode2v3 +*.perspectivev3 +!default.perspectivev3 +xcuserdata + +## Other +*.xccheckout +*.moved-aside +*.xcuserstate +### Scala template +*.class +*.log +/.bsp + +# sbt specific +.cache +.history +.lib/ +dist/* +target/ +lib_managed/ +src_managed/ +project/boot/ +project/plugins/project/ + +# Scala-IDE specific +.scala_dependencies +.worksheet +### Java template +*.class + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.ear + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* + +verilog/*.txt +verilog/basys3/* +verilog/pynq/* +verilog/verilator/* +!verilog/basys3/test.v +!verilog/pynq/design_1_wrapper.v +!verilog/pynq/test.v +!verilog/pynq/TMDS_PLLVR.v +!verilog/verilator/sim_main.cpp +*.jou +*.log +.Xil +vivado/basys3/riscv-basys3 +vivado/pynq/riscv-pynq +vivado/pynq/NA +.vscode +.metals diff --git a/lab3/Makefile b/lab3/Makefile new file mode 100644 index 0000000..78b42ff --- /dev/null +++ b/lab3/Makefile @@ -0,0 +1,55 @@ +# 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. + +test: + sbt test + +verilator: + sbt "runMain board.verilator.VerilogGenerator" + cd verilog/verilator && verilator --trace --exe --cc sim_main.cpp Top.v && make -C obj_dir -f VTop.mk + +verilator-sim: verilator + cd verilog/verilator && obj_dir/VTop $(SIM_TIME) + +basys3: + sbt "runMain board.basys3.VerilogGenerator" +pynq: + sbt "runMain board.pynq.VerilogGenerator" + +bitstream-basys3: basys3 + cd vivado/basys3 && vivado -mode batch -source generate_bitstream.tcl + +program-basys3: bitstream-basys3 + cd vivado/basys3 && vivado -mode batch -source program_device.tcl + +vivado-sim-basys3: basys3 + cd vivado/basys3 && vivado -mode batch -source run_simulation.tcl +bitstream-pynq: pynq + cd vivado/pynq && vivado -mode batch -source generate_bitstream.tcl + +program-pynq: bitstream-pynq + cd vivado/pynq && vivado -mode batch -source program_device.tcl + +vivado-sim-pynq: pynq + cd vivado/pynq && vivado -mode batch -source run_simulation.tcl + +arch-test: verilator + cp -r ../lab3 ~ && \ + cd ~/riscv-arch-test && \ + export TARGET_SIM=~/lab3/verilog/verilator/obj_dir/VTop && \ + export TARGETDIR=~/lab3/riscv-target && \ + export RISCV_TARGET=yatcpu && \ + make + +.PHONY: basys3 verilator test bitstream program verilator-sim vivado-sim diff --git a/lab3/build.sbt b/lab3/build.sbt new file mode 100644 index 0000000..75f138e --- /dev/null +++ b/lab3/build.sbt @@ -0,0 +1,24 @@ +import sbt.Keys.libraryDependencies +// See README.md for license details. + +ThisBuild / scalaVersion := "2.13.10" +ThisBuild / version := "0.1.0" +ThisBuild / organization := "io.github.howardlau1999" + +val chiselVersion = "3.6.0" + +lazy val root = (project in file(".")) + .settings( + name := "yatcpu", + libraryDependencies ++= Seq( + "edu.berkeley.cs" %% "chisel3" % chiselVersion, + "edu.berkeley.cs" %% "chiseltest" % "0.6.0" % "test", + ), + scalacOptions ++= Seq( + "-language:reflectiveCalls", + "-deprecation", + "-feature", + "-Xcheckinit", + ), + addCompilerPlugin("edu.berkeley.cs" % "chisel3-plugin" % chiselVersion cross CrossVersion.full), + ) diff --git a/lab3/coremark/yatcpu/core_portme.c b/lab3/coremark/yatcpu/core_portme.c new file mode 100644 index 0000000..3d7ae3b --- /dev/null +++ b/lab3/coremark/yatcpu/core_portme.c @@ -0,0 +1,169 @@ +/* +Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) + +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. + +Original Author: Shay Gal-on +*/ +#include "coremark.h" +#include "core_portme.h" + +#if VALIDATION_RUN +volatile ee_s32 seed1_volatile = 0x3415; +volatile ee_s32 seed2_volatile = 0x3415; +volatile ee_s32 seed3_volatile = 0x66; +#endif +#if PERFORMANCE_RUN +volatile ee_s32 seed1_volatile = 0x0; +volatile ee_s32 seed2_volatile = 0x0; +volatile ee_s32 seed3_volatile = 0x66; +#endif +#if PROFILE_RUN +volatile ee_s32 seed1_volatile = 0x8; +volatile ee_s32 seed2_volatile = 0x8; +volatile ee_s32 seed3_volatile = 0x8; +#endif +volatile ee_s32 seed4_volatile = ITERATIONS; +volatile ee_s32 seed5_volatile = 0; +/* Porting : Timing functions + How to capture time and convert to seconds must be ported to whatever is + supported by the platform. e.g. Read value from on board RTC, read value from + cpu clock cycles performance counter etc. Sample implementation for standard + time.h and windows.h definitions included. +*/ +CORETIMETYPE +barebones_clock() +{ + ee_u32 cyclel; + __asm__ __volatile__ ( + "rdcycle %0" : "=r"(cyclel) : : + ); + return cyclel; +} +/* Define : TIMER_RES_DIVIDER + Divider to trade off timer resolution and total time that can be + measured. + + Use lower values to increase resolution, but make sure that overflow + does not occur. If there are issues with the return value overflowing, + increase this value. + */ +#define GETMYTIME(_t) (*_t = barebones_clock()) +#define MYTIMEDIFF(fin, ini) ((fin) - (ini)) +#define TIMER_RES_DIVIDER 1 +#define SAMPLE_TIME_IMPLEMENTATION 1 +#define EE_TICKS_PER_SEC (CLOCKS_PER_SEC / TIMER_RES_DIVIDER) + +/** Define Host specific (POSIX), or target specific global time variables. */ +static CORETIMETYPE start_time_val, stop_time_val; + +/* Function : start_time + This function will be called right before starting the timed portion of + the benchmark. + + Implementation may be capturing a system timer (as implemented in the + example code) or zeroing some system parameters - e.g. setting the cpu clocks + cycles to 0. +*/ +void +start_time(void) +{ + GETMYTIME(&start_time_val); +} +/* Function : stop_time + This function will be called right after ending the timed portion of the + benchmark. + + Implementation may be capturing a system timer (as implemented in the + example code) or other system parameters - e.g. reading the current value of + cpu cycles counter. +*/ +void +stop_time(void) +{ + GETMYTIME(&stop_time_val); +} +/* Function : get_time + Return an abstract "ticks" number that signifies time on the system. + + Actual value returned may be cpu cycles, milliseconds or any other + value, as long as it can be converted to seconds by . This + methodology is taken to accommodate any hardware or simulated platform. The + sample implementation returns millisecs by default, and the resolution is + controlled by +*/ +CORE_TICKS +get_time(void) +{ + CORE_TICKS elapsed + = (CORE_TICKS)(MYTIMEDIFF(stop_time_val, start_time_val)); + return elapsed; +} +/* Function : time_in_secs + Convert the value returned by get_time to seconds. + + The type is used to accommodate systems with no support for + floating point. Default implementation implemented by the EE_TICKS_PER_SEC + macro above. +*/ +secs_ret +time_in_secs(CORE_TICKS ticks) +{ + secs_ret retval = ((secs_ret)ticks) / (secs_ret)EE_TICKS_PER_SEC; + return retval; +} + +ee_u32 default_num_contexts = 1; + +/* Function : portable_init + Target specific initialization code + Test for some common mistakes. +*/ +void +portable_init(core_portable *p, int *argc, char *argv[]) +{ + if (sizeof(ee_ptr_int) != sizeof(ee_u8 *)) + { + ee_printf( + "ERROR! Please define ee_ptr_int to a type that holds a " + "pointer!\n"); + } + if (sizeof(ee_u32) != 4) + { + ee_printf("ERROR! Please define ee_u32 to a 32b unsigned type!\n"); + } + p->portable_id = 1; +} +/* Function : portable_fini + Target specific final code +*/ +void +portable_fini(core_portable *p) +{ + p->portable_id = 0; +} + +unsigned int +__mulsi3 (unsigned int a, unsigned int b) +{ + unsigned int r = 0; + + while (a) + { + if (a & 1) + r += b; + a >>= 1; + b <<= 1; + } + return r; +} \ No newline at end of file diff --git a/lab3/coremark/yatcpu/core_portme.h b/lab3/coremark/yatcpu/core_portme.h new file mode 100644 index 0000000..7b0d646 --- /dev/null +++ b/lab3/coremark/yatcpu/core_portme.h @@ -0,0 +1,211 @@ +/* +Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) + +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. + +Original Author: Shay Gal-on +*/ +/* Topic : Description + This file contains configuration constants required to execute on + different platforms +*/ +#ifndef CORE_PORTME_H +#define CORE_PORTME_H +/************************/ +/* Data types and settings */ +/************************/ +/* Configuration : HAS_FLOAT + Define to 1 if the platform supports floating point. +*/ +#ifndef HAS_FLOAT +#define HAS_FLOAT 0 +#endif +/* Configuration : HAS_TIME_H + Define to 1 if platform has the time.h header file, + and implementation of functions thereof. +*/ +#ifndef HAS_TIME_H +#define HAS_TIME_H 0 +#define CLOCKS_PER_SEC 100000000 +#endif +/* Configuration : USE_CLOCK + Define to 1 if platform has the time.h header file, + and implementation of functions thereof. +*/ +#ifndef USE_CLOCK +#define USE_CLOCK 0 +#endif +/* Configuration : HAS_STDIO + Define to 1 if the platform has stdio.h. +*/ +#ifndef HAS_STDIO +#define HAS_STDIO 0 +#endif +/* Configuration : HAS_PRINTF + Define to 1 if the platform has stdio.h and implements the printf + function. +*/ +#ifndef HAS_PRINTF +#define HAS_PRINTF 0 +#endif + +/* Definitions : COMPILER_VERSION, COMPILER_FLAGS, MEM_LOCATION + Initialize these strings per platform +*/ +#ifndef COMPILER_VERSION +#ifdef __GNUC__ +#define COMPILER_VERSION "GCC"__VERSION__ +#else +#define COMPILER_VERSION "Please put compiler version here (e.g. gcc 4.1)" +#endif +#endif +#ifndef COMPILER_FLAGS +#define COMPILER_FLAGS \ + FLAGS_STR /* "Please put compiler flags here (e.g. -o3)" */ +#endif +#ifndef MEM_LOCATION +#define MEM_LOCATION "STACK" +#endif + +/* Data Types : + To avoid compiler issues, define the data types that need ot be used for + 8b, 16b and 32b in . + + *Imprtant* : + ee_ptr_int needs to be the data type used to hold pointers, otherwise + coremark may fail!!! +*/ +typedef signed short ee_s16; +typedef unsigned short ee_u16; +typedef signed int ee_s32; +typedef double ee_f32; +typedef unsigned char ee_u8; +typedef unsigned int ee_u32; +typedef ee_u32 ee_ptr_int; +typedef ee_u32 ee_size_t; +#define NULL ((void *)0) +/* align_mem : + This macro is used to align an offset to point to a 32b value. It is + used in the Matrix algorithm to initialize the input memory blocks. +*/ +#define align_mem(x) (void *)(4 + (((ee_ptr_int)(x)-1) & ~3)) + +/* Configuration : CORE_TICKS + Define type of return from the timing functions. + */ +#define CORETIMETYPE ee_u32 +typedef ee_u32 CORE_TICKS; + +/* Configuration : SEED_METHOD + Defines method to get seed values that cannot be computed at compile + time. + + Valid values : + SEED_ARG - from command line. + SEED_FUNC - from a system function. + SEED_VOLATILE - from volatile variables. +*/ +#ifndef SEED_METHOD +#define SEED_METHOD SEED_VOLATILE +#endif + +/* Configuration : MEM_METHOD + Defines method to get a block of memry. + + Valid values : + MEM_MALLOC - for platforms that implement malloc and have malloc.h. + MEM_STATIC - to use a static memory array. + MEM_STACK - to allocate the data block on the stack (NYI). +*/ +#ifndef MEM_METHOD +#define MEM_METHOD MEM_STATIC +#endif + +/* Configuration : MULTITHREAD + Define for parallel execution + + Valid values : + 1 - only one context (default). + N>1 - will execute N copies in parallel. + + Note : + If this flag is defined to more then 1, an implementation for launching + parallel contexts must be defined. + + Two sample implementations are provided. Use or + to enable them. + + It is valid to have a different implementation of + and in , to fit a particular architecture. +*/ +#ifndef MULTITHREAD +#define MULTITHREAD 1 +#define USE_PTHREAD 0 +#define USE_FORK 0 +#define USE_SOCKET 0 +#endif + +/* Configuration : MAIN_HAS_NOARGC + Needed if platform does not support getting arguments to main. + + Valid values : + 0 - argc/argv to main is supported + 1 - argc/argv to main is not supported + + Note : + This flag only matters if MULTITHREAD has been defined to a value + greater then 1. +*/ +#ifndef MAIN_HAS_NOARGC +#define MAIN_HAS_NOARGC 1 +#endif + +/* Configuration : MAIN_HAS_NORETURN + Needed if platform does not support returning a value from main. + + Valid values : + 0 - main returns an int, and return value will be 0. + 1 - platform does not support returning a value from main +*/ +#ifndef MAIN_HAS_NORETURN +#define MAIN_HAS_NORETURN 0 +#endif + +/* Variable : default_num_contexts + Not used for this simple port, must contain the value 1. +*/ +extern ee_u32 default_num_contexts; + +typedef struct CORE_PORTABLE_S +{ + ee_u8 portable_id; +} core_portable; + +/* target specific init/fini */ +void portable_init(core_portable *p, int *argc, char *argv[]); +void portable_fini(core_portable *p); + +#if !defined(PROFILE_RUN) && !defined(PERFORMANCE_RUN) \ + && !defined(VALIDATION_RUN) +#if (TOTAL_DATA_SIZE == 1200) +#define PROFILE_RUN 1 +#elif (TOTAL_DATA_SIZE == 2000) +#define PERFORMANCE_RUN 1 +#else +#define VALIDATION_RUN 1 +#endif +#endif + +int ee_printf(const char *fmt, ...); + +#endif /* CORE_PORTME_H */ diff --git a/lab3/coremark/yatcpu/core_portme.mak b/lab3/coremark/yatcpu/core_portme.mak new file mode 100644 index 0000000..e26c689 --- /dev/null +++ b/lab3/coremark/yatcpu/core_portme.mak @@ -0,0 +1,92 @@ +# Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) +# +# 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. +# +# Original Author: Shay Gal-on + +#File : core_portme.mak + +# Flag : OUTFLAG +# Use this flag to define how to to get an executable (e.g -o) +OUTFLAG= -o +# Flag : CC +# Use this flag to define compiler to use +CC = clang +# Flag : LD +# Use this flag to define compiler to use +LD = ld.lld +# Flag : AS +# Use this flag to define compiler to use +AS = clang +# Flag : CFLAGS +# Use this flag to define compiler options. Note, you can add compiler options from the command line using XCFLAGS="other flags" +PORT_CFLAGS = -O0 -g --target=riscv32-unknown-elf -march=rv32i -mabi=ilp32 +FLAGS_STR = "$(PORT_CFLAGS) $(XCFLAGS) $(XLFLAGS) $(LFLAGS_END)" +CFLAGS = $(PORT_CFLAGS) -I$(PORT_DIR) -I. -DFLAGS_STR=\"$(FLAGS_STR)\" +#Flag : LFLAGS_END +# Define any libraries needed for linking or other flags that should come at the end of the link line (e.g. linker scripts). +# Note : On certain platforms, the default clock_gettime implementation is supported but requires linking of librt. +SEPARATE_COMPILE=1 +# Flag : SEPARATE_COMPILE +# You must also define below how to create an object file, and how to link. +OBJOUT = -o +LFLAGS = -T $(PORT_DIR)/link.ld +ASFLAGS = -c --target=riscv32-unknown-elf -march=rv32i -mabi=ilp32 +OFLAG = -o +COUT = -c + +LFLAGS_END = +# Flag : PORT_SRCS +# Port specific source files can be added here +# You may also need cvt.c if the fcvt functions are not provided as intrinsics by your compiler! +PORT_SRCS = $(PORT_DIR)/core_portme.c $(PORT_DIR)/ee_printf.c $(PORT_DIR)/div.s $(PORT_DIR)/init.s +vpath %.c $(PORT_DIR) +vpath %.s $(PORT_DIR) + +PORT_OBJS = $(PORT_DIR)/init$(OEXT) $(PORT_DIR)/core_portme$(OEXT) $(PORT_DIR)/ee_printf$(OEXT) $(PORT_DIR)/div$(OEXT) +PORT_CLEAN = *$(OEXT) $(OUTFILE).asmbin + +# Flag : LOAD +# For a simple port, we assume self hosted compile and run, no load needed. + +# Flag : RUN +# For a simple port, we assume self hosted compile and run, simple invocation of the executable + +LOAD = echo "Please set LOAD to the process of loading the executable to the flash" +RUN = echo "Please set LOAD to the process of running the executable (e.g. via jtag, or board reset)" + +OEXT = .o +EXE = .bin + +$(OPATH)$(PORT_DIR)/%$(OEXT) : %.c + $(CC) $(CFLAGS) $(XCFLAGS) $(COUT) $< $(OBJOUT) $@ + +$(OPATH)%$(OEXT) : %.c + $(CC) $(CFLAGS) $(XCFLAGS) $(COUT) $< $(OBJOUT) $@ + +$(OPATH)$(PORT_DIR)/%$(OEXT) : %.s + $(AS) $(ASFLAGS) $< $(OBJOUT) $@ + +# Target : port_pre% and port_post% +# For the purpose of this simple port, no pre or post steps needed. + +.PHONY : port_prebuild port_postbuild port_prerun port_postrun port_preload port_postload +port_postbuild: $(OUTFILE) + llvm-objcopy -O binary -j .text -j .data $(OUTFILE) $(OUTFILE).asmbin +port_pre% port_post% : + +# FLAG : OPATH +# Path to the output folder. Default - current folder. +OPATH = ./ +MKDIR = mkdir -p + diff --git a/lab3/coremark/yatcpu/cvt.c b/lab3/coremark/yatcpu/cvt.c new file mode 100644 index 0000000..333e8ea --- /dev/null +++ b/lab3/coremark/yatcpu/cvt.c @@ -0,0 +1,127 @@ +/* +Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) + +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. +*/ +#include +#define CVTBUFSIZE 80 +static char CVTBUF[CVTBUFSIZE]; + +static char * +cvt(double arg, int ndigits, int *decpt, int *sign, char *buf, int eflag) +{ + int r2; + double fi, fj; + char * p, *p1; + + if (ndigits < 0) + ndigits = 0; + if (ndigits >= CVTBUFSIZE - 1) + ndigits = CVTBUFSIZE - 2; + r2 = 0; + *sign = 0; + p = &buf[0]; + if (arg < 0) + { + *sign = 1; + arg = -arg; + } + arg = modf(arg, &fi); + p1 = &buf[CVTBUFSIZE]; + + if (fi != 0) + { + p1 = &buf[CVTBUFSIZE]; + while (fi != 0) + { + fj = modf(fi / 10, &fi); + *--p1 = (int)((fj + .03) * 10) + '0'; + r2++; + } + while (p1 < &buf[CVTBUFSIZE]) + *p++ = *p1++; + } + else if (arg > 0) + { + while ((fj = arg * 10) < 1) + { + arg = fj; + r2--; + } + } + p1 = &buf[ndigits]; + if (eflag == 0) + p1 += r2; + *decpt = r2; + if (p1 < &buf[0]) + { + buf[0] = '\0'; + return buf; + } + while (p <= p1 && p < &buf[CVTBUFSIZE]) + { + arg *= 10; + arg = modf(arg, &fj); + *p++ = (int)fj + '0'; + } + if (p1 >= &buf[CVTBUFSIZE]) + { + buf[CVTBUFSIZE - 1] = '\0'; + return buf; + } + p = p1; + *p1 += 5; + while (*p1 > '9') + { + *p1 = '0'; + if (p1 > buf) + ++*--p1; + else + { + *p1 = '1'; + (*decpt)++; + if (eflag == 0) + { + if (p > buf) + *p = '0'; + p++; + } + } + } + *p = '\0'; + return buf; +} + +char * +ecvt(double arg, int ndigits, int *decpt, int *sign) +{ + return cvt(arg, ndigits, decpt, sign, CVTBUF, 1); +} + +char * +ecvtbuf(double arg, int ndigits, int *decpt, int *sign, char *buf) +{ + return cvt(arg, ndigits, decpt, sign, buf, 1); +} + +char * +fcvt(double arg, int ndigits, int *decpt, int *sign) +{ + return cvt(arg, ndigits, decpt, sign, CVTBUF, 0); +} + +char * +fcvtbuf(double arg, int ndigits, int *decpt, int *sign, char *buf) +{ + return cvt(arg, ndigits, decpt, sign, buf, 0); +} diff --git a/lab3/coremark/yatcpu/div.s b/lab3/coremark/yatcpu/div.s new file mode 100644 index 0000000..6725293 --- /dev/null +++ b/lab3/coremark/yatcpu/div.s @@ -0,0 +1,71 @@ +.text +.globl __divsi3 +__divsi3: + bltz a0, .L10 + bltz a1, .L11 + +.globl __udivsi3 +__udivsi3: + mv a2, a1 + mv a1, a0 + li a0, -1 + beqz a2, .L5 + li a3, 1 + bgeu a2, a1, .L2 +.L1: + blez a2, .L2 + slli a2, a2, 1 + slli a3, a3, 1 + bgtu a1, a2, .L1 +.L2: + li a0, 0 +.L3: + bltu a1, a2, .L4 + sub a1, a1, a2 + or a0, a0, a3 +.L4: + srli a3, a3, 1 + srli a2, a2, 1 + bnez a3, .L3 +.L5: + ret + +.globl __umodsi3 +__umodsi3: + move t0, ra + jal __udivsi3 + move a0, a1 + jr t0 + +.L10: + neg a0, a0 + bgtz a1, .L12 + + neg a1, a1 + j __udivsi3 +.L11: + neg a1, a1 +.L12: + move t0, ra + jal __udivsi3 + neg a0, a0 + jr t0 + +.globl __modsi3 +__modsi3: + move t0, ra + bltz a1, .L31 + bltz a0, .L32 +.L30: + jal __udivsi3 + move a0, a1 + jr t0 +.L31: + neg a1, a1 + bgez a0, .L30 +.L32: + neg a0, a0 + jal __udivsi3 + neg a0, a1 + jr t0 + diff --git a/lab3/coremark/yatcpu/ee_printf.c b/lab3/coremark/yatcpu/ee_printf.c new file mode 100644 index 0000000..9dde21a --- /dev/null +++ b/lab3/coremark/yatcpu/ee_printf.c @@ -0,0 +1,687 @@ +/* +Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) + +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. +*/ + +#include +#include + +#define ZEROPAD (1 << 0) /* Pad with zero */ +#define SIGN (1 << 1) /* Unsigned/signed long */ +#define PLUS (1 << 2) /* Show plus */ +#define SPACE (1 << 3) /* Spacer */ +#define LEFT (1 << 4) /* Left justified */ +#define HEX_PREP (1 << 5) /* 0x */ +#define UPPERCASE (1 << 6) /* 'ABCDEF' */ + +#define is_digit(c) ((c) >= '0' && (c) <= '9') + +static char * digits = "0123456789abcdefghijklmnopqrstuvwxyz"; +static char * upper_digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; +static ee_size_t strnlen(const char *s, ee_size_t count); + +static ee_size_t +strnlen(const char *s, ee_size_t count) +{ + const char *sc; + for (sc = s; *sc != '\0' && count--; ++sc) + ; + return sc - s; +} + +static int +skip_atoi(const char **s) +{ + int i = 0; + while (is_digit(**s)) + i = i * 10 + *((*s)++) - '0'; + return i; +} + +static char * +number(char *str, long num, int base, int size, int precision, int type) +{ + char c, sign, tmp[66]; + char *dig = digits; + int i; + + if (type & UPPERCASE) + dig = upper_digits; + if (type & LEFT) + type &= ~ZEROPAD; + if (base < 2 || base > 36) + return 0; + + c = (type & ZEROPAD) ? '0' : ' '; + sign = 0; + if (type & SIGN) + { + if (num < 0) + { + sign = '-'; + num = -num; + size--; + } + else if (type & PLUS) + { + sign = '+'; + size--; + } + else if (type & SPACE) + { + sign = ' '; + size--; + } + } + + if (type & HEX_PREP) + { + if (base == 16) + size -= 2; + else if (base == 8) + size--; + } + + i = 0; + + if (num == 0) + tmp[i++] = '0'; + else + { + while (num != 0) + { + tmp[i++] = dig[((unsigned long)num) % (unsigned)base]; + num = ((unsigned long)num) / (unsigned)base; + } + } + + if (i > precision) + precision = i; + size -= precision; + if (!(type & (ZEROPAD | LEFT))) + while (size-- > 0) + *str++ = ' '; + if (sign) + *str++ = sign; + + if (type & HEX_PREP) + { + if (base == 8) + *str++ = '0'; + else if (base == 16) + { + *str++ = '0'; + *str++ = digits[33]; + } + } + + if (!(type & LEFT)) + while (size-- > 0) + *str++ = c; + while (i < precision--) + *str++ = '0'; + while (i-- > 0) + *str++ = tmp[i]; + while (size-- > 0) + *str++ = ' '; + + return str; +} + +static char * +eaddr(char *str, unsigned char *addr, int size, int precision, int type) +{ + char tmp[24]; + char *dig = digits; + int i, len; + + if (type & UPPERCASE) + dig = upper_digits; + len = 0; + for (i = 0; i < 6; i++) + { + if (i != 0) + tmp[len++] = ':'; + tmp[len++] = dig[addr[i] >> 4]; + tmp[len++] = dig[addr[i] & 0x0F]; + } + + if (!(type & LEFT)) + while (len < size--) + *str++ = ' '; + for (i = 0; i < len; ++i) + *str++ = tmp[i]; + while (len < size--) + *str++ = ' '; + + return str; +} + +static char * +iaddr(char *str, unsigned char *addr, int size, int precision, int type) +{ + char tmp[24]; + int i, n, len; + + len = 0; + for (i = 0; i < 4; i++) + { + if (i != 0) + tmp[len++] = '.'; + n = addr[i]; + + if (n == 0) + tmp[len++] = digits[0]; + else + { + if (n >= 100) + { + tmp[len++] = digits[n / 100]; + n = n % 100; + tmp[len++] = digits[n / 10]; + n = n % 10; + } + else if (n >= 10) + { + tmp[len++] = digits[n / 10]; + n = n % 10; + } + + tmp[len++] = digits[n]; + } + } + + if (!(type & LEFT)) + while (len < size--) + *str++ = ' '; + for (i = 0; i < len; ++i) + *str++ = tmp[i]; + while (len < size--) + *str++ = ' '; + + return str; +} + +#if HAS_FLOAT + +char * ecvtbuf(double arg, int ndigits, int *decpt, int *sign, char *buf); +char * fcvtbuf(double arg, int ndigits, int *decpt, int *sign, char *buf); +static void ee_bufcpy(char *d, char *s, int count); + +void +ee_bufcpy(char *pd, char *ps, int count) +{ + char *pe = ps + count; + while (ps != pe) + *pd++ = *ps++; +} + +static void +parse_float(double value, char *buffer, char fmt, int precision) +{ + int decpt, sign, exp, pos; + char *digits = NULL; + char cvtbuf[80]; + int capexp = 0; + int magnitude; + + if (fmt == 'G' || fmt == 'E') + { + capexp = 1; + fmt += 'a' - 'A'; + } + + if (fmt == 'g') + { + digits = ecvtbuf(value, precision, &decpt, &sign, cvtbuf); + magnitude = decpt - 1; + if (magnitude < -4 || magnitude > precision - 1) + { + fmt = 'e'; + precision -= 1; + } + else + { + fmt = 'f'; + precision -= decpt; + } + } + + if (fmt == 'e') + { + digits = ecvtbuf(value, precision + 1, &decpt, &sign, cvtbuf); + + if (sign) + *buffer++ = '-'; + *buffer++ = *digits; + if (precision > 0) + *buffer++ = '.'; + ee_bufcpy(buffer, digits + 1, precision); + buffer += precision; + *buffer++ = capexp ? 'E' : 'e'; + + if (decpt == 0) + { + if (value == 0.0) + exp = 0; + else + exp = -1; + } + else + exp = decpt - 1; + + if (exp < 0) + { + *buffer++ = '-'; + exp = -exp; + } + else + *buffer++ = '+'; + + buffer[2] = (exp % 10) + '0'; + exp = exp / 10; + buffer[1] = (exp % 10) + '0'; + exp = exp / 10; + buffer[0] = (exp % 10) + '0'; + buffer += 3; + } + else if (fmt == 'f') + { + digits = fcvtbuf(value, precision, &decpt, &sign, cvtbuf); + if (sign) + *buffer++ = '-'; + if (*digits) + { + if (decpt <= 0) + { + *buffer++ = '0'; + *buffer++ = '.'; + for (pos = 0; pos < -decpt; pos++) + *buffer++ = '0'; + while (*digits) + *buffer++ = *digits++; + } + else + { + pos = 0; + while (*digits) + { + if (pos++ == decpt) + *buffer++ = '.'; + *buffer++ = *digits++; + } + } + } + else + { + *buffer++ = '0'; + if (precision > 0) + { + *buffer++ = '.'; + for (pos = 0; pos < precision; pos++) + *buffer++ = '0'; + } + } + } + + *buffer = '\0'; +} + +static void +decimal_point(char *buffer) +{ + while (*buffer) + { + if (*buffer == '.') + return; + if (*buffer == 'e' || *buffer == 'E') + break; + buffer++; + } + + if (*buffer) + { + int n = strnlen(buffer, 256); + while (n > 0) + { + buffer[n + 1] = buffer[n]; + n--; + } + + *buffer = '.'; + } + else + { + *buffer++ = '.'; + *buffer = '\0'; + } +} + +static void +cropzeros(char *buffer) +{ + char *stop; + + while (*buffer && *buffer != '.') + buffer++; + if (*buffer++) + { + while (*buffer && *buffer != 'e' && *buffer != 'E') + buffer++; + stop = buffer--; + while (*buffer == '0') + buffer--; + if (*buffer == '.') + buffer--; + while (buffer != stop) + *++buffer = 0; + } +} + +static char * +flt(char *str, double num, int size, int precision, char fmt, int flags) +{ + char tmp[80]; + char c, sign; + int n, i; + + // Left align means no zero padding + if (flags & LEFT) + flags &= ~ZEROPAD; + + // Determine padding and sign char + c = (flags & ZEROPAD) ? '0' : ' '; + sign = 0; + if (flags & SIGN) + { + if (num < 0.0) + { + sign = '-'; + num = -num; + size--; + } + else if (flags & PLUS) + { + sign = '+'; + size--; + } + else if (flags & SPACE) + { + sign = ' '; + size--; + } + } + + // Compute the precision value + if (precision < 0) + precision = 6; // Default precision: 6 + + // Convert floating point number to text + parse_float(num, tmp, fmt, precision); + + if ((flags & HEX_PREP) && precision == 0) + decimal_point(tmp); + if (fmt == 'g' && !(flags & HEX_PREP)) + cropzeros(tmp); + + n = strnlen(tmp, 256); + + // Output number with alignment and padding + size -= n; + if (!(flags & (ZEROPAD | LEFT))) + while (size-- > 0) + *str++ = ' '; + if (sign) + *str++ = sign; + if (!(flags & LEFT)) + while (size-- > 0) + *str++ = c; + for (i = 0; i < n; i++) + *str++ = tmp[i]; + while (size-- > 0) + *str++ = ' '; + + return str; +} + +#endif + +static int +ee_vsprintf(char *buf, const char *fmt, va_list args) +{ + int len; + unsigned long num; + int i, base; + char * str; + char * s; + + int flags; // Flags to number() + + int field_width; // Width of output field + int precision; // Min. # of digits for integers; max number of chars for + // from string + int qualifier; // 'h', 'l', or 'L' for integer fields + + for (str = buf; *fmt; fmt++) + { + if (*fmt != '%') + { + *str++ = *fmt; + continue; + } + + // Process flags + flags = 0; + repeat: + fmt++; // This also skips first '%' + switch (*fmt) + { + case '-': + flags |= LEFT; + goto repeat; + case '+': + flags |= PLUS; + goto repeat; + case ' ': + flags |= SPACE; + goto repeat; + case '#': + flags |= HEX_PREP; + goto repeat; + case '0': + flags |= ZEROPAD; + goto repeat; + } + + // Get field width + field_width = -1; + if (is_digit(*fmt)) + field_width = skip_atoi(&fmt); + else if (*fmt == '*') + { + fmt++; + field_width = va_arg(args, int); + if (field_width < 0) + { + field_width = -field_width; + flags |= LEFT; + } + } + + // Get the precision + precision = -1; + if (*fmt == '.') + { + ++fmt; + if (is_digit(*fmt)) + precision = skip_atoi(&fmt); + else if (*fmt == '*') + { + ++fmt; + precision = va_arg(args, int); + } + if (precision < 0) + precision = 0; + } + + // Get the conversion qualifier + qualifier = -1; + if (*fmt == 'l' || *fmt == 'L') + { + qualifier = *fmt; + fmt++; + } + + // Default base + base = 10; + + switch (*fmt) + { + case 'c': + if (!(flags & LEFT)) + while (--field_width > 0) + *str++ = ' '; + *str++ = (unsigned char)va_arg(args, int); + while (--field_width > 0) + *str++ = ' '; + continue; + + case 's': + s = va_arg(args, char *); + if (!s) + s = ""; + len = strnlen(s, precision); + if (!(flags & LEFT)) + while (len < field_width--) + *str++ = ' '; + for (i = 0; i < len; ++i) + *str++ = *s++; + while (len < field_width--) + *str++ = ' '; + continue; + + case 'p': + if (field_width == -1) + { + field_width = 2 * sizeof(void *); + flags |= ZEROPAD; + } + str = number(str, + (unsigned long)va_arg(args, void *), + 16, + field_width, + precision, + flags); + continue; + + case 'A': + flags |= UPPERCASE; + + case 'a': + if (qualifier == 'l') + str = eaddr(str, + va_arg(args, unsigned char *), + field_width, + precision, + flags); + else + str = iaddr(str, + va_arg(args, unsigned char *), + field_width, + precision, + flags); + continue; + + // Integer number formats - set up the flags and "break" + case 'o': + base = 8; + break; + + case 'X': + flags |= UPPERCASE; + + case 'x': + base = 16; + break; + + case 'd': + case 'i': + flags |= SIGN; + + case 'u': + break; + +#if HAS_FLOAT + + case 'f': + str = flt(str, + va_arg(args, double), + field_width, + precision, + *fmt, + flags | SIGN); + continue; + +#endif + + default: + if (*fmt != '%') + *str++ = '%'; + if (*fmt) + *str++ = *fmt; + else + --fmt; + continue; + } + + if (qualifier == 'l') + num = va_arg(args, unsigned long); + else if (flags & SIGN) + num = va_arg(args, int); + else + num = va_arg(args, unsigned int); + + str = number(str, num, base, field_width, precision, flags); + } + + *str = '\0'; + return str - buf; +} + +void +uart_send_char(char c) +{ + *((volatile unsigned int *) (0x40000010)) = c; +} + +int +ee_printf(const char *fmt, ...) +{ + char buf[1024], *p; + va_list args; + int n = 0; + + va_start(args, fmt); + ee_vsprintf(buf, fmt, args); + va_end(args); + p = buf; + while (*p) + { + uart_send_char(*p); + n++; + p++; + } + + return n; +} diff --git a/lab3/coremark/yatcpu/init.s b/lab3/coremark/yatcpu/init.s new file mode 100644 index 0000000..0efae64 --- /dev/null +++ b/lab3/coremark/yatcpu/init.s @@ -0,0 +1,16 @@ +.section .text.init +.globl _start +_start: + li sp, 4092 + call main + li x1, 0xBABECAFE +write_tohost: + sw x1, tohost, x0 +loop: + j loop + +.pushsection .tohost,"aw",@progbits + .align 4 + .global tohost + tohost: .word 0 +.popsection \ No newline at end of file diff --git a/lab3/coremark/yatcpu/link.ld b/lab3/coremark/yatcpu/link.ld new file mode 100644 index 0000000..2ae1500 --- /dev/null +++ b/lab3/coremark/yatcpu/link.ld @@ -0,0 +1,12 @@ +OUTPUT_ARCH( "riscv" ) +ENTRY(_start) + +SECTIONS +{ + . = 0x00001000; + .text : { *(.text.init) *(.text.startup) *(.text) } + .data ALIGN(0x1000) : { *(.data*) *(.rodata*) *(.sdata*) } + .tohost ALIGN(0x1000) : { *(.tohost) } + .bss : { *(.bss) } + _end = .; +} diff --git a/lab3/csrc/CMakeLists.txt b/lab3/csrc/CMakeLists.txt new file mode 100644 index 0000000..edbe658 --- /dev/null +++ b/lab3/csrc/CMakeLists.txt @@ -0,0 +1,43 @@ +# Make CMake happy +cmake_minimum_required(VERSION 3.18) +project(yatcpu-programs C CXX ASM) + +# Setting variables +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O0 --target=riscv32-unknown-elf -march=rv32i -mabi=ilp32") +set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -O0 --target=riscv32-unknown-elf -march=rv32i -mabi=ilp32") +set(C_PROGRAMS tetris hello fibonacci quicksort) +set(ASM_PROGRAMS mmio sb hazard) +set(LINKER_SCRIPT ${CMAKE_SOURCE_DIR}/link.lds) +set(LINKER_FLAGS -T ${LINKER_SCRIPT}) +set(OBJCOPY_ARGS -O binary -j .text -j .data) +if(NOT DEST_DIR) + set(DEST_DIR "../src/main/resources") +endif() + +# Let CMake know that there exists header files +include_directories("${CMAKE_SOURCE_DIR}") + +add_library(prelude init.S) +set_target_properties(prelude PROPERTIES LINK_DEPENDS ${LINKER_SCRIPT}) + +# Let's build our executables +foreach(program IN LISTS C_PROGRAMS) + add_executable(${program} ${program}.c) + set_target_properties(${program} PROPERTIES LINK_DEPENDS ${LINKER_SCRIPT}) + target_link_libraries(${program} prelude ${LINKER_FLAGS}) +endforeach() + +foreach(program IN LISTS ASM_PROGRAMS) + add_executable(${program} ${program}.S) + set_target_properties(${program} PROPERTIES LINK_DEPENDS ${LINKER_SCRIPT}) +endforeach() + +# Copy the .text section to .asmbin files +foreach(program IN LISTS C_PROGRAMS ASM_PROGRAMS) + add_custom_command( + TARGET ${program} + POST_BUILD + COMMAND ${CMAKE_OBJCOPY} ARGS ${OBJCOPY_ARGS} $ ${CMAKE_SOURCE_DIR}/${DEST_DIR}/${program}.asmbin + ) +endforeach() + diff --git a/lab3/csrc/build.bat b/lab3/csrc/build.bat new file mode 100644 index 0000000..b5a522b --- /dev/null +++ b/lab3/csrc/build.bat @@ -0,0 +1,3 @@ +rmdir /Q /S build +cmake -DCMAKE_TOOLCHAIN_FILE=toolchain.cmake -G"NMake Makefiles" -B build . +cmake --build build \ No newline at end of file diff --git a/lab3/csrc/build.sh b/lab3/csrc/build.sh new file mode 100644 index 0000000..e48a4ba --- /dev/null +++ b/lab3/csrc/build.sh @@ -0,0 +1,3 @@ +#!/bin/sh +rm -rf build +cmake -DCMAKE_TOOLCHAIN_FILE=toolchain.cmake -B build . && cmake --build build --parallel `nproc` diff --git a/lab3/csrc/fibonacci.c b/lab3/csrc/fibonacci.c new file mode 100644 index 0000000..9905dde --- /dev/null +++ b/lab3/csrc/fibonacci.c @@ -0,0 +1,22 @@ +// 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. + +int fib(int a) { + if (a == 1 || a == 2) return 1; + return fib(a - 1) + fib(a - 2); +} + +int main() { + *(int *)(4) = fib(10); +} \ No newline at end of file diff --git a/lab3/csrc/hazard.S b/lab3/csrc/hazard.S new file mode 100644 index 0000000..1d827ba --- /dev/null +++ b/lab3/csrc/hazard.S @@ -0,0 +1,48 @@ +# Copyright 2022 Canbin Huang +# +# 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. + +.globl _start +_start: + csrr a0, cycle + + addi t0, zero, 1 + sub t1, zero, t0 + and t2, t0, t1 + sw t2, 4(zero) + j skip1 + or t2, t0, t1 + xor t2, t0, t1 + +skip1: + addi t1, t2, 1 + add t2, t1, t2 + and t2, t1, t2 + lw t2, 2(t2) + or t3, t1, t2 + blt t2, t3, skip2 + or t3, t0, t0 + xor t3, t0, t1 + +skip2: + addi t4, zero, 3 + bne t3, t4, skip1 + sw t3, 8(zero) + auipc t4, 0 + jalr t4, 8(t4) + jalr t4, 4(t4) + csrr a1, cycle + sub ra, a1, a0 + +loop: + j loop \ No newline at end of file diff --git a/lab3/csrc/hello.c b/lab3/csrc/hello.c new file mode 100644 index 0000000..3e79635 --- /dev/null +++ b/lab3/csrc/hello.c @@ -0,0 +1,175 @@ +// 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. + +#include "mmio.h" + +#define MUL80(x) (((x) << 6) + ((x) << 4)) + +struct screen { + unsigned char row, col; +} scr; + +void copy_line(int prev, int cur) { + int *prev_vram_start = ((int *) (MUL80(prev) + VRAM_BASE)); + int *cur_vram_start = ((int *) (MUL80(cur) + VRAM_BASE)); + for (int i = 0; i < 20; ++i) { + prev_vram_start[i] = cur_vram_start[i]; + } +} + +void write_char(int row, int col, unsigned char ch) { + VRAM[MUL80(row) + col] = ch; +} + +void move_to(int row, int col) { + scr.row = row; + scr.col = col; +} + +void new_line() { + scr.col = 0; + if (scr.row == 29) { + for (int i = 0; i < 29; ++i) { + copy_line(i, i + 1); + } + int *vram = (int *) (MUL80(29) + VRAM_BASE); + for (int i = 0; i < 20; ++i) { + vram[i] = 0x20202020; + } + } else { + ++scr.row; + } +} + +void putch(unsigned char ch) { + if (ch == '\n') { + new_line(); + } else if (ch == '\r') { + scr.col = 0; + } else { + if (scr.col == 79) { + new_line(); + } + write_char(scr.row, scr.col, ch); + ++scr.col; + } +} + +void clear_screen() { + scr.row = 0; + scr.col = 0; + int *vram = ((int *) VRAM_BASE); + for (int i = 0; i < 600; ++i) vram[i] = 0x20202020; +} + +void print_hex(unsigned int counter) { + putch('0'); putch('x'); + for (int i = 7; i >= 0; --i) { + unsigned int num = (counter >> (i << 2)) & 0xF; + if (num < 10) { + putch('0' + num); + } else { + putch('A' + num - 10); + } + } +} + +void putstr(const char *s) { + while (*s) { + putch(*(s++)); + } +} + +int hc = 1; +int fast = 0; + +void print_timer() { + putstr("Hardware timer count limit = "); + print_hex(*TIMER_LIMIT); + putstr(", enabled = "); + print_hex(*TIMER_ENABLED); + putch('\n'); +} + +void print_uart() { + putstr("UART Baud rate = "); + print_hex(*UART_BAUDRATE); + putch('\n'); +} + +void handle_timer() { + putstr("Timer trigger times = "); + print_hex(hc++); + putch('\n'); + int mode = ((hc & 0x10) >> 4); + if (hc == 0x40) { + putstr("Disable timer!\n"); + *TIMER_ENABLED = 0; + print_timer(); + return; + } + if (fast ^ mode) { + putstr("Switch timer frequency\n"); + if (fast == 0) { + *TIMER_LIMIT = 25000000; + } else { + + *TIMER_LIMIT = 100000000; + } + fast = mode; + print_timer(); + } +} + +void handle_uart() { + unsigned int ch = *UART_RECV; + *UART_SEND = ch; + putstr("UART Recv hex = "); print_hex(ch); putstr(", ch = "); putch(ch); putch('\n'); +} + +void trap_handler(void *epc, unsigned int cause) { + putstr("Interrupt! EPC = "); + print_hex((unsigned int) epc); + putstr(", CAUSE = "); + print_hex(cause); + putch('\n'); + switch (cause) { + case 0x8000000B: + handle_uart(); + break; + default: + handle_timer(); + break; + } +} +extern void enable_interrupt(); +extern unsigned int get_epc(); +int main() { + clear_screen(); + hc = 0; + *TIMER_ENABLED = 1; + putstr("YatCPU Demo Program "); + putch(137); + putstr("2021 Howard Lau\n"); + putstr("Hello, world!\n"); + putstr("Last EPC = "); + print_hex(get_epc()); + putch('\n'); + print_timer(); + print_uart(); + *((int *) 0x4) = 0xDEADBEEF; + unsigned int i = 0; + enable_interrupt(); + for (;;) ; +} diff --git a/lab3/csrc/init.S b/lab3/csrc/init.S new file mode 100644 index 0000000..4534c78 --- /dev/null +++ b/lab3/csrc/init.S @@ -0,0 +1,107 @@ +# 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. + +.section .text.init +.globl _start +_start: + li sp, 4096 # Initialize stack pointer + call main # Jump to main function +loop: + j loop # Loop forever +.globl enable_interrupt +enable_interrupt: + la t0, __trap_entry + csrrw t1, mtvec, t0 # setup trap vector base + li t0, 0x1888 + csrrw t1, mstatus, t0 # enable interrupt + ret +.globl get_epc +get_epc: + csrr a0, mepc + ret +.weak trap_handler +tran_handler: + ret +__trap_entry: + csrw mscratch, sp + addi sp, sp, -128 + sw ra, 4(sp) + + sw gp, 12(sp) + sw tp, 16(sp) + sw t0, 20(sp) + sw t1, 24(sp) + sw t2, 28(sp) + sw tp, 32(sp) + sw s1, 36(sp) + sw a0, 40(sp) + sw a1, 44(sp) + sw a2, 48(sp) + sw a3, 52(sp) + sw a4, 56(sp) + sw a5, 60(sp) + sw a6, 64(sp) + sw a7, 68(sp) + sw s2, 72(sp) + sw s3, 76(sp) + sw s4, 80(sp) + sw s5, 84(sp) + sw s6, 88(sp) + sw s7, 92(sp) + sw s8, 96(sp) + sw s9, 100(sp) + sw s10, 104(sp) + sw s11, 108(sp) + sw t3, 112(sp) + sw t4, 116(sp) + sw t5, 120(sp) + sw t6, 124(sp) + + csrr a0, mepc + csrr a1, mcause + call trap_handler + + lw ra, 4(sp) + + lw gp, 12(sp) + lw tp, 16(sp) + lw t0, 20(sp) + lw t1, 24(sp) + lw t2, 28(sp) + lw tp, 32(sp) + lw s1, 36(sp) + lw a0, 40(sp) + lw a1, 44(sp) + lw a2, 48(sp) + lw a3, 52(sp) + lw a4, 56(sp) + lw a5, 60(sp) + lw a6, 64(sp) + lw a7, 68(sp) + lw s2, 72(sp) + lw s3, 76(sp) + lw s4, 80(sp) + lw s5, 84(sp) + lw s6, 88(sp) + lw s7, 92(sp) + lw s8, 96(sp) + lw s9, 100(sp) + lw s10, 104(sp) + lw s11, 108(sp) + lw t3, 112(sp) + lw t4, 116(sp) + lw t5, 120(sp) + lw t6, 124(sp) + csrr sp, mscratch + mret diff --git a/lab3/csrc/link.lds b/lab3/csrc/link.lds new file mode 100644 index 0000000..b5d8366 --- /dev/null +++ b/lab3/csrc/link.lds @@ -0,0 +1,11 @@ +OUTPUT_ARCH( "riscv" ) +ENTRY(_start) + +SECTIONS +{ + . = 0x00001000; + .text : { *(.text.init) *(.text.startup) *(.text) } + .data ALIGN(0x1000) : { *(.data*) *(.rodata*) *(.sdata*) } + .bss : { *(.bss) } + _end = .; +} diff --git a/lab3/csrc/mmio.S b/lab3/csrc/mmio.S new file mode 100644 index 0000000..7b49530 --- /dev/null +++ b/lab3/csrc/mmio.S @@ -0,0 +1,24 @@ +# 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. + +.globl _start +_start: + li a0, 0x80000000 + lw t0, 4(a0) + li a1, 0xBEEF + sw a1, 4(a0) + nop + lw t1, 4(a0) +loop: + j loop diff --git a/lab3/csrc/mmio.h b/lab3/csrc/mmio.h new file mode 100644 index 0000000..b1222dd --- /dev/null +++ b/lab3/csrc/mmio.h @@ -0,0 +1,23 @@ +// 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. + +#define VRAM_BASE 0x20000000 +#define VRAM ((volatile unsigned char *) VRAM_BASE) +#define TIMER_BASE 0x80000000 +#define TIMER_LIMIT ((volatile unsigned int *) (TIMER_BASE + 4)) +#define TIMER_ENABLED ((volatile unsigned int *) (TIMER_BASE + 8)) +#define UART_BASE 0x40000000 +#define UART_BAUDRATE ((volatile unsigned int *) (UART_BASE + 4)) +#define UART_RECV ((volatile unsigned int *) (UART_BASE + 12)) +#define UART_SEND ((volatile unsigned int *) (UART_BASE + 16)) diff --git a/lab3/csrc/quicksort.c b/lab3/csrc/quicksort.c new file mode 100644 index 0000000..5105ef1 --- /dev/null +++ b/lab3/csrc/quicksort.c @@ -0,0 +1,50 @@ +// 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. + +void quicksort(int *arr, int l, int r) { + if (l >= r) return; + int pivot = arr[l]; + int i = l, j = r; + while (i < j) { + while(arr[j] >= pivot && i < j) --j; + arr[i] = arr[j]; + while(arr[i] < pivot && i < j) ++i; + arr[j] = arr[i]; + } + arr[i] = pivot; + quicksort(arr, l, i - 1); + quicksort(arr, i + 1, r); +} + +int main() { + int nums[10]; + + nums[0] = 6; + nums[1] = 2; + nums[2] = 4; + nums[3] = 5; + nums[4] = 3; + nums[5] = 1; + nums[6] = 0; + nums[7] = 9; + nums[8] = 7; + nums[9] = 8; + + + quicksort(nums, 0, 9); + + for (int i = 1; i <= 10; ++i) { + *(int *)(i * 4) = nums[i - 1]; + } +} \ No newline at end of file diff --git a/lab3/csrc/sb.S b/lab3/csrc/sb.S new file mode 100644 index 0000000..ed71a72 --- /dev/null +++ b/lab3/csrc/sb.S @@ -0,0 +1,25 @@ +# 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. + +.globl _start +_start: + li a0, 0x4 + li t0, 0xDEADBEEF + sb t0, 0(a0) + lw t1, 0(a0) + li s2, 0x15 + sb s2, 1(a0) + lw ra, 0(a0) +loop: + j loop diff --git a/lab3/csrc/tetris.c b/lab3/csrc/tetris.c new file mode 100644 index 0000000..27b2b4c --- /dev/null +++ b/lab3/csrc/tetris.c @@ -0,0 +1,495 @@ +// 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. + +#ifdef DEBUG +#include +#endif + +#include "mmio.h" + +#define FALL_TIMER_LIMIT 50000000 +#define ROWS 22 +#define COLS 10 +#define OFFSET_X 28 +#define OFFSET_Y 3 +#define SCREEN_COLS 80 +#define SCREEN_ROWS 30 + +struct block { + unsigned int shape[3]; + unsigned int xywh; +}; + +struct block current; + +unsigned int score; + +unsigned char *board; + +#ifdef DEBUG +unsigned char screen[SCREEN_COLS * SCREEN_ROWS]; +#endif + +int wk_mul(int a, int b) { + int r = 0; + for (; b; a <<= 1, b >>= 1) + if (b & 1) + r += a; + return r; +} + +unsigned int make_xywh(unsigned int x, unsigned int y, unsigned int w, unsigned int h) { + return (x << 12) | (y << 4) | (w << 2) | h; +} + +void init_block(struct block *block, int type, int x, int y) { + int w = 0; int h = 0; + block->shape[0] = block->shape[1] = block->shape[2] = 0; + switch(type) { + case 0: // I + block->shape[0] = 0xF; + w = 3; h = 0; + break; + case 1: // O + block->shape[0] = 0x3; + block->shape[1] = 0x3; + w = 1; h = 1; + break; + case 2: // J + block->shape[0] = 0x4; + block->shape[1] = 0x7; + w = 2; h = 1; + break; + case 3: // T + block->shape[0] = 0x2; + block->shape[1] = 0x7; + w = 2; h = 1; + break; + case 4: // L + block->shape[0] = 0x1; + block->shape[1] = 0x7; + w = 2; h = 1; + break; + case 5: // Z + block->shape[0] = 0x6; + block->shape[1] = 0x3; + w = 2; h = 1; + break; + case 6: // S + block->shape[0] = 0x3; + block->shape[1] = 0x6; + w = 2; h = 1; + break; + } + block->xywh = make_xywh(x, y, w, h); +} + +unsigned int get_shape(struct block *block, unsigned int r, unsigned int c) { + return (block->shape[r] & (1 << c)) >> c; +} + +unsigned int check_bounds(struct block *block) { + unsigned int xywh = block->xywh; + unsigned int h = xywh & 0x3; + unsigned int w = (xywh & 0xC) >> 2; + unsigned int y = (xywh & 0xFF0) >> 4; + unsigned int x = (xywh & 0xF000) >> 12; + if (x < 0 || x + w >= COLS) return 0; + if (y < 0 || y + h >= ROWS) return 0; + return 1; +} + +void copy_block(struct block *dst, struct block *src) { + dst->xywh = src->xywh; + dst->shape[0] = src->shape[0]; + dst->shape[1] = src->shape[1]; + dst->shape[2] = src->shape[2]; +} + +unsigned int check_collision(struct block *block) { + unsigned int xywh = block->xywh; + unsigned int h = xywh & 0x3; + unsigned int w = (xywh & 0xC) >> 2; + unsigned int y = (xywh & 0xFF0) >> 4; + unsigned int x = (xywh & 0xF000) >> 12; + for (int r = 0; r <= h; ++r) { + for (int c = 0; c <= w; ++c) { + if (get_shape(block, r, c) && + board[wk_mul(y + r, COLS) + x + c]) + return 0; + } + } + return 1; +} + +void putch_at(int x, int y, unsigned char ch) { +#ifdef DEBUG + screen[wk_mul(OFFSET_Y + y, SCREEN_COLS) + x + OFFSET_X] = ch; +#else + VRAM[wk_mul(OFFSET_Y + y, SCREEN_COLS) + x + OFFSET_X] = ch; +#endif +} + +void block_move(struct block *block, int dir) { + unsigned int xywh = block->xywh; + unsigned int h = xywh & 0x3; + unsigned int w = (xywh & 0xC) >> 2; + unsigned int y = (xywh & 0xFF0) >> 4; + unsigned int x = (xywh & 0xF000) >> 12; + switch(dir) { + case 0: // Left + x--; + break; + case 1: // Right + x++; + break; + case 2: // Down + y++; + break; + default: + break; + } + block->xywh = (x << 12) | (y << 4) | (w << 2) | h; +} + +unsigned int move(struct block *block, int dir) { + struct block moved; + copy_block(&moved, block); + block_move(&moved, dir); + if (check_bounds(&moved) && check_collision(&moved)) { + copy_block(block, &moved); + return 1; + } + return 0; +} + +void block_rotate(struct block *block, unsigned int clock) { + unsigned int xywh = block->xywh; + unsigned int h = xywh & 0x3; + unsigned int w = (xywh & 0xC) >> 2; + unsigned int y = (xywh & 0xFF0) >> 4; + unsigned int x = (xywh & 0xF000) >> 12; + unsigned int xyhw = make_xywh(x, y, h, w); + unsigned int shape[3] = {0, 0, 0}; + if (clock) { + for (int r = 0; r <= h; ++r) { + for (int c = 0; c <= w; ++c) { + shape[c] = shape[c] | (get_shape(block, r, c) << (h - r)); + } + } + + } else { + for (int r = 0; r <= h; ++r) { + for (int c = 0; c <= w; ++c) { + shape[w - c] = shape[w - c] | (get_shape(block, r, c) << r); + } + } + } + block->shape[0] = shape[0]; + block->shape[1] = shape[1]; + block->shape[2] = shape[2]; + block->xywh = xyhw; +} + + +void rotate(struct block *block, int clock) { + struct block rotated; + copy_block(&rotated, block); + block_rotate(&rotated, clock); + if (check_bounds(&rotated) && check_collision(&rotated)) { + copy_block(block, &rotated); + return; + } + unsigned int xywh = rotated.xywh; + unsigned int h = xywh & 0x3; + unsigned int w = (xywh & 0xc) >> 2; + unsigned int y = (xywh & 0xff0) >> 4; + unsigned int x = (xywh & 0xf000) >> 12; + if (x + w >= COLS) { + x = COLS - w - 1; + } + rotated.xywh = make_xywh(x, y, w, h); + if (check_bounds(&rotated) && check_collision(&rotated)) { + copy_block(block, &rotated); + } +} + +void clear_board() { + for (int i = 0, s = wk_mul(ROWS, COLS); i < s; ++i) { + board[i] = 0; + } +} + +void fix_block(struct block *block) { + unsigned int xywh = block->xywh; + unsigned int h = xywh & 0x3; + unsigned int w = (xywh & 0xc) >> 2; + unsigned int y = (xywh & 0xff0) >> 4; + unsigned int x = (xywh & 0xf000) >> 12; +#ifdef DEBUG + printf("%d %d %d %d\n", x, y, w, h); +#endif + for (int r = 0; r <= h; ++r) { + for (int c = 0; c <= w; ++c) { + if (get_shape(block, r, c)) { + board[wk_mul(y + r, COLS) + x + c] = 1; + } + } + } +} + +void print_score() { + int c = 8; + putch_at(c++, -2, 'S'); + putch_at(c++, -2, 'C'); + putch_at(c++, -2, 'O'); + putch_at(c++, -2, 'R'); + putch_at(c++, -2, 'E'); + for (int i = 0; i < 5; ++i) { + unsigned int mask = 0xF << (i * 4); + unsigned int num = (score & mask) >> (i * 4); + putch_at(12 - i, -1, num + '0'); + } +} + +void draw_board() { + for (int r = 0; r < ROWS; ++r) { + for (int c = 0; c < COLS; ++c) { + if (board[wk_mul(r , COLS) + c] == 1) { + putch_at((c << 1) + 1, r, '['); + putch_at((c << 1) + 2, r, ']'); + } else { + putch_at((c << 1) + 1, r, ' '); + putch_at((c << 1)+ 2, r, ' '); + } + } + } + unsigned int xywh = current.xywh; + unsigned int h = xywh & 0x3; + unsigned int w = (xywh & 0xc) >> 2; + unsigned int y = (xywh & 0xff0) >> 4; + unsigned int x = (xywh & 0xf000) >> 12; + for (int r = 0; r <= h; ++r) { + for (int c = 0; c <= w; ++c) { + if (get_shape(¤t, r, c)) { + putch_at(((c + x) << 1) + 1, r + y, '['); + putch_at(((c + x) << 1) + 2, r + y, ']'); + } + } + } + print_score(); +} + + +void add_score(unsigned int delta) { + score += delta; + for (unsigned int i = 0, carry = 0; i < 32; i += 4) { + unsigned int mask = 0xF << i; + unsigned int num = (score & mask) >> i; + num += carry; + if (num >= 10) { + carry = 1; + num -= 10; + } else { + carry = 0; + } + score &= ~(mask); + score |= (num << i); + } +} + +void check_clear() { + unsigned int y = (current.xywh & 0xff0) >> 4; + unsigned int h = current.xywh & 0x3; + for (int r = y + h; r >= y; --r) { + unsigned int count = 0; + for (int c = 0; c < COLS; ++c) { + if (board[wk_mul(r , COLS) + c]) ++count; + } + if (count == COLS) { + add_score(1); + for (int nr = r - 1; nr > 0; --nr) { + for (int c = 0; c < COLS; ++c) { + board[wk_mul(nr + 1, COLS) + c] = board[wk_mul(nr, COLS) + c]; + } + } + ++r; ++y; + } + } +} + +unsigned int rand() { + static unsigned int seed = 990315; + seed = (wk_mul(1103515245 , seed) + 12345) & 0x7FFFFFFF; + return seed; +} + +unsigned int rand_type() { + unsigned int type = rand() & 0x7; + while (type == 7) { + type = rand() & 0x7; + } + return type; +} + +void fall() { + if (move(¤t, 2) == 0) { + fix_block(¤t); + check_clear(); + init_block(¤t, rand_type(), 4, 0); + } +} + +#ifdef DEBUG +void print_screen() { + for (int r = 0; r < SCREEN_ROWS; ++r) { + for (int c = 0; c < SCREEN_COLS; ++c) { + printf("%c", screen[wk_mul(r, SCREEN_COLS) + c]); + } + printf("\n"); + } + printf("\n"); +} +#endif + +void on_input(unsigned int ch) { + switch (ch) { + case 's': + fall(); + break; + case 'a': + move(¤t, 0); + break; + case 'd': + move(¤t, 1); + break; + case 'j': + rotate(¤t, 0); + break; + case 'k': + rotate(¤t, 1); + break; + } + draw_board(); +#ifdef DEBUG + print_screen(); +#endif +} + +void on_timer() { + fall(); + draw_board(); +} + +void trap_handler(void *epc, unsigned int cause) { + if (cause == 0x80000007) { + on_timer(); + } else { + unsigned int ch = *UART_RECV; + *UART_SEND = ch; + on_input(ch); + } +} + +void init() { + clear_board(); + // Draw border + for (int r = 0; r < ROWS; ++r) { + putch_at(0, r, '|'); + putch_at(COLS << 1 | 1, r, '|'); + } + for (int c = 0; c <= (2 << COLS | 1); ++c) { + putch_at(c, ROWS, '-'); + } + int c = 8; + putch_at(c++, ROWS + 1, 'T'); + putch_at(c++, ROWS + 1, 'E'); + putch_at(c++, ROWS + 1, 'T'); + putch_at(c++, ROWS + 1, 'R'); + putch_at(c++, ROWS + 1, 'I'); + putch_at(c++, ROWS + 1, 'S'); + c = 6; + putch_at(c++, ROWS + 3, 'H'); + putch_at(c++, ROWS + 3, 'o'); + putch_at(c++, ROWS + 3, 'w'); + putch_at(c++, ROWS + 3, 'a'); + putch_at(c++, ROWS + 3, 'r'); + putch_at(c++, ROWS + 3, 'd'); + c++; + putch_at(c++, ROWS + 3, 'L'); + putch_at(c++, ROWS + 3, 'a'); + putch_at(c++, ROWS + 3, 'u'); + c = 9; + putch_at(c++, ROWS + 4, '2'); + putch_at(c++, ROWS + 4, '0'); + putch_at(c++, ROWS + 4, '2'); + putch_at(c++, ROWS + 4, '1'); + init_block(¤t, rand_type(), 4, 0); + score = 0; + draw_board(); +} + +void clear_screen() { + int *vram = ((int *) VRAM_BASE); + for (int i = 0; i < 600; ++i) vram[i] = 0x20202020; +} + +extern void enable_interrupt(); + +int main() { +#ifdef DEBUG + unsigned char b[ROWS * COLS] = {0}; + board = b; + for (int i = 0; i < SCREEN_ROWS * SCREEN_COLS; ++i) screen[i] = '%'; + init(); +#else + board = (unsigned char *) 16384; + clear_screen(); + init(); + *((unsigned int *) 4) = 0xDEADBEEF; + enable_interrupt(); + *TIMER_ENABLED = 1; + *TIMER_LIMIT = FALL_TIMER_LIMIT; + for (;;); +#endif +#ifdef DEBUG + on_input('a'); + on_input('a'); + on_input('s'); + on_input('s'); + on_input('s'); + for (int i = 21; i >= 0; --i) { + on_timer(); + } + on_input('d'); + on_input('d'); + on_input('d'); + on_input('d'); + for (int i = 21; i >= 0; --i) { + on_timer(); + } + on_input('d'); + on_input('d'); + on_input('d'); + on_input('d'); + on_input('d'); + for (int i = 21; i >= 0; --i) { + on_timer(); + add_score(10); + } + print_score(); + print_screen(); + return 0; +#endif +} diff --git a/lab3/csrc/toolchain.cmake b/lab3/csrc/toolchain.cmake new file mode 100644 index 0000000..60bc5a9 --- /dev/null +++ b/lab3/csrc/toolchain.cmake @@ -0,0 +1,20 @@ +set(CMAKE_SYSTEM_NAME Generic) +set(CMAKE_SYSTEM_PROCESSOR riscv32) + +set(triple riscv32-unknown-elf) + +set(CMAKE_C_COMPILER clang) +set(CMAKE_C_COMPILER_TARGET ${triple}) +set(CMAKE_CXX_COMPILER clang++) +set(CMAKE_CXX_COMPILER_TARGET ${triple}) +set(CMAKE_ASM_COMPILER clang) +set(CMAKE_ASM_COMPILER_TARGET ${triple}) +set(CMAKE_AR llvm-ar CACHE FILEPATH "Archiver") +set(CMAKE_OBJCOPY llvm-objcopy) + +set(CMAKE_C_FLAGS_INIT "-mno-relax") +set(CMAKE_CXX_FLAGS_INIT "-mno-relax") +set(CMAKE_ASM_FLAGS_INIT "-mno-relax") +set(CMAKE_EXE_LINKER_FLAGS_INIT "-fuse-ld=lld -nostdlib -static -mno-relax") +set(CMAKE_MODULE_LINKER_FLAGS_INIT "-fuse-ld=lld -nostdlib -static -mno-relax") +set(CMAKE_SHARED_LINKER_FLAGS_INIT "-fuse-ld=lld -nostdlib -static -mno-relax") diff --git a/lab3/project/build.properties b/lab3/project/build.properties new file mode 100644 index 0000000..303541e --- /dev/null +++ b/lab3/project/build.properties @@ -0,0 +1 @@ +sbt.version = 1.9.6 diff --git a/lab3/project/plugins.sbt b/lab3/project/plugins.sbt new file mode 100644 index 0000000..5708f81 --- /dev/null +++ b/lab3/project/plugins.sbt @@ -0,0 +1 @@ +logLevel := Level.Warn diff --git a/lab3/riscv-target/yatcpu/Makefile.include b/lab3/riscv-target/yatcpu/Makefile.include new file mode 100644 index 0000000..e209499 --- /dev/null +++ b/lab3/riscv-target/yatcpu/Makefile.include @@ -0,0 +1,7 @@ +export TARGETDIR ?= riscv-target +export XLEN = 32 +export RISCV_TARGET = yatcpu +export RISCV_DEVICE = +export RISCV_TARGET_FLAGS = +export RISCV_ASSERT = 0 +JOBS = -j1 \ No newline at end of file diff --git a/lab3/riscv-target/yatcpu/device/rv32i_m/I/Makefile.include b/lab3/riscv-target/yatcpu/device/rv32i_m/I/Makefile.include new file mode 100644 index 0000000..d17e055 --- /dev/null +++ b/lab3/riscv-target/yatcpu/device/rv32i_m/I/Makefile.include @@ -0,0 +1,54 @@ +TARGET_SIM ?= verilog/verilator/obj_dir/VTop +TARGET_FLAGS ?= $(RISCV_TARGET_FLAGS) +ifeq ($(shell command -v $(TARGET_SIM) 2> /dev/null),) + $(error Target simulator executable '$(TARGET_SIM)` not found) +endif + +RISCV_PREFIX ?= riscv64-unknown-elf- +RISCV_GCC ?= $(RISCV_PREFIX)gcc +RISCV_OBJDUMP ?= $(RISCV_PREFIX)objdump +RISCV_OBJCOPY ?= $(RISCV_PREFIX)objcopy +RISCV_GCC_OPTS ?= -g -static -mcmodel=medany -fvisibility=hidden -nostdlib -nostartfiles $(RVTEST_DEFINES) + +COMPILE_CMD = $$(RISCV_GCC) $(1) $$(RISCV_GCC_OPTS) \ + -I$(ROOTDIR)/riscv-test-suite/env/ \ + -I$(TARGETDIR)/$(RISCV_TARGET)/ \ + -T$(TARGETDIR)/$(RISCV_TARGET)/link.ld \ + $$(<) -o $$@ + +OBJDUMP_CMD = $$(RISCV_OBJDUMP) $$@ -D > $$@.objdump; \ + $$(RISCV_OBJDUMP) $$@ --source > $$@.debug; \ + $$(RISCV_OBJDUMP) -t $$@ | grep " begin_signature$$$$" | awk '{ print $$$$1 }' > $$@.begin_signature; \ + $$(RISCV_OBJDUMP) -t $$@ | grep " end_signature$$$$" | awk '{ print $$$$1 }' > $$@.end_signature; \ + $$(RISCV_OBJDUMP) -t $$@ | grep " tohost$$$$" | awk '{ print $$$$1 }' > $$@.halt \ + + +OBJCOPY_CMD = $$(RISCV_OBJCOPY) $$@ -O binary -j .text -j .data -j .tohost $$@.asmbin + +COMPILE_TARGET=\ + $(COMPILE_CMD); \ + if [ $$$$? -ne 0 ] ; \ + then \ + echo "\e[31m$$(RISCV_GCC) failed for target $$(@) \e[39m" ; \ + exit 1 ; \ + fi ; \ + $(OBJDUMP_CMD); \ + if [ $$$$? -ne 0 ] ; \ + then \ + echo "\e[31m $$(RISCV_OBJDUMP) failed for target $$(@) \e[39m" ; \ + exit 1 ; \ + fi ; \ + $(OBJCOPY_CMD); \ + if [ $$$$? -ne 0 ] ; \ + then \ + echo "\e[31m $$(RISCV_OBJCOPY) failed for target $$(@) \e[39m" ; \ + exit 1 ; \ + fi ; \ + +RUN_CMD = $(TARGET_SIM) $(TARGET_FLAGS) \ + -signature 0x$(shell cat $(<).begin_signature) 0x$(shell cat $(<).end_signature) $(*).signature.output \ + -halt 0x$(shell cat $(<).halt) \ + -time 1000000 \ + -instruction $(<).asmbin +RUN_TARGET = \ + $(RUN_CMD) diff --git a/lab3/riscv-target/yatcpu/link.ld b/lab3/riscv-target/yatcpu/link.ld new file mode 100644 index 0000000..6afe7d6 --- /dev/null +++ b/lab3/riscv-target/yatcpu/link.ld @@ -0,0 +1,12 @@ +OUTPUT_ARCH( "riscv" ) +ENTRY(rvtest_entry_point) + +SECTIONS +{ + . = 0x00001000; + .text : { *(.text.init) *(.text.startup) *(.text) } + .data ALIGN(0x1000) : { *(.data*) *(.rodata*) *(.sdata*) } + .tohost ALIGN(0x1000) : { *(.tohost) } + .bss : { *(.bss) } + _end = .; +} diff --git a/lab3/riscv-target/yatcpu/model_test.h b/lab3/riscv-target/yatcpu/model_test.h new file mode 100644 index 0000000..ca8f8c6 --- /dev/null +++ b/lab3/riscv-target/yatcpu/model_test.h @@ -0,0 +1,46 @@ +#ifndef _COMPLIANCE_MODEL_H_ +#define _COMPLIANCE_MODEL_H_ + +#define ALIGNMENT 2 + +#define RVMODEL_DATA_SECTION \ + .pushsection .tohost,"aw",@progbits; \ + .align 4; .global tohost; tohost: .word 0; \ + .popsection; + +#define RVMODEL_BOOT + +#define RVMODEL_HALT \ + li x1, 0xBABECAFE; \ + write_tohost: \ + sw x1, tohost, x0; \ + loop: j loop + +//RV_COMPLIANCE_DATA_BEGIN +#define RVMODEL_DATA_BEGIN \ + .align 4; .global begin_signature; begin_signature: + +//RV_COMPLIANCE_DATA_END +#define RVMODEL_DATA_END \ + .align 4; .global end_signature; end_signature: \ + RVMODEL_DATA_SECTION \ + +//RVTEST_IO_INIT +#define RVMODEL_IO_INIT +//RVTEST_IO_WRITE_STR +#define RVMODEL_IO_WRITE_STR(_R, _STR) +//RVTEST_IO_CHECK +#define RVMODEL_IO_CHECK() +//RVTEST_IO_ASSERT_GPR_EQ +#define RVMODEL_IO_ASSERT_GPR_EQ(_S, _R, _I) +//RVTEST_IO_ASSERT_SFPR_EQ +#define RVMODEL_IO_ASSERT_SFPR_EQ(_F, _R, _I) +//RVTEST_IO_ASSERT_DFPR_EQ +#define RVMODEL_IO_ASSERT_DFPR_EQ(_D, _R, _I) + +#define RVMODEL_SET_MSW_INT +#define RVMODEL_CLEAR_MSW_INT +#define RVMODEL_CLEAR_MTIMER_INT +#define RVMODEL_CLEAR_MEXT_INT + +#endif diff --git a/lab3/src/main/resources/fibonacci.asmbin b/lab3/src/main/resources/fibonacci.asmbin new file mode 100644 index 0000000000000000000000000000000000000000..64069339cfb7969b109417089f2b2be66dddefde GIT binary patch literal 520 zcmXxhy=vS*5C`y?9qnzC;*7dLK&O%9vn~Ez|Dxks|DtLkj!@sb?I@4>wH?FxqtCE_ z7qIUWIDfqFW8LF&+b!TL4STWu)9+`oyqCeQu6r)FUA(dnGrE)fs(ZHj_}>k8p7oUJ kTa$pA!3?v}s!p?HyDS*n%Lo6L(@TggfErLUoW;TX1HN>BasU7T literal 0 HcmV?d00001 diff --git a/lab3/src/main/resources/hazard.asmbin b/lab3/src/main/resources/hazard.asmbin new file mode 100644 index 0000000000000000000000000000000000000000..9634dedd0a8868207a2c4709935706bc84493cb6 GIT binary patch literal 100 zcmXR`WjHXINr1taIly7_=OhMYr2>Y0h649(E6h80Wxo@CgTYRYt7IHgx-cW|26sYOSWJWp!4GRRiaAn5nP@1$Im>kboR$8Kjrhqyq38e%k&h<{ayq(o~lff>(z_deQEh{SbgGw+>q zzjMCxopaAj-v)s5?ErH&ypsid)&bm;C-uC0pl2rJJ-?NA^`0RcAaAwzif`|^UF$V9 z?Jf^(03O)^yek1b`ZDlX3V8Q1;4Go@&{>^_-`9EMW1V-^bRPXe=dqhQ@4lmRrcuOF z9`2-wr--MBr--MBr<|37hz}w@i1;AlgNP3zK8X0B;PR)%de0;0IlFqoVF_?LYd}Jp z=7bU&;U&%CH4Wc&C!ElURni@+rjv+9oJfL@%_ZV&t`X9u1)Q!#fNUuRoGrBgiE7k| zCMeljqR!SDB{9u#VhMw6D;dtVnnAj?pwpcQlI^9Sv%MC~cS3I-SPyE^;N7T2tORC2 z!&)aBylc8atp29kkpZ(K3A@TuFhhauq7~F^5`BTD`Hb?>55cpCCmSXO;GxMz7UF>T zhD&?2^wlX{zMpD1!gkK`&J&9QiOe=Wp`QXDp8_9a(heD8e$zb?MlD!PLyo%W-NRg6 z!@%B2z7xUO2BCk698L4x47lf#AYzk9p!rF;4t)kN@y+cictqSLkDvx&PXo=5i8VB5 zEUfA6sa8?5TQ0XvNIW1f!AE-(uRg@MwA^MI026i{NV44K(ra4!=}L>J)6)rgtD2iG zt!nAZzD}q+Y9Qys{>4Az=^`-mo9_2@05d5)%e$23*b{kfR%(95j}>S-7TT2NGZtfR znc@srl-{%0Gt^t)=U=^-1zQu`9pvto(Z0UY>cw5zhh=)Xl)}V1oQq_kX&U2@-dOkI zs~T?O{ah=2r~#y(mAOS8Q{g+e>5cNNj03+5E*?MBQ((!S4siAq znw}12iWmdT(}u6zccNzw)+cI_IpVTz?DIqYTUL+AA$W=UMIM3e!}<5;LTZikK#yAK z2U_=|)@XaI)_7--i{L7>#u=bT4z*Pu^wsD6vu+<$~NEBa&70ZsA#2YX{XR?^!ACeDGh$8X7b zsvGj%{#)E8oB7eNoSs7IRfE3cJw4Emv?aF5PGL z9o&m*hT}ILqsOwHVB-DpxZ%E5xuyjVvEzBP(kl9F8twQyhQD{7PX1k}UN-5OHL8wD z>9bTXK-F@cNe_81Wm(I^On{zgdsGLi*tX`0|_+^Ftysv%{=XK#W4~^q&Aurr_ z5+6S-Y83y~RzIr>tSYdoz^VeP3jALMUP%>p?;l|Onb9oUpUV#AQlkv^rgDSFQ@IQ) z43B1VES)Wm71+q|=x~8O&tM>N;1GKuRUBlwR3RfQ2agXI(nr+k!@10{VrDG;MhooC zjErPs?07aeGT7MyF_sxiy*82=6qrL^=t6FIXb4k?M0sJ3F${#?`%?J=OYYw-p8JRM z0w&{Q9FM?(O!{?pBy&O>cyX+d$>oYi3!OeB#&#zL4km?jXV1(_V6N?RF(85kItm0cO~fiwV{qzDB7 literal 0 HcmV?d00001 diff --git a/lab3/src/main/resources/quicksort.asmbin b/lab3/src/main/resources/quicksort.asmbin new file mode 100644 index 0000000000000000000000000000000000000000..ae8f834f31217c9609c9c77dced8aa6408bfc78b GIT binary patch literal 1028 zcmZuwzi-n(6n=N-vloU`Rv1`tbFrJIX&PuG)>?`f5%32TPzJ_=BKEkKN*zHK>PV5& zKLE86vn6+7Lt0>X+7hYY2B}6!s(Fu8>k+B;Q&L{YRqX{= z_19blZ@6kCTs7Zw)%wI$`#V=2lfX(bnpmRAq;7^%tVL3TKYpXUAB6WXCIJakR?J>;xe{L-gQIU(UoQuT3B zt7;~ux$?%jsYh*&+PuF#sg(F4XYlz&y!J=AYZLTOv;Lj(t_60}pCCWZ%6{pY`>aZ_ zB4Q(<-;F;i`L+bX=ZTc2bUrJtkBt@`jY%}R|<;p0Mgd^36)?DSP;<`#AAzLyBhWtsW@0cDIYp8x;= literal 0 HcmV?d00001 diff --git a/lab3/src/main/resources/sb.asmbin b/lab3/src/main/resources/sb.asmbin new file mode 100644 index 0000000000000000000000000000000000000000..fde0216ff6947c0b66cb85c21d84af9f23f2a4a1 GIT binary patch literal 36 scmWe;bzs95pR$yhwXJB9e0NFnYLI3~& literal 0 HcmV?d00001 diff --git a/lab3/src/main/resources/tetris.asmbin b/lab3/src/main/resources/tetris.asmbin new file mode 100644 index 0000000000000000000000000000000000000000..4c9ee9ace5a2cdebd6cfe2fe17a685cab71a3612 GIT binary patch literal 8196 zcmeHMUx-{+89(>$gxIDVFO!E7y3@TolWn@)u53bHD%_P>A4DMv@u48uG6X@zM8Z;( zV(;e81}Q3$ONc1aRd*tSN+i48LMhp$v$dMGwi5fG(nQooQR-;2G3?IV@%Me_oVoXA zC#DbWi!>1So^!r)&iC*4{W)`Brx0gKLR<}3UOp=DZ3+>eIAI=-KQ+EQ#NS^#9-HHz z4TU&f9@s~J`Fp_F=NZOLe`u%hD<2a6$fWT1ep2|Oj|qS5OTsTrn*PwYOn>5r_M{@&M3fAo*0KlU%vFBuN@I{xte4)#0P?_j@!{SNj!erdLV{RQkVV1EJo3)o-4 z{sQ(Fh?i^S(!MhT#C!NeRGJjg{j0(nGK^?w(y;tlBl1@bjLm3x(zMF6W>j7^t%_kq zl}XFmGiybARxNA9u%nSl+j?NujviRGt-Xd5?VWV22WOq=!Bxi^HQZ=)(zPC%b)$z? zU2DuJL}QZ$>*3i#^zdro`2AwvaZwtFE)stXx)_}mo^3$Zg~T6OOgu+GKMToG5eTbn zcVmoe+m>t|PuX2>rYLxB$C8jV)oxU7CKGdw-ab9=6^qdELPF~lMQ{7N(NhcDrbYS$~SiHLYQJtZcNEaAJE#HY*ZyPnWopL08YWhd-9 zYeG&-%c;+0d50i-X(5SlhriIkx%m47^>?2B+FgHav0bY-T$0Um2I%fi?dy76lH-$& zZE}5Fj_Zx>avaEU*tkoM59GYX?X_5GIB;9n6E@m0}-7PFhJD#D%zP@~tKQ>{bdSX?oNmQ|uGr&LMz#k&g!Py4c z-h@w?@FnX`K1KJEUDq+e`jYmOoO088{*R{7L zmWhARcHnaz>2KoqG1?wj;|O*n zn?P6Uuic@zX-yFw&fI>hT|-OqTkUub$I|xE*5C~-1J996t-)*Wz@E8yAGHy{`M~8 zh3rH+Bpbsvj2qGk*$#1AjVVs|#)v&l=ye^joopW>=h7H@mSY2FBK~2_aWYi-4m8Cz zoMR*R=sZ;2l7|=%{bSM=fA=ektb5O?cgPQwzq|y0p}eR3F8q7?EuLk6*`ejEYnqEZ zZ_0V86TKF^kot%K{@LddJ8p~r4b%rV>H`~j(@pXJUf7P}n@#vZT(2f)THWr|FnE$| zsrYOYp8U!}8+2XdU6nT>!?4C}9c#e!KXlH;+K^tWVy&9g{;V-wZO6qj{Jhyd?>r-- z2I5x*a_yzn>abHh8SaV)+|_kh0l9tOR-ATEIdva~~Ls_}PZ$P(gDNl1l$pbl?n&{&jw!_{#N_1>fdx$_v0He@o0b$Po^5gsXBy8@`BIoNG8+ z`y$bMj*a?IV@8}N|G-%aL*i2Uy;5gvY}c64^+WJ&p3l^?G0s%6{uFZS4huM>n1H_> z&h79^`K@w0FiYbtxg9>s^V!@EAI2Q%qeHQi^Z6HhwR9(TP6_0Mzz1EbJDc+le6b_3 z5q<*eh)v*=u_7MtFI)K3?PUv2@cF~&D@v;tbZskLce8olQ*pv`rVZj%-Tw&J@+x*P zCLfi0P4i*3E9CIAOqE%;jmI|KX54#A_W-@9agl#!iq zlhy+851mVu{zjm)MCDHQ1NH~h0x{LwN?)1>)*12C8dR|(lc!pP*Zb6Nxm@o#q3Xk` z$dRP~#UysFbUk+*J?)~7w_hds^g7mT@TAtlC-Q5p%-YIV@@pk0-6y`BUptuD7d*~( zpq`L*ZR74h)P5ybOa0EF)@mkHD?^8}em}IN>TNn>h4DjnL!E7T zH`edL8C`{wWBM-EDc#+A`X=;uYcHCMH_T_IR*s#6M(xGM0G+i}hEt;Us*Kqge}Jy% z^EIKw?KYA@`hlIP1qVd!gR18yKSv+!9Vt?N!8zv~DN9h3I>MS$R%@@RweT_UX7|>6 zdj;M$nr*fJaBp4hhtI0D@G~UaR$UGLTh4(G_9N2Y;6F)D&zV9DNAJSeY`$wfP#-L& zx&JmbJ8aMKQuC!SH^^8uW!(3{hu^?zDGLOwt}x4I+l@rd-y?&l>SKgsrT?h zJ+9AjvWXg^D&KKBY1P5J5?RoyT6`zQ|l?8Gm=m6j(7+^ zFRn@ckH~q=Gx?5u8{$~@Ke4E78o}2N?1JC9Zuk89nuvdkGZ5Fv2RTP@zK}gW;Vab< z%h`ooyXk($FLWd2;aV7S1H&)LI3#sO{T+OoFibV6>Widbtz2ZiabH)@U>N<}T{`bU zFN7D|lkpEZM|x~szG=ZGtnYi5R9qQQePejpqPwY2LGDsI11)02N0(A8WbzsF|EkPc z#D9eTl>9m-{wWusCq>`aj;YSAT+;F20%TOV$d+n!A_{U>*Ey-oEoXxpeC zb-Z{k-CJ!_PYWMw>pTYj)4re&qw8x6*k{ zAAT70Mmn$Q#Umu6y6Z$A{pVzrbmFSw;mJPqIeU?A=q-g}uJorFQM)(m0|9!s&^+LX zfMS>I`O#O5(Ay*Iz;Bts-)>`vTs@-XpW@hsdwCE1mg|zHv;p}st$XeYev|0g`HGxB zhLcikWhxS0iXq~ndXuEwGHrP7Yo^lC?=)?uwnD54AuD0J z37(5{3 z*TysZ!dKAm^x^vy_zrFQEkNEaF6Pf@!OxqzH~3|K?HGJsuZ6$Jt`VM4dv*L##AL*% zw7(E*Svts;IU{%>zeX7Boxe(JY=>KP4}X9TG@ZDRJ%i@cyMyPmYp_S=?(jJeInux7 zY~(NKr-a{F7V%!AbHmEB`E!H?`zalX(F?OW8HN%V+k5=M`Rlw9IjQ3Vx1Q z=L+J9^K(S`X&AZf3cV$XX^ID&lSY?R{16|xV-CR^r_38TH-iPl_j2uJjf4E}2+QRX z-bEe!UZ``wEpr*|ZyoN}^XB4?#x(J}JcWDrf?tje;SKfo!hyA)zKMF^ZGUK9DEY<_ mS3>R`hmp_LH%#!bjebWVOw#Y9@Be#W1OE>i`26mB#D4**0H>`0 literal 0 HcmV?d00001 diff --git a/lab3/src/main/resources/vga_font_8x16.bmp b/lab3/src/main/resources/vga_font_8x16.bmp new file mode 100644 index 0000000000000000000000000000000000000000..1aa58b97adc06ca07e07f83dc762bdce4b963d68 GIT binary patch literal 17462 zcmeHJJF?`)5riUS=om0{0@?_LT;2gk!BJo+bPm`$gA5#jK8;mYW@UFZ1~c!y;kO72JFBA zoVv<=hFyRa*nk~4fK%6e%&-fv0voUc2XOKcEawcn04uNoJ8%H!wBh{QGy`$+6^K7O zZ~*7D;r!b?0}HSM8?XZhaO$xwGwcGazy|EV0i1fI>kPX9E3g4OZ~&(sH->E60<6FW z?7#t>dKLB=b^%sk19sp5PQ50_47&g;umL-804HCe?VMp3U3;#}EzJv$hPoyIL zKl^dlw|kC*egEI9A+KuO841{@iMAiu_KTJmr5qqe=XLMhJK*M<&PN3Lx!vCGp-w05 z`IC&^oC=d(?SJC4Ejpqu%cDG@KTXHPoEj>WdrHnxK~f((cx=Zvy)Q-8$1b>}zT^j` zvBELC`r{_d7_%9bHn=aTy@ND!ul6z~pFd5Mcw3zl-6;oStzHj4ABqJ!%jByq&2(9h zC3IlTZ$;LaA4;h+<`6Lv%ZQ6Gs@!)TuS|75^<|LM-ys`;=}nIeX5CSP$9qb}u5(FP z&uUq=$-YZfS)VyCqyFdTk8A=^b%inUqRcSn z1Ggn*vz>b=G{$6TzE)19t5T0k>)-}YgNAfuGu`x^ATfegNjGy&(_&G4m3RE=cG@I3 zZ}8%pZqM;7@A;p$-axsn;#S7{{Aj*?9B;LkuHwGcbzA?c{?b(3Tm3ha9})0{U2MBX z=lvlduHRqyF^(hUu$660y0LW)kEireL=re*>$Q)B{&peG%?;LC`i-ayLzX|=9z-T# zH+ws$h*6;P^FHEYa@$R$w6_yg807M`G$Z z%~1R&^VM`jMv1$t`OufEbz|1ZvfBn{>6A& z7&aTM_zlSq1krih{j~4_@pn?c>HN40?OnGLmlL-WYsqJp`Ap|UvV~|e%OFp%rV7z$5Ja>G2v!@_RwIt9A+5ru}wI8Ti)>p z=DUR!%gg!Db4_N=$wl<&R! zANnTXurW_7PS#_6kr_8ei}U}-(X4*HD2S35lCh_-FVD+CEX0o6sP0SXF_wrM7^$(e9nGgDvJMAfKBB)qIxN%H%N1ZJwP1;>0wKOsl{t)v6}>+9%giV^b_8*Zlae zdDc?Y0~HS6U#7gbp)cC{{9s0zi_+R5*31pIaEJV$qe>`L?UuzDn|`ky!OXSjj>>FI0IhgQC?_=-f5cDS zSmo-W*9Li~7t`r>G`X81aJ7c+KyTg%1w9Fe_5+4LZsLzv5kFC(giO^J1 zv&9enCGnf)w?T4p8+=ZFpscWf#Sfqnn?Mvx-+2Cqt7s={{o$nQT`o#7A~|NJ)eDsz zP#nuP>C896FsQMHtOs#;T!|7jEq)G9!(1apgn)6e$_`YuaG$(?#iF!+I6ZHVR)rzO zUQJ3$*YRn(Rn0w@C_-s#{;i&#lN3Z&k9&)4W2%!qOjSP^j;m)P3r@sLyTBYX zS#W}apUdYBe9Iencw@h%_&c>}Iz?+qEzkzK`YOiv=E6SBjdX31*uFyH(nlxuFn z+QtJhrInAJGcnSVV>3)va^xdw2{~Mu9-14A{Jghlj-SV6*y9}8>Tn8M5feqm@yP6L z^4i#5s8iC{PU?PI9~m4A1&h$;QoHK58%IrAZ)Qho)L;f9vl13T#Ln3|-xXAmLaZP8 z)m`NIJrve%ZbHJD_s)f(sY-khRV=TmkVLOdmH$EiI)B_v5&K5- LisBRZyA1jtmw literal 0 HcmV?d00001 diff --git a/lab3/src/main/scala/board/basys3/BCD2Segments.scala b/lab3/src/main/scala/board/basys3/BCD2Segments.scala new file mode 100644 index 0000000..65b79b8 --- /dev/null +++ b/lab3/src/main/scala/board/basys3/BCD2Segments.scala @@ -0,0 +1,54 @@ +// 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 board.basys3 + +import chisel3._ +import chisel3.util._ + +class BCD2Segments extends Module { + val io = IO(new Bundle { + val bcd = Input(UInt(4.W)) + val segs = Output(UInt(8.W)) + }) + + val bcd = io.bcd + val segs = Wire(UInt(8.W)) + + segs := MuxLookup( + bcd, + 0xFF.U, + IndexedSeq( + 0.U -> "b10000001".U, + 1.U -> "b11001111".U, + 2.U -> "b10010010".U, + 3.U -> "b10000110".U, + 4.U -> "b11001100".U, + 5.U -> "b10100100".U, + 6.U -> "b10100000".U, + 7.U -> "b10001111".U, + 8.U -> "b10000000".U, + 9.U -> "b10000100".U, + 10.U -> "b00001000".U, + 11.U -> "b01100000".U, + 12.U -> "b00110001".U, + 13.U -> "b01000010".U, + 14.U -> "b00110000".U, + 15.U -> "b00111000".U, + ) + ) + + io.segs := segs +} + diff --git a/lab3/src/main/scala/board/basys3/OnboardDigitDisplay.scala b/lab3/src/main/scala/board/basys3/OnboardDigitDisplay.scala new file mode 100644 index 0000000..a07819b --- /dev/null +++ b/lab3/src/main/scala/board/basys3/OnboardDigitDisplay.scala @@ -0,0 +1,32 @@ +// 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 board.basys3 + +import chisel3._ + +class OnboardDigitDisplay extends Module { + val io = IO(new Bundle { + val digit_mask = Output(UInt(4.W)) + }) + + val counter = RegInit(UInt(16.W), 0.U) + val digit_mask = RegInit(UInt(4.W), "b0111".U) + + counter := counter + 1.U + when(counter === 0.U) { + digit_mask := (digit_mask << 1.U).asUInt + digit_mask(3) + } + io.digit_mask := digit_mask +} diff --git a/lab3/src/main/scala/board/basys3/SYSULogo.scala b/lab3/src/main/scala/board/basys3/SYSULogo.scala new file mode 100644 index 0000000..c41f4e6 --- /dev/null +++ b/lab3/src/main/scala/board/basys3/SYSULogo.scala @@ -0,0 +1,34 @@ +// 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 board.basys3 + +import chisel3._ +import chisel3.util._ + +class SYSULogo extends Module { + val io = IO(new Bundle { + val digit_mask = Input(UInt(4.W)) + val segs = Output(UInt(8.W)) + }) + + io.segs := MuxLookup( + io.digit_mask, + "b00100100".U, // "b0111".U, "b1101".U -> S + IndexedSeq( + "b1011".U -> "b01000100".U, // Y + "b1110".U -> "b01000001".U, // U + ) + ) +} diff --git a/lab3/src/main/scala/board/basys3/SegmentMux.scala b/lab3/src/main/scala/board/basys3/SegmentMux.scala new file mode 100644 index 0000000..9bb1bf7 --- /dev/null +++ b/lab3/src/main/scala/board/basys3/SegmentMux.scala @@ -0,0 +1,42 @@ +// 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 board.basys3 + +import chisel3._ +import chisel3.util._ + +class SegmentMux extends Module { + val io = IO(new Bundle { + val digit_mask = Input(UInt(4.W)) + val numbers = Input(UInt(16.W)) + val segs = Output(UInt(8.W)) + }) + + + val digit = RegInit(UInt(4.W), 0.U) + val bcd2segs = Module(new BCD2Segments) + + bcd2segs.io.bcd := digit + io.segs := bcd2segs.io.segs + digit := MuxLookup( + io.digit_mask, + io.numbers(3, 0), // "b1110".U + IndexedSeq( + "b1101".U -> io.numbers(7, 4), + "b1011".U -> io.numbers(11, 8), + "b0111".U -> io.numbers(15, 12) + ) + ) +} diff --git a/lab3/src/main/scala/board/basys3/Top.scala b/lab3/src/main/scala/board/basys3/Top.scala new file mode 100644 index 0000000..671e691 --- /dev/null +++ b/lab3/src/main/scala/board/basys3/Top.scala @@ -0,0 +1,128 @@ +// 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 board.basys3 + +import chisel3._ +import chisel3.stage.{ChiselGeneratorAnnotation, ChiselStage} +import chisel3.util._ +import peripheral._ +import riscv._ +import riscv.core.CPU + +class Top extends Module { + val binaryFilename = "tetris.asmbin" + val io = IO(new Bundle { + val switch = Input(UInt(16.W)) + + val segs = Output(UInt(8.W)) + val digit_mask = Output(UInt(4.W)) + + val hsync = Output(Bool()) + val vsync = Output(Bool()) + val rgb = Output(UInt(12.W)) + val led = Output(UInt(16.W)) + + val tx = Output(Bool()) + val rx = Input(Bool()) + + }) + + val mem = Module(new Memory(Parameters.MemorySizeInWords)) + val display = Module(new VGADisplay) + val timer = Module(new Timer) + val uart = Module(new Uart(frequency = 100000000, baudRate = 115200)) + val dummy = Module(new Dummy) + + display.io.bundle <> dummy.io.bundle + mem.io.bundle <> dummy.io.bundle + mem.io.debug_read_address := 0.U + timer.io.bundle <> dummy.io.bundle + uart.io.bundle <> dummy.io.bundle + io.tx := uart.io.txd + uart.io.rxd := io.rx + + val instruction_rom = Module(new InstructionROM(binaryFilename)) + val rom_loader = Module(new ROMLoader(instruction_rom.capacity)) + + rom_loader.io.rom_data := instruction_rom.io.data + rom_loader.io.load_address := Parameters.EntryAddress + instruction_rom.io.address := rom_loader.io.rom_address + + val CPU_clkdiv = RegInit(UInt(2.W), 0.U) + val CPU_tick = Wire(Bool()) + val CPU_next = Wire(UInt(2.W)) + CPU_next := Mux(CPU_clkdiv === 3.U, 0.U, CPU_clkdiv + 1.U) + CPU_tick := CPU_clkdiv === 0.U + CPU_clkdiv := CPU_next + + withClock(CPU_tick.asClock) { + val cpu = Module(new CPU(ImplementationType.FiveStageStall)) + cpu.io.interrupt_flag := Cat(uart.io.signal_interrupt, timer.io.signal_interrupt) + cpu.io.debug_read_address := 0.U + cpu.io.instruction_valid := rom_loader.io.load_finished + mem.io.instruction_address := cpu.io.instruction_address + cpu.io.instruction := mem.io.instruction + + when(!rom_loader.io.load_finished) { + rom_loader.io.bundle <> mem.io.bundle + cpu.io.memory_bundle.read_data := 0.U + }.otherwise { + rom_loader.io.bundle.read_data := 0.U + when(cpu.io.device_select === 4.U) { + cpu.io.memory_bundle <> timer.io.bundle + }.elsewhen(cpu.io.device_select === 2.U) { + cpu.io.memory_bundle <> uart.io.bundle + }.elsewhen(cpu.io.device_select === 1.U) { + cpu.io.memory_bundle <> display.io.bundle + }.otherwise { + cpu.io.memory_bundle <> mem.io.bundle + } + } + } + + io.hsync := display.io.hsync + io.vsync := display.io.vsync + + io.rgb := display.io.rgb + + mem.io.debug_read_address := io.switch(15, 1).asUInt << 2 + io.led := Mux( + io.switch(0), + mem.io.debug_read_data(31, 16).asUInt, + mem.io.debug_read_data(15, 0).asUInt, + ) + + val onboard_display = Module(new OnboardDigitDisplay) + io.digit_mask := onboard_display.io.digit_mask + + val sysu_logo = Module(new SYSULogo) + sysu_logo.io.digit_mask := io.digit_mask + + val seg_mux = Module(new SegmentMux) + seg_mux.io.digit_mask := io.digit_mask + seg_mux.io.numbers := io.led + + io.segs := MuxLookup( + io.switch, + seg_mux.io.segs, + IndexedSeq( + 0.U -> sysu_logo.io.segs + ) + ) +} + +object VerilogGenerator extends App { + (new ChiselStage).execute(Array("-X", "verilog", "-td", "verilog/basys3"), Seq(ChiselGeneratorAnnotation(() => new Top))) +} \ No newline at end of file diff --git a/lab3/src/main/scala/board/pynq/Top.scala b/lab3/src/main/scala/board/pynq/Top.scala new file mode 100644 index 0000000..14afbac --- /dev/null +++ b/lab3/src/main/scala/board/pynq/Top.scala @@ -0,0 +1,103 @@ +// Copyright 2022 Canbin Huang +// +// 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 board.pynq + +import chisel3._ +import chisel3.stage.{ChiselGeneratorAnnotation, ChiselStage} +import chisel3.util.Cat +import peripheral._ +import riscv.core.CPU +import riscv.{ImplementationType, Parameters} + +class Top extends Module { + val binaryFilename = "tetris.asmbin" + val io = IO(new Bundle() { + val hdmi_clk_n = Output(Bool()) + val hdmi_clk_p = Output(Bool()) + val hdmi_data_n = Output(UInt(3.W)) + val hdmi_data_p = Output(UInt(3.W)) + val hdmi_hpdn = Output(Bool()) + + val tx = Output(Bool()) + val rx = Input(Bool()) + + val led = Output(UInt(4.W)) + }) + val mem = Module(new Memory(Parameters.MemorySizeInWords)) + val display = Module(new HDMIDisplay) + val timer = Module(new Timer) + val uart = Module(new Uart(frequency = 125000000, baudRate = 115200)) + val dummy = Module(new Dummy) + + display.io.bundle <> dummy.io.bundle + mem.io.bundle <> dummy.io.bundle + mem.io.debug_read_address := 0.U + timer.io.bundle <> dummy.io.bundle + uart.io.bundle <> dummy.io.bundle + io.tx := uart.io.txd + uart.io.rxd := io.rx + + val instruction_rom = Module(new InstructionROM(binaryFilename)) + val rom_loader = Module(new ROMLoader(instruction_rom.capacity)) + + rom_loader.io.rom_data := instruction_rom.io.data + rom_loader.io.load_address := Parameters.EntryAddress + instruction_rom.io.address := rom_loader.io.rom_address + + val CPU_clkdiv = RegInit(UInt(2.W), 0.U) + val CPU_tick = Wire(Bool()) + val CPU_next = Wire(UInt(2.W)) + CPU_next := Mux(CPU_clkdiv === 3.U, 0.U, CPU_clkdiv + 1.U) + CPU_tick := CPU_clkdiv === 0.U + CPU_clkdiv := CPU_next + + withClock(CPU_tick.asClock) { + val cpu = Module(new CPU(implementation = ImplementationType.FiveStageStall)) + val instruction_valid = RegNext(rom_loader.io.load_finished) + cpu.io.interrupt_flag := Cat(uart.io.signal_interrupt, timer.io.signal_interrupt) + cpu.io.debug_read_address := 0.U + cpu.io.instruction_valid := instruction_valid + mem.io.instruction_address := cpu.io.instruction_address + cpu.io.instruction := mem.io.instruction + + when(!rom_loader.io.load_finished) { + rom_loader.io.bundle <> mem.io.bundle + cpu.io.memory_bundle.read_data := 0.U + }.otherwise { + rom_loader.io.bundle.read_data := 0.U + when(cpu.io.device_select === 4.U) { + cpu.io.memory_bundle <> timer.io.bundle + }.elsewhen(cpu.io.device_select === 2.U) { + cpu.io.memory_bundle <> uart.io.bundle + }.elsewhen(cpu.io.device_select === 1.U) { + cpu.io.memory_bundle <> display.io.bundle + }.otherwise { + cpu.io.memory_bundle <> mem.io.bundle + } + } + } + + io.led := 15.U(4.W) + + io.hdmi_hpdn := 1.U + io.hdmi_data_n := display.io.TMDSdata_n + io.hdmi_data_p := display.io.TMDSdata_p + io.hdmi_clk_n := display.io.TMDSclk_n + io.hdmi_clk_p := display.io.TMDSclk_p +} + +object VerilogGenerator extends App { + (new ChiselStage).execute(Array("-X", "verilog", "-td", "verilog/pynq"), Seq(ChiselGeneratorAnnotation(() => new Top))) +} \ No newline at end of file diff --git a/lab3/src/main/scala/board/verilator/Top.scala b/lab3/src/main/scala/board/verilator/Top.scala new file mode 100644 index 0000000..d685959 --- /dev/null +++ b/lab3/src/main/scala/board/verilator/Top.scala @@ -0,0 +1,42 @@ +// Copyright 2022 Canbin Huang +// +// 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 board.verilator + +import chisel3._ +import chisel3.stage.{ChiselGeneratorAnnotation, ChiselStage} +import riscv.ImplementationType +import riscv.core.{CPU, CPUBundle} + +class Top extends Module { + val io = IO(new CPUBundle) + + val cpu = Module(new CPU(implementation = ImplementationType.ThreeStage)) + + io.device_select := 0.U + cpu.io.debug_read_address := io.debug_read_address + io.debug_read_data := cpu.io.debug_read_data + + io.memory_bundle <> cpu.io.memory_bundle + io.instruction_address := cpu.io.instruction_address + cpu.io.instruction := io.instruction + + cpu.io.interrupt_flag := io.interrupt_flag + cpu.io.instruction_valid := io.instruction_valid +} + +object VerilogGenerator extends App { + (new ChiselStage).execute(Array("-X", "verilog", "-td", "verilog/verilator"), Seq(ChiselGeneratorAnnotation(() => + new Top()))) +} \ No newline at end of file diff --git a/lab3/src/main/scala/peripheral/Dummy.scala b/lab3/src/main/scala/peripheral/Dummy.scala new file mode 100644 index 0000000..fe4cb04 --- /dev/null +++ b/lab3/src/main/scala/peripheral/Dummy.scala @@ -0,0 +1,29 @@ +// 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 peripheral + +import chisel3._ +import riscv.Parameters + +// A dummy master that never initiates reads or writes +class Dummy extends Module { + val io = IO(new Bundle { + val bundle = Flipped(new RAMBundle) + }) + io.bundle.write_strobe := VecInit(Seq.fill(Parameters.WordSize)(false.B)) + io.bundle.write_data := 0.U + io.bundle.write_enable := false.B + io.bundle.address := 0.U +} diff --git a/lab3/src/main/scala/peripheral/FontROM.scala b/lab3/src/main/scala/peripheral/FontROM.scala new file mode 100644 index 0000000..b9b0d3b --- /dev/null +++ b/lab3/src/main/scala/peripheral/FontROM.scala @@ -0,0 +1,64 @@ +package peripheral + +import chisel3.experimental.{ChiselAnnotation, annotate} +import chisel3.util.experimental.loadMemoryFromFileInline +import chisel3.{Bundle, Input, Module, Output, SyncReadMem, UInt, _} +import firrtl.annotations.MemorySynthInit + +import java.io.FileWriter +import java.nio.file.Paths +import javax.imageio.ImageIO + +class FontROM(fontBitmapFilename: String = "vga_font_8x16.bmp") extends Module { + val glyphWidth = GlyphInfo.glyphWidth + val glyphHeight = GlyphInfo.glyphHeight + + val io = IO(new Bundle { + val glyph_index = Input(UInt(7.W)) + val glyph_y = Input(UInt(4.W)) + + val glyph_pixel_byte = Output(UInt(8.W)) + }) + + annotate(new ChiselAnnotation { + override def toFirrtl = + MemorySynthInit + }) + + val (hexTxtPath, glyphCount) = readFontBitmap() + val mem = SyncReadMem(glyphCount, UInt(8.W)) + loadMemoryFromFileInline(mem, hexTxtPath.toString.replaceAll("\\\\", "/")) + io.glyph_pixel_byte := mem.read(io.glyph_index * GlyphInfo.glyphHeight.U + io.glyph_y, true.B) + + def readFontBitmap() = { + val inputStream = getClass.getClassLoader.getResourceAsStream(fontBitmapFilename) + val image = ImageIO.read(inputStream) + + val glyphColumns = image.getWidth() / glyphWidth + val glyphRows = image.getHeight / glyphHeight + val glyphCount = glyphColumns * glyphRows + val glyphs = new Array[UInt](glyphCount * GlyphInfo.glyphHeight) + + for (row <- 0 until glyphRows) { + for (col <- 0 until glyphColumns) { + for (i <- 0 until glyphHeight) { + var lineInt = 0 + for (j <- 0 until glyphWidth) { + if (image.getRGB(col * glyphWidth + j, row * glyphHeight + i) != 0xFFFFFFFF) { + lineInt |= (1 << j) + } + } + glyphs((row * glyphColumns + col) * GlyphInfo.glyphHeight + i) = lineInt.U(8.W) + } + } + } + val currentDir = System.getProperty("user.dir") + val hexTxtPath = Paths.get(currentDir, "verilog", f"${fontBitmapFilename}.txt") + val writer = new FileWriter(hexTxtPath.toString) + for (i <- glyphs.indices) { + writer.write(f"@$i%x\n${glyphs(i).litValue}%02x\n") + } + writer.close() + (hexTxtPath, glyphs.length) + } +} diff --git a/lab3/src/main/scala/peripheral/HDMIDisplay.scala b/lab3/src/main/scala/peripheral/HDMIDisplay.scala new file mode 100644 index 0000000..42eccc7 --- /dev/null +++ b/lab3/src/main/scala/peripheral/HDMIDisplay.scala @@ -0,0 +1,403 @@ +// Copyright 2022 hrpccs +// +// 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 peripheral + +import chisel3._ +import chisel3.util._ +import riscv.Parameters + +class HDMISync extends Module { + val io = IO(new Bundle { + val hsync = Output(Bool()) + val vsync = Output(Bool()) + val video_on = Output(Bool()) + val p_tick = Output(Bool()) + val f_tick = Output(Bool()) + val x = Output(UInt(10.W)) + val y = Output(UInt(10.W)) + }) + + val DisplayHorizontal = ScreenInfo.DisplayHorizontal + val DisplayVertical = ScreenInfo.DisplayVertical + + val BorderLeft = 48 + val BorderRight = 16 + val BorderTop = 10 + val BorderBottom = 33 + + val RetraceHorizontal = 96 + val RetraceVertical = 2 + + val MaxHorizontal = DisplayHorizontal + BorderLeft + BorderRight + RetraceHorizontal - 1 + val MaxVertical = DisplayVertical + BorderTop + BorderBottom + RetraceVertical - 1 + + val RetraceHorizontalStart = DisplayHorizontal + BorderRight + val RetraceHorizontalEnd = RetraceHorizontalStart + RetraceHorizontal - 1 + + val RetraceVerticalStart = DisplayVertical + BorderBottom + val RetraceVerticalEnd = RetraceVerticalStart + RetraceVertical - 1 + + val pixel = RegInit(UInt(3.W), 0.U) + val pixel_next = Wire(UInt(3.W)) + val pixel_tick = Wire(Bool()) + + val v_count_reg = RegInit(UInt(10.W), 0.U) + val h_count_reg = RegInit(UInt(10.W), 0.U) + + val v_count_next = Wire(UInt(10.W)) + val h_count_next = Wire(UInt(10.W)) + + val vsync_reg = RegInit(Bool(), false.B) + val hsync_reg = RegInit(Bool(), false.B) + + val vsync_next = Wire(Bool()) + val hsync_next = Wire(Bool()) + + pixel_next := Mux(pixel === 4.U, 0.U, pixel + 1.U) + pixel_tick := pixel === 0.U + + h_count_next := Mux( + pixel_tick, + Mux(h_count_reg === MaxHorizontal.U, 0.U, h_count_reg + 1.U), + h_count_reg + ) + + v_count_next := Mux( + pixel_tick && h_count_reg === MaxHorizontal.U, + Mux(v_count_reg === MaxVertical.U, 0.U, v_count_reg + 1.U), + v_count_reg + ) + + hsync_next := h_count_reg >= RetraceHorizontalStart.U && h_count_reg <= RetraceHorizontalEnd.U + vsync_next := v_count_reg >= RetraceVerticalStart.U && v_count_reg <= RetraceVerticalEnd.U + + pixel := pixel_next + hsync_reg := hsync_next + vsync_reg := vsync_next + v_count_reg := v_count_next + h_count_reg := h_count_next + + io.video_on := h_count_reg < DisplayHorizontal.U && v_count_reg < DisplayVertical.U + io.hsync := hsync_reg + io.vsync := vsync_reg + io.x := h_count_reg + io.y := v_count_reg + io.p_tick := pixel_tick + io.f_tick := io.x === 0.U && io.y === 0.U +} + +class TMDS_encoder extends Module { + val io = IO(new Bundle() { + val video_data = Input(UInt(8.W)) //r,g,b,8bit + val control_data = Input(UInt(2.W)) + val video_on = Input(Bool()) + val TMDS = Output(UInt(10.W)) + }) + val Nb1s = PopCount(io.video_data) + val XNOR = Wire(Bool()) + XNOR := (Nb1s > 4.U(4.W)) || (Nb1s === 4.U(4.W) && io.video_data(0) === 0.U) + val xored = 1.U(1.W) ## xorfunc(io.video_data) + val xnored = 0.U(1.W) ## xnorfunc(io.video_data) + val q_m = Mux( + XNOR, + xnored, + xored + ) + val diff = PopCount(q_m).asSInt - 4.S + val diffSize = diff.getWidth + val disparitySize = 4 + val disparityReg = RegInit(0.S(disparitySize.W)) + val doutReg = RegInit("b1010101011".U(10.W)) + + //using recursion to compute + def xorfunc(value: UInt): UInt = { + value.getWidth match { + case 1 => value(0) + case s => val res = xorfunc(VecInit(value.asBools.drop(1)).asUInt) + value.asBools.head ^ res.asBools.head ## res + } + } + + def xnorfunc(value: UInt): UInt = { + value.getWidth match { + case 1 => value(0) + case s => val res = xnorfunc(VecInit(value.asBools.drop(1)).asUInt) + !(value.asBools.head ^ res.asBools.head) ## res + } + } + + when(io.video_on === false.B) { + disparityReg := 0.S + doutReg := "b1010101011".U(10.W) + switch(io.control_data) { + is("b00".U(2.W)) { + doutReg := "b1101010100".U(10.W) + } + is("b01".U(2.W)) { + doutReg := "b0010101011".U(10.W) + } + is("b10".U(2.W)) { + doutReg := "b0101010100".U(10.W) + } + } + }.otherwise { + when(disparityReg === 0.S || diff === 0.S) { + when(q_m(8) === false.B) { + doutReg := "b10".U(2.W) ## q_m(7, 0) + disparityReg := disparityReg - diff + }.otherwise { + doutReg := "b01".U(2.W) ## q_m(7, 0) + disparityReg := disparityReg + diff + } + }.elsewhen((!diff(diffSize - 1) && !disparityReg(disparitySize - 1)) + || (diff(diffSize - 1) && disparityReg(disparitySize - 1))) { + doutReg := 1.U(1.W) ## q_m(8) ## ~q_m(7, 0) + when(q_m(8)) { + disparityReg := disparityReg + 1.S - diff + }.otherwise { + disparityReg := disparityReg - diff + } + }.otherwise { + doutReg := 0.U(1.W) ## q_m + when(q_m(8)) { + disparityReg := disparityReg + diff + }.otherwise { + disparityReg := disparityReg - 1.S + diff + } + } + } + + io.TMDS := doutReg +} + +class HDMIDisplay extends Module { + val io = IO(new Bundle() { + val bundle = new RAMBundle + + val TMDSclk_p = Output(Bool()) + val TMDSdata_p = Output(UInt(3.W)) + val TMDSclk_n = Output(Bool()) + val TMDSdata_n = Output(UInt(3.W)) + }) + + val mem = Module(new BlockRAM(ScreenInfo.Chars / Parameters.WordSize)) + mem.io.write_enable := io.bundle.write_enable + mem.io.write_data := io.bundle.write_data + mem.io.write_address := io.bundle.address + mem.io.write_strobe := io.bundle.write_strobe + + mem.io.read_address := io.bundle.address + io.bundle.read_data := mem.io.read_data + + val pixel_clk = Wire(Bool()) + val hsync = Wire(Bool()) + val vsync = Wire(Bool()) + val sync = Module(new HDMISync) + hsync := sync.io.hsync + vsync := sync.io.vsync + pixel_clk := sync.io.p_tick + + val font_rom = Module(new FontROM) + val row = (sync.io.y >> log2Up(GlyphInfo.glyphHeight)).asUInt + val col = (sync.io.x >> log2Up(GlyphInfo.glyphWidth)).asUInt + val char_index = (row * ScreenInfo.CharCols.U) + col + val offset = char_index(1, 0) + val ch = Wire(UInt(8.W)) + + mem.io.debug_read_address := char_index + ch := MuxLookup( + offset, + 0.U, + IndexedSeq( + 0.U -> mem.io.debug_read_data(7, 0).asUInt, + 1.U -> mem.io.debug_read_data(15, 8).asUInt, + 2.U -> mem.io.debug_read_data(23, 16).asUInt, + 3.U -> mem.io.debug_read_data(31, 24).asUInt + ) + ) + font_rom.io.glyph_index := Mux(ch >= 32.U, ch - 31.U, 0.U) + font_rom.io.glyph_y := sync.io.y(log2Up(GlyphInfo.glyphHeight) - 1, 0) + val rgb = Wire(UInt(24.W)) //RGB 8:8:8 + // White if pixel_on and glyph pixel on + val glyph_x = sync.io.x(log2Up(GlyphInfo.glyphWidth) - 1, 0) + rgb := Mux(sync.io.video_on && font_rom.io.glyph_pixel_byte(glyph_x), 0xFFFFFFF.U, 0.U) + //TMDS_PLLVR is a vivado IP core, check it in /verilog/pynq/TMDS_PLLVR.v + val serial_clk = Wire(Clock()) + val pll_lock = Wire(Bool()) + val tmdspll = Module(new TMDS_PLLVR) + val rst = Wire(Reset()) + tmdspll.io.clkin := pixel_clk.asClock + serial_clk := tmdspll.io.clkout + pll_lock := tmdspll.io.lock + tmdspll.io.reset := reset + rst := ~pll_lock + + val tmds = Wire(UInt(3.W)) + val tmds_clk = Wire(Bool()) + withClockAndReset(pixel_clk.asClock, rst) { + val tmds_channel1 = Wire(UInt(10.W)) + val tmds_channel2 = Wire(UInt(10.W)) + val tmds_channel0 = Wire(UInt(10.W)) + + val tmds_green = Module(new TMDS_encoder) + val tmds_red = Module(new TMDS_encoder) + val tmds_blue = Module(new TMDS_encoder) + + tmds_red.io.video_on := sync.io.video_on + tmds_blue.io.video_on := sync.io.video_on + tmds_green.io.video_on := sync.io.video_on + + tmds_blue.io.control_data := sync.io.vsync ## sync.io.hsync + tmds_green.io.control_data := 0.U + tmds_red.io.control_data := 0.U + + tmds_red.io.video_data := rgb(23, 16) + tmds_blue.io.video_data := rgb(15, 8) + tmds_green.io.video_data := rgb(7, 0) + + tmds_channel0 := tmds_blue.io.TMDS + tmds_channel1 := tmds_green.io.TMDS + tmds_channel2 := tmds_red.io.TMDS + + val serdesBlue = Module(new Oser10Module()) + serdesBlue.io.data := tmds_channel0 + serdesBlue.io.fclk := serial_clk + + val serdesGreen = Module(new Oser10Module()) + serdesGreen.io.data := tmds_channel1 + serdesGreen.io.fclk := serial_clk + + val serdesRed = Module(new Oser10Module()) + serdesRed.io.data := tmds_channel2 + serdesRed.io.fclk := serial_clk + + tmds := serdesRed.io.q ## serdesGreen.io.q ## serdesBlue.io.q + + //serdesCLk : 25Mhz ,Why not directly use p_tick? + //cause Duty Ratio of p_tick is 10% , while which of serdesCLk is 50% + val serdesClk = Module(new Oser10Module()) + serdesClk.io.data := "b1111100000".U(10.W) + serdesClk.io.fclk := serial_clk + + tmds_clk := serdesClk.io.q + + val buffDiffBlue = Module(new OBUFDS) + buffDiffBlue.io.I := tmds(0) + val buffDiffGreen = Module(new OBUFDS) + buffDiffGreen.io.I := tmds(1) + val buffDiffRed = Module(new OBUFDS) + buffDiffRed.io.I := tmds(2) + val buffDiffClk = Module(new OBUFDS) + buffDiffClk.io.I := tmds_clk + + io.TMDSclk_p := buffDiffClk.io.O + io.TMDSclk_n := buffDiffClk.io.OB + io.TMDSdata_p := buffDiffRed.io.O ## buffDiffGreen.io.O ## buffDiffBlue.io.O + io.TMDSdata_n := buffDiffRed.io.OB ## buffDiffGreen.io.OB ## buffDiffBlue.io.OB + } +} + +//---------------------------------------- +//PLL frequency multiplier using BlackBox +class TMDS_PLLVR extends BlackBox { + val io = IO(new Bundle { + val clkin = Input(Clock()) + val reset = Input(Reset()) + val clkout = Output(Clock()) + val clkoutd = Output(Clock()) + val lock = Output(Bool()) + }) +} + +/* OSER10 : serializer 10:1*/ +class OSER10 extends Module { + val io = IO(new Bundle { + val Q = Output(Bool()) // OSER10 data output signal + val D0 = Input(Bool()) + val D1 = Input(Bool()) + val D2 = Input(Bool()) + val D3 = Input(Bool()) + val D4 = Input(Bool()) + val D5 = Input(Bool()) + val D6 = Input(Bool()) + val D7 = Input(Bool()) + val D8 = Input(Bool()) + val D9 = Input(Bool()) // OSER10 data input signal + val PCLK = Input(Clock()) // Primary clock input signal + val FCLK = Input(Clock()) // High speed clock input signal + val RESET = Input(Reset()) // Asynchronous reset input signal, + //active-high. + }) + withClockAndReset(io.FCLK, io.RESET) { + val count = RegInit(0.U(4.W)) + val countnext = Wire(UInt(4.W)) + io.Q := MuxLookup( + count, + 0.U, + IndexedSeq( + 0.U -> io.D0.asBool, + 1.U -> io.D1.asBool, + 2.U -> io.D2.asBool, + 3.U -> io.D3.asBool, + 4.U -> io.D4.asBool, + 5.U -> io.D5.asBool, + 6.U -> io.D6.asBool, + 7.U -> io.D7.asBool, + 8.U -> io.D8.asBool, + 9.U -> io.D9.asBool + ) + ) + countnext := Mux( + count === 9.U, 0.U, count + 1.U + ) + count := countnext + } +} + +class Oser10Module extends Module { + val io = IO(new Bundle { + val q = Output(Bool()) + val data = Input(UInt(10.W)) + val fclk = Input(Clock()) // Fast clock + }) + + val osr10 = Module(new OSER10()) + io.q := osr10.io.Q + osr10.io.D0 := io.data(0) + osr10.io.D1 := io.data(1) + osr10.io.D2 := io.data(2) + osr10.io.D3 := io.data(3) + osr10.io.D4 := io.data(4) + osr10.io.D5 := io.data(5) + osr10.io.D6 := io.data(6) + osr10.io.D7 := io.data(7) + osr10.io.D8 := io.data(8) + osr10.io.D9 := io.data(9) + osr10.io.PCLK := clock + osr10.io.FCLK := io.fclk + osr10.io.RESET := reset +} + +/* lvds output */ +class OBUFDS extends BlackBox { + val io = IO(new Bundle { + val O = Output(Bool()) + val OB = Output(Bool()) + val I = Input(Bool()) + }) +} +//----------------------------------------- + + diff --git a/lab3/src/main/scala/peripheral/InstructionROM.scala b/lab3/src/main/scala/peripheral/InstructionROM.scala new file mode 100644 index 0000000..4d7ed12 --- /dev/null +++ b/lab3/src/main/scala/peripheral/InstructionROM.scala @@ -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 peripheral + +import chisel3._ +import chisel3.experimental.{ChiselAnnotation, annotate} +import chisel3.util.experimental.loadMemoryFromFileInline +import firrtl.annotations.MemorySynthInit +import riscv.Parameters + +import java.io.FileWriter +import java.nio.file.{Files, Paths} +import java.nio.{ByteBuffer, ByteOrder} + +class InstructionROM(instructionFilename: String) extends Module { + val io = IO(new Bundle { + val address = Input(UInt(Parameters.AddrWidth)) + val data = Output(UInt(Parameters.InstructionWidth)) + }) + + val (instructionsInitFile, capacity) = readAsmBinary(instructionFilename) + val mem = Mem(capacity, UInt(Parameters.InstructionWidth)) + annotate(new ChiselAnnotation { + override def toFirrtl = + MemorySynthInit + }) + loadMemoryFromFileInline(mem, instructionsInitFile.toString.replaceAll("\\\\", "/")) + io.data := mem.read(io.address) + + def readAsmBinary(filename: String) = { + val inputStream = if (Files.exists(Paths.get(filename))) { + Files.newInputStream(Paths.get(filename)) + } else { + 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 + } + instructions = instructions :+ BigInt(0x00000013L) + instructions = instructions :+ BigInt(0x00000013L) + instructions = instructions :+ BigInt(0x00000013L) + val currentDir = System.getProperty("user.dir") + val exeTxtPath = Paths.get(currentDir, "verilog", f"${instructionFilename}.txt") + val writer = new FileWriter(exeTxtPath.toString) + for (i <- instructions.indices) { + writer.write(f"@$i%x\n${instructions(i)}%08x\n") + } + writer.close() + (exeTxtPath, instructions.length) + } +} diff --git a/lab3/src/main/scala/peripheral/Memory.scala b/lab3/src/main/scala/peripheral/Memory.scala new file mode 100644 index 0000000..a8bef25 --- /dev/null +++ b/lab3/src/main/scala/peripheral/Memory.scala @@ -0,0 +1,77 @@ +// 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 peripheral + +import chisel3._ +import riscv.Parameters + +class RAMBundle extends Bundle { + val address = Input(UInt(Parameters.AddrWidth)) + val write_data = Input(UInt(Parameters.DataWidth)) + val write_enable = Input(Bool()) + val write_strobe = Input(Vec(Parameters.WordSize, Bool())) + val read_data = Output(UInt(Parameters.DataWidth)) +} + +// The purpose of this module is to help the synthesis tool recognize +// our memory as a Block RAM template +class BlockRAM(capacity: Int) extends Module { + val io = IO(new Bundle { + val read_address = Input(UInt(Parameters.AddrWidth)) + val write_address = Input(UInt(Parameters.AddrWidth)) + val write_data = Input(UInt(Parameters.DataWidth)) + val write_enable = Input(Bool()) + val write_strobe = Input(Vec(Parameters.WordSize, Bool())) + + val debug_read_address = Input(UInt(Parameters.AddrWidth)) + + val read_data = Output(UInt(Parameters.DataWidth)) + val debug_read_data = Output(UInt(Parameters.DataWidth)) + }) + val mem = SyncReadMem(capacity, Vec(Parameters.WordSize, UInt(Parameters.ByteWidth))) + when(io.write_enable) { + val write_data_vec = Wire(Vec(Parameters.WordSize, UInt(Parameters.ByteWidth))) + for (i <- 0 until Parameters.WordSize) { + write_data_vec(i) := io.write_data((i + 1) * Parameters.ByteBits - 1, i * Parameters.ByteBits) + } + mem.write((io.write_address >> 2.U).asUInt, write_data_vec, io.write_strobe) + } + io.read_data := mem.read((io.read_address >> 2.U).asUInt, true.B).asUInt + io.debug_read_data := mem.read((io.debug_read_address >> 2.U).asUInt, true.B).asUInt +} + +class Memory(capacity: Int) extends Module { + val io = IO(new Bundle { + val bundle = new RAMBundle + + val instruction = Output(UInt(Parameters.DataWidth)) + val instruction_address = Input(UInt(Parameters.AddrWidth)) + + val debug_read_address = Input(UInt(Parameters.AddrWidth)) + val debug_read_data = Output(UInt(Parameters.DataWidth)) + }) + + val mem = SyncReadMem(capacity, Vec(Parameters.WordSize, UInt(Parameters.ByteWidth))) + when(io.bundle.write_enable) { + val write_data_vec = Wire(Vec(Parameters.WordSize, UInt(Parameters.ByteWidth))) + for (i <- 0 until Parameters.WordSize) { + write_data_vec(i) := io.bundle.write_data((i + 1) * Parameters.ByteBits - 1, i * Parameters.ByteBits) + } + mem.write((io.bundle.address >> 2.U).asUInt, write_data_vec, io.bundle.write_strobe) + } + io.bundle.read_data := mem.read((io.bundle.address >> 2.U).asUInt, true.B).asUInt + io.debug_read_data := mem.read((io.debug_read_address >> 2.U).asUInt, true.B).asUInt + io.instruction := mem.read((io.instruction_address >> 2.U).asUInt, true.B).asUInt +} \ No newline at end of file diff --git a/lab3/src/main/scala/peripheral/ROMLoader.scala b/lab3/src/main/scala/peripheral/ROMLoader.scala new file mode 100644 index 0000000..d3313e5 --- /dev/null +++ b/lab3/src/main/scala/peripheral/ROMLoader.scala @@ -0,0 +1,50 @@ +// 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 peripheral + +import chisel3._ +import riscv.Parameters + +class ROMLoader(capacity: Int) extends Module { + val io = IO(new Bundle { + val bundle = Flipped(new RAMBundle) + + val rom_address = Output(UInt(Parameters.AddrWidth)) + val rom_data = Input(UInt(Parameters.InstructionWidth)) + + val load_address = Input(UInt(Parameters.AddrWidth)) + val load_finished = Output(Bool()) + }) + + val address = RegInit(0.U(32.W)) + val valid = RegInit(false.B) + + io.bundle.write_strobe := VecInit(Seq.fill(Parameters.WordSize)(false.B)) + io.bundle.address := 0.U + io.bundle.write_data := 0.U + io.bundle.write_enable := false.B + when(address <= (capacity - 1).U) { + io.bundle.write_enable := true.B + io.bundle.write_data := io.rom_data + io.bundle.address := (address << 2.U).asUInt + io.load_address + io.bundle.write_strobe := VecInit(Seq.fill(Parameters.WordSize)(true.B)) + address := address + 1.U + when(address === (capacity - 1).U) { + valid := true.B + } + } + io.load_finished := valid + io.rom_address := address +} diff --git a/lab3/src/main/scala/peripheral/Timer.scala b/lab3/src/main/scala/peripheral/Timer.scala new file mode 100644 index 0000000..3edf8fb --- /dev/null +++ b/lab3/src/main/scala/peripheral/Timer.scala @@ -0,0 +1,60 @@ +// 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 peripheral + +import chisel3._ +import chisel3.util._ +import riscv.Parameters + +class Timer extends Module { + val io = IO(new Bundle { + val bundle = new RAMBundle + val signal_interrupt = Output(Bool()) + + val debug_limit = Output(UInt(Parameters.DataWidth)) + val debug_enabled = Output(Bool()) + }) + + val count = RegInit(0.U(32.W)) + val limit = RegInit(100000000.U(32.W)) + io.debug_limit := limit + val enabled = RegInit(true.B) + io.debug_enabled := enabled + + io.bundle.read_data := MuxLookup( + io.bundle.address, + 0.U, + IndexedSeq( + 0x4.U -> limit, + 0x8.U -> enabled.asUInt, + ) + ) + when(io.bundle.write_enable) { + when(io.bundle.address === 0x4.U) { + limit := io.bundle.write_data + count := 0.U + }.elsewhen(io.bundle.address === 0x8.U) { + enabled := io.bundle.write_data =/= 0.U + } + } + + io.signal_interrupt := enabled && (count >= (limit - 10.U)) + + when(count >= limit) { + count := 0.U + }.otherwise { + count := count + 1.U + } +} diff --git a/lab3/src/main/scala/peripheral/UART.scala b/lab3/src/main/scala/peripheral/UART.scala new file mode 100644 index 0000000..2d47c57 --- /dev/null +++ b/lab3/src/main/scala/peripheral/UART.scala @@ -0,0 +1,204 @@ +// 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 peripheral + +import chisel3._ +import chisel3.util._ + +class UartIO extends DecoupledIO(UInt(8.W)) { +} + + +/** + * Transmit part of the UART. + * A minimal version without any additional buffering. + * Use a ready/valid handshaking. + */ +class Tx(frequency: Int, baudRate: Int) extends Module { + val io = IO(new Bundle { + val txd = Output(UInt(1.W)) + val channel = Flipped(new UartIO()) + + }) + + val BIT_CNT = ((frequency + baudRate / 2) / baudRate - 1).U + + val shiftReg = RegInit(0x7ff.U) + val cntReg = RegInit(0.U(20.W)) + val bitsReg = RegInit(0.U(4.W)) + + io.channel.ready := (cntReg === 0.U) && (bitsReg === 0.U) + io.txd := shiftReg(0) + + when(cntReg === 0.U) { + + cntReg := BIT_CNT + when(bitsReg =/= 0.U) { + val shift = shiftReg >> 1 + shiftReg := Cat(1.U, shift(9, 0)) + bitsReg := bitsReg - 1.U + }.otherwise { + when(io.channel.valid) { + shiftReg := Cat(Cat(3.U, io.channel.bits), 0.U) // two stop bits, data, one start bit + bitsReg := 11.U + }.otherwise { + shiftReg := 0x7ff.U + } + } + + }.otherwise { + cntReg := cntReg - 1.U + } +} + +/** + * Receive part of the UART. + * A minimal version without any additional buffering. + * Use a ready/valid handshaking. + * + * The following code is inspired by Tommy's receive code at: + * https://github.com/tommythorn/yarvi + */ +class Rx(frequency: Int, baudRate: Int) extends Module { + val io = IO(new Bundle { + val rxd = Input(UInt(1.W)) + val channel = new UartIO() + + }) + + val BIT_CNT = ((frequency + baudRate / 2) / baudRate - 1).U + val START_CNT = ((3 * frequency / 2 + baudRate / 2) / baudRate - 1).U + + // Sync in the asynchronous RX data, reset to 1 to not start reading after a reset + val rxReg = RegNext(RegNext(io.rxd, 1.U), 1.U) + + val shiftReg = RegInit(0.U(8.W)) + val cntReg = RegInit(0.U(20.W)) + val bitsReg = RegInit(0.U(4.W)) + val valReg = RegInit(false.B) + + when(cntReg =/= 0.U) { + cntReg := cntReg - 1.U + }.elsewhen(bitsReg =/= 0.U) { + cntReg := BIT_CNT + shiftReg := Cat(rxReg, shiftReg >> 1) + bitsReg := bitsReg - 1.U + // the last shifted in + when(bitsReg === 1.U) { + valReg := true.B + } + }.elsewhen(rxReg === 0.U) { // wait 1.5 bits after falling edge of start + cntReg := START_CNT + bitsReg := 8.U + } + + when(valReg && io.channel.ready) { + valReg := false.B + } + + io.channel.bits := shiftReg + io.channel.valid := valReg +} + +/** + * A single byte buffer with a ready/valid interface + */ +class Buffer extends Module { + val io = IO(new Bundle { + val in = Flipped(new UartIO()) + val out = new UartIO() + }) + + val empty :: full :: Nil = Enum(2) + val stateReg = RegInit(empty) + val dataReg = RegInit(0.U(8.W)) + + io.in.ready := stateReg === empty + io.out.valid := stateReg === full + + when(stateReg === empty) { + when(io.in.valid) { + dataReg := io.in.bits + stateReg := full + } + }.otherwise { // full + when(io.out.ready) { + stateReg := empty + } + } + io.out.bits := dataReg +} + +/** + * A transmitter with a single buffer. + */ +class BufferedTx(frequency: Int, baudRate: Int) extends Module { + val io = IO(new Bundle { + val txd = Output(UInt(1.W)) + val channel = Flipped(new UartIO()) + + }) + val tx = Module(new Tx(frequency, baudRate)) + val buf = Module(new Buffer) + + buf.io.in <> io.channel + tx.io.channel <> buf.io.out + io.txd <> tx.io.txd +} + +class Uart(frequency: Int, baudRate: Int) extends Module { + val io = IO(new Bundle { + val bundle = new RAMBundle + val rxd = Input(UInt(1.W)) + val txd = Output(UInt(1.W)) + + val signal_interrupt = Output(Bool()) + }) + val interrupt = RegInit(false.B) + val rxData = RegInit(0.U) + + val tx = Module(new BufferedTx(frequency, baudRate)) + val rx = Module(new Rx(frequency, baudRate)) + + io.bundle.read_data := 0.U + when(io.bundle.address === 0x4.U) { + io.bundle.read_data := baudRate.U + }.elsewhen(io.bundle.address === 0xC.U) { + io.bundle.read_data := rxData + interrupt := false.B + } + + tx.io.channel.valid := false.B + tx.io.channel.bits := 0.U + when(io.bundle.write_enable) { + when(io.bundle.address === 0x8.U) { + interrupt := io.bundle.write_data =/= 0.U + }.elsewhen(io.bundle.address === 0x10.U) { + tx.io.channel.valid := true.B + tx.io.channel.bits := io.bundle.write_data + } + } + + io.txd := tx.io.txd + rx.io.rxd := io.rxd + + io.signal_interrupt := interrupt + rx.io.channel.ready := false.B + when(rx.io.channel.valid) { + rx.io.channel.ready := true.B + rxData := rx.io.channel.bits + interrupt := true.B + } +} diff --git a/lab3/src/main/scala/peripheral/VGADisplay.scala b/lab3/src/main/scala/peripheral/VGADisplay.scala new file mode 100644 index 0000000..9e6b0d6 --- /dev/null +++ b/lab3/src/main/scala/peripheral/VGADisplay.scala @@ -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 peripheral + +import chisel3._ +import chisel3.util._ +import riscv.Parameters + +object GlyphInfo { + val glyphWidth = 8 + val glyphHeight = 16 + // ASCII printable characters start from here + val spaceIndex = 1 +} + +object ScreenInfo { + val DisplayHorizontal = 640 + val DisplayVertical = 480 + + val CharCols = DisplayHorizontal / GlyphInfo.glyphWidth + val CharRows = DisplayVertical / GlyphInfo.glyphHeight + val Chars = CharCols * CharRows +} + + +class VGASync extends Module { + val io = IO(new Bundle { + val hsync = Output(Bool()) + val vsync = Output(Bool()) + val video_on = Output(Bool()) + val p_tick = Output(Bool()) + val f_tick = Output(Bool()) + val x = Output(UInt(10.W)) + val y = Output(UInt(10.W)) + }) + + val DisplayHorizontal = ScreenInfo.DisplayHorizontal + val DisplayVertical = ScreenInfo.DisplayVertical + + val BorderLeft = 48 + val BorderRight = 16 + val BorderTop = 10 + val BorderBottom = 33 + + val RetraceHorizontal = 96 + val RetraceVertical = 2 + + val MaxHorizontal = DisplayHorizontal + BorderLeft + BorderRight + RetraceHorizontal - 1 + val MaxVertical = DisplayVertical + BorderTop + BorderBottom + RetraceVertical - 1 + + val RetraceHorizontalStart = DisplayHorizontal + BorderRight + val RetraceHorizontalEnd = RetraceHorizontalStart + RetraceHorizontal - 1 + + val RetraceVerticalStart = DisplayVertical + BorderBottom + val RetraceVerticalEnd = RetraceVerticalStart + RetraceVertical - 1 + + val pixel = RegInit(UInt(2.W), 0.U) + val pixel_next = Wire(UInt(2.W)) + val pixel_tick = Wire(Bool()) + + val v_count_reg = RegInit(UInt(10.W), 0.U) + val h_count_reg = RegInit(UInt(10.W), 0.U) + + val v_count_next = Wire(UInt(10.W)) + val h_count_next = Wire(UInt(10.W)) + + val vsync_reg = RegInit(Bool(), false.B) + val hsync_reg = RegInit(Bool(), false.B) + + val vsync_next = Wire(Bool()) + val hsync_next = Wire(Bool()) + + pixel_next := pixel + 1.U + pixel_tick := pixel === 0.U + + h_count_next := Mux( + pixel_tick, + Mux(h_count_reg === MaxHorizontal.U, 0.U, h_count_reg + 1.U), + h_count_reg + ) + + v_count_next := Mux( + pixel_tick && h_count_reg === MaxHorizontal.U, + Mux(v_count_reg === MaxVertical.U, 0.U, v_count_reg + 1.U), + v_count_reg + ) + + hsync_next := h_count_reg >= RetraceHorizontalStart.U && h_count_reg <= RetraceHorizontalEnd.U + vsync_next := v_count_reg >= RetraceVerticalStart.U && v_count_reg <= RetraceVerticalEnd.U + + pixel := pixel_next + hsync_reg := hsync_next + vsync_reg := vsync_next + v_count_reg := v_count_next + h_count_reg := h_count_next + + io.video_on := h_count_reg < DisplayHorizontal.U && v_count_reg < DisplayVertical.U + io.hsync := hsync_reg + io.vsync := vsync_reg + io.x := h_count_reg + io.y := v_count_reg + io.p_tick := pixel_tick + io.f_tick := io.x === 0.U && io.y === 0.U +} + +class VGADisplay extends Module { + val io = IO(new Bundle() { + val bundle = new RAMBundle + + val hsync = Output(Bool()) + val vsync = Output(Bool()) + + val rgb = Output(UInt(12.W)) + }) + val mem = Module(new BlockRAM(ScreenInfo.Chars / Parameters.WordSize)) + mem.io.write_enable := io.bundle.write_enable + mem.io.write_data := io.bundle.write_data + mem.io.write_address := io.bundle.write_data + mem.io.write_strobe := io.bundle.write_strobe + + mem.io.read_address := io.bundle.address + io.bundle.read_data := mem.io.read_data + + val sync = Module(new VGASync) + io.hsync := sync.io.hsync + io.vsync := sync.io.vsync + + val font_rom = Module(new FontROM) + val row = (sync.io.y >> log2Up(GlyphInfo.glyphHeight)).asUInt + val col = (sync.io.x >> log2Up(GlyphInfo.glyphWidth)).asUInt + val char_index = (row * ScreenInfo.CharCols.U) + col + val offset = char_index(1, 0) + val ch = Wire(UInt(8.W)) + + mem.io.debug_read_address := char_index + ch := MuxLookup( + offset, + 0.U, + IndexedSeq( + 0.U -> mem.io.debug_read_data(7, 0).asUInt, + 1.U -> mem.io.debug_read_data(15, 8).asUInt, + 2.U -> mem.io.debug_read_data(23, 16).asUInt, + 3.U -> mem.io.debug_read_data(31, 24).asUInt + ) + ) + font_rom.io.glyph_index := Mux(ch >= 32.U, ch - 31.U, 0.U) + font_rom.io.glyph_y := sync.io.y(log2Up(GlyphInfo.glyphHeight) - 1, 0) + + // White if pixel_on and glyph pixel on + val glyph_x = sync.io.x(log2Up(GlyphInfo.glyphWidth) - 1, 0) + io.rgb := Mux(sync.io.video_on && font_rom.io.glyph_pixel_byte(glyph_x), 0xFFFF.U, 0.U) +} diff --git a/lab3/src/main/scala/riscv/Parameters.scala b/lab3/src/main/scala/riscv/Parameters.scala new file mode 100644 index 0000000..6737b26 --- /dev/null +++ b/lab3/src/main/scala/riscv/Parameters.scala @@ -0,0 +1,60 @@ +// 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 chisel3._ +import chisel3.util._ + +object ImplementationType { + val ThreeStage = 0 + val FiveStageStall = 1 + val FiveStageForward = 2 + val FiveStageFinal = 3 +} + +object Parameters { + val AddrBits = 32 + val AddrWidth = AddrBits.W + + val InstructionBits = 32 + val InstructionWidth = InstructionBits.W + val DataBits = 32 + val DataWidth = DataBits.W + val ByteBits = 8 + val ByteWidth = ByteBits.W + val WordSize = Math.ceil(DataBits / ByteBits).toInt + + val PhysicalRegisters = 32 + val PhysicalRegisterAddrBits = log2Up(PhysicalRegisters) + val PhysicalRegisterAddrWidth = PhysicalRegisterAddrBits.W + + val CSRRegisterAddrBits = 12 + val CSRRegisterAddrWidth = CSRRegisterAddrBits.W + + val InterruptFlagBits = 32 + val InterruptFlagWidth = InterruptFlagBits.W + + val HoldStateBits = 3 + val StallStateWidth = HoldStateBits.W + + val MemorySizeInBytes = 32768 + val MemorySizeInWords = MemorySizeInBytes / 4 + + val EntryAddress = 0x1000.U(Parameters.AddrWidth) + + val MasterDeviceCount = 1 + val SlaveDeviceCount = 8 + val SlaveDeviceCountBits = log2Up(Parameters.SlaveDeviceCount) +} diff --git a/lab3/src/main/scala/riscv/core/ALU.scala b/lab3/src/main/scala/riscv/core/ALU.scala new file mode 100644 index 0000000..fd47428 --- /dev/null +++ b/lab3/src/main/scala/riscv/core/ALU.scala @@ -0,0 +1,69 @@ +// 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.core + +import chisel3._ +import chisel3.experimental.ChiselEnum +import chisel3.util._ +import riscv.Parameters + +object ALUFunctions extends ChiselEnum { + val zero, add, sub, sll, slt, xor, or, and, srl, sra, sltu = Value +} + +class ALU extends Module { + val io = IO(new Bundle { + val func = Input(ALUFunctions()) + + val op1 = Input(UInt(Parameters.DataWidth)) + val op2 = Input(UInt(Parameters.DataWidth)) + + val result = Output(UInt(Parameters.DataWidth)) + }) + + io.result := 0.U + switch(io.func) { + is(ALUFunctions.add) { + io.result := io.op1 + io.op2 + } + is(ALUFunctions.sub) { + io.result := io.op1 - io.op2 + } + is(ALUFunctions.sll) { + io.result := io.op1 << io.op2(4, 0) + } + is(ALUFunctions.slt) { + io.result := io.op1.asSInt < io.op2.asSInt + } + is(ALUFunctions.xor) { + io.result := io.op1 ^ io.op2 + } + is(ALUFunctions.or) { + io.result := io.op1 | io.op2 + } + is(ALUFunctions.and) { + io.result := io.op1 & io.op2 + } + is(ALUFunctions.srl) { + io.result := io.op1 >> io.op2(4, 0) + } + is(ALUFunctions.sra) { + io.result := (io.op1.asSInt >> io.op2(4, 0)).asUInt + } + is(ALUFunctions.sltu) { + io.result := io.op1 < io.op2 + } + } +} diff --git a/lab3/src/main/scala/riscv/core/ALUControl.scala b/lab3/src/main/scala/riscv/core/ALUControl.scala new file mode 100644 index 0000000..ca9a92e --- /dev/null +++ b/lab3/src/main/scala/riscv/core/ALUControl.scala @@ -0,0 +1,87 @@ +// 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.core + +import chisel3._ +import chisel3.util._ +import riscv.core.threestage.{InstructionTypes, Instructions, InstructionsTypeI, InstructionsTypeR} + +class ALUControl extends Module { + val io = IO(new Bundle { + val opcode = Input(UInt(7.W)) + val funct3 = Input(UInt(3.W)) + val funct7 = Input(UInt(7.W)) + + val alu_funct = Output(ALUFunctions()) + }) + + io.alu_funct := ALUFunctions.zero + + switch(io.opcode) { + is(InstructionTypes.I) { + io.alu_funct := MuxLookup( + io.funct3, + ALUFunctions.zero, + IndexedSeq( + InstructionsTypeI.addi -> ALUFunctions.add, + InstructionsTypeI.slli -> ALUFunctions.sll, + InstructionsTypeI.slti -> ALUFunctions.slt, + InstructionsTypeI.sltiu -> ALUFunctions.sltu, + InstructionsTypeI.xori -> ALUFunctions.xor, + InstructionsTypeI.ori -> ALUFunctions.or, + InstructionsTypeI.andi -> ALUFunctions.and, + InstructionsTypeI.sri -> Mux(io.funct7(5), ALUFunctions.sra, ALUFunctions.srl) + ), + ) + } + is(InstructionTypes.RM) { + io.alu_funct := MuxLookup( + io.funct3, + ALUFunctions.zero, + IndexedSeq( + InstructionsTypeR.add_sub -> Mux(io.funct7(5), ALUFunctions.sub, ALUFunctions.add), + InstructionsTypeR.sll -> ALUFunctions.sll, + InstructionsTypeR.slt -> ALUFunctions.slt, + InstructionsTypeR.sltu -> ALUFunctions.sltu, + InstructionsTypeR.xor -> ALUFunctions.xor, + InstructionsTypeR.or -> ALUFunctions.or, + InstructionsTypeR.and -> ALUFunctions.and, + InstructionsTypeR.sr -> Mux(io.funct7(5), ALUFunctions.sra, ALUFunctions.srl) + ), + ) + } + is(InstructionTypes.B) { + io.alu_funct := ALUFunctions.add + } + is(InstructionTypes.L) { + io.alu_funct := ALUFunctions.add + } + is(InstructionTypes.S) { + io.alu_funct := ALUFunctions.add + } + is(Instructions.jal) { + io.alu_funct := ALUFunctions.add + } + is(Instructions.jalr) { + io.alu_funct := ALUFunctions.add + } + is(Instructions.lui) { + io.alu_funct := ALUFunctions.add + } + is(Instructions.auipc) { + io.alu_funct := ALUFunctions.add + } + } +} diff --git a/lab3/src/main/scala/riscv/core/CPU.scala b/lab3/src/main/scala/riscv/core/CPU.scala new file mode 100644 index 0000000..dba0a94 --- /dev/null +++ b/lab3/src/main/scala/riscv/core/CPU.scala @@ -0,0 +1,40 @@ +// 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.core + +import chisel3._ +import riscv.ImplementationType +import riscv.core.fivestage_final.{CPU => FiveStageCPUFinal} +import riscv.core.fivestage_forward.{CPU => FiveStageCPUForward} +import riscv.core.fivestage_stall.{CPU => FiveStageCPUStall} +import riscv.core.threestage.{CPU => ThreeStageCPU} + +class CPU(val implementation: Int = ImplementationType.FiveStageFinal) extends Module { + val io = IO(new CPUBundle) + implementation match { + case ImplementationType.ThreeStage => + val cpu = Module(new ThreeStageCPU) + cpu.io <> io + case ImplementationType.FiveStageStall => + val cpu = Module(new FiveStageCPUStall) + cpu.io <> io + case ImplementationType.FiveStageForward => + val cpu = Module(new FiveStageCPUForward) + cpu.io <> io + case _ => + val cpu = Module(new FiveStageCPUFinal) + cpu.io <> io + } +} diff --git a/lab3/src/main/scala/riscv/core/CPUBundle.scala b/lab3/src/main/scala/riscv/core/CPUBundle.scala new file mode 100644 index 0000000..730bacc --- /dev/null +++ b/lab3/src/main/scala/riscv/core/CPUBundle.scala @@ -0,0 +1,30 @@ +// 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.core + +import chisel3._ +import peripheral.RAMBundle +import riscv.Parameters + +class CPUBundle extends Bundle { + val instruction_address = Output(UInt(Parameters.AddrWidth)) + val instruction = Input(UInt(Parameters.DataWidth)) + val instruction_valid = Input(Bool()) + val memory_bundle = Flipped(new RAMBundle) + val device_select = Output(UInt(Parameters.SlaveDeviceCountBits.W)) + val interrupt_flag = Input(UInt(Parameters.InterruptFlagWidth)) + val debug_read_address = Input(UInt(Parameters.PhysicalRegisterAddrWidth)) + val debug_read_data = Output(UInt(Parameters.DataWidth)) +} diff --git a/lab3/src/main/scala/riscv/core/CSR.scala b/lab3/src/main/scala/riscv/core/CSR.scala new file mode 100644 index 0000000..d7b444e --- /dev/null +++ b/lab3/src/main/scala/riscv/core/CSR.scala @@ -0,0 +1,99 @@ +// 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.core + +import chisel3._ +import chisel3.util._ +import riscv.Parameters +import riscv.core.threestage.CSRDirectAccessBundle + + +object CSRRegister { + // Refer to Spec. Vol.II Page 8-10 + val MSTATUS = 0x300.U(Parameters.CSRRegisterAddrWidth) + val MIE = 0x304.U(Parameters.CSRRegisterAddrWidth) + val MTVEC = 0x305.U(Parameters.CSRRegisterAddrWidth) + val MSCRATCH = 0x340.U(Parameters.CSRRegisterAddrWidth) + val MEPC = 0x341.U(Parameters.CSRRegisterAddrWidth) + val MCAUSE = 0x342.U(Parameters.CSRRegisterAddrWidth) + val CycleL = 0xc00.U(Parameters.CSRRegisterAddrWidth) + val CycleH = 0xc80.U(Parameters.CSRRegisterAddrWidth) +} + +class CSR extends Module { + val io = IO(new Bundle { + val reg_read_address_id = Input(UInt(Parameters.CSRRegisterAddrWidth)) + val reg_write_enable_ex = Input(Bool()) + val reg_write_address_ex = Input(UInt(Parameters.CSRRegisterAddrWidth)) + val reg_write_data_ex = Input(UInt(Parameters.DataWidth)) + + val id_reg_read_data = Output(UInt(Parameters.DataWidth)) + + val clint_access_bundle = Flipped(new CSRDirectAccessBundle) + }) + + val mstatus = RegInit(UInt(Parameters.DataWidth), 0.U) + val mie = RegInit(UInt(Parameters.DataWidth), 0.U) + val mtvec = RegInit(UInt(Parameters.DataWidth), 0.U) + val mscratch = RegInit(UInt(Parameters.DataWidth), 0.U) + val mepc = RegInit(UInt(Parameters.DataWidth), 0.U) + val mcause = RegInit(UInt(Parameters.DataWidth), 0.U) + val cycles = RegInit(UInt(64.W), 0.U) + val regLUT = + IndexedSeq( + CSRRegister.MSTATUS -> mstatus, + CSRRegister.MIE -> mie, + CSRRegister.MTVEC -> mtvec, + CSRRegister.MSCRATCH -> mscratch, + CSRRegister.MEPC -> mepc, + CSRRegister.MCAUSE -> mcause, + CSRRegister.CycleL -> cycles(31, 0), + CSRRegister.CycleH -> cycles(63, 32), + ) + cycles := cycles + 1.U + + // If the pipeline and the CLINT are going to read and write the CSR at the same time, let the pipeline write first. + // This is implemented in a single cycle by passing reg_write_data_ex to clint and writing the data from the CLINT to the CSR. + io.id_reg_read_data := MuxLookup(io.reg_read_address_id, 0.U, regLUT) + + io.clint_access_bundle.mstatus := Mux(io.reg_write_enable_ex && io.reg_write_address_ex === CSRRegister.MSTATUS, io.reg_write_data_ex, mstatus) + io.clint_access_bundle.mtvec := Mux(io.reg_write_enable_ex && io.reg_write_address_ex === CSRRegister.MTVEC, io.reg_write_data_ex, mtvec) + io.clint_access_bundle.mcause := Mux(io.reg_write_enable_ex && io.reg_write_address_ex === CSRRegister.MCAUSE, io.reg_write_data_ex, mcause) + io.clint_access_bundle.mepc := Mux(io.reg_write_enable_ex && io.reg_write_address_ex === CSRRegister.MEPC, io.reg_write_data_ex, mepc) + + when(io.clint_access_bundle.direct_write_enable) { + mstatus := io.clint_access_bundle.mstatus_write_data + mepc := io.clint_access_bundle.mepc_write_data + mcause := io.clint_access_bundle.mcause_write_data + }.elsewhen(io.reg_write_enable_ex) { + when(io.reg_write_address_ex === CSRRegister.MSTATUS) { + mstatus := io.reg_write_data_ex + }.elsewhen(io.reg_write_address_ex === CSRRegister.MEPC) { + mepc := io.reg_write_data_ex + }.elsewhen(io.reg_write_address_ex === CSRRegister.MCAUSE) { + mcause := io.reg_write_data_ex + } + } + + when(io.reg_write_enable_ex) { + when(io.reg_write_address_ex === CSRRegister.MIE) { + mie := io.reg_write_data_ex + }.elsewhen(io.reg_write_address_ex === CSRRegister.MTVEC) { + mtvec := io.reg_write_data_ex + }.elsewhen(io.reg_write_address_ex === CSRRegister.MSCRATCH) { + mscratch := io.reg_write_data_ex + } + } +} diff --git a/lab3/src/main/scala/riscv/core/PipelineRegister.scala b/lab3/src/main/scala/riscv/core/PipelineRegister.scala new file mode 100644 index 0000000..d736e53 --- /dev/null +++ b/lab3/src/main/scala/riscv/core/PipelineRegister.scala @@ -0,0 +1,30 @@ +// 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.core + +import chisel3._ +import riscv.Parameters + +class PipelineRegister(width: Int = Parameters.DataBits, defaultValue: UInt = 0.U) extends Module { + val io = IO(new Bundle { + val stall = Input(Bool()) + val flush = Input(Bool()) + val in = Input(UInt(width.W)) + val out = Output(UInt(width.W)) + }) + // Lab3(PipelineRegister) + io.out := 0.U + // Lab3(PipelineRegister) End +} diff --git a/lab3/src/main/scala/riscv/core/RegisterFile.scala b/lab3/src/main/scala/riscv/core/RegisterFile.scala new file mode 100644 index 0000000..1000f6c --- /dev/null +++ b/lab3/src/main/scala/riscv/core/RegisterFile.scala @@ -0,0 +1,78 @@ +// 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.core + +import chisel3._ +import chisel3.util._ +import riscv.Parameters + +object Registers extends Enumeration { + type Register = Value + val zero, + ra, sp, gp, tp, + t0, t1, t2, fp, + s1, + a0, a1, a2, a3, a4, a5, a6, a7, + s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, + t3, t4, t5, t6 = Value +} + +class RegisterFile extends Module { + val io = IO(new Bundle { + val write_enable = Input(Bool()) + val write_address = Input(UInt(Parameters.PhysicalRegisterAddrWidth)) + val write_data = Input(UInt(Parameters.DataWidth)) + + val read_address1 = Input(UInt(Parameters.PhysicalRegisterAddrWidth)) + val read_address2 = Input(UInt(Parameters.PhysicalRegisterAddrWidth)) + val read_data1 = Output(UInt(Parameters.DataWidth)) + val read_data2 = Output(UInt(Parameters.DataWidth)) + + val debug_read_address = Input(UInt(Parameters.PhysicalRegisterAddrWidth)) + val debug_read_data = Output(UInt(Parameters.DataWidth)) + }) + val registers = Reg(Vec(Parameters.PhysicalRegisters, UInt(Parameters.DataWidth))) + + when(!reset.asBool) { + when(io.write_enable && io.write_address =/= 0.U) { + registers(io.write_address) := io.write_data + } + } + + io.read_data1 := MuxCase( + registers(io.read_address1), + IndexedSeq( + (io.read_address1 === 0.U) -> 0.U, + (io.read_address1 === io.write_address && io.write_enable) -> io.write_data + ) + ) + + io.read_data2 := MuxCase( + registers(io.read_address2), + IndexedSeq( + (io.read_address2 === 0.U) -> 0.U, + (io.read_address2 === io.write_address && io.write_enable) -> io.write_data + ) + ) + + io.debug_read_data := MuxCase( + registers(io.debug_read_address), + IndexedSeq( + (io.debug_read_address === 0.U) -> 0.U, + (io.debug_read_address === io.write_address && io.write_enable) -> io.write_data + ) + ) + +} diff --git a/lab3/src/main/scala/riscv/core/fivestage_final/CLINT.scala b/lab3/src/main/scala/riscv/core/fivestage_final/CLINT.scala new file mode 100644 index 0000000..8efe68b --- /dev/null +++ b/lab3/src/main/scala/riscv/core/fivestage_final/CLINT.scala @@ -0,0 +1,101 @@ +// 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.core.fivestage_final + +import chisel3._ +import chisel3.util.MuxLookup +import riscv.Parameters + +object InterruptStatus { + val None = 0x0.U(8.W) + val Timer0 = 0x1.U(8.W) + val Ret = 0xFF.U(8.W) +} + +class CSRDirectAccessBundle extends Bundle { + val mstatus = Input(UInt(Parameters.DataWidth)) + val mepc = Input(UInt(Parameters.DataWidth)) + val mcause = Input(UInt(Parameters.DataWidth)) + val mtvec = Input(UInt(Parameters.DataWidth)) + + val mstatus_write_data = Output(UInt(Parameters.DataWidth)) + val mepc_write_data = Output(UInt(Parameters.DataWidth)) + val mcause_write_data = Output(UInt(Parameters.DataWidth)) + + val direct_write_enable = Output(Bool()) +} + +// Core Local Interrupt Controller +class CLINT extends Module { + val io = IO(new Bundle { + val interrupt_flag = Input(UInt(Parameters.InterruptFlagWidth)) + + val instruction_id = Input(UInt(Parameters.InstructionWidth)) + val instruction_address_if = Input(UInt(Parameters.AddrWidth)) + + val jump_flag = Input(Bool()) + val jump_address = Input(UInt(Parameters.AddrWidth)) + + val id_interrupt_handler_address = Output(UInt(Parameters.AddrWidth)) + val id_interrupt_assert = Output(Bool()) + + val csr_bundle = new CSRDirectAccessBundle + }) + val interrupt_enable = io.csr_bundle.mstatus(3) + val instruction_address = Mux( + io.jump_flag, + io.jump_address, + io.instruction_address_if, + ) + val mstatus_disable_interrupt = io.csr_bundle.mstatus(31, 4) ## 0.U(1.W) ## io.csr_bundle.mstatus(2, 0) + val mstatus_recover_interrupt = io.csr_bundle.mstatus(31, 4) ## io.csr_bundle.mstatus(7) ## io.csr_bundle.mstatus(2, 0) + + when(io.instruction_id === InstructionsEnv.ecall || io.instruction_id === InstructionsEnv.ebreak) { + io.csr_bundle.mstatus_write_data := mstatus_disable_interrupt + io.csr_bundle.mepc_write_data := instruction_address + io.csr_bundle.mcause_write_data := MuxLookup( + io.instruction_id, + 10.U, + IndexedSeq( + InstructionsEnv.ecall -> 11.U, + InstructionsEnv.ebreak -> 3.U, + ) + ) + io.csr_bundle.direct_write_enable := true.B + io.id_interrupt_assert := true.B + io.id_interrupt_handler_address := io.csr_bundle.mtvec + }.elsewhen(io.interrupt_flag =/= InterruptStatus.None && interrupt_enable) { + io.csr_bundle.mstatus_write_data := mstatus_disable_interrupt + io.csr_bundle.mepc_write_data := instruction_address + io.csr_bundle.mcause_write_data := Mux(io.interrupt_flag(0), 0x80000007L.U, 0x8000000BL.U) + io.csr_bundle.direct_write_enable := true.B + io.id_interrupt_assert := true.B + io.id_interrupt_handler_address := io.csr_bundle.mtvec + }.elsewhen(io.instruction_id === InstructionsRet.mret) { + io.csr_bundle.mstatus_write_data := mstatus_recover_interrupt + io.csr_bundle.mepc_write_data := io.csr_bundle.mepc + io.csr_bundle.mcause_write_data := io.csr_bundle.mcause + io.csr_bundle.direct_write_enable := true.B + io.id_interrupt_assert := true.B + io.id_interrupt_handler_address := io.csr_bundle.mepc + }.otherwise { + io.csr_bundle.mstatus_write_data := io.csr_bundle.mstatus + io.csr_bundle.mepc_write_data := io.csr_bundle.mepc + io.csr_bundle.mcause_write_data := io.csr_bundle.mcause + io.csr_bundle.direct_write_enable := false.B + io.id_interrupt_assert := false.B + io.id_interrupt_handler_address := 0.U + } +} diff --git a/lab3/src/main/scala/riscv/core/fivestage_final/CPU.scala b/lab3/src/main/scala/riscv/core/fivestage_final/CPU.scala new file mode 100644 index 0000000..2629ba4 --- /dev/null +++ b/lab3/src/main/scala/riscv/core/fivestage_final/CPU.scala @@ -0,0 +1,169 @@ +// 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.core.fivestage_final + +import chisel3._ +import riscv.Parameters +import riscv.core.{CPUBundle, CSR, RegisterFile} + +class CPU extends Module { + val io = IO(new CPUBundle) + + val ctrl = Module(new Control) + val regs = Module(new RegisterFile) + val inst_fetch = Module(new InstructionFetch) + val if2id = Module(new IF2ID) + val id = Module(new InstructionDecode) + val id2ex = Module(new ID2EX) + val ex = Module(new Execute) + val ex2mem = Module(new EX2MEM) + val mem = Module(new MemoryAccess) + val mem2wb = Module(new MEM2WB) + val wb = Module(new WriteBack) + val forwarding = Module(new Forwarding) + val clint = Module(new CLINT) + val csr_regs = Module(new CSR) + + ctrl.io.jump_flag := id.io.if_jump_flag + ctrl.io.jump_instruction_id := id.io.ctrl_jump_instruction + ctrl.io.rs1_id := id.io.regs_reg1_read_address + ctrl.io.rs2_id := id.io.regs_reg2_read_address + ctrl.io.memory_read_enable_ex := id2ex.io.output_memory_read_enable + ctrl.io.rd_ex := id2ex.io.output_regs_write_address + ctrl.io.memory_read_enable_mem := ex2mem.io.output_memory_read_enable + ctrl.io.rd_mem := ex2mem.io.output_regs_write_address + + regs.io.write_enable := mem2wb.io.output_regs_write_enable + regs.io.write_address := mem2wb.io.output_regs_write_address + regs.io.write_data := wb.io.regs_write_data + regs.io.read_address1 := id.io.regs_reg1_read_address + regs.io.read_address2 := id.io.regs_reg2_read_address + + regs.io.debug_read_address := io.debug_read_address + io.debug_read_data := regs.io.debug_read_data + + io.instruction_address := inst_fetch.io.instruction_address + inst_fetch.io.stall_flag_ctrl := ctrl.io.pc_stall + inst_fetch.io.jump_flag_id := id.io.if_jump_flag + inst_fetch.io.jump_address_id := id.io.if_jump_address + inst_fetch.io.rom_instruction := io.instruction + inst_fetch.io.instruction_valid := io.instruction_valid + + if2id.io.stall := ctrl.io.if_stall + if2id.io.flush := ctrl.io.if_flush + if2id.io.instruction := inst_fetch.io.id_instruction + if2id.io.instruction_address := inst_fetch.io.instruction_address + if2id.io.interrupt_flag := io.interrupt_flag + + id.io.instruction := if2id.io.output_instruction + id.io.instruction_address := if2id.io.output_instruction_address + id.io.reg1_data := regs.io.read_data1 + id.io.reg2_data := regs.io.read_data2 + id.io.forward_from_mem := mem.io.forward_data + id.io.forward_from_wb := wb.io.regs_write_data + id.io.reg1_forward := forwarding.io.reg1_forward_id + id.io.reg2_forward := forwarding.io.reg2_forward_id + id.io.interrupt_assert := clint.io.id_interrupt_assert + id.io.interrupt_handler_address := clint.io.id_interrupt_handler_address + + id2ex.io.flush := ctrl.io.id_flush + id2ex.io.instruction := if2id.io.output_instruction + id2ex.io.instruction_address := if2id.io.output_instruction_address + id2ex.io.reg1_data := regs.io.read_data1 + id2ex.io.reg2_data := regs.io.read_data2 + id2ex.io.regs_reg1_read_address := id.io.regs_reg1_read_address + id2ex.io.regs_reg2_read_address := id.io.regs_reg2_read_address + id2ex.io.regs_write_enable := id.io.ex_reg_write_enable + id2ex.io.regs_write_address := id.io.ex_reg_write_address + id2ex.io.regs_write_source := id.io.ex_reg_write_source + id2ex.io.immediate := id.io.ex_immediate + id2ex.io.aluop1_source := id.io.ex_aluop1_source + id2ex.io.aluop2_source := id.io.ex_aluop2_source + id2ex.io.csr_write_enable := id.io.ex_csr_write_enable + id2ex.io.csr_address := id.io.ex_csr_address + id2ex.io.memory_read_enable := id.io.ex_memory_read_enable + id2ex.io.memory_write_enable := id.io.ex_memory_write_enable + id2ex.io.csr_read_data := csr_regs.io.id_reg_read_data + + ex.io.instruction := id2ex.io.output_instruction + ex.io.instruction_address := id2ex.io.output_instruction_address + ex.io.reg1_data := id2ex.io.output_reg1_data + ex.io.reg2_data := id2ex.io.output_reg2_data + ex.io.immediate := id2ex.io.output_immediate + ex.io.aluop1_source := id2ex.io.output_aluop1_source + ex.io.aluop2_source := id2ex.io.output_aluop2_source + ex.io.csr_read_data := id2ex.io.output_csr_read_data + ex.io.forward_from_mem := mem.io.forward_data + ex.io.forward_from_wb := wb.io.regs_write_data + ex.io.reg1_forward := forwarding.io.reg1_forward_ex + ex.io.reg2_forward := forwarding.io.reg2_forward_ex + + ex2mem.io.regs_write_enable := id2ex.io.output_regs_write_enable + ex2mem.io.regs_write_source := id2ex.io.output_regs_write_source + ex2mem.io.regs_write_address := id2ex.io.output_regs_write_address + ex2mem.io.instruction_address := id2ex.io.output_instruction_address + ex2mem.io.funct3 := id2ex.io.output_instruction(14, 12) + ex2mem.io.reg2_data := ex.io.mem_reg2_data + ex2mem.io.memory_read_enable := id2ex.io.output_memory_read_enable + ex2mem.io.memory_write_enable := id2ex.io.output_memory_write_enable + ex2mem.io.alu_result := ex.io.mem_alu_result + ex2mem.io.csr_read_data := id2ex.io.output_csr_read_data + + mem.io.alu_result := ex2mem.io.output_alu_result + mem.io.reg2_data := ex2mem.io.output_reg2_data + mem.io.memory_read_enable := ex2mem.io.output_memory_read_enable + mem.io.memory_write_enable := ex2mem.io.output_memory_write_enable + mem.io.funct3 := ex2mem.io.output_funct3 + mem.io.regs_write_source := ex2mem.io.output_regs_write_source + mem.io.csr_read_data := ex2mem.io.output_csr_read_data + io.device_select := mem.io.bundle.address(Parameters.AddrBits - 1, Parameters.AddrBits - Parameters.SlaveDeviceCountBits) + io.memory_bundle <> mem.io.bundle + io.memory_bundle.address := 0.U(Parameters.SlaveDeviceCountBits.W) ## mem.io.bundle.address(Parameters.AddrBits - 1 - Parameters.SlaveDeviceCountBits, 0) + + mem2wb.io.instruction_address := ex2mem.io.output_instruction_address + mem2wb.io.alu_result := ex2mem.io.output_alu_result + mem2wb.io.regs_write_enable := ex2mem.io.output_regs_write_enable + mem2wb.io.regs_write_source := ex2mem.io.output_regs_write_source + mem2wb.io.regs_write_address := ex2mem.io.output_regs_write_address + mem2wb.io.memory_read_data := mem.io.wb_memory_read_data + mem2wb.io.csr_read_data := ex2mem.io.output_csr_read_data + + wb.io.instruction_address := mem2wb.io.output_instruction_address + wb.io.alu_result := mem2wb.io.output_alu_result + wb.io.memory_read_data := mem2wb.io.output_memory_read_data + wb.io.regs_write_source := mem2wb.io.output_regs_write_source + wb.io.csr_read_data := mem2wb.io.output_csr_read_data + + forwarding.io.rs1_id := id.io.regs_reg1_read_address + forwarding.io.rs2_id := id.io.regs_reg2_read_address + forwarding.io.rs1_ex := id2ex.io.output_regs_reg1_read_address + forwarding.io.rs2_ex := id2ex.io.output_regs_reg2_read_address + forwarding.io.rd_mem := ex2mem.io.output_regs_write_address + forwarding.io.reg_write_enable_mem := ex2mem.io.output_regs_write_enable + forwarding.io.rd_wb := mem2wb.io.output_regs_write_address + forwarding.io.reg_write_enable_wb := mem2wb.io.output_regs_write_enable + + clint.io.instruction_address_if := inst_fetch.io.instruction_address + clint.io.instruction_id := if2id.io.output_instruction + clint.io.jump_flag := id.io.clint_jump_flag + clint.io.jump_address := id.io.clint_jump_address + clint.io.interrupt_flag := if2id.io.output_interrupt_flag + clint.io.csr_bundle <> csr_regs.io.clint_access_bundle + + csr_regs.io.reg_read_address_id := id.io.ex_csr_address + csr_regs.io.reg_write_enable_ex := id2ex.io.output_csr_write_enable + csr_regs.io.reg_write_address_ex := id2ex.io.output_csr_address + csr_regs.io.reg_write_data_ex := ex.io.csr_write_data +} diff --git a/lab3/src/main/scala/riscv/core/fivestage_final/Control.scala b/lab3/src/main/scala/riscv/core/fivestage_final/Control.scala new file mode 100644 index 0000000..b8b9579 --- /dev/null +++ b/lab3/src/main/scala/riscv/core/fivestage_final/Control.scala @@ -0,0 +1,43 @@ +// 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.core.fivestage_final + +import chisel3._ +import riscv.Parameters + +class Control extends Module { + val io = IO(new Bundle { + val jump_flag = Input(Bool()) + val jump_instruction_id = Input(Bool()) + val rs1_id = Input(UInt(Parameters.PhysicalRegisterAddrWidth)) + val rs2_id = Input(UInt(Parameters.PhysicalRegisterAddrWidth)) + val memory_read_enable_ex = Input(Bool()) + val rd_ex = Input(UInt(Parameters.PhysicalRegisterAddrWidth)) + val memory_read_enable_mem = Input(Bool()) + val rd_mem = Input(UInt(Parameters.PhysicalRegisterAddrWidth)) + + val if_flush = Output(Bool()) + val id_flush = Output(Bool()) + val pc_stall = Output(Bool()) + val if_stall = Output(Bool()) + }) + + // Lab3(Final) + io.if_flush := false.B + io.id_flush := false.B + io.pc_stall := false.B + io.if_stall := false.B + // Lab3(Final) End +} diff --git a/lab3/src/main/scala/riscv/core/fivestage_final/EX2MEM.scala b/lab3/src/main/scala/riscv/core/fivestage_final/EX2MEM.scala new file mode 100644 index 0000000..2c72271 --- /dev/null +++ b/lab3/src/main/scala/riscv/core/fivestage_final/EX2MEM.scala @@ -0,0 +1,108 @@ +// Copyright 2022 Canbin Huang +// +// 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.core.fivestage_final + +import chisel3._ +import riscv.Parameters +import riscv.core.PipelineRegister + +class EX2MEM extends Module { + val io = IO(new Bundle() { + val regs_write_enable = Input(Bool()) + val regs_write_source = Input(UInt(2.W)) + val regs_write_address = Input(UInt(Parameters.AddrWidth)) + val instruction_address = Input(UInt(Parameters.AddrWidth)) + val funct3 = Input(UInt(3.W)) + val reg2_data = Input(UInt(Parameters.DataWidth)) + val memory_read_enable = Input(Bool()) + val memory_write_enable = Input(Bool()) + val alu_result = Input(UInt(Parameters.DataWidth)) + val csr_read_data = Input(UInt(Parameters.DataWidth)) + + val output_regs_write_enable = Output(Bool()) + val output_regs_write_source = Output(UInt(2.W)) + val output_regs_write_address = Output(UInt(Parameters.AddrWidth)) + val output_instruction_address = Output(UInt(Parameters.AddrWidth)) + val output_funct3 = Output(UInt(Parameters.DataWidth)) + val output_reg2_data = Output(UInt(Parameters.DataWidth)) + val output_memory_read_enable = Output(Bool()) + val output_memory_write_enable = Output(Bool()) + val output_alu_result = Output(UInt(Parameters.DataWidth)) + val output_csr_read_data = Output(UInt(Parameters.DataWidth)) + }) + + val stall = false.B + val flush = false.B + + val regs_write_enable = Module(new PipelineRegister(1)) + regs_write_enable.io.in := io.regs_write_enable + regs_write_enable.io.stall := stall + regs_write_enable.io.flush := flush + io.output_regs_write_enable := regs_write_enable.io.out + + val regs_write_source = Module(new PipelineRegister(2)) + regs_write_source.io.in := io.regs_write_source + regs_write_source.io.stall := stall + regs_write_source.io.flush := flush + io.output_regs_write_source := regs_write_source.io.out + + val regs_write_address = Module(new PipelineRegister(Parameters.PhysicalRegisterAddrBits)) + regs_write_address.io.in := io.regs_write_address + regs_write_address.io.stall := stall + regs_write_address.io.flush := flush + io.output_regs_write_address := regs_write_address.io.out + + val instruction_address = Module(new PipelineRegister(Parameters.AddrBits)) + instruction_address.io.in := io.instruction_address + instruction_address.io.stall := stall + instruction_address.io.flush := flush + io.output_instruction_address := instruction_address.io.out + + val funct3 = Module(new PipelineRegister(3)) + funct3.io.in := io.funct3 + funct3.io.stall := stall + funct3.io.flush := flush + io.output_funct3 := funct3.io.out + + val reg2_data = Module(new PipelineRegister()) + reg2_data.io.in := io.reg2_data + reg2_data.io.stall := stall + reg2_data.io.flush := flush + io.output_reg2_data := reg2_data.io.out + + val alu_result = Module(new PipelineRegister()) + alu_result.io.in := io.alu_result + alu_result.io.stall := stall + alu_result.io.flush := flush + io.output_alu_result := alu_result.io.out + + val memory_read_enable = Module(new PipelineRegister(1)) + memory_read_enable.io.in := io.memory_read_enable + memory_read_enable.io.stall := stall + memory_read_enable.io.flush := flush + io.output_memory_read_enable := memory_read_enable.io.out + + val memory_write_enable = Module(new PipelineRegister(1)) + memory_write_enable.io.in := io.memory_write_enable + memory_write_enable.io.stall := stall + memory_write_enable.io.flush := flush + io.output_memory_write_enable := memory_write_enable.io.out + + val csr_read_data = Module(new PipelineRegister()) + csr_read_data.io.in := io.csr_read_data + csr_read_data.io.stall := stall + csr_read_data.io.flush := flush + io.output_csr_read_data := csr_read_data.io.out +} diff --git a/lab3/src/main/scala/riscv/core/fivestage_final/Execute.scala b/lab3/src/main/scala/riscv/core/fivestage_final/Execute.scala new file mode 100644 index 0000000..eb7f74b --- /dev/null +++ b/lab3/src/main/scala/riscv/core/fivestage_final/Execute.scala @@ -0,0 +1,93 @@ +// 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.core.fivestage_final + +import chisel3._ +import chisel3.util._ +import riscv.Parameters +import riscv.core.{ALU, ALUControl} + + +class Execute extends Module { + val io = IO(new Bundle { + val instruction = Input(UInt(Parameters.InstructionWidth)) + val instruction_address = Input(UInt(Parameters.AddrWidth)) + val reg1_data = Input(UInt(Parameters.DataWidth)) + val reg2_data = Input(UInt(Parameters.DataWidth)) + val immediate = Input(UInt(Parameters.DataWidth)) + val aluop1_source = Input(UInt(1.W)) + val aluop2_source = Input(UInt(1.W)) + val csr_read_data = Input(UInt(Parameters.DataWidth)) + val forward_from_mem = Input(UInt(Parameters.DataWidth)) + val forward_from_wb = Input(UInt(Parameters.DataWidth)) + val reg1_forward = Input(UInt(2.W)) + val reg2_forward = Input(UInt(2.W)) + + val mem_alu_result = Output(UInt(Parameters.DataWidth)) + val mem_reg2_data = Output(UInt(Parameters.DataWidth)) + val csr_write_data = Output(UInt(Parameters.DataWidth)) + }) + + val opcode = io.instruction(6, 0) + val funct3 = io.instruction(14, 12) + val funct7 = io.instruction(31, 25) + val uimm = io.instruction(19, 15) + + val alu = Module(new ALU) + val alu_ctrl = Module(new ALUControl) + + alu_ctrl.io.opcode := opcode + alu_ctrl.io.funct3 := funct3 + alu_ctrl.io.funct7 := funct7 + alu.io.func := alu_ctrl.io.alu_funct + + val reg1_data = MuxLookup( + io.reg1_forward, + io.reg1_data, + IndexedSeq( + ForwardingType.ForwardFromMEM -> io.forward_from_mem, + ForwardingType.ForwardFromWB -> io.forward_from_wb + ) + ) + alu.io.op1 := Mux( + io.aluop1_source === ALUOp1Source.InstructionAddress, + io.instruction_address, + reg1_data + ) + + val reg2_data = MuxLookup( + io.reg2_forward, + io.reg2_data, + IndexedSeq( + ForwardingType.ForwardFromMEM -> io.forward_from_mem, + ForwardingType.ForwardFromWB -> io.forward_from_wb + ) + ) + alu.io.op2 := Mux( + io.aluop2_source === ALUOp2Source.Immediate, + io.immediate, + reg2_data + ) + io.mem_alu_result := alu.io.result + io.mem_reg2_data := reg2_data + io.csr_write_data := MuxLookup(funct3, 0.U, IndexedSeq( + InstructionsTypeCSR.csrrw -> reg1_data, + InstructionsTypeCSR.csrrc -> io.csr_read_data.&((~reg1_data).asUInt), + InstructionsTypeCSR.csrrs -> io.csr_read_data.|(reg1_data), + InstructionsTypeCSR.csrrwi -> Cat(0.U(27.W), uimm), + InstructionsTypeCSR.csrrci -> io.csr_read_data.&((~Cat(0.U(27.W), uimm)).asUInt), + InstructionsTypeCSR.csrrsi -> io.csr_read_data.|(Cat(0.U(27.W), uimm)), + )) +} diff --git a/lab3/src/main/scala/riscv/core/fivestage_final/Forwarding.scala b/lab3/src/main/scala/riscv/core/fivestage_final/Forwarding.scala new file mode 100644 index 0000000..1014476 --- /dev/null +++ b/lab3/src/main/scala/riscv/core/fivestage_final/Forwarding.scala @@ -0,0 +1,49 @@ +// Copyright 2022 Canbin Huang +// +// 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.core.fivestage_final + +import chisel3._ +import riscv.Parameters + +object ForwardingType { + val NoForward = 0.U(2.W) + val ForwardFromMEM = 1.U(2.W) + val ForwardFromWB = 2.U(2.W) +} + +class Forwarding extends Module { + val io = IO(new Bundle() { + val rs1_id = Input(UInt(Parameters.PhysicalRegisterAddrWidth)) + val rs2_id = Input(UInt(Parameters.PhysicalRegisterAddrWidth)) + val rs1_ex = Input(UInt(Parameters.PhysicalRegisterAddrWidth)) + val rs2_ex = Input(UInt(Parameters.PhysicalRegisterAddrWidth)) + val rd_mem = Input(UInt(Parameters.PhysicalRegisterAddrWidth)) + val reg_write_enable_mem = Input(Bool()) + val rd_wb = Input(UInt(Parameters.PhysicalRegisterAddrWidth)) + val reg_write_enable_wb = Input(Bool()) + + val reg1_forward_id = Output(UInt(2.W)) + val reg2_forward_id = Output(UInt(2.W)) + val reg1_forward_ex = Output(UInt(2.W)) + val reg2_forward_ex = Output(UInt(2.W)) + }) + + // Lab3(Final) + io.reg1_forward_id := 0.U + io.reg2_forward_id := 0.U + io.reg1_forward_ex := 0.U + io.reg2_forward_ex := 0.U + // Lab3(Final) End +} diff --git a/lab3/src/main/scala/riscv/core/fivestage_final/ID2EX.scala b/lab3/src/main/scala/riscv/core/fivestage_final/ID2EX.scala new file mode 100644 index 0000000..15b85fb --- /dev/null +++ b/lab3/src/main/scala/riscv/core/fivestage_final/ID2EX.scala @@ -0,0 +1,163 @@ +// 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.core.fivestage_final + +import chisel3._ +import riscv.Parameters +import riscv.core.PipelineRegister + +class ID2EX extends Module { + val io = IO(new Bundle { + val flush = Input(Bool()) + val instruction = Input(UInt(Parameters.InstructionWidth)) + val instruction_address = Input(UInt(Parameters.AddrWidth)) + val regs_reg1_read_address = Input(UInt(Parameters.PhysicalRegisterAddrWidth)) + val regs_reg2_read_address = Input(UInt(Parameters.PhysicalRegisterAddrWidth)) + val regs_write_enable = Input(Bool()) + val regs_write_address = Input(UInt(Parameters.PhysicalRegisterAddrWidth)) + val regs_write_source = Input(UInt(2.W)) + val reg1_data = Input(UInt(Parameters.DataWidth)) + val reg2_data = Input(UInt(Parameters.DataWidth)) + val immediate = Input(UInt(Parameters.DataWidth)) + val aluop1_source = Input(UInt(1.W)) + val aluop2_source = Input(UInt(1.W)) + val csr_write_enable = Input(Bool()) + val csr_address = Input(UInt(Parameters.CSRRegisterAddrWidth)) + val memory_read_enable = Input(Bool()) + val memory_write_enable = Input(Bool()) + val csr_read_data = Input(UInt(Parameters.DataWidth)) + + val output_instruction = Output(UInt(Parameters.DataWidth)) + val output_instruction_address = Output(UInt(Parameters.AddrWidth)) + val output_regs_reg1_read_address = Output(UInt(Parameters.PhysicalRegisterAddrWidth)) + val output_regs_reg2_read_address = Output(UInt(Parameters.PhysicalRegisterAddrWidth)) + val output_regs_write_enable = Output(Bool()) + val output_regs_write_address = Output(UInt(Parameters.PhysicalRegisterAddrWidth)) + val output_regs_write_source = Output(UInt(2.W)) + val output_reg1_data = Output(UInt(Parameters.DataWidth)) + val output_reg2_data = Output(UInt(Parameters.DataWidth)) + val output_immediate = Output(UInt(Parameters.DataWidth)) + val output_aluop1_source = Output(UInt(1.W)) + val output_aluop2_source = Output(UInt(1.W)) + val output_csr_write_enable = Output(Bool()) + val output_csr_address = Output(UInt(Parameters.CSRRegisterAddrWidth)) + val output_memory_read_enable = Output(Bool()) + val output_memory_write_enable = Output(Bool()) + val output_csr_read_data = Output(UInt(Parameters.DataWidth)) + }) + val stall = false.B + + val instruction = Module(new PipelineRegister(defaultValue = InstructionsNop.nop)) + instruction.io.in := io.instruction + instruction.io.stall := stall + instruction.io.flush := io.flush + io.output_instruction := instruction.io.out + + val instruction_address = Module(new PipelineRegister(defaultValue = ProgramCounter.EntryAddress)) + instruction_address.io.in := io.instruction_address + instruction_address.io.stall := stall + instruction_address.io.flush := io.flush + io.output_instruction_address := instruction_address.io.out + + val regs_reg1_read_address = Module(new PipelineRegister(Parameters.PhysicalRegisterAddrBits)) + regs_reg1_read_address.io.in := io.regs_reg1_read_address + regs_reg1_read_address.io.stall := stall + regs_reg1_read_address.io.flush := io.flush + io.output_regs_reg1_read_address := regs_reg1_read_address.io.out + + val regs_reg2_read_address = Module(new PipelineRegister(Parameters.PhysicalRegisterAddrBits)) + regs_reg2_read_address.io.in := io.regs_reg2_read_address + regs_reg2_read_address.io.stall := stall + regs_reg2_read_address.io.flush := io.flush + io.output_regs_reg2_read_address := regs_reg2_read_address.io.out + + val regs_write_enable = Module(new PipelineRegister(1)) + regs_write_enable.io.in := io.regs_write_enable + regs_write_enable.io.stall := stall + regs_write_enable.io.flush := io.flush + io.output_regs_write_enable := regs_write_enable.io.out + + val regs_write_address = Module(new PipelineRegister(Parameters.PhysicalRegisterAddrBits)) + regs_write_address.io.in := io.regs_write_address + regs_write_address.io.stall := stall + regs_write_address.io.flush := io.flush + io.output_regs_write_address := regs_write_address.io.out + + val regs_write_source = Module(new PipelineRegister(2)) + regs_write_source.io.in := io.regs_write_source + regs_write_source.io.stall := stall + regs_write_source.io.flush := io.flush + io.output_regs_write_source := regs_write_source.io.out + + val reg1_data = Module(new PipelineRegister()) + reg1_data.io.in := io.reg1_data + reg1_data.io.stall := stall + reg1_data.io.flush := io.flush + io.output_reg1_data := reg1_data.io.out + + val reg2_data = Module(new PipelineRegister()) + reg2_data.io.in := io.reg2_data + reg2_data.io.stall := stall + reg2_data.io.flush := io.flush + io.output_reg2_data := reg2_data.io.out + + val immediate = Module(new PipelineRegister()) + immediate.io.in := io.immediate + immediate.io.stall := stall + immediate.io.flush := io.flush + io.output_immediate := immediate.io.out + + val aluop1_source = Module(new PipelineRegister(1)) + aluop1_source.io.in := io.aluop1_source + aluop1_source.io.stall := stall + aluop1_source.io.flush := io.flush + io.output_aluop1_source := aluop1_source.io.out + + val aluop2_source = Module(new PipelineRegister(1)) + aluop2_source.io.in := io.aluop2_source + aluop2_source.io.stall := stall + aluop2_source.io.flush := io.flush + io.output_aluop2_source := aluop2_source.io.out + + val csr_write_enable = Module(new PipelineRegister(1)) + csr_write_enable.io.in := io.csr_write_enable + csr_write_enable.io.stall := stall + csr_write_enable.io.flush := io.flush + io.output_csr_write_enable := csr_write_enable.io.out + + val csr_address = Module(new PipelineRegister(Parameters.CSRRegisterAddrBits)) + csr_address.io.in := io.csr_address + csr_address.io.stall := stall + csr_address.io.flush := io.flush + io.output_csr_address := csr_address.io.out + + val memory_read_enable = Module(new PipelineRegister(1)) + memory_read_enable.io.in := io.memory_read_enable + memory_read_enable.io.stall := stall + memory_read_enable.io.flush := io.flush + io.output_memory_read_enable := memory_read_enable.io.out + + val memory_write_enable = Module(new PipelineRegister(1)) + memory_write_enable.io.in := io.memory_write_enable + memory_write_enable.io.stall := stall + memory_write_enable.io.flush := io.flush + io.output_memory_write_enable := memory_write_enable.io.out + + val csr_read_data = Module(new PipelineRegister()) + csr_read_data.io.in := io.csr_read_data + csr_read_data.io.stall := stall + csr_read_data.io.flush := io.flush + io.output_csr_read_data := csr_read_data.io.out +} diff --git a/lab3/src/main/scala/riscv/core/fivestage_final/IF2ID.scala b/lab3/src/main/scala/riscv/core/fivestage_final/IF2ID.scala new file mode 100644 index 0000000..4eb9663 --- /dev/null +++ b/lab3/src/main/scala/riscv/core/fivestage_final/IF2ID.scala @@ -0,0 +1,51 @@ +// 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.core.fivestage_final + +import chisel3._ +import riscv.Parameters +import riscv.core.PipelineRegister + +class IF2ID extends Module { + val io = IO(new Bundle { + val stall = Input(Bool()) + val flush = Input(Bool()) + val instruction = Input(UInt(Parameters.InstructionWidth)) + val instruction_address = Input(UInt(Parameters.AddrWidth)) + val interrupt_flag = Input(UInt(Parameters.InterruptFlagWidth)) + + val output_instruction = Output(UInt(Parameters.DataWidth)) + val output_instruction_address = Output(UInt(Parameters.AddrWidth)) + val output_interrupt_flag = Output(UInt(Parameters.InterruptFlagWidth)) + }) + + val instruction = Module(new PipelineRegister(defaultValue = InstructionsNop.nop)) + instruction.io.in := io.instruction + instruction.io.stall := io.stall + instruction.io.flush := io.flush + io.output_instruction := instruction.io.out + + val instruction_address = Module(new PipelineRegister(defaultValue = ProgramCounter.EntryAddress)) + instruction_address.io.in := io.instruction_address + instruction_address.io.stall := io.stall + instruction_address.io.flush := io.flush + io.output_instruction_address := instruction_address.io.out + + val interrupt_flag = Module(new PipelineRegister(Parameters.InterruptFlagBits)) + interrupt_flag.io.in := io.interrupt_flag + interrupt_flag.io.stall := io.stall + interrupt_flag.io.flush := io.flush + io.output_interrupt_flag := interrupt_flag.io.out +} diff --git a/lab3/src/main/scala/riscv/core/fivestage_final/InstructionDecode.scala b/lab3/src/main/scala/riscv/core/fivestage_final/InstructionDecode.scala new file mode 100644 index 0000000..3fb1f5e --- /dev/null +++ b/lab3/src/main/scala/riscv/core/fivestage_final/InstructionDecode.scala @@ -0,0 +1,229 @@ +// 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.core.fivestage_final + +import chisel3._ +import chisel3.util._ +import riscv.Parameters + +object InstructionTypes { + val L = "b0000011".U + val I = "b0010011".U + val S = "b0100011".U + val RM = "b0110011".U + val B = "b1100011".U +} + +object Instructions { + val lui = "b0110111".U + val nop = "b0000001".U + val jal = "b1101111".U + val jalr = "b1100111".U + val auipc = "b0010111".U + val csr = "b1110011".U + val fence = "b0001111".U +} + +object InstructionsTypeL { + val lb = "b000".U + val lh = "b001".U + val lw = "b010".U + val lbu = "b100".U + val lhu = "b101".U +} + +object InstructionsTypeI { + val addi = 0.U + val slli = 1.U + val slti = 2.U + val sltiu = 3.U + val xori = 4.U + val sri = 5.U + val ori = 6.U + val andi = 7.U +} + +object InstructionsTypeS { + val sb = "b000".U + val sh = "b001".U + val sw = "b010".U +} + +object InstructionsTypeR { + val add_sub = 0.U + val sll = 1.U + val slt = 2.U + val sltu = 3.U + val xor = 4.U + val sr = 5.U + val or = 6.U + val and = 7.U +} + +object InstructionsTypeM { + val mul = 0.U + val mulh = 1.U + val mulhsu = 2.U + val mulhum = 3.U + val div = 4.U + val divu = 5.U + val rem = 6.U + val remu = 7.U +} + +object InstructionsTypeB { + val beq = "b000".U + val bne = "b001".U + val blt = "b100".U + val bge = "b101".U + val bltu = "b110".U + val bgeu = "b111".U +} + +object InstructionsTypeCSR { + val csrrw = "b001".U + val csrrs = "b010".U + val csrrc = "b011".U + val csrrwi = "b101".U + val csrrsi = "b110".U + val csrrci = "b111".U +} + +object InstructionsNop { + val nop = 0x00000013L.U(Parameters.DataWidth) +} + +object InstructionsRet { + val mret = 0x30200073L.U(Parameters.DataWidth) + val ret = 0x00008067L.U(Parameters.DataWidth) +} + +object InstructionsEnv { + val ecall = 0x00000073L.U(Parameters.DataWidth) + val ebreak = 0x00100073L.U(Parameters.DataWidth) +} + +object ALUOp1Source { + val Register = 0.U(1.W) + val InstructionAddress = 1.U(1.W) +} + +object ALUOp2Source { + val Register = 0.U(1.W) + val Immediate = 1.U(1.W) +} + +object RegWriteSource { + val ALUResult = 0.U(2.W) + val Memory = 1.U(2.W) + val CSR = 2.U(2.W) + val NextInstructionAddress = 3.U(2.W) +} + +class InstructionDecode extends Module { + val io = IO(new Bundle { + val instruction = Input(UInt(Parameters.InstructionWidth)) + val instruction_address = Input(UInt(Parameters.AddrWidth)) + val reg1_data = Input(UInt(Parameters.DataWidth)) + val reg2_data = Input(UInt(Parameters.DataWidth)) + val forward_from_mem = Input(UInt(Parameters.DataWidth)) + val forward_from_wb = Input(UInt(Parameters.DataWidth)) + val reg1_forward = Input(UInt(2.W)) + val reg2_forward = Input(UInt(2.W)) + val interrupt_assert = Input(Bool()) + val interrupt_handler_address = Input(UInt(Parameters.AddrWidth)) + + val regs_reg1_read_address = Output(UInt(Parameters.PhysicalRegisterAddrWidth)) + val regs_reg2_read_address = Output(UInt(Parameters.PhysicalRegisterAddrWidth)) + val ex_immediate = Output(UInt(Parameters.DataWidth)) + val ex_aluop1_source = Output(UInt(1.W)) + val ex_aluop2_source = Output(UInt(1.W)) + val ex_memory_read_enable = Output(Bool()) + val ex_memory_write_enable = Output(Bool()) + val ex_reg_write_source = Output(UInt(2.W)) + val ex_reg_write_enable = Output(Bool()) + val ex_reg_write_address = Output(UInt(Parameters.PhysicalRegisterAddrWidth)) + val ex_csr_address = Output(UInt(Parameters.CSRRegisterAddrWidth)) + val ex_csr_write_enable = Output(Bool()) + val ctrl_jump_instruction = Output(Bool()) + val clint_jump_flag = Output(Bool()) + val clint_jump_address = Output(UInt(Parameters.AddrWidth)) + val if_jump_flag = Output(Bool()) + val if_jump_address = Output(UInt(Parameters.AddrWidth)) + }) + val opcode = io.instruction(6, 0) + val funct3 = io.instruction(14, 12) + val funct7 = io.instruction(31, 25) + val rd = io.instruction(11, 7) + val rs1 = io.instruction(19, 15) + val rs2 = io.instruction(24, 20) + + io.regs_reg1_read_address := Mux(opcode === Instructions.lui, 0.U(Parameters.PhysicalRegisterAddrWidth), rs1) + io.regs_reg2_read_address := rs2 + io.ex_immediate := MuxLookup( + opcode, + Cat(Fill(20, io.instruction(31)), io.instruction(31, 20)), + IndexedSeq( + InstructionTypes.I -> Cat(Fill(21, io.instruction(31)), io.instruction(30, 20)), + InstructionTypes.L -> Cat(Fill(21, io.instruction(31)), io.instruction(30, 20)), + Instructions.jalr -> Cat(Fill(21, io.instruction(31)), io.instruction(30, 20)), + InstructionTypes.S -> Cat(Fill(21, io.instruction(31)), io.instruction(30, 25), io.instruction(11, 7)), + InstructionTypes.B -> Cat(Fill(20, io.instruction(31)), io.instruction(7), io.instruction(30, 25), io.instruction(11, 8), 0.U(1.W)), + Instructions.lui -> Cat(io.instruction(31, 12), 0.U(12.W)), + Instructions.auipc -> Cat(io.instruction(31, 12), 0.U(12.W)), + Instructions.jal -> Cat(Fill(12, io.instruction(31)), io.instruction(19, 12), io.instruction(20), io.instruction(30, 21), 0.U(1.W)) + ) + ) + io.ex_aluop1_source := Mux( + opcode === Instructions.auipc || opcode === InstructionTypes.B || opcode === Instructions.jal, + ALUOp1Source.InstructionAddress, + ALUOp1Source.Register + ) + io.ex_aluop2_source := Mux( + opcode === InstructionTypes.RM, + ALUOp2Source.Register, + ALUOp2Source.Immediate + ) + io.ex_memory_read_enable := opcode === InstructionTypes.L + io.ex_memory_write_enable := opcode === InstructionTypes.S + io.ex_reg_write_source := MuxLookup( + opcode, + RegWriteSource.ALUResult, + IndexedSeq( + InstructionTypes.L -> RegWriteSource.Memory, + Instructions.csr -> RegWriteSource.CSR, + Instructions.jal -> RegWriteSource.NextInstructionAddress, + Instructions.jalr -> RegWriteSource.NextInstructionAddress + ) + ) + io.ex_reg_write_enable := (opcode === InstructionTypes.RM) || (opcode === InstructionTypes.I) || + (opcode === InstructionTypes.L) || (opcode === Instructions.auipc) || (opcode === Instructions.lui) || + (opcode === Instructions.jal) || (opcode === Instructions.jalr) || (opcode === Instructions.csr) + io.ex_reg_write_address := io.instruction(11, 7) + io.ex_csr_address := io.instruction(31, 20) + io.ex_csr_write_enable := (opcode === Instructions.csr) && ( + funct3 === InstructionsTypeCSR.csrrw || funct3 === InstructionsTypeCSR.csrrwi || + funct3 === InstructionsTypeCSR.csrrs || funct3 === InstructionsTypeCSR.csrrsi || + funct3 === InstructionsTypeCSR.csrrc || funct3 === InstructionsTypeCSR.csrrci + ) + + // Lab3(Final) + io.ctrl_jump_instruction := false.B + io.clint_jump_flag := false.B + io.clint_jump_address := 0.U + io.if_jump_flag := false.B + io.if_jump_address := 0.U + // Lab3(Final) End +} diff --git a/lab3/src/main/scala/riscv/core/fivestage_final/InstructionFetch.scala b/lab3/src/main/scala/riscv/core/fivestage_final/InstructionFetch.scala new file mode 100644 index 0000000..2c4d4aa --- /dev/null +++ b/lab3/src/main/scala/riscv/core/fivestage_final/InstructionFetch.scala @@ -0,0 +1,48 @@ +// 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.core.fivestage_final + +import chisel3._ +import chisel3.util.MuxCase +import riscv.Parameters + +object ProgramCounter { + val EntryAddress = Parameters.EntryAddress +} + +class InstructionFetch extends Module { + val io = IO(new Bundle { + val stall_flag_ctrl = Input(Bool()) + val jump_flag_id = Input(Bool()) + val jump_address_id = Input(UInt(Parameters.AddrWidth)) + val rom_instruction = Input(UInt(Parameters.DataWidth)) + val instruction_valid = Input(Bool()) + + val instruction_address = Output(UInt(Parameters.AddrWidth)) + val id_instruction = Output(UInt(Parameters.InstructionWidth)) + }) + val pc = RegInit(ProgramCounter.EntryAddress) + + pc := MuxCase( + pc + 4.U, + IndexedSeq( + (io.jump_flag_id && !io.stall_flag_ctrl) -> io.jump_address_id, + (io.stall_flag_ctrl || !io.instruction_valid) -> pc + ) + ) + + io.instruction_address := pc + io.id_instruction := Mux(io.instruction_valid, io.rom_instruction, InstructionsNop.nop) +} diff --git a/lab3/src/main/scala/riscv/core/fivestage_final/MEM2WB.scala b/lab3/src/main/scala/riscv/core/fivestage_final/MEM2WB.scala new file mode 100644 index 0000000..34c17d1 --- /dev/null +++ b/lab3/src/main/scala/riscv/core/fivestage_final/MEM2WB.scala @@ -0,0 +1,83 @@ +// Copyright 2022 Canbin Huang +// +// 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.core.fivestage_final + +import chisel3._ +import riscv.Parameters +import riscv.core.PipelineRegister + +class MEM2WB extends Module { + val io = IO(new Bundle() { + val instruction_address = Input(UInt(Parameters.AddrWidth)) + val alu_result = Input(UInt(Parameters.DataWidth)) + val regs_write_enable = Input(Bool()) + val regs_write_source = Input(UInt(2.W)) + val regs_write_address = Input(UInt(Parameters.AddrWidth)) + val memory_read_data = Input(UInt(Parameters.DataWidth)) + val csr_read_data = Input(UInt(Parameters.DataWidth)) + + val output_instruction_address = Output(UInt(Parameters.AddrWidth)) + val output_alu_result = Output(UInt(Parameters.DataWidth)) + val output_regs_write_enable = Output(Bool()) + val output_regs_write_source = Output(UInt(2.W)) + val output_regs_write_address = Output(UInt(Parameters.AddrWidth)) + val output_memory_read_data = Output(UInt(Parameters.DataWidth)) + val output_csr_read_data = Output(UInt(Parameters.DataWidth)) + }) + val stall = false.B + val flush = false.B + + val alu_result = Module(new PipelineRegister()) + alu_result.io.in := io.alu_result + alu_result.io.stall := stall + alu_result.io.flush := flush + io.output_alu_result := alu_result.io.out + + val memory_read_data = Module(new PipelineRegister()) + memory_read_data.io.in := io.memory_read_data + memory_read_data.io.stall := stall + memory_read_data.io.flush := flush + io.output_memory_read_data := memory_read_data.io.out + + val regs_write_enable = Module(new PipelineRegister(1)) + regs_write_enable.io.in := io.regs_write_enable + regs_write_enable.io.stall := stall + regs_write_enable.io.flush := flush + io.output_regs_write_enable := regs_write_enable.io.out + + val regs_write_source = Module(new PipelineRegister(2)) + regs_write_source.io.in := io.regs_write_source + regs_write_source.io.stall := stall + regs_write_source.io.flush := flush + io.output_regs_write_source := regs_write_source.io.out + + val regs_write_address = Module(new PipelineRegister(Parameters.PhysicalRegisterAddrBits)) + regs_write_address.io.in := io.regs_write_address + regs_write_address.io.stall := stall + regs_write_address.io.flush := flush + io.output_regs_write_address := regs_write_address.io.out + + val instruction_address = Module(new PipelineRegister(Parameters.InstructionBits)) + instruction_address.io.in := io.instruction_address + instruction_address.io.stall := stall + instruction_address.io.flush := flush + io.output_instruction_address := instruction_address.io.out + + val csr_read_data = Module(new PipelineRegister()) + csr_read_data.io.in := io.csr_read_data + csr_read_data.io.stall := stall + csr_read_data.io.flush := flush + io.output_csr_read_data := csr_read_data.io.out +} diff --git a/lab3/src/main/scala/riscv/core/fivestage_final/MemoryAccess.scala b/lab3/src/main/scala/riscv/core/fivestage_final/MemoryAccess.scala new file mode 100644 index 0000000..342acfc --- /dev/null +++ b/lab3/src/main/scala/riscv/core/fivestage_final/MemoryAccess.scala @@ -0,0 +1,109 @@ +// Copyright 2022 Canbin Huang +// +// 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.core.fivestage_final + +import chisel3._ +import chisel3.util._ +import peripheral.RAMBundle +import riscv.Parameters + +class MemoryAccess extends Module { + val io = IO(new Bundle() { + val alu_result = Input(UInt(Parameters.DataWidth)) + val reg2_data = Input(UInt(Parameters.DataWidth)) + val memory_read_enable = Input(Bool()) + val memory_write_enable = Input(Bool()) + val funct3 = Input(UInt(3.W)) + val regs_write_source = Input(UInt(2.W)) + val csr_read_data = Input(UInt(Parameters.DataWidth)) + + val wb_memory_read_data = Output(UInt(Parameters.DataWidth)) + val forward_data = Output(UInt(Parameters.DataWidth)) + + val bundle = Flipped(new RAMBundle) + }) + val mem_address_index = io.alu_result(log2Up(Parameters.WordSize) - 1, 0).asUInt + + io.bundle.write_enable := io.memory_write_enable + io.bundle.write_data := 0.U + io.bundle.address := io.alu_result + io.bundle.write_strobe := VecInit(Seq.fill(Parameters.WordSize)(false.B)) + io.wb_memory_read_data := 0.U + + when(io.memory_read_enable) { + val data = io.bundle.read_data + io.wb_memory_read_data := MuxLookup( + io.funct3, + 0.U, + IndexedSeq( + InstructionsTypeL.lb -> MuxLookup( + mem_address_index, + Cat(Fill(24, data(31)), data(31, 24)), + IndexedSeq( + 0.U -> Cat(Fill(24, data(7)), data(7, 0)), + 1.U -> Cat(Fill(24, data(15)), data(15, 8)), + 2.U -> Cat(Fill(24, data(23)), data(23, 16)) + ) + ), + InstructionsTypeL.lbu -> MuxLookup( + mem_address_index, + Cat(Fill(24, 0.U), data(31, 24)), + IndexedSeq( + 0.U -> Cat(Fill(24, 0.U), data(7, 0)), + 1.U -> Cat(Fill(24, 0.U), data(15, 8)), + 2.U -> Cat(Fill(24, 0.U), data(23, 16)) + ) + ), + InstructionsTypeL.lh -> Mux( + mem_address_index === 0.U, + Cat(Fill(16, data(15)), data(15, 0)), + Cat(Fill(16, data(31)), data(31, 16)) + ), + InstructionsTypeL.lhu -> Mux( + mem_address_index === 0.U, + Cat(Fill(16, 0.U), data(15, 0)), + Cat(Fill(16, 0.U), data(31, 16)) + ), + InstructionsTypeL.lw -> data + ) + ) + }.elsewhen(io.memory_write_enable) { + io.bundle.write_data := io.reg2_data + io.bundle.write_strobe := VecInit(Seq.fill(Parameters.WordSize)(false.B)) + when(io.funct3 === InstructionsTypeS.sb) { + io.bundle.write_strobe(mem_address_index) := true.B + io.bundle.write_data := io.reg2_data(Parameters.ByteBits, 0) << (mem_address_index << log2Up(Parameters.ByteBits).U) + }.elsewhen(io.funct3 === InstructionsTypeS.sh) { + when(mem_address_index === 0.U) { + for (i <- 0 until Parameters.WordSize / 2) { + io.bundle.write_strobe(i) := true.B + } + io.bundle.write_data := io.reg2_data(Parameters.WordSize / 2 * Parameters.ByteBits, 0) + }.otherwise { + for (i <- Parameters.WordSize / 2 until Parameters.WordSize) { + io.bundle.write_strobe(i) := true.B + } + io.bundle.write_data := io.reg2_data(Parameters.WordSize / 2 * Parameters.ByteBits, 0) << (Parameters + .WordSize / 2 * Parameters.ByteBits) + } + }.elsewhen(io.funct3 === InstructionsTypeS.sw) { + for (i <- 0 until Parameters.WordSize) { + io.bundle.write_strobe(i) := true.B + } + } + } + + io.forward_data := Mux(io.regs_write_source === RegWriteSource.CSR, io.csr_read_data, io.alu_result) +} diff --git a/lab3/src/main/scala/riscv/core/fivestage_final/WriteBack.scala b/lab3/src/main/scala/riscv/core/fivestage_final/WriteBack.scala new file mode 100644 index 0000000..5e04a48 --- /dev/null +++ b/lab3/src/main/scala/riscv/core/fivestage_final/WriteBack.scala @@ -0,0 +1,40 @@ +// Copyright 2022 Canbin Huang +// +// 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.core.fivestage_final + +import chisel3._ +import chisel3.util._ +import riscv.Parameters + +class WriteBack extends Module { + val io = IO(new Bundle() { + val instruction_address = Input(UInt(Parameters.AddrWidth)) + val alu_result = Input(UInt(Parameters.DataWidth)) + val memory_read_data = Input(UInt(Parameters.DataWidth)) + val regs_write_source = Input(UInt(2.W)) + val csr_read_data = Input(UInt(Parameters.DataWidth)) + + val regs_write_data = Output(UInt(Parameters.DataWidth)) + }) + io.regs_write_data := MuxLookup( + io.regs_write_source, + io.alu_result, + IndexedSeq( + RegWriteSource.Memory -> io.memory_read_data, + RegWriteSource.CSR -> io.csr_read_data, + RegWriteSource.NextInstructionAddress -> (io.instruction_address + 4.U) + ) + ) +} diff --git a/lab3/src/main/scala/riscv/core/fivestage_forward/CLINT.scala b/lab3/src/main/scala/riscv/core/fivestage_forward/CLINT.scala new file mode 100644 index 0000000..e81b601 --- /dev/null +++ b/lab3/src/main/scala/riscv/core/fivestage_forward/CLINT.scala @@ -0,0 +1,103 @@ +// 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.core.fivestage_forward + +import chisel3._ +import chisel3.util.MuxLookup +import riscv.Parameters + +object InterruptStatus { + val None = 0x0.U(8.W) + val Timer0 = 0x1.U(8.W) + val Ret = 0xFF.U(8.W) +} + +class CSRDirectAccessBundle extends Bundle { + val mstatus = Input(UInt(Parameters.DataWidth)) + val mepc = Input(UInt(Parameters.DataWidth)) + val mcause = Input(UInt(Parameters.DataWidth)) + val mtvec = Input(UInt(Parameters.DataWidth)) + + val mstatus_write_data = Output(UInt(Parameters.DataWidth)) + val mepc_write_data = Output(UInt(Parameters.DataWidth)) + val mcause_write_data = Output(UInt(Parameters.DataWidth)) + + val direct_write_enable = Output(Bool()) +} + +// Core Local Interrupt Controller +class CLINT extends Module { + val io = IO(new Bundle { + val interrupt_flag = Input(UInt(Parameters.InterruptFlagWidth)) + + val instruction_ex = Input(UInt(Parameters.InstructionWidth)) + val instruction_address_if = Input(UInt(Parameters.AddrWidth)) + val instruction_address_id = Input(UInt(Parameters.AddrWidth)) + + val jump_flag = Input(Bool()) + val jump_address = Input(UInt(Parameters.AddrWidth)) + + val ex_interrupt_handler_address = Output(UInt(Parameters.AddrWidth)) + val ex_interrupt_assert = Output(Bool()) + + val csr_bundle = new CSRDirectAccessBundle + }) + val interrupt_enable = io.csr_bundle.mstatus(3) + val jumpping = RegNext(io.jump_flag || io.ex_interrupt_assert) + val instruction_address = Mux( + io.jump_flag, + io.jump_address, + Mux(jumpping, io.instruction_address_if, io.instruction_address_id) + ) + val mstatus_disable_interrupt = io.csr_bundle.mstatus(31, 4) ## 0.U(1.W) ## io.csr_bundle.mstatus(2, 0) + val mstatus_recover_interrupt = io.csr_bundle.mstatus(31, 4) ## io.csr_bundle.mstatus(7) ## io.csr_bundle.mstatus(2, 0) + + when(io.instruction_ex === InstructionsEnv.ecall || io.instruction_ex === InstructionsEnv.ebreak) { + io.csr_bundle.mstatus_write_data := mstatus_disable_interrupt + io.csr_bundle.mepc_write_data := instruction_address + io.csr_bundle.mcause_write_data := MuxLookup( + io.instruction_ex, + 10.U, + IndexedSeq( + InstructionsEnv.ecall -> 11.U, + InstructionsEnv.ebreak -> 3.U, + ) + ) + io.csr_bundle.direct_write_enable := true.B + io.ex_interrupt_assert := true.B + io.ex_interrupt_handler_address := io.csr_bundle.mtvec + }.elsewhen(io.interrupt_flag =/= InterruptStatus.None && interrupt_enable) { + io.csr_bundle.mstatus_write_data := mstatus_disable_interrupt + io.csr_bundle.mepc_write_data := instruction_address + io.csr_bundle.mcause_write_data := Mux(io.interrupt_flag(0), 0x80000007L.U, 0x8000000BL.U) + io.csr_bundle.direct_write_enable := true.B + io.ex_interrupt_assert := true.B + io.ex_interrupt_handler_address := io.csr_bundle.mtvec + }.elsewhen(io.instruction_ex === InstructionsRet.mret) { + io.csr_bundle.mstatus_write_data := mstatus_recover_interrupt + io.csr_bundle.mepc_write_data := io.csr_bundle.mepc + io.csr_bundle.mcause_write_data := io.csr_bundle.mcause + io.csr_bundle.direct_write_enable := true.B + io.ex_interrupt_assert := true.B + io.ex_interrupt_handler_address := io.csr_bundle.mepc + }.otherwise { + io.csr_bundle.mstatus_write_data := io.csr_bundle.mstatus + io.csr_bundle.mepc_write_data := io.csr_bundle.mepc + io.csr_bundle.mcause_write_data := io.csr_bundle.mcause + io.csr_bundle.direct_write_enable := false.B + io.ex_interrupt_assert := false.B + io.ex_interrupt_handler_address := 0.U + } +} diff --git a/lab3/src/main/scala/riscv/core/fivestage_forward/CPU.scala b/lab3/src/main/scala/riscv/core/fivestage_forward/CPU.scala new file mode 100644 index 0000000..7946b60 --- /dev/null +++ b/lab3/src/main/scala/riscv/core/fivestage_forward/CPU.scala @@ -0,0 +1,158 @@ +// 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.core.fivestage_forward + +import chisel3._ +import riscv.Parameters +import riscv.core.{CPUBundle, CSR, RegisterFile} + +class CPU extends Module { + val io = IO(new CPUBundle) + + val ctrl = Module(new Control) + val regs = Module(new RegisterFile) + val inst_fetch = Module(new InstructionFetch) + val if2id = Module(new IF2ID) + val id = Module(new InstructionDecode) + val id2ex = Module(new ID2EX) + val ex = Module(new Execute) + val ex2mem = Module(new EX2MEM) + val mem = Module(new MemoryAccess) + val mem2wb = Module(new MEM2WB) + val wb = Module(new WriteBack) + val forwarding = Module(new Forwarding) + val clint = Module(new CLINT) + val csr_regs = Module(new CSR) + + ctrl.io.jump_flag := ex.io.if_jump_flag + ctrl.io.rs1_id := id.io.regs_reg1_read_address + ctrl.io.rs2_id := id.io.regs_reg2_read_address + ctrl.io.memory_read_enable_ex := id2ex.io.output_memory_read_enable + ctrl.io.rd_ex := id2ex.io.output_regs_write_address + + regs.io.write_enable := mem2wb.io.output_regs_write_enable + regs.io.write_address := mem2wb.io.output_regs_write_address + regs.io.write_data := wb.io.regs_write_data + regs.io.read_address1 := id.io.regs_reg1_read_address + regs.io.read_address2 := id.io.regs_reg2_read_address + + regs.io.debug_read_address := io.debug_read_address + io.debug_read_data := regs.io.debug_read_data + + io.instruction_address := inst_fetch.io.instruction_address + inst_fetch.io.stall_flag_ctrl := ctrl.io.pc_stall + inst_fetch.io.jump_flag_id := ex.io.if_jump_flag + inst_fetch.io.jump_address_id := ex.io.if_jump_address + inst_fetch.io.rom_instruction := io.instruction + inst_fetch.io.instruction_valid := io.instruction_valid + + if2id.io.stall := ctrl.io.if_stall + if2id.io.flush := ctrl.io.if_flush + if2id.io.instruction := inst_fetch.io.id_instruction + if2id.io.instruction_address := inst_fetch.io.instruction_address + if2id.io.interrupt_flag := io.interrupt_flag + + id.io.instruction := if2id.io.output_instruction + + id2ex.io.flush := ctrl.io.id_flush + id2ex.io.instruction := if2id.io.output_instruction + id2ex.io.instruction_address := if2id.io.output_instruction_address + id2ex.io.reg1_data := regs.io.read_data1 + id2ex.io.reg2_data := regs.io.read_data2 + id2ex.io.regs_reg1_read_address := id.io.regs_reg1_read_address + id2ex.io.regs_reg2_read_address := id.io.regs_reg2_read_address + id2ex.io.regs_write_enable := id.io.ex_reg_write_enable + id2ex.io.regs_write_address := id.io.ex_reg_write_address + id2ex.io.regs_write_source := id.io.ex_reg_write_source + id2ex.io.immediate := id.io.ex_immediate + id2ex.io.aluop1_source := id.io.ex_aluop1_source + id2ex.io.aluop2_source := id.io.ex_aluop2_source + id2ex.io.csr_write_enable := id.io.ex_csr_write_enable + id2ex.io.csr_address := id.io.ex_csr_address + id2ex.io.memory_read_enable := id.io.ex_memory_read_enable + id2ex.io.memory_write_enable := id.io.ex_memory_write_enable + id2ex.io.csr_read_data := csr_regs.io.id_reg_read_data + + ex.io.instruction := id2ex.io.output_instruction + ex.io.instruction_address := id2ex.io.output_instruction_address + ex.io.reg1_data := id2ex.io.output_reg1_data + ex.io.reg2_data := id2ex.io.output_reg2_data + ex.io.immediate_id := id2ex.io.output_immediate + ex.io.aluop1_source_id := id2ex.io.output_aluop1_source + ex.io.aluop2_source_id := id2ex.io.output_aluop2_source + ex.io.csr_read_data_id := id2ex.io.output_csr_read_data + ex.io.forward_from_mem := mem.io.forward_data + ex.io.forward_from_wb := wb.io.regs_write_data + ex.io.reg1_forward := forwarding.io.reg1_forward_ex + ex.io.reg2_forward := forwarding.io.reg2_forward_ex + ex.io.interrupt_assert_clint := clint.io.ex_interrupt_assert + ex.io.interrupt_handler_address_clint := clint.io.ex_interrupt_handler_address + + ex2mem.io.regs_write_enable := id2ex.io.output_regs_write_enable + ex2mem.io.regs_write_source := id2ex.io.output_regs_write_source + ex2mem.io.regs_write_address := id2ex.io.output_regs_write_address + ex2mem.io.instruction_address := id2ex.io.output_instruction_address + ex2mem.io.funct3 := id2ex.io.output_instruction(14, 12) + ex2mem.io.reg2_data := ex.io.mem_reg2_data + ex2mem.io.memory_read_enable := id2ex.io.output_memory_read_enable + ex2mem.io.memory_write_enable := id2ex.io.output_memory_write_enable + ex2mem.io.alu_result := ex.io.mem_alu_result + ex2mem.io.csr_read_data := id2ex.io.output_csr_read_data + + mem.io.alu_result := ex2mem.io.output_alu_result + mem.io.reg2_data := ex2mem.io.output_reg2_data + mem.io.memory_read_enable := ex2mem.io.output_memory_read_enable + mem.io.memory_write_enable := ex2mem.io.output_memory_write_enable + mem.io.funct3 := ex2mem.io.output_funct3 + mem.io.regs_write_source := ex2mem.io.output_regs_write_source + mem.io.csr_read_data := ex2mem.io.output_csr_read_data + io.device_select := mem.io.bundle.address(Parameters.AddrBits - 1, Parameters.AddrBits - Parameters.SlaveDeviceCountBits) + io.memory_bundle <> mem.io.bundle + io.memory_bundle.address := 0.U(Parameters.SlaveDeviceCountBits.W) ## mem.io.bundle.address(Parameters.AddrBits - 1 - Parameters.SlaveDeviceCountBits, 0) + + mem2wb.io.instruction_address := ex2mem.io.output_instruction_address + mem2wb.io.alu_result := ex2mem.io.output_alu_result + mem2wb.io.regs_write_enable := ex2mem.io.output_regs_write_enable + mem2wb.io.regs_write_source := ex2mem.io.output_regs_write_source + mem2wb.io.regs_write_address := ex2mem.io.output_regs_write_address + mem2wb.io.memory_read_data := mem.io.wb_memory_read_data + mem2wb.io.csr_read_data := ex2mem.io.output_csr_read_data + + wb.io.instruction_address := mem2wb.io.output_instruction_address + wb.io.alu_result := mem2wb.io.output_alu_result + wb.io.memory_read_data := mem2wb.io.output_memory_read_data + wb.io.regs_write_source := mem2wb.io.output_regs_write_source + wb.io.csr_read_data := mem2wb.io.output_csr_read_data + + forwarding.io.rs1_ex := id2ex.io.output_regs_reg1_read_address + forwarding.io.rs2_ex := id2ex.io.output_regs_reg2_read_address + forwarding.io.rd_mem := ex2mem.io.output_regs_write_address + forwarding.io.reg_write_enable_mem := ex2mem.io.output_regs_write_enable + forwarding.io.rd_wb := mem2wb.io.output_regs_write_address + forwarding.io.reg_write_enable_wb := mem2wb.io.output_regs_write_enable + + clint.io.instruction_address_if := inst_fetch.io.instruction_address + clint.io.instruction_address_id := if2id.io.output_instruction_address + clint.io.instruction_ex := id2ex.io.output_instruction + clint.io.jump_flag := ex.io.clint_jump_flag + clint.io.jump_address := ex.io.clint_jump_address + clint.io.interrupt_flag := if2id.io.output_interrupt_flag + clint.io.csr_bundle <> csr_regs.io.clint_access_bundle + + csr_regs.io.reg_read_address_id := id.io.ex_csr_address + csr_regs.io.reg_write_enable_ex := id2ex.io.output_csr_write_enable + csr_regs.io.reg_write_address_ex := id2ex.io.output_csr_address + csr_regs.io.reg_write_data_ex := ex.io.csr_write_data +} diff --git a/lab3/src/main/scala/riscv/core/fivestage_forward/Control.scala b/lab3/src/main/scala/riscv/core/fivestage_forward/Control.scala new file mode 100644 index 0000000..9c71aaa --- /dev/null +++ b/lab3/src/main/scala/riscv/core/fivestage_forward/Control.scala @@ -0,0 +1,40 @@ +// 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.core.fivestage_forward + +import chisel3._ +import riscv.Parameters + +class Control extends Module { + val io = IO(new Bundle { + val jump_flag = Input(Bool()) + val rs1_id = Input(UInt(Parameters.PhysicalRegisterAddrWidth)) + val rs2_id = Input(UInt(Parameters.PhysicalRegisterAddrWidth)) + val memory_read_enable_ex = Input(Bool()) + val rd_ex = Input(UInt(Parameters.PhysicalRegisterAddrWidth)) + + val if_flush = Output(Bool()) + val id_flush = Output(Bool()) + val pc_stall = Output(Bool()) + val if_stall = Output(Bool()) + }) + + // Lab3(Forward) + io.if_flush := false.B + io.id_flush := false.B + io.pc_stall := false.B + io.if_stall := false.B + // Lab3(Forward) End +} diff --git a/lab3/src/main/scala/riscv/core/fivestage_forward/EX2MEM.scala b/lab3/src/main/scala/riscv/core/fivestage_forward/EX2MEM.scala new file mode 100644 index 0000000..e956ee1 --- /dev/null +++ b/lab3/src/main/scala/riscv/core/fivestage_forward/EX2MEM.scala @@ -0,0 +1,108 @@ +// Copyright 2022 Canbin Huang +// +// 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.core.fivestage_forward + +import chisel3._ +import riscv.Parameters +import riscv.core.PipelineRegister + +class EX2MEM extends Module { + val io = IO(new Bundle() { + val regs_write_enable = Input(Bool()) + val regs_write_source = Input(UInt(2.W)) + val regs_write_address = Input(UInt(Parameters.AddrWidth)) + val instruction_address = Input(UInt(Parameters.AddrWidth)) + val funct3 = Input(UInt(3.W)) + val reg2_data = Input(UInt(Parameters.DataWidth)) + val memory_read_enable = Input(Bool()) + val memory_write_enable = Input(Bool()) + val alu_result = Input(UInt(Parameters.DataWidth)) + val csr_read_data = Input(UInt(Parameters.DataWidth)) + + val output_regs_write_enable = Output(Bool()) + val output_regs_write_source = Output(UInt(2.W)) + val output_regs_write_address = Output(UInt(Parameters.AddrWidth)) + val output_instruction_address = Output(UInt(Parameters.AddrWidth)) + val output_funct3 = Output(UInt(Parameters.DataWidth)) + val output_reg2_data = Output(UInt(Parameters.DataWidth)) + val output_memory_read_enable = Output(Bool()) + val output_memory_write_enable = Output(Bool()) + val output_alu_result = Output(UInt(Parameters.DataWidth)) + val output_csr_read_data = Output(UInt(Parameters.DataWidth)) + }) + + val stall = false.B + val flush = false.B + + val regs_write_enable = Module(new PipelineRegister(1)) + regs_write_enable.io.in := io.regs_write_enable + regs_write_enable.io.stall := stall + regs_write_enable.io.flush := flush + io.output_regs_write_enable := regs_write_enable.io.out + + val regs_write_source = Module(new PipelineRegister(2)) + regs_write_source.io.in := io.regs_write_source + regs_write_source.io.stall := stall + regs_write_source.io.flush := flush + io.output_regs_write_source := regs_write_source.io.out + + val regs_write_address = Module(new PipelineRegister(Parameters.PhysicalRegisterAddrBits)) + regs_write_address.io.in := io.regs_write_address + regs_write_address.io.stall := stall + regs_write_address.io.flush := flush + io.output_regs_write_address := regs_write_address.io.out + + val instruction_address = Module(new PipelineRegister(Parameters.AddrBits)) + instruction_address.io.in := io.instruction_address + instruction_address.io.stall := stall + instruction_address.io.flush := flush + io.output_instruction_address := instruction_address.io.out + + val funct3 = Module(new PipelineRegister(3)) + funct3.io.in := io.funct3 + funct3.io.stall := stall + funct3.io.flush := flush + io.output_funct3 := funct3.io.out + + val reg2_data = Module(new PipelineRegister()) + reg2_data.io.in := io.reg2_data + reg2_data.io.stall := stall + reg2_data.io.flush := flush + io.output_reg2_data := reg2_data.io.out + + val alu_result = Module(new PipelineRegister()) + alu_result.io.in := io.alu_result + alu_result.io.stall := stall + alu_result.io.flush := flush + io.output_alu_result := alu_result.io.out + + val memory_read_enable = Module(new PipelineRegister(1)) + memory_read_enable.io.in := io.memory_read_enable + memory_read_enable.io.stall := stall + memory_read_enable.io.flush := flush + io.output_memory_read_enable := memory_read_enable.io.out + + val memory_write_enable = Module(new PipelineRegister(1)) + memory_write_enable.io.in := io.memory_write_enable + memory_write_enable.io.stall := stall + memory_write_enable.io.flush := flush + io.output_memory_write_enable := memory_write_enable.io.out + + val csr_read_data = Module(new PipelineRegister()) + csr_read_data.io.in := io.csr_read_data + csr_read_data.io.stall := stall + csr_read_data.io.flush := flush + io.output_csr_read_data := csr_read_data.io.out +} diff --git a/lab3/src/main/scala/riscv/core/fivestage_forward/Execute.scala b/lab3/src/main/scala/riscv/core/fivestage_forward/Execute.scala new file mode 100644 index 0000000..32a7fdc --- /dev/null +++ b/lab3/src/main/scala/riscv/core/fivestage_forward/Execute.scala @@ -0,0 +1,111 @@ +// 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.core.fivestage_forward + +import chisel3._ +import chisel3.util._ +import riscv.Parameters +import riscv.core.{ALU, ALUControl} + + +class Execute extends Module { + val io = IO(new Bundle { + val instruction = Input(UInt(Parameters.InstructionWidth)) + val instruction_address = Input(UInt(Parameters.AddrWidth)) + val reg1_data = Input(UInt(Parameters.DataWidth)) + val reg2_data = Input(UInt(Parameters.DataWidth)) + val immediate_id = Input(UInt(Parameters.DataWidth)) + val aluop1_source_id = Input(UInt(1.W)) + val aluop2_source_id = Input(UInt(1.W)) + val csr_read_data_id = Input(UInt(Parameters.DataWidth)) + val forward_from_mem = Input(UInt(Parameters.DataWidth)) + val forward_from_wb = Input(UInt(Parameters.DataWidth)) + val reg1_forward = Input(UInt(2.W)) + val reg2_forward = Input(UInt(2.W)) + val interrupt_assert_clint = Input(Bool()) + val interrupt_handler_address_clint = Input(UInt(Parameters.AddrWidth)) + + val mem_alu_result = Output(UInt(Parameters.DataWidth)) + val mem_reg2_data = Output(UInt(Parameters.DataWidth)) + val csr_write_data = Output(UInt(Parameters.DataWidth)) + val if_jump_flag = Output(Bool()) + val if_jump_address = Output(UInt(Parameters.AddrWidth)) + val clint_jump_flag = Output(Bool()) + val clint_jump_address = Output(UInt(Parameters.AddrWidth)) + }) + + val opcode = io.instruction(6, 0) + val funct3 = io.instruction(14, 12) + val funct7 = io.instruction(31, 25) + val uimm = io.instruction(19, 15) + + // ALU compute + val alu = Module(new ALU) + val alu_ctrl = Module(new ALUControl) + + alu_ctrl.io.opcode := opcode + alu_ctrl.io.funct3 := funct3 + alu_ctrl.io.funct7 := funct7 + alu.io.func := alu_ctrl.io.alu_funct + + // Lab3(Forward) + val reg1_data = 0.U + val reg2_data = 0.U + // Lab3(Forward) End + + alu.io.op1 := Mux( + io.aluop1_source_id === ALUOp1Source.InstructionAddress, + io.instruction_address, + reg1_data + ) + alu.io.op2 := Mux( + io.aluop2_source_id === ALUOp2Source.Immediate, + io.immediate_id, + reg2_data + ) + io.mem_alu_result := alu.io.result + io.mem_reg2_data := reg2_data + io.csr_write_data := MuxLookup(funct3, 0.U, IndexedSeq( + InstructionsTypeCSR.csrrw -> reg1_data, + InstructionsTypeCSR.csrrc -> io.csr_read_data_id.&((~reg1_data).asUInt), + InstructionsTypeCSR.csrrs -> io.csr_read_data_id.|(reg1_data), + InstructionsTypeCSR.csrrwi -> Cat(0.U(27.W), uimm), + InstructionsTypeCSR.csrrci -> io.csr_read_data_id.&((~Cat(0.U(27.W), uimm)).asUInt), + InstructionsTypeCSR.csrrsi -> io.csr_read_data_id.|(Cat(0.U(27.W), uimm)), + )) + + // jump and interrupt + val instruction_jump_flag = (opcode === Instructions.jal) || + (opcode === Instructions.jalr) || + (opcode === InstructionTypes.B) && MuxLookup( + funct3, + false.B, + IndexedSeq( + InstructionsTypeB.beq -> (reg1_data === reg2_data), + InstructionsTypeB.bne -> (reg1_data =/= reg2_data), + InstructionsTypeB.blt -> (reg1_data.asSInt < reg2_data.asSInt), + InstructionsTypeB.bge -> (reg1_data.asSInt >= reg2_data.asSInt), + InstructionsTypeB.bltu -> (reg1_data.asUInt < reg2_data.asUInt), + InstructionsTypeB.bgeu -> (reg1_data.asUInt >= reg2_data.asUInt) + ) + ) + io.clint_jump_flag := instruction_jump_flag + io.clint_jump_address := alu.io.result + io.if_jump_flag := io.interrupt_assert_clint || instruction_jump_flag + io.if_jump_address := Mux(io.interrupt_assert_clint, + io.interrupt_handler_address_clint, + alu.io.result + ) +} diff --git a/lab3/src/main/scala/riscv/core/fivestage_forward/Forwarding.scala b/lab3/src/main/scala/riscv/core/fivestage_forward/Forwarding.scala new file mode 100644 index 0000000..e644842 --- /dev/null +++ b/lab3/src/main/scala/riscv/core/fivestage_forward/Forwarding.scala @@ -0,0 +1,44 @@ +// Copyright 2022 Canbin Huang +// +// 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.core.fivestage_forward + +import chisel3._ +import riscv.Parameters + +object ForwardingType { + val NoForward = 0.U(2.W) + val ForwardFromMEM = 1.U(2.W) + val ForwardFromWB = 2.U(2.W) +} + +class Forwarding extends Module { + val io = IO(new Bundle() { + val rs1_ex = Input(UInt(Parameters.PhysicalRegisterAddrWidth)) + val rs2_ex = Input(UInt(Parameters.PhysicalRegisterAddrWidth)) + val rd_mem = Input(UInt(Parameters.PhysicalRegisterAddrWidth)) + val reg_write_enable_mem = Input(Bool()) + val rd_wb = Input(UInt(Parameters.PhysicalRegisterAddrWidth)) + val reg_write_enable_wb = Input(Bool()) + + // Forwarding Type + val reg1_forward_ex = Output(UInt(2.W)) + val reg2_forward_ex = Output(UInt(2.W)) + }) + + // Lab3(Forward) + io.reg1_forward_ex := 0.U + io.reg2_forward_ex := 0.U + // Lab3(Forward) End +} diff --git a/lab3/src/main/scala/riscv/core/fivestage_forward/ID2EX.scala b/lab3/src/main/scala/riscv/core/fivestage_forward/ID2EX.scala new file mode 100644 index 0000000..3399678 --- /dev/null +++ b/lab3/src/main/scala/riscv/core/fivestage_forward/ID2EX.scala @@ -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.core.fivestage_forward + +import chisel3._ +import riscv.Parameters +import riscv.core.PipelineRegister + +class ID2EX extends Module { + val io = IO(new Bundle { + val flush = Input(Bool()) + val instruction = Input(UInt(Parameters.InstructionWidth)) + val instruction_address = Input(UInt(Parameters.AddrWidth)) + val regs_reg1_read_address = Input(UInt(Parameters.PhysicalRegisterAddrWidth)) + val regs_reg2_read_address = Input(UInt(Parameters.PhysicalRegisterAddrWidth)) + val regs_write_enable = Input(Bool()) + val regs_write_address = Input(UInt(Parameters.PhysicalRegisterAddrWidth)) + val regs_write_source = Input(UInt(2.W)) + val reg1_data = Input(UInt(Parameters.DataWidth)) + val reg2_data = Input(UInt(Parameters.DataWidth)) + val immediate = Input(UInt(Parameters.DataWidth)) + val aluop1_source = Input(UInt(1.W)) + val aluop2_source = Input(UInt(1.W)) + val csr_write_enable = Input(Bool()) + val csr_address = Input(UInt(Parameters.CSRRegisterAddrWidth)) + val memory_read_enable = Input(Bool()) + val memory_write_enable = Input(Bool()) + val csr_read_data = Input(UInt(Parameters.DataWidth)) + + val output_instruction = Output(UInt(Parameters.DataWidth)) + val output_instruction_address = Output(UInt(Parameters.AddrWidth)) + val output_regs_reg1_read_address = Output(UInt(Parameters.PhysicalRegisterAddrWidth)) + val output_regs_reg2_read_address = Output(UInt(Parameters.PhysicalRegisterAddrWidth)) + val output_regs_write_enable = Output(Bool()) + val output_regs_write_address = Output(UInt(Parameters.PhysicalRegisterAddrWidth)) + val output_regs_write_source = Output(UInt(2.W)) + val output_reg1_data = Output(UInt(Parameters.DataWidth)) + val output_reg2_data = Output(UInt(Parameters.DataWidth)) + val output_immediate = Output(UInt(Parameters.DataWidth)) + val output_aluop1_source = Output(UInt(1.W)) + val output_aluop2_source = Output(UInt(1.W)) + val output_csr_write_enable = Output(Bool()) + val output_csr_address = Output(UInt(Parameters.CSRRegisterAddrWidth)) + val output_memory_read_enable = Output(Bool()) + val output_memory_write_enable = Output(Bool()) + val output_csr_read_data = Output(UInt(Parameters.DataWidth)) + }) + + val stall = false.B + + val instruction = Module(new PipelineRegister(defaultValue = InstructionsNop.nop)) + instruction.io.in := io.instruction + instruction.io.stall := stall + instruction.io.flush := io.flush + io.output_instruction := instruction.io.out + + val instruction_address = Module(new PipelineRegister(defaultValue = ProgramCounter.EntryAddress)) + instruction_address.io.in := io.instruction_address + instruction_address.io.stall := stall + instruction_address.io.flush := io.flush + io.output_instruction_address := instruction_address.io.out + + val regs_reg1_read_address = Module(new PipelineRegister(Parameters.PhysicalRegisterAddrBits)) + regs_reg1_read_address.io.in := io.regs_reg1_read_address + regs_reg1_read_address.io.stall := stall + regs_reg1_read_address.io.flush := io.flush + io.output_regs_reg1_read_address := regs_reg1_read_address.io.out + + val regs_reg2_read_address = Module(new PipelineRegister(Parameters.PhysicalRegisterAddrBits)) + regs_reg2_read_address.io.in := io.regs_reg2_read_address + regs_reg2_read_address.io.stall := stall + regs_reg2_read_address.io.flush := io.flush + io.output_regs_reg2_read_address := regs_reg2_read_address.io.out + + val regs_write_enable = Module(new PipelineRegister(1)) + regs_write_enable.io.in := io.regs_write_enable + regs_write_enable.io.stall := stall + regs_write_enable.io.flush := io.flush + io.output_regs_write_enable := regs_write_enable.io.out + + val regs_write_address = Module(new PipelineRegister(Parameters.PhysicalRegisterAddrBits)) + regs_write_address.io.in := io.regs_write_address + regs_write_address.io.stall := stall + regs_write_address.io.flush := io.flush + io.output_regs_write_address := regs_write_address.io.out + + val regs_write_source = Module(new PipelineRegister(2)) + regs_write_source.io.in := io.regs_write_source + regs_write_source.io.stall := stall + regs_write_source.io.flush := io.flush + io.output_regs_write_source := regs_write_source.io.out + + val reg1_data = Module(new PipelineRegister()) + reg1_data.io.in := io.reg1_data + reg1_data.io.stall := stall + reg1_data.io.flush := io.flush + io.output_reg1_data := reg1_data.io.out + + val reg2_data = Module(new PipelineRegister()) + reg2_data.io.in := io.reg2_data + reg2_data.io.stall := stall + reg2_data.io.flush := io.flush + io.output_reg2_data := reg2_data.io.out + + val immediate = Module(new PipelineRegister()) + immediate.io.in := io.immediate + immediate.io.stall := stall + immediate.io.flush := io.flush + io.output_immediate := immediate.io.out + + val aluop1_source = Module(new PipelineRegister(1)) + aluop1_source.io.in := io.aluop1_source + aluop1_source.io.stall := stall + aluop1_source.io.flush := io.flush + io.output_aluop1_source := aluop1_source.io.out + + val aluop2_source = Module(new PipelineRegister(1)) + aluop2_source.io.in := io.aluop2_source + aluop2_source.io.stall := stall + aluop2_source.io.flush := io.flush + io.output_aluop2_source := aluop2_source.io.out + + val csr_write_enable = Module(new PipelineRegister(1)) + csr_write_enable.io.in := io.csr_write_enable + csr_write_enable.io.stall := stall + csr_write_enable.io.flush := io.flush + io.output_csr_write_enable := csr_write_enable.io.out + + val csr_address = Module(new PipelineRegister(Parameters.CSRRegisterAddrBits)) + csr_address.io.in := io.csr_address + csr_address.io.stall := stall + csr_address.io.flush := io.flush + io.output_csr_address := csr_address.io.out + + val memory_read_enable = Module(new PipelineRegister(1)) + memory_read_enable.io.in := io.memory_read_enable + memory_read_enable.io.stall := stall + memory_read_enable.io.flush := io.flush + io.output_memory_read_enable := memory_read_enable.io.out + + val memory_write_enable = Module(new PipelineRegister(1)) + memory_write_enable.io.in := io.memory_write_enable + memory_write_enable.io.stall := stall + memory_write_enable.io.flush := io.flush + io.output_memory_write_enable := memory_write_enable.io.out + + val csr_read_data = Module(new PipelineRegister()) + csr_read_data.io.in := io.csr_read_data + csr_read_data.io.stall := stall + csr_read_data.io.flush := io.flush + io.output_csr_read_data := csr_read_data.io.out +} diff --git a/lab3/src/main/scala/riscv/core/fivestage_forward/IF2ID.scala b/lab3/src/main/scala/riscv/core/fivestage_forward/IF2ID.scala new file mode 100644 index 0000000..d6eea47 --- /dev/null +++ b/lab3/src/main/scala/riscv/core/fivestage_forward/IF2ID.scala @@ -0,0 +1,51 @@ +// 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.core.fivestage_forward + +import chisel3._ +import riscv.Parameters +import riscv.core.PipelineRegister + +class IF2ID extends Module { + val io = IO(new Bundle { + val stall = Input(Bool()) + val flush = Input(Bool()) + val instruction = Input(UInt(Parameters.InstructionWidth)) + val instruction_address = Input(UInt(Parameters.AddrWidth)) + val interrupt_flag = Input(UInt(Parameters.InterruptFlagWidth)) + + val output_instruction = Output(UInt(Parameters.DataWidth)) + val output_instruction_address = Output(UInt(Parameters.AddrWidth)) + val output_interrupt_flag = Output(UInt(Parameters.InterruptFlagWidth)) + }) + + val instruction = Module(new PipelineRegister(defaultValue = InstructionsNop.nop)) + instruction.io.in := io.instruction + instruction.io.stall := io.stall + instruction.io.flush := io.flush + io.output_instruction := instruction.io.out + + val instruction_address = Module(new PipelineRegister(defaultValue = ProgramCounter.EntryAddress)) + instruction_address.io.in := io.instruction_address + instruction_address.io.stall := io.stall + instruction_address.io.flush := io.flush + io.output_instruction_address := instruction_address.io.out + + val interrupt_flag = Module(new PipelineRegister(Parameters.InterruptFlagBits)) + interrupt_flag.io.in := io.interrupt_flag + interrupt_flag.io.stall := io.stall + interrupt_flag.io.flush := io.flush + io.output_interrupt_flag := interrupt_flag.io.out +} diff --git a/lab3/src/main/scala/riscv/core/fivestage_forward/InstructionDecode.scala b/lab3/src/main/scala/riscv/core/fivestage_forward/InstructionDecode.scala new file mode 100644 index 0000000..8abb0ea --- /dev/null +++ b/lab3/src/main/scala/riscv/core/fivestage_forward/InstructionDecode.scala @@ -0,0 +1,207 @@ +// 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.core.fivestage_forward + +import chisel3._ +import chisel3.util._ +import riscv.Parameters + +object InstructionTypes { + val L = "b0000011".U + val I = "b0010011".U + val S = "b0100011".U + val RM = "b0110011".U + val B = "b1100011".U +} + +object Instructions { + val lui = "b0110111".U + val nop = "b0000001".U + val jal = "b1101111".U + val jalr = "b1100111".U + val auipc = "b0010111".U + val csr = "b1110011".U + val fence = "b0001111".U +} + +object InstructionsTypeL { + val lb = "b000".U + val lh = "b001".U + val lw = "b010".U + val lbu = "b100".U + val lhu = "b101".U +} + +object InstructionsTypeI { + val addi = 0.U + val slli = 1.U + val slti = 2.U + val sltiu = 3.U + val xori = 4.U + val sri = 5.U + val ori = 6.U + val andi = 7.U +} + +object InstructionsTypeS { + val sb = "b000".U + val sh = "b001".U + val sw = "b010".U +} + +object InstructionsTypeR { + val add_sub = 0.U + val sll = 1.U + val slt = 2.U + val sltu = 3.U + val xor = 4.U + val sr = 5.U + val or = 6.U + val and = 7.U +} + +object InstructionsTypeM { + val mul = 0.U + val mulh = 1.U + val mulhsu = 2.U + val mulhum = 3.U + val div = 4.U + val divu = 5.U + val rem = 6.U + val remu = 7.U +} + +object InstructionsTypeB { + val beq = "b000".U + val bne = "b001".U + val blt = "b100".U + val bge = "b101".U + val bltu = "b110".U + val bgeu = "b111".U +} + +object InstructionsTypeCSR { + val csrrw = "b001".U + val csrrs = "b010".U + val csrrc = "b011".U + val csrrwi = "b101".U + val csrrsi = "b110".U + val csrrci = "b111".U +} + +object InstructionsNop { + val nop = 0x00000013L.U(Parameters.DataWidth) +} + +object InstructionsRet { + val mret = 0x30200073L.U(Parameters.DataWidth) + val ret = 0x00008067L.U(Parameters.DataWidth) +} + +object InstructionsEnv { + val ecall = 0x00000073L.U(Parameters.DataWidth) + val ebreak = 0x00100073L.U(Parameters.DataWidth) +} + +object ALUOp1Source { + val Register = 0.U(1.W) + val InstructionAddress = 1.U(1.W) +} + +object ALUOp2Source { + val Register = 0.U(1.W) + val Immediate = 1.U(1.W) +} + +object RegWriteSource { + val ALUResult = 0.U(2.W) + val Memory = 1.U(2.W) + val CSR = 2.U(2.W) + val NextInstructionAddress = 3.U(2.W) +} + +class InstructionDecode extends Module { + val io = IO(new Bundle { + val instruction = Input(UInt(Parameters.InstructionWidth)) + + val regs_reg1_read_address = Output(UInt(Parameters.PhysicalRegisterAddrWidth)) + val regs_reg2_read_address = Output(UInt(Parameters.PhysicalRegisterAddrWidth)) + val ex_immediate = Output(UInt(Parameters.DataWidth)) + val ex_aluop1_source = Output(Bool()) + val ex_aluop2_source = Output(Bool()) + val ex_memory_read_enable = Output(Bool()) + val ex_memory_write_enable = Output(Bool()) + val ex_reg_write_source = Output(UInt(2.W)) + val ex_reg_write_enable = Output(Bool()) + val ex_reg_write_address = Output(UInt(Parameters.PhysicalRegisterAddrWidth)) + val ex_csr_address = Output(UInt(Parameters.CSRRegisterAddrWidth)) + val ex_csr_write_enable = Output(Bool()) + }) + val opcode = io.instruction(6, 0) + val funct3 = io.instruction(14, 12) + val funct7 = io.instruction(31, 25) + val rd = io.instruction(11, 7) + val rs1 = io.instruction(19, 15) + val rs2 = io.instruction(24, 20) + + io.regs_reg1_read_address := Mux(opcode === Instructions.lui, 0.U(Parameters.PhysicalRegisterAddrWidth), rs1) + io.regs_reg2_read_address := rs2 + io.ex_immediate := MuxLookup( + opcode, + Cat(Fill(20, io.instruction(31)), io.instruction(31, 20)), + IndexedSeq( + InstructionTypes.I -> Cat(Fill(21, io.instruction(31)), io.instruction(30, 20)), + InstructionTypes.L -> Cat(Fill(21, io.instruction(31)), io.instruction(30, 20)), + Instructions.jalr -> Cat(Fill(21, io.instruction(31)), io.instruction(30, 20)), + InstructionTypes.S -> Cat(Fill(21, io.instruction(31)), io.instruction(30, 25), io.instruction(11, 7)), + InstructionTypes.B -> Cat(Fill(20, io.instruction(31)), io.instruction(7), io.instruction(30, 25), io.instruction(11, 8), 0.U(1.W)), + Instructions.lui -> Cat(io.instruction(31, 12), 0.U(12.W)), + Instructions.auipc -> Cat(io.instruction(31, 12), 0.U(12.W)), + Instructions.jal -> Cat(Fill(12, io.instruction(31)), io.instruction(19, 12), io.instruction(20), io.instruction(30, 21), 0.U(1.W)) + ) + ) + io.ex_aluop1_source := Mux( + opcode === Instructions.auipc || opcode === InstructionTypes.B || opcode === Instructions.jal, + ALUOp1Source.InstructionAddress, + ALUOp1Source.Register + ) + io.ex_aluop2_source := Mux( + opcode === InstructionTypes.RM, + ALUOp2Source.Register, + ALUOp2Source.Immediate + ) + io.ex_memory_read_enable := opcode === InstructionTypes.L + io.ex_memory_write_enable := opcode === InstructionTypes.S + io.ex_reg_write_source := MuxLookup( + opcode, + RegWriteSource.ALUResult, + IndexedSeq( + InstructionTypes.L -> RegWriteSource.Memory, + Instructions.csr -> RegWriteSource.CSR, + Instructions.jal -> RegWriteSource.NextInstructionAddress, + Instructions.jalr -> RegWriteSource.NextInstructionAddress + ) + ) + io.ex_reg_write_enable := (opcode === InstructionTypes.RM) || (opcode === InstructionTypes.I) || + (opcode === InstructionTypes.L) || (opcode === Instructions.auipc) || (opcode === Instructions.lui) || + (opcode === Instructions.jal) || (opcode === Instructions.jalr) || (opcode === Instructions.csr) + io.ex_reg_write_address := io.instruction(11, 7) + io.ex_csr_address := io.instruction(31, 20) + io.ex_csr_write_enable := (opcode === Instructions.csr) && ( + funct3 === InstructionsTypeCSR.csrrw || funct3 === InstructionsTypeCSR.csrrwi || + funct3 === InstructionsTypeCSR.csrrs || funct3 === InstructionsTypeCSR.csrrsi || + funct3 === InstructionsTypeCSR.csrrc || funct3 === InstructionsTypeCSR.csrrci + ) +} diff --git a/lab3/src/main/scala/riscv/core/fivestage_forward/InstructionFetch.scala b/lab3/src/main/scala/riscv/core/fivestage_forward/InstructionFetch.scala new file mode 100644 index 0000000..c74f1b4 --- /dev/null +++ b/lab3/src/main/scala/riscv/core/fivestage_forward/InstructionFetch.scala @@ -0,0 +1,48 @@ +// 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.core.fivestage_forward + +import chisel3._ +import chisel3.util.MuxCase +import riscv.Parameters + +object ProgramCounter { + val EntryAddress = Parameters.EntryAddress +} + +class InstructionFetch extends Module { + val io = IO(new Bundle { + val stall_flag_ctrl = Input(Bool()) + val jump_flag_id = Input(Bool()) + val jump_address_id = Input(UInt(Parameters.AddrWidth)) + val rom_instruction = Input(UInt(Parameters.DataWidth)) + val instruction_valid = Input(Bool()) + + val instruction_address = Output(UInt(Parameters.AddrWidth)) + val id_instruction = Output(UInt(Parameters.InstructionWidth)) + }) + val pc = RegInit(ProgramCounter.EntryAddress) + + pc := MuxCase( + pc + 4.U, + IndexedSeq( + (io.jump_flag_id && !io.stall_flag_ctrl) -> io.jump_address_id, + (io.stall_flag_ctrl || !io.instruction_valid) -> pc + ) + ) + + io.instruction_address := pc + io.id_instruction := Mux(io.instruction_valid, io.rom_instruction, InstructionsNop.nop) +} diff --git a/lab3/src/main/scala/riscv/core/fivestage_forward/MEM2WB.scala b/lab3/src/main/scala/riscv/core/fivestage_forward/MEM2WB.scala new file mode 100644 index 0000000..5b35869 --- /dev/null +++ b/lab3/src/main/scala/riscv/core/fivestage_forward/MEM2WB.scala @@ -0,0 +1,83 @@ +// Copyright 2022 Canbin Huang +// +// 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.core.fivestage_forward + +import chisel3._ +import riscv.Parameters +import riscv.core.PipelineRegister + +class MEM2WB extends Module { + val io = IO(new Bundle() { + val instruction_address = Input(UInt(Parameters.AddrWidth)) + val alu_result = Input(UInt(Parameters.DataWidth)) + val regs_write_enable = Input(Bool()) + val regs_write_source = Input(UInt(2.W)) + val regs_write_address = Input(UInt(Parameters.AddrWidth)) + val memory_read_data = Input(UInt(Parameters.DataWidth)) + val csr_read_data = Input(UInt(Parameters.DataWidth)) + + val output_instruction_address = Output(UInt(Parameters.AddrWidth)) + val output_alu_result = Output(UInt(Parameters.DataWidth)) + val output_regs_write_enable = Output(Bool()) + val output_regs_write_source = Output(UInt(2.W)) + val output_regs_write_address = Output(UInt(Parameters.AddrWidth)) + val output_memory_read_data = Output(UInt(Parameters.DataWidth)) + val output_csr_read_data = Output(UInt(Parameters.DataWidth)) + }) + val stall = false.B + val flush = false.B + + val alu_result = Module(new PipelineRegister()) + alu_result.io.in := io.alu_result + alu_result.io.stall := stall + alu_result.io.flush := flush + io.output_alu_result := alu_result.io.out + + val memory_read_data = Module(new PipelineRegister()) + memory_read_data.io.in := io.memory_read_data + memory_read_data.io.stall := stall + memory_read_data.io.flush := flush + io.output_memory_read_data := memory_read_data.io.out + + val regs_write_enable = Module(new PipelineRegister(1)) + regs_write_enable.io.in := io.regs_write_enable + regs_write_enable.io.stall := stall + regs_write_enable.io.flush := flush + io.output_regs_write_enable := regs_write_enable.io.out + + val regs_write_source = Module(new PipelineRegister(2)) + regs_write_source.io.in := io.regs_write_source + regs_write_source.io.stall := stall + regs_write_source.io.flush := flush + io.output_regs_write_source := regs_write_source.io.out + + val regs_write_address = Module(new PipelineRegister(Parameters.PhysicalRegisterAddrBits)) + regs_write_address.io.in := io.regs_write_address + regs_write_address.io.stall := stall + regs_write_address.io.flush := flush + io.output_regs_write_address := regs_write_address.io.out + + val instruction_address = Module(new PipelineRegister(Parameters.InstructionBits)) + instruction_address.io.in := io.instruction_address + instruction_address.io.stall := stall + instruction_address.io.flush := flush + io.output_instruction_address := instruction_address.io.out + + val csr_read_data = Module(new PipelineRegister()) + csr_read_data.io.in := io.csr_read_data + csr_read_data.io.stall := stall + csr_read_data.io.flush := flush + io.output_csr_read_data := csr_read_data.io.out +} diff --git a/lab3/src/main/scala/riscv/core/fivestage_forward/MemoryAccess.scala b/lab3/src/main/scala/riscv/core/fivestage_forward/MemoryAccess.scala new file mode 100644 index 0000000..b558aae --- /dev/null +++ b/lab3/src/main/scala/riscv/core/fivestage_forward/MemoryAccess.scala @@ -0,0 +1,109 @@ +// Copyright 2022 Canbin Huang +// +// 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.core.fivestage_forward + +import chisel3._ +import chisel3.util._ +import peripheral.RAMBundle +import riscv.Parameters + +class MemoryAccess extends Module { + val io = IO(new Bundle() { + val alu_result = Input(UInt(Parameters.DataWidth)) + val reg2_data = Input(UInt(Parameters.DataWidth)) + val memory_read_enable = Input(Bool()) + val memory_write_enable = Input(Bool()) + val funct3 = Input(UInt(3.W)) + val regs_write_source = Input(UInt(2.W)) + val csr_read_data = Input(UInt(Parameters.DataWidth)) + + val wb_memory_read_data = Output(UInt(Parameters.DataWidth)) + val forward_data = Output(UInt(Parameters.DataWidth)) + + val bundle = Flipped(new RAMBundle) + }) + val mem_address_index = io.alu_result(log2Up(Parameters.WordSize) - 1, 0).asUInt + + io.bundle.write_enable := io.memory_write_enable + io.bundle.write_data := 0.U + io.bundle.address := io.alu_result + io.bundle.write_strobe := VecInit(Seq.fill(Parameters.WordSize)(false.B)) + io.wb_memory_read_data := 0.U + + when(io.memory_read_enable) { + val data = io.bundle.read_data + io.wb_memory_read_data := MuxLookup( + io.funct3, + 0.U, + IndexedSeq( + InstructionsTypeL.lb -> MuxLookup( + mem_address_index, + Cat(Fill(24, data(31)), data(31, 24)), + IndexedSeq( + 0.U -> Cat(Fill(24, data(7)), data(7, 0)), + 1.U -> Cat(Fill(24, data(15)), data(15, 8)), + 2.U -> Cat(Fill(24, data(23)), data(23, 16)) + ) + ), + InstructionsTypeL.lbu -> MuxLookup( + mem_address_index, + Cat(Fill(24, 0.U), data(31, 24)), + IndexedSeq( + 0.U -> Cat(Fill(24, 0.U), data(7, 0)), + 1.U -> Cat(Fill(24, 0.U), data(15, 8)), + 2.U -> Cat(Fill(24, 0.U), data(23, 16)) + ) + ), + InstructionsTypeL.lh -> Mux( + mem_address_index === 0.U, + Cat(Fill(16, data(15)), data(15, 0)), + Cat(Fill(16, data(31)), data(31, 16)) + ), + InstructionsTypeL.lhu -> Mux( + mem_address_index === 0.U, + Cat(Fill(16, 0.U), data(15, 0)), + Cat(Fill(16, 0.U), data(31, 16)) + ), + InstructionsTypeL.lw -> data + ) + ) + }.elsewhen(io.memory_write_enable) { + io.bundle.write_data := io.reg2_data + io.bundle.write_strobe := VecInit(Seq.fill(Parameters.WordSize)(false.B)) + when(io.funct3 === InstructionsTypeS.sb) { + io.bundle.write_strobe(mem_address_index) := true.B + io.bundle.write_data := io.reg2_data(Parameters.ByteBits, 0) << (mem_address_index << log2Up(Parameters.ByteBits).U) + }.elsewhen(io.funct3 === InstructionsTypeS.sh) { + when(mem_address_index === 0.U) { + for (i <- 0 until Parameters.WordSize / 2) { + io.bundle.write_strobe(i) := true.B + } + io.bundle.write_data := io.reg2_data(Parameters.WordSize / 2 * Parameters.ByteBits, 0) + }.otherwise { + for (i <- Parameters.WordSize / 2 until Parameters.WordSize) { + io.bundle.write_strobe(i) := true.B + } + io.bundle.write_data := io.reg2_data(Parameters.WordSize / 2 * Parameters.ByteBits, 0) << (Parameters + .WordSize / 2 * Parameters.ByteBits) + } + }.elsewhen(io.funct3 === InstructionsTypeS.sw) { + for (i <- 0 until Parameters.WordSize) { + io.bundle.write_strobe(i) := true.B + } + } + } + + io.forward_data := Mux(io.regs_write_source === RegWriteSource.CSR, io.csr_read_data, io.alu_result) +} diff --git a/lab3/src/main/scala/riscv/core/fivestage_forward/WriteBack.scala b/lab3/src/main/scala/riscv/core/fivestage_forward/WriteBack.scala new file mode 100644 index 0000000..15d8e35 --- /dev/null +++ b/lab3/src/main/scala/riscv/core/fivestage_forward/WriteBack.scala @@ -0,0 +1,40 @@ +// Copyright 2022 Canbin Huang +// +// 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.core.fivestage_forward + +import chisel3._ +import chisel3.util._ +import riscv.Parameters + +class WriteBack extends Module { + val io = IO(new Bundle() { + val instruction_address = Input(UInt(Parameters.AddrWidth)) + val alu_result = Input(UInt(Parameters.DataWidth)) + val memory_read_data = Input(UInt(Parameters.DataWidth)) + val regs_write_source = Input(UInt(2.W)) + val csr_read_data = Input(UInt(Parameters.DataWidth)) + + val regs_write_data = Output(UInt(Parameters.DataWidth)) + }) + io.regs_write_data := MuxLookup( + io.regs_write_source, + io.alu_result, + IndexedSeq( + RegWriteSource.Memory -> io.memory_read_data, + RegWriteSource.CSR -> io.csr_read_data, + RegWriteSource.NextInstructionAddress -> (io.instruction_address + 4.U) + ) + ) +} diff --git a/lab3/src/main/scala/riscv/core/fivestage_stall/CLINT.scala b/lab3/src/main/scala/riscv/core/fivestage_stall/CLINT.scala new file mode 100644 index 0000000..301444e --- /dev/null +++ b/lab3/src/main/scala/riscv/core/fivestage_stall/CLINT.scala @@ -0,0 +1,103 @@ +// 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.core.fivestage_stall + +import chisel3._ +import chisel3.util.MuxLookup +import riscv.Parameters + +object InterruptStatus { + val None = 0x0.U(8.W) + val Timer0 = 0x1.U(8.W) + val Ret = 0xFF.U(8.W) +} + +class CSRDirectAccessBundle extends Bundle { + val mstatus = Input(UInt(Parameters.DataWidth)) + val mepc = Input(UInt(Parameters.DataWidth)) + val mcause = Input(UInt(Parameters.DataWidth)) + val mtvec = Input(UInt(Parameters.DataWidth)) + + val mstatus_write_data = Output(UInt(Parameters.DataWidth)) + val mepc_write_data = Output(UInt(Parameters.DataWidth)) + val mcause_write_data = Output(UInt(Parameters.DataWidth)) + + val direct_write_enable = Output(Bool()) +} + +// Core Local Interrupt Controller +class CLINT extends Module { + val io = IO(new Bundle { + val interrupt_flag = Input(UInt(Parameters.InterruptFlagWidth)) + + val instruction_ex = Input(UInt(Parameters.InstructionWidth)) + val instruction_address_if = Input(UInt(Parameters.AddrWidth)) + val instruction_address_id = Input(UInt(Parameters.AddrWidth)) + + val jump_flag = Input(Bool()) + val jump_address = Input(UInt(Parameters.AddrWidth)) + + val ex_interrupt_handler_address = Output(UInt(Parameters.AddrWidth)) + val ex_interrupt_assert = Output(Bool()) + + val csr_bundle = new CSRDirectAccessBundle + }) + val interrupt_enable = io.csr_bundle.mstatus(3) + val jumpping = RegNext(io.jump_flag || io.ex_interrupt_assert) + val instruction_address = Mux( + io.jump_flag, + io.jump_address, + Mux(jumpping, io.instruction_address_if, io.instruction_address_id) + ) + val mstatus_disable_interrupt = io.csr_bundle.mstatus(31, 4) ## 0.U(1.W) ## io.csr_bundle.mstatus(2, 0) + val mstatus_recover_interrupt = io.csr_bundle.mstatus(31, 4) ## io.csr_bundle.mstatus(7) ## io.csr_bundle.mstatus(2, 0) + + when(io.instruction_ex === InstructionsEnv.ecall || io.instruction_ex === InstructionsEnv.ebreak) { + io.csr_bundle.mstatus_write_data := mstatus_disable_interrupt + io.csr_bundle.mepc_write_data := instruction_address + io.csr_bundle.mcause_write_data := MuxLookup( + io.instruction_ex, + 10.U, + IndexedSeq( + InstructionsEnv.ecall -> 11.U, + InstructionsEnv.ebreak -> 3.U, + ) + ) + io.csr_bundle.direct_write_enable := true.B + io.ex_interrupt_assert := true.B + io.ex_interrupt_handler_address := io.csr_bundle.mtvec + }.elsewhen(io.interrupt_flag =/= InterruptStatus.None && interrupt_enable) { + io.csr_bundle.mstatus_write_data := mstatus_disable_interrupt + io.csr_bundle.mepc_write_data := instruction_address + io.csr_bundle.mcause_write_data := Mux(io.interrupt_flag(0), 0x80000007L.U, 0x8000000BL.U) + io.csr_bundle.direct_write_enable := true.B + io.ex_interrupt_assert := true.B + io.ex_interrupt_handler_address := io.csr_bundle.mtvec + }.elsewhen(io.instruction_ex === InstructionsRet.mret) { + io.csr_bundle.mstatus_write_data := mstatus_recover_interrupt + io.csr_bundle.mepc_write_data := io.csr_bundle.mepc + io.csr_bundle.mcause_write_data := io.csr_bundle.mcause + io.csr_bundle.direct_write_enable := true.B + io.ex_interrupt_assert := true.B + io.ex_interrupt_handler_address := io.csr_bundle.mepc + }.otherwise { + io.csr_bundle.mstatus_write_data := io.csr_bundle.mstatus + io.csr_bundle.mepc_write_data := io.csr_bundle.mepc + io.csr_bundle.mcause_write_data := io.csr_bundle.mcause + io.csr_bundle.direct_write_enable := false.B + io.ex_interrupt_assert := false.B + io.ex_interrupt_handler_address := 0.U + } +} diff --git a/lab3/src/main/scala/riscv/core/fivestage_stall/CPU.scala b/lab3/src/main/scala/riscv/core/fivestage_stall/CPU.scala new file mode 100644 index 0000000..16a85f8 --- /dev/null +++ b/lab3/src/main/scala/riscv/core/fivestage_stall/CPU.scala @@ -0,0 +1,148 @@ +// 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.core.fivestage_stall + +import chisel3._ +import riscv.Parameters +import riscv.core.{CPUBundle, CSR, RegisterFile} + +class CPU extends Module { + val io = IO(new CPUBundle) + + val ctrl = Module(new Control) + val regs = Module(new RegisterFile) + val inst_fetch = Module(new InstructionFetch) + val if2id = Module(new IF2ID) + val id = Module(new InstructionDecode) + val id2ex = Module(new ID2EX) + val ex = Module(new Execute) + val ex2mem = Module(new EX2MEM) + val mem = Module(new MemoryAccess) + val mem2wb = Module(new MEM2WB) + val wb = Module(new WriteBack) + val clint = Module(new CLINT) + val csr_regs = Module(new CSR) + + ctrl.io.jump_flag := ex.io.if_jump_flag + ctrl.io.rs1_id := id.io.regs_reg1_read_address + ctrl.io.rs2_id := id.io.regs_reg2_read_address + ctrl.io.rd_ex := id2ex.io.output_regs_write_address + ctrl.io.reg_write_enable_ex := id2ex.io.output_regs_write_enable + ctrl.io.rd_mem := ex2mem.io.output_regs_write_address + ctrl.io.reg_write_enable_mem := ex2mem.io.output_regs_write_enable + + regs.io.write_enable := mem2wb.io.output_regs_write_enable + regs.io.write_address := mem2wb.io.output_regs_write_address + regs.io.write_data := wb.io.regs_write_data + regs.io.read_address1 := id.io.regs_reg1_read_address + regs.io.read_address2 := id.io.regs_reg2_read_address + + regs.io.debug_read_address := io.debug_read_address + io.debug_read_data := regs.io.debug_read_data + + io.instruction_address := inst_fetch.io.instruction_address + inst_fetch.io.stall_flag_ctrl := ctrl.io.pc_stall + inst_fetch.io.jump_flag_id := ex.io.if_jump_flag + inst_fetch.io.jump_address_id := ex.io.if_jump_address + inst_fetch.io.rom_instruction := io.instruction + inst_fetch.io.instruction_valid := io.instruction_valid + + if2id.io.stall := ctrl.io.if_stall + if2id.io.flush := ctrl.io.if_flush + if2id.io.instruction := inst_fetch.io.id_instruction + if2id.io.instruction_address := inst_fetch.io.instruction_address + if2id.io.interrupt_flag := io.interrupt_flag + + id.io.instruction := if2id.io.output_instruction + + id2ex.io.flush := ctrl.io.id_flush + id2ex.io.instruction := if2id.io.output_instruction + id2ex.io.instruction_address := if2id.io.output_instruction_address + id2ex.io.reg1_data := regs.io.read_data1 + id2ex.io.reg2_data := regs.io.read_data2 + id2ex.io.regs_reg1_read_address := id.io.regs_reg1_read_address + id2ex.io.regs_reg2_read_address := id.io.regs_reg2_read_address + id2ex.io.regs_write_enable := id.io.ex_reg_write_enable + id2ex.io.regs_write_address := id.io.ex_reg_write_address + id2ex.io.regs_write_source := id.io.ex_reg_write_source + id2ex.io.immediate := id.io.ex_immediate + id2ex.io.aluop1_source := id.io.ex_aluop1_source + id2ex.io.aluop2_source := id.io.ex_aluop2_source + id2ex.io.csr_write_enable := id.io.ex_csr_write_enable + id2ex.io.csr_address := id.io.ex_csr_address + id2ex.io.memory_read_enable := id.io.ex_memory_read_enable + id2ex.io.memory_write_enable := id.io.ex_memory_write_enable + id2ex.io.csr_read_data := csr_regs.io.id_reg_read_data + + ex.io.instruction := id2ex.io.output_instruction + ex.io.instruction_address := id2ex.io.output_instruction_address + ex.io.reg1_data := id2ex.io.output_reg1_data + ex.io.reg2_data := id2ex.io.output_reg2_data + ex.io.immediate_id := id2ex.io.output_immediate + ex.io.aluop1_source_id := id2ex.io.output_aluop1_source + ex.io.aluop2_source_id := id2ex.io.output_aluop2_source + ex.io.csr_read_data_id := id2ex.io.output_csr_read_data + ex.io.interrupt_assert_clint := clint.io.ex_interrupt_assert + ex.io.interrupt_handler_address_clint := clint.io.ex_interrupt_handler_address + + ex2mem.io.regs_write_enable := id2ex.io.output_regs_write_enable + ex2mem.io.regs_write_source := id2ex.io.output_regs_write_source + ex2mem.io.regs_write_address := id2ex.io.output_regs_write_address + ex2mem.io.instruction_address := id2ex.io.output_instruction_address + ex2mem.io.funct3 := id2ex.io.output_instruction(14, 12) + ex2mem.io.reg2_data := ex.io.mem_reg2_data + ex2mem.io.memory_read_enable := id2ex.io.output_memory_read_enable + ex2mem.io.memory_write_enable := id2ex.io.output_memory_write_enable + ex2mem.io.alu_result := ex.io.mem_alu_result + ex2mem.io.csr_read_data := id2ex.io.output_csr_read_data + + mem.io.alu_result := ex2mem.io.output_alu_result + mem.io.reg2_data := ex2mem.io.output_reg2_data + mem.io.memory_read_enable := ex2mem.io.output_memory_read_enable + mem.io.memory_write_enable := ex2mem.io.output_memory_write_enable + mem.io.funct3 := ex2mem.io.output_funct3 + mem.io.regs_write_source := ex2mem.io.output_regs_write_source + mem.io.csr_read_data := ex2mem.io.output_csr_read_data + io.device_select := mem.io.bundle.address(Parameters.AddrBits - 1, Parameters.AddrBits - Parameters.SlaveDeviceCountBits) + io.memory_bundle <> mem.io.bundle + io.memory_bundle.address := 0.U(Parameters.SlaveDeviceCountBits.W) ## mem.io.bundle.address(Parameters.AddrBits - 1 - Parameters.SlaveDeviceCountBits, 0) + + mem2wb.io.instruction_address := ex2mem.io.output_instruction_address + mem2wb.io.alu_result := ex2mem.io.output_alu_result + mem2wb.io.regs_write_enable := ex2mem.io.output_regs_write_enable + mem2wb.io.regs_write_source := ex2mem.io.output_regs_write_source + mem2wb.io.regs_write_address := ex2mem.io.output_regs_write_address + mem2wb.io.memory_read_data := mem.io.wb_memory_read_data + mem2wb.io.csr_read_data := ex2mem.io.output_csr_read_data + + wb.io.instruction_address := mem2wb.io.output_instruction_address + wb.io.alu_result := mem2wb.io.output_alu_result + wb.io.memory_read_data := mem2wb.io.output_memory_read_data + wb.io.regs_write_source := mem2wb.io.output_regs_write_source + wb.io.csr_read_data := mem2wb.io.output_csr_read_data + + clint.io.instruction_address_if := inst_fetch.io.instruction_address + clint.io.instruction_address_id := if2id.io.output_instruction_address + clint.io.instruction_ex := id2ex.io.output_instruction + clint.io.jump_flag := ex.io.clint_jump_flag + clint.io.jump_address := ex.io.clint_jump_address + clint.io.interrupt_flag := if2id.io.output_interrupt_flag + clint.io.csr_bundle <> csr_regs.io.clint_access_bundle + + csr_regs.io.reg_read_address_id := id.io.ex_csr_address + csr_regs.io.reg_write_enable_ex := id2ex.io.output_csr_write_enable + csr_regs.io.reg_write_address_ex := id2ex.io.output_csr_address + csr_regs.io.reg_write_data_ex := ex.io.csr_write_data +} diff --git a/lab3/src/main/scala/riscv/core/fivestage_stall/Control.scala b/lab3/src/main/scala/riscv/core/fivestage_stall/Control.scala new file mode 100644 index 0000000..d084e03 --- /dev/null +++ b/lab3/src/main/scala/riscv/core/fivestage_stall/Control.scala @@ -0,0 +1,43 @@ +// 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.core.fivestage_stall + +import chisel3._ +import riscv.Parameters + +class Control extends Module { + val io = IO(new Bundle { + val jump_flag = Input(Bool()) + val rs1_id = Input(UInt(Parameters.PhysicalRegisterAddrWidth)) + val rs2_id = Input(UInt(Parameters.PhysicalRegisterAddrWidth)) + val rd_ex = Input(UInt(Parameters.PhysicalRegisterAddrWidth)) + val reg_write_enable_ex = Input(Bool()) + val rd_mem = Input(UInt(Parameters.PhysicalRegisterAddrWidth)) + val reg_write_enable_mem = Input(Bool()) + + val if_flush = Output(Bool()) + val id_flush = Output(Bool()) + val pc_stall = Output(Bool()) + val if_stall = Output(Bool()) + }) + + // Lab3(Stall) + io.if_flush := false.B + io.id_flush := false.B + + io.pc_stall := false.B + io.if_stall := false.B + // Lab3(Stall) End +} diff --git a/lab3/src/main/scala/riscv/core/fivestage_stall/EX2MEM.scala b/lab3/src/main/scala/riscv/core/fivestage_stall/EX2MEM.scala new file mode 100644 index 0000000..9db3de5 --- /dev/null +++ b/lab3/src/main/scala/riscv/core/fivestage_stall/EX2MEM.scala @@ -0,0 +1,108 @@ +// Copyright 2022 Canbin Huang +// +// 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.core.fivestage_stall + +import chisel3._ +import riscv.Parameters +import riscv.core.PipelineRegister + +class EX2MEM extends Module { + val io = IO(new Bundle() { + val regs_write_enable = Input(Bool()) + val regs_write_source = Input(UInt(2.W)) + val regs_write_address = Input(UInt(Parameters.AddrWidth)) + val instruction_address = Input(UInt(Parameters.AddrWidth)) + val funct3 = Input(UInt(3.W)) + val reg2_data = Input(UInt(Parameters.DataWidth)) + val memory_read_enable = Input(Bool()) + val memory_write_enable = Input(Bool()) + val alu_result = Input(UInt(Parameters.DataWidth)) + val csr_read_data = Input(UInt(Parameters.DataWidth)) + + val output_regs_write_enable = Output(Bool()) + val output_regs_write_source = Output(UInt(2.W)) + val output_regs_write_address = Output(UInt(Parameters.AddrWidth)) + val output_instruction_address = Output(UInt(Parameters.AddrWidth)) + val output_funct3 = Output(UInt(Parameters.DataWidth)) + val output_reg2_data = Output(UInt(Parameters.DataWidth)) + val output_memory_read_enable = Output(Bool()) + val output_memory_write_enable = Output(Bool()) + val output_alu_result = Output(UInt(Parameters.DataWidth)) + val output_csr_read_data = Output(UInt(Parameters.DataWidth)) + }) + + val stall = false.B + val flush = false.B + + val regs_write_enable = Module(new PipelineRegister(1)) + regs_write_enable.io.in := io.regs_write_enable + regs_write_enable.io.stall := stall + regs_write_enable.io.flush := flush + io.output_regs_write_enable := regs_write_enable.io.out + + val regs_write_source = Module(new PipelineRegister(2)) + regs_write_source.io.in := io.regs_write_source + regs_write_source.io.stall := stall + regs_write_source.io.flush := flush + io.output_regs_write_source := regs_write_source.io.out + + val regs_write_address = Module(new PipelineRegister(Parameters.PhysicalRegisterAddrBits)) + regs_write_address.io.in := io.regs_write_address + regs_write_address.io.stall := stall + regs_write_address.io.flush := flush + io.output_regs_write_address := regs_write_address.io.out + + val instruction_address = Module(new PipelineRegister(Parameters.AddrBits)) + instruction_address.io.in := io.instruction_address + instruction_address.io.stall := stall + instruction_address.io.flush := flush + io.output_instruction_address := instruction_address.io.out + + val funct3 = Module(new PipelineRegister(3)) + funct3.io.in := io.funct3 + funct3.io.stall := stall + funct3.io.flush := flush + io.output_funct3 := funct3.io.out + + val reg2_data = Module(new PipelineRegister()) + reg2_data.io.in := io.reg2_data + reg2_data.io.stall := stall + reg2_data.io.flush := flush + io.output_reg2_data := reg2_data.io.out + + val alu_result = Module(new PipelineRegister()) + alu_result.io.in := io.alu_result + alu_result.io.stall := stall + alu_result.io.flush := flush + io.output_alu_result := alu_result.io.out + + val memory_read_enable = Module(new PipelineRegister(1)) + memory_read_enable.io.in := io.memory_read_enable + memory_read_enable.io.stall := stall + memory_read_enable.io.flush := flush + io.output_memory_read_enable := memory_read_enable.io.out + + val memory_write_enable = Module(new PipelineRegister(1)) + memory_write_enable.io.in := io.memory_write_enable + memory_write_enable.io.stall := stall + memory_write_enable.io.flush := flush + io.output_memory_write_enable := memory_write_enable.io.out + + val csr_read_data = Module(new PipelineRegister()) + csr_read_data.io.in := io.csr_read_data + csr_read_data.io.stall := stall + csr_read_data.io.flush := flush + io.output_csr_read_data := csr_read_data.io.out +} diff --git a/lab3/src/main/scala/riscv/core/fivestage_stall/Execute.scala b/lab3/src/main/scala/riscv/core/fivestage_stall/Execute.scala new file mode 100644 index 0000000..a0ebe91 --- /dev/null +++ b/lab3/src/main/scala/riscv/core/fivestage_stall/Execute.scala @@ -0,0 +1,101 @@ +// 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.core.fivestage_stall + +import chisel3._ +import chisel3.util._ +import riscv.Parameters +import riscv.core.{ALU, ALUControl} + + +class Execute extends Module { + val io = IO(new Bundle { + val instruction = Input(UInt(Parameters.InstructionWidth)) + val instruction_address = Input(UInt(Parameters.AddrWidth)) + val reg1_data = Input(UInt(Parameters.DataWidth)) + val reg2_data = Input(UInt(Parameters.DataWidth)) + val immediate_id = Input(UInt(Parameters.DataWidth)) + val aluop1_source_id = Input(UInt(1.W)) + val aluop2_source_id = Input(UInt(1.W)) + val csr_read_data_id = Input(UInt(Parameters.DataWidth)) + val interrupt_assert_clint = Input(Bool()) + val interrupt_handler_address_clint = Input(UInt(Parameters.AddrWidth)) + + val mem_alu_result = Output(UInt(Parameters.DataWidth)) + val mem_reg2_data = Output(UInt(Parameters.DataWidth)) + val csr_write_data = Output(UInt(Parameters.DataWidth)) + val if_jump_flag = Output(Bool()) + val if_jump_address = Output(UInt(Parameters.AddrWidth)) + val clint_jump_flag = Output(Bool()) + val clint_jump_address = Output(UInt(Parameters.AddrWidth)) + }) + + val opcode = io.instruction(6, 0) + val funct3 = io.instruction(14, 12) + val funct7 = io.instruction(31, 25) + val uimm = io.instruction(19, 15) + + // ALU compute + val alu = Module(new ALU) + val alu_ctrl = Module(new ALUControl) + + alu_ctrl.io.opcode := opcode + alu_ctrl.io.funct3 := funct3 + alu_ctrl.io.funct7 := funct7 + alu.io.func := alu_ctrl.io.alu_funct + alu.io.op1 := Mux( + io.aluop1_source_id === ALUOp1Source.InstructionAddress, + io.instruction_address, + io.reg1_data + ) + alu.io.op2 := Mux( + io.aluop2_source_id === ALUOp2Source.Immediate, + io.immediate_id, + io.reg2_data + ) + io.mem_alu_result := alu.io.result + io.mem_reg2_data := io.reg2_data + io.csr_write_data := MuxLookup(funct3, 0.U, IndexedSeq( + InstructionsTypeCSR.csrrw -> io.reg1_data, + InstructionsTypeCSR.csrrc -> io.csr_read_data_id.&((~io.reg1_data).asUInt), + InstructionsTypeCSR.csrrs -> io.csr_read_data_id.|(io.reg1_data), + InstructionsTypeCSR.csrrwi -> Cat(0.U(27.W), uimm), + InstructionsTypeCSR.csrrci -> io.csr_read_data_id.&((~Cat(0.U(27.W), uimm)).asUInt), + InstructionsTypeCSR.csrrsi -> io.csr_read_data_id.|(Cat(0.U(27.W), uimm)), + )) + + // jump and interrupt + val instruction_jump_flag = (opcode === Instructions.jal) || + (opcode === Instructions.jalr) || + (opcode === InstructionTypes.B) && MuxLookup( + funct3, + false.B, + IndexedSeq( + InstructionsTypeB.beq -> (io.reg1_data === io.reg2_data), + InstructionsTypeB.bne -> (io.reg1_data =/= io.reg2_data), + InstructionsTypeB.blt -> (io.reg1_data.asSInt < io.reg2_data.asSInt), + InstructionsTypeB.bge -> (io.reg1_data.asSInt >= io.reg2_data.asSInt), + InstructionsTypeB.bltu -> (io.reg1_data.asUInt < io.reg2_data.asUInt), + InstructionsTypeB.bgeu -> (io.reg1_data.asUInt >= io.reg2_data.asUInt) + ) + ) + io.clint_jump_flag := instruction_jump_flag + io.clint_jump_address := alu.io.result + io.if_jump_flag := io.interrupt_assert_clint || instruction_jump_flag + io.if_jump_address := Mux(io.interrupt_assert_clint, + io.interrupt_handler_address_clint, + alu.io.result + ) +} diff --git a/lab3/src/main/scala/riscv/core/fivestage_stall/ID2EX.scala b/lab3/src/main/scala/riscv/core/fivestage_stall/ID2EX.scala new file mode 100644 index 0000000..8092774 --- /dev/null +++ b/lab3/src/main/scala/riscv/core/fivestage_stall/ID2EX.scala @@ -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.core.fivestage_stall + +import chisel3._ +import riscv.Parameters +import riscv.core.PipelineRegister + +class ID2EX extends Module { + val io = IO(new Bundle { + val flush = Input(Bool()) + val instruction = Input(UInt(Parameters.InstructionWidth)) + val instruction_address = Input(UInt(Parameters.AddrWidth)) + val regs_reg1_read_address = Input(UInt(Parameters.PhysicalRegisterAddrWidth)) + val regs_reg2_read_address = Input(UInt(Parameters.PhysicalRegisterAddrWidth)) + val regs_write_enable = Input(Bool()) + val regs_write_address = Input(UInt(Parameters.PhysicalRegisterAddrWidth)) + val regs_write_source = Input(UInt(2.W)) + val reg1_data = Input(UInt(Parameters.DataWidth)) + val reg2_data = Input(UInt(Parameters.DataWidth)) + val immediate = Input(UInt(Parameters.DataWidth)) + val aluop1_source = Input(UInt(1.W)) + val aluop2_source = Input(UInt(1.W)) + val csr_write_enable = Input(Bool()) + val csr_address = Input(UInt(Parameters.CSRRegisterAddrWidth)) + val memory_read_enable = Input(Bool()) + val memory_write_enable = Input(Bool()) + val csr_read_data = Input(UInt(Parameters.DataWidth)) + + val output_instruction = Output(UInt(Parameters.DataWidth)) + val output_instruction_address = Output(UInt(Parameters.AddrWidth)) + val output_regs_reg1_read_address = Output(UInt(Parameters.PhysicalRegisterAddrWidth)) + val output_regs_reg2_read_address = Output(UInt(Parameters.PhysicalRegisterAddrWidth)) + val output_regs_write_enable = Output(Bool()) + val output_regs_write_address = Output(UInt(Parameters.PhysicalRegisterAddrWidth)) + val output_regs_write_source = Output(UInt(2.W)) + val output_reg1_data = Output(UInt(Parameters.DataWidth)) + val output_reg2_data = Output(UInt(Parameters.DataWidth)) + val output_immediate = Output(UInt(Parameters.DataWidth)) + val output_aluop1_source = Output(UInt(1.W)) + val output_aluop2_source = Output(UInt(1.W)) + val output_csr_write_enable = Output(Bool()) + val output_csr_address = Output(UInt(Parameters.CSRRegisterAddrWidth)) + val output_memory_read_enable = Output(Bool()) + val output_memory_write_enable = Output(Bool()) + val output_csr_read_data = Output(UInt(Parameters.DataWidth)) + }) + + val stall = false.B + + val instruction = Module(new PipelineRegister(defaultValue = InstructionsNop.nop)) + instruction.io.in := io.instruction + instruction.io.stall := stall + instruction.io.flush := io.flush + io.output_instruction := instruction.io.out + + val instruction_address = Module(new PipelineRegister(defaultValue = ProgramCounter.EntryAddress)) + instruction_address.io.in := io.instruction_address + instruction_address.io.stall := stall + instruction_address.io.flush := io.flush + io.output_instruction_address := instruction_address.io.out + + val regs_reg1_read_address = Module(new PipelineRegister(Parameters.PhysicalRegisterAddrBits)) + regs_reg1_read_address.io.in := io.regs_reg1_read_address + regs_reg1_read_address.io.stall := stall + regs_reg1_read_address.io.flush := io.flush + io.output_regs_reg1_read_address := regs_reg1_read_address.io.out + + val regs_reg2_read_address = Module(new PipelineRegister(Parameters.PhysicalRegisterAddrBits)) + regs_reg2_read_address.io.in := io.regs_reg2_read_address + regs_reg2_read_address.io.stall := stall + regs_reg2_read_address.io.flush := io.flush + io.output_regs_reg2_read_address := regs_reg2_read_address.io.out + + val regs_write_enable = Module(new PipelineRegister(1)) + regs_write_enable.io.in := io.regs_write_enable + regs_write_enable.io.stall := stall + regs_write_enable.io.flush := io.flush + io.output_regs_write_enable := regs_write_enable.io.out + + val regs_write_address = Module(new PipelineRegister(Parameters.PhysicalRegisterAddrBits)) + regs_write_address.io.in := io.regs_write_address + regs_write_address.io.stall := stall + regs_write_address.io.flush := io.flush + io.output_regs_write_address := regs_write_address.io.out + + val regs_write_source = Module(new PipelineRegister(2)) + regs_write_source.io.in := io.regs_write_source + regs_write_source.io.stall := stall + regs_write_source.io.flush := io.flush + io.output_regs_write_source := regs_write_source.io.out + + val reg1_data = Module(new PipelineRegister()) + reg1_data.io.in := io.reg1_data + reg1_data.io.stall := stall + reg1_data.io.flush := io.flush + io.output_reg1_data := reg1_data.io.out + + val reg2_data = Module(new PipelineRegister()) + reg2_data.io.in := io.reg2_data + reg2_data.io.stall := stall + reg2_data.io.flush := io.flush + io.output_reg2_data := reg2_data.io.out + + val immediate = Module(new PipelineRegister()) + immediate.io.in := io.immediate + immediate.io.stall := stall + immediate.io.flush := io.flush + io.output_immediate := immediate.io.out + + val aluop1_source = Module(new PipelineRegister(1)) + aluop1_source.io.in := io.aluop1_source + aluop1_source.io.stall := stall + aluop1_source.io.flush := io.flush + io.output_aluop1_source := aluop1_source.io.out + + val aluop2_source = Module(new PipelineRegister(1)) + aluop2_source.io.in := io.aluop2_source + aluop2_source.io.stall := stall + aluop2_source.io.flush := io.flush + io.output_aluop2_source := aluop2_source.io.out + + val csr_write_enable = Module(new PipelineRegister(1)) + csr_write_enable.io.in := io.csr_write_enable + csr_write_enable.io.stall := stall + csr_write_enable.io.flush := io.flush + io.output_csr_write_enable := csr_write_enable.io.out + + val csr_address = Module(new PipelineRegister(Parameters.CSRRegisterAddrBits)) + csr_address.io.in := io.csr_address + csr_address.io.stall := stall + csr_address.io.flush := io.flush + io.output_csr_address := csr_address.io.out + + val memory_read_enable = Module(new PipelineRegister(1)) + memory_read_enable.io.in := io.memory_read_enable + memory_read_enable.io.stall := stall + memory_read_enable.io.flush := io.flush + io.output_memory_read_enable := memory_read_enable.io.out + + val memory_write_enable = Module(new PipelineRegister(1)) + memory_write_enable.io.in := io.memory_write_enable + memory_write_enable.io.stall := stall + memory_write_enable.io.flush := io.flush + io.output_memory_write_enable := memory_write_enable.io.out + + val csr_read_data = Module(new PipelineRegister()) + csr_read_data.io.in := io.csr_read_data + csr_read_data.io.stall := stall + csr_read_data.io.flush := io.flush + io.output_csr_read_data := csr_read_data.io.out +} diff --git a/lab3/src/main/scala/riscv/core/fivestage_stall/IF2ID.scala b/lab3/src/main/scala/riscv/core/fivestage_stall/IF2ID.scala new file mode 100644 index 0000000..6dc5bd6 --- /dev/null +++ b/lab3/src/main/scala/riscv/core/fivestage_stall/IF2ID.scala @@ -0,0 +1,51 @@ +// 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.core.fivestage_stall + +import chisel3._ +import riscv.Parameters +import riscv.core.PipelineRegister + +class IF2ID extends Module { + val io = IO(new Bundle { + val stall = Input(Bool()) + val flush = Input(Bool()) + val instruction = Input(UInt(Parameters.InstructionWidth)) + val instruction_address = Input(UInt(Parameters.AddrWidth)) + val interrupt_flag = Input(UInt(Parameters.InterruptFlagWidth)) + + val output_instruction = Output(UInt(Parameters.DataWidth)) + val output_instruction_address = Output(UInt(Parameters.AddrWidth)) + val output_interrupt_flag = Output(UInt(Parameters.InterruptFlagWidth)) + }) + + val instruction = Module(new PipelineRegister(defaultValue = InstructionsNop.nop)) + instruction.io.in := io.instruction + instruction.io.stall := io.stall + instruction.io.flush := io.flush + io.output_instruction := instruction.io.out + + val instruction_address = Module(new PipelineRegister(defaultValue = ProgramCounter.EntryAddress)) + instruction_address.io.in := io.instruction_address + instruction_address.io.stall := io.stall + instruction_address.io.flush := io.flush + io.output_instruction_address := instruction_address.io.out + + val interrupt_flag = Module(new PipelineRegister(Parameters.InterruptFlagBits)) + interrupt_flag.io.in := io.interrupt_flag + interrupt_flag.io.stall := io.stall + interrupt_flag.io.flush := io.flush + io.output_interrupt_flag := interrupt_flag.io.out +} diff --git a/lab3/src/main/scala/riscv/core/fivestage_stall/InstructionDecode.scala b/lab3/src/main/scala/riscv/core/fivestage_stall/InstructionDecode.scala new file mode 100644 index 0000000..e5e0549 --- /dev/null +++ b/lab3/src/main/scala/riscv/core/fivestage_stall/InstructionDecode.scala @@ -0,0 +1,207 @@ +// 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.core.fivestage_stall + +import chisel3._ +import chisel3.util._ +import riscv.Parameters + +object InstructionTypes { + val L = "b0000011".U + val I = "b0010011".U + val S = "b0100011".U + val RM = "b0110011".U + val B = "b1100011".U +} + +object Instructions { + val lui = "b0110111".U + val nop = "b0000001".U + val jal = "b1101111".U + val jalr = "b1100111".U + val auipc = "b0010111".U + val csr = "b1110011".U + val fence = "b0001111".U +} + +object InstructionsTypeL { + val lb = "b000".U + val lh = "b001".U + val lw = "b010".U + val lbu = "b100".U + val lhu = "b101".U +} + +object InstructionsTypeI { + val addi = 0.U + val slli = 1.U + val slti = 2.U + val sltiu = 3.U + val xori = 4.U + val sri = 5.U + val ori = 6.U + val andi = 7.U +} + +object InstructionsTypeS { + val sb = "b000".U + val sh = "b001".U + val sw = "b010".U +} + +object InstructionsTypeR { + val add_sub = 0.U + val sll = 1.U + val slt = 2.U + val sltu = 3.U + val xor = 4.U + val sr = 5.U + val or = 6.U + val and = 7.U +} + +object InstructionsTypeM { + val mul = 0.U + val mulh = 1.U + val mulhsu = 2.U + val mulhum = 3.U + val div = 4.U + val divu = 5.U + val rem = 6.U + val remu = 7.U +} + +object InstructionsTypeB { + val beq = "b000".U + val bne = "b001".U + val blt = "b100".U + val bge = "b101".U + val bltu = "b110".U + val bgeu = "b111".U +} + +object InstructionsTypeCSR { + val csrrw = "b001".U + val csrrs = "b010".U + val csrrc = "b011".U + val csrrwi = "b101".U + val csrrsi = "b110".U + val csrrci = "b111".U +} + +object InstructionsNop { + val nop = 0x00000013L.U(Parameters.DataWidth) +} + +object InstructionsRet { + val mret = 0x30200073L.U(Parameters.DataWidth) + val ret = 0x00008067L.U(Parameters.DataWidth) +} + +object InstructionsEnv { + val ecall = 0x00000073L.U(Parameters.DataWidth) + val ebreak = 0x00100073L.U(Parameters.DataWidth) +} + +object ALUOp1Source { + val Register = 0.U(1.W) + val InstructionAddress = 1.U(1.W) +} + +object ALUOp2Source { + val Register = 0.U(1.W) + val Immediate = 1.U(1.W) +} + +object RegWriteSource { + val ALUResult = 0.U(2.W) + val Memory = 1.U(2.W) + val CSR = 2.U(2.W) + val NextInstructionAddress = 3.U(2.W) +} + +class InstructionDecode extends Module { + val io = IO(new Bundle { + val instruction = Input(UInt(Parameters.InstructionWidth)) + + val regs_reg1_read_address = Output(UInt(Parameters.PhysicalRegisterAddrWidth)) + val regs_reg2_read_address = Output(UInt(Parameters.PhysicalRegisterAddrWidth)) + val ex_immediate = Output(UInt(Parameters.DataWidth)) + val ex_aluop1_source = Output(Bool()) + val ex_aluop2_source = Output(Bool()) + val ex_memory_read_enable = Output(Bool()) + val ex_memory_write_enable = Output(Bool()) + val ex_reg_write_source = Output(UInt(2.W)) + val ex_reg_write_enable = Output(Bool()) + val ex_reg_write_address = Output(UInt(Parameters.PhysicalRegisterAddrWidth)) + val ex_csr_address = Output(UInt(Parameters.CSRRegisterAddrWidth)) + val ex_csr_write_enable = Output(Bool()) + }) + val opcode = io.instruction(6, 0) + val funct3 = io.instruction(14, 12) + val funct7 = io.instruction(31, 25) + val rd = io.instruction(11, 7) + val rs1 = io.instruction(19, 15) + val rs2 = io.instruction(24, 20) + + io.regs_reg1_read_address := Mux(opcode === Instructions.lui, 0.U(Parameters.PhysicalRegisterAddrWidth), rs1) + io.regs_reg2_read_address := rs2 + io.ex_immediate := MuxLookup( + opcode, + Cat(Fill(20, io.instruction(31)), io.instruction(31, 20)), + IndexedSeq( + InstructionTypes.I -> Cat(Fill(21, io.instruction(31)), io.instruction(30, 20)), + InstructionTypes.L -> Cat(Fill(21, io.instruction(31)), io.instruction(30, 20)), + Instructions.jalr -> Cat(Fill(21, io.instruction(31)), io.instruction(30, 20)), + InstructionTypes.S -> Cat(Fill(21, io.instruction(31)), io.instruction(30, 25), io.instruction(11, 7)), + InstructionTypes.B -> Cat(Fill(20, io.instruction(31)), io.instruction(7), io.instruction(30, 25), io.instruction(11, 8), 0.U(1.W)), + Instructions.lui -> Cat(io.instruction(31, 12), 0.U(12.W)), + Instructions.auipc -> Cat(io.instruction(31, 12), 0.U(12.W)), + Instructions.jal -> Cat(Fill(12, io.instruction(31)), io.instruction(19, 12), io.instruction(20), io.instruction(30, 21), 0.U(1.W)) + ) + ) + io.ex_aluop1_source := Mux( + opcode === Instructions.auipc || opcode === InstructionTypes.B || opcode === Instructions.jal, + ALUOp1Source.InstructionAddress, + ALUOp1Source.Register + ) + io.ex_aluop2_source := Mux( + opcode === InstructionTypes.RM, + ALUOp2Source.Register, + ALUOp2Source.Immediate + ) + io.ex_memory_read_enable := opcode === InstructionTypes.L + io.ex_memory_write_enable := opcode === InstructionTypes.S + io.ex_reg_write_source := MuxLookup( + opcode, + RegWriteSource.ALUResult, + IndexedSeq( + InstructionTypes.L -> RegWriteSource.Memory, + Instructions.csr -> RegWriteSource.CSR, + Instructions.jal -> RegWriteSource.NextInstructionAddress, + Instructions.jalr -> RegWriteSource.NextInstructionAddress + ) + ) + io.ex_reg_write_enable := (opcode === InstructionTypes.RM) || (opcode === InstructionTypes.I) || + (opcode === InstructionTypes.L) || (opcode === Instructions.auipc) || (opcode === Instructions.lui) || + (opcode === Instructions.jal) || (opcode === Instructions.jalr) || (opcode === Instructions.csr) + io.ex_reg_write_address := io.instruction(11, 7) + io.ex_csr_address := io.instruction(31, 20) + io.ex_csr_write_enable := (opcode === Instructions.csr) && ( + funct3 === InstructionsTypeCSR.csrrw || funct3 === InstructionsTypeCSR.csrrwi || + funct3 === InstructionsTypeCSR.csrrs || funct3 === InstructionsTypeCSR.csrrsi || + funct3 === InstructionsTypeCSR.csrrc || funct3 === InstructionsTypeCSR.csrrci + ) +} diff --git a/lab3/src/main/scala/riscv/core/fivestage_stall/InstructionFetch.scala b/lab3/src/main/scala/riscv/core/fivestage_stall/InstructionFetch.scala new file mode 100644 index 0000000..44bcab1 --- /dev/null +++ b/lab3/src/main/scala/riscv/core/fivestage_stall/InstructionFetch.scala @@ -0,0 +1,48 @@ +// 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.core.fivestage_stall + +import chisel3._ +import chisel3.util.MuxCase +import riscv.Parameters + +object ProgramCounter { + val EntryAddress = Parameters.EntryAddress +} + +class InstructionFetch extends Module { + val io = IO(new Bundle { + val stall_flag_ctrl = Input(Bool()) + val jump_flag_id = Input(Bool()) + val jump_address_id = Input(UInt(Parameters.AddrWidth)) + val rom_instruction = Input(UInt(Parameters.DataWidth)) + val instruction_valid = Input(Bool()) + + val instruction_address = Output(UInt(Parameters.AddrWidth)) + val id_instruction = Output(UInt(Parameters.InstructionWidth)) + }) + val pc = RegInit(ProgramCounter.EntryAddress) + + pc := MuxCase( + pc + 4.U, + IndexedSeq( + (io.jump_flag_id && !io.stall_flag_ctrl) -> io.jump_address_id, + (io.stall_flag_ctrl || !io.instruction_valid) -> pc + ) + ) + + io.instruction_address := pc + io.id_instruction := Mux(io.instruction_valid, io.rom_instruction, InstructionsNop.nop) +} diff --git a/lab3/src/main/scala/riscv/core/fivestage_stall/MEM2WB.scala b/lab3/src/main/scala/riscv/core/fivestage_stall/MEM2WB.scala new file mode 100644 index 0000000..bbaafe8 --- /dev/null +++ b/lab3/src/main/scala/riscv/core/fivestage_stall/MEM2WB.scala @@ -0,0 +1,83 @@ +// Copyright 2022 Canbin Huang +// +// 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.core.fivestage_stall + +import chisel3._ +import riscv.Parameters +import riscv.core.PipelineRegister + +class MEM2WB extends Module { + val io = IO(new Bundle() { + val instruction_address = Input(UInt(Parameters.AddrWidth)) + val alu_result = Input(UInt(Parameters.DataWidth)) + val regs_write_enable = Input(Bool()) + val regs_write_source = Input(UInt(2.W)) + val regs_write_address = Input(UInt(Parameters.AddrWidth)) + val memory_read_data = Input(UInt(Parameters.DataWidth)) + val csr_read_data = Input(UInt(Parameters.DataWidth)) + + val output_instruction_address = Output(UInt(Parameters.AddrWidth)) + val output_alu_result = Output(UInt(Parameters.DataWidth)) + val output_regs_write_enable = Output(Bool()) + val output_regs_write_source = Output(UInt(2.W)) + val output_regs_write_address = Output(UInt(Parameters.AddrWidth)) + val output_memory_read_data = Output(UInt(Parameters.DataWidth)) + val output_csr_read_data = Output(UInt(Parameters.DataWidth)) + }) + val stall = false.B + val flush = false.B + + val alu_result = Module(new PipelineRegister()) + alu_result.io.in := io.alu_result + alu_result.io.stall := stall + alu_result.io.flush := flush + io.output_alu_result := alu_result.io.out + + val memory_read_data = Module(new PipelineRegister()) + memory_read_data.io.in := io.memory_read_data + memory_read_data.io.stall := stall + memory_read_data.io.flush := flush + io.output_memory_read_data := memory_read_data.io.out + + val regs_write_enable = Module(new PipelineRegister(1)) + regs_write_enable.io.in := io.regs_write_enable + regs_write_enable.io.stall := stall + regs_write_enable.io.flush := flush + io.output_regs_write_enable := regs_write_enable.io.out + + val regs_write_source = Module(new PipelineRegister(2)) + regs_write_source.io.in := io.regs_write_source + regs_write_source.io.stall := stall + regs_write_source.io.flush := flush + io.output_regs_write_source := regs_write_source.io.out + + val regs_write_address = Module(new PipelineRegister(Parameters.PhysicalRegisterAddrBits)) + regs_write_address.io.in := io.regs_write_address + regs_write_address.io.stall := stall + regs_write_address.io.flush := flush + io.output_regs_write_address := regs_write_address.io.out + + val instruction_address = Module(new PipelineRegister(Parameters.InstructionBits)) + instruction_address.io.in := io.instruction_address + instruction_address.io.stall := stall + instruction_address.io.flush := flush + io.output_instruction_address := instruction_address.io.out + + val csr_read_data = Module(new PipelineRegister()) + csr_read_data.io.in := io.csr_read_data + csr_read_data.io.stall := stall + csr_read_data.io.flush := flush + io.output_csr_read_data := csr_read_data.io.out +} diff --git a/lab3/src/main/scala/riscv/core/fivestage_stall/MemoryAccess.scala b/lab3/src/main/scala/riscv/core/fivestage_stall/MemoryAccess.scala new file mode 100644 index 0000000..511476d --- /dev/null +++ b/lab3/src/main/scala/riscv/core/fivestage_stall/MemoryAccess.scala @@ -0,0 +1,106 @@ +// Copyright 2022 Canbin Huang +// +// 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.core.fivestage_stall + +import chisel3._ +import chisel3.util._ +import peripheral.RAMBundle +import riscv.Parameters + +class MemoryAccess extends Module { + val io = IO(new Bundle() { + val alu_result = Input(UInt(Parameters.DataWidth)) + val reg2_data = Input(UInt(Parameters.DataWidth)) + val memory_read_enable = Input(Bool()) + val memory_write_enable = Input(Bool()) + val funct3 = Input(UInt(3.W)) + val regs_write_source = Input(UInt(2.W)) + val csr_read_data = Input(UInt(Parameters.DataWidth)) + + val wb_memory_read_data = Output(UInt(Parameters.DataWidth)) + + val bundle = Flipped(new RAMBundle) + }) + val mem_address_index = io.alu_result(log2Up(Parameters.WordSize) - 1, 0).asUInt + + io.bundle.write_enable := io.memory_write_enable + io.bundle.write_data := 0.U + io.bundle.address := io.alu_result + io.bundle.write_strobe := VecInit(Seq.fill(Parameters.WordSize)(false.B)) + io.wb_memory_read_data := 0.U + + when(io.memory_read_enable) { + val data = io.bundle.read_data + io.wb_memory_read_data := MuxLookup( + io.funct3, + 0.U, + IndexedSeq( + InstructionsTypeL.lb -> MuxLookup( + mem_address_index, + Cat(Fill(24, data(31)), data(31, 24)), + IndexedSeq( + 0.U -> Cat(Fill(24, data(7)), data(7, 0)), + 1.U -> Cat(Fill(24, data(15)), data(15, 8)), + 2.U -> Cat(Fill(24, data(23)), data(23, 16)) + ) + ), + InstructionsTypeL.lbu -> MuxLookup( + mem_address_index, + Cat(Fill(24, 0.U), data(31, 24)), + IndexedSeq( + 0.U -> Cat(Fill(24, 0.U), data(7, 0)), + 1.U -> Cat(Fill(24, 0.U), data(15, 8)), + 2.U -> Cat(Fill(24, 0.U), data(23, 16)) + ) + ), + InstructionsTypeL.lh -> Mux( + mem_address_index === 0.U, + Cat(Fill(16, data(15)), data(15, 0)), + Cat(Fill(16, data(31)), data(31, 16)) + ), + InstructionsTypeL.lhu -> Mux( + mem_address_index === 0.U, + Cat(Fill(16, 0.U), data(15, 0)), + Cat(Fill(16, 0.U), data(31, 16)) + ), + InstructionsTypeL.lw -> data + ) + ) + }.elsewhen(io.memory_write_enable) { + io.bundle.write_data := io.reg2_data + io.bundle.write_strobe := VecInit(Seq.fill(Parameters.WordSize)(false.B)) + when(io.funct3 === InstructionsTypeS.sb) { + io.bundle.write_strobe(mem_address_index) := true.B + io.bundle.write_data := io.reg2_data(Parameters.ByteBits, 0) << (mem_address_index << log2Up(Parameters.ByteBits).U) + }.elsewhen(io.funct3 === InstructionsTypeS.sh) { + when(mem_address_index === 0.U) { + for (i <- 0 until Parameters.WordSize / 2) { + io.bundle.write_strobe(i) := true.B + } + io.bundle.write_data := io.reg2_data(Parameters.WordSize / 2 * Parameters.ByteBits, 0) + }.otherwise { + for (i <- Parameters.WordSize / 2 until Parameters.WordSize) { + io.bundle.write_strobe(i) := true.B + } + io.bundle.write_data := io.reg2_data(Parameters.WordSize / 2 * Parameters.ByteBits, 0) << (Parameters + .WordSize / 2 * Parameters.ByteBits) + } + }.elsewhen(io.funct3 === InstructionsTypeS.sw) { + for (i <- 0 until Parameters.WordSize) { + io.bundle.write_strobe(i) := true.B + } + } + } +} diff --git a/lab3/src/main/scala/riscv/core/fivestage_stall/WriteBack.scala b/lab3/src/main/scala/riscv/core/fivestage_stall/WriteBack.scala new file mode 100644 index 0000000..b6652d8 --- /dev/null +++ b/lab3/src/main/scala/riscv/core/fivestage_stall/WriteBack.scala @@ -0,0 +1,40 @@ +// Copyright 2022 Canbin Huang +// +// 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.core.fivestage_stall + +import chisel3._ +import chisel3.util._ +import riscv.Parameters + +class WriteBack extends Module { + val io = IO(new Bundle() { + val instruction_address = Input(UInt(Parameters.AddrWidth)) + val alu_result = Input(UInt(Parameters.DataWidth)) + val memory_read_data = Input(UInt(Parameters.DataWidth)) + val regs_write_source = Input(UInt(2.W)) + val csr_read_data = Input(UInt(Parameters.DataWidth)) + + val regs_write_data = Output(UInt(Parameters.DataWidth)) + }) + io.regs_write_data := MuxLookup( + io.regs_write_source, + io.alu_result, + IndexedSeq( + RegWriteSource.Memory -> io.memory_read_data, + RegWriteSource.CSR -> io.csr_read_data, + RegWriteSource.NextInstructionAddress -> (io.instruction_address + 4.U) + ) + ) +} diff --git a/lab3/src/main/scala/riscv/core/threestage/CLINT.scala b/lab3/src/main/scala/riscv/core/threestage/CLINT.scala new file mode 100644 index 0000000..df86fa4 --- /dev/null +++ b/lab3/src/main/scala/riscv/core/threestage/CLINT.scala @@ -0,0 +1,88 @@ +// 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.core.threestage + +import chisel3._ +import chisel3.util.MuxLookup +import riscv.Parameters + +object InterruptStatus { + val None = 0x0.U(8.W) + val Timer0 = 0x1.U(8.W) + val Ret = 0xFF.U(8.W) +} + +class CSRDirectAccessBundle extends Bundle { + val mstatus = Input(UInt(Parameters.DataWidth)) + val mepc = Input(UInt(Parameters.DataWidth)) + val mcause = Input(UInt(Parameters.DataWidth)) + val mtvec = Input(UInt(Parameters.DataWidth)) + + val mstatus_write_data = Output(UInt(Parameters.DataWidth)) + val mepc_write_data = Output(UInt(Parameters.DataWidth)) + val mcause_write_data = Output(UInt(Parameters.DataWidth)) + + val direct_write_enable = Output(Bool()) +} + +// Core Local Interrupt Controller +class CLINT extends Module { + val io = IO(new Bundle { + val interrupt_flag = Input(UInt(Parameters.InterruptFlagWidth)) + + val instruction_ex = Input(UInt(Parameters.InstructionWidth)) + val instruction_address_if = Input(UInt(Parameters.AddrWidth)) + val instruction_address_id = Input(UInt(Parameters.AddrWidth)) + + val jump_flag = Input(Bool()) + val jump_address = Input(UInt(Parameters.AddrWidth)) + + val ex_interrupt_handler_address = Output(UInt(Parameters.AddrWidth)) + val ex_interrupt_assert = Output(Bool()) + + val csr_bundle = new CSRDirectAccessBundle + }) + val interrupt_enable = io.csr_bundle.mstatus(3) + val jumpping = RegNext(io.jump_flag || io.ex_interrupt_assert) + val instruction_address = Mux( + io.jump_flag, + io.jump_address, + Mux(jumpping, io.instruction_address_if, io.instruction_address_id) + ) + val mstatus_disable_interrupt = io.csr_bundle.mstatus(31, 4) ## 0.U(1.W) ## io.csr_bundle.mstatus(2, 0) + val mstatus_recover_interrupt = io.csr_bundle.mstatus(31, 4) ## io.csr_bundle.mstatus(7) ## io.csr_bundle.mstatus(2, 0) + val exception = io.instruction_ex === InstructionsEnv.ecall || io.instruction_ex === InstructionsEnv.ebreak + val interrupt = io.interrupt_flag =/= InterruptStatus.None && interrupt_enable + val mret = io.instruction_ex === InstructionsRet.mret + val interrupt_assert = exception || interrupt || mret + + io.csr_bundle.mstatus_write_data := Mux(mret, mstatus_recover_interrupt, mstatus_disable_interrupt) + io.csr_bundle.mepc_write_data := instruction_address + io.csr_bundle.mcause_write_data := Mux( + exception, + MuxLookup( + io.instruction_ex, + 10.U, + IndexedSeq( + InstructionsEnv.ecall -> 11.U, + InstructionsEnv.ebreak -> 3.U, + ) + ), + Mux(io.interrupt_flag(0), 0x80000007L.U, 0x8000000BL.U) + ) + io.csr_bundle.direct_write_enable := interrupt_assert + io.ex_interrupt_assert := interrupt_assert + io.ex_interrupt_handler_address := Mux(mret, io.csr_bundle.mepc, io.csr_bundle.mtvec) +} diff --git a/lab3/src/main/scala/riscv/core/threestage/CPU.scala b/lab3/src/main/scala/riscv/core/threestage/CPU.scala new file mode 100644 index 0000000..c0753e8 --- /dev/null +++ b/lab3/src/main/scala/riscv/core/threestage/CPU.scala @@ -0,0 +1,104 @@ +// 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.core.threestage + +import chisel3._ +import riscv.Parameters +import riscv.core.{CPUBundle, CSR, RegisterFile} + +class CPU extends Module { + val io = IO(new CPUBundle) + + val ctrl = Module(new Control) + val regs = Module(new RegisterFile) + val inst_fetch = Module(new InstructionFetch) + val if2id = Module(new IF2ID) + val id = Module(new InstructionDecode) + val id2ex = Module(new ID2EX) + val ex = Module(new Execute) + val clint = Module(new CLINT) + val csr_regs = Module(new CSR) + + // Lab3(Flush) + if2id.io.flush := false.B + id2ex.io.flush := false.B + // Lab3(Flush) End + + regs.io.write_enable := id2ex.io.output_regs_write_enable + regs.io.write_address := id2ex.io.output_regs_write_address + regs.io.write_data := ex.io.regs_write_data + regs.io.read_address1 := id.io.regs_reg1_read_address + regs.io.read_address2 := id.io.regs_reg2_read_address + regs.io.debug_read_address := io.debug_read_address + io.debug_read_data := regs.io.debug_read_data + + io.instruction_address := inst_fetch.io.instruction_address + inst_fetch.io.jump_flag_ex := ex.io.if_jump_flag + inst_fetch.io.jump_address_ex := ex.io.if_jump_address + inst_fetch.io.rom_instruction := io.instruction + inst_fetch.io.instruction_valid := io.instruction_valid + + if2id.io.instruction := inst_fetch.io.id_instruction + if2id.io.instruction_address := inst_fetch.io.instruction_address + if2id.io.interrupt_flag := io.interrupt_flag + + id.io.instruction := if2id.io.output_instruction + + id2ex.io.instruction := if2id.io.output_instruction + id2ex.io.instruction_address := if2id.io.output_instruction_address + id2ex.io.reg1_data := regs.io.read_data1 + id2ex.io.reg2_data := regs.io.read_data2 + id2ex.io.regs_write_enable := id.io.ex_reg_write_enable + id2ex.io.regs_write_address := id.io.ex_reg_write_address + id2ex.io.regs_write_source := id.io.ex_reg_write_source + id2ex.io.immediate := id.io.ex_immediate + id2ex.io.aluop1_source := id.io.ex_aluop1_source + id2ex.io.aluop2_source := id.io.ex_aluop2_source + id2ex.io.csr_write_enable := id.io.ex_csr_write_enable + id2ex.io.csr_address := id.io.ex_csr_address + id2ex.io.memory_read_enable := id.io.ex_memory_read_enable + id2ex.io.memory_write_enable := id.io.ex_memory_write_enable + id2ex.io.csr_read_data := csr_regs.io.id_reg_read_data + + ex.io.instruction := id2ex.io.output_instruction + ex.io.instruction_address := id2ex.io.output_instruction_address + ex.io.reg1_data := id2ex.io.output_reg1_data + ex.io.reg2_data := id2ex.io.output_reg2_data + ex.io.csr_read_data := id2ex.io.output_csr_read_data + ex.io.immediate_id := id2ex.io.output_immediate + ex.io.aluop1_source_id := id2ex.io.output_aluop1_source + ex.io.aluop2_source_id := id2ex.io.output_aluop2_source + ex.io.memory_read_enable_id := id2ex.io.output_memory_read_enable + ex.io.memory_write_enable_id := id2ex.io.output_memory_write_enable + ex.io.regs_write_source_id := id2ex.io.output_regs_write_source + ex.io.interrupt_assert_clint := clint.io.ex_interrupt_assert + ex.io.interrupt_handler_address_clint := clint.io.ex_interrupt_handler_address + io.device_select := ex.io.memory_bundle.address(Parameters.AddrBits - 1, Parameters.AddrBits - Parameters.SlaveDeviceCountBits) + io.memory_bundle <> ex.io.memory_bundle + io.memory_bundle.address := 0.U(Parameters.SlaveDeviceCountBits.W) ## ex.io.memory_bundle.address(Parameters.AddrBits - 1 - Parameters.SlaveDeviceCountBits, 0) + + clint.io.instruction_address_if := inst_fetch.io.instruction_address + clint.io.instruction_address_id := if2id.io.output_instruction_address + clint.io.instruction_ex := id2ex.io.output_instruction + clint.io.jump_flag := ex.io.clint_jump_flag + clint.io.jump_address := ex.io.clint_jump_address + clint.io.interrupt_flag := if2id.io.output_interrupt_flag + clint.io.csr_bundle <> csr_regs.io.clint_access_bundle + + csr_regs.io.reg_read_address_id := id.io.ex_csr_address + csr_regs.io.reg_write_enable_ex := id2ex.io.output_csr_write_enable + csr_regs.io.reg_write_address_ex := id2ex.io.output_csr_address + csr_regs.io.reg_write_data_ex := ex.io.csr_write_data +} diff --git a/lab3/src/main/scala/riscv/core/threestage/Control.scala b/lab3/src/main/scala/riscv/core/threestage/Control.scala new file mode 100644 index 0000000..f14cf75 --- /dev/null +++ b/lab3/src/main/scala/riscv/core/threestage/Control.scala @@ -0,0 +1,21 @@ +// 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.core.threestage + +import chisel3._ + +class Control extends Module { + // Lab3(Flush) +} diff --git a/lab3/src/main/scala/riscv/core/threestage/Execute.scala b/lab3/src/main/scala/riscv/core/threestage/Execute.scala new file mode 100644 index 0000000..95f9f6c --- /dev/null +++ b/lab3/src/main/scala/riscv/core/threestage/Execute.scala @@ -0,0 +1,191 @@ +// 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.core.threestage + +import chisel3._ +import chisel3.util._ +import peripheral.RAMBundle +import riscv.Parameters +import riscv.core.{ALU, ALUControl} + + +class Execute extends Module { + val io = IO(new Bundle { + val instruction = Input(UInt(Parameters.InstructionWidth)) + val instruction_address = Input(UInt(Parameters.AddrWidth)) + val reg1_data = Input(UInt(Parameters.DataWidth)) + val reg2_data = Input(UInt(Parameters.DataWidth)) + val csr_read_data = Input(UInt(Parameters.DataWidth)) + val immediate_id = Input(UInt(Parameters.DataWidth)) + val aluop1_source_id = Input(UInt(1.W)) + val aluop2_source_id = Input(UInt(1.W)) + val memory_read_enable_id = Input(Bool()) + val memory_write_enable_id = Input(Bool()) + val regs_write_source_id = Input(UInt(2.W)) + val interrupt_assert_clint = Input(Bool()) + val interrupt_handler_address_clint = Input(UInt(Parameters.AddrWidth)) + + val memory_bundle = Flipped(new RAMBundle) + + val csr_write_data = Output(UInt(Parameters.DataWidth)) + val regs_write_data = Output(UInt(Parameters.DataWidth)) + val if_jump_flag = Output(Bool()) + val if_jump_address = Output(UInt(Parameters.AddrWidth)) + val clint_jump_flag = Output(Bool()) + val clint_jump_address = Output(UInt(Parameters.AddrWidth)) + }) + + val opcode = io.instruction(6, 0) + val funct3 = io.instruction(14, 12) + val funct7 = io.instruction(31, 25) + val uimm = io.instruction(19, 15) + + // ALU compute + val alu = Module(new ALU) + val alu_ctrl = Module(new ALUControl) + + alu_ctrl.io.opcode := opcode + alu_ctrl.io.funct3 := funct3 + alu_ctrl.io.funct7 := funct7 + alu.io.func := alu_ctrl.io.alu_funct + alu.io.op1 := Mux( + io.aluop1_source_id === ALUOp1Source.InstructionAddress, + io.instruction_address, + io.reg1_data + ) + alu.io.op2 := Mux( + io.aluop2_source_id === ALUOp2Source.Immediate, + io.immediate_id, + io.reg2_data + ) + io.csr_write_data := MuxLookup( + funct3, + 0.U, + IndexedSeq( + InstructionsTypeCSR.csrrw -> io.reg1_data, + InstructionsTypeCSR.csrrc -> (io.csr_read_data & (~io.reg1_data).asUInt), + InstructionsTypeCSR.csrrs -> (io.csr_read_data | io.reg1_data), + InstructionsTypeCSR.csrrwi -> (0.U(27.W) ## uimm), + InstructionsTypeCSR.csrrci -> (io.csr_read_data & (~(0.U(27.W) ## uimm)).asUInt), + InstructionsTypeCSR.csrrsi -> (io.csr_read_data | 0.U(27.W) ## uimm), + ) + ) + + // memory access + val mem_address_index = alu.io.result(log2Up(Parameters.WordSize) - 1, 0).asUInt + val mem_read_data = Wire(UInt(Parameters.DataWidth)) + io.memory_bundle.write_enable := io.memory_write_enable_id + io.memory_bundle.write_data := 0.U + io.memory_bundle.address := alu.io.result + io.memory_bundle.write_strobe := VecInit(Seq.fill(Parameters.WordSize)(false.B)) + mem_read_data := 0.U + + when(io.memory_read_enable_id) { + val data = io.memory_bundle.read_data + mem_read_data := MuxLookup( + funct3, + 0.U, + IndexedSeq( + InstructionsTypeL.lb -> MuxLookup( + mem_address_index, + Cat(Fill(24, data(31)), data(31, 24)), + IndexedSeq( + 0.U -> Cat(Fill(24, data(7)), data(7, 0)), + 1.U -> Cat(Fill(24, data(15)), data(15, 8)), + 2.U -> Cat(Fill(24, data(23)), data(23, 16)) + ) + ), + InstructionsTypeL.lbu -> MuxLookup( + mem_address_index, + Cat(Fill(24, 0.U), data(31, 24)), + IndexedSeq( + 0.U -> Cat(Fill(24, 0.U), data(7, 0)), + 1.U -> Cat(Fill(24, 0.U), data(15, 8)), + 2.U -> Cat(Fill(24, 0.U), data(23, 16)) + ) + ), + InstructionsTypeL.lh -> Mux( + mem_address_index === 0.U, + Cat(Fill(16, data(15)), data(15, 0)), + Cat(Fill(16, data(31)), data(31, 16)) + ), + InstructionsTypeL.lhu -> Mux( + mem_address_index === 0.U, + Cat(Fill(16, 0.U), data(15, 0)), + Cat(Fill(16, 0.U), data(31, 16)) + ), + InstructionsTypeL.lw -> data + ) + ) + }.elsewhen(io.memory_write_enable_id) { + io.memory_bundle.write_data := io.reg2_data + io.memory_bundle.write_strobe := VecInit(Seq.fill(Parameters.WordSize)(false.B)) + when(funct3 === InstructionsTypeS.sb) { + io.memory_bundle.write_strobe(mem_address_index) := true.B + io.memory_bundle.write_data := io.reg2_data(Parameters.ByteBits, 0) << (mem_address_index << log2Up(Parameters.ByteBits).U) + }.elsewhen(funct3 === InstructionsTypeS.sh) { + when(mem_address_index === 0.U) { + for (i <- 0 until Parameters.WordSize / 2) { + io.memory_bundle.write_strobe(i) := true.B + } + io.memory_bundle.write_data := io.reg2_data(Parameters.WordSize / 2 * Parameters.ByteBits, 0) + }.otherwise { + for (i <- Parameters.WordSize / 2 until Parameters.WordSize) { + io.memory_bundle.write_strobe(i) := true.B + } + io.memory_bundle.write_data := io.reg2_data(Parameters.WordSize / 2 * Parameters.ByteBits, 0) << (Parameters + .WordSize / 2 * Parameters.ByteBits) + } + }.elsewhen(funct3 === InstructionsTypeS.sw) { + for (i <- 0 until Parameters.WordSize) { + io.memory_bundle.write_strobe(i) := true.B + } + } + } + + // write back + io.regs_write_data := MuxLookup( + io.regs_write_source_id, + alu.io.result, + IndexedSeq( + RegWriteSource.Memory -> mem_read_data, + RegWriteSource.CSR -> io.csr_read_data, + RegWriteSource.NextInstructionAddress -> (io.instruction_address + 4.U) + ) + ) + + // jump and interrupt + val instruction_jump_flag = (opcode === Instructions.jal) || + (opcode === Instructions.jalr) || + (opcode === InstructionTypes.B) && MuxLookup( + funct3, + false.B, + IndexedSeq( + InstructionsTypeB.beq -> (io.reg1_data === io.reg2_data), + InstructionsTypeB.bne -> (io.reg1_data =/= io.reg2_data), + InstructionsTypeB.blt -> (io.reg1_data.asSInt < io.reg2_data.asSInt), + InstructionsTypeB.bge -> (io.reg1_data.asSInt >= io.reg2_data.asSInt), + InstructionsTypeB.bltu -> (io.reg1_data.asUInt < io.reg2_data.asUInt), + InstructionsTypeB.bgeu -> (io.reg1_data.asUInt >= io.reg2_data.asUInt) + ) + ) + io.clint_jump_flag := instruction_jump_flag + io.clint_jump_address := alu.io.result + io.if_jump_flag := io.interrupt_assert_clint || instruction_jump_flag + io.if_jump_address := Mux(io.interrupt_assert_clint, + io.interrupt_handler_address_clint, + alu.io.result + ) +} diff --git a/lab3/src/main/scala/riscv/core/threestage/ID2EX.scala b/lab3/src/main/scala/riscv/core/threestage/ID2EX.scala new file mode 100644 index 0000000..e3f7cdb --- /dev/null +++ b/lab3/src/main/scala/riscv/core/threestage/ID2EX.scala @@ -0,0 +1,148 @@ +// 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.core.threestage + +import chisel3._ +import riscv.Parameters +import riscv.core.PipelineRegister + +class ID2EX extends Module { + val io = IO(new Bundle { + val flush = Input(Bool()) + val instruction = Input(UInt(Parameters.InstructionWidth)) + val instruction_address = Input(UInt(Parameters.AddrWidth)) + val regs_write_enable = Input(Bool()) + val regs_write_address = Input(UInt(Parameters.PhysicalRegisterAddrWidth)) + val regs_write_source = Input(UInt(2.W)) + val reg1_data = Input(UInt(Parameters.DataWidth)) + val reg2_data = Input(UInt(Parameters.DataWidth)) + val immediate = Input(UInt(Parameters.DataWidth)) + val aluop1_source = Input(UInt(1.W)) + val aluop2_source = Input(UInt(1.W)) + val csr_write_enable = Input(Bool()) + val csr_address = Input(UInt(Parameters.CSRRegisterAddrWidth)) + val memory_read_enable = Input(Bool()) + val memory_write_enable = Input(Bool()) + val csr_read_data = Input(UInt(Parameters.DataWidth)) + + val output_instruction = Output(UInt(Parameters.DataWidth)) + val output_instruction_address = Output(UInt(Parameters.AddrWidth)) + val output_regs_write_enable = Output(Bool()) + val output_regs_write_address = Output(UInt(Parameters.PhysicalRegisterAddrWidth)) + val output_regs_write_source = Output(UInt(2.W)) + val output_reg1_data = Output(UInt(Parameters.DataWidth)) + val output_reg2_data = Output(UInt(Parameters.DataWidth)) + val output_immediate = Output(UInt(Parameters.DataWidth)) + val output_aluop1_source = Output(UInt(1.W)) + val output_aluop2_source = Output(UInt(1.W)) + val output_csr_write_enable = Output(Bool()) + val output_csr_address = Output(UInt(Parameters.CSRRegisterAddrWidth)) + val output_memory_read_enable = Output(Bool()) + val output_memory_write_enable = Output(Bool()) + val output_csr_read_data = Output(UInt(Parameters.DataWidth)) + }) + + val stall = false.B + + val instruction = Module(new PipelineRegister(defaultValue = InstructionsNop.nop)) + instruction.io.in := io.instruction + instruction.io.stall := stall + instruction.io.flush := io.flush + io.output_instruction := instruction.io.out + + val instruction_address = Module(new PipelineRegister(defaultValue = ProgramCounter.EntryAddress)) + instruction_address.io.in := io.instruction_address + instruction_address.io.stall := stall + instruction_address.io.flush := io.flush + io.output_instruction_address := instruction_address.io.out + + val regs_write_enable = Module(new PipelineRegister(1)) + regs_write_enable.io.in := io.regs_write_enable + regs_write_enable.io.stall := stall + regs_write_enable.io.flush := io.flush + io.output_regs_write_enable := regs_write_enable.io.out + + val regs_write_address = Module(new PipelineRegister(Parameters.PhysicalRegisterAddrBits)) + regs_write_address.io.in := io.regs_write_address + regs_write_address.io.stall := stall + regs_write_address.io.flush := io.flush + io.output_regs_write_address := regs_write_address.io.out + + val regs_write_source = Module(new PipelineRegister(2)) + regs_write_source.io.in := io.regs_write_source + regs_write_source.io.stall := stall + regs_write_source.io.flush := io.flush + io.output_regs_write_source := regs_write_source.io.out + + val reg1_data = Module(new PipelineRegister()) + reg1_data.io.in := io.reg1_data + reg1_data.io.stall := stall + reg1_data.io.flush := io.flush + io.output_reg1_data := reg1_data.io.out + + val reg2_data = Module(new PipelineRegister()) + reg2_data.io.in := io.reg2_data + reg2_data.io.stall := stall + reg2_data.io.flush := io.flush + io.output_reg2_data := reg2_data.io.out + + val immediate = Module(new PipelineRegister()) + immediate.io.in := io.immediate + immediate.io.stall := stall + immediate.io.flush := io.flush + io.output_immediate := immediate.io.out + + val aluop1_source = Module(new PipelineRegister(1)) + aluop1_source.io.in := io.aluop1_source + aluop1_source.io.stall := stall + aluop1_source.io.flush := io.flush + io.output_aluop1_source := aluop1_source.io.out + + val aluop2_source = Module(new PipelineRegister(1)) + aluop2_source.io.in := io.aluop2_source + aluop2_source.io.stall := stall + aluop2_source.io.flush := io.flush + io.output_aluop2_source := aluop2_source.io.out + + val csr_write_enable = Module(new PipelineRegister(1)) + csr_write_enable.io.in := io.csr_write_enable + csr_write_enable.io.stall := stall + csr_write_enable.io.flush := io.flush + io.output_csr_write_enable := csr_write_enable.io.out + + val csr_address = Module(new PipelineRegister(Parameters.CSRRegisterAddrBits)) + csr_address.io.in := io.csr_address + csr_address.io.stall := stall + csr_address.io.flush := io.flush + io.output_csr_address := csr_address.io.out + + val memory_read_enable = Module(new PipelineRegister(1)) + memory_read_enable.io.in := io.memory_read_enable + memory_read_enable.io.stall := stall + memory_read_enable.io.flush := io.flush + io.output_memory_read_enable := memory_read_enable.io.out + + val memory_write_enable = Module(new PipelineRegister(1)) + memory_write_enable.io.in := io.memory_write_enable + memory_write_enable.io.stall := stall + memory_write_enable.io.flush := io.flush + io.output_memory_write_enable := memory_write_enable.io.out + + val csr_read_data = Module(new PipelineRegister()) + csr_read_data.io.in := io.csr_read_data + csr_read_data.io.stall := stall + csr_read_data.io.flush := io.flush + io.output_csr_read_data := csr_read_data.io.out +} diff --git a/lab3/src/main/scala/riscv/core/threestage/IF2ID.scala b/lab3/src/main/scala/riscv/core/threestage/IF2ID.scala new file mode 100644 index 0000000..4054e34 --- /dev/null +++ b/lab3/src/main/scala/riscv/core/threestage/IF2ID.scala @@ -0,0 +1,52 @@ +// 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.core.threestage + +import chisel3._ +import riscv.Parameters +import riscv.core.PipelineRegister + +class IF2ID extends Module { + val io = IO(new Bundle { + val flush = Input(Bool()) + val instruction = Input(UInt(Parameters.InstructionWidth)) + val instruction_address = Input(UInt(Parameters.AddrWidth)) + val interrupt_flag = Input(UInt(Parameters.InterruptFlagWidth)) + + val output_instruction = Output(UInt(Parameters.DataWidth)) + val output_instruction_address = Output(UInt(Parameters.AddrWidth)) + val output_interrupt_flag = Output(UInt(Parameters.InterruptFlagWidth)) + }) + + val stall = false.B + + val instruction = Module(new PipelineRegister(defaultValue = InstructionsNop.nop)) + instruction.io.in := io.instruction + instruction.io.stall := stall + instruction.io.flush := io.flush + io.output_instruction := instruction.io.out + + val instruction_address = Module(new PipelineRegister(defaultValue = ProgramCounter.EntryAddress)) + instruction_address.io.in := io.instruction_address + instruction_address.io.stall := stall + instruction_address.io.flush := io.flush + io.output_instruction_address := instruction_address.io.out + + val interrupt_flag = Module(new PipelineRegister(Parameters.InterruptFlagBits)) + interrupt_flag.io.in := io.interrupt_flag + interrupt_flag.io.stall := stall + interrupt_flag.io.flush := io.flush + io.output_interrupt_flag := interrupt_flag.io.out +} diff --git a/lab3/src/main/scala/riscv/core/threestage/InstructionDecode.scala b/lab3/src/main/scala/riscv/core/threestage/InstructionDecode.scala new file mode 100644 index 0000000..85db088 --- /dev/null +++ b/lab3/src/main/scala/riscv/core/threestage/InstructionDecode.scala @@ -0,0 +1,207 @@ +// 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.core.threestage + +import chisel3._ +import chisel3.util._ +import riscv.Parameters + +object InstructionTypes { + val L = "b0000011".U + val I = "b0010011".U + val S = "b0100011".U + val RM = "b0110011".U + val B = "b1100011".U +} + +object Instructions { + val lui = "b0110111".U + val nop = "b0000001".U + val jal = "b1101111".U + val jalr = "b1100111".U + val auipc = "b0010111".U + val csr = "b1110011".U + val fence = "b0001111".U +} + +object InstructionsTypeL { + val lb = "b000".U + val lh = "b001".U + val lw = "b010".U + val lbu = "b100".U + val lhu = "b101".U +} + +object InstructionsTypeI { + val addi = 0.U + val slli = 1.U + val slti = 2.U + val sltiu = 3.U + val xori = 4.U + val sri = 5.U + val ori = 6.U + val andi = 7.U +} + +object InstructionsTypeS { + val sb = "b000".U + val sh = "b001".U + val sw = "b010".U +} + +object InstructionsTypeR { + val add_sub = 0.U + val sll = 1.U + val slt = 2.U + val sltu = 3.U + val xor = 4.U + val sr = 5.U + val or = 6.U + val and = 7.U +} + +object InstructionsTypeM { + val mul = 0.U + val mulh = 1.U + val mulhsu = 2.U + val mulhum = 3.U + val div = 4.U + val divu = 5.U + val rem = 6.U + val remu = 7.U +} + +object InstructionsTypeB { + val beq = "b000".U + val bne = "b001".U + val blt = "b100".U + val bge = "b101".U + val bltu = "b110".U + val bgeu = "b111".U +} + +object InstructionsTypeCSR { + val csrrw = "b001".U + val csrrs = "b010".U + val csrrc = "b011".U + val csrrwi = "b101".U + val csrrsi = "b110".U + val csrrci = "b111".U +} + +object InstructionsNop { + val nop = 0x00000013L.U(Parameters.DataWidth) +} + +object InstructionsRet { + val mret = 0x30200073L.U(Parameters.DataWidth) + val ret = 0x00008067L.U(Parameters.DataWidth) +} + +object InstructionsEnv { + val ecall = 0x00000073L.U(Parameters.DataWidth) + val ebreak = 0x00100073L.U(Parameters.DataWidth) +} + +object ALUOp1Source { + val Register = 0.U(1.W) + val InstructionAddress = 1.U(1.W) +} + +object ALUOp2Source { + val Register = 0.U(1.W) + val Immediate = 1.U(1.W) +} + +object RegWriteSource { + val ALUResult = 0.U(2.W) + val Memory = 1.U(2.W) + val CSR = 2.U(2.W) + val NextInstructionAddress = 3.U(2.W) +} + +class InstructionDecode extends Module { + val io = IO(new Bundle { + val instruction = Input(UInt(Parameters.InstructionWidth)) + + val regs_reg1_read_address = Output(UInt(Parameters.PhysicalRegisterAddrWidth)) + val regs_reg2_read_address = Output(UInt(Parameters.PhysicalRegisterAddrWidth)) + val ex_immediate = Output(UInt(Parameters.DataWidth)) + val ex_aluop1_source = Output(Bool()) + val ex_aluop2_source = Output(Bool()) + val ex_memory_read_enable = Output(Bool()) + val ex_memory_write_enable = Output(Bool()) + val ex_reg_write_source = Output(UInt(2.W)) + val ex_reg_write_enable = Output(Bool()) + val ex_reg_write_address = Output(UInt(Parameters.PhysicalRegisterAddrWidth)) + val ex_csr_address = Output(UInt(Parameters.CSRRegisterAddrWidth)) + val ex_csr_write_enable = Output(Bool()) + }) + val opcode = io.instruction(6, 0) + val funct3 = io.instruction(14, 12) + val funct7 = io.instruction(31, 25) + val rd = io.instruction(11, 7) + val rs1 = io.instruction(19, 15) + val rs2 = io.instruction(24, 20) + + io.regs_reg1_read_address := Mux(opcode === Instructions.lui, 0.U(Parameters.PhysicalRegisterAddrWidth), rs1) + io.regs_reg2_read_address := rs2 + io.ex_immediate := MuxLookup( + opcode, + Cat(Fill(20, io.instruction(31)), io.instruction(31, 20)), + IndexedSeq( + InstructionTypes.I -> Cat(Fill(21, io.instruction(31)), io.instruction(30, 20)), + InstructionTypes.L -> Cat(Fill(21, io.instruction(31)), io.instruction(30, 20)), + Instructions.jalr -> Cat(Fill(21, io.instruction(31)), io.instruction(30, 20)), + InstructionTypes.S -> Cat(Fill(21, io.instruction(31)), io.instruction(30, 25), io.instruction(11, 7)), + InstructionTypes.B -> Cat(Fill(20, io.instruction(31)), io.instruction(7), io.instruction(30, 25), io.instruction(11, 8), 0.U(1.W)), + Instructions.lui -> Cat(io.instruction(31, 12), 0.U(12.W)), + Instructions.auipc -> Cat(io.instruction(31, 12), 0.U(12.W)), + Instructions.jal -> Cat(Fill(12, io.instruction(31)), io.instruction(19, 12), io.instruction(20), io.instruction(30, 21), 0.U(1.W)) + ) + ) + io.ex_aluop1_source := Mux( + opcode === Instructions.auipc || opcode === InstructionTypes.B || opcode === Instructions.jal, + ALUOp1Source.InstructionAddress, + ALUOp1Source.Register + ) + io.ex_aluop2_source := Mux( + opcode === InstructionTypes.RM, + ALUOp2Source.Register, + ALUOp2Source.Immediate + ) + io.ex_memory_read_enable := opcode === InstructionTypes.L + io.ex_memory_write_enable := opcode === InstructionTypes.S + io.ex_reg_write_source := MuxLookup( + opcode, + RegWriteSource.ALUResult, + IndexedSeq( + InstructionTypes.L -> RegWriteSource.Memory, + Instructions.csr -> RegWriteSource.CSR, + Instructions.jal -> RegWriteSource.NextInstructionAddress, + Instructions.jalr -> RegWriteSource.NextInstructionAddress + ) + ) + io.ex_reg_write_enable := (opcode === InstructionTypes.RM) || (opcode === InstructionTypes.I) || + (opcode === InstructionTypes.L) || (opcode === Instructions.auipc) || (opcode === Instructions.lui) || + (opcode === Instructions.jal) || (opcode === Instructions.jalr) || (opcode === Instructions.csr) + io.ex_reg_write_address := rd + io.ex_csr_address := io.instruction(31, 20) + io.ex_csr_write_enable := (opcode === Instructions.csr) && ( + funct3 === InstructionsTypeCSR.csrrw || funct3 === InstructionsTypeCSR.csrrwi || + funct3 === InstructionsTypeCSR.csrrs || funct3 === InstructionsTypeCSR.csrrsi || + funct3 === InstructionsTypeCSR.csrrc || funct3 === InstructionsTypeCSR.csrrci + ) +} diff --git a/lab3/src/main/scala/riscv/core/threestage/InstructionFetch.scala b/lab3/src/main/scala/riscv/core/threestage/InstructionFetch.scala new file mode 100644 index 0000000..8b30cb0 --- /dev/null +++ b/lab3/src/main/scala/riscv/core/threestage/InstructionFetch.scala @@ -0,0 +1,47 @@ +// 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.core.threestage + +import chisel3._ +import chisel3.util.MuxCase +import riscv.Parameters + +object ProgramCounter { + val EntryAddress = Parameters.EntryAddress +} + +class InstructionFetch extends Module { + val io = IO(new Bundle { + val jump_flag_ex = Input(Bool()) + val jump_address_ex = Input(UInt(Parameters.AddrWidth)) + val rom_instruction = Input(UInt(Parameters.DataWidth)) + val instruction_valid = Input(Bool()) + + val instruction_address = Output(UInt(Parameters.AddrWidth)) + val id_instruction = Output(UInt(Parameters.InstructionWidth)) + }) + val pc = RegInit(ProgramCounter.EntryAddress) + + pc := MuxCase( + pc, + IndexedSeq( + io.jump_flag_ex -> io.jump_address_ex, + io.instruction_valid -> (pc + 4.U) + ) + ) + + io.instruction_address := pc + io.id_instruction := Mux(io.instruction_valid, io.rom_instruction, InstructionsNop.nop) +} diff --git a/lab3/src/test/scala/riscv/FiveStageCPUFinalTest.scala b/lab3/src/test/scala/riscv/FiveStageCPUFinalTest.scala new file mode 100644 index 0000000..78ff929 --- /dev/null +++ b/lab3/src/test/scala/riscv/FiveStageCPUFinalTest.scala @@ -0,0 +1,73 @@ +// 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 chisel3._ +import chiseltest._ +import org.scalatest.flatspec.AnyFlatSpec + + +class FiveStageCPUFinalTest extends AnyFlatSpec with ChiselScalatestTester { + behavior of "Five-stage Pipelined CPU with Reduced Branch Delay" + it should "calculate recursively fibonacci(10)" in { + test(new TestTopModule("fibonacci.asmbin", ImplementationType.FiveStageFinal)).withAnnotations(TestAnnotations.annos) { c => + 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) + } + } + it should "quicksort 10 numbers" in { + test(new TestTopModule("quicksort.asmbin", ImplementationType.FiveStageFinal)).withAnnotations(TestAnnotations.annos) { c => + 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) + } + } + } + it should "store and load single byte" in { + test(new TestTopModule("sb.asmbin", ImplementationType.FiveStageFinal)).withAnnotations(TestAnnotations.annos) { c => + c.clock.step(1000) + 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) + } + } + it should "solve data and control hazards" in { + test(new TestTopModule("hazard.asmbin", ImplementationType.FiveStageFinal)).withAnnotations(TestAnnotations.annos) { c => + c.clock.step(1000) + c.io.regs_debug_read_address.poke(1.U) + c.io.regs_debug_read_data.expect(26.U) + c.io.mem_debug_read_address.poke(4.U) + c.clock.step() + c.io.mem_debug_read_data.expect(1.U) + c.io.mem_debug_read_address.poke(8.U) + c.clock.step() + c.io.mem_debug_read_data.expect(3.U) + } + } +} diff --git a/lab3/src/test/scala/riscv/FiveStageCPUForwardTest.scala b/lab3/src/test/scala/riscv/FiveStageCPUForwardTest.scala new file mode 100644 index 0000000..e6530ef --- /dev/null +++ b/lab3/src/test/scala/riscv/FiveStageCPUForwardTest.scala @@ -0,0 +1,73 @@ +// 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 chisel3._ +import chiseltest._ +import org.scalatest.flatspec.AnyFlatSpec + + +class FiveStageCPUForwardTest extends AnyFlatSpec with ChiselScalatestTester { + behavior of "Five-stage Pipelined CPU with Forwarding" + it should "calculate recursively fibonacci(10)" in { + test(new TestTopModule("fibonacci.asmbin", ImplementationType.FiveStageForward)).withAnnotations(TestAnnotations.annos) { c => + 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) + } + } + it should "quicksort 10 numbers" in { + test(new TestTopModule("quicksort.asmbin", ImplementationType.FiveStageForward)).withAnnotations(TestAnnotations.annos) { c => + 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) + } + } + } + it should "store and load single byte" in { + test(new TestTopModule("sb.asmbin", ImplementationType.FiveStageForward)).withAnnotations(TestAnnotations.annos) { c => + c.clock.step(1000) + 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) + } + } + it should "solve data and control hazards" in { + test(new TestTopModule("hazard.asmbin", ImplementationType.FiveStageForward)).withAnnotations(TestAnnotations.annos) { c => + c.clock.step(1000) + c.io.regs_debug_read_address.poke(1.U) + c.io.regs_debug_read_data.expect(27.U) + c.io.mem_debug_read_address.poke(4.U) + c.clock.step() + c.io.mem_debug_read_data.expect(1.U) + c.io.mem_debug_read_address.poke(8.U) + c.clock.step() + c.io.mem_debug_read_data.expect(3.U) + } + } +} diff --git a/lab3/src/test/scala/riscv/FiveStageCPUStallTest.scala b/lab3/src/test/scala/riscv/FiveStageCPUStallTest.scala new file mode 100644 index 0000000..078e380 --- /dev/null +++ b/lab3/src/test/scala/riscv/FiveStageCPUStallTest.scala @@ -0,0 +1,73 @@ +// 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 chisel3._ +import chiseltest._ +import org.scalatest.flatspec.AnyFlatSpec + + +class FiveStageCPUStallTest extends AnyFlatSpec with ChiselScalatestTester { + behavior of "Five-stage Pipelined CPU with Stalling" + it should "calculate recursively fibonacci(10)" in { + test(new TestTopModule("fibonacci.asmbin", ImplementationType.FiveStageStall)).withAnnotations(TestAnnotations.annos) { c => + 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) + } + } + it should "quicksort 10 numbers" in { + test(new TestTopModule("quicksort.asmbin", ImplementationType.FiveStageStall)).withAnnotations(TestAnnotations.annos) { c => + 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) + } + } + } + it should "store and load single byte" in { + test(new TestTopModule("sb.asmbin", ImplementationType.FiveStageStall)).withAnnotations(TestAnnotations.annos) { c => + c.clock.step(1000) + 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) + } + } + it should "solve data and control hazards" in { + test(new TestTopModule("hazard.asmbin", ImplementationType.FiveStageStall)).withAnnotations(TestAnnotations.annos) { c => + c.clock.step(1000) + c.io.regs_debug_read_address.poke(1.U) + c.io.regs_debug_read_data.expect(46.U) + c.io.mem_debug_read_address.poke(4.U) + c.clock.step() + c.io.mem_debug_read_data.expect(1.U) + c.io.mem_debug_read_address.poke(8.U) + c.clock.step() + c.io.mem_debug_read_data.expect(3.U) + } + } +} diff --git a/lab3/src/test/scala/riscv/PipelineRegisterTest.scala b/lab3/src/test/scala/riscv/PipelineRegisterTest.scala new file mode 100644 index 0000000..5348074 --- /dev/null +++ b/lab3/src/test/scala/riscv/PipelineRegisterTest.scala @@ -0,0 +1,58 @@ +// 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 chisel3._ +import chiseltest._ +import org.scalatest.flatspec.AnyFlatSpec +import riscv.core.PipelineRegister + +import scala.math.pow +import scala.util.Random + + +class PipelineRegisterTest extends AnyFlatSpec with ChiselScalatestTester { + behavior of "Pipeline Register" + it should "be able to stall and flush" in { + val rand = new Random + val default_value = rand.nextInt(pow(2, Parameters.DataBits).toInt).asUInt(Parameters.DataWidth) + test(new PipelineRegister(Parameters.DataBits, default_value)).withAnnotations(TestAnnotations.annos) { c => + var pre = default_value + for (_ <- 1 to 1000) { + val cur = rand.nextInt(pow(2, Parameters.DataBits).toInt).asUInt(Parameters.DataWidth) + c.io.in.poke(cur) + rand.nextInt(3) match { + case 0 => + c.io.stall.poke(false.B) + c.io.flush.poke(false.B) + c.clock.step() + c.io.out.expect(cur) + pre = cur + case 1 => + c.io.stall.poke(true.B) + c.io.flush.poke(false.B) + c.clock.step() + c.io.out.expect(pre) + case 2 => + c.io.stall.poke(false.B) + c.io.flush.poke(true.B) + c.clock.step() + c.io.out.expect(default_value) + pre = default_value + } + } + } + } +} \ No newline at end of file diff --git a/lab3/src/test/scala/riscv/TestAnnotations.scala b/lab3/src/test/scala/riscv/TestAnnotations.scala new file mode 100644 index 0000000..7842a95 --- /dev/null +++ b/lab3/src/test/scala/riscv/TestAnnotations.scala @@ -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 +} diff --git a/lab3/src/test/scala/riscv/TestTopModule.scala b/lab3/src/test/scala/riscv/TestTopModule.scala new file mode 100644 index 0000000..afa3fc6 --- /dev/null +++ b/lab3/src/test/scala/riscv/TestTopModule.scala @@ -0,0 +1,66 @@ +// 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 chisel3._ +import peripheral.{InstructionROM, Memory, ROMLoader} +import riscv.core.CPU + +class TestTopModule(exeFilename: String, implementation: Int) extends Module { + val io = IO(new Bundle { + val regs_debug_read_address = Input(UInt(Parameters.PhysicalRegisterAddrWidth)) + val mem_debug_read_address = Input(UInt(Parameters.AddrWidth)) + val regs_debug_read_data = Output(UInt(Parameters.DataWidth)) + val mem_debug_read_data = Output(UInt(Parameters.DataWidth)) + }) + + val mem = Module(new Memory(8192)) + val instruction_rom = Module(new InstructionROM(exeFilename)) + val rom_loader = Module(new ROMLoader(instruction_rom.capacity)) + + rom_loader.io.rom_data := instruction_rom.io.data + rom_loader.io.load_address := Parameters.EntryAddress + instruction_rom.io.address := rom_loader.io.rom_address + + val CPU_clkdiv = RegInit(UInt(2.W), 0.U) + val CPU_tick = Wire(Bool()) + val CPU_next = Wire(UInt(2.W)) + CPU_next := Mux(CPU_clkdiv === 3.U, 0.U, CPU_clkdiv + 1.U) + CPU_tick := CPU_clkdiv === 0.U + CPU_clkdiv := CPU_next + + withClock(CPU_tick.asClock) { + val cpu = Module(new CPU(implementation)) + cpu.io.debug_read_address := 0.U + cpu.io.instruction_valid := rom_loader.io.load_finished + mem.io.instruction_address := cpu.io.instruction_address + cpu.io.instruction := mem.io.instruction + cpu.io.interrupt_flag := 0.U + + when(!rom_loader.io.load_finished) { + rom_loader.io.bundle <> mem.io.bundle + cpu.io.memory_bundle.read_data := 0.U + }.otherwise { + rom_loader.io.bundle.read_data := 0.U + cpu.io.memory_bundle <> mem.io.bundle + } + + cpu.io.debug_read_address := io.regs_debug_read_address + io.regs_debug_read_data := cpu.io.debug_read_data + } + + mem.io.debug_read_address := io.mem_debug_read_address + io.mem_debug_read_data := mem.io.debug_read_data +} diff --git a/lab3/src/test/scala/riscv/ThreeStageCPUTest.scala b/lab3/src/test/scala/riscv/ThreeStageCPUTest.scala new file mode 100644 index 0000000..b015980 --- /dev/null +++ b/lab3/src/test/scala/riscv/ThreeStageCPUTest.scala @@ -0,0 +1,73 @@ +// 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 chisel3._ +import chiseltest._ +import org.scalatest.flatspec.AnyFlatSpec + + +class ThreeStageCPUTest extends AnyFlatSpec with ChiselScalatestTester { + behavior of "Three-stage Pipelined CPU" + it should "calculate recursively fibonacci(10)" in { + test(new TestTopModule("fibonacci.asmbin", ImplementationType.ThreeStage)).withAnnotations(TestAnnotations.annos) { c => + 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) + } + } + it should "quicksort 10 numbers" in { + test(new TestTopModule("quicksort.asmbin", ImplementationType.ThreeStage)).withAnnotations(TestAnnotations.annos) { c => + 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) + } + } + } + it should "store and load single byte" in { + test(new TestTopModule("sb.asmbin", ImplementationType.ThreeStage)).withAnnotations(TestAnnotations.annos) { c => + c.clock.step(1000) + 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) + } + } + it should "solve control hazards" in { + test(new TestTopModule("hazard.asmbin", ImplementationType.ThreeStage)).withAnnotations(TestAnnotations.annos) { c => + c.clock.step(1000) + c.io.regs_debug_read_address.poke(1.U) + c.io.regs_debug_read_data.expect(26.U) + c.io.mem_debug_read_address.poke(4.U) + c.clock.step() + c.io.mem_debug_read_data.expect(1.U) + c.io.mem_debug_read_address.poke(8.U) + c.clock.step() + c.io.mem_debug_read_data.expect(3.U) + } + } +} diff --git a/lab3/verilog/basys3/test.v b/lab3/verilog/basys3/test.v new file mode 100644 index 0000000..9f3f6a6 --- /dev/null +++ b/lab3/verilog/basys3/test.v @@ -0,0 +1,35 @@ +`timescale 1ns / 1ps +////////////////////////////////////////////////////////////////////////////////// +// Company: +// Engineer: +// +// Create Date: 2021/12/17 16:31:05 +// Design Name: +// Module Name: test +// Project Name: +// Target Devices: +// Tool Versions: +// Description: +// +// Dependencies: +// +// Revision: +// Revision 0.01 - File Created +// Additional Comments: +// +////////////////////////////////////////////////////////////////////////////////// + + +module test(); +reg clock; +reg reset; +initial begin +clock = 0; +forever #1 clock = ~clock; +end +initial begin +reset = 1; +#2 reset = 0; +end +Top top(clock, reset); +endmodule diff --git a/lab3/verilog/pynq/TMDS_PLLVR.v b/lab3/verilog/pynq/TMDS_PLLVR.v new file mode 100644 index 0000000..1bc4dfb --- /dev/null +++ b/lab3/verilog/pynq/TMDS_PLLVR.v @@ -0,0 +1,221 @@ + +// file: TMDS_PLLVR.v +// +// (c) Copyright 2008 - 2013 Xilinx, Inc. All rights reserved. +// +// This file contains confidential and proprietary information +// of Xilinx, Inc. and is protected under U.S. and +// international copyright and other intellectual property +// laws. +// +// DISCLAIMER +// This disclaimer is not a license and does not grant any +// rights to the materials distributed herewith. Except as +// otherwise provided in a valid license issued to you by +// Xilinx, and to the maximum extent permitted by applicable +// law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND +// WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES +// AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING +// BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON- +// INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and +// (2) Xilinx shall not be liable (whether in contract or tort, +// including negligence, or under any other theory of +// liability) for any loss or damage of any kind or nature +// related to, arising under or in connection with these +// materials, including for any direct, or any indirect, +// special, incidental, or consequential loss or damage +// (including loss of data, profits, goodwill, or any type of +// loss or damage suffered as a result of any action brought +// by a third party) even if such damage or loss was +// reasonably foreseeable or Xilinx had been advised of the +// possibility of the same. +// +// CRITICAL APPLICATIONS +// Xilinx products are not designed or intended to be fail- +// safe, or for use in any application requiring fail-safe +// performance, such as life-support or safety devices or +// systems, Class III medical devices, nuclear facilities, +// applications related to the deployment of airbags, or any +// other applications that could lead to death, personal +// injury, or severe property or environmental damage +// (individually and collectively, "Critical +// Applications"). Customer assumes the sole risk and +// liability of any use of Xilinx products in Critical +// Applications, subject only to applicable laws and +// regulations governing limitations on product liability. +// +// THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS +// PART OF THIS FILE AT ALL TIMES. +// +//---------------------------------------------------------------------------- +// User entered comments +//---------------------------------------------------------------------------- +// None +// +//---------------------------------------------------------------------------- +// Output Output Phase Duty Cycle Pk-to-Pk Phase +// Clock Freq (MHz) (degrees) (%) Jitter (ps) Error (ps) +//---------------------------------------------------------------------------- +// __clkout__250.00000______0.000______50.0______200.536____237.727 +// _clkoutd__100.00000______0.000______50.0______226.965____237.727 +// +//---------------------------------------------------------------------------- +// Input Clock Freq (MHz) Input Jitter (UI) +//---------------------------------------------------------------------------- +// __primary__________25.000____________0.010 + +`timescale 1ps/1ps + +(* CORE_GENERATION_INFO = "TMDS_PLLVR,clk_wiz_v6_0_5_0_0,{component_name=TMDS_PLLVR,use_phase_alignment=true,use_min_o_jitter=false,use_max_i_jitter=false,use_dyn_phase_shift=false,use_inclk_switchover=false,use_dyn_reconfig=false,enable_axi=0,feedback_source=FDBK_AUTO,PRIMITIVE=PLL,num_out_clk=2,clkin1_period=40.000,clkin2_period=10.0,use_power_down=false,use_reset=true,use_locked=true,use_inclk_stopped=false,feedback_type=SINGLE,CLOCK_MGR_TYPE=NA,manual_override=true}" *) + +module TMDS_PLLVR + ( + // Clock out ports + output clkout, + output clkoutd, + // Status and control signals + input reset, + output lock, + // Clock in ports + input clkin + ); + + TMDS_PLLVR_clk_wiz inst + ( + // Clock out ports + .clkout(clkout), + .clkoutd(clkoutd), + // Status and control signals + .reset(reset), + .lock(lock), + // Clock in ports + .clk_in1(clkin) + ); + +endmodule + + +module TMDS_PLLVR_clk_wiz + + (// Clock in ports + // Clock out ports + output clkout, + output clkoutd, + // Status and control signals + input reset, + output lock, + input clk_in1 + ); + // Input buffering + //------------------------------------ +wire clk_in1_TMDS_PLLVR; +wire clk_in2_TMDS_PLLVR; + IBUF clkin1_ibufg + (.O (clk_in1_TMDS_PLLVR), + .I (clk_in1)); + + + + + // Clocking PRIMITIVE + //------------------------------------ + + // Instantiation of the MMCM PRIMITIVE + // * Unused inputs are tied off + // * Unused outputs are labeled unused + + wire clkout_TMDS_PLLVR; + wire clkoutd_TMDS_PLLVR; + wire clk_out3_TMDS_PLLVR; + wire clk_out4_TMDS_PLLVR; + wire clk_out5_TMDS_PLLVR; + wire clk_out6_TMDS_PLLVR; + wire clk_out7_TMDS_PLLVR; + + wire [15:0] do_unused; + wire drdy_unused; + wire psdone_unused; + wire lock_int; + wire clkfbout_TMDS_PLLVR; + wire clkfbout_buf_TMDS_PLLVR; + wire clkfboutb_unused; + wire clkout2_unused; + wire clkout3_unused; + wire clkout4_unused; + wire clkout5_unused; + wire clkout6_unused; + wire clkfbstopped_unused; + wire clkinstopped_unused; + wire reset_high; + + PLLE2_ADV + #(.BANDWIDTH ("OPTIMIZED"), + .COMPENSATION ("ZHOLD"), + .STARTUP_WAIT ("FALSE"), + .DIVCLK_DIVIDE (1), + .CLKFBOUT_MULT (40), + .CLKFBOUT_PHASE (0.000), + .CLKOUT0_DIVIDE (4), + .CLKOUT0_PHASE (0.000), + .CLKOUT0_DUTY_CYCLE (0.500), + .CLKOUT1_DIVIDE (10), + .CLKOUT1_PHASE (0.000), + .CLKOUT1_DUTY_CYCLE (0.500), + .CLKIN1_PERIOD (40.000)) + plle2_adv_inst + // Output clocks + ( + .CLKFBOUT (clkfbout_TMDS_PLLVR), + .CLKOUT0 (clkout_TMDS_PLLVR), + .CLKOUT1 (clkoutd_TMDS_PLLVR), + .CLKOUT2 (clkout2_unused), + .CLKOUT3 (clkout3_unused), + .CLKOUT4 (clkout4_unused), + .CLKOUT5 (clkout5_unused), + // Input clock control + .CLKFBIN (clkfbout_buf_TMDS_PLLVR), + .CLKIN1 (clk_in1_TMDS_PLLVR), + .CLKIN2 (1'b0), + // Tied to always select the primary input clock + .CLKINSEL (1'b1), + // Ports for dynamic reconfiguration + .DADDR (7'h0), + .DCLK (1'b0), + .DEN (1'b0), + .DI (16'h0), + .DO (do_unused), + .DRDY (drdy_unused), + .DWE (1'b0), + // Other control and status signals + .LOCKED (lock_int), + .PWRDWN (1'b0), + .RST (reset_high)); + assign reset_high = reset; + + assign lock = lock_int; +// Clock Monitor clock assigning +//-------------------------------------- + // Output buffering + //----------------------------------- + + BUFG clkf_buf + (.O (clkfbout_buf_TMDS_PLLVR), + .I (clkfbout_TMDS_PLLVR)); + + + + + + + BUFG clkout1_buf + (.O (clkout), + .I (clkout_TMDS_PLLVR)); + + + BUFG clkout2_buf + (.O (clkoutd), + .I (clkoutd_TMDS_PLLVR)); + + + +endmodule diff --git a/lab3/verilog/pynq/test.v b/lab3/verilog/pynq/test.v new file mode 100644 index 0000000..9f3f6a6 --- /dev/null +++ b/lab3/verilog/pynq/test.v @@ -0,0 +1,35 @@ +`timescale 1ns / 1ps +////////////////////////////////////////////////////////////////////////////////// +// Company: +// Engineer: +// +// Create Date: 2021/12/17 16:31:05 +// Design Name: +// Module Name: test +// Project Name: +// Target Devices: +// Tool Versions: +// Description: +// +// Dependencies: +// +// Revision: +// Revision 0.01 - File Created +// Additional Comments: +// +////////////////////////////////////////////////////////////////////////////////// + + +module test(); +reg clock; +reg reset; +initial begin +clock = 0; +forever #1 clock = ~clock; +end +initial begin +reset = 1; +#2 reset = 0; +end +Top top(clock, reset); +endmodule diff --git a/lab3/verilog/verilator/sim_main.cpp b/lab3/verilog/verilator/sim_main.cpp new file mode 100644 index 0000000..d216137 --- /dev/null +++ b/lab3/verilog/verilator/sim_main.cpp @@ -0,0 +1,251 @@ +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "VTop.h" // From Verilating "top.v" + + +class Memory { + std::vector memory; + + public: + Memory(size_t size) : memory(size, 0) {} + + uint32_t read(size_t address) { + address = address / 4; + if (address >= memory.size()) { +// printf("invalid read address 0x%08x\n", address * 4); + return 0; + } + return memory[address]; + } + + uint32_t readInst(size_t address) { + address = address / 4; + if (address >= memory.size()) { +// printf("invalid read Inst address 0x%08x\n", address * 4); + return 0; + } + + return memory[address]; + } + + void write(size_t address, uint32_t value, bool write_strobe[4]) { + address = address / 4; + uint32_t write_mask = 0; + if (write_strobe[0]) write_mask |= 0x000000FF; + if (write_strobe[1]) write_mask |= 0x0000FF00; + if (write_strobe[2]) write_mask |= 0x00FF0000; + if (write_strobe[3]) write_mask |= 0xFF000000; + if (address >= memory.size()) { +// printf("invalid write address 0x%08x\n", address * 4); + return; + } + memory[address] = (memory[address] & ~write_mask) | (value & write_mask); + } + + void load_binary(std::string const& filename, size_t load_address = 0x1000) { + std::ifstream file(filename, std::ios::binary); + if (!file) { + throw std::runtime_error("Could not open file " + filename); + } + file.seekg(0, std::ios::end); + size_t size = file.tellg(); + if (load_address + size > memory.size() * 4) { + throw std::runtime_error("File " + filename + " is too large (File is " + + std::to_string(size) + " bytes. Memory is " + + std::to_string(memory.size() * 4 - load_address) + " bytes.)"); + } + file.seekg(0, std::ios::beg); + for (int i = 0; i < size / 4; ++i) { + file.read(reinterpret_cast(&memory[i + load_address / 4]), + sizeof(uint32_t)); + } + } +}; + +class VCDTracer { + VerilatedVcdC* tfp = nullptr; + + public: + void enable(std::string const& filename, VTop& top) { + Verilated::traceEverOn(true); + tfp = new VerilatedVcdC; + top.trace(tfp, 99); + tfp->open(filename.c_str()); + tfp->set_time_resolution("1ps"); + tfp->set_time_unit("1ns"); + if (!tfp->isOpen()) { + throw std::runtime_error("Failed to open VCD dump file " + filename); + } + } + + void dump(vluint64_t time) { + if (tfp) { + tfp->dump(time); + } + } + + ~VCDTracer() { + if (tfp) { + tfp->close(); + delete tfp; + } + } +}; + +uint32_t parse_number(std::string const& str) { + if (str.size() > 2) { + auto&& prefix = str.substr(0, 2); + if (prefix == "0x" || prefix == "0X") { + return std::stoul(str.substr(2), nullptr, 16); + } + } + return std::stoul(str); +} + +class Simulator { + vluint64_t main_time = 0; + vluint64_t max_sim_time = 10000; + uint32_t halt_address = 0; + size_t memory_words = 1024 * 1024; // 4MB + bool dump_vcd = false; + std::unique_ptr top; + std::unique_ptr vcd_tracer; + std::unique_ptr memory; + bool dump_signature = false; + unsigned long signature_begin, signature_end; + std::string signature_filename; + std::string instruction_filename; + + public: + void parse_args(std::vector const& args) { + if (auto it = std::find(args.begin(), args.end(), "-halt"); + it != args.end()) { + halt_address = parse_number(*(it + 1)); + } + + if (auto it = std::find(args.begin(), args.end(), "-memory"); + it != args.end()) { + memory_words = std::stoul(*(it + 1)); + } + + if (auto it = std::find(args.begin(), args.end(), "-time"); + it != args.end()) { + max_sim_time = std::stoul(*(it + 1)); + } + + if (auto it = std::find(args.begin(), args.end(), "-vcd"); + it != args.end()) { + vcd_tracer->enable(*(it + 1), *top); + } + + if (auto it = std::find(args.begin(), args.end(), "-signature"); + it != args.end()) { + dump_signature = true; + signature_begin = parse_number(*(it + 1)); + signature_end = parse_number(*(it + 2)); + signature_filename = *(it + 3); + } + + if (auto it = std::find(args.begin(), args.end(), "-instruction"); + it != args.end()) { + instruction_filename = *(it + 1); + } + } + + Simulator(std::vector const& args) + : top(std::make_unique()), + vcd_tracer(std::make_unique()) { + parse_args(args); + memory = std::make_unique(memory_words); + if (!instruction_filename.empty()) { + memory->load_binary(instruction_filename); + } + } + + void run() { + top->reset = 1; + top->clock = 0; + top->io_instruction_valid = 1; + top->eval(); + vcd_tracer->dump(main_time); + uint32_t data_memory_read_word = 0; + uint32_t inst_memory_read_word = 0; + uint32_t timer_interrupt = 0; + uint32_t counter = 0; + uint32_t clocktime = 1; + bool memory_write_strobe[4] = {false}; + while (main_time < max_sim_time && !Verilated::gotFinish()) { + ++main_time; + ++counter; + if(counter > clocktime){ + top->clock = !top->clock; + counter = 0; + } + if(main_time & 0x00ff0 == 0xff0) { + top->io_interrupt_flag = 1; + } else{ + top->io_interrupt_flag = 0; + } + if (main_time > 2) { + top->reset = 0; + } +// top->io_mem_slave_read_data = memory_read_word; + top->io_memory_bundle_read_data = data_memory_read_word; + top->io_instruction = inst_memory_read_word; + top->clock = !top->clock; + top->eval(); + top->io_interrupt_flag = 0; + + data_memory_read_word = memory->read(top->io_memory_bundle_address); + + + inst_memory_read_word = memory->readInst(top->io_instruction_address); + + if (top->io_memory_bundle_write_enable) { + memory_write_strobe[0] = top->io_memory_bundle_write_strobe_0; + memory_write_strobe[1] = top->io_memory_bundle_write_strobe_1; + memory_write_strobe[2] = top->io_memory_bundle_write_strobe_2; + memory_write_strobe[3] = top->io_memory_bundle_write_strobe_3; + memory->write(top->io_memory_bundle_address, top->io_memory_bundle_write_data, + memory_write_strobe); + } + vcd_tracer->dump(main_time); + if (halt_address) { + if (memory->read(halt_address) == 0xBABECAFE) { + break; + } + } + } + + if (dump_signature) { + char data[9] = {0}; + std::ofstream signature_file(signature_filename); + for (size_t addr = signature_begin; addr < signature_end; addr += 4) { + snprintf(data, 9, "%08x", memory->read(addr)); + signature_file << data << std::endl; + } + } + } + + ~Simulator() { + if (top) { + top->final(); + } + } +}; + +int main(int argc, char** argv) { + Verilated::commandArgs(argc, argv); + std::vector args(argv, argv + argc); + Simulator simulator(args); + simulator.run(); + return 0; +} diff --git a/lab3/vivado/basys3/basys3.xdc b/lab3/vivado/basys3/basys3.xdc new file mode 100644 index 0000000..9864546 --- /dev/null +++ b/lab3/vivado/basys3/basys3.xdc @@ -0,0 +1,307 @@ +# 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. + +## Clock signal +set_property PACKAGE_PIN W5 [get_ports clock] + set_property IOSTANDARD LVCMOS33 [get_ports clock] + create_clock -add -name sys_clk_pin -period 20.00 -waveform {0 5} [get_ports clock] + +## Switches +set_property PACKAGE_PIN V17 [get_ports {io_switch[0]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_switch[0]}] +set_property PACKAGE_PIN V16 [get_ports {io_switch[1]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_switch[1]}] +set_property PACKAGE_PIN W16 [get_ports {io_switch[2]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_switch[2]}] +set_property PACKAGE_PIN W17 [get_ports {io_switch[3]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_switch[3]}] +set_property PACKAGE_PIN W15 [get_ports {io_switch[4]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_switch[4]}] +set_property PACKAGE_PIN V15 [get_ports {io_switch[5]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_switch[5]}] +set_property PACKAGE_PIN W14 [get_ports {io_switch[6]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_switch[6]}] +set_property PACKAGE_PIN W13 [get_ports {io_switch[7]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_switch[7]}] +set_property PACKAGE_PIN V2 [get_ports {io_switch[8]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_switch[8]}] +set_property PACKAGE_PIN T3 [get_ports {io_switch[9]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_switch[9]}] +set_property PACKAGE_PIN T2 [get_ports {io_switch[10]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_switch[10]}] +set_property PACKAGE_PIN R3 [get_ports {io_switch[11]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_switch[11]}] +set_property PACKAGE_PIN W2 [get_ports {io_switch[12]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_switch[12]}] +set_property PACKAGE_PIN U1 [get_ports {io_switch[13]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_switch[13]}] +set_property PACKAGE_PIN T1 [get_ports {io_switch[14]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_switch[14]}] +set_property PACKAGE_PIN R2 [get_ports {io_switch[15]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_switch[15]}] + + +## LEDs +set_property PACKAGE_PIN U16 [get_ports {io_led[0]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_led[0]}] +set_property PACKAGE_PIN E19 [get_ports {io_led[1]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_led[1]}] +set_property PACKAGE_PIN U19 [get_ports {io_led[2]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_led[2]}] +set_property PACKAGE_PIN V19 [get_ports {io_led[3]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_led[3]}] +set_property PACKAGE_PIN W18 [get_ports {io_led[4]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_led[4]}] +set_property PACKAGE_PIN U15 [get_ports {io_led[5]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_led[5]}] +set_property PACKAGE_PIN U14 [get_ports {io_led[6]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_led[6]}] +set_property PACKAGE_PIN V14 [get_ports {io_led[7]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_led[7]}] +set_property PACKAGE_PIN V13 [get_ports {io_led[8]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_led[8]}] +set_property PACKAGE_PIN V3 [get_ports {io_led[9]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_led[9]}] +set_property PACKAGE_PIN W3 [get_ports {io_led[10]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_led[10]}] +set_property PACKAGE_PIN U3 [get_ports {io_led[11]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_led[11]}] +set_property PACKAGE_PIN P3 [get_ports {io_led[12]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_led[12]}] +set_property PACKAGE_PIN N3 [get_ports {io_led[13]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_led[13]}] +set_property PACKAGE_PIN P1 [get_ports {io_led[14]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_led[14]}] +set_property PACKAGE_PIN L1 [get_ports {io_led[15]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_led[15]}] + + +##7 segment display +set_property PACKAGE_PIN U7 [get_ports io_segs[0]] + set_property IOSTANDARD LVCMOS33 [get_ports io_segs[0]] +set_property PACKAGE_PIN V5 [get_ports io_segs[1]] + set_property IOSTANDARD LVCMOS33 [get_ports io_segs[1]] +set_property PACKAGE_PIN U5 [get_ports io_segs[2]] + set_property IOSTANDARD LVCMOS33 [get_ports io_segs[2]] +set_property PACKAGE_PIN V8 [get_ports io_segs[3]] + set_property IOSTANDARD LVCMOS33 [get_ports io_segs[3]] +set_property PACKAGE_PIN U8 [get_ports io_segs[4]] + set_property IOSTANDARD LVCMOS33 [get_ports io_segs[4]] +set_property PACKAGE_PIN W6 [get_ports io_segs[5]] + set_property IOSTANDARD LVCMOS33 [get_ports io_segs[5]] +set_property PACKAGE_PIN W7 [get_ports io_segs[6]] + set_property IOSTANDARD LVCMOS33 [get_ports io_segs[6]] +set_property PACKAGE_PIN V7 [get_ports io_segs[7]] + set_property IOSTANDARD LVCMOS33 [get_ports io_segs[7]] + +set_property PACKAGE_PIN U2 [get_ports {io_digit_mask[0]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_digit_mask[0]}] +set_property PACKAGE_PIN U4 [get_ports {io_digit_mask[1]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_digit_mask[1]}] +set_property PACKAGE_PIN V4 [get_ports {io_digit_mask[2]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_digit_mask[2]}] +set_property PACKAGE_PIN W4 [get_ports {io_digit_mask[3]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_digit_mask[3]}] + + +##Buttons +set_property PACKAGE_PIN U18 [get_ports reset] + set_property IOSTANDARD LVCMOS33 [get_ports reset] +#set_property PACKAGE_PIN T18 [get_ports io_freqIncrease] + #set_property IOSTANDARD LVCMOS33 [get_ports io_freqIncrease] +#set_property PACKAGE_PIN W19 [get_ports io_widthIncrease] + #set_property IOSTANDARD LVCMOS33 [get_ports io_widthIncrease] +#set_property PACKAGE_PIN T17 [get_ports io_widthDecrease] + #set_property IOSTANDARD LVCMOS33 [get_ports io_widthDecrease] +#set_property PACKAGE_PIN U17 [get_ports io_freqDecrease] + #set_property IOSTANDARD LVCMOS33 [get_ports io_freqDecrease] + + + +##Pmod Header JA +##Sch name = JA1 +#set_property PACKAGE_PIN J1 [get_ports {JA[0]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JA[0]}] +##Sch name = JA2 +#set_property PACKAGE_PIN L2 [get_ports {JA[1]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JA[1]}] +##Sch name = JA3 +#set_property PACKAGE_PIN J2 [get_ports {JA[2]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JA[2]}] +##Sch name = JA4 +#set_property PACKAGE_PIN G2 [get_ports {JA[3]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JA[3]}] +##Sch name = JA7 +#set_property PACKAGE_PIN H1 [get_ports {JA[4]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JA[4]}] +##Sch name = JA8 +#set_property PACKAGE_PIN K2 [get_ports {JA[5]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JA[5]}] +##Sch name = JA9 +#set_property PACKAGE_PIN H2 [get_ports {JA[6]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JA[6]}] +##Sch name = JA10 +#set_property PACKAGE_PIN G3 [get_ports {JA[7]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JA[7]}] + + + +##Pmod Header JB +##Sch name = JB1 +#set_property PACKAGE_PIN A14 [get_ports {JB[0]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JB[0]}] +##Sch name = JB2 +#set_property PACKAGE_PIN A16 [get_ports {JB[1]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JB[1]}] +##Sch name = JB3 +#set_property PACKAGE_PIN B15 [get_ports {JB[2]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JB[2]}] +##Sch name = JB4 +#set_property PACKAGE_PIN B16 [get_ports {JB[3]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JB[3]}] +##Sch name = JB7 +#set_property PACKAGE_PIN A15 [get_ports {JB[4]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JB[4]}] +##Sch name = JB8 +#set_property PACKAGE_PIN A17 [get_ports {JB[5]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JB[5]}] +##Sch name = JB9 +#set_property PACKAGE_PIN C15 [get_ports {JB[6]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JB[6]}] +##Sch name = JB10 +#set_property PACKAGE_PIN C16 [get_ports {JB[7]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JB[7]}] + + + +##Pmod Header JC +##Sch name = JC1 +#set_property PACKAGE_PIN K17 [get_ports {JC[0]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JC[0]}] +##Sch name = JC2 +#set_property PACKAGE_PIN M18 [get_ports {JC[1]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JC[1]}] +##Sch name = JC3 +#set_property PACKAGE_PIN N17 [get_ports {JC[2]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JC[2]}] +##Sch name = JC4 +#set_property PACKAGE_PIN P18 [get_ports {JC[3]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JC[3]}] +##Sch name = JC7 +#set_property PACKAGE_PIN L17 [get_ports {JC[4]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JC[4]}] +##Sch name = JC8 +#set_property PACKAGE_PIN M19 [get_ports {JC[5]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JC[5]}] +##Sch name = JC9 +#set_property PACKAGE_PIN P17 [get_ports {JC[6]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JC[6]}] +##Sch name = JC10 +#set_property PACKAGE_PIN R18 [get_ports {JC[7]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JC[7]}] + + +##Pmod Header JXADC +##Sch name = XA1_P +#set_property PACKAGE_PIN J3 [get_ports {JXADC[0]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JXADC[0]}] +##Sch name = XA2_P +#set_property PACKAGE_PIN L3 [get_ports {JXADC[1]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JXADC[1]}] +##Sch name = XA3_P +#set_property PACKAGE_PIN M2 [get_ports {JXADC[2]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JXADC[2]}] +##Sch name = XA4_P +#set_property PACKAGE_PIN N2 [get_ports {JXADC[3]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JXADC[3]}] +##Sch name = XA1_N +#set_property PACKAGE_PIN K3 [get_ports {JXADC[4]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JXADC[4]}] +##Sch name = XA2_N +#set_property PACKAGE_PIN M3 [get_ports {JXADC[5]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JXADC[5]}] +##Sch name = XA3_N +#set_property PACKAGE_PIN M1 [get_ports {JXADC[6]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JXADC[6]}] +##Sch name = XA4_N +#set_property PACKAGE_PIN N1 [get_ports {JXADC[7]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JXADC[7]}] + + + +##VGA Connector +set_property PACKAGE_PIN G19 [get_ports {io_rgb[8]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_rgb[8]}] +set_property PACKAGE_PIN H19 [get_ports {io_rgb[9]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_rgb[9]}] +set_property PACKAGE_PIN J19 [get_ports {io_rgb[10]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_rgb[10]}] +set_property PACKAGE_PIN N19 [get_ports {io_rgb[11]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_rgb[11]}] +set_property PACKAGE_PIN N18 [get_ports {io_rgb[0]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_rgb[0]}] +set_property PACKAGE_PIN L18 [get_ports {io_rgb[1]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_rgb[1]}] +set_property PACKAGE_PIN K18 [get_ports {io_rgb[2]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_rgb[2]}] +set_property PACKAGE_PIN J18 [get_ports {io_rgb[3]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_rgb[3]}] +set_property PACKAGE_PIN J17 [get_ports {io_rgb[4]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_rgb[4]}] +set_property PACKAGE_PIN H17 [get_ports {io_rgb[5]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_rgb[5]}] +set_property PACKAGE_PIN G17 [get_ports {io_rgb[6]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_rgb[6]}] +set_property PACKAGE_PIN D17 [get_ports {io_rgb[7]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_rgb[7]}] +set_property PACKAGE_PIN P19 [get_ports io_hsync] + set_property IOSTANDARD LVCMOS33 [get_ports io_hsync] +set_property PACKAGE_PIN R19 [get_ports io_vsync] + set_property IOSTANDARD LVCMOS33 [get_ports io_vsync] + + +##USB-RS232 Interface +set_property PACKAGE_PIN B18 [get_ports io_rx] + set_property IOSTANDARD LVCMOS33 [get_ports io_rx] +set_property PACKAGE_PIN A18 [get_ports io_tx] + set_property IOSTANDARD LVCMOS33 [get_ports io_tx] + + +##USB HID (PS/2) +#set_property PACKAGE_PIN C17 [get_ports PS2Clk] + #set_property IOSTANDARD LVCMOS33 [get_ports PS2Clk] + #set_property PULLUP true [get_ports PS2Clk] +#set_property PACKAGE_PIN B17 [get_ports PS2Data] + #set_property IOSTANDARD LVCMOS33 [get_ports PS2Data] + #set_property PULLUP true [get_ports PS2Data] + + +##Quad SPI Flash +##Note that CCLK_0 cannot be placed in 7 series devices. You can access it using the +##STARTUPE2 primitive. +#set_property PACKAGE_PIN D18 [get_ports {QspiDB[0]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {QspiDB[0]}] +#set_property PACKAGE_PIN D19 [get_ports {QspiDB[1]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {QspiDB[1]}] +#set_property PACKAGE_PIN G18 [get_ports {QspiDB[2]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {QspiDB[2]}] +#set_property PACKAGE_PIN F18 [get_ports {QspiDB[3]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {QspiDB[3]}] +#set_property PACKAGE_PIN K19 [get_ports QspiCSn] + #set_property IOSTANDARD LVCMOS33 [get_ports QspiCSn] + + +## Configuration options, can be used for all designs +set_property CONFIG_VOLTAGE 3.3 [current_design] +set_property CFGBVS VCCO [current_design] diff --git a/lab3/vivado/basys3/generate_and_program.tcl b/lab3/vivado/basys3/generate_and_program.tcl new file mode 100644 index 0000000..71df1af --- /dev/null +++ b/lab3/vivado/basys3/generate_and_program.tcl @@ -0,0 +1,17 @@ +# 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. + +# Only tested on Vivado 2020.1 on Windows 10 +source generate_bitstream.tcl +source program_device.tcl \ No newline at end of file diff --git a/lab3/vivado/basys3/generate_bitstream.tcl b/lab3/vivado/basys3/generate_bitstream.tcl new file mode 100644 index 0000000..e1a26fb --- /dev/null +++ b/lab3/vivado/basys3/generate_bitstream.tcl @@ -0,0 +1,55 @@ +# 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. + +source open_project.tcl + +while 1 { + if { [catch {launch_runs synth_1 -jobs 4 } ] } { + regexp {ERROR: \[Common (\d+-\d+)]} $errorInfo -> code + if { [string equal $code "12-978"] } { + puts "Already generated and up-to-date" + break + } elseif { [string equal $code "17-69"] } { + puts "Out of date, reset runs" + reset_runs synth_1 + continue + } else { + puts "UNKNOWN ERROR!!! $errorInfo" + exit + } + } + break +} + +wait_on_run synth_1 + +while 1 { + if { [catch {launch_runs impl_1 -jobs 4 -to_step write_bitstream } ] } { + regexp {ERROR: \[Vivado (\d+-\d+)]} $errorInfo -> code + if { [string equal $code "12-978"] } { + puts "Already generated and up-to-date" + break + } elseif { [string equal $code "12-1088"] } { + puts "Out of date, reset runs" + reset_runs impl_1 + continue + } else { + puts "UNKNOWN ERROR!!! $errorInfo" + exit + } + } + break +} + +wait_on_run impl_1 diff --git a/lab3/vivado/basys3/open_project.tcl b/lab3/vivado/basys3/open_project.tcl new file mode 100644 index 0000000..b20931a --- /dev/null +++ b/lab3/vivado/basys3/open_project.tcl @@ -0,0 +1,39 @@ +# 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. + +# Only tested on Vivado 2020.1 on Windows 10 + +# set variables +set project_dir riscv-basys3 +set project_name riscv-basys3 +set part xc7a35tcpg236-1 +set sources {../../verilog/basys3/Top.v} +set test_sources {../../verilog/basys3/test.v} + +# open the project. will create one if it doesn't exist +if {[file exist $project_dir]} { + # check that it's a directory + if {! [file isdirectory $project_dir]} { + puts "$project_dir exists, but it's a file" + } + open_project $project_dir/$project_name.xpr -part $part +} else { + create_project $project_name $project_dir -part $part +} + +add_files -norecurse $sources +update_compile_order -fileset sources_1 +add_files -fileset constrs_1 -norecurse basys3.xdc +add_files -fileset sim_1 -norecurse $test_sources +update_compile_order -fileset sim_1 diff --git a/lab3/vivado/basys3/program_device.tcl b/lab3/vivado/basys3/program_device.tcl new file mode 100644 index 0000000..12fe648 --- /dev/null +++ b/lab3/vivado/basys3/program_device.tcl @@ -0,0 +1,24 @@ +# 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. + +# Only tested on Vivado 2020.1 on Windows 10 +open_hw_manager +connect_hw_server -allow_non_jtag +open_hw_target +current_hw_device [get_hw_devices xc7a35t_0] +refresh_hw_server [current_hw_server] +open_hw_target [lindex [get_hw_targets] 0] +set_property PROGRAM.FILE {./riscv-basys3/riscv-basys3.runs/impl_1/Top.bit} [get_hw_devices xc7a35t_0] +program_hw_devices [get_hw_devices xc7a35t_0] +close_hw_target diff --git a/lab3/vivado/basys3/run.ps1 b/lab3/vivado/basys3/run.ps1 new file mode 100644 index 0000000..178feab --- /dev/null +++ b/lab3/vivado/basys3/run.ps1 @@ -0,0 +1,4 @@ +cd .. +sbt run +cd vivado +C:\Xilinx\Vivado\2020.1\bin\vivado -mode batch -source .\generate_and_program.tcl \ No newline at end of file diff --git a/lab3/vivado/basys3/run_simulation.tcl b/lab3/vivado/basys3/run_simulation.tcl new file mode 100644 index 0000000..7c1a23c --- /dev/null +++ b/lab3/vivado/basys3/run_simulation.tcl @@ -0,0 +1,24 @@ +# 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. + +source open_project.tcl + +launch_simulation +restart +open_vcd +log_wave -recursive [get_object /test/top/cpu/*] +log_vcd [get_object /test/top/cpu/*] +run 1000ns +close_vcd +close_sim diff --git a/lab3/vivado/pynq/generate_and_program.tcl b/lab3/vivado/pynq/generate_and_program.tcl new file mode 100644 index 0000000..71df1af --- /dev/null +++ b/lab3/vivado/pynq/generate_and_program.tcl @@ -0,0 +1,17 @@ +# 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. + +# Only tested on Vivado 2020.1 on Windows 10 +source generate_bitstream.tcl +source program_device.tcl \ No newline at end of file diff --git a/lab3/vivado/pynq/generate_bitstream.tcl b/lab3/vivado/pynq/generate_bitstream.tcl new file mode 100644 index 0000000..69d54c1 --- /dev/null +++ b/lab3/vivado/pynq/generate_bitstream.tcl @@ -0,0 +1,56 @@ +# 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. + +source open_project.tcl +set_param general.maxThreads 16 + +while 1 { + if { [catch {launch_runs synth_1 -jobs 16 } ] } { + regexp {ERROR: \[Common (\d+-\d+)]} $errorInfo -> code + if { [string equal $code "12-978"] } { + puts "Already generated and up-to-date" + break + } elseif { [string equal $code "17-69"] } { + puts "Out of date, reset runs" + reset_runs synth_1 + continue + } else { + puts "UNKNOWN ERROR!!! $errorInfo" + exit + } + } + break +} + +wait_on_run synth_1 + +while 1 { + if { [catch {launch_runs impl_1 -jobs 16 -to_step write_bitstream } ] } { + regexp {ERROR: \[Vivado (\d+-\d+)]} $errorInfo -> code + if { [string equal $code "12-978"] } { + puts "Already generated and up-to-date" + break + } elseif { [string equal $code "12-1088"] } { + puts "Out of date, reset runs" + reset_runs impl_1 + continue + } else { + puts "UNKNOWN ERROR!!! $errorInfo" + exit + } + } + break +} + +wait_on_run impl_1 diff --git a/lab3/vivado/pynq/open_project.tcl b/lab3/vivado/pynq/open_project.tcl new file mode 100644 index 0000000..52d029f --- /dev/null +++ b/lab3/vivado/pynq/open_project.tcl @@ -0,0 +1,40 @@ +# 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. + +# Only tested on Vivado 2020.1 on Windows 10 + +# set variables +set project_dir riscv-pynq +set project_name riscv-pynq +set part xc7z020clg400-1 +set sources {../../verilog/pynq/Top.v} +set test_sources {../../verilog/pynq/test.v} + +# open the project. will create one if it doesn't exist +if {[file exist $project_dir]} { + # check that it's a directory + if {! [file isdirectory $project_dir]} { + puts "$project_dir exists, but it's a file" + } + open_project $project_dir/$project_name.xpr -part $part +} else { + create_project $project_name $project_dir -part $part +} + +add_files -norecurse $sources +add_files -norecurse ../../verilog/pynq/TMDS_PLLVR.v +update_compile_order -fileset sources_1 +add_files -fileset constrs_1 -norecurse pynq.xdc +add_files -fileset sim_1 -norecurse $test_sources +update_compile_order -fileset sim_1 diff --git a/lab3/vivado/pynq/program_device.tcl b/lab3/vivado/pynq/program_device.tcl new file mode 100644 index 0000000..8da4e29 --- /dev/null +++ b/lab3/vivado/pynq/program_device.tcl @@ -0,0 +1,22 @@ +# 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. + +# Only tested on Vivado 2020.1 on Windows 10 +open_hw_manager +connect_hw_server -allow_non_jtag +refresh_hw_server [current_hw_server] +open_hw_target [lindex [get_hw_targets] 0] +set_property PROGRAM.FILE {riscv-pynq/riscv-pynq.runs/impl_1/Top.bit} [get_hw_devices xc7z020_1] +program_hw_devices [get_hw_devices xc7z020_1] +close_hw_target diff --git a/lab3/vivado/pynq/pynq.xdc b/lab3/vivado/pynq/pynq.xdc new file mode 100644 index 0000000..829af7b --- /dev/null +++ b/lab3/vivado/pynq/pynq.xdc @@ -0,0 +1,189 @@ +## This file is a general .xdc for the PYNQ-Z1 board Rev. C +## To use it in a project: +## - uncomment the lines corresponding to used pins +## - rename the used ports (in each line, after get_ports) according to the top level signal names in the project + +## Clock signal 125 MHz + +set_property -dict {PACKAGE_PIN H16 IOSTANDARD LVCMOS33} [get_ports clock] +create_clock -period 8.000 -name sys_clk_pin -waveform {0.000 4.000} -add [get_ports clock] + +##Switches + +set_property -dict { PACKAGE_PIN M20 IOSTANDARD LVCMOS33 } [get_ports { io_debug_step }]; #IO_L7N_T1_AD2N_35 Sch=sw[0] +#set_property -dict { PACKAGE_PIN M19 IOSTANDARD LVCMOS33 } [get_ports { sw[1] }]; #IO_L7P_T1_AD2P_35 Sch=sw[1] + +##RGB LEDs + +#set_property -dict { PACKAGE_PIN L15 IOSTANDARD LVCMOS33 } [get_ports { led4_b }]; #IO_L22N_T3_AD7N_35 Sch=led4_b +#set_property -dict { PACKAGE_PIN G17 IOSTANDARD LVCMOS33 } [get_ports { led4_g }]; #IO_L16P_T2_35 Sch=led4_g +#set_property -dict { PACKAGE_PIN N15 IOSTANDARD LVCMOS33 } [get_ports { led4_r }]; #IO_L21P_T3_DQS_AD14P_35 Sch=led4_r +#set_property -dict { PACKAGE_PIN G14 IOSTANDARD LVCMOS33 } [get_ports { led5_b }]; #IO_0_35 Sch=led5_b +#set_property -dict { PACKAGE_PIN L14 IOSTANDARD LVCMOS33 } [get_ports { led5_g }]; #IO_L22P_T3_AD7P_35 Sch=led5_g +#set_property -dict { PACKAGE_PIN M15 IOSTANDARD LVCMOS33 } [get_ports { led5_r }]; #IO_L23N_T3_35 Sch=led5_r + +##LEDs + +set_property -dict {PACKAGE_PIN R14 IOSTANDARD LVCMOS33} [get_ports {io_led[0]}] +set_property -dict {PACKAGE_PIN P14 IOSTANDARD LVCMOS33} [get_ports {io_led[1]}] +set_property -dict {PACKAGE_PIN N16 IOSTANDARD LVCMOS33} [get_ports {io_led[2]}] +set_property -dict {PACKAGE_PIN M14 IOSTANDARD LVCMOS33} [get_ports {io_led[3]}] + +##Buttons + +set_property -dict {PACKAGE_PIN D19 IOSTANDARD LVCMOS33} [get_ports reset] +set_property -dict { PACKAGE_PIN D20 IOSTANDARD LVCMOS33 } [get_ports { io_debug_clk }]; #IO_L4N_T0_35 Sch=btn[1] +#set_property -dict { PACKAGE_PIN L20 IOSTANDARD LVCMOS33 } [get_ports { btn[2] }]; #IO_L9N_T1_DQS_AD3N_35 Sch=btn[2] +#set_property -dict { PACKAGE_PIN L19 IOSTANDARD LVCMOS33 } [get_ports { btn[3] }]; #IO_L9P_T1_DQS_AD3P_35 Sch=btn[3] + +##Pmod Header JA + +#set_property -dict { PACKAGE_PIN Y18 IOSTANDARD LVCMOS33 } [get_ports { io_rx }]; #IO_L17P_T2_34 Sch=ja_p[1] +#set_property -dict { PACKAGE_PIN Y19 IOSTANDARD LVCMOS33 } [get_ports { io_tx }]; #IO_L17N_T2_34 Sch=ja_n[1] +set_property -dict {PACKAGE_PIN Y16 IOSTANDARD LVCMOS33} [get_ports io_rx] +set_property -dict {PACKAGE_PIN Y17 IOSTANDARD LVCMOS33} [get_ports io_tx] +#set_property -dict { PACKAGE_PIN U18 IOSTANDARD LVCMOS33 } [get_ports { ja[4] }]; #IO_L12P_T1_MRCC_34 Sch=ja_p[3] +#set_property -dict { PACKAGE_PIN U19 IOSTANDARD LVCMOS33 } [get_ports { ja[5] }]; #IO_L12N_T1_MRCC_34 Sch=ja_n[3] +#set_property -dict { PACKAGE_PIN W18 IOSTANDARD LVCMOS33 } [get_ports { ja[6] }]; #IO_L22P_T3_34 Sch=ja_p[4] +#set_property -dict { PACKAGE_PIN W19 IOSTANDARD LVCMOS33 } [get_ports { ja[7] }]; #IO_L22N_T3_34 Sch=ja_n[4] + +##Pmod Header JB + +#set_property -dict { PACKAGE_PIN W14 IOSTANDARD LVCMOS33 } [get_ports { jb[0] }]; #IO_L8P_T1_34 Sch=jb_p[1] +#set_property -dict { PACKAGE_PIN Y14 IOSTANDARD LVCMOS33 } [get_ports { jb[1] }]; #IO_L8N_T1_34 Sch=jb_n[1] +#set_property -dict { PACKAGE_PIN T11 IOSTANDARD LVCMOS33 } [get_ports { jb[2] }]; #IO_L1P_T0_34 Sch=jb_p[2] +#set_property -dict { PACKAGE_PIN T10 IOSTANDARD LVCMOS33 } [get_ports { jb[3] }]; #IO_L1N_T0_34 Sch=jb_n[2] +#set_property -dict { PACKAGE_PIN V16 IOSTANDARD LVCMOS33 } [get_ports { jb[4] }]; #IO_L18P_T2_34 Sch=jb_p[3] +#set_property -dict { PACKAGE_PIN W16 IOSTANDARD LVCMOS33 } [get_ports { jb[5] }]; #IO_L18N_T2_34 Sch=jb_n[3] +#set_property -dict { PACKAGE_PIN V12 IOSTANDARD LVCMOS33 } [get_ports { jb[6] }]; #IO_L4P_T0_34 Sch=jb_p[4] +#set_property -dict { PACKAGE_PIN W13 IOSTANDARD LVCMOS33 } [get_ports { jb[7] }]; #IO_L4N_T0_34 Sch=jb_n[4] + +##Audio Out + +#set_property -dict { PACKAGE_PIN R18 IOSTANDARD LVCMOS33 } [get_ports { aud_pwm }]; #IO_L20N_T3_34 Sch=aud_pwm +#set_property -dict { PACKAGE_PIN T17 IOSTANDARD LVCMOS33 } [get_ports { aud_sd }]; #IO_L20P_T3_34 Sch=aud_sd + +##Mic input + +#set_property -dict { PACKAGE_PIN F17 IOSTANDARD LVCMOS33 } [get_ports { m_clk }]; #IO_L6N_T0_VREF_35 Sch=m_clk +#set_property -dict { PACKAGE_PIN G18 IOSTANDARD LVCMOS33 } [get_ports { m_data }]; #IO_L16N_T2_35 Sch=m_data + +##ChipKit Single Ended Analog Inputs +##NOTE: The ck_an_p pins can be used as single ended analog inputs with voltages from 0-3.3V (Chipkit Analog pins A0-A5). +## These signals should only be connected to the XADC core. When using these pins as digital I/O, use pins ck_io[14-19]. + +#set_property -dict { PACKAGE_PIN D18 IOSTANDARD LVCMOS33 } [get_ports { ck_an_n[0] }]; #IO_L3N_T0_DQS_AD1N_35 Sch=ck_an_n[0] +#set_property -dict { PACKAGE_PIN E17 IOSTANDARD LVCMOS33 } [get_ports { ck_an_p[0] }]; #IO_L3P_T0_DQS_AD1P_35 Sch=ck_an_p[0] +#set_property -dict { PACKAGE_PIN E19 IOSTANDARD LVCMOS33 } [get_ports { ck_an_n[1] }]; #IO_L5N_T0_AD9N_35 Sch=ck_an_n[1] +#set_property -dict { PACKAGE_PIN E18 IOSTANDARD LVCMOS33 } [get_ports { ck_an_p[1] }]; #IO_L5P_T0_AD9P_35 Sch=ck_an_p[1] +#set_property -dict { PACKAGE_PIN J14 IOSTANDARD LVCMOS33 } [get_ports { ck_an_n[2] }]; #IO_L20N_T3_AD6N_35 Sch=ck_an_n[2] +#set_property -dict { PACKAGE_PIN K14 IOSTANDARD LVCMOS33 } [get_ports { ck_an_p[2] }]; #IO_L20P_T3_AD6P_35 Sch=ck_an_p[2] +#set_property -dict { PACKAGE_PIN J16 IOSTANDARD LVCMOS33 } [get_ports { ck_an_n[3] }]; #IO_L24N_T3_AD15N_35 Sch=ck_an_n[3] +#set_property -dict { PACKAGE_PIN K16 IOSTANDARD LVCMOS33 } [get_ports { ck_an_p[3] }]; #IO_L24P_T3_AD15P_35 Sch=ck_an_p[3] +#set_property -dict { PACKAGE_PIN H20 IOSTANDARD LVCMOS33 } [get_ports { ck_an_n[4] }]; #IO_L17N_T2_AD5N_35 Sch=ck_an_n[4] +#set_property -dict { PACKAGE_PIN J20 IOSTANDARD LVCMOS33 } [get_ports { ck_an_p[4] }]; #IO_L17P_T2_AD5P_35 Sch=ck_an_p[4] +#set_property -dict { PACKAGE_PIN G20 IOSTANDARD LVCMOS33 } [get_ports { ck_an_n[5] }]; #IO_L18N_T2_AD13N_35 Sch=ck_an_n[5] +#set_property -dict { PACKAGE_PIN G19 IOSTANDARD LVCMOS33 } [get_ports { ck_an_p[5] }]; #IO_L18P_T2_AD13P_35 Sch=ck_an_p[5] + +##ChipKit Digital I/O Low + +#set_property -dict { PACKAGE_PIN T14 IOSTANDARD LVCMOS33 } [get_ports { ck_io[0] }]; #IO_L5P_T0_34 Sch=ck_io[0] +#set_property -dict { PACKAGE_PIN U12 IOSTANDARD LVCMOS33 } [get_ports { ck_io[1] }]; #IO_L2N_T0_34 Sch=ck_io[1] +#set_property -dict { PACKAGE_PIN U13 IOSTANDARD LVCMOS33 } [get_ports { ck_io[2] }]; #IO_L3P_T0_DQS_PUDC_B_34 Sch=ck_io[2] +#set_property -dict { PACKAGE_PIN V13 IOSTANDARD LVCMOS33 } [get_ports { ck_io[3] }]; #IO_L3N_T0_DQS_34 Sch=ck_io[3] +#set_property -dict { PACKAGE_PIN V15 IOSTANDARD LVCMOS33 } [get_ports { ck_io[4] }]; #IO_L10P_T1_34 Sch=ck_io[4] +#set_property -dict { PACKAGE_PIN T15 IOSTANDARD LVCMOS33 } [get_ports { ck_io[5] }]; #IO_L5N_T0_34 Sch=ck_io[5] +#set_property -dict { PACKAGE_PIN R16 IOSTANDARD LVCMOS33 } [get_ports { ck_io[6] }]; #IO_L19P_T3_34 Sch=ck_io[6] +#set_property -dict { PACKAGE_PIN U17 IOSTANDARD LVCMOS33 } [get_ports { ck_io[7] }]; #IO_L9N_T1_DQS_34 Sch=ck_io[7] +#set_property -dict { PACKAGE_PIN V17 IOSTANDARD LVCMOS33 } [get_ports { ck_io[8] }]; #IO_L21P_T3_DQS_34 Sch=ck_io[8] +#set_property -dict { PACKAGE_PIN V18 IOSTANDARD LVCMOS33 } [get_ports { ck_io[9] }]; #IO_L21N_T3_DQS_34 Sch=ck_io[9] +#set_property -dict { PACKAGE_PIN T16 IOSTANDARD LVCMOS33 } [get_ports { ck_io[10] }]; #IO_L9P_T1_DQS_34 Sch=ck_io[10] +#set_property -dict { PACKAGE_PIN R17 IOSTANDARD LVCMOS33 } [get_ports { ck_io[11] }]; #IO_L19N_T3_VREF_34 Sch=ck_io[11] +#set_property -dict { PACKAGE_PIN P18 IOSTANDARD LVCMOS33 } [get_ports { ck_io[12] }]; #IO_L23N_T3_34 Sch=ck_io[12] +#set_property -dict { PACKAGE_PIN N17 IOSTANDARD LVCMOS33 } [get_ports { ck_io[13] }]; #IO_L23P_T3_34 Sch=ck_io[13] + +##ChipKit Digital I/O On Outer Analog Header +##NOTE: These pins should be used when using the analog header signals A0-A5 as digital I/O (Chipkit digital pins 14-19) + +#set_property -dict { PACKAGE_PIN Y11 IOSTANDARD LVCMOS33 } [get_ports { ck_io[14] }]; #IO_L18N_T2_13 Sch=ck_a[0] +#set_property -dict { PACKAGE_PIN Y12 IOSTANDARD LVCMOS33 } [get_ports { ck_io[15] }]; #IO_L20P_T3_13 Sch=ck_a[1] +#set_property -dict { PACKAGE_PIN W11 IOSTANDARD LVCMOS33 } [get_ports { ck_io[16] }]; #IO_L18P_T2_13 Sch=ck_a[2] +#set_property -dict { PACKAGE_PIN V11 IOSTANDARD LVCMOS33 } [get_ports { ck_io[17] }]; #IO_L21P_T3_DQS_13 Sch=ck_a[3] +#set_property -dict { PACKAGE_PIN T5 IOSTANDARD LVCMOS33 } [get_ports { ck_io[18] }]; #IO_L19P_T3_13 Sch=ck_a[4] +#set_property -dict { PACKAGE_PIN U10 IOSTANDARD LVCMOS33 } [get_ports { ck_io[19] }]; #IO_L12N_T1_MRCC_13 Sch=ck_a[5] + +##ChipKit Digital I/O On Inner Analog Header +##NOTE: These pins will need to be connected to the XADC core when used as differential analog inputs (Chipkit analog pins A6-A11) + +#set_property -dict { PACKAGE_PIN B20 IOSTANDARD LVCMOS33 } [get_ports { ck_io[20] }]; #IO_L1N_T0_AD0N_35 Sch=ad_n[0] +#set_property -dict { PACKAGE_PIN C20 IOSTANDARD LVCMOS33 } [get_ports { ck_io[21] }]; #IO_L1P_T0_AD0P_35 Sch=ad_p[0] +#set_property -dict { PACKAGE_PIN F20 IOSTANDARD LVCMOS33 } [get_ports { ck_io[22] }]; #IO_L15N_T2_DQS_AD12N_35 Sch=ad_n[12] +#set_property -dict { PACKAGE_PIN F19 IOSTANDARD LVCMOS33 } [get_ports { ck_io[23] }]; #IO_L15P_T2_DQS_AD12P_35 Sch=ad_p[12] +#set_property -dict { PACKAGE_PIN A20 IOSTANDARD LVCMOS33 } [get_ports { ck_io[24] }]; #IO_L2N_T0_AD8N_35 Sch=ad_n[8] +#set_property -dict { PACKAGE_PIN B19 IOSTANDARD LVCMOS33 } [get_ports { ck_io[25] }]; #IO_L2P_T0_AD8P_35 Sch=ad_p[8] + +##ChipKit Digital I/O High + +#set_property -dict { PACKAGE_PIN U5 IOSTANDARD LVCMOS33 } [get_ports { ck_io[26] }]; #IO_L19N_T3_VREF_13 Sch=ck_io[26] +#set_property -dict { PACKAGE_PIN V5 IOSTANDARD LVCMOS33 } [get_ports { ck_io[27] }]; #IO_L6N_T0_VREF_13 Sch=ck_io[27] +#set_property -dict { PACKAGE_PIN V6 IOSTANDARD LVCMOS33 } [get_ports { ck_io[28] }]; #IO_L22P_T3_13 Sch=ck_io[28] +#set_property -dict { PACKAGE_PIN U7 IOSTANDARD LVCMOS33 } [get_ports { ck_io[29] }]; #IO_L11P_T1_SRCC_13 Sch=ck_io[29] +#set_property -dict { PACKAGE_PIN V7 IOSTANDARD LVCMOS33 } [get_ports { ck_io[30] }]; #IO_L11N_T1_SRCC_13 Sch=ck_io[30] +#set_property -dict { PACKAGE_PIN U8 IOSTANDARD LVCMOS33 } [get_ports { ck_io[31] }]; #IO_L17N_T2_13 Sch=ck_io[31] +#set_property -dict { PACKAGE_PIN V8 IOSTANDARD LVCMOS33 } [get_ports { ck_io[32] }]; #IO_L15P_T2_DQS_13 Sch=ck_io[32] +#set_property -dict { PACKAGE_PIN V10 IOSTANDARD LVCMOS33 } [get_ports { ck_io[33] }]; #IO_L21N_T3_DQS_13 Sch=ck_io[33] +#set_property -dict { PACKAGE_PIN W10 IOSTANDARD LVCMOS33 } [get_ports { ck_io[34] }]; #IO_L16P_T2_13 Sch=ck_io[34] +#set_property -dict { PACKAGE_PIN W6 IOSTANDARD LVCMOS33 } [get_ports { ck_io[35] }]; #IO_L22N_T3_13 Sch=ck_io[35] +#set_property -dict { PACKAGE_PIN Y6 IOSTANDARD LVCMOS33 } [get_ports { ck_io[36] }]; #IO_L13N_T2_MRCC_13 Sch=ck_io[36] +#set_property -dict { PACKAGE_PIN Y7 IOSTANDARD LVCMOS33 } [get_ports { ck_io[37] }]; #IO_L13P_T2_MRCC_13 Sch=ck_io[37] +#set_property -dict { PACKAGE_PIN W8 IOSTANDARD LVCMOS33 } [get_ports { ck_io[38] }]; #IO_L15N_T2_DQS_13 Sch=ck_io[38] +#set_property -dict { PACKAGE_PIN Y8 IOSTANDARD LVCMOS33 } [get_ports { ck_io[39] }]; #IO_L14N_T2_SRCC_13 Sch=ck_io[39] +#set_property -dict { PACKAGE_PIN W9 IOSTANDARD LVCMOS33 } [get_ports { ck_io[40] }]; #IO_L16N_T2_13 Sch=ck_io[40] +#set_property -dict { PACKAGE_PIN Y9 IOSTANDARD LVCMOS33 } [get_ports { ck_io[41] }]; #IO_L14P_T2_SRCC_13 Sch=ck_io[41] +#set_property -dict { PACKAGE_PIN Y13 IOSTANDARD LVCMOS33 } [get_ports { ck_io[42] }]; #IO_L20N_T3_13 Sch=ck_ioa + +## ChipKit SPI + +#set_property -dict { PACKAGE_PIN W15 IOSTANDARD LVCMOS33 } [get_ports { ck_miso }]; #IO_L10N_T1_34 Sch=ck_miso +#set_property -dict { PACKAGE_PIN T12 IOSTANDARD LVCMOS33 } [get_ports { ck_mosi }]; #IO_L2P_T0_34 Sch=ck_mosi +#set_property -dict { PACKAGE_PIN H15 IOSTANDARD LVCMOS33 } [get_ports { ck_sck }]; #IO_L19P_T3_35 Sch=ck_sck +#set_property -dict { PACKAGE_PIN F16 IOSTANDARD LVCMOS33 } [get_ports { ck_ss }]; #IO_L6P_T0_35 Sch=ck_ss + +## ChipKit I2C + +#set_property -dict { PACKAGE_PIN P16 IOSTANDARD LVCMOS33 } [get_ports { ck_scl }]; #IO_L24N_T3_34 Sch=ck_scl +#set_property -dict { PACKAGE_PIN P15 IOSTANDARD LVCMOS33 } [get_ports { ck_sda }]; #IO_L24P_T3_34 Sch=ck_sda + +##HDMI Rx + +#set_property -dict { PACKAGE_PIN H17 IOSTANDARD LVCMOS33 } [get_ports { hdmi_rx_cec }]; #IO_L13N_T2_MRCC_35 Sch=hdmi_rx_cec +set_property -dict { PACKAGE_PIN P19 IOSTANDARD TMDS_33 } [get_ports { io_debug_hdmi_clk_n }]; #IO_L13N_T2_MRCC_34 Sch=hdmi_rx_clk_n +set_property -dict { PACKAGE_PIN N18 IOSTANDARD TMDS_33 } [get_ports { io_debug_hdmi_clk_p }]; #IO_L13P_T2_MRCC_34 Sch=hdmi_rx_clk_p +set_property -dict { PACKAGE_PIN W20 IOSTANDARD TMDS_33 } [get_ports { io_debug_hdmi_data_n[0] }]; #IO_L16N_T2_34 Sch=hdmi_rx_d_n[0] +set_property -dict { PACKAGE_PIN V20 IOSTANDARD TMDS_33 } [get_ports { io_debug_hdmi_data_p[0] }]; #IO_L16P_T2_34 Sch=hdmi_rx_d_p[0] +set_property -dict { PACKAGE_PIN U20 IOSTANDARD TMDS_33 } [get_ports { io_debug_hdmi_data_n[1] }]; #IO_L15N_T2_DQS_34 Sch=hdmi_rx_d_n[1] +set_property -dict { PACKAGE_PIN T20 IOSTANDARD TMDS_33 } [get_ports { io_debug_hdmi_data_p[1] }]; #IO_L15P_T2_DQS_34 Sch=hdmi_rx_d_p[1] +set_property -dict { PACKAGE_PIN P20 IOSTANDARD TMDS_33 } [get_ports { io_debug_hdmi_data_n[2] }]; #IO_L14N_T2_SRCC_34 Sch=hdmi_rx_d_n[2] +set_property -dict { PACKAGE_PIN N20 IOSTANDARD TMDS_33 } [get_ports { io_debug_hdmi_data_p[2] }]; #IO_L14P_T2_SRCC_34 Sch=hdmi_rx_d_p[2] +set_property -dict { PACKAGE_PIN T19 IOSTANDARD LVCMOS33 } [get_ports { io_debug_hdmi_hpdn }]; #IO_25_34 Sch=hdmi_rx_hpd +#set_property -dict { PACKAGE_PIN U14 IOSTANDARD LVCMOS33 } [get_ports { hdmi_rx_scl }]; #IO_L11P_T1_SRCC_34 Sch=hdmi_rx_scl +#set_property -dict { PACKAGE_PIN U15 IOSTANDARD LVCMOS33 } [get_ports { hdmi_rx_sda }]; #IO_L11N_T1_SRCC_34 Sch=hdmi_rx_sda + +##HDMI Tx + +#set_property -dict { PACKAGE_PIN G15 IOSTANDARD LVCMOS33 } [get_ports { hdmi_tx_cec }]; #IO_L19N_T3_VREF_35 Sch=hdmi_tx_cec +set_property -dict {PACKAGE_PIN L17 IOSTANDARD TMDS_33} [get_ports io_hdmi_clk_n] +set_property -dict {PACKAGE_PIN L16 IOSTANDARD TMDS_33} [get_ports io_hdmi_clk_p] +set_property -dict {PACKAGE_PIN K18 IOSTANDARD TMDS_33} [get_ports {io_hdmi_data_n[0]}] +set_property -dict {PACKAGE_PIN K17 IOSTANDARD TMDS_33} [get_ports {io_hdmi_data_p[0]}] +set_property -dict {PACKAGE_PIN J19 IOSTANDARD TMDS_33} [get_ports {io_hdmi_data_n[1]}] +set_property -dict {PACKAGE_PIN K19 IOSTANDARD TMDS_33} [get_ports {io_hdmi_data_p[1]}] +set_property -dict {PACKAGE_PIN H18 IOSTANDARD TMDS_33} [get_ports {io_hdmi_data_n[2]}] +set_property -dict {PACKAGE_PIN J18 IOSTANDARD TMDS_33} [get_ports {io_hdmi_data_p[2]}] +set_property -dict {PACKAGE_PIN R19 IOSTANDARD LVCMOS33} [get_ports io_hdmi_hpdn] +#set_property -dict { PACKAGE_PIN M17 IOSTANDARD LVCMOS33 } [get_ports { hdmi_tx_scl }]; #IO_L8P_T1_AD10P_35 Sch=hdmi_tx_scl +#set_property -dict { PACKAGE_PIN M18 IOSTANDARD LVCMOS33 } [get_ports { hdmi_tx_sda }]; #IO_L8N_T1_AD10N_35 Sch=hdmi_tx_sda + +##Crypto SDA + +#set_property -dict { PACKAGE_PIN J15 IOSTANDARD LVCMOS33 } [get_ports { crypto_sda }]; #IO_25_35 Sch=crypto_sda diff --git a/lab3/vivado/pynq/run.ps1 b/lab3/vivado/pynq/run.ps1 new file mode 100644 index 0000000..178feab --- /dev/null +++ b/lab3/vivado/pynq/run.ps1 @@ -0,0 +1,4 @@ +cd .. +sbt run +cd vivado +C:\Xilinx\Vivado\2020.1\bin\vivado -mode batch -source .\generate_and_program.tcl \ No newline at end of file diff --git a/lab3/vivado/pynq/run_simulation.tcl b/lab3/vivado/pynq/run_simulation.tcl new file mode 100644 index 0000000..f1f021a --- /dev/null +++ b/lab3/vivado/pynq/run_simulation.tcl @@ -0,0 +1,28 @@ +# 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. + +source open_project.tcl + +launch_simulation +restart +open_vcd +#log_wave -recursive [get_object /test/top/hdmi_display/*] +#log_vcd [get_object /test/top/hdmi_display/*] +#log_wave -recursive [get_object /test/top/*] +#log_vcd [get_object /test/top/*] +log_wave -recursive [get_object /test/top/hdmi_display/serdesBlue/osr10/*] +log_vcd [get_object /test/top/hdmi_display/serdesBlue/osr10/*] +run 1000000ns +close_vcd +close_sim diff --git a/lab4/.gitignore b/lab4/.gitignore new file mode 100644 index 0000000..946816b --- /dev/null +++ b/lab4/.gitignore @@ -0,0 +1,358 @@ +### Project Specific stuff +test_run_dir/* +### XilinxISE template +# intermediate build files +*.bgn +*.bit +*.bld +*.cmd_log +*.drc +*.ll +*.lso +*.msd +*.msk +*.ncd +*.ngc +*.ngd +*.ngr +*.pad +*.par +*.pcf +*.prj +*.ptwx +*.rbb +*.rbd +*.stx +*.syr +*.twr +*.twx +*.unroutes +*.ut +*.xpi +*.xst +*_bitgen.xwbt +*_envsettings.html +*_map.map +*_map.mrp +*_map.ngm +*_map.xrpt +*_ngdbuild.xrpt +*_pad.csv +*_pad.txt +*_par.xrpt +*_summary.html +*_summary.xml +*_usage.xml +*_xst.xrpt + +# project-wide generated files +*.gise +par_usage_statistics.html +usage_statistics_webtalk.html +webtalk.log +webtalk_pn.xml + +# generated folders +iseconfig/ +xlnx_auto_0_xdb/ +xst/ +_ngo/ +_xmsgs/ +### Eclipse template +*.pydevproject +.metadata +.gradle +bin/ +tmp/ +*.tmp +*.bak +*.swp +*~.nib +local.properties +.settings/ +.loadpath + +# Eclipse Core +.project + +# External tool builders +.externalToolBuilders/ + +# Locally stored "Eclipse launch configurations" +*.launch + +# CDT-specific +.cproject + +# JDT-specific (Eclipse Java Development Tools) +.classpath + +# Java annotation processor (APT) +.factorypath + +# PDT-specific +.buildpath + +# sbteclipse plugin +.target + +# TeXlipse plugin +.texlipse +### C template +# Object files +*.o +*.ko +*.obj +*.elf + +# Precompiled Headers +*.gch +*.pch + +# Libraries +*.lib +*.a +*.la +*.lo + +# Shared objects (inc. Windows DLLs) +*.dll +*.so +*.so.* +*.dylib + +# Executables +*.exe +*.out +*.app +*.i*86 +*.x86_64 +*.hex + +# Debug files +*.dSYM/ +### SBT template +# Simple Build Tool +# http://www.scala-sbt.org/release/docs/Getting-Started/Directories.html#configuring-version-control + +target/ +lib_managed/ +src_managed/ +project/boot/ +.history +.cache +### Emacs template +# -*- mode: gitignore; -*- +*~ +\#*\# +/.emacs.desktop +/.emacs.desktop.lock +*.elc +auto-save-list +tramp +.\#* + +# Org-mode +.org-id-locations +*_archive + +# flymake-mode +*_flymake.* + +# eshell files +/eshell/history +/eshell/lastdir + +# elpa packages +/elpa/ + +# reftex files +*.rel + +# AUCTeX auto folder +/auto/ + +# cask packages +.cask/ +### Vim template +[._]*.s[a-w][a-z] +[._]s[a-w][a-z] +*.un~ +Session.vim +.netrwhist +*~ +### JetBrains template +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio + +*.iml + +## Directory-based project format: +.idea/ +# if you remove the above rule, at least ignore the following: + +# User-specific stuff: +# .idea/workspace.xml +# .idea/tasks.xml +# .idea/dictionaries + +# Sensitive or high-churn files: +# .idea/dataSources.ids +# .idea/dataSources.xml +# .idea/sqlDataSources.xml +# .idea/dynamic.xml +# .idea/uiDesigner.xml + +# Gradle: +# .idea/gradle.xml +# .idea/libraries + +# Mongo Explorer plugin: +# .idea/mongoSettings.xml + +## File-based project format: +*.ipr +*.iws + +## Plugin-specific files: + +# IntelliJ +/out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +### C++ template +# Compiled Object files +*.slo +*.lo +*.o +*.obj + +# Precompiled Headers +*.gch +*.pch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app +### OSX template +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk +### Xcode template +# Xcode +# +# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore + +## Build generated +build/ +DerivedData + +## Various settings +*.pbxuser +!default.pbxuser +*.mode1v3 +!default.mode1v3 +*.mode2v3 +!default.mode2v3 +*.perspectivev3 +!default.perspectivev3 +xcuserdata + +## Other +*.xccheckout +*.moved-aside +*.xcuserstate +### Scala template +*.class +*.log +/.bsp + +# sbt specific +.cache +.history +.lib/ +dist/* +target/ +lib_managed/ +src_managed/ +project/boot/ +project/plugins/project/ + +# Scala-IDE specific +.scala_dependencies +.worksheet +### Java template +*.class + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.ear + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* + +verilog/*.txt +verilog/basys3/* +verilog/pynq/* +verilog/verilator/* +!verilog/basys3/test.v +!verilog/pynq/design_1_wrapper.v +!verilog/pynq/test.v +!verilog/pynq/TMDS_PLLVR.v +!verilog/verilator/sim_main.cpp +*.jou +*.log +.Xil +vivado/basys3/riscv-basys3 +vivado/pynq/riscv-pynq +vivado/pynq/NA +.vscode +.metals diff --git a/lab4/Makefile b/lab4/Makefile new file mode 100644 index 0000000..1bffd0a --- /dev/null +++ b/lab4/Makefile @@ -0,0 +1,47 @@ +# 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. + +test: + sbt test + +verilator: + sbt "runMain board.verilator.VerilogGenerator" + cd verilog/verilator && verilator --trace --exe --cc sim_main.cpp Top.v && make -C obj_dir -f VTop.mk + +verilator-sim: verilator + cd verilog/verilator && obj_dir/VTop $(SIM_TIME) + +basys3: + sbt "runMain board.basys3.VerilogGenerator" +pynq: + sbt "runMain board.pynq.VerilogGenerator" + +bitstream-basys3: basys3 + cd vivado/basys3 && vivado -mode batch -source generate_bitstream.tcl + +program-basys3: bitstream-basys3 + cd vivado/basys3 && vivado -mode batch -source program_device.tcl + +vivado-sim-basys3: basys3 + cd vivado/basys3 && vivado -mode batch -source run_simulation.tcl +bitstream-pynq: pynq + cd vivado/pynq && vivado -mode batch -source generate_bitstream.tcl + +program-pynq: bitstream-pynq + cd vivado/pynq && vivado -mode batch -source program_device.tcl + +vivado-sim-pynq: pynq + cd vivado/pynq && vivado -mode batch -source run_simulation.tcl + +.PHONY: basys3 verilator test bitstream program verilator-sim vivado-sim diff --git a/lab4/build.sbt b/lab4/build.sbt new file mode 100644 index 0000000..75f138e --- /dev/null +++ b/lab4/build.sbt @@ -0,0 +1,24 @@ +import sbt.Keys.libraryDependencies +// See README.md for license details. + +ThisBuild / scalaVersion := "2.13.10" +ThisBuild / version := "0.1.0" +ThisBuild / organization := "io.github.howardlau1999" + +val chiselVersion = "3.6.0" + +lazy val root = (project in file(".")) + .settings( + name := "yatcpu", + libraryDependencies ++= Seq( + "edu.berkeley.cs" %% "chisel3" % chiselVersion, + "edu.berkeley.cs" %% "chiseltest" % "0.6.0" % "test", + ), + scalacOptions ++= Seq( + "-language:reflectiveCalls", + "-deprecation", + "-feature", + "-Xcheckinit", + ), + addCompilerPlugin("edu.berkeley.cs" % "chisel3-plugin" % chiselVersion cross CrossVersion.full), + ) diff --git a/lab4/coremark/yatcpu/core_portme.c b/lab4/coremark/yatcpu/core_portme.c new file mode 100644 index 0000000..3d7ae3b --- /dev/null +++ b/lab4/coremark/yatcpu/core_portme.c @@ -0,0 +1,169 @@ +/* +Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) + +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. + +Original Author: Shay Gal-on +*/ +#include "coremark.h" +#include "core_portme.h" + +#if VALIDATION_RUN +volatile ee_s32 seed1_volatile = 0x3415; +volatile ee_s32 seed2_volatile = 0x3415; +volatile ee_s32 seed3_volatile = 0x66; +#endif +#if PERFORMANCE_RUN +volatile ee_s32 seed1_volatile = 0x0; +volatile ee_s32 seed2_volatile = 0x0; +volatile ee_s32 seed3_volatile = 0x66; +#endif +#if PROFILE_RUN +volatile ee_s32 seed1_volatile = 0x8; +volatile ee_s32 seed2_volatile = 0x8; +volatile ee_s32 seed3_volatile = 0x8; +#endif +volatile ee_s32 seed4_volatile = ITERATIONS; +volatile ee_s32 seed5_volatile = 0; +/* Porting : Timing functions + How to capture time and convert to seconds must be ported to whatever is + supported by the platform. e.g. Read value from on board RTC, read value from + cpu clock cycles performance counter etc. Sample implementation for standard + time.h and windows.h definitions included. +*/ +CORETIMETYPE +barebones_clock() +{ + ee_u32 cyclel; + __asm__ __volatile__ ( + "rdcycle %0" : "=r"(cyclel) : : + ); + return cyclel; +} +/* Define : TIMER_RES_DIVIDER + Divider to trade off timer resolution and total time that can be + measured. + + Use lower values to increase resolution, but make sure that overflow + does not occur. If there are issues with the return value overflowing, + increase this value. + */ +#define GETMYTIME(_t) (*_t = barebones_clock()) +#define MYTIMEDIFF(fin, ini) ((fin) - (ini)) +#define TIMER_RES_DIVIDER 1 +#define SAMPLE_TIME_IMPLEMENTATION 1 +#define EE_TICKS_PER_SEC (CLOCKS_PER_SEC / TIMER_RES_DIVIDER) + +/** Define Host specific (POSIX), or target specific global time variables. */ +static CORETIMETYPE start_time_val, stop_time_val; + +/* Function : start_time + This function will be called right before starting the timed portion of + the benchmark. + + Implementation may be capturing a system timer (as implemented in the + example code) or zeroing some system parameters - e.g. setting the cpu clocks + cycles to 0. +*/ +void +start_time(void) +{ + GETMYTIME(&start_time_val); +} +/* Function : stop_time + This function will be called right after ending the timed portion of the + benchmark. + + Implementation may be capturing a system timer (as implemented in the + example code) or other system parameters - e.g. reading the current value of + cpu cycles counter. +*/ +void +stop_time(void) +{ + GETMYTIME(&stop_time_val); +} +/* Function : get_time + Return an abstract "ticks" number that signifies time on the system. + + Actual value returned may be cpu cycles, milliseconds or any other + value, as long as it can be converted to seconds by . This + methodology is taken to accommodate any hardware or simulated platform. The + sample implementation returns millisecs by default, and the resolution is + controlled by +*/ +CORE_TICKS +get_time(void) +{ + CORE_TICKS elapsed + = (CORE_TICKS)(MYTIMEDIFF(stop_time_val, start_time_val)); + return elapsed; +} +/* Function : time_in_secs + Convert the value returned by get_time to seconds. + + The type is used to accommodate systems with no support for + floating point. Default implementation implemented by the EE_TICKS_PER_SEC + macro above. +*/ +secs_ret +time_in_secs(CORE_TICKS ticks) +{ + secs_ret retval = ((secs_ret)ticks) / (secs_ret)EE_TICKS_PER_SEC; + return retval; +} + +ee_u32 default_num_contexts = 1; + +/* Function : portable_init + Target specific initialization code + Test for some common mistakes. +*/ +void +portable_init(core_portable *p, int *argc, char *argv[]) +{ + if (sizeof(ee_ptr_int) != sizeof(ee_u8 *)) + { + ee_printf( + "ERROR! Please define ee_ptr_int to a type that holds a " + "pointer!\n"); + } + if (sizeof(ee_u32) != 4) + { + ee_printf("ERROR! Please define ee_u32 to a 32b unsigned type!\n"); + } + p->portable_id = 1; +} +/* Function : portable_fini + Target specific final code +*/ +void +portable_fini(core_portable *p) +{ + p->portable_id = 0; +} + +unsigned int +__mulsi3 (unsigned int a, unsigned int b) +{ + unsigned int r = 0; + + while (a) + { + if (a & 1) + r += b; + a >>= 1; + b <<= 1; + } + return r; +} \ No newline at end of file diff --git a/lab4/coremark/yatcpu/core_portme.h b/lab4/coremark/yatcpu/core_portme.h new file mode 100644 index 0000000..7b0d646 --- /dev/null +++ b/lab4/coremark/yatcpu/core_portme.h @@ -0,0 +1,211 @@ +/* +Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) + +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. + +Original Author: Shay Gal-on +*/ +/* Topic : Description + This file contains configuration constants required to execute on + different platforms +*/ +#ifndef CORE_PORTME_H +#define CORE_PORTME_H +/************************/ +/* Data types and settings */ +/************************/ +/* Configuration : HAS_FLOAT + Define to 1 if the platform supports floating point. +*/ +#ifndef HAS_FLOAT +#define HAS_FLOAT 0 +#endif +/* Configuration : HAS_TIME_H + Define to 1 if platform has the time.h header file, + and implementation of functions thereof. +*/ +#ifndef HAS_TIME_H +#define HAS_TIME_H 0 +#define CLOCKS_PER_SEC 100000000 +#endif +/* Configuration : USE_CLOCK + Define to 1 if platform has the time.h header file, + and implementation of functions thereof. +*/ +#ifndef USE_CLOCK +#define USE_CLOCK 0 +#endif +/* Configuration : HAS_STDIO + Define to 1 if the platform has stdio.h. +*/ +#ifndef HAS_STDIO +#define HAS_STDIO 0 +#endif +/* Configuration : HAS_PRINTF + Define to 1 if the platform has stdio.h and implements the printf + function. +*/ +#ifndef HAS_PRINTF +#define HAS_PRINTF 0 +#endif + +/* Definitions : COMPILER_VERSION, COMPILER_FLAGS, MEM_LOCATION + Initialize these strings per platform +*/ +#ifndef COMPILER_VERSION +#ifdef __GNUC__ +#define COMPILER_VERSION "GCC"__VERSION__ +#else +#define COMPILER_VERSION "Please put compiler version here (e.g. gcc 4.1)" +#endif +#endif +#ifndef COMPILER_FLAGS +#define COMPILER_FLAGS \ + FLAGS_STR /* "Please put compiler flags here (e.g. -o3)" */ +#endif +#ifndef MEM_LOCATION +#define MEM_LOCATION "STACK" +#endif + +/* Data Types : + To avoid compiler issues, define the data types that need ot be used for + 8b, 16b and 32b in . + + *Imprtant* : + ee_ptr_int needs to be the data type used to hold pointers, otherwise + coremark may fail!!! +*/ +typedef signed short ee_s16; +typedef unsigned short ee_u16; +typedef signed int ee_s32; +typedef double ee_f32; +typedef unsigned char ee_u8; +typedef unsigned int ee_u32; +typedef ee_u32 ee_ptr_int; +typedef ee_u32 ee_size_t; +#define NULL ((void *)0) +/* align_mem : + This macro is used to align an offset to point to a 32b value. It is + used in the Matrix algorithm to initialize the input memory blocks. +*/ +#define align_mem(x) (void *)(4 + (((ee_ptr_int)(x)-1) & ~3)) + +/* Configuration : CORE_TICKS + Define type of return from the timing functions. + */ +#define CORETIMETYPE ee_u32 +typedef ee_u32 CORE_TICKS; + +/* Configuration : SEED_METHOD + Defines method to get seed values that cannot be computed at compile + time. + + Valid values : + SEED_ARG - from command line. + SEED_FUNC - from a system function. + SEED_VOLATILE - from volatile variables. +*/ +#ifndef SEED_METHOD +#define SEED_METHOD SEED_VOLATILE +#endif + +/* Configuration : MEM_METHOD + Defines method to get a block of memry. + + Valid values : + MEM_MALLOC - for platforms that implement malloc and have malloc.h. + MEM_STATIC - to use a static memory array. + MEM_STACK - to allocate the data block on the stack (NYI). +*/ +#ifndef MEM_METHOD +#define MEM_METHOD MEM_STATIC +#endif + +/* Configuration : MULTITHREAD + Define for parallel execution + + Valid values : + 1 - only one context (default). + N>1 - will execute N copies in parallel. + + Note : + If this flag is defined to more then 1, an implementation for launching + parallel contexts must be defined. + + Two sample implementations are provided. Use or + to enable them. + + It is valid to have a different implementation of + and in , to fit a particular architecture. +*/ +#ifndef MULTITHREAD +#define MULTITHREAD 1 +#define USE_PTHREAD 0 +#define USE_FORK 0 +#define USE_SOCKET 0 +#endif + +/* Configuration : MAIN_HAS_NOARGC + Needed if platform does not support getting arguments to main. + + Valid values : + 0 - argc/argv to main is supported + 1 - argc/argv to main is not supported + + Note : + This flag only matters if MULTITHREAD has been defined to a value + greater then 1. +*/ +#ifndef MAIN_HAS_NOARGC +#define MAIN_HAS_NOARGC 1 +#endif + +/* Configuration : MAIN_HAS_NORETURN + Needed if platform does not support returning a value from main. + + Valid values : + 0 - main returns an int, and return value will be 0. + 1 - platform does not support returning a value from main +*/ +#ifndef MAIN_HAS_NORETURN +#define MAIN_HAS_NORETURN 0 +#endif + +/* Variable : default_num_contexts + Not used for this simple port, must contain the value 1. +*/ +extern ee_u32 default_num_contexts; + +typedef struct CORE_PORTABLE_S +{ + ee_u8 portable_id; +} core_portable; + +/* target specific init/fini */ +void portable_init(core_portable *p, int *argc, char *argv[]); +void portable_fini(core_portable *p); + +#if !defined(PROFILE_RUN) && !defined(PERFORMANCE_RUN) \ + && !defined(VALIDATION_RUN) +#if (TOTAL_DATA_SIZE == 1200) +#define PROFILE_RUN 1 +#elif (TOTAL_DATA_SIZE == 2000) +#define PERFORMANCE_RUN 1 +#else +#define VALIDATION_RUN 1 +#endif +#endif + +int ee_printf(const char *fmt, ...); + +#endif /* CORE_PORTME_H */ diff --git a/lab4/coremark/yatcpu/core_portme.mak b/lab4/coremark/yatcpu/core_portme.mak new file mode 100644 index 0000000..e26c689 --- /dev/null +++ b/lab4/coremark/yatcpu/core_portme.mak @@ -0,0 +1,92 @@ +# Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) +# +# 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. +# +# Original Author: Shay Gal-on + +#File : core_portme.mak + +# Flag : OUTFLAG +# Use this flag to define how to to get an executable (e.g -o) +OUTFLAG= -o +# Flag : CC +# Use this flag to define compiler to use +CC = clang +# Flag : LD +# Use this flag to define compiler to use +LD = ld.lld +# Flag : AS +# Use this flag to define compiler to use +AS = clang +# Flag : CFLAGS +# Use this flag to define compiler options. Note, you can add compiler options from the command line using XCFLAGS="other flags" +PORT_CFLAGS = -O0 -g --target=riscv32-unknown-elf -march=rv32i -mabi=ilp32 +FLAGS_STR = "$(PORT_CFLAGS) $(XCFLAGS) $(XLFLAGS) $(LFLAGS_END)" +CFLAGS = $(PORT_CFLAGS) -I$(PORT_DIR) -I. -DFLAGS_STR=\"$(FLAGS_STR)\" +#Flag : LFLAGS_END +# Define any libraries needed for linking or other flags that should come at the end of the link line (e.g. linker scripts). +# Note : On certain platforms, the default clock_gettime implementation is supported but requires linking of librt. +SEPARATE_COMPILE=1 +# Flag : SEPARATE_COMPILE +# You must also define below how to create an object file, and how to link. +OBJOUT = -o +LFLAGS = -T $(PORT_DIR)/link.ld +ASFLAGS = -c --target=riscv32-unknown-elf -march=rv32i -mabi=ilp32 +OFLAG = -o +COUT = -c + +LFLAGS_END = +# Flag : PORT_SRCS +# Port specific source files can be added here +# You may also need cvt.c if the fcvt functions are not provided as intrinsics by your compiler! +PORT_SRCS = $(PORT_DIR)/core_portme.c $(PORT_DIR)/ee_printf.c $(PORT_DIR)/div.s $(PORT_DIR)/init.s +vpath %.c $(PORT_DIR) +vpath %.s $(PORT_DIR) + +PORT_OBJS = $(PORT_DIR)/init$(OEXT) $(PORT_DIR)/core_portme$(OEXT) $(PORT_DIR)/ee_printf$(OEXT) $(PORT_DIR)/div$(OEXT) +PORT_CLEAN = *$(OEXT) $(OUTFILE).asmbin + +# Flag : LOAD +# For a simple port, we assume self hosted compile and run, no load needed. + +# Flag : RUN +# For a simple port, we assume self hosted compile and run, simple invocation of the executable + +LOAD = echo "Please set LOAD to the process of loading the executable to the flash" +RUN = echo "Please set LOAD to the process of running the executable (e.g. via jtag, or board reset)" + +OEXT = .o +EXE = .bin + +$(OPATH)$(PORT_DIR)/%$(OEXT) : %.c + $(CC) $(CFLAGS) $(XCFLAGS) $(COUT) $< $(OBJOUT) $@ + +$(OPATH)%$(OEXT) : %.c + $(CC) $(CFLAGS) $(XCFLAGS) $(COUT) $< $(OBJOUT) $@ + +$(OPATH)$(PORT_DIR)/%$(OEXT) : %.s + $(AS) $(ASFLAGS) $< $(OBJOUT) $@ + +# Target : port_pre% and port_post% +# For the purpose of this simple port, no pre or post steps needed. + +.PHONY : port_prebuild port_postbuild port_prerun port_postrun port_preload port_postload +port_postbuild: $(OUTFILE) + llvm-objcopy -O binary -j .text -j .data $(OUTFILE) $(OUTFILE).asmbin +port_pre% port_post% : + +# FLAG : OPATH +# Path to the output folder. Default - current folder. +OPATH = ./ +MKDIR = mkdir -p + diff --git a/lab4/coremark/yatcpu/cvt.c b/lab4/coremark/yatcpu/cvt.c new file mode 100644 index 0000000..333e8ea --- /dev/null +++ b/lab4/coremark/yatcpu/cvt.c @@ -0,0 +1,127 @@ +/* +Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) + +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. +*/ +#include +#define CVTBUFSIZE 80 +static char CVTBUF[CVTBUFSIZE]; + +static char * +cvt(double arg, int ndigits, int *decpt, int *sign, char *buf, int eflag) +{ + int r2; + double fi, fj; + char * p, *p1; + + if (ndigits < 0) + ndigits = 0; + if (ndigits >= CVTBUFSIZE - 1) + ndigits = CVTBUFSIZE - 2; + r2 = 0; + *sign = 0; + p = &buf[0]; + if (arg < 0) + { + *sign = 1; + arg = -arg; + } + arg = modf(arg, &fi); + p1 = &buf[CVTBUFSIZE]; + + if (fi != 0) + { + p1 = &buf[CVTBUFSIZE]; + while (fi != 0) + { + fj = modf(fi / 10, &fi); + *--p1 = (int)((fj + .03) * 10) + '0'; + r2++; + } + while (p1 < &buf[CVTBUFSIZE]) + *p++ = *p1++; + } + else if (arg > 0) + { + while ((fj = arg * 10) < 1) + { + arg = fj; + r2--; + } + } + p1 = &buf[ndigits]; + if (eflag == 0) + p1 += r2; + *decpt = r2; + if (p1 < &buf[0]) + { + buf[0] = '\0'; + return buf; + } + while (p <= p1 && p < &buf[CVTBUFSIZE]) + { + arg *= 10; + arg = modf(arg, &fj); + *p++ = (int)fj + '0'; + } + if (p1 >= &buf[CVTBUFSIZE]) + { + buf[CVTBUFSIZE - 1] = '\0'; + return buf; + } + p = p1; + *p1 += 5; + while (*p1 > '9') + { + *p1 = '0'; + if (p1 > buf) + ++*--p1; + else + { + *p1 = '1'; + (*decpt)++; + if (eflag == 0) + { + if (p > buf) + *p = '0'; + p++; + } + } + } + *p = '\0'; + return buf; +} + +char * +ecvt(double arg, int ndigits, int *decpt, int *sign) +{ + return cvt(arg, ndigits, decpt, sign, CVTBUF, 1); +} + +char * +ecvtbuf(double arg, int ndigits, int *decpt, int *sign, char *buf) +{ + return cvt(arg, ndigits, decpt, sign, buf, 1); +} + +char * +fcvt(double arg, int ndigits, int *decpt, int *sign) +{ + return cvt(arg, ndigits, decpt, sign, CVTBUF, 0); +} + +char * +fcvtbuf(double arg, int ndigits, int *decpt, int *sign, char *buf) +{ + return cvt(arg, ndigits, decpt, sign, buf, 0); +} diff --git a/lab4/coremark/yatcpu/div.s b/lab4/coremark/yatcpu/div.s new file mode 100644 index 0000000..6725293 --- /dev/null +++ b/lab4/coremark/yatcpu/div.s @@ -0,0 +1,71 @@ +.text +.globl __divsi3 +__divsi3: + bltz a0, .L10 + bltz a1, .L11 + +.globl __udivsi3 +__udivsi3: + mv a2, a1 + mv a1, a0 + li a0, -1 + beqz a2, .L5 + li a3, 1 + bgeu a2, a1, .L2 +.L1: + blez a2, .L2 + slli a2, a2, 1 + slli a3, a3, 1 + bgtu a1, a2, .L1 +.L2: + li a0, 0 +.L3: + bltu a1, a2, .L4 + sub a1, a1, a2 + or a0, a0, a3 +.L4: + srli a3, a3, 1 + srli a2, a2, 1 + bnez a3, .L3 +.L5: + ret + +.globl __umodsi3 +__umodsi3: + move t0, ra + jal __udivsi3 + move a0, a1 + jr t0 + +.L10: + neg a0, a0 + bgtz a1, .L12 + + neg a1, a1 + j __udivsi3 +.L11: + neg a1, a1 +.L12: + move t0, ra + jal __udivsi3 + neg a0, a0 + jr t0 + +.globl __modsi3 +__modsi3: + move t0, ra + bltz a1, .L31 + bltz a0, .L32 +.L30: + jal __udivsi3 + move a0, a1 + jr t0 +.L31: + neg a1, a1 + bgez a0, .L30 +.L32: + neg a0, a0 + jal __udivsi3 + neg a0, a1 + jr t0 + diff --git a/lab4/coremark/yatcpu/ee_printf.c b/lab4/coremark/yatcpu/ee_printf.c new file mode 100644 index 0000000..9dde21a --- /dev/null +++ b/lab4/coremark/yatcpu/ee_printf.c @@ -0,0 +1,687 @@ +/* +Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) + +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. +*/ + +#include +#include + +#define ZEROPAD (1 << 0) /* Pad with zero */ +#define SIGN (1 << 1) /* Unsigned/signed long */ +#define PLUS (1 << 2) /* Show plus */ +#define SPACE (1 << 3) /* Spacer */ +#define LEFT (1 << 4) /* Left justified */ +#define HEX_PREP (1 << 5) /* 0x */ +#define UPPERCASE (1 << 6) /* 'ABCDEF' */ + +#define is_digit(c) ((c) >= '0' && (c) <= '9') + +static char * digits = "0123456789abcdefghijklmnopqrstuvwxyz"; +static char * upper_digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; +static ee_size_t strnlen(const char *s, ee_size_t count); + +static ee_size_t +strnlen(const char *s, ee_size_t count) +{ + const char *sc; + for (sc = s; *sc != '\0' && count--; ++sc) + ; + return sc - s; +} + +static int +skip_atoi(const char **s) +{ + int i = 0; + while (is_digit(**s)) + i = i * 10 + *((*s)++) - '0'; + return i; +} + +static char * +number(char *str, long num, int base, int size, int precision, int type) +{ + char c, sign, tmp[66]; + char *dig = digits; + int i; + + if (type & UPPERCASE) + dig = upper_digits; + if (type & LEFT) + type &= ~ZEROPAD; + if (base < 2 || base > 36) + return 0; + + c = (type & ZEROPAD) ? '0' : ' '; + sign = 0; + if (type & SIGN) + { + if (num < 0) + { + sign = '-'; + num = -num; + size--; + } + else if (type & PLUS) + { + sign = '+'; + size--; + } + else if (type & SPACE) + { + sign = ' '; + size--; + } + } + + if (type & HEX_PREP) + { + if (base == 16) + size -= 2; + else if (base == 8) + size--; + } + + i = 0; + + if (num == 0) + tmp[i++] = '0'; + else + { + while (num != 0) + { + tmp[i++] = dig[((unsigned long)num) % (unsigned)base]; + num = ((unsigned long)num) / (unsigned)base; + } + } + + if (i > precision) + precision = i; + size -= precision; + if (!(type & (ZEROPAD | LEFT))) + while (size-- > 0) + *str++ = ' '; + if (sign) + *str++ = sign; + + if (type & HEX_PREP) + { + if (base == 8) + *str++ = '0'; + else if (base == 16) + { + *str++ = '0'; + *str++ = digits[33]; + } + } + + if (!(type & LEFT)) + while (size-- > 0) + *str++ = c; + while (i < precision--) + *str++ = '0'; + while (i-- > 0) + *str++ = tmp[i]; + while (size-- > 0) + *str++ = ' '; + + return str; +} + +static char * +eaddr(char *str, unsigned char *addr, int size, int precision, int type) +{ + char tmp[24]; + char *dig = digits; + int i, len; + + if (type & UPPERCASE) + dig = upper_digits; + len = 0; + for (i = 0; i < 6; i++) + { + if (i != 0) + tmp[len++] = ':'; + tmp[len++] = dig[addr[i] >> 4]; + tmp[len++] = dig[addr[i] & 0x0F]; + } + + if (!(type & LEFT)) + while (len < size--) + *str++ = ' '; + for (i = 0; i < len; ++i) + *str++ = tmp[i]; + while (len < size--) + *str++ = ' '; + + return str; +} + +static char * +iaddr(char *str, unsigned char *addr, int size, int precision, int type) +{ + char tmp[24]; + int i, n, len; + + len = 0; + for (i = 0; i < 4; i++) + { + if (i != 0) + tmp[len++] = '.'; + n = addr[i]; + + if (n == 0) + tmp[len++] = digits[0]; + else + { + if (n >= 100) + { + tmp[len++] = digits[n / 100]; + n = n % 100; + tmp[len++] = digits[n / 10]; + n = n % 10; + } + else if (n >= 10) + { + tmp[len++] = digits[n / 10]; + n = n % 10; + } + + tmp[len++] = digits[n]; + } + } + + if (!(type & LEFT)) + while (len < size--) + *str++ = ' '; + for (i = 0; i < len; ++i) + *str++ = tmp[i]; + while (len < size--) + *str++ = ' '; + + return str; +} + +#if HAS_FLOAT + +char * ecvtbuf(double arg, int ndigits, int *decpt, int *sign, char *buf); +char * fcvtbuf(double arg, int ndigits, int *decpt, int *sign, char *buf); +static void ee_bufcpy(char *d, char *s, int count); + +void +ee_bufcpy(char *pd, char *ps, int count) +{ + char *pe = ps + count; + while (ps != pe) + *pd++ = *ps++; +} + +static void +parse_float(double value, char *buffer, char fmt, int precision) +{ + int decpt, sign, exp, pos; + char *digits = NULL; + char cvtbuf[80]; + int capexp = 0; + int magnitude; + + if (fmt == 'G' || fmt == 'E') + { + capexp = 1; + fmt += 'a' - 'A'; + } + + if (fmt == 'g') + { + digits = ecvtbuf(value, precision, &decpt, &sign, cvtbuf); + magnitude = decpt - 1; + if (magnitude < -4 || magnitude > precision - 1) + { + fmt = 'e'; + precision -= 1; + } + else + { + fmt = 'f'; + precision -= decpt; + } + } + + if (fmt == 'e') + { + digits = ecvtbuf(value, precision + 1, &decpt, &sign, cvtbuf); + + if (sign) + *buffer++ = '-'; + *buffer++ = *digits; + if (precision > 0) + *buffer++ = '.'; + ee_bufcpy(buffer, digits + 1, precision); + buffer += precision; + *buffer++ = capexp ? 'E' : 'e'; + + if (decpt == 0) + { + if (value == 0.0) + exp = 0; + else + exp = -1; + } + else + exp = decpt - 1; + + if (exp < 0) + { + *buffer++ = '-'; + exp = -exp; + } + else + *buffer++ = '+'; + + buffer[2] = (exp % 10) + '0'; + exp = exp / 10; + buffer[1] = (exp % 10) + '0'; + exp = exp / 10; + buffer[0] = (exp % 10) + '0'; + buffer += 3; + } + else if (fmt == 'f') + { + digits = fcvtbuf(value, precision, &decpt, &sign, cvtbuf); + if (sign) + *buffer++ = '-'; + if (*digits) + { + if (decpt <= 0) + { + *buffer++ = '0'; + *buffer++ = '.'; + for (pos = 0; pos < -decpt; pos++) + *buffer++ = '0'; + while (*digits) + *buffer++ = *digits++; + } + else + { + pos = 0; + while (*digits) + { + if (pos++ == decpt) + *buffer++ = '.'; + *buffer++ = *digits++; + } + } + } + else + { + *buffer++ = '0'; + if (precision > 0) + { + *buffer++ = '.'; + for (pos = 0; pos < precision; pos++) + *buffer++ = '0'; + } + } + } + + *buffer = '\0'; +} + +static void +decimal_point(char *buffer) +{ + while (*buffer) + { + if (*buffer == '.') + return; + if (*buffer == 'e' || *buffer == 'E') + break; + buffer++; + } + + if (*buffer) + { + int n = strnlen(buffer, 256); + while (n > 0) + { + buffer[n + 1] = buffer[n]; + n--; + } + + *buffer = '.'; + } + else + { + *buffer++ = '.'; + *buffer = '\0'; + } +} + +static void +cropzeros(char *buffer) +{ + char *stop; + + while (*buffer && *buffer != '.') + buffer++; + if (*buffer++) + { + while (*buffer && *buffer != 'e' && *buffer != 'E') + buffer++; + stop = buffer--; + while (*buffer == '0') + buffer--; + if (*buffer == '.') + buffer--; + while (buffer != stop) + *++buffer = 0; + } +} + +static char * +flt(char *str, double num, int size, int precision, char fmt, int flags) +{ + char tmp[80]; + char c, sign; + int n, i; + + // Left align means no zero padding + if (flags & LEFT) + flags &= ~ZEROPAD; + + // Determine padding and sign char + c = (flags & ZEROPAD) ? '0' : ' '; + sign = 0; + if (flags & SIGN) + { + if (num < 0.0) + { + sign = '-'; + num = -num; + size--; + } + else if (flags & PLUS) + { + sign = '+'; + size--; + } + else if (flags & SPACE) + { + sign = ' '; + size--; + } + } + + // Compute the precision value + if (precision < 0) + precision = 6; // Default precision: 6 + + // Convert floating point number to text + parse_float(num, tmp, fmt, precision); + + if ((flags & HEX_PREP) && precision == 0) + decimal_point(tmp); + if (fmt == 'g' && !(flags & HEX_PREP)) + cropzeros(tmp); + + n = strnlen(tmp, 256); + + // Output number with alignment and padding + size -= n; + if (!(flags & (ZEROPAD | LEFT))) + while (size-- > 0) + *str++ = ' '; + if (sign) + *str++ = sign; + if (!(flags & LEFT)) + while (size-- > 0) + *str++ = c; + for (i = 0; i < n; i++) + *str++ = tmp[i]; + while (size-- > 0) + *str++ = ' '; + + return str; +} + +#endif + +static int +ee_vsprintf(char *buf, const char *fmt, va_list args) +{ + int len; + unsigned long num; + int i, base; + char * str; + char * s; + + int flags; // Flags to number() + + int field_width; // Width of output field + int precision; // Min. # of digits for integers; max number of chars for + // from string + int qualifier; // 'h', 'l', or 'L' for integer fields + + for (str = buf; *fmt; fmt++) + { + if (*fmt != '%') + { + *str++ = *fmt; + continue; + } + + // Process flags + flags = 0; + repeat: + fmt++; // This also skips first '%' + switch (*fmt) + { + case '-': + flags |= LEFT; + goto repeat; + case '+': + flags |= PLUS; + goto repeat; + case ' ': + flags |= SPACE; + goto repeat; + case '#': + flags |= HEX_PREP; + goto repeat; + case '0': + flags |= ZEROPAD; + goto repeat; + } + + // Get field width + field_width = -1; + if (is_digit(*fmt)) + field_width = skip_atoi(&fmt); + else if (*fmt == '*') + { + fmt++; + field_width = va_arg(args, int); + if (field_width < 0) + { + field_width = -field_width; + flags |= LEFT; + } + } + + // Get the precision + precision = -1; + if (*fmt == '.') + { + ++fmt; + if (is_digit(*fmt)) + precision = skip_atoi(&fmt); + else if (*fmt == '*') + { + ++fmt; + precision = va_arg(args, int); + } + if (precision < 0) + precision = 0; + } + + // Get the conversion qualifier + qualifier = -1; + if (*fmt == 'l' || *fmt == 'L') + { + qualifier = *fmt; + fmt++; + } + + // Default base + base = 10; + + switch (*fmt) + { + case 'c': + if (!(flags & LEFT)) + while (--field_width > 0) + *str++ = ' '; + *str++ = (unsigned char)va_arg(args, int); + while (--field_width > 0) + *str++ = ' '; + continue; + + case 's': + s = va_arg(args, char *); + if (!s) + s = ""; + len = strnlen(s, precision); + if (!(flags & LEFT)) + while (len < field_width--) + *str++ = ' '; + for (i = 0; i < len; ++i) + *str++ = *s++; + while (len < field_width--) + *str++ = ' '; + continue; + + case 'p': + if (field_width == -1) + { + field_width = 2 * sizeof(void *); + flags |= ZEROPAD; + } + str = number(str, + (unsigned long)va_arg(args, void *), + 16, + field_width, + precision, + flags); + continue; + + case 'A': + flags |= UPPERCASE; + + case 'a': + if (qualifier == 'l') + str = eaddr(str, + va_arg(args, unsigned char *), + field_width, + precision, + flags); + else + str = iaddr(str, + va_arg(args, unsigned char *), + field_width, + precision, + flags); + continue; + + // Integer number formats - set up the flags and "break" + case 'o': + base = 8; + break; + + case 'X': + flags |= UPPERCASE; + + case 'x': + base = 16; + break; + + case 'd': + case 'i': + flags |= SIGN; + + case 'u': + break; + +#if HAS_FLOAT + + case 'f': + str = flt(str, + va_arg(args, double), + field_width, + precision, + *fmt, + flags | SIGN); + continue; + +#endif + + default: + if (*fmt != '%') + *str++ = '%'; + if (*fmt) + *str++ = *fmt; + else + --fmt; + continue; + } + + if (qualifier == 'l') + num = va_arg(args, unsigned long); + else if (flags & SIGN) + num = va_arg(args, int); + else + num = va_arg(args, unsigned int); + + str = number(str, num, base, field_width, precision, flags); + } + + *str = '\0'; + return str - buf; +} + +void +uart_send_char(char c) +{ + *((volatile unsigned int *) (0x40000010)) = c; +} + +int +ee_printf(const char *fmt, ...) +{ + char buf[1024], *p; + va_list args; + int n = 0; + + va_start(args, fmt); + ee_vsprintf(buf, fmt, args); + va_end(args); + p = buf; + while (*p) + { + uart_send_char(*p); + n++; + p++; + } + + return n; +} diff --git a/lab4/coremark/yatcpu/init.s b/lab4/coremark/yatcpu/init.s new file mode 100644 index 0000000..0efae64 --- /dev/null +++ b/lab4/coremark/yatcpu/init.s @@ -0,0 +1,16 @@ +.section .text.init +.globl _start +_start: + li sp, 4092 + call main + li x1, 0xBABECAFE +write_tohost: + sw x1, tohost, x0 +loop: + j loop + +.pushsection .tohost,"aw",@progbits + .align 4 + .global tohost + tohost: .word 0 +.popsection \ No newline at end of file diff --git a/lab4/coremark/yatcpu/link.ld b/lab4/coremark/yatcpu/link.ld new file mode 100644 index 0000000..2ae1500 --- /dev/null +++ b/lab4/coremark/yatcpu/link.ld @@ -0,0 +1,12 @@ +OUTPUT_ARCH( "riscv" ) +ENTRY(_start) + +SECTIONS +{ + . = 0x00001000; + .text : { *(.text.init) *(.text.startup) *(.text) } + .data ALIGN(0x1000) : { *(.data*) *(.rodata*) *(.sdata*) } + .tohost ALIGN(0x1000) : { *(.tohost) } + .bss : { *(.bss) } + _end = .; +} diff --git a/lab4/csrc/CMakeLists.txt b/lab4/csrc/CMakeLists.txt new file mode 100644 index 0000000..a445640 --- /dev/null +++ b/lab4/csrc/CMakeLists.txt @@ -0,0 +1,66 @@ +# Make CMake happy +cmake_minimum_required(VERSION 3.18) +project(yatcpu-programs C CXX ASM) + +# Setting variables +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O0 --target=riscv32-unknown-elf -march=rv32i -mabi=ilp32") +set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -O0 --target=riscv32-unknown-elf -march=rv32i -mabi=ilp32") +set(C_PROGRAMS tetris hello fibonacci quicksort paging tetris_mmu) +set(ASM_PROGRAMS mmio sb) +set(LINKER_SCRIPT ${CMAKE_SOURCE_DIR}/link.lds) +set(LINKER_FLAGS -T ${LINKER_SCRIPT}) +set(OBJCOPY_ARGS -O binary -j .text -j .data) +if(NOT DEST_DIR) + set(DEST_DIR "../src/main/resources") +endif() + +# Let CMake know that there exists header files +include_directories("${CMAKE_SOURCE_DIR}") + +add_library(prelude init.S) +set_target_properties(prelude PROPERTIES LINK_DEPENDS ${LINKER_SCRIPT}) + +# Let's build our executables +foreach(program IN LISTS C_PROGRAMS) + add_executable(${program} ${program}.c) + set_target_properties(${program} PROPERTIES LINK_DEPENDS ${LINKER_SCRIPT}) + target_link_libraries(${program} prelude ${LINKER_FLAGS}) +endforeach() + +foreach(program IN LISTS ASM_PROGRAMS) + add_executable(${program} ${program}.S) + set_target_properties(${program} PROPERTIES LINK_DEPENDS ${LINKER_SCRIPT}) +endforeach() + +set(PROGRAMS litenes) +# NES Emulator +include_directories(${CMAKE_SOURCE_DIR}/LiteNES/include) +add_definitions(-DYATCPU) +add_library(fce + ${CMAKE_SOURCE_DIR}/LiteNES/src/fce/common.c + ${CMAKE_SOURCE_DIR}/LiteNES/src/fce/cpu-addressing.c + ${CMAKE_SOURCE_DIR}/LiteNES/src/fce/cpu.c + ${CMAKE_SOURCE_DIR}/LiteNES/src/fce/fce.c + ${CMAKE_SOURCE_DIR}/LiteNES/src/fce/memory.c + ${CMAKE_SOURCE_DIR}/LiteNES/src/fce/mmc.c + ${CMAKE_SOURCE_DIR}/LiteNES/src/fce/ppu.c + ${CMAKE_SOURCE_DIR}/LiteNES/src/fce/psg.c +) +target_compile_options(fce PRIVATE "-O3") +add_executable(litenes + ${CMAKE_SOURCE_DIR}/LiteNES/src/main.c + ${CMAKE_SOURCE_DIR}/LiteNES/src/hal.c + ${CMAKE_SOURCE_DIR}/LiteNES/src/rom.c +) +set_target_properties(litenes PROPERTIES LINK_DEPENDS ${LINKER_SCRIPT}) +target_link_libraries(litenes prelude fce ${LINKER_FLAGS}) + +# Copy the .text and .data section to .asmbin files +foreach(program IN LISTS C_PROGRAMS ASM_PROGRAMS PROGRAMS) + add_custom_command( + TARGET ${program} + POST_BUILD + COMMAND ${CMAKE_OBJCOPY} ARGS ${OBJCOPY_ARGS} $ ${CMAKE_SOURCE_DIR}/${DEST_DIR}/${program}.asmbin + ) +endforeach() + diff --git a/lab4/csrc/build.bat b/lab4/csrc/build.bat new file mode 100644 index 0000000..b5a522b --- /dev/null +++ b/lab4/csrc/build.bat @@ -0,0 +1,3 @@ +rmdir /Q /S build +cmake -DCMAKE_TOOLCHAIN_FILE=toolchain.cmake -G"NMake Makefiles" -B build . +cmake --build build \ No newline at end of file diff --git a/lab4/csrc/build.sh b/lab4/csrc/build.sh new file mode 100644 index 0000000..e48a4ba --- /dev/null +++ b/lab4/csrc/build.sh @@ -0,0 +1,3 @@ +#!/bin/sh +rm -rf build +cmake -DCMAKE_TOOLCHAIN_FILE=toolchain.cmake -B build . && cmake --build build --parallel `nproc` diff --git a/lab4/csrc/fibonacci.c b/lab4/csrc/fibonacci.c new file mode 100644 index 0000000..9905dde --- /dev/null +++ b/lab4/csrc/fibonacci.c @@ -0,0 +1,22 @@ +// 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. + +int fib(int a) { + if (a == 1 || a == 2) return 1; + return fib(a - 1) + fib(a - 2); +} + +int main() { + *(int *)(4) = fib(10); +} \ No newline at end of file diff --git a/lab4/csrc/hello.c b/lab4/csrc/hello.c new file mode 100644 index 0000000..3e79635 --- /dev/null +++ b/lab4/csrc/hello.c @@ -0,0 +1,175 @@ +// 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. + +#include "mmio.h" + +#define MUL80(x) (((x) << 6) + ((x) << 4)) + +struct screen { + unsigned char row, col; +} scr; + +void copy_line(int prev, int cur) { + int *prev_vram_start = ((int *) (MUL80(prev) + VRAM_BASE)); + int *cur_vram_start = ((int *) (MUL80(cur) + VRAM_BASE)); + for (int i = 0; i < 20; ++i) { + prev_vram_start[i] = cur_vram_start[i]; + } +} + +void write_char(int row, int col, unsigned char ch) { + VRAM[MUL80(row) + col] = ch; +} + +void move_to(int row, int col) { + scr.row = row; + scr.col = col; +} + +void new_line() { + scr.col = 0; + if (scr.row == 29) { + for (int i = 0; i < 29; ++i) { + copy_line(i, i + 1); + } + int *vram = (int *) (MUL80(29) + VRAM_BASE); + for (int i = 0; i < 20; ++i) { + vram[i] = 0x20202020; + } + } else { + ++scr.row; + } +} + +void putch(unsigned char ch) { + if (ch == '\n') { + new_line(); + } else if (ch == '\r') { + scr.col = 0; + } else { + if (scr.col == 79) { + new_line(); + } + write_char(scr.row, scr.col, ch); + ++scr.col; + } +} + +void clear_screen() { + scr.row = 0; + scr.col = 0; + int *vram = ((int *) VRAM_BASE); + for (int i = 0; i < 600; ++i) vram[i] = 0x20202020; +} + +void print_hex(unsigned int counter) { + putch('0'); putch('x'); + for (int i = 7; i >= 0; --i) { + unsigned int num = (counter >> (i << 2)) & 0xF; + if (num < 10) { + putch('0' + num); + } else { + putch('A' + num - 10); + } + } +} + +void putstr(const char *s) { + while (*s) { + putch(*(s++)); + } +} + +int hc = 1; +int fast = 0; + +void print_timer() { + putstr("Hardware timer count limit = "); + print_hex(*TIMER_LIMIT); + putstr(", enabled = "); + print_hex(*TIMER_ENABLED); + putch('\n'); +} + +void print_uart() { + putstr("UART Baud rate = "); + print_hex(*UART_BAUDRATE); + putch('\n'); +} + +void handle_timer() { + putstr("Timer trigger times = "); + print_hex(hc++); + putch('\n'); + int mode = ((hc & 0x10) >> 4); + if (hc == 0x40) { + putstr("Disable timer!\n"); + *TIMER_ENABLED = 0; + print_timer(); + return; + } + if (fast ^ mode) { + putstr("Switch timer frequency\n"); + if (fast == 0) { + *TIMER_LIMIT = 25000000; + } else { + + *TIMER_LIMIT = 100000000; + } + fast = mode; + print_timer(); + } +} + +void handle_uart() { + unsigned int ch = *UART_RECV; + *UART_SEND = ch; + putstr("UART Recv hex = "); print_hex(ch); putstr(", ch = "); putch(ch); putch('\n'); +} + +void trap_handler(void *epc, unsigned int cause) { + putstr("Interrupt! EPC = "); + print_hex((unsigned int) epc); + putstr(", CAUSE = "); + print_hex(cause); + putch('\n'); + switch (cause) { + case 0x8000000B: + handle_uart(); + break; + default: + handle_timer(); + break; + } +} +extern void enable_interrupt(); +extern unsigned int get_epc(); +int main() { + clear_screen(); + hc = 0; + *TIMER_ENABLED = 1; + putstr("YatCPU Demo Program "); + putch(137); + putstr("2021 Howard Lau\n"); + putstr("Hello, world!\n"); + putstr("Last EPC = "); + print_hex(get_epc()); + putch('\n'); + print_timer(); + print_uart(); + *((int *) 0x4) = 0xDEADBEEF; + unsigned int i = 0; + enable_interrupt(); + for (;;) ; +} diff --git a/lab4/csrc/init.S b/lab4/csrc/init.S new file mode 100644 index 0000000..1d4dbce --- /dev/null +++ b/lab4/csrc/init.S @@ -0,0 +1,117 @@ +# 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. + +.section .text.init +.globl _start +_start: + li sp, 0x10000000 # Initialize stack pointer + call main # Jump to main function +loop: + j loop # Loop forever +.globl enable_interrupt +enable_interrupt: + la t0, __trap_entry + csrrw t1, mtvec, t0 # setup trap vector base + li t0, 0x1888 + csrrw t1, mstatus, t0 # enable interrupt + ret +.globl enable_paging +enable_paging: + li t0, 0x80000005 # ppn << 12 = 0x005000 + csrw satp, t0 + ret +.globl get_mtval +get_mtval: + csrr a0, mtval + ret + +.globl get_epc +get_epc: + csrr a0, mepc + ret +.weak trap_handler +tran_handler: + ret +__trap_entry: + csrw mscratch, sp + addi sp, sp, -128 + sw ra, 4(sp) + + sw gp, 12(sp) + sw tp, 16(sp) + sw t0, 20(sp) + sw t1, 24(sp) + sw t2, 28(sp) + sw tp, 32(sp) + sw s1, 36(sp) + sw a0, 40(sp) + sw a1, 44(sp) + sw a2, 48(sp) + sw a3, 52(sp) + sw a4, 56(sp) + sw a5, 60(sp) + sw a6, 64(sp) + sw a7, 68(sp) + sw s2, 72(sp) + sw s3, 76(sp) + sw s4, 80(sp) + sw s5, 84(sp) + sw s6, 88(sp) + sw s7, 92(sp) + sw s8, 96(sp) + sw s9, 100(sp) + sw s10, 104(sp) + sw s11, 108(sp) + sw t3, 112(sp) + sw t4, 116(sp) + sw t5, 120(sp) + sw t6, 124(sp) + + csrr a0, mepc + csrr a1, mcause + call trap_handler + + lw ra, 4(sp) + + lw gp, 12(sp) + lw tp, 16(sp) + lw t0, 20(sp) + lw t1, 24(sp) + lw t2, 28(sp) + lw tp, 32(sp) + lw s1, 36(sp) + lw a0, 40(sp) + lw a1, 44(sp) + lw a2, 48(sp) + lw a3, 52(sp) + lw a4, 56(sp) + lw a5, 60(sp) + lw a6, 64(sp) + lw a7, 68(sp) + lw s2, 72(sp) + lw s3, 76(sp) + lw s4, 80(sp) + lw s5, 84(sp) + lw s6, 88(sp) + lw s7, 92(sp) + lw s8, 96(sp) + lw s9, 100(sp) + lw s10, 104(sp) + lw s11, 108(sp) + lw t3, 112(sp) + lw t4, 116(sp) + lw t5, 120(sp) + lw t6, 124(sp) + csrr sp, mscratch + mret diff --git a/lab4/csrc/link.lds b/lab4/csrc/link.lds new file mode 100644 index 0000000..a166fc7 --- /dev/null +++ b/lab4/csrc/link.lds @@ -0,0 +1,12 @@ +OUTPUT_ARCH( "riscv" ) +ENTRY(_start) + +SECTIONS +{ + . = 0x00001000; + .text : { *(.text.init) *(.text.startup) *(.text) } + .data ALIGN(0x1000) : { *(.data*) *(.rodata*) *(.sdata*) } + . = 0x00100000; + .bss : { *(.bss) } + _end = .; +} diff --git a/lab4/csrc/mm.h b/lab4/csrc/mm.h new file mode 100644 index 0000000..5d4c89a --- /dev/null +++ b/lab4/csrc/mm.h @@ -0,0 +1,43 @@ +// Copyright 2022 hrpccs +// +// 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. + +typedef unsigned int uint32; +typedef uint32 pte_t; +typedef uint32* pagetable_t; + +#define PGSIZE 4096 // bytes per page +#define PGSHIFT 12 // bits of offset within a page + +#define PGROUNDUP(sz) (((sz)+PGSIZE-1) & ~(PGSIZE-1)) +#define PGROUNDDOWN(a) (((a)) & ~(PGSIZE-1)) + +#define PTE_V (1L << 0) // valid +#define PTE_R (1L << 1) +#define PTE_W (1L << 2) +#define PTE_X (1L << 3) +#define PTE_U (1L << 4) // 1 -> user can access + +// shift a physical address to the right place for a PTE. +#define PA2PTE(pa) ((((uint32)pa) >> 12) << 10) + +#define PTE2PA(pte) (((pte) >> 10) << 12) + +#define PTE_FLAGS(pte) ((pte) & 0x3FF) + +// extract the two 10-bit page table indices from a virtual address. +#define PXMASK 0x3FF // 10 bits +#define PXSHIFT(level) (PGSHIFT+(10*(level))) +#define PX(level, va) ((((uint32) (va)) >> PXSHIFT(level)) & PXMASK) + +#define MAXVA (1L << (10 + 10 + 12)) diff --git a/lab4/csrc/mmio.S b/lab4/csrc/mmio.S new file mode 100644 index 0000000..7b49530 --- /dev/null +++ b/lab4/csrc/mmio.S @@ -0,0 +1,24 @@ +# 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. + +.globl _start +_start: + li a0, 0x80000000 + lw t0, 4(a0) + li a1, 0xBEEF + sw a1, 4(a0) + nop + lw t1, 4(a0) +loop: + j loop diff --git a/lab4/csrc/mmio.h b/lab4/csrc/mmio.h new file mode 100644 index 0000000..fb0fa5f --- /dev/null +++ b/lab4/csrc/mmio.h @@ -0,0 +1,33 @@ +// 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. + +#define VRAM_BASE 0x20000000 +#define VRAM ((volatile unsigned char *) VRAM_BASE) +#define TIMER_BASE 0x80000000 +#define TIMER_LIMIT ((volatile unsigned int *) (TIMER_BASE + 4)) +#define TIMER_ENABLED ((volatile unsigned int *) (TIMER_BASE + 8)) +#define UART_BASE 0x40000000 +#define UART_BAUDRATE ((volatile unsigned int *) (UART_BASE + 4)) +#define UART_RECV ((volatile unsigned int *) (UART_BASE + 12)) +#define UART_SEND ((volatile unsigned int *) (UART_BASE + 16)) +//remap the mmio to reduce memory usage of page table +#define VA_VRAM_BASE 0x00100000 +#define VA_VRAM ((volatile unsigned char *) VA_VRAM_BASE) +#define VA_TIMER_BASE 0x00200000 +#define VA_TIMER_LIMIT ((volatile unsigned int *) (VA_TIMER_BASE + 4)) +#define VA_TIMER_ENABLED ((volatile unsigned int *) (VA_TIMER_BASE + 8)) +#define VA_UART_BASE 0x00300000 +#define VA_UART_BAUDRATE ((volatile unsigned int *) (VA_UART_BASE + 4)) +#define VA_UART_RECV ((volatile unsigned int *) (VA_UART_BASE + 12)) +#define VA_UART_SEND ((volatile unsigned int *) (VA_UART_BASE + 16)) \ No newline at end of file diff --git a/lab4/csrc/paging.c b/lab4/csrc/paging.c new file mode 100644 index 0000000..d8d59d5 --- /dev/null +++ b/lab4/csrc/paging.c @@ -0,0 +1,191 @@ +// # Copyright 2022 hrpccs +// # +// # 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. + +#include "mm.h" +#include "mmio.h" + + + +#define SCREEN_COLS 80 +#define SCREEN_ROWS 30 +#define INT_TIMER_LIMIT 50000000 +#define PAGEDIR_BASE 0x5000 + +typedef unsigned int uint32; +typedef uint32 pte_t; +typedef uint32* pagetable_t; + +extern void enable_paging(); +extern void enable_interrupt(); +extern int get_mtval(); + +int wk_mul(int a, int b) { + int r = 0; + for (; b; a <<= 1, b >>= 1) + if (b & 1) + r += a; + return r; +} + +void memoryset(unsigned char *dest,unsigned char num, unsigned int size){ + for(unsigned int i=0;i=0){ + int* taddr = (int*)(t<<12); + for(int i=0;i>2;i++){ + taddr[i]=0; + } + pgtbl[PX(1,va)] = PA2PTE(t<<12) | PTE_V; + }else{ + while(1); + for(int i=0;i<14;i++){ + putch_at(i,22,"out of memory!"[i]); + } + while(1); + } + } + pagetable_t n = (void*)PTE2PA(pgtbl[PX(1,va)]); + n[PX(0,va)] = PA2PTE(pa) | perm | PTE_V; +} + + +void kvminit(){ + pagetable_t pgtbl = (void*)PAGEDIR_BASE; + // memoryset(pgtbl,0,PGSIZE); //后面需要读这个内存,所以先初始化 + for(int i=0;i>2;i++){ + pgtbl[i]=0; + } + + pm[PAGEDIR_BASE >> 12] = 1; + pm[0]=1; + pm[1]=1; + pm[2]=1; + pm[3]=1; + pm[4]=1; + //create pte mmap for text + pgtbl[1023] = PA2PTE(PAGEDIR_BASE) | PTE_R | PTE_W; + map(pgtbl,PAGEDIR_BASE,PAGEDIR_BASE,PTE_R | PTE_W); + map(pgtbl,0x0,0x0, PTE_W | PTE_R ); //kernel stack + map(pgtbl,0x1000,0x1000, PTE_W | PTE_R | PTE_X ); // + map(pgtbl,0x2000,0x2000, PTE_W | PTE_R | PTE_X ); // + map(pgtbl,0x3000,0x3000, PTE_W | PTE_R | PTE_X ); // + map(pgtbl,0x4000,0x4000, PTE_W | PTE_R | PTE_X ); // + map(pgtbl,VA_VRAM_BASE,VRAM_BASE, PTE_W | PTE_R ); // + map(pgtbl,VA_VRAM_BASE + PGSIZE,VRAM_BASE + PGSIZE, PTE_W | PTE_R); + map(pgtbl,VA_UART_BASE,UART_BASE, PTE_W | PTE_R ); // + map(pgtbl,VA_TIMER_BASE,TIMER_BASE, PTE_W | PTE_R ); // +} + +void clear_screen() { + int *vram = ((int *) VRAM_BASE); + for (int i = 0; i < 600; ++i) vram[i] = 0x20202020; +} + +void trap_handler(void *epc, unsigned int cause) { + if (cause == 10 || cause == 15 || cause == 13) { + for(int i=0;i<39;i++){ + putch_at(i,4,"A not handled page fault caused by : 0x"[i]); + } + int mtval = get_mtval(); + char ch; + for (int i = 0; i < 8; ++i) { + unsigned int mask = 0xF << (i * 4); + unsigned int num = (mtval & mask) >> (i * 4); + if(num >= 10){ + ch = num - 10 + 'A'; + }else{ + ch = num + '0'; + } + putch_at(39+7-i,4,ch); + } + while(1); //目前还没有处理page-fault,因为还没有建立完整的映射。 + } else if(cause == 0x80000007){ + for(int i=0;i<16;i++){ + putch_at(i,3,"timer count : 0x"[i]); + } + char ch; + for (int i = 0; i < 8; ++i) { + unsigned int mask = 0xF << (i * 4); + unsigned int num = (timercount & mask) >> (i * 4); + if(num >= 10){ + ch = num - 10 + 'A'; + }else{ + ch = num + '0'; + } + putch_at(16+7-i,3,ch); + } + timercount += 1; + + } +} + +int main(){ + putch_at = __putch_at; + for(int i=0;i<8;i++){ + pm[i] = 0; + } + timercount = 0; + clear_screen(); + for(int i=0;i<19;i++){ + putch_at(i,0,"print before paging"[i]); + } + kvminit(); + putch_at = __vputch_at; + enable_paging(); + for(int i=0;i<18;i++){ + putch_at(i,1,"print after paging"[i]); + } + enable_interrupt(); + *VA_TIMER_ENABLED = 1; + *VA_TIMER_LIMIT = INT_TIMER_LIMIT; + + while(1){ + if(timercount == 0x20){ + *(int*)0x11415 = 1130; + } + } + for(;;); +} \ No newline at end of file diff --git a/lab4/csrc/quicksort.c b/lab4/csrc/quicksort.c new file mode 100644 index 0000000..5105ef1 --- /dev/null +++ b/lab4/csrc/quicksort.c @@ -0,0 +1,50 @@ +// 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. + +void quicksort(int *arr, int l, int r) { + if (l >= r) return; + int pivot = arr[l]; + int i = l, j = r; + while (i < j) { + while(arr[j] >= pivot && i < j) --j; + arr[i] = arr[j]; + while(arr[i] < pivot && i < j) ++i; + arr[j] = arr[i]; + } + arr[i] = pivot; + quicksort(arr, l, i - 1); + quicksort(arr, i + 1, r); +} + +int main() { + int nums[10]; + + nums[0] = 6; + nums[1] = 2; + nums[2] = 4; + nums[3] = 5; + nums[4] = 3; + nums[5] = 1; + nums[6] = 0; + nums[7] = 9; + nums[8] = 7; + nums[9] = 8; + + + quicksort(nums, 0, 9); + + for (int i = 1; i <= 10; ++i) { + *(int *)(i * 4) = nums[i - 1]; + } +} \ No newline at end of file diff --git a/lab4/csrc/say_goodbye.c b/lab4/csrc/say_goodbye.c new file mode 100644 index 0000000..566e7e2 --- /dev/null +++ b/lab4/csrc/say_goodbye.c @@ -0,0 +1,44 @@ + +void uart_send_char(char c) +{ + *((volatile unsigned int *) (0x40000010)) = c; + // *((volatile unsigned int *) (0x40000000)) = c; +} + + +void waste_some_time(int cycle) { + unsigned int a = 135; + while (cycle--) { + a++; + } +} + +int main() { + + // const char* s = "abcd"; + const char* s = "Never gonna give you up~ Never gonna let you down~\n\ + Never gonna run around and~ desert you~\n"; + + while (1) { + + + // for (int i = 0; i < ; i++) { + // uart_send_char(s[i]); + // waste_some_time(100); + // } + + const char *p = s; + while (*p != 0) + { + uart_send_char(*p); + p++; + waste_some_time(100); + } + + waste_some_time(200); + + break; // print once, but pressing CPU reset can print again + } + + return 0; +} diff --git a/lab4/csrc/sb.S b/lab4/csrc/sb.S new file mode 100644 index 0000000..ed71a72 --- /dev/null +++ b/lab4/csrc/sb.S @@ -0,0 +1,25 @@ +# 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. + +.globl _start +_start: + li a0, 0x4 + li t0, 0xDEADBEEF + sb t0, 0(a0) + lw t1, 0(a0) + li s2, 0x15 + sb s2, 1(a0) + lw ra, 0(a0) +loop: + j loop diff --git a/lab4/csrc/tetris.c b/lab4/csrc/tetris.c new file mode 100644 index 0000000..6ce1f3a --- /dev/null +++ b/lab4/csrc/tetris.c @@ -0,0 +1,498 @@ +// 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. + +#ifdef DEBUG +#include +#endif + +#include "mmio.h" + +#define FALL_TIMER_LIMIT 50000000 +#define ROWS 22 +#define COLS 10 +#define OFFSET_X 28 +#define OFFSET_Y 3 +#define SCREEN_COLS 80 +#define SCREEN_ROWS 30 + +struct block { + unsigned int shape[3]; + unsigned int xywh; +}; + +struct block current; + +unsigned int score; + +unsigned char *board; + +#ifdef DEBUG +unsigned char screen[SCREEN_COLS * SCREEN_ROWS]; +#endif + +int wk_mul(int a, int b) { + int r = 0; + for (; b; a <<= 1, b >>= 1) + if (b & 1) + r += a; + return r; +} + +unsigned int make_xywh(unsigned int x, unsigned int y, unsigned int w, unsigned int h) { + return (x << 12) | (y << 4) | (w << 2) | h; +} + +void init_block(struct block *block, int type, int x, int y) { + int w = 0; int h = 0; + block->shape[0] = block->shape[1] = block->shape[2] = 0; + switch(type) { + case 0: // I + block->shape[0] = 0xF; + w = 3; h = 0; + break; + case 1: // O + block->shape[0] = 0x3; + block->shape[1] = 0x3; + w = 1; h = 1; + break; + case 2: // J + block->shape[0] = 0x4; + block->shape[1] = 0x7; + w = 2; h = 1; + break; + case 3: // T + block->shape[0] = 0x2; + block->shape[1] = 0x7; + w = 2; h = 1; + break; + case 4: // L + block->shape[0] = 0x1; + block->shape[1] = 0x7; + w = 2; h = 1; + break; + case 5: // Z + block->shape[0] = 0x6; + block->shape[1] = 0x3; + w = 2; h = 1; + break; + case 6: // S + block->shape[0] = 0x3; + block->shape[1] = 0x6; + w = 2; h = 1; + break; + } + block->xywh = make_xywh(x, y, w, h); +} + +unsigned int get_shape(struct block *block, unsigned int r, unsigned int c) { + return (block->shape[r] & (1 << c)) >> c; +} + +unsigned int check_bounds(struct block *block) { + unsigned int xywh = block->xywh; + unsigned int h = xywh & 0x3; + unsigned int w = (xywh & 0xC) >> 2; + unsigned int y = (xywh & 0xFF0) >> 4; + unsigned int x = (xywh & 0xF000) >> 12; + if (x < 0 || x + w >= COLS) return 0; + if (y < 0 || y + h >= ROWS) return 0; + return 1; +} + +void copy_block(struct block *dst, struct block *src) { + dst->xywh = src->xywh; + dst->shape[0] = src->shape[0]; + dst->shape[1] = src->shape[1]; + dst->shape[2] = src->shape[2]; +} + +unsigned int check_collision(struct block *block) { + unsigned int xywh = block->xywh; + unsigned int h = xywh & 0x3; + unsigned int w = (xywh & 0xC) >> 2; + unsigned int y = (xywh & 0xFF0) >> 4; + unsigned int x = (xywh & 0xF000) >> 12; + for (int r = 0; r <= h; ++r) { + for (int c = 0; c <= w; ++c) { + if (get_shape(block, r, c) && + board[wk_mul(y + r, COLS) + x + c]) + return 0; + } + } + return 1; +} + +void putch_at(int x, int y, unsigned char ch) { +#ifdef DEBUG + screen[wk_mul(OFFSET_Y + y, SCREEN_COLS) + x + OFFSET_X] = ch; +#else + VRAM[wk_mul(OFFSET_Y + y, SCREEN_COLS) + x + OFFSET_X] = ch; +#endif +} + +void block_move(struct block *block, int dir) { + unsigned int xywh = block->xywh; + unsigned int h = xywh & 0x3; + unsigned int w = (xywh & 0xC) >> 2; + unsigned int y = (xywh & 0xFF0) >> 4; + unsigned int x = (xywh & 0xF000) >> 12; + switch(dir) { + case 0: // Left + x--; + break; + case 1: // Right + x++; + break; + case 2: // Down + y++; + break; + default: + break; + } + block->xywh = (x << 12) | (y << 4) | (w << 2) | h; +} + +unsigned int move(struct block *block, int dir) { + struct block moved; + copy_block(&moved, block); + block_move(&moved, dir); + if (check_bounds(&moved) && check_collision(&moved)) { + copy_block(block, &moved); + return 1; + } + return 0; +} + +void block_rotate(struct block *block, unsigned int clock) { + unsigned int xywh = block->xywh; + unsigned int h = xywh & 0x3; + unsigned int w = (xywh & 0xC) >> 2; + unsigned int y = (xywh & 0xFF0) >> 4; + unsigned int x = (xywh & 0xF000) >> 12; + unsigned int xyhw = make_xywh(x, y, h, w); + unsigned int shape[3] = {0, 0, 0}; + if (clock) { + for (int r = 0; r <= h; ++r) { + for (int c = 0; c <= w; ++c) { + shape[c] = shape[c] | (get_shape(block, r, c) << (h - r)); + } + } + + } else { + for (int r = 0; r <= h; ++r) { + for (int c = 0; c <= w; ++c) { + shape[w - c] = shape[w - c] | (get_shape(block, r, c) << r); + } + } + } + block->shape[0] = shape[0]; + block->shape[1] = shape[1]; + block->shape[2] = shape[2]; + block->xywh = xyhw; +} + + +void rotate(struct block *block, int clock) { + struct block rotated; + copy_block(&rotated, block); + block_rotate(&rotated, clock); + if (check_bounds(&rotated) && check_collision(&rotated)) { + copy_block(block, &rotated); + return; + } + unsigned int xywh = rotated.xywh; + unsigned int h = xywh & 0x3; + unsigned int w = (xywh & 0xc) >> 2; + unsigned int y = (xywh & 0xff0) >> 4; + unsigned int x = (xywh & 0xf000) >> 12; + if (x + w >= COLS) { + x = COLS - w - 1; + } + rotated.xywh = make_xywh(x, y, w, h); + if (check_bounds(&rotated) && check_collision(&rotated)) { + copy_block(block, &rotated); + } +} + +void clear_board() { + for (int i = 0, s = wk_mul(ROWS, COLS); i < s; ++i) { + board[i] = 0; + } +} + +void fix_block(struct block *block) { + unsigned int xywh = block->xywh; + unsigned int h = xywh & 0x3; + unsigned int w = (xywh & 0xc) >> 2; + unsigned int y = (xywh & 0xff0) >> 4; + unsigned int x = (xywh & 0xf000) >> 12; +#ifdef DEBUG + printf("%d %d %d %d\n", x, y, w, h); +#endif + for (int r = 0; r <= h; ++r) { + for (int c = 0; c <= w; ++c) { + if (get_shape(block, r, c)) { + board[wk_mul(y + r, COLS) + x + c] = 1; + } + } + } +} + +void print_score() { + int c = 8; + putch_at(c++, -2, 'S'); + putch_at(c++, -2, 'C'); + putch_at(c++, -2, 'O'); + putch_at(c++, -2, 'R'); + putch_at(c++, -2, 'E'); + for (int i = 0; i < 5; ++i) { + unsigned int mask = 0xF << (i * 4); + unsigned int num = (score & mask) >> (i * 4); + putch_at(12 - i, -1, num + '0'); + } +} + +void draw_board() { + for (int r = 0; r < ROWS; ++r) { + for (int c = 0; c < COLS; ++c) { + if (board[wk_mul(r , COLS) + c] == 1) { + putch_at((c << 1) + 1, r, '['); + putch_at((c << 1) + 2, r, ']'); + } else { + putch_at((c << 1) + 1, r, ' '); + putch_at((c << 1)+ 2, r, ' '); + } + } + } + unsigned int xywh = current.xywh; + unsigned int h = xywh & 0x3; + unsigned int w = (xywh & 0xc) >> 2; + unsigned int y = (xywh & 0xff0) >> 4; + unsigned int x = (xywh & 0xf000) >> 12; + for (int r = 0; r <= h; ++r) { + for (int c = 0; c <= w; ++c) { + if (get_shape(¤t, r, c)) { + putch_at(((c + x) << 1) + 1, r + y, '['); + putch_at(((c + x) << 1) + 2, r + y, ']'); + } + } + } + print_score(); +} + + +void add_score(unsigned int delta) { + score += delta; + for (unsigned int i = 0, carry = 0; i < 32; i += 4) { + unsigned int mask = 0xF << i; + unsigned int num = (score & mask) >> i; + num += carry; + if (num >= 10) { + carry = 1; + num -= 10; + } else { + carry = 0; + } + score &= ~(mask); + score |= (num << i); + } +} + +void check_clear() { + unsigned int y = (current.xywh & 0xff0) >> 4; + unsigned int h = current.xywh & 0x3; + for (int r = y + h; r >= y; --r) { + unsigned int count = 0; + for (int c = 0; c < COLS; ++c) { + if (board[wk_mul(r , COLS) + c]) ++count; + } + if (count == COLS) { + add_score(1); + for (int nr = r - 1; nr > 0; --nr) { + for (int c = 0; c < COLS; ++c) { + board[wk_mul(nr + 1, COLS) + c] = board[wk_mul(nr, COLS) + c]; + } + } + ++r; ++y; + } + } +} + +unsigned int rand() { + static unsigned int seed = 990315; + seed = (wk_mul(1103515245 , seed) + 12345) & 0x7FFFFFFF; + return seed; +} + +unsigned int rand_type() { + unsigned int type = rand() & 0x7; + while (type == 7) { + type = rand() & 0x7; + } + return type; +} + +void fall() { + if (move(¤t, 2) == 0) { + fix_block(¤t); + check_clear(); + init_block(¤t, rand_type(), 4, 0); + } +} + +#ifdef DEBUG +void print_screen() { + for (int r = 0; r < SCREEN_ROWS; ++r) { + for (int c = 0; c < SCREEN_COLS; ++c) { + printf("%c", screen[wk_mul(r, SCREEN_COLS) + c]); + } + printf("\n"); + } + printf("\n"); +} +#endif + +void on_input(unsigned int ch) { + switch (ch) { + case 's': + fall(); + break; + case 'a': + move(¤t, 0); + break; + case 'd': + move(¤t, 1); + break; + case 'j': + rotate(¤t, 0); + break; + case 'k': + rotate(¤t, 1); + break; + } + draw_board(); +#ifdef DEBUG + print_screen(); +#endif +} + +void on_timer() { + fall(); + draw_board(); +} + +void trap_handler(void *epc, unsigned int cause) { + if (cause == 0x80000007) { + on_timer(); + } else if (cause == 0x8000000B){ + unsigned int ch = *UART_RECV; + *UART_SEND = ch; + on_input(ch); + } +} + +void init() { + clear_board(); + // Draw border + for (int r = 0; r < ROWS; ++r) { + putch_at(0, r, '|'); + putch_at(COLS << 1 | 1, r, '|'); + } + for (int c = 0; c <= (COLS << 1 | 1); ++c) { + putch_at(c, ROWS, '-'); + } + int c = 8; + putch_at(c++, ROWS + 1, 'T'); + putch_at(c++, ROWS + 1, 'E'); + putch_at(c++, ROWS + 1, 'T'); + putch_at(c++, ROWS + 1, 'R'); + putch_at(c++, ROWS + 1, 'I'); + putch_at(c++, ROWS + 1, 'S'); + c = 6; + putch_at(c++, ROWS + 3, 'H'); + putch_at(c++, ROWS + 3, 'o'); + putch_at(c++, ROWS + 3, 'w'); + putch_at(c++, ROWS + 3, 'a'); + putch_at(c++, ROWS + 3, 'r'); + putch_at(c++, ROWS + 3, 'd'); + c++; + putch_at(c++, ROWS + 3, 'L'); + putch_at(c++, ROWS + 3, 'a'); + putch_at(c++, ROWS + 3, 'u'); + c = 9; + putch_at(c++, ROWS + 4, '2'); + putch_at(c++, ROWS + 4, '0'); + putch_at(c++, ROWS + 4, '2'); + putch_at(c++, ROWS + 4, '1'); + init_block(¤t, rand_type(), 4, 0); + score = 0; + draw_board(); +} + +void clear_screen() { + int *vram = ((int *) VRAM_BASE); + for (int i = 0; i < 600; ++i) vram[i] = 0x20202020; +} + +extern void enable_interrupt(); + +int main() { +#ifdef DEBUG + unsigned char b[ROWS * COLS] = {0}; + board = b; + for (int i = 0; i < SCREEN_ROWS * SCREEN_COLS; ++i) screen[i] = '%'; + init(); +#else + board = (unsigned char *) 16384; + for (int i = 0; i < 16384; i += 4) { + *((int*) (board + i)) = 0; + } + clear_screen(); + init(); + *((unsigned int *) 4) = 0xDEADBEEF; + enable_interrupt(); + *TIMER_ENABLED = 1; + *TIMER_LIMIT = FALL_TIMER_LIMIT; + for (;;); +#endif +#ifdef DEBUG + on_input('a'); + on_input('a'); + on_input('s'); + on_input('s'); + on_input('s'); + for (int i = 21; i >= 0; --i) { + on_timer(); + } + on_input('d'); + on_input('d'); + on_input('d'); + on_input('d'); + for (int i = 21; i >= 0; --i) { + on_timer(); + } + on_input('d'); + on_input('d'); + on_input('d'); + on_input('d'); + on_input('d'); + for (int i = 21; i >= 0; --i) { + on_timer(); + add_score(10); + } + print_score(); + print_screen(); + return 0; +#endif +} diff --git a/lab4/csrc/tetris_mmu.c b/lab4/csrc/tetris_mmu.c new file mode 100644 index 0000000..b9ce7a4 --- /dev/null +++ b/lab4/csrc/tetris_mmu.c @@ -0,0 +1,568 @@ +// 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. + +#ifdef DEBUG +#include +#endif + +#include "mmio.h" +#include "mm.h" + +#define FALL_TIMER_LIMIT 50000000 +#define ROWS 22 +#define COLS 10 +#define OFFSET_X 28 +#define OFFSET_Y 3 +#define SCREEN_COLS 80 +#define SCREEN_ROWS 30 + + +struct block { + unsigned int shape[3]; + unsigned int xywh; +}; + +struct block current; + +unsigned int score; + +unsigned char *board; + + + +int pm[8]; //板子上有32kb内存,八个页 +int timercount=0; +// void (*putch_at)(int,int,unsigned char); +#define PAGEDIR_BASE 0x5000 + +#ifdef DEBUG +unsigned char screen[SCREEN_COLS * SCREEN_ROWS]; +#endif + +int wk_mul(int a, int b) { + int r = 0; + for (; b; a <<= 1, b >>= 1) + if (b & 1) + r += a; + return r; +} + +unsigned int make_xywh(unsigned int x, unsigned int y, unsigned int w, unsigned int h) { + return (x << 12) | (y << 4) | (w << 2) | h; +} + +void init_block(struct block *block, int type, int x, int y) { + int w = 0; int h = 0; + block->shape[0] = block->shape[1] = block->shape[2] = 0; + switch(type) { + case 0: // I + block->shape[0] = 0xF; + w = 3; h = 0; + break; + case 1: // O + block->shape[0] = 0x3; + block->shape[1] = 0x3; + w = 1; h = 1; + break; + case 2: // J + block->shape[0] = 0x4; + block->shape[1] = 0x7; + w = 2; h = 1; + break; + case 3: // T + block->shape[0] = 0x2; + block->shape[1] = 0x7; + w = 2; h = 1; + break; + case 4: // L + block->shape[0] = 0x1; + block->shape[1] = 0x7; + w = 2; h = 1; + break; + case 5: // Z + block->shape[0] = 0x6; + block->shape[1] = 0x3; + w = 2; h = 1; + break; + case 6: // S + block->shape[0] = 0x3; + block->shape[1] = 0x6; + w = 2; h = 1; + break; + } + block->xywh = make_xywh(x, y, w, h); +} + +unsigned int get_shape(struct block *block, unsigned int r, unsigned int c) { + return (block->shape[r] & (1 << c)) >> c; +} + +unsigned int check_bounds(struct block *block) { + unsigned int xywh = block->xywh; + unsigned int h = xywh & 0x3; + unsigned int w = (xywh & 0xC) >> 2; + unsigned int y = (xywh & 0xFF0) >> 4; + unsigned int x = (xywh & 0xF000) >> 12; + if (x < 0 || x + w >= COLS) return 0; + if (y < 0 || y + h >= ROWS) return 0; + return 1; +} + +void copy_block(struct block *dst, struct block *src) { + dst->xywh = src->xywh; + dst->shape[0] = src->shape[0]; + dst->shape[1] = src->shape[1]; + dst->shape[2] = src->shape[2]; +} + +unsigned int check_collision(struct block *block) { + unsigned int xywh = block->xywh; + unsigned int h = xywh & 0x3; + unsigned int w = (xywh & 0xC) >> 2; + unsigned int y = (xywh & 0xFF0) >> 4; + unsigned int x = (xywh & 0xF000) >> 12; + for (int r = 0; r <= h; ++r) { + for (int c = 0; c <= w; ++c) { + if (get_shape(block, r, c) && + board[wk_mul(y + r, COLS) + x + c]) + return 0; + } + } + return 1; +} + +void putch_at(int x, int y, unsigned char ch) { +#ifdef DEBUG + screen[wk_mul(OFFSET_Y + y, SCREEN_COLS) + x + OFFSET_X] = ch; +#else + VA_VRAM[wk_mul(OFFSET_Y + y, SCREEN_COLS) + x + OFFSET_X] = ch; +#endif +} + + +void block_move(struct block *block, int dir) { + unsigned int xywh = block->xywh; + unsigned int h = xywh & 0x3; + unsigned int w = (xywh & 0xC) >> 2; + unsigned int y = (xywh & 0xFF0) >> 4; + unsigned int x = (xywh & 0xF000) >> 12; + switch(dir) { + case 0: // Left + x--; + break; + case 1: // Right + x++; + break; + case 2: // Down + y++; + break; + default: + break; + } + block->xywh = (x << 12) | (y << 4) | (w << 2) | h; +} + +unsigned int move(struct block *block, int dir) { + struct block moved; + copy_block(&moved, block); + block_move(&moved, dir); + if (check_bounds(&moved) && check_collision(&moved)) { + copy_block(block, &moved); + return 1; + } + return 0; +} + +void block_rotate(struct block *block, unsigned int clock) { + unsigned int xywh = block->xywh; + unsigned int h = xywh & 0x3; + unsigned int w = (xywh & 0xC) >> 2; + unsigned int y = (xywh & 0xFF0) >> 4; + unsigned int x = (xywh & 0xF000) >> 12; + unsigned int xyhw = make_xywh(x, y, h, w); + unsigned int shape[3] = {0, 0, 0}; + if (clock) { + for (int r = 0; r <= h; ++r) { + for (int c = 0; c <= w; ++c) { + shape[c] = shape[c] | (get_shape(block, r, c) << (h - r)); + } + } + + } else { + for (int r = 0; r <= h; ++r) { + for (int c = 0; c <= w; ++c) { + shape[w - c] = shape[w - c] | (get_shape(block, r, c) << r); + } + } + } + block->shape[0] = shape[0]; + block->shape[1] = shape[1]; + block->shape[2] = shape[2]; + block->xywh = xyhw; +} + + +void rotate(struct block *block, int clock) { + struct block rotated; + copy_block(&rotated, block); + block_rotate(&rotated, clock); + if (check_bounds(&rotated) && check_collision(&rotated)) { + copy_block(block, &rotated); + return; + } + unsigned int xywh = rotated.xywh; + unsigned int h = xywh & 0x3; + unsigned int w = (xywh & 0xc) >> 2; + unsigned int y = (xywh & 0xff0) >> 4; + unsigned int x = (xywh & 0xf000) >> 12; + if (x + w >= COLS) { + x = COLS - w - 1; + } + rotated.xywh = make_xywh(x, y, w, h); + if (check_bounds(&rotated) && check_collision(&rotated)) { + copy_block(block, &rotated); + } +} + +void clear_board() { + for (int i = 0, s = wk_mul(ROWS, COLS); i < s; ++i) { + board[i] = 0; + } +} + +void fix_block(struct block *block) { + unsigned int xywh = block->xywh; + unsigned int h = xywh & 0x3; + unsigned int w = (xywh & 0xc) >> 2; + unsigned int y = (xywh & 0xff0) >> 4; + unsigned int x = (xywh & 0xf000) >> 12; +#ifdef DEBUG + printf("%d %d %d %d\n", x, y, w, h); +#endif + for (int r = 0; r <= h; ++r) { + for (int c = 0; c <= w; ++c) { + if (get_shape(block, r, c)) { + board[wk_mul(y + r, COLS) + x + c] = 1; + } + } + } +} + +void print_score() { + int c = 8; + putch_at(c++, -2, 'S'); + putch_at(c++, -2, 'C'); + putch_at(c++, -2, 'O'); + putch_at(c++, -2, 'R'); + putch_at(c++, -2, 'E'); + for (int i = 0; i < 5; ++i) { + unsigned int mask = 0xF << (i * 4); + unsigned int num = (score & mask) >> (i * 4); + putch_at(12 - i, -1, num + '0'); + } +} + +void draw_board() { + for (int r = 0; r < ROWS; ++r) { + for (int c = 0; c < COLS; ++c) { + if (board[wk_mul(r , COLS) + c] == 1) { + putch_at((c << 1) + 1, r, '['); + putch_at((c << 1) + 2, r, ']'); + } else { + putch_at((c << 1) + 1, r, ' '); + putch_at((c << 1)+ 2, r, ' '); + } + } + } + unsigned int xywh = current.xywh; + unsigned int h = xywh & 0x3; + unsigned int w = (xywh & 0xc) >> 2; + unsigned int y = (xywh & 0xff0) >> 4; + unsigned int x = (xywh & 0xf000) >> 12; + for (int r = 0; r <= h; ++r) { + for (int c = 0; c <= w; ++c) { + if (get_shape(¤t, r, c)) { + putch_at(((c + x) << 1) + 1, r + y, '['); + putch_at(((c + x) << 1) + 2, r + y, ']'); + } + } + } + print_score(); +} + + +void add_score(unsigned int delta) { + score += delta; + for (unsigned int i = 0, carry = 0; i < 32; i += 4) { + unsigned int mask = 0xF << i; + unsigned int num = (score & mask) >> i; + num += carry; + if (num >= 10) { + carry = 1; + num -= 10; + } else { + carry = 0; + } + score &= ~(mask); + score |= (num << i); + } +} + +void check_clear() { + unsigned int y = (current.xywh & 0xff0) >> 4; + unsigned int h = current.xywh & 0x3; + for (int r = y + h; r >= y; --r) { + unsigned int count = 0; + for (int c = 0; c < COLS; ++c) { + if (board[wk_mul(r , COLS) + c]) ++count; + } + if (count == COLS) { + add_score(1); + for (int nr = r - 1; nr > 0; --nr) { + for (int c = 0; c < COLS; ++c) { + board[wk_mul(nr + 1, COLS) + c] = board[wk_mul(nr, COLS) + c]; + } + } + ++r; ++y; + } + } +} + +unsigned int rand() { + static unsigned int seed = 990315; + seed = (wk_mul(1103515245 , seed) + 12345) & 0x7FFFFFFF; + return seed; +} + +unsigned int rand_type() { + unsigned int type = rand() & 0x7; + while (type == 7) { + type = rand() & 0x7; + } + return type; +} + +void fall() { + if (move(¤t, 2) == 0) { + fix_block(¤t); + check_clear(); + init_block(¤t, rand_type(), 4, 0); + } +} + +#ifdef DEBUG +void print_screen() { + for (int r = 0; r < SCREEN_ROWS; ++r) { + for (int c = 0; c < SCREEN_COLS; ++c) { + printf("%c", screen[wk_mul(r, SCREEN_COLS) + c]); + } + printf("\n"); + } + printf("\n"); +} +#endif + +void on_input(unsigned int ch) { + switch (ch) { + case 's': + fall(); + break; + case 'a': + move(¤t, 0); + break; + case 'd': + move(¤t, 1); + break; + case 'j': + rotate(¤t, 0); + break; + case 'k': + rotate(¤t, 1); + break; + } + draw_board(); +#ifdef DEBUG + print_screen(); +#endif +} + +void on_timer() { + fall(); + draw_board(); +} + +void trap_handler(void *epc, unsigned int cause) { + if (cause == 0x80000007) { + on_timer(); + } else if (cause == 0x8000000B){ + unsigned int ch = *VA_UART_RECV; + *VA_UART_SEND = ch; + on_input(ch); + } +} + +void init() { + clear_board(); + // Draw border + for (int r = 0; r < ROWS; ++r) { + putch_at(0, r, '|'); + putch_at(COLS << 1 | 1, r, '|'); + } + for (int c = 0; c <= (2 << COLS | 1); ++c) { + putch_at(c, ROWS, '-'); + } + int c = 8; + putch_at(c++, ROWS + 1, 'B'); + putch_at(c++, ROWS + 1, 'e'); + putch_at(c++, ROWS + 1, 'g'); + putch_at(c++, ROWS + 1, 'i'); + putch_at(c++, ROWS + 1, 'n'); + putch_at(c++, ROWS + 1, ' '); + c = 6; + putch_at(c++, ROWS + 3, 'P'); + putch_at(c++, ROWS + 3, 'a'); + putch_at(c++, ROWS + 3, 'g'); + putch_at(c++, ROWS + 3, 'i'); + putch_at(c++, ROWS + 3, 'n'); + putch_at(c++, ROWS + 3, 'g'); + c++; + putch_at(c++, ROWS + 3, 'h'); + putch_at(c++, ROWS + 3, 'r'); + putch_at(c++, ROWS + 3, 'p'); + c = 9; + putch_at(c++, ROWS + 4, '2'); + putch_at(c++, ROWS + 4, '0'); + putch_at(c++, ROWS + 4, '2'); + putch_at(c++, ROWS + 4, '2'); + init_block(¤t, rand_type(), 4, 0); + score = 0; + draw_board(); +} + +int alloc(){ + int index = 0; + int max = 8; + while(index < max){ + if(pm[index] == 0){ + pm[index] = 1; + break; + } + index++; + } + return index == max ? -1 : index; +} + +int map(pagetable_t pgtbl,uint32 va,uint32 pa,int perm){ + int t; + if((pgtbl[PX(1,va)] & PTE_V )!= PTE_V){ //前缀不存在 + t=alloc(); //申请一个页给前缀页表 + if(t>=0){ + pgtbl[PX(1,va)] = PA2PTE(t<<12) | PTE_V; + }else{ + return -1; + } + } + int* n = (void*)PTE2PA(pgtbl[PX(1,va)]); + n[PX(0,va)] = PA2PTE(pa) | perm | PTE_V; + return 0; +} + +void kvminit(){ + //init global valuable + for(int i=0;i<8;i++){ + pm[i] = 0; + } + timercount = 0; + + pagetable_t pgtbl = (void*)PAGEDIR_BASE; + // memoryset(pgtbl,0,PGSIZE); //后面需要读这个内存,所以先初始化 + for(int i=0;i>2;i++){ + pgtbl[i]=0; + } + + pm[PAGEDIR_BASE >> 12] = 1; + pm[0]=1; + pm[1]=1; + pm[2]=1; + pm[3]=1; + pm[4]=1; + //create pte mmap for text + map(pgtbl,PAGEDIR_BASE,PAGEDIR_BASE,PTE_R | PTE_W); + map(pgtbl,0x0,0x0, PTE_W | PTE_R ); //kernel stack + map(pgtbl,0x1000,0x1000, PTE_W | PTE_R | PTE_X ); // + map(pgtbl,0x2000,0x2000, PTE_W | PTE_R | PTE_X ); // + map(pgtbl,0x3000,0x3000, PTE_W | PTE_R | PTE_X ); // + map(pgtbl,0x4000,0x4000, PTE_W | PTE_R | PTE_X ); // + map(pgtbl,VA_VRAM_BASE,VRAM_BASE, PTE_W | PTE_R ); // + map(pgtbl,VA_VRAM_BASE + PGSIZE,VRAM_BASE + PGSIZE, PTE_W | PTE_R); + map(pgtbl,VA_UART_BASE,UART_BASE, PTE_W | PTE_R ); // + map(pgtbl,VA_TIMER_BASE,TIMER_BASE, PTE_W | PTE_R ); // +} + +void clear_screen() { + int *vram = ((int *) VA_VRAM_BASE); + for (int i = 0; i < 600; ++i) vram[i] = 0x20202020; +} + +extern void enable_interrupt(); +extern void enable_paging(); + +int main() { +#ifdef DEBUG + unsigned char b[ROWS * COLS] = {0}; + board = b; + for (int i = 0; i < SCREEN_ROWS * SCREEN_COLS; ++i) screen[i] = '%'; + init(); +#else + kvminit(); + enable_paging(); + board = (unsigned char *) 16640; //0x4100 + clear_screen(); + init(); + *((unsigned int *) 4) = 0xDEADBEEF; + enable_interrupt(); + *VA_TIMER_ENABLED = 1; + *VA_TIMER_LIMIT = FALL_TIMER_LIMIT; + for (;;); +#endif +#ifdef DEBUG + on_input('a'); + on_input('a'); + on_input('s'); + on_input('s'); + on_input('s'); + for (int i = 21; i >= 0; --i) { + on_timer(); + } + on_input('d'); + on_input('d'); + on_input('d'); + on_input('d'); + for (int i = 21; i >= 0; --i) { + on_timer(); + } + on_input('d'); + on_input('d'); + on_input('d'); + on_input('d'); + on_input('d'); + for (int i = 21; i >= 0; --i) { + on_timer(); + add_score(10); + } + print_score(); + print_screen(); + return 0; +#endif +} diff --git a/lab4/csrc/toolchain.cmake b/lab4/csrc/toolchain.cmake new file mode 100644 index 0000000..60bc5a9 --- /dev/null +++ b/lab4/csrc/toolchain.cmake @@ -0,0 +1,20 @@ +set(CMAKE_SYSTEM_NAME Generic) +set(CMAKE_SYSTEM_PROCESSOR riscv32) + +set(triple riscv32-unknown-elf) + +set(CMAKE_C_COMPILER clang) +set(CMAKE_C_COMPILER_TARGET ${triple}) +set(CMAKE_CXX_COMPILER clang++) +set(CMAKE_CXX_COMPILER_TARGET ${triple}) +set(CMAKE_ASM_COMPILER clang) +set(CMAKE_ASM_COMPILER_TARGET ${triple}) +set(CMAKE_AR llvm-ar CACHE FILEPATH "Archiver") +set(CMAKE_OBJCOPY llvm-objcopy) + +set(CMAKE_C_FLAGS_INIT "-mno-relax") +set(CMAKE_CXX_FLAGS_INIT "-mno-relax") +set(CMAKE_ASM_FLAGS_INIT "-mno-relax") +set(CMAKE_EXE_LINKER_FLAGS_INIT "-fuse-ld=lld -nostdlib -static -mno-relax") +set(CMAKE_MODULE_LINKER_FLAGS_INIT "-fuse-ld=lld -nostdlib -static -mno-relax") +set(CMAKE_SHARED_LINKER_FLAGS_INIT "-fuse-ld=lld -nostdlib -static -mno-relax") diff --git a/lab4/project/build.properties b/lab4/project/build.properties new file mode 100644 index 0000000..303541e --- /dev/null +++ b/lab4/project/build.properties @@ -0,0 +1 @@ +sbt.version = 1.9.6 diff --git a/lab4/project/plugins.sbt b/lab4/project/plugins.sbt new file mode 100644 index 0000000..5708f81 --- /dev/null +++ b/lab4/project/plugins.sbt @@ -0,0 +1 @@ +logLevel := Level.Warn diff --git a/lab4/riscv-target/yatcpu/Makefile.include b/lab4/riscv-target/yatcpu/Makefile.include new file mode 100644 index 0000000..e209499 --- /dev/null +++ b/lab4/riscv-target/yatcpu/Makefile.include @@ -0,0 +1,7 @@ +export TARGETDIR ?= riscv-target +export XLEN = 32 +export RISCV_TARGET = yatcpu +export RISCV_DEVICE = +export RISCV_TARGET_FLAGS = +export RISCV_ASSERT = 0 +JOBS = -j1 \ No newline at end of file diff --git a/lab4/riscv-target/yatcpu/device/rv32i_m/I/Makefile.include b/lab4/riscv-target/yatcpu/device/rv32i_m/I/Makefile.include new file mode 100644 index 0000000..d17e055 --- /dev/null +++ b/lab4/riscv-target/yatcpu/device/rv32i_m/I/Makefile.include @@ -0,0 +1,54 @@ +TARGET_SIM ?= verilog/verilator/obj_dir/VTop +TARGET_FLAGS ?= $(RISCV_TARGET_FLAGS) +ifeq ($(shell command -v $(TARGET_SIM) 2> /dev/null),) + $(error Target simulator executable '$(TARGET_SIM)` not found) +endif + +RISCV_PREFIX ?= riscv64-unknown-elf- +RISCV_GCC ?= $(RISCV_PREFIX)gcc +RISCV_OBJDUMP ?= $(RISCV_PREFIX)objdump +RISCV_OBJCOPY ?= $(RISCV_PREFIX)objcopy +RISCV_GCC_OPTS ?= -g -static -mcmodel=medany -fvisibility=hidden -nostdlib -nostartfiles $(RVTEST_DEFINES) + +COMPILE_CMD = $$(RISCV_GCC) $(1) $$(RISCV_GCC_OPTS) \ + -I$(ROOTDIR)/riscv-test-suite/env/ \ + -I$(TARGETDIR)/$(RISCV_TARGET)/ \ + -T$(TARGETDIR)/$(RISCV_TARGET)/link.ld \ + $$(<) -o $$@ + +OBJDUMP_CMD = $$(RISCV_OBJDUMP) $$@ -D > $$@.objdump; \ + $$(RISCV_OBJDUMP) $$@ --source > $$@.debug; \ + $$(RISCV_OBJDUMP) -t $$@ | grep " begin_signature$$$$" | awk '{ print $$$$1 }' > $$@.begin_signature; \ + $$(RISCV_OBJDUMP) -t $$@ | grep " end_signature$$$$" | awk '{ print $$$$1 }' > $$@.end_signature; \ + $$(RISCV_OBJDUMP) -t $$@ | grep " tohost$$$$" | awk '{ print $$$$1 }' > $$@.halt \ + + +OBJCOPY_CMD = $$(RISCV_OBJCOPY) $$@ -O binary -j .text -j .data -j .tohost $$@.asmbin + +COMPILE_TARGET=\ + $(COMPILE_CMD); \ + if [ $$$$? -ne 0 ] ; \ + then \ + echo "\e[31m$$(RISCV_GCC) failed for target $$(@) \e[39m" ; \ + exit 1 ; \ + fi ; \ + $(OBJDUMP_CMD); \ + if [ $$$$? -ne 0 ] ; \ + then \ + echo "\e[31m $$(RISCV_OBJDUMP) failed for target $$(@) \e[39m" ; \ + exit 1 ; \ + fi ; \ + $(OBJCOPY_CMD); \ + if [ $$$$? -ne 0 ] ; \ + then \ + echo "\e[31m $$(RISCV_OBJCOPY) failed for target $$(@) \e[39m" ; \ + exit 1 ; \ + fi ; \ + +RUN_CMD = $(TARGET_SIM) $(TARGET_FLAGS) \ + -signature 0x$(shell cat $(<).begin_signature) 0x$(shell cat $(<).end_signature) $(*).signature.output \ + -halt 0x$(shell cat $(<).halt) \ + -time 1000000 \ + -instruction $(<).asmbin +RUN_TARGET = \ + $(RUN_CMD) diff --git a/lab4/riscv-target/yatcpu/link.ld b/lab4/riscv-target/yatcpu/link.ld new file mode 100644 index 0000000..6afe7d6 --- /dev/null +++ b/lab4/riscv-target/yatcpu/link.ld @@ -0,0 +1,12 @@ +OUTPUT_ARCH( "riscv" ) +ENTRY(rvtest_entry_point) + +SECTIONS +{ + . = 0x00001000; + .text : { *(.text.init) *(.text.startup) *(.text) } + .data ALIGN(0x1000) : { *(.data*) *(.rodata*) *(.sdata*) } + .tohost ALIGN(0x1000) : { *(.tohost) } + .bss : { *(.bss) } + _end = .; +} diff --git a/lab4/riscv-target/yatcpu/model_test.h b/lab4/riscv-target/yatcpu/model_test.h new file mode 100644 index 0000000..ca8f8c6 --- /dev/null +++ b/lab4/riscv-target/yatcpu/model_test.h @@ -0,0 +1,46 @@ +#ifndef _COMPLIANCE_MODEL_H_ +#define _COMPLIANCE_MODEL_H_ + +#define ALIGNMENT 2 + +#define RVMODEL_DATA_SECTION \ + .pushsection .tohost,"aw",@progbits; \ + .align 4; .global tohost; tohost: .word 0; \ + .popsection; + +#define RVMODEL_BOOT + +#define RVMODEL_HALT \ + li x1, 0xBABECAFE; \ + write_tohost: \ + sw x1, tohost, x0; \ + loop: j loop + +//RV_COMPLIANCE_DATA_BEGIN +#define RVMODEL_DATA_BEGIN \ + .align 4; .global begin_signature; begin_signature: + +//RV_COMPLIANCE_DATA_END +#define RVMODEL_DATA_END \ + .align 4; .global end_signature; end_signature: \ + RVMODEL_DATA_SECTION \ + +//RVTEST_IO_INIT +#define RVMODEL_IO_INIT +//RVTEST_IO_WRITE_STR +#define RVMODEL_IO_WRITE_STR(_R, _STR) +//RVTEST_IO_CHECK +#define RVMODEL_IO_CHECK() +//RVTEST_IO_ASSERT_GPR_EQ +#define RVMODEL_IO_ASSERT_GPR_EQ(_S, _R, _I) +//RVTEST_IO_ASSERT_SFPR_EQ +#define RVMODEL_IO_ASSERT_SFPR_EQ(_F, _R, _I) +//RVTEST_IO_ASSERT_DFPR_EQ +#define RVMODEL_IO_ASSERT_DFPR_EQ(_D, _R, _I) + +#define RVMODEL_SET_MSW_INT +#define RVMODEL_CLEAR_MSW_INT +#define RVMODEL_CLEAR_MTIMER_INT +#define RVMODEL_CLEAR_MEXT_INT + +#endif diff --git a/lab4/src/main/resources/fibonacci.asmbin b/lab4/src/main/resources/fibonacci.asmbin new file mode 100644 index 0000000000000000000000000000000000000000..529496d501259a61ff51e4ec613f2549ede5d2a0 GIT binary patch literal 520 zcmXZZv1;5v5CG7b9nEc%;*7dLK&O%9vnUtgQ9znFc?H|v|O zH?xmRfUX?Rhqzgfah@XnmwXSTIsutFkop5ia|zOZ0?C|_{Iikbi;?Q9k!dti|1{G4 zGSdDwk|C>QDJHC*)w6n5&+1t+Z`E7%R=rhk)m!yey&Y=#Q)csB?GQ2tVG@CI#E?5A z@fakc<|Y)*Q0Yx5qoE2ZRE}uhQ`nD0Q%u6tC3N7Ea1ax!kwfj64n2p%$kgB{G;Tyk zeiV-4h+4Fvb(W634ad=T6PS09&2$zkX>}HjhcrR$_kKlXvhH~dS8pC*0cWtyGq`%Y z%~L&-`hK;5?=+mH{CBk2vHKF2}DI3A(EojU;?|Ib7w9~`H8&v)_u7% zbLKneJKs5TvQYzCCtCp)o$9+80GKoZ%14iyx$>UgxejmrPOfbB4m$ujyS0zL-n!N3 z3mL`@+3^I(@K%sragg1wfQ%$T_8bB!;->64ZpzM+rVM{!%C4FzyU&|4@}ntxuA5RA z9I;$>wsXXD#B;=R#B;=RDT)^2EyP=hw-9e3-a@>Ec#F9FX^Xx|AxWQ!6aAnQFz3FzwO=cHO*RGi?Y%n(*XKX`}xf^PXbr}J-D;{7Qivf3IEx@`B z?smsH+f?N4rW$7vBj`rrLAJRVbT`+6tjDn2p18%f6fJj4&C0byUk*esYEhRxs70g* zp@4z8PS<7E>AGw8H$oF>C{H9{JFmbT2SHyMp02ZSpb=`@522?9(6->&W#@D~!~tZ- zbUgzxKs@eyjnvB(llII$Mn3DI_iYcuY>s#4>!(T!AWzJIxM zO{(34xK3H~b;kcfUj2=-=0$#qCw-$q5MCT-2JYjtA;Xw|r0mqgpI+u|F5ufDPmuI@U!OYs5-z9(Uz8=JUV1 zUMu*MU#}*}#ji2-y6irU@4(j<`<)-OQ@6G4M{Thu9;hwdM{Nm@+G5Y$&EcLmha8y7 zC3Ypm9ZRj9-!QK7T_g*(ojpUAKBO*t$#R1P29c$jzNb5cEzJWW5o>TA-JY`SJYpf@t)JQfIl!^tQo6% zx#_F=^~3p^(6x;H9u4Ds?7~@P53DOwe{|12t~kdoHT}lEqIu)miFM^=Zj>)1@E+<$ zdk%rr(@Im7bD~Azoki?f$Lr(i8DHP4SYwOc7V*c~+eigf-)Kz(TCbn|J6>=3@3i!` zfjx7K{K^k$7C1)qmt~G;t<5u<>v~S&9i0pI7M|bR^DF9#K4NSJXTMj={)YT`24@u2 zIj?9cOO3{&6C2ktXYa`Gq&kb8(YCW5pM_5^ zmP^amWXI>;TvB-F0Od&k!&ZN*3al!ys=%rOs|x&|3cQ-k@7O&k`qN_>u{)a?&L+nM z>`Z2djwG{bksldLXGJPg7|)B*k+G4ycwWF@e9u1dLb5Oa7;onI0X@M8uIyc66w{1tKCno_u38Jw%v&p6h&eWOx`uP@o(gM+7>;@2+Gn zFA}?V(7JylM=<3d{dffSq*I5*f%Kbn;l=TMI-4yV%(wfHh}aPy+?ycdw%%=9#m)@o PGbDB;3oZDE0tNjSxiaS7 literal 0 HcmV?d00001 diff --git a/lab4/src/main/resources/mmio.asmbin b/lab4/src/main/resources/mmio.asmbin new file mode 100644 index 0000000000000000000000000000000000000000..22cc8f4b9b5d3ab1ce53f87b27cbafea18e571e6 GIT binary patch literal 32 mcmXqKWoT$ta%I?ll!0M#>(_V6N?RF(85kItm0cO~fiwV{qzDB7 literal 0 HcmV?d00001 diff --git a/lab4/src/main/resources/quicksort.asmbin b/lab4/src/main/resources/quicksort.asmbin new file mode 100644 index 0000000000000000000000000000000000000000..ddf0f043fa685e6776ff7d014fc2cd388dfd6fe9 GIT binary patch literal 1012 zcmZvbF>ljQ5XbMm=NB&wsjM)t;O1gCO-&kTB-UE07#I-n0SYJsV?hyn+}BEspa^xO zNa+VaG-9^oegI}BBoG@aLLh`(hySx1D5!&V_UZob{qFwf>w@ZgMD%$?*R~M%B++<# zTMox}dvBZN`_tiA_8yLihC#h=WBFbeeNTv=+*}|IuM)Ro;?5o7=mBx}F|i*@Za$aX zdL=o0ExDaa?!1#6eURM!D%lqrTFtFR4ZVh5L$9IN&};S+7kU?Z7kU?Z7kU?Z7kbyS zd<*>kDLWZICbO85Y6@YRu~3`{!>PcxG_6>wAdx0Wr3!^IVXV|rqRdjNR9iTv9Xo0{ zam;e+sE*L46Kl1SXtR=P6^WXO;+ndW)XbH%rn4$hgqQlXJ&$|7~GiB7OmrC2qe7iaY**eSdkVg6Y@xK-UX*RBOq< zoWj%JXXTy8_kJ1hDV*;$z_)u)@~Lp6@Gge*X7`AA|Dfyz=YwP8e2xeloAdLl9!idA z&arb22ky`fV$5Lc4+nDpaDeM9$MNMa3cZ)i|1nm4&a7mw{g_qzGWt~I!M)oc1&>bm z=wmq_cxe1o!c%2;9Wm!Fyp2k49XmJf9D?&cc7Kw4+QALMF zx3lFYbhT&jI)na^)gz9q9x=;L`QC#s$3B#P!B?EMPlKCNS^2k*nWNkWb+?$ literal 0 HcmV?d00001 diff --git a/lab4/src/main/resources/sb.asmbin b/lab4/src/main/resources/sb.asmbin new file mode 100644 index 0000000000000000000000000000000000000000..fde0216ff6947c0b66cb85c21d84af9f23f2a4a1 GIT binary patch literal 36 scmWe;bzs95pR$yhwXJB9e0NFnYLI3~& literal 0 HcmV?d00001 diff --git a/lab4/src/main/resources/tetris.asmbin b/lab4/src/main/resources/tetris.asmbin new file mode 100644 index 0000000000000000000000000000000000000000..3d3132450f4c1610aad971a4d15267361cca9056 GIT binary patch literal 8300 zcmeHMZ;V`36~FJ#ebY1rwtZ}4h_R2oJJY2s%aUy!;-|M}77ZZ=jP-*b+$CdysA+5J zej=J#-jwjcn34(B4@RnNiP2~@-C=_vWY)|!V#HL1Mnkj^2^dLqq--tQ`Qz`Ld++>v zTgnIY6PrwC-u-vZ`JMAS=iIk>M~s||gm|+go6?F#IQv7#xva)^3YEJUJVyK4LguFCzw zRTFEj+V^``O}^%;seijFawPUjHGZ?ieu@1O`z7{E?3XH9%3yy6`!m>|!Tt>PXRtqm z{Tb5bVm8`;a)fn1l0>s2xp_@^V~&%I%{rc1auT)X;Mq;aXI(G55ygTPn8`eqC~5 zr)TZ7=d!(HusvFClPzlbG~1+pXueO;x8G4yE6q?Yh~ihPyP$t79L>FBFk#yz?+YkMuUboOEd-^J}g{RkI-q=F; zY^^87QXTk~+t9I{xcN-<_GoD#qv72fS`n zI^n@}M@=mwM!=Vm)2`+~y#@Q28x?s<6u+!F!|?!KAbwU(E;;AARoGsQn94ow+ zFa`J0xOEWkuz`8)*m$>gcJXGrb-Z#+@bg?Z_VxPX`Wc*n90C6jPaWf*L0wn4c16{m&{=VvUb8>a8=!*NI#F&0L?8ItOka_Gih{@(Zm{a_(y$Y0O{JV`V)? z_B7@%z7IccnV+A^)Z3nX2RTv4ZYU3sF4FMnDXn*zc-A4k^MQ!M;H*QxRf+vLoOcKP zXzBpR)(6N7iYM|V`@ydoew14k_@X%Q9NA|N+yZ7B$h{N;CDcTE2Cn+qA>Z+{&YN71 zc+KcK&eiI@m=NH(;M!^8X)B&@qJI0R-#+SE(BnCB!UyU%%3(g@ zsf@f`Ft(PCTVJYuD^2tbO<+V^>cE#hevWs!i@7p!cRSg`wvE}j0_K>z%uU2?voe~) zntBs9ZQ9xjd7D^Ayf*m9-%qlID`7x9Eni8XpSQQ%JoD%q@yzb?@H=z18Sc&rj(yZ9 zgC%k_Vu<87<}Vv=>M_!{F~5O2xPx_!td73c|DitprP-hQ~gKV;cGic@5Y69 z^jN(KoH{1QQ$6CI13K&9l-rU2c>HP34-$D^BF_gV&o>cg=!3a`@@<^a`cV3mhpZjn z#W|4WcXX`B=jqw-;W3W;?UoPS`u{y1H@zfu0w3&LtpYz>=Ye0ucYL?FHY11V-=;Q$ zkMx|X&79k@$JXW?uOlqFxxRR~+ruKSoS;4~R#?}=jq*Qm%7LSeP6z$U=P{3*10DG} zet2uUO5eV^UGbxQ{y6&iXw3u8zQK8*Zij~d=&2m)9gO@r?x7KPgcV_3{DQ{R)->|V z8T1dlANgL}LcZd9g#P=<<~3_M_v{6oM@(I3>|r}`yxSL<8kE8wJuk1b*hhpJ@)_rC z<_zj}o$7TjAEfKNspVv69e%JrsC|*K-LCH>)^5tnzyx`^-u17>tagX4i3ObDw{A6Un`1nS8?q0Jmewcj#f0CUPJE4q4@owD{ zk-v1lYKWQ9D)+-0+c^iAwyEc(J=}Anw+8QlHJwpo-XzHHxC?pVrHvaZve7a6d|hKo z>tG|vZajGz_zm|U138BEG(9ft!QOkFVxc-hXQgd8A&U3tn$wL1=00I>c~jci>*sv# zi@2`LQ6Go?W0$$#l0CSyhKELBE93@0H@KD_Bz$;IX3g9=GgmtVz5MQccdx*EgnCos zP%5G(AU+4rF#f!s>`LP_|F#~39vnl2-Tc4E#!ynt`(W=ZsXqIGzB&$WkuJbQ_t}Sa zt%J`wKU$rPJ>$$z(`$QNXEY~!*wQ|qx!A)vzAv?wvF=}MF)w|lhgm^$lXPtC*`n9p zbJ6r(XAyV9Id_1!RNJU;UZwlN={W~AT&N$P?#7%#{?j3rP^@vx^tg*V-40#D z8580OWc0-bWMGUiZ0vcL)-cu|vAJZ#-1ll1Jott08mLvq$9Ts1pX=j6U;Sd;@6kLU ztl%^7TRMpoeN)>9EOc!3a!NP%82ib8jrrHN;L1RMlE=F*;!Bb} z9^?<6oeky7Zy0@lY3gk!|8a_&?|7su?xCeHxWqA}#;bvceULHyPGLZX=^ZbJi;FBv z+e&%;s3?9+``y&bOWie%J;WWlFTLm4Hoocom(e?_kiT#2^%az7$woad4jX-5G%`1= zona7*N+8TR@w2SwHRN-yfu0q)@veUF8ac%Ws@rspuy3BUe-i7R-gtNYEa`7#J$fx14Ho|}>ys_kr*bUWOLneGQK}qY z6vdnReHr6kRdO*Gd#91VI9_oF_z~_V*}A=dzGX0e&m3m_dN=2ubU(rGv=gfH@Ov24 zGHM*>GiIf~qu=EGMZJf?@lBS=>%k*BuQ7jx&mQQh(5rm9|9-#VguyvipCSIH&!Ak4 zGq@kRfIA!dMPp}$#__%ZF^>0Bc;_6%_Lcz@vPZ?`PY2+GrAAqdA557 zc{|?o=ZM)?d(Lq3 zCzPKozip0EV~B}Y=`LG4j6B(1rP_raLCdUt3j7`Jkp^;dUW$lfKOOf+v*^Rkdp+F` z&|TpS@>f0^MaZQty@N={|NK_>(E*v3zj?ghU!6nUnZW-y`Z$-z7}ajvWmrDhOtlyo zbx1z%ACPVPpn3CtLcFapi=WG{|Mago>z``ul+ZZEpP)R&@8QPJHgY%A8%- M%n9+8kKQ2u3;t?Qwg3PC literal 0 HcmV?d00001 diff --git a/lab4/src/main/resources/vga_font_8x16.bmp b/lab4/src/main/resources/vga_font_8x16.bmp new file mode 100644 index 0000000000000000000000000000000000000000..1aa58b97adc06ca07e07f83dc762bdce4b963d68 GIT binary patch literal 17462 zcmeHJJF?`)5riUS=om0{0@?_LT;2gk!BJo+bPm`$gA5#jK8;mYW@UFZ1~c!y;kO72JFBA zoVv<=hFyRa*nk~4fK%6e%&-fv0voUc2XOKcEawcn04uNoJ8%H!wBh{QGy`$+6^K7O zZ~*7D;r!b?0}HSM8?XZhaO$xwGwcGazy|EV0i1fI>kPX9E3g4OZ~&(sH->E60<6FW z?7#t>dKLB=b^%sk19sp5PQ50_47&g;umL-804HCe?VMp3U3;#}EzJv$hPoyIL zKl^dlw|kC*egEI9A+KuO841{@iMAiu_KTJmr5qqe=XLMhJK*M<&PN3Lx!vCGp-w05 z`IC&^oC=d(?SJC4Ejpqu%cDG@KTXHPoEj>WdrHnxK~f((cx=Zvy)Q-8$1b>}zT^j` zvBELC`r{_d7_%9bHn=aTy@ND!ul6z~pFd5Mcw3zl-6;oStzHj4ABqJ!%jByq&2(9h zC3IlTZ$;LaA4;h+<`6Lv%ZQ6Gs@!)TuS|75^<|LM-ys`;=}nIeX5CSP$9qb}u5(FP z&uUq=$-YZfS)VyCqyFdTk8A=^b%inUqRcSn z1Ggn*vz>b=G{$6TzE)19t5T0k>)-}YgNAfuGu`x^ATfegNjGy&(_&G4m3RE=cG@I3 zZ}8%pZqM;7@A;p$-axsn;#S7{{Aj*?9B;LkuHwGcbzA?c{?b(3Tm3ha9})0{U2MBX z=lvlduHRqyF^(hUu$660y0LW)kEireL=re*>$Q)B{&peG%?;LC`i-ayLzX|=9z-T# zH+ws$h*6;P^FHEYa@$R$w6_yg807M`G$Z z%~1R&^VM`jMv1$t`OufEbz|1ZvfBn{>6A& z7&aTM_zlSq1krih{j~4_@pn?c>HN40?OnGLmlL-WYsqJp`Ap|UvV~|e%OFp%rV7z$5Ja>G2v!@_RwIt9A+5ru}wI8Ti)>p z=DUR!%gg!Db4_N=$wl<&R! zANnTXurW_7PS#_6kr_8ei}U}-(X4*HD2S35lCh_-FVD+CEX0o6sP0SXF_wrM7^$(e9nGgDvJMAfKBB)qIxN%H%N1ZJwP1;>0wKOsl{t)v6}>+9%giV^b_8*Zlae zdDc?Y0~HS6U#7gbp)cC{{9s0zi_+R5*31pIaEJV$qe>`L?UuzDn|`ky!OXSjj>>FI0IhgQC?_=-f5cDS zSmo-W*9Li~7t`r>G`X81aJ7c+KyTg%1w9Fe_5+4LZsLzv5kFC(giO^J1 zv&9enCGnf)w?T4p8+=ZFpscWf#Sfqnn?Mvx-+2Cqt7s={{o$nQT`o#7A~|NJ)eDsz zP#nuP>C896FsQMHtOs#;T!|7jEq)G9!(1apgn)6e$_`YuaG$(?#iF!+I6ZHVR)rzO zUQJ3$*YRn(Rn0w@C_-s#{;i&#lN3Z&k9&)4W2%!qOjSP^j;m)P3r@sLyTBYX zS#W}apUdYBe9Iencw@h%_&c>}Iz?+qEzkzK`YOiv=E6SBjdX31*uFyH(nlxuFn z+QtJhrInAJGcnSVV>3)va^xdw2{~Mu9-14A{Jghlj-SV6*y9}8>Tn8M5feqm@yP6L z^4i#5s8iC{PU?PI9~m4A1&h$;QoHK58%IrAZ)Qho)L;f9vl13T#Ln3|-xXAmLaZP8 z)m`NIJrve%ZbHJD_s)f(sY-khRV=TmkVLOdmH$EiI)B_v5&K5- LisBRZyA1jtmw literal 0 HcmV?d00001 diff --git a/lab4/src/main/scala/board/basys3/BCD2Segments.scala b/lab4/src/main/scala/board/basys3/BCD2Segments.scala new file mode 100644 index 0000000..65b79b8 --- /dev/null +++ b/lab4/src/main/scala/board/basys3/BCD2Segments.scala @@ -0,0 +1,54 @@ +// 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 board.basys3 + +import chisel3._ +import chisel3.util._ + +class BCD2Segments extends Module { + val io = IO(new Bundle { + val bcd = Input(UInt(4.W)) + val segs = Output(UInt(8.W)) + }) + + val bcd = io.bcd + val segs = Wire(UInt(8.W)) + + segs := MuxLookup( + bcd, + 0xFF.U, + IndexedSeq( + 0.U -> "b10000001".U, + 1.U -> "b11001111".U, + 2.U -> "b10010010".U, + 3.U -> "b10000110".U, + 4.U -> "b11001100".U, + 5.U -> "b10100100".U, + 6.U -> "b10100000".U, + 7.U -> "b10001111".U, + 8.U -> "b10000000".U, + 9.U -> "b10000100".U, + 10.U -> "b00001000".U, + 11.U -> "b01100000".U, + 12.U -> "b00110001".U, + 13.U -> "b01000010".U, + 14.U -> "b00110000".U, + 15.U -> "b00111000".U, + ) + ) + + io.segs := segs +} + diff --git a/lab4/src/main/scala/board/basys3/OnboardDigitDisplay.scala b/lab4/src/main/scala/board/basys3/OnboardDigitDisplay.scala new file mode 100644 index 0000000..a07819b --- /dev/null +++ b/lab4/src/main/scala/board/basys3/OnboardDigitDisplay.scala @@ -0,0 +1,32 @@ +// 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 board.basys3 + +import chisel3._ + +class OnboardDigitDisplay extends Module { + val io = IO(new Bundle { + val digit_mask = Output(UInt(4.W)) + }) + + val counter = RegInit(UInt(16.W), 0.U) + val digit_mask = RegInit(UInt(4.W), "b0111".U) + + counter := counter + 1.U + when(counter === 0.U) { + digit_mask := (digit_mask << 1.U).asUInt + digit_mask(3) + } + io.digit_mask := digit_mask +} diff --git a/lab4/src/main/scala/board/basys3/SYSULogo.scala b/lab4/src/main/scala/board/basys3/SYSULogo.scala new file mode 100644 index 0000000..c41f4e6 --- /dev/null +++ b/lab4/src/main/scala/board/basys3/SYSULogo.scala @@ -0,0 +1,34 @@ +// 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 board.basys3 + +import chisel3._ +import chisel3.util._ + +class SYSULogo extends Module { + val io = IO(new Bundle { + val digit_mask = Input(UInt(4.W)) + val segs = Output(UInt(8.W)) + }) + + io.segs := MuxLookup( + io.digit_mask, + "b00100100".U, // "b0111".U, "b1101".U -> S + IndexedSeq( + "b1011".U -> "b01000100".U, // Y + "b1110".U -> "b01000001".U, // U + ) + ) +} diff --git a/lab4/src/main/scala/board/basys3/SegmentMux.scala b/lab4/src/main/scala/board/basys3/SegmentMux.scala new file mode 100644 index 0000000..9bb1bf7 --- /dev/null +++ b/lab4/src/main/scala/board/basys3/SegmentMux.scala @@ -0,0 +1,42 @@ +// 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 board.basys3 + +import chisel3._ +import chisel3.util._ + +class SegmentMux extends Module { + val io = IO(new Bundle { + val digit_mask = Input(UInt(4.W)) + val numbers = Input(UInt(16.W)) + val segs = Output(UInt(8.W)) + }) + + + val digit = RegInit(UInt(4.W), 0.U) + val bcd2segs = Module(new BCD2Segments) + + bcd2segs.io.bcd := digit + io.segs := bcd2segs.io.segs + digit := MuxLookup( + io.digit_mask, + io.numbers(3, 0), // "b1110".U + IndexedSeq( + "b1101".U -> io.numbers(7, 4), + "b1011".U -> io.numbers(11, 8), + "b0111".U -> io.numbers(15, 12) + ) + ) +} diff --git a/lab4/src/main/scala/board/basys3/Top.scala b/lab4/src/main/scala/board/basys3/Top.scala new file mode 100644 index 0000000..e699750 --- /dev/null +++ b/lab4/src/main/scala/board/basys3/Top.scala @@ -0,0 +1,143 @@ +// 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 board.basys3 + +import chisel3._ +import chisel3.experimental.ChiselEnum +import chisel3.util._ +import riscv._ +import peripheral.{CharacterDisplay, DummySlave, InstructionROM, Memory, ROMLoader, Timer, Uart, VGADisplay} +import bus.{BusArbiter, BusSwitch} +import chisel3.stage.{ChiselGeneratorAnnotation, ChiselStage} +import riscv.core.CPU + +object BootStates extends ChiselEnum { + val Init, Loading, Finished = Value +} + +class Top extends Module { + val binaryFilename = "tetris.asmbin" + val io = IO(new Bundle { + val switch = Input(UInt(16.W)) + + val segs = Output(UInt(8.W)) + val digit_mask = Output(UInt(4.W)) + + val hsync = Output(Bool()) + val vsync = Output(Bool()) + val rgb = Output(UInt(12.W)) + val led = Output(UInt(16.W)) + + val tx = Output(Bool()) + val rx = Input(Bool()) + }) + val boot_state = RegInit(BootStates.Init) + + val uart = Module(new Uart(100000000, 115200)) + io.tx := uart.io.txd + uart.io.rxd := io.rx + + val cpu = Module(new CPU) + val mem = Module(new Memory(Parameters.MemorySizeInWords)) + val timer = Module(new Timer) + val dummy = Module(new DummySlave) + val bus_arbiter = Module(new BusArbiter) + val bus_switch = Module(new BusSwitch) + + val instruction_rom = Module(new InstructionROM(binaryFilename)) + val rom_loader = Module(new ROMLoader(instruction_rom.capacity)) + + val vga_display = Module(new VGADisplay) + bus_arbiter.io.bus_request(0) := true.B + + 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 := Parameters.EntryAddress + rom_loader.io.load_start := false.B + rom_loader.io.rom_data := instruction_rom.io.data + 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) { + cpu.io.stall_flag_bus := false.B + cpu.io.instruction_valid := true.B + } + } + val display = Module(new CharacterDisplay) + bus_switch.io.slaves(1) <> display.io.channels + bus_switch.io.slaves(2) <> uart.io.channels + bus_switch.io.slaves(4) <> timer.io.channels + + cpu.io.interrupt_flag := Cat(uart.io.signal_interrupt, timer.io.signal_interrupt) + + cpu.io.debug_read_address := 0.U + mem.io.debug_read_address := 0.U + + io.hsync := vga_display.io.hsync + io.vsync := vga_display.io.vsync + + display.io.x := vga_display.io.x + display.io.y := vga_display.io.y + display.io.video_on := vga_display.io.video_on + + io.rgb := display.io.rgb + + mem.io.debug_read_address := io.switch(15, 1).asUInt << 2 + io.led := Mux( + io.switch(0), + mem.io.debug_read_data(31, 16).asUInt, + mem.io.debug_read_data(15, 0).asUInt, + ) + + val onboard_display = Module(new OnboardDigitDisplay) + io.digit_mask := onboard_display.io.digit_mask + + val sysu_logo = Module(new SYSULogo) + sysu_logo.io.digit_mask := io.digit_mask + + val seg_mux = Module(new SegmentMux) + seg_mux.io.digit_mask := io.digit_mask + seg_mux.io.numbers := io.led + + io.segs := MuxLookup( + io.switch, + seg_mux.io.segs, + IndexedSeq( + 0.U -> sysu_logo.io.segs + ) + ) +} + +object VerilogGenerator extends App { + (new ChiselStage).execute(Array("-X", "verilog", "-td", "verilog/basys3"), Seq(ChiselGeneratorAnnotation(() => new Top))) +} \ No newline at end of file diff --git a/lab4/src/main/scala/board/pynq/Top.scala b/lab4/src/main/scala/board/pynq/Top.scala new file mode 100644 index 0000000..04f976b --- /dev/null +++ b/lab4/src/main/scala/board/pynq/Top.scala @@ -0,0 +1,149 @@ +// Copyright 2022 Canbin Huang +// +// 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 board.pynq + +import bus.{AXI4LiteChannels, AXI4LiteInterface, BusArbiter, BusSwitch} +import chisel3._ +import chisel3.experimental.ChiselEnum +import chisel3.stage.{ChiselGeneratorAnnotation, ChiselStage} +import chisel3.util.{Cat, is, switch} +import peripheral._ +import riscv.{ImplementationType, Parameters} +import riscv.core.{CPU, CPUBundle} + +object BootStates extends ChiselEnum { + val Init, Loading, BusWait, Finished = Value +} + +class Top extends Module { + val binaryFilename = "litenes.asmbin" + val io = IO(new Bundle() { + val hdmi_clk_n = Output(Bool()) + val hdmi_clk_p = Output(Bool()) + val hdmi_data_n = Output(UInt(3.W)) + val hdmi_data_p = Output(UInt(3.W)) + val hdmi_hpdn = Output(Bool()) + + val axi_mem = new AXI4LiteInterface(32, 32) + + val tx = Output(Bool()) + val rx = Input(Bool()) + + val led = Output(UInt(4.W)) + }) + val boot_state = RegInit(BootStates.Init) + io.led := boot_state.asUInt + val uart = Module(new Uart(125000000, 115200)) + io.tx := uart.io.txd + uart.io.rxd := io.rx + + val cpu = Module(new CPU) + val mem = Wire(new AXI4LiteChannels(32, 32)) + val timer = Module(new Timer) + val dummy = Module(new DummySlave) + val bus_arbiter = Module(new BusArbiter) + val bus_switch = Module(new BusSwitch) + mem.write_address_channel.AWADDR <> io.axi_mem.AWADDR + mem.write_address_channel.AWPROT <> io.axi_mem.AWPROT + mem.write_address_channel.AWREADY <> io.axi_mem.AWREADY + mem.write_address_channel.AWVALID <> io.axi_mem.AWVALID + mem.read_address_channel.ARADDR <> io.axi_mem.ARADDR + mem.read_address_channel.ARPROT <> io.axi_mem.ARPROT + mem.read_address_channel.ARREADY <> io.axi_mem.ARREADY + mem.read_address_channel.ARVALID <> io.axi_mem.ARVALID + mem.read_data_channel.RDATA <> io.axi_mem.RDATA + mem.read_data_channel.RVALID <> io.axi_mem.RVALID + mem.read_data_channel.RRESP <> io.axi_mem.RRESP + mem.read_data_channel.RREADY <> io.axi_mem.RREADY + mem.write_data_channel.WDATA <> io.axi_mem.WDATA + mem.write_data_channel.WVALID <> io.axi_mem.WVALID + mem.write_data_channel.WSTRB <> io.axi_mem.WSTRB + mem.write_data_channel.WREADY <> io.axi_mem.WREADY + mem.write_response_channel.BVALID <> io.axi_mem.BVALID + mem.write_response_channel.BRESP <> io.axi_mem.BRESP + mem.write_response_channel.BREADY <> io.axi_mem.BREADY + + val instruction_rom = Module(new InstructionROM(binaryFilename)) + val rom_loader = Module(new ROMLoader(instruction_rom.capacity)) + + val hdmi_display = Module(new HDMIDisplay) + bus_arbiter.io.bus_request(0) := true.B + + 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 := Parameters.EntryAddress + rom_loader.io.load_start := false.B + rom_loader.io.rom_data := instruction_rom.io.data + instruction_rom.io.address := rom_loader.io.rom_address + cpu.io.stall_flag_bus := true.B + cpu.io.instruction_valid := false.B + rom_loader.io.channels <> dummy.io.channels + bus_switch.io.slaves(0) <> mem + switch(boot_state) { + is(BootStates.Init) { + rom_loader.io.load_start := true.B + boot_state := BootStates.Loading + rom_loader.io.channels <> mem + bus_switch.io.slaves(0) <> dummy.io.channels + } + is(BootStates.Loading) { + rom_loader.io.load_start := false.B + rom_loader.io.channels <> mem + bus_switch.io.slaves(0) <> dummy.io.channels + when(rom_loader.io.load_finished) { + boot_state := BootStates.BusWait + } + } + is(BootStates.BusWait) { + when(!cpu.io.bus_busy) { + boot_state := BootStates.Finished + } + } + is(BootStates.Finished) { + cpu.io.stall_flag_bus := false.B + cpu.io.instruction_valid := true.B + rom_loader.io.channels <> dummy.io.channels + bus_switch.io.slaves(0) <> mem + } + } + + val display = Module(new PixelDisplay) + bus_switch.io.slaves(1) <> display.io.channels + bus_switch.io.slaves(2) <> uart.io.channels + bus_switch.io.slaves(4) <> timer.io.channels + + cpu.io.interrupt_flag := uart.io.signal_interrupt ## timer.io.signal_interrupt + io.led := uart.io.signal_interrupt ## timer.io.signal_interrupt ## boot_state.asUInt + + cpu.io.debug_read_address := 0.U + + display.io.x := hdmi_display.io.x_next + display.io.y := hdmi_display.io.y_next + display.io.video_on := hdmi_display.io.video_on + hdmi_display.io.rgb := display.io.rgb + + io.hdmi_hpdn := 1.U + io.hdmi_data_n := hdmi_display.io.TMDSdata_n + io.hdmi_data_p := hdmi_display.io.TMDSdata_p + io.hdmi_clk_n := hdmi_display.io.TMDSclk_n + io.hdmi_clk_p := hdmi_display.io.TMDSclk_p +} + +object VerilogGenerator extends App { + (new ChiselStage).execute(Array("-X", "verilog", "-td", "verilog/pynq"), Seq(ChiselGeneratorAnnotation(() => new Top))) +} \ No newline at end of file diff --git a/lab4/src/main/scala/board/verilator/Top.scala b/lab4/src/main/scala/board/verilator/Top.scala new file mode 100644 index 0000000..4b5e180 --- /dev/null +++ b/lab4/src/main/scala/board/verilator/Top.scala @@ -0,0 +1,71 @@ +// 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 board.verilator + +import bus.{AXI4LiteSlave, AXI4LiteSlaveBundle, BusArbiter, BusSwitch} +import chisel3._ +import chisel3.stage.{ChiselGeneratorAnnotation, ChiselStage} +import peripheral.DummySlave +import riscv.Parameters +import riscv.core.CPU + +class Top extends Module { + + val io = IO(new Bundle { + val signal_interrupt = Input(Bool()) + + val mem_slave = new AXI4LiteSlaveBundle(Parameters.AddrBits, Parameters.DataBits) + val uart_slave = new AXI4LiteSlaveBundle(Parameters.AddrBits, Parameters.DataBits) + + val cpu_debug_read_address = Input(UInt(Parameters.PhysicalRegisterAddrWidth)) + val cpu_debug_read_data = Output(UInt(Parameters.DataWidth)) + }) + + // Memory is controlled in C++ code + val mem_slave = Module(new AXI4LiteSlave(Parameters.AddrBits, Parameters.DataBits)) + io.mem_slave <> mem_slave.io.bundle + + // UART is controlled in C++ code + val uart_slave = Module(new AXI4LiteSlave(Parameters.AddrBits, Parameters.DataBits)) + io.uart_slave <> uart_slave.io.bundle + + val cpu = Module(new CPU) + val dummy = Module(new DummySlave) + val bus_arbiter = Module(new BusArbiter) + val bus_switch = Module(new BusSwitch) + + bus_arbiter.io.bus_request(0) := true.B + + 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 + } + + cpu.io.stall_flag_bus := false.B + cpu.io.instruction_valid := true.B + bus_switch.io.slaves(0) <> mem_slave.io.channels + bus_switch.io.slaves(2) <> uart_slave.io.channels + + cpu.io.interrupt_flag := io.signal_interrupt + + cpu.io.debug_read_address := io.cpu_debug_read_address + io.cpu_debug_read_data := cpu.io.debug_read_data +} + +object VerilogGenerator extends App { + (new ChiselStage).execute(Array("-X", "verilog", "-td", "verilog/verilator"), Seq(ChiselGeneratorAnnotation(() => + new Top()))) +} \ No newline at end of file diff --git a/lab4/src/main/scala/bus/AXI4Lite.scala b/lab4/src/main/scala/bus/AXI4Lite.scala new file mode 100644 index 0000000..212419a --- /dev/null +++ b/lab4/src/main/scala/bus/AXI4Lite.scala @@ -0,0 +1,197 @@ +// 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 bus + +import chisel3._ +import chisel3.experimental.ChiselEnum +import chisel3.util._ +import riscv.Parameters + +object AXI4Lite { + val protWidth = 3 + val respWidth = 2 +} + +class AXI4LiteWriteAddressChannel(addrWidth: Int) extends Bundle { + + val AWVALID = Output(Bool()) + val AWREADY = Input(Bool()) + val AWADDR = Output(UInt(addrWidth.W)) + val AWPROT = Output(UInt(AXI4Lite.protWidth.W)) + +} + +class AXI4LiteWriteDataChannel(dataWidth: Int) extends Bundle { + val WVALID = Output(Bool()) + val WREADY = Input(Bool()) + val WDATA = Output(UInt(dataWidth.W)) + val WSTRB = Output(UInt((dataWidth / 8).W)) +} + +class AXI4LiteWriteResponseChannel extends Bundle { + val BVALID = Input(Bool()) + val BREADY = Output(Bool()) + val BRESP = Input(UInt(AXI4Lite.respWidth.W)) +} + +class AXI4LiteReadAddressChannel(addrWidth: Int) extends Bundle { + val ARVALID = Output(Bool()) + val ARREADY = Input(Bool()) + val ARADDR = Output(UInt(addrWidth.W)) + val ARPROT = Output(UInt(AXI4Lite.protWidth.W)) +} + +class AXI4LiteReadDataChannel(dataWidth: Int) extends Bundle { + val RVALID = Input(Bool()) + val RREADY = Output(Bool()) + val RDATA = Input(UInt(dataWidth.W)) + val RRESP = Input(UInt(AXI4Lite.respWidth.W)) +} + +class AXI4LiteInterface(addrWidth: Int, dataWidth: Int) extends Bundle { + val AWVALID = Output(Bool()) + val AWREADY = Input(Bool()) + val AWADDR = Output(UInt(addrWidth.W)) + val AWPROT = Output(UInt(AXI4Lite.protWidth.W)) + val WVALID = Output(Bool()) + val WREADY = Input(Bool()) + val WDATA = Output(UInt(dataWidth.W)) + val WSTRB = Output(UInt((dataWidth / 8).W)) + val BVALID = Input(Bool()) + val BREADY = Output(Bool()) + val BRESP = Input(UInt(AXI4Lite.respWidth.W)) + val ARVALID = Output(Bool()) + val ARREADY = Input(Bool()) + val ARADDR = Output(UInt(addrWidth.W)) + val ARPROT = Output(UInt(AXI4Lite.protWidth.W)) + val RVALID = Input(Bool()) + val RREADY = Output(Bool()) + val RDATA = Input(UInt(dataWidth.W)) + val RRESP = Input(UInt(AXI4Lite.respWidth.W)) +} + +class AXI4LiteChannels(addrWidth: Int, dataWidth: Int) extends Bundle { + val write_address_channel = new AXI4LiteWriteAddressChannel(addrWidth) + val write_data_channel = new AXI4LiteWriteDataChannel(dataWidth) + val write_response_channel = new AXI4LiteWriteResponseChannel() + val read_address_channel = new AXI4LiteReadAddressChannel(addrWidth) + val read_data_channel = new AXI4LiteReadDataChannel(dataWidth) +} + +class AXI4LiteSlaveBundle(addrWidth: Int, dataWidth: Int) extends Bundle { + val read = Output(Bool()) + val write = Output(Bool()) + val read_data = Input(UInt(dataWidth.W)) + val read_valid = Input(Bool()) + val write_data = Output(UInt(dataWidth.W)) + val write_strobe = Output(Vec(Parameters.WordSize, Bool())) + val address = Output(UInt(addrWidth.W)) +} + +class AXI4LiteMasterBundle(addrWidth: Int, dataWidth: Int) extends Bundle { + val read = Input(Bool()) + val write = Input(Bool()) + val read_data = Output(UInt(dataWidth.W)) + val write_data = Input(UInt(dataWidth.W)) + val write_strobe = Input(Vec(Parameters.WordSize, Bool())) + val address = Input(UInt(addrWidth.W)) + + val busy = Output(Bool()) + val read_valid = Output(Bool()) + val write_valid = Output(Bool()) +} + +object AXI4LiteStates extends ChiselEnum { + val Idle, ReadAddr, ReadData, WriteAddr, WriteData, WriteResp = Value +} + +class AXI4LiteSlave(addrWidth: Int, dataWidth: Int) extends Module { + val io = IO(new Bundle { + val channels = Flipped(new AXI4LiteChannels(addrWidth, dataWidth)) + val bundle = new AXI4LiteSlaveBundle(addrWidth, dataWidth) + }) + val state = RegInit(AXI4LiteStates.Idle) + val addr = RegInit(0.U(dataWidth.W)) + io.bundle.address := addr + val read = RegInit(false.B) + io.bundle.read := read + val write = RegInit(false.B) + io.bundle.write := write + val write_data = RegInit(0.U(dataWidth.W)) + io.bundle.write_data := write_data + val write_strobe = RegInit(VecInit(Seq.fill(Parameters.WordSize)(false.B))) + io.bundle.write_strobe := write_strobe + + val ARREADY = RegInit(false.B) + io.channels.read_address_channel.ARREADY := ARREADY + val RVALID = RegInit(false.B) + io.channels.read_data_channel.RVALID := RVALID + val RRESP = RegInit(0.U(AXI4Lite.respWidth)) + io.channels.read_data_channel.RRESP := RRESP + + io.channels.read_data_channel.RDATA := io.bundle.read_data + + val AWREADY = RegInit(false.B) + io.channels.write_address_channel.AWREADY := AWREADY + val WREADY = RegInit(false.B) + io.channels.write_data_channel.WREADY := WREADY + write_data := io.channels.write_data_channel.WDATA + val BVALID = RegInit(false.B) + io.channels.write_response_channel.BVALID := BVALID + val BRESP = WireInit(0.U(AXI4Lite.respWidth)) + io.channels.write_response_channel.BRESP := BRESP + //lab4(BUS) + +} + +class AXI4LiteMaster(addrWidth: Int, dataWidth: Int) extends Module { + val io = IO(new Bundle { + val channels = new AXI4LiteChannels(addrWidth, dataWidth) + val bundle = new AXI4LiteMasterBundle(addrWidth, dataWidth) + }) + val state = RegInit(AXI4LiteStates.Idle) + io.bundle.busy := state =/= AXI4LiteStates.Idle + + val addr = RegInit(0.U(dataWidth.W)) + val read_valid = RegInit(false.B) + io.bundle.read_valid := read_valid + val write_valid = RegInit(false.B) + io.bundle.write_valid := write_valid + val write_data = RegInit(0.U(dataWidth.W)) + val write_strobe = RegInit(VecInit(Seq.fill(Parameters.WordSize)(false.B))) + val read_data = RegInit(0.U(dataWidth.W)) + + io.channels.read_address_channel.ARADDR := 0.U + val ARVALID = RegInit(false.B) + io.channels.read_address_channel.ARVALID := ARVALID + io.channels.read_address_channel.ARPROT := 0.U + val RREADY = RegInit(false.B) + io.channels.read_data_channel.RREADY := RREADY + + io.bundle.read_data := io.channels.read_data_channel.RDATA + val AWVALID = RegInit(false.B) + io.channels.write_address_channel.AWADDR := 0.U + io.channels.write_address_channel.AWVALID := AWVALID + val WVALID = RegInit(false.B) + io.channels.write_data_channel.WVALID := WVALID + io.channels.write_data_channel.WDATA := write_data + io.channels.write_address_channel.AWPROT := 0.U + io.channels.write_data_channel.WSTRB := write_strobe.asUInt + val BREADY = RegInit(false.B) + io.channels.write_response_channel.BREADY := BREADY + + //lab4(BUS) + +} diff --git a/lab4/src/main/scala/bus/BusArbiter.scala b/lab4/src/main/scala/bus/BusArbiter.scala new file mode 100644 index 0000000..57f39f8 --- /dev/null +++ b/lab4/src/main/scala/bus/BusArbiter.scala @@ -0,0 +1,40 @@ +// 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 bus + +import chisel3._ +import riscv.Parameters + +class BusArbiter extends Module { + val io = IO(new Bundle { + val bus_request = Input(Vec(Parameters.MasterDeviceCount, Bool())) + val bus_granted = Output(Vec(Parameters.MasterDeviceCount, Bool())) + + val ctrl_stall_flag = Output(Bool()) + }) + val granted = Wire(UInt()) + // Static Priority Arbitration + // Higher number = Higher priority + granted := 0.U + for (i <- 0 until Parameters.MasterDeviceCount) { + when(io.bus_request(i.U)) { + granted := i.U + } + } + for (i <- 0 until Parameters.MasterDeviceCount) { + io.bus_granted(i.U) := i.U === granted + } + io.ctrl_stall_flag := !io.bus_granted(0.U) +} diff --git a/lab4/src/main/scala/bus/BusSwitch.scala b/lab4/src/main/scala/bus/BusSwitch.scala new file mode 100644 index 0000000..9f9e2de --- /dev/null +++ b/lab4/src/main/scala/bus/BusSwitch.scala @@ -0,0 +1,33 @@ +// 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 bus + +import chisel3._ +import peripheral.DummyMaster +import riscv.Parameters + +class BusSwitch extends Module { + val io = IO(new Bundle { + val address = Input(UInt(Parameters.AddrWidth)) + val slaves = Vec(Parameters.SlaveDeviceCount, new AXI4LiteChannels(Parameters.AddrBits, Parameters.DataBits)) + val master = Flipped(new AXI4LiteChannels(Parameters.AddrBits, Parameters.DataBits)) + }) + val dummy = Module(new DummyMaster) + val index = io.address(Parameters.AddrBits - 1, Parameters.AddrBits - Parameters.SlaveDeviceCountBits) + for (i <- 0 until Parameters.SlaveDeviceCount) { + io.slaves(i) <> dummy.io.channels + } + io.master <> io.slaves(index) +} diff --git a/lab4/src/main/scala/peripheral/CharacterDisplay.scala b/lab4/src/main/scala/peripheral/CharacterDisplay.scala new file mode 100644 index 0000000..639f7e7 --- /dev/null +++ b/lab4/src/main/scala/peripheral/CharacterDisplay.scala @@ -0,0 +1,89 @@ +// 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 peripheral + +import chisel3._ +import bus.{AXI4LiteChannels, AXI4LiteSlave} +import chisel3.{Bool, Bundle, Flipped, Module, Mux, Output, UInt, Wire} +import chisel3.util.{MuxLookup, log2Up} +import peripheral.ScreenInfo.{DisplayHorizontal, DisplayVertical} +import riscv.Parameters + +object GlyphInfo { + val glyphWidth = 8 + val glyphHeight = 16 + // ASCII printable characters start from here + val spaceIndex = 1 +} + +object ScreenInfo { + val DisplayHorizontal = 640 + val DisplayVertical = 480 +} + +object CharacterBufferInfo { + val CharCols = DisplayHorizontal / GlyphInfo.glyphWidth + val CharRows = DisplayVertical / GlyphInfo.glyphHeight + val Chars = CharCols * CharRows +} + +class CharacterDisplay extends Module { + val io = IO(new Bundle() { + val channels = Flipped(new AXI4LiteChannels(log2Up(CharacterBufferInfo.Chars), Parameters.DataBits)) + + val x = Input(UInt(16.W)) + val y = Input(UInt(16.W)) + val video_on = Input(Bool()) + + val rgb = Output(UInt(24.W)) + }) + val slave = Module(new AXI4LiteSlave(log2Up(CharacterBufferInfo.Chars), Parameters.DataBits)) + slave.io.channels <> io.channels + val mem = Module(new BlockRAM(CharacterBufferInfo.Chars / Parameters.WordSize)) + slave.io.bundle.read_valid := true.B + mem.io.write_enable := slave.io.bundle.write + mem.io.write_data := slave.io.bundle.write_data + mem.io.write_address := slave.io.bundle.address + mem.io.write_strobe := slave.io.bundle.write_strobe + + mem.io.read_address := slave.io.bundle.address + slave.io.bundle.read_data := mem.io.read_data + + + val font_rom = Module(new FontROM) + val row = (io.y >> log2Up(GlyphInfo.glyphHeight)).asUInt + val col = (io.x >> log2Up(GlyphInfo.glyphWidth)).asUInt + val char_index = (row * CharacterBufferInfo.CharCols.U) + col + val offset = char_index(1, 0) + val ch = Wire(UInt(8.W)) + + mem.io.debug_read_address := char_index + ch := MuxLookup( + offset, + 0.U, + IndexedSeq( + 0.U -> mem.io.debug_read_data(7, 0).asUInt, + 1.U -> mem.io.debug_read_data(15, 8).asUInt, + 2.U -> mem.io.debug_read_data(23, 16).asUInt, + 3.U -> mem.io.debug_read_data(31, 24).asUInt + ) + ) + font_rom.io.glyph_index := Mux(ch >= 32.U, ch - 31.U, 0.U) + font_rom.io.glyph_y := io.y(log2Up(GlyphInfo.glyphHeight) - 1, 0) + + // White if pixel_on and glyph pixel on + val glyph_x = io.x(log2Up(GlyphInfo.glyphWidth) - 1, 0) + io.rgb := Mux(io.video_on && font_rom.io.glyph_pixel_byte(glyph_x), 0xFFFFFF.U, 0.U) +} diff --git a/lab4/src/main/scala/peripheral/DummyMaster.scala b/lab4/src/main/scala/peripheral/DummyMaster.scala new file mode 100644 index 0000000..ced75f5 --- /dev/null +++ b/lab4/src/main/scala/peripheral/DummyMaster.scala @@ -0,0 +1,33 @@ +// 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 peripheral + +import bus.{AXI4LiteChannels, AXI4LiteMaster} +import chisel3._ +import riscv.Parameters + +// A dummy master that never initiates reads or writes +class DummyMaster extends Module { + val io = IO(new Bundle { + val channels = new AXI4LiteChannels(Parameters.AddrBits, Parameters.DataBits) + }) + val master = Module(new AXI4LiteMaster(Parameters.AddrBits, Parameters.DataBits)) + master.io.channels <> io.channels + master.io.bundle.write_strobe := VecInit(Seq.fill(Parameters.WordSize)(false.B)) + master.io.bundle.write_data := 0.U + master.io.bundle.write := false.B + master.io.bundle.read := false.B + master.io.bundle.address := 0.U +} diff --git a/lab4/src/main/scala/peripheral/DummySlave.scala b/lab4/src/main/scala/peripheral/DummySlave.scala new file mode 100644 index 0000000..cdd98d3 --- /dev/null +++ b/lab4/src/main/scala/peripheral/DummySlave.scala @@ -0,0 +1,32 @@ +// 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 peripheral + +import bus.{AXI4LiteChannels, AXI4LiteSlave} +import chisel3._ +import riscv.Parameters + +// A dummy AXI4 slave that only returns 0 on read +// and ignores all writes +class DummySlave extends Module { + val io = IO(new Bundle { + val channels = Flipped(new AXI4LiteChannels(4, Parameters.DataBits)) + }) + + val slave = Module(new AXI4LiteSlave(Parameters.AddrBits, Parameters.DataBits)) + slave.io.channels <> io.channels + slave.io.bundle.read_valid := true.B + slave.io.bundle.read_data := 0xDEADBEEFL.U +} diff --git a/lab4/src/main/scala/peripheral/FontROM.scala b/lab4/src/main/scala/peripheral/FontROM.scala new file mode 100644 index 0000000..8954e54 --- /dev/null +++ b/lab4/src/main/scala/peripheral/FontROM.scala @@ -0,0 +1,65 @@ +package peripheral + +import chisel3._ +import chisel3.experimental.{ChiselAnnotation, annotate} +import chisel3.util.experimental.loadMemoryFromFileInline +import chisel3.{Bundle, Input, Module, Output, SyncReadMem, UInt} +import firrtl.annotations.MemorySynthInit + +import java.io.FileWriter +import java.nio.file.Paths +import javax.imageio.ImageIO + +class FontROM(fontBitmapFilename: String = "vga_font_8x16.bmp") extends Module { + val glyphWidth = GlyphInfo.glyphWidth + val glyphHeight = GlyphInfo.glyphHeight + + val io = IO(new Bundle { + val glyph_index = Input(UInt(7.W)) + val glyph_y = Input(UInt(4.W)) + + val glyph_pixel_byte = Output(UInt(8.W)) + }) + + annotate(new ChiselAnnotation { + override def toFirrtl = + MemorySynthInit + }) + + val (hexTxtPath, glyphCount) = readFontBitmap() + val mem = SyncReadMem(glyphCount, UInt(8.W)) + loadMemoryFromFileInline(mem, hexTxtPath.toString.replaceAll("\\\\", "/")) + io.glyph_pixel_byte := mem.read(io.glyph_index * GlyphInfo.glyphHeight.U + io.glyph_y, true.B) + + def readFontBitmap() = { + val inputStream = getClass.getClassLoader.getResourceAsStream(fontBitmapFilename) + val image = ImageIO.read(inputStream) + + val glyphColumns = image.getWidth() / glyphWidth + val glyphRows = image.getHeight / glyphHeight + val glyphCount = glyphColumns * glyphRows + val glyphs = new Array[UInt](glyphCount * GlyphInfo.glyphHeight) + + for (row <- 0 until glyphRows) { + for (col <- 0 until glyphColumns) { + for (i <- 0 until glyphHeight) { + var lineInt = 0 + for (j <- 0 until glyphWidth) { + if (image.getRGB(col * glyphWidth + j, row * glyphHeight + i) != 0xFFFFFFFF) { + lineInt |= (1 << j) + } + } + glyphs((row * glyphColumns + col) * GlyphInfo.glyphHeight + i) = lineInt.U(8.W) + } + } + } + val currentDir = System.getProperty("user.dir") + val hexTxtPath = Paths.get(currentDir, "verilog", f"${fontBitmapFilename}.txt") + val writer = new FileWriter(hexTxtPath.toString) + for (i <- glyphs.indices) { + writer.write(f"@$i%x\n${glyphs(i).litValue}%02x\n") + } + writer.close() + (hexTxtPath, glyphs.length) + } +} diff --git a/lab4/src/main/scala/peripheral/HDMIDisplay.scala b/lab4/src/main/scala/peripheral/HDMIDisplay.scala new file mode 100644 index 0000000..635bc10 --- /dev/null +++ b/lab4/src/main/scala/peripheral/HDMIDisplay.scala @@ -0,0 +1,398 @@ +// Copyright 2022 hrpccs +// +// 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 peripheral + +import bus.{AXI4LiteChannels, AXI4LiteSlave} +import chisel3._ +import chisel3.util._ +import riscv.Parameters + +class HDMISync extends Module { + val io = IO(new Bundle { + val hsync = Output(Bool()) + val vsync = Output(Bool()) + val video_on = Output(Bool()) + val p_tick = Output(Bool()) + val f_tick = Output(Bool()) + val x = Output(UInt(10.W)) + val y = Output(UInt(10.W)) + val x_next = Output(UInt(10.W)) + val y_next = Output(UInt(10.W)) + }) + + val DisplayHorizontal = ScreenInfo.DisplayHorizontal + val DisplayVertical = ScreenInfo.DisplayVertical + + val BorderLeft = 48 + val BorderRight = 16 + val BorderTop = 10 + val BorderBottom = 33 + + val RetraceHorizontal = 96 + val RetraceVertical = 2 + + val MaxHorizontal = DisplayHorizontal + BorderLeft + BorderRight + RetraceHorizontal - 1 + val MaxVertical = DisplayVertical + BorderTop + BorderBottom + RetraceVertical - 1 + + val RetraceHorizontalStart = DisplayHorizontal + BorderRight + val RetraceHorizontalEnd = RetraceHorizontalStart + RetraceHorizontal - 1 + + val RetraceVerticalStart = DisplayVertical + BorderBottom + val RetraceVerticalEnd = RetraceVerticalStart + RetraceVertical - 1 + + val pixel = RegInit(UInt(3.W), 0.U) + val pixel_next = Wire(UInt(3.W)) + val pixel_tick = Wire(Bool()) + + val v_count_reg = RegInit(UInt(10.W), 0.U) + val h_count_reg = RegInit(UInt(10.W), 0.U) + + val v_count_next = Wire(UInt(10.W)) + val h_count_next = Wire(UInt(10.W)) + + val vsync_reg = RegInit(Bool(), false.B) + val hsync_reg = RegInit(Bool(), false.B) + + val vsync_next = Wire(Bool()) + val hsync_next = Wire(Bool()) + + pixel_next := Mux(pixel === 4.U, 0.U, pixel + 1.U) + pixel_tick := pixel === 0.U + + h_count_next := Mux( + pixel_tick, + Mux(h_count_reg === MaxHorizontal.U, 0.U, h_count_reg + 1.U), + h_count_reg + ) + + v_count_next := Mux( + pixel_tick && h_count_reg === MaxHorizontal.U, + Mux(v_count_reg === MaxVertical.U, 0.U, v_count_reg + 1.U), + v_count_reg + ) + + hsync_next := h_count_reg >= RetraceHorizontalStart.U && h_count_reg <= RetraceHorizontalEnd.U + vsync_next := v_count_reg >= RetraceVerticalStart.U && v_count_reg <= RetraceVerticalEnd.U + + pixel := pixel_next + hsync_reg := hsync_next + vsync_reg := vsync_next + v_count_reg := v_count_next + h_count_reg := h_count_next + + io.video_on := h_count_reg < DisplayHorizontal.U && v_count_reg < DisplayVertical.U + io.hsync := hsync_reg + io.vsync := vsync_reg + io.x := h_count_reg + io.y := v_count_reg + io.x_next := h_count_next + io.y_next := v_count_next + io.p_tick := pixel_tick + io.f_tick := io.x === 0.U && io.y === 0.U +} + +class TMDS_encoder extends Module { + val io = IO(new Bundle() { + val video_data = Input(UInt(8.W)) //r,g,b,8bit + val control_data = Input(UInt(2.W)) + val video_on = Input(Bool()) + val TMDS = Output(UInt(10.W)) + }) + val Nb1s = PopCount(io.video_data) + + def xorfct(value: UInt): UInt = { + val vin = VecInit(value.asBools) + val res = VecInit(511.U.asBools) + res(0) := vin(0) + for(i <- 1 to 7){ + res(i) := res(i-1) ^ vin(i) + } + res(8) := 1.U + res.asUInt + } + + val xored = xorfct(io.video_data) + + def xnorfct(value: UInt): UInt = { + val vin = VecInit(value.asBools) + val res = VecInit(511.U.asBools) + res(0) := vin(0) + for(i <- 1 to 7){ + res(i) := !(res(i-1) ^ vin(i)) + } + res(8) := 0.U + res.asUInt + } + + val xnored = xnorfct(io.video_data) + + val XNOR = (Nb1s > 4.U(4.W)) || (Nb1s === 4.U(4.W) && io.video_data(0) === 0.U) + val q_m = RegInit(0.U(9.W)) + q_m := Mux( + XNOR, + xnored, + xored + ) + + val diffSize = 4 + val diff = RegInit(0.S(diffSize.W)) + diff := PopCount(q_m).asSInt - 4.S + + val disparitySize = 4 + val disparityReg = RegInit(0.S(disparitySize.W)) + val doutReg = RegInit("b1010101011".U(10.W)) + + when(io.video_on === false.B) { + disparityReg := 0.S + doutReg := "b1010101011".U(10.W) + switch(io.control_data) { + is("b00".U(2.W)) { + doutReg := "b1101010100".U(10.W) + } + is("b01".U(2.W)) { + doutReg := "b0010101011".U(10.W) + } + is("b10".U(2.W)) { + doutReg := "b0101010100".U(10.W) + } + } + }.otherwise { + when(disparityReg === 0.S || diff === 0.S) { + when(q_m(8) === false.B) { + doutReg := "b10".U(2.W) ## ~q_m(7, 0) + disparityReg := disparityReg - diff + }.otherwise { + doutReg := "b01".U(2.W) ## q_m(7, 0) + disparityReg := disparityReg + diff + } + }.elsewhen((!diff(diffSize - 1) && !disparityReg(disparitySize - 1)) + || (diff(diffSize - 1) && disparityReg(disparitySize - 1))) { + doutReg := 1.U(1.W) ## q_m(8) ## ~q_m(7, 0) + when(q_m(8)) { + disparityReg := disparityReg + 1.S - diff + }.otherwise { + disparityReg := disparityReg - diff + } + }.otherwise { + doutReg := 0.U(1.W) ## q_m + when(q_m(8)) { + disparityReg := disparityReg + diff + }.otherwise { + disparityReg := disparityReg - 1.S + diff + } + } + } + + io.TMDS := doutReg +} + +class HDMIDisplay extends Module { + val io = IO(new Bundle() { + val rgb = Input(UInt(24.W)) + val x = Output(UInt(16.W)) + val y = Output(UInt(16.W)) + val x_next = Output(UInt(16.W)) + val y_next = Output(UInt(16.W)) + val video_on = Output(Bool()) + + val TMDSclk_p = Output(Bool()) + val TMDSdata_p = Output(UInt(3.W)) + val TMDSclk_n = Output(Bool()) + val TMDSdata_n = Output(UInt(3.W)) + }) + val rgb = io.rgb + val pixel_clk = Wire(Bool()) + val hsync = Wire(Bool()) + val vsync = Wire(Bool()) + val sync = Module(new HDMISync) + + io.x := sync.io.x + io.y := sync.io.y + io.x_next := sync.io.x_next + io.y_next := sync.io.y_next + io.video_on := sync.io.video_on + + hsync := sync.io.hsync + vsync := sync.io.vsync + pixel_clk := sync.io.p_tick + + // TMDS_PLLVR is a vivado IP core, check it in /verilog/pynq/TMDS_PLLVR.v + val serial_clk = Wire(Clock()) + val pll_lock = Wire(Bool()) + val tmdspll = Module(new TMDS_PLLVR) + val rst = Wire(Reset()) + tmdspll.io.clkin := pixel_clk.asClock + serial_clk := tmdspll.io.clkout + pll_lock := tmdspll.io.lock + tmdspll.io.reset := reset + rst := ~pll_lock + + val tmds = Wire(UInt(3.W)) + val tmds_clk = Wire(Bool()) + withClockAndReset(pixel_clk.asClock, rst) { + val tmds_channel1 = Wire(UInt(10.W)) + val tmds_channel2 = Wire(UInt(10.W)) + val tmds_channel0 = Wire(UInt(10.W)) + + val tmds_green = Module(new TMDS_encoder) + val tmds_red = Module(new TMDS_encoder) + val tmds_blue = Module(new TMDS_encoder) + + tmds_red.io.video_on := sync.io.video_on + tmds_blue.io.video_on := sync.io.video_on + tmds_green.io.video_on := sync.io.video_on + + tmds_blue.io.control_data := sync.io.vsync ## sync.io.hsync + tmds_green.io.control_data := 0.U + tmds_red.io.control_data := 0.U + + tmds_red.io.video_data := rgb(23, 16) + tmds_blue.io.video_data := rgb(7, 0) + tmds_green.io.video_data := rgb(15, 8) + + tmds_channel0 := tmds_blue.io.TMDS + tmds_channel1 := tmds_green.io.TMDS + tmds_channel2 := tmds_red.io.TMDS + + val serdesBlue = Module(new Oser10Module()) + serdesBlue.io.data := tmds_channel0 + serdesBlue.io.fclk := serial_clk + + val serdesGreen = Module(new Oser10Module()) + serdesGreen.io.data := tmds_channel1 + serdesGreen.io.fclk := serial_clk + + val serdesRed = Module(new Oser10Module()) + serdesRed.io.data := tmds_channel2 + serdesRed.io.fclk := serial_clk + + tmds := serdesRed.io.q ## serdesGreen.io.q ## serdesBlue.io.q + + //serdesCLk : 25Mhz ,Why not directly use p_tick? + //cause Duty Ratio of p_tick is 10% , while which of serdesCLk is 50% + val serdesClk = Module(new Oser10Module()) + serdesClk.io.data := "b1111100000".U(10.W) + serdesClk.io.fclk := serial_clk + + tmds_clk := serdesClk.io.q + + val buffDiffBlue = Module(new OBUFDS) + buffDiffBlue.io.I := tmds(0) + val buffDiffGreen = Module(new OBUFDS) + buffDiffGreen.io.I := tmds(1) + val buffDiffRed = Module(new OBUFDS) + buffDiffRed.io.I := tmds(2) + val buffDiffClk = Module(new OBUFDS) + buffDiffClk.io.I := tmds_clk + + io.TMDSclk_p := buffDiffClk.io.O + io.TMDSclk_n := buffDiffClk.io.OB + io.TMDSdata_p := buffDiffRed.io.O ## buffDiffGreen.io.O ## buffDiffBlue.io.O + io.TMDSdata_n := buffDiffRed.io.OB ## buffDiffGreen.io.OB ## buffDiffBlue.io.OB + } +} + +//---------------------------------------- +//PLL frequency multiplier using BlackBox +class TMDS_PLLVR extends BlackBox { + val io = IO(new Bundle { + val clkin = Input(Clock()) + val reset = Input(Reset()) + val clkout = Output(Clock()) + val clkoutd = Output(Clock()) + val lock = Output(Bool()) + }) +} + +/* OSER10 : serializer 10:1*/ +class OSER10 extends Module { + val io = IO(new Bundle { + val Q = Output(Bool()) // OSER10 data output signal + val D0 = Input(Bool()) + val D1 = Input(Bool()) + val D2 = Input(Bool()) + val D3 = Input(Bool()) + val D4 = Input(Bool()) + val D5 = Input(Bool()) + val D6 = Input(Bool()) + val D7 = Input(Bool()) + val D8 = Input(Bool()) + val D9 = Input(Bool()) // OSER10 data input signal + val PCLK = Input(Clock()) // Primary clock input signal + val FCLK = Input(Clock()) // High speed clock input signal + val RESET = Input(Reset()) // Asynchronous reset input signal, + //active-high. + }) + withClockAndReset(io.FCLK, io.RESET) { + val count = RegInit(0.U(4.W)) + val countnext = Wire(UInt(4.W)) + io.Q := MuxLookup( + count, + 0.U, + IndexedSeq( + 0.U -> io.D0.asBool, + 1.U -> io.D1.asBool, + 2.U -> io.D2.asBool, + 3.U -> io.D3.asBool, + 4.U -> io.D4.asBool, + 5.U -> io.D5.asBool, + 6.U -> io.D6.asBool, + 7.U -> io.D7.asBool, + 8.U -> io.D8.asBool, + 9.U -> io.D9.asBool + ) + ) + countnext := Mux( + count === 9.U, 0.U, count + 1.U + ) + count := countnext + } +} + +class Oser10Module extends Module { + val io = IO(new Bundle { + val q = Output(Bool()) + val data = Input(UInt(10.W)) + val fclk = Input(Clock()) // Fast clock + }) + + val osr10 = Module(new OSER10()) + io.q := osr10.io.Q + osr10.io.D0 := io.data(0) + osr10.io.D1 := io.data(1) + osr10.io.D2 := io.data(2) + osr10.io.D3 := io.data(3) + osr10.io.D4 := io.data(4) + osr10.io.D5 := io.data(5) + osr10.io.D6 := io.data(6) + osr10.io.D7 := io.data(7) + osr10.io.D8 := io.data(8) + osr10.io.D9 := io.data(9) + osr10.io.PCLK := clock + osr10.io.FCLK := io.fclk + osr10.io.RESET := reset +} + +/* lvds output */ +class OBUFDS extends BlackBox { + val io = IO(new Bundle { + val O = Output(Bool()) + val OB = Output(Bool()) + val I = Input(Bool()) + }) +} +//----------------------------------------- + + diff --git a/lab4/src/main/scala/peripheral/InstructionROM.scala b/lab4/src/main/scala/peripheral/InstructionROM.scala new file mode 100644 index 0000000..b166bcf --- /dev/null +++ b/lab4/src/main/scala/peripheral/InstructionROM.scala @@ -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 peripheral + +import chisel3._ +import chisel3.experimental.{ChiselAnnotation, annotate} +import chisel3.util.experimental.loadMemoryFromFileInline +import firrtl.annotations.MemorySynthInit +import riscv.Parameters + +import java.io.{FileInputStream, FileWriter} +import java.nio.file.{Files, Paths} +import java.nio.{ByteBuffer, ByteOrder} + +class InstructionROM(instructionFilename: String) extends Module { + val io = IO(new Bundle { + val address = Input(UInt(Parameters.AddrWidth)) + val data = Output(UInt(Parameters.InstructionWidth)) + }) + + val (instructionsInitFile, capacity) = readAsmBinary(instructionFilename) + val mem = SyncReadMem(capacity, UInt(Parameters.InstructionWidth)) + annotate(new ChiselAnnotation { + override def toFirrtl = + MemorySynthInit + }) + loadMemoryFromFileInline(mem, instructionsInitFile.toString.replaceAll("\\\\", "/")) + io.data := mem.read(io.address, true.B) + + def readAsmBinary(filename: String) = { + val inputStream = if (Files.exists(Paths.get(filename))) { + Files.newInputStream(Paths.get(filename)) + } else { + 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 + } + instructions = instructions :+ BigInt(0x00000013L) + instructions = instructions :+ BigInt(0x00000013L) + instructions = instructions :+ BigInt(0x00000013L) + val currentDir = System.getProperty("user.dir") + val exeTxtPath = Paths.get(currentDir, "verilog", f"${instructionFilename}.txt") + val writer = new FileWriter(exeTxtPath.toString) + for (i <- instructions.indices) { + writer.write(f"@$i%x\n${instructions(i)}%08x\n") + } + writer.close() + (exeTxtPath, instructions.length) + } +} diff --git a/lab4/src/main/scala/peripheral/InterruptController.scala b/lab4/src/main/scala/peripheral/InterruptController.scala new file mode 100644 index 0000000..c26972e --- /dev/null +++ b/lab4/src/main/scala/peripheral/InterruptController.scala @@ -0,0 +1,26 @@ +// 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 peripheral + +import chisel3._ +import riscv.Parameters + +// TODO(howard): implementation +class InterruptController extends Module { + val io = IO(new Bundle { + val interrupts = Vec(Parameters.SlaveDeviceCount, Bool()) + val cpu_interrupt_flag = Output(UInt(Parameters.InterruptFlagWidth)) + }) +} diff --git a/lab4/src/main/scala/peripheral/Memory.scala b/lab4/src/main/scala/peripheral/Memory.scala new file mode 100644 index 0000000..0ea2e52 --- /dev/null +++ b/lab4/src/main/scala/peripheral/Memory.scala @@ -0,0 +1,72 @@ +// 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 peripheral + +import bus.{AXI4LiteChannels, AXI4LiteSlave} +import chisel3._ +import riscv.Parameters + +// The purpose of this module is to help the synthesis tool recognize +// our memory as a Block RAM template +class BlockRAM(capacity: Int) extends Module { + val io = IO(new Bundle { + val read_address = Input(UInt(Parameters.AddrWidth)) + val write_address = Input(UInt(Parameters.AddrWidth)) + val write_data = Input(UInt(Parameters.DataWidth)) + val write_enable = Input(Bool()) + val write_strobe = Input(Vec(Parameters.WordSize, Bool())) + + val debug_read_address = Input(UInt(Parameters.AddrWidth)) + + val read_data = Output(UInt(Parameters.DataWidth)) + val debug_read_data = Output(UInt(Parameters.DataWidth)) + }) + val mem = SyncReadMem(capacity, Vec(Parameters.WordSize, UInt(Parameters.ByteWidth))) + when(io.write_enable) { + val write_data_vec = Wire(Vec(Parameters.WordSize, UInt(Parameters.ByteWidth))) + for (i <- 0 until Parameters.WordSize) { + write_data_vec(i) := io.write_data((i + 1) * Parameters.ByteBits - 1, i * Parameters.ByteBits) + } + mem.write((io.write_address >> 2.U).asUInt, write_data_vec, io.write_strobe) + } + io.read_data := mem.read((io.read_address >> 2.U).asUInt, true.B).asUInt + io.debug_read_data := mem.read((io.debug_read_address >> 2.U).asUInt, true.B).asUInt +} + +// This module wraps the Block RAM with an AXI4-Lite interface +class Memory(capacity: Int) extends Module { + val io = IO(new Bundle { + val channels = Flipped(new AXI4LiteChannels(Parameters.AddrBits, Parameters.DataBits)) + + val debug_read_address = Input(UInt(Parameters.AddrWidth)) + val debug_read_data = Output(UInt(Parameters.DataWidth)) + }) + + val mem = Module(new BlockRAM(capacity)) + val slave = Module(new AXI4LiteSlave(Parameters.AddrBits, Parameters.DataBits)) + slave.io.channels <> io.channels + slave.io.bundle.read_valid := true.B + + mem.io.write_enable := slave.io.bundle.write + mem.io.write_data := slave.io.bundle.write_data + mem.io.write_address := slave.io.bundle.address + mem.io.write_strobe := slave.io.bundle.write_strobe + + mem.io.read_address := slave.io.bundle.address + slave.io.bundle.read_data := mem.io.read_data + + mem.io.debug_read_address := io.debug_read_address + io.debug_read_data := mem.io.debug_read_data +} diff --git a/lab4/src/main/scala/peripheral/PixelDisplay.scala b/lab4/src/main/scala/peripheral/PixelDisplay.scala new file mode 100644 index 0000000..eb2f3ed --- /dev/null +++ b/lab4/src/main/scala/peripheral/PixelDisplay.scala @@ -0,0 +1,56 @@ +// 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 peripheral + +import bus.{AXI4LiteChannels, AXI4LiteSlave} +import chisel3._ +import chisel3.util.log2Up +import riscv.Parameters + +class PixelDisplay extends Module { + val io = IO(new Bundle() { + val channels = Flipped(new AXI4LiteChannels(32, Parameters.DataBits)) + + val x = Input(UInt(16.W)) + val y = Input(UInt(16.W)) + val video_on = Input(Bool()) + + val rgb = Output(UInt(24.W)) + }) + val slave = Module(new AXI4LiteSlave(32, Parameters.DataBits)) + slave.io.channels <> io.channels + + // 320x240, RGB 565 + val mem = Module(new BlockRAM(320 * 240 / 2)) + slave.io.bundle.read_valid := true.B + mem.io.write_enable := slave.io.bundle.write + mem.io.write_data := slave.io.bundle.write_data + mem.io.write_address := slave.io.bundle.address + mem.io.write_strobe := slave.io.bundle.write_strobe + + mem.io.read_address := slave.io.bundle.address + slave.io.bundle.read_data := mem.io.read_data + + + val pixel_x = io.x(15, 1).asUInt + val pixel_y = io.y(15, 1).asUInt + mem.io.debug_read_address := (pixel_y * 320.U + pixel_x) << 1 + + val pixel = Mux(pixel_x(0), mem.io.debug_read_data(31, 16), mem.io.debug_read_data(15, 0)) + val r = pixel(15, 11) ## 0.U(3.W) + val g = pixel(10, 5) ## 0.U(2.W) + val b = pixel(4, 0) ## 0.U(3.W) + io.rgb := Mux(io.video_on, r ## g ## b, 0.U) +} diff --git a/lab4/src/main/scala/peripheral/ROMLoader.scala b/lab4/src/main/scala/peripheral/ROMLoader.scala new file mode 100644 index 0000000..4677c9e --- /dev/null +++ b/lab4/src/main/scala/peripheral/ROMLoader.scala @@ -0,0 +1,80 @@ +// 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 peripheral + +import bus.{AXI4LiteChannels, AXI4LiteMaster} +import chisel3._ +import chisel3.util._ +import riscv.Parameters + +class ROMLoader(capacity: Int) extends Module { + val io = IO(new Bundle { + val channels = new AXI4LiteChannels(Parameters.AddrBits, Parameters.InstructionBits) + + val rom_address = Output(UInt(Parameters.AddrWidth)) + val rom_data = Input(UInt(Parameters.InstructionWidth)) + + val load_start = Input(Bool()) + val load_address = Input(UInt(Parameters.AddrWidth)) + val load_finished = Output(Bool()) + }) + val master = Module(new AXI4LiteMaster(Parameters.AddrBits, Parameters.InstructionBits)) + master.io.channels <> io.channels + + val address = RegInit(0.U(32.W)) + val valid = RegInit(false.B) + val loading = RegInit(false.B) + + master.io.bundle.read := false.B + io.load_finished := false.B + + when(io.load_start) { + valid := false.B + loading := true.B + address := 0.U + } + + master.io.bundle.write := false.B + master.io.bundle.write_data := 0.U + master.io.bundle.write_strobe := VecInit(Seq.fill(Parameters.WordSize)(false.B)) + master.io.bundle.address := 0.U + + when(!loading && !master.io.bundle.busy && address >= (capacity - 1).U) { + io.load_finished := true.B + } + when(loading) { + valid := true.B + when(!master.io.bundle.busy && !master.io.bundle.write_valid) { + when(valid) { + master.io.bundle.write := true.B + master.io.bundle.write_data := io.rom_data + master.io.bundle.write_strobe := VecInit(Seq.fill(Parameters.WordSize)(true.B)) + master.io.bundle.address := (address << 2.U).asUInt + io.load_address + } + } + when(master.io.bundle.write_valid) { + when(address >= (capacity - 1).U) { + loading := false.B + }.otherwise { + loading := true.B + address := address + 1.U + valid := false.B + } + }.otherwise { + address := address + } + } + io.rom_address := address +} diff --git a/lab4/src/main/scala/peripheral/SPI.scala b/lab4/src/main/scala/peripheral/SPI.scala new file mode 100644 index 0000000..405fc87 --- /dev/null +++ b/lab4/src/main/scala/peripheral/SPI.scala @@ -0,0 +1,24 @@ +// 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 peripheral + +import chisel3._ +import chisel3.util._ + +class SPI extends Module { + val io = IO(new Bundle { + + }) +} diff --git a/lab4/src/main/scala/peripheral/Timer.scala b/lab4/src/main/scala/peripheral/Timer.scala new file mode 100644 index 0000000..c598909 --- /dev/null +++ b/lab4/src/main/scala/peripheral/Timer.scala @@ -0,0 +1,67 @@ +// 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 peripheral + +import bus.{AXI4LiteChannels, AXI4LiteSlave} +import chisel3._ +import chisel3.util._ +import riscv.Parameters + +class Timer extends Module { + val io = IO(new Bundle { + val channels = Flipped(new AXI4LiteChannels(8, Parameters.DataBits)) + val signal_interrupt = Output(Bool()) + + val debug_limit = Output(UInt(Parameters.DataWidth)) + val debug_enabled = Output(Bool()) + }) + val slave = Module(new AXI4LiteSlave(8, Parameters.DataBits)) + slave.io.channels <> io.channels + + val count = RegInit(0.U(32.W)) + val limit = RegInit(100000000.U(32.W)) + io.debug_limit := limit + val enabled = RegInit(true.B) + io.debug_enabled := enabled + + slave.io.bundle.read_data := 0.U + slave.io.bundle.read_valid := true.B + when(slave.io.bundle.read) { + slave.io.bundle.read_data := MuxLookup( + slave.io.bundle.address, + 0.U, + IndexedSeq( + 0x4.U -> limit, + 0x8.U -> enabled.asUInt, + ) + ) + } + when(slave.io.bundle.write) { + when(slave.io.bundle.address === 0x4.U) { + limit := slave.io.bundle.write_data + count := 0.U + }.elsewhen(slave.io.bundle.address === 0x8.U) { + enabled := slave.io.bundle.write_data =/= 0.U + } + } + + io.signal_interrupt := enabled && (count >= (limit - 10.U)) + + when(count >= limit) { + count := 0.U + }.otherwise { + count := count + 1.U + } +} diff --git a/lab4/src/main/scala/peripheral/UART.scala b/lab4/src/main/scala/peripheral/UART.scala new file mode 100644 index 0000000..f21545c --- /dev/null +++ b/lab4/src/main/scala/peripheral/UART.scala @@ -0,0 +1,211 @@ +// 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 peripheral + +import bus.{AXI4LiteChannels, AXI4LiteSlave} +import chisel3._ +import chisel3.util._ +import riscv.Parameters + +class UartIO extends DecoupledIO(UInt(8.W)) { +} + + +/** + * Transmit part of the UART. + * A minimal version without any additional buffering. + * Use a ready/valid handshaking. + */ +class Tx(frequency: Int, baudRate: Int) extends Module { + val io = IO(new Bundle { + val txd = Output(UInt(1.W)) + val channel = Flipped(new UartIO()) + + }) + + val BIT_CNT = ((frequency + baudRate / 2) / baudRate - 1).U + + val shiftReg = RegInit(0x7ff.U) + val cntReg = RegInit(0.U(20.W)) + val bitsReg = RegInit(0.U(4.W)) + + io.channel.ready := (cntReg === 0.U) && (bitsReg === 0.U) + io.txd := shiftReg(0) + + when(cntReg === 0.U) { + + cntReg := BIT_CNT + when(bitsReg =/= 0.U) { + val shift = shiftReg >> 1 + shiftReg := Cat(1.U, shift(9, 0)) + bitsReg := bitsReg - 1.U + }.otherwise { + when(io.channel.valid) { + shiftReg := Cat(Cat(3.U, io.channel.bits), 0.U) // two stop bits, data, one start bit + bitsReg := 11.U + }.otherwise { + shiftReg := 0x7ff.U + } + } + + }.otherwise { + cntReg := cntReg - 1.U + } +} + +/** + * Receive part of the UART. + * A minimal version without any additional buffering. + * Use a ready/valid handshaking. + * + * The following code is inspired by Tommy's receive code at: + * https://github.com/tommythorn/yarvi + */ +class Rx(frequency: Int, baudRate: Int) extends Module { + val io = IO(new Bundle { + val rxd = Input(UInt(1.W)) + val channel = new UartIO() + + }) + + val BIT_CNT = ((frequency + baudRate / 2) / baudRate - 1).U + val START_CNT = ((3 * frequency / 2 + baudRate / 2) / baudRate - 1).U + + // Sync in the asynchronous RX data, reset to 1 to not start reading after a reset + val rxReg = RegNext(RegNext(io.rxd, 1.U), 1.U) + + val shiftReg = RegInit(0.U(8.W)) + val cntReg = RegInit(0.U(20.W)) + val bitsReg = RegInit(0.U(4.W)) + val valReg = RegInit(false.B) + + when(cntReg =/= 0.U) { + cntReg := cntReg - 1.U + }.elsewhen(bitsReg =/= 0.U) { + cntReg := BIT_CNT + shiftReg := Cat(rxReg, shiftReg >> 1) + bitsReg := bitsReg - 1.U + // the last shifted in + when(bitsReg === 1.U) { + valReg := true.B + } + }.elsewhen(rxReg === 0.U) { // wait 1.5 bits after falling edge of start + cntReg := START_CNT + bitsReg := 8.U + } + + when(valReg && io.channel.ready) { + valReg := false.B + } + + io.channel.bits := shiftReg + io.channel.valid := valReg +} + +/** + * A single byte buffer with a ready/valid interface + */ +class Buffer extends Module { + val io = IO(new Bundle { + val in = Flipped(new UartIO()) + val out = new UartIO() + }) + + val empty :: full :: Nil = Enum(2) + val stateReg = RegInit(empty) + val dataReg = RegInit(0.U(8.W)) + + io.in.ready := stateReg === empty + io.out.valid := stateReg === full + + when(stateReg === empty) { + when(io.in.valid) { + dataReg := io.in.bits + stateReg := full + } + }.otherwise { // full + when(io.out.ready) { + stateReg := empty + } + } + io.out.bits := dataReg +} + +/** + * A transmitter with a single buffer. + */ +class BufferedTx(frequency: Int, baudRate: Int) extends Module { + val io = IO(new Bundle { + val txd = Output(UInt(1.W)) + val channel = Flipped(new UartIO()) + + }) + val tx = Module(new Tx(frequency, baudRate)) + val buf = Module(new Buffer) + + buf.io.in <> io.channel + tx.io.channel <> buf.io.out + io.txd <> tx.io.txd +} + +class Uart(frequency: Int, baudRate: Int) extends Module { + val io = IO(new Bundle { + val channels = Flipped(new AXI4LiteChannels(8, Parameters.DataBits)) + val rxd = Input(UInt(1.W)) + val txd = Output(UInt(1.W)) + + val signal_interrupt = Output(Bool()) + }) + val interrupt = RegInit(false.B) + val rxData = RegInit(0.U) + val slave = Module(new AXI4LiteSlave(8, Parameters.DataBits)) + slave.io.channels <> io.channels + + val tx = Module(new BufferedTx(frequency, baudRate)) + val rx = Module(new Rx(frequency, baudRate)) + + slave.io.bundle.read_data := 0.U + slave.io.bundle.read_valid := true.B + when(slave.io.bundle.read) { + when(slave.io.bundle.address === 0x4.U) { + slave.io.bundle.read_data := baudRate.U + }.elsewhen(slave.io.bundle.address === 0xC.U) { + slave.io.bundle.read_data := rxData + interrupt := false.B + } + } + + tx.io.channel.valid := false.B + tx.io.channel.bits := 0.U + when(slave.io.bundle.write) { + when(slave.io.bundle.address === 0x8.U) { + interrupt := slave.io.bundle.write_data =/= 0.U + }.elsewhen(slave.io.bundle.address === 0x10.U) { + tx.io.channel.valid := true.B + tx.io.channel.bits := slave.io.bundle.write_data + } + } + + io.txd := tx.io.txd + rx.io.rxd := io.rxd + + io.signal_interrupt := interrupt + rx.io.channel.ready := false.B + when(rx.io.channel.valid) { + rx.io.channel.ready := true.B + rxData := rx.io.channel.bits + interrupt := true.B + } +} diff --git a/lab4/src/main/scala/peripheral/VGADisplay.scala b/lab4/src/main/scala/peripheral/VGADisplay.scala new file mode 100644 index 0000000..09724e3 --- /dev/null +++ b/lab4/src/main/scala/peripheral/VGADisplay.scala @@ -0,0 +1,129 @@ +// 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 peripheral + +import bus.{AXI4LiteChannels, AXI4LiteSlave} +import chisel3._ +import chisel3.experimental.{ChiselAnnotation, annotate} +import chisel3.util._ +import chisel3.util.experimental.loadMemoryFromFileInline +import firrtl.annotations.MemorySynthInit +import riscv.Parameters + +import java.io.FileWriter +import java.nio.file.Paths +import javax.imageio.ImageIO + + + + +class VGASync extends Module { + val io = IO(new Bundle { + val hsync = Output(Bool()) + val vsync = Output(Bool()) + val video_on = Output(Bool()) + val p_tick = Output(Bool()) + val f_tick = Output(Bool()) + val x = Output(UInt(10.W)) + val y = Output(UInt(10.W)) + }) + + val DisplayHorizontal = ScreenInfo.DisplayHorizontal + val DisplayVertical = ScreenInfo.DisplayVertical + + val BorderLeft = 48 + val BorderRight = 16 + val BorderTop = 10 + val BorderBottom = 33 + + val RetraceHorizontal = 96 + val RetraceVertical = 2 + + val MaxHorizontal = DisplayHorizontal + BorderLeft + BorderRight + RetraceHorizontal - 1 + val MaxVertical = DisplayVertical + BorderTop + BorderBottom + RetraceVertical - 1 + + val RetraceHorizontalStart = DisplayHorizontal + BorderRight + val RetraceHorizontalEnd = RetraceHorizontalStart + RetraceHorizontal - 1 + + val RetraceVerticalStart = DisplayVertical + BorderBottom + val RetraceVerticalEnd = RetraceVerticalStart + RetraceVertical - 1 + + val pixel = RegInit(UInt(2.W), 0.U) + val pixel_next = Wire(UInt(2.W)) + val pixel_tick = Wire(Bool()) + + val v_count_reg = RegInit(UInt(10.W), 0.U) + val h_count_reg = RegInit(UInt(10.W), 0.U) + + val v_count_next = Wire(UInt(10.W)) + val h_count_next = Wire(UInt(10.W)) + + val vsync_reg = RegInit(Bool(), false.B) + val hsync_reg = RegInit(Bool(), false.B) + + val vsync_next = Wire(Bool()) + val hsync_next = Wire(Bool()) + + pixel_next := pixel + 1.U + pixel_tick := pixel === 0.U + + h_count_next := Mux( + pixel_tick, + Mux(h_count_reg === MaxHorizontal.U, 0.U, h_count_reg + 1.U), + h_count_reg + ) + + v_count_next := Mux( + pixel_tick && h_count_reg === MaxHorizontal.U, + Mux(v_count_reg === MaxVertical.U, 0.U, v_count_reg + 1.U), + v_count_reg + ) + + hsync_next := h_count_reg >= RetraceHorizontalStart.U && h_count_reg <= RetraceHorizontalEnd.U + vsync_next := v_count_reg >= RetraceVerticalStart.U && v_count_reg <= RetraceVerticalEnd.U + + pixel := pixel_next + hsync_reg := hsync_next + vsync_reg := vsync_next + v_count_reg := v_count_next + h_count_reg := h_count_next + + io.video_on := h_count_reg < DisplayHorizontal.U && v_count_reg < DisplayVertical.U + io.hsync := hsync_reg + io.vsync := vsync_reg + io.x := h_count_reg + io.y := v_count_reg + io.p_tick := pixel_tick + io.f_tick := io.x === 0.U && io.y === 0.U +} + +class VGADisplay extends Module { + val io = IO(new Bundle() { + val rgb = Input(UInt(24.W)) + val x = Output(UInt(16.W)) + val y = Output(UInt(16.W)) + val video_on = Output(Bool()) + + val hsync = Output(Bool()) + val vsync = Output(Bool()) + }) + + val sync = Module(new VGASync) + io.hsync := sync.io.hsync + io.vsync := sync.io.vsync + io.x := sync.io.x + io.y := sync.io.y + io.video_on := sync.io.y +} diff --git a/lab4/src/main/scala/riscv/Parameters.scala b/lab4/src/main/scala/riscv/Parameters.scala new file mode 100644 index 0000000..b319498 --- /dev/null +++ b/lab4/src/main/scala/riscv/Parameters.scala @@ -0,0 +1,58 @@ +// 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 chisel3._ +import chisel3.util._ + +object ImplementationType { + val ThreeStage = 0 + val FiveStage = 1 +} + +object Parameters { + val AddrBits = 32 + val AddrWidth = AddrBits.W + + val InstructionBits = 32 + val InstructionWidth = InstructionBits.W + val DataBits = 32 + val DataWidth = DataBits.W + val ByteBits = 8 + val ByteWidth = ByteBits.W + val WordSize = Math.ceil(DataBits / ByteBits).toInt + + val PhysicalRegisters = 32 + val PhysicalRegisterAddrBits = log2Up(PhysicalRegisters) + val PhysicalRegisterAddrWidth = PhysicalRegisterAddrBits.W + + val CSRRegisterAddrBits = 12 + val CSRRegisterAddrWidth = CSRRegisterAddrBits.W + + val InterruptFlagBits = 32 + val InterruptFlagWidth = InterruptFlagBits.W + + val HoldStateBits = 3 + val StallStateWidth = HoldStateBits.W + + val MemorySizeInBytes = 32768 + val MemorySizeInWords = MemorySizeInBytes / 4 + + val EntryAddress = 0x1000.U(Parameters.AddrWidth) + + val MasterDeviceCount = 1 + val SlaveDeviceCount = 8 + val SlaveDeviceCountBits = log2Up(Parameters.SlaveDeviceCount) +} diff --git a/lab4/src/main/scala/riscv/core/BusBundle.scala b/lab4/src/main/scala/riscv/core/BusBundle.scala new file mode 100644 index 0000000..d8774bf --- /dev/null +++ b/lab4/src/main/scala/riscv/core/BusBundle.scala @@ -0,0 +1,32 @@ +// 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.core + +import chisel3._ +import riscv.Parameters + +class BusBundle extends Bundle { + val read = Output(Bool()) + val address = Output(UInt(Parameters.AddrWidth)) + val read_data = Input(UInt(Parameters.DataWidth)) + val read_valid = Input(Bool()) + val write = Output(Bool()) + val write_data = Output(UInt(Parameters.DataWidth)) + val write_strobe = Output(Vec(Parameters.WordSize, Bool())) + val write_valid = Input(Bool()) + val busy = Input(Bool()) + val request = Output(Bool()) + val granted = Input(Bool()) +} diff --git a/lab4/src/main/scala/riscv/core/CPU.scala b/lab4/src/main/scala/riscv/core/CPU.scala new file mode 100644 index 0000000..28939f8 --- /dev/null +++ b/lab4/src/main/scala/riscv/core/CPU.scala @@ -0,0 +1,32 @@ +// 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.core + +import chisel3._ +import threestage.{CPU => ThreeStageCPU} +import fivestage.{CPU => FiveStageCPU} +import riscv.ImplementationType + +class CPU(val implementation: Int = ImplementationType.FiveStage) extends Module { + val io = IO(new CPUBundle) + implementation match { + case ImplementationType.ThreeStage => + val cpu = Module(new ThreeStageCPU) + cpu.io <> io + case _ => + val cpu = Module(new FiveStageCPU) + cpu.io <> io + } +} diff --git a/lab4/src/main/scala/riscv/core/CPUBundle.scala b/lab4/src/main/scala/riscv/core/CPUBundle.scala new file mode 100644 index 0000000..0ee109d --- /dev/null +++ b/lab4/src/main/scala/riscv/core/CPUBundle.scala @@ -0,0 +1,32 @@ +// 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.core + +import bus.{AXI4LiteChannels, AXI4LiteMasterBundle} +import chisel3._ +import riscv.Parameters + +class CPUBundle extends Bundle { + val axi4_channels = new AXI4LiteChannels(Parameters.AddrBits, Parameters.DataBits) + val bus_address = Output(UInt(Parameters.AddrWidth)) + val interrupt_flag = Input(UInt(Parameters.InterruptFlagWidth)) + val stall_flag_bus = Input(Bool()) + val debug_read_address = Input(UInt(Parameters.PhysicalRegisterAddrWidth)) + val debug_read_data = Output(UInt(Parameters.DataWidth)) + + val instruction_valid = Input(Bool()) + val bus_busy = Output(Bool()) + val debug = Output(Vec(6, UInt(32.W))) +} diff --git a/lab4/src/main/scala/riscv/core/fivestage/ALU.scala b/lab4/src/main/scala/riscv/core/fivestage/ALU.scala new file mode 100644 index 0000000..a25d475 --- /dev/null +++ b/lab4/src/main/scala/riscv/core/fivestage/ALU.scala @@ -0,0 +1,70 @@ +// 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.core.fivestage + +import chisel3._ +import chisel3.experimental.ChiselEnum +import chisel3.util._ +import riscv.Parameters + +object ALUFunctions extends ChiselEnum { + val zero, add, sub, sll, slt, xor, or, and, srl, sra, sltu = Value +} + +class ALU extends Module { + val io = IO(new Bundle { + val func = Input(ALUFunctions()) + + val op1 = Input(UInt(Parameters.DataWidth)) + val op2 = Input(UInt(Parameters.DataWidth)) + + val result = Output(UInt(Parameters.DataWidth)) + }) + + io.result := 0.U + switch(io.func) { + is(ALUFunctions.add) { + io.result := io.op1 + io.op2 + } + is(ALUFunctions.sub) { + io.result := io.op1 - io.op2 + } + is(ALUFunctions.sll) { + io.result := io.op1 << io.op2(4, 0) + } + is(ALUFunctions.slt) { + io.result := io.op1.asSInt < io.op2.asSInt + } + is(ALUFunctions.xor) { + io.result := io.op1 ^ io.op2 + } + is(ALUFunctions.or) { + io.result := io.op1 | io.op2 + } + is(ALUFunctions.and) { + io.result := io.op1 & io.op2 + } + is(ALUFunctions.srl) { + io.result := io.op1 >> io.op2(4, 0) + } + is(ALUFunctions.sra) { + io.result := (io.op1.asSInt >> io.op2(4, 0)).asUInt + } + is(ALUFunctions.sltu) { + io.result := io.op1 < io.op2 + } + } + +} diff --git a/lab4/src/main/scala/riscv/core/fivestage/ALUControl.scala b/lab4/src/main/scala/riscv/core/fivestage/ALUControl.scala new file mode 100644 index 0000000..c51c54c --- /dev/null +++ b/lab4/src/main/scala/riscv/core/fivestage/ALUControl.scala @@ -0,0 +1,86 @@ +// 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.core.fivestage + +import chisel3._ +import chisel3.util._ + +class ALUControl extends Module { + val io = IO(new Bundle { + val opcode = Input(UInt(7.W)) + val funct3 = Input(UInt(3.W)) + val funct7 = Input(UInt(7.W)) + + val alu_funct = Output(ALUFunctions()) + }) + + io.alu_funct := ALUFunctions.zero + + switch(io.opcode) { + is(InstructionTypes.I) { + io.alu_funct := MuxLookup( + io.funct3, + ALUFunctions.zero, + IndexedSeq( + InstructionsTypeI.addi -> ALUFunctions.add, + InstructionsTypeI.slli -> ALUFunctions.sll, + InstructionsTypeI.slti -> ALUFunctions.slt, + InstructionsTypeI.sltiu -> ALUFunctions.sltu, + InstructionsTypeI.xori -> ALUFunctions.xor, + InstructionsTypeI.ori -> ALUFunctions.or, + InstructionsTypeI.andi -> ALUFunctions.and, + InstructionsTypeI.sri -> Mux(io.funct7(5), ALUFunctions.sra, ALUFunctions.srl) + ), + ) + } + is(InstructionTypes.RM) { + io.alu_funct := MuxLookup( + io.funct3, + ALUFunctions.zero, + IndexedSeq( + InstructionsTypeR.add_sub -> Mux(io.funct7(5), ALUFunctions.sub, ALUFunctions.add), + InstructionsTypeR.sll -> ALUFunctions.sll, + InstructionsTypeR.slt -> ALUFunctions.slt, + InstructionsTypeR.sltu -> ALUFunctions.sltu, + InstructionsTypeR.xor -> ALUFunctions.xor, + InstructionsTypeR.or -> ALUFunctions.or, + InstructionsTypeR.and -> ALUFunctions.and, + InstructionsTypeR.sr -> Mux(io.funct7(5), ALUFunctions.sra, ALUFunctions.srl) + ), + ) + } + is(InstructionTypes.B) { + io.alu_funct := ALUFunctions.add + } + is(InstructionTypes.L) { + io.alu_funct := ALUFunctions.add + } + is(InstructionTypes.S) { + io.alu_funct := ALUFunctions.add + } + is(Instructions.jal) { + io.alu_funct := ALUFunctions.add + } + is(Instructions.jalr) { + io.alu_funct := ALUFunctions.add + } + is(Instructions.lui) { + io.alu_funct := ALUFunctions.add + } + is(Instructions.auipc) { + io.alu_funct := ALUFunctions.add + } + } +} diff --git a/lab4/src/main/scala/riscv/core/fivestage/CLINT.scala b/lab4/src/main/scala/riscv/core/fivestage/CLINT.scala new file mode 100644 index 0000000..5b8b7f7 --- /dev/null +++ b/lab4/src/main/scala/riscv/core/fivestage/CLINT.scala @@ -0,0 +1,183 @@ +// 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.core.fivestage + +import chisel3._ +import chisel3.util._ +import riscv.Parameters + +object InterruptStatus { + val None = 0x0.U(8.W) + val Timer0 = 0x1.U(8.W) + val Ret = 0xFF.U(8.W) +} + +object InterruptEntry { + val Timer0 = 0x4.U(8.W) +} + +object InterruptState { + val Idle = 0x0.U + val SyncAssert = 0x1.U + val AsyncAssert = 0x2.U + val MRET = 0x3.U +} + +object CSRState { + val Idle = 0x0.U + val MSTATUS = 0x1.U + val MEPC = 0x2.U + val MRET = 0x3.U + val MCAUSE = 0x4.U +} + +// Core Local Interrupt Controller +class CLINT extends Module { + val io = IO(new Bundle { + // Interrupt signals from peripherals + val interrupt_flag = Input(UInt(Parameters.InterruptFlagWidth)) + + // Current instruction from instruction decode + val instruction = Input(UInt(Parameters.InstructionWidth)) + val instruction_address_if = Input(UInt(Parameters.AddrWidth)) + + val jump_flag = Input(Bool()) + val jump_address = Input(UInt(Parameters.AddrWidth)) + + val csr_mtvec = Input(UInt(Parameters.DataWidth)) + val csr_mepc = Input(UInt(Parameters.DataWidth)) + val csr_mstatus = Input(UInt(Parameters.DataWidth)) + + // Is global interrupt enabled (from MSTATUS)? + val interrupt_enable = Input(Bool()) + + val ctrl_stall_flag = Output(Bool()) + + val csr_reg_write_enable = Output(Bool()) + val csr_reg_write_address = Output(UInt(Parameters.CSRRegisterAddrWidth)) + val csr_reg_write_data = Output(UInt(Parameters.DataWidth)) + + val id_interrupt_handler_address = Output(UInt(Parameters.AddrWidth)) + val id_interrupt_assert = Output(Bool()) + }) + + val interrupt_state = WireInit(0.U) + val csr_state = RegInit(CSRState.Idle) + val instruction_address = RegInit(UInt(Parameters.AddrWidth), 0.U) + val cause = RegInit(UInt(Parameters.DataWidth), 0.U) + val interrupt_assert = RegInit(Bool(), false.B) + val interrupt_handler_address = RegInit(UInt(Parameters.AddrWidth), 0.U) + val csr_reg_write_enable = RegInit(Bool(), false.B) + val csr_reg_write_address = RegInit(UInt(Parameters.CSRRegisterAddrWidth), 0.U) + val csr_reg_write_data = RegInit(UInt(Parameters.DataWidth), 0.U) + + io.ctrl_stall_flag := interrupt_state =/= InterruptState.Idle || csr_state =/= CSRState.Idle + + // Interrupt FSM + when(io.instruction === InstructionsEnv.ecall || io.instruction === InstructionsEnv.ebreak) { + interrupt_state := InterruptState.SyncAssert + }.elsewhen(io.interrupt_flag =/= InterruptStatus.None && io.interrupt_enable) { + interrupt_state := InterruptState.AsyncAssert + }.elsewhen(io.instruction === InstructionsRet.mret) { + interrupt_state := InterruptState.MRET + }.otherwise { + interrupt_state := InterruptState.Idle + } + + // CSR FSM + when(csr_state === CSRState.Idle) { + when(interrupt_state === InterruptState.SyncAssert) { + // Synchronous Interrupt + csr_state := CSRState.MEPC + instruction_address := Mux( + io.jump_flag, + io.jump_address - 4.U, + io.instruction_address_if + ) + + cause := MuxLookup( + io.instruction, + 10.U, + IndexedSeq( + InstructionsEnv.ecall -> 11.U, + InstructionsEnv.ebreak -> 3.U, + ) + ) + }.elsewhen(interrupt_state === InterruptState.AsyncAssert) { + // Asynchronous Interrupt + cause := 0x8000000BL.U + when(io.interrupt_flag(0)) { + cause := 0x80000007L.U + } + csr_state := CSRState.MEPC + instruction_address := Mux( + io.jump_flag, + io.jump_address, + io.instruction_address_if, + ) + }.elsewhen(interrupt_state === InterruptState.MRET) { + // Interrupt Return + csr_state := CSRState.MRET + } + }.elsewhen(csr_state === CSRState.MEPC) { + csr_state := CSRState.MSTATUS + }.elsewhen(csr_state === CSRState.MSTATUS) { + csr_state := CSRState.MCAUSE + }.elsewhen(csr_state === CSRState.MCAUSE) { + csr_state := CSRState.Idle + }.elsewhen(csr_state === CSRState.MRET) { + csr_state := CSRState.Idle + }.otherwise { + csr_state := CSRState.Idle + } + + csr_reg_write_enable := csr_state =/= CSRState.Idle + csr_reg_write_address := Cat(Fill(20, 0.U(1.W)), MuxLookup( + csr_state, + 0.U(Parameters.CSRRegisterAddrWidth), + IndexedSeq( + CSRState.MEPC -> CSRRegister.MEPC, + CSRState.MCAUSE -> CSRRegister.MCAUSE, + CSRState.MSTATUS -> CSRRegister.MSTATUS, + CSRState.MRET -> CSRRegister.MSTATUS, + ) + )) + csr_reg_write_data := MuxLookup( + csr_state, + 0.U(Parameters.DataWidth), + IndexedSeq( + CSRState.MEPC -> instruction_address, + CSRState.MCAUSE -> cause, + CSRState.MSTATUS -> Cat(io.csr_mstatus(31, 4), 0.U(1.W), io.csr_mstatus(2, 0)), + CSRState.MRET -> Cat(io.csr_mstatus(31, 4), io.csr_mstatus(7), io.csr_mstatus(2, 0)), + ) + ) + io.csr_reg_write_enable := csr_reg_write_enable + io.csr_reg_write_address := csr_reg_write_address + io.csr_reg_write_data := csr_reg_write_data + + interrupt_assert := csr_state === CSRState.MCAUSE || csr_state === CSRState.MRET + interrupt_handler_address := MuxLookup( + csr_state, + 0.U(Parameters.AddrWidth), + IndexedSeq( + CSRState.MCAUSE -> io.csr_mtvec, + CSRState.MRET -> io.csr_mepc, + ) + ) + + io.id_interrupt_assert := interrupt_assert + io.id_interrupt_handler_address := interrupt_handler_address +} diff --git a/lab4/src/main/scala/riscv/core/fivestage/CPU.scala b/lab4/src/main/scala/riscv/core/fivestage/CPU.scala new file mode 100644 index 0000000..a8ccd85 --- /dev/null +++ b/lab4/src/main/scala/riscv/core/fivestage/CPU.scala @@ -0,0 +1,217 @@ +// 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.core.fivestage + +import bus.{AXI4LiteChannels, AXI4LiteMaster} +import chisel3._ +import riscv.Parameters +import riscv.core.CPUBundle + +class CPU extends Module { + val io = IO(new CPUBundle) + + val ctrl = Module(new Control) + val regs = Module(new RegisterFile) + val inst_fetch = Module(new InstructionFetch) + val if2id = Module(new IF2ID) + val id = Module(new InstructionDecode) + val id2ex = Module(new ID2EX) + val ex = Module(new Execute) + val ex2mem = Module(new EX2MEM) + val mem = Module(new MemoryAccess) + val mem2wb = Module(new MEM2WB) + val wb = Module(new WriteBack) + val forwarding = Module(new Forwarding) + val clint = Module(new CLINT) + val csr_regs = Module(new CSR) + val axi4_master = Module(new AXI4LiteMaster(Parameters.AddrBits, Parameters.DataBits)) + + axi4_master.io.channels <> io.axi4_channels + io.debug(0) := ex.io.reg1_data + io.debug(1) := ex.io.reg2_data + io.debug(2) := ex.io.instruction_address + io.debug(3) := ex.io.instruction + io.debug(4) := inst_fetch.io.jump_address_id + io.debug(5) := inst_fetch.io.jump_flag_id + io.bus_busy := axi4_master.io.bundle.busy + + // The MEM module takes precedence over IF (but let the previous fetch finish) + val mem_granted = RegInit(false.B) + when(mem_granted) { + inst_fetch.io.instruction_valid := false.B + io.bus_address := mem.io.bus.address + axi4_master.io.bundle.read := mem.io.bus.read + axi4_master.io.bundle.address := mem.io.bus.address + axi4_master.io.bundle.write := mem.io.bus.write + axi4_master.io.bundle.write_data := mem.io.bus.write_data + axi4_master.io.bundle.write_strobe := mem.io.bus.write_strobe + when(!mem.io.bus.request) { + mem_granted := false.B + } + }.otherwise { + // Default to fetch instructions from main memory + mem_granted := false.B + axi4_master.io.bundle.read := !axi4_master.io.bundle.busy && !axi4_master.io.bundle.read_valid && !mem.io.bus.request + axi4_master.io.bundle.address := inst_fetch.io.bus_address + io.bus_address := inst_fetch.io.bus_address + axi4_master.io.bundle.write := false.B + axi4_master.io.bundle.write_data := 0.U + axi4_master.io.bundle.write_strobe := VecInit(Seq.fill(Parameters.WordSize)(false.B)) + } + + when(mem.io.bus.request) { + when(!axi4_master.io.bundle.busy && !axi4_master.io.bundle.read_valid) { + mem_granted := true.B + } + } + + inst_fetch.io.instruction_valid := io.instruction_valid && axi4_master.io.bundle.read_valid && !mem_granted + inst_fetch.io.bus_data := axi4_master.io.bundle.read_data + + mem.io.bus.read_data := axi4_master.io.bundle.read_data + mem.io.bus.read_valid := axi4_master.io.bundle.read_valid + mem.io.bus.write_valid := axi4_master.io.bundle.write_valid + mem.io.bus.busy := axi4_master.io.bundle.busy + mem.io.bus.granted := mem_granted + + ctrl.io.jump_flag := id.io.if_jump_flag + ctrl.io.stall_flag_if := inst_fetch.io.ctrl_stall_flag + ctrl.io.stall_flag_mem := mem.io.ctrl_stall_flag + ctrl.io.stall_flag_clint := clint.io.ctrl_stall_flag + ctrl.io.stall_flag_bus := io.stall_flag_bus + ctrl.io.rs1_id := id.io.regs_reg1_read_address + ctrl.io.rs2_id := id.io.regs_reg2_read_address + ctrl.io.memory_read_enable_ex := ex2mem.io.memory_read_enable + ctrl.io.rd_ex := ex2mem.io.regs_write_address + + regs.io.write_enable := mem2wb.io.output_regs_write_enable + regs.io.write_address := mem2wb.io.output_regs_write_address + regs.io.write_data := wb.io.regs_write_data + regs.io.read_address1 := id.io.regs_reg1_read_address + regs.io.read_address2 := id.io.regs_reg2_read_address + + regs.io.debug_read_address := io.debug_read_address + io.debug_read_data := regs.io.debug_read_data + + inst_fetch.io.stall_flag_ctrl := ctrl.io.pc_stall + inst_fetch.io.jump_flag_id := id.io.if_jump_flag + inst_fetch.io.jump_address_id := id.io.if_jump_address + + if2id.io.stall_flag := ctrl.io.if_stall + if2id.io.flush_enable := ctrl.io.if_flush + if2id.io.instruction := inst_fetch.io.id_instruction + if2id.io.instruction_address := inst_fetch.io.id_instruction_address + if2id.io.interrupt_flag := io.interrupt_flag + + id.io.reg1_data := regs.io.read_data1 + id.io.reg2_data := regs.io.read_data2 + id.io.instruction := if2id.io.output_instruction + id.io.instruction_address := if2id.io.output_instruction_address + id.io.interrupt_assert := clint.io.id_interrupt_assert + id.io.interrupt_handler_address := clint.io.id_interrupt_handler_address + + id2ex.io.stall_flag := ctrl.io.id_stall + id2ex.io.flush_enable := ctrl.io.id_flush + id2ex.io.instruction := if2id.io.output_instruction + id2ex.io.instruction_address := if2id.io.output_instruction_address + id2ex.io.regs_write_enable := id.io.ex_reg_write_enable + id2ex.io.regs_write_address := id.io.ex_reg_write_address + id2ex.io.regs_write_source := id.io.ex_reg_write_source + id2ex.io.reg1_data := regs.io.read_data1 + id2ex.io.reg2_data := regs.io.read_data2 + id2ex.io.immediate := id.io.ex_immediate + id2ex.io.aluop1_source := id.io.ex_aluop1_source + id2ex.io.aluop2_source := id.io.ex_aluop2_source + id2ex.io.csr_write_enable := id.io.ex_csr_write_enable + id2ex.io.csr_address := id.io.ex_csr_address + id2ex.io.memory_read_enable := id.io.ex_memory_read_enable + id2ex.io.memory_write_enable := id.io.ex_memory_write_enable + id2ex.io.csr_read_data := csr_regs.io.id_reg_data + + ex.io.instruction := id2ex.io.output_instruction + ex.io.instruction_address := id2ex.io.output_instruction_address + ex.io.reg1_data := id2ex.io.output_reg1_data + ex.io.reg2_data := id2ex.io.output_reg2_data + ex.io.immediate := id2ex.io.output_immediate + ex.io.aluop1_source := id2ex.io.output_aluop1_source + ex.io.aluop2_source := id2ex.io.output_aluop2_source + ex.io.csr_read_data := id2ex.io.output_csr_read_data + ex.io.forward_from_mem := mem.io.forward_to_ex + ex.io.forward_from_wb := wb.io.regs_write_data + ex.io.aluop1_forward := forwarding.io.aluop1_forward_ex + ex.io.aluop2_forward := forwarding.io.aluop2_forward_ex + + ex2mem.io.stall_flag := ctrl.io.ex_stall + ex2mem.io.flush_enable := false.B + ex2mem.io.regs_write_enable := id2ex.io.output_regs_write_enable + ex2mem.io.regs_write_source := id2ex.io.output_regs_write_source + ex2mem.io.regs_write_address := id2ex.io.output_regs_write_address + ex2mem.io.instruction_address := id2ex.io.output_instruction_address + ex2mem.io.instruction := id2ex.io.output_instruction + ex2mem.io.reg1_data := id2ex.io.output_reg1_data + ex2mem.io.reg2_data := id2ex.io.output_reg2_data + ex2mem.io.memory_read_enable := id2ex.io.output_memory_read_enable + ex2mem.io.memory_write_enable := id2ex.io.output_memory_write_enable + ex2mem.io.alu_result := ex.io.mem_alu_result + ex2mem.io.csr_read_data := id2ex.io.output_csr_read_data + + mem.io.alu_result := ex2mem.io.output_alu_result + mem.io.reg2_data := ex2mem.io.output_reg2_data + mem.io.memory_read_enable := ex2mem.io.output_memory_read_enable + mem.io.memory_write_enable := ex2mem.io.output_memory_write_enable + mem.io.funct3 := ex2mem.io.output_instruction(14, 12) + mem.io.regs_write_source := ex2mem.io.output_regs_write_source + mem.io.csr_read_data := ex2mem.io.output_csr_read_data + + mem2wb.io.instruction_address := ex2mem.io.output_instruction_address + mem2wb.io.alu_result := ex2mem.io.output_alu_result + mem2wb.io.regs_write_enable := ex2mem.io.output_regs_write_enable + mem2wb.io.regs_write_source := ex2mem.io.output_regs_write_source + mem2wb.io.regs_write_address := ex2mem.io.output_regs_write_address + mem2wb.io.memory_read_data := mem.io.wb_memory_read_data + mem2wb.io.csr_read_data := ex2mem.io.output_csr_read_data + + wb.io.instruction_address := mem2wb.io.output_instruction_address + wb.io.alu_result := mem2wb.io.output_alu_result + wb.io.memory_read_data := mem2wb.io.output_memory_read_data + wb.io.regs_write_source := mem2wb.io.output_regs_write_source + wb.io.csr_read_data := mem2wb.io.output_csr_read_data + + forwarding.io.rs1_ex := id2ex.io.output_instruction(19, 15) + forwarding.io.rs2_ex := id2ex.io.output_instruction(24, 20) + forwarding.io.rd_mem := ex2mem.io.output_regs_write_address + forwarding.io.reg_write_enable_mem := ex2mem.io.output_regs_write_enable + forwarding.io.rd_wb := mem2wb.io.output_regs_write_address + forwarding.io.reg_write_enable_wb := mem2wb.io.output_regs_write_enable + + clint.io.instruction := if2id.io.output_instruction + clint.io.instruction_address_if := inst_fetch.io.id_instruction_address + clint.io.jump_flag := id.io.if_jump_flag + clint.io.jump_address := ex2mem.io.output_alu_result + clint.io.csr_mepc := csr_regs.io.clint_csr_mepc + clint.io.csr_mtvec := csr_regs.io.clint_csr_mtvec + clint.io.csr_mstatus := csr_regs.io.clint_csr_mstatus + clint.io.interrupt_enable := csr_regs.io.interrupt_enable + clint.io.interrupt_flag := if2id.io.output_interrupt_flag + + csr_regs.io.reg_write_enable_ex := id2ex.io.output_csr_write_enable + csr_regs.io.reg_write_address_ex := id2ex.io.output_csr_address + csr_regs.io.reg_write_data_ex := ex.io.csr_write_data + csr_regs.io.reg_read_address_id := id.io.ex_csr_address + csr_regs.io.reg_write_enable_clint := clint.io.csr_reg_write_enable + csr_regs.io.reg_write_address_clint := clint.io.csr_reg_write_address + csr_regs.io.reg_write_data_clint := clint.io.csr_reg_write_data + csr_regs.io.reg_read_address_clint := 0.U +} diff --git a/lab4/src/main/scala/riscv/core/fivestage/CSR.scala b/lab4/src/main/scala/riscv/core/fivestage/CSR.scala new file mode 100644 index 0000000..9c21d6c --- /dev/null +++ b/lab4/src/main/scala/riscv/core/fivestage/CSR.scala @@ -0,0 +1,126 @@ +// 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.core.fivestage + +import chisel3._ +import chisel3.util._ +import riscv.Parameters + + +object CSRRegister { + // Refer to Spec. Vol.II Page 8-10 + val CycleL = 0xc00.U(Parameters.CSRRegisterAddrWidth) + val CycleH = 0xc80.U(Parameters.CSRRegisterAddrWidth) + val MTVEC = 0x305.U(Parameters.CSRRegisterAddrWidth) + val MCAUSE = 0x342.U(Parameters.CSRRegisterAddrWidth) + val MEPC = 0x341.U(Parameters.CSRRegisterAddrWidth) + val MIE = 0x304.U(Parameters.CSRRegisterAddrWidth) + val MSTATUS = 0x300.U(Parameters.CSRRegisterAddrWidth) + val MSCRATCH = 0x340.U(Parameters.CSRRegisterAddrWidth) +} + +class CSR extends Module { + val io = IO(new Bundle { + val reg_write_enable_ex = Input(Bool()) + val reg_read_address_id = Input(UInt(Parameters.CSRRegisterAddrWidth)) + val reg_write_address_ex = Input(UInt(Parameters.CSRRegisterAddrWidth)) + val reg_write_data_ex = Input(UInt(Parameters.DataWidth)) + + val reg_write_enable_clint = Input(Bool()) + val reg_read_address_clint = Input(UInt(Parameters.CSRRegisterAddrWidth)) + val reg_write_address_clint = Input(UInt(Parameters.CSRRegisterAddrWidth)) + val reg_write_data_clint = Input(UInt(Parameters.DataWidth)) + + val interrupt_enable = Output(Bool()) + + val id_reg_data = Output(UInt(Parameters.DataWidth)) + + val clint_reg_data = Output(UInt(Parameters.DataWidth)) + val clint_csr_mtvec = Output(UInt(Parameters.DataWidth)) + val clint_csr_mepc = Output(UInt(Parameters.DataWidth)) + val clint_csr_mstatus = Output(UInt(Parameters.DataWidth)) + }) + + + val cycles = RegInit(UInt(64.W), 0.U) + val mtvec = RegInit(UInt(Parameters.DataWidth), 0.U) + val mcause = RegInit(UInt(Parameters.DataWidth), 0.U) + val mepc = RegInit(UInt(Parameters.DataWidth), 0.U) + val mie = RegInit(UInt(Parameters.DataWidth), 0.U) + val mstatus = RegInit(UInt(Parameters.DataWidth), 0.U) + val mscratch = RegInit(UInt(Parameters.DataWidth), 0.U) + + cycles := cycles + 1.U + io.clint_csr_mtvec := mtvec + io.clint_csr_mepc := mepc + io.clint_csr_mstatus := mstatus + io.interrupt_enable := mstatus(3) === 1.U + + val reg_write_address = Wire(UInt(Parameters.CSRRegisterAddrWidth)) + val reg_write_data = Wire(UInt(Parameters.DataWidth)) + reg_write_address := 0.U + reg_write_data := 0.U + + val reg_read_address = Wire(UInt(Parameters.CSRRegisterAddrWidth)) + val reg_read_data = Wire(UInt(Parameters.DataWidth)) + reg_read_address := 0.U + reg_read_data := 0.U + + when(io.reg_write_enable_ex) { + reg_write_address := io.reg_write_address_ex(11, 0) + reg_write_data := io.reg_write_data_ex + }.elsewhen(io.reg_write_enable_clint) { + reg_write_address := io.reg_write_address_clint(11, 0) + reg_write_data := io.reg_write_data_clint + } + + when(reg_write_address === CSRRegister.MTVEC) { + mtvec := reg_write_data + }.elsewhen(reg_write_address === CSRRegister.MCAUSE) { + mcause := reg_write_data + }.elsewhen(reg_write_address === CSRRegister.MEPC) { + mepc := reg_write_data + }.elsewhen(reg_write_address === CSRRegister.MIE) { + mie := reg_write_data + }.elsewhen(reg_write_address === CSRRegister.MSTATUS) { + mstatus := reg_write_data + }.elsewhen(reg_write_address === CSRRegister.MSCRATCH) { + mscratch := reg_write_data + } + + val regLUT = + IndexedSeq( + CSRRegister.CycleL -> cycles(31, 0), + CSRRegister.CycleH -> cycles(63, 32), + CSRRegister.MTVEC -> mtvec, + CSRRegister.MCAUSE -> mcause, + CSRRegister.MEPC -> mepc, + CSRRegister.MIE -> mie, + CSRRegister.MSTATUS -> mstatus, + CSRRegister.MSCRATCH -> mscratch, + ) + + io.id_reg_data := MuxLookup( + io.reg_read_address_id, + 0.U, + regLUT, + ) + + io.clint_reg_data := MuxLookup( + io.reg_read_address_clint, + 0.U, + regLUT, + ) +} diff --git a/lab4/src/main/scala/riscv/core/fivestage/Cache.scala b/lab4/src/main/scala/riscv/core/fivestage/Cache.scala new file mode 100644 index 0000000..4b75d4a --- /dev/null +++ b/lab4/src/main/scala/riscv/core/fivestage/Cache.scala @@ -0,0 +1,23 @@ +// 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.core.fivestage + +import chisel3._ + +class Cache(cacheLineBytes: Int, associativity: Int, cacheLines: Int) extends Module { + val io = IO(new Bundle { + + }) +} diff --git a/lab4/src/main/scala/riscv/core/fivestage/Control.scala b/lab4/src/main/scala/riscv/core/fivestage/Control.scala new file mode 100644 index 0000000..339f09f --- /dev/null +++ b/lab4/src/main/scala/riscv/core/fivestage/Control.scala @@ -0,0 +1,48 @@ +// 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.core.fivestage + +import chisel3._ +import riscv.Parameters + +class Control extends Module { + val io = IO(new Bundle { + val jump_flag = Input(Bool()) + val stall_flag_if = Input(Bool()) + val stall_flag_mem = Input(Bool()) + val stall_flag_clint = Input(Bool()) + val stall_flag_bus = Input(Bool()) + val rs1_id = Input(UInt(Parameters.PhysicalRegisterAddrWidth)) + val rs2_id = Input(UInt(Parameters.PhysicalRegisterAddrWidth)) + val memory_read_enable_ex = Input(Bool()) + val rd_ex = Input(UInt(Parameters.PhysicalRegisterAddrWidth)) + + val if_flush = Output(Bool()) + val id_flush = Output(Bool()) + val pc_stall = Output(Bool()) + val if_stall = Output(Bool()) + val id_stall = Output(Bool()) + val ex_stall = Output(Bool()) + }) + + val id_hazard = io.memory_read_enable_ex && (io.rd_ex === io.rs1_id || io.rd_ex === io.rs2_id) + io.if_flush := io.jump_flag + io.id_flush := id_hazard + + io.pc_stall := io.stall_flag_mem || io.stall_flag_clint || id_hazard || io.stall_flag_bus || io.stall_flag_if + io.if_stall := io.stall_flag_mem || io.stall_flag_clint || id_hazard + io.id_stall := io.stall_flag_mem || io.stall_flag_clint + io.ex_stall := io.stall_flag_mem || io.stall_flag_clint +} diff --git a/lab4/src/main/scala/riscv/core/fivestage/EX2MEM.scala b/lab4/src/main/scala/riscv/core/fivestage/EX2MEM.scala new file mode 100644 index 0000000..c18c962 --- /dev/null +++ b/lab4/src/main/scala/riscv/core/fivestage/EX2MEM.scala @@ -0,0 +1,115 @@ +// Copyright 2022 Canbin Huang +// +// 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.core.fivestage + +import chisel3._ +import riscv.Parameters + +class EX2MEM extends Module { + val io = IO(new Bundle() { + val stall_flag = Input(Bool()) + val flush_enable = Input(Bool()) + val regs_write_enable = Input(Bool()) + val regs_write_source = Input(UInt(2.W)) + val regs_write_address = Input(UInt(Parameters.AddrWidth)) + val instruction_address = Input(UInt(Parameters.AddrWidth)) + val instruction = Input(UInt(Parameters.DataWidth)) + val reg1_data = Input(UInt(Parameters.DataWidth)) + val reg2_data = Input(UInt(Parameters.DataWidth)) + val memory_read_enable = Input(Bool()) + val memory_write_enable = Input(Bool()) + val alu_result = Input(UInt(Parameters.DataWidth)) + val csr_read_data = Input(UInt(Parameters.DataWidth)) + + val output_regs_write_enable = Output(Bool()) + val output_regs_write_source = Output(UInt(2.W)) + val output_regs_write_address = Output(UInt(Parameters.AddrWidth)) + val output_instruction_address = Output(UInt(Parameters.AddrWidth)) + val output_instruction = Output(UInt(Parameters.DataWidth)) + val output_reg1_data = Output(UInt(Parameters.DataWidth)) + val output_reg2_data = Output(UInt(Parameters.DataWidth)) + val output_memory_read_enable = Output(Bool()) + val output_memory_write_enable = Output(Bool()) + val output_alu_result = Output(UInt(Parameters.DataWidth)) + val output_csr_read_data = Output(UInt(Parameters.DataWidth)) + }) + val write_enable = !io.stall_flag + + val regs_write_enable = Module(new PipelineRegister(1)) + regs_write_enable.io.in := io.regs_write_enable + regs_write_enable.io.write_enable := write_enable + regs_write_enable.io.flush_enable := io.flush_enable + io.output_regs_write_enable := regs_write_enable.io.out + + val regs_write_source = Module(new PipelineRegister(2)) + regs_write_source.io.in := io.regs_write_source + regs_write_source.io.write_enable := write_enable + regs_write_source.io.flush_enable := io.flush_enable + io.output_regs_write_source := regs_write_source.io.out + + val regs_write_address = Module(new PipelineRegister(Parameters.PhysicalRegisterAddrBits)) + regs_write_address.io.in := io.regs_write_address + regs_write_address.io.write_enable := write_enable + regs_write_address.io.flush_enable := io.flush_enable + io.output_regs_write_address := regs_write_address.io.out + + val instruction_address = Module(new PipelineRegister(Parameters.AddrBits)) + instruction_address.io.in := io.instruction_address + instruction_address.io.write_enable := write_enable + instruction_address.io.flush_enable := io.flush_enable + io.output_instruction_address := instruction_address.io.out + + val instruction = Module(new PipelineRegister(Parameters.InstructionBits)) + instruction.io.in := io.instruction + instruction.io.write_enable := write_enable + instruction.io.flush_enable := io.flush_enable + io.output_instruction := instruction.io.out + + val reg1_data = Module(new PipelineRegister()) + reg1_data.io.in := io.reg1_data + reg1_data.io.write_enable := write_enable + reg1_data.io.flush_enable := io.flush_enable + io.output_reg1_data := reg1_data.io.out + + val reg2_data = Module(new PipelineRegister()) + reg2_data.io.in := io.reg2_data + reg2_data.io.write_enable := write_enable + reg2_data.io.flush_enable := io.flush_enable + io.output_reg2_data := reg2_data.io.out + + val alu_result = Module(new PipelineRegister()) + alu_result.io.in := io.alu_result + alu_result.io.write_enable := write_enable + alu_result.io.flush_enable := io.flush_enable + io.output_alu_result := alu_result.io.out + + val memory_read_enable = Module(new PipelineRegister(1)) + memory_read_enable.io.in := io.memory_read_enable + memory_read_enable.io.write_enable := write_enable + memory_read_enable.io.flush_enable := io.flush_enable + io.output_memory_read_enable := memory_read_enable.io.out + + val memory_write_enable = Module(new PipelineRegister(1)) + memory_write_enable.io.in := io.memory_write_enable + memory_write_enable.io.write_enable := write_enable + memory_write_enable.io.flush_enable := io.flush_enable + io.output_memory_write_enable := memory_write_enable.io.out + + val csr_read_data = Module(new PipelineRegister()) + csr_read_data.io.in := io.csr_read_data + csr_read_data.io.write_enable := write_enable + csr_read_data.io.flush_enable := io.flush_enable + io.output_csr_read_data := csr_read_data.io.out +} diff --git a/lab4/src/main/scala/riscv/core/fivestage/Execute.scala b/lab4/src/main/scala/riscv/core/fivestage/Execute.scala new file mode 100644 index 0000000..9aa57c9 --- /dev/null +++ b/lab4/src/main/scala/riscv/core/fivestage/Execute.scala @@ -0,0 +1,91 @@ +// 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.core.fivestage + +import chisel3._ +import chisel3.experimental.ChiselEnum +import chisel3.util._ +import riscv.Parameters + +object MemoryAccessStates extends ChiselEnum { + val Idle, Read, Write, ReadWrite = Value +} + +class Execute extends Module { + val io = IO(new Bundle { + val instruction = Input(UInt(Parameters.InstructionWidth)) + val instruction_address = Input(UInt(Parameters.AddrWidth)) + val reg1_data = Input(UInt(Parameters.DataWidth)) + val reg2_data = Input(UInt(Parameters.DataWidth)) + val immediate = Input(UInt(Parameters.DataWidth)) + val aluop1_source = Input(UInt(1.W)) + val aluop2_source = Input(UInt(1.W)) + val csr_read_data = Input(UInt(Parameters.DataWidth)) + val forward_from_mem = Input(UInt(Parameters.DataWidth)) + val forward_from_wb = Input(UInt(Parameters.DataWidth)) + val aluop1_forward = Input(UInt(2.W)) + val aluop2_forward = Input(UInt(2.W)) + + val mem_alu_result = Output(UInt(Parameters.DataWidth)) + val csr_write_data = Output(UInt(Parameters.DataWidth)) + }) + + val opcode = io.instruction(6, 0) + val funct3 = io.instruction(14, 12) + val funct7 = io.instruction(31, 25) + val rd = io.instruction(11, 7) + val uimm = io.instruction(19, 15) + + val alu = Module(new ALU) + val alu_ctrl = Module(new ALUControl) + + alu_ctrl.io.opcode := opcode + alu_ctrl.io.funct3 := funct3 + alu_ctrl.io.funct7 := funct7 + alu.io.func := alu_ctrl.io.alu_funct + alu.io.op1 := Mux( + io.aluop1_source === ALUOp1Source.InstructionAddress, + io.instruction_address, + MuxLookup( + io.aluop1_forward, + io.reg1_data, + IndexedSeq( + ForwardingType.ForwardFromMEM -> io.forward_from_mem, + ForwardingType.ForwardFromWB -> io.forward_from_wb + ) + ) + ) + alu.io.op2 := Mux( + io.aluop2_source === ALUOp2Source.Immediate, + io.immediate, + MuxLookup( + io.aluop2_forward, + io.reg2_data, + IndexedSeq( + ForwardingType.ForwardFromMEM -> io.forward_from_mem, + ForwardingType.ForwardFromWB -> io.forward_from_wb + ) + ) + ) + io.mem_alu_result := alu.io.result + io.csr_write_data := MuxLookup(funct3, 0.U, IndexedSeq( + InstructionsTypeCSR.csrrw -> io.reg1_data, + InstructionsTypeCSR.csrrc -> io.csr_read_data.&((~io.reg1_data).asUInt), + InstructionsTypeCSR.csrrs -> io.csr_read_data.|(io.reg1_data), + InstructionsTypeCSR.csrrwi -> Cat(0.U(27.W), uimm), + InstructionsTypeCSR.csrrci -> io.csr_read_data.&((~Cat(0.U(27.W), uimm)).asUInt), + InstructionsTypeCSR.csrrsi -> io.csr_read_data.|(Cat(0.U(27.W), uimm)), + )) +} diff --git a/lab4/src/main/scala/riscv/core/fivestage/Forwarding.scala b/lab4/src/main/scala/riscv/core/fivestage/Forwarding.scala new file mode 100644 index 0000000..2369a82 --- /dev/null +++ b/lab4/src/main/scala/riscv/core/fivestage/Forwarding.scala @@ -0,0 +1,53 @@ +// Copyright 2022 Canbin Huang +// +// 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.core.fivestage + +import chisel3._ +import riscv.Parameters + +object ForwardingType { + val NoForward = 0.U(2.W) + val ForwardFromMEM = 1.U(2.W) + val ForwardFromWB = 2.U(2.W) +} + +class Forwarding extends Module { + val io = IO(new Bundle() { + val rs1_ex = Input(UInt(Parameters.PhysicalRegisterAddrWidth)) + val rs2_ex = Input(UInt(Parameters.PhysicalRegisterAddrWidth)) + val rd_mem = Input(UInt(Parameters.PhysicalRegisterAddrWidth)) + val reg_write_enable_mem = Input(Bool()) + val rd_wb = Input(UInt(Parameters.PhysicalRegisterAddrWidth)) + val reg_write_enable_wb = Input(Bool()) + + val aluop1_forward_ex = Output(UInt(2.W)) + val aluop2_forward_ex = Output(UInt(2.W)) + }) + when(io.reg_write_enable_mem && io.rd_mem =/= 0.U && io.rd_mem === io.rs1_ex) { + io.aluop1_forward_ex := ForwardingType.ForwardFromMEM + }.elsewhen(io.reg_write_enable_wb && io.rd_wb =/= 0.U && io.rd_wb === io.rs1_ex) { + io.aluop1_forward_ex := ForwardingType.ForwardFromWB + }.otherwise { + io.aluop1_forward_ex := ForwardingType.NoForward + } + + when(io.reg_write_enable_mem && io.rd_mem =/= 0.U && io.rd_mem === io.rs2_ex) { + io.aluop2_forward_ex := ForwardingType.ForwardFromMEM + }.elsewhen(io.reg_write_enable_wb && io.rd_wb =/= 0.U && io.rd_wb === io.rs2_ex) { + io.aluop2_forward_ex := ForwardingType.ForwardFromWB + }.otherwise { + io.aluop2_forward_ex := ForwardingType.NoForward + } +} diff --git a/lab4/src/main/scala/riscv/core/fivestage/ID2EX.scala b/lab4/src/main/scala/riscv/core/fivestage/ID2EX.scala new file mode 100644 index 0000000..8b71c01 --- /dev/null +++ b/lab4/src/main/scala/riscv/core/fivestage/ID2EX.scala @@ -0,0 +1,147 @@ +// 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.core.fivestage + +import chisel3._ +import riscv.Parameters + +class ID2EX extends Module { + val io = IO(new Bundle { + val stall_flag = Input(Bool()) + val flush_enable = Input(Bool()) + val instruction = Input(UInt(Parameters.InstructionWidth)) + val instruction_address = Input(UInt(Parameters.AddrWidth)) + val regs_write_enable = Input(Bool()) + val regs_write_address = Input(UInt(Parameters.PhysicalRegisterAddrWidth)) + val regs_write_source = Input(UInt(2.W)) + val reg1_data = Input(UInt(Parameters.DataWidth)) + val reg2_data = Input(UInt(Parameters.DataWidth)) + val immediate = Input(UInt(Parameters.DataWidth)) + val aluop1_source = Input(UInt(1.W)) + val aluop2_source = Input(UInt(1.W)) + val csr_write_enable = Input(Bool()) + val csr_address = Input(UInt(Parameters.CSRRegisterAddrWidth)) + val memory_read_enable = Input(Bool()) + val memory_write_enable = Input(Bool()) + val csr_read_data = Input(UInt(Parameters.DataWidth)) + + val output_instruction = Output(UInt(Parameters.DataWidth)) + val output_instruction_address = Output(UInt(Parameters.AddrWidth)) + val output_regs_write_enable = Output(Bool()) + val output_regs_write_address = Output(UInt(Parameters.PhysicalRegisterAddrWidth)) + val output_regs_write_source = Output(UInt(2.W)) + val output_reg1_data = Output(UInt(Parameters.DataWidth)) + val output_reg2_data = Output(UInt(Parameters.DataWidth)) + val output_immediate = Output(UInt(Parameters.DataWidth)) + val output_aluop1_source = Output(UInt(1.W)) + val output_aluop2_source = Output(UInt(1.W)) + val output_csr_write_enable = Output(Bool()) + val output_csr_address = Output(UInt(Parameters.CSRRegisterAddrWidth)) + val output_memory_read_enable = Output(Bool()) + val output_memory_write_enable = Output(Bool()) + val output_csr_read_data = Output(UInt(Parameters.DataWidth)) + }) + val write_enable = !io.stall_flag + + val instruction = Module(new PipelineRegister(defaultValue = InstructionsNop.nop)) + instruction.io.in := io.instruction + instruction.io.write_enable := write_enable + instruction.io.flush_enable := io.flush_enable + io.output_instruction := instruction.io.out + + val instruction_address = Module(new PipelineRegister(defaultValue = ProgramCounter.EntryAddress)) + instruction_address.io.in := io.instruction_address + instruction_address.io.write_enable := write_enable + instruction_address.io.flush_enable := io.flush_enable + io.output_instruction_address := instruction_address.io.out + + val regs_write_enable = Module(new PipelineRegister(1)) + regs_write_enable.io.in := io.regs_write_enable + regs_write_enable.io.write_enable := write_enable + regs_write_enable.io.flush_enable := io.flush_enable + io.output_regs_write_enable := regs_write_enable.io.out + + val regs_write_address = Module(new PipelineRegister(Parameters.PhysicalRegisterAddrBits)) + regs_write_address.io.in := io.regs_write_address + regs_write_address.io.write_enable := write_enable + regs_write_address.io.flush_enable := io.flush_enable + io.output_regs_write_address := regs_write_address.io.out + + val regs_write_source = Module(new PipelineRegister(2)) + regs_write_source.io.in := io.regs_write_source + regs_write_source.io.write_enable := write_enable + regs_write_source.io.flush_enable := io.flush_enable + io.output_regs_write_source := regs_write_source.io.out + + val reg1_data = Module(new PipelineRegister()) + reg1_data.io.in := io.reg1_data + reg1_data.io.write_enable := write_enable + reg1_data.io.flush_enable := io.flush_enable + io.output_reg1_data := reg1_data.io.out + + val reg2_data = Module(new PipelineRegister()) + reg2_data.io.in := io.reg2_data + reg2_data.io.write_enable := write_enable + reg2_data.io.flush_enable := io.flush_enable + io.output_reg2_data := reg2_data.io.out + + val immediate = Module(new PipelineRegister()) + immediate.io.in := io.immediate + immediate.io.write_enable := write_enable + immediate.io.flush_enable := io.flush_enable + io.output_immediate := immediate.io.out + + val aluop1_source = Module(new PipelineRegister(1)) + aluop1_source.io.in := io.aluop1_source + aluop1_source.io.write_enable := write_enable + aluop1_source.io.flush_enable := io.flush_enable + io.output_aluop1_source := aluop1_source.io.out + + val aluop2_source = Module(new PipelineRegister(1)) + aluop2_source.io.in := io.aluop2_source + aluop2_source.io.write_enable := write_enable + aluop2_source.io.flush_enable := io.flush_enable + io.output_aluop2_source := aluop2_source.io.out + + val csr_write_enable = Module(new PipelineRegister(1)) + csr_write_enable.io.in := io.csr_write_enable + csr_write_enable.io.write_enable := write_enable + csr_write_enable.io.flush_enable := io.flush_enable + io.output_csr_write_enable := csr_write_enable.io.out + + val csr_address = Module(new PipelineRegister(Parameters.CSRRegisterAddrBits)) + csr_address.io.in := io.csr_address + csr_address.io.write_enable := write_enable + csr_address.io.flush_enable := io.flush_enable + io.output_csr_address := csr_address.io.out + + val memory_read_enable = Module(new PipelineRegister(1)) + memory_read_enable.io.in := io.memory_read_enable + memory_read_enable.io.write_enable := write_enable + memory_read_enable.io.flush_enable := io.flush_enable + io.output_memory_read_enable := memory_read_enable.io.out + + val memory_write_enable = Module(new PipelineRegister(1)) + memory_write_enable.io.in := io.memory_write_enable + memory_write_enable.io.write_enable := write_enable + memory_write_enable.io.flush_enable := io.flush_enable + io.output_memory_write_enable := memory_write_enable.io.out + + val csr_read_data = Module(new PipelineRegister()) + csr_read_data.io.in := io.csr_read_data + csr_read_data.io.write_enable := write_enable + csr_read_data.io.flush_enable := io.flush_enable + io.output_csr_read_data := csr_read_data.io.out +} diff --git a/lab4/src/main/scala/riscv/core/fivestage/IF2ID.scala b/lab4/src/main/scala/riscv/core/fivestage/IF2ID.scala new file mode 100644 index 0000000..0413654 --- /dev/null +++ b/lab4/src/main/scala/riscv/core/fivestage/IF2ID.scala @@ -0,0 +1,52 @@ +// 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.core.fivestage + +import chisel3._ +import riscv.Parameters + +class IF2ID extends Module { + val io = IO(new Bundle { + val stall_flag = Input(Bool()) + val flush_enable = Input(Bool()) + val instruction = Input(UInt(Parameters.InstructionWidth)) + val instruction_address = Input(UInt(Parameters.AddrWidth)) + val interrupt_flag = Input(UInt(Parameters.InterruptFlagWidth)) + + val output_instruction = Output(UInt(Parameters.DataWidth)) + val output_instruction_address = Output(UInt(Parameters.AddrWidth)) + val output_interrupt_flag = Output(UInt(Parameters.InterruptFlagWidth)) + }) + + val write_enable = !io.stall_flag + + val instruction = Module(new PipelineRegister(defaultValue = InstructionsNop.nop)) + instruction.io.in := io.instruction + instruction.io.write_enable := write_enable + instruction.io.flush_enable := io.flush_enable + io.output_instruction := instruction.io.out + + val instruction_address = Module(new PipelineRegister(defaultValue = ProgramCounter.EntryAddress)) + instruction_address.io.in := io.instruction_address + instruction_address.io.write_enable := write_enable + instruction_address.io.flush_enable := io.flush_enable + io.output_instruction_address := instruction_address.io.out + + val interrupt_flag = Module(new PipelineRegister(Parameters.InterruptFlagBits)) + interrupt_flag.io.in := io.interrupt_flag + interrupt_flag.io.write_enable := write_enable + interrupt_flag.io.flush_enable := io.flush_enable + io.output_interrupt_flag := interrupt_flag.io.out +} diff --git a/lab4/src/main/scala/riscv/core/fivestage/InstructionDecode.scala b/lab4/src/main/scala/riscv/core/fivestage/InstructionDecode.scala new file mode 100644 index 0000000..3255ddb --- /dev/null +++ b/lab4/src/main/scala/riscv/core/fivestage/InstructionDecode.scala @@ -0,0 +1,238 @@ +// 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.core.fivestage + +import chisel3._ +import chisel3.util._ +import riscv.Parameters + +object InstructionTypes { + val L = "b0000011".U + val I = "b0010011".U + val S = "b0100011".U + val RM = "b0110011".U + val B = "b1100011".U +} + +object Instructions { + val lui = "b0110111".U + val nop = "b0000001".U + val jal = "b1101111".U + val jalr = "b1100111".U + val auipc = "b0010111".U + val csr = "b1110011".U + val fence = "b0001111".U +} + +object InstructionsTypeL { + val lb = "b000".U + val lh = "b001".U + val lw = "b010".U + val lbu = "b100".U + val lhu = "b101".U +} + +object InstructionsTypeI { + val addi = 0.U + val slli = 1.U + val slti = 2.U + val sltiu = 3.U + val xori = 4.U + val sri = 5.U + val ori = 6.U + val andi = 7.U +} + +object InstructionsTypeS { + val sb = "b000".U + val sh = "b001".U + val sw = "b010".U +} + +object InstructionsTypeR { + val add_sub = 0.U + val sll = 1.U + val slt = 2.U + val sltu = 3.U + val xor = 4.U + val sr = 5.U + val or = 6.U + val and = 7.U +} + +object InstructionsTypeM { + val mul = 0.U + val mulh = 1.U + val mulhsu = 2.U + val mulhum = 3.U + val div = 4.U + val divu = 5.U + val rem = 6.U + val remu = 7.U +} + +object InstructionsTypeB { + val beq = "b000".U + val bne = "b001".U + val blt = "b100".U + val bge = "b101".U + val bltu = "b110".U + val bgeu = "b111".U +} + +object InstructionsTypeCSR { + val csrrw = "b001".U + val csrrs = "b010".U + val csrrc = "b011".U + val csrrwi = "b101".U + val csrrsi = "b110".U + val csrrci = "b111".U +} + +object InstructionsNop { + val nop = 0x00000013L.U(Parameters.DataWidth) +} + +object InstructionsRet { + val mret = 0x30200073L.U(Parameters.DataWidth) + val ret = 0x00008067L.U(Parameters.DataWidth) +} + +object InstructionsEnv { + val ecall = 0x00000073L.U(Parameters.DataWidth) + val ebreak = 0x00100073L.U(Parameters.DataWidth) +} + +object ALUOp1Source { + val Register = 0.U(1.W) + val InstructionAddress = 1.U(1.W) +} + +object ALUOp2Source { + val Register = 0.U(1.W) + val Immediate = 1.U(1.W) +} + +object RegWriteSource { + val ALUResult = 0.U(2.W) + val Memory = 1.U(2.W) + val CSR = 2.U(2.W) + val NextInstructionAddress = 3.U(2.W) +} + +class InstructionDecode extends Module { + val io = IO(new Bundle { + val instruction = Input(UInt(Parameters.InstructionWidth)) + val instruction_address = Input(UInt(Parameters.AddrWidth)) + val reg1_data = Input(UInt(Parameters.DataWidth)) + val reg2_data = Input(UInt(Parameters.DataWidth)) + val interrupt_assert = Input(Bool()) + val interrupt_handler_address = Input(UInt(Parameters.AddrWidth)) + + val regs_reg1_read_address = Output(UInt(Parameters.PhysicalRegisterAddrWidth)) + val regs_reg2_read_address = Output(UInt(Parameters.PhysicalRegisterAddrWidth)) + val ex_reg1_data = Output(UInt(Parameters.DataWidth)) + val ex_reg2_data = Output(UInt(Parameters.DataWidth)) + val ex_immediate = Output(UInt(Parameters.DataWidth)) + val ex_aluop1_source = Output(UInt(1.W)) + val ex_aluop2_source = Output(UInt(1.W)) + val ex_memory_read_enable = Output(Bool()) + val ex_memory_write_enable = Output(Bool()) + val ex_reg_write_source = Output(UInt(2.W)) + val ex_reg_write_enable = Output(Bool()) + val ex_reg_write_address = Output(UInt(Parameters.PhysicalRegisterAddrWidth)) + val ex_csr_address = Output(UInt(Parameters.CSRRegisterAddrWidth)) + val ex_csr_write_enable = Output(Bool()) + val if_jump_flag = Output(Bool()) + val if_jump_address = Output(UInt(Parameters.AddrWidth)) + }) + val opcode = io.instruction(6, 0) + val funct3 = io.instruction(14, 12) + val funct7 = io.instruction(31, 25) + val rd = io.instruction(11, 7) + val rs1 = io.instruction(19, 15) + val rs2 = io.instruction(24, 20) + + io.regs_reg1_read_address := Mux(opcode === Instructions.lui, 0.U(Parameters.PhysicalRegisterAddrWidth), rs1) + io.regs_reg2_read_address := rs2 + io.ex_reg1_data := io.reg1_data + io.ex_reg2_data := io.reg2_data + val immediate = MuxLookup( + opcode, + Cat(Fill(20, io.instruction(31)), io.instruction(31, 20)), + IndexedSeq( + InstructionTypes.I -> Cat(Fill(21, io.instruction(31)), io.instruction(30, 20)), + InstructionTypes.L -> Cat(Fill(21, io.instruction(31)), io.instruction(30, 20)), + Instructions.jalr -> Cat(Fill(21, io.instruction(31)), io.instruction(30, 20)), + InstructionTypes.S -> Cat(Fill(21, io.instruction(31)), io.instruction(30, 25), io.instruction(11, 7)), + InstructionTypes.B -> Cat(Fill(20, io.instruction(31)), io.instruction(7), io.instruction(30, 25), io.instruction(11, 8), 0.U(1.W)), + Instructions.lui -> Cat(io.instruction(31, 12), 0.U(12.W)), + Instructions.auipc -> Cat(io.instruction(31, 12), 0.U(12.W)), + Instructions.jal -> Cat(Fill(12, io.instruction(31)), io.instruction(19, 12), io.instruction(20), io.instruction(30, 21), 0.U(1.W)) + ) + ) + io.ex_immediate := immediate + io.ex_aluop1_source := Mux( + opcode === Instructions.auipc || opcode === InstructionTypes.B || opcode === Instructions.jal, + ALUOp1Source.InstructionAddress, + ALUOp1Source.Register + ) + io.ex_aluop2_source := Mux( + opcode === InstructionTypes.RM, + ALUOp2Source.Register, + ALUOp2Source.Immediate + ) + io.ex_memory_read_enable := opcode === InstructionTypes.L + io.ex_memory_write_enable := opcode === InstructionTypes.S + io.ex_reg_write_source := MuxLookup( + opcode, + RegWriteSource.ALUResult, + IndexedSeq( + InstructionTypes.L -> RegWriteSource.Memory, + Instructions.csr -> RegWriteSource.CSR, + Instructions.jal -> RegWriteSource.NextInstructionAddress, + Instructions.jalr -> RegWriteSource.NextInstructionAddress + ) + ) + io.ex_reg_write_enable := (opcode === InstructionTypes.RM) || (opcode === InstructionTypes.I) || + (opcode === InstructionTypes.L) || (opcode === Instructions.auipc) || (opcode === Instructions.lui) || + (opcode === Instructions.jal) || (opcode === Instructions.jalr) || (opcode === Instructions.csr) + io.ex_reg_write_address := io.instruction(11, 7) + io.ex_csr_address := io.instruction(31, 20) + io.ex_csr_write_enable := (opcode === Instructions.csr) && ( + funct3 === InstructionsTypeCSR.csrrw || funct3 === InstructionsTypeCSR.csrrwi || + funct3 === InstructionsTypeCSR.csrrs || funct3 === InstructionsTypeCSR.csrrsi || + funct3 === InstructionsTypeCSR.csrrc || funct3 === InstructionsTypeCSR.csrrci + ) + io.if_jump_flag := io.interrupt_assert || + (opcode === Instructions.jal) || + (opcode === Instructions.jalr) || + (opcode === InstructionTypes.B) && MuxLookup( + funct3, + false.B, + IndexedSeq( + InstructionsTypeB.beq -> (io.reg1_data === io.reg2_data), + InstructionsTypeB.bne -> (io.reg1_data =/= io.reg2_data), + InstructionsTypeB.blt -> (io.reg1_data.asSInt < io.reg2_data.asSInt), + InstructionsTypeB.bge -> (io.reg1_data.asSInt >= io.reg2_data.asSInt), + InstructionsTypeB.bltu -> (io.reg1_data.asUInt < io.reg2_data.asUInt), + InstructionsTypeB.bgeu -> (io.reg1_data.asUInt >= io.reg2_data.asUInt) + ) + ) + io.if_jump_address := Mux(io.interrupt_assert, + io.interrupt_handler_address, + io.ex_immediate + Mux(opcode === Instructions.jalr, io.reg1_data, io.instruction_address) + ) +} diff --git a/lab4/src/main/scala/riscv/core/fivestage/InstructionFetch.scala b/lab4/src/main/scala/riscv/core/fivestage/InstructionFetch.scala new file mode 100644 index 0000000..6c32088 --- /dev/null +++ b/lab4/src/main/scala/riscv/core/fivestage/InstructionFetch.scala @@ -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.core.fivestage + +import chisel3._ +import chisel3.util.MuxCase +import riscv.Parameters + +object ProgramCounter { + val EntryAddress = Parameters.EntryAddress +} + +class InstructionFetch extends Module { + val io = IO(new Bundle { + val stall_flag_ctrl = Input(Bool()) + val jump_flag_id = Input(Bool()) + val jump_address_id = Input(UInt(Parameters.AddrWidth)) + val instruction_valid = Input(Bool()) + + val bus_request = Output(Bool()) + val bus_address = Output(UInt(Parameters.AddrWidth)) + val bus_data = Input(UInt(Parameters.InstructionWidth)) + val bus_read = Output(Bool()) + + val ctrl_stall_flag = Output(Bool()) + val id_instruction_address = Output(UInt(Parameters.AddrWidth)) + val id_instruction = Output(UInt(Parameters.InstructionWidth)) + }) + val pending_jump = RegInit(false.B) + val pc = RegInit(ProgramCounter.EntryAddress) + io.bus_read := true.B + io.bus_request := true.B + + pc := MuxCase( + pc + 4.U, + IndexedSeq( + io.jump_flag_id -> io.jump_address_id, + io.stall_flag_ctrl -> pc + ) + ) + when(!io.instruction_valid) { + when(io.jump_flag_id) { + pending_jump := true.B + } + } + when(io.instruction_valid) { + when(pending_jump) { + pending_jump := false.B + } + } + io.id_instruction := Mux(io.instruction_valid && !io.jump_flag_id && !pending_jump, io.bus_data, + InstructionsNop.nop) + io.ctrl_stall_flag := !io.instruction_valid || pending_jump + io.id_instruction_address := pc + io.bus_address := pc +} diff --git a/lab4/src/main/scala/riscv/core/fivestage/MEM2WB.scala b/lab4/src/main/scala/riscv/core/fivestage/MEM2WB.scala new file mode 100644 index 0000000..eba0938 --- /dev/null +++ b/lab4/src/main/scala/riscv/core/fivestage/MEM2WB.scala @@ -0,0 +1,82 @@ +// Copyright 2022 Canbin Huang +// +// 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.core.fivestage + +import chisel3._ +import riscv.Parameters + +class MEM2WB extends Module { + val io = IO(new Bundle() { + val instruction_address = Input(UInt(Parameters.AddrWidth)) + val alu_result = Input(UInt(Parameters.DataWidth)) + val regs_write_enable = Input(Bool()) + val regs_write_source = Input(UInt(2.W)) + val regs_write_address = Input(UInt(Parameters.AddrWidth)) + val memory_read_data = Input(UInt(Parameters.DataWidth)) + val csr_read_data = Input(UInt(Parameters.DataWidth)) + + val output_instruction_address = Output(UInt(Parameters.AddrWidth)) + val output_alu_result = Output(UInt(Parameters.DataWidth)) + val output_regs_write_enable = Output(Bool()) + val output_regs_write_source = Output(UInt(2.W)) + val output_regs_write_address = Output(UInt(Parameters.AddrWidth)) + val output_memory_read_data = Output(UInt(Parameters.DataWidth)) + val output_csr_read_data = Output(UInt(Parameters.DataWidth)) + }) + val flush_enable = false.B + val write_enable = true.B + + val alu_result = Module(new PipelineRegister()) + alu_result.io.in := io.alu_result + alu_result.io.write_enable := write_enable + alu_result.io.flush_enable := flush_enable + io.output_alu_result := alu_result.io.out + + val memory_read_data = Module(new PipelineRegister()) + memory_read_data.io.in := io.memory_read_data + memory_read_data.io.write_enable := write_enable + memory_read_data.io.flush_enable := flush_enable + io.output_memory_read_data := memory_read_data.io.out + + val regs_write_enable = Module(new PipelineRegister(1)) + regs_write_enable.io.in := io.regs_write_enable + regs_write_enable.io.write_enable := write_enable + regs_write_enable.io.flush_enable := flush_enable + io.output_regs_write_enable := regs_write_enable.io.out + + val regs_write_source = Module(new PipelineRegister(2)) + regs_write_source.io.in := io.regs_write_source + regs_write_source.io.write_enable := write_enable + regs_write_source.io.flush_enable := flush_enable + io.output_regs_write_source := regs_write_source.io.out + + val regs_write_address = Module(new PipelineRegister(Parameters.PhysicalRegisterAddrBits)) + regs_write_address.io.in := io.regs_write_address + regs_write_address.io.write_enable := write_enable + regs_write_address.io.flush_enable := flush_enable + io.output_regs_write_address := regs_write_address.io.out + + val instruction_address = Module(new PipelineRegister(Parameters.InstructionBits)) + instruction_address.io.in := io.instruction_address + instruction_address.io.write_enable := write_enable + instruction_address.io.flush_enable := flush_enable + io.output_instruction_address := instruction_address.io.out + + val csr_read_data = Module(new PipelineRegister()) + csr_read_data.io.in := io.csr_read_data + csr_read_data.io.write_enable := write_enable + csr_read_data.io.flush_enable := flush_enable + io.output_csr_read_data := csr_read_data.io.out +} diff --git a/lab4/src/main/scala/riscv/core/fivestage/MemoryAccess.scala b/lab4/src/main/scala/riscv/core/fivestage/MemoryAccess.scala new file mode 100644 index 0000000..a3377ee --- /dev/null +++ b/lab4/src/main/scala/riscv/core/fivestage/MemoryAccess.scala @@ -0,0 +1,151 @@ +// Copyright 2022 Canbin Huang +// +// 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.core.fivestage + +import chisel3._ +import chisel3.util._ +import riscv.Parameters +import riscv.core.BusBundle + +class MemoryAccess extends Module { + val io = IO(new Bundle() { + val alu_result = Input(UInt(Parameters.DataWidth)) + val reg2_data = Input(UInt(Parameters.DataWidth)) + val memory_read_enable = Input(Bool()) + val memory_write_enable = Input(Bool()) + val funct3 = Input(UInt(3.W)) + val regs_write_source = Input(UInt(2.W)) + val csr_read_data = Input(UInt(Parameters.DataWidth)) + + val wb_memory_read_data = Output(UInt(Parameters.DataWidth)) + val ctrl_stall_flag = Output(Bool()) + val forward_to_ex = Output(UInt(Parameters.DataWidth)) + + val bus = new BusBundle + }) + val mem_address_index = io.alu_result(log2Up(Parameters.WordSize) - 1, 0).asUInt + val mem_access_state = RegInit(MemoryAccessStates.Idle) + + def on_bus_transaction_finished() = { + mem_access_state := MemoryAccessStates.Idle + io.ctrl_stall_flag := false.B + } + + io.bus.request := false.B + io.bus.read := false.B + io.bus.address := io.alu_result(Parameters.AddrBits - 1, log2Up(Parameters.WordSize)) ## 0.U(log2Up(Parameters.WordSize).W) + io.bus.write_data := 0.U + io.bus.write_strobe := VecInit(Seq.fill(Parameters.WordSize)(false.B)) + io.bus.write := false.B + io.wb_memory_read_data := 0.U + io.ctrl_stall_flag := false.B + + when(io.memory_read_enable) { + when(mem_access_state === MemoryAccessStates.Idle) { + // Start the read transaction when the bus is available + io.ctrl_stall_flag := true.B + io.bus.read := true.B + io.bus.request := true.B + when(io.bus.granted) { + mem_access_state := MemoryAccessStates.Read + } + }.elsewhen(mem_access_state === MemoryAccessStates.Read) { + io.bus.request := true.B + io.bus.read := false.B + io.ctrl_stall_flag := true.B + when(io.bus.read_valid) { + val data = io.bus.read_data + io.wb_memory_read_data := MuxLookup( + io.funct3, + 0.U, + IndexedSeq( + InstructionsTypeL.lb -> MuxLookup( + mem_address_index, + Cat(Fill(24, data(31)), data(31, 24)), + IndexedSeq( + 0.U -> Cat(Fill(24, data(7)), data(7, 0)), + 1.U -> Cat(Fill(24, data(15)), data(15, 8)), + 2.U -> Cat(Fill(24, data(23)), data(23, 16)) + ) + ), + InstructionsTypeL.lbu -> MuxLookup( + mem_address_index, + Cat(Fill(24, 0.U), data(31, 24)), + IndexedSeq( + 0.U -> Cat(Fill(24, 0.U), data(7, 0)), + 1.U -> Cat(Fill(24, 0.U), data(15, 8)), + 2.U -> Cat(Fill(24, 0.U), data(23, 16)) + ) + ), + InstructionsTypeL.lh -> Mux( + mem_address_index === 0.U, + Cat(Fill(16, data(15)), data(15, 0)), + Cat(Fill(16, data(31)), data(31, 16)) + ), + InstructionsTypeL.lhu -> Mux( + mem_address_index === 0.U, + Cat(Fill(16, 0.U), data(15, 0)), + Cat(Fill(16, 0.U), data(31, 16)) + ), + InstructionsTypeL.lw -> data + ) + ) + on_bus_transaction_finished() + } + } + }.elsewhen(io.memory_write_enable) { + when(mem_access_state === MemoryAccessStates.Idle) { + // Start the write transaction when there the bus is available + io.ctrl_stall_flag := true.B + io.bus.write_data := io.reg2_data + io.bus.write := true.B + io.bus.write_strobe := VecInit(Seq.fill(Parameters.WordSize)(false.B)) + when(io.funct3 === InstructionsTypeS.sb) { + io.bus.write_strobe(mem_address_index) := true.B + io.bus.write_data := io.reg2_data(Parameters.ByteBits, 0) << (mem_address_index << log2Up(Parameters.ByteBits).U) + }.elsewhen(io.funct3 === InstructionsTypeS.sh) { + when(mem_address_index === 0.U) { + for (i <- 0 until Parameters.WordSize / 2) { + io.bus.write_strobe(i) := true.B + } + io.bus.write_data := io.reg2_data(Parameters.WordSize / 2 * Parameters.ByteBits, 0) + }.otherwise { + for (i <- Parameters.WordSize / 2 until Parameters.WordSize) { + io.bus.write_strobe(i) := true.B + } + io.bus.write_data := io.reg2_data(Parameters.WordSize / 2 * Parameters.ByteBits, 0) << (Parameters + .WordSize / 2 * Parameters.ByteBits) + } + }.elsewhen(io.funct3 === InstructionsTypeS.sw) { + for (i <- 0 until Parameters.WordSize) { + io.bus.write_strobe(i) := true.B + } + } + io.bus.request := true.B + when(io.bus.granted) { + mem_access_state := MemoryAccessStates.Write + } + }.elsewhen(mem_access_state === MemoryAccessStates.Write) { + io.bus.request := true.B + io.ctrl_stall_flag := true.B + io.bus.write := false.B + when(io.bus.write_valid) { + on_bus_transaction_finished() + } + } + } + + io.forward_to_ex := Mux(io.regs_write_source === RegWriteSource.CSR, io.csr_read_data, io.alu_result) +} diff --git a/lab4/src/main/scala/riscv/core/fivestage/PipelineRegister.scala b/lab4/src/main/scala/riscv/core/fivestage/PipelineRegister.scala new file mode 100644 index 0000000..2dd5142 --- /dev/null +++ b/lab4/src/main/scala/riscv/core/fivestage/PipelineRegister.scala @@ -0,0 +1,35 @@ +// 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.core.fivestage + +import chisel3._ +import riscv.Parameters + +class PipelineRegister(width: Int = Parameters.DataBits, defaultValue: UInt = 0.U) extends Module { + val io = IO(new Bundle { + val write_enable = Input(Bool()) + val flush_enable = Input(Bool()) + val in = Input(UInt(width.W)) + val out = Output(UInt(width.W)) + }) + + val reg = RegInit(UInt(width.W), defaultValue) + when(io.write_enable) { + reg := io.in + }.elsewhen(io.flush_enable) { + reg := defaultValue + } + io.out := reg +} diff --git a/lab4/src/main/scala/riscv/core/fivestage/RegisterFile.scala b/lab4/src/main/scala/riscv/core/fivestage/RegisterFile.scala new file mode 100644 index 0000000..e21d395 --- /dev/null +++ b/lab4/src/main/scala/riscv/core/fivestage/RegisterFile.scala @@ -0,0 +1,78 @@ +// 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.core.fivestage + +import chisel3._ +import chisel3.util._ +import riscv.Parameters + +object Registers extends Enumeration { + type Register = Value + val zero, + ra, sp, gp, tp, + t0, t1, t2, fp, + s1, + a0, a1, a2, a3, a4, a5, a6, a7, + s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, + t3, t4, t5, t6 = Value +} + +class RegisterFile extends Module { + val io = IO(new Bundle { + val write_enable = Input(Bool()) + val write_address = Input(UInt(Parameters.PhysicalRegisterAddrWidth)) + val write_data = Input(UInt(Parameters.DataWidth)) + + val read_address1 = Input(UInt(Parameters.PhysicalRegisterAddrWidth)) + val read_address2 = Input(UInt(Parameters.PhysicalRegisterAddrWidth)) + val read_data1 = Output(UInt(Parameters.DataWidth)) + val read_data2 = Output(UInt(Parameters.DataWidth)) + + val debug_read_address = Input(UInt(Parameters.PhysicalRegisterAddrWidth)) + val debug_read_data = Output(UInt(Parameters.DataWidth)) + }) + val registers = Reg(Vec(Parameters.PhysicalRegisters, UInt(Parameters.DataWidth))) + + when(!reset.asBool) { + when(io.write_enable && io.write_address =/= 0.U) { + registers(io.write_address) := io.write_data + } + } + + io.read_data1 := MuxCase( + registers(io.read_address1), + IndexedSeq( + (io.read_address1 === 0.U) -> 0.U, + (io.read_address1 === io.write_address && io.write_enable) -> io.write_data + ) + ) + + io.read_data2 := MuxCase( + registers(io.read_address2), + IndexedSeq( + (io.read_address2 === 0.U) -> 0.U, + (io.read_address2 === io.write_address && io.write_enable) -> io.write_data + ) + ) + + io.debug_read_data := MuxCase( + registers(io.debug_read_address), + IndexedSeq( + (io.debug_read_address === 0.U) -> 0.U, + (io.debug_read_address === io.write_address && io.write_enable) -> io.write_data + ) + ) + +} diff --git a/lab4/src/main/scala/riscv/core/fivestage/WriteBack.scala b/lab4/src/main/scala/riscv/core/fivestage/WriteBack.scala new file mode 100644 index 0000000..d935168 --- /dev/null +++ b/lab4/src/main/scala/riscv/core/fivestage/WriteBack.scala @@ -0,0 +1,40 @@ +// Copyright 2022 Canbin Huang +// +// 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.core.fivestage + +import chisel3._ +import chisel3.util._ +import riscv.Parameters + +class WriteBack extends Module { + val io = IO(new Bundle() { + val instruction_address = Input(UInt(Parameters.AddrWidth)) + val alu_result = Input(UInt(Parameters.DataWidth)) + val memory_read_data = Input(UInt(Parameters.DataWidth)) + val regs_write_source = Input(UInt(2.W)) + val csr_read_data = Input(UInt(Parameters.DataWidth)) + + val regs_write_data = Output(UInt(Parameters.DataWidth)) + }) + io.regs_write_data := MuxLookup( + io.regs_write_source, + io.alu_result, + IndexedSeq( + RegWriteSource.Memory -> io.memory_read_data, + RegWriteSource.CSR -> io.csr_read_data, + RegWriteSource.NextInstructionAddress -> (io.instruction_address + 4.U) + ) + ) +} diff --git a/lab4/src/main/scala/riscv/core/threestage/ALU.scala b/lab4/src/main/scala/riscv/core/threestage/ALU.scala new file mode 100644 index 0000000..11c66f6 --- /dev/null +++ b/lab4/src/main/scala/riscv/core/threestage/ALU.scala @@ -0,0 +1,67 @@ +// 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.core.threestage + +import chisel3._ +import chisel3.experimental.ChiselEnum +import chisel3.util._ +import riscv.Parameters + +object ALUFunctions extends ChiselEnum { + val zero, add, sub, sll, slt, xor, or, and, sr, sltu = Value +} + +class ALU extends Module { + val io = IO(new Bundle { + val func = Input(ALUFunctions()) + + val op1 = Input(UInt(Parameters.DataWidth)) + val op2 = Input(UInt(Parameters.DataWidth)) + + val result = Output(UInt(Parameters.DataWidth)) + }) + + io.result := 0.U + switch(io.func) { + is(ALUFunctions.add) { + io.result := io.op1 + io.op2 + } + is(ALUFunctions.sub) { + io.result := io.op1 - io.op2 + } + is(ALUFunctions.sll) { + io.result := io.op1 << io.op2(4, 0) + } + is(ALUFunctions.slt) { + io.result := io.op1.asSInt < io.op2.asSInt + } + is(ALUFunctions.xor) { + io.result := io.op1 ^ io.op2 + } + is(ALUFunctions.or) { + io.result := io.op1 | io.op2 + } + is(ALUFunctions.and) { + io.result := io.op1 & io.op2 + } + is(ALUFunctions.sr) { + io.result := io.op1 >> io.op2(4, 0) + } + is(ALUFunctions.sltu) { + io.result := io.op1 < io.op2 + } + } + +} diff --git a/lab4/src/main/scala/riscv/core/threestage/ALUControl.scala b/lab4/src/main/scala/riscv/core/threestage/ALUControl.scala new file mode 100644 index 0000000..0d79b19 --- /dev/null +++ b/lab4/src/main/scala/riscv/core/threestage/ALUControl.scala @@ -0,0 +1,77 @@ +// 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.core.threestage + +import chisel3._ +import chisel3.util._ + +class ALUControl extends Module { + val io = IO(new Bundle { + val opcode = Input(UInt(7.W)) + val funct3 = Input(UInt(3.W)) + val funct7 = Input(UInt(7.W)) + + val alu_funct = Output(ALUFunctions()) + }) + + io.alu_funct := ALUFunctions.zero + + switch(io.opcode) { + is(InstructionTypes.I) { + io.alu_funct := MuxLookup( + io.funct3, + ALUFunctions.zero, + IndexedSeq( + InstructionsTypeI.addi -> ALUFunctions.add, + InstructionsTypeI.slli -> ALUFunctions.sll, + InstructionsTypeI.slti -> ALUFunctions.slt, + InstructionsTypeI.sltiu -> ALUFunctions.sltu, + InstructionsTypeI.xori -> ALUFunctions.xor, + InstructionsTypeI.ori -> ALUFunctions.or, + InstructionsTypeI.andi -> ALUFunctions.and, + InstructionsTypeI.sri -> ALUFunctions.sr, + ), + ) + } + is(InstructionTypes.RM) { + io.alu_funct := MuxLookup( + io.funct3, + ALUFunctions.zero, + IndexedSeq( + InstructionsTypeR.add_sub -> Mux(io.funct7(5), ALUFunctions.sub, ALUFunctions.add), + InstructionsTypeR.sll -> ALUFunctions.sll, + InstructionsTypeR.slt -> ALUFunctions.slt, + InstructionsTypeR.sltu -> ALUFunctions.sltu, + InstructionsTypeR.xor -> ALUFunctions.xor, + InstructionsTypeR.or -> ALUFunctions.or, + InstructionsTypeR.and -> ALUFunctions.and, + InstructionsTypeR.sr -> ALUFunctions.sr, + ), + ) + } + is(Instructions.jal) { + io.alu_funct := ALUFunctions.add + } + is(Instructions.jalr) { + io.alu_funct := ALUFunctions.add + } + is(Instructions.lui) { + io.alu_funct := ALUFunctions.add + } + is(Instructions.auipc) { + io.alu_funct := ALUFunctions.add + } + } +} diff --git a/lab4/src/main/scala/riscv/core/threestage/CLINT.scala b/lab4/src/main/scala/riscv/core/threestage/CLINT.scala new file mode 100644 index 0000000..7ebed6b --- /dev/null +++ b/lab4/src/main/scala/riscv/core/threestage/CLINT.scala @@ -0,0 +1,183 @@ +// 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.core.threestage + +import chisel3._ +import chisel3.util._ +import riscv.Parameters + +object InterruptStatus { + val None = 0x0.U(8.W) + val Timer0 = 0x1.U(8.W) + val Ret = 0xFF.U(8.W) +} + +object InterruptEntry { + val Timer0 = 0x4.U(8.W) +} + +object InterruptState { + val Idle = 0x0.U + val SyncAssert = 0x1.U + val AsyncAssert = 0x2.U + val MRET = 0x3.U +} + +object CSRState { + val Idle = 0x0.U + val MSTATUS = 0x1.U + val MEPC = 0x2.U + val MRET = 0x3.U + val MCAUSE = 0x4.U +} + +// Core Local Interrupt Controller +class CLINT extends Module { + val io = IO(new Bundle { + // Interrupt signals from peripherals + val interrupt_flag = Input(UInt(Parameters.InterruptFlagWidth)) + + // Current instruction from instruction decode + val instruction = Input(UInt(Parameters.InstructionWidth)) + val instruction_address_id = Input(UInt(Parameters.AddrWidth)) + + val jump_flag = Input(Bool()) + val jump_address = Input(UInt(Parameters.AddrWidth)) + + val csr_mtvec = Input(UInt(Parameters.DataWidth)) + val csr_mepc = Input(UInt(Parameters.DataWidth)) + val csr_mstatus = Input(UInt(Parameters.DataWidth)) + + // Is global interrupt enabled (from MSTATUS)? + val interrupt_enable = Input(Bool()) + + val ctrl_stall_flag = Output(Bool()) + + val csr_reg_write_enable = Output(Bool()) + val csr_reg_write_address = Output(UInt(Parameters.CSRRegisterAddrWidth)) + val csr_reg_write_data = Output(UInt(Parameters.DataWidth)) + + val ex_interrupt_handler_address = Output(UInt(Parameters.AddrWidth)) + val ex_interrupt_assert = Output(Bool()) + }) + + val interrupt_state = WireInit(0.U) + val csr_state = RegInit(CSRState.Idle) + val instruction_address = RegInit(UInt(Parameters.AddrWidth), 0.U) + val cause = RegInit(UInt(Parameters.DataWidth), 0.U) + val interrupt_assert = RegInit(Bool(), false.B) + val interrupt_handler_address = RegInit(UInt(Parameters.AddrWidth), 0.U) + val csr_reg_write_enable = RegInit(Bool(), false.B) + val csr_reg_write_address = RegInit(UInt(Parameters.CSRRegisterAddrWidth), 0.U) + val csr_reg_write_data = RegInit(UInt(Parameters.DataWidth), 0.U) + + io.ctrl_stall_flag := interrupt_state =/= InterruptState.Idle || csr_state =/= CSRState.Idle + + // Interrupt FSM + when(io.instruction === InstructionsEnv.ecall || io.instruction === InstructionsEnv.ebreak) { + interrupt_state := InterruptState.SyncAssert + }.elsewhen(io.interrupt_flag =/= InterruptStatus.None && io.interrupt_enable) { + interrupt_state := InterruptState.AsyncAssert + }.elsewhen(io.instruction === InstructionsRet.mret) { + interrupt_state := InterruptState.MRET + }.otherwise { + interrupt_state := InterruptState.Idle + } + + // CSR FSM + when(csr_state === CSRState.Idle) { + when(interrupt_state === InterruptState.SyncAssert) { + // Synchronous Interrupt + csr_state := CSRState.MEPC + instruction_address := Mux( + io.jump_flag, + io.jump_address - 4.U, + io.instruction_address_id + ) + + cause := MuxLookup( + io.instruction, + 10.U, + IndexedSeq( + InstructionsEnv.ecall -> 11.U, + InstructionsEnv.ebreak -> 3.U, + ) + ) + }.elsewhen(interrupt_state === InterruptState.AsyncAssert) { + // Asynchronous Interrupt + cause := 0x8000000BL.U + when(io.interrupt_flag(0)) { + cause := 0x80000007L.U + } + csr_state := CSRState.MEPC + instruction_address := Mux( + io.jump_flag, + io.jump_address, + io.instruction_address_id, + ) + }.elsewhen(interrupt_state === InterruptState.MRET) { + // Interrupt Return + csr_state := CSRState.MRET + } + }.elsewhen(csr_state === CSRState.MEPC) { + csr_state := CSRState.MSTATUS + }.elsewhen(csr_state === CSRState.MSTATUS) { + csr_state := CSRState.MCAUSE + }.elsewhen(csr_state === CSRState.MCAUSE) { + csr_state := CSRState.Idle + }.elsewhen(csr_state === CSRState.MRET) { + csr_state := CSRState.Idle + }.otherwise { + csr_state := CSRState.Idle + } + + csr_reg_write_enable := csr_state =/= CSRState.Idle + csr_reg_write_address := Cat(Fill(20, 0.U(1.W)), MuxLookup( + csr_state, + 0.U(Parameters.CSRRegisterAddrWidth), + IndexedSeq( + CSRState.MEPC -> CSRRegister.MEPC, + CSRState.MCAUSE -> CSRRegister.MCAUSE, + CSRState.MSTATUS -> CSRRegister.MSTATUS, + CSRState.MRET -> CSRRegister.MSTATUS, + ) + )) + csr_reg_write_data := MuxLookup( + csr_state, + 0.U(Parameters.DataWidth), + IndexedSeq( + CSRState.MEPC -> instruction_address, + CSRState.MCAUSE -> cause, + CSRState.MSTATUS -> Cat(io.csr_mstatus(31, 4), 0.U(1.W), io.csr_mstatus(2, 0)), + CSRState.MRET -> Cat(io.csr_mstatus(31, 4), io.csr_mstatus(7), io.csr_mstatus(2, 0)), + ) + ) + io.csr_reg_write_enable := csr_reg_write_enable + io.csr_reg_write_address := csr_reg_write_address + io.csr_reg_write_data := csr_reg_write_data + + interrupt_assert := csr_state === CSRState.MCAUSE || csr_state === CSRState.MRET + interrupt_handler_address := MuxLookup( + csr_state, + 0.U(Parameters.AddrWidth), + IndexedSeq( + CSRState.MCAUSE -> io.csr_mtvec, + CSRState.MRET -> io.csr_mepc, + ) + ) + + io.ex_interrupt_assert := interrupt_assert + io.ex_interrupt_handler_address := interrupt_handler_address +} diff --git a/lab4/src/main/scala/riscv/core/threestage/CPU.scala b/lab4/src/main/scala/riscv/core/threestage/CPU.scala new file mode 100644 index 0000000..76e0777 --- /dev/null +++ b/lab4/src/main/scala/riscv/core/threestage/CPU.scala @@ -0,0 +1,167 @@ +// 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.core.threestage + +import bus.{AXI4LiteChannels, AXI4LiteMaster} +import chisel3._ +import riscv.Parameters +import riscv.core.CPUBundle + +class CPU extends Module { + val io = IO(new CPUBundle) + + val ctrl = Module(new Control) + val regs = Module(new RegisterFile) + val inst_fetch = Module(new InstructionFetch) + val if2id = Module(new IF2ID) + val id = Module(new InstructionDecode) + val id2ex = Module(new ID2EX) + val ex = Module(new Execute) + val clint = Module(new CLINT) + val csr_regs = Module(new CSR) + val axi4_master = Module(new AXI4LiteMaster(Parameters.AddrBits, Parameters.DataBits)) + + axi4_master.io.channels <> io.axi4_channels + io.debug(0) := ex.io.reg1_data + io.debug(1) := ex.io.reg2_data + io.debug(2) := ex.io.instruction_address + io.debug(3) := ex.io.instruction + io.debug(4) := ex.io.ctrl_jump_flag + io.debug(5) := ex.io.ctrl_jump_address + io.bus_busy := axi4_master.io.bundle.busy + + // The EX module takes precedence over IF (but let the previous fetch finish) + val ex_granted = RegInit(false.B) + when(ex_granted) { + inst_fetch.io.instruction_valid := false.B + io.bus_address := ex.io.bus.address + axi4_master.io.bundle.read := ex.io.bus.read + axi4_master.io.bundle.address := ex.io.bus.address + axi4_master.io.bundle.write := ex.io.bus.write + axi4_master.io.bundle.write_data := ex.io.bus.write_data + axi4_master.io.bundle.write_strobe := ex.io.bus.write_strobe + when(!ex.io.bus.request) { + ex_granted := false.B + } + }.otherwise { + // Default to fetch instructions from main memory + ex_granted := false.B + axi4_master.io.bundle.read := !axi4_master.io.bundle.busy && !axi4_master.io.bundle.read_valid && !ex.io.bus.request + axi4_master.io.bundle.address := inst_fetch.io.bus_address + io.bus_address := inst_fetch.io.bus_address + axi4_master.io.bundle.write := false.B + axi4_master.io.bundle.write_data := 0.U + axi4_master.io.bundle.write_strobe := VecInit(Seq.fill(Parameters.WordSize)(false.B)) + } + + when(ex.io.bus.request) { + when(!axi4_master.io.bundle.busy && !axi4_master.io.bundle.read_valid) { + ex_granted := true.B + } + } + + inst_fetch.io.instruction_valid := io.instruction_valid && axi4_master.io.bundle.read_valid && !ex_granted + inst_fetch.io.bus_data := axi4_master.io.bundle.read_data + + ex.io.bus.read_data := axi4_master.io.bundle.read_data + ex.io.bus.read_valid := axi4_master.io.bundle.read_valid + ex.io.bus.write_valid := axi4_master.io.bundle.write_valid + ex.io.bus.busy := axi4_master.io.bundle.busy + ex.io.bus.granted := ex_granted + + ctrl.io.jump_flag := ex.io.ctrl_jump_flag + ctrl.io.jump_address := ex.io.ctrl_jump_address + ctrl.io.stall_flag_if := inst_fetch.io.ctrl_stall_flag + ctrl.io.stall_flag_ex := ex.io.ctrl_stall_flag + ctrl.io.stall_flag_id := id.io.ctrl_stall_flag + ctrl.io.stall_flag_clint := clint.io.ctrl_stall_flag + ctrl.io.stall_flag_bus := io.stall_flag_bus + + regs.io.write_enable := ex.io.regs_write_enable + regs.io.write_address := ex.io.regs_write_address + regs.io.write_data := ex.io.regs_write_data + regs.io.read_address1 := id.io.regs_reg1_read_address + regs.io.read_address2 := id.io.regs_reg2_read_address + + regs.io.debug_read_address := io.debug_read_address + io.debug_read_data := regs.io.debug_read_data + + inst_fetch.io.jump_flag_ctrl := ctrl.io.pc_jump_flag + inst_fetch.io.jump_address_ctrl := ctrl.io.pc_jump_address + inst_fetch.io.stall_flag_ctrl := ctrl.io.output_stall_flag + + if2id.io.instruction := inst_fetch.io.id_instruction + if2id.io.instruction_address := inst_fetch.io.id_instruction_address + if2id.io.stall_flag := ctrl.io.output_stall_flag + if2id.io.jump_flag := ctrl.io.pc_jump_flag + if2id.io.interrupt_flag := io.interrupt_flag + + id.io.reg1_data := regs.io.read_data1 + id.io.reg2_data := regs.io.read_data2 + id.io.instruction := if2id.io.output_instruction + id.io.instruction_address := if2id.io.output_instruction_address + id.io.csr_read_data := csr_regs.io.id_reg_data + + id2ex.io.instruction := id.io.ex_instruction + id2ex.io.instruction_address := id.io.ex_instruction_address + id2ex.io.csr_read_data := id.io.ex_csr_read_data + id2ex.io.csr_write_enable := id.io.ex_csr_write_enable + id2ex.io.csr_write_address := id.io.ex_csr_write_address + id2ex.io.op1 := id.io.ex_op1 + id2ex.io.op2 := id.io.ex_op2 + id2ex.io.op1_jump := id.io.ex_op1_jump + id2ex.io.op2_jump := id.io.ex_op2_jump + id2ex.io.reg1_data := id.io.ex_reg1_data + id2ex.io.reg2_data := id.io.ex_reg2_data + id2ex.io.regs_write_enable := id.io.ex_reg_write_enable + id2ex.io.regs_write_address := id.io.ex_reg_write_address + id2ex.io.stall_flag := ctrl.io.output_stall_flag + id2ex.io.jump_flag := ctrl.io.pc_jump_flag + + ex.io.instruction := id2ex.io.output_instruction + ex.io.instruction_address := id2ex.io.output_instruction_address + ex.io.csr_reg_data_id := id2ex.io.output_csr_read_data + ex.io.csr_reg_write_enable_id := id2ex.io.output_csr_write_enable + ex.io.csr_reg_write_address_id := id2ex.io.output_csr_write_address + ex.io.op1 := id2ex.io.output_op1 + ex.io.op2 := id2ex.io.output_op2 + ex.io.op1_jump := id2ex.io.output_op1_jump + ex.io.op2_jump := id2ex.io.output_op2_jump + ex.io.reg1_data := id2ex.io.output_reg1_data + ex.io.reg2_data := id2ex.io.output_reg2_data + ex.io.regs_write_enable_id := id2ex.io.output_regs_write_enable + ex.io.regs_write_address_id := id2ex.io.output_regs_write_address + ex.io.interrupt_assert := clint.io.ex_interrupt_assert + ex.io.interrupt_handler_address := clint.io.ex_interrupt_handler_address + + clint.io.instruction := id.io.ex_instruction + clint.io.instruction_address_id := id.io.instruction_address + clint.io.jump_flag := ex.io.ctrl_jump_flag + clint.io.jump_address := ex.io.ctrl_jump_address + clint.io.csr_mepc := csr_regs.io.clint_csr_mepc + clint.io.csr_mtvec := csr_regs.io.clint_csr_mtvec + clint.io.csr_mstatus := csr_regs.io.clint_csr_mstatus + clint.io.interrupt_enable := csr_regs.io.interrupt_enable + clint.io.interrupt_flag := if2id.io.output_interrupt_flag + + csr_regs.io.reg_write_enable_ex := ex.io.csr_reg_write_enable + csr_regs.io.reg_write_address_ex := ex.io.csr_reg_write_address + csr_regs.io.reg_write_data_ex := ex.io.csr_reg_write_data + csr_regs.io.reg_read_address_id := id.io.csr_read_address + csr_regs.io.reg_write_enable_clint := clint.io.csr_reg_write_enable + csr_regs.io.reg_write_address_clint := clint.io.csr_reg_write_address + csr_regs.io.reg_write_data_clint := clint.io.csr_reg_write_data + csr_regs.io.reg_read_address_clint := 0.U +} diff --git a/lab4/src/main/scala/riscv/core/threestage/CSR.scala b/lab4/src/main/scala/riscv/core/threestage/CSR.scala new file mode 100644 index 0000000..f2f5d0a --- /dev/null +++ b/lab4/src/main/scala/riscv/core/threestage/CSR.scala @@ -0,0 +1,126 @@ +// 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.core.threestage + +import chisel3._ +import chisel3.util._ +import riscv.Parameters + + +object CSRRegister { + // Refer to Spec. Vol.II Page 8-10 + val CycleL = 0xc00.U(Parameters.CSRRegisterAddrWidth) + val CycleH = 0xc80.U(Parameters.CSRRegisterAddrWidth) + val MTVEC = 0x305.U(Parameters.CSRRegisterAddrWidth) + val MCAUSE = 0x342.U(Parameters.CSRRegisterAddrWidth) + val MEPC = 0x341.U(Parameters.CSRRegisterAddrWidth) + val MIE = 0x304.U(Parameters.CSRRegisterAddrWidth) + val MSTATUS = 0x300.U(Parameters.CSRRegisterAddrWidth) + val MSCRATCH = 0x340.U(Parameters.CSRRegisterAddrWidth) +} + +class CSR extends Module { + val io = IO(new Bundle { + val reg_write_enable_ex = Input(Bool()) + val reg_read_address_id = Input(UInt(Parameters.CSRRegisterAddrWidth)) + val reg_write_address_ex = Input(UInt(Parameters.CSRRegisterAddrWidth)) + val reg_write_data_ex = Input(UInt(Parameters.DataWidth)) + + val reg_write_enable_clint = Input(Bool()) + val reg_read_address_clint = Input(UInt(Parameters.CSRRegisterAddrWidth)) + val reg_write_address_clint = Input(UInt(Parameters.CSRRegisterAddrWidth)) + val reg_write_data_clint = Input(UInt(Parameters.DataWidth)) + + val interrupt_enable = Output(Bool()) + + val id_reg_data = Output(UInt(Parameters.DataWidth)) + + val clint_reg_data = Output(UInt(Parameters.DataWidth)) + val clint_csr_mtvec = Output(UInt(Parameters.DataWidth)) + val clint_csr_mepc = Output(UInt(Parameters.DataWidth)) + val clint_csr_mstatus = Output(UInt(Parameters.DataWidth)) + }) + + + val cycles = RegInit(UInt(64.W), 0.U) + val mtvec = RegInit(UInt(Parameters.DataWidth), 0.U) + val mcause = RegInit(UInt(Parameters.DataWidth), 0.U) + val mepc = RegInit(UInt(Parameters.DataWidth), 0.U) + val mie = RegInit(UInt(Parameters.DataWidth), 0.U) + val mstatus = RegInit(UInt(Parameters.DataWidth), 0.U) + val mscratch = RegInit(UInt(Parameters.DataWidth), 0.U) + + cycles := cycles + 1.U + io.clint_csr_mtvec := mtvec + io.clint_csr_mepc := mepc + io.clint_csr_mstatus := mstatus + io.interrupt_enable := mstatus(3) === 1.U + + val reg_write_address = Wire(UInt(Parameters.CSRRegisterAddrWidth)) + val reg_write_data = Wire(UInt(Parameters.DataWidth)) + reg_write_address := 0.U + reg_write_data := 0.U + + val reg_read_address = Wire(UInt(Parameters.CSRRegisterAddrWidth)) + val reg_read_data = Wire(UInt(Parameters.DataWidth)) + reg_read_address := 0.U + reg_read_data := 0.U + + when(io.reg_write_enable_ex) { + reg_write_address := io.reg_write_address_ex(11, 0) + reg_write_data := io.reg_write_data_ex + }.elsewhen(io.reg_write_enable_clint) { + reg_write_address := io.reg_write_address_clint(11, 0) + reg_write_data := io.reg_write_data_clint + } + + when(reg_write_address === CSRRegister.MTVEC) { + mtvec := reg_write_data + }.elsewhen(reg_write_address === CSRRegister.MCAUSE) { + mcause := reg_write_data + }.elsewhen(reg_write_address === CSRRegister.MEPC) { + mepc := reg_write_data + }.elsewhen(reg_write_address === CSRRegister.MIE) { + mie := reg_write_data + }.elsewhen(reg_write_address === CSRRegister.MSTATUS) { + mstatus := reg_write_data + }.elsewhen(reg_write_address === CSRRegister.MSCRATCH) { + mscratch := reg_write_data + } + + val regLUT = + IndexedSeq( + CSRRegister.CycleL -> cycles(31, 0), + CSRRegister.CycleH -> cycles(63, 32), + CSRRegister.MTVEC -> mtvec, + CSRRegister.MCAUSE -> mcause, + CSRRegister.MEPC -> mepc, + CSRRegister.MIE -> mie, + CSRRegister.MSTATUS -> mstatus, + CSRRegister.MSCRATCH -> mscratch, + ) + + io.id_reg_data := MuxLookup( + io.reg_read_address_id, + 0.U, + regLUT, + ) + + io.clint_reg_data := MuxLookup( + io.reg_read_address_clint, + 0.U, + regLUT, + ) +} diff --git a/lab4/src/main/scala/riscv/core/threestage/Cache.scala b/lab4/src/main/scala/riscv/core/threestage/Cache.scala new file mode 100644 index 0000000..4e52315 --- /dev/null +++ b/lab4/src/main/scala/riscv/core/threestage/Cache.scala @@ -0,0 +1,23 @@ +// 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.core.threestage + +import chisel3._ + +class Cache(cacheLineBytes: Int, associativity: Int, cacheLines: Int) extends Module { + val io = IO(new Bundle { + + }) +} diff --git a/lab4/src/main/scala/riscv/core/threestage/Control.scala b/lab4/src/main/scala/riscv/core/threestage/Control.scala new file mode 100644 index 0000000..6790492 --- /dev/null +++ b/lab4/src/main/scala/riscv/core/threestage/Control.scala @@ -0,0 +1,55 @@ +// 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.core.threestage + +import chisel3._ +import chisel3.util._ +import riscv.Parameters + +object StallStates { + val None = 0.U + val PC = 1.U + val IF = 2.U + val ID = 3.U +} + +class Control extends Module { + val io = IO(new Bundle { + val jump_flag = Input(Bool()) + val stall_flag_if = Input(Bool()) + val stall_flag_id = Input(Bool()) + val stall_flag_ex = Input(Bool()) + val stall_flag_clint = Input(Bool()) + val stall_flag_bus = Input(Bool()) + val jump_address = Input(UInt(Parameters.AddrWidth)) + + val output_stall_flag = Output(UInt(Parameters.StallStateWidth)) + + val pc_jump_flag = Output(Bool()) + val pc_jump_address = Output(UInt(Parameters.AddrWidth)) + }) + + io.pc_jump_flag := io.jump_flag + io.pc_jump_address := io.jump_address + + io.output_stall_flag := MuxCase( + StallStates.None, + IndexedSeq( + (io.jump_flag || io.stall_flag_ex || io.stall_flag_clint) -> StallStates.ID, + io.stall_flag_id -> StallStates.IF, + (io.stall_flag_bus || io.stall_flag_if) -> StallStates.PC, + ) + ) +} diff --git a/lab4/src/main/scala/riscv/core/threestage/Execute.scala b/lab4/src/main/scala/riscv/core/threestage/Execute.scala new file mode 100644 index 0000000..5b1d675 --- /dev/null +++ b/lab4/src/main/scala/riscv/core/threestage/Execute.scala @@ -0,0 +1,315 @@ +// 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.core.threestage + +import chisel3._ +import chisel3.experimental.ChiselEnum +import chisel3.util._ +import riscv.Parameters +import riscv.core.BusBundle + +object MemoryAccessStates extends ChiselEnum { + val Idle, Read, Write, ReadWrite = Value +} + +class Execute extends Module { + val io = IO(new Bundle { + val instruction = Input(UInt(Parameters.InstructionWidth)) + val instruction_address = Input(UInt(Parameters.AddrWidth)) + val interrupt_assert = Input(Bool()) + val interrupt_handler_address = Input(UInt(Parameters.AddrWidth)) + val regs_write_enable_id = Input(Bool()) + val regs_write_address_id = Input(UInt(Parameters.PhysicalRegisterAddrWidth)) + val csr_reg_write_enable_id = Input(Bool()) + val csr_reg_write_address_id = Input(UInt(Parameters.CSRRegisterAddrWidth)) + val csr_reg_data_id = Input(UInt(Parameters.DataWidth)) + val reg1_data = Input(UInt(Parameters.DataWidth)) + val reg2_data = Input(UInt(Parameters.DataWidth)) + val op1 = Input(UInt(Parameters.DataWidth)) + val op2 = Input(UInt(Parameters.DataWidth)) + val op1_jump = Input(UInt(Parameters.DataWidth)) + val op2_jump = Input(UInt(Parameters.DataWidth)) + + val bus = new BusBundle + + val regs_write_enable = Output(Bool()) + val regs_write_address = Output(UInt(Parameters.PhysicalRegisterAddrWidth)) + val regs_write_data = Output(UInt(Parameters.DataWidth)) + + val ctrl_stall_flag = Output(Bool()) + val ctrl_jump_flag = Output(Bool()) + val ctrl_jump_address = Output(UInt(Parameters.AddrWidth)) + + val csr_reg_write_enable = Output(Bool()) + val csr_reg_write_address = Output(UInt(Parameters.CSRRegisterAddrWidth)) + val csr_reg_write_data = Output(UInt(Parameters.DataWidth)) + }) + + val opcode = io.instruction(6, 0) + val funct3 = io.instruction(14, 12) + val funct7 = io.instruction(31, 25) + val rd = io.instruction(11, 7) + val uimm = io.instruction(19, 15) + + val alu = Module(new ALU) + val alu_ctrl = Module(new ALUControl) + + alu_ctrl.io.opcode := opcode + alu_ctrl.io.funct3 := funct3 + alu_ctrl.io.funct7 := funct7 + alu.io.func := alu_ctrl.io.alu_funct + alu.io.op1 := io.op1 + alu.io.op2 := io.op2 + + + val mem_read_address_index = (io.op1 + io.op2) (log2Up(Parameters.WordSize) - 1, 0).asUInt + val mem_write_address_index = (io.op1 + io.op2) (log2Up(Parameters.WordSize) - 1, 0).asUInt + val mem_access_state = RegInit(MemoryAccessStates.Idle) + val pending_interrupt = RegInit(false.B) + val pending_interrupt_handler_address = RegInit(Parameters.EntryAddress) + + val jump_flag = Wire(Bool()) + val jump_address = Wire(UInt(Parameters.AddrWidth)) + + io.ctrl_jump_flag := jump_flag || io.interrupt_assert + io.ctrl_jump_address := Mux(io.interrupt_assert, io.interrupt_handler_address, jump_address) + + io.bus.read := false.B + io.bus.address := 0.U + io.bus.write_data := 0.U + io.bus.write_strobe := VecInit(Seq.fill(Parameters.WordSize)(false.B)) + io.bus.write := false.B + io.regs_write_enable := io.regs_write_enable_id && !io.interrupt_assert + io.regs_write_address := io.regs_write_address_id + io.regs_write_data := 0.U + io.csr_reg_write_enable := io.csr_reg_write_enable_id && !io.interrupt_assert + io.csr_reg_write_address := io.csr_reg_write_address_id + io.csr_reg_write_data := 0.U + io.bus.request := false.B + + def disable_control() = { + disable_stall() + disable_jump() + } + + def disable_stall() = { + io.ctrl_stall_flag := false.B + } + + def disable_jump() = { + jump_address := 0.U + jump_flag := false.B + } + + def check_interrupt_during_bus_transaction() = { + // Store the interrupt and process later + when(io.interrupt_assert) { + pending_interrupt := true.B + pending_interrupt_handler_address := io.interrupt_handler_address + io.ctrl_jump_flag := false.B + } + } + + def on_bus_transaction_finished() = { + mem_access_state := MemoryAccessStates.Idle + io.ctrl_stall_flag := false.B + when(pending_interrupt) { + pending_interrupt := false.B + io.ctrl_jump_flag := true.B + io.ctrl_jump_address := pending_interrupt_handler_address + } + } + + when(opcode === InstructionTypes.I) { + disable_control() + val mask = (0xFFFFFFFFL.U >> io.instruction(24, 20)).asUInt + io.regs_write_data := alu.io.result + when(funct3 === InstructionsTypeI.sri) { + when(funct7(5).asBool) { + io.regs_write_data := alu.io.result & mask | + (Fill(32, io.op1(31)) & (~mask).asUInt).asUInt + } + } + }.elsewhen(opcode === InstructionTypes.RM) { + disable_control() + // TODO(howard): support mul and div + when(funct7 === 0.U || funct7 === 0x20.U) { + val mask = (0xFFFFFFFFL.U >> io.reg2_data(4, 0)).asUInt + io.regs_write_data := alu.io.result + when(funct3 === InstructionsTypeR.sr) { + when(funct7(5).asBool) { + io.regs_write_data := alu.io.result & mask | + (Fill(32, io.op1(31)) & (~mask).asUInt).asUInt + } + } + } + }.elsewhen(opcode === InstructionTypes.L) { + disable_control() + + when(mem_access_state === MemoryAccessStates.Idle) { + // Start the read transaction when there is no interrupt asserted + // and the bus is available + when(!io.interrupt_assert) { + io.ctrl_stall_flag := true.B + io.regs_write_enable := false.B + io.bus.read := true.B + io.bus.address := io.op1 + io.op2 + io.bus.request := true.B + when(io.bus.granted) { + mem_access_state := MemoryAccessStates.Read + } + } + }.elsewhen(mem_access_state === MemoryAccessStates.Read) { + check_interrupt_during_bus_transaction() + io.bus.request := true.B + io.bus.read := false.B + io.ctrl_stall_flag := true.B + io.bus.address := io.op1 + io.op2 + when(io.bus.read_valid) { + io.regs_write_enable := true.B + val data = io.bus.read_data + io.regs_write_data := MuxLookup( + funct3, + 0.U, + IndexedSeq( + InstructionsTypeL.lb -> MuxLookup( + mem_read_address_index, + Cat(Fill(24, data(31)), data(31, 24)), + IndexedSeq( + 0.U -> Cat(Fill(24, data(7)), data(7, 0)), + 1.U -> Cat(Fill(24, data(15)), data(15, 8)), + 2.U -> Cat(Fill(24, data(23)), data(23, 16)) + ) + ), + InstructionsTypeL.lbu -> MuxLookup( + mem_read_address_index, + Cat(Fill(24, 0.U), data(31, 24)), + IndexedSeq( + 0.U -> Cat(Fill(24, 0.U), data(7, 0)), + 1.U -> Cat(Fill(24, 0.U), data(15, 8)), + 2.U -> Cat(Fill(24, 0.U), data(23, 16)) + ) + ), + InstructionsTypeL.lh -> Mux( + mem_read_address_index === 0.U, + Cat(Fill(16, data(15)), data(15, 0)), + Cat(Fill(16, data(31)), data(31, 16)) + ), + InstructionsTypeL.lhu -> Mux( + mem_read_address_index === 0.U, + Cat(Fill(16, 0.U), data(15, 0)), + Cat(Fill(16, 0.U), data(31, 16)) + ), + InstructionsTypeL.lw -> data + ) + ) + on_bus_transaction_finished() + } + } + }.elsewhen(opcode === InstructionTypes.S) { + disable_control() + + when(mem_access_state === MemoryAccessStates.Idle) { + // Start the write transaction when there is no interrupt asserted + // and the bus is available + when(!io.interrupt_assert) { + io.ctrl_stall_flag := true.B + io.bus.address := io.op1 + io.op2 + io.bus.write_data := io.reg2_data + io.bus.write := true.B + io.bus.write_strobe := VecInit(Seq.fill(Parameters.WordSize)(false.B)) + when(funct3 === InstructionsTypeS.sb) { + io.bus.write_strobe(mem_write_address_index) := true.B + io.bus.write_data := io.reg2_data(Parameters.ByteBits, 0) << (mem_write_address_index << log2Up(Parameters + .ByteBits).U) + }.elsewhen(funct3 === InstructionsTypeS.sh) { + when(mem_write_address_index === 0.U) { + for (i <- 0 until Parameters.WordSize / 2) { + io.bus.write_strobe(i) := true.B + } + io.bus.write_data := io.reg2_data(Parameters.WordSize / 2 * Parameters.ByteBits, 0) + }.otherwise { + for (i <- Parameters.WordSize / 2 until Parameters.WordSize) { + io.bus.write_strobe(i) := true.B + } + io.bus.write_data := io.reg2_data(Parameters.WordSize / 2 * Parameters.ByteBits, 0) << (Parameters + .WordSize / 2 * Parameters.ByteBits) + } + }.elsewhen(funct3 === InstructionsTypeS.sw) { + for (i <- 0 until Parameters.WordSize) { + io.bus.write_strobe(i) := true.B + } + } + io.bus.request := true.B + when(io.bus.granted) { + mem_access_state := MemoryAccessStates.Write + } + } + }.elsewhen(mem_access_state === MemoryAccessStates.Write) { + check_interrupt_during_bus_transaction() + io.bus.request := true.B + io.ctrl_stall_flag := true.B + io.bus.write := false.B + io.bus.address := io.op1 + io.op2 + when(io.bus.write_valid) { + on_bus_transaction_finished() + } + } + }.elsewhen(opcode === InstructionTypes.B) { + disable_control() + jump_flag := MuxLookup( + funct3, + 0.U, + IndexedSeq( + InstructionsTypeB.beq -> (io.op1 === io.op2), + InstructionsTypeB.bne -> (io.op1 =/= io.op2), + InstructionsTypeB.bltu -> (io.op1 < io.op2), + InstructionsTypeB.bgeu -> (io.op1 >= io.op2), + InstructionsTypeB.blt -> (io.op1.asSInt < io.op2.asSInt), + InstructionsTypeB.bge -> (io.op1.asSInt >= io.op2.asSInt) + ) + ) + jump_address := Fill(32, io.ctrl_jump_flag) & (io.op1_jump + io.op2_jump) + }.elsewhen(opcode === Instructions.jal || opcode === Instructions.jalr) { + disable_stall() + jump_flag := true.B + jump_address := io.op1_jump + io.op2_jump + io.regs_write_data := io.op1 + io.op2 + }.elsewhen(opcode === Instructions.lui || opcode === Instructions.auipc) { + disable_control() + io.regs_write_data := io.op1 + io.op2 + }.elsewhen(opcode === Instructions.csr) { + disable_control() + io.csr_reg_write_data := MuxLookup(funct3, 0.U, IndexedSeq( + InstructionsTypeCSR.csrrw -> io.reg1_data, + InstructionsTypeCSR.csrrc -> io.csr_reg_data_id.&((~io.reg1_data).asUInt), + InstructionsTypeCSR.csrrs -> io.csr_reg_data_id.|(io.reg1_data), + InstructionsTypeCSR.csrrwi -> Cat(0.U(27.W), uimm), + InstructionsTypeCSR.csrrci -> io.csr_reg_data_id.&((~Cat(0.U(27.W), uimm)).asUInt), + InstructionsTypeCSR.csrrsi -> io.csr_reg_data_id.|(Cat(0.U(27.W), uimm)), + )) + io.regs_write_data := MuxLookup(funct3, 0.U, IndexedSeq( + InstructionsTypeCSR.csrrw -> io.csr_reg_data_id, + InstructionsTypeCSR.csrrc -> io.csr_reg_data_id, + InstructionsTypeCSR.csrrs -> io.csr_reg_data_id, + InstructionsTypeCSR.csrrwi -> io.csr_reg_data_id, + InstructionsTypeCSR.csrrci -> io.csr_reg_data_id, + InstructionsTypeCSR.csrrsi -> io.csr_reg_data_id, + )) + }.otherwise { + disable_control() + io.regs_write_data := 0.U + } +} diff --git a/lab4/src/main/scala/riscv/core/threestage/ID2EX.scala b/lab4/src/main/scala/riscv/core/threestage/ID2EX.scala new file mode 100644 index 0000000..fedd882 --- /dev/null +++ b/lab4/src/main/scala/riscv/core/threestage/ID2EX.scala @@ -0,0 +1,132 @@ +// 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.core.threestage + +import chisel3._ +import riscv.Parameters + +class ID2EX extends Module { + val io = IO(new Bundle { + val instruction = Input(UInt(Parameters.InstructionWidth)) + val instruction_address = Input(UInt(Parameters.AddrWidth)) + val regs_write_enable = Input(Bool()) + val regs_write_address = Input(UInt(Parameters.PhysicalRegisterAddrWidth)) + val reg1_data = Input(UInt(Parameters.DataWidth)) + val reg2_data = Input(UInt(Parameters.DataWidth)) + val op1 = Input(UInt(Parameters.DataWidth)) + val op2 = Input(UInt(Parameters.DataWidth)) + val op1_jump = Input(UInt(Parameters.DataWidth)) + val op2_jump = Input(UInt(Parameters.DataWidth)) + val csr_write_enable = Input(Bool()) + val csr_write_address = Input(UInt(Parameters.CSRRegisterAddrWidth)) + val csr_read_data = Input(UInt(Parameters.DataWidth)) + val stall_flag = Input(UInt(Parameters.StallStateWidth)) + val jump_flag = Input(Bool()) + + val output_instruction = Output(UInt(Parameters.DataWidth)) + val output_instruction_address = Output(UInt(Parameters.AddrWidth)) + val output_regs_write_enable = Output(Bool()) + val output_regs_write_address = Output(UInt(Parameters.PhysicalRegisterAddrWidth)) + val output_reg1_data = Output(UInt(Parameters.DataWidth)) + val output_reg2_data = Output(UInt(Parameters.DataWidth)) + val output_op1 = Output(UInt(Parameters.DataWidth)) + val output_op2 = Output(UInt(Parameters.DataWidth)) + val output_op1_jump = Output(UInt(Parameters.DataWidth)) + val output_op2_jump = Output(UInt(Parameters.DataWidth)) + val output_csr_write_enable = Output(Bool()) + val output_csr_write_address = Output(UInt(Parameters.CSRRegisterAddrWidth)) + val output_csr_read_data = Output(UInt(Parameters.DataWidth)) + }) + val write_enable = io.stall_flag < StallStates.ID + val flush_enable = io.jump_flag + + val instruction = Module(new PipelineRegister(defaultValue = InstructionsNop.nop)) + instruction.io.in := io.instruction + instruction.io.write_enable := write_enable + instruction.io.flush_enable := flush_enable + io.output_instruction := instruction.io.out + + val instruction_address = Module(new PipelineRegister(defaultValue = ProgramCounter.EntryAddress)) + instruction_address.io.in := io.instruction_address + instruction_address.io.write_enable := write_enable + instruction_address.io.flush_enable := flush_enable + io.output_instruction_address := instruction_address.io.out + + val regs_write_enable = Module(new PipelineRegister(1)) + regs_write_enable.io.in := io.regs_write_enable + regs_write_enable.io.write_enable := write_enable + regs_write_enable.io.flush_enable := flush_enable + io.output_regs_write_enable := regs_write_enable.io.out + + val regs_write_address = Module(new PipelineRegister(Parameters.PhysicalRegisterAddrBits)) + regs_write_address.io.in := io.regs_write_address + regs_write_address.io.write_enable := write_enable + regs_write_address.io.flush_enable := flush_enable + io.output_regs_write_address := regs_write_address.io.out + + val reg1_data = Module(new PipelineRegister()) + reg1_data.io.in := io.reg1_data + reg1_data.io.write_enable := write_enable + reg1_data.io.flush_enable := flush_enable + io.output_reg1_data := reg1_data.io.out + + val reg2_data = Module(new PipelineRegister()) + reg2_data.io.in := io.reg2_data + reg2_data.io.write_enable := write_enable + reg2_data.io.flush_enable := flush_enable + io.output_reg2_data := reg2_data.io.out + + val op1 = Module(new PipelineRegister()) + op1.io.in := io.op1 + op1.io.write_enable := write_enable + op1.io.flush_enable := flush_enable + io.output_op1 := op1.io.out + + val op2 = Module(new PipelineRegister()) + op2.io.in := io.op2 + op2.io.write_enable := write_enable + op2.io.flush_enable := flush_enable + io.output_op2 := op2.io.out + + val op1_jump = Module(new PipelineRegister()) + op1_jump.io.in := io.op1_jump + op1_jump.io.write_enable := write_enable + op1_jump.io.flush_enable := flush_enable + io.output_op1_jump := op1_jump.io.out + + val op2_jump = Module(new PipelineRegister()) + op2_jump.io.in := io.op2_jump + op2_jump.io.write_enable := write_enable + op2_jump.io.flush_enable := flush_enable + io.output_op2_jump := op2_jump.io.out + + val csr_write_enable = Module(new PipelineRegister()) + csr_write_enable.io.in := io.csr_write_enable + csr_write_enable.io.write_enable := write_enable + csr_write_enable.io.flush_enable := flush_enable + io.output_csr_write_enable := csr_write_enable.io.out + + val csr_write_address = Module(new PipelineRegister()) + csr_write_address.io.in := io.csr_write_address + csr_write_address.io.write_enable := write_enable + csr_write_address.io.flush_enable := flush_enable + io.output_csr_write_address := csr_write_address.io.out + + val csr_read_data = Module(new PipelineRegister()) + csr_read_data.io.in := io.csr_read_data + csr_read_data.io.write_enable := write_enable + csr_read_data.io.flush_enable := flush_enable + io.output_csr_read_data := csr_read_data.io.out +} diff --git a/lab4/src/main/scala/riscv/core/threestage/IF2ID.scala b/lab4/src/main/scala/riscv/core/threestage/IF2ID.scala new file mode 100644 index 0000000..b0f6c27 --- /dev/null +++ b/lab4/src/main/scala/riscv/core/threestage/IF2ID.scala @@ -0,0 +1,53 @@ +// 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.core.threestage + +import chisel3._ +import riscv.Parameters + +class IF2ID extends Module { + val io = IO(new Bundle { + val instruction = Input(UInt(Parameters.InstructionWidth)) + val instruction_address = Input(UInt(Parameters.AddrWidth)) + val stall_flag = Input(UInt(Parameters.StallStateWidth)) + val interrupt_flag = Input(UInt(Parameters.InterruptFlagWidth)) + val jump_flag = Input(Bool()) + + val output_instruction = Output(UInt(Parameters.DataWidth)) + val output_instruction_address = Output(UInt(Parameters.AddrWidth)) + val output_interrupt_flag = Output(UInt(Parameters.InterruptFlagWidth)) + }) + + val write_enable = io.stall_flag < StallStates.IF + val flush_enable = io.jump_flag + + val instruction = Module(new PipelineRegister(defaultValue = InstructionsNop.nop)) + instruction.io.in := io.instruction + instruction.io.write_enable := write_enable + instruction.io.flush_enable := flush_enable + io.output_instruction := instruction.io.out + + val instruction_address = Module(new PipelineRegister(defaultValue = ProgramCounter.EntryAddress)) + instruction_address.io.in := io.instruction_address + instruction_address.io.write_enable := write_enable + instruction_address.io.flush_enable := flush_enable + io.output_instruction_address := instruction_address.io.out + + val interrupt_flag = Module(new PipelineRegister()) + interrupt_flag.io.in := io.interrupt_flag + interrupt_flag.io.write_enable := write_enable + interrupt_flag.io.flush_enable := flush_enable + io.output_interrupt_flag := interrupt_flag.io.out +} diff --git a/lab4/src/main/scala/riscv/core/threestage/InstructionDecode.scala b/lab4/src/main/scala/riscv/core/threestage/InstructionDecode.scala new file mode 100644 index 0000000..90b34fd --- /dev/null +++ b/lab4/src/main/scala/riscv/core/threestage/InstructionDecode.scala @@ -0,0 +1,317 @@ +// 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.core.threestage + +import chisel3._ +import chisel3.util._ +import riscv.Parameters + + +object InstructionTypes { + val L = "b0000011".U + val I = "b0010011".U + val S = "b0100011".U + val RM = "b0110011".U + val B = "b1100011".U +} + +object Instructions { + val lui = "b0110111".U + val nop = "b0000001".U + val jal = "b1101111".U + val jalr = "b1100111".U + val auipc = "b0010111".U + val csr = "b1110011".U + val fence = "b0001111".U +} + +object InstructionsTypeL { + val lb = "b000".U + val lh = "b001".U + val lw = "b010".U + val lbu = "b100".U + val lhu = "b101".U +} + +object InstructionsTypeI { + val addi = 0.U + val slli = 1.U + val slti = 2.U + val sltiu = 3.U + val xori = 4.U + val sri = 5.U + val ori = 6.U + val andi = 7.U +} + +object InstructionsTypeS { + val sb = "b000".U + val sh = "b001".U + val sw = "b010".U +} + +object InstructionsTypeR { + val add_sub = 0.U + val sll = 1.U + val slt = 2.U + val sltu = 3.U + val xor = 4.U + val sr = 5.U + val or = 6.U + val and = 7.U +} + +object InstructionsTypeM { + val mul = 0.U + val mulh = 1.U + val mulhsu = 2.U + val mulhum = 3.U + val div = 4.U + val divu = 5.U + val rem = 6.U + val remu = 7.U +} + +object InstructionsTypeB { + val beq = "b000".U + val bne = "b001".U + val blt = "b100".U + val bge = "b101".U + val bltu = "b110".U + val bgeu = "b111".U +} + +object InstructionsTypeCSR { + val csrrw = "b001".U + val csrrs = "b010".U + val csrrc = "b011".U + val csrrwi = "b101".U + val csrrsi = "b110".U + val csrrci = "b111".U +} + +object InstructionsNop { + val nop = 0x00000013L.U(Parameters.DataWidth) +} + +object InstructionsRet { + val mret = 0x30200073L.U(Parameters.DataWidth) + val ret = 0x00008067L.U(Parameters.DataWidth) +} + +object InstructionsEnv { + val ecall = 0x00000073L.U(Parameters.DataWidth) + val ebreak = 0x00100073L.U(Parameters.DataWidth) +} + +class InstructionDecode extends Module { + val io = IO(new Bundle { + val instruction = Input(UInt(Parameters.InstructionWidth)) + val instruction_address = Input(UInt(Parameters.AddrWidth)) + val reg1_data = Input(UInt(Parameters.DataWidth)) + val reg2_data = Input(UInt(Parameters.DataWidth)) + + val csr_read_data = Input(UInt(Parameters.DataWidth)) + + val regs_reg1_read_address = Output(UInt(Parameters.PhysicalRegisterAddrWidth)) + val regs_reg2_read_address = Output(UInt(Parameters.PhysicalRegisterAddrWidth)) + + val ctrl_stall_flag = Output(UInt(Parameters.StallStateWidth)) + + val ex_op1 = Output(UInt(Parameters.DataWidth)) + val ex_op2 = Output(UInt(Parameters.DataWidth)) + val ex_op1_jump = Output(UInt(Parameters.DataWidth)) + val ex_op2_jump = Output(UInt(Parameters.DataWidth)) + val ex_instruction = Output(UInt(Parameters.DataWidth)) + val ex_instruction_address = Output(UInt(Parameters.AddrWidth)) + val ex_reg1_data = Output(UInt(Parameters.DataWidth)) + val ex_reg2_data = Output(UInt(Parameters.DataWidth)) + val ex_reg_write_enable = Output(Bool()) + val ex_reg_write_address = Output(UInt(Parameters.PhysicalRegisterAddrWidth)) + + val csr_read_address = Output(UInt(Parameters.CSRRegisterAddrWidth)) + val ex_csr_write_enable = Output(Bool()) + val ex_csr_write_address = Output(UInt(Parameters.CSRRegisterAddrWidth)) + val ex_csr_write_data = Output(UInt(Parameters.DataWidth)) + val ex_csr_read_data = Output(UInt(Parameters.DataWidth)) + }) + val opcode = io.instruction(6, 0) + val funct3 = io.instruction(14, 12) + val funct7 = io.instruction(31, 25) + val rd = io.instruction(11, 7) + val rs1 = io.instruction(19, 15) + val rs2 = io.instruction(24, 20) + + def disable_regs() = { + disable_write() + io.regs_reg1_read_address := 0.U + io.regs_reg2_read_address := 0.U + } + + def disable_write() = { + io.ex_reg_write_enable := false.B + io.ex_reg_write_address := 0.U + } + + def enable_write(addr: UInt) = { + io.ex_reg_write_enable := true.B + io.ex_reg_write_address := addr + } + + io.ex_instruction := io.instruction + io.ex_instruction_address := io.instruction_address + io.ex_reg1_data := io.reg1_data + io.ex_reg2_data := io.reg2_data + io.ex_op1 := 0.U + io.ex_op2 := 0.U + io.ex_op1_jump := 0.U + io.ex_op2_jump := 0.U + io.ctrl_stall_flag := false.B + io.csr_read_address := 0.U + io.ex_csr_read_data := io.csr_read_data + io.ex_csr_write_enable := false.B + io.ex_csr_write_data := 0.U + io.ex_csr_write_address := 0.U + + when(opcode === InstructionTypes.L) { + when( + funct3 === InstructionsTypeL.lb || + funct3 === InstructionsTypeL.lh || + funct3 === InstructionsTypeL.lw || + funct3 === InstructionsTypeL.lbu || + funct3 === InstructionsTypeL.lhu + ) { + enable_write(rd) + io.regs_reg1_read_address := rs1 + io.regs_reg2_read_address := 0.U + io.ex_op1 := io.reg1_data + io.ex_op2 := Cat(Fill(20, io.instruction(31)), io.instruction(31, 20)) + }.otherwise { + disable_regs() + } + }.elsewhen(opcode === InstructionTypes.I) { + enable_write(rd) + io.regs_reg1_read_address := rs1 + io.regs_reg2_read_address := 0.U + io.ex_op1 := io.reg1_data + io.ex_op2 := Cat(Fill(20, io.instruction(31)), io.instruction(31, 20)) + }.elsewhen(opcode === InstructionTypes.S) { + when(funct3 === InstructionsTypeS.sb || + funct3 === InstructionsTypeS.sh || + funct3 === InstructionsTypeS.sw) { + disable_write() + io.regs_reg1_read_address := rs1 + io.regs_reg2_read_address := rs2 + io.ex_op1 := io.reg1_data + io.ex_op2 := Cat(Fill(20, io.instruction(31)), io.instruction(31, 25), io.instruction(11, 7)) + }.otherwise { + disable_regs() + } + }.elsewhen(opcode === InstructionTypes.RM) { + when(funct7 === 0.U || funct7 === 0x20.U) { + enable_write(rd) + io.regs_reg1_read_address := rs1 + io.regs_reg2_read_address := rs2 + io.ex_op1 := io.reg1_data + io.ex_op2 := io.reg2_data + }.otherwise { + // TODO(howard): implement mul and div + disable_regs() + } + }.elsewhen(opcode === InstructionTypes.B) { + when( + funct3 === InstructionsTypeB.beq || + funct3 === InstructionsTypeB.bne || + funct3 === InstructionsTypeB.blt || + funct3 === InstructionsTypeB.bge || + funct3 === InstructionsTypeB.bltu || + funct3 === InstructionsTypeB.bgeu + ) { + disable_write() + io.regs_reg1_read_address := rs1 + io.regs_reg2_read_address := rs2 + io.ex_op1 := io.reg1_data + io.ex_op2 := io.reg2_data + io.ex_op1_jump := io.instruction_address + io.ex_op2_jump := Cat(Fill(20, io.instruction(31)), io.instruction(7), io.instruction(30, 25), io.instruction + (11, 8), 0.U(1.W)) + }.otherwise { + disable_regs() + } + }.elsewhen(opcode === Instructions.jal) { + enable_write(rd) + io.regs_reg1_read_address := 0.U + io.regs_reg2_read_address := 0.U + io.ex_op1 := io.instruction_address + io.ex_op2 := 4.U + io.ex_op1_jump := io.instruction_address + io.ex_op2_jump := Cat(Fill(12, io.instruction(31)), io.instruction(19, 12), io.instruction(20), io.instruction + (30, 21), 0.U(1.W)) + }.elsewhen(opcode === Instructions.jalr) { + enable_write(rd) + io.regs_reg1_read_address := rs1 + io.regs_reg2_read_address := 0.U + io.ex_op1 := io.instruction_address + io.ex_op2 := 4.U + io.ex_op1_jump := io.reg1_data + io.ex_op2_jump := Cat(Fill(20, io.instruction(31)), io.instruction(31, 20)) + }.elsewhen(opcode === Instructions.lui) { + enable_write(rd) + io.regs_reg1_read_address := 0.U + io.regs_reg2_read_address := 0.U + io.ex_op1 := Cat(io.instruction(31, 12), Fill(12, 0.U(1.W))) + io.ex_op2 := 0.U + }.elsewhen(opcode === Instructions.auipc) { + enable_write(rd) + io.regs_reg1_read_address := 0.U + io.regs_reg2_read_address := 0.U + io.ex_op1 := io.instruction_address + io.ex_op2 := Cat(io.instruction(31, 12), Fill(12, 0.U(1.W))) + }.elsewhen(opcode === Instructions.csr) { + disable_regs() + io.csr_read_address := Cat(0.U(20.W), io.instruction(31, 20)) + io.ex_csr_write_address := Cat(0.U(20.W), io.instruction(31, 20)) + when( + funct3 === InstructionsTypeCSR.csrrc || + funct3 === InstructionsTypeCSR.csrrs || + funct3 === InstructionsTypeCSR.csrrw + ) { + io.regs_reg1_read_address := rs1 + io.regs_reg2_read_address := 0.U + io.ex_reg_write_enable := true.B + io.ex_reg_write_address := rd + io.ex_csr_write_enable := true.B + }.elsewhen( + funct3 === InstructionsTypeCSR.csrrci || + funct3 === InstructionsTypeCSR.csrrsi || + funct3 === InstructionsTypeCSR.csrrwi + ) { + io.regs_reg1_read_address := 0.U + io.regs_reg2_read_address := 0.U + io.ex_reg_write_enable := true.B + io.ex_reg_write_address := rd + io.ex_csr_write_enable := true.B + }.otherwise { + io.ex_csr_write_enable := false.B + io.ex_csr_write_data := 0.U + io.ex_csr_write_address := 0.U + } + }.elsewhen(opcode === Instructions.nop) { + disable_regs() + }.otherwise { + disable_regs() + } + +} diff --git a/lab4/src/main/scala/riscv/core/threestage/InstructionFetch.scala b/lab4/src/main/scala/riscv/core/threestage/InstructionFetch.scala new file mode 100644 index 0000000..63d80b5 --- /dev/null +++ b/lab4/src/main/scala/riscv/core/threestage/InstructionFetch.scala @@ -0,0 +1,69 @@ +// 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.core.threestage + +import chisel3._ +import chisel3.util.MuxCase +import riscv.Parameters + +object ProgramCounter { + val EntryAddress = Parameters.EntryAddress +} + +class InstructionFetch extends Module { + val io = IO(new Bundle { + val stall_flag_ctrl = Input(Bool()) + val jump_flag_ctrl = Input(Bool()) + val jump_address_ctrl = Input(UInt(Parameters.AddrWidth)) + val instruction_valid = Input(Bool()) + + val bus_request = Output(Bool()) + val bus_address = Output(UInt(Parameters.AddrWidth)) + val bus_data = Input(UInt(Parameters.InstructionWidth)) + val bus_read = Output(Bool()) + + val ctrl_stall_flag = Output(Bool()) + val id_instruction_address = Output(UInt(Parameters.AddrWidth)) + val id_instruction = Output(UInt(Parameters.InstructionWidth)) + }) + val instruction_address = RegInit(ProgramCounter.EntryAddress) + val pending_jump = RegInit(false.B) + val pc = RegInit(ProgramCounter.EntryAddress) + io.bus_read := true.B + io.bus_request := true.B + + pc := MuxCase( + pc + 4.U, + IndexedSeq( + io.jump_flag_ctrl -> io.jump_address_ctrl, + (io.stall_flag_ctrl >= StallStates.PC) -> pc + ) + ) + when(!io.instruction_valid) { + when(io.jump_flag_ctrl) { + pending_jump := true.B + } + } + when(io.instruction_valid) { + when(pending_jump) { + pending_jump := false.B + } + } + io.id_instruction := Mux(io.instruction_valid && !io.jump_flag_ctrl && !pending_jump, io.bus_data, + InstructionsNop.nop) + io.ctrl_stall_flag := !io.instruction_valid || pending_jump + io.id_instruction_address := pc + io.bus_address := pc +} diff --git a/lab4/src/main/scala/riscv/core/threestage/PipelineRegister.scala b/lab4/src/main/scala/riscv/core/threestage/PipelineRegister.scala new file mode 100644 index 0000000..1d54282 --- /dev/null +++ b/lab4/src/main/scala/riscv/core/threestage/PipelineRegister.scala @@ -0,0 +1,35 @@ +// 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.core.threestage + +import chisel3._ +import riscv.Parameters + +class PipelineRegister(width: Int = Parameters.DataBits, defaultValue: UInt = 0.U) extends Module { + val io = IO(new Bundle { + val write_enable = Input(Bool()) + val flush_enable = Input(Bool()) + val in = Input(UInt(width.W)) + val out = Output(UInt(width.W)) + }) + + val reg = RegInit(UInt(width.W), defaultValue) + when(io.write_enable) { + reg := io.in + }.elsewhen(io.flush_enable) { + reg := defaultValue + } + io.out := reg +} diff --git a/lab4/src/main/scala/riscv/core/threestage/RegisterFile.scala b/lab4/src/main/scala/riscv/core/threestage/RegisterFile.scala new file mode 100644 index 0000000..3d68974 --- /dev/null +++ b/lab4/src/main/scala/riscv/core/threestage/RegisterFile.scala @@ -0,0 +1,78 @@ +// 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.core.threestage + +import chisel3._ +import chisel3.util._ +import riscv.Parameters + +object Registers extends Enumeration { + type Register = Value + val zero, + ra, sp, gp, tp, + t0, t1, t2, fp, + s1, + a0, a1, a2, a3, a4, a5, a6, a7, + s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, + t3, t4, t5, t6 = Value +} + +class RegisterFile extends Module { + val io = IO(new Bundle { + val write_enable = Input(Bool()) + val write_address = Input(UInt(Parameters.PhysicalRegisterAddrWidth)) + val write_data = Input(UInt(Parameters.DataWidth)) + + val read_address1 = Input(UInt(Parameters.PhysicalRegisterAddrWidth)) + val read_address2 = Input(UInt(Parameters.PhysicalRegisterAddrWidth)) + val read_data1 = Output(UInt(Parameters.DataWidth)) + val read_data2 = Output(UInt(Parameters.DataWidth)) + + val debug_read_address = Input(UInt(Parameters.PhysicalRegisterAddrWidth)) + val debug_read_data = Output(UInt(Parameters.DataWidth)) + }) + val registers = Reg(Vec(Parameters.PhysicalRegisters, UInt(Parameters.DataWidth))) + + when(!reset.asBool) { + when(io.write_enable && io.write_address =/= 0.U) { + registers(io.write_address) := io.write_data + } + } + + io.read_data1 := MuxCase( + registers(io.read_address1), + IndexedSeq( + (io.read_address1 === 0.U) -> 0.U, + (io.read_address1 === io.write_address && io.write_enable) -> io.write_data + ) + ) + + io.read_data2 := MuxCase( + registers(io.read_address2), + IndexedSeq( + (io.read_address2 === 0.U) -> 0.U, + (io.read_address2 === io.write_address && io.write_enable) -> io.write_data + ) + ) + + io.debug_read_data := MuxCase( + registers(io.debug_read_address), + IndexedSeq( + (io.debug_read_address === 0.U) -> 0.U, + (io.debug_read_address === io.write_address && io.write_enable) -> io.write_data + ) + ) + +} diff --git a/lab4/src/main/scala/riscv/debug/DebugModule.scala b/lab4/src/main/scala/riscv/debug/DebugModule.scala new file mode 100644 index 0000000..23ab101 --- /dev/null +++ b/lab4/src/main/scala/riscv/debug/DebugModule.scala @@ -0,0 +1,33 @@ +// 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.debug + +import chisel3._ + +object DMRegisters { + val DATA0 = 0x04.U + val DATA11 = 0x0F.U + val DMCONTROL = 0x10.U + val DMSTATUS = 0x11.U + val HARTINFO = 0x12.U + val ABSTRACTCS = 0x16.U + val COMMAND = 0x17.U +} + +class DebugModule extends Module { + val io = IO(new Bundle { + + }) +} diff --git a/lab4/src/main/scala/riscv/debug/DebugTransportModule.scala b/lab4/src/main/scala/riscv/debug/DebugTransportModule.scala new file mode 100644 index 0000000..0af98b4 --- /dev/null +++ b/lab4/src/main/scala/riscv/debug/DebugTransportModule.scala @@ -0,0 +1,35 @@ +// 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.debug + +import chisel3._ +import chisel3.util._ + +object DTMRegisters { + val IDCODE = 0x01.U + val DTMCS = 0x10.U + val DMI = 0x11.U + val BYPASS1F = 0x1F.U +} + +class DebugTransportModule extends Module { + val io = IO(new Bundle { + + }) + + val idcode = 0x1e200151.U + val dtmcs = RegInit("b00000000000000000101000011100001".U) + val dmi = RegInit(UInt(48.W)) +} diff --git a/lab4/src/test/scala/riscv/BusTest.scala b/lab4/src/test/scala/riscv/BusTest.scala new file mode 100644 index 0000000..9e9fe1a --- /dev/null +++ b/lab4/src/test/scala/riscv/BusTest.scala @@ -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) + } + } +} + + + diff --git a/lab4/src/test/scala/riscv/TestAnnotations.scala b/lab4/src/test/scala/riscv/TestAnnotations.scala new file mode 100644 index 0000000..7842a95 --- /dev/null +++ b/lab4/src/test/scala/riscv/TestAnnotations.scala @@ -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 +} diff --git a/lab4/src/test/scala/riscv/fivestage/CPUTest.scala b/lab4/src/test/scala/riscv/fivestage/CPUTest.scala new file mode 100644 index 0000000..8de3bbb --- /dev/null +++ b/lab4/src/test/scala/riscv/fivestage/CPUTest.scala @@ -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 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 "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 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 "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) + } + } +} diff --git a/lab4/src/test/scala/riscv/threestage/CPUTest.scala b/lab4/src/test/scala/riscv/threestage/CPUTest.scala new file mode 100644 index 0000000..0c1535c --- /dev/null +++ b/lab4/src/test/scala/riscv/threestage/CPUTest.scala @@ -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) + } + } +} + diff --git a/lab4/verilog/basys3/test.v b/lab4/verilog/basys3/test.v new file mode 100644 index 0000000..9f3f6a6 --- /dev/null +++ b/lab4/verilog/basys3/test.v @@ -0,0 +1,35 @@ +`timescale 1ns / 1ps +////////////////////////////////////////////////////////////////////////////////// +// Company: +// Engineer: +// +// Create Date: 2021/12/17 16:31:05 +// Design Name: +// Module Name: test +// Project Name: +// Target Devices: +// Tool Versions: +// Description: +// +// Dependencies: +// +// Revision: +// Revision 0.01 - File Created +// Additional Comments: +// +////////////////////////////////////////////////////////////////////////////////// + + +module test(); +reg clock; +reg reset; +initial begin +clock = 0; +forever #1 clock = ~clock; +end +initial begin +reset = 1; +#2 reset = 0; +end +Top top(clock, reset); +endmodule diff --git a/lab4/verilog/pynq/TMDS_PLLVR.v b/lab4/verilog/pynq/TMDS_PLLVR.v new file mode 100644 index 0000000..1bc4dfb --- /dev/null +++ b/lab4/verilog/pynq/TMDS_PLLVR.v @@ -0,0 +1,221 @@ + +// file: TMDS_PLLVR.v +// +// (c) Copyright 2008 - 2013 Xilinx, Inc. All rights reserved. +// +// This file contains confidential and proprietary information +// of Xilinx, Inc. and is protected under U.S. and +// international copyright and other intellectual property +// laws. +// +// DISCLAIMER +// This disclaimer is not a license and does not grant any +// rights to the materials distributed herewith. Except as +// otherwise provided in a valid license issued to you by +// Xilinx, and to the maximum extent permitted by applicable +// law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND +// WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES +// AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING +// BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON- +// INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and +// (2) Xilinx shall not be liable (whether in contract or tort, +// including negligence, or under any other theory of +// liability) for any loss or damage of any kind or nature +// related to, arising under or in connection with these +// materials, including for any direct, or any indirect, +// special, incidental, or consequential loss or damage +// (including loss of data, profits, goodwill, or any type of +// loss or damage suffered as a result of any action brought +// by a third party) even if such damage or loss was +// reasonably foreseeable or Xilinx had been advised of the +// possibility of the same. +// +// CRITICAL APPLICATIONS +// Xilinx products are not designed or intended to be fail- +// safe, or for use in any application requiring fail-safe +// performance, such as life-support or safety devices or +// systems, Class III medical devices, nuclear facilities, +// applications related to the deployment of airbags, or any +// other applications that could lead to death, personal +// injury, or severe property or environmental damage +// (individually and collectively, "Critical +// Applications"). Customer assumes the sole risk and +// liability of any use of Xilinx products in Critical +// Applications, subject only to applicable laws and +// regulations governing limitations on product liability. +// +// THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS +// PART OF THIS FILE AT ALL TIMES. +// +//---------------------------------------------------------------------------- +// User entered comments +//---------------------------------------------------------------------------- +// None +// +//---------------------------------------------------------------------------- +// Output Output Phase Duty Cycle Pk-to-Pk Phase +// Clock Freq (MHz) (degrees) (%) Jitter (ps) Error (ps) +//---------------------------------------------------------------------------- +// __clkout__250.00000______0.000______50.0______200.536____237.727 +// _clkoutd__100.00000______0.000______50.0______226.965____237.727 +// +//---------------------------------------------------------------------------- +// Input Clock Freq (MHz) Input Jitter (UI) +//---------------------------------------------------------------------------- +// __primary__________25.000____________0.010 + +`timescale 1ps/1ps + +(* CORE_GENERATION_INFO = "TMDS_PLLVR,clk_wiz_v6_0_5_0_0,{component_name=TMDS_PLLVR,use_phase_alignment=true,use_min_o_jitter=false,use_max_i_jitter=false,use_dyn_phase_shift=false,use_inclk_switchover=false,use_dyn_reconfig=false,enable_axi=0,feedback_source=FDBK_AUTO,PRIMITIVE=PLL,num_out_clk=2,clkin1_period=40.000,clkin2_period=10.0,use_power_down=false,use_reset=true,use_locked=true,use_inclk_stopped=false,feedback_type=SINGLE,CLOCK_MGR_TYPE=NA,manual_override=true}" *) + +module TMDS_PLLVR + ( + // Clock out ports + output clkout, + output clkoutd, + // Status and control signals + input reset, + output lock, + // Clock in ports + input clkin + ); + + TMDS_PLLVR_clk_wiz inst + ( + // Clock out ports + .clkout(clkout), + .clkoutd(clkoutd), + // Status and control signals + .reset(reset), + .lock(lock), + // Clock in ports + .clk_in1(clkin) + ); + +endmodule + + +module TMDS_PLLVR_clk_wiz + + (// Clock in ports + // Clock out ports + output clkout, + output clkoutd, + // Status and control signals + input reset, + output lock, + input clk_in1 + ); + // Input buffering + //------------------------------------ +wire clk_in1_TMDS_PLLVR; +wire clk_in2_TMDS_PLLVR; + IBUF clkin1_ibufg + (.O (clk_in1_TMDS_PLLVR), + .I (clk_in1)); + + + + + // Clocking PRIMITIVE + //------------------------------------ + + // Instantiation of the MMCM PRIMITIVE + // * Unused inputs are tied off + // * Unused outputs are labeled unused + + wire clkout_TMDS_PLLVR; + wire clkoutd_TMDS_PLLVR; + wire clk_out3_TMDS_PLLVR; + wire clk_out4_TMDS_PLLVR; + wire clk_out5_TMDS_PLLVR; + wire clk_out6_TMDS_PLLVR; + wire clk_out7_TMDS_PLLVR; + + wire [15:0] do_unused; + wire drdy_unused; + wire psdone_unused; + wire lock_int; + wire clkfbout_TMDS_PLLVR; + wire clkfbout_buf_TMDS_PLLVR; + wire clkfboutb_unused; + wire clkout2_unused; + wire clkout3_unused; + wire clkout4_unused; + wire clkout5_unused; + wire clkout6_unused; + wire clkfbstopped_unused; + wire clkinstopped_unused; + wire reset_high; + + PLLE2_ADV + #(.BANDWIDTH ("OPTIMIZED"), + .COMPENSATION ("ZHOLD"), + .STARTUP_WAIT ("FALSE"), + .DIVCLK_DIVIDE (1), + .CLKFBOUT_MULT (40), + .CLKFBOUT_PHASE (0.000), + .CLKOUT0_DIVIDE (4), + .CLKOUT0_PHASE (0.000), + .CLKOUT0_DUTY_CYCLE (0.500), + .CLKOUT1_DIVIDE (10), + .CLKOUT1_PHASE (0.000), + .CLKOUT1_DUTY_CYCLE (0.500), + .CLKIN1_PERIOD (40.000)) + plle2_adv_inst + // Output clocks + ( + .CLKFBOUT (clkfbout_TMDS_PLLVR), + .CLKOUT0 (clkout_TMDS_PLLVR), + .CLKOUT1 (clkoutd_TMDS_PLLVR), + .CLKOUT2 (clkout2_unused), + .CLKOUT3 (clkout3_unused), + .CLKOUT4 (clkout4_unused), + .CLKOUT5 (clkout5_unused), + // Input clock control + .CLKFBIN (clkfbout_buf_TMDS_PLLVR), + .CLKIN1 (clk_in1_TMDS_PLLVR), + .CLKIN2 (1'b0), + // Tied to always select the primary input clock + .CLKINSEL (1'b1), + // Ports for dynamic reconfiguration + .DADDR (7'h0), + .DCLK (1'b0), + .DEN (1'b0), + .DI (16'h0), + .DO (do_unused), + .DRDY (drdy_unused), + .DWE (1'b0), + // Other control and status signals + .LOCKED (lock_int), + .PWRDWN (1'b0), + .RST (reset_high)); + assign reset_high = reset; + + assign lock = lock_int; +// Clock Monitor clock assigning +//-------------------------------------- + // Output buffering + //----------------------------------- + + BUFG clkf_buf + (.O (clkfbout_buf_TMDS_PLLVR), + .I (clkfbout_TMDS_PLLVR)); + + + + + + + BUFG clkout1_buf + (.O (clkout), + .I (clkout_TMDS_PLLVR)); + + + BUFG clkout2_buf + (.O (clkoutd), + .I (clkoutd_TMDS_PLLVR)); + + + +endmodule diff --git a/lab4/verilog/pynq/design_1_wrapper.v b/lab4/verilog/pynq/design_1_wrapper.v new file mode 100644 index 0000000..5e2092d --- /dev/null +++ b/lab4/verilog/pynq/design_1_wrapper.v @@ -0,0 +1,136 @@ +//Copyright 1986-2020 Xilinx, Inc. All Rights Reserved. +//-------------------------------------------------------------------------------- +//Tool Version: Vivado v.2020.1 (win64) Build 2902540 Wed May 27 19:54:49 MDT 2020 +//Date : Thu Jun 9 10:53:21 2022 +//Host : DESKTOP-UR8AHA2 running 64-bit major release (build 9200) +//Command : generate_target design_1_wrapper.bd +//Design : design_1_wrapper +//Purpose : IP block netlist +//-------------------------------------------------------------------------------- +`timescale 1 ps / 1 ps + +module design_1_wrapper + (DDR_addr, + DDR_ba, + DDR_cas_n, + DDR_ck_n, + DDR_ck_p, + DDR_cke, + DDR_cs_n, + DDR_dm, + DDR_dq, + DDR_dqs_n, + DDR_dqs_p, + DDR_odt, + DDR_ras_n, + DDR_reset_n, + DDR_we_n, + FIXED_IO_ddr_vrn, + FIXED_IO_ddr_vrp, + FIXED_IO_mio, + FIXED_IO_ps_clk, + FIXED_IO_ps_porb, + FIXED_IO_ps_srstb, + io_hdmi_clk_n, + io_hdmi_clk_p, + io_hdmi_data_n, + io_hdmi_data_p, + io_hdmi_hpdn, + io_led, + io_rx, + io_tx, + reset); + inout [14:0]DDR_addr; + inout [2:0]DDR_ba; + inout DDR_cas_n; + inout DDR_ck_n; + inout DDR_ck_p; + inout DDR_cke; + inout DDR_cs_n; + inout [3:0]DDR_dm; + inout [31:0]DDR_dq; + inout [3:0]DDR_dqs_n; + inout [3:0]DDR_dqs_p; + inout DDR_odt; + inout DDR_ras_n; + inout DDR_reset_n; + inout DDR_we_n; + inout FIXED_IO_ddr_vrn; + inout FIXED_IO_ddr_vrp; + inout [53:0]FIXED_IO_mio; + inout FIXED_IO_ps_clk; + inout FIXED_IO_ps_porb; + inout FIXED_IO_ps_srstb; + output io_hdmi_clk_n; + output io_hdmi_clk_p; + output [2:0]io_hdmi_data_n; + output [2:0]io_hdmi_data_p; + output io_hdmi_hpdn; + output [3:0]io_led; + input io_rx; + output io_tx; + input reset; + + wire [14:0]DDR_addr; + wire [2:0]DDR_ba; + wire DDR_cas_n; + wire DDR_ck_n; + wire DDR_ck_p; + wire DDR_cke; + wire DDR_cs_n; + wire [3:0]DDR_dm; + wire [31:0]DDR_dq; + wire [3:0]DDR_dqs_n; + wire [3:0]DDR_dqs_p; + wire DDR_odt; + wire DDR_ras_n; + wire DDR_reset_n; + wire DDR_we_n; + wire FIXED_IO_ddr_vrn; + wire FIXED_IO_ddr_vrp; + wire [53:0]FIXED_IO_mio; + wire FIXED_IO_ps_clk; + wire FIXED_IO_ps_porb; + wire FIXED_IO_ps_srstb; + wire io_hdmi_clk_n; + wire io_hdmi_clk_p; + wire [2:0]io_hdmi_data_n; + wire [2:0]io_hdmi_data_p; + wire io_hdmi_hpdn; + wire [3:0]io_led; + wire io_rx; + wire io_tx; + wire reset; + + design_1 design_1_i + (.DDR_addr(DDR_addr), + .DDR_ba(DDR_ba), + .DDR_cas_n(DDR_cas_n), + .DDR_ck_n(DDR_ck_n), + .DDR_ck_p(DDR_ck_p), + .DDR_cke(DDR_cke), + .DDR_cs_n(DDR_cs_n), + .DDR_dm(DDR_dm), + .DDR_dq(DDR_dq), + .DDR_dqs_n(DDR_dqs_n), + .DDR_dqs_p(DDR_dqs_p), + .DDR_odt(DDR_odt), + .DDR_ras_n(DDR_ras_n), + .DDR_reset_n(DDR_reset_n), + .DDR_we_n(DDR_we_n), + .FIXED_IO_ddr_vrn(FIXED_IO_ddr_vrn), + .FIXED_IO_ddr_vrp(FIXED_IO_ddr_vrp), + .FIXED_IO_mio(FIXED_IO_mio), + .FIXED_IO_ps_clk(FIXED_IO_ps_clk), + .FIXED_IO_ps_porb(FIXED_IO_ps_porb), + .FIXED_IO_ps_srstb(FIXED_IO_ps_srstb), + .io_hdmi_clk_n(io_hdmi_clk_n), + .io_hdmi_clk_p(io_hdmi_clk_p), + .io_hdmi_data_n(io_hdmi_data_n), + .io_hdmi_data_p(io_hdmi_data_p), + .io_hdmi_hpdn(io_hdmi_hpdn), + .io_led(io_led), + .io_rx(io_rx), + .io_tx(io_tx), + .reset(reset)); +endmodule diff --git a/lab4/verilog/pynq/test.v b/lab4/verilog/pynq/test.v new file mode 100644 index 0000000..9f3f6a6 --- /dev/null +++ b/lab4/verilog/pynq/test.v @@ -0,0 +1,35 @@ +`timescale 1ns / 1ps +////////////////////////////////////////////////////////////////////////////////// +// Company: +// Engineer: +// +// Create Date: 2021/12/17 16:31:05 +// Design Name: +// Module Name: test +// Project Name: +// Target Devices: +// Tool Versions: +// Description: +// +// Dependencies: +// +// Revision: +// Revision 0.01 - File Created +// Additional Comments: +// +////////////////////////////////////////////////////////////////////////////////// + + +module test(); +reg clock; +reg reset; +initial begin +clock = 0; +forever #1 clock = ~clock; +end +initial begin +reset = 1; +#2 reset = 0; +end +Top top(clock, reset); +endmodule diff --git a/lab4/verilog/verilator/sim_main.cpp b/lab4/verilog/verilator/sim_main.cpp new file mode 100644 index 0000000..e2713fc --- /dev/null +++ b/lab4/verilog/verilator/sim_main.cpp @@ -0,0 +1,230 @@ +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "VTop.h" // From Verilating "top.v" + +class Memory { + std::vector memory; + + public: + Memory(size_t size) : memory(size, 0) {} + uint32_t read(size_t address) { + address = address / 4; + if (address >= memory.size()) { + printf("invalid read address 0x%08x\n", address * 4); + return 0; + } + return memory[address]; + } + + void write(size_t address, uint32_t value, bool write_strobe[4]) { + address = address / 4; + uint32_t write_mask = 0; + if (write_strobe[0]) write_mask |= 0x000000FF; + if (write_strobe[1]) write_mask |= 0x0000FF00; + if (write_strobe[2]) write_mask |= 0x00FF0000; + if (write_strobe[3]) write_mask |= 0xFF000000; + if (address >= memory.size()) { + printf("invalid write address 0x%08x\n", address * 4); + return; + } + memory[address] = (memory[address] & ~write_mask) | (value & write_mask); + } + + void load_binary(std::string const& filename, size_t load_address = 0x1000) { + std::ifstream file(filename, std::ios::binary); + if (!file) { + throw std::runtime_error("Could not open file " + filename); + } + file.seekg(0, std::ios::end); + size_t size = file.tellg(); + if (load_address + size > memory.size() * 4) { + throw std::runtime_error("File " + filename + " is too large (File is " + + std::to_string(size) + " bytes. Memory is " + + std::to_string(memory.size() * 4 - load_address) + " bytes.)"); + } + file.seekg(0, std::ios::beg); + for (int i = 0; i < size / 4; ++i) { + file.read(reinterpret_cast(&memory[i + load_address / 4]), + sizeof(uint32_t)); + } + } +}; + +class VCDTracer { + VerilatedVcdC* tfp = nullptr; + + public: + void enable(std::string const& filename, VTop& top) { + Verilated::traceEverOn(true); + tfp = new VerilatedVcdC; + top.trace(tfp, 99); + tfp->open(filename.c_str()); + tfp->set_time_resolution("1ps"); + tfp->set_time_unit("1ns"); + if (!tfp->isOpen()) { + throw std::runtime_error("Failed to open VCD dump file " + filename); + } + } + + void dump(vluint64_t time) { + if (tfp) { + tfp->dump(time); + } + } + + ~VCDTracer() { + if (tfp) { + tfp->close(); + delete tfp; + } + } +}; + +uint32_t parse_number(std::string const& str) { + if (str.size() > 2) { + auto&& prefix = str.substr(0, 2); + if (prefix == "0x" || prefix == "0X") { + return std::stoul(str.substr(2), nullptr, 16); + } + } + return std::stoul(str); +} + +class Simulator { + vluint64_t main_time = 0; + vluint64_t max_sim_time = 10000; + uint32_t halt_address = 0; + size_t memory_words = 1024 * 1024; // 4MB + bool dump_vcd = false; + std::unique_ptr top; + std::unique_ptr vcd_tracer; + std::unique_ptr memory; + bool dump_signature = false; + unsigned long signature_begin, signature_end; + std::string signature_filename; + std::string instruction_filename; + + public: + void parse_args(std::vector const& args) { + if (auto it = std::find(args.begin(), args.end(), "-halt"); + it != args.end()) { + halt_address = parse_number(*(it + 1)); + } + + if (auto it = std::find(args.begin(), args.end(), "-memory"); + it != args.end()) { + memory_words = std::stoul(*(it + 1)); + } + + if (auto it = std::find(args.begin(), args.end(), "-time"); + it != args.end()) { + max_sim_time = std::stoul(*(it + 1)); + } + + if (auto it = std::find(args.begin(), args.end(), "-vcd"); + it != args.end()) { + vcd_tracer->enable(*(it + 1), *top); + } + + if (auto it = std::find(args.begin(), args.end(), "-signature"); + it != args.end()) { + dump_signature = true; + signature_begin = parse_number(*(it + 1)); + signature_end = parse_number(*(it + 2)); + signature_filename = *(it + 3); + } + + if (auto it = std::find(args.begin(), args.end(), "-instruction"); + it != args.end()) { + instruction_filename = *(it + 1); + } + } + + Simulator(std::vector const& args) + : top(std::make_unique()), + vcd_tracer(std::make_unique()) { + parse_args(args); + memory = std::make_unique(memory_words); + if (!instruction_filename.empty()) { + memory->load_binary(instruction_filename); + } + } + + void run() { + top->reset = 1; + top->clock = 0; + top->io_mem_slave_read_valid = true; + top->eval(); + vcd_tracer->dump(main_time); + uint32_t memory_read_word = 0; + bool memory_write_strobe[4] = {false}; + bool uart_debounce = false; + while (main_time < max_sim_time && !Verilated::gotFinish()) { + ++main_time; + if (main_time > 2) { + top->reset = 0; + } + top->io_mem_slave_read_data = memory_read_word; + top->clock = !top->clock; + top->eval(); + if (top->io_uart_slave_write) { + if (uart_debounce && top->clock) { + std::cout << (char)top->io_uart_slave_write_data << std::flush; + } + if (!uart_debounce && top->clock) { + uart_debounce = true; + } + } else { + uart_debounce = false; + } + if (top->io_mem_slave_read) { + memory_read_word = memory->read(top->io_mem_slave_address); + } + if (top->io_mem_slave_write) { + memory_write_strobe[0] = top->io_mem_slave_write_strobe_0; + memory_write_strobe[1] = top->io_mem_slave_write_strobe_1; + memory_write_strobe[2] = top->io_mem_slave_write_strobe_2; + memory_write_strobe[3] = top->io_mem_slave_write_strobe_3; + memory->write(top->io_mem_slave_address, top->io_mem_slave_write_data, + memory_write_strobe); + } + vcd_tracer->dump(main_time); + if (halt_address) { + if (memory->read(halt_address) == 0xBABECAFE) { + break; + } + } + } + + if (dump_signature) { + char data[9] = {0}; + std::ofstream signature_file(signature_filename); + for (size_t addr = signature_begin; addr < signature_end; addr += 4) { + snprintf(data, 9, "%08x", memory->read(addr)); + signature_file << data << std::endl; + } + } + } + + ~Simulator() { + if (top) { + top->final(); + } + } +}; + +int main(int argc, char** argv) { + Verilated::commandArgs(argc, argv); + std::vector args(argv, argv + argc); + Simulator simulator(args); + simulator.run(); + return 0; +} diff --git a/lab4/vivado/basys3/basys3.xdc b/lab4/vivado/basys3/basys3.xdc new file mode 100644 index 0000000..9864546 --- /dev/null +++ b/lab4/vivado/basys3/basys3.xdc @@ -0,0 +1,307 @@ +# 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. + +## Clock signal +set_property PACKAGE_PIN W5 [get_ports clock] + set_property IOSTANDARD LVCMOS33 [get_ports clock] + create_clock -add -name sys_clk_pin -period 20.00 -waveform {0 5} [get_ports clock] + +## Switches +set_property PACKAGE_PIN V17 [get_ports {io_switch[0]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_switch[0]}] +set_property PACKAGE_PIN V16 [get_ports {io_switch[1]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_switch[1]}] +set_property PACKAGE_PIN W16 [get_ports {io_switch[2]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_switch[2]}] +set_property PACKAGE_PIN W17 [get_ports {io_switch[3]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_switch[3]}] +set_property PACKAGE_PIN W15 [get_ports {io_switch[4]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_switch[4]}] +set_property PACKAGE_PIN V15 [get_ports {io_switch[5]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_switch[5]}] +set_property PACKAGE_PIN W14 [get_ports {io_switch[6]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_switch[6]}] +set_property PACKAGE_PIN W13 [get_ports {io_switch[7]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_switch[7]}] +set_property PACKAGE_PIN V2 [get_ports {io_switch[8]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_switch[8]}] +set_property PACKAGE_PIN T3 [get_ports {io_switch[9]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_switch[9]}] +set_property PACKAGE_PIN T2 [get_ports {io_switch[10]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_switch[10]}] +set_property PACKAGE_PIN R3 [get_ports {io_switch[11]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_switch[11]}] +set_property PACKAGE_PIN W2 [get_ports {io_switch[12]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_switch[12]}] +set_property PACKAGE_PIN U1 [get_ports {io_switch[13]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_switch[13]}] +set_property PACKAGE_PIN T1 [get_ports {io_switch[14]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_switch[14]}] +set_property PACKAGE_PIN R2 [get_ports {io_switch[15]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_switch[15]}] + + +## LEDs +set_property PACKAGE_PIN U16 [get_ports {io_led[0]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_led[0]}] +set_property PACKAGE_PIN E19 [get_ports {io_led[1]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_led[1]}] +set_property PACKAGE_PIN U19 [get_ports {io_led[2]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_led[2]}] +set_property PACKAGE_PIN V19 [get_ports {io_led[3]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_led[3]}] +set_property PACKAGE_PIN W18 [get_ports {io_led[4]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_led[4]}] +set_property PACKAGE_PIN U15 [get_ports {io_led[5]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_led[5]}] +set_property PACKAGE_PIN U14 [get_ports {io_led[6]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_led[6]}] +set_property PACKAGE_PIN V14 [get_ports {io_led[7]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_led[7]}] +set_property PACKAGE_PIN V13 [get_ports {io_led[8]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_led[8]}] +set_property PACKAGE_PIN V3 [get_ports {io_led[9]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_led[9]}] +set_property PACKAGE_PIN W3 [get_ports {io_led[10]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_led[10]}] +set_property PACKAGE_PIN U3 [get_ports {io_led[11]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_led[11]}] +set_property PACKAGE_PIN P3 [get_ports {io_led[12]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_led[12]}] +set_property PACKAGE_PIN N3 [get_ports {io_led[13]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_led[13]}] +set_property PACKAGE_PIN P1 [get_ports {io_led[14]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_led[14]}] +set_property PACKAGE_PIN L1 [get_ports {io_led[15]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_led[15]}] + + +##7 segment display +set_property PACKAGE_PIN U7 [get_ports io_segs[0]] + set_property IOSTANDARD LVCMOS33 [get_ports io_segs[0]] +set_property PACKAGE_PIN V5 [get_ports io_segs[1]] + set_property IOSTANDARD LVCMOS33 [get_ports io_segs[1]] +set_property PACKAGE_PIN U5 [get_ports io_segs[2]] + set_property IOSTANDARD LVCMOS33 [get_ports io_segs[2]] +set_property PACKAGE_PIN V8 [get_ports io_segs[3]] + set_property IOSTANDARD LVCMOS33 [get_ports io_segs[3]] +set_property PACKAGE_PIN U8 [get_ports io_segs[4]] + set_property IOSTANDARD LVCMOS33 [get_ports io_segs[4]] +set_property PACKAGE_PIN W6 [get_ports io_segs[5]] + set_property IOSTANDARD LVCMOS33 [get_ports io_segs[5]] +set_property PACKAGE_PIN W7 [get_ports io_segs[6]] + set_property IOSTANDARD LVCMOS33 [get_ports io_segs[6]] +set_property PACKAGE_PIN V7 [get_ports io_segs[7]] + set_property IOSTANDARD LVCMOS33 [get_ports io_segs[7]] + +set_property PACKAGE_PIN U2 [get_ports {io_digit_mask[0]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_digit_mask[0]}] +set_property PACKAGE_PIN U4 [get_ports {io_digit_mask[1]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_digit_mask[1]}] +set_property PACKAGE_PIN V4 [get_ports {io_digit_mask[2]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_digit_mask[2]}] +set_property PACKAGE_PIN W4 [get_ports {io_digit_mask[3]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_digit_mask[3]}] + + +##Buttons +set_property PACKAGE_PIN U18 [get_ports reset] + set_property IOSTANDARD LVCMOS33 [get_ports reset] +#set_property PACKAGE_PIN T18 [get_ports io_freqIncrease] + #set_property IOSTANDARD LVCMOS33 [get_ports io_freqIncrease] +#set_property PACKAGE_PIN W19 [get_ports io_widthIncrease] + #set_property IOSTANDARD LVCMOS33 [get_ports io_widthIncrease] +#set_property PACKAGE_PIN T17 [get_ports io_widthDecrease] + #set_property IOSTANDARD LVCMOS33 [get_ports io_widthDecrease] +#set_property PACKAGE_PIN U17 [get_ports io_freqDecrease] + #set_property IOSTANDARD LVCMOS33 [get_ports io_freqDecrease] + + + +##Pmod Header JA +##Sch name = JA1 +#set_property PACKAGE_PIN J1 [get_ports {JA[0]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JA[0]}] +##Sch name = JA2 +#set_property PACKAGE_PIN L2 [get_ports {JA[1]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JA[1]}] +##Sch name = JA3 +#set_property PACKAGE_PIN J2 [get_ports {JA[2]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JA[2]}] +##Sch name = JA4 +#set_property PACKAGE_PIN G2 [get_ports {JA[3]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JA[3]}] +##Sch name = JA7 +#set_property PACKAGE_PIN H1 [get_ports {JA[4]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JA[4]}] +##Sch name = JA8 +#set_property PACKAGE_PIN K2 [get_ports {JA[5]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JA[5]}] +##Sch name = JA9 +#set_property PACKAGE_PIN H2 [get_ports {JA[6]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JA[6]}] +##Sch name = JA10 +#set_property PACKAGE_PIN G3 [get_ports {JA[7]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JA[7]}] + + + +##Pmod Header JB +##Sch name = JB1 +#set_property PACKAGE_PIN A14 [get_ports {JB[0]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JB[0]}] +##Sch name = JB2 +#set_property PACKAGE_PIN A16 [get_ports {JB[1]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JB[1]}] +##Sch name = JB3 +#set_property PACKAGE_PIN B15 [get_ports {JB[2]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JB[2]}] +##Sch name = JB4 +#set_property PACKAGE_PIN B16 [get_ports {JB[3]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JB[3]}] +##Sch name = JB7 +#set_property PACKAGE_PIN A15 [get_ports {JB[4]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JB[4]}] +##Sch name = JB8 +#set_property PACKAGE_PIN A17 [get_ports {JB[5]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JB[5]}] +##Sch name = JB9 +#set_property PACKAGE_PIN C15 [get_ports {JB[6]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JB[6]}] +##Sch name = JB10 +#set_property PACKAGE_PIN C16 [get_ports {JB[7]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JB[7]}] + + + +##Pmod Header JC +##Sch name = JC1 +#set_property PACKAGE_PIN K17 [get_ports {JC[0]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JC[0]}] +##Sch name = JC2 +#set_property PACKAGE_PIN M18 [get_ports {JC[1]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JC[1]}] +##Sch name = JC3 +#set_property PACKAGE_PIN N17 [get_ports {JC[2]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JC[2]}] +##Sch name = JC4 +#set_property PACKAGE_PIN P18 [get_ports {JC[3]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JC[3]}] +##Sch name = JC7 +#set_property PACKAGE_PIN L17 [get_ports {JC[4]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JC[4]}] +##Sch name = JC8 +#set_property PACKAGE_PIN M19 [get_ports {JC[5]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JC[5]}] +##Sch name = JC9 +#set_property PACKAGE_PIN P17 [get_ports {JC[6]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JC[6]}] +##Sch name = JC10 +#set_property PACKAGE_PIN R18 [get_ports {JC[7]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JC[7]}] + + +##Pmod Header JXADC +##Sch name = XA1_P +#set_property PACKAGE_PIN J3 [get_ports {JXADC[0]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JXADC[0]}] +##Sch name = XA2_P +#set_property PACKAGE_PIN L3 [get_ports {JXADC[1]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JXADC[1]}] +##Sch name = XA3_P +#set_property PACKAGE_PIN M2 [get_ports {JXADC[2]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JXADC[2]}] +##Sch name = XA4_P +#set_property PACKAGE_PIN N2 [get_ports {JXADC[3]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JXADC[3]}] +##Sch name = XA1_N +#set_property PACKAGE_PIN K3 [get_ports {JXADC[4]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JXADC[4]}] +##Sch name = XA2_N +#set_property PACKAGE_PIN M3 [get_ports {JXADC[5]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JXADC[5]}] +##Sch name = XA3_N +#set_property PACKAGE_PIN M1 [get_ports {JXADC[6]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JXADC[6]}] +##Sch name = XA4_N +#set_property PACKAGE_PIN N1 [get_ports {JXADC[7]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {JXADC[7]}] + + + +##VGA Connector +set_property PACKAGE_PIN G19 [get_ports {io_rgb[8]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_rgb[8]}] +set_property PACKAGE_PIN H19 [get_ports {io_rgb[9]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_rgb[9]}] +set_property PACKAGE_PIN J19 [get_ports {io_rgb[10]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_rgb[10]}] +set_property PACKAGE_PIN N19 [get_ports {io_rgb[11]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_rgb[11]}] +set_property PACKAGE_PIN N18 [get_ports {io_rgb[0]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_rgb[0]}] +set_property PACKAGE_PIN L18 [get_ports {io_rgb[1]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_rgb[1]}] +set_property PACKAGE_PIN K18 [get_ports {io_rgb[2]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_rgb[2]}] +set_property PACKAGE_PIN J18 [get_ports {io_rgb[3]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_rgb[3]}] +set_property PACKAGE_PIN J17 [get_ports {io_rgb[4]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_rgb[4]}] +set_property PACKAGE_PIN H17 [get_ports {io_rgb[5]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_rgb[5]}] +set_property PACKAGE_PIN G17 [get_ports {io_rgb[6]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_rgb[6]}] +set_property PACKAGE_PIN D17 [get_ports {io_rgb[7]}] + set_property IOSTANDARD LVCMOS33 [get_ports {io_rgb[7]}] +set_property PACKAGE_PIN P19 [get_ports io_hsync] + set_property IOSTANDARD LVCMOS33 [get_ports io_hsync] +set_property PACKAGE_PIN R19 [get_ports io_vsync] + set_property IOSTANDARD LVCMOS33 [get_ports io_vsync] + + +##USB-RS232 Interface +set_property PACKAGE_PIN B18 [get_ports io_rx] + set_property IOSTANDARD LVCMOS33 [get_ports io_rx] +set_property PACKAGE_PIN A18 [get_ports io_tx] + set_property IOSTANDARD LVCMOS33 [get_ports io_tx] + + +##USB HID (PS/2) +#set_property PACKAGE_PIN C17 [get_ports PS2Clk] + #set_property IOSTANDARD LVCMOS33 [get_ports PS2Clk] + #set_property PULLUP true [get_ports PS2Clk] +#set_property PACKAGE_PIN B17 [get_ports PS2Data] + #set_property IOSTANDARD LVCMOS33 [get_ports PS2Data] + #set_property PULLUP true [get_ports PS2Data] + + +##Quad SPI Flash +##Note that CCLK_0 cannot be placed in 7 series devices. You can access it using the +##STARTUPE2 primitive. +#set_property PACKAGE_PIN D18 [get_ports {QspiDB[0]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {QspiDB[0]}] +#set_property PACKAGE_PIN D19 [get_ports {QspiDB[1]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {QspiDB[1]}] +#set_property PACKAGE_PIN G18 [get_ports {QspiDB[2]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {QspiDB[2]}] +#set_property PACKAGE_PIN F18 [get_ports {QspiDB[3]}] + #set_property IOSTANDARD LVCMOS33 [get_ports {QspiDB[3]}] +#set_property PACKAGE_PIN K19 [get_ports QspiCSn] + #set_property IOSTANDARD LVCMOS33 [get_ports QspiCSn] + + +## Configuration options, can be used for all designs +set_property CONFIG_VOLTAGE 3.3 [current_design] +set_property CFGBVS VCCO [current_design] diff --git a/lab4/vivado/basys3/generate_and_program.tcl b/lab4/vivado/basys3/generate_and_program.tcl new file mode 100644 index 0000000..71df1af --- /dev/null +++ b/lab4/vivado/basys3/generate_and_program.tcl @@ -0,0 +1,17 @@ +# 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. + +# Only tested on Vivado 2020.1 on Windows 10 +source generate_bitstream.tcl +source program_device.tcl \ No newline at end of file diff --git a/lab4/vivado/basys3/generate_bitstream.tcl b/lab4/vivado/basys3/generate_bitstream.tcl new file mode 100644 index 0000000..e1a26fb --- /dev/null +++ b/lab4/vivado/basys3/generate_bitstream.tcl @@ -0,0 +1,55 @@ +# 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. + +source open_project.tcl + +while 1 { + if { [catch {launch_runs synth_1 -jobs 4 } ] } { + regexp {ERROR: \[Common (\d+-\d+)]} $errorInfo -> code + if { [string equal $code "12-978"] } { + puts "Already generated and up-to-date" + break + } elseif { [string equal $code "17-69"] } { + puts "Out of date, reset runs" + reset_runs synth_1 + continue + } else { + puts "UNKNOWN ERROR!!! $errorInfo" + exit + } + } + break +} + +wait_on_run synth_1 + +while 1 { + if { [catch {launch_runs impl_1 -jobs 4 -to_step write_bitstream } ] } { + regexp {ERROR: \[Vivado (\d+-\d+)]} $errorInfo -> code + if { [string equal $code "12-978"] } { + puts "Already generated and up-to-date" + break + } elseif { [string equal $code "12-1088"] } { + puts "Out of date, reset runs" + reset_runs impl_1 + continue + } else { + puts "UNKNOWN ERROR!!! $errorInfo" + exit + } + } + break +} + +wait_on_run impl_1 diff --git a/lab4/vivado/basys3/open_project.tcl b/lab4/vivado/basys3/open_project.tcl new file mode 100644 index 0000000..b20931a --- /dev/null +++ b/lab4/vivado/basys3/open_project.tcl @@ -0,0 +1,39 @@ +# 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. + +# Only tested on Vivado 2020.1 on Windows 10 + +# set variables +set project_dir riscv-basys3 +set project_name riscv-basys3 +set part xc7a35tcpg236-1 +set sources {../../verilog/basys3/Top.v} +set test_sources {../../verilog/basys3/test.v} + +# open the project. will create one if it doesn't exist +if {[file exist $project_dir]} { + # check that it's a directory + if {! [file isdirectory $project_dir]} { + puts "$project_dir exists, but it's a file" + } + open_project $project_dir/$project_name.xpr -part $part +} else { + create_project $project_name $project_dir -part $part +} + +add_files -norecurse $sources +update_compile_order -fileset sources_1 +add_files -fileset constrs_1 -norecurse basys3.xdc +add_files -fileset sim_1 -norecurse $test_sources +update_compile_order -fileset sim_1 diff --git a/lab4/vivado/basys3/program_device.tcl b/lab4/vivado/basys3/program_device.tcl new file mode 100644 index 0000000..12fe648 --- /dev/null +++ b/lab4/vivado/basys3/program_device.tcl @@ -0,0 +1,24 @@ +# 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. + +# Only tested on Vivado 2020.1 on Windows 10 +open_hw_manager +connect_hw_server -allow_non_jtag +open_hw_target +current_hw_device [get_hw_devices xc7a35t_0] +refresh_hw_server [current_hw_server] +open_hw_target [lindex [get_hw_targets] 0] +set_property PROGRAM.FILE {./riscv-basys3/riscv-basys3.runs/impl_1/Top.bit} [get_hw_devices xc7a35t_0] +program_hw_devices [get_hw_devices xc7a35t_0] +close_hw_target diff --git a/lab4/vivado/basys3/run.ps1 b/lab4/vivado/basys3/run.ps1 new file mode 100644 index 0000000..178feab --- /dev/null +++ b/lab4/vivado/basys3/run.ps1 @@ -0,0 +1,4 @@ +cd .. +sbt run +cd vivado +C:\Xilinx\Vivado\2020.1\bin\vivado -mode batch -source .\generate_and_program.tcl \ No newline at end of file diff --git a/lab4/vivado/basys3/run_simulation.tcl b/lab4/vivado/basys3/run_simulation.tcl new file mode 100644 index 0000000..7c1a23c --- /dev/null +++ b/lab4/vivado/basys3/run_simulation.tcl @@ -0,0 +1,24 @@ +# 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. + +source open_project.tcl + +launch_simulation +restart +open_vcd +log_wave -recursive [get_object /test/top/cpu/*] +log_vcd [get_object /test/top/cpu/*] +run 1000ns +close_vcd +close_sim diff --git a/lab4/vivado/pynq/generate_and_program.tcl b/lab4/vivado/pynq/generate_and_program.tcl new file mode 100644 index 0000000..71df1af --- /dev/null +++ b/lab4/vivado/pynq/generate_and_program.tcl @@ -0,0 +1,17 @@ +# 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. + +# Only tested on Vivado 2020.1 on Windows 10 +source generate_bitstream.tcl +source program_device.tcl \ No newline at end of file diff --git a/lab4/vivado/pynq/generate_bitstream.tcl b/lab4/vivado/pynq/generate_bitstream.tcl new file mode 100644 index 0000000..886475e --- /dev/null +++ b/lab4/vivado/pynq/generate_bitstream.tcl @@ -0,0 +1,57 @@ +# 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. + +source open_project.tcl +set_param general.maxThreads 16 +update_module_reference design_1_Top_0_0 + +while 1 { + if { [catch {launch_runs synth_1 -jobs 16 } ] } { + regexp {ERROR: \[Common (\d+-\d+)]} $errorInfo -> code + if { [string equal $code "12-978"] } { + puts "Already generated and up-to-date" + break + } elseif { [string equal $code "17-69"] } { + puts "Out of date, reset runs" + reset_runs synth_1 + continue + } else { + puts "UNKNOWN ERROR!!! $errorInfo" + exit + } + } + break +} + +wait_on_run synth_1 + +while 1 { + if { [catch {launch_runs impl_1 -jobs 16 -to_step write_bitstream } ] } { + regexp {ERROR: \[Vivado (\d+-\d+)]} $errorInfo -> code + if { [string equal $code "12-978"] } { + puts "Already generated and up-to-date" + break + } elseif { [string equal $code "12-1088"] } { + puts "Out of date, reset runs" + reset_runs impl_1 + continue + } else { + puts "UNKNOWN ERROR!!! $errorInfo" + exit + } + } + break +} + +wait_on_run impl_1 diff --git a/lab4/vivado/pynq/open_project.tcl b/lab4/vivado/pynq/open_project.tcl new file mode 100644 index 0000000..d3cc816 --- /dev/null +++ b/lab4/vivado/pynq/open_project.tcl @@ -0,0 +1,29 @@ +# 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. + +# Only tested on Vivado 2020.1 on Windows 10 +set project_dir riscv-pynq +set project_name riscv-pynq +set part xc7z020clg400-1 + +# open the project. will create one if it doesn't exist +if {[file exist $project_dir]} { + # check that it's a directory + if {! [file isdirectory $project_dir]} { + puts "$project_dir exists, but it's a file" + } + open_project $project_dir/$project_name.xpr -part $part +} else { + source riscv-pynq.tcl +} \ No newline at end of file diff --git a/lab4/vivado/pynq/program_device.tcl b/lab4/vivado/pynq/program_device.tcl new file mode 100644 index 0000000..fb6caab --- /dev/null +++ b/lab4/vivado/pynq/program_device.tcl @@ -0,0 +1,22 @@ +# 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. + +# Only tested on Vivado 2020.1 on Windows 10 +open_hw_manager +connect_hw_server -allow_non_jtag +refresh_hw_server [current_hw_server] +open_hw_target [lindex [get_hw_targets] 0] +set_property PROGRAM.FILE {riscv-pynq/riscv-pynq.runs/impl_1/design_1_wrapper.bit} [get_hw_devices xc7z020_1] +program_hw_devices [get_hw_devices xc7z020_1] +close_hw_target diff --git a/lab4/vivado/pynq/pynq.xdc b/lab4/vivado/pynq/pynq.xdc new file mode 100644 index 0000000..bdcd6b9 --- /dev/null +++ b/lab4/vivado/pynq/pynq.xdc @@ -0,0 +1,189 @@ +## This file is a general .xdc for the PYNQ-Z1 board Rev. C +## To use it in a project: +## - uncomment the lines corresponding to used pins +## - rename the used ports (in each line, after get_ports) according to the top level signal names in the project + +## Clock signal 125 MHz + +set_property -dict { PACKAGE_PIN H16 IOSTANDARD LVCMOS33 } [get_ports { clock }]; #IO_L13P_T2_MRCC_35 Sch=sysclk +create_clock -add -name sys_clk_pin -period 8.00 -waveform {0 4} [get_ports { clock }]; + +##Switches + +set_property -dict { PACKAGE_PIN M20 IOSTANDARD LVCMOS33 } [get_ports { io_debug_step }]; #IO_L7N_T1_AD2N_35 Sch=sw[0] +#set_property -dict { PACKAGE_PIN M19 IOSTANDARD LVCMOS33 } [get_ports { sw[1] }]; #IO_L7P_T1_AD2P_35 Sch=sw[1] + +##RGB LEDs + +#set_property -dict { PACKAGE_PIN L15 IOSTANDARD LVCMOS33 } [get_ports { led4_b }]; #IO_L22N_T3_AD7N_35 Sch=led4_b +#set_property -dict { PACKAGE_PIN G17 IOSTANDARD LVCMOS33 } [get_ports { led4_g }]; #IO_L16P_T2_35 Sch=led4_g +#set_property -dict { PACKAGE_PIN N15 IOSTANDARD LVCMOS33 } [get_ports { led4_r }]; #IO_L21P_T3_DQS_AD14P_35 Sch=led4_r +#set_property -dict { PACKAGE_PIN G14 IOSTANDARD LVCMOS33 } [get_ports { led5_b }]; #IO_0_35 Sch=led5_b +#set_property -dict { PACKAGE_PIN L14 IOSTANDARD LVCMOS33 } [get_ports { led5_g }]; #IO_L22P_T3_AD7P_35 Sch=led5_g +#set_property -dict { PACKAGE_PIN M15 IOSTANDARD LVCMOS33 } [get_ports { led5_r }]; #IO_L23N_T3_35 Sch=led5_r + +##LEDs + +set_property -dict { PACKAGE_PIN R14 IOSTANDARD LVCMOS33 } [get_ports { io_led[0] }]; #IO_L6N_T0_VREF_34 Sch=led[0] +set_property -dict { PACKAGE_PIN P14 IOSTANDARD LVCMOS33 } [get_ports { io_led[1] }]; #IO_L6P_T0_34 Sch=led[1] +set_property -dict { PACKAGE_PIN N16 IOSTANDARD LVCMOS33 } [get_ports { io_led[2] }]; #IO_L21N_T3_DQS_AD14N_35 Sch=led[2] +set_property -dict { PACKAGE_PIN M14 IOSTANDARD LVCMOS33 } [get_ports { io_led[3] }]; #IO_L23P_T3_35 Sch=led[3] + +##Buttons + +set_property -dict { PACKAGE_PIN D19 IOSTANDARD LVCMOS33 } [get_ports { reset }]; #IO_L4P_T0_35 Sch=btn[0] +set_property -dict { PACKAGE_PIN D20 IOSTANDARD LVCMOS33 } [get_ports { io_debug_clk }]; #IO_L4N_T0_35 Sch=btn[1] +#set_property -dict { PACKAGE_PIN L20 IOSTANDARD LVCMOS33 } [get_ports { btn[2] }]; #IO_L9N_T1_DQS_AD3N_35 Sch=btn[2] +#set_property -dict { PACKAGE_PIN L19 IOSTANDARD LVCMOS33 } [get_ports { btn[3] }]; #IO_L9P_T1_DQS_AD3P_35 Sch=btn[3] + +##Pmod Header JA + +#set_property -dict { PACKAGE_PIN Y18 IOSTANDARD LVCMOS33 } [get_ports { io_rx }]; #IO_L17P_T2_34 Sch=ja_p[1] +#set_property -dict { PACKAGE_PIN Y19 IOSTANDARD LVCMOS33 } [get_ports { io_tx }]; #IO_L17N_T2_34 Sch=ja_n[1] +set_property -dict { PACKAGE_PIN Y16 IOSTANDARD LVCMOS33 } [get_ports { io_rx }]; #IO_L7P_T1_34 Sch=ja_p[2] +set_property -dict { PACKAGE_PIN Y17 IOSTANDARD LVCMOS33 } [get_ports { io_tx }]; #IO_L7N_T1_34 Sch=ja_n[2] +#set_property -dict { PACKAGE_PIN U18 IOSTANDARD LVCMOS33 } [get_ports { ja[4] }]; #IO_L12P_T1_MRCC_34 Sch=ja_p[3] +#set_property -dict { PACKAGE_PIN U19 IOSTANDARD LVCMOS33 } [get_ports { ja[5] }]; #IO_L12N_T1_MRCC_34 Sch=ja_n[3] +#set_property -dict { PACKAGE_PIN W18 IOSTANDARD LVCMOS33 } [get_ports { ja[6] }]; #IO_L22P_T3_34 Sch=ja_p[4] +#set_property -dict { PACKAGE_PIN W19 IOSTANDARD LVCMOS33 } [get_ports { ja[7] }]; #IO_L22N_T3_34 Sch=ja_n[4] + +##Pmod Header JB + +#set_property -dict { PACKAGE_PIN W14 IOSTANDARD LVCMOS33 } [get_ports { jb[0] }]; #IO_L8P_T1_34 Sch=jb_p[1] +#set_property -dict { PACKAGE_PIN Y14 IOSTANDARD LVCMOS33 } [get_ports { jb[1] }]; #IO_L8N_T1_34 Sch=jb_n[1] +#set_property -dict { PACKAGE_PIN T11 IOSTANDARD LVCMOS33 } [get_ports { jb[2] }]; #IO_L1P_T0_34 Sch=jb_p[2] +#set_property -dict { PACKAGE_PIN T10 IOSTANDARD LVCMOS33 } [get_ports { jb[3] }]; #IO_L1N_T0_34 Sch=jb_n[2] +#set_property -dict { PACKAGE_PIN V16 IOSTANDARD LVCMOS33 } [get_ports { jb[4] }]; #IO_L18P_T2_34 Sch=jb_p[3] +#set_property -dict { PACKAGE_PIN W16 IOSTANDARD LVCMOS33 } [get_ports { jb[5] }]; #IO_L18N_T2_34 Sch=jb_n[3] +#set_property -dict { PACKAGE_PIN V12 IOSTANDARD LVCMOS33 } [get_ports { jb[6] }]; #IO_L4P_T0_34 Sch=jb_p[4] +#set_property -dict { PACKAGE_PIN W13 IOSTANDARD LVCMOS33 } [get_ports { jb[7] }]; #IO_L4N_T0_34 Sch=jb_n[4] + +##Audio Out + +#set_property -dict { PACKAGE_PIN R18 IOSTANDARD LVCMOS33 } [get_ports { aud_pwm }]; #IO_L20N_T3_34 Sch=aud_pwm +#set_property -dict { PACKAGE_PIN T17 IOSTANDARD LVCMOS33 } [get_ports { aud_sd }]; #IO_L20P_T3_34 Sch=aud_sd + +##Mic input + +#set_property -dict { PACKAGE_PIN F17 IOSTANDARD LVCMOS33 } [get_ports { m_clk }]; #IO_L6N_T0_VREF_35 Sch=m_clk +#set_property -dict { PACKAGE_PIN G18 IOSTANDARD LVCMOS33 } [get_ports { m_data }]; #IO_L16N_T2_35 Sch=m_data + +##ChipKit Single Ended Analog Inputs +##NOTE: The ck_an_p pins can be used as single ended analog inputs with voltages from 0-3.3V (Chipkit Analog pins A0-A5). +## These signals should only be connected to the XADC core. When using these pins as digital I/O, use pins ck_io[14-19]. + +#set_property -dict { PACKAGE_PIN D18 IOSTANDARD LVCMOS33 } [get_ports { ck_an_n[0] }]; #IO_L3N_T0_DQS_AD1N_35 Sch=ck_an_n[0] +#set_property -dict { PACKAGE_PIN E17 IOSTANDARD LVCMOS33 } [get_ports { ck_an_p[0] }]; #IO_L3P_T0_DQS_AD1P_35 Sch=ck_an_p[0] +#set_property -dict { PACKAGE_PIN E19 IOSTANDARD LVCMOS33 } [get_ports { ck_an_n[1] }]; #IO_L5N_T0_AD9N_35 Sch=ck_an_n[1] +#set_property -dict { PACKAGE_PIN E18 IOSTANDARD LVCMOS33 } [get_ports { ck_an_p[1] }]; #IO_L5P_T0_AD9P_35 Sch=ck_an_p[1] +#set_property -dict { PACKAGE_PIN J14 IOSTANDARD LVCMOS33 } [get_ports { ck_an_n[2] }]; #IO_L20N_T3_AD6N_35 Sch=ck_an_n[2] +#set_property -dict { PACKAGE_PIN K14 IOSTANDARD LVCMOS33 } [get_ports { ck_an_p[2] }]; #IO_L20P_T3_AD6P_35 Sch=ck_an_p[2] +#set_property -dict { PACKAGE_PIN J16 IOSTANDARD LVCMOS33 } [get_ports { ck_an_n[3] }]; #IO_L24N_T3_AD15N_35 Sch=ck_an_n[3] +#set_property -dict { PACKAGE_PIN K16 IOSTANDARD LVCMOS33 } [get_ports { ck_an_p[3] }]; #IO_L24P_T3_AD15P_35 Sch=ck_an_p[3] +#set_property -dict { PACKAGE_PIN H20 IOSTANDARD LVCMOS33 } [get_ports { ck_an_n[4] }]; #IO_L17N_T2_AD5N_35 Sch=ck_an_n[4] +#set_property -dict { PACKAGE_PIN J20 IOSTANDARD LVCMOS33 } [get_ports { ck_an_p[4] }]; #IO_L17P_T2_AD5P_35 Sch=ck_an_p[4] +#set_property -dict { PACKAGE_PIN G20 IOSTANDARD LVCMOS33 } [get_ports { ck_an_n[5] }]; #IO_L18N_T2_AD13N_35 Sch=ck_an_n[5] +#set_property -dict { PACKAGE_PIN G19 IOSTANDARD LVCMOS33 } [get_ports { ck_an_p[5] }]; #IO_L18P_T2_AD13P_35 Sch=ck_an_p[5] + +##ChipKit Digital I/O Low + +#set_property -dict { PACKAGE_PIN T14 IOSTANDARD LVCMOS33 } [get_ports { ck_io[0] }]; #IO_L5P_T0_34 Sch=ck_io[0] +#set_property -dict { PACKAGE_PIN U12 IOSTANDARD LVCMOS33 } [get_ports { ck_io[1] }]; #IO_L2N_T0_34 Sch=ck_io[1] +#set_property -dict { PACKAGE_PIN U13 IOSTANDARD LVCMOS33 } [get_ports { ck_io[2] }]; #IO_L3P_T0_DQS_PUDC_B_34 Sch=ck_io[2] +#set_property -dict { PACKAGE_PIN V13 IOSTANDARD LVCMOS33 } [get_ports { ck_io[3] }]; #IO_L3N_T0_DQS_34 Sch=ck_io[3] +#set_property -dict { PACKAGE_PIN V15 IOSTANDARD LVCMOS33 } [get_ports { ck_io[4] }]; #IO_L10P_T1_34 Sch=ck_io[4] +#set_property -dict { PACKAGE_PIN T15 IOSTANDARD LVCMOS33 } [get_ports { ck_io[5] }]; #IO_L5N_T0_34 Sch=ck_io[5] +#set_property -dict { PACKAGE_PIN R16 IOSTANDARD LVCMOS33 } [get_ports { ck_io[6] }]; #IO_L19P_T3_34 Sch=ck_io[6] +#set_property -dict { PACKAGE_PIN U17 IOSTANDARD LVCMOS33 } [get_ports { ck_io[7] }]; #IO_L9N_T1_DQS_34 Sch=ck_io[7] +#set_property -dict { PACKAGE_PIN V17 IOSTANDARD LVCMOS33 } [get_ports { ck_io[8] }]; #IO_L21P_T3_DQS_34 Sch=ck_io[8] +#set_property -dict { PACKAGE_PIN V18 IOSTANDARD LVCMOS33 } [get_ports { ck_io[9] }]; #IO_L21N_T3_DQS_34 Sch=ck_io[9] +#set_property -dict { PACKAGE_PIN T16 IOSTANDARD LVCMOS33 } [get_ports { ck_io[10] }]; #IO_L9P_T1_DQS_34 Sch=ck_io[10] +#set_property -dict { PACKAGE_PIN R17 IOSTANDARD LVCMOS33 } [get_ports { ck_io[11] }]; #IO_L19N_T3_VREF_34 Sch=ck_io[11] +#set_property -dict { PACKAGE_PIN P18 IOSTANDARD LVCMOS33 } [get_ports { ck_io[12] }]; #IO_L23N_T3_34 Sch=ck_io[12] +#set_property -dict { PACKAGE_PIN N17 IOSTANDARD LVCMOS33 } [get_ports { ck_io[13] }]; #IO_L23P_T3_34 Sch=ck_io[13] + +##ChipKit Digital I/O On Outer Analog Header +##NOTE: These pins should be used when using the analog header signals A0-A5 as digital I/O (Chipkit digital pins 14-19) + +#set_property -dict { PACKAGE_PIN Y11 IOSTANDARD LVCMOS33 } [get_ports { ck_io[14] }]; #IO_L18N_T2_13 Sch=ck_a[0] +#set_property -dict { PACKAGE_PIN Y12 IOSTANDARD LVCMOS33 } [get_ports { ck_io[15] }]; #IO_L20P_T3_13 Sch=ck_a[1] +#set_property -dict { PACKAGE_PIN W11 IOSTANDARD LVCMOS33 } [get_ports { ck_io[16] }]; #IO_L18P_T2_13 Sch=ck_a[2] +#set_property -dict { PACKAGE_PIN V11 IOSTANDARD LVCMOS33 } [get_ports { ck_io[17] }]; #IO_L21P_T3_DQS_13 Sch=ck_a[3] +#set_property -dict { PACKAGE_PIN T5 IOSTANDARD LVCMOS33 } [get_ports { ck_io[18] }]; #IO_L19P_T3_13 Sch=ck_a[4] +#set_property -dict { PACKAGE_PIN U10 IOSTANDARD LVCMOS33 } [get_ports { ck_io[19] }]; #IO_L12N_T1_MRCC_13 Sch=ck_a[5] + +##ChipKit Digital I/O On Inner Analog Header +##NOTE: These pins will need to be connected to the XADC core when used as differential analog inputs (Chipkit analog pins A6-A11) + +#set_property -dict { PACKAGE_PIN B20 IOSTANDARD LVCMOS33 } [get_ports { ck_io[20] }]; #IO_L1N_T0_AD0N_35 Sch=ad_n[0] +#set_property -dict { PACKAGE_PIN C20 IOSTANDARD LVCMOS33 } [get_ports { ck_io[21] }]; #IO_L1P_T0_AD0P_35 Sch=ad_p[0] +#set_property -dict { PACKAGE_PIN F20 IOSTANDARD LVCMOS33 } [get_ports { ck_io[22] }]; #IO_L15N_T2_DQS_AD12N_35 Sch=ad_n[12] +#set_property -dict { PACKAGE_PIN F19 IOSTANDARD LVCMOS33 } [get_ports { ck_io[23] }]; #IO_L15P_T2_DQS_AD12P_35 Sch=ad_p[12] +#set_property -dict { PACKAGE_PIN A20 IOSTANDARD LVCMOS33 } [get_ports { ck_io[24] }]; #IO_L2N_T0_AD8N_35 Sch=ad_n[8] +#set_property -dict { PACKAGE_PIN B19 IOSTANDARD LVCMOS33 } [get_ports { ck_io[25] }]; #IO_L2P_T0_AD8P_35 Sch=ad_p[8] + +##ChipKit Digital I/O High + +#set_property -dict { PACKAGE_PIN U5 IOSTANDARD LVCMOS33 } [get_ports { ck_io[26] }]; #IO_L19N_T3_VREF_13 Sch=ck_io[26] +#set_property -dict { PACKAGE_PIN V5 IOSTANDARD LVCMOS33 } [get_ports { ck_io[27] }]; #IO_L6N_T0_VREF_13 Sch=ck_io[27] +#set_property -dict { PACKAGE_PIN V6 IOSTANDARD LVCMOS33 } [get_ports { ck_io[28] }]; #IO_L22P_T3_13 Sch=ck_io[28] +#set_property -dict { PACKAGE_PIN U7 IOSTANDARD LVCMOS33 } [get_ports { ck_io[29] }]; #IO_L11P_T1_SRCC_13 Sch=ck_io[29] +#set_property -dict { PACKAGE_PIN V7 IOSTANDARD LVCMOS33 } [get_ports { ck_io[30] }]; #IO_L11N_T1_SRCC_13 Sch=ck_io[30] +#set_property -dict { PACKAGE_PIN U8 IOSTANDARD LVCMOS33 } [get_ports { ck_io[31] }]; #IO_L17N_T2_13 Sch=ck_io[31] +#set_property -dict { PACKAGE_PIN V8 IOSTANDARD LVCMOS33 } [get_ports { ck_io[32] }]; #IO_L15P_T2_DQS_13 Sch=ck_io[32] +#set_property -dict { PACKAGE_PIN V10 IOSTANDARD LVCMOS33 } [get_ports { ck_io[33] }]; #IO_L21N_T3_DQS_13 Sch=ck_io[33] +#set_property -dict { PACKAGE_PIN W10 IOSTANDARD LVCMOS33 } [get_ports { ck_io[34] }]; #IO_L16P_T2_13 Sch=ck_io[34] +#set_property -dict { PACKAGE_PIN W6 IOSTANDARD LVCMOS33 } [get_ports { ck_io[35] }]; #IO_L22N_T3_13 Sch=ck_io[35] +#set_property -dict { PACKAGE_PIN Y6 IOSTANDARD LVCMOS33 } [get_ports { ck_io[36] }]; #IO_L13N_T2_MRCC_13 Sch=ck_io[36] +#set_property -dict { PACKAGE_PIN Y7 IOSTANDARD LVCMOS33 } [get_ports { ck_io[37] }]; #IO_L13P_T2_MRCC_13 Sch=ck_io[37] +#set_property -dict { PACKAGE_PIN W8 IOSTANDARD LVCMOS33 } [get_ports { ck_io[38] }]; #IO_L15N_T2_DQS_13 Sch=ck_io[38] +#set_property -dict { PACKAGE_PIN Y8 IOSTANDARD LVCMOS33 } [get_ports { ck_io[39] }]; #IO_L14N_T2_SRCC_13 Sch=ck_io[39] +#set_property -dict { PACKAGE_PIN W9 IOSTANDARD LVCMOS33 } [get_ports { ck_io[40] }]; #IO_L16N_T2_13 Sch=ck_io[40] +#set_property -dict { PACKAGE_PIN Y9 IOSTANDARD LVCMOS33 } [get_ports { ck_io[41] }]; #IO_L14P_T2_SRCC_13 Sch=ck_io[41] +#set_property -dict { PACKAGE_PIN Y13 IOSTANDARD LVCMOS33 } [get_ports { ck_io[42] }]; #IO_L20N_T3_13 Sch=ck_ioa + +## ChipKit SPI + +#set_property -dict { PACKAGE_PIN W15 IOSTANDARD LVCMOS33 } [get_ports { ck_miso }]; #IO_L10N_T1_34 Sch=ck_miso +#set_property -dict { PACKAGE_PIN T12 IOSTANDARD LVCMOS33 } [get_ports { ck_mosi }]; #IO_L2P_T0_34 Sch=ck_mosi +#set_property -dict { PACKAGE_PIN H15 IOSTANDARD LVCMOS33 } [get_ports { ck_sck }]; #IO_L19P_T3_35 Sch=ck_sck +#set_property -dict { PACKAGE_PIN F16 IOSTANDARD LVCMOS33 } [get_ports { ck_ss }]; #IO_L6P_T0_35 Sch=ck_ss + +## ChipKit I2C + +#set_property -dict { PACKAGE_PIN P16 IOSTANDARD LVCMOS33 } [get_ports { ck_scl }]; #IO_L24N_T3_34 Sch=ck_scl +#set_property -dict { PACKAGE_PIN P15 IOSTANDARD LVCMOS33 } [get_ports { ck_sda }]; #IO_L24P_T3_34 Sch=ck_sda + +##HDMI Rx + +#set_property -dict { PACKAGE_PIN H17 IOSTANDARD LVCMOS33 } [get_ports { hdmi_rx_cec }]; #IO_L13N_T2_MRCC_35 Sch=hdmi_rx_cec +set_property -dict { PACKAGE_PIN P19 IOSTANDARD TMDS_33 } [get_ports { io_debug_hdmi_clk_n }]; #IO_L13N_T2_MRCC_34 Sch=hdmi_rx_clk_n +set_property -dict { PACKAGE_PIN N18 IOSTANDARD TMDS_33 } [get_ports { io_debug_hdmi_clk_p }]; #IO_L13P_T2_MRCC_34 Sch=hdmi_rx_clk_p +set_property -dict { PACKAGE_PIN W20 IOSTANDARD TMDS_33 } [get_ports { io_debug_hdmi_data_n[0] }]; #IO_L16N_T2_34 Sch=hdmi_rx_d_n[0] +set_property -dict { PACKAGE_PIN V20 IOSTANDARD TMDS_33 } [get_ports { io_debug_hdmi_data_p[0] }]; #IO_L16P_T2_34 Sch=hdmi_rx_d_p[0] +set_property -dict { PACKAGE_PIN U20 IOSTANDARD TMDS_33 } [get_ports { io_debug_hdmi_data_n[1] }]; #IO_L15N_T2_DQS_34 Sch=hdmi_rx_d_n[1] +set_property -dict { PACKAGE_PIN T20 IOSTANDARD TMDS_33 } [get_ports { io_debug_hdmi_data_p[1] }]; #IO_L15P_T2_DQS_34 Sch=hdmi_rx_d_p[1] +set_property -dict { PACKAGE_PIN P20 IOSTANDARD TMDS_33 } [get_ports { io_debug_hdmi_data_n[2] }]; #IO_L14N_T2_SRCC_34 Sch=hdmi_rx_d_n[2] +set_property -dict { PACKAGE_PIN N20 IOSTANDARD TMDS_33 } [get_ports { io_debug_hdmi_data_p[2] }]; #IO_L14P_T2_SRCC_34 Sch=hdmi_rx_d_p[2] +set_property -dict { PACKAGE_PIN T19 IOSTANDARD LVCMOS33 } [get_ports { io_debug_hdmi_hpdn }]; #IO_25_34 Sch=hdmi_rx_hpd +#set_property -dict { PACKAGE_PIN U14 IOSTANDARD LVCMOS33 } [get_ports { hdmi_rx_scl }]; #IO_L11P_T1_SRCC_34 Sch=hdmi_rx_scl +#set_property -dict { PACKAGE_PIN U15 IOSTANDARD LVCMOS33 } [get_ports { hdmi_rx_sda }]; #IO_L11N_T1_SRCC_34 Sch=hdmi_rx_sda + +##HDMI Tx + +#set_property -dict { PACKAGE_PIN G15 IOSTANDARD LVCMOS33 } [get_ports { hdmi_tx_cec }]; #IO_L19N_T3_VREF_35 Sch=hdmi_tx_cec +set_property -dict { PACKAGE_PIN L17 IOSTANDARD TMDS_33 } [get_ports { io_hdmi_clk_n }]; #IO_L11N_T1_SRCC_35 Sch=hdmi_tx_clk_n +set_property -dict { PACKAGE_PIN L16 IOSTANDARD TMDS_33 } [get_ports { io_hdmi_clk_p }]; #IO_L11P_T1_SRCC_35 Sch=hdmi_tx_clk_p +set_property -dict { PACKAGE_PIN K18 IOSTANDARD TMDS_33 } [get_ports { io_hdmi_data_n[0] }]; #IO_L12N_T1_MRCC_35 Sch=hdmi_tx_d_n[0] +set_property -dict { PACKAGE_PIN K17 IOSTANDARD TMDS_33 } [get_ports { io_hdmi_data_p[0] }]; #IO_L12P_T1_MRCC_35 Sch=hdmi_tx_d_p[0] +set_property -dict { PACKAGE_PIN J19 IOSTANDARD TMDS_33 } [get_ports { io_hdmi_data_n[1] }]; #IO_L10N_T1_AD11N_35 Sch=hdmi_tx_d_n[1] +set_property -dict { PACKAGE_PIN K19 IOSTANDARD TMDS_33 } [get_ports { io_hdmi_data_p[1] }]; #IO_L10P_T1_AD11P_35 Sch=hdmi_tx_d_p[1] +set_property -dict { PACKAGE_PIN H18 IOSTANDARD TMDS_33 } [get_ports { io_hdmi_data_n[2] }]; #IO_L14N_T2_AD4N_SRCC_35 Sch=hdmi_tx_d_n[2] +set_property -dict { PACKAGE_PIN J18 IOSTANDARD TMDS_33 } [get_ports { io_hdmi_data_p[2] }]; #IO_L14P_T2_AD4P_SRCC_35 Sch=hdmi_tx_d_p[2] +set_property -dict { PACKAGE_PIN R19 IOSTANDARD LVCMOS33 } [get_ports { io_hdmi_hpdn }]; #IO_0_34 Sch=hdmi_tx_hpdn +#set_property -dict { PACKAGE_PIN M17 IOSTANDARD LVCMOS33 } [get_ports { hdmi_tx_scl }]; #IO_L8P_T1_AD10P_35 Sch=hdmi_tx_scl +#set_property -dict { PACKAGE_PIN M18 IOSTANDARD LVCMOS33 } [get_ports { hdmi_tx_sda }]; #IO_L8N_T1_AD10N_35 Sch=hdmi_tx_sda + +##Crypto SDA + +#set_property -dict { PACKAGE_PIN J15 IOSTANDARD LVCMOS33 } [get_ports { crypto_sda }]; #IO_25_35 Sch=crypto_sda \ No newline at end of file diff --git a/lab4/vivado/pynq/riscv-pynq.tcl b/lab4/vivado/pynq/riscv-pynq.tcl new file mode 100644 index 0000000..9f033d7 --- /dev/null +++ b/lab4/vivado/pynq/riscv-pynq.tcl @@ -0,0 +1,1602 @@ +#***************************************************************************************** +# Vivado (TM) v2020.1 (64-bit) +# +# riscv-pynq.tcl: Tcl script for re-creating project 'riscv-pynq' +# +# Generated by Vivado on Thu Jun 09 10:55:13 +0800 2022 +# IP Build 2902112 on Wed May 27 22:43:36 MDT 2020 +# +# This file contains the Vivado Tcl commands for re-creating the project to the state* +# when this script was generated. In order to re-create the project, please source this +# file in the Vivado Tcl Shell. +# +# * Note that the runs in the created project will be configured the same way as the +# original project, however they will not be launched automatically. To regenerate the +# run results please launch the synthesis/implementation runs as needed. +# +#***************************************************************************************** +# NOTE: In order to use this script for source control purposes, please make sure that the +# following files are added to the source control system:- +# +# 1. This project restoration tcl script (riscv-pynq.tcl) that was generated. +# +# 2. The following source(s) files that were local or imported into the original project. +# (Please see the '$orig_proj_dir' and '$origin_dir' variable setting below at the start of the script) +# +# "verilog/pynq/design_1_wrapper.v" +# +# 3. The following remote source files that were added to the original project:- +# +# "verilog/pynq/TMDS_PLLVR.v" +# "verilog/pynq/Top.v" +# "vivado/pynq/pynq.xdc" +# "verilog/pynq/test.v" +# +#***************************************************************************************** + +# Set the reference directory for source file relative paths (by default the value is script directory path) +set origin_dir "../.." + +# Use origin directory path location variable, if specified in the tcl shell +if { [info exists ::origin_dir_loc] } { + set origin_dir $::origin_dir_loc +} + +# Set the project name +set _xil_proj_name_ "riscv-pynq" + +# Use project name variable, if specified in the tcl shell +if { [info exists ::user_project_name] } { + set _xil_proj_name_ $::user_project_name +} + +variable script_file +set script_file "riscv-pynq.tcl" + +# Help information for this script +proc print_help {} { + variable script_file + puts "\nDescription:" + puts "Recreate a Vivado project from this script. The created project will be" + puts "functionally equivalent to the original project for which this script was" + puts "generated. The script contains commands for creating a project, filesets," + puts "runs, adding/importing sources and setting properties on various objects.\n" + puts "Syntax:" + puts "$script_file" + puts "$script_file -tclargs \[--origin_dir \]" + puts "$script_file -tclargs \[--project_name \]" + puts "$script_file -tclargs \[--help\]\n" + puts "Usage:" + puts "Name Description" + puts "-------------------------------------------------------------------------" + puts "\[--origin_dir \] Determine source file paths wrt this path. Default" + puts " origin_dir path value is \".\", otherwise, the value" + puts " that was set with the \"-paths_relative_to\" switch" + puts " when this script was generated.\n" + puts "\[--project_name \] Create project with the specified name. Default" + puts " name is the name of the project from where this" + puts " script was generated.\n" + puts "\[--help\] Print help information for this script" + puts "-------------------------------------------------------------------------\n" + exit 0 +} + +if { $::argc > 0 } { + for {set i 0} {$i < $::argc} {incr i} { + set option [string trim [lindex $::argv $i]] + switch -regexp -- $option { + "--origin_dir" { incr i; set origin_dir [lindex $::argv $i] } + "--project_name" { incr i; set _xil_proj_name_ [lindex $::argv $i] } + "--help" { print_help } + default { + if { [regexp {^-} $option] } { + puts "ERROR: Unknown option '$option' specified, please type '$script_file -tclargs --help' for usage info.\n" + return 1 + } + } + } + } +} + +# Set the directory path for the original project from where this script was exported +set orig_proj_dir "[file normalize "$origin_dir/vivado/pynq/riscv-pynq"]" + +# Create project +create_project ${_xil_proj_name_} ./${_xil_proj_name_} -part xc7z020clg400-1 + +# Set the directory path for the new project +set proj_dir [get_property directory [current_project]] + +# Set project properties +set obj [current_project] +set_property -name "default_lib" -value "xil_defaultlib" -objects $obj +set_property -name "enable_vhdl_2008" -value "1" -objects $obj +set_property -name "ip_cache_permissions" -value "read write" -objects $obj +set_property -name "ip_output_repo" -value "$proj_dir/${_xil_proj_name_}.cache/ip" -objects $obj +set_property -name "mem.enable_memory_map_generation" -value "1" -objects $obj +set_property -name "part" -value "xc7z020clg400-1" -objects $obj +set_property -name "sim.central_dir" -value "$proj_dir/${_xil_proj_name_}.ip_user_files" -objects $obj +set_property -name "sim.ip.auto_export_scripts" -value "1" -objects $obj +set_property -name "simulator_language" -value "Mixed" -objects $obj +set_property -name "webtalk.activehdl_export_sim" -value "1" -objects $obj +set_property -name "webtalk.ies_export_sim" -value "1" -objects $obj +set_property -name "webtalk.modelsim_export_sim" -value "1" -objects $obj +set_property -name "webtalk.questa_export_sim" -value "1" -objects $obj +set_property -name "webtalk.riviera_export_sim" -value "1" -objects $obj +set_property -name "webtalk.vcs_export_sim" -value "1" -objects $obj +set_property -name "webtalk.xcelium_export_sim" -value "1" -objects $obj +set_property -name "webtalk.xsim_export_sim" -value "1" -objects $obj +set_property -name "xpm_libraries" -value "XPM_CDC XPM_MEMORY" -objects $obj + +# Create 'sources_1' fileset (if not found) +if {[string equal [get_filesets -quiet sources_1] ""]} { + create_fileset -srcset sources_1 +} + +# Set 'sources_1' fileset object +set obj [get_filesets sources_1] +set files [list \ + [file normalize "${origin_dir}/verilog/pynq/TMDS_PLLVR.v"] \ + [file normalize "${origin_dir}/verilog/pynq/Top.v"] \ +] +add_files -norecurse -fileset $obj $files + +# Import local files from the original project +set files [list \ + [file normalize "${origin_dir}/verilog/pynq/design_1_wrapper.v" ]\ +] +set imported_files [import_files -fileset sources_1 $files] + +# Set 'sources_1' fileset file properties for remote files +# None + +# Set 'sources_1' fileset file properties for local files +# None + +# Set 'sources_1' fileset properties +set obj [get_filesets sources_1] +set_property -name "top" -value "design_1_wrapper" -objects $obj +set_property -name "top_auto_set" -value "0" -objects $obj + +# Create 'constrs_1' fileset (if not found) +if {[string equal [get_filesets -quiet constrs_1] ""]} { + create_fileset -constrset constrs_1 +} + +# Set 'constrs_1' fileset object +set obj [get_filesets constrs_1] + +# Add/Import constrs file and set constrs file properties +set file "[file normalize "$origin_dir/vivado/pynq/pynq.xdc"]" +set file_added [add_files -norecurse -fileset $obj [list $file]] +set file "$origin_dir/vivado/pynq/pynq.xdc" +set file [file normalize $file] +set file_obj [get_files -of_objects [get_filesets constrs_1] [list "*$file"]] +set_property -name "file_type" -value "XDC" -objects $file_obj + +# Set 'constrs_1' fileset properties +set obj [get_filesets constrs_1] +set_property -name "target_part" -value "xc7z020clg400-1" -objects $obj + +# Create 'sim_1' fileset (if not found) +if {[string equal [get_filesets -quiet sim_1] ""]} { + create_fileset -simset sim_1 +} + +# Set 'sim_1' fileset object +set obj [get_filesets sim_1] +set files [list \ + [file normalize "${origin_dir}/verilog/pynq/test.v"] \ +] +add_files -norecurse -fileset $obj $files + +# Set 'sim_1' fileset file properties for remote files +# None + +# Set 'sim_1' fileset file properties for local files +# None + +# Set 'sim_1' fileset properties +set obj [get_filesets sim_1] +set_property -name "hbs.configure_design_for_hier_access" -value "1" -objects $obj +set_property -name "top" -value "test" -objects $obj +set_property -name "top_lib" -value "xil_defaultlib" -objects $obj + +# Set 'utils_1' fileset object +set obj [get_filesets utils_1] +# Empty (no sources present) + +# Set 'utils_1' fileset properties +set obj [get_filesets utils_1] + + +# Adding sources referenced in BDs, if not already added +if { [get_files TMDS_PLLVR.v] == "" } { + import_files -quiet -fileset sources_1 ${origin_dir}/verilog/pynq/TMDS_PLLVR.v +} +if { [get_files Top.v] == "" } { + import_files -quiet -fileset sources_1 ${origin_dir}/verilog/pynq/Top.v +} + + +# Proc to create BD design_1 +proc cr_bd_design_1 { parentCell } { +# The design that will be created by this Tcl proc contains the following +# module references: +# Top + + + + # CHANGE DESIGN NAME HERE + set design_name design_1 + + common::send_gid_msg -ssname BD::TCL -id 2010 -severity "INFO" "Currently there is no design <$design_name> in project, so creating one..." + + create_bd_design $design_name + + set bCheckIPsPassed 1 + ################################################################## + # CHECK IPs + ################################################################## + set bCheckIPs 1 + if { $bCheckIPs == 1 } { + set list_check_ips "\ + xilinx.com:ip:processing_system7:5.5\ + xilinx.com:ip:proc_sys_reset:5.0\ + " + + set list_ips_missing "" + common::send_gid_msg -ssname BD::TCL -id 2011 -severity "INFO" "Checking if the following IPs exist in the project's IP catalog: $list_check_ips ." + + foreach ip_vlnv $list_check_ips { + set ip_obj [get_ipdefs -all $ip_vlnv] + if { $ip_obj eq "" } { + lappend list_ips_missing $ip_vlnv + } + } + + if { $list_ips_missing ne "" } { + catch {common::send_gid_msg -ssname BD::TCL -id 2012 -severity "ERROR" "The following IPs are not found in the IP Catalog:\n $list_ips_missing\n\nResolution: Please add the repository containing the IP(s) to the project." } + set bCheckIPsPassed 0 + } + + } + + ################################################################## + # CHECK Modules + ################################################################## + set bCheckModules 1 + if { $bCheckModules == 1 } { + set list_check_mods "\ + Top\ + " + + set list_mods_missing "" + common::send_gid_msg -ssname BD::TCL -id 2020 -severity "INFO" "Checking if the following modules exist in the project's sources: $list_check_mods ." + + foreach mod_vlnv $list_check_mods { + if { [can_resolve_reference $mod_vlnv] == 0 } { + lappend list_mods_missing $mod_vlnv + } + } + + if { $list_mods_missing ne "" } { + catch {common::send_gid_msg -ssname BD::TCL -id 2021 -severity "ERROR" "The following module(s) are not found in the project: $list_mods_missing" } + common::send_gid_msg -ssname BD::TCL -id 2022 -severity "INFO" "Please add source files for the missing module(s) above." + set bCheckIPsPassed 0 + } +} + + if { $bCheckIPsPassed != 1 } { + common::send_gid_msg -ssname BD::TCL -id 2023 -severity "WARNING" "Will not continue with creation of design due to the error(s) above." + return 3 + } + + variable script_folder + + if { $parentCell eq "" } { + set parentCell [get_bd_cells /] + } + + # Get object for parentCell + set parentObj [get_bd_cells $parentCell] + if { $parentObj == "" } { + catch {common::send_gid_msg -ssname BD::TCL -id 2090 -severity "ERROR" "Unable to find parent cell <$parentCell>!"} + return + } + + # Make sure parentObj is hier blk + set parentType [get_property TYPE $parentObj] + if { $parentType ne "hier" } { + catch {common::send_gid_msg -ssname BD::TCL -id 2091 -severity "ERROR" "Parent <$parentObj> has TYPE = <$parentType>. Expected to be ."} + return + } + + # Save current instance; Restore later + set oldCurInst [current_bd_instance .] + + # Set parent object as current + current_bd_instance $parentObj + + + # Create interface ports + set DDR [ create_bd_intf_port -mode Master -vlnv xilinx.com:interface:ddrx_rtl:1.0 DDR ] + + set FIXED_IO [ create_bd_intf_port -mode Master -vlnv xilinx.com:display_processing_system7:fixedio_rtl:1.0 FIXED_IO ] + + + # Create ports + set io_hdmi_clk_n [ create_bd_port -dir O -type clk io_hdmi_clk_n ] + set io_hdmi_clk_p [ create_bd_port -dir O -type clk io_hdmi_clk_p ] + set io_hdmi_data_n [ create_bd_port -dir O -from 2 -to 0 io_hdmi_data_n ] + set io_hdmi_data_p [ create_bd_port -dir O -from 2 -to 0 io_hdmi_data_p ] + set io_hdmi_hpdn [ create_bd_port -dir O io_hdmi_hpdn ] + set io_led [ create_bd_port -dir O -from 3 -to 0 io_led ] + set io_rx [ create_bd_port -dir I io_rx ] + set io_tx [ create_bd_port -dir O io_tx ] + set reset [ create_bd_port -dir I -type rst reset ] + set_property -dict [ list \ + CONFIG.POLARITY {ACTIVE_HIGH} \ + ] $reset + + # Create instance: Top_0, and set properties + set block_name Top + set block_cell_name Top_0 + if { [catch {set Top_0 [create_bd_cell -type module -reference $block_name $block_cell_name] } errmsg] } { + catch {common::send_gid_msg -ssname BD::TCL -id 2095 -severity "ERROR" "Unable to add referenced block <$block_name>. Please add the files for ${block_name}'s definition into the project."} + return 1 + } elseif { $Top_0 eq "" } { + catch {common::send_gid_msg -ssname BD::TCL -id 2096 -severity "ERROR" "Unable to referenced block <$block_name>. Please add the files for ${block_name}'s definition into the project."} + return 1 + } + + set_property -dict [ list \ + CONFIG.POLARITY {ACTIVE_HIGH} \ + ] [get_bd_pins /Top_0/reset] + + # Create instance: axi_mem_intercon, and set properties + set axi_mem_intercon [ create_bd_cell -type ip -vlnv xilinx.com:ip:axi_interconnect:2.1 axi_mem_intercon ] + set_property -dict [ list \ + CONFIG.NUM_MI {1} \ + ] $axi_mem_intercon + + # Create instance: processing_system7_0, and set properties + set processing_system7_0 [ create_bd_cell -type ip -vlnv xilinx.com:ip:processing_system7:5.5 processing_system7_0 ] + set_property -dict [ list \ + CONFIG.PCW_ACT_APU_PERIPHERAL_FREQMHZ {650.000000} \ + CONFIG.PCW_ACT_CAN0_PERIPHERAL_FREQMHZ {23.8095} \ + CONFIG.PCW_ACT_CAN1_PERIPHERAL_FREQMHZ {23.8095} \ + CONFIG.PCW_ACT_CAN_PERIPHERAL_FREQMHZ {10.000000} \ + CONFIG.PCW_ACT_DCI_PERIPHERAL_FREQMHZ {10.096154} \ + CONFIG.PCW_ACT_ENET0_PERIPHERAL_FREQMHZ {125.000000} \ + CONFIG.PCW_ACT_ENET1_PERIPHERAL_FREQMHZ {10.000000} \ + CONFIG.PCW_ACT_FPGA0_PERIPHERAL_FREQMHZ {125.000000} \ + CONFIG.PCW_ACT_FPGA1_PERIPHERAL_FREQMHZ {10.000000} \ + CONFIG.PCW_ACT_FPGA2_PERIPHERAL_FREQMHZ {10.000000} \ + CONFIG.PCW_ACT_FPGA3_PERIPHERAL_FREQMHZ {10.000000} \ + CONFIG.PCW_ACT_I2C_PERIPHERAL_FREQMHZ {50} \ + CONFIG.PCW_ACT_PCAP_PERIPHERAL_FREQMHZ {200.000000} \ + CONFIG.PCW_ACT_QSPI_PERIPHERAL_FREQMHZ {200.000000} \ + CONFIG.PCW_ACT_SDIO_PERIPHERAL_FREQMHZ {50.000000} \ + CONFIG.PCW_ACT_SMC_PERIPHERAL_FREQMHZ {10.000000} \ + CONFIG.PCW_ACT_SPI_PERIPHERAL_FREQMHZ {10.000000} \ + CONFIG.PCW_ACT_TPIU_PERIPHERAL_FREQMHZ {200.000000} \ + CONFIG.PCW_ACT_TTC0_CLK0_PERIPHERAL_FREQMHZ {108.333336} \ + CONFIG.PCW_ACT_TTC0_CLK1_PERIPHERAL_FREQMHZ {108.333336} \ + CONFIG.PCW_ACT_TTC0_CLK2_PERIPHERAL_FREQMHZ {108.333336} \ + CONFIG.PCW_ACT_TTC1_CLK0_PERIPHERAL_FREQMHZ {108.333336} \ + CONFIG.PCW_ACT_TTC1_CLK1_PERIPHERAL_FREQMHZ {108.333336} \ + CONFIG.PCW_ACT_TTC1_CLK2_PERIPHERAL_FREQMHZ {108.333336} \ + CONFIG.PCW_ACT_TTC_PERIPHERAL_FREQMHZ {50} \ + CONFIG.PCW_ACT_UART_PERIPHERAL_FREQMHZ {100.000000} \ + CONFIG.PCW_ACT_USB0_PERIPHERAL_FREQMHZ {60} \ + CONFIG.PCW_ACT_USB1_PERIPHERAL_FREQMHZ {60} \ + CONFIG.PCW_ACT_WDT_PERIPHERAL_FREQMHZ {108.333336} \ + CONFIG.PCW_APU_CLK_RATIO_ENABLE {6:2:1} \ + CONFIG.PCW_APU_PERIPHERAL_FREQMHZ {650} \ + CONFIG.PCW_ARMPLL_CTRL_FBDIV {26} \ + CONFIG.PCW_CAN0_BASEADDR {0xE0008000} \ + CONFIG.PCW_CAN0_CAN0_IO {} \ + CONFIG.PCW_CAN0_HIGHADDR {0xE0008FFF} \ + CONFIG.PCW_CAN0_PERIPHERAL_CLKSRC {External} \ + CONFIG.PCW_CAN0_PERIPHERAL_ENABLE {0} \ + CONFIG.PCW_CAN0_PERIPHERAL_FREQMHZ {-1} \ + CONFIG.PCW_CAN1_BASEADDR {0xE0009000} \ + CONFIG.PCW_CAN1_CAN1_IO {} \ + CONFIG.PCW_CAN1_HIGHADDR {0xE0009FFF} \ + CONFIG.PCW_CAN1_PERIPHERAL_CLKSRC {External} \ + CONFIG.PCW_CAN1_PERIPHERAL_ENABLE {0} \ + CONFIG.PCW_CAN1_PERIPHERAL_FREQMHZ {-1} \ + CONFIG.PCW_CAN_PERIPHERAL_CLKSRC {IO PLL} \ + CONFIG.PCW_CAN_PERIPHERAL_DIVISOR0 {1} \ + CONFIG.PCW_CAN_PERIPHERAL_DIVISOR1 {1} \ + CONFIG.PCW_CAN_PERIPHERAL_FREQMHZ {100} \ + CONFIG.PCW_CAN_PERIPHERAL_VALID {0} \ + CONFIG.PCW_CLK0_FREQ {125000000} \ + CONFIG.PCW_CLK1_FREQ {10000000} \ + CONFIG.PCW_CLK2_FREQ {10000000} \ + CONFIG.PCW_CLK3_FREQ {10000000} \ + CONFIG.PCW_CORE0_FIQ_INTR {0} \ + CONFIG.PCW_CORE0_IRQ_INTR {0} \ + CONFIG.PCW_CORE1_FIQ_INTR {0} \ + CONFIG.PCW_CORE1_IRQ_INTR {0} \ + CONFIG.PCW_CPU_CPU_6X4X_MAX_RANGE {667} \ + CONFIG.PCW_CPU_CPU_PLL_FREQMHZ {1300.000} \ + CONFIG.PCW_CPU_PERIPHERAL_CLKSRC {ARM PLL} \ + CONFIG.PCW_CPU_PERIPHERAL_DIVISOR0 {2} \ + CONFIG.PCW_CRYSTAL_PERIPHERAL_FREQMHZ {50} \ + CONFIG.PCW_DCI_PERIPHERAL_CLKSRC {DDR PLL} \ + CONFIG.PCW_DCI_PERIPHERAL_DIVISOR0 {52} \ + CONFIG.PCW_DCI_PERIPHERAL_DIVISOR1 {2} \ + CONFIG.PCW_DCI_PERIPHERAL_FREQMHZ {10.159} \ + CONFIG.PCW_DDRPLL_CTRL_FBDIV {21} \ + CONFIG.PCW_DDR_DDR_PLL_FREQMHZ {1050.000} \ + CONFIG.PCW_DDR_HPRLPR_QUEUE_PARTITION {HPR(0)/LPR(32)} \ + CONFIG.PCW_DDR_HPR_TO_CRITICAL_PRIORITY_LEVEL {15} \ + CONFIG.PCW_DDR_LPR_TO_CRITICAL_PRIORITY_LEVEL {2} \ + CONFIG.PCW_DDR_PERIPHERAL_CLKSRC {DDR PLL} \ + CONFIG.PCW_DDR_PERIPHERAL_DIVISOR0 {2} \ + CONFIG.PCW_DDR_PORT0_HPR_ENABLE {0} \ + CONFIG.PCW_DDR_PORT1_HPR_ENABLE {0} \ + CONFIG.PCW_DDR_PORT2_HPR_ENABLE {0} \ + CONFIG.PCW_DDR_PORT3_HPR_ENABLE {0} \ + CONFIG.PCW_DDR_PRIORITY_READPORT_0 {} \ + CONFIG.PCW_DDR_PRIORITY_READPORT_2 {} \ + CONFIG.PCW_DDR_PRIORITY_WRITEPORT_0 {} \ + CONFIG.PCW_DDR_PRIORITY_WRITEPORT_2 {} \ + CONFIG.PCW_DDR_RAM_BASEADDR {0x00100000} \ + CONFIG.PCW_DDR_RAM_HIGHADDR {0x1FFFFFFF} \ + CONFIG.PCW_DDR_WRITE_TO_CRITICAL_PRIORITY_LEVEL {2} \ + CONFIG.PCW_DM_WIDTH {4} \ + CONFIG.PCW_DQS_WIDTH {4} \ + CONFIG.PCW_DQ_WIDTH {32} \ + CONFIG.PCW_ENET0_BASEADDR {0xE000B000} \ + CONFIG.PCW_ENET0_ENET0_IO {MIO 16 .. 27} \ + CONFIG.PCW_ENET0_GRP_MDIO_ENABLE {1} \ + CONFIG.PCW_ENET0_GRP_MDIO_IO {MIO 52 .. 53} \ + CONFIG.PCW_ENET0_HIGHADDR {0xE000BFFF} \ + CONFIG.PCW_ENET0_PERIPHERAL_CLKSRC {IO PLL} \ + CONFIG.PCW_ENET0_PERIPHERAL_DIVISOR0 {8} \ + CONFIG.PCW_ENET0_PERIPHERAL_DIVISOR1 {1} \ + CONFIG.PCW_ENET0_PERIPHERAL_ENABLE {1} \ + CONFIG.PCW_ENET0_PERIPHERAL_FREQMHZ {1000 Mbps} \ + CONFIG.PCW_ENET0_RESET_ENABLE {1} \ + CONFIG.PCW_ENET0_RESET_IO {MIO 9} \ + CONFIG.PCW_ENET1_BASEADDR {0xE000C000} \ + CONFIG.PCW_ENET1_ENET1_IO {} \ + CONFIG.PCW_ENET1_HIGHADDR {0xE000CFFF} \ + CONFIG.PCW_ENET1_PERIPHERAL_CLKSRC {IO PLL} \ + CONFIG.PCW_ENET1_PERIPHERAL_DIVISOR0 {1} \ + CONFIG.PCW_ENET1_PERIPHERAL_DIVISOR1 {1} \ + CONFIG.PCW_ENET1_PERIPHERAL_ENABLE {0} \ + CONFIG.PCW_ENET1_PERIPHERAL_FREQMHZ {1000 Mbps} \ + CONFIG.PCW_ENET1_RESET_ENABLE {0} \ + CONFIG.PCW_ENET1_RESET_IO {} \ + CONFIG.PCW_FTM_CTI_IN1 {} \ + CONFIG.PCW_FTM_CTI_IN3 {} \ + CONFIG.PCW_FTM_CTI_OUT1 {} \ + CONFIG.PCW_FTM_CTI_OUT3 {} \ + CONFIG.PCW_GPIO_EMIO_GPIO_WIDTH {64} \ + CONFIG.PCW_GPIO_HIGHADDR {0xE000AFFF} \ + CONFIG.PCW_GPIO_MIO_GPIO_ENABLE {1} \ + CONFIG.PCW_GPIO_MIO_GPIO_IO {MIO} \ + CONFIG.PCW_GPIO_PERIPHERAL_ENABLE {0} \ + CONFIG.PCW_I2C0_BASEADDR {0xE0004000} \ + CONFIG.PCW_I2C0_GRP_INT_ENABLE {0} \ + CONFIG.PCW_I2C0_GRP_INT_IO {} \ + CONFIG.PCW_I2C0_PERIPHERAL_ENABLE {0} \ + CONFIG.PCW_I2C0_RESET_ENABLE {0} \ + CONFIG.PCW_I2C0_RESET_IO {} \ + CONFIG.PCW_I2C1_HIGHADDR {0xE0005FFF} \ + CONFIG.PCW_I2C1_I2C1_IO {} \ + CONFIG.PCW_I2C_PERIPHERAL_FREQMHZ {25} \ + CONFIG.PCW_I2C_RESET_ENABLE {1} \ + CONFIG.PCW_I2C_RESET_POLARITY {Active Low} \ + CONFIG.PCW_I2C_RESET_SELECT {} \ + CONFIG.PCW_NAND_NAND_IO {} \ + CONFIG.PCW_NOR_GRP_CS0_ENABLE {0} \ + CONFIG.PCW_NOR_GRP_CS0_IO {} \ + CONFIG.PCW_NOR_GRP_SRAM_CS0_ENABLE {0} \ + CONFIG.PCW_NOR_GRP_SRAM_CS0_IO {} \ + CONFIG.PCW_NOR_GRP_SRAM_INT_ENABLE {0} \ + CONFIG.PCW_NOR_GRP_SRAM_INT_IO {} \ + CONFIG.PCW_NOR_PERIPHERAL_ENABLE {0} \ + CONFIG.PCW_NOR_SRAM_CS0_T_CEOE {1} \ + CONFIG.PCW_NOR_SRAM_CS0_T_PC {1} \ + CONFIG.PCW_NOR_SRAM_CS0_T_RC {11} \ + CONFIG.PCW_NOR_SRAM_CS0_T_TR {1} \ + CONFIG.PCW_NOR_SRAM_CS0_T_WC {11} \ + CONFIG.PCW_NOR_SRAM_CS0_T_WP {1} \ + CONFIG.PCW_NOR_SRAM_CS0_WE_TIME {0} \ + CONFIG.PCW_NOR_SRAM_CS1_T_CEOE {1} \ + CONFIG.PCW_NOR_SRAM_CS1_T_PC {1} \ + CONFIG.PCW_NOR_SRAM_CS1_T_RC {11} \ + CONFIG.PCW_NOR_SRAM_CS1_T_TR {1} \ + CONFIG.PCW_NOR_SRAM_CS1_T_WC {11} \ + CONFIG.PCW_NOR_SRAM_CS1_T_WP {1} \ + CONFIG.PCW_NOR_SRAM_CS1_WE_TIME {0} \ + CONFIG.PCW_OVERRIDE_BASIC_CLOCK {0} \ + CONFIG.PCW_P2F_CAN0_INTR {0} \ + CONFIG.PCW_P2F_CAN1_INTR {0} \ + CONFIG.PCW_P2F_CTI_INTR {0} \ + CONFIG.PCW_P2F_DMAC0_INTR {0} \ + CONFIG.PCW_P2F_DMAC1_INTR {0} \ + CONFIG.PCW_P2F_DMAC2_INTR {0} \ + CONFIG.PCW_P2F_DMAC3_INTR {0} \ + CONFIG.PCW_P2F_DMAC4_INTR {0} \ + CONFIG.PCW_P2F_DMAC5_INTR {0} \ + CONFIG.PCW_P2F_DMAC6_INTR {0} \ + CONFIG.PCW_P2F_DMAC7_INTR {0} \ + CONFIG.PCW_P2F_DMAC_ABORT_INTR {0} \ + CONFIG.PCW_P2F_ENET0_INTR {0} \ + CONFIG.PCW_P2F_ENET1_INTR {0} \ + CONFIG.PCW_P2F_GPIO_INTR {0} \ + CONFIG.PCW_P2F_I2C0_INTR {0} \ + CONFIG.PCW_P2F_I2C1_INTR {0} \ + CONFIG.PCW_P2F_QSPI_INTR {0} \ + CONFIG.PCW_P2F_SDIO0_INTR {0} \ + CONFIG.PCW_P2F_SDIO1_INTR {0} \ + CONFIG.PCW_P2F_SMC_INTR {0} \ + CONFIG.PCW_P2F_SPI0_INTR {0} \ + CONFIG.PCW_P2F_SPI1_INTR {0} \ + CONFIG.PCW_P2F_UART0_INTR {0} \ + CONFIG.PCW_P2F_UART1_INTR {0} \ + CONFIG.PCW_P2F_USB0_INTR {0} \ + CONFIG.PCW_P2F_USB1_INTR {0} \ + CONFIG.PCW_PACKAGE_DDR_BOARD_DELAY0 {0.223} \ + CONFIG.PCW_PACKAGE_DDR_BOARD_DELAY1 {0.212} \ + CONFIG.PCW_PACKAGE_DDR_BOARD_DELAY2 {0.085} \ + CONFIG.PCW_PACKAGE_DDR_BOARD_DELAY3 {0.092} \ + CONFIG.PCW_PACKAGE_DDR_DQS_TO_CLK_DELAY_0 {0.040} \ + CONFIG.PCW_PACKAGE_DDR_DQS_TO_CLK_DELAY_1 {0.058} \ + CONFIG.PCW_PACKAGE_DDR_DQS_TO_CLK_DELAY_2 {-0.009} \ + CONFIG.PCW_PACKAGE_DDR_DQS_TO_CLK_DELAY_3 {-0.033} \ + CONFIG.PCW_PACKAGE_NAME {clg400} \ + CONFIG.PCW_PCAP_PERIPHERAL_CLKSRC {IO PLL} \ + CONFIG.PCW_PCAP_PERIPHERAL_DIVISOR0 {5} \ + CONFIG.PCW_PCAP_PERIPHERAL_FREQMHZ {200} \ + CONFIG.PCW_PERIPHERAL_BOARD_PRESET {None} \ + CONFIG.PCW_PJTAG_PERIPHERAL_ENABLE {0} \ + CONFIG.PCW_PJTAG_PJTAG_IO {} \ + CONFIG.PCW_QSPI_GRP_SINGLE_SS_ENABLE {1} \ + CONFIG.PCW_QSPI_GRP_SINGLE_SS_IO {MIO 1 .. 6} \ + CONFIG.PCW_QSPI_GRP_SS1_ENABLE {0} \ + CONFIG.PCW_QSPI_GRP_SS1_IO {} \ + CONFIG.PCW_SD0_GRP_WP_ENABLE {0} \ + CONFIG.PCW_SD0_GRP_WP_IO {} \ + CONFIG.PCW_SD1_GRP_POW_ENABLE {0} \ + CONFIG.PCW_SD1_GRP_POW_IO {} \ + CONFIG.PCW_SD1_PERIPHERAL_ENABLE {0} \ + CONFIG.PCW_SD1_SD1_IO {} \ + CONFIG.PCW_SPI0_GRP_SS1_ENABLE {0} \ + CONFIG.PCW_SPI0_GRP_SS1_IO {} \ + CONFIG.PCW_SPI0_HIGHADDR {0xE0006FFF} \ + CONFIG.PCW_SPI0_PERIPHERAL_ENABLE {0} \ + CONFIG.PCW_SPI0_SPI0_IO {} \ + CONFIG.PCW_SPI1_GRP_SS1_ENABLE {0} \ + CONFIG.PCW_SPI1_GRP_SS1_IO {} \ + CONFIG.PCW_SPI1_HIGHADDR {0xE0007FFF} \ + CONFIG.PCW_SPI1_PERIPHERAL_ENABLE {0} \ + CONFIG.PCW_SPI1_SPI1_IO {} \ + CONFIG.PCW_TRACE_GRP_2BIT_ENABLE {0} \ + CONFIG.PCW_TRACE_GRP_2BIT_IO {} \ + CONFIG.PCW_TRACE_GRP_4BIT_ENABLE {0} \ + CONFIG.PCW_TRACE_GRP_4BIT_IO {} \ + CONFIG.PCW_TRACE_INTERNAL_WIDTH {2} \ + CONFIG.PCW_TRACE_PERIPHERAL_ENABLE {0} \ + CONFIG.PCW_TRACE_PIPELINE_WIDTH {8} \ + CONFIG.PCW_TRACE_TRACE_IO {} \ + CONFIG.PCW_TTC1_BASEADDR {0xE0105000} \ + CONFIG.PCW_TTC1_CLK0_PERIPHERAL_CLKSRC {CPU_1X} \ + CONFIG.PCW_TTC1_CLK0_PERIPHERAL_DIVISOR0 {1} \ + CONFIG.PCW_TTC1_CLK0_PERIPHERAL_FREQMHZ {133.333333} \ + CONFIG.PCW_TTC1_CLK1_PERIPHERAL_CLKSRC {CPU_1X} \ + CONFIG.PCW_TTC1_CLK1_PERIPHERAL_DIVISOR0 {1} \ + CONFIG.PCW_TTC1_CLK1_PERIPHERAL_FREQMHZ {133.333333} \ + CONFIG.PCW_TTC1_CLK2_PERIPHERAL_CLKSRC {CPU_1X} \ + CONFIG.PCW_TTC1_CLK2_PERIPHERAL_DIVISOR0 {1} \ + CONFIG.PCW_TTC1_CLK2_PERIPHERAL_FREQMHZ {133.333333} \ + CONFIG.PCW_TTC1_HIGHADDR {0xE0105fff} \ + CONFIG.PCW_TTC1_PERIPHERAL_ENABLE {0} \ + CONFIG.PCW_TTC1_TTC1_IO {} \ + CONFIG.PCW_UART0_HIGHADDR {0xE0000FFF} \ + CONFIG.PCW_UART0_PERIPHERAL_ENABLE {1} \ + CONFIG.PCW_UART0_UART0_IO {MIO 14 .. 15} \ + CONFIG.PCW_UART1_BASEADDR {0xE0001000} \ + CONFIG.PCW_UART1_BAUD_RATE {115200} \ + CONFIG.PCW_UART1_GRP_FULL_ENABLE {0} \ + CONFIG.PCW_UART1_GRP_FULL_IO {} \ + CONFIG.PCW_UART_PERIPHERAL_CLKSRC {IO PLL} \ + CONFIG.PCW_UART_PERIPHERAL_DIVISOR0 {10} \ + CONFIG.PCW_UART_PERIPHERAL_FREQMHZ {100} \ + CONFIG.PCW_UART_PERIPHERAL_VALID {1} \ + CONFIG.PCW_UIPARAM_ACT_DDR_FREQ_MHZ {525.000000} \ + CONFIG.PCW_UIPARAM_DDR_ADV_ENABLE {0} \ + CONFIG.PCW_UIPARAM_DDR_AL {0} \ + CONFIG.PCW_UIPARAM_DDR_BANK_ADDR_COUNT {3} \ + CONFIG.PCW_UIPARAM_DDR_BL {8} \ + CONFIG.PCW_UIPARAM_DDR_BOARD_DELAY0 {0.223} \ + CONFIG.PCW_UIPARAM_DDR_BOARD_DELAY1 {0.212} \ + CONFIG.PCW_UIPARAM_DDR_BOARD_DELAY2 {0.085} \ + CONFIG.PCW_UIPARAM_DDR_BOARD_DELAY3 {0.092} \ + CONFIG.PCW_UIPARAM_DDR_BUS_WIDTH {16 Bit} \ + CONFIG.PCW_UIPARAM_DDR_CL {7} \ + CONFIG.PCW_UIPARAM_DDR_CLOCK_0_LENGTH_MM {25.8} \ + CONFIG.PCW_UIPARAM_DDR_CLOCK_0_PACKAGE_LENGTH {80.4535} \ + CONFIG.PCW_UIPARAM_DDR_CLOCK_0_PROPOGATION_DELAY {160} \ + CONFIG.PCW_UIPARAM_DDR_CLOCK_1_LENGTH_MM {25.8} \ + CONFIG.PCW_UIPARAM_DDR_CLOCK_1_PACKAGE_LENGTH {80.4535} \ + CONFIG.PCW_UIPARAM_DDR_CLOCK_1_PROPOGATION_DELAY {160} \ + CONFIG.PCW_UIPARAM_DDR_CLOCK_2_LENGTH_MM {0} \ + CONFIG.PCW_UIPARAM_DDR_CLOCK_2_PACKAGE_LENGTH {80.4535} \ + CONFIG.PCW_UIPARAM_DDR_CLOCK_2_PROPOGATION_DELAY {160} \ + CONFIG.PCW_UIPARAM_DDR_CLOCK_3_LENGTH_MM {0} \ + CONFIG.PCW_UIPARAM_DDR_CLOCK_3_PACKAGE_LENGTH {80.4535} \ + CONFIG.PCW_UIPARAM_DDR_CLOCK_3_PROPOGATION_DELAY {160} \ + CONFIG.PCW_UIPARAM_DDR_CLOCK_STOP_EN {0} \ + CONFIG.PCW_UIPARAM_DDR_COL_ADDR_COUNT {10} \ + CONFIG.PCW_UIPARAM_DDR_CWL {6} \ + CONFIG.PCW_UIPARAM_DDR_DEVICE_CAPACITY {4096 MBits} \ + CONFIG.PCW_UIPARAM_DDR_DQS_0_LENGTH_MM {15.6} \ + CONFIG.PCW_UIPARAM_DDR_DQS_0_PACKAGE_LENGTH {105.056} \ + CONFIG.PCW_UIPARAM_DDR_DQS_0_PROPOGATION_DELAY {160} \ + CONFIG.PCW_UIPARAM_DDR_DQS_1_LENGTH_MM {18.8} \ + CONFIG.PCW_UIPARAM_DDR_DQS_1_PACKAGE_LENGTH {66.904} \ + CONFIG.PCW_UIPARAM_DDR_DQS_1_PROPOGATION_DELAY {160} \ + CONFIG.PCW_UIPARAM_DDR_DQS_2_LENGTH_MM {0} \ + CONFIG.PCW_UIPARAM_DDR_DQS_2_PACKAGE_LENGTH {89.1715} \ + CONFIG.PCW_UIPARAM_DDR_DQS_2_PROPOGATION_DELAY {160} \ + CONFIG.PCW_UIPARAM_DDR_DQS_3_LENGTH_MM {0} \ + CONFIG.PCW_UIPARAM_DDR_DQS_3_PACKAGE_LENGTH {113.63} \ + CONFIG.PCW_UIPARAM_DDR_DQS_3_PROPOGATION_DELAY {160} \ + CONFIG.PCW_UIPARAM_DDR_DQS_TO_CLK_DELAY_0 {0.040} \ + CONFIG.PCW_UIPARAM_DDR_DQS_TO_CLK_DELAY_1 {0.058} \ + CONFIG.PCW_UIPARAM_DDR_DQS_TO_CLK_DELAY_2 {-0.009} \ + CONFIG.PCW_UIPARAM_DDR_DQS_TO_CLK_DELAY_3 {-0.033} \ + CONFIG.PCW_UIPARAM_DDR_DQ_0_LENGTH_MM {16.5} \ + CONFIG.PCW_UIPARAM_DDR_DQ_0_PACKAGE_LENGTH {98.503} \ + CONFIG.PCW_UIPARAM_DDR_DQ_0_PROPOGATION_DELAY {160} \ + CONFIG.PCW_UIPARAM_DDR_DQ_1_LENGTH_MM {18} \ + CONFIG.PCW_UIPARAM_DDR_DQ_1_PACKAGE_LENGTH {68.5855} \ + CONFIG.PCW_UIPARAM_DDR_DQ_1_PROPOGATION_DELAY {160} \ + CONFIG.PCW_UIPARAM_DDR_DQ_2_LENGTH_MM {0} \ + CONFIG.PCW_UIPARAM_DDR_DQ_2_PACKAGE_LENGTH {90.295} \ + CONFIG.PCW_UIPARAM_DDR_DQ_2_PROPOGATION_DELAY {160} \ + CONFIG.PCW_UIPARAM_DDR_DQ_3_LENGTH_MM {0} \ + CONFIG.PCW_UIPARAM_DDR_DQ_3_PACKAGE_LENGTH {103.977} \ + CONFIG.PCW_UIPARAM_DDR_DQ_3_PROPOGATION_DELAY {160} \ + CONFIG.PCW_UIPARAM_DDR_DRAM_WIDTH {16 Bits} \ + CONFIG.PCW_UIPARAM_DDR_ECC {Disabled} \ + CONFIG.PCW_UIPARAM_DDR_ENABLE {1} \ + CONFIG.PCW_UIPARAM_DDR_FREQ_MHZ {525} \ + CONFIG.PCW_UIPARAM_DDR_HIGH_TEMP {Normal (0-85)} \ + CONFIG.PCW_UIPARAM_DDR_MEMORY_TYPE {DDR 3} \ + CONFIG.PCW_UIPARAM_DDR_PARTNO {MT41J256M16 RE-125} \ + CONFIG.PCW_UIPARAM_DDR_ROW_ADDR_COUNT {15} \ + CONFIG.PCW_UIPARAM_DDR_SPEED_BIN {DDR3_1066F} \ + CONFIG.PCW_UIPARAM_DDR_TRAIN_DATA_EYE {1} \ + CONFIG.PCW_UIPARAM_DDR_TRAIN_READ_GATE {1} \ + CONFIG.PCW_UIPARAM_DDR_TRAIN_WRITE_LEVEL {1} \ + CONFIG.PCW_UIPARAM_DDR_T_FAW {40.0} \ + CONFIG.PCW_UIPARAM_DDR_T_RAS_MIN {35.0} \ + CONFIG.PCW_UIPARAM_DDR_T_RC {48.91} \ + CONFIG.PCW_UIPARAM_DDR_T_RCD {7} \ + CONFIG.PCW_UIPARAM_DDR_T_RP {7} \ + CONFIG.PCW_UIPARAM_DDR_USE_INTERNAL_VREF {0} \ + CONFIG.PCW_UIPARAM_GENERATE_SUMMARY {NA} \ + CONFIG.PCW_USB0_BASEADDR {0xE0102000} \ + CONFIG.PCW_USB0_HIGHADDR {0xE0102fff} \ + CONFIG.PCW_USB0_PERIPHERAL_ENABLE {1} \ + CONFIG.PCW_USB0_PERIPHERAL_FREQMHZ {60} \ + CONFIG.PCW_USB0_RESET_ENABLE {1} \ + CONFIG.PCW_USB0_RESET_IO {MIO 46} \ + CONFIG.PCW_USB0_USB0_IO {MIO 28 .. 39} \ + CONFIG.PCW_USB1_BASEADDR {0xE0103000} \ + CONFIG.PCW_USB1_HIGHADDR {0xE0103fff} \ + CONFIG.PCW_USB1_PERIPHERAL_ENABLE {0} \ + CONFIG.PCW_USB1_PERIPHERAL_FREQMHZ {60} \ + CONFIG.PCW_USB1_RESET_ENABLE {0} \ + CONFIG.PCW_USB1_RESET_IO {} \ + CONFIG.PCW_USB_RESET_ENABLE {1} \ + CONFIG.PCW_USB_RESET_POLARITY {Active Low} \ + CONFIG.PCW_USB_RESET_SELECT {Share reset pin} \ + CONFIG.PCW_USE_AXI_FABRIC_IDLE {0} \ + CONFIG.PCW_USE_AXI_NONSECURE {1} \ + CONFIG.PCW_USE_CORESIGHT {0} \ + CONFIG.PCW_USE_CROSS_TRIGGER {0} \ + CONFIG.PCW_USE_CR_FABRIC {1} \ + CONFIG.PCW_USE_DDR_BYPASS {0} \ + CONFIG.PCW_USE_DEBUG {0} \ + CONFIG.PCW_USE_DEFAULT_ACP_USER_VAL {0} \ + CONFIG.PCW_USE_DMA0 {0} \ + CONFIG.PCW_USE_DMA1 {0} \ + CONFIG.PCW_USE_DMA2 {0} \ + CONFIG.PCW_USE_DMA3 {0} \ + CONFIG.PCW_USE_EXPANDED_IOP {0} \ + CONFIG.PCW_USE_EXPANDED_PS_SLCR_REGISTERS {0} \ + CONFIG.PCW_USE_FABRIC_INTERRUPT {0} \ + CONFIG.PCW_USE_HIGH_OCM {0} \ + CONFIG.PCW_USE_M_AXI_GP0 {0} \ + CONFIG.PCW_USE_M_AXI_GP1 {0} \ + CONFIG.PCW_USE_PROC_EVENT_BUS {0} \ + CONFIG.PCW_USE_PS_SLCR_REGISTERS {0} \ + CONFIG.PCW_USE_S_AXI_ACP {0} \ + CONFIG.PCW_USE_S_AXI_GP0 {0} \ + CONFIG.PCW_USE_S_AXI_GP1 {0} \ + CONFIG.PCW_USE_S_AXI_HP0 {1} \ + CONFIG.PCW_USE_S_AXI_HP1 {0} \ + CONFIG.PCW_USE_S_AXI_HP2 {0} \ + CONFIG.PCW_USE_S_AXI_HP3 {0} \ + CONFIG.PCW_USE_TRACE {0} \ + CONFIG.PCW_USE_TRACE_DATA_EDGE_DETECTOR {0} \ + CONFIG.PCW_VALUE_SILVERSION {3} \ + CONFIG.PCW_WDT_PERIPHERAL_CLKSRC {CPU_1X} \ + CONFIG.PCW_WDT_PERIPHERAL_DIVISOR0 {1} \ + CONFIG.PCW_WDT_PERIPHERAL_ENABLE {0} \ + CONFIG.PCW_WDT_PERIPHERAL_FREQMHZ {133.333333} \ + CONFIG.PCW_WDT_WDT_IO {