├── project ├── plugins.sbt └── build.properties ├── nexus-am ├── tests │ ├── cputest │ │ ├── .gitignore │ │ ├── tests │ │ │ ├── dummy.c │ │ │ ├── dummy │ │ │ ├── sum.c │ │ │ ├── dummy.i │ │ │ ├── dummy.s │ │ │ ├── unalign.c │ │ │ ├── wanshu.c │ │ │ ├── fact.c │ │ │ ├── hello-str.c │ │ │ ├── div.c │ │ │ ├── mov-c.c │ │ │ ├── prime.c │ │ │ ├── shuixianhua.c │ │ │ ├── fib.c │ │ │ ├── goldbach.c │ │ │ ├── switch.c │ │ │ ├── leap-year.c │ │ │ ├── if-else.c │ │ │ ├── movsx.c │ │ │ ├── bubble-sort.c │ │ │ ├── pascal.c │ │ │ ├── select-sort.c │ │ │ ├── string.c │ │ │ ├── mul-longlong.c │ │ │ ├── to-lower-case.c │ │ │ ├── shift.c │ │ │ ├── quick-sort.c │ │ │ ├── recursion.c │ │ │ ├── max.c │ │ │ ├── add.c │ │ │ ├── load-store.c │ │ │ ├── bit.c │ │ │ ├── min3.c │ │ │ ├── add-longlong.c │ │ │ ├── sub-longlong.c │ │ │ └── matrix-mul.c │ │ ├── include │ │ │ └── trap.h │ │ └── Makefile │ └── amtest │ │ ├── Makefile │ │ ├── src │ │ ├── tests │ │ │ ├── mp.c │ │ │ ├── audio │ │ │ │ ├── little-star.pcm │ │ │ │ └── audio-data.S │ │ │ ├── hello.c │ │ │ ├── rtc.c │ │ │ ├── keyboard.c │ │ │ ├── intr.c │ │ │ ├── audio.c │ │ │ ├── video.c │ │ │ ├── vm.c │ │ │ └── devscan.c │ │ └── main.c │ │ └── include │ │ └── amtest.h ├── apps │ ├── dhrystone │ │ └── Makefile │ ├── coremark │ │ └── Makefile │ └── microbench │ │ ├── Makefile │ │ └── src │ │ ├── lzip │ │ └── lzip.c │ │ ├── queen │ │ └── queen.c │ │ ├── sieve │ │ └── sieve.c │ │ ├── qsort │ │ └── qsort.c │ │ ├── fib │ │ └── fib.c │ │ └── 15pz │ │ └── 15pz.cpp ├── am │ ├── src │ │ ├── nutshell │ │ │ ├── common │ │ │ │ ├── mainargs.S │ │ │ │ ├── uartlite.c │ │ │ │ ├── timer.c │ │ │ │ └── ioe.c │ │ │ ├── isa │ │ │ │ └── riscv │ │ │ │ │ ├── boot │ │ │ │ │ ├── loader64.ld │ │ │ │ │ └── start.S │ │ │ │ │ └── trm.c │ │ │ ├── include │ │ │ │ └── nutshell.h │ │ │ └── ldscript │ │ │ │ └── section.ld │ │ └── dummy │ │ │ ├── audio.c │ │ │ ├── mpe.c │ │ │ ├── cte.c │ │ │ ├── input.c │ │ │ ├── vme.c │ │ │ └── video.c │ ├── Makefile │ ├── include │ │ ├── arch │ │ │ └── riscv64-nutshell.h │ │ └── riscv.h │ ├── arch │ │ ├── isa │ │ │ └── riscv64.mk │ │ └── riscv64-nutshell.mk │ ├── am.h │ └── amdev.h ├── libs │ └── klib │ │ ├── Makefile │ │ ├── src │ │ ├── cpp.c │ │ └── io.c │ │ └── include │ │ ├── klib-macros.h │ │ └── klib.h ├── .gitignore ├── Makefile ├── Makefile.check ├── Makefile.lib ├── README.md ├── Makefile.app └── Makefile.compile ├── nemu ├── tools │ └── qemu-diff │ │ ├── src │ │ └── isa │ │ │ └── riscv64 │ │ │ └── init.c │ │ ├── include │ │ └── isa │ │ │ └── riscv64.h │ │ └── Makefile ├── src │ ├── device │ │ ├── intr.c │ │ ├── io │ │ │ ├── mmio.c │ │ │ ├── map.c │ │ │ └── port-io.c │ │ ├── alarm.c │ │ ├── timer.c │ │ ├── device.c │ │ └── serial.c │ ├── monitor │ │ ├── debug │ │ │ ├── expr.h │ │ │ ├── watchpoint.h │ │ │ ├── watchpoint.c │ │ │ ├── log.c │ │ │ ├── ui.c │ │ │ └── expr.c │ │ └── difftest │ │ │ └── ref.c │ ├── engine │ │ └── interpreter │ │ │ ├── init.c │ │ │ └── c_op.h │ ├── isa │ │ └── riscv64 │ │ │ ├── exec │ │ │ ├── all-instr.h │ │ │ ├── special.c │ │ │ ├── control.h │ │ │ ├── ldst.h │ │ │ └── amo.h │ │ │ ├── difftest │ │ │ ├── difftest.h │ │ │ ├── dut.c │ │ │ └── ref.c │ │ │ ├── local-include │ │ │ ├── rtl.h │ │ │ ├── reg.h │ │ │ └── intr.h │ │ │ ├── clint.c │ │ │ ├── init.c │ │ │ ├── intr.c │ │ │ └── logo.c │ ├── main.c │ └── memory │ │ ├── vaddr.c │ │ └── paddr.c ├── .gitignore ├── include │ ├── device │ │ ├── alarm.h │ │ └── map.h │ ├── monitor │ │ ├── monitor.h │ │ ├── log.h │ │ └── difftest.h │ ├── memory │ │ ├── paddr.h │ │ └── vaddr.h │ ├── macro.h │ ├── debug.h │ ├── cpu │ │ ├── decode.h │ │ └── exec.h │ ├── common.h │ ├── isa.h │ ├── rtl │ │ ├── rtl.h │ │ └── pseudo.h │ └── isa │ │ └── riscv64.h ├── README.md └── Makefile ├── docs ├── 10.10.md ├── [20200812] 第二期一生一芯计划启动会v7.pdf ├── 9.18.md ├── 11.7.md ├── 11.15.md ├── 11.11.md ├── 9.9_其他.md ├── 10.26.md ├── 9.28.md ├── 8.26 学习总结.md ├── 9.22.md ├── 9.12 verilator.md ├── 9.8_总结.md ├── 9.30.md ├── 11.13.md ├── 10.28.md ├── 10.4.md ├── 11.16.md ├── 9.16.md ├── 11.8.md ├── 10.14.md ├── 8.27_nemu.md ├── 8.26_yuh.md ├── 9.7_nemu.md ├── 9.23.md ├── 9.15.md └── 9.11 讨论.md ├── verilator ├── difftest ├── nemu_so │ ├── microbench.bin │ └── riscv64-nemu-interpreter-so ├── constants.h ├── difftestIO.h ├── main.cpp ├── difftest.h ├── emulator.h ├── common.h ├── ram.h └── ram.cpp ├── README.md ├── .gdbinit └── src ├── main └── scala │ ├── common │ ├── DataReadIO.scala │ ├── InstReadIO.scala │ ├── DataWriteIO.scala │ └── RamIO.scala │ ├── sim │ ├── diffTestIO.scala │ └── simTop.scala │ └── nutcore │ ├── top.scala │ ├── regfile.scala │ └── alu.scala └── test └── scala ├── print ├── print_try.scala └── mem_test.scala └── nutcore ├── alu_test.scala └── regfile_test.scala /project/plugins.sbt: -------------------------------------------------------------------------------- 1 | logLevel := Level.Warn 2 | -------------------------------------------------------------------------------- /nexus-am/tests/cputest/.gitignore: -------------------------------------------------------------------------------- 1 | /Makefile.* 2 | -------------------------------------------------------------------------------- /project/build.properties: -------------------------------------------------------------------------------- 1 | sbt.version = 1.3.10 2 | -------------------------------------------------------------------------------- /nemu/tools/qemu-diff/src/isa/riscv64/init.c: -------------------------------------------------------------------------------- 1 | void init_isa(void) { 2 | } 3 | -------------------------------------------------------------------------------- /nexus-am/tests/cputest/tests/dummy.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | return 0; 3 | } 4 | -------------------------------------------------------------------------------- /docs/10.10.md: -------------------------------------------------------------------------------- 1 | ### 今日任务 2 | 3 | 4 | 5 | 当前bug: 为何regfile的Mem始终读不出来值? 能存进去, 但是读取的值都是0! -------------------------------------------------------------------------------- /verilator/difftest: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jensen-yan/kisscpu/HEAD/verilator/difftest -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # kisscpu 2 | 3 | ### 使用KISS原则来设计自己的cpu 4 | 5 | 所有的开发过程都记录在docs/ 中, 根据日期分类, 欢迎查阅和学习 -------------------------------------------------------------------------------- /nemu/src/device/intr.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void dev_raise_intr() { 4 | cpu.INTR = true; 5 | } 6 | -------------------------------------------------------------------------------- /nexus-am/apps/dhrystone/Makefile: -------------------------------------------------------------------------------- 1 | NAME = dhrystone 2 | SRCS = dry.c 3 | include $(AM_HOME)/Makefile.app 4 | -------------------------------------------------------------------------------- /nemu/.gitignore: -------------------------------------------------------------------------------- 1 | *.* 2 | * 3 | !*/ 4 | !Makefile* 5 | !*.[cSh] 6 | !.gitignore 7 | !README.md 8 | !runall.sh 9 | -------------------------------------------------------------------------------- /verilator/nemu_so/microbench.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jensen-yan/kisscpu/HEAD/verilator/nemu_so/microbench.bin -------------------------------------------------------------------------------- /docs/[20200812] 第二期一生一芯计划启动会v7.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jensen-yan/kisscpu/HEAD/docs/[20200812] 第二期一生一芯计划启动会v7.pdf -------------------------------------------------------------------------------- /nexus-am/tests/cputest/tests/dummy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jensen-yan/kisscpu/HEAD/nexus-am/tests/cputest/tests/dummy -------------------------------------------------------------------------------- /nexus-am/am/src/nutshell/common/mainargs.S: -------------------------------------------------------------------------------- 1 | .section .rodata 2 | .globl __am_mainargs 3 | __am_mainargs: 4 | .asciz MAINARGS 5 | -------------------------------------------------------------------------------- /nexus-am/am/Makefile: -------------------------------------------------------------------------------- 1 | NAME := am 2 | LIBS := klib 3 | SRCS = $(addprefix src/, $(AM_SRCS)) 4 | 5 | include $(AM_HOME)/Makefile.lib 6 | -------------------------------------------------------------------------------- /nexus-am/apps/coremark/Makefile: -------------------------------------------------------------------------------- 1 | NAME = coremark 2 | SRCS = $(shell find -L ./src/ -name "*.c") 3 | include $(AM_HOME)/Makefile.app 4 | -------------------------------------------------------------------------------- /nexus-am/tests/amtest/Makefile: -------------------------------------------------------------------------------- 1 | NAME := amtest 2 | SRCS := $(shell find -L ./src/ -name "*.[cS]") 3 | 4 | include $(AM_HOME)/Makefile.app 5 | -------------------------------------------------------------------------------- /nemu/include/device/alarm.h: -------------------------------------------------------------------------------- 1 | #ifndef __DEVICE_ALARM_H__ 2 | #define __DEVICE_ALARM_H__ 3 | 4 | void add_alarm_handle(void *h); 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /verilator/constants.h: -------------------------------------------------------------------------------- 1 | #ifndef __CONSTANTS_H__ 2 | #define __CONSTANTS_H__ 3 | 4 | #define NUM_REG 32 5 | #define XLEN 32 6 | 7 | #endif 8 | 9 | -------------------------------------------------------------------------------- /verilator/nemu_so/riscv64-nemu-interpreter-so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jensen-yan/kisscpu/HEAD/verilator/nemu_so/riscv64-nemu-interpreter-so -------------------------------------------------------------------------------- /nexus-am/tests/amtest/src/tests/mp.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void mp_print() { 4 | while (1) { 5 | printf("%d", _cpu()); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /nemu/src/monitor/debug/expr.h: -------------------------------------------------------------------------------- 1 | #ifndef __EXPR_H__ 2 | #define __EXPR_H__ 3 | 4 | #include 5 | 6 | word_t expr(char *, bool *); 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /nexus-am/apps/microbench/Makefile: -------------------------------------------------------------------------------- 1 | NAME = microbench 2 | SRCS = $(shell find -L ./src/ -name "*.c" -o -name "*.cpp") 3 | include $(AM_HOME)/Makefile.app 4 | -------------------------------------------------------------------------------- /nexus-am/tests/amtest/src/tests/audio/little-star.pcm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jensen-yan/kisscpu/HEAD/nexus-am/tests/amtest/src/tests/audio/little-star.pcm -------------------------------------------------------------------------------- /nexus-am/libs/klib/Makefile: -------------------------------------------------------------------------------- 1 | NAME = klib 2 | SRCS = $(shell find src/ -name "*.c") 3 | include $(AM_HOME)/Makefile.lib 4 | OBJS += src/stdio.o src/stdlib.o src/string.o 5 | -------------------------------------------------------------------------------- /nexus-am/.gitignore: -------------------------------------------------------------------------------- 1 | !* 2 | .* 3 | !.gitignore 4 | *~ 5 | *.a 6 | *.o 7 | *.d 8 | __pycache__ 9 | *.pyc 10 | *.ini 11 | *.log 12 | tags 13 | cscope.* 14 | build/ 15 | -------------------------------------------------------------------------------- /nexus-am/am/include/arch/riscv64-nutshell.h: -------------------------------------------------------------------------------- 1 | #ifndef __ARCH_H__ 2 | 3 | struct _Context { 4 | uintptr_t dummy; 5 | }; 6 | 7 | #define GPRx dummy 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /.gdbinit: -------------------------------------------------------------------------------- 1 | set args /home/yanyue/nutshell_v2/kisscpu/nexus-am/tests/cputest/build/dummy-riscv64-nutshell.bin 2 | b CEmulator::execute_cycles 3 | b difftest_step(CEmulator*, int) 4 | r 5 | -------------------------------------------------------------------------------- /nexus-am/am/src/nutshell/isa/riscv/boot/loader64.ld: -------------------------------------------------------------------------------- 1 | pmem_base = 0x80000000; 2 | 3 | MEMORY { 4 | ram (rwxa) : ORIGIN = 0x80000000, LENGTH = 128M 5 | } 6 | 7 | INCLUDE "section.ld" 8 | -------------------------------------------------------------------------------- /nexus-am/tests/amtest/src/tests/hello.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void hello() { 4 | for (int i = 0; i < 10; i ++) { 5 | putstr("Hello, AM World @ " __ISA__ "\n"); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /docs/9.18.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | #### 今日任务 4 | 5 | 1. 完成单周期64位流水线, 并完整能验证第一条指令. 6 | 7 | 8 | 9 | 设计框架: 10 | 11 | 生成的verilog文件中, 有InstReadIO, DataReadIO, DataWriteIO(还是共用一个mem算了) 12 | 13 | 这是在顶层 -------------------------------------------------------------------------------- /nexus-am/am/src/nutshell/isa/riscv/boot/start.S: -------------------------------------------------------------------------------- 1 | .section entry, "ax" 2 | .globl _start 3 | .type _start, @function 4 | 5 | _start: 6 | mv s0, zero 7 | la sp, _stack_pointer 8 | jal _trm_init 9 | -------------------------------------------------------------------------------- /nexus-am/tests/amtest/src/tests/audio/audio-data.S: -------------------------------------------------------------------------------- 1 | .section .data 2 | .global audio_payload, audio_payload_end 3 | .p2align 3 4 | audio_payload: 5 | .incbin "src/tests/audio/little-star.pcm" 6 | audio_payload_end: 7 | -------------------------------------------------------------------------------- /docs/11.7.md: -------------------------------------------------------------------------------- 1 | ### 今日任务 2 | 3 | 1. 不管之前有多少懈怠, 但是尽量努力的去做, 不用管结果! 加油. 4 | 2. 今天争取把AXI总线接口给添上, 5 | 1. 先看看体系结构的教材 6 | 2. 再看看之前写的cpu 7 | 3. 把现在kisscpu的ram接口改成握手机制 8 | 4. 进行一下测试 9 | 5. 把陈国凯的axi接口拿来, 添加到kisscpu中 10 | 6. 进行测试 -------------------------------------------------------------------------------- /nemu/src/engine/interpreter/init.c: -------------------------------------------------------------------------------- 1 | void ui_mainloop(); 2 | void init_device(); 3 | 4 | void engine_start() { 5 | /* Initialize devices. */ 6 | init_device(); 7 | 8 | /* Receive commands from user. */ 9 | ui_mainloop(); 10 | } 11 | -------------------------------------------------------------------------------- /nexus-am/tests/cputest/tests/sum.c: -------------------------------------------------------------------------------- 1 | #include "trap.h" 2 | 3 | int main() { 4 | int i = 1; 5 | volatile int sum = 0; 6 | while(i <= 100) { 7 | sum += i; 8 | i ++; 9 | } 10 | 11 | nemu_assert(sum == 5050); 12 | 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /src/main/scala/common/DataReadIO.scala: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import chisel3._ 4 | import constans._ 5 | 6 | class DataReadIO extends Bundle { 7 | val addr = Output(UInt(XLEN.W)) 8 | val data = Input(UInt(XLEN.W)) 9 | val en = Output(Bool()) 10 | } 11 | -------------------------------------------------------------------------------- /src/main/scala/common/InstReadIO.scala: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import chisel3._ 4 | import constans._ 5 | 6 | class InstReadIO extends Bundle { 7 | val addr = Output(UInt(XLEN.W)) 8 | val data = Input(UInt(XLEN.W)) 9 | val en = Output(Bool()) 10 | } 11 | -------------------------------------------------------------------------------- /nemu/README.md: -------------------------------------------------------------------------------- 1 | # NEMU 2 | 3 | NEMU模拟器是[南京大学计算机系ICS课程实验PA](https://github.com/NJU-ProjectN/)的一部分, 4 | 本仓库仅保留与NutShell相关的riscv64功能, 与课程作业关联较大的内容将去除或留空. 5 | 6 | 关于NEMU的具体介绍, 请参考[NEMU的上游仓库](https://github.com/NJU-ProjectN/nemu)或[PA实验讲义](https://nju-projectn.github.io/ics-pa-gitbook/). 7 | -------------------------------------------------------------------------------- /nemu/src/isa/riscv64/exec/all-instr.h: -------------------------------------------------------------------------------- 1 | #include "../local-include/rtl.h" 2 | 3 | #include "amo.h" 4 | #include "compute.h" 5 | #include "control.h" 6 | #include "ldst.h" 7 | #include "muldiv.h" 8 | #include "system.h" 9 | 10 | make_EHelper(inv); 11 | make_EHelper(nemu_trap); 12 | -------------------------------------------------------------------------------- /nexus-am/am/src/dummy/audio.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void __am_audio_init() { 4 | } 5 | 6 | size_t __am_audio_write(uintptr_t reg, void *buf, size_t size) { 7 | return 0; 8 | } 9 | 10 | size_t __am_audio_read(uintptr_t reg, void *buf, size_t size) { 11 | return 0; 12 | } 13 | -------------------------------------------------------------------------------- /nexus-am/tests/cputest/include/trap.h: -------------------------------------------------------------------------------- 1 | #ifndef __TRAP_H__ 2 | #define __TRAP_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | __attribute__((noinline)) 9 | void nemu_assert(int cond) { 10 | if (!cond) _halt(1); 11 | } 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /nexus-am/tests/cputest/tests/dummy.i: -------------------------------------------------------------------------------- 1 | # 1 "dummy.c" 2 | # 1 "" 3 | # 1 "" 4 | # 31 "" 5 | # 1 "/opt/riscv64-lin/sysroot/usr/include/stdc-predef.h" 1 3 4 6 | # 32 "" 2 7 | # 1 "dummy.c" 8 | int main() { 9 | return 0; 10 | } 11 | -------------------------------------------------------------------------------- /docs/11.15.md: -------------------------------------------------------------------------------- 1 | #### 今日任务 2 | 3 | 1. 修改axi, 添加暂存指令的 4 | 2. 能够跑通乘法指令 5 | 3. 希望能跑通服务器上的指令 6 | 7 | 8 | 9 | ``` 10 | mul-longlong 11 | 12 | reg 24 s8 different at pc = [0x 800000a8], right=[0x 1], wrong=[0x 0] cyc = 290 13 | 14 | 15 | ``` 16 | 17 | -------------------------------------------------------------------------------- /nexus-am/am/arch/isa/riscv64.mk: -------------------------------------------------------------------------------- 1 | #CROSS_COMPILE := riscv64-linux-gnu- 2 | CROSS_COMPILE := riscv64-unknown-linux-gnu- 3 | COMMON_FLAGS := -fno-pic -march=rv64g -mcmodel=medany 4 | CFLAGS += $(COMMON_FLAGS) -static 5 | ASFLAGS += $(COMMON_FLAGS) -O0 6 | LDFLAGS += -melf64lriscv 7 | -------------------------------------------------------------------------------- /nexus-am/am/src/dummy/mpe.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int _mpe_init(void (*entry)()) { 4 | return 1; 5 | } 6 | 7 | int _ncpu() { 8 | return 1; 9 | } 10 | 11 | int _cpu() { 12 | return 0; 13 | } 14 | 15 | intptr_t _atomic_xchg(volatile intptr_t *addr, intptr_t newval) { 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /src/main/scala/common/DataWriteIO.scala: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import chisel3._ 4 | import constans._ 5 | 6 | class DataWriteIO extends Bundle { 7 | val addr = Output(UInt(XLEN.W)) 8 | val data = Output(UInt(XLEN.W)) 9 | val en = Output(Bool()) 10 | val mask = Output(UInt((XLEN/8).W)) 11 | } 12 | -------------------------------------------------------------------------------- /verilator/difftestIO.h: -------------------------------------------------------------------------------- 1 | #ifndef __DIFFTESTIO_H__ 2 | #define __DIFFTESTIO_H__ 3 | 4 | #include "common.h" 5 | 6 | typedef struct diffTestIO_t 7 | { 8 | paddr_t regfile[NUM_REG]; 9 | paddr_t PC; //PC must follow regFile continuously in address space 10 | paddr_t empty[6]; 11 | } diffTestIO; 12 | 13 | #endif -------------------------------------------------------------------------------- /nexus-am/tests/cputest/tests/dummy.s: -------------------------------------------------------------------------------- 1 | .file "dummy.c" 2 | .option nopic 3 | .text 4 | .section .text.startup,"ax",@progbits 5 | .align 1 6 | .globl main 7 | .type main, @function 8 | main: 9 | li a0,0 10 | ret 11 | .size main, .-main 12 | .ident "GCC: (GNU) 8.3.0" 13 | .section .note.GNU-stack,"",@progbits 14 | -------------------------------------------------------------------------------- /nemu/src/isa/riscv64/difftest/difftest.h: -------------------------------------------------------------------------------- 1 | #ifndef __RISCV64_DIFF_TEST_H__ 2 | #define __RISCV64_DIFF_TEST_H__ 3 | 4 | #define DIFFTEST_REG_SIZE (sizeof(uint64_t) * (32 + 1 + 6)) // GRPs + pc + [m|s][status|cause|epc] 5 | 6 | void isa_difftest_getregs_hook(void); 7 | void isa_difftest_setregs_hook(void); 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /nexus-am/Makefile: -------------------------------------------------------------------------------- 1 | include Makefile.check 2 | 3 | AM_HOME ?= $(shell pwd) 4 | 5 | default: 6 | @$(MAKE) -s -C am 7 | 8 | # clean everything 9 | ALLMAKE = $(dir $(shell find . -mindepth 2 -name "Makefile")) 10 | $(ALLMAKE): 11 | -@$(MAKE) -s -C $@ clean 12 | 13 | clean: $(ALLMAKE) 14 | 15 | .PHONY: default clean $(ALLMAKE) 16 | -------------------------------------------------------------------------------- /nexus-am/libs/klib/src/cpp.c: -------------------------------------------------------------------------------- 1 | #include "klib.h" 2 | 3 | #if !defined(__ISA_NATIVE__) && !defined(__PLATFORM_NATIVE__) 4 | 5 | void __dso_handle() { 6 | } 7 | 8 | void __cxa_guard_acquire() { 9 | } 10 | 11 | void __cxa_guard_release() { 12 | } 13 | 14 | 15 | void __cxa_atexit() { 16 | assert(0); 17 | } 18 | 19 | #endif 20 | -------------------------------------------------------------------------------- /docs/11.11.md: -------------------------------------------------------------------------------- 1 | ### 今日任务 2 | 3 | 1. 之前两天把axi直接放在服务器上去测试, 又因为服务器上没法用dve来调试波形, 还是一步一步来, 先简单的在本地上测试, 加入axi_ram后, 争取能读出第一条指令! 4 | 5 | 6 | 7 | 现在addr_W 应该是 32 还是64? 8 | 9 | id_W 统一为4 10 | 11 | size_W 统一为3 12 | 13 | 注意还要在AXI_ram中修改bin文件!!! 14 | 15 | 似乎axi_ram中的mem地址宽度还是要改成20, 这样才能读入正确的数据把 16 | 17 | 18 | 19 | AXI_ram 的数据存储的是大端序, 暂时改成小端的! -------------------------------------------------------------------------------- /src/main/scala/sim/diffTestIO.scala: -------------------------------------------------------------------------------- 1 | package sim 2 | 3 | import chisel3._ 4 | import chisel3.util._ 5 | 6 | import common.constans._ 7 | 8 | class diffTestIO extends Bundle{ 9 | val regfile = Output(Vec(NUM_REG, UInt(XLEN.W))) 10 | val PC = Output(UInt(XLEN.W)) 11 | val PC_valid = Output(Bool()) 12 | val nemu_halt= Output(Bool()) 13 | } -------------------------------------------------------------------------------- /nemu/src/main.c: -------------------------------------------------------------------------------- 1 | void init_monitor(int, char *[]); 2 | void engine_start(); 3 | int goodtrap(void); 4 | int is_batch_mode(); 5 | 6 | int main(int argc, char *argv[]) { 7 | /* Initialize the monitor. */ 8 | init_monitor(argc, argv); 9 | 10 | /* Start engine. */ 11 | engine_start(); 12 | 13 | return (is_batch_mode() ? !goodtrap() : 0); 14 | } 15 | -------------------------------------------------------------------------------- /nexus-am/am/src/nutshell/include/nutshell.h: -------------------------------------------------------------------------------- 1 | #ifndef __NUTSHELL_H__ 2 | #define __NUTSHELL_H__ 3 | 4 | #include 5 | 6 | #include ISA_H // "x86.h", "mips32.h", ... 7 | 8 | # define RTC_ADDR 0x3800bff8 9 | # define SCREEN_ADDR 0x40001000 10 | # define SYNC_ADDR 0x40001004 11 | # define FB_ADDR 0x50000000 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /nexus-am/am/src/dummy/cte.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int _cte_init(_Context*(*handler)(_Event, _Context*)) { 4 | return 0; 5 | } 6 | 7 | _Context* _kcontext(_Area kstack, void (*entry)(void *), void *arg) { 8 | return NULL; 9 | } 10 | 11 | void _yield() { 12 | } 13 | 14 | int _intr_read() { 15 | return 0; 16 | } 17 | 18 | void _intr_write(int enable) { 19 | } 20 | -------------------------------------------------------------------------------- /docs/9.9_其他.md: -------------------------------------------------------------------------------- 1 | ### 9.9 2 | 3 | #### RT-thread 4 | 5 | 使用组成原理框架, 6 | 7 | qemu 跑起来 8 | 9 | 10 | 11 | lab_cpu/ riscv 12 | 13 | bsp/ 适配机型 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | mcause, mepc, scratch, 22 | 23 | I + Zsr, csr 映射到内存地址上 24 | 25 | 26 | 27 | 原则 28 | 29 | 来设计自己的cpu -------------------------------------------------------------------------------- /nemu/include/monitor/monitor.h: -------------------------------------------------------------------------------- 1 | #ifndef __MONITOR_MONITOR_H__ 2 | #define __MONITOR_MONITOR_H__ 3 | 4 | #include 5 | 6 | enum { NEMU_STOP, NEMU_RUNNING, NEMU_END, NEMU_ABORT }; 7 | 8 | typedef struct { 9 | int state; 10 | vaddr_t halt_pc; 11 | uint32_t halt_ret; 12 | } NEMUState; 13 | 14 | extern NEMUState nemu_state; 15 | 16 | void display_inv_msg(vaddr_t pc); 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /nexus-am/am/src/dummy/input.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | size_t __am_input_read(uintptr_t reg, void *buf, size_t size) { 5 | switch (reg) { 6 | case _DEVREG_INPUT_KBD: { 7 | _DEV_INPUT_KBD_t *kbd = (_DEV_INPUT_KBD_t *)buf; 8 | kbd->keydown = 0; 9 | kbd->keycode = _KEY_NONE; 10 | return sizeof(_DEV_INPUT_KBD_t); 11 | } 12 | } 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /nexus-am/tests/cputest/tests/unalign.c: -------------------------------------------------------------------------------- 1 | #include "trap.h" 2 | 3 | volatile unsigned x = 0xffffffff; 4 | volatile unsigned char buf[16]; 5 | 6 | int main() { 7 | 8 | for(int i = 0; i < 4; i++) { 9 | *((volatile unsigned*)(buf + 3)) = 0xaabbccdd; 10 | 11 | x = *((volatile unsigned*)(buf + 3)); 12 | nemu_assert(x == 0xaabbccdd); 13 | 14 | buf[0] = buf[1] = 0; 15 | } 16 | 17 | return 0; 18 | } 19 | -------------------------------------------------------------------------------- /nemu/src/isa/riscv64/local-include/rtl.h: -------------------------------------------------------------------------------- 1 | #ifndef __RISCV64_RTL_H__ 2 | #define __RISCV64_RTL_H__ 3 | 4 | #include 5 | #include "reg.h" 6 | 7 | static inline make_rtl(lr, rtlreg_t* dest, int r, int width) { 8 | rtl_mv(s, dest, ®_l(r)); 9 | } 10 | 11 | static inline make_rtl(sr, int r, const rtlreg_t *src1, int width) { 12 | if (r != 0) { rtl_mv(s, ®_l(r), src1); } 13 | } 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /nemu/tools/qemu-diff/include/isa/riscv64.h: -------------------------------------------------------------------------------- 1 | #ifndef __RISCV64_H__ 2 | #define __RISCV64_H__ 3 | 4 | #define ISA_QEMU_BIN "qemu-system-riscv64" 5 | #define ISA_QEMU_ARGS 6 | 7 | #include "../../../../src/isa/riscv64/difftest/difftest.h" 8 | 9 | union isa_gdb_regs { 10 | struct { 11 | uint64_t gpr[32]; 12 | uint64_t pc; 13 | }; 14 | struct { 15 | uint32_t array[77]; 16 | }; 17 | }; 18 | 19 | #endif 20 | -------------------------------------------------------------------------------- /docs/10.26.md: -------------------------------------------------------------------------------- 1 | ### 今日任务 2 | 3 | 1. 尝试跑microbench 4 | 2. 尝试跑rt-thread 5 | 6 | 7 | 8 | 跑microbench 发现会进入init_timer的函数, 导致RAM超过范围, 类似uart的处理方法, 把nexus-am/am/src/nutshell/common/timer.c的所有函数变成return 0 9 | 10 | 但是发现microbench 需要mul 指令, 没有实现, 放弃 11 | 12 | dhrystone, coremark 都需要 remuw指令, 没有实现, 放弃 13 | 14 | 15 | 16 | 尽量参考nutshell的axi总线命名 17 | 18 | 去改名字, 有自己命名方法 19 | 20 | 可以在服务器上进行测试, 64G, 21 | 22 | 参考他人的bsp方法, 去测试rt-thread -------------------------------------------------------------------------------- /nexus-am/am/src/dummy/vme.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int _vme_init(void* (*pgalloc_f)(size_t), void (*pgfree_f)(void*)) { 4 | return 0; 5 | } 6 | 7 | void _protect(_AddressSpace *as) { 8 | } 9 | 10 | void _unprotect(_AddressSpace *as) { 11 | } 12 | 13 | void _map(_AddressSpace *as, void *va, void *pa, int prot) { 14 | } 15 | 16 | _Context* _ucontext(_AddressSpace *as, _Area kstack, void *entry) { 17 | return NULL; 18 | } 19 | -------------------------------------------------------------------------------- /nexus-am/tests/cputest/tests/wanshu.c: -------------------------------------------------------------------------------- 1 | #include "trap.h" 2 | 3 | int ans[] = {6, 28}; 4 | 5 | int main() { 6 | int n, sum, i, k = 0; 7 | for(n = 1; n < 30; n ++) { 8 | sum = 0; 9 | for(i = 1; i < n; i ++) { 10 | if(n % i == 0) { 11 | sum += i; 12 | } 13 | } 14 | 15 | if(sum == n) { 16 | nemu_assert(n == ans[k]); 17 | k ++; 18 | } 19 | } 20 | 21 | nemu_assert(k == 2); 22 | 23 | return 0; 24 | } 25 | -------------------------------------------------------------------------------- /nexus-am/tests/cputest/tests/fact.c: -------------------------------------------------------------------------------- 1 | #include "trap.h" 2 | 3 | int f[15]; 4 | int ans[] = {1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800, 39916800, 479001600}; 5 | 6 | int fact(int n) { 7 | if(n == 0 || n == 1) return 1; 8 | else return fact(n - 1) * n; 9 | } 10 | 11 | int main() { 12 | int i; 13 | for(i = 0; i < 13; i ++) { 14 | f[i] = fact(i); 15 | nemu_assert(f[i] == ans[i]); 16 | } 17 | 18 | return 0; 19 | } 20 | 21 | -------------------------------------------------------------------------------- /nexus-am/tests/cputest/tests/hello-str.c: -------------------------------------------------------------------------------- 1 | #include "trap.h" 2 | 3 | char buf[128]; 4 | 5 | int main() { 6 | sprintf(buf, "%s", "Hello world!\n"); 7 | nemu_assert(strcmp(buf, "Hello world!\n") == 0); 8 | 9 | sprintf(buf, "%d + %d = %d\n", 1, 1, 2); 10 | nemu_assert(strcmp(buf, "1 + 1 = 2\n") == 0); 11 | 12 | sprintf(buf, "%d + %d = %d\n", 2, 10, 12); 13 | nemu_assert(strcmp(buf, "2 + 10 = 12\n") == 0); 14 | 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /nexus-am/tests/cputest/tests/div.c: -------------------------------------------------------------------------------- 1 | #include "trap.h" 2 | 3 | #define N 10 4 | int a[N]; 5 | 6 | int main() { 7 | int i, j; 8 | for(i = 0; i < N; i ++) 9 | a[i] = i; 10 | for(i = 0; i < N; i ++) 11 | for(j = 1; j < N + 1; j ++) 12 | a[i] *= j; 13 | for(i = 0; i < N; i ++) 14 | for(j = 1; j < N + 1; j ++) 15 | a[i] /= j; 16 | 17 | for(i = 0; i < N; i ++) 18 | nemu_assert(a[i] == i); 19 | 20 | return 0; 21 | } 22 | -------------------------------------------------------------------------------- /src/test/scala/print/print_try.scala: -------------------------------------------------------------------------------- 1 | package print 2 | 3 | import chisel3._ 4 | import sim.elaborate.args 5 | 6 | class print_try extends Module{ 7 | val io = IO(new Bundle() { 8 | val in = Input(UInt(1.W)) 9 | }) 10 | io := DontCare 11 | 12 | val my = 33.U 13 | printf(p"my = $my") 14 | } 15 | 16 | 17 | object elaborate extends App { 18 | (new stage.ChiselStage).execute(args, Seq(stage.ChiselGeneratorAnnotation(() => new print_try))) 19 | } -------------------------------------------------------------------------------- /nexus-am/tests/cputest/tests/mov-c.c: -------------------------------------------------------------------------------- 1 | #include "trap.h" 2 | 3 | volatile int A[10]; 4 | volatile int b; 5 | 6 | int main() { 7 | A[0] = 0; 8 | A[1] = 1; 9 | A[2] = 2; 10 | A[3] = 3; 11 | A[4] = 4; 12 | 13 | b = A[3]; 14 | A[5] = b; 15 | 16 | nemu_assert(A[0] == 0); 17 | nemu_assert(A[1] == 1); 18 | nemu_assert(A[2] == 2); 19 | nemu_assert(A[3] == 3); 20 | nemu_assert(A[4] == 4); 21 | nemu_assert(b == 3); 22 | nemu_assert(A[5] == 3); 23 | 24 | return 0; 25 | } 26 | -------------------------------------------------------------------------------- /nemu/src/monitor/debug/watchpoint.h: -------------------------------------------------------------------------------- 1 | #ifndef __WATCHPOINT_H__ 2 | #define __WATCHPOINT_H__ 3 | 4 | #include 5 | 6 | typedef struct watchpoint { 7 | int NO; 8 | struct watchpoint *next; 9 | 10 | /* TODO: Add more members if necessary */ 11 | 12 | char *expr; 13 | word_t new_val; 14 | word_t old_val; 15 | } WP; 16 | 17 | int set_watchpoint(char *e); 18 | bool delete_watchpoint(int NO); 19 | void list_watchpoint(); 20 | WP* scan_watchpoint(); 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /nexus-am/tests/cputest/tests/prime.c: -------------------------------------------------------------------------------- 1 | #include "trap.h" 2 | 3 | int ans[] = {101, 103, 107, 109, 113, 127, 131, 137, 139, 149}; 4 | 5 | int main() { 6 | int m, i, n = 0; 7 | int prime; 8 | for(m = 101; m <= 150; m += 2) { 9 | prime = 1; 10 | for(i = 2; i < m; i ++) { 11 | if(m % i == 0) { 12 | prime = 0; 13 | break; 14 | } 15 | } 16 | if(prime) { 17 | nemu_assert(i == ans[n]); 18 | n ++; 19 | } 20 | } 21 | 22 | nemu_assert(n == 10); 23 | 24 | return 0; 25 | } 26 | -------------------------------------------------------------------------------- /nexus-am/tests/cputest/tests/shuixianhua.c: -------------------------------------------------------------------------------- 1 | #include "trap.h" 2 | 3 | int ans[] = {153, 370, 371, 407}; 4 | 5 | int cube(int n) { 6 | return n * n * n; 7 | } 8 | 9 | int main() { 10 | int n, n2, n1, n0; 11 | int k = 0; 12 | for(n = 100; n < 500; n ++) { 13 | n2 = n / 100; 14 | n1 = (n / 10) % 10; 15 | n0 = n % 10; 16 | 17 | if(n == cube(n2) + cube(n1) + cube(n0)) { 18 | nemu_assert(n == ans[k]); 19 | k ++; 20 | } 21 | } 22 | 23 | nemu_assert(k == 4); 24 | 25 | return 0; 26 | } 27 | -------------------------------------------------------------------------------- /nemu/src/isa/riscv64/local-include/reg.h: -------------------------------------------------------------------------------- 1 | #ifndef __RISCV64_REG_H__ 2 | #define __RISCV64_REG_H__ 3 | 4 | #include 5 | 6 | static inline int check_reg_index(int index) { 7 | assert(index >= 0 && index < 32); 8 | return index; 9 | } 10 | 11 | #define reg_l(index) (cpu.gpr[check_reg_index(index)]._64) 12 | 13 | static inline const char* reg_name(int index, int width) { 14 | extern const char* regsl[]; 15 | assert(index >= 0 && index < 32); 16 | return regsl[index]; 17 | } 18 | 19 | #endif 20 | -------------------------------------------------------------------------------- /nemu/src/monitor/debug/watchpoint.c: -------------------------------------------------------------------------------- 1 | #include "watchpoint.h" 2 | #include "expr.h" 3 | 4 | #define NR_WP 32 5 | 6 | static WP wp_pool[NR_WP] = {}; 7 | static WP *head = NULL, *free_ = NULL; 8 | 9 | void init_wp_pool() { 10 | int i; 11 | for (i = 0; i < NR_WP; i ++) { 12 | wp_pool[i].NO = i; 13 | wp_pool[i].next = &wp_pool[i + 1]; 14 | } 15 | wp_pool[NR_WP - 1].next = NULL; 16 | 17 | head = NULL; 18 | free_ = wp_pool; 19 | } 20 | 21 | /* TODO: Implement the functionality of watchpoint */ 22 | 23 | 24 | -------------------------------------------------------------------------------- /nexus-am/tests/amtest/src/tests/rtc.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void rtc_test() { 5 | _DEV_TIMER_DATE_t rtc; 6 | int sec = 1; 7 | while (1) { 8 | while(uptime() < 1000 * sec) ; 9 | get_timeofday(&rtc); 10 | printf("%d-%d-%d %02d:%02d:%02d GMT (", rtc.year, rtc.month, rtc.day, rtc.hour, rtc.minute, rtc.second); 11 | if (sec == 1) { 12 | printf("%d second).\n", sec); 13 | } else { 14 | printf("%d seconds).\n", sec); 15 | } 16 | sec ++; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /nemu/include/memory/paddr.h: -------------------------------------------------------------------------------- 1 | #ifndef __MEMORY_PADDR_H__ 2 | #define __MEMORY_PADDR_H__ 3 | 4 | #include 5 | 6 | #define PMEM_SIZE (256 * 1024 * 1024) 7 | 8 | /* convert the guest physical address in the guest program to host virtual address in NEMU */ 9 | void* guest_to_host(paddr_t addr); 10 | /* convert the host virtual address in NEMU to guest physical address in the guest program */ 11 | paddr_t host_to_guest(void *addr); 12 | 13 | word_t paddr_read(paddr_t addr, int len); 14 | void paddr_write(paddr_t addr, word_t data, int len); 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /nexus-am/tests/cputest/tests/fib.c: -------------------------------------------------------------------------------- 1 | #include "trap.h" 2 | 3 | int fib[40] = {1, 1}; 4 | int ans[] = {1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946, 17711, 28657, 46368, 75025, 121393, 196418, 317811, 514229, 832040, 1346269, 2178309, 3524578, 5702887, 9227465, 14930352, 24157817, 39088169, 63245986, 102334155}; 5 | 6 | int main() { 7 | int i; 8 | for(i = 2; i < 40; i ++) { 9 | fib[i] = fib[i - 1] + fib[i - 2]; 10 | nemu_assert(fib[i] == ans[i]); 11 | } 12 | 13 | nemu_assert(i == 40); 14 | 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /nexus-am/tests/cputest/tests/goldbach.c: -------------------------------------------------------------------------------- 1 | #include "trap.h" 2 | 3 | int is_prime(int n) { 4 | if(n < 2) return 0; 5 | 6 | int i; 7 | for(i = 2; i < n; i ++) { 8 | if(n % i == 0) { 9 | return 0; 10 | } 11 | } 12 | 13 | return 1; 14 | } 15 | 16 | int goldbach(int n) { 17 | int i; 18 | for(i = 2; i < n; i ++) { 19 | if(is_prime(i) && is_prime(n - i)) { 20 | return 1; 21 | } 22 | } 23 | 24 | return 0; 25 | } 26 | 27 | int main() { 28 | int n; 29 | for(n = 4; n <= 30; n += 2) { 30 | nemu_assert(goldbach(n) == 1); 31 | } 32 | 33 | return 0; 34 | } 35 | -------------------------------------------------------------------------------- /nexus-am/am/src/dummy/video.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define W 320 5 | #define H 240 6 | 7 | size_t __am_video_read(uintptr_t reg, void *buf, size_t size) { 8 | switch (reg) { 9 | case _DEVREG_VIDEO_INFO: { 10 | _DEV_VIDEO_INFO_t *info = (_DEV_VIDEO_INFO_t *)buf; 11 | info->width = W; 12 | info->height = H; 13 | return sizeof(_DEV_VIDEO_INFO_t); 14 | } 15 | } 16 | return 0; 17 | } 18 | 19 | size_t __am_video_write(uintptr_t reg, void *buf, size_t size) { 20 | return 0; 21 | } 22 | 23 | void __am_vga_init() { 24 | } 25 | -------------------------------------------------------------------------------- /verilator/main.cpp: -------------------------------------------------------------------------------- 1 | #include "ram.h" 2 | #include "difftest.h" 3 | #include "difftestIO.h" 4 | #include 5 | using namespace std; 6 | #include "emulator.h" 7 | #include "stdio.h" 8 | 9 | long sc_time = 0; 10 | double sc_time_stamp(){ 11 | return sc_time; 12 | } 13 | 14 | int main(int argc, char** argv){ 15 | CRam* ram = new CRam(argv[1]); 16 | init_difftest(0, NULL,ram); 17 | CEmulator* emulator = new CEmulator(ram, &sc_time); 18 | // difftest_step(emulator, 20); 19 | // emulator->step(40); 20 | emulator->execute_cycles(20000); 21 | 22 | return 0; 23 | } -------------------------------------------------------------------------------- /src/test/scala/nutcore/alu_test.scala: -------------------------------------------------------------------------------- 1 | package nutcore 2 | 3 | import chisel3.iotesters.PeekPokeTester 4 | import common.constans._ 5 | 6 | class alu_test(c: alu) extends PeekPokeTester(c){ 7 | // 对10个操作验证一下 8 | // sub: 3+2 = 5 9 | 10 | for(i <- 0 until 17){ 11 | // 先写入, 再读出进行验证 12 | // rf(i) = i, 在expect 13 | poke(c.io.alu_op, ALU_SRAW) 14 | poke(c.io.src1, -8) 15 | poke(c.io.src2, 1) 16 | expect(c.io.result, i/2) 17 | } 18 | 19 | } 20 | 21 | 22 | object alu_test_gen extends App{ 23 | chisel3.iotesters.Driver.execute(args, () => new alu)(c => new alu_test(c)) 24 | } -------------------------------------------------------------------------------- /nexus-am/tests/amtest/src/tests/keyboard.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define NAME(key) \ 5 | [_KEY_##key] = #key, 6 | 7 | const char *names[256] = { 8 | [_KEY_NONE] = "NONE", 9 | _KEYS(NAME) 10 | }; 11 | 12 | void keyboard_test() { 13 | printf("Try to press any key...\n"); 14 | while (1) { 15 | int key = read_key(); 16 | int down = 0; 17 | if (key & 0x8000) { 18 | key ^= 0x8000; 19 | down = 1; 20 | } 21 | if (key != _KEY_NONE) { 22 | printf("Get key: %d %s %s\n", key, names[key], down ? "down" : "up"); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /nexus-am/tests/amtest/src/tests/intr.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | _Context *simple_trap(_Event ev, _Context *ctx) { 4 | switch(ev.event) { 5 | case _EVENT_IRQ_TIMER: 6 | printf("t"); break; 7 | case _EVENT_IRQ_IODEV: 8 | printf("d"); read_key(); break; 9 | case _EVENT_YIELD: 10 | printf("y"); break; 11 | } 12 | return ctx; 13 | } 14 | 15 | void hello_intr() { 16 | printf("Hello, AM World @ " __ISA__ "\n"); 17 | printf(" t = timer, d = device, y = yield\n"); 18 | _intr_write(1); 19 | while (1) { 20 | for (volatile int i = 0; i < 10000000; i++) ; 21 | _yield(); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /nexus-am/tests/amtest/include/amtest.h: -------------------------------------------------------------------------------- 1 | #ifndef __AMUNIT_H__ 2 | #define __AMUNIT_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #define IOE ({ _ioe_init(); }) 9 | #define CTE(h) ({ _Context *h(_Event, _Context *); _cte_init(h); }) 10 | #define VME(f1, f2) ({ void *f1(size_t); void f2(void *); _vme_init(f1, f2); }) 11 | #define MPE ({ _mpe_init(entry); }) 12 | 13 | extern void (*entry)(); 14 | 15 | #define CASE(id, entry_, ...) \ 16 | case id: { \ 17 | void entry_(); \ 18 | entry = entry_; \ 19 | __VA_ARGS__; \ 20 | entry_(); \ 21 | break; \ 22 | } 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /src/test/scala/print/mem_test.scala: -------------------------------------------------------------------------------- 1 | package print 2 | 3 | import chisel3.iotesters.PeekPokeTester 4 | /* 5 | class mem_test(c: mem_print) extends PeekPokeTester(c){ 6 | 7 | for(i <- 0 until 32){ 8 | // 先写入, 再读出进行验证 9 | // rf(i) = i, 在expect 10 | poke(c.io.we, 1) 11 | poke(c.io.waddr, i) 12 | poke(c.io.wdata, i) 13 | step(1) 14 | } 15 | // 读出验证 rf(i) === i 16 | for(i <- 0 until 32){ 17 | poke(c.io.raddr1, i) 18 | expect(c.io.rdata1, i) 19 | } 20 | 21 | } 22 | 23 | 24 | object mem_test_gen extends App{ 25 | chisel3.iotesters.Driver.execute(args, () => new mem_print)(c => new mem_test(c)) 26 | }*/ -------------------------------------------------------------------------------- /nemu/include/monitor/log.h: -------------------------------------------------------------------------------- 1 | #ifndef __MONITOR_LOG_H__ 2 | #define __MONITOR_LOG_H__ 3 | 4 | #include 5 | 6 | #ifdef DEBUG 7 | extern FILE* log_fp; 8 | # define log_write(...) \ 9 | do { \ 10 | extern bool log_enable(); \ 11 | if (log_fp != NULL && log_enable()) { \ 12 | fprintf(log_fp, __VA_ARGS__); \ 13 | fflush(log_fp); \ 14 | } \ 15 | } while (0) 16 | #else 17 | # define log_write(...) 18 | #endif 19 | 20 | #define _Log(...) \ 21 | do { \ 22 | printf(__VA_ARGS__); \ 23 | log_write(__VA_ARGS__); \ 24 | } while (0) 25 | 26 | void strcatf(char *buf, const char *fmt, ...); 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /docs/9.28.md: -------------------------------------------------------------------------------- 1 | #### 今日任务 2 | 3 | 1. 解决流水线冲突问题(使用前递方法), 优先阅读体系结构讲义, 然后再看soder的实现方法 4 | 5 | 2. 转移指令必须等到其延迟槽指令取进流水线之后才能进入后续的流水线阶段! 位于 ID 阶段的转移指令必须等到其对应的转移延迟槽指令可以进入 ID 阶段的时候才能进入到EXE 阶段。 6 | 7 | 3. 注意使用nemu的数据库! 的nemu.so 有更新!!! 8 | 9 | 4. 突然觉得自己的进度也不是很慢, 还是可以继续往后面做的, 加油! 10 | 11 | 5. 处理器对外接口需要改成AXI4 的接口, 之后需要更新的 12 | 13 | 14 | 15 | 其他 16 | 17 | 字节跳动, 希望做riscv的芯片, 在服务器芯片上有一定地位 18 | 19 | 香山核, 希望做出一个类似linux的开源项目 20 | 21 | riscv在中国会有很大的发展, 特别是这样的国际环境下 22 | 23 | 国内外riscv现状: 24 | 25 | 1. 中国企业20%, 总部在瑞士 26 | 2. 有做软件, 工具, 应用, IP商 27 | 3. 学术界上使用riscv来进行体系结构上的验证, 是很好的研究载体. 28 | 4. 未来十年有我们很大的发挥空间 29 | 5. 我们都处在这个时代之中, 我们也在书写自己的历史! 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /nexus-am/tests/cputest/Makefile: -------------------------------------------------------------------------------- 1 | include $(AM_HOME)/Makefile.check 2 | .PHONY: all run clean latest $(ALL) 3 | 4 | ALL = $(basename $(notdir $(shell find tests/. -name "*.c"))) 5 | 6 | all: $(addprefix Makefile., $(ALL)) 7 | @echo "" $(ALL) 8 | 9 | $(ALL): %: Makefile.% 10 | 11 | Makefile.%: tests/%.c latest 12 | @/bin/echo -e "NAME = $*\nSRCS = $<\nLIBS += klib\ninclude $${AM_HOME}/Makefile.app" > $@ 13 | -@make -s -f $@ ARCH=$(ARCH) $(MAKECMDGOALS) 14 | -@rm -f Makefile.$* 15 | 16 | #cancel rules included by $(AM_HOME)/Makefile.check 17 | image: ; 18 | default $(MAKECMDGOALS): all ; 19 | 20 | clean: 21 | rm -rf Makefile.* build/ 22 | 23 | latest: 24 | -------------------------------------------------------------------------------- /nexus-am/am/src/nutshell/ldscript/section.ld: -------------------------------------------------------------------------------- 1 | ENTRY(_start) 2 | 3 | SECTIONS { 4 | . = ORIGIN(ram); 5 | .text : { 6 | *(entry) 7 | *(.text) 8 | } 9 | etext = .; 10 | _etext = .; 11 | .rodata : { 12 | *(.rodata*) 13 | } 14 | .data : { 15 | *(.data) 16 | } 17 | edata = .; 18 | _data = .; 19 | .bss : { 20 | _bss_start = .; 21 | *(.bss*) 22 | *(.sbss*) 23 | *(.scommon) 24 | } 25 | _stack_top = ALIGN(0x1000); 26 | . = _stack_top + 0x8000; 27 | _stack_pointer = .; 28 | end = .; 29 | _end = .; 30 | _heap_start = ALIGN(0x1000); 31 | _pmem_start = pmem_base; 32 | _pmem_end = _pmem_start + LENGTH(ram); 33 | } 34 | -------------------------------------------------------------------------------- /nexus-am/tests/cputest/tests/switch.c: -------------------------------------------------------------------------------- 1 | #include "trap.h" 2 | 3 | int switch_case(int n) { 4 | int ret; 5 | switch(n) { 6 | case 0: ret = 0; break; 7 | case 1: ret = 2; break; 8 | case 2: case 3: ret = 5; break; 9 | case 4: case 5: case 6: case 7: ret = 8; break; 10 | case 8: case 9: case 10: case 11: ret = 10; break; 11 | case 12: ret = 15; break; 12 | default: ret = -1; break; 13 | } 14 | 15 | return ret; 16 | } 17 | 18 | int ans[] = {-1, 0, 2, 5, 5, 8, 8, 8, 8, 10, 10, 10, 10, 15, -1}; 19 | 20 | int main() { 21 | int i; 22 | for(i = 0; i < 15; i ++) { 23 | nemu_assert(switch_case(i - 1) == ans[i]); 24 | } 25 | 26 | nemu_assert(i == 15); 27 | 28 | return 0; 29 | } 30 | -------------------------------------------------------------------------------- /verilator/difftest.h: -------------------------------------------------------------------------------- 1 | #ifndef __DIFFTESTIO_H__ 2 | #define __DIFFTESTIO_H__ 3 | 4 | #include "common.h" 5 | #include "ram.h" 6 | #include "emulator.h" 7 | 8 | 9 | 10 | 11 | void init_difftest(reg_t *reg, char* imgPath, CRam* ram); 12 | int difftest_step(CEmulator* emu); 13 | 14 | 15 | static const char *reg_name[DIFFTEST_NR_REG] = { 16 | "$0", "ra", "sp", "gp", "tp", "t0", "t1", "t2", 17 | "s0", "s1", "a0", "a1", "a2", "a3", "a4", "a5", 18 | "a6", "a7", "s2", "s3", "s4", "s5", "s6", "s7", 19 | "s8", "s9", "s10", "s11", "t3", "t4", "t5", "t6", 20 | "this_pc" 21 | #ifndef __RV32__ 22 | ,"mstatus", "mcause", "mepc", 23 | "sstatus", "scause", "sepc" 24 | #endif 25 | }; 26 | 27 | #endif -------------------------------------------------------------------------------- /nexus-am/tests/cputest/tests/leap-year.c: -------------------------------------------------------------------------------- 1 | #include "trap.h" 2 | 3 | int is_leap_year(int n) { 4 | return (n % 4 == 0 && n % 100 != 0) || (n % 400 == 0); 5 | } 6 | 7 | int ans[] = {0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}; 8 | 9 | int main() { 10 | int i; 11 | for(i = 0; i < 125; i ++) { 12 | nemu_assert(is_leap_year(i + 1890) == ans[i]); 13 | } 14 | 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /nexus-am/tests/cputest/tests/if-else.c: -------------------------------------------------------------------------------- 1 | #include "trap.h" 2 | 3 | int if_else(int n) { 4 | int cost; 5 | if(n > 500) cost = 150; 6 | else if(n > 300) cost = 100; 7 | else if(n > 100) cost = 75; 8 | else if(n > 50) cost = 50; 9 | else cost = 0; 10 | 11 | return cost; 12 | } 13 | 14 | int test_data[] = {-1, 0, 49, 50, 51, 99, 100, 101, 299, 300, 301, 499, 500, 501}; 15 | int ans[] = {0, 0, 0, 0, 50, 50, 50, 75, 75, 75, 100, 100, 100, 150}; 16 | 17 | #define NR_DATA LENGTH(test_data) 18 | 19 | int main() { 20 | int i, ans_idx = 0; 21 | for(i = 0; i < NR_DATA; i ++) { 22 | nemu_assert(if_else(test_data[i]) == ans[ans_idx ++]); 23 | } 24 | 25 | nemu_assert(i == NR_DATA); 26 | 27 | return 0; 28 | } 29 | -------------------------------------------------------------------------------- /docs/8.26 学习总结.md: -------------------------------------------------------------------------------- 1 | ### 8月26日学习总结 2 | 3 | #### chisel学习 4 | 5 | 1. chisel-bootcamp 前三章节学习, 做了一些笔记在纸上, 之后用到再查询吧 6 | 2. chisel-tutorial 学习以及阅读源代码, 有过bootcamp学习, 看这个就比较快了, 但是测试还是依靠poke, expect这些, 对于写大项目还是不太实用啊, 不过能在本地运行chisel了 7 | 3. 一些知乎, 博客等随时查阅 8 | 9 | 10 | 11 | #### riscv 复习 12 | 13 | 之前学过, 主要是把指令手册重新复习了一遍, 还有些特权指令集之类的 14 | 15 | 16 | 17 | #### 框架搭建 18 | 19 | 这一块觉得是最难的, 感觉要学的东西很多, 也花了挺多时间阅读代码, 主要参考 20 | 21 | 1. riscv-soder, 直接实用c++的模拟器去验证, 大概阅读了源代码, 但是和nutshell毕竟不同, 没有使用任何的开源工具. 阅读了一级, 二级流水线的chisel代码, 感觉有挺多可以学习的. 22 | 2. nemu, am这些代码, 也看了南京大学的教学任务书, 感觉要实现的还是挺多, 之后还要更改成64位框架, 以及如何和verilator之类进行交互, 也阅读了Nutshell的部分代码, 不是很了解整个验证流程. 23 | 3. 还是希望能搭建好框架之后, 能够一键进行调试, 毕竟我们没有这方面的开发经验, 感觉要独立搭建好框架,对我自己来说, 难度挺高的, 而且之后可能也没有足够的时间进行chisel开发. 24 | 25 | -------------------------------------------------------------------------------- /nemu/include/macro.h: -------------------------------------------------------------------------------- 1 | #ifndef __MACRO_H__ 2 | #define __MACRO_H__ 3 | 4 | #define str_temp(x) #x 5 | #define str(x) str_temp(x) 6 | 7 | #define concat_temp(x, y) x ## y 8 | #define concat(x, y) concat_temp(x, y) 9 | #define concat3(x, y, z) concat(concat(x, y), z) 10 | #define concat4(x, y, z, w) concat3(concat(x, y), z, w) 11 | #define concat5(x, y, z, v, w) concat4(concat(x, y), z, v, w) 12 | 13 | #define MAP(c, f) c(f) 14 | 15 | #define uint_type(bits) concat3(uint, bits, _t) 16 | #define BITMASK(bits) ((1 << (bits)) - 1) 17 | #define BITS(x, hi, lo) (((x) >> (lo)) & BITMASK((hi) - (lo) + 1)) // similar to x[hi:lo] in verilog 18 | #define SEXT(x, len) ({ struct { int64_t n : len; } __x = { .n = x }; (int64_t)__x.n; }) 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /nexus-am/tests/cputest/tests/movsx.c: -------------------------------------------------------------------------------- 1 | #include "trap.h" 2 | 3 | volatile int A[10]; 4 | volatile int b; 5 | volatile signed char C[10]; 6 | int main() { 7 | A[0] = 0; 8 | A[1] = 1; 9 | A[2] = 2; 10 | A[3] = 3; 11 | A[4] = 4; 12 | 13 | b = A[3]; 14 | A[5] = b; 15 | C[0] = 'a'; 16 | nemu_assert(C[0] == 'a'); 17 | C[1] = C[0]; 18 | nemu_assert(C[1] == 'a'); 19 | A[0] = (int)C[0]; 20 | nemu_assert(A[0] == 'a'); 21 | C[1] = 0x80; 22 | A[0] = (int)C[1]; 23 | nemu_assert(A[1] == 1); 24 | nemu_assert(A[2] == 2); 25 | nemu_assert(A[3] == 3); 26 | nemu_assert(A[4] == 4); 27 | nemu_assert(b == 3); 28 | nemu_assert(A[5] == 3); 29 | nemu_assert(C[1] == 0xffffff80); 30 | nemu_assert(A[0] == 0xffffff80); 31 | 32 | return 0; 33 | } 34 | -------------------------------------------------------------------------------- /src/main/scala/nutcore/top.scala: -------------------------------------------------------------------------------- 1 | package nutcore 2 | 3 | import chisel3._ 4 | import common._ 5 | 6 | class topIO extends Bundle{ 7 | val instReadIO = new InstReadIO 8 | val dataReadIO = new DataReadIO 9 | val dataWriteIO = new DataWriteIO 10 | // val dataRamIO = new DataRamIO 11 | } 12 | 13 | 14 | class top extends Module{ 15 | val io = IO(new topIO) 16 | val cpath = Module(new cpath) 17 | val dpath = Module(new dpath) 18 | 19 | // 和外部连接 20 | // io.instReadIO <> dpath.io.instReadIO 21 | // io.dataReadIO <> dpath.io.dataReadIO 22 | // io.dataWriteIO <> dpath.io.dataWriteIO 23 | // io.dataRamIO <> dpath.io.dataRamIO 24 | 25 | // 两个模块连接 26 | cpath.io.ctl <> dpath.io.ctl 27 | cpath.io.dat <> dpath.io.dat 28 | 29 | } -------------------------------------------------------------------------------- /nexus-am/tests/cputest/tests/bubble-sort.c: -------------------------------------------------------------------------------- 1 | #include "trap.h" 2 | 3 | #define N 20 4 | 5 | int a[N] = {2, 12, 14, 6, 13, 15, 16, 10, 0, 18, 11, 19, 9, 1, 7, 5, 4, 3, 8, 17}; 6 | 7 | void bubble_sort() { 8 | int i, j, t; 9 | for(j = 0; j < N; j ++) { 10 | for(i = 0; i < N - 1 - j; i ++) { 11 | if(a[i] > a[i + 1]) { 12 | t = a[i]; 13 | a[i] = a[i + 1]; 14 | a[i + 1] = t; 15 | } 16 | } 17 | } 18 | } 19 | 20 | int main() { 21 | bubble_sort(); 22 | 23 | int i; 24 | for(i = 0; i < N; i ++) { 25 | nemu_assert(a[i] == i); 26 | } 27 | 28 | nemu_assert(i == N); 29 | 30 | bubble_sort(); 31 | 32 | for(i = 0; i < N; i ++) { 33 | nemu_assert(a[i] == i); 34 | } 35 | 36 | nemu_assert(i == N); 37 | 38 | return 0; 39 | } 40 | -------------------------------------------------------------------------------- /nemu/src/device/io/mmio.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define NR_MAP 16 4 | 5 | static IOMap maps[NR_MAP] = {}; 6 | static int nr_map = 0; 7 | 8 | /* device interface */ 9 | void add_mmio_map(char *name, paddr_t addr, uint8_t* space, int len, io_callback_t callback) { 10 | assert(nr_map < NR_MAP); 11 | maps[nr_map] = (IOMap){ .name = name, .low = addr, .high = addr + len - 1, 12 | .space = space, .callback = callback }; 13 | Log("Add mmio map '%s' at [0x%08x, 0x%08x]", maps[nr_map].name, maps[nr_map].low, maps[nr_map].high); 14 | 15 | nr_map ++; 16 | } 17 | 18 | /* bus interface */ 19 | IOMap* fetch_mmio_map(paddr_t addr) { 20 | int mapid = find_mapid_by_addr(maps, nr_map, addr); 21 | return (mapid == -1 ? NULL : &maps[mapid]); 22 | } 23 | -------------------------------------------------------------------------------- /nexus-am/apps/microbench/src/lzip/lzip.c: -------------------------------------------------------------------------------- 1 | #include "quicklz.h" 2 | #include 3 | 4 | static int SIZE; 5 | 6 | static qlz_state_compress *state; 7 | static char *blk; 8 | static char *compress; 9 | static int len; 10 | 11 | void bench_lzip_prepare() { 12 | SIZE = setting->size; 13 | bench_srand(1); 14 | state = bench_alloc(sizeof(qlz_state_compress)); 15 | blk = bench_alloc(SIZE); 16 | compress = bench_alloc(SIZE + 400); 17 | for (int i = 0; i < SIZE; i ++) { 18 | blk[i] = 'a' + bench_rand() % 26; 19 | } 20 | } 21 | 22 | void bench_lzip_run() { 23 | len = qlz_compress(blk, compress, SIZE, state); 24 | } 25 | 26 | int bench_lzip_validate() { 27 | return checksum(compress, compress + len) == setting->checksum; 28 | } 29 | 30 | -------------------------------------------------------------------------------- /nexus-am/tests/cputest/tests/pascal.c: -------------------------------------------------------------------------------- 1 | #include "trap.h" 2 | 3 | #define N 31 4 | 5 | int a[N]; 6 | int ans[] = {1, 30, 435, 4060, 27405, 142506, 593775, 2035800, 5852925, 14307150, 30045015, 54627300, 86493225, 119759850, 145422675, 155117520, 145422675, 119759850, 86493225, 54627300, 30045015, 14307150, 5852925, 2035800, 593775, 142506, 27405, 4060, 435, 30, 1}; 7 | 8 | int main() { 9 | int i, j; 10 | int t0, t1; 11 | a[0] = a[1] = 1; 12 | 13 | for(i = 2; i < N; i ++) { 14 | t0 = 1; 15 | for(j = 1; j < i; j ++) { 16 | t1 = a[j]; 17 | a[j] = t0 + t1; 18 | t0 = t1; 19 | } 20 | a[i] = 1; 21 | } 22 | 23 | for(j = 0; j < N; j ++) { 24 | nemu_assert(a[j] == ans[j]); 25 | } 26 | 27 | nemu_assert(j == N); 28 | 29 | return 0; 30 | } 31 | -------------------------------------------------------------------------------- /src/test/scala/nutcore/regfile_test.scala: -------------------------------------------------------------------------------- 1 | package nutcore 2 | 3 | import chisel3.iotesters.PeekPokeTester 4 | 5 | import scala.util.Random 6 | 7 | class regfile_test(c: regfile) extends PeekPokeTester(c){ 8 | val randNum = new Random() 9 | val data = randNum.nextInt(1000) 10 | for(i <- 0 until 32){ 11 | // 先写入, 再读出进行验证 12 | // rf(i) = i*10, 在expect 13 | poke(c.io.we, 1) 14 | poke(c.io.waddr, i) 15 | poke(c.io.wdata, i*10) 16 | step(1) 17 | } 18 | // 读出验证 rf(i) === i 19 | for(i <- 0 until 32){ 20 | poke(c.io.raddr1, i) 21 | expect(c.io.rdata1, i*10) 22 | } 23 | 24 | } 25 | 26 | 27 | object regfile_test_gen extends App{ 28 | chisel3.iotesters.Driver.execute(args, () => new regfile)(c => new regfile_test(c)) 29 | } -------------------------------------------------------------------------------- /nemu/src/isa/riscv64/exec/special.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | make_EHelper(inv) { 6 | /* invalid opcode */ 7 | 8 | uint32_t instr[2]; 9 | s->seq_pc = cpu.pc; 10 | instr[0] = instr_fetch(&s->seq_pc, 4); 11 | instr[1] = instr_fetch(&s->seq_pc, 4); 12 | 13 | printf("invalid opcode(PC = 0x%016lx): %08x %08x ...\n\n", 14 | cpu.pc, instr[0], instr[1]); 15 | 16 | display_inv_msg(cpu.pc); 17 | 18 | rtl_exit(NEMU_ABORT, cpu.pc, -1); 19 | 20 | print_asm("invalid opcode"); 21 | } 22 | 23 | make_EHelper(nemu_trap) { 24 | difftest_skip_ref(); 25 | 26 | rtl_exit(NEMU_END, cpu.pc, cpu.gpr[10]._64); // grp[10] is $a0 27 | 28 | print_asm("nemu trap"); 29 | return; 30 | } 31 | -------------------------------------------------------------------------------- /nexus-am/tests/cputest/tests/select-sort.c: -------------------------------------------------------------------------------- 1 | #include "trap.h" 2 | 3 | #define N 20 4 | 5 | int a[N] = {2, 12, 14, 6, 13, 15, 16, 10, 0, 18, 11, 19, 9, 1, 7, 5, 4, 3, 8, 17}; 6 | 7 | void select_sort() { 8 | int i, j, k, t; 9 | for(i = 0; i < N - 1; i ++) { 10 | k = i; 11 | for(j = i + 1; j < N; j ++) { 12 | if(a[j] < a[k]) { 13 | k = j; 14 | } 15 | } 16 | 17 | t = a[i]; 18 | a[i] = a[k]; 19 | a[k] = t; 20 | } 21 | } 22 | 23 | int main() { 24 | select_sort(); 25 | 26 | int i; 27 | for(i = 0; i < N; i ++) { 28 | nemu_assert(a[i] == i); 29 | } 30 | 31 | nemu_assert(i == N); 32 | 33 | select_sort(); 34 | 35 | for(i = 0; i < N; i ++) { 36 | nemu_assert(a[i] == i); 37 | } 38 | 39 | nemu_assert(i == N); 40 | 41 | return 0; 42 | } 43 | -------------------------------------------------------------------------------- /nexus-am/tests/cputest/tests/string.c: -------------------------------------------------------------------------------- 1 | #include "trap.h" 2 | 3 | char *s[] = { 4 | "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 5 | "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab", 6 | "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 7 | ", World!\n", 8 | "Hello, World!\n", 9 | "#####" 10 | }; 11 | 12 | char str1[] = "Hello"; 13 | char str[20]; 14 | 15 | int main() { 16 | nemu_assert(strcmp(s[0], s[2]) == 0); 17 | nemu_assert(strcmp(s[0], s[1]) == -1); 18 | nemu_assert(strcmp(s[0] + 1, s[1] + 1) == -1); 19 | nemu_assert(strcmp(s[0] + 2, s[1] + 2) == -1); 20 | nemu_assert(strcmp(s[0] + 3, s[1] + 3) == -1); 21 | 22 | nemu_assert(strcmp( strcat(strcpy(str, str1), s[3]), s[4]) == 0); 23 | 24 | nemu_assert(memcmp(memset(str, '#', 5), s[5], 5) == 0); 25 | 26 | return 0; 27 | } 28 | -------------------------------------------------------------------------------- /docs/9.22.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | #### 特权指令 4 | 5 | 1. 分为M,S, U三种模式, M必须实现, 一般还可以实现U, 对linux需要实现S 6 | 2. CSR的[11:0] 用于约定: [11:10] 表示读写(00/01/10)or只读(11), [9:8]表示可以访问的最低特权级别(00-U, 01-S, 10-Hypervisor?, 11-M) 7 | 3. 具体的之后再看吧 8 | 9 | 10 | 11 | #### 64位要改的部分 12 | 13 | 1. 所有reg(32个通用+ pc) 均为64位 14 | 2. 每次PC+8 15 | 3. 添加addiw 这些指令, 能支持word(32位字) 16 | 4. 对每个模块 debug_alu 这样分别宏定义来调试 17 | 5. 译码方式可能要改 18 | 19 | 20 | 21 | #### debug 22 | 23 | 1. 为何在第一拍没有读出指令? 24 | 2. 首次创建变量时用等号=初始化,如果变量引用的对象不能立即确定状态或本身就是可变对象,则在后续更新状态时应该用“:=”。 25 | 26 | 27 | 28 | #### 命名规范 29 | 30 | 1. 类名用CPerson, C开头表示类, 成员名用m_ 开头. 31 | 2. 函数用大驼峰, InitQueue 32 | 3. 变量用驼峰, emitClass 33 | 4. 常量, 宏定义, 枚举, 一般所有字母大写, 可以加下划线 34 | 35 | 36 | 37 | 如何在nemu上运行不同的仿真程序并执行? 38 | 39 | 40 | 41 | 注意: mem读写是异步的, 对于单周期流水线来说, 要等到下一拍才能读出正确的指令! 所以可以开始改成5级流水线来执行吧 -------------------------------------------------------------------------------- /nexus-am/apps/microbench/src/queen/queen.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | static unsigned int FULL; 4 | 5 | static unsigned int dfs(unsigned int row, unsigned int ld, unsigned int rd) { 6 | if (row == FULL) { 7 | return 1; 8 | } else { 9 | unsigned int pos = FULL & (~(row | ld | rd)), ans = 0; 10 | while (pos) { 11 | unsigned int p = (pos & (~pos + 1)); 12 | pos -= p; 13 | ans += dfs(row | p, (ld | p) << 1, (rd | p) >> 1); 14 | } 15 | return ans; 16 | } 17 | } 18 | 19 | static unsigned int ans; 20 | 21 | void bench_queen_prepare() { 22 | ans = 0; 23 | FULL = (1 << setting->size) - 1; 24 | } 25 | 26 | void bench_queen_run() { 27 | ans = dfs(0, 0, 0); 28 | } 29 | 30 | int bench_queen_validate() { 31 | return ans == setting->checksum; 32 | } 33 | -------------------------------------------------------------------------------- /nexus-am/Makefile.check: -------------------------------------------------------------------------------- 1 | ## Always build "default" 2 | .DEFAULT_GOAL = default 3 | 4 | ## Ignore checks for make clean 5 | ifneq ($(MAKECMDGOALS),clean) 6 | 7 | ## Check: Environment variable $AM_HOME must exist 8 | ifeq ($(AM_HOME),) 9 | $(error Environment variable AM_HOME must be defined.) 10 | endif 11 | 12 | ## Check: Environment variable $ARCH must be in the supported list 13 | ARCH ?= native 14 | ARCHS := $(basename $(notdir $(shell ls $(AM_HOME)/am/arch/*.mk))) 15 | ifeq ($(filter $(ARCHS), $(ARCH)), ) 16 | $(error Invalid ARCH. Supported: $(ARCHS)) 17 | endif 18 | 19 | ## ARCH=x86-qemu -> ISA=x86; PLATFORM=qemu 20 | ARCH_SPLIT = $(subst -, ,$(ARCH)) 21 | ISA ?= $(word 1,$(ARCH_SPLIT)) 22 | PLATFORM ?= $(word 2,$(ARCH_SPLIT)) 23 | 24 | include $(AM_HOME)/am/arch/$(ARCH).mk 25 | 26 | endif 27 | -------------------------------------------------------------------------------- /nemu/src/isa/riscv64/difftest/dut.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "../local-include/reg.h" 5 | #include "difftest.h" 6 | 7 | bool isa_difftest_checkregs(CPU_state *ref_r, vaddr_t pc) { 8 | if (memcmp(&cpu.gpr[1], &ref_r->gpr[1], DIFFTEST_REG_SIZE - sizeof(cpu.gpr[0]))) { 9 | int i; 10 | // do not check $0 11 | for (i = 1; i < sizeof(cpu.gpr) / sizeof(cpu.gpr[0]); i ++) { 12 | difftest_check_reg(reg_name(i, 4), pc, ref_r->gpr[i]._64, cpu.gpr[i]._64); 13 | } 14 | difftest_check_reg("pc", pc, ref_r->pc, cpu.pc); 15 | return false; 16 | } 17 | return true; 18 | } 19 | 20 | void isa_difftest_attach(void) { 21 | ref_difftest_memcpy_from_dut(PMEM_BASE, guest_to_host(0), PMEM_SIZE); 22 | ref_difftest_setregs(&cpu); 23 | } 24 | -------------------------------------------------------------------------------- /nexus-am/Makefile.lib: -------------------------------------------------------------------------------- 1 | include $(AM_HOME)/Makefile.check 2 | $(info # Building lib-$(NAME) [$(ARCH)]) 3 | 4 | LIB_DIR ?= $(shell pwd) 5 | INC_DIR += $(LIB_DIR)/include/ 6 | DST_DIR ?= $(LIB_DIR)/build/$(ARCH)/ 7 | ARCHIVE ?= $(LIB_DIR)/build/$(NAME)-$(ARCH).a 8 | 9 | ## Default: Build a linkable archive (.a) 10 | default: $(ARCHIVE) 11 | 12 | INC_DIR += $(addsuffix /include/, $(addprefix $(AM_HOME)/libs/, $(LIBS))) 13 | CFLAGS += -fdata-sections -ffunction-sections -fno-builtin 14 | 15 | ## Paste in "Makefile.compile" here 16 | include $(AM_HOME)/Makefile.compile 17 | 18 | ## Compliation rule for objects -> .a (using ar) 19 | $(ARCHIVE): $(OBJS) 20 | @echo + AR "->" $(shell realpath $@ --relative-to .) 21 | @ar rcs $(ARCHIVE) $(OBJS) 22 | 23 | clean: 24 | rm -rf $(LIB_DIR)/build/ 25 | 26 | .PHONY: default clean 27 | -------------------------------------------------------------------------------- /nexus-am/tests/cputest/tests/mul-longlong.c: -------------------------------------------------------------------------------- 1 | #include "trap.h" 2 | 3 | long long mul(long long a,long long b) { 4 | long long ans = a*b; 5 | return ans; 6 | } 7 | 8 | int test_data[] = { 0xaeb1c2aa, 0x4500ff2b, 0x877190af, 0x11f42438}; 9 | long long ans[] = { 0x19d29ab9db1a18e4LL, 0xea15986d3ac3088eLL, 0x2649e980fc0db236LL, 0xfa4c43da0a4a7d30LL, 0x1299898e2c56b139LL, 0xdf8123d50a319e65LL, 0x4d6dfa84c15dd68LL, 0x38c5d79b9e4357a1LL, 0xf78b91cb1efc4248LL, 0x14255a47fdfcc40LL}; 10 | 11 | #define NR_DATA LENGTH(test_data) 12 | 13 | int main() { 14 | int i,j,ans_idx = 0; 15 | for (i = 0;i < NR_DATA;i++) { 16 | for (j = i;j < NR_DATA;j++) { 17 | nemu_assert(ans[ans_idx++] == mul(test_data[i],test_data[j])); 18 | } 19 | nemu_assert(j == NR_DATA); 20 | } 21 | 22 | nemu_assert(i == NR_DATA); 23 | 24 | return 0; 25 | } 26 | 27 | -------------------------------------------------------------------------------- /src/main/scala/common/RamIO.scala: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import chisel3._ 4 | import constans._ 5 | 6 | class RamIO extends Bundle { 7 | val req = Output(Bool()) 8 | val wr = Output(Bool()) 9 | val size = Output(UInt(3.W)) 10 | val addr = Output(UInt(XLEN.W)) 11 | val wdata = Output(UInt(XLEN.W)) 12 | 13 | val rdata = Input(UInt(XLEN.W)) 14 | val addr_ok = Input(Bool()) 15 | val data_ok = Input(Bool()) 16 | 17 | override def toPrintable: Printable = { 18 | p"RamIO:" + 19 | p" req : ${req}" + 20 | p" wr : ${wr}" + 21 | p" size : ${size}" + 22 | p" addr : 0x${Hexadecimal(addr)}" + 23 | p" wdata : 0x${Hexadecimal(wdata)}" + 24 | p" rdata : 0x${Hexadecimal(rdata)}" + 25 | p" addr_ok: ${addr_ok}" + 26 | p" data_ok: ${data_ok}\n" 27 | } 28 | 29 | } 30 | 31 | -------------------------------------------------------------------------------- /nemu/include/debug.h: -------------------------------------------------------------------------------- 1 | #ifndef __DEBUG_H__ 2 | #define __DEBUG_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #define Log(format, ...) \ 9 | _Log("\33[1;34m[%s,%d,%s] " format "\33[0m\n", \ 10 | __FILE__, __LINE__, __func__, ## __VA_ARGS__) 11 | 12 | #define Assert(cond, ...) \ 13 | do { \ 14 | if (!(cond)) { \ 15 | fflush(stdout); \ 16 | fprintf(stderr, "\33[1;31m"); \ 17 | fprintf(stderr, __VA_ARGS__); \ 18 | fprintf(stderr, "\33[0m\n"); \ 19 | extern void isa_reg_display(); \ 20 | extern void monitor_statistic(); \ 21 | isa_reg_display(); \ 22 | monitor_statistic(); \ 23 | assert(cond); \ 24 | } \ 25 | } while (0) 26 | 27 | #define panic(...) Assert(0, __VA_ARGS__) 28 | 29 | #define TODO() panic("please implement me") 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /nexus-am/am/src/nutshell/isa/riscv/trm.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | extern char _heap_start; 6 | extern char _pmem_end; 7 | int main(const char *args); 8 | void __am_init_uartlite(void); 9 | void __am_uartlite_putchar(char ch); 10 | 11 | _Area _heap = { 12 | .start = &_heap_start, 13 | .end = &_pmem_end, 14 | }; 15 | 16 | void _putc(char ch) { 17 | __am_uartlite_putchar(ch); 18 | } 19 | 20 | void _halt(int code) { 21 | __asm__ volatile("mv a0, %0; .word 0x0005006b" : :"r"(code)); 22 | 23 | // should not reach here during simulation 24 | printf("Exit with code = %d\n", code); 25 | 26 | // should not reach here on FPGA 27 | while (1); 28 | } 29 | 30 | void _trm_init() { 31 | __am_init_uartlite(); 32 | extern const char __am_mainargs; 33 | int ret = main(&__am_mainargs); 34 | _halt(ret); 35 | } 36 | -------------------------------------------------------------------------------- /src/main/scala/sim/simTop.scala: -------------------------------------------------------------------------------- 1 | package sim 2 | 3 | import chisel3._ 4 | import chisel3.util._ 5 | import chisel3.util.experimental.BoringUtils 6 | import common._ 7 | import nutcore._ 8 | 9 | 10 | class simTop extends Module{ 11 | val io = IO(new Bundle{ 12 | val diffTestIO = new diffTestIO 13 | val topIO = new topIO 14 | }) 15 | io := DontCare // 不会被使用 16 | 17 | val mycoretop = Module(new top()) 18 | BoringUtils.addSink(io.diffTestIO.regfile, "diffTestRegfile") 19 | BoringUtils.addSink(io.diffTestIO.PC, "diffTestPC") 20 | BoringUtils.addSink(io.diffTestIO.PC_valid, "diffTestPC_valid") 21 | BoringUtils.addSink(io.diffTestIO.nemu_halt, "diffTestHalt") 22 | io.topIO <> mycoretop.io 23 | 24 | } 25 | 26 | object elaborate extends App { 27 | (new stage.ChiselStage).execute(args, Seq(stage.ChiselGeneratorAnnotation(() => new simTop))) 28 | } -------------------------------------------------------------------------------- /nemu/src/monitor/difftest/ref.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | void cpu_exec(uint64_t); 7 | 8 | void difftest_memcpy_from_dut(paddr_t dest, void *src, size_t n) { 9 | memcpy(guest_to_host(dest - PMEM_BASE), src, n); 10 | } 11 | 12 | void difftest_getregs(void *r) { 13 | isa_difftest_getregs(r); 14 | } 15 | 16 | void difftest_setregs(const void *r) { 17 | isa_difftest_setregs(r); 18 | } 19 | 20 | void difftest_exec(uint64_t n) { 21 | cpu_exec(n); 22 | } 23 | 24 | void difftest_raise_intr(word_t NO) { 25 | isa_difftest_raise_intr(NO); 26 | } 27 | 28 | void difftest_init(void) { 29 | /* Perform ISA dependent initialization. */ 30 | init_isa(); 31 | 32 | /* create dummy address space for serial */ 33 | add_mmio_map("difftest.serial", 0xa10003f8, new_space(8), 8, NULL); 34 | } 35 | -------------------------------------------------------------------------------- /docs/9.12 verilator.md: -------------------------------------------------------------------------------- 1 | ### Verilator 学习 2 | 3 | #### 概述 4 | 5 | 1. 把verilog设计转换成C++/ systemC模型, 编译之后就可执行. 不是传统的模拟器, 而是编译器 6 | 7 | 2. verilator类似gcc, 仿真时候, 自己写一个C++ 包装文件, main 把模型实例化为C++对象. 8 | 9 | 3. 注意当前版本: 从3.9 升级到4.1了 10 | 11 | 4. make 太慢, 改成 make -j4 (只有IO密集才能做多核优化) 12 | 13 | 5. . ~/verilator.sh 来更换成4.1 版本 14 | 15 | ```bash 16 | export PATH=$HOME/.local/verilator/bin:$PATH 17 | # 新安装的verilator放在了.loval/verilator这里, 所以每次要设置下才能使用新版的, 和旧版区别在于 --build 选项 18 | ``` 19 | 20 | 21 | 22 | 23 | 24 | 1. 译码的src 操作数, 尝试用peekpoke进行测试, 对每个小模块 25 | 2. 对整个cpu的测试, 26 | 27 | 28 | 29 | ​ 王凯帆, 金越 30 | 31 | 1. 尽量用nemu 二进制文件, 可以直接调用具体函数. 先用来验证, 直接使用, 直接用来搭建框架. 能尽快写出rtl的代码. difftest.cpp 32 | 2. nutshell 直接用gdb, 在代码中添加printf来看看的. 33 | 3. 明白nutshell 的具体执行一条语句的具体. 只用明白第一条指令的如何对比, 来看具体. 实现add指令, 来具体实现来. 关注在处理器设计上, 能够明白第一条指令是如何对比的. 能尽量早的开始写rtl代码. 把verilog直接翻译成chisel代码. 34 | 35 | -------------------------------------------------------------------------------- /docs/9.8_总结.md: -------------------------------------------------------------------------------- 1 | 9.8 2 | 3 | 4 | 5 | ### Verilator 6 | 7 | “ Verilator”包将所有可综合的,许多行为的,Verilog和SystemVerilog设计转换为C ++或SystemC模型,编译后即可执行。Verilator不是传统的模拟器,而是编译器。 8 | 9 | 1. 类似于gcc, 读取verilog代码,可选的添加覆盖范围或者波形跟踪, 编译为c++/systemC模型, 这是验证 10 | 2. 仿真: 用户写主文件 11 | 12 | 13 | 14 | 15 | 16 | #### 当前面临的困难与挑战 17 | 18 | 1. 还是不知道如何搭建框架? 以下几个尝试 19 | 1. 有没有直接方便的开源框架可以直接用? spike? soder自带的? 伯克利的? verilog去套用组成原理的 20 | 2. 果壳框架能否直接修改? 关键是不用改太多, 并且有说明文档最好 21 | 3. 自己写, 难度很大, 不了解 22 | 4. 尝试由浅入深. soder自带的 -> verilog -> spike -> nutshell, 一步步脚印来 23 | 2. chiesl学习还不完全, 尝试复习bootcamp, 做tutorial(之后来吧) 24 | 3. 64位和32位之间的区别以及如何移植过去? 读文档吧 25 | 26 | 27 | 28 | #### riscv-soder 29 | 30 | 1. 有完整的工具链, riscv-gcc, riscv-objdump, riscv-isa-sim可以快速执行riscv二进制文件(模拟), 前端服务器fesvr加载riscv二进制文件并连接到--isa模拟器/chisel创建的模拟器 31 | 2. 主机-- 运行模拟器的机器, inst$ ; 目标机--模拟机(riscv核的机器) 32 | 3. 可以登陆服务器, 我就用我自己的吧, 有riscv工具链 33 | 34 | -------------------------------------------------------------------------------- /nexus-am/am/src/nutshell/common/uartlite.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define UARTLITE_MMIO 0x40600000 4 | #define UARTLITE_RX_FIFO 0x0 5 | #define UARTLITE_TX_FIFO 0x4 6 | #define UARTLITE_STAT_REG 0x8 7 | #define UARTLITE_CTRL_REG 0xc 8 | 9 | #define UARTLITE_RST_FIFO 0x03 10 | #define UARTLITE_TX_FULL 0x08 11 | #define UARTLITE_RX_VALID 0x01 12 | 13 | void __am_init_uartlite(void) { 14 | // outb(UARTLITE_MMIO + UARTLITE_CTRL_REG, UARTLITE_RST_FIFO); 15 | } 16 | 17 | void __am_uartlite_putchar(char ch) { 18 | // if (ch == '\n') __am_uartlite_putchar('\r'); 19 | 20 | // while (inb(UARTLITE_MMIO + UARTLITE_STAT_REG) & UARTLITE_TX_FULL); 21 | // outb(UARTLITE_MMIO + UARTLITE_TX_FIFO, ch); 22 | } 23 | 24 | int __am_uartlite_getchar() { 25 | // if (inb(UARTLITE_MMIO + UARTLITE_STAT_REG) & UARTLITE_RX_VALID) 26 | // return inb(UARTLITE_MMIO + UARTLITE_RX_FIFO); 27 | return 0; 28 | } 29 | -------------------------------------------------------------------------------- /nexus-am/tests/cputest/tests/to-lower-case.c: -------------------------------------------------------------------------------- 1 | #include "trap.h" 2 | 3 | char to_lower_case(char c) { 4 | return (c >= 'A' && c <= 'Z' ? (c + 32) : c); 5 | } 6 | 7 | volatile char ans [] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 8 | 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 9 | 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127}; 10 | 11 | int main() { 12 | int i; 13 | for(i = 0; i < 128; i ++) { 14 | nemu_assert(to_lower_case(i) == ans[i]); 15 | } 16 | 17 | return 0; 18 | } 19 | -------------------------------------------------------------------------------- /nemu/include/cpu/decode.h: -------------------------------------------------------------------------------- 1 | #ifndef __CPU_DECODE_H__ 2 | #define __CPU_DECODE_H__ 3 | 4 | #include 5 | 6 | #define OP_STR_SIZE 40 7 | enum { OP_TYPE_REG, OP_TYPE_MEM, OP_TYPE_IMM }; 8 | 9 | typedef struct { 10 | uint32_t type; 11 | int width; 12 | union { 13 | uint32_t reg; 14 | word_t imm; 15 | sword_t simm; 16 | }; 17 | rtlreg_t *preg; 18 | rtlreg_t val; 19 | char str[OP_STR_SIZE]; 20 | } Operand; 21 | 22 | typedef struct { 23 | uint32_t opcode; 24 | vaddr_t seq_pc; // sequential pc 25 | uint32_t is_jmp; 26 | vaddr_t jmp_pc; 27 | Operand src1, dest, src2; 28 | int width; 29 | rtlreg_t tmp_reg[4]; 30 | ISADecodeInfo isa; 31 | } DecodeExecState; 32 | 33 | #define make_DHelper(name) void concat(decode_, name) (DecodeExecState *s) 34 | 35 | #ifdef DEBUG 36 | #define print_Dop(...) snprintf(__VA_ARGS__) 37 | #else 38 | #define print_Dop(...) 39 | #endif 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /nexus-am/tests/cputest/tests/shift.c: -------------------------------------------------------------------------------- 1 | #include "trap.h" 2 | 3 | unsigned test[] = { 4 | 0x12345678, 0x98765432, 0x0, 0xeffa1000, 0x7fffffff, 0x80000000, 0x33, 0xffffffff 5 | }; 6 | 7 | unsigned srl_ans[] = { 8 | 0x2468ac, 0x130eca8, 0x0, 0x1dff420, 0xffffff, 0x1000000, 0x0, 0x1ffffff 9 | }; 10 | 11 | unsigned srlv_ans[] = { 12 | 0x1234567, 0x4c3b2a1, 0x0, 0x1dff420, 0x7fffff, 0x400000, 0x0, 0x1fffff 13 | }; 14 | 15 | unsigned srav_ans[] = { 16 | 0x1234567, 0xfcc3b2a1, 0x0, 0xffdff420, 0x7fffff, 0xffc00000, 0x0, 0xffffffff 17 | }; 18 | 19 | 20 | int main() { 21 | unsigned i; 22 | 23 | for(i = 0; i < LENGTH(test); i ++) { 24 | nemu_assert((test[i] >> 7) == srl_ans[i]); 25 | } 26 | 27 | for(i = 0; i < LENGTH(test); i ++) { 28 | nemu_assert((unsigned)((int)test[i] >> (i + 4)) == srav_ans[i]); 29 | } 30 | 31 | for(i = 0; i < LENGTH(test); i ++) { 32 | nemu_assert((test[i] >> (i + 4)) == srlv_ans[i]); 33 | } 34 | 35 | return 0; 36 | } 37 | -------------------------------------------------------------------------------- /nemu/src/isa/riscv64/clint.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "local-include/csr.h" 5 | 6 | #define CLINT_MMIO 0xa2000000 7 | #define CLINT_MTIMECMP (0x4000 / sizeof(clint_base[0])) 8 | #define CLINT_MTIME (0xBFF8 / sizeof(clint_base[0])) 9 | 10 | static uint64_t *clint_base = NULL; 11 | 12 | static inline void update_mtip(void) { 13 | mip->mtip = (clint_base[CLINT_MTIME] >= clint_base[CLINT_MTIMECMP]); 14 | } 15 | 16 | void clint_intr(void) { 17 | if (nemu_state.state == NEMU_RUNNING) { 18 | clint_base[CLINT_MTIME] += 0x800; 19 | update_mtip(); 20 | } 21 | } 22 | 23 | static void clint_io_handler(uint32_t offset, int len, bool is_write) { 24 | update_mtip(); 25 | } 26 | 27 | void init_clint(void) { 28 | clint_base = (void *)new_space(0x10000); 29 | add_mmio_map("clint", CLINT_MMIO, (void *)clint_base, 0x10000, clint_io_handler); 30 | add_alarm_handle(clint_intr); 31 | } 32 | -------------------------------------------------------------------------------- /nemu/src/monitor/debug/log.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | FILE *log_fp = NULL; 5 | 6 | void init_log(const char *log_file) { 7 | if (log_file == NULL) return; 8 | log_fp = fopen(log_file, "w"); 9 | Assert(log_fp, "Can not open '%s'", log_file); 10 | } 11 | 12 | char log_bytebuf[80] = {}; 13 | char log_asmbuf[80] = {}; 14 | static char tempbuf[256] = {}; 15 | 16 | void strcatf(char *buf, const char *fmt, ...) { 17 | va_list ap; 18 | va_start(ap, fmt); 19 | vsnprintf(tempbuf, sizeof(tempbuf), fmt, ap); 20 | va_end(ap); 21 | strcat(buf, tempbuf); 22 | } 23 | 24 | void asm_print(vaddr_t ori_pc, int instr_len, bool print_flag) { 25 | snprintf(tempbuf, sizeof(tempbuf), FMT_WORD ": %s%*.s%s", ori_pc, log_bytebuf, 26 | 50 - (12 + 3 * instr_len), "", log_asmbuf); 27 | log_write("%s\n", tempbuf); 28 | if (print_flag) { 29 | puts(tempbuf); 30 | } 31 | 32 | log_bytebuf[0] = '\0'; 33 | log_asmbuf[0] = '\0'; 34 | } 35 | -------------------------------------------------------------------------------- /nemu/include/common.h: -------------------------------------------------------------------------------- 1 | #ifndef __COMMON_H__ 2 | #define __COMMON_H__ 3 | 4 | #define DEBUG 5 | //#define DIFF_TEST 6 | 7 | #ifdef __ISA_riscv64__ 8 | # define ISA64 9 | #endif 10 | 11 | #if _SHARE 12 | // do not enable these features while building a reference design 13 | #undef DIFF_TEST 14 | #undef DEBUG 15 | #endif 16 | 17 | /* You will define this macro in PA2 */ 18 | #define HAS_IOE 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | typedef uint8_t bool; 25 | 26 | #ifdef ISA64 27 | typedef uint64_t word_t; 28 | typedef int64_t sword_t; 29 | #define FMT_WORD "0x%016lx" 30 | #else 31 | typedef uint32_t word_t; 32 | typedef int32_t sword_t; 33 | #define FMT_WORD "0x%08x" 34 | #endif 35 | 36 | typedef word_t rtlreg_t; 37 | typedef word_t vaddr_t; 38 | typedef uint32_t paddr_t; 39 | typedef uint16_t ioaddr_t; 40 | 41 | #define false 0 42 | #define true 1 43 | 44 | #include 45 | #include 46 | 47 | #endif 48 | -------------------------------------------------------------------------------- /nexus-am/apps/microbench/src/sieve/sieve.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | static int N; 4 | 5 | static int ans; 6 | static uint32_t *primes; 7 | 8 | static inline int get(int n) { 9 | return (primes[n >> 5] >> (n & 31)) & 1; 10 | } 11 | 12 | static inline void clear(int n) { 13 | primes[n >> 5] &= ~(1ul << (n & 31)); 14 | } 15 | 16 | void bench_sieve_prepare() { 17 | N = setting->size; 18 | primes = (uint32_t*)bench_alloc(N / 8 + 128); 19 | for (int i = 0; i <= N / 32; i ++) { 20 | primes[i] = 0xffffffff; 21 | } 22 | } 23 | 24 | void bench_sieve_run() { 25 | for (int i = 1; i <= N; i ++) 26 | if (!get(i)) return; 27 | for (int i = 2; i * i <= N; i ++) { 28 | if (get(i)) { 29 | for (int j = i + i; j <= N; j += i) 30 | clear(j); 31 | } 32 | } 33 | ans = 0; 34 | for (int i = 2; i <= N; i ++) 35 | if (get(i)) { 36 | ans ++; 37 | } 38 | } 39 | 40 | int bench_sieve_validate() { 41 | return ans == setting->checksum; 42 | } 43 | -------------------------------------------------------------------------------- /nemu/src/isa/riscv64/init.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "local-include/csr.h" 4 | 5 | static const uint32_t img [] = { 6 | 0x800002b7, // lui t0,0x80000 7 | 0x0002a023, // sw zero,0(t0) 8 | 0x0002a503, // lw a0,0(t0) 9 | 0x0000006b, // nemu_trap 10 | }; 11 | 12 | void init_clint(void); 13 | 14 | void init_isa(void) { 15 | cpu.gpr[0]._64 = 0; 16 | cpu.pc = PMEM_BASE + IMAGE_START; 17 | 18 | cpu.mode = MODE_M; 19 | #ifndef __DIFF_REF_QEMU__ 20 | // QEMU seems to initialize mstatus with 0 21 | mstatus->val = 0x00001800; 22 | #endif 23 | 24 | #define ext(e) (1 << ((e) - 'a')) 25 | misa->extensions = ext('i') | ext('m') | ext('a') | ext('c') | ext('s') | ext('u'); 26 | #ifdef __DIFF_REF_QEMU__ 27 | misa->extensions |= ext('d') | ext('f'); 28 | #endif 29 | misa->mxl = 2; // XLEN = 64 30 | 31 | memcpy(guest_to_host(IMAGE_START), img, sizeof(img)); 32 | 33 | init_clint(); 34 | extern void init_sdcard(); 35 | init_sdcard(); 36 | } 37 | -------------------------------------------------------------------------------- /nexus-am/tests/cputest/tests/quick-sort.c: -------------------------------------------------------------------------------- 1 | #include "trap.h" 2 | 3 | #define N 20 4 | 5 | int a[N] = {2, 12, 14, 6, 13, 15, 16, 10, 0, 18, 11, 19, 9, 1, 7, 5, 4, 3, 8, 17}; 6 | 7 | int partition(int *a, int p, int q) { 8 | int pivot = a[p]; 9 | int i = p, j = q; 10 | while(i < j) { 11 | while(i < j && a[j] > pivot) j --; 12 | a[i] = a[j]; 13 | 14 | while(i < j && a[i] <= pivot) i ++; 15 | a[j] = a[i]; 16 | } 17 | 18 | a[i] = pivot; 19 | return i; 20 | } 21 | 22 | void quick_sort(int *a, int p, int q) { 23 | if(p >= q) return; 24 | 25 | int m = partition(a, p, q); 26 | quick_sort(a, p, m - 1); 27 | quick_sort(a, m + 1, q); 28 | } 29 | 30 | int main() { 31 | quick_sort(a, 0, N - 1); 32 | 33 | int i; 34 | for(i = 0; i < N; i ++) { 35 | nemu_assert(a[i] == i); 36 | } 37 | 38 | nemu_assert(i == N); 39 | 40 | quick_sort(a, 0, N - 1); 41 | 42 | for(i = 0; i < N; i ++) { 43 | nemu_assert(a[i] == i); 44 | } 45 | 46 | nemu_assert(i == N); 47 | 48 | return 0; 49 | } 50 | -------------------------------------------------------------------------------- /nexus-am/apps/microbench/src/qsort/qsort.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | static int N, *data; 4 | 5 | void bench_qsort_prepare() { 6 | bench_srand(1); 7 | 8 | N = setting->size; 9 | 10 | data = bench_alloc(N * sizeof(int)); 11 | for (int i = 0; i < N; i ++) { 12 | int a = bench_rand(); 13 | int b = bench_rand(); 14 | data[i] = (a << 16) | b; 15 | } 16 | } 17 | 18 | static void swap(int *a, int *b) { 19 | int t = *a; 20 | *a = *b; 21 | *b = t; 22 | } 23 | 24 | static void myqsort(int *a, int l, int r) { 25 | if (l < r) { 26 | int p = a[l], pivot = l, j; 27 | for (j = l + 1; j < r; j ++) { 28 | if (a[j] < p) { 29 | swap(&a[++pivot], &a[j]); 30 | } 31 | } 32 | swap(&a[pivot], &a[l]); 33 | myqsort(a, l, pivot); 34 | myqsort(a, pivot + 1, r); 35 | } 36 | } 37 | 38 | void bench_qsort_run() { 39 | myqsort(data, 0, N); 40 | } 41 | 42 | int bench_qsort_validate() { 43 | return checksum(data, data + N) == setting->checksum; 44 | } 45 | -------------------------------------------------------------------------------- /nemu/include/monitor/difftest.h: -------------------------------------------------------------------------------- 1 | #ifndef __MONITOR_DIFFTEST_H__ 2 | #define __MONITOR_DIFFTEST_H__ 3 | 4 | #include 5 | 6 | #ifdef DIFF_TEST 7 | void difftest_skip_ref(void); 8 | void difftest_skip_dut(int nr_ref, int nr_dut); 9 | void difftest_step(vaddr_t ori_pc, vaddr_t next_pc); 10 | #else 11 | #define difftest_skip_ref() 12 | #define difftest_skip_dut(nr_ref, nr_dut) 13 | #define difftest_step(ori_pc, next_pc) 14 | #endif 15 | 16 | extern void (*ref_difftest_memcpy_from_dut)(paddr_t dest, void *src, size_t n); 17 | extern void (*ref_difftest_getregs)(void *c); 18 | extern void (*ref_difftest_setregs)(const void *c); 19 | extern void (*ref_difftest_exec)(uint64_t n); 20 | 21 | static inline bool difftest_check_reg(const char *name, vaddr_t pc, rtlreg_t ref, rtlreg_t dut) { 22 | if (ref != dut) { 23 | Log("%s is different after executing instruction at pc = " FMT_WORD ", right = " FMT_WORD ", wrong = " FMT_WORD, 24 | name, pc, ref, dut); 25 | return false; 26 | } 27 | return true; 28 | } 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /nemu/src/isa/riscv64/local-include/intr.h: -------------------------------------------------------------------------------- 1 | #ifndef __INTR_H__ 2 | #define __INTR_H__ 3 | 4 | #include 5 | 6 | enum { 7 | EX_IAM, // instruction address misaligned 8 | EX_IAF, // instruction address fault 9 | EX_II, // illegal instruction 10 | EX_BP, // breakpoint 11 | EX_LAM, // load address misaligned 12 | EX_LAF, // load address fault 13 | EX_SAM, // store/amo address misaligned 14 | EX_SAF, // store/amo address fault 15 | EX_ECU, // ecall from U-mode 16 | EX_ECS, // ecall from S-mode 17 | EX_RS0, // reserved 18 | EX_ECM, // ecall from M-mode 19 | EX_IPF, // instruction page fault 20 | EX_LPF, // load page fault 21 | EX_RS1, // reserved 22 | EX_SPF, // store/amo page fault 23 | }; 24 | 25 | // now NEMU does not support EX_IAM, 26 | // so it may ok to use EX_IAM to indicate a successful memory access 27 | #define MEM_OK 0 28 | 29 | void raise_intr(DecodeExecState *s, word_t NO, vaddr_t epc); 30 | #define return_on_mem_ex() do { if (cpu.mem_exception != MEM_OK) return; } while (0) 31 | 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /nexus-am/am/src/nutshell/common/timer.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | // static unsigned long boot_time = 0; 7 | static inline uint32_t read_time(void) { 8 | // return ind(RTC_ADDR) / 1000; // unit: ms 9 | return 0; 10 | } 11 | 12 | size_t __am_timer_read(uintptr_t reg, void *buf, size_t size) { 13 | /* 14 | switch (reg) { 15 | case _DEVREG_TIMER_UPTIME: { 16 | _DEV_TIMER_UPTIME_t *uptime = (_DEV_TIMER_UPTIME_t *)buf; 17 | uptime->hi = 0; 18 | uptime->lo = read_time() - boot_time; 19 | return sizeof(_DEV_TIMER_UPTIME_t); 20 | } 21 | case _DEVREG_TIMER_DATE: { 22 | _DEV_TIMER_DATE_t *rtc = (_DEV_TIMER_DATE_t *)buf; 23 | rtc->second = 0; 24 | rtc->minute = 0; 25 | rtc->hour = 0; 26 | rtc->day = 0; 27 | rtc->month = 0; 28 | rtc->year = 2018; 29 | return sizeof(_DEV_TIMER_DATE_t); 30 | } 31 | }*/ 32 | return 0; 33 | } 34 | 35 | void __am_timer_init() { 36 | // boot_time = read_time(); 37 | } 38 | -------------------------------------------------------------------------------- /nexus-am/tests/amtest/src/tests/audio.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void audio_test() { 5 | _DEV_AUDIO_INIT_t init; 6 | init.freq = 8000; 7 | init.channels = 1; 8 | init.samples = 1024; 9 | init.bufsize = 8192; 10 | _io_write(_DEV_AUDIO, _DEVREG_AUDIO_INIT, &init, sizeof(init)); 11 | 12 | extern uint8_t audio_payload, audio_payload_end; 13 | uint32_t audio_len = &audio_payload_end - &audio_payload; 14 | _DEV_AUDIO_SBCTRL_t ctl; 15 | int nplay = 0; 16 | ctl.stream = &audio_payload; 17 | ctl.wait = 1; 18 | while (nplay < audio_len) { 19 | ctl.len = (audio_len - nplay > 4096 ? 4096 : audio_len - nplay); 20 | _io_write(_DEV_AUDIO, _DEVREG_AUDIO_SBCTRL, &ctl, sizeof(ctl)); 21 | ctl.stream += ctl.len; 22 | nplay += ctl.len; 23 | printf("Already play %d/%d bytes of data\n", nplay, audio_len); 24 | } 25 | 26 | // wait until the audio finishes 27 | _DEV_AUDIO_SBSTAT_t stat; 28 | do { 29 | _io_read(_DEV_AUDIO, _DEVREG_AUDIO_SBSTAT, &stat, sizeof(stat)); 30 | } while (stat.count > 0); 31 | } 32 | -------------------------------------------------------------------------------- /docs/9.30.md: -------------------------------------------------------------------------------- 1 | #### 今日任务 2 | 3 | 1. 完成deepin V20的升级 4 | 2. 向5级流水线中添加ready-go 这些控制逻辑, 仿照之前体系结构cpu 5 | 3. 添加前递逻辑来处理冲突 6 | 7 | 8 | 9 | 复习之前的握手机制 10 | 11 | ```verilog 12 | // ds_ready_go && es_allowin 表示ds, es 两级握手成功 13 | assign ds_ready_go = 1'b1; // 准备向后传 14 | assign ds_allowin = !ds_valid || ds_ready_go && es_allowin; // ds可以接受前面的流水: 两种情况 当前缓存无效 || 当前有效, 可以向后传, 后面可以接受(后两级握手成功) 15 | assign ds_to_es_valid = ds_valid && ds_ready_go; 16 | // 当前valid 且 准备后传 -> 更新下一级valid 17 | always @(posedge clk) begin 18 | if (reset) begin 19 | ds_valid <= 1'b0; 20 | end 21 | else if (ds_allowin) begin 22 | ds_valid <= fs_to_ds_valid; 23 | // 当前可接受且上一级可以走(握手成功), 就把上一级valid更新到这一级的valid上 24 | end 25 | 26 | if (fs_to_ds_valid && ds_allowin) begin 27 | // 把fs_to_ds_valid = fs_valid && fs_ready_go 28 | // 握手成功且fs_valid, 传递 29 | fs_to_ds_bus_r <= fs_to_ds_bus; 30 | end 31 | end 32 | ``` 33 | 34 | 35 | 36 | 数据相关: 两条指令, 访问同一个reg/mem, 且有一条写 37 | 38 | 控制相关: 一条转移, 另一条取决上一条是否跳转, 来执行这一条 39 | 40 | 结构相关: 两条指令使用同一个硬件资源(ALU) -------------------------------------------------------------------------------- /nexus-am/tests/cputest/tests/recursion.c: -------------------------------------------------------------------------------- 1 | #include "trap.h" 2 | 3 | int f0(int, int); 4 | int f1(int, int); 5 | int f2(int, int); 6 | int f3(int, int); 7 | 8 | int (*func[])(int, int) = { 9 | f0, f1, f2, f3, 10 | }; 11 | 12 | int rec = 0, lvl = 0; 13 | 14 | int f0(int n, int l) { 15 | if (l > lvl) lvl = l; 16 | rec ++; 17 | return n <= 0 ? 1 : func[3](n / 3, l + 1); 18 | }; 19 | 20 | int f1(int n, int l) { 21 | if (l > lvl) lvl = l; 22 | rec ++; 23 | return n <= 0 ? 1 : func[0](n - 1, l + 1); 24 | }; 25 | 26 | int f2(int n, int l) { 27 | if (l > lvl) lvl = l; 28 | rec ++; 29 | return n <= 0 ? 1 : func[1](n, l + 1) + 9; 30 | }; 31 | 32 | int f3(int n, int l) { 33 | if (l > lvl) lvl = l; 34 | rec ++; 35 | return n <= 0 ? 1 : func[2](n / 2, l + 1) * 3 + func[2](n / 2, l + 1) * 2; 36 | }; 37 | 38 | int ans[] = {38270, 218, 20}; 39 | 40 | int main() { 41 | int x = func[0](14371, 0); 42 | nemu_assert(x == ans[0]); // answer 43 | nemu_assert(rec == ans[1]); // # recursions 44 | nemu_assert(lvl == ans[2]); // max depth 45 | return 0; 46 | } 47 | -------------------------------------------------------------------------------- /nemu/src/memory/vaddr.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | static word_t vaddr_read_cross_page(vaddr_t addr, int type, int len) { 6 | return 0; 7 | } 8 | 9 | static void vaddr_write_cross_page(vaddr_t addr, word_t data, int len) { 10 | } 11 | 12 | word_t vaddr_mmu_read(vaddr_t addr, int len, int type) { 13 | paddr_t pg_base = isa_mmu_translate(addr, type, len); 14 | int ret = pg_base & PAGE_MASK; 15 | if (ret == MEM_RET_OK) { 16 | addr = pg_base | (addr & PAGE_MASK); 17 | return paddr_read(addr, len); 18 | } else if (len != 1 && ret == MEM_RET_CROSS_PAGE) { 19 | return vaddr_read_cross_page(addr, type, len); 20 | } 21 | return 0; 22 | } 23 | 24 | void vaddr_mmu_write(vaddr_t addr, word_t data, int len) { 25 | paddr_t pg_base = isa_mmu_translate(addr, MEM_TYPE_WRITE, len); 26 | int ret = pg_base & PAGE_MASK; 27 | if (ret == MEM_RET_OK) { 28 | addr = pg_base | (addr & PAGE_MASK); 29 | paddr_write(addr, data, len); 30 | } else if (len != 1 && ret == MEM_RET_CROSS_PAGE) { 31 | vaddr_write_cross_page(addr, data, len); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /nemu/src/device/alarm.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define TIMER_HZ 100 6 | #define MAX_HANDLER 8 7 | 8 | typedef void (*alarm_handler_t) (void); 9 | static alarm_handler_t handler[MAX_HANDLER] = {}; 10 | static int idx = 0; 11 | static uint32_t jiffy = 0; 12 | 13 | void add_alarm_handle(void *h) { 14 | assert(idx < MAX_HANDLER); 15 | handler[idx ++] = h; 16 | } 17 | 18 | uint32_t uptime() { return jiffy / TIMER_HZ; } 19 | 20 | static void alarm_sig_handler(int signum) { 21 | int i; 22 | for (i = 0; i < idx; i ++) { 23 | handler[i](); 24 | } 25 | 26 | jiffy ++; 27 | } 28 | 29 | void init_alarm(void) { 30 | struct sigaction s; 31 | memset(&s, 0, sizeof(s)); 32 | s.sa_handler = alarm_sig_handler; 33 | int ret = sigaction(SIGVTALRM, &s, NULL); 34 | Assert(ret == 0, "Can not set signal handler"); 35 | 36 | struct itimerval it = {}; 37 | it.it_value.tv_sec = 0; 38 | it.it_value.tv_usec = 1000000 / TIMER_HZ; 39 | it.it_interval = it.it_value; 40 | ret = setitimer(ITIMER_VIRTUAL, &it, NULL); 41 | Assert(ret == 0, "Can not set timer"); 42 | } 43 | -------------------------------------------------------------------------------- /nexus-am/tests/cputest/tests/max.c: -------------------------------------------------------------------------------- 1 | #include "trap.h" 2 | 3 | int max(int x, int y) { 4 | int z; 5 | if(x > y) { z = x; } 6 | else { z = y; } 7 | return z; 8 | } 9 | 10 | int test_data[] = {0, 1, 2, 0x7fffffff, 0x80000000, 0x80000001, 0xfffffffe, 0xffffffff}; 11 | int ans[] = {0, 0x1, 0x2, 0x7fffffff, 0, 0, 0, 0, 0x1, 0x1, 0x2, 0x7fffffff, 0x1, 0x1, 0x1, 0x1, 0x2, 0x2, 0x2, 0x7fffffff, 0x2, 0x2, 0x2, 0x2, 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff, 0, 0x1, 0x2, 0x7fffffff, 0x80000000, 0x80000001, 0xfffffffe, 0xffffffff, 0, 0x1, 0x2, 0x7fffffff, 0x80000001, 0x80000001, 0xfffffffe, 0xffffffff, 0, 0x1, 0x2, 0x7fffffff, 0xfffffffe, 0xfffffffe, 0xfffffffe, 0xffffffff, 0, 0x1, 0x2, 0x7fffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff}; 12 | 13 | #define NR_DATA LENGTH(test_data) 14 | 15 | int main() { 16 | int i, j, ans_idx = 0; 17 | for(i = 0; i < NR_DATA; i ++) { 18 | for(j = 0; j < NR_DATA; j ++) { 19 | nemu_assert(max(test_data[i], test_data[j]) == ans[ans_idx ++]); 20 | } 21 | nemu_assert(j == NR_DATA); 22 | } 23 | 24 | nemu_assert(i == NR_DATA); 25 | 26 | return 0; 27 | } 28 | -------------------------------------------------------------------------------- /nemu/include/device/map.h: -------------------------------------------------------------------------------- 1 | #ifndef __DEVICE_MAP_H__ 2 | #define __DEVICE_MAP_H__ 3 | 4 | #include 5 | 6 | typedef void(*io_callback_t)(uint32_t, int, bool); 7 | uint8_t* new_space(int size); 8 | 9 | typedef struct { 10 | char *name; 11 | // we treat ioaddr_t as paddr_t here 12 | paddr_t low; 13 | paddr_t high; 14 | uint8_t *space; 15 | io_callback_t callback; 16 | } IOMap; 17 | 18 | static inline bool map_inside(IOMap *map, paddr_t addr) { 19 | return (addr >= map->low && addr <= map->high); 20 | } 21 | 22 | static inline int find_mapid_by_addr(IOMap *maps, int size, paddr_t addr) { 23 | int i; 24 | for (i = 0; i < size; i ++) { 25 | if (map_inside(maps + i, addr)) { 26 | difftest_skip_ref(); 27 | return i; 28 | } 29 | } 30 | return -1; 31 | } 32 | 33 | void add_pio_map(char *name, ioaddr_t addr, uint8_t *space, int len, io_callback_t callback); 34 | void add_mmio_map(char *name, paddr_t addr, uint8_t* space, int len, io_callback_t callback); 35 | 36 | word_t map_read(paddr_t addr, int len, IOMap *map); 37 | void map_write(paddr_t addr, word_t data, int len, IOMap *map); 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /docs/11.13.md: -------------------------------------------------------------------------------- 1 | ### 今日任务 2 | 3 | 1. 完成axi_data 接口的添加, 能够跑其他测试 4 | 2. 争取在服务器上能运行axi测试 5 | 6 | 7 | 8 | 注意: 每次还要修改AXI_ram中的读取文件, 把dummy改成其他的 9 | 10 | 把新版本verilator的路径加入到PATH中, 之后都用4.101 版本的了 11 | 12 | 13 | 14 | 注意大小端转换, 写入的也改成大端! 这样读出来的经过转换就是小端 15 | 16 | 服了, 注意了大小端, 但是写入的wstrb还有问题, 还要对axi_ram 进行修改! 17 | 18 | 19 | 20 | ``` 21 | 80000094: 00050b93 mv s7,a0 22 | 80000098: 000a0c93 mv s9,s4 23 | 8000009c: 03750533 mul a0,a0,s7 // a0 = a0*s7 24 | 800000a0: 00043783 ld a5,0(s0) // a5 = 25 | 800000a4: 001c0c1b addiw s8,s8,1 26 | 800000a8: 004c8c93 addi s9,s9,4 27 | 800000ac: 00840413 addi s0,s0,8 28 | 800000b0: 40a78533 sub a0,a5,a0 29 | 30 | reg 8 s0 different at pc = [0x 800000a8], right=[0x 80000dd8], wrong=[0x 80000de0] cyc=286 31 | 32 | cyc=283, 写入s0 = rf(8) = de0, 指令 = a4 = addiw 33 | 取出的指令有问题! a4 = 001c0c1b != 00840413 34 | cyc = 215 , 取出的指令正确, cyc=216, 指令变成0 35 | 36 | 37 | reg 24 s8 different at pc = [0x 800000a8], right=[0x 1], wrong=[0x 0] cyc = 290 38 | 39 | cyc = 275 应该流水却没有 40 | ``` 41 | 42 | -------------------------------------------------------------------------------- /nemu/src/device/timer.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #define RTC_PORT 0x48 // Note that this is not the standard 7 | #define RTC_MMIO 0xa1000048 8 | 9 | static uint32_t *rtc_port_base = NULL; 10 | 11 | static void rtc_io_handler(uint32_t offset, int len, bool is_write) { 12 | assert(offset == 0 || offset == 8 || offset == 12); 13 | if (!is_write) { 14 | struct timeval now; 15 | gettimeofday(&now, NULL); 16 | uint32_t seconds = now.tv_sec; 17 | uint32_t useconds = now.tv_usec; 18 | rtc_port_base[0] = seconds * 1000 + (useconds + 500) / 1000; 19 | rtc_port_base[2] = useconds; 20 | rtc_port_base[3] = seconds; 21 | } 22 | } 23 | 24 | static void timer_intr() { 25 | if (nemu_state.state == NEMU_RUNNING) { 26 | extern void dev_raise_intr(void); 27 | dev_raise_intr(); 28 | } 29 | } 30 | 31 | void init_timer() { 32 | rtc_port_base = (void*)new_space(16); 33 | add_pio_map("rtc", RTC_PORT, (void *)rtc_port_base, 16, rtc_io_handler); 34 | add_mmio_map("rtc", RTC_MMIO, (void *)rtc_port_base, 16, rtc_io_handler); 35 | add_alarm_handle(timer_intr); 36 | } 37 | -------------------------------------------------------------------------------- /nexus-am/tests/cputest/tests/add.c: -------------------------------------------------------------------------------- 1 | #include "trap.h" 2 | 3 | int add(int a, int b) { 4 | int c = a + b; 5 | return c; 6 | } 7 | 8 | int test_data[] = {0, 1, 2, 0x7fffffff, 0x80000000, 0x80000001, 0xfffffffe, 0xffffffff}; 9 | int ans[] = {0, 0x1, 0x2, 0x7fffffff, 0x80000000, 0x80000001, 0xfffffffe, 0xffffffff, 0x1, 0x2, 0x3, 0x80000000, 0x80000001, 0x80000002, 0xffffffff, 0, 0x2, 0x3, 0x4, 0x80000001, 0x80000002, 0x80000003, 0, 0x1, 0x7fffffff, 0x80000000, 0x80000001, 0xfffffffe, 0xffffffff, 0, 0x7ffffffd, 0x7ffffffe, 0x80000000, 0x80000001, 0x80000002, 0xffffffff, 0, 0x1, 0x7ffffffe, 0x7fffffff, 0x80000001, 0x80000002, 0x80000003, 0, 0x1, 0x2, 0x7fffffff, 0x80000000, 0xfffffffe, 0xffffffff, 0, 0x7ffffffd, 0x7ffffffe, 0x7fffffff, 0xfffffffc, 0xfffffffd, 0xffffffff, 0, 0x1, 0x7ffffffe, 0x7fffffff, 0x80000000, 0xfffffffd, 0xfffffffe}; 10 | 11 | #define NR_DATA LENGTH(test_data) 12 | 13 | int main() { 14 | int i, j, ans_idx = 0; 15 | for(i = 0; i < NR_DATA; i ++) { 16 | for(j = 0; j < NR_DATA; j ++) { 17 | nemu_assert(add(test_data[i], test_data[j]) == ans[ans_idx ++]); 18 | } 19 | nemu_assert(j == NR_DATA); 20 | } 21 | 22 | nemu_assert(i == NR_DATA); 23 | 24 | return 0; 25 | } 26 | -------------------------------------------------------------------------------- /nexus-am/tests/amtest/src/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void (*entry)() = NULL; // mp entry 4 | 5 | static const char *tests[256] = { 6 | ['h'] = "hello", 7 | ['H'] = "display this help message", 8 | ['i'] = "interrupt/yield test", 9 | ['d'] = "scan devices", 10 | ['m'] = "multiprocessor test", 11 | ['t'] = "real-time clock test", 12 | ['k'] = "readkey test", 13 | ['v'] = "display test", 14 | ['a'] = "audio test", 15 | ['p'] = "x86 virtual memory test", 16 | }; 17 | 18 | int main(const char *args) { 19 | switch (args[0]) { 20 | CASE('h', hello); 21 | CASE('i', hello_intr, IOE, CTE(simple_trap)); 22 | CASE('d', devscan, IOE); 23 | CASE('m', mp_print, MPE); 24 | CASE('t', rtc_test, IOE); 25 | CASE('k', keyboard_test, IOE); 26 | CASE('v', video_test, IOE); 27 | CASE('a', audio_test, IOE); 28 | CASE('p', vm_test, CTE(vm_handler), VME(simple_pgalloc, simple_pgfree)); 29 | case 'H': 30 | default: 31 | printf("Usage: make run mainargs=*\n"); 32 | for (int ch = 0; ch < 256; ch++) { 33 | if (tests[ch]) { 34 | printf(" %c: %s\n", ch, tests[ch]); 35 | } 36 | } 37 | } 38 | return 0; 39 | } 40 | -------------------------------------------------------------------------------- /nemu/src/device/device.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #ifdef HAS_IOE 4 | 5 | #include 6 | #include 7 | 8 | void init_alarm(); 9 | void init_serial(); 10 | void init_timer(); 11 | void init_vga(); 12 | void init_i8042(); 13 | void init_audio(); 14 | 15 | void send_key(uint8_t, bool); 16 | 17 | static int device_update_flag = false; 18 | 19 | static void set_device_update_flag() { 20 | device_update_flag = true; 21 | } 22 | 23 | void device_update() { 24 | if (!device_update_flag) { 25 | return; 26 | } 27 | device_update_flag = false; 28 | 29 | SDL_Event event; 30 | while (SDL_PollEvent(&event)) { 31 | switch (event.type) { 32 | case SDL_QUIT: { 33 | void monitor_statistic(); 34 | monitor_statistic(); 35 | exit(0); 36 | } 37 | 38 | default: break; 39 | } 40 | } 41 | } 42 | 43 | void sdl_clear_event_queue() { 44 | SDL_Event event; 45 | while (SDL_PollEvent(&event)); 46 | } 47 | 48 | void init_device() { 49 | init_serial(); 50 | init_timer(); 51 | 52 | add_alarm_handle(set_device_update_flag); 53 | init_alarm(); 54 | } 55 | #else 56 | 57 | void init_device() { 58 | } 59 | 60 | #endif /* HAS_IOE */ 61 | -------------------------------------------------------------------------------- /nexus-am/README.md: -------------------------------------------------------------------------------- 1 | # The Abstract Machine (AM) 2 | 3 | ## 注意 4 | 5 | 这是一个临时的仓库,仅用于支持NutShell运行一些基本的程序。 6 | 7 | AM项目是[南京大学计算机系若干课程实验](https://github.com/NJU-ProjectN/)的一部分, 8 | 本仓库将与课程作业相关的若干.c文件替换成.o文件,具体包括 9 | ``` 10 | libs/klib/src/{stdio,stdlib,string}.o 11 | ``` 12 | 13 | upstream正在重构,预计可在2020/09/01前完成重构,届时再从upstream中fork一个分支来支持NutShell。 14 | 15 | ## 介绍 16 | 17 | 抽象计算机:必要的抽象,帮你编写一个完整的计算机系统! 18 | 19 | 目录组织: 20 | 21 | * `am/`:AM头文件、每个体系结构分别实现的AM代码。 22 | * `libs/`:建立在AM上、体系结构无关的运行库,如软件模拟浮点数、基础libc功能等。 23 | * `apps/`:一些运行在AM上应用程序示例。 24 | * `tests/`: 用来测试AM实现的简单测试程序。 25 | 26 | ## 创建一个AM应用 27 | 28 | 在任何目录都可以创建运行在AM上的应用程序。程序用C/C++语言编写,除AM之外无法调用其他库函数(但可以引用`stdarg.h`, `limits.h`等包含体系结构相关数据定义的头文件)。 29 | 30 | 为此你需要在应用程序项目的根目录添加一个Makefile: 31 | 32 | ``` 33 | NAME = app-name 34 | SRCS = src/main.c src/help.c src/lib.cpp 35 | include $(AM_HOME)/Makefile.app 36 | ``` 37 | 38 | 一些注意事项: 39 | 40 | * `NAME`定义了应用的名字。编译后会在`build/`目录里出现以此命名的应用程序。 41 | * `SRCS`指定了编译应用所需的源文件。可以放在应用目录中的任意位置。 42 | 43 | * 应用目录下的`include/`目录会被添加到编译的`-I`选项中。 44 | * 环境变量`AM_HOME`需要包含**nexus-am项目的根目录的绝对路径**。 45 | 46 | 编译时,首先确保`AM_HOME`正确设置,然后执行`make ARCH=体系结构名`编译。例如`make ARCH=native`将会编译成本地可运行的项目,`make ARCH=mips32-minimal`生成用于仿真的MIPS32程序。`ARCH`缺省时默认编译到本地。 47 | -------------------------------------------------------------------------------- /nexus-am/tests/cputest/tests/load-store.c: -------------------------------------------------------------------------------- 1 | #include "trap.h" 2 | 3 | unsigned short mem[] = { 4 | 0x0, 0x0258, 0x4abc, 0x7fff, 0x8000, 0x8100, 0xabcd, 0xffff 5 | }; 6 | 7 | unsigned lh_ans[] = { 8 | 0x00000000, 0x00000258, 0x00004abc, 0x00007fff, 0xffff8000, 0xffff8100, 0xffffabcd, 0xffffffff 9 | }; 10 | 11 | unsigned lhu_ans[] = { 12 | 0x00000000, 0x00000258, 0x00004abc, 0x00007fff, 0x00008000, 0x00008100, 0x0000abcd, 0x0000ffff 13 | }; 14 | 15 | unsigned sh_ans[] = { 16 | 0x0000fffd, 0x0000fff7, 0x0000ffdf, 0x0000ff7f, 0x0000fdff, 0x0000f7ff, 0x0000dfff, 0x00007fff 17 | }; 18 | 19 | unsigned lwlr_ans[] = { 20 | 0xbc025800, 0x7fff4a, 0xcd810080, 0xffffab 21 | }; 22 | 23 | int main() { 24 | unsigned i; 25 | 26 | for(i = 0; i < LENGTH(mem); i ++) { 27 | nemu_assert((short)mem[i] == lh_ans[i]); 28 | } 29 | 30 | for(i = 0; i < LENGTH(mem); i ++) { 31 | nemu_assert(mem[i] == lhu_ans[i]); 32 | } 33 | 34 | for(i = 0; i < ((LENGTH(mem) / 2) - 1); i ++) { 35 | unsigned x = ((unsigned*)((void*)mem + 1))[i]; 36 | nemu_assert(x == lwlr_ans[i]); 37 | } 38 | 39 | for(i = 0; i < LENGTH(mem); i ++) { 40 | mem[i] = ~(1 << (2 * i + 1)); 41 | nemu_assert(mem[i] == sh_ans[i]); 42 | } 43 | 44 | return 0; 45 | } 46 | -------------------------------------------------------------------------------- /nexus-am/tests/cputest/tests/bit.c: -------------------------------------------------------------------------------- 1 | #include "trap.h" 2 | 3 | typedef unsigned char uint8_t; 4 | __attribute__((noinline)) 5 | bool getbit(void *buf, int offset){ 6 | int byte = offset >> 3; 7 | offset &= 7; 8 | uint8_t mask = 1 << offset; 9 | return (((uint8_t *)buf)[byte] & mask) != 0; 10 | } 11 | __attribute__((noinline)) 12 | void setbit(void *buf, int offset, bool bit){ 13 | int byte = offset >> 3; 14 | offset &= 7; 15 | uint8_t mask = 1 << offset; 16 | 17 | uint8_t * volatile p = buf + byte; 18 | *p = (bit == 0 ? (*p & ~mask) : (*p | mask)); 19 | } 20 | 21 | int main() { 22 | uint8_t buf[2]; 23 | 24 | buf[0] = 0xaa; 25 | buf[1] = 0x0; 26 | nemu_assert(getbit(buf, 0) == 0); 27 | nemu_assert(getbit(buf, 1) == 1); 28 | nemu_assert(getbit(buf, 2) == 0); 29 | nemu_assert(getbit(buf, 3) == 1); 30 | nemu_assert(getbit(buf, 4) == 0); 31 | nemu_assert(getbit(buf, 5) == 1); 32 | nemu_assert(getbit(buf, 6) == 0); 33 | nemu_assert(getbit(buf, 7) == 1); 34 | 35 | setbit(buf, 8, 1); 36 | setbit(buf, 9, 0); 37 | setbit(buf, 10, 1); 38 | setbit(buf, 11, 0); 39 | setbit(buf, 12, 1); 40 | setbit(buf, 13, 0); 41 | setbit(buf, 14, 1); 42 | setbit(buf, 15, 0); 43 | nemu_assert(buf[1] == 0x55); 44 | 45 | return 0; 46 | } 47 | -------------------------------------------------------------------------------- /nemu/src/isa/riscv64/difftest/ref.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "../local-include/csr.h" 4 | #include "difftest.h" 5 | 6 | static void csr_prepare() { 7 | cpu.mstatus = mstatus->val; 8 | cpu.mcause = mcause->val; 9 | cpu.mepc = mepc->val; 10 | 11 | rtlreg_t temp; 12 | csr_read(&temp, 0x100); // sstatus 13 | cpu.sstatus = temp; 14 | cpu.scause = scause->val; 15 | cpu.sepc = sepc->val; 16 | } 17 | 18 | static void csr_writeback() { 19 | mstatus->val = cpu.mstatus; 20 | mcause ->val = cpu.mcause ; 21 | mepc ->val = cpu.mepc ; 22 | //sstatus->val = cpu.sstatus; // sstatus is a shadow of mstatus 23 | scause ->val = cpu.scause ; 24 | sepc ->val = cpu.sepc ; 25 | } 26 | 27 | void isa_difftest_getregs(void *r) { 28 | csr_prepare(); 29 | memcpy(r, &cpu, DIFFTEST_REG_SIZE); 30 | } 31 | 32 | void isa_difftest_setregs(const void *r) { 33 | memcpy(&cpu, r, DIFFTEST_REG_SIZE); 34 | csr_writeback(); 35 | } 36 | 37 | void isa_difftest_raise_intr(word_t NO) { 38 | DecodeExecState s; 39 | s.is_jmp = 0; 40 | s.isa = (ISADecodeInfo) { 0 }; 41 | 42 | void raise_intr(DecodeExecState *s, word_t NO, vaddr_t epc); 43 | raise_intr(&s, NO, cpu.pc); 44 | update_pc(&s); 45 | } 46 | -------------------------------------------------------------------------------- /nexus-am/Makefile.app: -------------------------------------------------------------------------------- 1 | APP_DIR ?= $(shell pwd) 2 | INC_DIR += $(APP_DIR)/include/ 3 | DST_DIR ?= $(APP_DIR)/build/$(ARCH)/ 4 | BINARY ?= $(APP_DIR)/build/$(NAME)-$(ARCH) 5 | BINARY_REL = $(shell realpath $(BINARY) --relative-to .) 6 | 7 | ## Paste in "Makefile.check" here 8 | include $(AM_HOME)/Makefile.check 9 | $(info # Building $(NAME) [$(ARCH)] with AM_HOME {$(AM_HOME)}) 10 | 11 | ## Default: Build a runnable image 12 | default: image 13 | 14 | LIBS += klib 15 | INC_DIR += $(addsuffix /include/, $(addprefix $(AM_HOME)/libs/, $(LIBS))) 16 | 17 | ## Paste in "Makefile.compile" here 18 | include $(AM_HOME)/Makefile.compile 19 | 20 | ## Produce a list of files to be linked: app objects, AM, and libraries 21 | LINK_LIBS = $(sort $(LIBS)) 22 | LINK_FILES = \ 23 | $(OBJS) \ 24 | $(AM_HOME)/am/build/am-$(ARCH).a \ 25 | $(addsuffix -$(ARCH).a, $(join \ 26 | $(addsuffix /build/, $(addprefix $(AM_HOME)/libs/, $(LINK_LIBS))), \ 27 | $(LINK_LIBS) \ 28 | )) 29 | 30 | $(OBJS): $(PREBUILD) 31 | image: $(OBJS) am $(LIBS) prompt 32 | prompt: $(OBJS) am $(LIBS) 33 | run: default 34 | 35 | prompt: 36 | @echo \# Creating binary image [$(ARCH)] 37 | 38 | clean: 39 | rm -rf $(APP_DIR)/build/ 40 | 41 | .PHONY: default run image prompt clean 42 | -------------------------------------------------------------------------------- /nemu/include/isa.h: -------------------------------------------------------------------------------- 1 | #ifndef __ISA_H__ 2 | #define __ISA_H__ 3 | 4 | #include _ISA_H_ 5 | 6 | #define IMAGE_START concat(__ISA__, _IMAGE_START) 7 | #define PMEM_BASE concat(__ISA__, _PMEM_BASE) 8 | typedef concat(__ISA__, _CPU_state) CPU_state; 9 | typedef concat(__ISA__, _ISADecodeInfo) ISADecodeInfo; 10 | 11 | // monitor 12 | extern char isa_logo[]; 13 | void init_isa(); 14 | 15 | // reg 16 | extern CPU_state cpu; 17 | void isa_reg_display(); 18 | word_t isa_reg_str2val(const char *name, bool *success); 19 | 20 | // exec 21 | vaddr_t isa_exec_once(); 22 | 23 | // memory 24 | enum { MEM_TYPE_IFETCH, MEM_TYPE_READ, MEM_TYPE_WRITE }; 25 | enum { MEM_RET_OK, MEM_RET_NEED_TRANSLATE, MEM_RET_FAIL, MEM_RET_CROSS_PAGE }; 26 | paddr_t isa_mmu_translate(vaddr_t vaddr, int type, int len); 27 | #ifndef isa_vaddr_check 28 | int isa_vaddr_check(vaddr_t vaddr, int type, int len); 29 | #endif 30 | #define isa_has_mem_exception concat(__ISA__, _has_mem_exception) 31 | 32 | // difftest 33 | // for dut 34 | bool isa_difftest_checkregs(CPU_state *ref_r, vaddr_t pc); 35 | void isa_difftest_attach(); 36 | 37 | // for ref 38 | void isa_difftest_getregs(void *r); 39 | void isa_difftest_setregs(const void *r); 40 | void isa_difftest_raise_intr(word_t NO); 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /nexus-am/am/arch/riscv64-nutshell.mk: -------------------------------------------------------------------------------- 1 | include $(AM_HOME)/am/arch/isa/riscv64.mk 2 | 3 | AM_SRCS := nutshell/isa/riscv/trm.c \ 4 | nutshell/common/mainargs.S \ 5 | nutshell/common/uartlite.c \ 6 | nutshell/common/ioe.c \ 7 | nutshell/common/timer.c \ 8 | dummy/input.c \ 9 | dummy/video.c \ 10 | dummy/audio.c \ 11 | dummy/cte.c \ 12 | dummy/vme.c \ 13 | dummy/mpe.c \ 14 | nutshell/isa/riscv/boot/start.S 15 | 16 | CFLAGS += -I$(AM_HOME)/am/src/nutshell/include -DISA_H=\"riscv.h\" 17 | 18 | ASFLAGS += -DMAINARGS=\"$(mainargs)\" 19 | .PHONY: $(AM_HOME)/am/src/nutshell/common/mainargs.S 20 | 21 | LDFLAGS += -L $(AM_HOME)/am/src/nutshell/ldscript 22 | LDFLAGS += -T $(AM_HOME)/am/src/nutshell/isa/riscv/boot/loader64.ld 23 | 24 | image: 25 | @echo + LD "->" $(BINARY_REL).elf 26 | @$(LD) $(LDFLAGS) --gc-sections -o $(BINARY).elf --start-group $(LINK_FILES) --end-group 27 | @$(OBJDUMP) -d $(BINARY).elf > $(BINARY).txt 28 | @echo + OBJCOPY "->" $(BINARY_REL).bin 29 | @$(OBJCOPY) -S --set-section-flags .bss=alloc,contents -O binary $(BINARY).elf $(BINARY).bin 30 | 31 | run: 32 | $(MAKE) -C $(NUTSHELL_HOME) emu IMAGE="$(BINARY).bin" DATAWIDTH=64 33 | -------------------------------------------------------------------------------- /src/main/scala/nutcore/regfile.scala: -------------------------------------------------------------------------------- 1 | package nutcore 2 | 3 | import chisel3._ 4 | import chisel3.util._ 5 | import chisel3.util.experimental.BoringUtils 6 | 7 | import common.constans._ 8 | 9 | 10 | class regfile extends Module{ 11 | val io = IO(new Bundle() { 12 | val raddr1 = Input (UInt(ADDR_W.W)) // 自动推断地址位宽 = 5 13 | val raddr2 = Input (UInt(ADDR_W.W)) 14 | val rdata1 = Output(UInt(XLEN.W)) 15 | val rdata2 = Output(UInt(XLEN.W)) 16 | val we = Input (Bool()) 17 | val waddr = Input (UInt(ADDR_W.W)) 18 | val wdata = Input (UInt(XLEN.W)) 19 | }) 20 | val rf = Mem(NUM_REG, UInt(XLEN.W)) // 32个64位宽的regfile 21 | 22 | // 读 23 | io.rdata1 := Mux(io.raddr1 === 0.U, 0.U(XLEN.W), rf(io.raddr1)) 24 | io.rdata2 := Mux(io.raddr2 === 0.U, 0.U(XLEN.W), rf(io.raddr2)) 25 | // 写 26 | when(io.we && (io.waddr =/= 0.U)){ 27 | rf(io.waddr) := io.wdata 28 | } 29 | if(ADD_SOURCE) { 30 | BoringUtils.addSource(VecInit((0 to NUM_REG - 1).map(i => rf(i.U))), "diffTestRegfile") // VecInit把32个rf输出包装成一个Vec输出! 31 | } 32 | if(DEBUG_PRINT) { 33 | printf("RF: s0 = [%x] rdata1(%d)=[%x] rdata2(%d)=[%x] wdata(%d)=[%x] we=%d\n", rf(8), io.raddr1, io.rdata1, io.raddr2, io.rdata2, io.waddr, io.wdata, io.we) 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /nemu/tools/qemu-diff/Makefile: -------------------------------------------------------------------------------- 1 | ifneq ($(MAKECMDGOALS),clean) # ignore check for make clean 2 | ISA ?= riscv64 3 | ISAS = $(shell ls src/isa/) 4 | 5 | ifeq ($(filter $(ISAS), $(ISA)), ) # ISA must be valid 6 | $(error Invalid ISA. Supported: $(ISAS)) 7 | endif 8 | endif 9 | 10 | INC_DIR += ./include 11 | BUILD_DIR ?= ./build 12 | OBJ_DIR ?= $(BUILD_DIR)/obj-$(ISA) 13 | BINARY ?= $(BUILD_DIR)/$(ISA)-qemu-so 14 | 15 | .DEFAULT_GOAL = app 16 | 17 | # Compilation flags 18 | CC = gcc 19 | LD = gcc 20 | INCLUDES = $(addprefix -I, $(INC_DIR)) 21 | CFLAGS += -O2 -fPIC -MMD -Wall -Werror -DNEMU_HOME=$(NEMU_HOME) $(INCLUDES) \ 22 | -D_ISA_H_=\"isa/$(ISA).h\" 23 | 24 | # Files to be compiled 25 | SRCS = $(shell find src/ -name "*.c" | grep -v "isa") 26 | SRCS += $(shell find src/isa/$(ISA) -name "*.c") 27 | OBJS = $(SRCS:src/%.c=$(OBJ_DIR)/%.o) 28 | 29 | # Compilation patterns 30 | $(OBJ_DIR)/%.o: src/%.c 31 | @echo + CC $< 32 | @mkdir -p $(dir $@) 33 | @$(CC) $(CFLAGS) -c -o $@ $< 34 | 35 | 36 | # Depencies 37 | -include $(OBJS:.o=.d) 38 | 39 | # Some convinient rules 40 | 41 | .PHONY: app clean 42 | app: $(BINARY) 43 | 44 | $(BINARY): $(OBJS) 45 | @echo + LD $@ 46 | @$(LD) -O2 -rdynamic -shared -fPIC -o $@ $^ 47 | 48 | 49 | clean: 50 | -rm -rf $(BUILD_DIR) 51 | -------------------------------------------------------------------------------- /nexus-am/tests/cputest/tests/min3.c: -------------------------------------------------------------------------------- 1 | #include "trap.h" 2 | 3 | int min3(int x, int y, int z) { 4 | int m; 5 | if(x < y) { m = x; } 6 | else { m = y; } 7 | if(z < m) m = z; 8 | return m; 9 | } 10 | 11 | int test_data[] = {0, 0x7fffffff, 0x80000000, 0xffffffff}; 12 | int ans [] = {0, 0, -2147483648, -1, 0, 0, -2147483648, -1, -2147483648, -2147483648, -2147483648, -2147483648, -1, -1, -2147483648, -1, 0, 0, -2147483648, -1, 0, 2147483647, -2147483648, -1, -2147483648, -2147483648, -2147483648, -2147483648, -1, -1, -2147483648, -1, -2147483648, -2147483648, -2147483648, -2147483648, -2147483648, -2147483648, -2147483648, -2147483648, -2147483648, -2147483648, -2147483648, -2147483648, -2147483648, -2147483648, -2147483648, -2147483648, -1, -1, -2147483648, -1, -1, -1, -2147483648, -1, -2147483648, -2147483648, -2147483648, -2147483648, -1, -1, -2147483648, -1}; 13 | 14 | #define NR_DATA LENGTH(test_data) 15 | 16 | int main() { 17 | int i, j, k, ans_idx = 0; 18 | for(i = 0; i < NR_DATA; i ++) { 19 | for(j = 0; j < NR_DATA; j ++) { 20 | for(k = 0; k < NR_DATA; k ++) { 21 | nemu_assert(min3(test_data[i], test_data[j], test_data[k]) == ans[ans_idx ++]); 22 | } 23 | nemu_assert(k == NR_DATA); 24 | } 25 | nemu_assert(j == NR_DATA); 26 | } 27 | 28 | nemu_assert(i == NR_DATA); 29 | 30 | return 0; 31 | } 32 | -------------------------------------------------------------------------------- /nexus-am/am/src/nutshell/common/ioe.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void __am_vga_init(); 5 | void __am_timer_init(); 6 | void __am_audio_init(); 7 | 8 | int _ioe_init() { 9 | __am_vga_init(); 10 | __am_timer_init(); 11 | __am_audio_init(); 12 | return 0; 13 | } 14 | 15 | size_t __am_timer_read(uintptr_t reg, void *buf, size_t size); 16 | size_t __am_video_read(uintptr_t reg, void *buf, size_t size); 17 | size_t __am_video_write(uintptr_t reg, void *buf, size_t size); 18 | size_t __am_input_read(uintptr_t reg, void *buf, size_t size); 19 | size_t __am_audio_read(uintptr_t reg, void *buf, size_t size); 20 | size_t __am_audio_write(uintptr_t reg, void *buf, size_t size); 21 | 22 | size_t _io_read(uint32_t dev, uintptr_t reg, void *buf, size_t size) { 23 | switch (dev) { 24 | case _DEV_INPUT: return __am_input_read(reg, buf, size); 25 | case _DEV_TIMER: return __am_timer_read(reg, buf, size); 26 | case _DEV_VIDEO: return __am_video_read(reg, buf, size); 27 | case _DEV_AUDIO: return __am_audio_read(reg, buf, size); 28 | } 29 | return 0; 30 | } 31 | 32 | size_t _io_write(uint32_t dev, uintptr_t reg, void *buf, size_t size) { 33 | switch (dev) { 34 | case _DEV_VIDEO: return __am_video_write(reg, buf, size); 35 | case _DEV_AUDIO: return __am_audio_write(reg, buf, size); 36 | } 37 | return 0; 38 | } 39 | -------------------------------------------------------------------------------- /nexus-am/libs/klib/include/klib-macros.h: -------------------------------------------------------------------------------- 1 | #ifndef __KLIB_MACROS_H__ 2 | #define __KLIB_MACROS_H__ 3 | 4 | #include 5 | 6 | #ifndef __cplusplus 7 | typedef uint8_t bool; 8 | #define false 0 9 | #define true 1 10 | #endif 11 | 12 | #define ROUNDUP(a, sz) ((((uintptr_t)a)+(sz)-1) & ~((sz)-1)) 13 | #define ROUNDDOWN(a, sz) ((((uintptr_t)a)) & ~((sz)-1)) 14 | 15 | #define LENGTH(arr) (sizeof(arr) / sizeof((arr)[0])) 16 | 17 | #define RANGE(st, ed) (_Area) { .start = (void *)(st), .end = (void *)(ed) } 18 | #define IN_RANGE(ptr, area) ((area).start <= (ptr) && (ptr) < (area).end) 19 | 20 | #define STRINGIFY(s) #s 21 | #define TOSTRING(s) STRINGIFY(s) 22 | 23 | #define _CONCAT(x, y) x ## y 24 | #define CONCAT(x, y) _CONCAT(x, y) 25 | 26 | #define static_assert(const_cond) \ 27 | static char CONCAT(_static_assert_, __LINE__) [(const_cond) ? 1 : -1] __attribute__((unused)) 28 | 29 | static inline void *upcast(uint32_t ptr) { 30 | return (void *)(uintptr_t)ptr; 31 | } 32 | 33 | static inline void putstr(const char *s) { 34 | while (*s) _putc(*s ++); 35 | } 36 | 37 | #define panic_on(cond, s) \ 38 | do { \ 39 | if (cond) { \ 40 | putstr("AM Panic: "); putstr(s); \ 41 | putstr(" @ " __FILE__ ":" TOSTRING(__LINE__) " \n"); \ 42 | _halt(1); \ 43 | } \ 44 | } while (0) 45 | 46 | #define panic(s) panic_on(1, s) 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /nemu/src/isa/riscv64/exec/control.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | static inline make_EHelper(jal) { 4 | rtl_li(s, ddest, s->seq_pc); 5 | rtl_j(s, s->jmp_pc); 6 | 7 | print_asm_template2(jal); 8 | } 9 | 10 | static inline make_EHelper(jalr) { 11 | rtl_addi(s, s0, dsrc1, id_src2->imm); 12 | #ifdef __ENGINE_interpreter__ 13 | rtl_andi(s, s0, s0, ~0x1lu); 14 | #endif 15 | rtl_jr(s, s0); 16 | 17 | rtl_li(s, ddest, s->seq_pc); 18 | 19 | #ifndef __DIFF_REF_NEMU__ 20 | difftest_skip_dut(1, 2); 21 | #endif 22 | 23 | print_asm_template3(jalr); 24 | } 25 | 26 | static inline make_EHelper(beq) { 27 | rtl_jrelop(s, RELOP_EQ, dsrc1, dsrc2, s->jmp_pc); 28 | print_asm_template3(beq); 29 | } 30 | 31 | static inline make_EHelper(bne) { 32 | rtl_jrelop(s, RELOP_NE, dsrc1, dsrc2, s->jmp_pc); 33 | print_asm_template3(bne); 34 | } 35 | 36 | static inline make_EHelper(blt) { 37 | rtl_jrelop(s, RELOP_LT, dsrc1, dsrc2, s->jmp_pc); 38 | print_asm_template3(blt); 39 | } 40 | 41 | static inline make_EHelper(bge) { 42 | rtl_jrelop(s, RELOP_GE, dsrc1, dsrc2, s->jmp_pc); 43 | print_asm_template3(bge); 44 | } 45 | 46 | static inline make_EHelper(bltu) { 47 | rtl_jrelop(s, RELOP_LTU, dsrc1, dsrc2, s->jmp_pc); 48 | print_asm_template3(bltu); 49 | } 50 | 51 | static inline make_EHelper(bgeu) { 52 | rtl_jrelop(s, RELOP_GEU, dsrc1, dsrc2, s->jmp_pc); 53 | print_asm_template3(bgeu); 54 | } 55 | -------------------------------------------------------------------------------- /nemu/include/rtl/rtl.h: -------------------------------------------------------------------------------- 1 | #ifndef __RTL_RTL_H__ 2 | #define __RTL_RTL_H__ 3 | 4 | #include 5 | 6 | #define id_src1 (&s->src1) 7 | #define id_src2 (&s->src2) 8 | #define id_dest (&s->dest) 9 | 10 | #define dsrc1 (id_src1->preg) 11 | #define dsrc2 (id_src2->preg) 12 | #define ddest (id_dest->preg) 13 | #define s0 (&s->tmp_reg[0]) 14 | #define s1 (&s->tmp_reg[1]) 15 | #define s2 (&s->tmp_reg[2]) 16 | #define t0 (&s->tmp_reg[3]) 17 | 18 | extern const rtlreg_t rzero; 19 | #define rz (&rzero) 20 | 21 | #define make_rtl(name, ...) void concat(rtl_, name)(DecodeExecState *s, __VA_ARGS__) 22 | 23 | void rtl_exit(int state, vaddr_t halt_pc, uint32_t halt_ret); 24 | 25 | // relation operation 26 | enum { 27 | // +-- unsign 28 | // | +-- sign 29 | // | | +-- equal 30 | // | | | +-- invert 31 | // | | | | 32 | RELOP_FALSE = 0 | 0 | 0 | 0, 33 | RELOP_TRUE = 0 | 0 | 0 | 1, 34 | RELOP_EQ = 0 | 0 | 2 | 0, 35 | RELOP_NE = 0 | 0 | 2 | 1, 36 | 37 | RELOP_LT = 0 | 4 | 0 | 0, 38 | RELOP_LE = 0 | 4 | 2 | 0, 39 | RELOP_GT = 0 | 4 | 2 | 1, 40 | RELOP_GE = 0 | 4 | 0 | 1, 41 | 42 | RELOP_LTU = 8 | 0 | 0 | 0, 43 | RELOP_LEU = 8 | 0 | 2 | 0, 44 | RELOP_GTU = 8 | 0 | 2 | 1, 45 | RELOP_GEU = 8 | 0 | 0 | 1, 46 | }; 47 | 48 | #include 49 | #include 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /nemu/src/isa/riscv64/exec/ldst.h: -------------------------------------------------------------------------------- 1 | #include "../local-include/intr.h" 2 | 3 | static inline make_EHelper(ld) { 4 | rtl_lm(s, ddest, dsrc1, id_src2->imm, s->width); 5 | 6 | print_Dop(id_src1->str, OP_STR_SIZE, "%ld(%s)", id_src2->imm, reg_name(id_src1->reg, 4)); 7 | switch (s->width) { 8 | case 8: print_asm_template2(ld); break; 9 | case 4: print_asm_template2(lwu); break; 10 | case 2: print_asm_template2(lhu); break; 11 | case 1: print_asm_template2(lbu); break; 12 | default: assert(0); 13 | } 14 | } 15 | 16 | // load sign value 17 | static inline make_EHelper(lds) { 18 | rtl_lms(s, ddest, dsrc1, id_src2->imm, s->width); 19 | 20 | print_Dop(id_src1->str, OP_STR_SIZE, "%ld(%s)", id_src2->imm, reg_name(id_src1->reg, 4)); 21 | switch (s->width) { 22 | case 4: print_asm_template2(lw); break; 23 | case 2: print_asm_template2(lh); break; 24 | case 1: print_asm_template2(lb); break; 25 | default: assert(0); 26 | } 27 | } 28 | 29 | static inline make_EHelper(st) { 30 | rtl_sm(s, dsrc1, id_src2->imm, ddest, s->width); 31 | 32 | print_Dop(id_src1->str, OP_STR_SIZE, "%ld(%s)", id_src2->imm, reg_name(id_src1->reg, 4)); 33 | switch (s->width) { 34 | case 8: print_asm_template2(sd); break; 35 | case 4: print_asm_template2(sw); break; 36 | case 2: print_asm_template2(sh); break; 37 | case 1: print_asm_template2(sb); break; 38 | default: assert(0); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /nexus-am/libs/klib/src/io.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | uint32_t uptime() { 5 | _DEV_TIMER_UPTIME_t uptime; 6 | _io_read(_DEV_TIMER, _DEVREG_TIMER_UPTIME, &uptime, sizeof(uptime)); 7 | return uptime.lo; 8 | } 9 | 10 | void get_timeofday(void *rtc) { 11 | _io_read(_DEV_TIMER, _DEVREG_TIMER_DATE, rtc, sizeof(_DEV_TIMER_DATE_t)); 12 | } 13 | 14 | int read_key() { 15 | _DEV_INPUT_KBD_t key; 16 | _io_read(_DEV_INPUT, _DEVREG_INPUT_KBD, &key, sizeof(_DEV_INPUT_KBD_t)); 17 | int ret = key.keycode; 18 | if (key.keydown) ret |= 0x8000; 19 | return ret; 20 | } 21 | 22 | void draw_rect(uint32_t *pixels, int x, int y, int w, int h) { 23 | _DEV_VIDEO_FBCTRL_t ctl = (_DEV_VIDEO_FBCTRL_t) { 24 | .pixels = pixels, 25 | .x = x, .y = y, .w = w, .h = h, 26 | .sync = 0, 27 | }; 28 | _io_write(_DEV_VIDEO, _DEVREG_VIDEO_FBCTRL, &ctl, sizeof(ctl)); 29 | } 30 | 31 | void draw_sync() { 32 | _DEV_VIDEO_FBCTRL_t ctl; 33 | ctl.pixels = NULL; 34 | ctl.x = ctl.y = ctl.w = ctl.h = 0; 35 | ctl.sync = 1; 36 | _io_write(_DEV_VIDEO, _DEVREG_VIDEO_FBCTRL, &ctl, sizeof(ctl)); 37 | } 38 | 39 | int screen_width() { 40 | _DEV_VIDEO_INFO_t info; 41 | _io_read(_DEV_VIDEO, _DEVREG_VIDEO_INFO, &info, sizeof(info)); 42 | return info.width; 43 | } 44 | 45 | int screen_height() { 46 | _DEV_VIDEO_INFO_t info; 47 | _io_read(_DEV_VIDEO, _DEVREG_VIDEO_INFO, &info, sizeof(info)); 48 | return info.height; 49 | } 50 | -------------------------------------------------------------------------------- /verilator/emulator.h: -------------------------------------------------------------------------------- 1 | #ifndef __EMULATOR_H__ 2 | #define __EMULATOR_H__ 3 | 4 | #include "ram.h" 5 | // #include "VsimTop.h" 6 | #include "VsimSoc.h" 7 | #include "difftestIO.h" 8 | 9 | /** 10 | * @brief 运行kisscpu的模拟器 11 | * 12 | */ 13 | class CEmulator 14 | { 15 | private: 16 | /** 17 | * @brief 当前时钟 18 | * 19 | */ 20 | int m_cycles = 0; 21 | long* m_sc_time; 22 | /** 23 | * @brief 模拟器运行需要的ram指针 24 | * 25 | */ 26 | CRam *m_ram; 27 | /** 28 | * @brief verilator生成的顶层指针 29 | * 30 | */ 31 | // VsimTop* m_simtop; 32 | VsimSoc* m_simtop; 33 | /** 34 | * @brief 波形指针 35 | * 36 | */ 37 | VerilatedVcdC* m_tfp; 38 | /** 39 | * @brief reset n个时钟 40 | * 41 | * @param cycles n次 42 | */ 43 | void reset_ncycles(int cycles); 44 | 45 | void evalRam(); 46 | public: 47 | /** 48 | * @brief Construct a new CEmulator object 49 | * 50 | * @param input_ram 输入ram 51 | */ 52 | CEmulator(CRam* input_ram, long* input_time); 53 | ~CEmulator(); 54 | /** 55 | * @brief 模拟器运行几步 56 | * 57 | * @param i 执行步数 58 | */ 59 | void step(int i); 60 | /** 61 | * @brief 读取DUT的所有reg到r中 62 | * 63 | * @param r 存放kisscpu的reg信息 64 | */ 65 | void read_emu_regs(reg_t* r); 66 | double sc_time_stamp (); 67 | void single_cycle(); 68 | void execute_cycles(int n); 69 | }; 70 | 71 | #endif 72 | -------------------------------------------------------------------------------- /nemu/include/cpu/exec.h: -------------------------------------------------------------------------------- 1 | #ifndef __CPU_EXEC_H__ 2 | #define __CPU_EXEC_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #define make_EHelper(name) void concat(exec_, name) (DecodeExecState *s) 10 | 11 | static inline uint32_t instr_fetch(vaddr_t *pc, int len) { 12 | uint32_t instr = vaddr_ifetch(*pc, len); 13 | #ifdef DEBUG 14 | uint8_t *p_instr = (void *)&instr; 15 | int i; 16 | for (i = 0; i < len; i ++) { 17 | extern char log_bytebuf[]; 18 | strcatf(log_bytebuf, "%02x ", p_instr[i]); 19 | } 20 | #endif 21 | (*pc) += len; 22 | return instr; 23 | } 24 | 25 | static inline void update_pc(DecodeExecState *s) { 26 | cpu.pc = (s->is_jmp ? s->jmp_pc : s->seq_pc); 27 | } 28 | 29 | #ifdef DEBUG 30 | #define print_asm(...) \ 31 | do { \ 32 | extern char log_asmbuf[]; \ 33 | strcatf(log_asmbuf, __VA_ARGS__); \ 34 | } while (0) 35 | #else 36 | #define print_asm(...) 37 | #endif 38 | 39 | #ifndef suffix_char 40 | #define suffix_char(width) ' ' 41 | #endif 42 | 43 | #define print_asm_template1(instr) \ 44 | print_asm(str(instr) "%c %s", suffix_char(id_dest->width), id_dest->str) 45 | 46 | #define print_asm_template2(instr) \ 47 | print_asm(str(instr) "%c %s,%s", suffix_char(id_dest->width), id_src1->str, id_dest->str) 48 | 49 | #define print_asm_template3(instr) \ 50 | print_asm(str(instr) "%c %s,%s,%s", suffix_char(id_dest->width), id_src1->str, id_src2->str, id_dest->str) 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /verilator/common.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file common.h 3 | * @author your name (you@domain.com) 4 | * @brief 5 | * @version 0.1 6 | * @date 2020-09-23 7 | * 8 | * @copyright Copyright (c) 2020 9 | * 10 | */ 11 | #ifndef __COMMON_H__ 12 | #define __COMMON_H__ 13 | 14 | #include "constants.h" 15 | #define DEBUG_PRINT // 决定是否输出nemu调试信息 16 | // TODO: 17 | #define __RV64__ 18 | // #define __RV32__ 19 | 20 | #define vcdTrace true // 是否输出波形, 关闭快一点 21 | 22 | typedef unsigned char uint8_t; 23 | typedef unsigned int uint32_t; 24 | typedef unsigned long int uint64_t; 25 | 26 | 27 | #ifdef __RV32__ 28 | typedef uint32_t reg_t; 29 | typedef uint32_t paddr_t; 30 | #else 31 | typedef uint64_t reg_t; 32 | typedef uint64_t paddr_t; // 对数据地址取64位, 数据也是64位 33 | #endif 34 | 35 | typedef uint32_t iaddr_t; // 对指令地址取32位 36 | typedef uint8_t mask_t; 37 | 38 | /** 39 | * @brief 枚举的不同变量 40 | * 41 | */ 42 | //! 0~31: GPRs 43 | enum { 44 | DIFFTEST_THIS_PC = 32, ///< pc放在32号处 45 | #ifndef __RV32__ 46 | DIFFTEST_MSTATUS, 47 | DIFFTEST_MCAUSE, 48 | DIFFTEST_MEPC, 49 | DIFFTEST_SSTATUS, 50 | DIFFTEST_SCAUSE, 51 | DIFFTEST_SEPC, 52 | #endif 53 | DIFFTEST_NR_REG 54 | }; 55 | // 64位下 DIFFTEST_NR_REG = 39, 32位 = 33 56 | 57 | // typedef reg_t ref_reg[DIFFTEST_NR_REG] emu_reg; 58 | // reg_t ref_reg[DIFFTEST_NR_REG]; // 用于验证的reg集合 59 | // reg_t emu_reg[DIFFTEST_NR_REG]; // 仿真得到的reg集合 60 | 61 | 62 | #define ADDRSTART 0x80000000 63 | #define RAMSIZE (128 * 1024 * 1024) 64 | 65 | 66 | #endif -------------------------------------------------------------------------------- /docs/10.28.md: -------------------------------------------------------------------------------- 1 | ### 今日任务 2 | 3 | 1. 阅读并复习riscv操作系统的知识, 思考启动rtt到底需要怎样修改bsp, 能否在不支持时钟中断, 甚至不需要csr的情况下启动? 不需要乘除法支持可以吗? 4 | 5 | 6 | 7 | 1. call 至少需要csr, 需要函数调用啊, 这里涉及中断? 8 | 2. 当前问题: 在使用objdump之后发现.bin文件无法读取, 或者说对于rtt的源码, 要怎么才能变成.bin文件, 让nemu去比对. 或者只是单纯不比对, 直接让我的处理器去运行? 出现bug怎么办. 9 | 3. 可能方法: 10 | 1. 拷贝rtt源码到am项目中, 使用现成的makefile来生成.bin文件(最好办法). 11 | 2. 不使用am, nemu项目, 直接编译生成的代码, 想办法让开头指向0x8000_0000, 直接去运行rtt 12 | 3. 参考他人的办法, 或者nutshell的办法去做. 13 | 14 | 15 | 16 | 原来nutshell是有很多说明的啊..... 感觉自己摸索了好久, 看说明就立刻明白了! 17 | 18 | [https://github.com/OSCPU/NutShell-doc/blob/master/%E4%BB%8B%E7%BB%8D/NutShell-tutorial.md](https://github.com/OSCPU/NutShell-doc/blob/master/介绍/NutShell-tutorial.md) 19 | 20 | 不过这个说明能放在首页吗, 找了这么久居然才发现...... 21 | 22 | 23 | 24 | ``` 25 | # U 模式 26 | 1. Ustatus 2. Uie 3. Utvec 4. Uscratch 27 | 5. Uepc 6. Ucause 7. Utval 8. Uip 28 | # S 模式 29 | 1. Sstatus 2. Sedeleg 3. Sideleg 4. Sie 30 | 5. Stvec 6. Scounteren 7. Sscratch 8. Sepc 31 | 9. Scause 10. Stval 11. Sip 12. Satp 32 | # M 模式 33 | 1. Mvendorid 2. Marchid 3. Mimpid 4. Mhartid 34 | 5. Mstatus 6. Mstatus 7. Misa 8. Medeleg 35 | 9. Mideleg 10. Mie 11. Mtvec 12. Mcounteren 36 | 13. Mscratch 14. Mepc 15. Mcause 16. Mtval 37 | 29. Mip 38 | 39 | 保留写入保留值,读取忽略值(WPRI) 40 | Reserved Writes Preserve Values, Reads Ignore Values 41 | 写入/只读合法值(WLRL) Write/Read Only Legal Values 42 | 写任何值,读取合法值(WARL) Write Any Values, Reads Legal Values 43 | ``` 44 | 45 | -------------------------------------------------------------------------------- /docs/10.4.md: -------------------------------------------------------------------------------- 1 | ### 今日任务 2 | 3 | 1. 思考在没有延迟槽指令的情况下如何更好的流水, 少阻塞--- 还是先阻塞吧 4 | 2. branch指令的判断逻辑放在dec还是exe上?---------- 还是放在dec上, 更快 5 | 3. 参考riscv书籍上的 / 再认真阅读soder上的 6 | 7 | 8 | 9 | 成功解决 10 | 11 | 1. 既然现在的ram是立刻读出来指令的, 索性强行加reg把指令缓存一拍, 就可以模拟同步读的ram了 12 | 13 | 2. 对于跳转指令, 由于没有延迟槽指令, 本来想着阻塞一拍, 但是控制逻辑要改很多, 突然想到直接把下一条指令改成nop就完美了, 所以改成了下面的 14 | 15 | 3. ```scala 16 | io.instReadIO.addr := if_pc_next 17 | io.instReadIO.en := to_fs_valid && fs_allowin // 握手成功且可以流水才读指令 18 | val if_inst = Wire(UInt(XLEN.W)) 19 | val if_reg_inst = Reg(UInt(XLEN.W)) // 缓存一拍获取的指令 20 | if_reg_inst := io.instReadIO.data 21 | // if_inst := if_reg_inst 22 | if_inst := Mux(io.ctl.dec_pc_sel === PC_4, if_reg_inst, BUBBLE) // 如果是跳转指令, 强行改成nop 23 | // 注意: 这是凭空增加的一条指令, 例如原有指令是jal, j; 现在改成了jal, nop, 这里的nop和j的pc相同, 但是指令不同, 不会影响后来执行j的结果! 24 | ``` 25 | 26 | 4. 发现nemu只能执行9条指令, 所以重新clone老师的nemu 27 | 28 | ``` 29 | git clone https://github.com/OSCPU/nemu 30 | cd nemu 31 | rm -rf .git 32 | make run DIFF=nemu ISA=riscv64 NEMU_HOME=/home/yanyue/nutshell_v2/kisscpu/nemu 33 | // DIFF要改成nemu, 加上NEMU_HOME这些 34 | // 会在build文件中生成最新的nemu_so 35 | ``` 36 | 37 | 5. 当前问题: 为何nemu还是只能执行9条指令??? 38 | 39 | 6. address (0x4060000c) is out of bound {???} [0x00000000, 0x00000000] at pc = 0x000000008000012c 40 | 41 | 7. 解决问题: 在询问了杨宇恒同学后, 发现问题是在访问串口地址出错, 所以把am/src/nutshell/common/uartlite 中的函数, 除了return 0 都删除, 再重新编译运行即可 42 | 43 | 44 | 45 | 当前bug: 46 | 47 | ​ jal nop jalr(会使用到ra, 这时候jal的ra还没写入regfile, 需要使用数据前递技术) 48 | 49 | -------------------------------------------------------------------------------- /verilator/ram.h: -------------------------------------------------------------------------------- 1 | #ifndef __RAM_H__ 2 | #define __RAM_H__ 3 | 4 | #include "common.h" 5 | /** 6 | * 使用数组模拟的RAM类 7 | */ 8 | class CRam 9 | { 10 | private: 11 | /** 巨大的RAM数组(存储指令和数组, 统一的!), 每个元素64位 */ 12 | paddr_t m_ram[RAMSIZE / sizeof(paddr_t)]; 13 | int m_ramSize; ///< ram的大小, 单位为64byte 14 | int m_imgSize; ///< ram内存储img的大小 15 | long* sc_time; ///< 打印波形的时钟 16 | 17 | public: 18 | /** 19 | * @brief Construct a new CRam object 20 | * 21 | * @param imgPath 输入img文件的地址路径 22 | */ 23 | CRam(char* imgPath); 24 | /** 25 | * @brief Destroy the CRam object 26 | * 27 | */ 28 | ~CRam(); 29 | /** 30 | * @brief Get the Img Start object 获取img的起始地址 31 | * 32 | * @return void* 返回img起始地址 33 | */ 34 | void *getImgStart(); 35 | /** 36 | * @brief Get the Img Size object 获取img大小 37 | * 38 | * @return int 返回img大小 39 | */ 40 | int getImgSize(); 41 | 42 | // 指令, 数据读写功能 43 | /** 44 | * @brief 指令读 45 | * 46 | * @param addr 指令地址 47 | * @param en enable 48 | * @return paddr_t 返回具体指令 49 | */ 50 | iaddr_t InstRead(paddr_t addr, bool en); 51 | /** 52 | * @brief 数据读 53 | * 54 | * @param addr 数据地址 55 | * @param en 56 | * @return paddr_t 返回具体数据 57 | */ 58 | paddr_t DataRead(paddr_t addr, bool en); 59 | /** 60 | * @brief 数据写 61 | * 62 | * @param addr 63 | * @param data 64 | * @param en 65 | */ 66 | void DataWrite(paddr_t addr, paddr_t data, bool en, mask_t mask); 67 | }; 68 | 69 | 70 | #endif -------------------------------------------------------------------------------- /docs/11.16.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ``` 4 | div: 5 | 6 | right pc = [0x 8000007c], wrong pc = [0x 80000088] cyc = 418 7 | 8 | 80000070: 00b00693 li a3,11 9 | 80000074: 00062703 lw a4,0(a2) 10 | 80000078: 00100793 li a5,1 11 | 8000007c: 02f7073b mulw a4,a4,a5 12 | 80000080: 0017879b addiw a5,a5,1 13 | 80000084: fed79ce3 bne a5,a3,8000007c 14 | // a3=b, a5=2, 不等, 回到7c, 不应该到88 15 | 80000088: 00e62023 sw a4,0(a2) 16 | 8000008c: 00460613 addi a2,a2,4 17 | 18 | cyc=344, bne刚进入if, 但是直接取指令80000088的, 分支预测错误 19 | cyc = 347,80000084 这条指令错误, 应该是fed79ce3, 不是0017879b, 但恰好用了错误的, 应该等bne进入dec才去译码, 但这时候bne阻塞在if, dec的addiw译码, if_pc_next错误, 取出了错误的指令, dummy怎么过的? 20 | 原来跳转指令获得data_ok后, 进入dec,这一拍才发请求,这时pc_next刚好变化, pre_if 就用变化后的地址去取指令, 取出的就是跳转后的指令, 还真是一个巧合啊! 21 | cyc=407, bne才进入dec, 这时候应该刷新一下if的指令(把pc, inst都变成nop, 或者把if_valid变成0, 或者在它进入dec时候valid变成0),但这时候由于if取出的是80000088指令,等了好几拍之后, 它的data_ok后的下一拍, 直接取8000008c指令了, 真正的8000007c指令地址被丢失了, 怎么办呢? 22 | 尝试失败: 让inst_fetching直到ds_allowin流水才变成0, 阻碍延迟槽指令的取指, 但是这样形成了很奇怪的现象, 还是别把inst_fecthing的语义弄得太复杂, 简单就好 23 | ``` 24 | 25 | 26 | 27 | 当前方法: 28 | 29 | 暂时放弃添加乘除法, 防止axi变得非常复杂, 就通过编译器的方法去除乘除法指令. 30 | 31 | 添加mmio的转接桥, 在服务器上能跑hello程序, 主要根据地址来区别两个通道, 并且输入到core的通道都直接连接到mmio和mem两个上面 32 | 33 | 34 | 35 | 添加了ADD_SOURCE 宏定义, 可以不输出difftest 接口 36 | 37 | 删除soc_top.v 中awqos, awcache, aruser, arqos 四个变量 38 | 39 | 40 | 41 | 在ysyx_yanyue.v 最前面加上 42 | 43 | `define RANDOMIZE_DELAY 0 44 | 45 | 46 | 47 | 修改起始地址到0x4000_0000 48 | 49 | 50 | 51 | 成功啦, 居然能输出Hello World! 了, 在服务器上都没有调试, 就成功了, 太不容易了啊!!! -------------------------------------------------------------------------------- /nemu/src/device/io/map.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #define IO_SPACE_MAX (1024 * 1024) 7 | 8 | static uint8_t io_space[IO_SPACE_MAX] PG_ALIGN = {}; 9 | static uint8_t *p_space = io_space; 10 | 11 | uint8_t* new_space(int size) { 12 | uint8_t *p = p_space; 13 | // page aligned; 14 | size = (size + (PAGE_SIZE - 1)) & ~PAGE_MASK; 15 | p_space += size; 16 | assert(p_space - io_space < IO_SPACE_MAX); 17 | return p; 18 | } 19 | 20 | static inline void check_bound(IOMap *map, paddr_t addr) { 21 | Assert(map != NULL && addr <= map->high && addr >= map->low, 22 | "address (0x%08x) is out of bound {%s} [0x%08x, 0x%08x] at pc = " FMT_WORD, 23 | addr, (map ? map->name : "???"), (map ? map->low : 0), (map ? map->high : 0), cpu.pc); 24 | } 25 | 26 | static inline void invoke_callback(io_callback_t c, paddr_t offset, int len, bool is_write) { 27 | if (c != NULL) { c(offset, len, is_write); } 28 | } 29 | 30 | word_t map_read(paddr_t addr, int len, IOMap *map) { 31 | assert(len >= 1 && len <= 8); 32 | check_bound(map, addr); 33 | paddr_t offset = addr - map->low; 34 | invoke_callback(map->callback, offset, len, false); // prepare data to read 35 | 36 | word_t data = *(word_t *)(map->space + offset) & (~0Lu >> ((8 - len) << 3)); 37 | return data; 38 | } 39 | 40 | void map_write(paddr_t addr, word_t data, int len, IOMap *map) { 41 | assert(len >= 1 && len <= 8); 42 | check_bound(map, addr); 43 | paddr_t offset = addr - map->low; 44 | 45 | memcpy(map->space + offset, &data, len); 46 | 47 | invoke_callback(map->callback, offset, len, true); 48 | } 49 | -------------------------------------------------------------------------------- /nexus-am/tests/cputest/tests/add-longlong.c: -------------------------------------------------------------------------------- 1 | #include "trap.h" 2 | 3 | long long add(long long a, long long b) { 4 | long long c = a + b; 5 | return c; 6 | } 7 | 8 | long long test_data[] = {0, 1, 2, 0x7fffffffffffffffLL, 0x8000000000000000LL, 0x8000000000000001LL, 0xfffffffffffffffeLL, 0xffffffffffffffffLL}; 9 | long long ans[] = {0LL, 0x1LL, 0x2LL, 0x7fffffffffffffffLL, 0x8000000000000000LL, 0x8000000000000001LL, 0xfffffffffffffffeLL, 0xffffffffffffffffLL, 0x1LL, 0x2LL, 0x3LL, 0x8000000000000000LL, 0x8000000000000001LL, 0x8000000000000002LL, 0xffffffffffffffffLL, 0LL, 0x2LL, 0x3LL, 0x4LL, 0x8000000000000001LL, 0x8000000000000002LL, 0x8000000000000003LL, 0LL, 0x1LL, 0x7fffffffffffffffLL, 0x8000000000000000LL, 0x8000000000000001LL, 0xfffffffffffffffeLL, 0xffffffffffffffffLL, 0LL, 0x7ffffffffffffffdLL, 0x7ffffffffffffffeLL, 0x8000000000000000LL, 0x8000000000000001LL, 0x8000000000000002LL, 0xffffffffffffffffLL, 0LL, 0x1LL, 0x7ffffffffffffffeLL, 0x7fffffffffffffffLL, 0x8000000000000001LL, 0x8000000000000002LL, 0x8000000000000003LL, 0LL, 0x1LL, 0x2LL, 0x7fffffffffffffffLL, 0x8000000000000000LL, 0xfffffffffffffffeLL, 0xffffffffffffffffLL, 0LL, 0x7ffffffffffffffdLL, 0x7ffffffffffffffeLL, 0x7fffffffffffffffLL, 0xfffffffffffffffcLL, 0xfffffffffffffffdLL, 0xffffffffffffffffLL, 0LL, 0x1LL, 0x7ffffffffffffffeLL, 0x7fffffffffffffffLL, 0x8000000000000000LL, 0xfffffffffffffffdLL, 0xfffffffffffffffeLL}; 10 | 11 | #define NR_DATA LENGTH(test_data) 12 | 13 | int main() { 14 | int i, j, ans_idx = 0; 15 | for(i = 0; i < NR_DATA; i ++) { 16 | for(j = 0; j < NR_DATA; j ++) { 17 | nemu_assert(add(test_data[i], test_data[j]) == ans[ans_idx ++]); 18 | } 19 | } 20 | 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /nexus-am/tests/cputest/tests/sub-longlong.c: -------------------------------------------------------------------------------- 1 | #include "trap.h" 2 | 3 | long long sub(long long a, long long b) { 4 | long long c = a - b; 5 | return c; 6 | } 7 | 8 | long long test_data[] = {0, 1, 2, 0x7fffffffffffffffLL, 0x8000000000000000LL, 0x8000000000000001LL, 0xfffffffffffffffeLL, 0xffffffffffffffffLL}; 9 | long long ans[] = {0LL, 0xffffffffffffffffLL, 0xfffffffffffffffeLL, 0x8000000000000001LL, 0x8000000000000000LL, 0x7fffffffffffffffLL, 0x2LL, 0x1LL, 0x1LL, 0LL, 0xffffffffffffffffLL, 0x8000000000000002LL, 0x8000000000000001LL, 0x8000000000000000LL, 0x3LL, 0x2LL, 0x2LL, 0x1LL, 0LL, 0x8000000000000003LL, 0x8000000000000002LL, 0x8000000000000001LL, 0x4LL, 0x3LL, 0x7fffffffffffffffLL, 0x7ffffffffffffffeLL, 0x7ffffffffffffffdLL, 0LL, 0xffffffffffffffffLL, 0xfffffffffffffffeLL, 0x8000000000000001LL, 0x8000000000000000LL, 0x8000000000000000LL, 0x7fffffffffffffffLL, 0x7ffffffffffffffeLL, 0x1LL, 0LL, 0xffffffffffffffffLL, 0x8000000000000002LL, 0x8000000000000001LL, 0x8000000000000001LL, 0x8000000000000000LL, 0x7fffffffffffffffLL, 0x2LL, 0x1LL, 0LL, 0x8000000000000003LL, 0x8000000000000002LL, 0xfffffffffffffffeLL, 0xfffffffffffffffdLL, 0xfffffffffffffffcLL, 0x7fffffffffffffffLL, 0x7ffffffffffffffeLL, 0x7ffffffffffffffdLL, 0LL, 0xffffffffffffffffLL, 0xffffffffffffffffLL, 0xfffffffffffffffeLL, 0xfffffffffffffffdLL, 0x8000000000000000LL, 0x7fffffffffffffffLL, 0x7ffffffffffffffeLL, 0x1LL, 0LL}; 10 | 11 | #define NR_DATA LENGTH(test_data) 12 | 13 | int main() { 14 | int i, j, ans_idx = 0; 15 | for(i = 0; i < NR_DATA; i ++) { 16 | for(j = 0; j < NR_DATA; j ++) { 17 | nemu_assert(sub(test_data[i], test_data[j]) == ans[ans_idx ++]); 18 | } 19 | } 20 | 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /nemu/src/device/io/port-io.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define PORT_IO_SPACE_MAX 65535 4 | 5 | #define NR_MAP 8 6 | static IOMap maps[NR_MAP] = {}; 7 | static int nr_map = 0; 8 | 9 | /* device interface */ 10 | void add_pio_map(char *name, ioaddr_t addr, uint8_t *space, int len, io_callback_t callback) { 11 | assert(nr_map < NR_MAP); 12 | assert(addr + len <= PORT_IO_SPACE_MAX); 13 | maps[nr_map] = (IOMap){ .name = name, .low = addr, .high = addr + len - 1, 14 | .space = space, .callback = callback }; 15 | Log("Add port-io map '%s' at [0x%08x, 0x%08x]", maps[nr_map].name, maps[nr_map].low, maps[nr_map].high); 16 | 17 | nr_map ++; 18 | } 19 | 20 | uint32_t pio_read_common(ioaddr_t addr, int len) { 21 | assert(addr + len - 1 < PORT_IO_SPACE_MAX); 22 | int mapid = find_mapid_by_addr(maps, nr_map, addr); 23 | assert(mapid != -1); 24 | return map_read(addr, len, &maps[mapid]); 25 | } 26 | 27 | void pio_write_common(ioaddr_t addr, uint32_t data, int len) { 28 | assert(addr + len - 1 < PORT_IO_SPACE_MAX); 29 | int mapid = find_mapid_by_addr(maps, nr_map, addr); 30 | assert(mapid != -1); 31 | map_write(addr, data, len, &maps[mapid]); 32 | } 33 | 34 | /* CPU interface */ 35 | uint32_t pio_read_l(ioaddr_t addr) { return pio_read_common(addr, 4); } 36 | uint32_t pio_read_w(ioaddr_t addr) { return pio_read_common(addr, 2); } 37 | uint32_t pio_read_b(ioaddr_t addr) { return pio_read_common(addr, 1); } 38 | void pio_write_l(ioaddr_t addr, uint32_t data) { pio_write_common(addr, data, 4); } 39 | void pio_write_w(ioaddr_t addr, uint32_t data) { pio_write_common(addr, data, 2); } 40 | void pio_write_b(ioaddr_t addr, uint32_t data) { pio_write_common(addr, data, 1); } 41 | -------------------------------------------------------------------------------- /nexus-am/apps/microbench/src/fib/fib.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // f(n) = (f(n-1) + f(n-2) + .. f(n-m)) mod 2^32 4 | 5 | #define N 2147483603 6 | static int M; 7 | 8 | static void put(uint32_t *m, int i, int j, uint32_t data) { 9 | m[i * M + j] = data; 10 | } 11 | 12 | static uint32_t get(uint32_t *m, int i, int j) { 13 | return m[i * M + j]; 14 | } 15 | 16 | static inline void mult(uint32_t *c, uint32_t *a, uint32_t *b) { 17 | for (int i = 0; i < M; i ++) 18 | for (int j = 0; j < M; j ++) { 19 | put(c, i, j, 0); 20 | for (int k = 0; k < M; k ++) { 21 | put(c, i, j, get(c, i, j) + get(a, i, k) * get(b, k, j)); 22 | } 23 | } 24 | } 25 | 26 | static inline void assign(uint32_t *a, uint32_t *b) { 27 | for (int i = 0; i < M; i ++) 28 | for (int j = 0; j < M; j ++) 29 | put(a, i, j, get(b, i, j)); 30 | } 31 | 32 | static uint32_t *A, *ans, *T, *tmp; 33 | 34 | void bench_fib_prepare() { 35 | M = setting->size; 36 | int sz = sizeof(uint32_t) * M * M; 37 | A = bench_alloc(sz); 38 | T = bench_alloc(sz); 39 | ans = bench_alloc(sz); 40 | tmp = bench_alloc(sz); 41 | } 42 | 43 | void bench_fib_run() { 44 | for (int i = 0; i < M; i ++) 45 | for (int j = 0; j < M; j ++) { 46 | uint32_t x = (i == M - 1 || j == i + 1); 47 | put(A, i, j, x); 48 | put(T, i, j, x); 49 | put(ans, i, j, i == j); 50 | } 51 | 52 | for (int n = N; n > 0; n >>= 1) { 53 | if (n & 1) { 54 | mult(tmp, ans, T); 55 | assign(ans, tmp); 56 | } 57 | mult(tmp, T, T); 58 | assign(T, tmp); 59 | } 60 | } 61 | 62 | int bench_fib_validate() { 63 | return get(ans, M-1, M-1) == setting->checksum; 64 | } 65 | -------------------------------------------------------------------------------- /docs/9.16.md: -------------------------------------------------------------------------------- 1 | #### 今日任务 2 | 3 | 1. 阅读soder的单周期流水线代码 4 | 2. 学习动态链接的相关函数 5 | 3. 添加nemu这个.o文件并获取5个diff函数 6 | 4. 添加debug功能, 尝试在单周期上执行一条指令 7 | 8 | 9 | 10 | #### dlopen 11 | 12 | ```c 13 | #include 14 | 15 | void *dlopen(const char *filename, int flags); 16 | // 返回一个handle, 其他函数dlsym, dlclose可以用 17 | // filename == NULL, handle=主函数, filename有/ , 解析路径 18 | 19 | int dlclose(void *handle); 20 | 21 | ``` 22 | 23 | 1. 使用nm libadd.so 查看所有的符号, 更好的办法, 用 `readelf -s libadd.so` 24 | 2. g++ 为了实现同名函数的重载, 需要对函数名修饰 25 | 26 | 27 | 28 | ```c 29 | #if 整型常量表达式1 30 | 程序段1 31 | #elif 整型常量表达式2 32 | 程序段2 33 | #elif 整型常量表达式3 34 | 程序段3 35 | #else 36 | 程序段4 37 | #endif 38 | 39 | #ifdef 宏名(DEBUG) 40 | 程序段1 41 | #elif defined __RV64__ 42 | 程序 43 | #else 44 | 程序段2 45 | #endif 46 | // 如果当前的宏已被定义过,则对“程序段1”进行编译,否则对“程序段2”进行编译。 47 | // #if 后面跟的是“整型常量表达式”,而 #ifdef 和 #ifndef 后面跟的只能是一个宏名,不能是其他的。 48 | ``` 49 | 50 | 以单下划线(_)表明是标准库的变量 51 | 52 | 双下划线(__) 开头表明是编译器的变量 53 | 54 | 建议自己在命名的时候不要用下划线开头,避免与标准库中的命名冲突 55 | 56 | 57 | 58 | ```c 59 | const uint32_t isa_default_img [] = { 60 | 0x800002b7, // lui t0,0x8000 t0 = 0x8000_0000 61 | 0x0002a023, // sw zero,0(t0) 0x8000_0000位置为0 62 | 0x0002a503, // lw a0,0(t0) a0 = 0 63 | 0x0000006b, // nemu_trap 64 | }; 65 | ``` 66 | 67 | 这是默认的numu执行的4条指令 68 | 69 | 问题: 如何在nemu是一个黑箱的情况下, 更改nemu执行的指令? 70 | 71 | ​ 答: 使用difftest_memcpy, 输入img文件, 然后去让nemu执行: TODO: yes! 72 | 73 | 如何加入ram, 因为soder中有IMem, Dmem, 在scala/verilog/c++中如何添加? 74 | 75 | 我怎么让我自己的cpu去跑特定的指令呢? 明天完成吧 76 | 77 | 78 | 79 | 问题: 我们scala的cpu的指令mem, 数据mem应该怎么实现啊, 以及如何初始化4条指令进去呢? 80 | 81 | ​ 答: 仍然使用c++, 申请一个很大的dataram(可读可写), instram(只读), 然后把cpu的VsimTop的相关连线通过verilator来连接就好, 这样就很完美啦 -------------------------------------------------------------------------------- /docs/11.8.md: -------------------------------------------------------------------------------- 1 | ### 今日任务 2 | 3 | 1. 把nutshell框架复制出来 4 | 2. 可能需要添加mmio, uart, 然后开始测试我的cpu 5 | 3. 还需要调试axi框架 6 | 4. 希望最后能成功打印一串H 7 | 8 | 9 | 10 | 密码: 11 | 12 | ``` 13 | f45d476147fe! 14 | ``` 15 | 16 | 17 | 18 | 注: 修改起始地址=0x40000000 19 | 20 | 21 | 22 | 1. 添加乘除法指令, 参考杨宇恒的代码 23 | 2. 使用microbench这些进行测试 24 | 3. 使用verilator来调试hello.bin, 争取能成功实现hello 25 | 26 | 27 | 28 | debug: 29 | 30 | ``` 31 | prime: 32 | reg 14 a4 different at pc = [0x 8000005c], right=[0x 1], wrong=[0x 0] cyc = 32 33 | 34 | remw rd, rs1, rs2 35 | x[rd] = sext(x[rs1][31: 0] %𝑠 x[rs2][31: 0]) 36 | 求余数字(Remainder Word). R-type, RV64M only. 37 | x[rs1]的低 32 位除以 x[rs2]的低 32 位,向 0 舍入,都视为 2 的补码,将余数的有符号扩展 38 | 写入 x[rd]。 39 | 40 | 0000000080000028
: 41 | 80000028: fd010113 addi sp,sp,-48 42 | 8000002c: 02813023 sd s0,32(sp) 43 | 80000030: 00913c23 sd s1,24(sp) 44 | 80000034: 01213823 sd s2,16(sp) 45 | 80000038: 01313423 sd s3,8(sp) 46 | 8000003c: 02113423 sd ra,40(sp) 47 | 80000040: 00000493 li s1,0 48 | 80000044: 06500413 li s0,101 49 | 80000048: 00001997 auipc s3,0x1 50 | 8000004c: d0098993 addi s3,s3,-768 # 80000d48 51 | 80000050: 09700913 li s2,151 52 | 80000054: 00200793 li a5,2 // a5 = 2 53 | 80000058: 02f4673b remw a4,s0,a5 54 | // s0 = 101 % 2 = 1 -> a4 55 | 8000005c: 0017879b addiw a5,a5,1 // a5+1 = 3 56 | 80000060: 02070263 beqz a4,80000084 57 | 80000064: fe879ae3 bne a5,s0,80000058 // a5 != s0, j 58 58 | 80000068: 00249793 slli a5,s1,0x2 59 | 8000006c: 00f987b3 add a5,s3,a5 60 | ``` 61 | 62 | -------------------------------------------------------------------------------- /nexus-am/am/include/riscv.h: -------------------------------------------------------------------------------- 1 | #ifndef __RISCV_H__ 2 | #define __RISCV_H__ 3 | 4 | #ifndef __ASSEMBLER__ 5 | 6 | #include 7 | 8 | typedef union { 9 | struct { uint32_t lo, hi; }; 10 | int64_t val; 11 | } R64; 12 | 13 | static inline uint8_t inb(uintptr_t addr) { return *(volatile uint8_t *)addr; } 14 | static inline uint16_t inw(uintptr_t addr) { return *(volatile uint16_t *)addr; } 15 | static inline uint32_t inl(uintptr_t addr) { return *(volatile uint32_t *)addr; } 16 | static inline uint64_t ind(uintptr_t addr) { return *(volatile uint64_t *)addr; } 17 | 18 | static inline void outb(uintptr_t addr, uint8_t data) { *(volatile uint8_t *)addr = data; } 19 | static inline void outw(uintptr_t addr, uint16_t data) { *(volatile uint16_t *)addr = data; } 20 | static inline void outl(uintptr_t addr, uint32_t data) { *(volatile uint32_t *)addr = data; } 21 | static inline void outd(uintptr_t addr, uint64_t data) { *(volatile uint64_t *)addr = data; } 22 | 23 | enum { MODE_U = 0, MODE_S, MODE_H, MODE_M }; 24 | #define MSTATUS_IE(mode) ((1 << (mode)) << 0) 25 | #define MSTATUS_PIE(mode) ((1 << (mode)) << 4) 26 | #define MSTATUS_MPP(mode) ((mode) << 11) 27 | #define MSTATUS_SPP(mode) ((mode) << 8) 28 | #define MSTATUS_MXR (1 << 19) 29 | #define MSTATUS_SUM (1 << 18) 30 | #define MSTATUS_MPRV (1 << 17) 31 | 32 | #define PTE_V 0x01 33 | #define PTE_R 0x02 34 | #define PTE_W 0x04 35 | #define PTE_X 0x08 36 | #define PTE_U 0x10 37 | 38 | // Address in page table entry 39 | #define PTE_ADDR(pte) (((uintptr_t)(pte) & ~0x3ff) << 2) 40 | 41 | #define PTW_SV32 ((ptw_config) { .ptw_level = 2, .vpn_width = 10 }) 42 | #define PTW_SV39 ((ptw_config) { .ptw_level = 3, .vpn_width = 9 }) 43 | #define PTW_SV48 ((ptw_config) { .ptw_level = 4, .vpn_width = 9 }) 44 | 45 | #endif 46 | 47 | #endif 48 | -------------------------------------------------------------------------------- /nemu/include/memory/vaddr.h: -------------------------------------------------------------------------------- 1 | #ifndef __MEMORY_VADDR_H__ 2 | #define __MEMORY_VADDR_H__ 3 | 4 | #include 5 | 6 | static inline word_t vaddr_read(vaddr_t addr, int len) { 7 | word_t vaddr_read1(vaddr_t addr); 8 | word_t vaddr_read2(vaddr_t addr); 9 | word_t vaddr_read4(vaddr_t addr); 10 | word_t vaddr_read8(vaddr_t addr); 11 | switch (len) { 12 | case 1: return vaddr_read1(addr); 13 | case 2: return vaddr_read2(addr); 14 | case 4: return vaddr_read4(addr); 15 | #ifdef ISA64 16 | case 8: return vaddr_read8(addr); 17 | #endif 18 | default: assert(0); 19 | } 20 | } 21 | 22 | static inline void vaddr_write(vaddr_t addr, word_t data, int len) { 23 | void vaddr_write1(vaddr_t addr, word_t data); 24 | void vaddr_write2(vaddr_t addr, word_t data); 25 | void vaddr_write4(vaddr_t addr, word_t data); 26 | void vaddr_write8(vaddr_t addr, word_t data); 27 | switch (len) { 28 | case 1: vaddr_write1(addr, data); break; 29 | case 2: vaddr_write2(addr, data); break; 30 | case 4: vaddr_write4(addr, data); break; 31 | #ifdef ISA64 32 | case 8: vaddr_write8(addr, data); break; 33 | #endif 34 | default: assert(0); 35 | } 36 | } 37 | 38 | static inline word_t vaddr_ifetch(vaddr_t addr, int len) { 39 | word_t vaddr_ifetch1(vaddr_t addr); 40 | word_t vaddr_ifetch2(vaddr_t addr); 41 | word_t vaddr_ifetch4(vaddr_t addr); 42 | word_t vaddr_ifetch8(vaddr_t addr); 43 | switch (len) { 44 | case 1: return vaddr_ifetch1(addr); 45 | case 2: return vaddr_ifetch2(addr); 46 | case 4: return vaddr_ifetch4(addr); 47 | #ifdef ISA64 48 | case 8: return vaddr_ifetch8(addr); 49 | #endif 50 | default: assert(0); 51 | } 52 | } 53 | 54 | 55 | #define PAGE_SIZE 4096 56 | #define PAGE_MASK (PAGE_SIZE - 1) 57 | #define PG_ALIGN __attribute((aligned(PAGE_SIZE))) 58 | 59 | #endif 60 | -------------------------------------------------------------------------------- /nexus-am/Makefile.compile: -------------------------------------------------------------------------------- 1 | $(shell mkdir -p $(DST_DIR)) 2 | 3 | OBJS = $(addprefix $(DST_DIR)/, $(addsuffix .o, $(basename $(SRCS)))) 4 | AS = $(CROSS_COMPILE)gcc 5 | CC = $(CROSS_COMPILE)gcc 6 | CXX = $(CROSS_COMPILE)g++ 7 | LD = $(CROSS_COMPILE)ld 8 | OBJDUMP = $(CROSS_COMPILE)objdump 9 | OBJCOPY = $(CROSS_COMPILE)objcopy 10 | READELF = $(CROSS_COMPILE)readelf 11 | INCLUDES += $(addprefix -I, $(INC_DIR)) -I$(AM_HOME)/am/ 12 | INCLUDES += -I$(AM_HOME)/am/include 13 | CFLAGS += -O2 -MMD -Wall -Werror -ggdb $(INCLUDES) \ 14 | -D__ISA__=\"$(ISA)\" -D__ISA_$(shell echo $(ISA) | tr a-z A-Z)__ \ 15 | -D__PLATFORM__=\"$(PLATFORM)\" -D__PLATFORM_$(shell echo $(PLATFORM) | tr a-z A-Z)__ \ 16 | -D__ARCH__=$(ARCH) -D__ARCH_$(shell echo $(ARCH) | tr a-z A-Z | tr - _) \ 17 | -DARCH_H=\"arch/$(ARCH).h\" \ 18 | -fno-asynchronous-unwind-tables -fno-builtin -fno-stack-protector \ 19 | -Wno-main 20 | CXXFLAGS += $(CFLAGS) -ffreestanding -fno-rtti -fno-exceptions 21 | ASFLAGS += -MMD $(INCLUDES) 22 | 23 | ## Compliation rule for .c -> .o (using gcc) 24 | $(DST_DIR)/%.o: %.c 25 | @mkdir -p $(dir $@) && echo + CC $< 26 | @$(CC) -std=gnu11 $(CFLAGS) -c -o $@ $(realpath $<) 27 | 28 | ## Compliation rule for .cpp -> .o (using g++) 29 | $(DST_DIR)/%.o: %.cpp 30 | @mkdir -p $(dir $@) && echo + CXX $< 31 | @$(CXX) -std=c++11 $(CXXFLAGS) -c -o $@ $(realpath $<) 32 | 33 | ## Compliation rule for .S -> .o (using as) 34 | $(DST_DIR)/%.o: %.S 35 | @mkdir -p $(dir $@) && echo + AS $< 36 | @$(AS) $(ASFLAGS) -c -o $@ $(realpath $<) 37 | 38 | ## Paste in dependencies (gcc generated .d) here 39 | -include $(addprefix $(DST_DIR)/, $(addsuffix .d, $(basename $(SRCS)))) 40 | 41 | ## Compilation rules for libraries 42 | am: 43 | @$(MAKE) -s -C $(AM_HOME) 44 | 45 | $(sort $(LIBS)): %: 46 | @$(MAKE) -s -C $(AM_HOME)/libs/$* 47 | 48 | .PHONY: $(LIBS) am 49 | -------------------------------------------------------------------------------- /nemu/include/rtl/pseudo.h: -------------------------------------------------------------------------------- 1 | #ifndef __RTL_PSEUDO_H__ 2 | #define __RTL_PSEUDO_H__ 3 | 4 | #ifndef __RTL_RTL_H__ 5 | #error "Should be only included by " 6 | #endif 7 | 8 | /* RTL pseudo instructions */ 9 | 10 | static inline make_rtl(li, rtlreg_t* dest, const rtlreg_t imm) { 11 | rtl_addi(s, dest, rz, imm); 12 | } 13 | 14 | static inline make_rtl(mv, rtlreg_t* dest, const rtlreg_t *src1) { 15 | if (dest != src1) rtl_add(s, dest, src1, rz); 16 | } 17 | 18 | static inline make_rtl(not, rtlreg_t *dest, const rtlreg_t* src1) { 19 | // dest <- ~src1 20 | // TODO(); 21 | rtl_xori(s, dest, src1, -1); 22 | } 23 | 24 | static inline make_rtl(neg, rtlreg_t *dest, const rtlreg_t* src1) { 25 | // dest <- -src1 26 | // TODO(); 27 | rtl_sub(s, dest, rz, src1); 28 | } 29 | 30 | static inline make_rtl(sext, rtlreg_t* dest, const rtlreg_t* src1, int width) { 31 | // dest <- signext(src1[(width * 8 - 1) .. 0]) 32 | // TODO(); 33 | 34 | const int word_size = sizeof(word_t); 35 | if (width == word_size) { 36 | rtl_mv(s, dest, src1); 37 | } else { 38 | assert(width == 1 || width == 2 || width == 4); 39 | rtl_shli(s, dest, src1, (word_size - width) * 8); 40 | rtl_sari(s, dest, dest, (word_size - width) * 8); 41 | } 42 | } 43 | 44 | static inline make_rtl(zext, rtlreg_t* dest, const rtlreg_t* src1, int width) { 45 | // dest <- zeroext(src1[(width * 8 - 1) .. 0]) 46 | // TODO(); 47 | 48 | const int word_size = sizeof(word_t); 49 | if (width == word_size) { 50 | rtl_mv(s, dest, src1); 51 | } else { 52 | assert(width == 1 || width == 2 || width == 4); 53 | rtl_shli(s, dest, src1, (word_size - width) * 8); 54 | rtl_shri(s, dest, dest, (word_size - width) * 8); 55 | } 56 | } 57 | 58 | static inline make_rtl(msb, rtlreg_t* dest, const rtlreg_t* src1, int width) { 59 | // dest <- src1[width * 8 - 1] 60 | // TODO(); 61 | rtl_shri(s, dest, src1, width * 8 - 1); 62 | if (width != 4) { 63 | rtl_andi(s, dest, dest, 0x1); 64 | } 65 | } 66 | 67 | #endif 68 | -------------------------------------------------------------------------------- /docs/10.14.md: -------------------------------------------------------------------------------- 1 | ### 今日任务 2 | 3 | 对于延迟槽指令必须要丢弃, 还是假设每次不跳转, 然后到执行级时候把前面刷掉指令, reflush一下. 这样不会有奇怪的比对问题了! 4 | 5 | 6 | 7 | 解决了 8 | 9 | ```scala 10 | val dec_reflush = io.ctl.dec_pc_sel =/= PC_4 // 如果dec是转移指令, 对下一拍的ds_valid刷新, 当前拍取出的指令= nop 11 | if_inst := Mux(dec_reflush, BUBBLE, if_reg_inst) // 如果是跳转指令, 强行改成nop 12 | 13 | when(dec_reflush){ 14 | ds_valid := false.B 15 | }.elsewhen(ds_allowin) { 16 | ds_valid := fs_to_ds_valid 17 | } 18 | ``` 19 | 20 | 21 | 22 | 23 | 24 | 修复bug: 25 | 26 | 在处理前递时候, 必须保证前递的信号是有效的, 之前直接用soder的就出现了问题 27 | 28 | ```scala 29 | dec_op1_data := MuxCase(rf_rs1_data, Array( 30 | ((io.ctl.op1_sel === OP1_IMZ)) -> imm_z, 31 | ((io.ctl.op1_sel === OP1_PC)) -> dec_reg_pc, 32 | (es_valid && (exe_reg_wbaddr === dec_rs1_addr) && (dec_rs1_addr =/= 0.U) && exe_reg_ctrl_rf_wen) -> exe_alu_out, 33 | (ms_valid && (mem_reg_wbaddr === dec_rs1_addr) && (dec_rs1_addr =/= 0.U) && mem_reg_ctrl_rf_wen) -> mem_wbdata, 34 | (ws_valid && (wb_reg_wbaddr === dec_rs1_addr) && (dec_rs1_addr =/= 0.U) && wb_reg_ctrl_rf_wen) -> wb_reg_wbdata 35 | )) // 且那一级别需要有效吧? 36 | // 注意先完成TODO! 之前注意到这个bug但是没有修复! 37 | dec_op2_data 同理 38 | ``` 39 | 40 | 41 | 42 | ``` 43 | // gdb debug 44 | gdb obj_dir/VsimTop 45 | set args /home/yanyue/nutshell_v2/kisscpu/nexus-am/tests/cputest/build/dummy-riscv64-nutshell.bin 46 | b CEmulator::step(int) 47 | b difftest_step(CEmulator*, int) 48 | 49 | set auto-load safe-path / 50 | "/home/yanyue/.gdbinit". 51 | ``` 52 | 53 | 54 | 55 | 当前问题: 56 | 57 | regfile 弄出来的32个reg仍然都是0, 在regfile打印的值也都是0, 应该怎么解决? 58 | 59 | 在没有addSourrce的情况下, 读出rf(8)的值是正常的, rf(1)=0, 先检查写ra时候是不是出问题了 60 | 61 | 62 | 63 | 一个巨大的bug!!! 64 | 65 | ```scala 66 | when(io.we.toBool() && io.waddr =/= 0.U){ 67 | rf(io.wdata) := io.wdata // 改成 rf(io.waddr) := io.wdata 68 | } 69 | ``` 70 | 71 | 这是在测试regfile的时候, 懒惰的没有写好测试程序, 并且那时候wdata = waddr, 导致没有发现这个问题! 非常严重, 以后一定要好好写测试程序 72 | 73 | 74 | 75 | 参考nutshell的测试框架, 修改了自己的测试程序, 成功比对啦! 太棒了, 终于不用肉眼比对了, 重构代码之后也更加简单清晰! 76 | 77 | 78 | 79 | 突然发现居然生成了波形代码! 意外啊, 果然nutshell的代码很不错, 终于解决了两周以来不能生成波形的bug了! 80 | 81 | -------------------------------------------------------------------------------- /nexus-am/apps/microbench/src/15pz/15pz.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "puzzle.h" 3 | #include "heap.h" 4 | 5 | const int N = 4; 6 | 7 | static int PUZZLE_S[N*N] = { 8 | 1, 2, 3, 4, 9 | 5, 6, 7, 8, 10 | 9, 10, 0, 11, 11 | 13, 14, 15, 12, 12 | }; 13 | 14 | static int PUZZLE_M[N*N] = { 15 | 1, 2, 3, 4, 16 | 5, 6, 7, 8, 17 | 12, 0, 14, 13, 18 | 11, 15, 10, 9, 19 | }; 20 | 21 | static int PUZZLE_L[N*N] = { 22 | 0, 2, 3, 4, 23 | 9, 6, 7, 8, 24 | 5, 11, 10, 12, 25 | 1, 15, 13, 14, 26 | }; 27 | 28 | static int ans; 29 | 30 | extern "C" { 31 | 32 | void bench_15pz_prepare() { 33 | } 34 | 35 | void bench_15pz_run() { 36 | N_puzzle puzzle; 37 | int MAXN; 38 | 39 | switch (setting->size) { 40 | case 0: puzzle = N_puzzle(PUZZLE_S); MAXN = 10; break; 41 | case 1: puzzle = N_puzzle(PUZZLE_M); MAXN = 2048; break; 42 | case 2: puzzle = N_puzzle(PUZZLE_L); MAXN = 16384; break; 43 | default: assert(0); 44 | } 45 | assert(puzzle.solvable()); 46 | 47 | auto *heap = (Updatable_heap> *) bench_alloc(sizeof(Updatable_heap>)); 48 | heap->init(MAXN); 49 | heap->push( puzzle, 0 ); 50 | 51 | int n = 0; 52 | ans = -1; 53 | 54 | while( heap->size() != 0 && n != MAXN ) { 55 | N_puzzle top = heap->pop(); 56 | ++n; 57 | 58 | if ( top == N_puzzle::solution() ) { 59 | // We are done 60 | ans = heap->length(top) * n; 61 | return; 62 | } 63 | 64 | if ( top.tile_left_possible() ) { 65 | heap->push( top.tile_left(), heap->length( top ) + 1 ); 66 | } 67 | 68 | if ( top.tile_right_possible() ) { 69 | heap->push( top.tile_right(), heap->length( top ) + 1 ); 70 | } 71 | 72 | if ( top.tile_up_possible() ) { 73 | heap->push( top.tile_up(), heap->length( top ) + 1 ); 74 | } 75 | 76 | if ( top.tile_down_possible() ) { 77 | heap->push( top.tile_down(), heap->length( top ) + 1 ); 78 | } 79 | } 80 | } 81 | 82 | 83 | int bench_15pz_validate() { 84 | return (uint32_t)ans == setting->checksum; 85 | } 86 | 87 | } 88 | 89 | -------------------------------------------------------------------------------- /docs/8.27_nemu.md: -------------------------------------------------------------------------------- 1 | 8.27 2 | 3 | 4 | 5 | ### 学习南京大学课程 6 | 7 | 1. 统计代码行数 8 | 9 | ```c 10 | find . | grep '\.c$\|\.h$' | xargs wc -l 11 | ``` 12 | 13 | 1. find 搜索目录文件中 . (当前文件所在目录), 列出所有文件 14 | 15 | 2. grep 正则匹配对应文件, -v 选中不匹配的 16 | 17 | 3. xargs 把标准输入转换为参数, 传送给第一个参数指定的程序, 等价于如下`wc -l a.c b.c ` (markdown 用反引号` 来作为代码) 18 | 19 | 4. 如下 20 | 21 | ``` 22 | ./myprog < data > /dev/null 23 | ``` 24 | 25 | `/dev/null`是一个特殊的文件, 任何试图输出到它的信息都会被丢弃. 总之, 上面的命令将`myprog`的输出过滤掉, 保留了`time`的计时结果, 方便又整洁. 26 | 27 | 5. Makefile 格式如下 28 | 29 | ``` 30 | hello:hello.c 31 | gcc hello.c -o hello # 注意开头的tab, 而不是空格 32 | 33 | .PHONY: clean # 防止已经有clean文件, 说明clean是伪目标 34 | 35 | clean: 36 | rm hello # 注意开头的tab, 而不是空格 37 | ``` 38 | 39 | 6. 对于 #!/bin/bash 开头的脚本文件 用bash ... 来执行! 40 | 41 | 7. ^E 表示 ctrl + E; CR 表示回车键; \pattern 来搜索, 用n下一个, N上一个 42 | 43 | 8. 在新的分支中提交代码, 不要用git commit, 用 `git checkout -B 分支名` 44 | 45 | 9. 注意我使用的是zsh, 不是bash, 要用`source ~./zshrc ` 46 | 47 | ### NEMU 48 | 49 | 1. 在NEMU中,每一个硬件部件都由一个程序相关的数据对象来模拟,例如变量,排列,结构体等;而对这些部件的操作则通过对相应数据对象的操作来模拟。例如NEMU中使用复制来模拟内存,那么对这个副本进行读取则相当于对内存进行读取。 50 | 2. nemu 由 monitor, cpu, mem, 设备构成 51 | 3. NEMU是一个用来执行客户程序的程序,但客户程序一开始并不存在于客户计算机中。我们需要将客户程序读入到客户计算机中,这件事是monitor来负责的, 需要init_monitor() 52 | 4. 约定。具体地,我们让monitor直接把一个累积的客户程序读入到一个固定的内存位置`IMAGE_START`(也就是`0x100000` 53 | 54 | ```c 55 | const uint32_t isa_default_img [] = { 56 | 0x800002b7, // lui t0,0x8000 t0 = 0x8000_0000 57 | 0x0002a023, // sw zero,0(t0) 0x8000_0000位置为0 58 | 0x0002a503, // lw a0,0(t0) a0 = 0 59 | 0x0000006b, // nemu_trap 60 | }; 61 | ``` 62 | 63 | PC 取指从0x8100_0000开始 64 | 65 | 6. 如果运行NEMU时未指定客户程序,那么monitor将读入一个内置的客户程序,放在`nemu/src/isa/$ISA/init.c`中 66 | 7. 对于某些ISA来说,物理内存并不是从0开始编址的,例如mips32和riscv32的物理地址均从`0x80000000`开始。 67 | 8. 将来CPU访问内存时,我们重定向CPU将需要访问的内存地址映射到`pmem`中的相应替换位置。例如如果mips32的CPU打算访问内存地址`0x80001234`,我们最终就会将其访问`pmem[0x1234]`。这种机制有一个专门的名字,叫地址映射,在后续的PA中我们将会再遇到它。 68 | 9. `cpu.pc`初始化寄存器的一个重要工作是将的初始值设置为`PC_START`,通过 `PC_START`地址映射之后会得到刚才我们约定的内存位置`0x100000`,这样就可以让CPU从我们约定的内存位置开始执行客户程序了 69 | 70 | 71 | -------------------------------------------------------------------------------- /src/main/scala/nutcore/alu.scala: -------------------------------------------------------------------------------- 1 | package nutcore 2 | 3 | import chisel3._ 4 | import chisel3.util._ 5 | import common.constans._ 6 | 7 | class alu extends Module{ 8 | val io = IO(new Bundle{ 9 | val alu_op = Input(UInt(aluFunc_w.W)) 10 | val src1 = Input(UInt(XLEN.W)) 11 | val src2 = Input(UInt(XLEN.W)) 12 | val result = Output(UInt(XLEN.W)) 13 | 14 | // val stall = Output(Bool()) 15 | }) 16 | 17 | /* 18 | // Multiplier 19 | val isMulDiv = io.alu_op === ALU_MUL || io.alu_op === ALU_MULH || io.alu_op === ALU_MULHSU || 20 | io.alu_op === ALU_MULHU || io.alu_op === ALU_DIV || io.alu_op === ALU_DIVU || 21 | io.alu_op === ALU_REM || io.alu_op === ALU_REMU || io.alu_op === ALU_MULW || 22 | io.alu_op === ALU_DIVW || io.alu_op === ALU_DIVUW || io.alu_op === ALU_REMW || 23 | io.alu_op === ALU_REMUW 24 | val multiplier = Module(new Multiplier) 25 | multiplier.io.start := isMulDiv 26 | multiplier.io.a := io.src1 27 | multiplier.io.b := io.src2 28 | multiplier.io.op := io.alu_op 29 | io.stall := isMulDiv && multiplier.io.stall_req 30 | */ 31 | val op = io.alu_op 32 | var src1 = io.src1 33 | val src2 = io.src2 34 | val shamt = io.src2(5,0).asUInt() // 移位, 取低5位, 35 | // TODO: 64位 取低6位 36 | 37 | // 只实现了12个 38 | io.result := MuxCase(0.U, Array( 39 | (op === ALU_ADD) -> (src1 + src2).asUInt(), 40 | (op === ALU_SUB) -> (src1 - src2).asUInt(), 41 | (op === ALU_AND) -> (src1 & src2).asUInt(), 42 | (op === ALU_OR ) -> (src1 | src2).asUInt(), 43 | (op === ALU_XOR) -> (src1 ^ src2).asUInt(), 44 | (op === ALU_SLT) -> (src1.asSInt() < src2.asSInt()).asUInt(), 45 | (op === ALU_SLTU)-> (src1 < src2).asUInt(), 46 | (op === ALU_SLL) -> (src1 << shamt)(XLEN-1, 0).asUInt(), 47 | (op === ALU_SRA) -> (src1.asSInt() >> shamt).asUInt(), 48 | (op === ALU_SRAW)-> Cat(Fill(32, src1(31)), (src1(31,0).asSInt() >> shamt).asUInt()), 49 | (op === ALU_SRL) -> (src1 >> shamt).asUInt(), 50 | (op === ALU_COPY_1)-> src1, 51 | (op === ALU_COPY_2)-> src2 52 | // (isMulDiv) -> multiplier.io.mult_out 53 | )) 54 | if(DEBUG_PRINT) { 55 | printf("ALU: func = %d, src1=[%x] src2=[%x] result=[%x]\n", op, src1, src2, io.result); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /nemu/src/isa/riscv64/exec/amo.h: -------------------------------------------------------------------------------- 1 | #include "../local-include/intr.h" 2 | 3 | static inline make_EHelper(lr) { 4 | rtl_lm(s, s0, dsrc1, 0, s->width); 5 | return_on_mem_ex(); 6 | cpu.lr_addr = *dsrc1; 7 | rtl_sext(s, ddest, s0, s->width); 8 | 9 | print_asm_template3(lr); 10 | } 11 | 12 | static inline make_EHelper(sc) { 13 | // should check overlapping instead of equality 14 | if (cpu.lr_addr == *dsrc1) { 15 | rtl_sm(s, dsrc1, 0, dsrc2, s->width); 16 | return_on_mem_ex(); 17 | rtl_li(s, s0, 0); 18 | } else { 19 | rtl_li(s, s0, 1); 20 | } 21 | rtl_sr(s, id_dest->reg, s0, 0); 22 | 23 | print_asm_template3(sc); 24 | } 25 | 26 | static void inline amo_load(DecodeExecState *s) { 27 | rtl_lm(s, s0, dsrc1, 0, s->width); 28 | rtl_sext(s, s0, s0, s->width); 29 | } 30 | 31 | static void inline amo_update(DecodeExecState *s) { 32 | rtl_sm(s, dsrc1, 0, s1, s->width); 33 | return_on_mem_ex(); 34 | rtl_sr(s, id_dest->reg, s0, 0); 35 | } 36 | 37 | static inline make_EHelper(amoswap) { 38 | amo_load(s); 39 | return_on_mem_ex(); 40 | rtl_mv(s, s1, dsrc2); // swap 41 | amo_update(s); 42 | return_on_mem_ex(); 43 | print_asm_template3(amoswap); 44 | } 45 | 46 | static inline make_EHelper(amoadd) { 47 | amo_load(s); 48 | return_on_mem_ex(); 49 | rtl_add(s, s1, s0, dsrc2); 50 | amo_update(s); 51 | return_on_mem_ex(); 52 | print_asm_template3(amoor); 53 | } 54 | 55 | static inline make_EHelper(amoor) { 56 | amo_load(s); 57 | return_on_mem_ex(); 58 | rtl_or(s, s1, s0, dsrc2); 59 | amo_update(s); 60 | return_on_mem_ex(); 61 | print_asm_template3(amoor); 62 | } 63 | 64 | static inline make_EHelper(amoand) { 65 | amo_load(s); 66 | return_on_mem_ex(); 67 | rtl_and(s, s1, s0, dsrc2); 68 | amo_update(s); 69 | return_on_mem_ex(); 70 | print_asm_template3(amoand); 71 | } 72 | 73 | static inline make_EHelper(amomaxu) { 74 | amo_load(s); 75 | return_on_mem_ex(); 76 | *s1 = (*s0 > *dsrc2 ? *s0 : *dsrc2); 77 | amo_update(s); 78 | return_on_mem_ex(); 79 | print_asm_template3(amomaxu); 80 | } 81 | 82 | static inline make_EHelper(amoxor) { 83 | amo_load(s); 84 | return_on_mem_ex(); 85 | rtl_xor(s, s1, s0, dsrc2); 86 | amo_update(s); 87 | return_on_mem_ex(); 88 | print_asm_template3(amoxor); 89 | } 90 | -------------------------------------------------------------------------------- /nexus-am/tests/cputest/tests/matrix-mul.c: -------------------------------------------------------------------------------- 1 | #include "trap.h" 2 | 3 | #define N 10 4 | int a[N][N] = { 5 | {31, -73, -67, -28, 87, -17, -15, -35, -53, -54}, 6 | {52, 36, 9, -91, -27, -78, 42, 82, 19, -6}, 7 | {41, -56, 31, 32, -52, 74, 28, 20, 55, -72}, 8 | {-59, 2, -79, -8, 44, 55, -83, -95, -45, 50}, 9 | {-95, 61, -63, 62, -16, 52, 40, 92, -32, -26}, 10 | {-99, 52, 96, 63, -75, -74, -82, 82, -95, 42}, 11 | {11, -22, 27, -27, -27, -76, -71, 58, -40, -65}, 12 | {91, -53, -67, 72, 36, -77, -3, 93, -24, 97}, 13 | {-52, -11, -77, -93, -92, -24, 70, 18, 56, 88}, 14 | {-43, -41, -26, 11, -84, -14, -41, 83, 27, -11} 15 | }; 16 | int b[N][N] = { 17 | {-48, -70, -40, -82, -74, -63, -59, -72, -100, -72}, 18 | {5, -84, 28, 56, 60, -33, -42, -50, -83, -83}, 19 | {-5, 5, 48, 75, -78, -9, 9, 2, 88, 70}, 20 | {69, 23, 66, 66, -11, 50, 67, 18, -58, 76}, 21 | {30, 45, 32, 25, -73, 57, -67, -14, 53, -33}, 22 | {98, -86, -63, 80, -45, -88, 80, -64, 58, -84}, 23 | {-55, -39, -13, -27, -37, 8, -96, 84, -89, 31}, 24 | {-82, 58, 81, -41, -58, 36, 76, -79, -29, 23}, 25 | {86, -46, 16, -18, 81, 90, 35, -90, 43, 55}, 26 | {-38, -19, -40, 82, -76, 57, -29, -2, 79, -48}, 27 | }; 28 | 29 | int ans[N][N] = { 30 | {-1317, 10379, -5821, -14322, -4330, -3114, -9940, 7033, -1883, -6027}, 31 | {-24266, -861, 4044, -19824, -223, 886, -11988, -6442, -13846, -1054}, 32 | {9783, -7073, -918, -5911, -967, -7100, 14605, -7556, -3439, 9607}, 33 | {15980, -520, -13297, 15043, 6185, -3654, 1325, 4193, 16925, -17761}, 34 | {2566, 3187, 10248, 7925, 6318, 1421, 14648, 700, -12193, 1083}, 35 | {-12603, 19006, 20952, 18599, -1539, 5184, 17408, 6740, 6264, 15114}, 36 | {-12715, 15121, 9963, -13717, 2411, -2196, 6147, -1698, -3389, 8200}, 37 | {-19007, 12417, 5723, -11309, -19242, 15740, -3791, -3949, -13130, -21}, 38 | {-12557, -5970, -11570, -8905, 12227, 7814, -5094, 4532, 1071, -1309}, 39 | {-2955, 9381, 6372, -6898, 9117, 5753, 20778, -5045, 1047, 12114}}; 40 | 41 | int c[N][N]; 42 | 43 | int main() { 44 | int i, j, k; 45 | for(i = 0; i < N; i ++) { 46 | for(j = 0; j < N; j ++) { 47 | c[i][j] = 0; 48 | for(k = 0; k < N; k ++) { 49 | c[i][j] += a[i][k] * b[k][j]; 50 | } 51 | nemu_assert(c[i][j] == ans[i][j]); 52 | nemu_assert(k == N); 53 | } 54 | nemu_assert(j == N); 55 | } 56 | 57 | nemu_assert(i == N); 58 | 59 | return 0; 60 | } 61 | -------------------------------------------------------------------------------- /nexus-am/tests/amtest/src/tests/video.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define FPS 30 4 | #define N 32 5 | 6 | static inline uint32_t pixel(uint8_t r, uint8_t g, uint8_t b) { 7 | return (r << 16) | (g << 8) | b; 8 | } 9 | static inline uint8_t R(uint32_t p) { return p >> 16; } 10 | static inline uint8_t G(uint32_t p) { return p >> 8; } 11 | static inline uint8_t B(uint32_t p) { return p; } 12 | 13 | static uint32_t canvas[N][N]; 14 | static int used[N][N]; 15 | 16 | static uint32_t color_buf[32 * 32]; 17 | 18 | void redraw() { 19 | int w = screen_width() / N; 20 | int h = screen_height() / N; 21 | int block_size = w * h; 22 | assert((uint32_t)block_size <= LENGTH(color_buf)); 23 | 24 | int x, y, k; 25 | for (y = 0; y < N; y ++) { 26 | for (x = 0; x < N; x ++) { 27 | for (k = 0; k < block_size; k ++) { 28 | color_buf[k] = canvas[y][x]; 29 | } 30 | draw_rect(color_buf, x * w, y * h, w, h); 31 | } 32 | } 33 | 34 | draw_sync(); 35 | } 36 | 37 | static uint32_t p(int tsc) { 38 | int b = tsc & 0xff; 39 | return pixel(b * 6, b * 7, b); 40 | } 41 | 42 | void update() { 43 | static int tsc = 0; 44 | static int dx[4] = {0, 1, 0, -1}; 45 | static int dy[4] = {1, 0, -1, 0}; 46 | 47 | tsc ++; 48 | 49 | for (int i = 0; i < N; i ++) 50 | for (int j = 0; j < N; j ++) { 51 | used[i][j] = 0; 52 | } 53 | 54 | int init = tsc * 1; 55 | canvas[0][0] = p(init); used[0][0] = 1; 56 | int x = 0, y = 0, d = 0; 57 | for (int step = 1; step < N * N; step ++) { 58 | for (int t = 0; t < 4; t ++) { 59 | int x1 = x + dx[d], y1 = y + dy[d]; 60 | if (x1 >= 0 && x1 < N && y1 >= 0 && y1 < N && !used[x1][y1]) { 61 | x = x1; y = y1; 62 | used[x][y] = 1; 63 | canvas[x][y] = p(init + step / 2); 64 | break; 65 | } 66 | d = (d + 1) % 4; 67 | } 68 | } 69 | } 70 | 71 | void video_test() { 72 | unsigned long last = 0; 73 | unsigned long fps_last = 0; 74 | int fps = 0; 75 | 76 | while (1) { 77 | unsigned long upt = uptime(); 78 | if (upt - last > 1000 / FPS) { 79 | update(); 80 | redraw(); 81 | last = upt; 82 | fps ++; 83 | } 84 | if (upt - fps_last > 1000) { 85 | // display fps every 1s 86 | printf("%d: FPS = %d\n", upt, fps); 87 | fps_last = upt; 88 | fps = 0; 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /docs/8.26_yuh.md: -------------------------------------------------------------------------------- 1 | ### Chisel-scalar language 2 | 3 | + boot-camp 4 | + 感觉读的时候是一过一忘。 5 | + 可能需要真正写chisel的时候,有个模块实现目标,之后一点点找能用哪些chisel知识。用多了能记住chisel代码的样子吧 6 | + 我把bootcamp中感觉以后能用的总结了一下,算一个细致一些的cheat-sheet吧 7 | + scalar 8 | + 看了一下coursa上面的scalar课程,也是光看一遍记不住 9 | + 印象最深的是val和var的区别。val不能重新赋值而var可以。对val的’重新赋值‘操作大概是把原来的val变量清除掉,创建一个新的。也和chisel中对val变量修改(reg)或定义逻辑(wire)时,除了第一次赋值用=外,都要用:=相关吧。 10 | + 因为看的比较早,还没有总结的习惯。。。[TODO]: 如果需要还是重看一遍总结一下吧 11 | 12 | ### Chisel-scalar framwork 13 | 14 | + github上的chisel-tutorial 15 | + 我看这个是想知道一个chisel模块该怎么验证。 16 | + 这里面是用一个sbt命令行/intellij中直接运行一个模块,貌似是从某个特定的chisel模块继承过来就可以sbt运行?看的比较早,当时没有去弄明白就过去了。[TODO]: 还是要把chisel-scalar自带的验证框架弄明白,把模版、常用函数总结一些。 17 | + sbt 18 | + 由于上面用了sbt命令行,并且文件结构中一些奇怪文件夹。于是看了一下sbt官网上tutorial 19 | + 是有简单的.sbt文件介绍,然而貌似只要用chisel-template中模版就行了?[TODO]: 把sbt模版、使用方法总结一下。 20 | + soder/nutshell 21 | + 参照项目做上面的总结。 22 | 23 | ### veirlator simulator 24 | 25 | + 参照文档和tutorial:C++接口看起来可以很强大的样子 26 | + 看soder中使用:[TODO] 没太看懂是怎么把测试程序二进制加载到memory模块里的。。。貌似调了一个riscv-isa-sim/fesvr中的模块?但我以为riscv-isa-sim是一个类似enmu的东西? 27 | 28 | ### nemu simulator 29 | 30 | + .h文件emmm我好像对他的功能之前就没太搞明白。比如我有一个宏定义,调用者和被调用者都要用。那我如果把宏写到.h里,.c就要include一个自己的.h,我感觉有点奇怪。。。 31 | 32 | + 梳理记录了主要的几个函数调用关系:感觉这很帮助源码阅读 33 | + 调用特定体系结构的decode的时候一种手工实现继承的感觉。。。 34 | + 微指令很炫酷了,BTW是不是虚拟机都是这个样子。[TODO]: 设计可以复用的译码/执行的微指令,并简洁直观的做好文档。 35 | 36 | + 怎么验证nemu写的是对的?[TODO] 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | ## Summary 47 | 48 | 我非常想先把验证框架理解好,具体目标是我可以写一个空的top模块之后一键make,这样就可以快乐地开始写chisel。 49 | 50 | + 大方向是想对比一些netshell和soder/rocket的框架是什么样子,于是看了上面的东西 51 | + TODO在于 52 | + scalar内验证 53 | + 把sbt模版、使用方法总结一下。 54 | + 把chisel-scalar自带的验证框架弄明白,把模版、常用函数总结一些。 55 | + verilator 56 | + C模版 57 | + 怎么加载二进制测试程序 58 | + nemu 59 | + 怎么验证nemu 60 | + 拓展riscv64 61 | + 虽然和项目关系不大,但我还是很想知道soder/rocket框架是什么样的。。。 62 | 63 | 关于指导和合作 64 | 65 | + 我觉得有时候比较难下手的原因是,不确定我想看的内容是不是项目需要的,这是因为我不太清楚 66 | 67 | + 框架 --> 几个模块是怎么组合到一起的 --> 描述不太好,大概是我读nemu,我比较想先明确的一个大方向是,最后的框架中,nemu模块的那个函数会被调用,怎么把trace数据给verilator做对比的。 68 | 69 | 不太清楚这些就感觉,‘诶,好像我把nemu看完了也没啥用’。我不太能权衡这个是自己一点点理解的收获大,还是老师讲一下高效,或者我们分工学习、互相讲能提高合作能力。但就我自己而言,我这两周比较忙、开学之后课也不少,所以就。。。时间精力不太够。。。 70 | 71 | + 我比较期待 72 | 73 | + 分工学习 --> 互相讲解 --> 每个人进度同步 74 | 75 | 的模式。我比较希望能通过这个项目理解大项目的合作模式,具体说,如何权衡每人负责一部分,带来的高效性;以及每个人都理解每部分细节、集思广益地讨论,带来的更好的结果。当然此外,多理解每个细节也是很提高能力的。 76 | 77 | + 我感觉余子豪老师是非常担心我们合作的过程中,没有整体框架的感觉,只关注某个模块中的TODO,遇到一些需要系统修补的地方就依赖别人。但我觉得这还是调整合作模式的问题吧,怎么样能够高效地完成项目又能提高每个人的能力。 -------------------------------------------------------------------------------- /nemu/src/isa/riscv64/intr.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "local-include/csr.h" 4 | #include "local-include/rtl.h" 5 | #include "local-include/intr.h" 6 | 7 | #define INTR_BIT (1ULL << 63) 8 | enum { 9 | IRQ_USIP, IRQ_SSIP, IRQ_HSIP, IRQ_MSIP, 10 | IRQ_UTIP, IRQ_STIP, IRQ_HTIP, IRQ_MTIP, 11 | IRQ_UEIP, IRQ_SEIP, IRQ_HEIP, IRQ_MEIP 12 | }; 13 | 14 | void raise_intr(DecodeExecState *s, word_t NO, vaddr_t epc) { 15 | // TODO: Trigger an interrupt/exception with ``NO'' 16 | 17 | word_t deleg = (NO & INTR_BIT ? mideleg->val : medeleg->val); 18 | bool delegS = ((deleg & (1 << (NO & 0xf))) != 0) && (cpu.mode < MODE_M); 19 | 20 | if (delegS) { 21 | scause->val = NO; 22 | sepc->val = epc; 23 | mstatus->spp = cpu.mode; 24 | mstatus->spie = mstatus->sie; 25 | mstatus->sie = 0; 26 | switch (NO) { 27 | case EX_IPF: case EX_LPF: case EX_SPF: 28 | case EX_LAM: case EX_SAM: 29 | break; 30 | default: stval->val = 0; 31 | } 32 | cpu.mode = MODE_S; 33 | rtl_li(s, s0, stvec->val); 34 | } else { 35 | mcause->val = NO; 36 | mepc->val = epc; 37 | mstatus->mpp = cpu.mode; 38 | mstatus->mpie = mstatus->mie; 39 | mstatus->mie = 0; 40 | switch (NO) { 41 | case EX_IPF: case EX_LPF: case EX_SPF: 42 | case EX_LAM: case EX_SAM: 43 | break; 44 | default: mtval->val = 0; 45 | } 46 | cpu.mode = MODE_M; 47 | rtl_li(s, s0, mtvec->val); 48 | } 49 | 50 | switch (NO) { 51 | case EX_II: 52 | case EX_IPF: 53 | case EX_LPF: 54 | case EX_SPF: difftest_skip_dut(1, 2); break; 55 | } 56 | 57 | rtl_jr(s, s0); 58 | } 59 | 60 | void query_intr(DecodeExecState *s) { 61 | word_t intr_vec = mie->val & mip->val; 62 | if (!intr_vec) return; 63 | 64 | const int priority [] = { 65 | IRQ_MEIP, IRQ_MSIP, IRQ_MTIP, 66 | IRQ_SEIP, IRQ_SSIP, IRQ_STIP, 67 | IRQ_UEIP, IRQ_USIP, IRQ_UTIP 68 | }; 69 | int i; 70 | for (i = 0; i < 9; i ++) { 71 | int irq = priority[i]; 72 | if (intr_vec & (1 << irq)) { 73 | bool deleg = (mideleg->val & (1 << irq)) != 0; 74 | bool global_enable = (deleg ? ((cpu.mode == MODE_S) && mstatus->sie) || (cpu.mode < MODE_S) : 75 | ((cpu.mode == MODE_M) && mstatus->mie) || (cpu.mode < MODE_M)); 76 | if (global_enable) { 77 | raise_intr(s, irq | INTR_BIT, cpu.pc); 78 | update_pc(s); 79 | } 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /docs/9.7_nemu.md: -------------------------------------------------------------------------------- 1 | 9.7 2 | 3 | 4 | 5 | ### AM 6 | 7 | > AM项目分为三大部分: 8 | > 9 | > - `nexus-am/am/` - 不同架构的AM API实现, 目前我们只需要关注`nexus-am/am/src/$ISA/nemu/`以及相应的头文件即可 10 | > - `nexus-am/tests/`和`nexus-am/apps/` - 一些功能测试和直接运行在AM上的应用程序 11 | > - `nexus-am/libs/` - 一些架构无关的函数库, 方便应用程序的开发 12 | 13 | 14 | 15 | > `nexus-am/am/src/nemu-common/trm.c`中的代码, 你会发现只需要实现很少的API就可以支撑起程序在TRM上运行了: 16 | > 17 | > - `_Area _heap`结构用于指示堆区的起始和末尾 18 | > - `void _putc(char ch)`用于输出一个字符 19 | > - `void _halt(int code)`用于结束程序的运行 20 | > - `void _trm_init()`用于进行TRM相关的初始化工作 21 | 22 | ```c 23 | _Area _heap = { 24 | .start = &_heap_start, 25 | .end = &_heap_end, 26 | }; 27 | 28 | void _putc(char ch) { 29 | outb(SERIAL_PORT, ch); 30 | } 31 | 32 | void _halt(int code) { 33 | nemu_trap(code); 34 | 35 | // should not reach here 36 | while (1); 37 | } 38 | 39 | void _trm_init() { 40 | extern const char _start; 41 | const char *mainargs = &_start - 0x100000; 42 | int ret = main(mainargs); 43 | _halt(ret); 44 | } 45 | ``` 46 | 47 | > 编译得到的可执行文件的行为进行简单的梳理: 48 | > 49 | > 1. 第一条指令从`nexus-am/am/src/$ISA/nemu/boot/start.S`开始, 设置好栈顶之后就跳转到`nexus-am/am/src/nemu-common/trm.c`的`_trm_init()`函数处执行. 50 | > 2. 在`_trm_init()`中调用`main()`函数执行程序的主体功能, `main()`函数还带一个参数, 目前我们暂时不会用到, 后面我们再介绍它. 51 | > 3. 从`main()`函数返回后, 调用`_halt()`结束运行. 52 | 53 | 54 | 55 | > 有一个特殊的架构叫`native`, 是用GNU/Linux默认的运行时环境来实现的AM API. 例如我们通过`gcc hello.c`编译程序时, 就会编译到GNU/Linux提供的运行时环境; 你在PA1试玩的超级玛丽, 也是编译到`native`上并运行. 和`$ISA-nemu`相比, `native`有如下好处: 56 | > 57 | > - 直接运行在真机上, 可以相信真机的行为永远是对的 58 | > - 就算软件有bug, 在`native`上调试也比较方便(例如可以使用GDB, 比NEMU的monitor方便很多) 59 | 60 | ```c 61 | make ALL=string ARCH=native run // 更换到native上进行调试 62 | ``` 63 | 64 | 65 | 66 | > 通常来说, 进行DiffTest需要提供一个和DUT(Design Under Test, 测试对象) 功能相同但实现方式不同的REF(Reference, 参考实现), 然后让它们接受相同的输入, 观测它们的行为是否相同.( 例如在真正机器上运行这些指令) 67 | > 68 | > "计算机的状态"就恰恰是那些时序逻辑部件的状态, 也就是寄存器和内存的值. 检测这些值是否相同即可 69 | > 70 | >  我们让NEMU和QEMU逐条指令地执行同一个客户程序. 双方每执行完一条指令, 就检查各自的寄存器和内存的状态, 如果发现状态不一致, 就马上报告错误, 停止客户程序的执行. 71 | 72 | 73 | 74 | > 实现DiffTest, 我们在DUT和REF之间定义了如下的一组API: 75 | > 76 | > ``` 77 | > // 从DUT host memory的`src`处拷贝`n`字节到REF guest memory的`dest`处 78 | > void difftest_memcpy_from_dut(paddr_t dest, void *src, size_t n); 79 | > // 获取REF的寄存器状态到`r` 80 | > void difftest_getregs(void *r); 81 | > // 设置REF的寄存器状态为`r` 82 | > void difftest_setregs(const void *r); 83 | > // 让REF执行`n`条指令 84 | > void difftest_exec(uint64_t n); 85 | > // 初始化REF的DiffTest功能 86 | > void difftest_init(); 87 | > ``` 88 | > 89 | > -------------------------------------------------------------------------------- /nemu/src/device/serial.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /* http://en.wikibooks.org/wiki/Serial_Programming/8250_UART_Programming */ 4 | // NOTE: this is compatible to 16550 5 | 6 | #define SERIAL_PORT 0x3F8 7 | #define SERIAL_MMIO 0xa10003F8 8 | 9 | #define CH_OFFSET 0 10 | #define LSR_OFFSET 5 11 | #define LSR_TX_READY 0x20 12 | #define LSR_RX_READY 0x01 13 | 14 | #define QUEUE_SIZE 1024 15 | static char queue[QUEUE_SIZE] = {}; 16 | static int f = 0, r = 0; 17 | 18 | static uint8_t *serial_base = NULL; 19 | 20 | static void serial_enqueue(char ch) { 21 | int next = (r + 1) % QUEUE_SIZE; 22 | if (next != f) { 23 | // not full 24 | queue[r] = ch; 25 | r = next; 26 | } 27 | } 28 | 29 | static char serial_dequeue() { 30 | char ch = 0xff; 31 | 32 | extern uint32_t uptime(); 33 | static uint32_t last = 0; 34 | uint32_t now = uptime(); 35 | if (now > last) { 36 | Log("now = %d", now); 37 | last = now; 38 | } 39 | // 90s after starting 40 | if (now > 90) { 41 | if (f != r) { 42 | ch = queue[f]; 43 | f = (f + 1) % QUEUE_SIZE; 44 | } 45 | } 46 | return ch; 47 | } 48 | 49 | static inline uint8_t serial_rx_ready_flag(void) { 50 | return (f == r ? 0 : LSR_RX_READY); 51 | } 52 | 53 | static void serial_io_handler(uint32_t offset, int len, bool is_write) { 54 | assert(len == 1); 55 | switch (offset) { 56 | /* We bind the serial port with the host stdout in NEMU. */ 57 | case CH_OFFSET: 58 | if (is_write) putc(serial_base[0], stderr); 59 | else serial_base[0] = serial_dequeue(); 60 | break; 61 | case LSR_OFFSET: 62 | if (!is_write) serial_base[5] = LSR_TX_READY | serial_rx_ready_flag(); 63 | break; 64 | } 65 | } 66 | 67 | #define rt_thread_cmd "memtrace\n" 68 | #define busybox_cmd "ls\n" \ 69 | "cd /root\n" \ 70 | "echo hello2\n" \ 71 | "cd /root/benchmark\n" \ 72 | "./stream\n" \ 73 | "echo hello3\n" \ 74 | "cd /root/redis\n" \ 75 | "ls\n" \ 76 | "ifconfig -a\n" \ 77 | "ls\n" \ 78 | "./redis-server\n" \ 79 | 80 | #define debian_cmd "root\n" \ 81 | 82 | static void preset_input() { 83 | char buf[] = debian_cmd; 84 | int i; 85 | for (i = 0; i < strlen(buf); i ++) { 86 | serial_enqueue(buf[i]); 87 | } 88 | } 89 | 90 | void init_serial() { 91 | serial_base = new_space(8); 92 | add_pio_map("serial", SERIAL_PORT, serial_base, 8, serial_io_handler); 93 | add_mmio_map("serial", SERIAL_MMIO, serial_base, 8, serial_io_handler); 94 | 95 | preset_input(); 96 | } 97 | -------------------------------------------------------------------------------- /nemu/include/isa/riscv64.h: -------------------------------------------------------------------------------- 1 | #ifndef __ISA_RISCV64_H__ 2 | #define __ISA_RISCV64_H__ 3 | 4 | #include 5 | 6 | // memory 7 | #ifdef __ENGINE_rv64__ 8 | #define riscv64_IMAGE_START 0x100000 9 | #else 10 | #define riscv64_IMAGE_START 0x0 11 | #endif 12 | #define riscv64_PMEM_BASE 0x80000000 13 | 14 | // reg 15 | 16 | typedef struct { 17 | union { 18 | uint64_t _64; 19 | } gpr[32]; 20 | 21 | uint64_t pc; 22 | uint64_t mstatus, mcause, mepc; 23 | uint64_t sstatus, scause, sepc; 24 | 25 | uint8_t mode; 26 | 27 | bool amo; 28 | int mem_exception; 29 | 30 | // for LR/SC 31 | uint64_t lr_addr; 32 | 33 | bool INTR; 34 | } riscv64_CPU_state; 35 | 36 | // decode 37 | typedef struct { 38 | union { 39 | struct { 40 | uint32_t opcode1_0 : 2; 41 | uint32_t opcode6_2 : 5; 42 | uint32_t rd : 5; 43 | uint32_t funct3 : 3; 44 | uint32_t rs1 : 5; 45 | uint32_t rs2 : 5; 46 | uint32_t funct7 : 7; 47 | } r; 48 | struct { 49 | uint32_t opcode1_0 : 2; 50 | uint32_t opcode6_2 : 5; 51 | uint32_t rd : 5; 52 | uint32_t funct3 : 3; 53 | uint32_t rs1 : 5; 54 | int32_t simm11_0 :12; 55 | } i; 56 | struct { 57 | uint32_t opcode1_0 : 2; 58 | uint32_t opcode6_2 : 5; 59 | uint32_t imm4_0 : 5; 60 | uint32_t funct3 : 3; 61 | uint32_t rs1 : 5; 62 | uint32_t rs2 : 5; 63 | int32_t simm11_5 : 7; 64 | } s; 65 | struct { 66 | uint32_t opcode1_0 : 2; 67 | uint32_t opcode6_2 : 5; 68 | uint32_t imm11 : 1; 69 | uint32_t imm4_1 : 4; 70 | uint32_t funct3 : 3; 71 | uint32_t rs1 : 5; 72 | uint32_t rs2 : 5; 73 | uint32_t imm10_5 : 6; 74 | int32_t simm12 : 1; 75 | } b; 76 | struct { 77 | uint32_t opcode1_0 : 2; 78 | uint32_t opcode6_2 : 5; 79 | uint32_t rd : 5; 80 | int32_t simm31_12 :20; 81 | } u; 82 | struct { 83 | uint32_t opcode1_0 : 2; 84 | uint32_t opcode6_2 : 5; 85 | uint32_t rd : 5; 86 | uint32_t imm19_12 : 8; 87 | uint32_t imm11 : 1; 88 | uint32_t imm10_1 :10; 89 | int32_t simm20 : 1; 90 | } j; 91 | struct { 92 | uint32_t pad7 :20; 93 | uint32_t csr :12; 94 | } csr; 95 | uint32_t val; 96 | } instr; 97 | } riscv64_ISADecodeInfo; 98 | 99 | #define riscv64_has_mem_exception() (cpu.mem_exception != 0) 100 | 101 | #endif 102 | -------------------------------------------------------------------------------- /nexus-am/tests/amtest/src/tests/vm.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | static _Context *uctx; 4 | static _AddressSpace prot; 5 | static uintptr_t st = 0; 6 | static int first_trap = 1; 7 | 8 | void *simple_pgalloc(size_t size) { 9 | if (st == 0) { st = (uintptr_t)_heap.start; } 10 | while (st % size != 0) st++; 11 | void *ret = (void *)st; 12 | st += size; 13 | return ret; 14 | } 15 | 16 | void simple_pgfree(void *ptr) { 17 | } 18 | 19 | _Context* vm_handler(_Event ev, _Context *ctx) { 20 | switch (ev.event) { 21 | case _EVENT_YIELD: 22 | break; 23 | case _EVENT_IRQ_TIMER: 24 | case _EVENT_IRQ_IODEV: 25 | printf("==== interrupt (%s) ====\n", ev.msg); 26 | break; 27 | case _EVENT_PAGEFAULT: 28 | printf("PF: %x %s%s%s\n", 29 | ev.ref, 30 | (ev.cause & _PROT_NONE) ? "[not present]" : "", 31 | (ev.cause & _PROT_READ) ? "[read fail]" : "", 32 | (ev.cause & _PROT_WRITE) ? "[write fail]" : ""); 33 | break; 34 | case _EVENT_SYSCALL: 35 | _intr_write(1); 36 | for (int volatile i = 0; i < 1000000; i++) ; 37 | printf("%d ", ctx->GPRx); 38 | break; 39 | default: 40 | assert(0); 41 | } 42 | if (first_trap) { 43 | first_trap = 0; 44 | return uctx; 45 | } else { 46 | return ctx; 47 | } 48 | } 49 | 50 | uint8_t code[] = { 51 | #ifdef __ARCH_NATIVE 52 | 0x31, 0xc0, // xor %eax, %eax 53 | 0x83, 0xc0, 0x01, // add $1, %eax 54 | 0xff, 0x14, 0x25, 0x00, 0x00, 0x10, 0x00, // call *0x100000 55 | 0xeb, 0xf4, // jmp 2 56 | #else 57 | 0x31, 0xc0, // xor %eax, %eax 58 | 0x8d, 0xb6, // lea 0(%esi), %esi 59 | 0x00, 0x00, 0x00, 0x00, 60 | 0x83, 0xc0, 0x01, // add $1, %eax 61 | 0xcd, 0x80, // int $0x80 62 | 0xeb, 0xf9, // jmp 8 63 | #endif 64 | 65 | }; 66 | 67 | void vm_test() { 68 | if (!strncmp(__ISA__, "x86", 3) == 0 && 69 | !strcmp(__ISA__, "native") == 0) { 70 | printf("Not supported architecture.\n"); 71 | return; 72 | } 73 | _protect(&prot); 74 | printf("Protected address space: [%p, %p)\n", prot.area.start, prot.area.end); 75 | 76 | uint8_t *ptr = (void*)((uintptr_t)(prot.area.start) + 77 | ((uintptr_t)(prot.area.end) - (uintptr_t)(prot.area.start)) / 2); 78 | 79 | void *pg = simple_pgalloc(prot.pgsize); 80 | memcpy(pg, code, sizeof(code)); 81 | 82 | _map(&prot, ptr, pg, _PROT_WRITE | _PROT_READ | _PROT_EXEC); 83 | printf("Code copied to %p (physical %p) execute\n", ptr, pg); 84 | 85 | static uint8_t stack[4096]; 86 | uctx = _ucontext(&prot, RANGE(stack, stack + sizeof(stack)), ptr); 87 | 88 | _intr_write(1); 89 | _yield(); 90 | } 91 | -------------------------------------------------------------------------------- /nemu/src/engine/interpreter/c_op.h: -------------------------------------------------------------------------------- 1 | #ifndef __C_OP_H__ 2 | #define __C_OP_H__ 3 | 4 | #include 5 | 6 | #ifdef ISA64 7 | #define c_shift_mask 0x3f 8 | #else 9 | #define c_shift_mask 0x1f 10 | #endif 11 | 12 | #define c_add(a, b) ((a) + (b)) 13 | #define c_sub(a, b) ((a) - (b)) 14 | #define c_and(a, b) ((a) & (b)) 15 | #define c_or(a, b) ((a) | (b)) 16 | #define c_xor(a, b) ((a) ^ (b)) 17 | #define c_shl(a, b) ((a) << ((b) & c_shift_mask)) 18 | #define c_shr(a, b) ((a) >> ((b) & c_shift_mask)) 19 | #define c_sar(a, b) ((sword_t)(a) >> ((b) & c_shift_mask)) 20 | 21 | #ifdef ISA64 22 | #define c_sext32to64(a) ((int64_t)(int32_t)(a)) 23 | #define c_addw(a, b) c_sext32to64((a) + (b)) 24 | #define c_subw(a, b) c_sext32to64((a) - (b)) 25 | #define c_shlw(a, b) c_sext32to64((uint32_t)(a) << ((b) & 0x1f)) 26 | #define c_shrw(a, b) c_sext32to64((uint32_t)(a) >> ((b) & 0x1f)) 27 | #define c_sarw(a, b) c_sext32to64(( int32_t)(a) >> ((b) & 0x1f)) 28 | #endif 29 | 30 | #define c_mul_lo(a, b) ((a) * (b)) 31 | #define c_imul_lo(a, b) ((sword_t)(a) * (sword_t)(b)) 32 | #ifdef ISA64 33 | # define c_mul_hi(a, b) (((__uint128_t)(a) * (__uint128_t)(b)) >> 64) 34 | # define c_imul_hi(a, b) (((__int128_t)(sword_t)(a) * (__int128_t)(sword_t)(b)) >> 64) 35 | # define c_mulw(a, b) c_sext32to64((a) * (b)) 36 | # define c_divw(a, b) c_sext32to64(( int32_t)(a) / ( int32_t)(b)) 37 | # define c_divuw(a, b) c_sext32to64((uint32_t)(a) / (uint32_t)(b)) 38 | # define c_remw(a, b) c_sext32to64(( int32_t)(a) % ( int32_t)(b)) 39 | # define c_remuw(a, b) c_sext32to64((uint32_t)(a) % (uint32_t)(b)) 40 | #else 41 | # define c_mul_hi(a, b) (((uint64_t)(a) * (uint64_t)(b)) >> 32) 42 | # define c_imul_hi(a, b) (((int64_t)(sword_t)(a) * (int64_t)(sword_t)(b)) >> 32) 43 | #endif 44 | 45 | #define c_div_q(a, b) ((a) / (b)) 46 | #define c_div_r(a, b) ((a) % (b)) 47 | #define c_idiv_q(a, b) ((sword_t)(a) / (sword_t)(b)) 48 | #define c_idiv_r(a, b) ((sword_t)(a) % (sword_t)(b)) 49 | 50 | static inline bool interpret_relop(uint32_t relop, const rtlreg_t src1, const rtlreg_t src2) { 51 | switch (relop) { 52 | case RELOP_FALSE: return false; 53 | case RELOP_TRUE: return true; 54 | case RELOP_EQ: return src1 == src2; 55 | case RELOP_NE: return src1 != src2; 56 | case RELOP_LT: return (sword_t)src1 < (sword_t)src2; 57 | case RELOP_LE: return (sword_t)src1 <= (sword_t)src2; 58 | case RELOP_GT: return (sword_t)src1 > (sword_t)src2; 59 | case RELOP_GE: return (sword_t)src1 >= (sword_t)src2; 60 | case RELOP_LTU: return src1 < src2; 61 | case RELOP_LEU: return src1 <= src2; 62 | case RELOP_GTU: return src1 > src2; 63 | case RELOP_GEU: return src1 >= src2; 64 | default: panic("unsupport relop = %d", relop); 65 | } 66 | } 67 | 68 | #endif 69 | -------------------------------------------------------------------------------- /docs/9.23.md: -------------------------------------------------------------------------------- 1 | #### 今日计划 2 | 3 | 1. 使用doxygen来管理自己代码, 多写注释 4 | 2. 完成五级流水线, 能跑lui指令 5 | 3. 生成波形来方便debug 6 | 7 | 8 | 9 | #### doxygen 10 | 11 | 参考 12 | 13 | ```c 14 | // 文件的开头必须有文件注释,否则该文件不会被识别: 15 | /*! \file math.h */ 16 | 17 | // 这几种能识别 18 | /** 19 | * ... text ... 20 | */ 21 | 22 | /*! 23 | * ... text ... 24 | */ 25 | 26 | /// 27 | /// ... text ... 28 | /// 29 | 30 | //! 31 | //!... text ... 32 | //! 33 | ``` 34 | 35 | ```c++ 36 | 一个简单例子 37 | //! A test class. 38 | /*! 39 | A more elaborate class description. 40 | */ 41 | 42 | class QTstyle_Test 43 | { 44 | public: 45 | 46 | //! An enum. 47 | /*! More detailed enum description. */ 48 | enum TEnum { 49 | TVal1, /*!< Enum value TVal1. */ < 是对前面变量的说明 50 | TVal2, /*!< Enum value TVal2. */ 51 | TVal3 /*!< Enum value TVal3. */ 52 | } 53 | //! Enum pointer. 54 | /*! Details. */ 55 | *enumPtr, 56 | //! Enum variable. 57 | /*! Details. */ 58 | enumVar; 59 | 60 | //! A constructor. 61 | /*! 62 | A more elaborate description of the constructor. 63 | */ 64 | QTstyle_Test(); 65 | 66 | //! A destructor. 67 | /*! 68 | A more elaborate description of the destructor. 69 | */ 70 | ~QTstyle_Test(); 71 | 72 | //! A normal member taking two arguments and returning an integer value. 73 | /*! 74 | \param a an integer argument. \param 表示参数 \todo表示下次做 75 | \param s a constant character pointer. 76 | \return The test results 77 | \sa QTstyle_Test(), ~QTstyle_Test(), testMeToo() and publicVar() 78 | */ 79 | int testMe(int a,const char *s); 80 | 81 | //! A pure virtual member. 82 | /*! 83 | \sa testMe() 84 | \param c1 the first argument. 85 | \param c2 the second argument. 86 | */ 87 | virtual void testMeToo(char c1,char c2) = 0; 88 | 89 | //! A public variable. 90 | /*! 91 | Details. 92 | */ 93 | int publicVar; 94 | 95 | //! A function variable. 96 | /*! 97 | Details. 98 | */ 99 | int (*handler)(int a,int b); 100 | }; 101 | 102 | ``` 103 | 104 | 块注释建议统一使用 105 | 106 | **/\**** 107 | 108 | …… 109 | 110 | ***/** 111 | 112 | 行注释建议统一使用 113 | 114 | **///< …** 115 | 116 | **/\** …… */ 117 | 118 | 119 | 120 | 当前几个问题: 121 | 122 | 1. 写好doxygen 123 | 2. 如何生成波形, 还没弄好 124 | 3. 对于流水线不同级别, 使用decoupled来默认ready, 替代allowin, ready_to_go这些 125 | 4. 如何利用am来加载程序到ram中, 来跑不同的测试程序 126 | 5. 对于数据读写, 要实现同步读, 在c++中收到请求后, 先step, 再返回数据 127 | 6. 对于流水线的验证, 可能需要输出valid信号, 来保证本条指令成功执行, 然后和nemu进行对比. -------------------------------------------------------------------------------- /nexus-am/am/am.h: -------------------------------------------------------------------------------- 1 | /* 2 | * The Nexus Abstract Machine Architecture (AM) 3 | * A portable abstraction of a bare-metal computer 4 | */ 5 | 6 | #ifndef __AM_H__ 7 | #define __AM_H__ 8 | 9 | #include 10 | #include 11 | #include ARCH_H // "arch/x86-qemu.h", "arch/native.h", ... 12 | 13 | #ifdef __cplusplus 14 | extern "C" { 15 | #endif 16 | 17 | // ===================== Constants and Structs ======================= 18 | 19 | enum { 20 | _EVENT_NULL = 0, 21 | _EVENT_ERROR, 22 | _EVENT_IRQ_TIMER, 23 | _EVENT_IRQ_IODEV, 24 | _EVENT_PAGEFAULT, 25 | _EVENT_SYSCALL, 26 | _EVENT_YIELD, 27 | }; 28 | 29 | enum { 30 | _PROT_NONE = 0x1, // no access 31 | _PROT_READ = 0x2, // can read 32 | _PROT_WRITE = 0x4, // can write 33 | _PROT_EXEC = 0x8, // can execute 34 | }; 35 | 36 | // Memory area for [@start, @end) 37 | typedef struct _Area { 38 | void *start, *end; 39 | } _Area; 40 | 41 | // An event of type @event, caused by @cause of pointer @ref 42 | typedef struct _Event { 43 | int event; 44 | uintptr_t cause, ref; 45 | const char *msg; 46 | } _Event; 47 | 48 | // Arch-dependent processor context 49 | typedef struct _Context _Context; 50 | 51 | // A protected address space with user memory @area 52 | // and arch-dependent @ptr 53 | typedef struct _AddressSpace { 54 | size_t pgsize; 55 | _Area area; 56 | void *ptr; 57 | } _AddressSpace; 58 | 59 | // ====================== Turing Machine (TRM) ======================= 60 | 61 | extern _Area _heap; 62 | void _putc(char ch); 63 | void _halt(int code) __attribute__((__noreturn__)); 64 | 65 | // ======================= I/O Extension (IOE) ======================= 66 | 67 | int _ioe_init(); 68 | size_t _io_read (uint32_t dev, uintptr_t reg, void *buf, size_t size); 69 | size_t _io_write(uint32_t dev, uintptr_t reg, void *buf, size_t size); 70 | 71 | // ====================== Context Extension (CTE) ==================== 72 | 73 | int _cte_init(_Context *(*handler)(_Event ev, _Context *ctx)); 74 | void _yield(); 75 | int _intr_read(); 76 | void _intr_write(int enable); 77 | _Context* _kcontext(_Area kstack, void (*entry)(void *), void *arg); 78 | 79 | // ================= Virtual Memory Extension (VME) ================== 80 | 81 | int _vme_init(void *(*pgalloc)(size_t size), void (*pgfree)(void *)); 82 | void _protect(_AddressSpace *as); 83 | void _unprotect(_AddressSpace *as); 84 | void _map(_AddressSpace *as, void *va, void *pa, int prot); 85 | _Context *_ucontext(_AddressSpace *as, _Area kstack, void *entry); 86 | 87 | // ================= Multi-Processor Extension (MPE) ================= 88 | 89 | int _mpe_init(void (*entry)()); 90 | int _ncpu(); 91 | int _cpu(); 92 | intptr_t _atomic_xchg(volatile intptr_t *addr, intptr_t newval); 93 | 94 | #ifdef __cplusplus 95 | } 96 | #endif 97 | 98 | #endif 99 | -------------------------------------------------------------------------------- /nexus-am/libs/klib/include/klib.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Static runtime library for a system software on AbstractMachine 3 | */ 4 | 5 | #ifndef __KLIB_H__ 6 | #define __KLIB_H__ 7 | 8 | #include 9 | #include 10 | 11 | //#define __NATIVE_USE_KLIB__ 12 | 13 | #ifdef __NATIVE_USE_KLIB__ 14 | #define strlen my_strlen 15 | #define strcpy my_strcpy 16 | #define strncpy my_strncpy 17 | #define strcat my_strcat 18 | #define strcmp my_strcmp 19 | #define strncmp my_strncmp 20 | #define memset my_memset 21 | #define memcpy my_memcpy 22 | #define memcmp my_memcmp 23 | #define printf my_printf 24 | #define vsprintf my_vsprintf 25 | #define sprintf my_sprintf 26 | #define snprintf my_snprintf 27 | #define malloc my_malloc 28 | #define free my_free 29 | #endif 30 | 31 | #ifdef __cplusplus 32 | extern "C" { 33 | #endif 34 | 35 | // am devices 36 | 37 | uint32_t uptime(); 38 | void get_timeofday(void *rtc); 39 | int read_key(); 40 | void draw_rect(uint32_t *pixels, int x, int y, int w, int h); 41 | void draw_sync(); 42 | int screen_width(); 43 | int screen_height(); 44 | 45 | // string.h 46 | void *memset(void* v, int c, size_t n); 47 | void *memcpy(void* dst, const void* src, size_t n); 48 | void *memmove(void* dst, const void* src, size_t n); 49 | int memcmp(const void* s1, const void* s2, size_t n); 50 | size_t strlen(const char* s); 51 | char *strcat(char* dst, const char* src); 52 | char *strcpy(char* dst, const char* src); 53 | char *strncpy(char* dst, const char* src, size_t n); 54 | int strcmp(const char* s1, const char* s2); 55 | int strncmp(const char* s1, const char* s2, size_t n); 56 | char *strtok(char* s,const char* delim); 57 | char *strstr(const char *, const char *); 58 | char *strchr(const char *s, int c); 59 | char *strrchr(const char *s, int c); 60 | 61 | // stdlib.h 62 | int atoi(const char* nptr); 63 | int abs(int x); 64 | unsigned long time(); 65 | void srand(unsigned int seed); 66 | int rand(); 67 | void *malloc(size_t size); 68 | void free(void *ptr); 69 | 70 | // stdio.h 71 | int printf(const char* fmt, ...); 72 | int sprintf(char* out, const char* format, ...); 73 | int snprintf(char* s, size_t n, const char* format, ...); 74 | int vsprintf(char *str, const char *format, va_list ap); 75 | int vsnprintf(char *str, size_t size, const char *format, va_list ap); 76 | int sscanf(const char *str, const char *format, ...); 77 | 78 | void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *)); 79 | 80 | // assert.h 81 | #ifdef NDEBUG 82 | #define assert(ignore) ((void)0) 83 | #else 84 | #define assert(cond) \ 85 | do { \ 86 | if (!(cond)) { \ 87 | printf("Assertion fail at %s:%d\n", __FILE__, __LINE__); \ 88 | _halt(1); \ 89 | } \ 90 | } while (0) 91 | #endif 92 | 93 | #ifdef __cplusplus 94 | } 95 | #endif 96 | 97 | #endif 98 | -------------------------------------------------------------------------------- /nemu/src/monitor/debug/ui.c: -------------------------------------------------------------------------------- 1 | #include "expr.h" 2 | #include "watchpoint.h" 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | void cpu_exec(uint64_t); 9 | int is_batch_mode(); 10 | 11 | /* We use the `readline' library to provide more flexibility to read from stdin. */ 12 | static char* rl_gets() { 13 | static char *line_read = NULL; 14 | 15 | if (line_read) { 16 | free(line_read); 17 | line_read = NULL; 18 | } 19 | 20 | line_read = readline("(nemu) "); 21 | 22 | if (line_read && *line_read) { 23 | add_history(line_read); 24 | } 25 | 26 | return line_read; 27 | } 28 | 29 | static int cmd_c(char *args) { 30 | cpu_exec(-1); 31 | return 0; 32 | } 33 | 34 | static int cmd_q(char *args) { 35 | return -1; 36 | } 37 | 38 | static int cmd_help(char *args); 39 | 40 | static struct { 41 | char *name; 42 | char *description; 43 | int (*handler) (char *); 44 | } cmd_table [] = { 45 | { "help", "Display informations about all supported commands", cmd_help }, 46 | { "c", "Continue the execution of the program", cmd_c }, 47 | { "q", "Exit NEMU", cmd_q }, 48 | 49 | /* TODO: Add more commands */ 50 | 51 | }; 52 | 53 | #define NR_CMD (sizeof(cmd_table) / sizeof(cmd_table[0])) 54 | 55 | static int cmd_help(char *args) { 56 | /* extract the first argument */ 57 | char *arg = strtok(NULL, " "); 58 | int i; 59 | 60 | if (arg == NULL) { 61 | /* no argument given */ 62 | for (i = 0; i < NR_CMD; i ++) { 63 | printf("%s - %s\n", cmd_table[i].name, cmd_table[i].description); 64 | } 65 | } 66 | else { 67 | for (i = 0; i < NR_CMD; i ++) { 68 | if (strcmp(arg, cmd_table[i].name) == 0) { 69 | printf("%s - %s\n", cmd_table[i].name, cmd_table[i].description); 70 | return 0; 71 | } 72 | } 73 | printf("Unknown command '%s'\n", arg); 74 | } 75 | return 0; 76 | } 77 | 78 | void ui_mainloop() { 79 | if (is_batch_mode()) { 80 | cmd_c(NULL); 81 | return; 82 | } 83 | 84 | for (char *str; (str = rl_gets()) != NULL; ) { 85 | char *str_end = str + strlen(str); 86 | 87 | /* extract the first token as the command */ 88 | char *cmd = strtok(str, " "); 89 | if (cmd == NULL) { continue; } 90 | 91 | /* treat the remaining string as the arguments, 92 | * which may need further parsing 93 | */ 94 | char *args = cmd + strlen(cmd) + 1; 95 | if (args >= str_end) { 96 | args = NULL; 97 | } 98 | 99 | #ifdef HAS_IOE 100 | extern void sdl_clear_event_queue(void); 101 | sdl_clear_event_queue(); 102 | #endif 103 | 104 | int i; 105 | for (i = 0; i < NR_CMD; i ++) { 106 | if (strcmp(cmd, cmd_table[i].name) == 0) { 107 | if (cmd_table[i].handler(args) < 0) { return; } 108 | break; 109 | } 110 | } 111 | 112 | if (i == NR_CMD) { printf("Unknown command '%s'\n", cmd); } 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /nemu/src/monitor/debug/expr.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /* We use the POSIX regex functions to process regular expressions. 4 | * Type 'man regex' for more information about POSIX regex functions. 5 | */ 6 | #include 7 | #include 8 | 9 | enum { 10 | TK_NOTYPE = 256, TK_EQ 11 | 12 | /* TODO: Add more token types */ 13 | 14 | }; 15 | 16 | static struct rule { 17 | char *regex; 18 | int token_type; 19 | } rules[] = { 20 | 21 | /* TODO: Add more rules. 22 | * Pay attention to the precedence level of different rules. 23 | */ 24 | 25 | {" +", TK_NOTYPE}, // spaces 26 | {"\\+", '+'}, // plus 27 | {"==", TK_EQ} // equal 28 | }; 29 | 30 | #define NR_REGEX (sizeof(rules) / sizeof(rules[0]) ) 31 | 32 | static regex_t re[NR_REGEX] = {}; 33 | 34 | /* Rules are used for many times. 35 | * Therefore we compile them only once before any usage. 36 | */ 37 | void init_regex() { 38 | int i; 39 | char error_msg[128]; 40 | int ret; 41 | 42 | for (i = 0; i < NR_REGEX; i ++) { 43 | ret = regcomp(&re[i], rules[i].regex, REG_EXTENDED); 44 | if (ret != 0) { 45 | regerror(ret, &re[i], error_msg, 128); 46 | panic("regex compilation failed: %s\n%s", error_msg, rules[i].regex); 47 | } 48 | } 49 | } 50 | 51 | typedef struct token { 52 | int type; 53 | char str[32]; 54 | } Token; 55 | 56 | static Token tokens[32] __attribute__((used)) = {}; 57 | static int nr_token __attribute__((used)) = 0; 58 | 59 | static bool make_token(char *e) { 60 | int position = 0; 61 | int i; 62 | regmatch_t pmatch; 63 | 64 | nr_token = 0; 65 | 66 | while (e[position] != '\0') { 67 | /* Try all rules one by one. */ 68 | for (i = 0; i < NR_REGEX; i ++) { 69 | if (regexec(&re[i], e + position, 1, &pmatch, 0) == 0 && pmatch.rm_so == 0) { 70 | char *substr_start = e + position; 71 | int substr_len = pmatch.rm_eo; 72 | 73 | Log("match rules[%d] = \"%s\" at position %d with len %d: %.*s", 74 | i, rules[i].regex, position, substr_len, substr_len, substr_start); 75 | position += substr_len; 76 | 77 | /* TODO: Now a new token is recognized with rules[i]. Add codes 78 | * to record the token in the array `tokens'. For certain types 79 | * of tokens, some extra actions should be performed. 80 | */ 81 | 82 | switch (rules[i].token_type) { 83 | default: TODO(); 84 | } 85 | 86 | break; 87 | } 88 | } 89 | 90 | if (i == NR_REGEX) { 91 | printf("no match at position %d\n%s\n%*.s^\n", position, e, position, ""); 92 | return false; 93 | } 94 | } 95 | 96 | return true; 97 | } 98 | 99 | word_t expr(char *e, bool *success) { 100 | if (!make_token(e)) { 101 | *success = false; 102 | return 0; 103 | } 104 | 105 | /* TODO: Insert codes to evaluate the expression. */ 106 | TODO(); 107 | 108 | return 0; 109 | } 110 | -------------------------------------------------------------------------------- /nexus-am/am/amdev.h: -------------------------------------------------------------------------------- 1 | #ifndef __AMDEV_H__ 2 | #define __AMDEV_H__ 3 | 4 | #include 5 | 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif 9 | 10 | // =========================== AM Devices ============================ 11 | 12 | #define _DEV_PERFCNT 0x0000ac01 // AM Virtual Performance Counter 13 | #define _DEV_INPUT 0x0000ac02 // AM Virtual Input Device 14 | #define _DEV_TIMER 0x0000ac03 // AM Virtual Timer 15 | #define _DEV_VIDEO 0x0000ac04 // AM Virtual Video Controller 16 | #define _DEV_SERIAL 0x0000ac05 // AM Virtual Serial 17 | #define _DEV_STORAGE 0x0000ac06 // AM Virtual Persistent Storage 18 | #define _DEV_AUDIO 0x0000ac07 // AM Virtual Audio Controller 19 | #define _DEV_PCICONF 0x00000080 // PCI Configuration Space 20 | 21 | #define _AM_DEVREG(dev, reg, id, ...) \ 22 | enum { _DEVREG_##dev##_##reg = id }; \ 23 | typedef struct { __VA_ARGS__; } __attribute__((packed)) \ 24 | _DEV_##dev##_##reg##_t; 25 | 26 | // ================= Device Register Specifications ================== 27 | 28 | _AM_DEVREG(INPUT, KBD, 1, int keydown, keycode); 29 | _AM_DEVREG(TIMER, UPTIME, 1, uint32_t hi, lo); 30 | _AM_DEVREG(TIMER, DATE, 2, int year, month, day, hour, minute, second); 31 | _AM_DEVREG(VIDEO, INFO, 1, int width, height); 32 | _AM_DEVREG(VIDEO, FBCTRL, 2, int x, y; uint32_t *pixels; int w, h, sync); 33 | _AM_DEVREG(SERIAL, RECV, 1, uint8_t data); 34 | _AM_DEVREG(SERIAL, SEND, 2, uint8_t data); 35 | _AM_DEVREG(SERIAL, STAT, 3, uint8_t data); 36 | _AM_DEVREG(SERIAL, CTRL, 4, uint8_t data); 37 | _AM_DEVREG(STORAGE, INFO, 1, uint32_t blksz, blkcnt); 38 | _AM_DEVREG(STORAGE, RDCTRL, 2, void *buf; uint32_t blkno, blkcnt); 39 | _AM_DEVREG(STORAGE, WRCTRL, 3, void *buf; uint32_t blkno, blkcnt); 40 | _AM_DEVREG(AUDIO, INIT, 1, uint32_t freq, channels, samples, bufsize); 41 | _AM_DEVREG(AUDIO, SBCTRL, 2, uint8_t *stream; int len, wait); 42 | _AM_DEVREG(AUDIO, SBSTAT, 3, int bufsize, count); 43 | #define _DEVREG_PCICONF(bus, slot, func, offset) \ 44 | ((uint32_t)( 1) << 31) | ((uint32_t)( bus) << 16) | \ 45 | ((uint32_t)(slot) << 11) | ((uint32_t)(func) << 8) | (offset) 46 | 47 | // ============================ Key Codes ============================ 48 | 49 | #define _KEYS(_) \ 50 | _(ESCAPE) \ 51 | _(F1) _(F2) _(F3) _(F4) _(F5) _(F6) _(F7) _(F8) _(F9) _(F10) _(F11) _(F12) \ 52 | _(GRAVE) _(1) _(2) _(3) _(4) _(5) _(6) _(7) _(8) _(9) _(0) \ 53 | _(MINUS) _(EQUALS) _(BACKSPACE) \ 54 | _(TAB) _(Q) _(W) _(E) _(R) _(T) _(Y) _(U) _(I) _(O) _(P) \ 55 | _(LEFTBRACKET) _(RIGHTBRACKET) _(BACKSLASH) \ 56 | _(CAPSLOCK) _(A) _(S) _(D) _(F) _(G) _(H) _(J) _(K) _(L) \ 57 | _(SEMICOLON) _(APOSTROPHE) _(RETURN) \ 58 | _(LSHIFT) _(Z) _(X) _(C) _(V) _(B) _(N) _(M) \ 59 | _(COMMA) _(PERIOD) _(SLASH) _(RSHIFT) \ 60 | _(LCTRL) _(APPLICATION) _(LALT) _(SPACE) _(RALT) _(RCTRL) \ 61 | _(UP) _(DOWN) _(LEFT) _(RIGHT) _(INSERT) _(DELETE) \ 62 | _(HOME) _(END) _(PAGEUP) _(PAGEDOWN) 63 | #define _KEY_NAME(k) _KEY_##k, 64 | enum { 65 | _KEY_NONE = 0, 66 | _KEYS(_KEY_NAME) 67 | }; 68 | 69 | #ifdef __cplusplus 70 | } 71 | #endif 72 | 73 | #endif 74 | -------------------------------------------------------------------------------- /nexus-am/tests/amtest/src/tests/devscan.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | static void input_test() { 5 | printf("Input device test skipped.\n"); 6 | } 7 | 8 | static void timer_test() { 9 | _DEV_TIMER_UPTIME_t uptime; 10 | uint32_t t0, t1; 11 | 12 | _io_read(_DEV_TIMER, _DEVREG_TIMER_UPTIME, &uptime, sizeof(uptime)); 13 | t0 = uptime.lo; 14 | 15 | for (int volatile i = 0; i < 10000000; i ++) ; 16 | 17 | _io_read(_DEV_TIMER, _DEVREG_TIMER_UPTIME, &uptime, sizeof(uptime)); 18 | t1 = uptime.lo; 19 | 20 | printf("Loop 10^7 time elapse: %d ms\n", t1 - t0); 21 | } 22 | 23 | static void video_test() { 24 | _DEV_VIDEO_INFO_t info; 25 | _io_read(_DEV_VIDEO, _DEVREG_VIDEO_INFO, &info, sizeof(info)); 26 | printf("Screen size: %d x %d\n", info.width, info.height); 27 | for (int x = 0; x < 100; x++) 28 | for (int y = 0; y < 100; y++) { 29 | _DEV_VIDEO_FBCTRL_t ctl; 30 | uint32_t pixel = 0x006a005f; 31 | ctl.x = info.width / 2 - 50 + x; 32 | ctl.y = info.height / 2 - 50 + y; 33 | ctl.w = ctl.h = 1; 34 | ctl.sync = 1; 35 | ctl.pixels = &pixel; 36 | _io_write(_DEV_VIDEO, _DEVREG_VIDEO_FBCTRL, &ctl, sizeof(ctl)); 37 | } 38 | printf("You should see a purple square on the screen.\n"); 39 | } 40 | 41 | static uint32_t pci_conf_read(uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset) { 42 | uint32_t res; 43 | int nread = _io_read(_DEV_PCICONF, _DEVREG_PCICONF(bus, slot, func, offset), &res, 4); 44 | return (nread == 0) ? 0xffffffff : res; 45 | } 46 | 47 | static void pciconf_test() { 48 | for (int bus = 0; bus < 256; bus ++) 49 | for (int slot = 0; slot < 32; slot ++) { 50 | uint32_t info = pci_conf_read(bus, slot, 0, 0); 51 | uint16_t id = info >> 16, vendor = info & 0xffff; 52 | if (vendor != 0xffff) { 53 | printf("Get device %d:%d, id %x vendor %x", bus, slot, id, vendor); 54 | if (id == 0x100e && vendor == 0x8086) { 55 | printf(" <-- This is an Intel e1000 NIC card!"); 56 | } 57 | printf("\n"); 58 | } 59 | } 60 | } 61 | 62 | static void storage_test() { 63 | #define nbytes 512 64 | static char buf[nbytes]; 65 | _DEV_STORAGE_INFO_t info; 66 | _DEV_STORAGE_RDCTRL_t ctl; 67 | 68 | _io_read(_DEV_STORAGE, _DEVREG_STORAGE_INFO, &info, sizeof(info)); 69 | printf("Storage: %d blocks of %d size. Show first 512 bytes\n", info.blkcnt, info.blksz); 70 | 71 | ctl.buf = buf; 72 | ctl.blkno = 0; 73 | ctl.blkcnt = nbytes / info.blksz; 74 | _io_write(_DEV_STORAGE, _DEVREG_STORAGE_RDCTRL, &ctl, sizeof(ctl)); 75 | 76 | for (uint32_t i = 0; i < nbytes; i += 2) { 77 | printf("%02x%02x ", buf[i] & 0xff, buf[i+1] & 0xff); 78 | if ((i+2) % 32 == 0) printf("\n"); 79 | } 80 | } 81 | 82 | uint32_t devices[] = { 83 | _DEV_INPUT, _DEV_TIMER, _DEV_VIDEO, _DEV_PCICONF, 84 | }; 85 | 86 | void devscan() { 87 | printf("_heap = [%08x, %08x)\n", _heap.start, _heap.end); 88 | input_test(); 89 | timer_test(); 90 | video_test(); 91 | storage_test(); 92 | pciconf_test(); 93 | printf("Test End!\n"); 94 | while (1); 95 | } 96 | -------------------------------------------------------------------------------- /nemu/src/memory/paddr.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | static uint8_t pmem[PMEM_SIZE] PG_ALIGN = {}; 9 | 10 | void* guest_to_host(paddr_t addr) { return &pmem[addr]; } 11 | paddr_t host_to_guest(void *addr) { return (void *)pmem - addr; } 12 | 13 | IOMap* fetch_mmio_map(paddr_t addr); 14 | 15 | void init_mem() { 16 | #ifndef DIFF_TEST 17 | srand(time(0)); 18 | uint32_t *p = (uint32_t *)pmem; 19 | int i; 20 | for (i = 0; i < PMEM_SIZE / sizeof(p[0]); i ++) { 21 | p[i] = rand(); 22 | } 23 | #endif 24 | } 25 | 26 | static inline bool in_pmem(paddr_t addr) { 27 | return (PMEM_BASE <= addr) && (addr <= PMEM_BASE + PMEM_SIZE - 1); 28 | } 29 | 30 | static inline word_t pmem_read(paddr_t addr, int len) { 31 | void *p = &pmem[addr - PMEM_BASE]; 32 | switch (len) { 33 | case 1: return *(uint8_t *)p; 34 | case 2: return *(uint16_t *)p; 35 | case 4: return *(uint32_t *)p; 36 | #ifdef ISA64 37 | case 8: return *(uint64_t *)p; 38 | #endif 39 | default: assert(0); 40 | } 41 | } 42 | 43 | static inline void pmem_write(paddr_t addr, word_t data, int len) { 44 | void *p = &pmem[addr - PMEM_BASE]; 45 | switch (len) { 46 | case 1: *(uint8_t *)p = data; return; 47 | case 2: *(uint16_t *)p = data; return; 48 | case 4: *(uint32_t *)p = data; return; 49 | #ifdef ISA64 50 | case 8: *(uint64_t *)p = data; return; 51 | #endif 52 | default: assert(0); 53 | } 54 | } 55 | 56 | /* Memory accessing interfaces */ 57 | 58 | inline word_t paddr_read(paddr_t addr, int len) { 59 | if (in_pmem(addr)) return pmem_read(addr, len); 60 | else return map_read(addr, len, fetch_mmio_map(addr)); 61 | } 62 | 63 | inline void paddr_write(paddr_t addr, word_t data, int len) { 64 | if (in_pmem(addr)) pmem_write(addr, data, len); 65 | else map_write(addr, data, len, fetch_mmio_map(addr)); 66 | } 67 | 68 | word_t vaddr_mmu_read(vaddr_t addr, int len, int type); 69 | void vaddr_mmu_write(vaddr_t addr, word_t data, int len); 70 | 71 | #define def_vaddr_template(bytes) \ 72 | word_t concat(vaddr_ifetch, bytes) (vaddr_t addr) { \ 73 | int ret = isa_vaddr_check(addr, MEM_TYPE_IFETCH, bytes); \ 74 | if (ret == MEM_RET_OK) return paddr_read(addr, bytes); \ 75 | else if (ret == MEM_RET_NEED_TRANSLATE) return vaddr_mmu_read(addr, bytes, MEM_TYPE_IFETCH); \ 76 | return 0; \ 77 | } \ 78 | word_t concat(vaddr_read, bytes) (vaddr_t addr) { \ 79 | int ret = isa_vaddr_check(addr, MEM_TYPE_READ, bytes); \ 80 | if (ret == MEM_RET_OK) return paddr_read(addr, bytes); \ 81 | else if (ret == MEM_RET_NEED_TRANSLATE) return vaddr_mmu_read(addr, bytes, MEM_TYPE_READ); \ 82 | return 0; \ 83 | } \ 84 | void concat(vaddr_write, bytes) (vaddr_t addr, word_t data) { \ 85 | int ret = isa_vaddr_check(addr, MEM_TYPE_WRITE, bytes); \ 86 | if (ret == MEM_RET_OK) paddr_write(addr, data, bytes); \ 87 | else if (ret == MEM_RET_NEED_TRANSLATE) vaddr_mmu_write(addr, data, bytes); \ 88 | } 89 | 90 | def_vaddr_template(1) 91 | def_vaddr_template(2) 92 | def_vaddr_template(4) 93 | #ifdef ISA64 94 | def_vaddr_template(8) 95 | #endif 96 | -------------------------------------------------------------------------------- /nemu/src/isa/riscv64/logo.c: -------------------------------------------------------------------------------- 1 | // refer to http://www.patorjk.com/software/taag/#p=display&f=Big&t=Type%20Something%20 2 | 3 | /* 4 | _ __ __ _ 5 | (_) | \/ | | | 6 | _ __ _ ___ ___ ________ __ | \ / | __ _ _ __ _ _ __ _| | 7 | | '__| / __|/ __|______\ \ / / | |\/| |/ _` | '_ \| | | |/ _` | | 8 | | | | \__ \ (__ \ V / | | | | (_| | | | | |_| | (_| | | 9 | |_| |_|___/\___| \_/ |_| |_|\__,_|_| |_|\__,_|\__,_|_| 10 | 11 | */ 12 | 13 | unsigned char isa_logo[] = { 14 | 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5f, 0x20, 0x20, 0x20, 0x20, 15 | 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 16 | 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5f, 0x5f, 0x20, 17 | 0x20, 0x5f, 0x5f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 18 | 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 19 | 0x20, 0x20, 0x20, 0x20, 0x5f, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 20 | 0x20, 0x28, 0x5f, 0x29, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 21 | 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 22 | 0x20, 0x20, 0x20, 0x7c, 0x20, 0x20, 0x5c, 0x2f, 0x20, 0x20, 0x7c, 0x20, 23 | 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 24 | 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7c, 0x20, 25 | 0x7c, 0x0a, 0x20, 0x20, 0x5f, 0x20, 0x5f, 0x5f, 0x20, 0x5f, 0x20, 0x5f, 26 | 0x5f, 0x5f, 0x20, 0x20, 0x5f, 0x5f, 0x5f, 0x20, 0x5f, 0x5f, 0x5f, 0x5f, 27 | 0x5f, 0x5f, 0x5f, 0x5f, 0x20, 0x20, 0x20, 0x5f, 0x5f, 0x20, 0x7c, 0x20, 28 | 0x5c, 0x20, 0x20, 0x2f, 0x20, 0x7c, 0x20, 0x5f, 0x5f, 0x20, 0x5f, 0x20, 29 | 0x5f, 0x20, 0x5f, 0x5f, 0x20, 0x20, 0x5f, 0x20, 0x20, 0x20, 0x5f, 0x20, 30 | 0x20, 0x5f, 0x5f, 0x20, 0x5f, 0x7c, 0x20, 0x7c, 0x0a, 0x20, 0x7c, 0x20, 31 | 0x27, 0x5f, 0x5f, 0x7c, 0x20, 0x2f, 0x20, 0x5f, 0x5f, 0x7c, 0x2f, 0x20, 32 | 0x5f, 0x5f, 0x7c, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5c, 0x20, 0x5c, 33 | 0x20, 0x2f, 0x20, 0x2f, 0x20, 0x7c, 0x20, 0x7c, 0x5c, 0x2f, 0x7c, 0x20, 34 | 0x7c, 0x2f, 0x20, 0x5f, 0x60, 0x20, 0x7c, 0x20, 0x27, 0x5f, 0x20, 0x5c, 35 | 0x7c, 0x20, 0x7c, 0x20, 0x7c, 0x20, 0x7c, 0x2f, 0x20, 0x5f, 0x60, 0x20, 36 | 0x7c, 0x20, 0x7c, 0x0a, 0x20, 0x7c, 0x20, 0x7c, 0x20, 0x20, 0x7c, 0x20, 37 | 0x5c, 0x5f, 0x5f, 0x20, 0x5c, 0x20, 0x28, 0x5f, 0x5f, 0x20, 0x20, 0x20, 38 | 0x20, 0x20, 0x20, 0x20, 0x20, 0x5c, 0x20, 0x56, 0x20, 0x2f, 0x20, 0x20, 39 | 0x7c, 0x20, 0x7c, 0x20, 0x20, 0x7c, 0x20, 0x7c, 0x20, 0x28, 0x5f, 0x7c, 40 | 0x20, 0x7c, 0x20, 0x7c, 0x20, 0x7c, 0x20, 0x7c, 0x20, 0x7c, 0x5f, 0x7c, 41 | 0x20, 0x7c, 0x20, 0x28, 0x5f, 0x7c, 0x20, 0x7c, 0x20, 0x7c, 0x0a, 0x20, 42 | 0x7c, 0x5f, 0x7c, 0x20, 0x20, 0x7c, 0x5f, 0x7c, 0x5f, 0x5f, 0x5f, 0x2f, 43 | 0x5c, 0x5f, 0x5f, 0x5f, 0x7c, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 44 | 0x20, 0x5c, 0x5f, 0x2f, 0x20, 0x20, 0x20, 0x7c, 0x5f, 0x7c, 0x20, 0x20, 45 | 0x7c, 0x5f, 0x7c, 0x5c, 0x5f, 0x5f, 0x2c, 0x5f, 0x7c, 0x5f, 0x7c, 0x20, 46 | 0x7c, 0x5f, 0x7c, 0x5c, 0x5f, 0x5f, 0x2c, 0x5f, 0x7c, 0x5c, 0x5f, 0x5f, 47 | 0x2c, 0x5f, 0x7c, 0x5f, 0x7c, 0x0a 48 | }; 49 | -------------------------------------------------------------------------------- /verilator/ram.cpp: -------------------------------------------------------------------------------- 1 | #include "ram.h" 2 | #include 3 | #include 4 | #include 5 | 6 | CRam::CRam(char* imgPath) 7 | { 8 | m_ramSize = RAMSIZE / sizeof(paddr_t); 9 | memset(m_ram, 0, m_ramSize); 10 | /* 11 | #ifdef DEBUG 12 | m_imgSize = 4; 13 | m_ram[0] = 0x800002b7; // lui t0,0x80000 14 | m_ram[1] = 0x800002b7; // lui t0,0x80000 15 | m_ram[2] = 0x0002a023; // sw zero,0(t0) 16 | m_ram[3] = 0x0002a503; // lw a0,0(t0) 17 | 18 | #else 19 | */ 20 | assert(imgPath && "No image file"); 21 | FILE *fp = fopen(imgPath, "rb"); 22 | assert(fp && "Cannot open file"); 23 | 24 | fseek(fp, 0, SEEK_END); 25 | m_imgSize = ftell(fp); 26 | 27 | fseek(fp, 0, SEEK_SET); 28 | int ret = fread(m_ram, m_imgSize, 1, fp); // 把指令数据都读入ram中 29 | assert(ret && "read img failed"); 30 | fclose(fp); 31 | 32 | // #endif 33 | 34 | 35 | 36 | } 37 | 38 | CRam::~CRam() 39 | { 40 | } 41 | 42 | void* CRam::getImgStart() 43 | { 44 | return m_ram; 45 | } 46 | 47 | int CRam::getImgSize() 48 | { 49 | return m_imgSize; 50 | } 51 | 52 | 53 | 54 | iaddr_t CRam::InstRead(paddr_t addr, bool en){ 55 | // printf("inst read addr = 0x%016lx en = %d\n", addr, en); 56 | if(!en) return 0; 57 | assert(ADDRSTART <= addr && 58 | addr <= ADDRSTART + m_ramSize && 59 | "read addr out of range"); 60 | return m_ram[(addr - ADDRSTART) / sizeof(paddr_t)] >> ((addr % sizeof(paddr_t)) * 8); // 读Iram 61 | } 62 | 63 | paddr_t CRam::DataRead(paddr_t addr, bool en){ 64 | #ifdef DEBUG_PRINT 65 | printf("data read addr = 0x%016lx en = %d\n", addr, en); 66 | // paddr_t addr_debug = 0x0000000080000030; 67 | // printf("data[] = 0x%016lx\n", m_ram[(addr_debug - ADDRSTART) / sizeof(paddr_t)]); 68 | #endif 69 | if(!en) return 0; 70 | assert(ADDRSTART <= addr && 71 | addr <= ADDRSTART + m_ramSize && 72 | "read data addr out of range"); 73 | return m_ram[(addr - ADDRSTART) / sizeof(paddr_t)] >> ((addr % sizeof(paddr_t)) * 8); // 读data_ram 74 | // 根据地址后3位选取确定的数据, lw, lb, lh这些需要 75 | // TODO: 应该需要在chisel中实现! 76 | } 77 | 78 | void CRam::DataWrite(paddr_t addr, paddr_t data, bool en, mask_t mask){ 79 | if(!en) return; 80 | assert(ADDRSTART <= addr && 81 | addr <= ADDRSTART + m_ramSize && 82 | "write data addr out of range"); 83 | if (en) { 84 | paddr_t data_mask = data; 85 | paddr_t fullMask = 0; 86 | paddr_t ff = 0xff; // 直接用0xff会导致默认转换成32位的! 一定要注意! 87 | for (size_t i = 0; i < 8; i++) 88 | { 89 | if ((mask >> i) & 0x1) 90 | { 91 | fullMask = fullMask | (ff << (i*8)); 92 | } 93 | } 94 | data_mask = (fullMask & data) | (~fullMask & m_ram[(addr - ADDRSTART) / sizeof(paddr_t)]); 95 | // 如果lb写入8byte, 其他要保持不变 96 | m_ram[(addr - ADDRSTART) / sizeof(paddr_t)] = data_mask; 97 | #ifdef DEBUG_PRINT 98 | printf("mask = %x, fullMask= 0x%016lx, data = 0x%016lx, data_mask = 0x%016lx\n", mask, fullMask, data, data_mask); 99 | #endif 100 | } 101 | } -------------------------------------------------------------------------------- /docs/9.15.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | #### 今日任务 4 | 5 | 1. 使用BoringUtils 来验证regfile 6 | 2. 添加nemu二进制文件来搭建框架 7 | 8 | 9 | 10 | #### BoringUtils 11 | 12 | 1. 13 | 14 | 2. 目的: 生成可遍历层次结构的可综合跨模块引用的实用结构, 由FIRRTL来连接线路 15 | 16 | 3. ```scala 17 | class Constant extends Module { 18 | val io = IO(new Bundle{}) 19 | val x = Wire(UInt(6.W)) 20 | x := 42.U 21 | } 22 | class Expect extends Module { 23 | val io = IO(new Bundle{}) 24 | val y = Wire(UInt(6.W)) 25 | y := 0.U 26 | // This assertion will fail unless we bore! 27 | chisel3.assert(y === 42.U, "y should be 42 in module Expect") 28 | } 29 | ``` 30 | 31 | 4. 可以在不修改IO结构的情况下, 连接x, y 32 | 33 | 1. 分层boring(钻孔)使用BoringUtils.bore 34 | 35 | ```scala 36 | // 在父模块实例化两个, 连接x,y 37 | class Top extends Module { 38 | val io = IO(new Bundle{}) 39 | val constant = Module(new Constant) 40 | val expect = Module(new Expect) 41 | BoringUtils.bore(constant.x, Seq(expect.y)) 42 | } 43 | ``` 44 | 45 | 2. 不分层: BoringUtils.addSink/addSource 46 | 47 | ```scala 48 | class Constant extends Module { 49 | val io = IO(new Bundle{}) 50 | val x = Wire(UInt(6.W)) 51 | x := 42.U 52 | BoringUtils.addSource(x, "uniqueId") 53 | } 54 | class Expect extends Module { 55 | val io = IO(new Bundle{}) 56 | val y = Wire(UInt(6.W)) 57 | y := 0.U 58 | // This assertion will fail unless we bore! 59 | chisel3.assert(y === 42.U, "y should be 42 in module Expect") 60 | BoringUtils.addSink(y, "uniqueId") 61 | } 62 | class Top extends Module { 63 | val io = IO(new Bundle{}) 64 | val constant = Module(new Constant) 65 | val expect = Module(new Expect) 66 | } 67 | ``` 68 | 69 | 70 | 71 | 72 | 73 | #### 问题 74 | 75 | 1. chisel顶层代码就用stage 去运行吗, 然后sbt "run ..." 76 | 2. 为何这样无法assert报错, printf, 他的结果除了输出verilog文件, 还能怎么执行了? 应该怎么去printf? 77 | 3. 顶层应该用c++ 代码去跑verilator吗, 感觉sbt的东西封装了太多, 不清楚具体流程 78 | 4. 再去看看nutshell代码吧, 然后使用gdb去跟踪一下. 原则上我应该先测试小的模块, 再去跑大的cpu. 79 | 80 | 81 | 82 | #### 比对 83 | 84 | 1. 应该要比对32个寄存器的值, pc值, 85 | 86 | 2. 最直接的比对pc是否相同, 87 | 88 | 3. 内置的函数包括 89 | 90 | ```c++ 91 | // 从DUT host memory的`src`处拷贝`n`字节到REF guest memory的`dest`处 92 | void difftest_memcpy_from_dut(paddr_t dest, void *src, size_t n); 93 | // 获取REF的寄存器状态到`r` 94 | void difftest_getregs(void *r); 95 | // 设置REF的寄存器状态为`r` 96 | void difftest_setregs(const void *r); 97 | // 让REF执行`n`条指令 98 | void difftest_exec(uint64_t n); 99 | // 初始化REF的DiffTest功能 100 | void difftest_init(); 101 | ``` 102 | 103 | 104 | 105 | #### verilator manual 106 | 107 | ``` 108 | --assert 用assert 109 | -CFLAGS makefile C编译器选项 CFLAGS = -g -O2 -Wall 110 | -cc 产生C++文件 111 | --debug 可以debug 112 | --exe 链接,产生可执行文件 113 | --gdb 与gdb交互 114 | -LDLIBS 告诉链接器要链接哪些库文件,如LIBS = -lpthread -liconv 115 | -LDFLAGS:gcc 等编译器会用到的一些优化参数,也可以在里面指定库文件的位置。用法 LDFLAGS=-L/usr/lib -L/path/to/your/lib (在哪里寻找库文件) 116 | -Mdir 输出文件目录 117 | 118 | ``` 119 | 120 | -------------------------------------------------------------------------------- /nemu/Makefile: -------------------------------------------------------------------------------- 1 | NAME = nemu 2 | NEMU_HOME = $(shell pwd) 3 | 4 | ifneq ($(MAKECMDGOALS),clean) # ignore check for make clean 5 | ISA ?= riscv64 6 | ISAS = $(shell ls src/isa/) 7 | ifeq ($(filter $(ISAS), $(ISA)), ) # ISA must be valid 8 | $(error Invalid ISA. Supported: $(ISAS)) 9 | endif 10 | 11 | ENGINE ?= interpreter 12 | ENGINES = $(shell ls src/engine/) 13 | ifeq ($(filter $(ENGINES), $(ENGINE)), ) # ENGINE must be valid 14 | $(error Invalid ENGINE. Supported: $(ENGINES)) 15 | endif 16 | 17 | $(info Building $(ISA)-$(NAME)-$(ENGINE)) 18 | 19 | endif 20 | 21 | INC_DIR += ./include ./src/engine/$(ENGINE) 22 | BUILD_DIR ?= ./build 23 | 24 | ifdef SHARE 25 | SO = -so 26 | SO_CFLAGS = -fPIC -D_SHARE=1 27 | SO_LDLAGS = -shared -fPIC 28 | else 29 | LD_LIBS = -lSDL2 -lreadline -ldl 30 | endif 31 | 32 | ifndef SHARE 33 | DIFF ?= kvm 34 | ifneq ($(ISA),x86) 35 | ifeq ($(DIFF),kvm) 36 | DIFF = qemu 37 | $(info KVM is only supported with ISA=x86, use QEMU instead) 38 | endif 39 | endif 40 | 41 | ifeq ($(DIFF),qemu) 42 | DIFF_REF_PATH = $(NEMU_HOME)/tools/qemu-diff 43 | DIFF_REF_SO = $(DIFF_REF_PATH)/build/$(ISA)-qemu-so 44 | CFLAGS += -D__DIFF_REF_QEMU__ 45 | else ifeq ($(DIFF),kvm) 46 | DIFF_REF_PATH = $(NEMU_HOME)/tools/kvm-diff 47 | DIFF_REF_SO = $(DIFF_REF_PATH)/build/$(ISA)-kvm-so 48 | CFLAGS += -D__DIFF_REF_KVM__ 49 | else ifeq ($(DIFF),nemu) 50 | DIFF_REF_PATH = $(NEMU_HOME) 51 | DIFF_REF_SO = $(DIFF_REF_PATH)/build/$(ISA)-nemu-interpreter-so 52 | CFLAGS += -D__DIFF_REF_NEMU__ 53 | MKFLAGS = ISA=$(ISA) SHARE=1 ENGINE=interpreter 54 | else 55 | $(error invalid DIFF. Supported: qemu kvm nemu) 56 | endif 57 | endif 58 | 59 | OBJ_DIR ?= $(BUILD_DIR)/obj-$(ISA)-$(ENGINE)$(SO) 60 | BINARY ?= $(BUILD_DIR)/$(ISA)-$(NAME)-$(ENGINE)$(SO) 61 | 62 | .DEFAULT_GOAL = app 63 | 64 | # Compilation flags 65 | CC = gcc 66 | LD = gcc 67 | INCLUDES = $(addprefix -I, $(INC_DIR)) 68 | CFLAGS += -O2 -MMD -Wall -Werror -ggdb3 $(INCLUDES) \ 69 | -D__ENGINE_$(ENGINE)__ \ 70 | -D__ISA__=$(ISA) -D__ISA_$(ISA)__ -D_ISA_H_=\"isa/$(ISA).h\" 71 | 72 | # Files to be compiled 73 | SRCS = $(shell find src/ -name "*.c" | grep -v "isa\|engine") 74 | SRCS += $(shell find src/isa/$(ISA) -name "*.c") 75 | SRCS += $(shell find src/engine/$(ENGINE) -name "*.c") 76 | OBJS = $(SRCS:src/%.c=$(OBJ_DIR)/%.o) 77 | 78 | # Compilation patterns 79 | $(OBJ_DIR)/%.o: src/%.c 80 | @echo + CC $< 81 | @mkdir -p $(dir $@) 82 | @$(CC) $(CFLAGS) $(SO_CFLAGS) -c -o $@ $< 83 | 84 | 85 | # Depencies 86 | -include $(OBJS:.o=.d) 87 | 88 | # Some convenient rules 89 | 90 | .PHONY: app run gdb clean run-env $(DIFF_REF_SO) 91 | app: $(BINARY) 92 | 93 | override ARGS ?= --log=$(BUILD_DIR)/nemu-log.txt 94 | override ARGS += --diff=$(DIFF_REF_SO) 95 | 96 | # Command to execute NEMU 97 | IMG := 98 | NEMU_EXEC := $(BINARY) $(ARGS) $(IMG) 99 | 100 | $(BINARY): $(OBJS) 101 | @echo + LD $@ 102 | @$(LD) -O2 -rdynamic $(SO_LDLAGS) -o $@ $^ $(LD_LIBS) 103 | 104 | run-env: $(BINARY) $(DIFF_REF_SO) 105 | 106 | all: run 107 | 108 | run: run-env 109 | $(NEMU_EXEC) 110 | 111 | gdb: run-env 112 | gdb -s $(BINARY) --args $(NEMU_EXEC) 113 | 114 | $(DIFF_REF_SO): 115 | $(MAKE) -C $(DIFF_REF_PATH) $(MKFLAGS) 116 | 117 | clean: 118 | -rm -rf $(BUILD_DIR) 119 | $(MAKE) -C tools/gen-expr clean 120 | $(MAKE) -C tools/qemu-diff clean 121 | $(MAKE) -C tools/kvm-diff clean 122 | -------------------------------------------------------------------------------- /docs/9.11 讨论.md: -------------------------------------------------------------------------------- 1 | #### 9.11 讨论 2 | 3 | 4 | 5 | 刘彤老师 6 | 7 | 1. 为何参加项目: 为数不多的能完成cpu核心部分并流片, 并有老师做一些脏活,获得好处需要自己多付出。每个人基础都有差距。基础决定当前起点,态度决定上限。 8 | 2. 碰到问题怎么办: 先看文档,先自己解决,问助教老师。 9 | 3. 流片需要做的事:前端:SOC搭建,系统测试(看文档), 进行代码综合,时序约束工程师,生成网表文件。 后端:fbf文件(标准时延文件)。数字后端流程:确保库文件正确,调用工具,完成布局布线(11月7号之前必须要把代码完成),做eco,在网表上做一些直接的连线;eda的检查。芯片最重要的是责任心,要对自己写的每一行代码负责,才能做出好的芯片。(11月7号之后可以一起来体验下后端过程) 10 | 11 | 12 | 13 | 余子豪老师 14 | 15 | 1. 没有指导书的情况下怎么生存下来 16 | 17 | 2. 非常困难 18 | 19 | 1. 能跑RT-Thread的处理器: 可以试试看----- 把学过的知识点整合起来 20 | 2. Chisel: scala很多语法看不懂, 感觉很难----- 有教程, 可以学会怎么写 21 | 3. 自己搭框架: 你在开玩笑? ----- 感觉第一步都不会,**测试大家是否有能力解决复杂问题**, 需要意识到**自己没有这样的能力**, 也是一个**改变自己的机会**。 22 | 23 | 3. 没有受到过这种训练 24 | 25 | | 基本原理 | 做事方案 | 正确性分享 | 代表例子 | 26 | | -------- | -------- | ---------- | -------------------- | 27 | | 阐述 | 明确 | 基本正确 | 高中物理实验 | 28 | | 阐述 | 明确 | 可能出错 | 程序设计作业 | 29 | | 阐述 | 需要思考 | 基本正确 | 数学/算法题 | 30 | | 阐述 | 需要思考 | 可能出错 | ?? | 31 | | 需要探索 | 需要思考 | 可能出错 | 业界和科研的真实能力 | 32 | 33 | 4. 越是希望指导书照顾自己, 越没有解决真实问题的能力, 有的人打比赛可能适应要快点 34 | 35 | 5. 一个事实:不可能抱着指导书过一辈子!!!以后面对的问题比课程实验复杂更多,如果觉得提供框架是老师的义务,已经从心态上放弃了改变自己的机会。 36 | 37 | 6. 任务分解: 自己来写指导书 38 | 39 | 1. 只能做简单,目标明确,可操作的事情; 没有人能一下子解决一个复杂问题 40 | 2. KISS法则: Keep It Simple, Stupid. 防止完美主义 41 | 3. 问题: nemu, am 中有很多比较琐碎的东西, 我们也要自己写吗 42 | 43 | 7. 例子: 44 | 45 | 1. 先跑个简单的, memcpy(一个for循环即可) 46 | 2. 先实现单周期的几条指令 47 | 3. 自己搭框架, 分解 48 | 1. 框架需要对riscv的仿真运行有什么支持? 49 | 2. 框架和chisel写的代码怎么对接? 50 | 3. DiffTest和框架怎么 51 | 4. Verilator怎么用? 使用KISS法则 52 | 53 | 8. 写最简单的框架 54 | 55 | 1. 别管diffTest, 用chisel实现几条指令,用verilator跑memcpy 56 | 2. 先用chisel跑计数器(always + 1) 57 | 3. 先用verilog实现计数器, **用verilator来跑** 58 | 4. 只有一件事:了解verilator! 59 | 5. 指导书可能成为了严重阻碍思想和能力成长的枷锁! 60 | 61 | 9. 最基本的生存技能: STFW + RTFM 62 | 63 | 1. 这也是本科教学最重要, 也最缺的部分!否则没有指导书就做不了事情。 64 | 2. 我来试试, 看能不能获得一些有用的信息。 65 | 3. 可以学习verilog怎么和C++代码交互, 最重要的是: 有简单例子!从例子中能对仿真有新的认识!(vivado背后的事情) 66 | 67 | 10. 自己写指导书 68 | 69 | 1. 了解verilator 70 | 2. 用verilog实现计数器, 用verilator仿真 71 | 3. 改成chisel实现 72 | 4. chisel来实现几条riscv指令, 跑memcpy 73 | 5. 加上diffTest(继续分解, 怎么验证一条指令!) 74 | 6. 自己搭框架也不是很难, 就算没有nutshell也可以做到。 75 | 76 | 11. 本质上之前都是本能选择逃避,但是站在职业生涯角度来说,是不行的。出来混,迟早要还的。还了这笔债,能有很多进展 77 | 78 | 12. 误区 79 | 80 | 1. 误区1: 去年也是一个多月没有进展(可以看去年的git log),框架上添加功能更简单, 错的! 必须要了解细节。 去理解一条指令在nutshell上是怎么执行的。 81 | 2. 误区2:去年也没有详细指导,可能被坑一个多月。 82 | 3. 大家都低估了自己搭框架的意义: 观念的改变,能力的成长,细节的理解,项目的辅助。 83 | 4. 误区3: 去年大家做的都不一样,完全没法去问。分工后也不了解别人踩坑的每一处细节。组队的焦虑:唉,都是我拖了大家的后腿。都有自己的焦虑 84 | 5. 好好珍惜:从零开始独立构建一个完整系统/芯片的时光。以后可能再也没这样的机会了!未来只能负责某个模块,以后组队的机会多的是/ 甚至在前人的基础上改进。 85 | 86 | 13. 自觉树立成长意识: 87 | 88 | 1. 尝试自己寻找解决方法 89 | 2. 问方法,不问具体答案: 尝试了ABC方法都不能解决, 是不是方法不对? 90 | 3. 老师/助教 也不直接回复答案,引导去解决问题。 91 | 4. 有同学分享了整理的笔记: 在自己尝试之前不要看, 做了之后去比较 92 | 5. 还是觉得很痛苦: 毕竟在温室下逃避了3年,一定要经历的。 93 | 6. 我们是顶尖高校的本科生,代表国家的未来。 我们不改变,国家就没有未来! 94 | 95 | 14. 11月7号只剩两个月,我能完成吗? 96 | 97 | 1. 也低估了框架的潜力: 一天正确实现RV64I的所有指令,3天正确实现流水线。 98 | 2. 实现处理器不难,框架是最难的,越往后越快。 99 | 3. 还在迷茫,先把RT-Thread补上来就好! 100 | 101 | 15. 我们没有定心丸:只有真正去做,去推进,看项目有进展,才会有更加客观的估计。别管最后能到什么境地,尝试去做就好了。 102 | 103 | 16. 接受不确定性的规律:即便大牛也预测不了技术发展的方向。 104 | 105 | 17. 改变自己, 从今天开始. 对自己要求高一点,我们是要做大事的! 任务分解是解决复杂问题的唯一方法: 多使用KISS, 越简单越好! 106 | 107 | 18. 直接用am进行裸机运行. 不用添加调试器那些的功能. 需要在nemu上添加指令. 在rtl上实现和fpga上是不同的, 所以实现指令有助于写chisel代码. 108 | 109 | --------------------------------------------------------------------------------