# PicoRV32 ## 安裝 Gnu toolchain ```bash git clone https://github.com/riscv/riscv-gnu-toolchain cd riscv-gnu-toolchain git submodule update --init --recursive ``` ### Prerequisites On Ubuntu, executing the following command should suffice: ```bash= sudo apt-get install autoconf automake autotools-dev curl python3 libmpc-dev libmpfr-dev libgmp-dev gawk build-essential bison flex texinfo gperf libtool patchutils bc zlib1g-dev libexpat-dev ninja-build ``` ### Installation (Linux) To build the Linux cross-compiler, pick an install path. If you choose, say, /opt/riscv, then add /opt/riscv/bin to your PATH now. ```bash= vim ~/.bashrc export RISCV="/opt/riscv" export PATH=$PATH:$RISCV/bin :wq #save and quit source ~/.bashrc ``` Create a directory in opt ```bash= cd /opt sudo mkdir riscv sudo chown $USER riscv ``` Then, simply run the following command: ```bash= cd riscv-gnu-toolchain ./configure --prefix=/opt/riscv --with-arch=rv32gc --with-abi=ilp32d make linux ``` ### Result ```bash= make[12]: Nothing to be done for 'install-data-am'. make[12]: Leaving directory '/home/eason/riscv-gnu-toolchain-rv32i/build/build-gdb-newlib/gdb/build-gnulib/import' make[11]: Leaving directory '/home/eason/riscv-gnu-toolchain-rv32i/build/build-gdb-newlib/gdb/build-gnulib/import' make[10]: Leaving directory '/home/eason/riscv-gnu-toolchain-rv32i/build/build-gdb-newlib/gdb/build-gnulib/import' make[9]: Leaving directory '/home/eason/riscv-gnu-toolchain-rv32i/build/build-gdb-newlib/gdb/build-gnulib/import' make[8]: Leaving directory '/home/eason/riscv-gnu-toolchain-rv32i/build/build-gdb-newlib/gdb/build-gnulib' make[7]: Leaving directory '/home/eason/riscv-gnu-toolchain-rv32i/build/build-gdb-newlib/gdb/build-gnulib' make[6]: Leaving directory '/home/eason/riscv-gnu-toolchain-rv32i/build/build-gdb-newlib/gdb/build-gnulib' make[5]: Leaving directory '/home/eason/riscv-gnu-toolchain-rv32i/build/build-gdb-newlib/gdb' make[4]: Leaving directory '/home/eason/riscv-gnu-toolchain-rv32i/build/build-gdb-newlib/gdb' make[3]: Leaving directory '/home/eason/riscv-gnu-toolchain-rv32i/build/build-gdb-newlib/gdb' make[2]: Leaving directory '/home/eason/riscv-gnu-toolchain-rv32i/build/build-gdb-newlib' make[1]: Leaving directory '/home/eason/riscv-gnu-toolchain-rv32i/build/build-gdb-newlib' mkdir -p stamps/ && touch stamps/build-gdb-newlib ``` :::success Gnu-toolchain install complete. ::: ## 安裝PicoRv32 :::danger ~~Not complete riscv32i build tools~~ Not complete make test_verilator ::: ### install ```bash= make download-tools make -j$(nproc) build-tools ``` ### Problem * riscv32i build tools :::warning ```bash= make[4]: Leaving directory '/home/eason/picorv32/riscv-gnu-toolchain-riscv32i/build/build-gcc-newlib-stage1/gcc' make[3]: Leaving directory '/home/eason/picorv32/riscv-gnu-toolchain-riscv32i/build/build-gcc-newlib-stage1' mkdir -p stamps/ && touch stamps/build-gcc-newlib-stage1 make[2]: Leaving directory '/home/eason/picorv32/riscv-gnu-toolchain-riscv32i/build' make[1]: *** [Makefile:158: build-riscv32i-tools-bh] Error 2 make[1]: Leaving directory '/home/eason/picorv32' make: *** [Makefile:167: build-tools] Error 2 ``` ::: * I found there are others have the same problem: https://github.com/YosysHQ/picorv32/issues/213 :::success * Modify the code line : picorv32/Makefile : ```bash=150 git submodule update --init $$$$reference_riscv_gcc riscv-gcc; \ git submodule update --init $$$$reference_riscv_glibc riscv-glibc; \ git submodule update --init $$$$reference_riscv_newlib riscv-newlib; \ mkdir build; cd build; ../configure --with-arch=$(2) --prefix=$(RISCV_GNU_TOOLCHAIN_INSTALL_PREFIX)$(subst riscv32,,$(1)) #; make ``` picorv32/riscv-gnu-toolchain-rv32i/riscv-gdb/gdb/Makefile.in : ```bash=427 unittests/scoped_restore-selftests.c \ unittests/string_view-selftests.c \ (delete it !) unittests/tracepoint-selftests.c \ unittests/unpack-selftests.c \ ``` Result : ```bash= + ../configure --with-arch=rv32i --prefix=/opt/riscv32i checking for gcc... gcc checking whether the C compiler works... yes checking for C compiler default output file name... a.out checking for suffix of executables... checking whether we are cross compiling... no checking for suffix of object files... o checking whether we are using the GNU C compiler... yes checking whether gcc accepts -g... yes checking for gcc option to accept ISO C89... none needed checking for grep that handles long lines and -e... /usr/bin/grep checking for fgrep... /usr/bin/grep -F checking for grep that handles long lines and -e... (cached) /usr/bin/grep checking for bash... /bin/bash checking for __gmpz_init in -lgmp... yes checking for mpfr_init in -lmpfr... yes checking for mpc_init2 in -lmpc... yes checking for curl... /usr/bin/curl checking for wget... /usr/bin/wget checking for ftp... /usr/bin/ftp configure: creating ./config.status config.status: creating Makefile config.status: creating scripts/wrapper/awk/awk config.status: creating scripts/wrapper/sed/sed make[1]: Leaving directory '/home/eason/picorv32' ``` ::: * make test_verilator ::: warning ```bash= eason@eason-virtual-machine:~/picorv32$ make test /opt/riscv32i/bin/riscv32-unknown-elf-gcc -Os -mabi=ilp32 -march=rv32imc -ffreestanding -nostdlib -o firmware/firmware.elf \ -Wl,--build-id=none,-Bstatic,-T,firmware/sections.lds,-Map,firmware/firmware.map,--strip-debug \ firmware/start.o firmware/irq.o firmware/print.o firmware/hello.o firmware/sieve.o firmware/multest.o firmware/stats.o tests/addi.o tests/add.o tests/andi.o tests/and.o tests/auipc.o tests/beq.o tests/bge.o tests/bgeu.o tests/blt.o tests/bltu.o tests/bne.o tests/div.o tests/divu.o tests/jalr.o tests/jal.o tests/j.o tests/lb.o tests/lbu.o tests/lh.o tests/lhu.o tests/lui.o tests/lw.o tests/mulh.o tests/mulhsu.o tests/mulhu.o tests/mul.o tests/ori.o tests/or.o tests/rem.o tests/remu.o tests/sb.o tests/sh.o tests/simple.o tests/slli.o tests/sll.o tests/slti.o tests/slt.o tests/srai.o tests/sra.o tests/srli.o tests/srl.o tests/sub.o tests/sw.o tests/xori.o tests/xor.o -lgcc bash: line 1: /opt/riscv32i/bin/riscv32-unknown-elf-gcc: No such file or directory make: *** [Makefile:110: firmware/firmware.elf] Error 127 eason@eason-virtual-machine:~/picorv32$ riscv32-unknown-elf-gcc riscv32-unknown-elf-gcc: command not found ``` ![image](https://hackmd.io/_uploads/ryfZBK6dT.png) Under the path , i didnt find riscv32-unknown-elf-gcc ::: ### How to solve I can't find the answer. ## pico.v ### modify the code to add the new instruction. * I want to implement power function. * which is `power rd,rs1,rs2` * It can calculat rs1^rs2 and store it back to rd. |31:25|24:20|19:15|14:12|11:7|6:0| |:-:|:-:|:-:|:-:|:-:|:-:| |funct7|rs2|rs1|funct3|rs|opcode| ```verilog=644 // Instruction Decoder reg instr_power; // add the new instruction reg instr_lui, instr_auipc, instr_jal, instr_jalr; reg instr_beq, instr_bne, instr_blt, instr_bge, instr_bltu, instr_bgeu; ``` ```verilog=680 assign instr_trap = (CATCH_ILLINSN || WITH_PCPI) && !{instr_lui, instr_auipc, instr_jal, instr_jalr, instr_beq, instr_bne, instr_blt, instr_bge, instr_bltu, instr_bgeu, instr_lb, instr_lh, instr_lw, instr_lbu, instr_lhu, instr_sb, instr_sh, instr_sw, instr_addi, instr_slti, instr_sltiu, instr_xori, instr_ori, instr_andi, instr_slli, instr_srli, instr_srai, instr_add, instr_sub, instr_sll, instr_slt, instr_sltu, instr_xor, instr_srl, instr_sra, instr_or, instr_and, instr_rdcycle, instr_rdcycleh, instr_rdinstr, instr_rdinstrh, instr_fence, instr_getq, instr_setq, instr_retirq, instr_maskirq, instr_waitirq, instr_timer, instr_power}; // add this ``` ```verilog=737 if (instr_power) new_ascii_instr = "power"; // add this if (instr_add) new_ascii_instr = "add"; if (instr_sub) new_ascii_instr = "sub"; if (instr_sll) new_ascii_instr = "sll"; ``` ```verilog=863 is_lui_auipc_jal_jalr_addi_add_sub <= |{instr_lui, instr_auipc, instr_jal, instr_jalr, instr_addi, instr_add, instr_sub, instr_power}; // add this ``` * And next I need to modify the code that is used to sepcify the `opcode`. ![image](https://hackmd.io/_uploads/ry3VSFRda.png) * I choose `opcode = 0011011` that there is no one using this `opcode` * Remember to add the `opcode` to `is_alu_reg_imm` ```verilog=877 is_beq_bne_blt_bge_bltu_bgeu <= mem_rdata_latched[6:0] == 7'b1100011; is_lb_lh_lw_lbu_lhu <= mem_rdata_latched[6:0] == 7'b0000011; is_sb_sh_sw <= mem_rdata_latched[6:0] == 7'b0100011; is_alu_reg_imm <= mem_rdata_latched[6:0] == 7'b0010011 | mem_rdata_latched[6:0] == 7'b0110011; is_alu_reg_reg <= mem_rdata_latched[6:0] == 7'b0110011; ``` ```verilog=1151 instr_addi <= 0; instr_slti <= 0; instr_sltiu <= 0; instr_xori <= 0; instr_ori <= 0; instr_andi <= 0; // add this instr_power <= 0; ``` * Add the `alu_out` ```verilog= 1274 case (1'b1) is_lui_auipc_jal_jalr_addi_add_sub: alu_out = alu_add_sub; instr_power : alu_out = alu_power_out; ``` * Add the calculate. ```verilog=1230 reg [31:0] alu_add_sub; generate if (TWO_CYCLE_ALU) begin always @(posedge clk) begin alu_add_sub <= instr_sub ? reg_op1 - reg_op2 : reg_op1 + reg_op2; alu_power_out <= reg_op1 ** reg_op2; alu_eq <= reg_op1 == reg_op2; // add this calculate alu_lts <= $signed(reg_op1) < $signed(reg_op2); alu_ltu <= reg_op1 < reg_op2; alu_shl <= reg_op1 << reg_op2[4:0]; alu_shr <= $signed({instr_sra || instr_srai ? reg_op1[31] : 1'b0, reg_op1}) >>> reg_op2[4:0]; end end else begin always @* begin alu_add_sub = instr_sub ? reg_op1 - reg_op2 : reg_op1 + reg_op2; alu_power_out <= reg_op1 ** reg_op2; alu_eq = reg_op1 == reg_op2; // add this calculate alu_lts = $signed(reg_op1) < $signed(reg_op2); alu_ltu = reg_op1 < reg_op2; alu_shl = reg_op1 << reg_op2[4:0]; alu_shr = $signed({instr_sra || instr_srai ? reg_op1[31] : 1'b0, reg_op1}) >>> reg_op2[4:0]; end end endgenerate ``` * We can modify the code to save logical resources and power consumption. ```verilog= alu_power_out <= (reg_op1 % 2) ? reg_op1 << ((reg_op1 >> 1)*reg_op2) : reg_op1 ^ reg_op2; ``` * Because if use the the Multiplier logical resources and power consumption will be high. * So I choose to first determine whether reg_op1 is a power of 2, and then decide whether to use the left shift operator or the multiplication operator.