├── .gitignore ├── README.md ├── examples └── icebreaker │ ├── .gitignore │ ├── Makefile │ ├── README.md │ ├── boot.s │ ├── firmware.c │ ├── firmware.py │ ├── icebreaker.pcf │ ├── simpleuart.v │ ├── spiflash.v │ ├── spimemio.v │ ├── syscalls.c │ ├── testbench.gtkw │ ├── testbench.v │ └── top.v └── source ├── .gitignore ├── Makefile ├── README.md ├── dhry.h ├── dhry_1.c ├── dhry_1_orig.c ├── dhry_2.c ├── dhry_orig.h ├── firmware.S ├── firmware.c ├── picorv_common.v ├── picorv_core.py ├── picorv_ctrl.v ├── picorv_ctrl_fm.gtkw ├── picorv_ctrl_fm_insn.sby ├── picorv_ctrl_fm_insn.sv ├── picorv_ctrl_fm_regs.sby ├── picorv_ctrl_fm_regs.sv ├── picorv_exec.v ├── picorv_ldst.v ├── syscalls.c ├── test.tcl ├── test.v ├── test.xdc ├── testbench.gtkw └── testbench.v /.gitignore: -------------------------------------------------------------------------------- 1 | /picorv.v 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PicoRV 2 | 3 | Clean rewrite of PicoRV32, with improved flexibility and extensibility, support for RV64, and more. 4 | 5 | **Early alpha. Work in progress.** 6 | 7 | 8 | ## Getting Started 9 | 10 | ``` 11 | # Generate picorv.v 12 | make -C source generate 13 | 14 | # icebreaker example design 15 | cd examples/icebreaker/ 16 | 17 | # run simulation 18 | make 19 | 20 | # display sim waveform 21 | gtkwave testbench.vcd testbench.gtkw 22 | 23 | # run synthesis 24 | make design.bin 25 | 26 | # compile firmware 27 | make firmware.bin 28 | 29 | # program icebreaker board 30 | make prog 31 | ``` 32 | -------------------------------------------------------------------------------- /examples/icebreaker/.gitignore: -------------------------------------------------------------------------------- 1 | /boot.elf 2 | /boot.hex 3 | /boot_tpl.hex 4 | /design.asc 5 | /design.bin 6 | /design.json 7 | /design_pnr.log 8 | /design_tpl.asc 9 | /design_ys.log 10 | /firmware.bin 11 | /firmware.elf 12 | /firmware.hex 13 | /testbench 14 | /testbench.vcd 15 | -------------------------------------------------------------------------------- /examples/icebreaker/Makefile: -------------------------------------------------------------------------------- 1 | PCF = icebreaker.pcf 2 | VLOG = top.v ../../picorv.v spimemio.v simpleuart.v 3 | SIMLIB = $(shell yosys-config --datdir)/ice40/cells_sim.v 4 | SHELL = bash 5 | 6 | test: testbench boot.hex firmware.hex 7 | vvp -N testbench 8 | 9 | testbench: testbench.v spiflash.v $(VLOG) $(SIMLIB) 10 | iverilog -DPICORV_DEBUG -s testbench -o testbench testbench.v spiflash.v $(VLOG) $(SIMLIB) 11 | 12 | prog: design.bin firmware.bin 13 | iceprog design.bin 14 | iceprog -o 1M firmware.bin 15 | 16 | prog_fw: firmware.bin 17 | iceprog -o 1M firmware.bin 18 | 19 | boot.hex: boot.elf 20 | riscv32-unknown-elf-objcopy -O verilog boot.elf /dev/stdout | sed -r 's,(..) (..) (..) (..),\4\3\2\1,g' > boot.hex 21 | 22 | boot_tpl.hex: 23 | icebram -g 32 256 > boot_tpl.hex 24 | 25 | boot.elf: boot.s 26 | riscv32-unknown-elf-as -o boot.elf boot.s 27 | 28 | firmware.bin: firmware.hex 29 | firmware.hex: firmware.elf firmware.py 30 | riscv32-unknown-elf-objcopy -O verilog firmware.elf /dev/stdout | \ 31 | python3 firmware.py `riscv32-unknown-elf-nm firmware.elf | grep ' T _start$$' | cut -f1 -d' '` 32 | 33 | firmware.elf: firmware.c syscalls.c 34 | riscv32-unknown-elf-gcc -o firmware.elf firmware.c syscalls.c 35 | 36 | design.json: $(VLOG) boot_tpl.hex 37 | yosys -l design_ys.log -p 'synth_ice40 -top top -json $@' $(VLOG) 38 | 39 | design_tpl.asc: design.json $(PCF) 40 | nextpnr-ice40 -l design_pnr.log --up5k --package sg48 --asc design_tpl.asc --pcf $(PCF) --json design.json --placer heap 41 | 42 | design.asc: design_tpl.asc boot_tpl.hex boot.hex 43 | icebram boot_tpl.hex <( egrep -v '^@0+\s$$' boot.hex; ) < design_tpl.asc > design.asc 44 | 45 | design.bin: design.asc 46 | icepack design.asc design.bin 47 | 48 | clean: 49 | rm -f testbench testbench.vcd 50 | rm -f firmware.elf firmware.hex 51 | rm -f boot.hex boot.elf firmware.bin 52 | rm -f design.json design.asc design.bin 53 | rm -f design_ys.log design_pnr.log 54 | rm -f boot_tpl.hex design_tpl.asc 55 | -------------------------------------------------------------------------------- /examples/icebreaker/README.md: -------------------------------------------------------------------------------- 1 | PicoRV icebreaker demo 2 | ====================== 3 | 4 | A simple demo system based on the [iCEBreaker FPGA development board](https://www.crowdsupply.com/1bitsquared/icebreaker-fpga). 5 | 6 | This demo expects the 7-segment module attached to PMOD1A. 7 | 8 | ``` 9 | # run simulation 10 | make 11 | 12 | # display sim waveform 13 | gtkwave testbench.vcd testbench.gtkw 14 | 15 | # run synthesis 16 | make design.bin 17 | 18 | # compile firmware 19 | make firmware.bin 20 | 21 | # program icebreaker board 22 | make prog 23 | ``` 24 | -------------------------------------------------------------------------------- /examples/icebreaker/boot.s: -------------------------------------------------------------------------------- 1 | /* 2 | * PicoRV -- A Small and Extensible RISC-V Processor 3 | * 4 | * Copyright (C) 2019 Claire Wolf 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | * 18 | */ 19 | 20 | start: 21 | li ra, 0 22 | li sp, 0 23 | li gp, 0 24 | li tp, 0 25 | li t0, 0 26 | li t1, 0 27 | li t2, 0 28 | li s0, 0 29 | li s1, 0 30 | li a0, 0 31 | li a1, 0 32 | li a2, 0 33 | li a3, 0 34 | li a4, 0 35 | li a5, 0 36 | li a6, 0 37 | li a7, 0 38 | li s2, 0 39 | li s3, 0 40 | li s4, 0 41 | li s5, 0 42 | li s6, 0 43 | li s7, 0 44 | li s8, 0 45 | li s9, 0 46 | li s10, 0 47 | li s11, 0 48 | li t3, 0 49 | li t4, 0 50 | li t5, 0 51 | li t6, 0 52 | li sp, 0x00020000-16 53 | sw zero, 0(sp) 54 | sw zero, 4(sp) 55 | sw zero, 8(sp) 56 | sw zero, 12(sp) 57 | li t0, 0x01100000 58 | 1: 59 | lw a0, 0(t0) 60 | lw a1, 4(t0) 61 | addi t0, t0, 8 62 | beqz a0, 3f 63 | 2: 64 | lw a2, 0(t0) 65 | addi t0, t0, 4 66 | sw a2, 0(a1) 67 | addi a1, a1, 4 68 | addi a0, a0, -4 69 | beqz a0, 1b 70 | j 2b 71 | 3: 72 | jalr ra, 0(a1) 73 | 4: 74 | j 4b 75 | -------------------------------------------------------------------------------- /examples/icebreaker/firmware.c: -------------------------------------------------------------------------------- 1 | /* 2 | * PicoRV -- A Small and Extensible RISC-V Processor 3 | * 4 | * Copyright (C) 2019 Claire Wolf 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | * 18 | */ 19 | 20 | #include 21 | #include 22 | 23 | #define REG_LEDS (*((volatile uint8_t*)0x00000400)) 24 | #define REG_BTNS (*((volatile uint8_t*)0x00000401)) 25 | 26 | #define REG_SPI (*((volatile uint32_t*)0x00000404)) 27 | 28 | #define REG_PM1A_DI (*((volatile uint8_t*)0x00000408)) 29 | #define REG_PM1A_DO (*((volatile uint8_t*)0x00000409)) 30 | #define REG_PM1A_OE (*((volatile uint8_t*)0x0000040a)) 31 | 32 | #define REG_PM1B_DI (*((volatile uint8_t*)0x0000040c)) 33 | #define REG_PM1B_DO (*((volatile uint8_t*)0x0000040d)) 34 | #define REG_PM1B_OE (*((volatile uint8_t*)0x0000040e)) 35 | 36 | #define REG_UARTDIV (*((volatile uint32_t*)0x00000410)) 37 | #define REG_UARTDAT (*((volatile uint32_t*)0x00000414)) 38 | 39 | extern void pause(int cnt); 40 | 41 | __asm__( 42 | "pause:\n" 43 | "1: addi a0, a0, -1\n" 44 | "bgtz a0, 1b\n" 45 | "ret\n" 46 | ); 47 | 48 | // 7 SEGMENT: 49 | // 50 | // s[7]=0 s[7]=1 51 | // 52 | // --0-- --0-- 53 | // | | | | 54 | // 5 1 5 1 55 | // | | | | 56 | // --6-- --6-- 57 | // | | | | 58 | // 4 2 4 2 59 | // | | | | 60 | // --3-- --3-- 61 | 62 | void hexlo(int val) 63 | { 64 | #define s(n) &~(1<> 0) & 15; 115 | int hi = (val >> 4) & 15; 116 | 117 | for (int i = 0; i < 100; i++) 118 | { 119 | hexlo(lo); 120 | pause(1000); 121 | hexhi(hi); 122 | pause(1000); 123 | } 124 | 125 | REG_PM1A_DO = 255; 126 | } 127 | 128 | int decout(int val) 129 | { 130 | int lo = val % 10; 131 | int hi = (val / 10) % 10; 132 | 133 | for (int i = 0; i < 100; i++) 134 | { 135 | hexlo(lo); 136 | pause(1000); 137 | hexhi(hi); 138 | pause(1000); 139 | } 140 | 141 | REG_PM1A_DO = 255; 142 | } 143 | 144 | int main() 145 | { 146 | REG_UARTDIV = 104; 147 | REG_UARTDAT = 'B'; 148 | printf("ooting.\n"); 149 | 150 | REG_PM1A_DO = 255; 151 | REG_PM1A_OE = 255; 152 | 153 | for (int i = 1;; i++) { 154 | REG_LEDS = 0x60 ^ (1 << (i&7)); 155 | if (REG_BTNS == 8) 156 | decout(i); 157 | else 158 | hexout(i); 159 | } 160 | 161 | return 0; 162 | } 163 | -------------------------------------------------------------------------------- /examples/icebreaker/firmware.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # 3 | # PicoRV -- A Small and Extensible RISC-V Processor 4 | # 5 | # Copyright (C) 2019 Claire Wolf 6 | # 7 | # Permission to use, copy, modify, and/or distribute this software for any 8 | # purpose with or without fee is hereby granted, provided that the above 9 | # copyright notice and this permission notice appear in all copies. 10 | # 11 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 | # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 | # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 | # 19 | 20 | import sys 21 | 22 | block_start = None 23 | block_data = list() 24 | flash_data = list() 25 | 26 | def block_fin(start): 27 | global block_start, block_data, flash_data 28 | if block_start is not None: 29 | assert 0x10000 <= block_start 30 | assert block_start + len(block_data) <= 0x30000 31 | while len(block_data) % 4 != 0: 32 | block_data.append(0) 33 | if len(block_data) != 0: 34 | flash_data += [ 35 | (len(block_data) >> 0) & 255, 36 | (len(block_data) >> 8) & 255, 37 | (len(block_data) >> 16) & 255, 38 | (len(block_data) >> 24) & 255, 39 | (block_start >> 0) & 255, 40 | (block_start >> 8) & 255, 41 | (block_start >> 16) & 255, 42 | (block_start >> 24) & 255, 43 | ] + block_data 44 | else: 45 | assert len(block_data) == 0 46 | block_start = start 47 | block_data = list() 48 | 49 | for line in sys.stdin: 50 | line = line.split() 51 | if line[0].startswith("@"): 52 | block_fin(int(line[0][1:], 16)) 53 | continue 54 | block_data += [int(v, 16) for v in line] 55 | 56 | block_fin(None) 57 | 58 | entry = int(sys.argv[1], 16) 59 | 60 | flash_data += [ 61 | 0, 0, 0, 0, 62 | (entry >> 0) & 255, 63 | (entry >> 8) & 255, 64 | (entry >> 16) & 255, 65 | (entry >> 24) & 255, 66 | ] + block_data 67 | 68 | with open("firmware.hex", "wt") as f: 69 | print("@100000", file=f) 70 | print(" ".join(["%02x" % v for v in flash_data]), file=f) 71 | 72 | with open("firmware.bin", "wb") as f: 73 | f.write(bytes(flash_data)) 74 | -------------------------------------------------------------------------------- /examples/icebreaker/icebreaker.pcf: -------------------------------------------------------------------------------- 1 | # 12 MHz clock 2 | set_io -nowarn CLK 35 3 | 4 | # RS232 5 | set_io -nowarn RX 6 6 | set_io -nowarn TX 9 7 | 8 | # LEDs and Button 9 | set_io -nowarn BTN_N 10 10 | set_io -nowarn LEDR_N 11 11 | set_io -nowarn LEDG_N 37 12 | 13 | # RGB LED Driver 14 | set_io -nowarn LED_RED_N 39 15 | set_io -nowarn LED_GRN_N 40 16 | set_io -nowarn LED_BLU_N 41 17 | 18 | # SPI Flash 19 | set_io -nowarn FLASH_SCK 15 20 | set_io -nowarn FLASH_SSB 16 21 | set_io -nowarn FLASH_IO0 14 22 | set_io -nowarn FLASH_IO1 17 23 | set_io -nowarn FLASH_IO2 12 24 | set_io -nowarn FLASH_IO3 13 25 | 26 | # PMOD 1A 27 | set_io -nowarn P1A1 4 28 | set_io -nowarn P1A2 2 29 | set_io -nowarn P1A3 47 30 | set_io -nowarn P1A4 45 31 | set_io -nowarn P1A7 3 32 | set_io -nowarn P1A8 48 33 | set_io -nowarn P1A9 46 34 | set_io -nowarn P1A10 44 35 | 36 | # PMOD 1B 37 | set_io -nowarn P1B1 43 38 | set_io -nowarn P1B2 38 39 | set_io -nowarn P1B3 34 40 | set_io -nowarn P1B4 31 41 | set_io -nowarn P1B7 42 42 | set_io -nowarn P1B8 36 43 | set_io -nowarn P1B9 32 44 | set_io -nowarn P1B10 28 45 | 46 | # PMOD 2 47 | set_io -nowarn P2_1 27 48 | set_io -nowarn P2_2 25 49 | set_io -nowarn P2_3 21 50 | set_io -nowarn P2_4 19 51 | set_io -nowarn P2_7 26 52 | set_io -nowarn P2_8 23 53 | set_io -nowarn P2_9 20 54 | set_io -nowarn P2_10 18 55 | 56 | # LEDs and Buttons (PMOD 2) 57 | set_io -nowarn LED1 27 58 | set_io -nowarn LED2 25 59 | set_io -nowarn LED3 21 60 | set_io -nowarn BTN2 19 61 | set_io -nowarn LED5 26 62 | set_io -nowarn LED4 23 63 | set_io -nowarn BTN1 20 64 | set_io -nowarn BTN3 18 65 | -------------------------------------------------------------------------------- /examples/icebreaker/simpleuart.v: -------------------------------------------------------------------------------- 1 | /* 2 | * PicoRV -- A Small and Extensible RISC-V Processor 3 | * 4 | * Copyright (C) 2019 Claire Wolf 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | * 18 | */ 19 | 20 | module simpleuart ( 21 | input clk, 22 | input resetn, 23 | 24 | output ser_tx, 25 | input ser_rx, 26 | 27 | input [3:0] reg_div_we, 28 | input [31:0] reg_div_di, 29 | output [31:0] reg_div_do, 30 | 31 | input reg_dat_we, 32 | input reg_dat_re, 33 | input [31:0] reg_dat_di, 34 | output [31:0] reg_dat_do, 35 | output reg_dat_wait 36 | ); 37 | reg [31:0] cfg_divider; 38 | 39 | reg [3:0] recv_state; 40 | reg [31:0] recv_divcnt; 41 | reg [7:0] recv_pattern; 42 | reg [7:0] recv_buf_data; 43 | reg recv_buf_valid; 44 | 45 | reg [9:0] send_pattern; 46 | reg [3:0] send_bitcnt; 47 | reg [31:0] send_divcnt; 48 | reg send_dummy; 49 | 50 | assign reg_div_do = cfg_divider; 51 | 52 | assign reg_dat_wait = reg_dat_we && (send_bitcnt || send_dummy); 53 | assign reg_dat_do = recv_buf_valid ? recv_buf_data : ~0; 54 | 55 | always @(posedge clk) begin 56 | if (!resetn) begin 57 | cfg_divider <= 1; 58 | end else begin 59 | if (reg_div_we[0]) cfg_divider[ 7: 0] <= reg_div_di[ 7: 0]; 60 | if (reg_div_we[1]) cfg_divider[15: 8] <= reg_div_di[15: 8]; 61 | if (reg_div_we[2]) cfg_divider[23:16] <= reg_div_di[23:16]; 62 | if (reg_div_we[3]) cfg_divider[31:24] <= reg_div_di[31:24]; 63 | end 64 | end 65 | 66 | always @(posedge clk) begin 67 | if (!resetn) begin 68 | recv_state <= 0; 69 | recv_divcnt <= 0; 70 | recv_pattern <= 0; 71 | recv_buf_data <= 0; 72 | recv_buf_valid <= 0; 73 | end else begin 74 | recv_divcnt <= recv_divcnt + 1; 75 | if (reg_dat_re) 76 | recv_buf_valid <= 0; 77 | case (recv_state) 78 | 0: begin 79 | if (!ser_rx) 80 | recv_state <= 1; 81 | recv_divcnt <= 0; 82 | end 83 | 1: begin 84 | if (2*recv_divcnt > cfg_divider) begin 85 | recv_state <= 2; 86 | recv_divcnt <= 0; 87 | end 88 | end 89 | 10: begin 90 | if (recv_divcnt > cfg_divider) begin 91 | recv_buf_data <= recv_pattern; 92 | recv_buf_valid <= 1; 93 | recv_state <= 0; 94 | end 95 | end 96 | default: begin 97 | if (recv_divcnt > cfg_divider) begin 98 | recv_pattern <= {ser_rx, recv_pattern[7:1]}; 99 | recv_state <= recv_state + 1; 100 | recv_divcnt <= 0; 101 | end 102 | end 103 | endcase 104 | end 105 | end 106 | 107 | assign ser_tx = send_pattern[0]; 108 | 109 | always @(posedge clk) begin 110 | if (reg_div_we) 111 | send_dummy <= 1; 112 | send_divcnt <= send_divcnt + 1; 113 | if (!resetn) begin 114 | send_pattern <= ~0; 115 | send_bitcnt <= 0; 116 | send_divcnt <= 0; 117 | send_dummy <= 1; 118 | end else begin 119 | if (send_dummy && !send_bitcnt) begin 120 | send_pattern <= ~0; 121 | send_bitcnt <= 15; 122 | send_divcnt <= 0; 123 | send_dummy <= 0; 124 | end else 125 | if (reg_dat_we && !send_bitcnt) begin 126 | send_pattern <= {1'b1, reg_dat_di[7:0], 1'b0}; 127 | send_bitcnt <= 10; 128 | send_divcnt <= 0; 129 | end else 130 | if (send_divcnt > cfg_divider && send_bitcnt) begin 131 | send_pattern <= {1'b1, send_pattern[9:1]}; 132 | send_bitcnt <= send_bitcnt - 1; 133 | send_divcnt <= 0; 134 | end 135 | end 136 | end 137 | endmodule 138 | -------------------------------------------------------------------------------- /examples/icebreaker/spiflash.v: -------------------------------------------------------------------------------- 1 | /* 2 | * PicoRV -- A Small and Extensible RISC-V Processor 3 | * 4 | * Copyright (C) 2019 Claire Wolf 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | * 18 | */ 19 | 20 | `timescale 1 ns / 1 ps 21 | 22 | // 23 | // Simple SPI flash simulation model 24 | // 25 | // This model samples io input signals 1ns before the SPI clock edge and 26 | // updates output signals 1ns after the SPI clock edge. 27 | // 28 | // Supported commands: 29 | // AB, B9, FF, 03, BB, EB, ED 30 | // 31 | // Well written SPI flash data sheets: 32 | // Cypress S25FL064L http://www.cypress.com/file/316661/download 33 | // Cypress S25FL128L http://www.cypress.com/file/316171/download 34 | // 35 | // SPI flash used on iCEBreaker board: 36 | // https://www.winbond.com/resource-files/w25q128jv%20dtr%20revb%2011042016.pdf 37 | // 38 | 39 | module spiflash ( 40 | input csb, 41 | input clk, 42 | inout io0, // MOSI 43 | inout io1, // MISO 44 | inout io2, 45 | inout io3 46 | ); 47 | localparam verbose = 0; 48 | localparam integer latency = 8; 49 | 50 | reg [7:0] buffer; 51 | integer bitcount = 0; 52 | integer bytecount = 0; 53 | integer dummycount = 0; 54 | 55 | reg [7:0] spi_cmd; 56 | reg [7:0] xip_cmd = 0; 57 | reg [23:0] spi_addr; 58 | 59 | reg [7:0] spi_in; 60 | reg [7:0] spi_out; 61 | reg spi_io_vld; 62 | 63 | reg powered_up = 0; 64 | 65 | localparam [3:0] mode_spi = 1; 66 | localparam [3:0] mode_dspi_rd = 2; 67 | localparam [3:0] mode_dspi_wr = 3; 68 | localparam [3:0] mode_qspi_rd = 4; 69 | localparam [3:0] mode_qspi_wr = 5; 70 | localparam [3:0] mode_qspi_ddr_rd = 6; 71 | localparam [3:0] mode_qspi_ddr_wr = 7; 72 | 73 | reg [3:0] mode = 0; 74 | reg [3:0] next_mode = 0; 75 | 76 | reg io0_oe = 0; 77 | reg io1_oe = 0; 78 | reg io2_oe = 0; 79 | reg io3_oe = 0; 80 | 81 | reg io0_dout = 0; 82 | reg io1_dout = 0; 83 | reg io2_dout = 0; 84 | reg io3_dout = 0; 85 | 86 | assign #1 io0 = io0_oe ? io0_dout : 1'bz; 87 | assign #1 io1 = io1_oe ? io1_dout : 1'bz; 88 | assign #1 io2 = io2_oe ? io2_dout : 1'bz; 89 | assign #1 io3 = io3_oe ? io3_dout : 1'bz; 90 | 91 | wire io0_delayed; 92 | wire io1_delayed; 93 | wire io2_delayed; 94 | wire io3_delayed; 95 | 96 | assign #1 io0_delayed = io0; 97 | assign #1 io1_delayed = io1; 98 | assign #1 io2_delayed = io2; 99 | assign #1 io3_delayed = io3; 100 | 101 | // 16 MB (128Mb) Flash 102 | reg [7:0] memory [0:16*1024*1024-1]; 103 | 104 | reg [1023:0] firmware_file; 105 | initial begin 106 | if (!$value$plusargs("firmware=%s", firmware_file)) 107 | firmware_file = "firmware.hex"; 108 | $readmemh(firmware_file, memory); 109 | end 110 | 111 | task spi_action; 112 | begin 113 | spi_in = buffer; 114 | 115 | if (bytecount == 1) begin 116 | spi_cmd = buffer; 117 | 118 | if (spi_cmd == 8'h ab) 119 | powered_up = 1; 120 | 121 | if (spi_cmd == 8'h b9) 122 | powered_up = 0; 123 | 124 | if (spi_cmd == 8'h ff) 125 | xip_cmd = 0; 126 | end 127 | 128 | if (powered_up && spi_cmd == 'h 03) begin 129 | if (bytecount == 2) 130 | spi_addr[23:16] = buffer; 131 | 132 | if (bytecount == 3) 133 | spi_addr[15:8] = buffer; 134 | 135 | if (bytecount == 4) 136 | spi_addr[7:0] = buffer; 137 | 138 | if (bytecount >= 4) begin 139 | buffer = memory[spi_addr]; 140 | spi_addr = spi_addr + 1; 141 | end 142 | end 143 | 144 | if (powered_up && spi_cmd == 'h bb) begin 145 | if (bytecount == 1) 146 | mode = mode_dspi_rd; 147 | 148 | if (bytecount == 2) 149 | spi_addr[23:16] = buffer; 150 | 151 | if (bytecount == 3) 152 | spi_addr[15:8] = buffer; 153 | 154 | if (bytecount == 4) 155 | spi_addr[7:0] = buffer; 156 | 157 | if (bytecount == 5) begin 158 | xip_cmd = (buffer == 8'h a5) ? spi_cmd : 8'h 00; 159 | mode = mode_dspi_wr; 160 | dummycount = latency; 161 | end 162 | 163 | if (bytecount >= 5) begin 164 | buffer = memory[spi_addr]; 165 | spi_addr = spi_addr + 1; 166 | end 167 | end 168 | 169 | if (powered_up && spi_cmd == 'h eb) begin 170 | if (bytecount == 1) 171 | mode = mode_qspi_rd; 172 | 173 | if (bytecount == 2) 174 | spi_addr[23:16] = buffer; 175 | 176 | if (bytecount == 3) 177 | spi_addr[15:8] = buffer; 178 | 179 | if (bytecount == 4) 180 | spi_addr[7:0] = buffer; 181 | 182 | if (bytecount == 5) begin 183 | xip_cmd = (buffer == 8'h a5) ? spi_cmd : 8'h 00; 184 | mode = mode_qspi_wr; 185 | dummycount = latency; 186 | end 187 | 188 | if (bytecount >= 5) begin 189 | buffer = memory[spi_addr]; 190 | spi_addr = spi_addr + 1; 191 | end 192 | end 193 | 194 | if (powered_up && spi_cmd == 'h ed) begin 195 | if (bytecount == 1) 196 | next_mode = mode_qspi_ddr_rd; 197 | 198 | if (bytecount == 2) 199 | spi_addr[23:16] = buffer; 200 | 201 | if (bytecount == 3) 202 | spi_addr[15:8] = buffer; 203 | 204 | if (bytecount == 4) 205 | spi_addr[7:0] = buffer; 206 | 207 | if (bytecount == 5) begin 208 | xip_cmd = (buffer == 8'h a5) ? spi_cmd : 8'h 00; 209 | mode = mode_qspi_ddr_wr; 210 | dummycount = latency; 211 | end 212 | 213 | if (bytecount >= 5) begin 214 | buffer = memory[spi_addr]; 215 | spi_addr = spi_addr + 1; 216 | end 217 | end 218 | 219 | spi_out = buffer; 220 | spi_io_vld = 1; 221 | 222 | if (verbose) begin 223 | if (bytecount == 1) 224 | $write(""); 225 | $write("", spi_in, spi_out); 226 | end 227 | 228 | end 229 | endtask 230 | 231 | task ddr_rd_edge; 232 | begin 233 | buffer = {buffer, io3_delayed, io2_delayed, io1_delayed, io0_delayed}; 234 | bitcount = bitcount + 4; 235 | if (bitcount == 8) begin 236 | bitcount = 0; 237 | bytecount = bytecount + 1; 238 | spi_action; 239 | end 240 | end 241 | endtask 242 | 243 | task ddr_wr_edge; 244 | begin 245 | io0_oe = 1; 246 | io1_oe = 1; 247 | io2_oe = 1; 248 | io3_oe = 1; 249 | 250 | io0_dout = buffer[4]; 251 | io1_dout = buffer[5]; 252 | io2_dout = buffer[6]; 253 | io3_dout = buffer[7]; 254 | 255 | buffer = {buffer, 4'h 0}; 256 | bitcount = bitcount + 4; 257 | if (bitcount == 8) begin 258 | bitcount = 0; 259 | bytecount = bytecount + 1; 260 | spi_action; 261 | end 262 | end 263 | endtask 264 | 265 | always @(csb) begin 266 | if (csb) begin 267 | if (verbose) begin 268 | $display(""); 269 | $fflush; 270 | end 271 | buffer = 0; 272 | bitcount = 0; 273 | bytecount = 0; 274 | mode = mode_spi; 275 | io0_oe = 0; 276 | io1_oe = 0; 277 | io2_oe = 0; 278 | io3_oe = 0; 279 | end else 280 | if (xip_cmd) begin 281 | buffer = xip_cmd; 282 | bitcount = 0; 283 | bytecount = 1; 284 | spi_action; 285 | end 286 | end 287 | 288 | always @(csb, clk) begin 289 | spi_io_vld = 0; 290 | if (!csb && !clk) begin 291 | if (dummycount > 0) begin 292 | io0_oe = 0; 293 | io1_oe = 0; 294 | io2_oe = 0; 295 | io3_oe = 0; 296 | end else 297 | case (mode) 298 | mode_spi: begin 299 | io0_oe = 0; 300 | io1_oe = 1; 301 | io2_oe = 0; 302 | io3_oe = 0; 303 | io1_dout = buffer[7]; 304 | end 305 | mode_dspi_rd: begin 306 | io0_oe = 0; 307 | io1_oe = 0; 308 | io2_oe = 0; 309 | io3_oe = 0; 310 | end 311 | mode_dspi_wr: begin 312 | io0_oe = 1; 313 | io1_oe = 1; 314 | io2_oe = 0; 315 | io3_oe = 0; 316 | io0_dout = buffer[6]; 317 | io1_dout = buffer[7]; 318 | end 319 | mode_qspi_rd: begin 320 | io0_oe = 0; 321 | io1_oe = 0; 322 | io2_oe = 0; 323 | io3_oe = 0; 324 | end 325 | mode_qspi_wr: begin 326 | io0_oe = 1; 327 | io1_oe = 1; 328 | io2_oe = 1; 329 | io3_oe = 1; 330 | io0_dout = buffer[4]; 331 | io1_dout = buffer[5]; 332 | io2_dout = buffer[6]; 333 | io3_dout = buffer[7]; 334 | end 335 | mode_qspi_ddr_rd: begin 336 | ddr_rd_edge; 337 | end 338 | mode_qspi_ddr_wr: begin 339 | ddr_wr_edge; 340 | end 341 | endcase 342 | if (next_mode) begin 343 | case (next_mode) 344 | mode_qspi_ddr_rd: begin 345 | io0_oe = 0; 346 | io1_oe = 0; 347 | io2_oe = 0; 348 | io3_oe = 0; 349 | end 350 | mode_qspi_ddr_wr: begin 351 | io0_oe = 1; 352 | io1_oe = 1; 353 | io2_oe = 1; 354 | io3_oe = 1; 355 | io0_dout = buffer[4]; 356 | io1_dout = buffer[5]; 357 | io2_dout = buffer[6]; 358 | io3_dout = buffer[7]; 359 | end 360 | endcase 361 | mode = next_mode; 362 | next_mode = 0; 363 | end 364 | end 365 | end 366 | 367 | always @(posedge clk) begin 368 | if (!csb) begin 369 | if (dummycount > 0) begin 370 | dummycount = dummycount - 1; 371 | end else 372 | case (mode) 373 | mode_spi: begin 374 | buffer = {buffer, io0}; 375 | bitcount = bitcount + 1; 376 | if (bitcount == 8) begin 377 | bitcount = 0; 378 | bytecount = bytecount + 1; 379 | spi_action; 380 | end 381 | end 382 | mode_dspi_rd, mode_dspi_wr: begin 383 | buffer = {buffer, io1, io0}; 384 | bitcount = bitcount + 2; 385 | if (bitcount == 8) begin 386 | bitcount = 0; 387 | bytecount = bytecount + 1; 388 | spi_action; 389 | end 390 | end 391 | mode_qspi_rd, mode_qspi_wr: begin 392 | buffer = {buffer, io3, io2, io1, io0}; 393 | bitcount = bitcount + 4; 394 | if (bitcount == 8) begin 395 | bitcount = 0; 396 | bytecount = bytecount + 1; 397 | spi_action; 398 | end 399 | end 400 | mode_qspi_ddr_rd: begin 401 | ddr_rd_edge; 402 | end 403 | mode_qspi_ddr_wr: begin 404 | ddr_wr_edge; 405 | end 406 | endcase 407 | end 408 | end 409 | endmodule 410 | -------------------------------------------------------------------------------- /examples/icebreaker/spimemio.v: -------------------------------------------------------------------------------- 1 | /* 2 | * PicoRV -- A Small and Extensible RISC-V Processor 3 | * 4 | * Copyright (C) 2019 Claire Wolf 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | * 18 | */ 19 | 20 | `timescale 1 ns / 1 ps 21 | 22 | module spimemio ( 23 | input clk, resetn, 24 | 25 | input valid, 26 | output ready, 27 | input [23:0] addr, 28 | output reg [31:0] rdata, 29 | 30 | output flash_csb, 31 | output flash_clk, 32 | 33 | output flash_io0_oe, 34 | output flash_io1_oe, 35 | output flash_io2_oe, 36 | output flash_io3_oe, 37 | 38 | output flash_io0_do, 39 | output flash_io1_do, 40 | output flash_io2_do, 41 | output flash_io3_do, 42 | 43 | input flash_io0_di, 44 | input flash_io1_di, 45 | input flash_io2_di, 46 | input flash_io3_di, 47 | 48 | input [3:0] cfgreg_we, 49 | input [31:0] cfgreg_di, 50 | output [31:0] cfgreg_do 51 | ); 52 | reg xfer_resetn; 53 | reg din_valid; 54 | wire din_ready; 55 | reg [7:0] din_data; 56 | reg [3:0] din_tag; 57 | reg din_cont; 58 | reg din_qspi; 59 | reg din_ddr; 60 | reg din_rd; 61 | 62 | wire dout_valid; 63 | wire [7:0] dout_data; 64 | wire [3:0] dout_tag; 65 | 66 | reg [23:0] buffer; 67 | 68 | reg [23:0] rd_addr; 69 | reg rd_valid; 70 | reg rd_wait; 71 | reg rd_inc; 72 | 73 | assign ready = valid && (addr == rd_addr) && rd_valid; 74 | wire jump = valid && !ready && (addr != rd_addr+4) && rd_valid; 75 | 76 | reg softreset; 77 | 78 | reg config_en; // cfgreg[31] 79 | reg config_ddr; // cfgreg[22] 80 | reg config_qspi; // cfgreg[21] 81 | reg config_cont; // cfgreg[20] 82 | reg [3:0] config_dummy; // cfgreg[19:16] 83 | reg [3:0] config_oe; // cfgreg[11:8] 84 | reg config_csb; // cfgreg[5] 85 | reg config_clk; // cfgref[4] 86 | reg [3:0] config_do; // cfgreg[3:0] 87 | 88 | assign cfgreg_do[31] = config_en; 89 | assign cfgreg_do[30:23] = 0; 90 | assign cfgreg_do[22] = config_ddr; 91 | assign cfgreg_do[21] = config_qspi; 92 | assign cfgreg_do[20] = config_cont; 93 | assign cfgreg_do[19:16] = config_dummy; 94 | assign cfgreg_do[15:12] = 0; 95 | assign cfgreg_do[11:8] = {flash_io3_oe, flash_io2_oe, flash_io1_oe, flash_io0_oe}; 96 | assign cfgreg_do[7:6] = 0; 97 | assign cfgreg_do[5] = flash_csb; 98 | assign cfgreg_do[4] = flash_clk; 99 | assign cfgreg_do[3:0] = {flash_io3_di, flash_io2_di, flash_io1_di, flash_io0_di}; 100 | 101 | always @(posedge clk) begin 102 | softreset <= !config_en || cfgreg_we; 103 | if (!resetn) begin 104 | softreset <= 1; 105 | config_en <= 1; 106 | config_csb <= 0; 107 | config_clk <= 0; 108 | config_oe <= 0; 109 | config_do <= 0; 110 | config_ddr <= 0; 111 | config_qspi <= 0; 112 | config_cont <= 0; 113 | config_dummy <= 8; 114 | end else begin 115 | if (cfgreg_we[0]) begin 116 | config_csb <= cfgreg_di[5]; 117 | config_clk <= cfgreg_di[4]; 118 | config_do <= cfgreg_di[3:0]; 119 | end 120 | if (cfgreg_we[1]) begin 121 | config_oe <= cfgreg_di[11:8]; 122 | end 123 | if (cfgreg_we[2]) begin 124 | config_ddr <= cfgreg_di[22]; 125 | config_qspi <= cfgreg_di[21]; 126 | config_cont <= cfgreg_di[20]; 127 | config_dummy <= cfgreg_di[19:16]; 128 | end 129 | if (cfgreg_we[3]) begin 130 | config_en <= cfgreg_di[31]; 131 | end 132 | end 133 | end 134 | 135 | wire xfer_csb; 136 | wire xfer_clk; 137 | 138 | wire xfer_io0_oe; 139 | wire xfer_io1_oe; 140 | wire xfer_io2_oe; 141 | wire xfer_io3_oe; 142 | 143 | wire xfer_io0_do; 144 | wire xfer_io1_do; 145 | wire xfer_io2_do; 146 | wire xfer_io3_do; 147 | 148 | reg xfer_io0_90; 149 | reg xfer_io1_90; 150 | reg xfer_io2_90; 151 | reg xfer_io3_90; 152 | 153 | always @(negedge clk) begin 154 | xfer_io0_90 <= xfer_io0_do; 155 | xfer_io1_90 <= xfer_io1_do; 156 | xfer_io2_90 <= xfer_io2_do; 157 | xfer_io3_90 <= xfer_io3_do; 158 | end 159 | 160 | assign flash_csb = config_en ? xfer_csb : config_csb; 161 | assign flash_clk = config_en ? xfer_clk : config_clk; 162 | 163 | assign flash_io0_oe = config_en ? xfer_io0_oe : config_oe[0]; 164 | assign flash_io1_oe = config_en ? xfer_io1_oe : config_oe[1]; 165 | assign flash_io2_oe = config_en ? xfer_io2_oe : config_oe[2]; 166 | assign flash_io3_oe = config_en ? xfer_io3_oe : config_oe[3]; 167 | 168 | assign flash_io0_do = config_en ? (config_ddr ? xfer_io0_90 : xfer_io0_do) : config_do[0]; 169 | assign flash_io1_do = config_en ? (config_ddr ? xfer_io1_90 : xfer_io1_do) : config_do[1]; 170 | assign flash_io2_do = config_en ? (config_ddr ? xfer_io2_90 : xfer_io2_do) : config_do[2]; 171 | assign flash_io3_do = config_en ? (config_ddr ? xfer_io3_90 : xfer_io3_do) : config_do[3]; 172 | 173 | wire xfer_dspi = din_ddr && !din_qspi; 174 | wire xfer_ddr = din_ddr && din_qspi; 175 | 176 | spimemio_xfer xfer ( 177 | .clk (clk ), 178 | .resetn (xfer_resetn ), 179 | .din_valid (din_valid ), 180 | .din_ready (din_ready ), 181 | .din_data (din_data ), 182 | .din_tag (din_tag ), 183 | .din_cont (din_cont ), 184 | .din_dspi (xfer_dspi ), 185 | .din_qspi (din_qspi ), 186 | .din_ddr (xfer_ddr ), 187 | .din_rd (din_rd ), 188 | .dout_valid (dout_valid ), 189 | .dout_data (dout_data ), 190 | .dout_tag (dout_tag ), 191 | .flash_csb (xfer_csb ), 192 | .flash_clk (xfer_clk ), 193 | .flash_io0_oe (xfer_io0_oe ), 194 | .flash_io1_oe (xfer_io1_oe ), 195 | .flash_io2_oe (xfer_io2_oe ), 196 | .flash_io3_oe (xfer_io3_oe ), 197 | .flash_io0_do (xfer_io0_do ), 198 | .flash_io1_do (xfer_io1_do ), 199 | .flash_io2_do (xfer_io2_do ), 200 | .flash_io3_do (xfer_io3_do ), 201 | .flash_io0_di (flash_io0_di), 202 | .flash_io1_di (flash_io1_di), 203 | .flash_io2_di (flash_io2_di), 204 | .flash_io3_di (flash_io3_di) 205 | ); 206 | 207 | reg [3:0] state; 208 | 209 | always @(posedge clk) begin 210 | xfer_resetn <= 1; 211 | din_valid <= 0; 212 | 213 | if (!resetn || softreset) begin 214 | state <= 0; 215 | xfer_resetn <= 0; 216 | rd_valid <= 0; 217 | din_tag <= 0; 218 | din_cont <= 0; 219 | din_qspi <= 0; 220 | din_ddr <= 0; 221 | din_rd <= 0; 222 | end else begin 223 | if (dout_valid && dout_tag == 1) buffer[ 7: 0] <= dout_data; 224 | if (dout_valid && dout_tag == 2) buffer[15: 8] <= dout_data; 225 | if (dout_valid && dout_tag == 3) buffer[23:16] <= dout_data; 226 | if (dout_valid && dout_tag == 4) begin 227 | rdata <= {dout_data, buffer}; 228 | rd_addr <= rd_inc ? rd_addr + 4 : addr; 229 | rd_valid <= 1; 230 | rd_wait <= rd_inc; 231 | rd_inc <= 1; 232 | end 233 | 234 | if (valid) 235 | rd_wait <= 0; 236 | 237 | case (state) 238 | 0: begin 239 | din_valid <= 1; 240 | din_data <= 8'h ff; 241 | din_tag <= 0; 242 | if (din_ready) begin 243 | din_valid <= 0; 244 | state <= 1; 245 | end 246 | end 247 | 1: begin 248 | if (dout_valid) begin 249 | xfer_resetn <= 0; 250 | state <= 2; 251 | end 252 | end 253 | 2: begin 254 | din_valid <= 1; 255 | din_data <= 8'h ab; 256 | din_tag <= 0; 257 | if (din_ready) begin 258 | din_valid <= 0; 259 | state <= 3; 260 | end 261 | end 262 | 3: begin 263 | if (dout_valid) begin 264 | xfer_resetn <= 0; 265 | state <= 4; 266 | end 267 | end 268 | 4: begin 269 | rd_inc <= 0; 270 | din_valid <= 1; 271 | din_tag <= 0; 272 | case ({config_ddr, config_qspi}) 273 | 2'b11: din_data <= 8'h ED; 274 | 2'b01: din_data <= 8'h EB; 275 | 2'b10: din_data <= 8'h BB; 276 | 2'b00: din_data <= 8'h 03; 277 | endcase 278 | if (din_ready) begin 279 | din_valid <= 0; 280 | state <= 5; 281 | end 282 | end 283 | 5: begin 284 | if (valid && !ready) begin 285 | din_valid <= 1; 286 | din_tag <= 0; 287 | din_data <= addr[23:16]; 288 | din_qspi <= config_qspi; 289 | din_ddr <= config_ddr; 290 | if (din_ready) begin 291 | din_valid <= 0; 292 | state <= 6; 293 | end 294 | end 295 | end 296 | 6: begin 297 | din_valid <= 1; 298 | din_tag <= 0; 299 | din_data <= addr[15:8]; 300 | if (din_ready) begin 301 | din_valid <= 0; 302 | state <= 7; 303 | end 304 | end 305 | 7: begin 306 | din_valid <= 1; 307 | din_tag <= 0; 308 | din_data <= addr[7:0]; 309 | if (din_ready) begin 310 | din_valid <= 0; 311 | din_data <= 0; 312 | state <= config_qspi || config_ddr ? 8 : 9; 313 | end 314 | end 315 | 8: begin 316 | din_valid <= 1; 317 | din_tag <= 0; 318 | din_data <= config_cont ? 8'h A5 : 8'h FF; 319 | if (din_ready) begin 320 | din_rd <= 1; 321 | din_data <= config_dummy; 322 | din_valid <= 0; 323 | state <= 9; 324 | end 325 | end 326 | 9: begin 327 | din_valid <= 1; 328 | din_tag <= 1; 329 | if (din_ready) begin 330 | din_valid <= 0; 331 | state <= 10; 332 | end 333 | end 334 | 10: begin 335 | din_valid <= 1; 336 | din_data <= 8'h 00; 337 | din_tag <= 2; 338 | if (din_ready) begin 339 | din_valid <= 0; 340 | state <= 11; 341 | end 342 | end 343 | 11: begin 344 | din_valid <= 1; 345 | din_tag <= 3; 346 | if (din_ready) begin 347 | din_valid <= 0; 348 | state <= 12; 349 | end 350 | end 351 | 12: begin 352 | if (!rd_wait || valid) begin 353 | din_valid <= 1; 354 | din_tag <= 4; 355 | if (din_ready) begin 356 | din_valid <= 0; 357 | state <= 9; 358 | end 359 | end 360 | end 361 | endcase 362 | 363 | if (jump) begin 364 | rd_inc <= 0; 365 | rd_valid <= 0; 366 | xfer_resetn <= 0; 367 | if (config_cont) begin 368 | state <= 5; 369 | end else begin 370 | state <= 4; 371 | din_qspi <= 0; 372 | din_ddr <= 0; 373 | end 374 | din_rd <= 0; 375 | end 376 | end 377 | end 378 | endmodule 379 | 380 | module spimemio_xfer ( 381 | input clk, resetn, 382 | 383 | input din_valid, 384 | output din_ready, 385 | input [7:0] din_data, 386 | input [3:0] din_tag, 387 | input din_cont, 388 | input din_dspi, 389 | input din_qspi, 390 | input din_ddr, 391 | input din_rd, 392 | 393 | output dout_valid, 394 | output [7:0] dout_data, 395 | output [3:0] dout_tag, 396 | 397 | output reg flash_csb, 398 | output reg flash_clk, 399 | 400 | output reg flash_io0_oe, 401 | output reg flash_io1_oe, 402 | output reg flash_io2_oe, 403 | output reg flash_io3_oe, 404 | 405 | output reg flash_io0_do, 406 | output reg flash_io1_do, 407 | output reg flash_io2_do, 408 | output reg flash_io3_do, 409 | 410 | input flash_io0_di, 411 | input flash_io1_di, 412 | input flash_io2_di, 413 | input flash_io3_di 414 | ); 415 | reg [7:0] obuffer; 416 | reg [7:0] ibuffer; 417 | 418 | reg [3:0] count; 419 | reg [3:0] dummy_count; 420 | 421 | reg xfer_cont; 422 | reg xfer_dspi; 423 | reg xfer_qspi; 424 | reg xfer_ddr; 425 | reg xfer_ddr_q; 426 | reg xfer_rd; 427 | reg [3:0] xfer_tag; 428 | reg [3:0] xfer_tag_q; 429 | 430 | reg [7:0] next_obuffer; 431 | reg [7:0] next_ibuffer; 432 | reg [3:0] next_count; 433 | 434 | reg fetch; 435 | reg next_fetch; 436 | reg last_fetch; 437 | 438 | always @(posedge clk) begin 439 | xfer_ddr_q <= xfer_ddr; 440 | xfer_tag_q <= xfer_tag; 441 | end 442 | 443 | assign din_ready = din_valid && resetn && next_fetch; 444 | 445 | assign dout_valid = (xfer_ddr_q ? fetch && !last_fetch : next_fetch && !fetch) && resetn; 446 | assign dout_data = ibuffer; 447 | assign dout_tag = xfer_tag_q; 448 | 449 | always @* begin 450 | flash_io0_oe = 0; 451 | flash_io1_oe = 0; 452 | flash_io2_oe = 0; 453 | flash_io3_oe = 0; 454 | 455 | flash_io0_do = 0; 456 | flash_io1_do = 0; 457 | flash_io2_do = 0; 458 | flash_io3_do = 0; 459 | 460 | next_obuffer = obuffer; 461 | next_ibuffer = ibuffer; 462 | next_count = count; 463 | next_fetch = 0; 464 | 465 | if (dummy_count == 0) begin 466 | casez ({xfer_ddr, xfer_qspi, xfer_dspi}) 467 | 3'b 000: begin 468 | flash_io0_oe = 1; 469 | flash_io0_do = obuffer[7]; 470 | 471 | if (flash_clk) begin 472 | next_obuffer = {obuffer[6:0], 1'b 0}; 473 | next_count = count - |count; 474 | end else begin 475 | next_ibuffer = {ibuffer[6:0], flash_io1_di}; 476 | end 477 | 478 | next_fetch = (next_count == 0); 479 | end 480 | 3'b 01?: begin 481 | flash_io0_oe = !xfer_rd; 482 | flash_io1_oe = !xfer_rd; 483 | flash_io2_oe = !xfer_rd; 484 | flash_io3_oe = !xfer_rd; 485 | 486 | flash_io0_do = obuffer[4]; 487 | flash_io1_do = obuffer[5]; 488 | flash_io2_do = obuffer[6]; 489 | flash_io3_do = obuffer[7]; 490 | 491 | if (flash_clk) begin 492 | next_obuffer = {obuffer[3:0], 4'b 0000}; 493 | next_count = count - {|count, 2'b00}; 494 | end else begin 495 | next_ibuffer = {ibuffer[3:0], flash_io3_di, flash_io2_di, flash_io1_di, flash_io0_di}; 496 | end 497 | 498 | next_fetch = (next_count == 0); 499 | end 500 | 3'b 11?: begin 501 | flash_io0_oe = !xfer_rd; 502 | flash_io1_oe = !xfer_rd; 503 | flash_io2_oe = !xfer_rd; 504 | flash_io3_oe = !xfer_rd; 505 | 506 | flash_io0_do = obuffer[4]; 507 | flash_io1_do = obuffer[5]; 508 | flash_io2_do = obuffer[6]; 509 | flash_io3_do = obuffer[7]; 510 | 511 | next_obuffer = {obuffer[3:0], 4'b 0000}; 512 | next_ibuffer = {ibuffer[3:0], flash_io3_di, flash_io2_di, flash_io1_di, flash_io0_di}; 513 | next_count = count - {|count, 2'b00}; 514 | 515 | next_fetch = (next_count == 0); 516 | end 517 | 3'b ??1: begin 518 | flash_io0_oe = !xfer_rd; 519 | flash_io1_oe = !xfer_rd; 520 | 521 | flash_io0_do = obuffer[6]; 522 | flash_io1_do = obuffer[7]; 523 | 524 | if (flash_clk) begin 525 | next_obuffer = {obuffer[5:0], 2'b 00}; 526 | next_count = count - {|count, 1'b0}; 527 | end else begin 528 | next_ibuffer = {ibuffer[5:0], flash_io1_di, flash_io0_di}; 529 | end 530 | 531 | next_fetch = (next_count == 0); 532 | end 533 | endcase 534 | end 535 | end 536 | 537 | always @(posedge clk) begin 538 | if (!resetn) begin 539 | fetch <= 1; 540 | last_fetch <= 1; 541 | flash_csb <= 1; 542 | flash_clk <= 0; 543 | count <= 0; 544 | dummy_count <= 0; 545 | xfer_tag <= 0; 546 | xfer_cont <= 0; 547 | xfer_dspi <= 0; 548 | xfer_qspi <= 0; 549 | xfer_ddr <= 0; 550 | xfer_rd <= 0; 551 | end else begin 552 | fetch <= next_fetch; 553 | last_fetch <= xfer_ddr ? fetch : 1; 554 | if (dummy_count) begin 555 | flash_clk <= !flash_clk && !flash_csb; 556 | dummy_count <= dummy_count - flash_clk; 557 | end else 558 | if (count) begin 559 | flash_clk <= !flash_clk && !flash_csb; 560 | obuffer <= next_obuffer; 561 | ibuffer <= next_ibuffer; 562 | count <= next_count; 563 | end 564 | if (din_valid && din_ready) begin 565 | flash_csb <= 0; 566 | flash_clk <= 0; 567 | 568 | count <= 8; 569 | dummy_count <= din_rd ? din_data : 0; 570 | obuffer <= din_data; 571 | 572 | xfer_tag <= din_tag; 573 | xfer_cont <= din_cont; 574 | xfer_dspi <= din_dspi; 575 | xfer_qspi <= din_qspi; 576 | xfer_ddr <= din_ddr; 577 | xfer_rd <= din_rd; 578 | end 579 | end 580 | end 581 | endmodule 582 | -------------------------------------------------------------------------------- /examples/icebreaker/syscalls.c: -------------------------------------------------------------------------------- 1 | /* 2 | * PicoRV -- A Small and Extensible RISC-V Processor 3 | * 4 | * Copyright (C) 2019 Claire Wolf 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | * 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | #define UNIMPL_FUNC(_f) ".globl " #_f "\n.type " #_f ", @function\n" #_f ":\n" 25 | 26 | asm ( 27 | ".text\n" 28 | ".align 2\n" 29 | UNIMPL_FUNC(_open) 30 | UNIMPL_FUNC(_openat) 31 | UNIMPL_FUNC(_lseek) 32 | UNIMPL_FUNC(_stat) 33 | UNIMPL_FUNC(_lstat) 34 | UNIMPL_FUNC(_fstatat) 35 | UNIMPL_FUNC(_isatty) 36 | UNIMPL_FUNC(_access) 37 | UNIMPL_FUNC(_faccessat) 38 | UNIMPL_FUNC(_link) 39 | UNIMPL_FUNC(_unlink) 40 | UNIMPL_FUNC(_execve) 41 | UNIMPL_FUNC(_getpid) 42 | UNIMPL_FUNC(_fork) 43 | UNIMPL_FUNC(_kill) 44 | UNIMPL_FUNC(_wait) 45 | UNIMPL_FUNC(_times) 46 | UNIMPL_FUNC(_gettimeofday) 47 | UNIMPL_FUNC(_ftime) 48 | UNIMPL_FUNC(_utime) 49 | UNIMPL_FUNC(_chown) 50 | UNIMPL_FUNC(_chmod) 51 | UNIMPL_FUNC(_chdir) 52 | UNIMPL_FUNC(_getcwd) 53 | UNIMPL_FUNC(_sysconf) 54 | "j unimplemented_syscall\n" 55 | ); 56 | 57 | void unimplemented_syscall() 58 | { 59 | const char *p = "Unimplemented system call called!\n"; 60 | while (*p) 61 | *(volatile int*)0x00000414 = *(p++); 62 | asm volatile ("ebreak"); 63 | __builtin_unreachable(); 64 | } 65 | 66 | ssize_t _read(int file, void *ptr, size_t len) 67 | { 68 | // always EOF 69 | return 0; 70 | } 71 | 72 | ssize_t _write(int file, const void *ptr, size_t len) 73 | { 74 | const void *eptr = ptr + len; 75 | while (ptr != eptr) { 76 | if (*(char*)ptr == '\n') 77 | *(volatile int*)0x00000414 = '\r'; 78 | *(volatile int*)0x00000414 = *(char*)(ptr++); 79 | } 80 | return len; 81 | } 82 | 83 | int _close(int file) 84 | { 85 | // close is called before _exit() 86 | return 0; 87 | } 88 | 89 | int _fstat(int file, struct stat *st) 90 | { 91 | // fstat is called during libc startup 92 | errno = ENOENT; 93 | return -1; 94 | } 95 | 96 | void *_sbrk(ptrdiff_t incr) 97 | { 98 | extern unsigned char _end[]; // Defined by linker 99 | static unsigned long heap_end; 100 | 101 | if (heap_end == 0) 102 | heap_end = (long)_end; 103 | 104 | heap_end += incr; 105 | return (void *)(heap_end - incr); 106 | } 107 | 108 | void _exit(int exit_status) 109 | { 110 | asm volatile ("ebreak"); 111 | __builtin_unreachable(); 112 | } 113 | -------------------------------------------------------------------------------- /examples/icebreaker/testbench.gtkw: -------------------------------------------------------------------------------- 1 | [*] 2 | [*] GTKWave Analyzer v3.3.86 (w)1999-2017 BSI 3 | [*] Wed Feb 19 12:31:29 2020 4 | [*] 5 | [dumpfile] "/home/claire/Work/picorv/examples/icebreaker/testbench.vcd" 6 | [dumpfile_mtime] "Wed Feb 19 12:21:31 2020" 7 | [dumpfile_size] 207240914 8 | [savefile] "/home/claire/Work/picorv/examples/icebreaker/testbench.gtkw" 9 | [timestart] 92000000 10 | [size] 1000 600 11 | [pos] -1318 51 12 | *-29.786324 2518380000 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 13 | [sst_width] 223 14 | [signals_width] 102 15 | [sst_expanded] 1 16 | [sst_vpaned_height] 152 17 | @28 18 | testbench.CLK 19 | @200 20 | - 21 | @28 22 | testbench.LED1 23 | testbench.LED2 24 | testbench.LED3 25 | testbench.LED4 26 | testbench.LED5 27 | @200 28 | - 29 | @28 30 | testbench.RX 31 | testbench.TX 32 | @200 33 | - 34 | @29 35 | testbench.FLASH_IO0 36 | @28 37 | testbench.FLASH_IO1 38 | testbench.FLASH_IO2 39 | testbench.FLASH_IO3 40 | testbench.FLASH_SCK 41 | testbench.FLASH_SSB 42 | [pattern_trace] 1 43 | [pattern_trace] 0 44 | -------------------------------------------------------------------------------- /examples/icebreaker/testbench.v: -------------------------------------------------------------------------------- 1 | /* 2 | * PicoRV -- A Small and Extensible RISC-V Processor 3 | * 4 | * Copyright (C) 2019 Claire Wolf 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | * 18 | */ 19 | 20 | `timescale 1 ns / 1 ps 21 | 22 | module testbench; 23 | reg CLK; 24 | integer i; 25 | 26 | initial begin 27 | $dumpfile("testbench.vcd"); 28 | $dumpvars(0, testbench); 29 | 30 | #5 CLK = 0; 31 | for (i = 0; i < 100; i = i+1) begin 32 | repeat (6000) #5 CLK = ~CLK; 33 | if (i%10 == 0) begin 34 | if (i) 35 | $display(); 36 | $write("Running [%2d%%] ", i); 37 | $fflush; 38 | end else begin 39 | $write("."); 40 | $fflush; 41 | end 42 | end 43 | 44 | $display(); 45 | $display("DONE"); 46 | end 47 | 48 | wire LED1; 49 | wire LED2; 50 | wire LED3; 51 | wire LED4; 52 | wire LED5; 53 | 54 | wire FLASH_SSB; 55 | wire FLASH_SCK; 56 | wire FLASH_IO0; 57 | wire FLASH_IO1; 58 | wire FLASH_IO2; 59 | wire FLASH_IO3; 60 | 61 | spiflash spiflash ( 62 | .csb(FLASH_SSB), 63 | .clk(FLASH_SCK), 64 | .io0(FLASH_IO0), 65 | .io1(FLASH_IO1), 66 | .io2(FLASH_IO2), 67 | .io3(FLASH_IO3) 68 | ); 69 | 70 | top uut ( 71 | .CLK (CLK), 72 | 73 | .LED1 (LED1), 74 | .LED2 (LED2), 75 | .LED3 (LED3), 76 | .LED4 (LED4), 77 | .LED5 (LED5), 78 | 79 | .FLASH_SSB (FLASH_SSB), 80 | .FLASH_SCK (FLASH_SCK), 81 | .FLASH_IO0 (FLASH_IO0), 82 | .FLASH_IO1 (FLASH_IO1), 83 | .FLASH_IO2 (FLASH_IO2), 84 | .FLASH_IO3 (FLASH_IO3), 85 | 86 | .RX (RX), 87 | .TX (TX) 88 | ); 89 | endmodule 90 | -------------------------------------------------------------------------------- /examples/icebreaker/top.v: -------------------------------------------------------------------------------- 1 | /* 2 | * PicoRV -- A Small and Extensible RISC-V Processor 3 | * 4 | * Copyright (C) 2019 Claire Wolf 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | * 18 | */ 19 | 20 | `timescale 1 ns / 1 ps 21 | 22 | module top ( 23 | input CLK, 24 | 25 | // LEDs 26 | output LED1, 27 | output LED2, 28 | output LED3, 29 | output LED4, 30 | output LED5, 31 | output LEDR_N, 32 | output LEDG_N, 33 | 34 | // Buttons 35 | input BTN1, 36 | input BTN2, 37 | input BTN3, 38 | input BTN_N, 39 | 40 | // PMOD 1A 41 | inout P1A1, 42 | inout P1A2, 43 | inout P1A3, 44 | inout P1A4, 45 | inout P1A7, 46 | inout P1A8, 47 | inout P1A9, 48 | inout P1A10, 49 | 50 | // PMOD 1B 51 | inout P1B1, 52 | inout P1B2, 53 | inout P1B3, 54 | inout P1B4, 55 | inout P1B7, 56 | inout P1B8, 57 | inout P1B9, 58 | inout P1B10, 59 | 60 | // FLASH 61 | output FLASH_SSB, 62 | output FLASH_SCK, 63 | inout FLASH_IO0, 64 | inout FLASH_IO1, 65 | inout FLASH_IO2, 66 | inout FLASH_IO3, 67 | 68 | // RS232 69 | input RX, 70 | output TX 71 | ); 72 | // CLOCK AND RESET 73 | // --------------- 74 | 75 | wire clock = CLK; 76 | 77 | reg reset = 1; 78 | reg [4:0] reset_cnt = 0; 79 | 80 | always @(posedge clock) begin 81 | reset <= reset_cnt != 31; 82 | reset_cnt <= reset_cnt + (reset_cnt != 31); 83 | end 84 | 85 | 86 | // IOs 87 | // --- 88 | 89 | reg [6:0] leds; 90 | assign {LEDR_N, LEDG_N, LED5, LED4, LED3, LED2, LED1} = leds; 91 | 92 | wire flash_csb; 93 | wire flash_clk; 94 | 95 | wire flash_io0_oe, flash_io0_do, flash_io0_di; 96 | wire flash_io1_oe, flash_io1_do, flash_io1_di; 97 | wire flash_io2_oe, flash_io2_do, flash_io2_di; 98 | wire flash_io3_oe, flash_io3_do, flash_io3_di; 99 | 100 | reg [7:0] pmod1_oe, pmod1_do, pmod2_oe, pmod2_do; 101 | wire [7:0] pmod1_di, pmod2_di; 102 | 103 | assign FLASH_SSB = flash_csb; 104 | assign FLASH_SCK = flash_clk; 105 | 106 | SB_IO #( 107 | .PIN_TYPE(6'b 1010_01), 108 | .PULLUP(1'b 0) 109 | ) flash_io_buf [3:0] ( 110 | .PACKAGE_PIN({FLASH_IO3, FLASH_IO2, FLASH_IO1, FLASH_IO0}), 111 | .OUTPUT_ENABLE({flash_io3_oe, flash_io2_oe, flash_io1_oe, flash_io0_oe}), 112 | .D_OUT_0({flash_io3_do, flash_io2_do, flash_io1_do, flash_io0_do}), 113 | .D_IN_0({flash_io3_di, flash_io2_di, flash_io1_di, flash_io0_di}) 114 | ); 115 | 116 | SB_IO #( 117 | .PIN_TYPE(6'b 1010_01), 118 | .PULLUP(1'b 0) 119 | ) pmod1_io_buf [7:0] ( 120 | .PACKAGE_PIN({P1A10, P1A9, P1A8, P1A7, P1A4, P1A3, P1A2, P1A1}), 121 | .OUTPUT_ENABLE(pmod1_oe), 122 | .D_OUT_0(pmod1_do), 123 | .D_IN_0(pmod1_di) 124 | ); 125 | 126 | SB_IO #( 127 | .PIN_TYPE(6'b 1010_01), 128 | .PULLUP(1'b 0) 129 | ) pmod2_io_buf [7:0] ( 130 | .PACKAGE_PIN({P1B10, P1B9, P1B8, P1B7, P1B4, P1B3, P1B2, P1B1}), 131 | .OUTPUT_ENABLE(pmod2_oe), 132 | .D_OUT_0(pmod2_do), 133 | .D_IN_0(pmod2_di) 134 | ); 135 | 136 | 137 | // SYSTEM 138 | // ------ 139 | 140 | wire mem_valid; 141 | reg mem_ready; 142 | wire mem_insn; 143 | wire [31:0] mem_addr; 144 | wire [31:0] mem_rdata; 145 | wire [31:0] mem_wdata; 146 | wire [ 3:0] mem_wstrb; 147 | 148 | reg [31:0] mem_rdata_zpage_data; 149 | reg mem_rdata_zpage_valid; 150 | 151 | reg [31:0] mem_rdata_regs_data; 152 | reg mem_rdata_regs_valid; 153 | 154 | wire [31:0] mem_rdata_spram1_data; 155 | reg mem_rdata_spram1_valid; 156 | 157 | wire [31:0] mem_rdata_spram2_data; 158 | reg mem_rdata_spram2_valid; 159 | 160 | reg [31:0] zpage [0:255]; 161 | 162 | initial begin 163 | `ifdef PICORV_DEBUG 164 | $readmemh("boot.hex", zpage); 165 | `else 166 | $readmemh("boot_tpl.hex", zpage); 167 | `endif 168 | end 169 | 170 | // 0x00000000 - 0x000003ff 171 | wire zpage_valid = mem_valid && mem_addr[31:10] == 0; 172 | 173 | // 0x00000400 - 0x000007ff 174 | wire regs_valid = mem_valid && mem_addr[31:10] == 1; 175 | wire ledreg_valid = mem_valid && mem_addr == 32'h 00000400; 176 | wire spireg_valid = mem_valid && mem_addr == 32'h 00000404; 177 | wire pmodareg_valid = mem_valid && mem_addr == 32'h 00000408; 178 | wire pmodbreg_valid = mem_valid && mem_addr == 32'h 0000040C; 179 | wire uartdivreg_valid = mem_valid && mem_addr == 32'h 00000410; 180 | wire uartdatreg_valid = mem_valid && mem_addr == 32'h 00000414; 181 | 182 | // 0x00010000 - 0x0002ffff 183 | wire spram1_valid = mem_valid && mem_addr[31:16] == 1; 184 | wire spram2_valid = mem_valid && mem_addr[31:16] == 2; 185 | 186 | // 0x01000000 - 0x01f1ffff 187 | wire spi_valid = mem_valid && mem_addr[31:24] == 1; 188 | 189 | wire spi_ready; 190 | wire [31:0] spi_rdata; 191 | wire [31:0] spireg_do; 192 | 193 | wire [31:0] uartdivreg_do; 194 | wire [31:0] uartdatreg_do; 195 | wire uartdatreg_wait; 196 | 197 | always @(posedge clock) begin 198 | mem_ready <= 0; 199 | mem_rdata_zpage_data <= 'bx; 200 | mem_rdata_zpage_valid <= 0; 201 | mem_rdata_regs_data <= 'bx; 202 | mem_rdata_regs_valid <= 0; 203 | mem_rdata_spram1_valid <= 0; 204 | mem_rdata_spram2_valid <= 0; 205 | 206 | (* parallel_case *) 207 | case (1) 208 | zpage_valid: begin 209 | mem_ready <= 1; 210 | mem_rdata_zpage_data <= zpage[mem_addr[9:2]]; 211 | mem_rdata_zpage_valid <= 1; 212 | if (mem_wstrb[0]) zpage[mem_addr[9:2]][ 7: 0] <= mem_wdata[ 7: 0]; 213 | if (mem_wstrb[1]) zpage[mem_addr[9:2]][15: 8] <= mem_wdata[15: 8]; 214 | if (mem_wstrb[2]) zpage[mem_addr[9:2]][23:16] <= mem_wdata[23:16]; 215 | if (mem_wstrb[3]) zpage[mem_addr[9:2]][31:24] <= mem_wdata[31:24]; 216 | end 217 | regs_valid: begin 218 | mem_ready <= 1; 219 | mem_rdata_regs_valid <= 1; 220 | (* parallel_case *) 221 | case (1) 222 | ledreg_valid: begin 223 | if (mem_wstrb[0]) leds <= mem_wdata; 224 | mem_rdata_regs_data <= {BTN_N, BTN3, BTN2, BTN1, 1'b0, leds}; 225 | end 226 | pmodareg_valid: begin 227 | if (mem_wstrb[1]) pmod1_do <= mem_wdata[15:8]; 228 | if (mem_wstrb[2]) pmod1_oe <= mem_wdata[23:16]; 229 | mem_rdata_regs_data <= {pmod1_oe, pmod1_do, pmod1_di}; 230 | end 231 | pmodbreg_valid: begin 232 | if (mem_wstrb[1]) pmod2_do <= mem_wdata[15:8]; 233 | if (mem_wstrb[2]) pmod2_oe <= mem_wdata[23:16]; 234 | mem_rdata_regs_data <= {pmod2_oe, pmod2_do, pmod2_di}; 235 | end 236 | spireg_valid: begin 237 | mem_rdata_regs_data <= spireg_do; 238 | end 239 | uartdivreg_valid: begin 240 | mem_rdata_regs_data <= uartdivreg_do; 241 | end 242 | uartdatreg_valid: begin 243 | if (uartdatreg_wait) 244 | mem_ready <= 0; 245 | mem_rdata_regs_data <= uartdatreg_do; 246 | end 247 | endcase 248 | end 249 | spram1_valid: begin 250 | mem_ready <= 1; 251 | mem_rdata_spram1_valid <= 1; 252 | end 253 | spram2_valid: begin 254 | mem_ready <= 1; 255 | mem_rdata_spram2_valid <= 1; 256 | end 257 | spi_valid: begin 258 | mem_ready <= spi_ready; 259 | mem_rdata_regs_data <= spi_rdata; 260 | mem_rdata_regs_valid <= 1; 261 | end 262 | endcase 263 | 264 | if (mem_ready || reset) begin 265 | mem_ready <= 0; 266 | end 267 | end 268 | 269 | SB_SPRAM256KA spram1_lo ( 270 | .ADDRESS(mem_addr[15:2]), 271 | .DATAIN(mem_wdata[15:0]), 272 | .MASKWREN({{2{spram1_valid && mem_wstrb[1]}}, {2{spram1_valid && mem_wstrb[0]}}}), 273 | .WREN(spram1_valid && mem_wstrb), 274 | .CHIPSELECT(1'b1), 275 | .CLOCK(clock), 276 | .STANDBY(1'b0), 277 | .SLEEP(1'b0), 278 | .POWEROFF(1'b1), 279 | .DATAOUT(mem_rdata_spram1_data[15:0]) 280 | ); 281 | 282 | SB_SPRAM256KA spram1_hi ( 283 | .ADDRESS(mem_addr[15:2]), 284 | .DATAIN(mem_wdata[31:16]), 285 | .MASKWREN({{2{spram1_valid && mem_wstrb[3]}}, {2{spram1_valid && mem_wstrb[2]}}}), 286 | .WREN(spram1_valid && mem_wstrb), 287 | .CHIPSELECT(1'b1), 288 | .CLOCK(clock), 289 | .STANDBY(1'b0), 290 | .SLEEP(1'b0), 291 | .POWEROFF(1'b1), 292 | .DATAOUT(mem_rdata_spram1_data[31:16]) 293 | ); 294 | 295 | SB_SPRAM256KA spram2_lo ( 296 | .ADDRESS(mem_addr[15:2]), 297 | .DATAIN(mem_wdata[15:0]), 298 | .MASKWREN({{2{spram2_valid && mem_wstrb[1]}}, {2{spram2_valid && mem_wstrb[0]}}}), 299 | .WREN(spram2_valid && mem_wstrb), 300 | .CHIPSELECT(1'b1), 301 | .CLOCK(clock), 302 | .STANDBY(1'b0), 303 | .SLEEP(1'b0), 304 | .POWEROFF(1'b1), 305 | .DATAOUT(mem_rdata_spram2_data[15:0]) 306 | ); 307 | 308 | SB_SPRAM256KA spram2_hi ( 309 | .ADDRESS(mem_addr[15:2]), 310 | .DATAIN(mem_wdata[31:16]), 311 | .MASKWREN({{2{spram2_valid && mem_wstrb[3]}}, {2{spram2_valid && mem_wstrb[2]}}}), 312 | .WREN(spram2_valid && mem_wstrb), 313 | .CHIPSELECT(1'b1), 314 | .CLOCK(clock), 315 | .STANDBY(1'b0), 316 | .SLEEP(1'b0), 317 | .POWEROFF(1'b1), 318 | .DATAOUT(mem_rdata_spram2_data[31:16]) 319 | ); 320 | 321 | spimemio spi ( 322 | .clk (clock), 323 | .resetn (!reset), 324 | 325 | .valid (spi_valid), 326 | .ready (spi_ready), 327 | .addr (mem_addr[23:0]), 328 | .rdata (spi_rdata), 329 | 330 | .flash_csb (flash_csb), 331 | .flash_clk (flash_clk), 332 | .flash_io0_oe (flash_io0_oe), 333 | .flash_io1_oe (flash_io1_oe), 334 | .flash_io2_oe (flash_io2_oe), 335 | .flash_io3_oe (flash_io3_oe), 336 | .flash_io0_do (flash_io0_do), 337 | .flash_io1_do (flash_io1_do), 338 | .flash_io2_do (flash_io2_do), 339 | .flash_io3_do (flash_io3_do), 340 | .flash_io0_di (flash_io0_di), 341 | .flash_io1_di (flash_io1_di), 342 | .flash_io2_di (flash_io2_di), 343 | .flash_io3_di (flash_io3_di), 344 | 345 | .cfgreg_we (spireg_valid ? mem_wstrb : 4'b 0000), 346 | .cfgreg_di (mem_wdata), 347 | .cfgreg_do (spireg_do) 348 | ); 349 | 350 | simpleuart uart ( 351 | .clk (clock), 352 | .resetn (!reset), 353 | 354 | .ser_tx (TX), 355 | .ser_rx (RX), 356 | 357 | .reg_div_we (uartdivreg_valid ? mem_wstrb : 4'b 0000), 358 | .reg_div_di (mem_wdata), 359 | .reg_div_do (uartdivreg_do), 360 | 361 | .reg_dat_we (uartdatreg_valid ? |mem_wstrb : 1'b 0), 362 | .reg_dat_re (uartdatreg_valid && !mem_wstrb), 363 | .reg_dat_di (mem_wdata), 364 | .reg_dat_do (uartdatreg_do), 365 | .reg_dat_wait (uartdatreg_wait) 366 | ); 367 | 368 | assign mem_rdata = 369 | mem_rdata_zpage_valid ? mem_rdata_zpage_data : 370 | mem_rdata_regs_valid ? mem_rdata_regs_data : 371 | mem_rdata_spram1_valid ? mem_rdata_spram1_data : 372 | mem_rdata_spram2_valid ? mem_rdata_spram2_data : 'bx; 373 | 374 | picorv_ez #( 375 | .CPI(2), 376 | .XLEN(32) 377 | ) cpu ( 378 | .clock (clock), 379 | .reset (reset), 380 | .mem_valid (mem_valid), 381 | .mem_ready (mem_ready), 382 | .mem_insn (mem_insn ), 383 | .mem_addr (mem_addr ), 384 | .mem_rdata (mem_rdata), 385 | .mem_wdata (mem_wdata), 386 | .mem_wstrb (mem_wstrb) 387 | ); 388 | endmodule 389 | -------------------------------------------------------------------------------- /source/.gitignore: -------------------------------------------------------------------------------- 1 | /picorv_core.v 2 | /dhry.elf 3 | /dhry.hex 4 | /dhry.vvp 5 | /dhry_1.o 6 | /dhry_2.o 7 | /syscalls.o 8 | /testbench.vcd 9 | /firmware.elf 10 | /firmware.hex 11 | /testbench 12 | /test.asc 13 | /test.json 14 | /test_nextpnr.log 15 | /test_yosys.log 16 | /.Xil/ 17 | /test_vivado.log 18 | -------------------------------------------------------------------------------- /source/Makefile: -------------------------------------------------------------------------------- 1 | 2 | PICORV_V = picorv_common.v picorv_core.v picorv_ctrl.v picorv_exec.v picorv_ldst.v 3 | 4 | test: testbench firmware.hex 5 | vvp -N testbench +vcd 6 | 7 | firmware.hex: firmware.elf 8 | riscv32-unknown-elf-objcopy -O verilog firmware.elf firmware.hex 9 | 10 | testbench: testbench.v $(PICORV_V) firmware.elf 11 | iverilog -DPICORV_DEBUG -DSTART="32'h`riscv32-unknown-elf-nm firmware.elf | grep ' T _start$$' | cut -f1 -d' '`" -o $@ \ 12 | -D'HEXFILE="firmware.hex"' -s testbench testbench.v $(PICORV_V) 13 | 14 | firmware.elf: firmware.S firmware.c 15 | riscv32-unknown-elf-gcc -march=rv32ic -Os -Wall -Wextra -o firmware.elf firmware.S firmware.c -ffreestanding -nostdlib 16 | 17 | picorv_core.v: picorv_core.py 18 | python3 picorv_core.py > picorv_core.v 19 | 20 | test.json: test.v $(PICORV_V) 21 | yosys -v2 -l test_yosys.log -p 'synth_ice40 -retime -json test.json -top test' test.v $(PICORV_V) 22 | 23 | test.asc: test.json 24 | nextpnr-ice40 -l test_nextpnr.log --hx8k --package ct256 --pcf-allow-unconstrained \ 25 | --freq 50 --json test.json --placer heap --asc test.asc 26 | 27 | vivado: test.v $(PICORV_V) 28 | rm -rf .Xil test_vivado.log 29 | vivado -mode batch -source test.tcl -nojournal -log test_vivado.log 30 | 31 | dhry: dhry.vvp dhry.hex 32 | vvp -N dhry.vvp +vcd +fast 33 | 34 | dhry.hex: dhry.elf 35 | riscv32-unknown-elf-objcopy -O verilog dhry.elf dhry.hex 36 | 37 | dhry.vvp: testbench.v $(PICORV_V) dhry.elf 38 | iverilog -DPICORV_DEBUG -DSTART="32'h`riscv32-unknown-elf-nm dhry.elf | grep ' T _start$$' | cut -f1 -d' '`" -o $@ \ 39 | -D'HEXFILE="dhry.hex"' -s testbench testbench.v $(PICORV_V) 40 | 41 | dhry.elf: dhry_1.o dhry_2.o syscalls.o 42 | riscv32-unknown-elf-gcc -march=rv32ic -o dhry.elf dhry_1.o dhry_2.o syscalls.o 43 | 44 | dhry_1.o: dhry_1.c dhry.h 45 | riscv32-unknown-elf-gcc -march=rv32ic -DRISCV -O3 -c -o dhry_1.o dhry_1.c -Wno-implicit-int -Wno-implicit-function-declaration 46 | 47 | dhry_2.o: dhry_2.c dhry.h 48 | riscv32-unknown-elf-gcc -march=rv32ic -DRISCV -O3 -c -o dhry_2.o dhry_2.c -Wno-implicit-int -Wno-implicit-function-declaration 49 | 50 | syscalls.o: syscalls.c 51 | riscv32-unknown-elf-gcc -march=rv32ic -DRISCV -O3 -c -o syscalls.o syscalls.c 52 | 53 | disasm: 54 | riscv32-unknown-elf-objdump -M numeric,no-aliases -s -d firmware.elf 55 | 56 | generate: $(PICORV_V) 57 | echo "// --------------------------------------------------------------------" > ../picorv.v.new 58 | echo "// GENERATED WITH 'make -C source generate' IN PICORV SOURCE REPOSITORY" >> ../picorv.v.new 59 | echo "// --------------------------------------------------------------------" >> ../picorv.v.new 60 | for f in $(PICORV_V); do echo; echo "// ---- $$f ----"; cat $$f; done >> ../picorv.v.new 61 | mv ../picorv.v.new ../picorv.v 62 | 63 | clean: 64 | rm -rf picorv_core.v testbench firmware.hex firmware.elf testbench.vcd 65 | rm -rf test.json test.asc test_yosys.log test_nextpnr.log 66 | rm -rf dhry.elf dhry.hex dhry.vvp dhry_1.o dhry_2.o syscalls.o 67 | rm -rf .Xil test_vivado.log 68 | -------------------------------------------------------------------------------- /source/README.md: -------------------------------------------------------------------------------- 1 | PicoRV Source Code 2 | ================== 3 | 4 | ``` 5 | # Generate ../picorv.v 6 | make generate 7 | 8 | # Run simple test bench 9 | make test 10 | 11 | # Run dhrystone benchmark 12 | make dhry 13 | 14 | # Test synthesis for iCE40HX with Yosys+nextpnr 15 | make test.asc 16 | 17 | # Test synthesis for Kintex UltraScale with Vivado 18 | make vivado 19 | ``` 20 | -------------------------------------------------------------------------------- /source/dhry.h: -------------------------------------------------------------------------------- 1 | /* 2 | **************************************************************************** 3 | * 4 | * "DHRYSTONE" Benchmark Program 5 | * ----------------------------- 6 | * 7 | * Version: C, Version 2.1 8 | * 9 | * File: dhry.h (part 1 of 3) 10 | * 11 | * Date: May 25, 1988 12 | * 13 | * Author: Reinhold P. Weicker 14 | * Siemens AG, AUT E 51 15 | * Postfach 3220 16 | * 8520 Erlangen 17 | * Germany (West) 18 | * Phone: [+49]-9131-7-20330 19 | * (8-17 Central European Time) 20 | * Usenet: ..!mcsun!unido!estevax!weicker 21 | * 22 | * Original Version (in Ada) published in 23 | * "Communications of the ACM" vol. 27., no. 10 (Oct. 1984), 24 | * pp. 1013 - 1030, together with the statistics 25 | * on which the distribution of statements etc. is based. 26 | * 27 | * In this C version, the following C library functions are used: 28 | * - strcpy, strcmp (inside the measurement loop) 29 | * - printf, scanf (outside the measurement loop) 30 | * In addition, Berkeley UNIX system calls "times ()" or "time ()" 31 | * are used for execution time measurement. For measurements 32 | * on other systems, these calls have to be changed. 33 | * 34 | * Collection of Results: 35 | * Reinhold Weicker (address see above) and 36 | * 37 | * Rick Richardson 38 | * PC Research. Inc. 39 | * 94 Apple Orchard Drive 40 | * Tinton Falls, NJ 07724 41 | * Phone: (201) 389-8963 (9-17 EST) 42 | * Usenet: ...!uunet!pcrat!rick 43 | * 44 | * Please send results to Rick Richardson and/or Reinhold Weicker. 45 | * Complete information should be given on hardware and software used. 46 | * Hardware information includes: Machine type, CPU, type and size 47 | * of caches; for microprocessors: clock frequency, memory speed 48 | * (number of wait states). 49 | * Software information includes: Compiler (and runtime library) 50 | * manufacturer and version, compilation switches, OS version. 51 | * The Operating System version may give an indication about the 52 | * compiler; Dhrystone itself performs no OS calls in the measurement loop. 53 | * 54 | * The complete output generated by the program should be mailed 55 | * such that at least some checks for correctness can be made. 56 | * 57 | *************************************************************************** 58 | * 59 | * History: This version C/2.1 has been made for two reasons: 60 | * 61 | * 1) There is an obvious need for a common C version of 62 | * Dhrystone, since C is at present the most popular system 63 | * programming language for the class of processors 64 | * (microcomputers, minicomputers) where Dhrystone is used most. 65 | * There should be, as far as possible, only one C version of 66 | * Dhrystone such that results can be compared without 67 | * restrictions. In the past, the C versions distributed 68 | * by Rick Richardson (Version 1.1) and by Reinhold Weicker 69 | * had small (though not significant) differences. 70 | * 71 | * 2) As far as it is possible without changes to the Dhrystone 72 | * statistics, optimizing compilers should be prevented from 73 | * removing significant statements. 74 | * 75 | * This C version has been developed in cooperation with 76 | * Rick Richardson (Tinton Falls, NJ), it incorporates many 77 | * ideas from the "Version 1.1" distributed previously by 78 | * him over the UNIX network Usenet. 79 | * I also thank Chaim Benedelac (National Semiconductor), 80 | * David Ditzel (SUN), Earl Killian and John Mashey (MIPS), 81 | * Alan Smith and Rafael Saavedra-Barrera (UC at Berkeley) 82 | * for their help with comments on earlier versions of the 83 | * benchmark. 84 | * 85 | * Changes: In the initialization part, this version follows mostly 86 | * Rick Richardson's version distributed via Usenet, not the 87 | * version distributed earlier via floppy disk by Reinhold Weicker. 88 | * As a concession to older compilers, names have been made 89 | * unique within the first 8 characters. 90 | * Inside the measurement loop, this version follows the 91 | * version previously distributed by Reinhold Weicker. 92 | * 93 | * At several places in the benchmark, code has been added, 94 | * but within the measurement loop only in branches that 95 | * are not executed. The intention is that optimizing compilers 96 | * should be prevented from moving code out of the measurement 97 | * loop, or from removing code altogether. Since the statements 98 | * that are executed within the measurement loop have NOT been 99 | * changed, the numbers defining the "Dhrystone distribution" 100 | * (distribution of statements, operand types and locality) 101 | * still hold. Except for sophisticated optimizing compilers, 102 | * execution times for this version should be the same as 103 | * for previous versions. 104 | * 105 | * Since it has proven difficult to subtract the time for the 106 | * measurement loop overhead in a correct way, the loop check 107 | * has been made a part of the benchmark. This does have 108 | * an impact - though a very minor one - on the distribution 109 | * statistics which have been updated for this version. 110 | * 111 | * All changes within the measurement loop are described 112 | * and discussed in the companion paper "Rationale for 113 | * Dhrystone version 2". 114 | * 115 | * Because of the self-imposed limitation that the order and 116 | * distribution of the executed statements should not be 117 | * changed, there are still cases where optimizing compilers 118 | * may not generate code for some statements. To a certain 119 | * degree, this is unavoidable for small synthetic benchmarks. 120 | * Users of the benchmark are advised to check code listings 121 | * whether code is generated for all statements of Dhrystone. 122 | * 123 | * Version 2.1 is identical to version 2.0 distributed via 124 | * the UNIX network Usenet in March 1988 except that it corrects 125 | * some minor deficiencies that were found by users of version 2.0. 126 | * The only change within the measurement loop is that a 127 | * non-executed "else" part was added to the "if" statement in 128 | * Func_3, and a non-executed "else" part removed from Proc_3. 129 | * 130 | *************************************************************************** 131 | * 132 | * Defines: The following "Defines" are possible: 133 | * -DREG=register (default: Not defined) 134 | * As an approximation to what an average C programmer 135 | * might do, the "register" storage class is applied 136 | * (if enabled by -DREG=register) 137 | * - for local variables, if they are used (dynamically) 138 | * five or more times 139 | * - for parameters if they are used (dynamically) 140 | * six or more times 141 | * Note that an optimal "register" strategy is 142 | * compiler-dependent, and that "register" declarations 143 | * do not necessarily lead to faster execution. 144 | * -DNOSTRUCTASSIGN (default: Not defined) 145 | * Define if the C compiler does not support 146 | * assignment of structures. 147 | * -DNOENUMS (default: Not defined) 148 | * Define if the C compiler does not support 149 | * enumeration types. 150 | * -DTIMES (default) 151 | * -DTIME 152 | * The "times" function of UNIX (returning process times) 153 | * or the "time" function (returning wallclock time) 154 | * is used for measurement. 155 | * For single user machines, "time ()" is adequate. For 156 | * multi-user machines where you cannot get single-user 157 | * access, use the "times ()" function. If you have 158 | * neither, use a stopwatch in the dead of night. 159 | * "printf"s are provided marking the points "Start Timer" 160 | * and "Stop Timer". DO NOT use the UNIX "time(1)" 161 | * command, as this will measure the total time to 162 | * run this program, which will (erroneously) include 163 | * the time to allocate storage (malloc) and to perform 164 | * the initialization. 165 | * -DHZ=nnn 166 | * In Berkeley UNIX, the function "times" returns process 167 | * time in 1/HZ seconds, with HZ = 60 for most systems. 168 | * CHECK YOUR SYSTEM DESCRIPTION BEFORE YOU JUST APPLY 169 | * A VALUE. 170 | * 171 | *************************************************************************** 172 | * 173 | * Compilation model and measurement (IMPORTANT): 174 | * 175 | * This C version of Dhrystone consists of three files: 176 | * - dhry.h (this file, containing global definitions and comments) 177 | * - dhry_1.c (containing the code corresponding to Ada package Pack_1) 178 | * - dhry_2.c (containing the code corresponding to Ada package Pack_2) 179 | * 180 | * The following "ground rules" apply for measurements: 181 | * - Separate compilation 182 | * - No procedure merging 183 | * - Otherwise, compiler optimizations are allowed but should be indicated 184 | * - Default results are those without register declarations 185 | * See the companion paper "Rationale for Dhrystone Version 2" for a more 186 | * detailed discussion of these ground rules. 187 | * 188 | * For 16-Bit processors (e.g. 80186, 80286), times for all compilation 189 | * models ("small", "medium", "large" etc.) should be given if possible, 190 | * together with a definition of these models for the compiler system used. 191 | * 192 | ************************************************************************** 193 | * 194 | * Dhrystone (C version) statistics: 195 | * 196 | * [Comment from the first distribution, updated for version 2. 197 | * Note that because of language differences, the numbers are slightly 198 | * different from the Ada version.] 199 | * 200 | * The following program contains statements of a high level programming 201 | * language (here: C) in a distribution considered representative: 202 | * 203 | * assignments 52 (51.0 %) 204 | * control statements 33 (32.4 %) 205 | * procedure, function calls 17 (16.7 %) 206 | * 207 | * 103 statements are dynamically executed. The program is balanced with 208 | * respect to the three aspects: 209 | * 210 | * - statement type 211 | * - operand type 212 | * - operand locality 213 | * operand global, local, parameter, or constant. 214 | * 215 | * The combination of these three aspects is balanced only approximately. 216 | * 217 | * 1. Statement Type: 218 | * ----------------- number 219 | * 220 | * V1 = V2 9 221 | * (incl. V1 = F(..) 222 | * V = Constant 12 223 | * Assignment, 7 224 | * with array element 225 | * Assignment, 6 226 | * with record component 227 | * -- 228 | * 34 34 229 | * 230 | * X = Y +|-|"&&"|"|" Z 5 231 | * X = Y +|-|"==" Constant 6 232 | * X = X +|- 1 3 233 | * X = Y *|/ Z 2 234 | * X = Expression, 1 235 | * two operators 236 | * X = Expression, 1 237 | * three operators 238 | * -- 239 | * 18 18 240 | * 241 | * if .... 14 242 | * with "else" 7 243 | * without "else" 7 244 | * executed 3 245 | * not executed 4 246 | * for ... 7 | counted every time 247 | * while ... 4 | the loop condition 248 | * do ... while 1 | is evaluated 249 | * switch ... 1 250 | * break 1 251 | * declaration with 1 252 | * initialization 253 | * -- 254 | * 34 34 255 | * 256 | * P (...) procedure call 11 257 | * user procedure 10 258 | * library procedure 1 259 | * X = F (...) 260 | * function call 6 261 | * user function 5 262 | * library function 1 263 | * -- 264 | * 17 17 265 | * --- 266 | * 103 267 | * 268 | * The average number of parameters in procedure or function calls 269 | * is 1.82 (not counting the function values as implicit parameters). 270 | * 271 | * 272 | * 2. Operators 273 | * ------------ 274 | * number approximate 275 | * percentage 276 | * 277 | * Arithmetic 32 50.8 278 | * 279 | * + 21 33.3 280 | * - 7 11.1 281 | * * 3 4.8 282 | * / (int div) 1 1.6 283 | * 284 | * Comparison 27 42.8 285 | * 286 | * == 9 14.3 287 | * /= 4 6.3 288 | * > 1 1.6 289 | * < 3 4.8 290 | * >= 1 1.6 291 | * <= 9 14.3 292 | * 293 | * Logic 4 6.3 294 | * 295 | * && (AND-THEN) 1 1.6 296 | * | (OR) 1 1.6 297 | * ! (NOT) 2 3.2 298 | * 299 | * -- ----- 300 | * 63 100.1 301 | * 302 | * 303 | * 3. Operand Type (counted once per operand reference): 304 | * --------------- 305 | * number approximate 306 | * percentage 307 | * 308 | * Integer 175 72.3 % 309 | * Character 45 18.6 % 310 | * Pointer 12 5.0 % 311 | * String30 6 2.5 % 312 | * Array 2 0.8 % 313 | * Record 2 0.8 % 314 | * --- ------- 315 | * 242 100.0 % 316 | * 317 | * When there is an access path leading to the final operand (e.g. a record 318 | * component), only the final data type on the access path is counted. 319 | * 320 | * 321 | * 4. Operand Locality: 322 | * ------------------- 323 | * number approximate 324 | * percentage 325 | * 326 | * local variable 114 47.1 % 327 | * global variable 22 9.1 % 328 | * parameter 45 18.6 % 329 | * value 23 9.5 % 330 | * reference 22 9.1 % 331 | * function result 6 2.5 % 332 | * constant 55 22.7 % 333 | * --- ------- 334 | * 242 100.0 % 335 | * 336 | * 337 | * The program does not compute anything meaningful, but it is syntactically 338 | * and semantically correct. All variables have a value assigned to them 339 | * before they are used as a source operand. 340 | * 341 | * There has been no explicit effort to account for the effects of a 342 | * cache, or to balance the use of long or short displacements for code or 343 | * data. 344 | * 345 | *************************************************************************** 346 | */ 347 | 348 | /* Compiler and system dependent definitions: */ 349 | 350 | #ifndef TIME 351 | //#define TIMES 352 | #endif 353 | /* Use times(2) time function unless */ 354 | /* explicitly defined otherwise */ 355 | 356 | #ifdef TIMES 357 | #include 358 | #include 359 | /* for "times" */ 360 | #endif 361 | 362 | #define Mic_secs_Per_Second 1000000.0 363 | /* Berkeley UNIX C returns process times in seconds/HZ */ 364 | 365 | #ifdef NOSTRUCTASSIGN 366 | #define structassign(d, s) memcpy(&(d), &(s), sizeof(d)) 367 | #else 368 | #define structassign(d, s) d = s 369 | #endif 370 | 371 | #ifdef NOENUM 372 | #define Ident_1 0 373 | #define Ident_2 1 374 | #define Ident_3 2 375 | #define Ident_4 3 376 | #define Ident_5 4 377 | typedef int Enumeration; 378 | #else 379 | typedef enum {Ident_1, Ident_2, Ident_3, Ident_4, Ident_5} 380 | Enumeration; 381 | #endif 382 | /* for boolean and enumeration types in Ada, Pascal */ 383 | 384 | /* General definitions: */ 385 | 386 | #include 387 | #include 388 | #include 389 | /* for strcpy, strcmp */ 390 | 391 | #define Null 0 392 | /* Value of a Null pointer */ 393 | #define true 1 394 | #define false 0 395 | 396 | typedef int One_Thirty; 397 | typedef int One_Fifty; 398 | typedef char Capital_Letter; 399 | typedef int Boolean; 400 | typedef char Str_30 [31]; 401 | typedef int Arr_1_Dim [50]; 402 | typedef int Arr_2_Dim [50] [50]; 403 | 404 | typedef struct record 405 | { 406 | struct record *Ptr_Comp; 407 | Enumeration Discr; 408 | union { 409 | struct { 410 | Enumeration Enum_Comp; 411 | int Int_Comp; 412 | char Str_Comp [31]; 413 | } var_1; 414 | struct { 415 | Enumeration E_Comp_2; 416 | char Str_2_Comp [31]; 417 | } var_2; 418 | struct { 419 | char Ch_1_Comp; 420 | char Ch_2_Comp; 421 | } var_3; 422 | } variant; 423 | } Rec_Type, *Rec_Pointer; 424 | 425 | 426 | -------------------------------------------------------------------------------- /source/dhry_1.c: -------------------------------------------------------------------------------- 1 | /* 2 | **************************************************************************** 3 | * 4 | * "DHRYSTONE" Benchmark Program 5 | * ----------------------------- 6 | * 7 | * Version: C, Version 2.1 8 | * 9 | * File: dhry_1.c (part 2 of 3) 10 | * 11 | * Date: May 25, 1988 12 | * 13 | * Author: Reinhold P. Weicker 14 | * 15 | **************************************************************************** 16 | */ 17 | 18 | #include "dhry.h" 19 | 20 | /* Global Variables: */ 21 | 22 | Rec_Pointer Ptr_Glob, 23 | Next_Ptr_Glob; 24 | int Int_Glob; 25 | Boolean Bool_Glob; 26 | char Ch_1_Glob, 27 | Ch_2_Glob; 28 | int Arr_1_Glob [50]; 29 | int Arr_2_Glob [50] [50]; 30 | 31 | //extern char *malloc (); 32 | Enumeration Func_1 (); 33 | /* forward declaration necessary since Enumeration may not simply be int */ 34 | 35 | #ifndef REG 36 | Boolean Reg = false; 37 | #define REG 38 | /* REG becomes defined as empty */ 39 | /* i.e. no register variables */ 40 | #else 41 | Boolean Reg = true; 42 | #endif 43 | 44 | /* variables for time measurement: */ 45 | 46 | #ifdef TIMES 47 | struct tms time_info; 48 | extern int times (); 49 | /* see library function "times" */ 50 | #define Too_Small_Time 120 51 | /* Measurements should last at least about 2 seconds */ 52 | #endif 53 | #ifdef TIME 54 | extern long time(); 55 | /* see library function "time" */ 56 | #define Too_Small_Time 2 57 | /* Measurements should last at least 2 seconds */ 58 | #endif 59 | #ifdef RISCV 60 | long rvcycles() 61 | { 62 | int cycles; 63 | asm volatile ("csrrs %0, 0xb00, zero" : "=r"(cycles)); 64 | // printf("[time() -> %d]", cycles); 65 | return cycles; 66 | } 67 | 68 | long rvinsns() 69 | { 70 | int insns; 71 | asm volatile ("csrrs %0, 0xb02, zero" : "=r"(insns)); 72 | // printf("[insn() -> %d]", insns); 73 | return insns; 74 | } 75 | #endif 76 | 77 | long Begin_Time, 78 | End_Time, 79 | User_Time; 80 | #ifdef RISCV 81 | long Begin_Insn, 82 | End_Insn, 83 | User_Insn; 84 | #endif 85 | float Microseconds, 86 | Dhrystones_Per_Second; 87 | 88 | /* end of variables for time measurement */ 89 | 90 | 91 | main () 92 | /*****/ 93 | 94 | /* main program, corresponds to procedures */ 95 | /* Main and Proc_0 in the Ada version */ 96 | { 97 | One_Fifty Int_1_Loc; 98 | REG One_Fifty Int_2_Loc; 99 | One_Fifty Int_3_Loc; 100 | REG char Ch_Index; 101 | Enumeration Enum_Loc; 102 | Str_30 Str_1_Loc; 103 | Str_30 Str_2_Loc; 104 | REG int Run_Index; 105 | REG int Number_Of_Runs; 106 | 107 | /* Initializations */ 108 | 109 | Next_Ptr_Glob = (Rec_Pointer) malloc (sizeof (Rec_Type)); 110 | Ptr_Glob = (Rec_Pointer) malloc (sizeof (Rec_Type)); 111 | 112 | Ptr_Glob->Ptr_Comp = Next_Ptr_Glob; 113 | Ptr_Glob->Discr = Ident_1; 114 | Ptr_Glob->variant.var_1.Enum_Comp = Ident_3; 115 | Ptr_Glob->variant.var_1.Int_Comp = 40; 116 | strcpy (Ptr_Glob->variant.var_1.Str_Comp, 117 | "DHRYSTONE PROGRAM, SOME STRING"); 118 | strcpy (Str_1_Loc, "DHRYSTONE PROGRAM, 1'ST STRING"); 119 | 120 | Arr_2_Glob [8][7] = 10; 121 | /* Was missing in published program. Without this statement, */ 122 | /* Arr_2_Glob [8][7] would have an undefined value. */ 123 | /* Warning: With 16-Bit processors and Number_Of_Runs > 32000, */ 124 | /* overflow may occur for this array element. */ 125 | 126 | printf ("\n"); 127 | printf ("Dhrystone Benchmark, Version 2.1 (Language: C)\n"); 128 | printf ("\n"); 129 | if (Reg) 130 | { 131 | printf ("Program compiled with 'register' attribute\n"); 132 | printf ("\n"); 133 | } 134 | else 135 | { 136 | printf ("Program compiled without 'register' attribute\n"); 137 | printf ("\n"); 138 | } 139 | printf ("Please give the number of runs through the benchmark: "); 140 | { 141 | // int n; 142 | // scanf ("%d", &n); 143 | Number_Of_Runs = 100; 144 | } 145 | printf ("\n"); 146 | 147 | printf ("Execution starts, %d runs through Dhrystone\n", Number_Of_Runs); 148 | 149 | /***************/ 150 | /* Start timer */ 151 | /***************/ 152 | 153 | #ifdef TIMES 154 | times (&time_info); 155 | Begin_Time = (long) time_info.tms_utime; 156 | #endif 157 | #ifdef TIME 158 | Begin_Time = time ( (long *) 0); 159 | #endif 160 | #ifdef RISCV 161 | Begin_Time = rvcycles(); 162 | Begin_Insn = rvinsns(); 163 | #endif 164 | 165 | for (Run_Index = 1; Run_Index <= Number_Of_Runs; ++Run_Index) 166 | { 167 | 168 | Proc_5(); 169 | Proc_4(); 170 | /* Ch_1_Glob == 'A', Ch_2_Glob == 'B', Bool_Glob == true */ 171 | Int_1_Loc = 2; 172 | Int_2_Loc = 3; 173 | strcpy (Str_2_Loc, "DHRYSTONE PROGRAM, 2'ND STRING"); 174 | Enum_Loc = Ident_2; 175 | Bool_Glob = ! Func_2 (Str_1_Loc, Str_2_Loc); 176 | /* Bool_Glob == 1 */ 177 | while (Int_1_Loc < Int_2_Loc) /* loop body executed once */ 178 | { 179 | Int_3_Loc = 5 * Int_1_Loc - Int_2_Loc; 180 | /* Int_3_Loc == 7 */ 181 | Proc_7 (Int_1_Loc, Int_2_Loc, &Int_3_Loc); 182 | /* Int_3_Loc == 7 */ 183 | Int_1_Loc += 1; 184 | } /* while */ 185 | /* Int_1_Loc == 3, Int_2_Loc == 3, Int_3_Loc == 7 */ 186 | Proc_8 (Arr_1_Glob, Arr_2_Glob, Int_1_Loc, Int_3_Loc); 187 | /* Int_Glob == 5 */ 188 | Proc_1 (Ptr_Glob); 189 | for (Ch_Index = 'A'; Ch_Index <= Ch_2_Glob; ++Ch_Index) 190 | /* loop body executed twice */ 191 | { 192 | if (Enum_Loc == Func_1 (Ch_Index, 'C')) 193 | /* then, not executed */ 194 | { 195 | Proc_6 (Ident_1, &Enum_Loc); 196 | strcpy (Str_2_Loc, "DHRYSTONE PROGRAM, 3'RD STRING"); 197 | Int_2_Loc = Run_Index; 198 | Int_Glob = Run_Index; 199 | } 200 | } 201 | /* Int_1_Loc == 3, Int_2_Loc == 3, Int_3_Loc == 7 */ 202 | Int_2_Loc = Int_2_Loc * Int_1_Loc; 203 | Int_1_Loc = Int_2_Loc / Int_3_Loc; 204 | Int_2_Loc = 7 * (Int_2_Loc - Int_3_Loc) - Int_1_Loc; 205 | /* Int_1_Loc == 1, Int_2_Loc == 13, Int_3_Loc == 7 */ 206 | Proc_2 (&Int_1_Loc); 207 | /* Int_1_Loc == 5 */ 208 | 209 | } /* loop "for Run_Index" */ 210 | 211 | /**************/ 212 | /* Stop timer */ 213 | /**************/ 214 | 215 | #ifdef TIMES 216 | times (&time_info); 217 | End_Time = (long) time_info.tms_utime; 218 | #endif 219 | #ifdef TIME 220 | End_Time = time ( (long *) 0); 221 | #endif 222 | #ifdef RISCV 223 | End_Time = rvcycles (); 224 | End_Insn = rvinsns (); 225 | #endif 226 | 227 | printf ("Execution ends\n"); 228 | printf ("\n"); 229 | printf ("Final values of the variables used in the benchmark:\n"); 230 | printf ("\n"); 231 | printf ("Int_Glob: %d\n", Int_Glob); 232 | printf (" should be: %d\n", 5); 233 | printf ("Bool_Glob: %d\n", Bool_Glob); 234 | printf (" should be: %d\n", 1); 235 | printf ("Ch_1_Glob: %c\n", Ch_1_Glob); 236 | printf (" should be: %c\n", 'A'); 237 | printf ("Ch_2_Glob: %c\n", Ch_2_Glob); 238 | printf (" should be: %c\n", 'B'); 239 | printf ("Arr_1_Glob[8]: %d\n", Arr_1_Glob[8]); 240 | printf (" should be: %d\n", 7); 241 | printf ("Arr_2_Glob[8][7]: %d\n", Arr_2_Glob[8][7]); 242 | printf (" should be: Number_Of_Runs + 10\n"); 243 | printf ("Ptr_Glob->\n"); 244 | printf (" Ptr_Comp: %d\n", (int) Ptr_Glob->Ptr_Comp); 245 | printf (" should be: (implementation-dependent)\n"); 246 | printf (" Discr: %d\n", Ptr_Glob->Discr); 247 | printf (" should be: %d\n", 0); 248 | printf (" Enum_Comp: %d\n", Ptr_Glob->variant.var_1.Enum_Comp); 249 | printf (" should be: %d\n", 2); 250 | printf (" Int_Comp: %d\n", Ptr_Glob->variant.var_1.Int_Comp); 251 | printf (" should be: %d\n", 17); 252 | printf (" Str_Comp: %s\n", Ptr_Glob->variant.var_1.Str_Comp); 253 | printf (" should be: DHRYSTONE PROGRAM, SOME STRING\n"); 254 | printf ("Next_Ptr_Glob->\n"); 255 | printf (" Ptr_Comp: %d\n", (int) Next_Ptr_Glob->Ptr_Comp); 256 | printf (" should be: (implementation-dependent), same as above\n"); 257 | printf (" Discr: %d\n", Next_Ptr_Glob->Discr); 258 | printf (" should be: %d\n", 0); 259 | printf (" Enum_Comp: %d\n", Next_Ptr_Glob->variant.var_1.Enum_Comp); 260 | printf (" should be: %d\n", 1); 261 | printf (" Int_Comp: %d\n", Next_Ptr_Glob->variant.var_1.Int_Comp); 262 | printf (" should be: %d\n", 18); 263 | printf (" Str_Comp: %s\n", 264 | Next_Ptr_Glob->variant.var_1.Str_Comp); 265 | printf (" should be: DHRYSTONE PROGRAM, SOME STRING\n"); 266 | printf ("Int_1_Loc: %d\n", Int_1_Loc); 267 | printf (" should be: %d\n", 5); 268 | printf ("Int_2_Loc: %d\n", Int_2_Loc); 269 | printf (" should be: %d\n", 13); 270 | printf ("Int_3_Loc: %d\n", Int_3_Loc); 271 | printf (" should be: %d\n", 7); 272 | printf ("Enum_Loc: %d\n", Enum_Loc); 273 | printf (" should be: %d\n", 1); 274 | printf ("Str_1_Loc: %s\n", Str_1_Loc); 275 | printf (" should be: DHRYSTONE PROGRAM, 1'ST STRING\n"); 276 | printf ("Str_2_Loc: %s\n", Str_2_Loc); 277 | printf (" should be: DHRYSTONE PROGRAM, 2'ND STRING\n"); 278 | printf ("\n"); 279 | 280 | User_Time = End_Time - Begin_Time; 281 | 282 | #ifdef RISCV 283 | User_Insn = End_Insn - Begin_Insn; 284 | 285 | printf("Number_Of_Runs: %d\n", Number_Of_Runs); 286 | printf("User_Time: %d cycles, %d insn\n", User_Time, User_Insn); 287 | 288 | int Cycles_Per_Instruction_x1000 = (1000 * User_Time) / User_Insn; 289 | printf("Cycles_Per_Instruction: %d.%d%d%d\n", Cycles_Per_Instruction_x1000 / 1000, 290 | (Cycles_Per_Instruction_x1000 / 100) % 10, 291 | (Cycles_Per_Instruction_x1000 / 10) % 10, 292 | (Cycles_Per_Instruction_x1000 / 1) % 10); 293 | 294 | int Dhrystones_Per_Second_Per_MHz = (Number_Of_Runs * 1000000) / User_Time; 295 | printf("Dhrystones_Per_Second_Per_MHz: %d\n", Dhrystones_Per_Second_Per_MHz); 296 | 297 | int DMIPS_Per_MHz_x1000 = (1000 * Dhrystones_Per_Second_Per_MHz) / 1757; 298 | printf("DMIPS_Per_MHz: %d.%d%d%d\n", DMIPS_Per_MHz_x1000 / 1000, 299 | (DMIPS_Per_MHz_x1000 / 100) % 10, 300 | (DMIPS_Per_MHz_x1000 / 10) % 10, 301 | (DMIPS_Per_MHz_x1000 / 1) % 10); 302 | #else 303 | if (User_Time < Too_Small_Time) 304 | { 305 | printf ("Measured time too small to obtain meaningful results\n"); 306 | printf ("Please increase number of runs\n"); 307 | printf ("\n"); 308 | } 309 | else 310 | { 311 | #ifdef TIME 312 | Microseconds = (float) User_Time * Mic_secs_Per_Second 313 | / (float) Number_Of_Runs; 314 | Dhrystones_Per_Second = (float) Number_Of_Runs / (float) User_Time; 315 | #else 316 | Microseconds = (float) User_Time * Mic_secs_Per_Second 317 | / ((float) HZ * ((float) Number_Of_Runs)); 318 | Dhrystones_Per_Second = ((float) HZ * (float) Number_Of_Runs) 319 | / (float) User_Time; 320 | #endif 321 | printf ("Microseconds for one run through Dhrystone: "); 322 | printf ("%6.1f \n", Microseconds); 323 | printf ("Dhrystones per Second: "); 324 | printf ("%6.1f \n", Dhrystones_Per_Second); 325 | printf ("\n"); 326 | } 327 | #endif 328 | 329 | putchar(0); 330 | } 331 | 332 | 333 | Proc_1 (Ptr_Val_Par) 334 | /******************/ 335 | 336 | REG Rec_Pointer Ptr_Val_Par; 337 | /* executed once */ 338 | { 339 | REG Rec_Pointer Next_Record = Ptr_Val_Par->Ptr_Comp; 340 | /* == Ptr_Glob_Next */ 341 | /* Local variable, initialized with Ptr_Val_Par->Ptr_Comp, */ 342 | /* corresponds to "rename" in Ada, "with" in Pascal */ 343 | 344 | structassign (*Ptr_Val_Par->Ptr_Comp, *Ptr_Glob); 345 | Ptr_Val_Par->variant.var_1.Int_Comp = 5; 346 | Next_Record->variant.var_1.Int_Comp 347 | = Ptr_Val_Par->variant.var_1.Int_Comp; 348 | Next_Record->Ptr_Comp = Ptr_Val_Par->Ptr_Comp; 349 | Proc_3 (&Next_Record->Ptr_Comp); 350 | /* Ptr_Val_Par->Ptr_Comp->Ptr_Comp 351 | == Ptr_Glob->Ptr_Comp */ 352 | if (Next_Record->Discr == Ident_1) 353 | /* then, executed */ 354 | { 355 | Next_Record->variant.var_1.Int_Comp = 6; 356 | Proc_6 (Ptr_Val_Par->variant.var_1.Enum_Comp, 357 | &Next_Record->variant.var_1.Enum_Comp); 358 | Next_Record->Ptr_Comp = Ptr_Glob->Ptr_Comp; 359 | Proc_7 (Next_Record->variant.var_1.Int_Comp, 10, 360 | &Next_Record->variant.var_1.Int_Comp); 361 | } 362 | else /* not executed */ 363 | structassign (*Ptr_Val_Par, *Ptr_Val_Par->Ptr_Comp); 364 | } /* Proc_1 */ 365 | 366 | 367 | Proc_2 (Int_Par_Ref) 368 | /******************/ 369 | /* executed once */ 370 | /* *Int_Par_Ref == 1, becomes 4 */ 371 | 372 | One_Fifty *Int_Par_Ref; 373 | { 374 | One_Fifty Int_Loc; 375 | Enumeration Enum_Loc; 376 | 377 | Int_Loc = *Int_Par_Ref + 10; 378 | do /* executed once */ 379 | if (Ch_1_Glob == 'A') 380 | /* then, executed */ 381 | { 382 | Int_Loc -= 1; 383 | *Int_Par_Ref = Int_Loc - Int_Glob; 384 | Enum_Loc = Ident_1; 385 | } /* if */ 386 | while (Enum_Loc != Ident_1); /* true */ 387 | } /* Proc_2 */ 388 | 389 | 390 | Proc_3 (Ptr_Ref_Par) 391 | /******************/ 392 | /* executed once */ 393 | /* Ptr_Ref_Par becomes Ptr_Glob */ 394 | 395 | Rec_Pointer *Ptr_Ref_Par; 396 | 397 | { 398 | if (Ptr_Glob != Null) 399 | /* then, executed */ 400 | *Ptr_Ref_Par = Ptr_Glob->Ptr_Comp; 401 | Proc_7 (10, Int_Glob, &Ptr_Glob->variant.var_1.Int_Comp); 402 | } /* Proc_3 */ 403 | 404 | 405 | Proc_4 () /* without parameters */ 406 | /*******/ 407 | /* executed once */ 408 | { 409 | Boolean Bool_Loc; 410 | 411 | Bool_Loc = Ch_1_Glob == 'A'; 412 | Bool_Glob = Bool_Loc | Bool_Glob; 413 | Ch_2_Glob = 'B'; 414 | } /* Proc_4 */ 415 | 416 | 417 | Proc_5 () /* without parameters */ 418 | /*******/ 419 | /* executed once */ 420 | { 421 | Ch_1_Glob = 'A'; 422 | Bool_Glob = false; 423 | } /* Proc_5 */ 424 | 425 | 426 | /* Procedure for the assignment of structures, */ 427 | /* if the C compiler doesn't support this feature */ 428 | #ifdef NOSTRUCTASSIGN 429 | memcpy (d, s, l) 430 | register char *d; 431 | register char *s; 432 | register int l; 433 | { 434 | while (l--) *d++ = *s++; 435 | } 436 | #endif 437 | 438 | 439 | -------------------------------------------------------------------------------- /source/dhry_1_orig.c: -------------------------------------------------------------------------------- 1 | /* 2 | **************************************************************************** 3 | * 4 | * "DHRYSTONE" Benchmark Program 5 | * ----------------------------- 6 | * 7 | * Version: C, Version 2.1 8 | * 9 | * File: dhry_1.c (part 2 of 3) 10 | * 11 | * Date: May 25, 1988 12 | * 13 | * Author: Reinhold P. Weicker 14 | * 15 | **************************************************************************** 16 | */ 17 | 18 | #include "dhry.h" 19 | 20 | /* Global Variables: */ 21 | 22 | Rec_Pointer Ptr_Glob, 23 | Next_Ptr_Glob; 24 | int Int_Glob; 25 | Boolean Bool_Glob; 26 | char Ch_1_Glob, 27 | Ch_2_Glob; 28 | int Arr_1_Glob [50]; 29 | int Arr_2_Glob [50] [50]; 30 | 31 | extern char *malloc (); 32 | Enumeration Func_1 (); 33 | /* forward declaration necessary since Enumeration may not simply be int */ 34 | 35 | #ifndef REG 36 | Boolean Reg = false; 37 | #define REG 38 | /* REG becomes defined as empty */ 39 | /* i.e. no register variables */ 40 | #else 41 | Boolean Reg = true; 42 | #endif 43 | 44 | /* variables for time measurement: */ 45 | 46 | #ifdef TIMES 47 | struct tms time_info; 48 | extern int times (); 49 | /* see library function "times" */ 50 | #define Too_Small_Time 120 51 | /* Measurements should last at least about 2 seconds */ 52 | #endif 53 | #ifdef TIME 54 | extern long time(); 55 | /* see library function "time" */ 56 | #define Too_Small_Time 2 57 | /* Measurements should last at least 2 seconds */ 58 | #endif 59 | 60 | long Begin_Time, 61 | End_Time, 62 | User_Time; 63 | float Microseconds, 64 | Dhrystones_Per_Second; 65 | 66 | /* end of variables for time measurement */ 67 | 68 | 69 | main () 70 | /*****/ 71 | 72 | /* main program, corresponds to procedures */ 73 | /* Main and Proc_0 in the Ada version */ 74 | { 75 | One_Fifty Int_1_Loc; 76 | REG One_Fifty Int_2_Loc; 77 | One_Fifty Int_3_Loc; 78 | REG char Ch_Index; 79 | Enumeration Enum_Loc; 80 | Str_30 Str_1_Loc; 81 | Str_30 Str_2_Loc; 82 | REG int Run_Index; 83 | REG int Number_Of_Runs; 84 | 85 | /* Initializations */ 86 | 87 | Next_Ptr_Glob = (Rec_Pointer) malloc (sizeof (Rec_Type)); 88 | Ptr_Glob = (Rec_Pointer) malloc (sizeof (Rec_Type)); 89 | 90 | Ptr_Glob->Ptr_Comp = Next_Ptr_Glob; 91 | Ptr_Glob->Discr = Ident_1; 92 | Ptr_Glob->variant.var_1.Enum_Comp = Ident_3; 93 | Ptr_Glob->variant.var_1.Int_Comp = 40; 94 | strcpy (Ptr_Glob->variant.var_1.Str_Comp, 95 | "DHRYSTONE PROGRAM, SOME STRING"); 96 | strcpy (Str_1_Loc, "DHRYSTONE PROGRAM, 1'ST STRING"); 97 | 98 | Arr_2_Glob [8][7] = 10; 99 | /* Was missing in published program. Without this statement, */ 100 | /* Arr_2_Glob [8][7] would have an undefined value. */ 101 | /* Warning: With 16-Bit processors and Number_Of_Runs > 32000, */ 102 | /* overflow may occur for this array element. */ 103 | 104 | printf ("\n"); 105 | printf ("Dhrystone Benchmark, Version 2.1 (Language: C)\n"); 106 | printf ("\n"); 107 | if (Reg) 108 | { 109 | printf ("Program compiled with 'register' attribute\n"); 110 | printf ("\n"); 111 | } 112 | else 113 | { 114 | printf ("Program compiled without 'register' attribute\n"); 115 | printf ("\n"); 116 | } 117 | printf ("Please give the number of runs through the benchmark: "); 118 | { 119 | int n; 120 | scanf ("%d", &n); 121 | Number_Of_Runs = n; 122 | } 123 | printf ("\n"); 124 | 125 | printf ("Execution starts, %d runs through Dhrystone\n", Number_Of_Runs); 126 | 127 | /***************/ 128 | /* Start timer */ 129 | /***************/ 130 | 131 | #ifdef TIMES 132 | times (&time_info); 133 | Begin_Time = (long) time_info.tms_utime; 134 | #endif 135 | #ifdef TIME 136 | Begin_Time = time ( (long *) 0); 137 | #endif 138 | 139 | for (Run_Index = 1; Run_Index <= Number_Of_Runs; ++Run_Index) 140 | { 141 | 142 | Proc_5(); 143 | Proc_4(); 144 | /* Ch_1_Glob == 'A', Ch_2_Glob == 'B', Bool_Glob == true */ 145 | Int_1_Loc = 2; 146 | Int_2_Loc = 3; 147 | strcpy (Str_2_Loc, "DHRYSTONE PROGRAM, 2'ND STRING"); 148 | Enum_Loc = Ident_2; 149 | Bool_Glob = ! Func_2 (Str_1_Loc, Str_2_Loc); 150 | /* Bool_Glob == 1 */ 151 | while (Int_1_Loc < Int_2_Loc) /* loop body executed once */ 152 | { 153 | Int_3_Loc = 5 * Int_1_Loc - Int_2_Loc; 154 | /* Int_3_Loc == 7 */ 155 | Proc_7 (Int_1_Loc, Int_2_Loc, &Int_3_Loc); 156 | /* Int_3_Loc == 7 */ 157 | Int_1_Loc += 1; 158 | } /* while */ 159 | /* Int_1_Loc == 3, Int_2_Loc == 3, Int_3_Loc == 7 */ 160 | Proc_8 (Arr_1_Glob, Arr_2_Glob, Int_1_Loc, Int_3_Loc); 161 | /* Int_Glob == 5 */ 162 | Proc_1 (Ptr_Glob); 163 | for (Ch_Index = 'A'; Ch_Index <= Ch_2_Glob; ++Ch_Index) 164 | /* loop body executed twice */ 165 | { 166 | if (Enum_Loc == Func_1 (Ch_Index, 'C')) 167 | /* then, not executed */ 168 | { 169 | Proc_6 (Ident_1, &Enum_Loc); 170 | strcpy (Str_2_Loc, "DHRYSTONE PROGRAM, 3'RD STRING"); 171 | Int_2_Loc = Run_Index; 172 | Int_Glob = Run_Index; 173 | } 174 | } 175 | /* Int_1_Loc == 3, Int_2_Loc == 3, Int_3_Loc == 7 */ 176 | Int_2_Loc = Int_2_Loc * Int_1_Loc; 177 | Int_1_Loc = Int_2_Loc / Int_3_Loc; 178 | Int_2_Loc = 7 * (Int_2_Loc - Int_3_Loc) - Int_1_Loc; 179 | /* Int_1_Loc == 1, Int_2_Loc == 13, Int_3_Loc == 7 */ 180 | Proc_2 (&Int_1_Loc); 181 | /* Int_1_Loc == 5 */ 182 | 183 | } /* loop "for Run_Index" */ 184 | 185 | /**************/ 186 | /* Stop timer */ 187 | /**************/ 188 | 189 | #ifdef TIMES 190 | times (&time_info); 191 | End_Time = (long) time_info.tms_utime; 192 | #endif 193 | #ifdef TIME 194 | End_Time = time ( (long *) 0); 195 | #endif 196 | 197 | printf ("Execution ends\n"); 198 | printf ("\n"); 199 | printf ("Final values of the variables used in the benchmark:\n"); 200 | printf ("\n"); 201 | printf ("Int_Glob: %d\n", Int_Glob); 202 | printf (" should be: %d\n", 5); 203 | printf ("Bool_Glob: %d\n", Bool_Glob); 204 | printf (" should be: %d\n", 1); 205 | printf ("Ch_1_Glob: %c\n", Ch_1_Glob); 206 | printf (" should be: %c\n", 'A'); 207 | printf ("Ch_2_Glob: %c\n", Ch_2_Glob); 208 | printf (" should be: %c\n", 'B'); 209 | printf ("Arr_1_Glob[8]: %d\n", Arr_1_Glob[8]); 210 | printf (" should be: %d\n", 7); 211 | printf ("Arr_2_Glob[8][7]: %d\n", Arr_2_Glob[8][7]); 212 | printf (" should be: Number_Of_Runs + 10\n"); 213 | printf ("Ptr_Glob->\n"); 214 | printf (" Ptr_Comp: %d\n", (int) Ptr_Glob->Ptr_Comp); 215 | printf (" should be: (implementation-dependent)\n"); 216 | printf (" Discr: %d\n", Ptr_Glob->Discr); 217 | printf (" should be: %d\n", 0); 218 | printf (" Enum_Comp: %d\n", Ptr_Glob->variant.var_1.Enum_Comp); 219 | printf (" should be: %d\n", 2); 220 | printf (" Int_Comp: %d\n", Ptr_Glob->variant.var_1.Int_Comp); 221 | printf (" should be: %d\n", 17); 222 | printf (" Str_Comp: %s\n", Ptr_Glob->variant.var_1.Str_Comp); 223 | printf (" should be: DHRYSTONE PROGRAM, SOME STRING\n"); 224 | printf ("Next_Ptr_Glob->\n"); 225 | printf (" Ptr_Comp: %d\n", (int) Next_Ptr_Glob->Ptr_Comp); 226 | printf (" should be: (implementation-dependent), same as above\n"); 227 | printf (" Discr: %d\n", Next_Ptr_Glob->Discr); 228 | printf (" should be: %d\n", 0); 229 | printf (" Enum_Comp: %d\n", Next_Ptr_Glob->variant.var_1.Enum_Comp); 230 | printf (" should be: %d\n", 1); 231 | printf (" Int_Comp: %d\n", Next_Ptr_Glob->variant.var_1.Int_Comp); 232 | printf (" should be: %d\n", 18); 233 | printf (" Str_Comp: %s\n", 234 | Next_Ptr_Glob->variant.var_1.Str_Comp); 235 | printf (" should be: DHRYSTONE PROGRAM, SOME STRING\n"); 236 | printf ("Int_1_Loc: %d\n", Int_1_Loc); 237 | printf (" should be: %d\n", 5); 238 | printf ("Int_2_Loc: %d\n", Int_2_Loc); 239 | printf (" should be: %d\n", 13); 240 | printf ("Int_3_Loc: %d\n", Int_3_Loc); 241 | printf (" should be: %d\n", 7); 242 | printf ("Enum_Loc: %d\n", Enum_Loc); 243 | printf (" should be: %d\n", 1); 244 | printf ("Str_1_Loc: %s\n", Str_1_Loc); 245 | printf (" should be: DHRYSTONE PROGRAM, 1'ST STRING\n"); 246 | printf ("Str_2_Loc: %s\n", Str_2_Loc); 247 | printf (" should be: DHRYSTONE PROGRAM, 2'ND STRING\n"); 248 | printf ("\n"); 249 | 250 | User_Time = End_Time - Begin_Time; 251 | 252 | if (User_Time < Too_Small_Time) 253 | { 254 | printf ("Measured time too small to obtain meaningful results\n"); 255 | printf ("Please increase number of runs\n"); 256 | printf ("\n"); 257 | } 258 | else 259 | { 260 | #ifdef TIME 261 | Microseconds = (float) User_Time * Mic_secs_Per_Second 262 | / (float) Number_Of_Runs; 263 | Dhrystones_Per_Second = (float) Number_Of_Runs / (float) User_Time; 264 | #else 265 | Microseconds = (float) User_Time * Mic_secs_Per_Second 266 | / ((float) HZ * ((float) Number_Of_Runs)); 267 | Dhrystones_Per_Second = ((float) HZ * (float) Number_Of_Runs) 268 | / (float) User_Time; 269 | #endif 270 | printf ("Microseconds for one run through Dhrystone: "); 271 | printf ("%6.1f \n", Microseconds); 272 | printf ("Dhrystones per Second: "); 273 | printf ("%6.1f \n", Dhrystones_Per_Second); 274 | printf ("\n"); 275 | } 276 | 277 | } 278 | 279 | 280 | Proc_1 (Ptr_Val_Par) 281 | /******************/ 282 | 283 | REG Rec_Pointer Ptr_Val_Par; 284 | /* executed once */ 285 | { 286 | REG Rec_Pointer Next_Record = Ptr_Val_Par->Ptr_Comp; 287 | /* == Ptr_Glob_Next */ 288 | /* Local variable, initialized with Ptr_Val_Par->Ptr_Comp, */ 289 | /* corresponds to "rename" in Ada, "with" in Pascal */ 290 | 291 | structassign (*Ptr_Val_Par->Ptr_Comp, *Ptr_Glob); 292 | Ptr_Val_Par->variant.var_1.Int_Comp = 5; 293 | Next_Record->variant.var_1.Int_Comp 294 | = Ptr_Val_Par->variant.var_1.Int_Comp; 295 | Next_Record->Ptr_Comp = Ptr_Val_Par->Ptr_Comp; 296 | Proc_3 (&Next_Record->Ptr_Comp); 297 | /* Ptr_Val_Par->Ptr_Comp->Ptr_Comp 298 | == Ptr_Glob->Ptr_Comp */ 299 | if (Next_Record->Discr == Ident_1) 300 | /* then, executed */ 301 | { 302 | Next_Record->variant.var_1.Int_Comp = 6; 303 | Proc_6 (Ptr_Val_Par->variant.var_1.Enum_Comp, 304 | &Next_Record->variant.var_1.Enum_Comp); 305 | Next_Record->Ptr_Comp = Ptr_Glob->Ptr_Comp; 306 | Proc_7 (Next_Record->variant.var_1.Int_Comp, 10, 307 | &Next_Record->variant.var_1.Int_Comp); 308 | } 309 | else /* not executed */ 310 | structassign (*Ptr_Val_Par, *Ptr_Val_Par->Ptr_Comp); 311 | } /* Proc_1 */ 312 | 313 | 314 | Proc_2 (Int_Par_Ref) 315 | /******************/ 316 | /* executed once */ 317 | /* *Int_Par_Ref == 1, becomes 4 */ 318 | 319 | One_Fifty *Int_Par_Ref; 320 | { 321 | One_Fifty Int_Loc; 322 | Enumeration Enum_Loc; 323 | 324 | Int_Loc = *Int_Par_Ref + 10; 325 | do /* executed once */ 326 | if (Ch_1_Glob == 'A') 327 | /* then, executed */ 328 | { 329 | Int_Loc -= 1; 330 | *Int_Par_Ref = Int_Loc - Int_Glob; 331 | Enum_Loc = Ident_1; 332 | } /* if */ 333 | while (Enum_Loc != Ident_1); /* true */ 334 | } /* Proc_2 */ 335 | 336 | 337 | Proc_3 (Ptr_Ref_Par) 338 | /******************/ 339 | /* executed once */ 340 | /* Ptr_Ref_Par becomes Ptr_Glob */ 341 | 342 | Rec_Pointer *Ptr_Ref_Par; 343 | 344 | { 345 | if (Ptr_Glob != Null) 346 | /* then, executed */ 347 | *Ptr_Ref_Par = Ptr_Glob->Ptr_Comp; 348 | Proc_7 (10, Int_Glob, &Ptr_Glob->variant.var_1.Int_Comp); 349 | } /* Proc_3 */ 350 | 351 | 352 | Proc_4 () /* without parameters */ 353 | /*******/ 354 | /* executed once */ 355 | { 356 | Boolean Bool_Loc; 357 | 358 | Bool_Loc = Ch_1_Glob == 'A'; 359 | Bool_Glob = Bool_Loc | Bool_Glob; 360 | Ch_2_Glob = 'B'; 361 | } /* Proc_4 */ 362 | 363 | 364 | Proc_5 () /* without parameters */ 365 | /*******/ 366 | /* executed once */ 367 | { 368 | Ch_1_Glob = 'A'; 369 | Bool_Glob = false; 370 | } /* Proc_5 */ 371 | 372 | 373 | /* Procedure for the assignment of structures, */ 374 | /* if the C compiler doesn't support this feature */ 375 | #ifdef NOSTRUCTASSIGN 376 | memcpy (d, s, l) 377 | register char *d; 378 | register char *s; 379 | register int l; 380 | { 381 | while (l--) *d++ = *s++; 382 | } 383 | #endif 384 | 385 | 386 | -------------------------------------------------------------------------------- /source/dhry_2.c: -------------------------------------------------------------------------------- 1 | /* 2 | **************************************************************************** 3 | * 4 | * "DHRYSTONE" Benchmark Program 5 | * ----------------------------- 6 | * 7 | * Version: C, Version 2.1 8 | * 9 | * File: dhry_2.c (part 3 of 3) 10 | * 11 | * Date: May 25, 1988 12 | * 13 | * Author: Reinhold P. Weicker 14 | * 15 | **************************************************************************** 16 | */ 17 | 18 | #include "dhry.h" 19 | 20 | #ifndef REG 21 | #define REG 22 | /* REG becomes defined as empty */ 23 | /* i.e. no register variables */ 24 | #endif 25 | 26 | extern int Int_Glob; 27 | extern char Ch_1_Glob; 28 | 29 | 30 | Proc_6 (Enum_Val_Par, Enum_Ref_Par) 31 | /*********************************/ 32 | /* executed once */ 33 | /* Enum_Val_Par == Ident_3, Enum_Ref_Par becomes Ident_2 */ 34 | 35 | Enumeration Enum_Val_Par; 36 | Enumeration *Enum_Ref_Par; 37 | { 38 | *Enum_Ref_Par = Enum_Val_Par; 39 | if (! Func_3 (Enum_Val_Par)) 40 | /* then, not executed */ 41 | *Enum_Ref_Par = Ident_4; 42 | switch (Enum_Val_Par) 43 | { 44 | case Ident_1: 45 | *Enum_Ref_Par = Ident_1; 46 | break; 47 | case Ident_2: 48 | if (Int_Glob > 100) 49 | /* then */ 50 | *Enum_Ref_Par = Ident_1; 51 | else *Enum_Ref_Par = Ident_4; 52 | break; 53 | case Ident_3: /* executed */ 54 | *Enum_Ref_Par = Ident_2; 55 | break; 56 | case Ident_4: break; 57 | case Ident_5: 58 | *Enum_Ref_Par = Ident_3; 59 | break; 60 | } /* switch */ 61 | } /* Proc_6 */ 62 | 63 | 64 | Proc_7 (Int_1_Par_Val, Int_2_Par_Val, Int_Par_Ref) 65 | /**********************************************/ 66 | /* executed three times */ 67 | /* first call: Int_1_Par_Val == 2, Int_2_Par_Val == 3, */ 68 | /* Int_Par_Ref becomes 7 */ 69 | /* second call: Int_1_Par_Val == 10, Int_2_Par_Val == 5, */ 70 | /* Int_Par_Ref becomes 17 */ 71 | /* third call: Int_1_Par_Val == 6, Int_2_Par_Val == 10, */ 72 | /* Int_Par_Ref becomes 18 */ 73 | One_Fifty Int_1_Par_Val; 74 | One_Fifty Int_2_Par_Val; 75 | One_Fifty *Int_Par_Ref; 76 | { 77 | One_Fifty Int_Loc; 78 | 79 | Int_Loc = Int_1_Par_Val + 2; 80 | *Int_Par_Ref = Int_2_Par_Val + Int_Loc; 81 | } /* Proc_7 */ 82 | 83 | 84 | Proc_8 (Arr_1_Par_Ref, Arr_2_Par_Ref, Int_1_Par_Val, Int_2_Par_Val) 85 | /*********************************************************************/ 86 | /* executed once */ 87 | /* Int_Par_Val_1 == 3 */ 88 | /* Int_Par_Val_2 == 7 */ 89 | Arr_1_Dim Arr_1_Par_Ref; 90 | Arr_2_Dim Arr_2_Par_Ref; 91 | int Int_1_Par_Val; 92 | int Int_2_Par_Val; 93 | { 94 | REG One_Fifty Int_Index; 95 | REG One_Fifty Int_Loc; 96 | 97 | Int_Loc = Int_1_Par_Val + 5; 98 | Arr_1_Par_Ref [Int_Loc] = Int_2_Par_Val; 99 | Arr_1_Par_Ref [Int_Loc+1] = Arr_1_Par_Ref [Int_Loc]; 100 | Arr_1_Par_Ref [Int_Loc+30] = Int_Loc; 101 | for (Int_Index = Int_Loc; Int_Index <= Int_Loc+1; ++Int_Index) 102 | Arr_2_Par_Ref [Int_Loc] [Int_Index] = Int_Loc; 103 | Arr_2_Par_Ref [Int_Loc] [Int_Loc-1] += 1; 104 | Arr_2_Par_Ref [Int_Loc+20] [Int_Loc] = Arr_1_Par_Ref [Int_Loc]; 105 | Int_Glob = 5; 106 | } /* Proc_8 */ 107 | 108 | 109 | Enumeration Func_1 (Ch_1_Par_Val, Ch_2_Par_Val) 110 | /*************************************************/ 111 | /* executed three times */ 112 | /* first call: Ch_1_Par_Val == 'H', Ch_2_Par_Val == 'R' */ 113 | /* second call: Ch_1_Par_Val == 'A', Ch_2_Par_Val == 'C' */ 114 | /* third call: Ch_1_Par_Val == 'B', Ch_2_Par_Val == 'C' */ 115 | 116 | Capital_Letter Ch_1_Par_Val; 117 | Capital_Letter Ch_2_Par_Val; 118 | { 119 | Capital_Letter Ch_1_Loc; 120 | Capital_Letter Ch_2_Loc; 121 | 122 | Ch_1_Loc = Ch_1_Par_Val; 123 | Ch_2_Loc = Ch_1_Loc; 124 | if (Ch_2_Loc != Ch_2_Par_Val) 125 | /* then, executed */ 126 | return (Ident_1); 127 | else /* not executed */ 128 | { 129 | Ch_1_Glob = Ch_1_Loc; 130 | return (Ident_2); 131 | } 132 | } /* Func_1 */ 133 | 134 | 135 | Boolean Func_2 (Str_1_Par_Ref, Str_2_Par_Ref) 136 | /*************************************************/ 137 | /* executed once */ 138 | /* Str_1_Par_Ref == "DHRYSTONE PROGRAM, 1'ST STRING" */ 139 | /* Str_2_Par_Ref == "DHRYSTONE PROGRAM, 2'ND STRING" */ 140 | 141 | Str_30 Str_1_Par_Ref; 142 | Str_30 Str_2_Par_Ref; 143 | { 144 | REG One_Thirty Int_Loc; 145 | Capital_Letter Ch_Loc; 146 | 147 | Int_Loc = 2; 148 | while (Int_Loc <= 2) /* loop body executed once */ 149 | if (Func_1 (Str_1_Par_Ref[Int_Loc], 150 | Str_2_Par_Ref[Int_Loc+1]) == Ident_1) 151 | /* then, executed */ 152 | { 153 | Ch_Loc = 'A'; 154 | Int_Loc += 1; 155 | } /* if, while */ 156 | if (Ch_Loc >= 'W' && Ch_Loc < 'Z') 157 | /* then, not executed */ 158 | Int_Loc = 7; 159 | if (Ch_Loc == 'R') 160 | /* then, not executed */ 161 | return (true); 162 | else /* executed */ 163 | { 164 | if (strcmp (Str_1_Par_Ref, Str_2_Par_Ref) > 0) 165 | /* then, not executed */ 166 | { 167 | Int_Loc += 7; 168 | Int_Glob = Int_Loc; 169 | return (true); 170 | } 171 | else /* executed */ 172 | return (false); 173 | } /* if Ch_Loc */ 174 | } /* Func_2 */ 175 | 176 | 177 | Boolean Func_3 (Enum_Par_Val) 178 | /***************************/ 179 | /* executed once */ 180 | /* Enum_Par_Val == Ident_3 */ 181 | Enumeration Enum_Par_Val; 182 | { 183 | Enumeration Enum_Loc; 184 | 185 | Enum_Loc = Enum_Par_Val; 186 | if (Enum_Loc == Ident_3) 187 | /* then, executed */ 188 | return (true); 189 | else /* not executed */ 190 | return (false); 191 | } /* Func_3 */ 192 | 193 | -------------------------------------------------------------------------------- /source/dhry_orig.h: -------------------------------------------------------------------------------- 1 | /* 2 | **************************************************************************** 3 | * 4 | * "DHRYSTONE" Benchmark Program 5 | * ----------------------------- 6 | * 7 | * Version: C, Version 2.1 8 | * 9 | * File: dhry.h (part 1 of 3) 10 | * 11 | * Date: May 25, 1988 12 | * 13 | * Author: Reinhold P. Weicker 14 | * Siemens AG, AUT E 51 15 | * Postfach 3220 16 | * 8520 Erlangen 17 | * Germany (West) 18 | * Phone: [+49]-9131-7-20330 19 | * (8-17 Central European Time) 20 | * Usenet: ..!mcsun!unido!estevax!weicker 21 | * 22 | * Original Version (in Ada) published in 23 | * "Communications of the ACM" vol. 27., no. 10 (Oct. 1984), 24 | * pp. 1013 - 1030, together with the statistics 25 | * on which the distribution of statements etc. is based. 26 | * 27 | * In this C version, the following C library functions are used: 28 | * - strcpy, strcmp (inside the measurement loop) 29 | * - printf, scanf (outside the measurement loop) 30 | * In addition, Berkeley UNIX system calls "times ()" or "time ()" 31 | * are used for execution time measurement. For measurements 32 | * on other systems, these calls have to be changed. 33 | * 34 | * Collection of Results: 35 | * Reinhold Weicker (address see above) and 36 | * 37 | * Rick Richardson 38 | * PC Research. Inc. 39 | * 94 Apple Orchard Drive 40 | * Tinton Falls, NJ 07724 41 | * Phone: (201) 389-8963 (9-17 EST) 42 | * Usenet: ...!uunet!pcrat!rick 43 | * 44 | * Please send results to Rick Richardson and/or Reinhold Weicker. 45 | * Complete information should be given on hardware and software used. 46 | * Hardware information includes: Machine type, CPU, type and size 47 | * of caches; for microprocessors: clock frequency, memory speed 48 | * (number of wait states). 49 | * Software information includes: Compiler (and runtime library) 50 | * manufacturer and version, compilation switches, OS version. 51 | * The Operating System version may give an indication about the 52 | * compiler; Dhrystone itself performs no OS calls in the measurement loop. 53 | * 54 | * The complete output generated by the program should be mailed 55 | * such that at least some checks for correctness can be made. 56 | * 57 | *************************************************************************** 58 | * 59 | * History: This version C/2.1 has been made for two reasons: 60 | * 61 | * 1) There is an obvious need for a common C version of 62 | * Dhrystone, since C is at present the most popular system 63 | * programming language for the class of processors 64 | * (microcomputers, minicomputers) where Dhrystone is used most. 65 | * There should be, as far as possible, only one C version of 66 | * Dhrystone such that results can be compared without 67 | * restrictions. In the past, the C versions distributed 68 | * by Rick Richardson (Version 1.1) and by Reinhold Weicker 69 | * had small (though not significant) differences. 70 | * 71 | * 2) As far as it is possible without changes to the Dhrystone 72 | * statistics, optimizing compilers should be prevented from 73 | * removing significant statements. 74 | * 75 | * This C version has been developed in cooperation with 76 | * Rick Richardson (Tinton Falls, NJ), it incorporates many 77 | * ideas from the "Version 1.1" distributed previously by 78 | * him over the UNIX network Usenet. 79 | * I also thank Chaim Benedelac (National Semiconductor), 80 | * David Ditzel (SUN), Earl Killian and John Mashey (MIPS), 81 | * Alan Smith and Rafael Saavedra-Barrera (UC at Berkeley) 82 | * for their help with comments on earlier versions of the 83 | * benchmark. 84 | * 85 | * Changes: In the initialization part, this version follows mostly 86 | * Rick Richardson's version distributed via Usenet, not the 87 | * version distributed earlier via floppy disk by Reinhold Weicker. 88 | * As a concession to older compilers, names have been made 89 | * unique within the first 8 characters. 90 | * Inside the measurement loop, this version follows the 91 | * version previously distributed by Reinhold Weicker. 92 | * 93 | * At several places in the benchmark, code has been added, 94 | * but within the measurement loop only in branches that 95 | * are not executed. The intention is that optimizing compilers 96 | * should be prevented from moving code out of the measurement 97 | * loop, or from removing code altogether. Since the statements 98 | * that are executed within the measurement loop have NOT been 99 | * changed, the numbers defining the "Dhrystone distribution" 100 | * (distribution of statements, operand types and locality) 101 | * still hold. Except for sophisticated optimizing compilers, 102 | * execution times for this version should be the same as 103 | * for previous versions. 104 | * 105 | * Since it has proven difficult to subtract the time for the 106 | * measurement loop overhead in a correct way, the loop check 107 | * has been made a part of the benchmark. This does have 108 | * an impact - though a very minor one - on the distribution 109 | * statistics which have been updated for this version. 110 | * 111 | * All changes within the measurement loop are described 112 | * and discussed in the companion paper "Rationale for 113 | * Dhrystone version 2". 114 | * 115 | * Because of the self-imposed limitation that the order and 116 | * distribution of the executed statements should not be 117 | * changed, there are still cases where optimizing compilers 118 | * may not generate code for some statements. To a certain 119 | * degree, this is unavoidable for small synthetic benchmarks. 120 | * Users of the benchmark are advised to check code listings 121 | * whether code is generated for all statements of Dhrystone. 122 | * 123 | * Version 2.1 is identical to version 2.0 distributed via 124 | * the UNIX network Usenet in March 1988 except that it corrects 125 | * some minor deficiencies that were found by users of version 2.0. 126 | * The only change within the measurement loop is that a 127 | * non-executed "else" part was added to the "if" statement in 128 | * Func_3, and a non-executed "else" part removed from Proc_3. 129 | * 130 | *************************************************************************** 131 | * 132 | * Defines: The following "Defines" are possible: 133 | * -DREG=register (default: Not defined) 134 | * As an approximation to what an average C programmer 135 | * might do, the "register" storage class is applied 136 | * (if enabled by -DREG=register) 137 | * - for local variables, if they are used (dynamically) 138 | * five or more times 139 | * - for parameters if they are used (dynamically) 140 | * six or more times 141 | * Note that an optimal "register" strategy is 142 | * compiler-dependent, and that "register" declarations 143 | * do not necessarily lead to faster execution. 144 | * -DNOSTRUCTASSIGN (default: Not defined) 145 | * Define if the C compiler does not support 146 | * assignment of structures. 147 | * -DNOENUMS (default: Not defined) 148 | * Define if the C compiler does not support 149 | * enumeration types. 150 | * -DTIMES (default) 151 | * -DTIME 152 | * The "times" function of UNIX (returning process times) 153 | * or the "time" function (returning wallclock time) 154 | * is used for measurement. 155 | * For single user machines, "time ()" is adequate. For 156 | * multi-user machines where you cannot get single-user 157 | * access, use the "times ()" function. If you have 158 | * neither, use a stopwatch in the dead of night. 159 | * "printf"s are provided marking the points "Start Timer" 160 | * and "Stop Timer". DO NOT use the UNIX "time(1)" 161 | * command, as this will measure the total time to 162 | * run this program, which will (erroneously) include 163 | * the time to allocate storage (malloc) and to perform 164 | * the initialization. 165 | * -DHZ=nnn 166 | * In Berkeley UNIX, the function "times" returns process 167 | * time in 1/HZ seconds, with HZ = 60 for most systems. 168 | * CHECK YOUR SYSTEM DESCRIPTION BEFORE YOU JUST APPLY 169 | * A VALUE. 170 | * 171 | *************************************************************************** 172 | * 173 | * Compilation model and measurement (IMPORTANT): 174 | * 175 | * This C version of Dhrystone consists of three files: 176 | * - dhry.h (this file, containing global definitions and comments) 177 | * - dhry_1.c (containing the code corresponding to Ada package Pack_1) 178 | * - dhry_2.c (containing the code corresponding to Ada package Pack_2) 179 | * 180 | * The following "ground rules" apply for measurements: 181 | * - Separate compilation 182 | * - No procedure merging 183 | * - Otherwise, compiler optimizations are allowed but should be indicated 184 | * - Default results are those without register declarations 185 | * See the companion paper "Rationale for Dhrystone Version 2" for a more 186 | * detailed discussion of these ground rules. 187 | * 188 | * For 16-Bit processors (e.g. 80186, 80286), times for all compilation 189 | * models ("small", "medium", "large" etc.) should be given if possible, 190 | * together with a definition of these models for the compiler system used. 191 | * 192 | ************************************************************************** 193 | * 194 | * Dhrystone (C version) statistics: 195 | * 196 | * [Comment from the first distribution, updated for version 2. 197 | * Note that because of language differences, the numbers are slightly 198 | * different from the Ada version.] 199 | * 200 | * The following program contains statements of a high level programming 201 | * language (here: C) in a distribution considered representative: 202 | * 203 | * assignments 52 (51.0 %) 204 | * control statements 33 (32.4 %) 205 | * procedure, function calls 17 (16.7 %) 206 | * 207 | * 103 statements are dynamically executed. The program is balanced with 208 | * respect to the three aspects: 209 | * 210 | * - statement type 211 | * - operand type 212 | * - operand locality 213 | * operand global, local, parameter, or constant. 214 | * 215 | * The combination of these three aspects is balanced only approximately. 216 | * 217 | * 1. Statement Type: 218 | * ----------------- number 219 | * 220 | * V1 = V2 9 221 | * (incl. V1 = F(..) 222 | * V = Constant 12 223 | * Assignment, 7 224 | * with array element 225 | * Assignment, 6 226 | * with record component 227 | * -- 228 | * 34 34 229 | * 230 | * X = Y +|-|"&&"|"|" Z 5 231 | * X = Y +|-|"==" Constant 6 232 | * X = X +|- 1 3 233 | * X = Y *|/ Z 2 234 | * X = Expression, 1 235 | * two operators 236 | * X = Expression, 1 237 | * three operators 238 | * -- 239 | * 18 18 240 | * 241 | * if .... 14 242 | * with "else" 7 243 | * without "else" 7 244 | * executed 3 245 | * not executed 4 246 | * for ... 7 | counted every time 247 | * while ... 4 | the loop condition 248 | * do ... while 1 | is evaluated 249 | * switch ... 1 250 | * break 1 251 | * declaration with 1 252 | * initialization 253 | * -- 254 | * 34 34 255 | * 256 | * P (...) procedure call 11 257 | * user procedure 10 258 | * library procedure 1 259 | * X = F (...) 260 | * function call 6 261 | * user function 5 262 | * library function 1 263 | * -- 264 | * 17 17 265 | * --- 266 | * 103 267 | * 268 | * The average number of parameters in procedure or function calls 269 | * is 1.82 (not counting the function values as implicit parameters). 270 | * 271 | * 272 | * 2. Operators 273 | * ------------ 274 | * number approximate 275 | * percentage 276 | * 277 | * Arithmetic 32 50.8 278 | * 279 | * + 21 33.3 280 | * - 7 11.1 281 | * * 3 4.8 282 | * / (int div) 1 1.6 283 | * 284 | * Comparison 27 42.8 285 | * 286 | * == 9 14.3 287 | * /= 4 6.3 288 | * > 1 1.6 289 | * < 3 4.8 290 | * >= 1 1.6 291 | * <= 9 14.3 292 | * 293 | * Logic 4 6.3 294 | * 295 | * && (AND-THEN) 1 1.6 296 | * | (OR) 1 1.6 297 | * ! (NOT) 2 3.2 298 | * 299 | * -- ----- 300 | * 63 100.1 301 | * 302 | * 303 | * 3. Operand Type (counted once per operand reference): 304 | * --------------- 305 | * number approximate 306 | * percentage 307 | * 308 | * Integer 175 72.3 % 309 | * Character 45 18.6 % 310 | * Pointer 12 5.0 % 311 | * String30 6 2.5 % 312 | * Array 2 0.8 % 313 | * Record 2 0.8 % 314 | * --- ------- 315 | * 242 100.0 % 316 | * 317 | * When there is an access path leading to the final operand (e.g. a record 318 | * component), only the final data type on the access path is counted. 319 | * 320 | * 321 | * 4. Operand Locality: 322 | * ------------------- 323 | * number approximate 324 | * percentage 325 | * 326 | * local variable 114 47.1 % 327 | * global variable 22 9.1 % 328 | * parameter 45 18.6 % 329 | * value 23 9.5 % 330 | * reference 22 9.1 % 331 | * function result 6 2.5 % 332 | * constant 55 22.7 % 333 | * --- ------- 334 | * 242 100.0 % 335 | * 336 | * 337 | * The program does not compute anything meaningful, but it is syntactically 338 | * and semantically correct. All variables have a value assigned to them 339 | * before they are used as a source operand. 340 | * 341 | * There has been no explicit effort to account for the effects of a 342 | * cache, or to balance the use of long or short displacements for code or 343 | * data. 344 | * 345 | *************************************************************************** 346 | */ 347 | 348 | /* Compiler and system dependent definitions: */ 349 | 350 | #ifndef TIME 351 | #define TIMES 352 | #endif 353 | /* Use times(2) time function unless */ 354 | /* explicitly defined otherwise */ 355 | 356 | #ifdef TIMES 357 | #include 358 | #include 359 | /* for "times" */ 360 | #endif 361 | 362 | #define Mic_secs_Per_Second 1000000.0 363 | /* Berkeley UNIX C returns process times in seconds/HZ */ 364 | 365 | #ifdef NOSTRUCTASSIGN 366 | #define structassign(d, s) memcpy(&(d), &(s), sizeof(d)) 367 | #else 368 | #define structassign(d, s) d = s 369 | #endif 370 | 371 | #ifdef NOENUM 372 | #define Ident_1 0 373 | #define Ident_2 1 374 | #define Ident_3 2 375 | #define Ident_4 3 376 | #define Ident_5 4 377 | typedef int Enumeration; 378 | #else 379 | typedef enum {Ident_1, Ident_2, Ident_3, Ident_4, Ident_5} 380 | Enumeration; 381 | #endif 382 | /* for boolean and enumeration types in Ada, Pascal */ 383 | 384 | /* General definitions: */ 385 | 386 | #include 387 | /* for strcpy, strcmp */ 388 | 389 | #define Null 0 390 | /* Value of a Null pointer */ 391 | #define true 1 392 | #define false 0 393 | 394 | typedef int One_Thirty; 395 | typedef int One_Fifty; 396 | typedef char Capital_Letter; 397 | typedef int Boolean; 398 | typedef char Str_30 [31]; 399 | typedef int Arr_1_Dim [50]; 400 | typedef int Arr_2_Dim [50] [50]; 401 | 402 | typedef struct record 403 | { 404 | struct record *Ptr_Comp; 405 | Enumeration Discr; 406 | union { 407 | struct { 408 | Enumeration Enum_Comp; 409 | int Int_Comp; 410 | char Str_Comp [31]; 411 | } var_1; 412 | struct { 413 | Enumeration E_Comp_2; 414 | char Str_2_Comp [31]; 415 | } var_2; 416 | struct { 417 | char Ch_1_Comp; 418 | char Ch_2_Comp; 419 | } var_3; 420 | } variant; 421 | } Rec_Type, *Rec_Pointer; 422 | 423 | 424 | -------------------------------------------------------------------------------- /source/firmware.S: -------------------------------------------------------------------------------- 1 | /* 2 | * PicoRV -- A Small and Extensible RISC-V Processor 3 | * 4 | * Copyright (C) 2019 Claire Wolf 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | * 18 | */ 19 | 20 | .section .text 21 | .global main 22 | .global _start 23 | _start: 24 | addi x1, zero, 0 25 | addi x2, zero, 0 26 | addi x3, zero, 0 27 | addi x4, zero, 0 28 | addi x5, zero, 0 29 | addi x6, zero, 0 30 | addi x7, zero, 0 31 | addi x8, zero, 0 32 | addi x9, zero, 0 33 | addi x10, zero, 0 34 | addi x11, zero, 0 35 | addi x12, zero, 0 36 | addi x13, zero, 0 37 | addi x14, zero, 0 38 | addi x15, zero, 0 39 | addi x16, zero, 0 40 | addi x17, zero, 0 41 | addi x18, zero, 0 42 | addi x19, zero, 0 43 | addi x20, zero, 0 44 | addi x21, zero, 0 45 | addi x22, zero, 0 46 | addi x23, zero, 0 47 | addi x24, zero, 0 48 | addi x25, zero, 0 49 | addi x26, zero, 0 50 | addi x27, zero, 0 51 | addi x28, zero, 0 52 | addi x29, zero, 0 53 | addi x30, zero, 0 54 | addi x31, zero, 0 55 | li sp, 0x00100000 56 | call main 57 | end: 58 | j end 59 | -------------------------------------------------------------------------------- /source/firmware.c: -------------------------------------------------------------------------------- 1 | /* 2 | * PicoRV -- A Small and Extensible RISC-V Processor 3 | * 4 | * Copyright (C) 2019 Claire Wolf 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | * 18 | */ 19 | 20 | void putc(int c) 21 | { 22 | volatile char *p = (void*)0x00100000; 23 | *p = c; 24 | } 25 | 26 | void puts(char *s) 27 | { 28 | while (*s) putc(*(s++)); 29 | } 30 | 31 | int main() 32 | { 33 | puts("Hello World!\n"); 34 | putc(0); 35 | return 0; 36 | } 37 | -------------------------------------------------------------------------------- /source/picorv_common.v: -------------------------------------------------------------------------------- 1 | /* 2 | * PicoRV -- A Small and Extensible RISC-V Processor 3 | * 4 | * Copyright (C) 2019 Claire Wolf 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | * 18 | */ 19 | 20 | module picorv_ez #( 21 | parameter integer CPI = 1, 22 | parameter integer XLEN = 32, 23 | parameter integer ILEN = 32, 24 | parameter integer IALIGN = 32, 25 | parameter [0:0] PCPI = 0, 26 | parameter [0:0] PCPI_RS3 = 0, 27 | parameter [XLEN-1:0] SPINIT = 1, 28 | parameter [XLEN-1:0] RST_VECTOR = 0, 29 | parameter [XLEN-1:0] ISR_VECTOR = 0 30 | ) ( 31 | // control 32 | input clock, 33 | input reset, 34 | 35 | // interrupt control 36 | input irq_req, 37 | output irq_ack, 38 | 39 | // memory interface 40 | output mem_valid, 41 | input mem_ready, 42 | output mem_insn, 43 | output [XLEN-1:0] mem_addr, 44 | input [ 31:0] mem_rdata, 45 | output [ 31:0] mem_wdata, 46 | output [ 3:0] mem_wstrb, 47 | 48 | // pcpi 49 | output pcpi_valid, 50 | output [ILEN-1:0] pcpi_insn, 51 | output [ 15:0] pcpi_prefix, 52 | output [XLEN-1:0] pcpi_pc, 53 | output [XLEN-1:0] pcpi_rs1_data, 54 | output [XLEN-1:0] pcpi_rs2_data, 55 | output [XLEN-1:0] pcpi_rs3_data, 56 | input pcpi_ready, 57 | input pcpi_wb_write, 58 | input [XLEN-1:0] pcpi_wb_data, 59 | input pcpi_br_enable, 60 | input [XLEN-1:0] pcpi_br_nextpc 61 | ); 62 | wire pcpi_valid_raw; 63 | wire pcpi_rs1_valid; 64 | wire pcpi_rs2_valid; 65 | wire pcpi_rs3_valid; 66 | wire pcpi_wb_valid; 67 | 68 | wire [XLEN-1:0] pcpi_rs3_data_raw; 69 | assign pcpi_rs3_data = PCPI_RS3 ? pcpi_rs3_data_raw : 0; 70 | 71 | assign pcpi_valid = pcpi_valid_raw && pcpi_rs1_valid && pcpi_rs2_valid && (PCPI_RS3 && pcpi_rs3_valid) && pcpi_wb_valid; 72 | 73 | assign irq_ack = 0; 74 | 75 | picorv_core #( 76 | .CPI(CPI), 77 | .XLEN(XLEN), 78 | .ILEN(ILEN), 79 | .IALIGN(IALIGN), 80 | .SPINIT(SPINIT) 81 | ) core ( 82 | .clock (clock ), 83 | .reset (reset ), 84 | .rvec (RST_VECTOR ), 85 | 86 | .mem_valid (mem_valid ), 87 | .mem_ready (mem_ready ), 88 | .mem_insn (mem_insn ), 89 | .mem_addr (mem_addr ), 90 | .mem_rdata (mem_rdata ), 91 | .mem_wdata (mem_wdata ), 92 | .mem_wstrb (mem_wstrb ), 93 | 94 | .decode_valid ( ), 95 | .decode_insn ( ), 96 | .decode_prefix ( ), 97 | 98 | .pcpi_valid (pcpi_valid_raw), 99 | .pcpi_insn (pcpi_insn ), 100 | .pcpi_prefix (pcpi_prefix ), 101 | .pcpi_pc (pcpi_pc ), 102 | .pcpi_rs1_valid (pcpi_rs1_valid), 103 | .pcpi_rs1_data (pcpi_rs1_data ), 104 | .pcpi_rs2_valid (pcpi_rs2_valid), 105 | .pcpi_rs2_data (pcpi_rs2_data ), 106 | .pcpi_rs3_valid (pcpi_rs3_valid), 107 | .pcpi_rs3_data (pcpi_rs3_data_raw), 108 | .pcpi_ready (PCPI && pcpi_ready), 109 | .pcpi_wb_valid (pcpi_wb_valid ), 110 | .pcpi_wb_async (1'b 0 ), 111 | .pcpi_wb_write (PCPI && pcpi_ready ? pcpi_wb_write : 1'b 0), 112 | .pcpi_wb_data (PCPI && pcpi_ready ? pcpi_wb_data : {XLEN{1'b0}}), 113 | .pcpi_br_enable (PCPI && pcpi_ready ? pcpi_br_enable : 1'b 0), 114 | .pcpi_br_nextpc (PCPI && pcpi_ready ? pcpi_br_nextpc : {XLEN{1'b0}}), 115 | 116 | .awb_valid (1'b 0 ), 117 | .awb_ready ( ), 118 | .awb_addr (5'd 0 ), 119 | .awb_data ({XLEN{1'b0}} ) 120 | ); 121 | endmodule 122 | -------------------------------------------------------------------------------- /source/picorv_core.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # 3 | # PicoRV -- A Small and Extensible RISC-V Processor 4 | # 5 | # Copyright (C) 2019 Claire Wolf 6 | # 7 | # Permission to use, copy, modify, and/or distribute this software for any 8 | # purpose with or without fee is hereby granted, provided that the above 9 | # copyright notice and this permission notice appear in all copies. 10 | # 11 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 | # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 | # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 | # 19 | 20 | def csrs_cfg(): 21 | add_csr("mcycle", 0xb00) 22 | add_csr("minstret", 0xb02) 23 | add_csr("mcycleh", 0xb80) 24 | add_csr("minstreth", 0xb82) 25 | 26 | add_csr_post_vlog(""" 27 | {csr_mcycleh, csr_mcycle} = {csr_mcycleh, csr_mcycle} + 1; 28 | {csr_minstreth, csr_minstret} = {csr_minstreth, csr_minstret} + (pcpi_valid && pcpi_ready_ctrl); 29 | """) 30 | 31 | def components_cfg(): 32 | add_component("picorv_exec", "exec", br=True, params={"CPI": "CPI"}) 33 | add_component("picorv_ldst", "ldst", mem=True, awb=True) 34 | 35 | ##################################################################### 36 | 37 | print("""// generated by picorv_core.py 38 | module picorv_core #( 39 | parameter integer CPI = 2, 40 | parameter integer CSRS = 1, 41 | parameter integer XLEN = 32, 42 | parameter integer ILEN = 32, 43 | parameter integer IALIGN = 16, 44 | parameter integer RPORTS = 3, 45 | parameter [XLEN-1:0] SPINIT = 1 46 | ) ( 47 | // control 48 | input clock, 49 | input reset, 50 | input [XLEN-1:0] rvec, 51 | 52 | // memory interface 53 | output mem_valid, 54 | input mem_ready, 55 | output mem_insn, 56 | output [XLEN-1:0] mem_addr, 57 | input [ 31:0] mem_rdata, 58 | output [ 31:0] mem_wdata, 59 | output [ 3:0] mem_wstrb, 60 | 61 | // decode 62 | output decode_valid, 63 | output [ILEN-1:0] decode_insn, 64 | output [ 15:0] decode_prefix, 65 | 66 | // pcpi 67 | output pcpi_valid, 68 | output [ILEN-1:0] pcpi_insn, 69 | output [ 15:0] pcpi_prefix, 70 | output [XLEN-1:0] pcpi_pc, 71 | output pcpi_rs1_valid, 72 | output [XLEN-1:0] pcpi_rs1_data, 73 | output pcpi_rs2_valid, 74 | output [XLEN-1:0] pcpi_rs2_data, 75 | output pcpi_rs3_valid, 76 | output [XLEN-1:0] pcpi_rs3_data, 77 | input pcpi_ready, 78 | output pcpi_wb_valid, 79 | input pcpi_wb_async, 80 | input pcpi_wb_write, 81 | input [XLEN-1:0] pcpi_wb_data, 82 | input pcpi_br_enable, 83 | input [XLEN-1:0] pcpi_br_nextpc, 84 | 85 | // async writeback 86 | input awb_valid, 87 | output awb_ready, 88 | input [ 4:0] awb_addr, 89 | input [XLEN-1:0] awb_data 90 | ); 91 | wire pcpi_ready_ctrl; 92 | """) 93 | 94 | ##################################################################### 95 | 96 | csrs = [] 97 | csraddrs = dict() 98 | csrrstvals = dict() 99 | csrs_pre_vlog_snippets = [] 100 | csrs_post_vlog_snippets = [] 101 | 102 | print(" wire mem_reqst_csrs = 0;") 103 | print(" wire mem_grant_csrs;") 104 | print(" wire mem_valid_csrs = 0;") 105 | print(" wire mem_ready_csrs;") 106 | print(" wire [XLEN-1:0] mem_addr_csrs = 0;") 107 | print(" wire [ 31:0] mem_wdata_csrs = 0;") 108 | print(" wire [ 3:0] mem_wstrb_csrs = 0;") 109 | 110 | print(" wire pcpi_ready_csrs;") 111 | print(" wire pcpi_wb_write_csrs;") 112 | print(" wire pcpi_wb_async_csrs = 0;") 113 | print(" wire [XLEN-1:0] pcpi_wb_data_csrs;") 114 | print(" wire pcpi_br_enable_csrs = 0;") 115 | print(" wire [XLEN-1:0] pcpi_br_nextpc_csrs = 0;") 116 | 117 | print(" wire awb_valid_csrs = 0;") 118 | print(" wire awb_ready_csrs;") 119 | print(" wire [ 4:0] awb_addr_csrs = 0;") 120 | print(" wire [XLEN-1:0] awb_data_csrs = 0;") 121 | 122 | print(" wire csrinsn_valid = pcpi_valid && pcpi_insn[6:0] == 7'b 1110011 && pcpi_insn[13:12] != 2'b 00 && (pcpi_rs1_valid || pcpi_insn[14]);") 123 | print(" wire [11:0] csrinsn_addr = pcpi_insn[31:20];") 124 | print(" wire [XLEN-1:0] csrinsn_data = pcpi_insn[14] ? pcpi_insn[19:15] : pcpi_rs1_data;") 125 | print(" wire [1:0] csrinsn_op = pcpi_insn[13:12];") 126 | print(" reg csrinsn_ready;") 127 | print(" reg [XLEN-1:0] csrinsn_out;") 128 | print(" wire [XLEN-1:0] csrinsn_clr = 0;") 129 | print(" wire [XLEN-1:0] csrinsn_set = 0;") 130 | 131 | def add_csr(name, addr, rstval="0"): 132 | csrs.append(name) 133 | csraddrs[name] = addr 134 | csrrstvals[name] = rstval 135 | print(" reg [XLEN-1:0] csr_%s;" % name) 136 | print(" reg [XLEN-1:0] csr_%s_reg;" % name) 137 | print(" wire [XLEN-1:0] csr_%s_clr = 0;" % name) 138 | print(" wire [XLEN-1:0] csr_%s_set = 0;" % name) 139 | print(" always @(posedge clock) csr_%s_reg <= reset ? %s : csr_%s;" % (name, rstval, name)) 140 | 141 | def add_csr_pre_vlog(code): 142 | csrs_pre_vlog_snippets.append(code) 143 | 144 | def add_csr_post_vlog(code): 145 | csrs_post_vlog_snippets.append(code) 146 | 147 | csrs_cfg() 148 | 149 | print(" always @* begin") 150 | print(" csrinsn_ready = 0;") 151 | print(" csrinsn_out = 0;") 152 | 153 | for n in csrs: 154 | print(" csr_%s = csr_%s_reg;" % (n, n)) 155 | 156 | for c in csrs_pre_vlog_snippets: 157 | print(c) 158 | 159 | print(" if (csrinsn_valid) begin") 160 | print(" case (csrinsn_addr)") 161 | 162 | for n in csrs: 163 | print(" 12'h %03x: begin csrinsn_ready = 1; csrinsn_out = csr_%s; csr_%s = (csr_%s & ~csrinsn_clr) | csrinsn_set; end" % (csraddrs[n], n, n, n)) 164 | 165 | print(" endcase") 166 | print(" end else begin") 167 | 168 | for n in csrs: 169 | print(" csr_%s = (csr_%s & ~csr_%s_clr) | csr_%s_set;" % (n, n, n, n)) 170 | 171 | print(" end") 172 | 173 | for c in csrs_post_vlog_snippets: 174 | print(c) 175 | 176 | print(" if (!CSRS) begin") 177 | for n in csrs: 178 | print(" csr_%s = %s;" % (n, csrrstvals[n])) 179 | print(" end") 180 | 181 | print(" end") 182 | 183 | print(" assign pcpi_ready_csrs = csrinsn_ready && pcpi_valid && pcpi_wb_valid;") 184 | print(" assign pcpi_wb_write_csrs = pcpi_ready_csrs;") 185 | print(" assign pcpi_wb_data_csrs = pcpi_ready_csrs ? csrinsn_out : 0;") 186 | 187 | ##################################################################### 188 | 189 | components = ["csrs"] 190 | 191 | def add_component(modname, instname, params=dict(), ports=dict(), csrs=set(), mem=False, awb=False, br=False): 192 | components.append(instname) 193 | 194 | print(" wire mem_reqst_%s;" % instname) 195 | print(" wire mem_grant_%s;" % instname) 196 | print(" wire mem_valid_%s;" % instname) 197 | print(" wire mem_ready_%s;" % instname) 198 | print(" wire [XLEN-1:0] mem_addr_%s;" % instname) 199 | print(" wire [ 31:0] mem_wdata_%s;" % instname) 200 | print(" wire [ 3:0] mem_wstrb_%s;" % instname) 201 | 202 | print(" wire pcpi_ready_%s;" % instname) 203 | print(" wire pcpi_wb_write_%s;" % instname) 204 | print(" wire pcpi_wb_async_%s;" % instname) 205 | print(" wire [XLEN-1:0] pcpi_wb_data_%s;" % instname) 206 | print(" wire pcpi_br_enable_%s;" % instname) 207 | print(" wire [XLEN-1:0] pcpi_br_nextpc_%s;" % instname) 208 | 209 | print(" wire awb_valid_%s;" % instname) 210 | print(" wire awb_ready_%s;" % instname) 211 | print(" wire [ 4:0] awb_addr_%s;" % instname) 212 | print(" wire [XLEN-1:0] awb_data_%s;" % instname) 213 | 214 | print(" %s #(" % modname); 215 | print(" .XLEN(XLEN)") 216 | print(" , .ILEN(ILEN)") 217 | for key, val in params.items(): 218 | print(" , .%s(%s)" % (key, val)) 219 | print(" ) %s (" % instname) 220 | print(" .clock (clock )") 221 | print(" , .reset (reset )") 222 | if mem: 223 | print(" , .mem_reqst (mem_reqst_%s)" % instname) 224 | print(" , .mem_grant (mem_grant_%s)" % instname) 225 | print(" , .mem_valid (mem_valid_%s)" % instname) 226 | print(" , .mem_ready (mem_ready_%s)" % instname) 227 | print(" , .mem_addr (mem_addr_%s )" % instname) 228 | print(" , .mem_rdata (mem_rdata)") 229 | print(" , .mem_wdata (mem_wdata_%s )" % instname) 230 | print(" , .mem_wstrb (mem_wstrb_%s )" % instname) 231 | print(" , .decode_valid (decode_valid )") 232 | print(" , .decode_insn (decode_insn )") 233 | print(" , .decode_prefix (decode_prefix )") 234 | print(" , .pcpi_valid (pcpi_valid )") 235 | print(" , .pcpi_insn (pcpi_insn )") 236 | print(" , .pcpi_prefix (pcpi_prefix )") 237 | print(" , .pcpi_pc (pcpi_pc )") 238 | print(" , .pcpi_rs1_valid (pcpi_rs1_valid)") 239 | print(" , .pcpi_rs1_data (pcpi_rs1_data )") 240 | print(" , .pcpi_rs2_valid (pcpi_rs2_valid)") 241 | print(" , .pcpi_rs2_data (pcpi_rs2_data )") 242 | print(" , .pcpi_rs3_valid (pcpi_rs3_valid)") 243 | print(" , .pcpi_rs3_data (pcpi_rs3_data )") 244 | print(" , .pcpi_ready (pcpi_ready_%s )" % instname) 245 | print(" , .pcpi_wb_valid (pcpi_wb_valid )") 246 | print(" , .pcpi_wb_write (pcpi_wb_write_%s )" % instname) 247 | print(" , .pcpi_wb_data (pcpi_wb_data_%s )" % instname) 248 | if br: 249 | print(" , .pcpi_br_enable (pcpi_br_enable_%s)" % instname) 250 | print(" , .pcpi_br_nextpc (pcpi_br_nextpc_%s)" % instname) 251 | if awb: 252 | print(" , .pcpi_wb_async (pcpi_wb_async_%s )" % instname) 253 | print(" , .awb_valid (awb_valid_%s)" % instname) 254 | print(" , .awb_ready (awb_ready_%s)" % instname) 255 | print(" , .awb_addr (awb_addr_%s)" % instname) 256 | print(" , .awb_data (awb_data_%s)" % instname) 257 | for key, val in ports.items(): 258 | print(" , .%s(%s)" % (key, val)) 259 | print(" );") 260 | 261 | if not mem: 262 | print(" assign mem_reqst_%s = 0;" % instname) 263 | print(" assign mem_valid_%s = 0;" % instname) 264 | print(" assign mem_addr_%s = 0;" % instname) 265 | print(" assign mem_wdata_%s = 0;" % instname) 266 | print(" assign mem_wstrb_%s = 0;" % instname) 267 | 268 | if not br: 269 | print(" assign pcpi_br_enable_%s = 0;" % instname) 270 | print(" assign pcpi_br_nextpc_%s = 0;" % instname) 271 | 272 | if not awb: 273 | print(" assign pcpi_wb_async_%s = 0;" % instname) 274 | print(" assign awb_valid_%s = 0;" % instname) 275 | print(" assign awb_addr_%s = 0;" % instname) 276 | print(" assign awb_data_%s = 0;" % instname) 277 | 278 | components_cfg() 279 | 280 | ##################################################################### 281 | 282 | print(" wire mem_valid_ctrl;") 283 | print(" wire mem_ready_ctrl;") 284 | print(" wire [XLEN-1:0] mem_addr_ctrl;") 285 | print(" wire [XLEN-1:0] mem_wdata_ctrl = 0;") 286 | print(" wire [3:0] mem_wstrb_ctrl = 0;") 287 | 288 | print(" wire awb_valid_ctrl;") 289 | print(" wire awb_ready_ctrl;") 290 | print(" wire [ 4:0] awb_addr_ctrl;") 291 | print(" wire [XLEN-1:0] awb_data_ctrl;") 292 | 293 | for n in ["ctrl"] + components: 294 | print(" reg arb_mem_%s_reg;" % n) 295 | 296 | p = [] 297 | q = list(components) 298 | for n in components: 299 | print(" wire arb_mem_%s = %s;" % (n, " && ".join(["!arb_mem_%s" % m for m in p] + 300 | ["mem_reqst_%s" % n] + ["!(mem_reqst_%s && arb_mem_%s_reg)" % (m, m) for m in q[1:]]))) 301 | print(" assign mem_ready_%s = arb_mem_%s && mem_ready;" % (n, n)) 302 | print(" assign mem_grant_%s = arb_mem_%s;" % (n, n)) 303 | print(" always @(posedge clock) arb_mem_%s_reg <= reset ? 0 : arb_mem_%s;" % (n, n)) 304 | p.append(n) 305 | q = q[1:] 306 | 307 | print(" wire arb_mem_ctrl = mem_valid_ctrl && %s;" % (" && ".join(["!arb_mem_%s" % m for m in p]))) 308 | print(" assign mem_ready_ctrl = arb_mem_ctrl && mem_ready;") 309 | print(" always @(posedge clock) arb_mem_ctrl_reg <= reset ? 0 : arb_mem_ctrl;") 310 | 311 | p = [] 312 | for n in components: 313 | print(" wire arb_awb_%s = !awb_valid && %s;" % (n, " && ".join(["awb_valid_%s" % n] + ["!awb_valid_%s" % m for m in p]))) 314 | print(" assign awb_ready_%s = arb_awb_%s && awb_ready_ctrl;" % (n, n)) 315 | p.append(n) 316 | 317 | for n in ["valid", "addr", "wdata", "wstrb"]: 318 | print(" assign mem_%s = %s;" % (n, " | ".join(["(arb_mem_%s ? mem_%s_%s : 0)" % (m, n, m) for m in ["ctrl"] + components]))) 319 | print(" assign mem_insn = arb_mem_ctrl;") 320 | 321 | for n in ["valid", "addr", "data"]: 322 | print(" assign awb_%s_ctrl = awb_valid ? awb_%s : %s;" % (n, n, " | ".join(["(arb_awb_%s ? awb_%s_%s : 0)" % (m, n, m) for m in components]))) 323 | print(" assign awb_ready = awb_valid && awb_ready_ctrl;") 324 | 325 | print("assign pcpi_ready_ctrl = pcpi_ready|%s;" % "|".join(["pcpi_ready_%s" % n for n in components])) 326 | 327 | print(" picorv_ctrl #("); 328 | print(" .XLEN(XLEN)") 329 | print(" , .ILEN(ILEN)") 330 | print(" , .IALIGN(IALIGN)") 331 | print(" , .RPORTS(RPORTS)") 332 | print(" , .SPINIT(SPINIT)") 333 | print(" ) ctrl (") 334 | print(" .clock (clock )") 335 | print(" , .reset (reset )") 336 | print(" , .rvec (rvec )") 337 | print(" , .mem_valid (mem_valid_ctrl)") 338 | print(" , .mem_ready (mem_ready_ctrl)") 339 | print(" , .mem_addr (mem_addr_ctrl )") 340 | print(" , .mem_rdata (mem_rdata)") 341 | print(" , .decode_valid (decode_valid )") 342 | print(" , .decode_insn (decode_insn )") 343 | print(" , .decode_prefix (decode_prefix )") 344 | print(" , .pcpi_valid (pcpi_valid )") 345 | print(" , .pcpi_insn (pcpi_insn )") 346 | print(" , .pcpi_prefix (pcpi_prefix )") 347 | print(" , .pcpi_pc (pcpi_pc )") 348 | print(" , .pcpi_rs1_valid(pcpi_rs1_valid)") 349 | print(" , .pcpi_rs1_data (pcpi_rs1_data )") 350 | print(" , .pcpi_rs2_valid(pcpi_rs2_valid)") 351 | print(" , .pcpi_rs2_data (pcpi_rs2_data )") 352 | print(" , .pcpi_rs3_valid(pcpi_rs3_valid)") 353 | print(" , .pcpi_rs3_data (pcpi_rs3_data )") 354 | print(" , .pcpi_ready (pcpi_ready_ctrl)") 355 | print(" , .pcpi_wb_valid (pcpi_wb_valid)") 356 | print(" , .pcpi_wb_async (pcpi_wb_async|%s)" % "|".join(["pcpi_wb_async_%s" % n for n in components])) 357 | print(" , .pcpi_wb_write (pcpi_wb_write|%s)" % "|".join(["pcpi_wb_write_%s" % n for n in components])) 358 | print(" , .pcpi_wb_data (pcpi_wb_data|%s)" % "|".join(["pcpi_wb_data_%s" % n for n in components])) 359 | print(" , .pcpi_br_enable(pcpi_br_enable|%s)" % "|".join(["pcpi_br_enable_%s" % n for n in components])) 360 | print(" , .pcpi_br_nextpc(pcpi_br_nextpc|%s)" % "|".join(["pcpi_br_nextpc_%s" % n for n in components])) 361 | print(" , .awb_valid(awb_valid_ctrl)") 362 | print(" , .awb_ready(awb_ready_ctrl)") 363 | print(" , .awb_addr (awb_addr_ctrl)") 364 | print(" , .awb_data (awb_data_ctrl)") 365 | print(" );") 366 | 367 | print("endmodule") 368 | -------------------------------------------------------------------------------- /source/picorv_ctrl_fm.gtkw: -------------------------------------------------------------------------------- 1 | [*] 2 | [*] GTKWave Analyzer v3.3.86 (w)1999-2017 BSI 3 | [*] Mon Nov 4 09:14:41 2019 4 | [*] 5 | [dumpfile] "/home/clifford/Work/sprojects/2019/picorvng/picorvng_ctrl_fm_insn_cover/engine_0/trace0.vcd" 6 | [dumpfile_mtime] "Mon Nov 4 09:05:46 2019" 7 | [dumpfile_size] 41842 8 | [savefile] "/home/clifford/Work/sprojects/2019/picorvng/picorvng_ctrl_fm.gtkw" 9 | [timestart] 0 10 | [size] 1567 1018 11 | [pos] 878 64 12 | *-5.234744 58 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 13 | [treeopen] top. 14 | [sst_width] 223 15 | [signals_width] 286 16 | [sst_expanded] 1 17 | [sst_vpaned_height] 299 18 | @28 19 | top.clock 20 | top.reset 21 | top.busy 22 | @22 23 | top.rvec[31:0] 24 | @200 25 | - 26 | @28 27 | top.mem_valid 28 | top.mem_ready 29 | @22 30 | top.mem_addr[31:0] 31 | top.mem_rdata[31:0] 32 | @200 33 | - 34 | @28 35 | top.pcpi_valid 36 | @22 37 | top.pcpi_pc[31:0] 38 | top.pcpi_insn[31:0] 39 | top.pcpi_prefix[15:0] 40 | @200 41 | - 42 | @22 43 | top.pcpi_rd_addr[4:0] 44 | top.pcpi_rs1_addr[4:0] 45 | top.pcpi_rs2_addr[4:0] 46 | top.pcpi_rs3_addr[4:0] 47 | @200 48 | - 49 | @28 50 | top.pcpi_rs1_valid 51 | top.pcpi_rs2_valid 52 | top.pcpi_rs3_valid 53 | top.pcpi_wb_valid 54 | @200 55 | - 56 | @28 57 | top.pcpi_ready 58 | top.pcpi_wb_async 59 | top.pcpi_wb_write 60 | @29 61 | top.pcpi_br_enable 62 | @200 63 | - 64 | @28 65 | top.awb_valid 66 | top.awb_ready 67 | @22 68 | top.awb_addr[4:0] 69 | top.awb_data[31:0] 70 | @200 71 | - 72 | [pattern_trace] 1 73 | [pattern_trace] 0 74 | -------------------------------------------------------------------------------- /source/picorv_ctrl_fm_insn.sby: -------------------------------------------------------------------------------- 1 | [tasks] 2 | check 3 | cover 4 | deep 5 | 6 | [options] 7 | check: mode bmc 8 | cover: mode cover 9 | deep: mode bmc 10 | 11 | ~deep: depth 10 12 | deep: depth 15 13 | 14 | [engines] 15 | smtbmc boolector 16 | 17 | [script] 18 | read -noverific 19 | read -sv picorv_ctrl.v 20 | read -sv picorv_ctrl_fm_insn.sv 21 | prep -top top 22 | 23 | [files] 24 | picorv_ctrl.v 25 | picorv_ctrl_fm_insn.sv 26 | -------------------------------------------------------------------------------- /source/picorv_ctrl_fm_insn.sv: -------------------------------------------------------------------------------- 1 | /* 2 | * PicoRV -- A Small and Extensible RISC-V Processor 3 | * 4 | * Copyright (C) 2019 Claire Wolf 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | * 18 | */ 19 | 20 | module top #( 21 | parameter integer XLEN = 32, 22 | parameter integer ILEN = 32, 23 | parameter integer IALIGN = 16, 24 | parameter integer RPORTS = 3 25 | ) ( 26 | // control 27 | input clock, 28 | input reset, 29 | input [XLEN-1:0] rvec, 30 | 31 | // memory interface 32 | output mem_valid, 33 | input mem_ready, 34 | output [XLEN-1:0] mem_addr, 35 | input [ 31:0] mem_rdata, 36 | 37 | // decode 38 | output decode_valid, 39 | output [ILEN-1:0] decode_insn, 40 | output [ 15:0] decode_prefix, 41 | 42 | // pcpi 43 | output pcpi_valid, 44 | output [ILEN-1:0] pcpi_insn, 45 | output [ 15:0] pcpi_prefix, 46 | output [XLEN-1:0] pcpi_pc, 47 | output pcpi_rs1_valid, 48 | output [XLEN-1:0] pcpi_rs1_data, 49 | output pcpi_rs2_valid, 50 | output [XLEN-1:0] pcpi_rs2_data, 51 | output pcpi_rs3_valid, 52 | output [XLEN-1:0] pcpi_rs3_data, 53 | input pcpi_ready, 54 | output pcpi_wb_valid, 55 | input pcpi_wb_write, 56 | input pcpi_wb_async, 57 | input [XLEN-1:0] pcpi_wb_data, 58 | input pcpi_br_enable, 59 | input [XLEN-1:0] pcpi_br_nextpc, 60 | 61 | // async writeback 62 | input awb_valid, 63 | output awb_ready, 64 | input [ 4:0] awb_addr, 65 | input [XLEN-1:0] awb_data 66 | ); 67 | wire [4:0] pcpi_rd_addr = pcpi_insn[11:7]; 68 | wire [4:0] pcpi_rs1_addr = pcpi_insn[19:15]; 69 | wire [4:0] pcpi_rs2_addr = pcpi_insn[24:20]; 70 | wire [4:0] pcpi_rs3_addr = pcpi_insn[31:27]; 71 | 72 | picorv_ctrl #( 73 | .XLEN(XLEN), 74 | .ILEN(ILEN), 75 | .IALIGN(IALIGN), 76 | .RPORTS(RPORTS) 77 | ) uut ( 78 | .clock (clock ), 79 | .reset (reset ), 80 | .rvec (rvec ), 81 | 82 | .mem_valid (mem_valid ), 83 | .mem_ready (mem_ready ), 84 | .mem_addr (mem_addr ), 85 | .mem_rdata (mem_rdata ), 86 | 87 | .decode_valid (decode_valid ), 88 | .decode_insn (decode_insn ), 89 | .decode_prefix (decode_prefix ), 90 | 91 | .pcpi_valid (pcpi_valid ), 92 | .pcpi_insn (pcpi_insn ), 93 | .pcpi_prefix (pcpi_prefix ), 94 | .pcpi_pc (pcpi_pc ), 95 | .pcpi_rs1_valid (pcpi_rs1_valid), 96 | .pcpi_rs1_data (pcpi_rs1_data ), 97 | .pcpi_rs2_valid (pcpi_rs2_valid), 98 | .pcpi_rs2_data (pcpi_rs2_data ), 99 | .pcpi_rs3_valid (pcpi_rs3_valid), 100 | .pcpi_rs3_data (pcpi_rs3_data ), 101 | .pcpi_ready (pcpi_ready ), 102 | .pcpi_wb_valid (pcpi_wb_valid ), 103 | .pcpi_wb_write (pcpi_wb_write ), 104 | .pcpi_wb_async (pcpi_wb_async ), 105 | .pcpi_wb_data (pcpi_wb_data ), 106 | .pcpi_br_enable (pcpi_br_enable), 107 | .pcpi_br_nextpc (pcpi_br_nextpc), 108 | 109 | .awb_valid (awb_valid ), 110 | .awb_ready (awb_ready ), 111 | .awb_addr (awb_addr ), 112 | .awb_data (awb_data ) 113 | ); 114 | 115 | reg [7:0] memory [0:4096]; 116 | reg [31:0] expected_pc; 117 | reg [2:0] cover_tags = 0; 118 | 119 | initial begin 120 | assume (reset); 121 | end 122 | 123 | always @* begin 124 | if (pcpi_valid && pcpi_rs1_valid && pcpi_rs1_addr == awb_addr) 125 | assume (!awb_valid); 126 | if (pcpi_valid && pcpi_rs2_valid && pcpi_rs2_addr == awb_addr) 127 | assume (!awb_valid); 128 | if (pcpi_valid && pcpi_rs3_valid && pcpi_rs3_addr == awb_addr) 129 | assume (!awb_valid); 130 | 131 | if (mem_valid && mem_ready) begin 132 | assert (mem_addr[1:0] == 0); 133 | assume (mem_rdata[ 7: 0] == memory[mem_addr[11:0] + 12'd 0]); 134 | assume (mem_rdata[15: 8] == memory[mem_addr[11:0] + 12'd 1]); 135 | assume (mem_rdata[23:16] == memory[mem_addr[11:0] + 12'd 2]); 136 | assume (mem_rdata[31:24] == memory[mem_addr[11:0] + 12'd 3]); 137 | end 138 | if (pcpi_valid) begin 139 | assert (pcpi_prefix[ 7:0] == memory[pcpi_pc[11:0] + 12'd 0]); 140 | assert (pcpi_prefix[15:8] == memory[pcpi_pc[11:0] + 12'd 1]); 141 | if (pcpi_prefix[1:0] == 3) begin 142 | assert (pcpi_insn[15:0] == pcpi_prefix[15:0]); 143 | assert (pcpi_insn[23:16] == memory[pcpi_pc[11:0] + 12'd 2]); 144 | assert (pcpi_insn[31:24] == memory[pcpi_pc[11:0] + 12'd 3]); 145 | end 146 | end 147 | 148 | assume (rvec[0] == 0); 149 | assume (pcpi_br_nextpc[0] == 0); 150 | end 151 | 152 | always @(posedge clock) begin 153 | if (!reset) begin 154 | assert ($past(decode_valid) == (pcpi_valid && $past(pcpi_ready || !pcpi_valid))); 155 | if ($past(decode_valid)) begin 156 | assert ($past(decode_insn) == pcpi_insn); 157 | assert ($past(decode_prefix) == pcpi_prefix); 158 | end 159 | if (pcpi_valid && pcpi_ready) begin 160 | if (pcpi_br_enable) begin 161 | cover_tags[0] <= 1; 162 | expected_pc <= pcpi_br_nextpc; 163 | end else if (pcpi_prefix[1:0] == 3) begin 164 | cover_tags[1] <= 1; 165 | expected_pc <= pcpi_pc + 4; 166 | end else begin 167 | cover_tags[2] <= 1; 168 | expected_pc <= pcpi_pc + 2; 169 | end 170 | cover (&cover_tags); 171 | end 172 | if (pcpi_valid) begin 173 | assert (pcpi_pc == expected_pc); 174 | if ($past(pcpi_valid) && !$past(pcpi_ready)) begin 175 | assert ($stable(pcpi_insn)); 176 | assert ($stable(pcpi_prefix)); 177 | assert ($stable(pcpi_pc)); 178 | if (pcpi_rs1_valid && $past(pcpi_rs1_valid)) 179 | assert ($stable(pcpi_rs1_data)); 180 | if (pcpi_rs2_valid && $past(pcpi_rs2_valid)) 181 | assert ($stable(pcpi_rs2_data)); 182 | if (pcpi_rs3_valid && $past(pcpi_rs3_valid)) 183 | assert ($stable(pcpi_rs3_data)); 184 | end 185 | end 186 | end else begin 187 | expected_pc <= rvec; 188 | cover_tags <= 0; 189 | end 190 | end 191 | endmodule 192 | -------------------------------------------------------------------------------- /source/picorv_ctrl_fm_regs.sby: -------------------------------------------------------------------------------- 1 | [tasks] 2 | check 3 | cover 4 | deep 5 | 6 | [options] 7 | check: mode bmc 8 | cover: mode cover 9 | deep: mode bmc 10 | 11 | ~deep: depth 10 12 | deep: depth 15 13 | 14 | [engines] 15 | smtbmc boolector 16 | 17 | [script] 18 | read -noverific 19 | read -sv picorv_ctrl.v 20 | read -sv picorv_ctrl_fm_shadow.sv 21 | prep -top top 22 | 23 | [files] 24 | picorv_ctrl.v 25 | picorv_ctrl_fm_shadow.sv 26 | -------------------------------------------------------------------------------- /source/picorv_ctrl_fm_regs.sv: -------------------------------------------------------------------------------- 1 | /* 2 | * PicoRV -- A Small and Extensible RISC-V Processor 3 | * 4 | * Copyright (C) 2019 Claire Wolf 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | * 18 | */ 19 | 20 | module top #( 21 | parameter integer XLEN = 32, 22 | parameter integer ILEN = 32, 23 | parameter integer IALIGN = 16, 24 | parameter integer RPORTS = 3 25 | ) ( 26 | // control 27 | input clock, 28 | input reset, 29 | input [XLEN-1:0] rvec, 30 | 31 | // memory interface 32 | output mem_valid, 33 | input mem_ready, 34 | output [XLEN-1:0] mem_addr, 35 | input [ 31:0] mem_rdata, 36 | 37 | // pcpi 38 | output pcpi_valid, 39 | output [ILEN-1:0] pcpi_insn, 40 | output [ 15:0] pcpi_prefix, 41 | output [XLEN-1:0] pcpi_pc, 42 | output pcpi_rs1_valid, 43 | output [XLEN-1:0] pcpi_rs1_data, 44 | output pcpi_rs2_valid, 45 | output [XLEN-1:0] pcpi_rs2_data, 46 | output pcpi_rs3_valid, 47 | output [XLEN-1:0] pcpi_rs3_data, 48 | input pcpi_ready, 49 | output pcpi_wb_valid, 50 | input pcpi_wb_write, 51 | input pcpi_wb_async, 52 | input [XLEN-1:0] pcpi_wb_data, 53 | input pcpi_br_enable, 54 | input [XLEN-1:0] pcpi_br_nextpc, 55 | 56 | // async writeback 57 | input awb_valid, 58 | output awb_ready, 59 | input [ 4:0] awb_addr, 60 | input [XLEN-1:0] awb_data 61 | ); 62 | wire [4:0] pcpi_rd_addr = pcpi_insn[11:7]; 63 | wire [4:0] pcpi_rs1_addr = pcpi_insn[19:15]; 64 | wire [4:0] pcpi_rs2_addr = pcpi_insn[24:20]; 65 | wire [4:0] pcpi_rs3_addr = pcpi_insn[31:27]; 66 | 67 | picorv_ctrl #( 68 | .XLEN(XLEN), 69 | .ILEN(ILEN), 70 | .IALIGN(IALIGN), 71 | .RPORTS(RPORTS) 72 | ) uut ( 73 | .clock (clock ), 74 | .reset (reset ), 75 | .rvec (rvec ), 76 | 77 | .mem_valid (mem_valid ), 78 | .mem_ready (mem_ready ), 79 | .mem_addr (mem_addr ), 80 | .mem_rdata (mem_rdata ), 81 | 82 | .pcpi_valid (pcpi_valid ), 83 | .pcpi_insn (pcpi_insn ), 84 | .pcpi_prefix (pcpi_prefix ), 85 | .pcpi_pc (pcpi_pc ), 86 | .pcpi_rs1_valid (pcpi_rs1_valid), 87 | .pcpi_rs1_data (pcpi_rs1_data ), 88 | .pcpi_rs2_valid (pcpi_rs2_valid), 89 | .pcpi_rs2_data (pcpi_rs2_data ), 90 | .pcpi_rs3_valid (pcpi_rs3_valid), 91 | .pcpi_rs3_data (pcpi_rs3_data ), 92 | .pcpi_ready (pcpi_ready ), 93 | .pcpi_wb_valid (pcpi_wb_valid ), 94 | .pcpi_wb_write (pcpi_wb_write ), 95 | .pcpi_wb_async (pcpi_wb_async ), 96 | .pcpi_wb_data (pcpi_wb_data ), 97 | .pcpi_br_enable (pcpi_br_enable), 98 | .pcpi_br_nextpc (pcpi_br_nextpc), 99 | 100 | .awb_valid (awb_valid ), 101 | .awb_ready (awb_ready ), 102 | .awb_addr (awb_addr ), 103 | .awb_data (awb_data ) 104 | ); 105 | 106 | rand const reg [4:0] shadow_addr; 107 | reg [XLEN-1:0] shadow_data; 108 | reg shadow_pending = 0; 109 | reg shadow_valid = 0; 110 | 111 | initial begin 112 | assume (reset); 113 | assume (shadow_addr != 0); 114 | end 115 | 116 | always @* begin 117 | if (!pcpi_wb_valid) begin 118 | assume (!pcpi_wb_write); 119 | assume (!pcpi_wb_async); 120 | end 121 | assume (!pcpi_wb_write || !pcpi_wb_async); 122 | end 123 | 124 | always @(posedge clock) begin 125 | if (!reset) begin 126 | if (awb_valid && awb_addr == shadow_addr) begin 127 | assume (shadow_pending); 128 | if (awb_ready) begin 129 | shadow_pending <= 0; 130 | shadow_valid <= 1; 131 | shadow_data <= awb_data; 132 | end 133 | end 134 | 135 | if (pcpi_valid) begin 136 | if (shadow_addr == pcpi_insn[19:15] && pcpi_rs1_valid) begin 137 | assert (!shadow_pending); 138 | assert (!shadow_valid || shadow_data == pcpi_rs1_data); 139 | end 140 | if (shadow_addr == pcpi_insn[24:20] && pcpi_rs2_valid) begin 141 | assert (!shadow_pending); 142 | assert (!shadow_valid || shadow_data == pcpi_rs2_data); 143 | end 144 | if (shadow_addr == pcpi_insn[31:27] && pcpi_rs3_valid) begin 145 | assert (!shadow_pending); 146 | assert (!shadow_valid || shadow_data == pcpi_rs3_data); 147 | end 148 | if (shadow_addr == pcpi_insn[11:7] && pcpi_valid && !shadow_pending) begin 149 | assert (pcpi_wb_valid); 150 | end 151 | if (shadow_addr == pcpi_insn[11:7] && pcpi_ready && pcpi_wb_write) begin 152 | assert (!shadow_pending); 153 | shadow_valid <= 1; 154 | shadow_data <= pcpi_wb_data; 155 | end 156 | if (shadow_addr == pcpi_insn[11:7] && pcpi_ready && pcpi_wb_async) begin 157 | assert (!shadow_pending); 158 | shadow_pending <= 1; 159 | shadow_valid <= 0; 160 | end 161 | end 162 | 163 | cover (awb_valid && awb_ready && awb_addr == shadow_addr); 164 | end else begin 165 | shadow_pending <= 0; 166 | end 167 | end 168 | endmodule 169 | -------------------------------------------------------------------------------- /source/picorv_exec.v: -------------------------------------------------------------------------------- 1 | /* 2 | * PicoRV -- A Small and Extensible RISC-V Processor 3 | * 4 | * Copyright (C) 2019 Claire Wolf 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | * 18 | */ 19 | 20 | module picorv_exec #( 21 | parameter integer XLEN = 32, 22 | parameter integer ILEN = 32, 23 | parameter integer CPI = 2 24 | ) ( 25 | // control 26 | input clock, 27 | input reset, 28 | 29 | // decode 30 | input decode_valid, 31 | input [ILEN-1:0] decode_insn, 32 | input [ 15:0] decode_prefix, 33 | 34 | // pcpi 35 | input pcpi_valid, 36 | input [ILEN-1:0] pcpi_insn, 37 | input [ 15:0] pcpi_prefix, 38 | input [XLEN-1:0] pcpi_pc, 39 | input pcpi_rs1_valid, 40 | input [XLEN-1:0] pcpi_rs1_data, 41 | input pcpi_rs2_valid, 42 | input [XLEN-1:0] pcpi_rs2_data, 43 | input pcpi_rs3_valid, 44 | input [XLEN-1:0] pcpi_rs3_data, 45 | output pcpi_ready, 46 | input pcpi_wb_valid, 47 | output pcpi_wb_write, 48 | output [XLEN-1:0] pcpi_wb_data, 49 | output pcpi_br_enable, 50 | output [XLEN-1:0] pcpi_br_nextpc 51 | ); 52 | reg insn_lui; 53 | reg insn_auipc; 54 | reg insn_jal; 55 | reg insn_jalr; 56 | reg insn_br; 57 | reg insn_alu; 58 | 59 | always @(posedge clock) begin 60 | if (reset || decode_valid || pcpi_ready) begin 61 | insn_lui <= 0; 62 | insn_auipc <= 0; 63 | insn_jal <= 0; 64 | insn_jalr <= 0; 65 | insn_br <= 0; 66 | insn_alu <= 0; 67 | end 68 | 69 | if (!reset && decode_valid && (decode_prefix[4:0] != 5'b 11111 || ILEN == 32)) begin 70 | (* parallel_case *) 71 | casez ({decode_insn, XLEN==64}) 72 | 33'b zzzzzzz_zzzzz_zzzzz_zzz_zzzzz_0110111_z: insn_lui <= 1; // LUI 73 | 33'b zzzzzzz_zzzzz_zzzzz_zzz_zzzzz_0010111_z: insn_auipc <= 1; // AUIPC 74 | 33'b zzzzzzz_zzzzz_zzzzz_zzz_zzzzz_1101111_z: insn_jal <= 1; // JAL 75 | 33'b zzzzzzz_zzzzz_zzzzz_000_zzzzz_1100111_z: insn_jalr <= 1; // JALR 76 | 77 | 33'b zzzzzzz_zzzzz_zzzzz_000_zzzzz_1100011_z: insn_br <= 1; // BEQ 78 | 33'b zzzzzzz_zzzzz_zzzzz_001_zzzzz_1100011_z: insn_br <= 1; // BNE 79 | 33'b zzzzzzz_zzzzz_zzzzz_100_zzzzz_1100011_z: insn_br <= 1; // BLT 80 | 33'b zzzzzzz_zzzzz_zzzzz_101_zzzzz_1100011_z: insn_br <= 1; // BGE 81 | 33'b zzzzzzz_zzzzz_zzzzz_110_zzzzz_1100011_z: insn_br <= 1; // BLTU 82 | 33'b zzzzzzz_zzzzz_zzzzz_111_zzzzz_1100011_z: insn_br <= 1; // BGEU 83 | 84 | 33'b zzzzzzz_zzzzz_zzzzz_000_zzzzz_0010011_z: insn_alu <= 1; // ADDI 85 | 33'b zzzzzzz_zzzzz_zzzzz_010_zzzzz_0010011_z: insn_alu <= 1; // SLTI 86 | 33'b zzzzzzz_zzzzz_zzzzz_011_zzzzz_0010011_z: insn_alu <= 1; // SLTIU 87 | 33'b zzzzzzz_zzzzz_zzzzz_100_zzzzz_0010011_z: insn_alu <= 1; // XORI 88 | 33'b zzzzzzz_zzzzz_zzzzz_110_zzzzz_0010011_z: insn_alu <= 1; // ORI 89 | 33'b zzzzzzz_zzzzz_zzzzz_111_zzzzz_0010011_z: insn_alu <= 1; // ANDI 90 | 91 | 33'b 0000000_zzzzz_zzzzz_001_zzzzz_0010011_z: insn_alu <= 1; // SLLI 92 | 33'b 0000000_zzzzz_zzzzz_101_zzzzz_0010011_z: insn_alu <= 1; // SRLI 93 | 33'b 0100000_zzzzz_zzzzz_101_zzzzz_0010011_z: insn_alu <= 1; // SRAI 94 | 95 | 33'b 0000000_zzzzz_zzzzz_000_zzzzz_0110011_z: insn_alu <= 1; // ADD 96 | 33'b 0100000_zzzzz_zzzzz_000_zzzzz_0110011_z: insn_alu <= 1; // SUB 97 | 33'b 0000000_zzzzz_zzzzz_001_zzzzz_0110011_z: insn_alu <= 1; // SLL 98 | 33'b 0000000_zzzzz_zzzzz_010_zzzzz_0110011_z: insn_alu <= 1; // SLT 99 | 33'b 0000000_zzzzz_zzzzz_011_zzzzz_0110011_z: insn_alu <= 1; // SLTU 100 | 33'b 0000000_zzzzz_zzzzz_100_zzzzz_0110011_z: insn_alu <= 1; // XOR 101 | 33'b 0000000_zzzzz_zzzzz_101_zzzzz_0110011_z: insn_alu <= 1; // SRL 102 | 33'b 0100000_zzzzz_zzzzz_101_zzzzz_0110011_z: insn_alu <= 1; // SRA 103 | 33'b 0000000_zzzzz_zzzzz_110_zzzzz_0110011_z: insn_alu <= 1; // OR 104 | 33'b 0000000_zzzzz_zzzzz_111_zzzzz_0110011_z: insn_alu <= 1; // AND 105 | endcase 106 | end 107 | end 108 | 109 | reg insn_okay; 110 | 111 | always @* begin 112 | insn_okay = 1; 113 | 114 | if (insn_jalr && !pcpi_rs1_valid) begin 115 | insn_okay = 0; 116 | end 117 | 118 | if (insn_br && !(pcpi_rs1_valid && pcpi_rs2_valid)) begin 119 | insn_okay = 0; 120 | end 121 | 122 | if (insn_alu && !(pcpi_rs1_valid && (pcpi_rs2_valid || !pcpi_insn[5]))) begin 123 | insn_okay = 0; 124 | end 125 | end 126 | 127 | // ----------------------------------------------------------------------------------------------- 128 | 129 | reg pcpi_ready_nxt; 130 | reg pcpi_wb_write_nxt; 131 | reg [XLEN-1:0] pcpi_wb_data_nxt; 132 | reg pcpi_br_enable_nxt; 133 | reg [XLEN-1:0] pcpi_br_nextpc_nxt; 134 | 135 | reg pcpi_ready_reg; 136 | reg pcpi_wb_write_reg; 137 | reg [XLEN-1:0] pcpi_wb_data_reg; 138 | reg pcpi_br_enable_reg; 139 | reg [XLEN-1:0] pcpi_br_nextpc_reg; 140 | 141 | generate if (CPI > 1) begin:ffs 142 | always @(posedge clock) begin 143 | pcpi_ready_reg <= pcpi_ready_nxt && insn_okay; 144 | pcpi_wb_write_reg <= pcpi_wb_write_nxt; 145 | pcpi_wb_data_reg <= pcpi_wb_data_nxt; 146 | pcpi_br_enable_reg <= pcpi_br_enable_nxt; 147 | pcpi_br_nextpc_reg <= pcpi_br_nextpc_nxt; 148 | end 149 | end else begin:noffs 150 | always @* begin 151 | pcpi_ready_reg = pcpi_ready_nxt && insn_okay; 152 | pcpi_wb_write_reg = pcpi_wb_write_nxt; 153 | pcpi_wb_data_reg = pcpi_wb_data_nxt; 154 | pcpi_br_enable_reg = pcpi_br_enable_nxt; 155 | pcpi_br_nextpc_reg = pcpi_br_nextpc_nxt; 156 | end 157 | end endgenerate 158 | 159 | assign pcpi_ready = pcpi_ready_reg && (!pcpi_wb_write_reg || pcpi_wb_valid); 160 | assign pcpi_wb_write = pcpi_wb_write_reg; 161 | assign pcpi_wb_data = pcpi_wb_data_reg; 162 | assign pcpi_br_enable = pcpi_br_enable_reg; 163 | assign pcpi_br_nextpc = pcpi_br_nextpc_reg; 164 | 165 | // ----------------------------------------------------------------------------------------------- 166 | 167 | wire [XLEN-1:0] imm_itype = $signed(pcpi_insn[31:20]); 168 | wire [XLEN-1:0] imm_btype = $signed({pcpi_insn[31], pcpi_insn[7], pcpi_insn[30:25], pcpi_insn[11:8], 1'b0}); 169 | wire [XLEN-1:0] imm_utype = $signed({pcpi_insn[31:12]}); 170 | wire [XLEN-1:0] imm_jtype = $signed({pcpi_insn[31], pcpi_insn[19:12], pcpi_insn[20], pcpi_insn[30:21], 1'b0}); 171 | 172 | wire [XLEN-1:0] next_pc = pcpi_pc + (pcpi_prefix[1:0] == 2'b11 ? 4 : 2); 173 | wire [XLEN-1:0] branch_pc = pcpi_pc + (insn_auipc ? imm_utype << 12 : insn_jal ? imm_jtype : imm_btype); 174 | wire [XLEN-1:0] jalr_addr = (pcpi_rs1_data + imm_itype) & ~1; 175 | 176 | wire [XLEN-1:0] alu_rs1 = pcpi_rs1_data; 177 | wire [XLEN-1:0] alu_rs2 = pcpi_insn[5] ? pcpi_rs2_data : imm_itype; 178 | wire [XLEN-1:0] alu_out; 179 | 180 | picorv_exec_alu #( 181 | .XLEN(32) 182 | ) alu ( 183 | .din1(alu_rs1), 184 | .din2(alu_rs2), 185 | .fun3(pcpi_insn[14:12]), 186 | .fun7(pcpi_insn[31:25]), 187 | .bflg(insn_br), 188 | .iflg(!pcpi_insn[5]), 189 | .dout(alu_out) 190 | ); 191 | 192 | // ----------------------------------------------------------------------------------------------- 193 | 194 | always @* begin 195 | pcpi_ready_nxt = 0; 196 | pcpi_wb_write_nxt = 0; 197 | pcpi_wb_data_nxt = 0; 198 | pcpi_br_enable_nxt = 0; 199 | pcpi_br_nextpc_nxt = 0; 200 | 201 | if (insn_lui) begin 202 | pcpi_ready_nxt = 1; 203 | pcpi_wb_write_nxt = 1; 204 | pcpi_wb_data_nxt = imm_utype << 12; 205 | end 206 | 207 | if (insn_auipc) begin 208 | pcpi_ready_nxt = 1; 209 | pcpi_wb_write_nxt = 1; 210 | pcpi_wb_data_nxt = branch_pc; 211 | end 212 | 213 | if (insn_jal) begin 214 | pcpi_ready_nxt = 1; 215 | pcpi_wb_write_nxt = 1; 216 | pcpi_wb_data_nxt = next_pc; 217 | pcpi_br_enable_nxt = 1; 218 | pcpi_br_nextpc_nxt = branch_pc; 219 | end 220 | 221 | if (insn_jalr) begin 222 | pcpi_ready_nxt = 1; 223 | pcpi_wb_write_nxt = 1; 224 | pcpi_wb_data_nxt = next_pc; 225 | pcpi_br_enable_nxt = 1; 226 | pcpi_br_nextpc_nxt = jalr_addr; 227 | end 228 | 229 | if (insn_br) begin 230 | pcpi_ready_nxt = 1; 231 | pcpi_br_enable_nxt = alu_out[0]; 232 | pcpi_br_nextpc_nxt = branch_pc; 233 | end 234 | 235 | if (insn_alu) begin 236 | pcpi_ready_nxt = 1; 237 | pcpi_wb_write_nxt = 1; 238 | pcpi_wb_data_nxt = alu_out; 239 | end 240 | 241 | if (reset || (CPI > 1 && pcpi_ready)) begin 242 | pcpi_ready_nxt = 0; 243 | pcpi_wb_write_nxt = 0; 244 | pcpi_wb_data_nxt = 0; 245 | pcpi_br_enable_nxt = 0; 246 | pcpi_br_nextpc_nxt = 0; 247 | end 248 | end 249 | 250 | endmodule 251 | 252 | // ----------------------------------------------------------------------------------------------- 253 | 254 | module picorv_exec_alu #( 255 | parameter integer XLEN = 32 256 | ) ( 257 | input [XLEN-1:0] din1, 258 | input [XLEN-1:0] din2, 259 | input [ 2:0] fun3, 260 | input [ 6:0] fun7, 261 | input bflg, 262 | input iflg, 263 | output [XLEN-1:0] dout 264 | ); 265 | wire alu_neg = (fun7[5] && !iflg) || bflg; 266 | wire [XLEN-1:0] din2_neg = alu_neg ? ~din2 : din2; 267 | 268 | reg [XLEN-1:0] alu_out; 269 | reg alu_eq, alu_lt; 270 | 271 | wire [XLEN:0] din1_sext = {!(bflg ? fun3[1] : fun3[0]) && din1[XLEN-1], din1}; 272 | wire [XLEN:0] din2_sext = {!(bflg ? fun3[1] : fun3[0]) && din2[XLEN-1], din2}; 273 | 274 | assign dout = alu_out; 275 | 276 | function [XLEN-1:0] reflect; 277 | input [XLEN-1:0] din; 278 | integer i; 279 | begin 280 | for (i = 0; i < XLEN; i=i+1) 281 | reflect[i] = din[XLEN-i-1]; 282 | end 283 | endfunction 284 | 285 | always @* begin 286 | alu_out = 'bx; 287 | alu_eq = 'bx; 288 | alu_lt = 'bx; 289 | 290 | (* parallel_case, full_case *) 291 | casez ({bflg, fun3}) 292 | // BEQ, BNE, BLT, BGE, BLTU, BGEU, ADDI, ADD, SUB, SLT, SLTU 293 | 4'b 1_zzz, 4'b 0_000, 4'b 0_01z: begin 294 | alu_out = din1 + din2_neg + alu_neg; 295 | alu_eq = din1 == din2; 296 | alu_lt = $signed(din1_sext) < $signed(din2_sext); 297 | casez ({bflg, fun3}) 298 | 4'b 1_000: // BEQ 299 | alu_out = alu_eq; 300 | 4'b 1_001: // BNE 301 | alu_out = !alu_eq; 302 | 4'b 1_100, // BLT 303 | 4'b 1_110, // BLTU 304 | 4'b 0_010, // SLT 305 | 4'b 0_011: // SLTU 306 | alu_out = alu_lt; 307 | 4'b 1_101, // BGE 308 | 4'b 1_111: // BGEU 309 | alu_out = !alu_lt; 310 | endcase 311 | end 312 | 313 | // SLLI, SRLI, SRAI, SLL, SRL, SRA 314 | 4'b 0_z01: begin 315 | alu_out = fun3[2] ? din1 : reflect(din1); 316 | alu_out = {{XLEN{alu_out[XLEN-1] && fun7[5]}}, alu_out} >> (din2 & (XLEN-1)); 317 | alu_out = fun3[2] ? alu_out : reflect(alu_out); 318 | end 319 | 320 | // XOR, XNOR 321 | 4'b 0_100: begin 322 | alu_out = din1 ^ din2_neg; 323 | end 324 | 325 | // OR, ORN 326 | 4'b 0_110: begin 327 | alu_out = din1 | din2_neg; 328 | end 329 | 330 | // AND, ANDN 331 | 4'b 0_111: begin 332 | alu_out = din1 & din2_neg; 333 | end 334 | endcase 335 | end 336 | endmodule 337 | -------------------------------------------------------------------------------- /source/picorv_ldst.v: -------------------------------------------------------------------------------- 1 | /* 2 | * PicoRV -- A Small and Extensible RISC-V Processor 3 | * 4 | * Copyright (C) 2019 Claire Wolf 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | * 18 | */ 19 | 20 | module picorv_ldst #( 21 | parameter integer XLEN = 32, 22 | parameter integer ILEN = 32 23 | ) ( 24 | // control 25 | input clock, 26 | input reset, 27 | 28 | // memory interface 29 | output mem_reqst, 30 | input mem_grant, 31 | output mem_valid, 32 | input mem_ready, 33 | output [XLEN-1:0] mem_addr, 34 | input [ 31:0] mem_rdata, 35 | output [ 31:0] mem_wdata, 36 | output [ 3:0] mem_wstrb, 37 | 38 | // decode 39 | input decode_valid, 40 | input [ILEN-1:0] decode_insn, 41 | input [ 15:0] decode_prefix, 42 | 43 | // pcpi 44 | input pcpi_valid, 45 | input [ILEN-1:0] pcpi_insn, 46 | input [ 15:0] pcpi_prefix, 47 | input [XLEN-1:0] pcpi_pc, 48 | input pcpi_rs1_valid, 49 | input [XLEN-1:0] pcpi_rs1_data, 50 | input pcpi_rs2_valid, 51 | input [XLEN-1:0] pcpi_rs2_data, 52 | input pcpi_rs3_valid, 53 | input [XLEN-1:0] pcpi_rs3_data, 54 | output pcpi_ready, 55 | input pcpi_wb_valid, 56 | output pcpi_wb_async, 57 | output pcpi_wb_write, 58 | output [XLEN-1:0] pcpi_wb_data, 59 | 60 | // async writeback 61 | output awb_valid, 62 | input awb_ready, 63 | output [ 4:0] awb_addr, 64 | output [XLEN-1:0] awb_data 65 | ); 66 | reg insn_ld; 67 | reg insn_st; 68 | 69 | always @(posedge clock) begin 70 | if (reset || decode_valid || pcpi_ready) begin 71 | insn_ld <= 0; 72 | insn_st <= 0; 73 | end 74 | 75 | if (!reset && decode_valid && (decode_prefix[4:0] != 5'b 11111 || ILEN == 32)) begin 76 | (* parallel_case *) 77 | casez ({decode_insn, XLEN==64}) 78 | 33'b zzzzzzz_zzzzz_zzzzz_000_zzzzz_0000011_z: insn_ld <= 1; // LB 79 | 33'b zzzzzzz_zzzzz_zzzzz_001_zzzzz_0000011_z: insn_ld <= 1; // LH 80 | 33'b zzzzzzz_zzzzz_zzzzz_010_zzzzz_0000011_z: insn_ld <= 1; // LW 81 | 33'b zzzzzzz_zzzzz_zzzzz_011_zzzzz_0000011_1: insn_ld <= 1; // LD 82 | 33'b zzzzzzz_zzzzz_zzzzz_100_zzzzz_0000011_z: insn_ld <= 1; // LBU 83 | 33'b zzzzzzz_zzzzz_zzzzz_101_zzzzz_0000011_z: insn_ld <= 1; // LHU 84 | 33'b zzzzzzz_zzzzz_zzzzz_110_zzzzz_0000011_1: insn_ld <= 1; // LWU 85 | 86 | 33'b zzzzzzz_zzzzz_zzzzz_000_zzzzz_0100011_z: insn_st <= 1; // SB 87 | 33'b zzzzzzz_zzzzz_zzzzz_001_zzzzz_0100011_z: insn_st <= 1; // SH 88 | 33'b zzzzzzz_zzzzz_zzzzz_010_zzzzz_0100011_z: insn_st <= 1; // SW 89 | 33'b zzzzzzz_zzzzz_zzzzz_011_zzzzz_0100011_1: insn_st <= 1; // SD 90 | endcase 91 | end 92 | end 93 | 94 | reg insn_okay; 95 | 96 | always @* begin 97 | insn_okay = mem_grant; 98 | 99 | if (insn_ld && !pcpi_rs1_valid) begin 100 | insn_okay = 0; 101 | end 102 | 103 | if (insn_st && !(pcpi_rs1_valid && pcpi_rs2_valid)) begin 104 | insn_okay = 0; 105 | end 106 | end 107 | 108 | // ----------------------------------------------------------------------------------------------- 109 | 110 | reg mem_valid_reg; 111 | reg [XLEN-1:0] mem_addr_reg; 112 | reg [31:0] mem_rdata_processed; 113 | reg [31:0] mem_wdata_reg; 114 | reg [3:0] mem_wstrb_reg; 115 | reg [2:0] mem_funct3; 116 | reg [1:0] mem_shift; 117 | 118 | always @* begin 119 | mem_rdata_processed = mem_rdata >> (8*mem_shift); 120 | case (mem_funct3) 121 | 3'b 000: mem_rdata_processed = $signed(mem_rdata_processed[7:0]); 122 | 3'b 001: mem_rdata_processed = $signed(mem_rdata_processed[15:0]); 123 | 3'b 100: mem_rdata_processed = mem_rdata_processed[7:0]; 124 | 3'b 101: mem_rdata_processed = mem_rdata_processed[15:0]; 125 | endcase 126 | end 127 | 128 | assign mem_reqst = insn_ld || insn_st || mem_valid_reg; 129 | assign mem_valid = mem_valid_reg; 130 | assign mem_addr = mem_addr_reg; 131 | assign mem_wdata = mem_wdata_reg; 132 | assign mem_wstrb = mem_wstrb_reg; 133 | 134 | reg awb_valid_reg; 135 | reg [4:0] awb_addr_reg; 136 | reg [XLEN-1:0] awb_data_reg; 137 | 138 | assign awb_valid = awb_valid_reg; 139 | assign awb_addr = awb_addr_reg; 140 | assign awb_data = awb_data_reg; 141 | 142 | reg pcpi_ready_reg; 143 | reg pcpi_wb_write_reg; 144 | reg pcpi_wb_async_reg; 145 | 146 | assign pcpi_ready = pcpi_ready_reg && (!pcpi_wb_write_reg || pcpi_wb_valid); 147 | assign pcpi_wb_write = pcpi_wb_write_reg; 148 | assign pcpi_wb_async = pcpi_wb_async_reg; 149 | assign pcpi_wb_data = 0; 150 | 151 | // ----------------------------------------------------------------------------------------------- 152 | 153 | wire [XLEN-1:0] imm_itype = $signed(pcpi_insn[31:20]); 154 | wire [XLEN-1:0] imm_stype = $signed({pcpi_insn[31:25], pcpi_insn[11:7]}); 155 | 156 | wire [XLEN-1:0] ldst_addr = pcpi_rs1_data + (insn_st ? imm_stype : imm_itype); 157 | wire [3:0] ldst_mask = {pcpi_insn[13], pcpi_insn[13], pcpi_insn[13] || pcpi_insn[12], 1'b1}; 158 | 159 | always @(posedge clock) begin 160 | pcpi_ready_reg <= 0; 161 | pcpi_wb_async_reg <= 0; 162 | pcpi_wb_write_reg <= 0; 163 | 164 | if (insn_ld && insn_okay && !mem_valid_reg && !awb_valid_reg && pcpi_wb_valid) begin 165 | pcpi_ready_reg <= 1; 166 | mem_valid_reg <= 1; 167 | mem_addr_reg <= ldst_addr & ~3; 168 | mem_wstrb_reg <= 0; 169 | mem_funct3 <= pcpi_insn[14:12]; 170 | mem_shift <= ldst_addr & 3; 171 | pcpi_wb_async_reg <= 1; 172 | awb_addr_reg <= pcpi_insn[11:7]; 173 | end 174 | 175 | if (insn_st && insn_okay && !mem_valid_reg) begin 176 | pcpi_ready_reg <= 1; 177 | mem_valid_reg <= 1; 178 | mem_addr_reg <= ldst_addr & ~3; 179 | mem_wdata_reg <= pcpi_rs2_data << 8*(ldst_addr & 3); 180 | mem_wstrb_reg <= ldst_mask << (ldst_addr & 3); 181 | end 182 | 183 | if (mem_valid && mem_ready) begin 184 | mem_valid_reg <= 0; 185 | if (!mem_wstrb_reg) begin 186 | awb_valid_reg <= 1; 187 | awb_data_reg <= mem_rdata_processed; 188 | end 189 | end 190 | 191 | if (awb_valid && awb_ready) begin 192 | awb_valid_reg <= 0; 193 | end 194 | 195 | if (reset || pcpi_ready) begin 196 | pcpi_ready_reg <= 0; 197 | pcpi_wb_async_reg <= 0; 198 | pcpi_wb_write_reg <= 0; 199 | end 200 | 201 | if (reset) begin 202 | mem_valid_reg <= 0; 203 | awb_valid_reg <= 0; 204 | end 205 | end 206 | endmodule 207 | -------------------------------------------------------------------------------- /source/syscalls.c: -------------------------------------------------------------------------------- 1 | /* 2 | * PicoRV -- A Small and Extensible RISC-V Processor 3 | * 4 | * Copyright (C) 2019 Claire Wolf 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | * 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | #define UNIMPL_FUNC(_f) ".globl " #_f "\n.type " #_f ", @function\n" #_f ":\n" 25 | 26 | asm ( 27 | ".text\n" 28 | ".align 2\n" 29 | UNIMPL_FUNC(_open) 30 | UNIMPL_FUNC(_openat) 31 | UNIMPL_FUNC(_lseek) 32 | UNIMPL_FUNC(_stat) 33 | UNIMPL_FUNC(_lstat) 34 | UNIMPL_FUNC(_fstatat) 35 | UNIMPL_FUNC(_isatty) 36 | UNIMPL_FUNC(_access) 37 | UNIMPL_FUNC(_faccessat) 38 | UNIMPL_FUNC(_link) 39 | UNIMPL_FUNC(_unlink) 40 | UNIMPL_FUNC(_execve) 41 | UNIMPL_FUNC(_getpid) 42 | UNIMPL_FUNC(_fork) 43 | UNIMPL_FUNC(_kill) 44 | UNIMPL_FUNC(_wait) 45 | UNIMPL_FUNC(_times) 46 | UNIMPL_FUNC(_gettimeofday) 47 | UNIMPL_FUNC(_ftime) 48 | UNIMPL_FUNC(_utime) 49 | UNIMPL_FUNC(_chown) 50 | UNIMPL_FUNC(_chmod) 51 | UNIMPL_FUNC(_chdir) 52 | UNIMPL_FUNC(_getcwd) 53 | UNIMPL_FUNC(_sysconf) 54 | "j unimplemented_syscall\n" 55 | ); 56 | 57 | void unimplemented_syscall() 58 | { 59 | const char *p = "Unimplemented system call called!\n"; 60 | while (*p) 61 | *(volatile int*)0x10000000 = *(p++); 62 | asm volatile ("ebreak"); 63 | __builtin_unreachable(); 64 | } 65 | 66 | ssize_t _read(int file, void *ptr, size_t len) 67 | { 68 | // always EOF 69 | return 0; 70 | } 71 | 72 | ssize_t _write(int file, const void *ptr, size_t len) 73 | { 74 | const void *eptr = ptr + len; 75 | while (ptr != eptr) 76 | *(volatile int*)0x00100000 = *(char*)(ptr++); 77 | return len; 78 | } 79 | 80 | int _close(int file) 81 | { 82 | // close is called before _exit() 83 | return 0; 84 | } 85 | 86 | int _fstat(int file, struct stat *st) 87 | { 88 | // fstat is called during libc startup 89 | errno = ENOENT; 90 | return -1; 91 | } 92 | 93 | void *_sbrk(ptrdiff_t incr) 94 | { 95 | extern unsigned char _end[]; // Defined by linker 96 | static unsigned long heap_end; 97 | 98 | if (heap_end == 0) 99 | heap_end = (long)_end; 100 | 101 | heap_end += incr; 102 | return (void *)(heap_end - incr); 103 | } 104 | 105 | void _exit(int exit_status) 106 | { 107 | asm volatile ("ebreak"); 108 | __builtin_unreachable(); 109 | } 110 | -------------------------------------------------------------------------------- /source/test.tcl: -------------------------------------------------------------------------------- 1 | # vivado -mode batch -source test.tcl -nojournal -log test_vivado.log 2 | 3 | read_verilog test.v 4 | read_verilog picorv_core.v 5 | read_verilog picorv_ctrl.v 6 | read_verilog picorv_exec.v 7 | read_verilog picorv_ldst.v 8 | read_xdc test.xdc 9 | 10 | synth_design -part xcku035-fbva676-2-e -top test 11 | opt_design -sweep -remap -propconst 12 | opt_design -directive Explore 13 | 14 | place_design -directive Explore 15 | phys_opt_design -retime -rewire -critical_pin_opt -placement_opt -critical_cell_opt 16 | route_design -directive Explore 17 | place_design -post_place_opt 18 | phys_opt_design -retime 19 | route_design -directive NoTimingRelaxation 20 | 21 | report_utilization 22 | report_timing 23 | -------------------------------------------------------------------------------- /source/test.v: -------------------------------------------------------------------------------- 1 | /* 2 | * PicoRV -- A Small and Extensible RISC-V Processor 3 | * 4 | * Copyright (C) 2019 Claire Wolf 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | * 18 | */ 19 | 20 | module test ( 21 | // control 22 | input clock, 23 | input reset_d, 24 | 25 | // memory interface 26 | output reg mem_valid_q, 27 | input mem_ready_d, 28 | output reg mem_insn_q, 29 | output reg [31:0] mem_addr_q, 30 | input [31:0] mem_rdata_d, 31 | output reg [31:0] mem_wdata_q, 32 | output reg [ 3:0] mem_wstrb_q 33 | ); 34 | reg reset_q; 35 | wire mem_valid_d; 36 | reg mem_ready_q; 37 | wire mem_insn_d; 38 | wire [31:0] mem_addr_d; 39 | reg [31:0] mem_rdata_q; 40 | wire [31:0] mem_wdata_d; 41 | wire [ 3:0] mem_wstrb_d; 42 | 43 | always @(posedge clock) begin 44 | reset_q <= reset_d; 45 | mem_valid_q <= mem_valid_d; 46 | mem_ready_q <= mem_ready_d; 47 | mem_insn_q <= mem_insn_d; 48 | mem_addr_q <= mem_addr_d; 49 | mem_rdata_q <= mem_rdata_d; 50 | mem_wdata_q <= mem_wdata_d; 51 | mem_wstrb_q <= mem_wstrb_d; 52 | end 53 | 54 | picorv_core #( 55 | .CPI(2), 56 | .CSRS(0), 57 | .XLEN(32), 58 | .ILEN(32), 59 | .IALIGN(32), 60 | .RPORTS(3) 61 | ) cpu ( 62 | .clock (clock ), 63 | .reset (reset_q ), 64 | .rvec (32'h 0 ), 65 | .mem_valid (mem_valid_d ), 66 | .mem_ready (mem_ready_q ), 67 | .mem_insn (mem_insn_d ), 68 | .mem_addr (mem_addr_d ), 69 | .mem_rdata (mem_rdata_q ), 70 | .mem_wdata (mem_wdata_d ), 71 | .mem_wstrb (mem_wstrb_d ), 72 | .decode_valid ( ), 73 | .decode_insn ( ), 74 | .decode_prefix ( ), 75 | .pcpi_valid ( ), 76 | .pcpi_insn ( ), 77 | .pcpi_prefix ( ), 78 | .pcpi_pc ( ), 79 | .pcpi_rs1_valid ( ), 80 | .pcpi_rs1_data ( ), 81 | .pcpi_rs2_valid ( ), 82 | .pcpi_rs2_data ( ), 83 | .pcpi_rs3_valid ( ), 84 | .pcpi_rs3_data ( ), 85 | .pcpi_ready ( 1'b 0 ), 86 | .pcpi_wb_valid ( ), 87 | .pcpi_wb_async ( 1'b 0 ), 88 | .pcpi_wb_write ( 1'b 0 ), 89 | .pcpi_wb_data (32'b 0 ), 90 | .pcpi_br_enable ( 1'b 0 ), 91 | .pcpi_br_nextpc (32'b 0 ), 92 | .awb_valid ( 1'b 0 ), 93 | .awb_ready ( ), 94 | .awb_addr ( 1'b 0 ), 95 | .awb_data (32'b 0 ) 96 | ); 97 | endmodule 98 | -------------------------------------------------------------------------------- /source/test.xdc: -------------------------------------------------------------------------------- 1 | create_clock -period 2.50 [get_ports clock] 2 | -------------------------------------------------------------------------------- /source/testbench.gtkw: -------------------------------------------------------------------------------- 1 | [*] 2 | [*] GTKWave Analyzer v3.3.86 (w)1999-2017 BSI 3 | [*] Wed Nov 6 12:19:56 2019 4 | [*] 5 | [dumpfile] "/home/clifford/Work/sprojects/2019/picorvng/testbench.vcd" 6 | [dumpfile_mtime] "Wed Nov 6 12:17:33 2019" 7 | [dumpfile_size] 1796619 8 | [savefile] "/home/clifford/Work/sprojects/2019/picorvng/testbench.gtkw" 9 | [timestart] 0 10 | [size] 1403 1293 11 | [pos] -1 -1 12 | *-10.573535 4724 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 13 | [treeopen] testbench. 14 | [treeopen] testbench.uut. 15 | [treeopen] testbench.uut.exec. 16 | [sst_width] 223 17 | [signals_width] 283 18 | [sst_expanded] 1 19 | [sst_vpaned_height] 394 20 | @28 21 | testbench.clock 22 | testbench.reset 23 | @200 24 | - 25 | @28 26 | testbench.mem_valid 27 | testbench.mem_ready 28 | testbench.mem_insn 29 | @200 30 | - 31 | @22 32 | testbench.mem_addr[31:0] 33 | testbench.mem_rdata[31:0] 34 | testbench.mem_wdata[31:0] 35 | testbench.mem_wstrb[3:0] 36 | @200 37 | - 38 | @28 39 | testbench.uut.ctrl.pcpi_valid 40 | testbench.uut.ctrl.pcpi_ready 41 | @22 42 | testbench.uut.ctrl.pcpi_pc[31:0] 43 | @23 44 | testbench.uut.ctrl.pcpi_insn[31:0] 45 | @200 46 | - 47 | @22 48 | testbench.uut.ctrl.scoreboard[30:0] 49 | testbench.uut.ctrl.reg__x1__ra[31:0] 50 | testbench.uut.ctrl.reg__x2__sp[31:0] 51 | testbench.uut.ctrl.reg__x3__gp[31:0] 52 | testbench.uut.ctrl.reg__x4__tp[31:0] 53 | testbench.uut.ctrl.reg__x5__t0[31:0] 54 | testbench.uut.ctrl.reg__x6__t1[31:0] 55 | testbench.uut.ctrl.reg__x7__t2[31:0] 56 | testbench.uut.ctrl.reg__x8__fp[31:0] 57 | testbench.uut.ctrl.reg__x9__s1[31:0] 58 | testbench.uut.ctrl.reg_x10__a0[31:0] 59 | testbench.uut.ctrl.reg_x11__a1[31:0] 60 | testbench.uut.ctrl.reg_x12__a2[31:0] 61 | testbench.uut.ctrl.reg_x13__a3[31:0] 62 | testbench.uut.ctrl.reg_x14__a4[31:0] 63 | testbench.uut.ctrl.reg_x15__a5[31:0] 64 | testbench.uut.ctrl.reg_x16__a6[31:0] 65 | testbench.uut.ctrl.reg_x17__a7[31:0] 66 | testbench.uut.ctrl.reg_x18__s2[31:0] 67 | testbench.uut.ctrl.reg_x19__s3[31:0] 68 | testbench.uut.ctrl.reg_x20__s4[31:0] 69 | testbench.uut.ctrl.reg_x21__s5[31:0] 70 | testbench.uut.ctrl.reg_x22__s6[31:0] 71 | testbench.uut.ctrl.reg_x23__s7[31:0] 72 | testbench.uut.ctrl.reg_x24__s8[31:0] 73 | testbench.uut.ctrl.reg_x25__s9[31:0] 74 | testbench.uut.ctrl.reg_x26_s10[31:0] 75 | testbench.uut.ctrl.reg_x27_s11[31:0] 76 | testbench.uut.ctrl.reg_x28__t3[31:0] 77 | testbench.uut.ctrl.reg_x29__t4[31:0] 78 | testbench.uut.ctrl.reg_x30__t5[31:0] 79 | testbench.uut.ctrl.reg_x31__t6[31:0] 80 | [pattern_trace] 1 81 | [pattern_trace] 0 82 | -------------------------------------------------------------------------------- /source/testbench.v: -------------------------------------------------------------------------------- 1 | /* 2 | * PicoRV -- A Small and Extensible RISC-V Processor 3 | * 4 | * Copyright (C) 2019 Claire Wolf 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | * 18 | */ 19 | 20 | module testbench; 21 | localparam integer XLEN = 32; 22 | localparam integer ILEN = 32; 23 | localparam integer IALIGN = 16; 24 | 25 | reg clock; 26 | reg reset = 1; 27 | wire [XLEN-1:0] rvec = `START; 28 | 29 | wire mem_valid; 30 | reg mem_ready; 31 | wire mem_insn; 32 | wire [XLEN-1:0] mem_addr; 33 | wire [31:0] mem_wdata; 34 | wire [31:0] mem_rdata; 35 | wire [ 3:0] mem_wstrb; 36 | 37 | wire pcpi_valid; 38 | wire [ILEN-1:0] pcpi_insn; 39 | wire [ 15:0] pcpi_prefix; 40 | wire [XLEN-1:0] pcpi_pc; 41 | wire pcpi_rs1_valid; 42 | wire [XLEN-1:0] pcpi_rs1_data; 43 | wire pcpi_rs2_valid; 44 | wire [XLEN-1:0] pcpi_rs2_data; 45 | wire pcpi_rs3_valid; 46 | wire [XLEN-1:0] pcpi_rs3_data; 47 | reg pcpi_ready = 0; 48 | reg pcpi_wb_write = 0; 49 | reg pcpi_wb_async = 0; 50 | reg [XLEN-1:0] pcpi_wb_data = 0; 51 | reg pcpi_br_enable = 0; 52 | reg [XLEN-1:0] pcpi_br_nextpc = 0; 53 | 54 | reg awb_valid = 0; 55 | wire awb_ready; 56 | reg [ 4:0] awb_addr; 57 | reg [XLEN-1:0] awb_data; 58 | 59 | always #5 clock = clock === 1'b0; 60 | always @(posedge clock) reset <= 0; 61 | 62 | reg [7:0] memory [0:2**20-1]; 63 | reg fastmode; 64 | 65 | initial begin 66 | fastmode = $test$plusargs("fast"); 67 | $readmemh(`HEXFILE, memory); 68 | if ($test$plusargs("vcd")) begin 69 | $dumpfile("testbench.vcd"); 70 | $dumpvars(0, testbench); 71 | end 72 | repeat (1000000) @(posedge clock); 73 | $display("TIMEOUT"); 74 | $finish; 75 | end 76 | 77 | integer stallcnt = 0; 78 | integer termcnt = 0; 79 | always @(posedge clock) begin 80 | stallcnt <= mem_valid ? 0 : stallcnt + 1; 81 | termcnt <= termcnt - |termcnt; 82 | if (stallcnt > 100) begin 83 | $display("STALLED"); 84 | $finish; 85 | end 86 | if (termcnt == 1) begin 87 | $display("TERMINATED"); 88 | $finish; 89 | end 90 | end 91 | 92 | reg mem_arb; 93 | 94 | always @(posedge clock) begin 95 | mem_arb <= ($random & 1) || fastmode; 96 | end 97 | 98 | always @* begin 99 | mem_ready = mem_valid && mem_arb; 100 | end 101 | 102 | assign mem_rdata[ 7: 0] = mem_valid && mem_ready ? memory[mem_addr + 2'd 0] : 'bx; 103 | assign mem_rdata[15: 8] = mem_valid && mem_ready ? memory[mem_addr + 2'd 1] : 'bx; 104 | assign mem_rdata[23:16] = mem_valid && mem_ready ? memory[mem_addr + 2'd 2] : 'bx; 105 | assign mem_rdata[31:24] = mem_valid && mem_ready ? memory[mem_addr + 2'd 3] : 'bx; 106 | 107 | always @(posedge clock) begin 108 | if (mem_valid && mem_ready && mem_addr < 2**20) begin 109 | // if (mem_wstrb) begin 110 | // $display("[W:%b:%08x:%08x]", mem_wstrb, mem_addr, mem_wdata); 111 | // if (mem_wstrb != 4'b0001 && mem_wstrb != 4'b0010 && mem_wstrb != 4'b0100 && mem_wstrb != 4'b1000 && 112 | // mem_wstrb != 4'b0011 && mem_wstrb != 4'b1100 && mem_wstrb != 4'b1111) 113 | // termcnt = termcnt ? termcnt : 10; 114 | // end 115 | if (mem_wstrb[0]) memory[mem_addr + 2'd 0] <= mem_wdata[ 7: 0]; 116 | if (mem_wstrb[1]) memory[mem_addr + 2'd 1] <= mem_wdata[15: 8]; 117 | if (mem_wstrb[2]) memory[mem_addr + 2'd 2] <= mem_wdata[23:16]; 118 | if (mem_wstrb[3]) memory[mem_addr + 2'd 3] <= mem_wdata[31:24]; 119 | end 120 | if (mem_valid && mem_ready && mem_addr == 2**20) begin 121 | if (mem_wdata[7:0]) begin 122 | $write("%c", mem_wdata[7:0]); 123 | $fflush; 124 | end else begin 125 | $display("EOF"); 126 | $finish; 127 | end 128 | end 129 | end 130 | 131 | picorv_core #( 132 | .XLEN(XLEN), 133 | .ILEN(ILEN), 134 | .IALIGN(IALIGN), 135 | .SPINIT(2**20-16), 136 | .CPI(1) 137 | ) uut ( 138 | .clock (clock ), 139 | .reset (reset ), 140 | .rvec (rvec ), 141 | 142 | .mem_valid (mem_valid ), 143 | .mem_ready (mem_ready ), 144 | .mem_insn (mem_insn ), 145 | .mem_addr (mem_addr ), 146 | .mem_rdata (mem_rdata ), 147 | .mem_wdata (mem_wdata ), 148 | .mem_wstrb (mem_wstrb ), 149 | 150 | .pcpi_valid (pcpi_valid ), 151 | .pcpi_insn (pcpi_insn ), 152 | .pcpi_prefix (pcpi_prefix ), 153 | .pcpi_pc (pcpi_pc ), 154 | .pcpi_rs1_valid (pcpi_rs1_valid ), 155 | .pcpi_rs1_data (pcpi_rs1_data ), 156 | .pcpi_rs2_valid (pcpi_rs2_valid ), 157 | .pcpi_rs2_data (pcpi_rs2_data ), 158 | .pcpi_rs3_valid (pcpi_rs3_valid ), 159 | .pcpi_rs3_data (pcpi_rs3_data ), 160 | .pcpi_ready (pcpi_ready ), 161 | .pcpi_wb_write (pcpi_wb_write ), 162 | .pcpi_wb_async (pcpi_wb_async ), 163 | .pcpi_wb_data (pcpi_wb_data ), 164 | .pcpi_br_enable (pcpi_br_enable ), 165 | .pcpi_br_nextpc (pcpi_br_nextpc ), 166 | 167 | .awb_valid (awb_valid ), 168 | .awb_ready (awb_ready ), 169 | .awb_addr (awb_addr ), 170 | .awb_data (awb_data ) 171 | ); 172 | endmodule 173 | --------------------------------------------------------------------------------