This commit is contained in:
Polprzewodnikowy 2021-08-05 19:50:29 +02:00
parent 2172c7ff15
commit e61d06275d
319 changed files with 24937 additions and 7006 deletions

4
.gitmodules vendored
View File

@ -2,7 +2,7 @@
path = sw/cic
url = https://github.com/ManCloud/UltraCIC-III.git
ignore = dirty
[submodule "fw/v2/picorv32"]
path = fw/v2/picorv32
[submodule "fw/picorv32"]
path = fw/picorv32
url = https://github.com/cliffordwolf/picorv32.git
ignore = dirty

View File

View File

@ -19,7 +19,7 @@
#
# Quartus Prime
# Version 20.1.1 Build 720 11/11/2020 SJ Lite Edition
# Date created = 11:10:16 August 01, 2021
# Date created = 22:48:47 August 04, 2021
#
# -------------------------------------------------------------------------- #
#
@ -46,6 +46,7 @@ set_global_assignment -name LAST_QUARTUS_VERSION "20.1.1 Lite Edition"
set_global_assignment -name PROJECT_OUTPUT_DIRECTORY output_files
set_global_assignment -name NUM_PARALLEL_PROCESSORS ALL
set_global_assignment -name FLOW_ENABLE_POWER_ANALYZER ON
#set_global_assignment -name VERILOG_FILE picorv32/picorv32.v
# Pin & Location Assignments
# ==========================
@ -59,7 +60,7 @@ set_location_assignment PIN_13 -to o_ftdi_clk
set_location_assignment PIN_14 -to i_ftdi_so
set_location_assignment PIN_15 -to i_ftdi_cts
set_location_assignment PIN_17 -to o_led
set_location_assignment PIN_21 -to o_rtc_scl
set_location_assignment PIN_21 -to io_rtc_scl
set_location_assignment PIN_22 -to io_rtc_sda
set_location_assignment PIN_24 -to io_n64_si_dq
set_location_assignment PIN_25 -to i_n64_nmi
@ -129,6 +130,12 @@ set_location_assignment PIN_118 -to io_sd_cmd
set_location_assignment PIN_119 -to io_sd_dat[3]
set_location_assignment PIN_120 -to io_sd_dat[2]
set_location_assignment PIN_123 -to o_n64_int
set_location_assignment PIN_130 -to io_flash_dq[0]
set_location_assignment PIN_131 -to o_flash_clk
set_location_assignment PIN_132 -to io_flash_dq[3]
set_location_assignment PIN_134 -to o_flash_cs
set_location_assignment PIN_135 -to io_flash_dq[1]
set_location_assignment PIN_136 -to io_flash_dq[2]
set_location_assignment PIN_138 -to io_pmod[0]
set_location_assignment PIN_140 -to io_pmod[1]
set_location_assignment PIN_141 -to io_pmod[2]
@ -168,6 +175,11 @@ set_global_assignment -name ENABLE_OCT_DONE OFF
set_global_assignment -name EXTERNAL_FLASH_FALLBACK_ADDRESS 00000000
set_global_assignment -name USE_CONFIGURATION_DEVICE OFF
# Signal Tap Assignments
# ======================
set_global_assignment -name ENABLE_SIGNALTAP ON
set_global_assignment -name USE_SIGNALTAP_FILE stp.stp
# Power Estimation Assignments
# ============================
set_global_assignment -name POWER_PRESET_COOLING_SOLUTION "NO HEAT SINK WITH STILL AIR"
@ -181,6 +193,15 @@ set_global_assignment -name OUTPUT_IO_TIMING_NEAR_END_VMEAS "HALF VCCIO" -fall
set_global_assignment -name OUTPUT_IO_TIMING_FAR_END_VMEAS "HALF SIGNAL SWING" -rise
set_global_assignment -name OUTPUT_IO_TIMING_FAR_END_VMEAS "HALF SIGNAL SWING" -fall
# start AUTO_INSERT_SLD_NODE_ENTITY(auto_signaltap_0)
# ---------------------------------------------------
# Signal Tap Assignments
# ======================
# end AUTO_INSERT_SLD_NODE_ENTITY(auto_signaltap_0)
# -------------------------------------------------
# --------------------------
# start ENTITY(SummerCart64)
@ -196,13 +217,69 @@ set_instance_assignment -name WEAK_PULL_UP_RESISTOR ON -to i_n64_si_clk
set_instance_assignment -name WEAK_PULL_UP_RESISTOR ON -to io_n64_si_dq
set_instance_assignment -name WEAK_PULL_UP_RESISTOR ON -to o_n64_int
# end ENTITY(SummerCart64)
# ------------------------
# start DESIGN_PARTITION(Top)
# ---------------------------
# Incremental Compilation Assignments
# ===================================
set_global_assignment -name PARTITION_NETLIST_TYPE SOURCE -section_id Top
set_global_assignment -name PARTITION_FITTER_PRESERVATION_LEVEL PLACEMENT_AND_ROUTING -section_id Top
set_global_assignment -name PARTITION_COLOR 16764057 -section_id Top
set_global_assignment -name SYSTEMVERILOG_FILE rtl/pll.sv
# end DESIGN_PARTITION(Top)
# -------------------------
# end ENTITY(SummerCart64)
# ------------------------
# set_global_assignment -name VHDL_FILE neorv32/rtl/core/neorv32_application_image.vhd
# set_global_assignment -name VHDL_FILE neorv32/rtl/core/neorv32_boot_rom.vhd
# set_global_assignment -name VHDL_FILE neorv32/rtl/core/neorv32_bootloader_image.vhd
# set_global_assignment -name VHDL_FILE neorv32/rtl/core/neorv32_bus_keeper.vhd
# set_global_assignment -name VHDL_FILE neorv32/rtl/core/neorv32_busswitch.vhd
# set_global_assignment -name VHDL_FILE neorv32/rtl/core/neorv32_cfs.vhd
# set_global_assignment -name VHDL_FILE neorv32/rtl/core/neorv32_cpu.vhd
# set_global_assignment -name VHDL_FILE neorv32/rtl/core/neorv32_cpu_alu.vhd
# set_global_assignment -name VHDL_FILE neorv32/rtl/core/neorv32_cpu_bus.vhd
# set_global_assignment -name VHDL_FILE neorv32/rtl/core/neorv32_cpu_control.vhd
# set_global_assignment -name VHDL_FILE neorv32/rtl/core/neorv32_cpu_cp_fpu.vhd
# set_global_assignment -name VHDL_FILE neorv32/rtl/core/neorv32_cpu_cp_muldiv.vhd
# set_global_assignment -name VHDL_FILE neorv32/rtl/core/neorv32_cpu_cp_shifter.vhd
# set_global_assignment -name VHDL_FILE neorv32/rtl/core/neorv32_cpu_decompressor.vhd
# set_global_assignment -name VHDL_FILE neorv32/rtl/core/neorv32_cpu_regfile.vhd
# set_global_assignment -name VHDL_FILE neorv32/rtl/core/neorv32_debug_dm.vhd
# set_global_assignment -name VHDL_FILE neorv32/rtl/core/neorv32_debug_dtm.vhd
# set_global_assignment -name VHDL_FILE neorv32/rtl/core/neorv32_dmem.vhd
# set_global_assignment -name VHDL_FILE neorv32/rtl/core/neorv32_fifo.vhd
# set_global_assignment -name VHDL_FILE neorv32/rtl/core/neorv32_gpio.vhd
# set_global_assignment -name VHDL_FILE neorv32/rtl/core/neorv32_icache.vhd
# set_global_assignment -name VHDL_FILE neorv32/rtl/core/neorv32_imem.vhd
# set_global_assignment -name VHDL_FILE neorv32/rtl/core/neorv32_mtime.vhd
# set_global_assignment -name VHDL_FILE neorv32/rtl/core/neorv32_neoled.vhd
# set_global_assignment -name VHDL_FILE neorv32/rtl/core/neorv32_package.vhd
# set_global_assignment -name VHDL_FILE neorv32/rtl/core/neorv32_pwm.vhd
# set_global_assignment -name VHDL_FILE neorv32/rtl/core/neorv32_slink.vhd
# set_global_assignment -name VHDL_FILE neorv32/rtl/core/neorv32_spi.vhd
# set_global_assignment -name VHDL_FILE neorv32/rtl/core/neorv32_sysinfo.vhd
# set_global_assignment -name VHDL_FILE neorv32/rtl/core/neorv32_top.vhd
# set_global_assignment -name VHDL_FILE neorv32/rtl/core/neorv32_trng.vhd
# set_global_assignment -name VHDL_FILE neorv32/rtl/core/neorv32_twi.vhd
# set_global_assignment -name VHDL_FILE neorv32/rtl/core/neorv32_uart.vhd
# set_global_assignment -name VHDL_FILE neorv32/rtl/core/neorv32_wdt.vhd
# set_global_assignment -name VHDL_FILE neorv32/rtl/core/neorv32_wishbone.vhd
# set_global_assignment -name VHDL_FILE neorv32/rtl/core/neorv32_xirq.vhd
set_global_assignment -name OPTIMIZATION_MODE BALANCED
set_global_assignment -name VERILOG_FILE btldr/btldr.sv
set_global_assignment -name VERILOG_FILE picorv32/picorv32.v
set_global_assignment -name QSYS_FILE rtl/intel/snp/intel_snp.qsys
set_global_assignment -name QIP_FILE rtl/intel/pll/intel_pll.qip
set_global_assignment -name SDC_FILE SummerCart64.sdc
set_global_assignment -name SIGNALTAP_FILE stp.stp
set_global_assignment -name SYSTEMVERILOG_FILE rtl/cpu/cpu_i2c.sv
set_global_assignment -name SYSTEMVERILOG_FILE rtl/cpu/cpu_led.sv
set_global_assignment -name SYSTEMVERILOG_FILE rtl/cpu/cpu_ram.sv
set_global_assignment -name SYSTEMVERILOG_FILE rtl/cpu/cpu_soc.sv
set_global_assignment -name SYSTEMVERILOG_FILE rtl/cpu/cpu_bus.sv
set_global_assignment -name SYSTEMVERILOG_FILE rtl/SummerCart64.sv
set_global_assignment -name QIP_FILE rtl/intel/intel_pll.qip
set_global_assignment -name SYSTEMVERILOG_FILE rtl/system/system.sv
set_global_assignment -name SLD_FILE db/stp_auto_stripped.stp
set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top

31
fw/btldr/Makefile Normal file
View File

@ -0,0 +1,31 @@
CROSS=riscv64-unknown-elf-
CFLAGS=-mabi=ilp32 -march=rv32i -Wl,-Bstatic,--strip-debug -ffreestanding -nostdlib
all: btldr.hex btldr.bin btldr.sv print_size
startup.o: startup.S
$(CROSS)gcc -x assembler-with-cpp -c $(CFLAGS) startup.s -o startup.o
btldr.o: btldr.c
$(CROSS)gcc -c $(CFLAGS) -o btldr.o btldr.c
btldr.elf: SC64_PicoRV32I.ld startup.o btldr.o
$(CROSS)gcc $(CFLAGS) -TSC64_PicoRV32I.ld startup.o btldr.o -o btldr.elf
btldr.hex: btldr.elf
$(CROSS)objcopy -O ihex btldr.elf btldr.hex
btldr.bin: btldr.elf
$(CROSS)objcopy -O binary btldr.elf btldr.bin
btldr.sv: btldr.bin
python3 bin2v.py
print_size:
@echo 'Size of target .elf file:'
$(CROSS)size -B btldr.elf
clean:
rm -f btldr.sv btldr.bin btldr.hex btldr.elf btldr.o startup.o
.PHONY: clean

View File

@ -0,0 +1,40 @@
MEMORY
{
ram (rwx) : org = 0x00000000, len = 24k
rom (rx) : org = 0x01000000, len = 1k
}
ENTRY(reset_handler);
SECTIONS
{
.text :
{
. = ALIGN(4);
*(.text .text* .rodata .rodata* .srodata .srodata*)
. = ALIGN(4);
} > rom AT > rom
.data :
{
. = ALIGN(4);
__data_init_start = LOADADDR(.data);
__data_start = .;
*(.data .data.* .sdata .stada.*);
. = ALIGN(4);
__data_end = .;
} > ram AT > rom
.bss :
{
. = ALIGN(4);
__bss_start = .;
*(.bss .bss.* .sbss .sbss.*)
. = ALIGN(4);
*(COMMON);
. = ALIGN(4);
__bss_end = .;
} > ram AT > ram
}
__stack_pointer = ORIGIN(ram) + LENGTH(ram) - 16;

48
fw/btldr/bin2v.py Normal file
View File

@ -0,0 +1,48 @@
#!/usr/bin/env python3
import struct
with open('btldr.bin', mode='rb') as code:
with open('btldr.sv', mode='w') as rom:
rom_formatted = ''
index = 0
for line in iter(lambda: code.read(4), ''):
if (not line):
break
value = format(struct.unpack('<I', line)[0], '08x')
rom_formatted += f' {index}: rom_data = 32\'h{value};\n'
index += 1
rom.write(f'''module cpu_bootloader (
if_system.sys system_if,
if_cpu_bus_out cpu_bus_if,
if_cpu_bus_in cpu_bootloader_if
);
wire request;
reg ack;
reg [31:0] rom_data;
reg [31:0] q;
assign request = (cpu_bus_if.address[31:24] == 8'h01) && cpu_bus_if.req;
assign cpu_bootloader_if.ack = ack & request;
assign cpu_bootloader_if.rdata = cpu_bootloader_if.ack ? q : 32'd0;
always_comb begin
case (cpu_bus_if.address[9:2])
{rom_formatted}
default: rom_data = 32'h0000_0000;
endcase
end
always_ff @(posedge system_if.clk) begin
ack <= 1'b0;
q <= rom_data;
if (request) begin
ack <= 1'b1;
end
end
endmodule
''')

BIN
fw/btldr/btldr.bin Normal file

Binary file not shown.

17
fw/btldr/btldr.c Normal file
View File

@ -0,0 +1,17 @@
#define LED *((volatile unsigned int *) 0x80000000)
volatile int counter = 0;
int main (void) {
while (1) {
if (counter++ == 0x000FFFFF) {
LED ^= 1;
counter = 0;
}
}
}
void irq_handler(void) {
LED = 1;
while (1);
}

BIN
fw/btldr/btldr.elf Normal file

Binary file not shown.

23
fw/btldr/btldr.hex Normal file
View File

@ -0,0 +1,23 @@
:020000040100F9
:100000000B6000066F008001130000001300000069
:10001000EF0040110B0000046F000000930000008F
:10002000176100FF130101FD93010000130200009E
:100030009302000013030000930300001304000068
:100040009304000013050000930500001306000050
:100050009306000013070000930700001308000038
:10006000930800001309000093090000130A000020
:10007000930A0000130B0000930B0000130C000008
:10008000930C0000130D0000930D0000130E0000F0
:10009000930E0000130F0000930F000017050000DF
:1000A0001305450A930500001306000063DCC50034
:1000B0008326050023A0D500130545009385450040
:1000C000E3C8C5FE13050000930540006358B50062
:1000D0002320050013054500E34CB5FEEF0080002A
:1000E0006F000000130101FF2326810013040101AA
:1000F00083270000938617002320D00037071000C5
:100100001307F7FFE396E7FEB707008003A7070092
:10011000B70700801347170023A0E7002320000043
:100120006FF01FFD130101FF23268100130401015D
:10013000B70700801307100023A0E7006F0000003E
:0400000501000000F6
:00000001FF

BIN
fw/btldr/btldr.o Normal file

Binary file not shown.

111
fw/btldr/btldr.sv Normal file
View File

@ -0,0 +1,111 @@
module cpu_bootloader (
if_system.sys system_if,
if_cpu_bus_out cpu_bus_if,
if_cpu_bus_in cpu_bootloader_if
);
wire request;
reg ack;
reg [31:0] rom_data;
reg [31:0] q;
assign request = (cpu_bus_if.address[31:24] == 8'h01) && cpu_bus_if.req;
assign cpu_bootloader_if.ack = ack & request;
assign cpu_bootloader_if.rdata = cpu_bootloader_if.ack ? q : 32'd0;
always_comb begin
case (cpu_bus_if.address[9:2])
0: rom_data = 32'h0600600b;
1: rom_data = 32'h0180006f;
2: rom_data = 32'h00000013;
3: rom_data = 32'h00000013;
4: rom_data = 32'h114000ef;
5: rom_data = 32'h0400000b;
6: rom_data = 32'h0000006f;
7: rom_data = 32'h00000093;
8: rom_data = 32'hff006117;
9: rom_data = 32'hfd010113;
10: rom_data = 32'h00000193;
11: rom_data = 32'h00000213;
12: rom_data = 32'h00000293;
13: rom_data = 32'h00000313;
14: rom_data = 32'h00000393;
15: rom_data = 32'h00000413;
16: rom_data = 32'h00000493;
17: rom_data = 32'h00000513;
18: rom_data = 32'h00000593;
19: rom_data = 32'h00000613;
20: rom_data = 32'h00000693;
21: rom_data = 32'h00000713;
22: rom_data = 32'h00000793;
23: rom_data = 32'h00000813;
24: rom_data = 32'h00000893;
25: rom_data = 32'h00000913;
26: rom_data = 32'h00000993;
27: rom_data = 32'h00000a13;
28: rom_data = 32'h00000a93;
29: rom_data = 32'h00000b13;
30: rom_data = 32'h00000b93;
31: rom_data = 32'h00000c13;
32: rom_data = 32'h00000c93;
33: rom_data = 32'h00000d13;
34: rom_data = 32'h00000d93;
35: rom_data = 32'h00000e13;
36: rom_data = 32'h00000e93;
37: rom_data = 32'h00000f13;
38: rom_data = 32'h00000f93;
39: rom_data = 32'h00000517;
40: rom_data = 32'h0a450513;
41: rom_data = 32'h00000593;
42: rom_data = 32'h00000613;
43: rom_data = 32'h00c5dc63;
44: rom_data = 32'h00052683;
45: rom_data = 32'h00d5a023;
46: rom_data = 32'h00450513;
47: rom_data = 32'h00458593;
48: rom_data = 32'hfec5c8e3;
49: rom_data = 32'h00000513;
50: rom_data = 32'h00400593;
51: rom_data = 32'h00b55863;
52: rom_data = 32'h00052023;
53: rom_data = 32'h00450513;
54: rom_data = 32'hfeb54ce3;
55: rom_data = 32'h008000ef;
56: rom_data = 32'h0000006f;
57: rom_data = 32'hff010113;
58: rom_data = 32'h00812623;
59: rom_data = 32'h01010413;
60: rom_data = 32'h00002783;
61: rom_data = 32'h00178693;
62: rom_data = 32'h00d02023;
63: rom_data = 32'h00100737;
64: rom_data = 32'hfff70713;
65: rom_data = 32'hfee796e3;
66: rom_data = 32'h800007b7;
67: rom_data = 32'h0007a703;
68: rom_data = 32'h800007b7;
69: rom_data = 32'h00174713;
70: rom_data = 32'h00e7a023;
71: rom_data = 32'h00002023;
72: rom_data = 32'hfd1ff06f;
73: rom_data = 32'hff010113;
74: rom_data = 32'h00812623;
75: rom_data = 32'h01010413;
76: rom_data = 32'h800007b7;
77: rom_data = 32'h00100713;
78: rom_data = 32'h00e7a023;
79: rom_data = 32'h0000006f;
default: rom_data = 32'h0000_0000;
endcase
end
always_ff @(posedge system_if.clk) begin
ack <= 1'b0;
q <= rom_data;
if (request) begin
ack <= 1'b1;
end
end
endmodule

94
fw/btldr/custom_ops.S Normal file
View File

@ -0,0 +1,94 @@
#define regnum_q0 0
#define regnum_q1 1
#define regnum_q2 2
#define regnum_q3 3
#define regnum_x0 0
#define regnum_x1 1
#define regnum_x2 2
#define regnum_x3 3
#define regnum_x4 4
#define regnum_x5 5
#define regnum_x6 6
#define regnum_x7 7
#define regnum_x8 8
#define regnum_x9 9
#define regnum_x10 10
#define regnum_x11 11
#define regnum_x12 12
#define regnum_x13 13
#define regnum_x14 14
#define regnum_x15 15
#define regnum_x16 16
#define regnum_x17 17
#define regnum_x18 18
#define regnum_x19 19
#define regnum_x20 20
#define regnum_x21 21
#define regnum_x22 22
#define regnum_x23 23
#define regnum_x24 24
#define regnum_x25 25
#define regnum_x26 26
#define regnum_x27 27
#define regnum_x28 28
#define regnum_x29 29
#define regnum_x30 30
#define regnum_x31 31
#define regnum_zero 0
#define regnum_ra 1
#define regnum_sp 2
#define regnum_gp 3
#define regnum_tp 4
#define regnum_t0 5
#define regnum_t1 6
#define regnum_t2 7
#define regnum_s0 8
#define regnum_s1 9
#define regnum_a0 10
#define regnum_a1 11
#define regnum_a2 12
#define regnum_a3 13
#define regnum_a4 14
#define regnum_a5 15
#define regnum_a6 16
#define regnum_a7 17
#define regnum_s2 18
#define regnum_s3 19
#define regnum_s4 20
#define regnum_s5 21
#define regnum_s6 22
#define regnum_s7 23
#define regnum_s8 24
#define regnum_s9 25
#define regnum_s10 26
#define regnum_s11 27
#define regnum_t3 28
#define regnum_t4 29
#define regnum_t5 30
#define regnum_t6 31
// x8 is s0 and also fp
#define regnum_fp 8
#define r_type_insn(_f7, _rs2, _rs1, _f3, _rd, _opc) \
.word (((_f7) << 25) | ((_rs2) << 20) | ((_rs1) << 15) | ((_f3) << 12) | ((_rd) << 7) | ((_opc) << 0))
#define picorv32_getq_insn(_rd, _qs) \
r_type_insn(0b0000000, 0, regnum_ ## _qs, 0b100, regnum_ ## _rd, 0b0001011)
#define picorv32_setq_insn(_qd, _rs) \
r_type_insn(0b0000001, 0, regnum_ ## _rs, 0b010, regnum_ ## _qd, 0b0001011)
#define picorv32_retirq_insn() \
r_type_insn(0b0000010, 0, 0, 0b000, 0, 0b0001011)
#define picorv32_maskirq_insn(_rd, _rs) \
r_type_insn(0b0000011, 0, regnum_ ## _rs, 0b110, regnum_ ## _rd, 0b0001011)
#define picorv32_waitirq_insn(_rd) \
r_type_insn(0b0000100, 0, 0, 0b100, regnum_ ## _rd, 0b0001011)
#define picorv32_timer_insn(_rd, _rs) \
r_type_insn(0b0000101, 0, regnum_ ## _rs, 0b110, regnum_ ## _rd, 0b0001011)

82
fw/btldr/startup.S Normal file
View File

@ -0,0 +1,82 @@
#include "custom_ops.S"
.global reset_handler
.global irq_handler
.weak irq_handler
.set irq_handler, default_irq_handler
.section .text
reset_handler:
picorv32_maskirq_insn(zero, zero)
j start_handler
.balign 16
irq_handler:
call irq_handler
picorv32_retirq_insn()
default_irq_handler:
j default_irq_handler
start_handler:
li ra, 0
la sp, __stack_pointer
li gp, 0
li tp, 0
li t0, 0
li t1, 0
li t2, 0
li s0, 0
li s1, 0
li a0, 0
li a1, 0
li a2, 0
li a3, 0
li a4, 0
li a5, 0
li a6, 0
li a7, 0
li s2, 0
li s3, 0
li s4, 0
li s5, 0
li s6, 0
li s7, 0
li s8, 0
li s9, 0
li s10, 0
li s11, 0
li t3, 0
li t4, 0
li t5, 0
li t6, 0
init_data:
la a0, __data_init_start
la a1, __data_start
la a2, __data_end
bge a1, a2, init_bss
loop_init_data:
lw a3, 0(a0)
sw a3, 0(a1)
addi a0, a0, 4
addi a1, a1, 4
blt a1, a2, loop_init_data
init_bss:
la a0, __bss_start
la a1, __bss_end
bge a0, a1, entry_point
loop_init_bss:
sw zero, 0(a0)
addi a0, a0, 4
blt a0, a1, loop_init_bss
entry_point:
call main
loop:
j loop

BIN
fw/btldr/startup.o Normal file

Binary file not shown.

37
fw/picorv32/.gitignore vendored Normal file
View File

@ -0,0 +1,37 @@
/tests/*.o
/firmware/*.o
/firmware/firmware.bin
/firmware/firmware.elf
/firmware/firmware.hex
/firmware/firmware.map
/dhrystone/dhry.bin
/dhrystone/dhry.elf
/dhrystone/dhry.hex
/dhrystone/dhry.map
/dhrystone/testbench.vvp
/dhrystone/testbench.vcd
/dhrystone/testbench_nola.vvp
/dhrystone/testbench_nola.vcd
/dhrystone/timing.vvp
/dhrystone/timing.txt
/dhrystone/*.d
/dhrystone/*.o
/riscv-gnu-toolchain-riscv32i
/riscv-gnu-toolchain-riscv32ic
/riscv-gnu-toolchain-riscv32im
/riscv-gnu-toolchain-riscv32imc
/testbench.vvp
/testbench_wb.vvp
/testbench_ez.vvp
/testbench_sp.vvp
/testbench_rvf.vvp
/testbench_synth.vvp
/testbench.gtkw
/testbench.vcd
/testbench.trace
/testbench_verilator*
/check.smt2
/check.vcd
/synth.log
/synth.v
.*.swp

184
fw/picorv32/Makefile Normal file
View File

@ -0,0 +1,184 @@
RISCV_GNU_TOOLCHAIN_GIT_REVISION = 411d134
RISCV_GNU_TOOLCHAIN_INSTALL_PREFIX = /opt/riscv32
# Give the user some easy overrides for local configuration quirks.
# If you change one of these and it breaks, then you get to keep both pieces.
SHELL = bash
PYTHON = python3
VERILATOR = verilator
ICARUS_SUFFIX =
IVERILOG = iverilog$(ICARUS_SUFFIX)
VVP = vvp$(ICARUS_SUFFIX)
TEST_OBJS = $(addsuffix .o,$(basename $(wildcard tests/*.S)))
FIRMWARE_OBJS = firmware/start.o firmware/irq.o firmware/print.o firmware/hello.o firmware/sieve.o firmware/multest.o firmware/stats.o
GCC_WARNS = -Werror -Wall -Wextra -Wshadow -Wundef -Wpointer-arith -Wcast-qual -Wcast-align -Wwrite-strings
GCC_WARNS += -Wredundant-decls -Wstrict-prototypes -Wmissing-prototypes -pedantic # -Wconversion
TOOLCHAIN_PREFIX = $(RISCV_GNU_TOOLCHAIN_INSTALL_PREFIX)i/bin/riscv32-unknown-elf-
COMPRESSED_ISA = C
# Add things like "export http_proxy=... https_proxy=..." here
GIT_ENV = true
test: testbench.vvp firmware/firmware.hex
$(VVP) -N $<
test_vcd: testbench.vvp firmware/firmware.hex
$(VVP) -N $< +vcd +trace +noerror
test_rvf: testbench_rvf.vvp firmware/firmware.hex
$(VVP) -N $< +vcd +trace +noerror
test_wb: testbench_wb.vvp firmware/firmware.hex
$(VVP) -N $<
test_wb_vcd: testbench_wb.vvp firmware/firmware.hex
$(VVP) -N $< +vcd +trace +noerror
test_ez: testbench_ez.vvp
$(VVP) -N $<
test_ez_vcd: testbench_ez.vvp
$(VVP) -N $< +vcd
test_sp: testbench_sp.vvp firmware/firmware.hex
$(VVP) -N $<
test_axi: testbench.vvp firmware/firmware.hex
$(VVP) -N $< +axi_test
test_synth: testbench_synth.vvp firmware/firmware.hex
$(VVP) -N $<
test_verilator: testbench_verilator firmware/firmware.hex
./testbench_verilator
testbench.vvp: testbench.v picorv32.v
$(IVERILOG) -o $@ $(subst C,-DCOMPRESSED_ISA,$(COMPRESSED_ISA)) $^
chmod -x $@
testbench_rvf.vvp: testbench.v picorv32.v rvfimon.v
$(IVERILOG) -o $@ -D RISCV_FORMAL $(subst C,-DCOMPRESSED_ISA,$(COMPRESSED_ISA)) $^
chmod -x $@
testbench_wb.vvp: testbench_wb.v picorv32.v
$(IVERILOG) -o $@ $(subst C,-DCOMPRESSED_ISA,$(COMPRESSED_ISA)) $^
chmod -x $@
testbench_ez.vvp: testbench_ez.v picorv32.v
$(IVERILOG) -o $@ $(subst C,-DCOMPRESSED_ISA,$(COMPRESSED_ISA)) $^
chmod -x $@
testbench_sp.vvp: testbench.v picorv32.v
$(IVERILOG) -o $@ $(subst C,-DCOMPRESSED_ISA,$(COMPRESSED_ISA)) -DSP_TEST $^
chmod -x $@
testbench_synth.vvp: testbench.v synth.v
$(IVERILOG) -o $@ -DSYNTH_TEST $^
chmod -x $@
testbench_verilator: testbench.v picorv32.v testbench.cc
$(VERILATOR) --cc --exe -Wno-lint -trace --top-module picorv32_wrapper testbench.v picorv32.v testbench.cc \
$(subst C,-DCOMPRESSED_ISA,$(COMPRESSED_ISA)) --Mdir testbench_verilator_dir
$(MAKE) -C testbench_verilator_dir -f Vpicorv32_wrapper.mk
cp testbench_verilator_dir/Vpicorv32_wrapper testbench_verilator
check: check-yices
check-%: check.smt2
yosys-smtbmc -s $(subst check-,,$@) -t 30 --dump-vcd check.vcd check.smt2
yosys-smtbmc -s $(subst check-,,$@) -t 25 --dump-vcd check.vcd -i check.smt2
check.smt2: picorv32.v
yosys -v2 -p 'read_verilog -formal picorv32.v' \
-p 'prep -top picorv32 -nordff' \
-p 'assertpmux -noinit; opt -fast' \
-p 'write_smt2 -wires check.smt2'
synth.v: picorv32.v scripts/yosys/synth_sim.ys
yosys -qv3 -l synth.log scripts/yosys/synth_sim.ys
firmware/firmware.hex: firmware/firmware.bin firmware/makehex.py
$(PYTHON) firmware/makehex.py $< 32768 > $@
firmware/firmware.bin: firmware/firmware.elf
$(TOOLCHAIN_PREFIX)objcopy -O binary $< $@
chmod -x $@
firmware/firmware.elf: $(FIRMWARE_OBJS) $(TEST_OBJS) firmware/sections.lds
$(TOOLCHAIN_PREFIX)gcc -Os -ffreestanding -nostdlib -o $@ \
-Wl,-Bstatic,-T,firmware/sections.lds,-Map,firmware/firmware.map,--strip-debug \
$(FIRMWARE_OBJS) $(TEST_OBJS) -lgcc
chmod -x $@
firmware/start.o: firmware/start.S
$(TOOLCHAIN_PREFIX)gcc -c -march=rv32im$(subst C,c,$(COMPRESSED_ISA)) -o $@ $<
firmware/%.o: firmware/%.c
$(TOOLCHAIN_PREFIX)gcc -c -march=rv32i$(subst C,c,$(COMPRESSED_ISA)) -Os --std=c99 $(GCC_WARNS) -ffreestanding -nostdlib -o $@ $<
tests/%.o: tests/%.S tests/riscv_test.h tests/test_macros.h
$(TOOLCHAIN_PREFIX)gcc -c -march=rv32im -o $@ -DTEST_FUNC_NAME=$(notdir $(basename $<)) \
-DTEST_FUNC_TXT='"$(notdir $(basename $<))"' -DTEST_FUNC_RET=$(notdir $(basename $<))_ret $<
download-tools:
sudo bash -c 'set -ex; mkdir -p /var/cache/distfiles; $(GIT_ENV); \
$(foreach REPO,riscv-gnu-toolchain riscv-binutils-gdb riscv-gcc riscv-glibc riscv-newlib, \
if ! test -d /var/cache/distfiles/$(REPO).git; then rm -rf /var/cache/distfiles/$(REPO).git.part; \
git clone --bare https://github.com/riscv/$(REPO) /var/cache/distfiles/$(REPO).git.part; \
mv /var/cache/distfiles/$(REPO).git.part /var/cache/distfiles/$(REPO).git; else \
(cd /var/cache/distfiles/$(REPO).git; git fetch https://github.com/riscv/$(REPO)); fi;)'
define build_tools_template
build-$(1)-tools:
@read -p "This will remove all existing data from $(RISCV_GNU_TOOLCHAIN_INSTALL_PREFIX)$(subst riscv32,,$(1)). Type YES to continue: " reply && [[ "$$$$reply" == [Yy][Ee][Ss] || "$$$$reply" == [Yy] ]]
sudo bash -c "set -ex; rm -rf $(RISCV_GNU_TOOLCHAIN_INSTALL_PREFIX)$(subst riscv32,,$(1)); mkdir -p $(RISCV_GNU_TOOLCHAIN_INSTALL_PREFIX)$(subst riscv32,,$(1)); chown $$$${USER}: $(RISCV_GNU_TOOLCHAIN_INSTALL_PREFIX)$(subst riscv32,,$(1))"
+$(MAKE) build-$(1)-tools-bh
build-$(1)-tools-bh:
+set -ex; $(GIT_ENV); \
if [ -d /var/cache/distfiles/riscv-gnu-toolchain.git ]; then reference_riscv_gnu_toolchain="--reference /var/cache/distfiles/riscv-gnu-toolchain.git"; else reference_riscv_gnu_toolchain=""; fi; \
if [ -d /var/cache/distfiles/riscv-binutils-gdb.git ]; then reference_riscv_binutils_gdb="--reference /var/cache/distfiles/riscv-binutils-gdb.git"; else reference_riscv_binutils_gdb=""; fi; \
if [ -d /var/cache/distfiles/riscv-gcc.git ]; then reference_riscv_gcc="--reference /var/cache/distfiles/riscv-gcc.git"; else reference_riscv_gcc=""; fi; \
if [ -d /var/cache/distfiles/riscv-glibc.git ]; then reference_riscv_glibc="--reference /var/cache/distfiles/riscv-glibc.git"; else reference_riscv_glibc=""; fi; \
if [ -d /var/cache/distfiles/riscv-newlib.git ]; then reference_riscv_newlib="--reference /var/cache/distfiles/riscv-newlib.git"; else reference_riscv_newlib=""; fi; \
rm -rf riscv-gnu-toolchain-$(1); git clone $$$$reference_riscv_gnu_toolchain https://github.com/riscv/riscv-gnu-toolchain riscv-gnu-toolchain-$(1); \
cd riscv-gnu-toolchain-$(1); git checkout $(RISCV_GNU_TOOLCHAIN_GIT_REVISION); \
git submodule update --init $$$$reference_riscv_binutils_gdb riscv-binutils; \
git submodule update --init $$$$reference_riscv_binutils_gdb riscv-gdb; \
git submodule update --init $$$$reference_riscv_gcc riscv-gcc; \
git submodule update --init $$$$reference_riscv_glibc riscv-glibc; \
git submodule update --init $$$$reference_riscv_newlib riscv-newlib; \
mkdir build; cd build; ../configure --with-arch=$(2) --prefix=$(RISCV_GNU_TOOLCHAIN_INSTALL_PREFIX)$(subst riscv32,,$(1)); make
.PHONY: build-$(1)-tools
endef
$(eval $(call build_tools_template,riscv32i,rv32i))
$(eval $(call build_tools_template,riscv32ic,rv32ic))
$(eval $(call build_tools_template,riscv32im,rv32im))
$(eval $(call build_tools_template,riscv32imc,rv32imc))
build-tools:
@echo "This will remove all existing data from $(RISCV_GNU_TOOLCHAIN_INSTALL_PREFIX)i, $(RISCV_GNU_TOOLCHAIN_INSTALL_PREFIX)ic, $(RISCV_GNU_TOOLCHAIN_INSTALL_PREFIX)im, and $(RISCV_GNU_TOOLCHAIN_INSTALL_PREFIX)imc."
@read -p "Type YES to continue: " reply && [[ "$$reply" == [Yy][Ee][Ss] || "$$reply" == [Yy] ]]
sudo bash -c "set -ex; rm -rf $(RISCV_GNU_TOOLCHAIN_INSTALL_PREFIX){i,ic,im,imc}; mkdir -p $(RISCV_GNU_TOOLCHAIN_INSTALL_PREFIX){i,ic,im,imc}; chown $${USER}: $(RISCV_GNU_TOOLCHAIN_INSTALL_PREFIX){i,ic,im,imc}"
+$(MAKE) build-riscv32i-tools-bh
+$(MAKE) build-riscv32ic-tools-bh
+$(MAKE) build-riscv32im-tools-bh
+$(MAKE) build-riscv32imc-tools-bh
toc:
gawk '/^-+$$/ { y=tolower(x); gsub("[^a-z0-9]+", "-", y); gsub("-$$", "", y); printf("- [%s](#%s)\n", x, y); } { x=$$0; }' README.md
clean:
rm -rf riscv-gnu-toolchain-riscv32i riscv-gnu-toolchain-riscv32ic \
riscv-gnu-toolchain-riscv32im riscv-gnu-toolchain-riscv32imc
rm -vrf $(FIRMWARE_OBJS) $(TEST_OBJS) check.smt2 check.vcd synth.v synth.log \
firmware/firmware.elf firmware/firmware.bin firmware/firmware.hex firmware/firmware.map \
testbench.vvp testbench_sp.vvp testbench_synth.vvp testbench_ez.vvp \
testbench_rvf.vvp testbench_wb.vvp testbench.vcd testbench.trace \
testbench_verilator testbench_verilator_dir
.PHONY: test test_vcd test_sp test_axi test_wb test_wb_vcd test_ez test_ez_vcd test_synth download-tools build-tools toc clean

735
fw/picorv32/README.md Normal file
View File

@ -0,0 +1,735 @@
PicoRV32 - A Size-Optimized RISC-V CPU
======================================
PicoRV32 is a CPU core that implements the [RISC-V RV32IMC Instruction Set](http://riscv.org/).
It can be configured as RV32E, RV32I, RV32IC, RV32IM, or RV32IMC core, and optionally
contains a built-in interrupt controller.
Tools (gcc, binutils, etc..) can be obtained via the [RISC-V Website](https://riscv.org/software-status/).
The examples bundled with PicoRV32 expect various RV32 toolchains to be installed in `/opt/riscv32i[m][c]`. See
the [build instructions below](#building-a-pure-rv32i-toolchain) for details.
PicoRV32 is free and open hardware licensed under the [ISC license](http://en.wikipedia.org/wiki/ISC_license)
(a license that is similar in terms to the MIT license or the 2-clause BSD license).
#### Table of Contents
- [Features and Typical Applications](#features-and-typical-applications)
- [Files in this Repository](#files-in-this-repository)
- [Verilog Module Parameters](#verilog-module-parameters)
- [Cycles per Instruction Performance](#cycles-per-instruction-performance)
- [PicoRV32 Native Memory Interface](#picorv32-native-memory-interface)
- [Pico Co-Processor Interface (PCPI)](#pico-co-processor-interface-pcpi)
- [Custom Instructions for IRQ Handling](#custom-instructions-for-irq-handling)
- [Building a pure RV32I Toolchain](#building-a-pure-rv32i-toolchain)
- [Linking binaries with newlib for PicoRV32](#linking-binaries-with-newlib-for-picorv32)
- [Evaluation: Timing and Utilization on Xilinx 7-Series FPGAs](#evaluation-timing-and-utilization-on-xilinx-7-series-fpgas)
Features and Typical Applications
---------------------------------
- Small (750-2000 LUTs in 7-Series Xilinx Architecture)
- High f<sub>max</sub> (250-450 MHz on 7-Series Xilinx FPGAs)
- Selectable native memory interface or AXI4-Lite master
- Optional IRQ support (using a simple custom ISA)
- Optional Co-Processor Interface
This CPU is meant to be used as auxiliary processor in FPGA designs and ASICs. Due
to its high f<sub>max</sub> it can be integrated in most existing designs without crossing
clock domains. When operated on a lower frequency, it will have a lot of timing
slack and thus can be added to a design without compromising timing closure.
For even smaller size it is possible disable support for registers `x16`..`x31` as
well as `RDCYCLE[H]`, `RDTIME[H]`, and `RDINSTRET[H]` instructions, turning the
processor into an RV32E core.
Furthermore it is possible to choose between a dual-port and a single-port
register file implementation. The former provides better performance while
the latter results in a smaller core.
*Note: In architectures that implement the register file in dedicated memory
resources, such as many FPGAs, disabling the 16 upper registers and/or
disabling the dual-port register file may not further reduce the core size.*
The core exists in three variations: `picorv32`, `picorv32_axi` and `picorv32_wb`.
The first provides a simple native memory interface, that is easy to use in simple
environments. `picorv32_axi` provides an AXI-4 Lite Master interface that can
easily be integrated with existing systems that are already using the AXI
standard. `picorv32_wb` provides a Wishbone master interface.
A separate core `picorv32_axi_adapter` is provided to bridge between the native
memory interface and AXI4. This core can be used to create custom cores that
include one or more PicoRV32 cores together with local RAM, ROM, and
memory-mapped peripherals, communicating with each other using the native
interface, and communicating with the outside world via AXI4.
The optional IRQ feature can be used to react to events from the outside, implement
fault handlers, or catch instructions from a larger ISA and emulate them in
software.
The optional Pico Co-Processor Interface (PCPI) can be used to implement
non-branching instructions in an external coprocessor. Implementations
of PCPI cores that implement the M Standard Extension instructions
`MUL[H[SU|U]]` and `DIV[U]/REM[U]` are included in this package.
Files in this Repository
------------------------
#### README.md
You are reading it right now.
#### picorv32.v
This Verilog file contains the following Verilog modules:
| Module | Description |
| ------------------------ | --------------------------------------------------------------------- |
| `picorv32` | The PicoRV32 CPU |
| `picorv32_axi` | The version of the CPU with AXI4-Lite interface |
| `picorv32_axi_adapter` | Adapter from PicoRV32 Memory Interface to AXI4-Lite |
| `picorv32_wb` | The version of the CPU with Wishbone Master interface |
| `picorv32_pcpi_mul` | A PCPI core that implements the `MUL[H[SU\|U]]` instructions |
| `picorv32_pcpi_fast_mul` | A version of `picorv32_pcpi_fast_mul` using a single cycle multiplier |
| `picorv32_pcpi_div` | A PCPI core that implements the `DIV[U]/REM[U]` instructions |
Simply copy this file into your project.
#### Makefile and testbenches
A basic test environment. Run `make test` to run the standard test bench (`testbench.v`)
in the standard configurations. There are other test benches and configurations. See
the `test_*` make target in the Makefile for details.
Run `make test_ez` to run `testbench_ez.v`, a very simple test bench that does
not require an external firmware .hex file. This can be useful in environments
where the RISC-V compiler toolchain is not available.
*Note: The test bench is using Icarus Verilog. However, Icarus Verilog 0.9.7
(the latest release at the time of writing) has a few bugs that prevent the
test bench from running. Upgrade to the latest github master of Icarus Verilog
to run the test bench.*
#### firmware/
A simple test firmware. This runs the basic tests from `tests/`, some C code, tests IRQ
handling and the multiply PCPI core.
All the code in `firmware/` is in the public domain. Simply copy whatever you can use.
#### tests/
Simple instruction-level tests from [riscv-tests](https://github.com/riscv/riscv-tests).
#### dhrystone/
Another simple test firmware that runs the Dhrystone benchmark.
#### picosoc/
A simple example SoC using PicoRV32 that can execute code directly from a
memory mapped SPI flash.
#### scripts/
Various scripts and examples for different (synthesis) tools and hardware architectures.
Verilog Module Parameters
-------------------------
The following Verilog module parameters can be used to configure the PicoRV32
core.
#### ENABLE_COUNTERS (default = 1)
This parameter enables support for the `RDCYCLE[H]`, `RDTIME[H]`, and
`RDINSTRET[H]` instructions. This instructions will cause a hardware
trap (like any other unsupported instruction) if `ENABLE_COUNTERS` is set to zero.
*Note: Strictly speaking the `RDCYCLE[H]`, `RDTIME[H]`, and `RDINSTRET[H]`
instructions are not optional for an RV32I core. But chances are they are not
going to be missed after the application code has been debugged and profiled.
This instructions are optional for an RV32E core.*
#### ENABLE_COUNTERS64 (default = 1)
This parameter enables support for the `RDCYCLEH`, `RDTIMEH`, and `RDINSTRETH`
instructions. If this parameter is set to 0, and `ENABLE_COUNTERS` is set to 1,
then only the `RDCYCLE`, `RDTIME`, and `RDINSTRET` instructions are available.
#### ENABLE_REGS_16_31 (default = 1)
This parameter enables support for registers the `x16`..`x31`. The RV32E ISA
excludes this registers. However, the RV32E ISA spec requires a hardware trap
for when code tries to access this registers. This is not implemented in PicoRV32.
#### ENABLE_REGS_DUALPORT (default = 1)
The register file can be implemented with two or one read ports. A dual ported
register file improves performance a bit, but can also increase the size of
the core.
#### LATCHED_MEM_RDATA (default = 0)
Set this to 1 if the `mem_rdata` is kept stable by the external circuit after a
transaction. In the default configuration the PicoRV32 core only expects the
`mem_rdata` input to be valid in the cycle with `mem_valid && mem_ready` and
latches the value internally.
This parameter is only available for the `picorv32` core. In the
`picorv32_axi` and `picorv32_wb` core this is implicitly set to 0.
#### TWO_STAGE_SHIFT (default = 1)
By default shift operations are performed in two stages: first shifts in units
of 4 bits and then shifts in units of 1 bit. This speeds up shift operations,
but adds additional hardware. Set this parameter to 0 to disable the two-stage
shift to further reduce the size of the core.
#### BARREL_SHIFTER (default = 0)
By default shift operations are performed by successively shifting by a
small amount (see `TWO_STAGE_SHIFT` above). With this option set, a barrel
shifter is used instead.
#### TWO_CYCLE_COMPARE (default = 0)
This relaxes the longest data path a bit by adding an additional FF stage
at the cost of adding an additional clock cycle delay to the conditional
branch instructions.
*Note: Enabling this parameter will be most effective when retiming (aka
"register balancing") is enabled in the synthesis flow.*
#### TWO_CYCLE_ALU (default = 0)
This adds an additional FF stage in the ALU data path, improving timing
at the cost of an additional clock cycle for all instructions that use
the ALU.
*Note: Enabling this parameter will be most effective when retiming (aka
"register balancing") is enabled in the synthesis flow.*
#### COMPRESSED_ISA (default = 0)
This enables support for the RISC-V Compressed Instruction Set.
#### CATCH_MISALIGN (default = 1)
Set this to 0 to disable the circuitry for catching misaligned memory
accesses.
#### CATCH_ILLINSN (default = 1)
Set this to 0 to disable the circuitry for catching illegal instructions.
The core will still trap on `EBREAK` instructions with this option
set to 0. With IRQs enabled, an `EBREAK` normally triggers an IRQ 1. With
this option set to 0, an `EBREAK` will trap the processor without
triggering an interrupt.
#### ENABLE_PCPI (default = 0)
Set this to 1 to enable the Pico Co-Processor Interface (PCPI).
#### ENABLE_MUL (default = 0)
This parameter internally enables PCPI and instantiates the `picorv32_pcpi_mul`
core that implements the `MUL[H[SU|U]]` instructions. The external PCPI
interface only becomes functional when ENABLE_PCPI is set as well.
#### ENABLE_FAST_MUL (default = 0)
This parameter internally enables PCPI and instantiates the `picorv32_pcpi_fast_mul`
core that implements the `MUL[H[SU|U]]` instructions. The external PCPI
interface only becomes functional when ENABLE_PCPI is set as well.
If both ENABLE_MUL and ENABLE_FAST_MUL are set then the ENABLE_MUL setting
will be ignored and the fast multiplier core will be instantiated.
#### ENABLE_DIV (default = 0)
This parameter internally enables PCPI and instantiates the `picorv32_pcpi_div`
core that implements the `DIV[U]/REM[U]` instructions. The external PCPI
interface only becomes functional when ENABLE_PCPI is set as well.
#### ENABLE_IRQ (default = 0)
Set this to 1 to enable IRQs. (see "Custom Instructions for IRQ Handling" below
for a discussion of IRQs)
#### ENABLE_IRQ_QREGS (default = 1)
Set this to 0 to disable support for the `getq` and `setq` instructions. Without
the q-registers, the irq return address will be stored in x3 (gp) and the IRQ
bitmask in x4 (tp), the global pointer and thread pointer registers according
to the RISC-V ABI. Code generated from ordinary C code will not interact with
those registers.
Support for q-registers is always disabled when ENABLE_IRQ is set to 0.
#### ENABLE_IRQ_TIMER (default = 1)
Set this to 0 to disable support for the `timer` instruction.
Support for the timer is always disabled when ENABLE_IRQ is set to 0.
#### ENABLE_TRACE (default = 0)
Produce an execution trace using the `trace_valid` and `trace_data` output ports.
For a demontration of this feature run `make test_vcd` to create a trace file
and then run `python3 showtrace.py testbench.trace firmware/firmware.elf` to decode
it.
#### REGS_INIT_ZERO (default = 0)
Set this to 1 to initialize all registers to zero (using a Verilog `initial` block).
This can be useful for simulation or formal verification.
#### MASKED_IRQ (default = 32'h 0000_0000)
A 1 bit in this bitmask corresponds to a permanently disabled IRQ.
#### LATCHED_IRQ (default = 32'h ffff_ffff)
A 1 bit in this bitmask indicates that the corresponding IRQ is "latched", i.e.
when the IRQ line is high for only one cycle, the interrupt will be marked as
pending and stay pending until the interrupt handler is called (aka "pulse
interrupts" or "edge-triggered interrupts").
Set a bit in this bitmask to 0 to convert an interrupt line to operate
as "level sensitive" interrupt.
#### PROGADDR_RESET (default = 32'h 0000_0000)
The start address of the program.
#### PROGADDR_IRQ (default = 32'h 0000_0010)
The start address of the interrupt handler.
#### STACKADDR (default = 32'h ffff_ffff)
When this parameter has a value different from 0xffffffff, then register `x2` (the
stack pointer) is initialized to this value on reset. (All other registers remain
uninitialized.) Note that the RISC-V calling convention requires the stack pointer
to be aligned on 16 bytes boundaries (4 bytes for the RV32I soft float calling
convention).
Cycles per Instruction Performance
----------------------------------
*A short reminder: This core is optimized for size and f<sub>max</sub>, not performance.*
Unless stated otherwise, the following numbers apply to a PicoRV32 with
ENABLE_REGS_DUALPORT active and connected to a memory that can accommodate
requests within one clock cycle.
The average Cycles per Instruction (CPI) is approximately 4, depending on the mix of
instructions in the code. The CPI numbers for the individual instructions can
be found in the table below. The column "CPI (SP)" contains the CPI numbers for
a core built without ENABLE_REGS_DUALPORT.
| Instruction | CPI | CPI (SP) |
| ---------------------| ----:| --------:|
| direct jump (jal) | 3 | 3 |
| ALU reg + immediate | 3 | 3 |
| ALU reg + reg | 3 | 4 |
| branch (not taken) | 3 | 4 |
| memory load | 5 | 5 |
| memory store | 5 | 6 |
| branch (taken) | 5 | 6 |
| indirect jump (jalr) | 6 | 6 |
| shift operations | 4-14 | 4-15 |
When `ENABLE_MUL` is activated, then a `MUL` instruction will execute
in 40 cycles and a `MULH[SU|U]` instruction will execute in 72 cycles.
When `ENABLE_DIV` is activated, then a `DIV[U]/REM[U]` instruction will
execute in 40 cycles.
When `BARREL_SHIFTER` is activated, a shift operation takes as long as
any other ALU operation.
The following dhrystone benchmark results are for a core with enabled
`ENABLE_FAST_MUL`, `ENABLE_DIV`, and `BARREL_SHIFTER` options.
Dhrystone benchmark results: 0.516 DMIPS/MHz (908 Dhrystones/Second/MHz)
For the Dhrystone benchmark the average CPI is 4.100.
Without using the look-ahead memory interface (usually required for max
clock speed), this results drop to 0.305 DMIPS/MHz and 5.232 CPI.
PicoRV32 Native Memory Interface
--------------------------------
The native memory interface of PicoRV32 is a simple valid-ready interface
that can run one memory transfer at a time:
output mem_valid
output mem_instr
input mem_ready
output [31:0] mem_addr
output [31:0] mem_wdata
output [ 3:0] mem_wstrb
input [31:0] mem_rdata
The core initiates a memory transfer by asserting `mem_valid`. The valid
signal stays high until the peer asserts `mem_ready`. All core outputs
are stable over the `mem_valid` period. If the memory transfer is an
instruction fetch, the core asserts `mem_instr`.
#### Read Transfer
In a read transfer `mem_wstrb` has the value 0 and `mem_wdata` is unused.
The memory reads the address `mem_addr` and makes the read value available on
`mem_rdata` in the cycle `mem_ready` is high.
There is no need for an external wait cycle. The memory read can be implemented
asynchronously with `mem_ready` going high in the same cycle as `mem_valid`, or
`mem_ready` being tied to constant 1.
#### Write Transfer
In a write transfer `mem_wstrb` is not 0 and `mem_rdata` is unused. The memory
write the data at `mem_wdata` to the address `mem_addr` and acknowledges the
transfer by asserting `mem_ready`.
The 4 bits of `mem_wstrb` are write enables for the four bytes in the addressed
word. Only the 8 values `0000`, `1111`, `1100`, `0011`, `1000`, `0100`, `0010`,
and `0001` are possible, i.e. no write, write 32 bits, write upper 16 bits,
write lower 16, or write a single byte respectively.
There is no need for an external wait cycle. The memory can acknowledge the
write immediately with `mem_ready` going high in the same cycle as
`mem_valid`, or `mem_ready` being tied to constant 1.
#### Look-Ahead Interface
The PicoRV32 core also provides a "Look-Ahead Memory Interface" that provides
all information about the next memory transfer one clock cycle earlier than the
normal interface.
output mem_la_read
output mem_la_write
output [31:0] mem_la_addr
output [31:0] mem_la_wdata
output [ 3:0] mem_la_wstrb
In the clock cycle before `mem_valid` goes high, this interface will output a
pulse on `mem_la_read` or `mem_la_write` to indicate the start of a read or
write transaction in the next clock cycle.
*Note: The signals `mem_la_read`, `mem_la_write`, and `mem_la_addr` are driven
by combinatorial circuits within the PicoRV32 core. It might be harder to
achieve timing closure with the look-ahead interface than with the normal
memory interface described above.*
Pico Co-Processor Interface (PCPI)
----------------------------------
The Pico Co-Processor Interface (PCPI) can be used to implement non-branching
instructions in external cores:
output pcpi_valid
output [31:0] pcpi_insn
output [31:0] pcpi_rs1
output [31:0] pcpi_rs2
input pcpi_wr
input [31:0] pcpi_rd
input pcpi_wait
input pcpi_ready
When an unsupported instruction is encountered and the PCPI feature is
activated (see ENABLE_PCPI above), then `pcpi_valid` is asserted, the
instruction word itself is output on `pcpi_insn`, the `rs1` and `rs2`
fields are decoded and the values in those registers are output
on `pcpi_rs1` and `pcpi_rs2`.
An external PCPI core can then decode the instruction, execute it, and assert
`pcpi_ready` when execution of the instruction is finished. Optionally a
result value can be written to `pcpi_rd` and `pcpi_wr` asserted. The
PicoRV32 core will then decode the `rd` field of the instruction and
write the value from `pcpi_rd` to the respective register.
When no external PCPI core acknowledges the instruction within 16 clock
cycles, then an illegal instruction exception is raised and the respective
interrupt handler is called. A PCPI core that needs more than a couple of
cycles to execute an instruction, should assert `pcpi_wait` as soon as
the instruction has been decoded successfully and keep it asserted until
it asserts `pcpi_ready`. This will prevent the PicoRV32 core from raising
an illegal instruction exception.
Custom Instructions for IRQ Handling
------------------------------------
*Note: The IRQ handling features in PicoRV32 do not follow the RISC-V
Privileged ISA specification. Instead a small set of very simple custom
instructions is used to implement IRQ handling with minimal hardware
overhead.*
The following custom instructions are only supported when IRQs are enabled
via the `ENABLE_IRQ` parameter (see above).
The PicoRV32 core has a built-in interrupt controller with 32 interrupt inputs. An
interrupt can be triggered by asserting the corresponding bit in the `irq`
input of the core.
When the interrupt handler is started, the `eoi` End Of Interrupt (EOI) signals
for the handled interrupts go high. The `eoi` signals go low again when the
interrupt handler returns.
The IRQs 0-2 can be triggered internally by the following built-in interrupt sources:
| IRQ | Interrupt Source |
| ---:| ------------------------------------|
| 0 | Timer Interrupt |
| 1 | EBREAK/ECALL or Illegal Instruction |
| 2 | BUS Error (Unalign Memory Access) |
This interrupts can also be triggered by external sources, such as co-processors
connected via PCPI.
The core has 4 additional 32-bit registers `q0 .. q3` that are used for IRQ
handling. When the IRQ handler is called, the register `q0` contains the return
address and `q1` contains a bitmask of all IRQs to be handled. This means one
call to the interrupt handler needs to service more than one IRQ when more than
one bit is set in `q1`.
When support for compressed instructions is enabled, then the LSB of q0 is set
when the interrupted instruction is a compressed instruction. This can be used if
the IRQ handler wants to decode the interrupted instruction.
Registers `q2` and `q3` are uninitialized and can be used as temporary storage
when saving/restoring register values in the IRQ handler.
All of the following instructions are encoded under the `custom0` opcode. The f3
and rs2 fields are ignored in all this instructions.
See [firmware/custom_ops.S](firmware/custom_ops.S) for GNU assembler macros that
implement mnemonics for this instructions.
See [firmware/start.S](firmware/start.S) for an example implementation of an
interrupt handler assembler wrapper, and [firmware/irq.c](firmware/irq.c) for
the actual interrupt handler.
#### getq rd, qs
This instruction copies the value from a q-register to a general-purpose
register.
0000000 ----- 000XX --- XXXXX 0001011
f7 rs2 qs f3 rd opcode
Example:
getq x5, q2
#### setq qd, rs
This instruction copies the value from a general-purpose register to a
q-register.
0000001 ----- XXXXX --- 000XX 0001011
f7 rs2 rs f3 qd opcode
Example:
setq q2, x5
#### retirq
Return from interrupt. This instruction copies the value from `q0`
to the program counter and re-enables interrupts.
0000010 ----- 00000 --- 00000 0001011
f7 rs2 rs f3 rd opcode
Example:
retirq
#### maskirq
The "IRQ Mask" register contains a bitmask of masked (disabled) interrupts.
This instruction writes a new value to the irq mask register and reads the old
value.
0000011 ----- XXXXX --- XXXXX 0001011
f7 rs2 rs f3 rd opcode
Example:
maskirq x1, x2
The processor starts with all interrupts disabled.
An illegal instruction or bus error while the illegal instruction or bus error
interrupt is disabled will cause the processor to halt.
#### waitirq
Pause execution until an interrupt becomes pending. The bitmask of pending IRQs
is written to `rd`.
0000100 ----- 00000 --- XXXXX 0001011
f7 rs2 rs f3 rd opcode
Example:
waitirq x1
#### timer
Reset the timer counter to a new value. The counter counts down clock cycles and
triggers the timer interrupt when transitioning from 1 to 0. Setting the
counter to zero disables the timer. The old value of the counter is written to
`rd`.
0000101 ----- XXXXX --- XXXXX 0001011
f7 rs2 rs f3 rd opcode
Example:
timer x1, x2
Building a pure RV32I Toolchain
-------------------------------
TL;DR: Run the following commands to build the complete toolchain:
make download-tools
make -j$(nproc) build-tools
The default settings in the [riscv-tools](https://github.com/riscv/riscv-tools) build
scripts will build a compiler, assembler and linker that can target any RISC-V ISA,
but the libraries are built for RV32G and RV64G targets. Follow the instructions
below to build a complete toolchain (including libraries) that target a pure RV32I
CPU.
The following commands will build the RISC-V GNU toolchain and libraries for a
pure RV32I target, and install it in `/opt/riscv32i`:
# Ubuntu packages needed:
sudo apt-get install autoconf automake autotools-dev curl libmpc-dev \
libmpfr-dev libgmp-dev gawk build-essential bison flex texinfo \
gperf libtool patchutils bc zlib1g-dev git libexpat1-dev
sudo mkdir /opt/riscv32i
sudo chown $USER /opt/riscv32i
git clone https://github.com/riscv/riscv-gnu-toolchain riscv-gnu-toolchain-rv32i
cd riscv-gnu-toolchain-rv32i
git checkout 411d134
git submodule update --init --recursive
mkdir build; cd build
../configure --with-arch=rv32i --prefix=/opt/riscv32i
make -j$(nproc)
The commands will all be named using the prefix `riscv32-unknown-elf-`, which
makes it easy to install them side-by-side with the regular riscv-tools (those
are using the name prefix `riscv64-unknown-elf-` by default).
Alternatively you can simply use one of the following make targets from PicoRV32's
Makefile to build a `RV32I[M][C]` toolchain. You still need to install all
prerequisites, as described above. Then run any of the following commands in the
PicoRV32 source directory:
| Command | Install Directory | ISA |
|:---------------------------------------- |:------------------ |:-------- |
| `make -j$(nproc) build-riscv32i-tools` | `/opt/riscv32i/` | `RV32I` |
| `make -j$(nproc) build-riscv32ic-tools` | `/opt/riscv32ic/` | `RV32IC` |
| `make -j$(nproc) build-riscv32im-tools` | `/opt/riscv32im/` | `RV32IM` |
| `make -j$(nproc) build-riscv32imc-tools` | `/opt/riscv32imc/` | `RV32IMC` |
Or simply run `make -j$(nproc) build-tools` to build and install all four tool chains.
By default calling any of those make targets will (re-)download the toolchain
sources. Run `make download-tools` to download the sources to `/var/cache/distfiles/`
once in advance.
*Note: These instructions are for git rev 411d134 (2018-02-14) of riscv-gnu-toolchain.*
Linking binaries with newlib for PicoRV32
-----------------------------------------
The tool chains (see last section for install instructions) come with a version of
the newlib C standard library.
Use the linker script [firmware/riscv.ld](firmware/riscv.ld) for linking binaries
against the newlib library. Using this linker script will create a binary that
has its entry point at 0x10000. (The default linker script does not have a static
entry point, thus a proper ELF loader would be needed that can determine the
entry point at runtime while loading the program.)
Newlib comes with a few syscall stubs. You need to provide your own implementation
of those syscalls and link your program with this implementation, overwriting the
default stubs from newlib. See `syscalls.c` in [scripts/cxxdemo/](scripts/cxxdemo/)
for an example of how to do that.
Evaluation: Timing and Utilization on Xilinx 7-Series FPGAs
-----------------------------------------------------------
The following evaluations have been performed with Vivado 2017.3.
#### Timing on Xilinx 7-Series FPGAs
The `picorv32_axi` module with enabled `TWO_CYCLE_ALU` has been placed and
routed for Xilinx Artix-7T, Kintex-7T, Virtex-7T, Kintex UltraScale, and Virtex
UltraScale devices in all speed grades. A binary search is used to find the
shortest clock period for which the design meets timing.
See `make table.txt` in [scripts/vivado/](scripts/vivado/).
| Device | Device | Speedgrade | Clock Period (Freq.) |
|:------------------------- |:---------------------|:----------:| --------------------:|
| Xilinx Kintex-7T | xc7k70t-fbg676-2 | -2 | 2.4 ns (416 MHz) |
| Xilinx Kintex-7T | xc7k70t-fbg676-3 | -3 | 2.2 ns (454 MHz) |
| Xilinx Virtex-7T | xc7v585t-ffg1761-2 | -2 | 2.3 ns (434 MHz) |
| Xilinx Virtex-7T | xc7v585t-ffg1761-3 | -3 | 2.2 ns (454 MHz) |
| Xilinx Kintex UltraScale | xcku035-fbva676-2-e | -2 | 2.0 ns (500 MHz) |
| Xilinx Kintex UltraScale | xcku035-fbva676-3-e | -3 | 1.8 ns (555 MHz) |
| Xilinx Virtex UltraScale | xcvu065-ffvc1517-2-e | -2 | 2.1 ns (476 MHz) |
| Xilinx Virtex UltraScale | xcvu065-ffvc1517-3-e | -3 | 2.0 ns (500 MHz) |
| Xilinx Kintex UltraScale+ | xcku3p-ffva676-2-e | -2 | 1.4 ns (714 MHz) |
| Xilinx Kintex UltraScale+ | xcku3p-ffva676-3-e | -3 | 1.3 ns (769 MHz) |
| Xilinx Virtex UltraScale+ | xcvu3p-ffvc1517-2-e | -2 | 1.5 ns (666 MHz) |
| Xilinx Virtex UltraScale+ | xcvu3p-ffvc1517-3-e | -3 | 1.4 ns (714 MHz) |
#### Utilization on Xilinx 7-Series FPGAs
The following table lists the resource utilization in area-optimized synthesis
for the following three cores:
- **PicoRV32 (small):** The `picorv32` module without counter instructions,
without two-stage shifts, with externally latched `mem_rdata`, and without
catching of misaligned memory accesses and illegal instructions.
- **PicoRV32 (regular):** The `picorv32` module in its default configuration.
- **PicoRV32 (large):** The `picorv32` module with enabled PCPI, IRQ, MUL,
DIV, BARREL_SHIFTER, and COMPRESSED_ISA features.
See `make area` in [scripts/vivado/](scripts/vivado/).
| Core Variant | Slice LUTs | LUTs as Memory | Slice Registers |
|:------------------ | ----------:| --------------:| ---------------:|
| PicoRV32 (small) | 761 | 48 | 442 |
| PicoRV32 (regular) | 917 | 48 | 583 |
| PicoRV32 (large) | 2019 | 88 | 1085 |

View File

@ -0,0 +1,69 @@
USE_MYSTDLIB = 0
OBJS = dhry_1.o dhry_2.o stdlib.o
CFLAGS = -MD -O3 -march=rv32im -DTIME -DRISCV
TOOLCHAIN_PREFIX = /opt/riscv32im/bin/riscv32-unknown-elf-
ifeq ($(USE_MYSTDLIB),1)
CFLAGS += -DUSE_MYSTDLIB -ffreestanding -nostdlib
OBJS += start.o
else
OBJS += syscalls.o
endif
test: testbench.vvp dhry.hex
vvp -N testbench.vvp
test_trace: testbench.vvp dhry.hex
vvp -N $< +trace
python3 ../showtrace.py testbench.trace dhry.elf > testbench.ins
test_nola: testbench_nola.vvp dhry.hex
vvp -N testbench_nola.vvp
timing: timing.txt
grep '^##' timing.txt | gawk 'x != "" {print x,$$3-y;} {x=$$2;y=$$3;}' | sort | uniq -c | \
gawk '{printf("%03d-%-7s %2d %-8s (%d)\n",$$3,$$2,$$3,$$2,$$1);}' | sort | cut -c13-
timing.txt: timing.vvp dhry.hex
vvp -N timing.vvp > timing.txt
testbench.vvp: testbench.v ../picorv32.v
iverilog -o testbench.vvp testbench.v ../picorv32.v
chmod -x testbench.vvp
testbench_nola.vvp: testbench_nola.v ../picorv32.v
iverilog -o testbench_nola.vvp testbench_nola.v ../picorv32.v
chmod -x testbench_nola.vvp
timing.vvp: testbench.v ../picorv32.v
iverilog -o timing.vvp -DTIMING testbench.v ../picorv32.v
chmod -x timing.vvp
dhry.hex: dhry.elf
$(TOOLCHAIN_PREFIX)objcopy -O verilog $< $@
ifeq ($(USE_MYSTDLIB),1)
dhry.elf: $(OBJS) sections.lds
$(TOOLCHAIN_PREFIX)gcc $(CFLAGS) -Wl,-Bstatic,-T,sections.lds,-Map,dhry.map,--strip-debug -o $@ $(OBJS) -lgcc
chmod -x $@
else
dhry.elf: $(OBJS)
$(TOOLCHAIN_PREFIX)gcc $(CFLAGS) -Wl,-Bstatic,-T,../firmware/riscv.ld,-Map,dhry.map,--strip-debug -o $@ $(OBJS) -lgcc -lc
chmod -x $@
endif
%.o: %.c
$(TOOLCHAIN_PREFIX)gcc -c $(CFLAGS) $<
%.o: %.S
$(TOOLCHAIN_PREFIX)gcc -c $(CFLAGS) $<
dhry_1.o dhry_2.o: CFLAGS += -Wno-implicit-int -Wno-implicit-function-declaration
clean:
rm -rf *.o *.d dhry.elf dhry.map dhry.bin dhry.hex testbench.vvp testbench.vcd timing.vvp timing.txt testbench_nola.vvp
.PHONY: test clean
-include *.d

View File

@ -0,0 +1 @@
The Dhrystone benchmark and a verilog testbench to run it.

View File

@ -0,0 +1,423 @@
/*
****************************************************************************
*
* "DHRYSTONE" Benchmark Program
* -----------------------------
*
* Version: C, Version 2.1
*
* File: dhry.h (part 1 of 3)
*
* Date: May 25, 1988
*
* Author: Reinhold P. Weicker
* Siemens AG, AUT E 51
* Postfach 3220
* 8520 Erlangen
* Germany (West)
* Phone: [+49]-9131-7-20330
* (8-17 Central European Time)
* Usenet: ..!mcsun!unido!estevax!weicker
*
* Original Version (in Ada) published in
* "Communications of the ACM" vol. 27., no. 10 (Oct. 1984),
* pp. 1013 - 1030, together with the statistics
* on which the distribution of statements etc. is based.
*
* In this C version, the following C library functions are used:
* - strcpy, strcmp (inside the measurement loop)
* - printf, scanf (outside the measurement loop)
* In addition, Berkeley UNIX system calls "times ()" or "time ()"
* are used for execution time measurement. For measurements
* on other systems, these calls have to be changed.
*
* Collection of Results:
* Reinhold Weicker (address see above) and
*
* Rick Richardson
* PC Research. Inc.
* 94 Apple Orchard Drive
* Tinton Falls, NJ 07724
* Phone: (201) 389-8963 (9-17 EST)
* Usenet: ...!uunet!pcrat!rick
*
* Please send results to Rick Richardson and/or Reinhold Weicker.
* Complete information should be given on hardware and software used.
* Hardware information includes: Machine type, CPU, type and size
* of caches; for microprocessors: clock frequency, memory speed
* (number of wait states).
* Software information includes: Compiler (and runtime library)
* manufacturer and version, compilation switches, OS version.
* The Operating System version may give an indication about the
* compiler; Dhrystone itself performs no OS calls in the measurement loop.
*
* The complete output generated by the program should be mailed
* such that at least some checks for correctness can be made.
*
***************************************************************************
*
* History: This version C/2.1 has been made for two reasons:
*
* 1) There is an obvious need for a common C version of
* Dhrystone, since C is at present the most popular system
* programming language for the class of processors
* (microcomputers, minicomputers) where Dhrystone is used most.
* There should be, as far as possible, only one C version of
* Dhrystone such that results can be compared without
* restrictions. In the past, the C versions distributed
* by Rick Richardson (Version 1.1) and by Reinhold Weicker
* had small (though not significant) differences.
*
* 2) As far as it is possible without changes to the Dhrystone
* statistics, optimizing compilers should be prevented from
* removing significant statements.
*
* This C version has been developed in cooperation with
* Rick Richardson (Tinton Falls, NJ), it incorporates many
* ideas from the "Version 1.1" distributed previously by
* him over the UNIX network Usenet.
* I also thank Chaim Benedelac (National Semiconductor),
* David Ditzel (SUN), Earl Killian and John Mashey (MIPS),
* Alan Smith and Rafael Saavedra-Barrera (UC at Berkeley)
* for their help with comments on earlier versions of the
* benchmark.
*
* Changes: In the initialization part, this version follows mostly
* Rick Richardson's version distributed via Usenet, not the
* version distributed earlier via floppy disk by Reinhold Weicker.
* As a concession to older compilers, names have been made
* unique within the first 8 characters.
* Inside the measurement loop, this version follows the
* version previously distributed by Reinhold Weicker.
*
* At several places in the benchmark, code has been added,
* but within the measurement loop only in branches that
* are not executed. The intention is that optimizing compilers
* should be prevented from moving code out of the measurement
* loop, or from removing code altogether. Since the statements
* that are executed within the measurement loop have NOT been
* changed, the numbers defining the "Dhrystone distribution"
* (distribution of statements, operand types and locality)
* still hold. Except for sophisticated optimizing compilers,
* execution times for this version should be the same as
* for previous versions.
*
* Since it has proven difficult to subtract the time for the
* measurement loop overhead in a correct way, the loop check
* has been made a part of the benchmark. This does have
* an impact - though a very minor one - on the distribution
* statistics which have been updated for this version.
*
* All changes within the measurement loop are described
* and discussed in the companion paper "Rationale for
* Dhrystone version 2".
*
* Because of the self-imposed limitation that the order and
* distribution of the executed statements should not be
* changed, there are still cases where optimizing compilers
* may not generate code for some statements. To a certain
* degree, this is unavoidable for small synthetic benchmarks.
* Users of the benchmark are advised to check code listings
* whether code is generated for all statements of Dhrystone.
*
* Version 2.1 is identical to version 2.0 distributed via
* the UNIX network Usenet in March 1988 except that it corrects
* some minor deficiencies that were found by users of version 2.0.
* The only change within the measurement loop is that a
* non-executed "else" part was added to the "if" statement in
* Func_3, and a non-executed "else" part removed from Proc_3.
*
***************************************************************************
*
* Defines: The following "Defines" are possible:
* -DREG=register (default: Not defined)
* As an approximation to what an average C programmer
* might do, the "register" storage class is applied
* (if enabled by -DREG=register)
* - for local variables, if they are used (dynamically)
* five or more times
* - for parameters if they are used (dynamically)
* six or more times
* Note that an optimal "register" strategy is
* compiler-dependent, and that "register" declarations
* do not necessarily lead to faster execution.
* -DNOSTRUCTASSIGN (default: Not defined)
* Define if the C compiler does not support
* assignment of structures.
* -DNOENUMS (default: Not defined)
* Define if the C compiler does not support
* enumeration types.
* -DTIMES (default)
* -DTIME
* The "times" function of UNIX (returning process times)
* or the "time" function (returning wallclock time)
* is used for measurement.
* For single user machines, "time ()" is adequate. For
* multi-user machines where you cannot get single-user
* access, use the "times ()" function. If you have
* neither, use a stopwatch in the dead of night.
* "printf"s are provided marking the points "Start Timer"
* and "Stop Timer". DO NOT use the UNIX "time(1)"
* command, as this will measure the total time to
* run this program, which will (erroneously) include
* the time to allocate storage (malloc) and to perform
* the initialization.
* -DHZ=nnn
* In Berkeley UNIX, the function "times" returns process
* time in 1/HZ seconds, with HZ = 60 for most systems.
* CHECK YOUR SYSTEM DESCRIPTION BEFORE YOU JUST APPLY
* A VALUE.
*
***************************************************************************
*
* Compilation model and measurement (IMPORTANT):
*
* This C version of Dhrystone consists of three files:
* - dhry.h (this file, containing global definitions and comments)
* - dhry_1.c (containing the code corresponding to Ada package Pack_1)
* - dhry_2.c (containing the code corresponding to Ada package Pack_2)
*
* The following "ground rules" apply for measurements:
* - Separate compilation
* - No procedure merging
* - Otherwise, compiler optimizations are allowed but should be indicated
* - Default results are those without register declarations
* See the companion paper "Rationale for Dhrystone Version 2" for a more
* detailed discussion of these ground rules.
*
* For 16-Bit processors (e.g. 80186, 80286), times for all compilation
* models ("small", "medium", "large" etc.) should be given if possible,
* together with a definition of these models for the compiler system used.
*
**************************************************************************
*
* Dhrystone (C version) statistics:
*
* [Comment from the first distribution, updated for version 2.
* Note that because of language differences, the numbers are slightly
* different from the Ada version.]
*
* The following program contains statements of a high level programming
* language (here: C) in a distribution considered representative:
*
* assignments 52 (51.0 %)
* control statements 33 (32.4 %)
* procedure, function calls 17 (16.7 %)
*
* 103 statements are dynamically executed. The program is balanced with
* respect to the three aspects:
*
* - statement type
* - operand type
* - operand locality
* operand global, local, parameter, or constant.
*
* The combination of these three aspects is balanced only approximately.
*
* 1. Statement Type:
* ----------------- number
*
* V1 = V2 9
* (incl. V1 = F(..)
* V = Constant 12
* Assignment, 7
* with array element
* Assignment, 6
* with record component
* --
* 34 34
*
* X = Y +|-|"&&"|"|" Z 5
* X = Y +|-|"==" Constant 6
* X = X +|- 1 3
* X = Y *|/ Z 2
* X = Expression, 1
* two operators
* X = Expression, 1
* three operators
* --
* 18 18
*
* if .... 14
* with "else" 7
* without "else" 7
* executed 3
* not executed 4
* for ... 7 | counted every time
* while ... 4 | the loop condition
* do ... while 1 | is evaluated
* switch ... 1
* break 1
* declaration with 1
* initialization
* --
* 34 34
*
* P (...) procedure call 11
* user procedure 10
* library procedure 1
* X = F (...)
* function call 6
* user function 5
* library function 1
* --
* 17 17
* ---
* 103
*
* The average number of parameters in procedure or function calls
* is 1.82 (not counting the function values as implicit parameters).
*
*
* 2. Operators
* ------------
* number approximate
* percentage
*
* Arithmetic 32 50.8
*
* + 21 33.3
* - 7 11.1
* * 3 4.8
* / (int div) 1 1.6
*
* Comparison 27 42.8
*
* == 9 14.3
* /= 4 6.3
* > 1 1.6
* < 3 4.8
* >= 1 1.6
* <= 9 14.3
*
* Logic 4 6.3
*
* && (AND-THEN) 1 1.6
* | (OR) 1 1.6
* ! (NOT) 2 3.2
*
* -- -----
* 63 100.1
*
*
* 3. Operand Type (counted once per operand reference):
* ---------------
* number approximate
* percentage
*
* Integer 175 72.3 %
* Character 45 18.6 %
* Pointer 12 5.0 %
* String30 6 2.5 %
* Array 2 0.8 %
* Record 2 0.8 %
* --- -------
* 242 100.0 %
*
* When there is an access path leading to the final operand (e.g. a record
* component), only the final data type on the access path is counted.
*
*
* 4. Operand Locality:
* -------------------
* number approximate
* percentage
*
* local variable 114 47.1 %
* global variable 22 9.1 %
* parameter 45 18.6 %
* value 23 9.5 %
* reference 22 9.1 %
* function result 6 2.5 %
* constant 55 22.7 %
* --- -------
* 242 100.0 %
*
*
* The program does not compute anything meaningful, but it is syntactically
* and semantically correct. All variables have a value assigned to them
* before they are used as a source operand.
*
* There has been no explicit effort to account for the effects of a
* cache, or to balance the use of long or short displacements for code or
* data.
*
***************************************************************************
*/
/* Compiler and system dependent definitions: */
#ifndef TIME
#define TIMES
#endif
/* Use times(2) time function unless */
/* explicitly defined otherwise */
#ifdef TIMES
#include <sys/types.h>
#include <sys/times.h>
/* for "times" */
#endif
#define Mic_secs_Per_Second 1000000.0
/* Berkeley UNIX C returns process times in seconds/HZ */
#ifdef NOSTRUCTASSIGN
#define structassign(d, s) memcpy(&(d), &(s), sizeof(d))
#else
#define structassign(d, s) d = s
#endif
#ifdef NOENUM
#define Ident_1 0
#define Ident_2 1
#define Ident_3 2
#define Ident_4 3
#define Ident_5 4
typedef int Enumeration;
#else
typedef enum {Ident_1, Ident_2, Ident_3, Ident_4, Ident_5}
Enumeration;
#endif
/* for boolean and enumeration types in Ada, Pascal */
/* General definitions: */
#include <stdio.h>
/* for strcpy, strcmp */
#define Null 0
/* Value of a Null pointer */
#define true 1
#define false 0
typedef int One_Thirty;
typedef int One_Fifty;
typedef char Capital_Letter;
typedef int Boolean;
typedef char Str_30 [31];
typedef int Arr_1_Dim [50];
typedef int Arr_2_Dim [50] [50];
typedef struct record
{
struct record *Ptr_Comp;
Enumeration Discr;
union {
struct {
Enumeration Enum_Comp;
int Int_Comp;
char Str_Comp [31];
} var_1;
struct {
Enumeration E_Comp_2;
char Str_2_Comp [31];
} var_2;
struct {
char Ch_1_Comp;
char Ch_2_Comp;
} var_3;
} variant;
} Rec_Type, *Rec_Pointer;

View File

@ -0,0 +1,427 @@
/*
****************************************************************************
*
* "DHRYSTONE" Benchmark Program
* -----------------------------
*
* Version: C, Version 2.1
*
* File: dhry_1.c (part 2 of 3)
*
* Date: May 25, 1988
*
* Author: Reinhold P. Weicker
*
****************************************************************************
*/
#include "dhry.h"
#ifdef USE_MYSTDLIB
extern char *malloc ();
#else
# include <stdlib.h>
# include <string.h>
#endif
/* Global Variables: */
Rec_Pointer Ptr_Glob,
Next_Ptr_Glob;
int Int_Glob;
Boolean Bool_Glob;
char Ch_1_Glob,
Ch_2_Glob;
int Arr_1_Glob [50];
int Arr_2_Glob [50] [50];
Enumeration Func_1 ();
/* forward declaration necessary since Enumeration may not simply be int */
#ifndef REG
Boolean Reg = false;
#define REG
/* REG becomes defined as empty */
/* i.e. no register variables */
#else
Boolean Reg = true;
#endif
/* variables for time measurement: */
#ifdef IGN_TIMES
struct tms time_info;
extern int times ();
/* see library function "times" */
#define Too_Small_Time 120
/* Measurements should last at least about 2 seconds */
#endif
#ifdef TIME
extern long time();
#ifdef RISCV
extern long insn();
#endif
/* see library function "time" */
#define Too_Small_Time 2
/* Measurements should last at least 2 seconds */
#endif
long Begin_Time,
End_Time,
User_Time;
#ifdef RISCV
long Begin_Insn,
End_Insn,
User_Insn;
#endif
float Microseconds,
Dhrystones_Per_Second;
/* end of variables for time measurement */
main ()
/*****/
/* main program, corresponds to procedures */
/* Main and Proc_0 in the Ada version */
{
One_Fifty Int_1_Loc;
REG One_Fifty Int_2_Loc;
One_Fifty Int_3_Loc;
REG char Ch_Index;
Enumeration Enum_Loc;
Str_30 Str_1_Loc;
Str_30 Str_2_Loc;
REG int Run_Index;
REG int Number_Of_Runs;
/* Initializations */
Next_Ptr_Glob = (Rec_Pointer) malloc (sizeof (Rec_Type));
Ptr_Glob = (Rec_Pointer) malloc (sizeof (Rec_Type));
Ptr_Glob->Ptr_Comp = Next_Ptr_Glob;
Ptr_Glob->Discr = Ident_1;
Ptr_Glob->variant.var_1.Enum_Comp = Ident_3;
Ptr_Glob->variant.var_1.Int_Comp = 40;
strcpy (Ptr_Glob->variant.var_1.Str_Comp,
"DHRYSTONE PROGRAM, SOME STRING");
strcpy (Str_1_Loc, "DHRYSTONE PROGRAM, 1'ST STRING");
Arr_2_Glob [8][7] = 10;
/* Was missing in published program. Without this statement, */
/* Arr_2_Glob [8][7] would have an undefined value. */
/* Warning: With 16-Bit processors and Number_Of_Runs > 32000, */
/* overflow may occur for this array element. */
printf ("\n");
printf ("Dhrystone Benchmark, Version 2.1 (Language: C)\n");
printf ("\n");
if (Reg)
{
printf ("Program compiled with 'register' attribute\n");
printf ("\n");
}
else
{
printf ("Program compiled without 'register' attribute\n");
printf ("\n");
}
printf ("Please give the number of runs through the benchmark: ");
{
// int n;
// scanf ("%d", &n);
Number_Of_Runs = 100;
}
printf ("\n");
printf ("Execution starts, %d runs through Dhrystone\n", Number_Of_Runs);
/***************/
/* Start timer */
/***************/
#ifdef IGN_TIMES
times (&time_info);
Begin_Time = (long) time_info.tms_utime;
#endif
#ifdef TIME
Begin_Time = time ( (long *) 0);
#ifdef RISCV
Begin_Insn = insn ( (long *) 0);
#endif
#endif
for (Run_Index = 1; Run_Index <= Number_Of_Runs; ++Run_Index)
{
Proc_5();
Proc_4();
/* Ch_1_Glob == 'A', Ch_2_Glob == 'B', Bool_Glob == true */
Int_1_Loc = 2;
Int_2_Loc = 3;
strcpy (Str_2_Loc, "DHRYSTONE PROGRAM, 2'ND STRING");
Enum_Loc = Ident_2;
Bool_Glob = ! Func_2 (Str_1_Loc, Str_2_Loc);
/* Bool_Glob == 1 */
while (Int_1_Loc < Int_2_Loc) /* loop body executed once */
{
Int_3_Loc = 5 * Int_1_Loc - Int_2_Loc;
/* Int_3_Loc == 7 */
Proc_7 (Int_1_Loc, Int_2_Loc, &Int_3_Loc);
/* Int_3_Loc == 7 */
Int_1_Loc += 1;
} /* while */
/* Int_1_Loc == 3, Int_2_Loc == 3, Int_3_Loc == 7 */
Proc_8 (Arr_1_Glob, Arr_2_Glob, Int_1_Loc, Int_3_Loc);
/* Int_Glob == 5 */
Proc_1 (Ptr_Glob);
for (Ch_Index = 'A'; Ch_Index <= Ch_2_Glob; ++Ch_Index)
/* loop body executed twice */
{
if (Enum_Loc == Func_1 (Ch_Index, 'C'))
/* then, not executed */
{
Proc_6 (Ident_1, &Enum_Loc);
strcpy (Str_2_Loc, "DHRYSTONE PROGRAM, 3'RD STRING");
Int_2_Loc = Run_Index;
Int_Glob = Run_Index;
}
}
/* Int_1_Loc == 3, Int_2_Loc == 3, Int_3_Loc == 7 */
Int_2_Loc = Int_2_Loc * Int_1_Loc;
Int_1_Loc = Int_2_Loc / Int_3_Loc;
Int_2_Loc = 7 * (Int_2_Loc - Int_3_Loc) - Int_1_Loc;
/* Int_1_Loc == 1, Int_2_Loc == 13, Int_3_Loc == 7 */
Proc_2 (&Int_1_Loc);
/* Int_1_Loc == 5 */
} /* loop "for Run_Index" */
/**************/
/* Stop timer */
/**************/
#ifdef IGN_TIMES
times (&time_info);
End_Time = (long) time_info.tms_utime;
#endif
#ifdef TIME
End_Time = time ( (long *) 0);
#ifdef RISCV
End_Insn = insn ( (long *) 0);
#endif
#endif
printf ("Execution ends\n");
printf ("\n");
printf ("Final values of the variables used in the benchmark:\n");
printf ("\n");
printf ("Int_Glob: %d\n", Int_Glob);
printf (" should be: %d\n", 5);
printf ("Bool_Glob: %d\n", Bool_Glob);
printf (" should be: %d\n", 1);
printf ("Ch_1_Glob: %c\n", Ch_1_Glob);
printf (" should be: %c\n", 'A');
printf ("Ch_2_Glob: %c\n", Ch_2_Glob);
printf (" should be: %c\n", 'B');
printf ("Arr_1_Glob[8]: %d\n", Arr_1_Glob[8]);
printf (" should be: %d\n", 7);
printf ("Arr_2_Glob[8][7]: %d\n", Arr_2_Glob[8][7]);
printf (" should be: Number_Of_Runs + 10\n");
printf ("Ptr_Glob->\n");
printf (" Ptr_Comp: %d\n", (int) Ptr_Glob->Ptr_Comp);
printf (" should be: (implementation-dependent)\n");
printf (" Discr: %d\n", Ptr_Glob->Discr);
printf (" should be: %d\n", 0);
printf (" Enum_Comp: %d\n", Ptr_Glob->variant.var_1.Enum_Comp);
printf (" should be: %d\n", 2);
printf (" Int_Comp: %d\n", Ptr_Glob->variant.var_1.Int_Comp);
printf (" should be: %d\n", 17);
printf (" Str_Comp: %s\n", Ptr_Glob->variant.var_1.Str_Comp);
printf (" should be: DHRYSTONE PROGRAM, SOME STRING\n");
printf ("Next_Ptr_Glob->\n");
printf (" Ptr_Comp: %d\n", (int) Next_Ptr_Glob->Ptr_Comp);
printf (" should be: (implementation-dependent), same as above\n");
printf (" Discr: %d\n", Next_Ptr_Glob->Discr);
printf (" should be: %d\n", 0);
printf (" Enum_Comp: %d\n", Next_Ptr_Glob->variant.var_1.Enum_Comp);
printf (" should be: %d\n", 1);
printf (" Int_Comp: %d\n", Next_Ptr_Glob->variant.var_1.Int_Comp);
printf (" should be: %d\n", 18);
printf (" Str_Comp: %s\n",
Next_Ptr_Glob->variant.var_1.Str_Comp);
printf (" should be: DHRYSTONE PROGRAM, SOME STRING\n");
printf ("Int_1_Loc: %d\n", Int_1_Loc);
printf (" should be: %d\n", 5);
printf ("Int_2_Loc: %d\n", Int_2_Loc);
printf (" should be: %d\n", 13);
printf ("Int_3_Loc: %d\n", Int_3_Loc);
printf (" should be: %d\n", 7);
printf ("Enum_Loc: %d\n", Enum_Loc);
printf (" should be: %d\n", 1);
printf ("Str_1_Loc: %s\n", Str_1_Loc);
printf (" should be: DHRYSTONE PROGRAM, 1'ST STRING\n");
printf ("Str_2_Loc: %s\n", Str_2_Loc);
printf (" should be: DHRYSTONE PROGRAM, 2'ND STRING\n");
printf ("\n");
User_Time = End_Time - Begin_Time;
#ifdef RISCV
User_Insn = End_Insn - Begin_Insn;
printf("Number_Of_Runs: %d\n", Number_Of_Runs);
printf("User_Time: %d cycles, %d insn\n", User_Time, User_Insn);
int Cycles_Per_Instruction_x1000 = (1000 * User_Time) / User_Insn;
printf("Cycles_Per_Instruction: %d.%d%d%d\n", Cycles_Per_Instruction_x1000 / 1000,
(Cycles_Per_Instruction_x1000 / 100) % 10,
(Cycles_Per_Instruction_x1000 / 10) % 10,
(Cycles_Per_Instruction_x1000 / 1) % 10);
int Dhrystones_Per_Second_Per_MHz = (Number_Of_Runs * 1000000) / User_Time;
printf("Dhrystones_Per_Second_Per_MHz: %d\n", Dhrystones_Per_Second_Per_MHz);
int DMIPS_Per_MHz_x1000 = (1000 * Dhrystones_Per_Second_Per_MHz) / 1757;
printf("DMIPS_Per_MHz: %d.%d%d%d\n", DMIPS_Per_MHz_x1000 / 1000,
(DMIPS_Per_MHz_x1000 / 100) % 10,
(DMIPS_Per_MHz_x1000 / 10) % 10,
(DMIPS_Per_MHz_x1000 / 1) % 10);
#else
if (User_Time < Too_Small_Time)
{
printf ("Measured time too small to obtain meaningful results\n");
printf ("Please increase number of runs\n");
printf ("\n");
}
else
{
#ifdef TIME
Microseconds = (float) User_Time * Mic_secs_Per_Second
/ (float) Number_Of_Runs;
Dhrystones_Per_Second = (float) Number_Of_Runs / (float) User_Time;
#else
Microseconds = (float) User_Time * Mic_secs_Per_Second
/ ((float) HZ * ((float) Number_Of_Runs));
Dhrystones_Per_Second = ((float) HZ * (float) Number_Of_Runs)
/ (float) User_Time;
#endif
printf ("Microseconds for one run through Dhrystone: ");
printf ("%6.1f \n", Microseconds);
printf ("Dhrystones per Second: ");
printf ("%6.1f \n", Dhrystones_Per_Second);
printf ("\n");
}
#endif
}
Proc_1 (Ptr_Val_Par)
/******************/
REG Rec_Pointer Ptr_Val_Par;
/* executed once */
{
REG Rec_Pointer Next_Record = Ptr_Val_Par->Ptr_Comp;
/* == Ptr_Glob_Next */
/* Local variable, initialized with Ptr_Val_Par->Ptr_Comp, */
/* corresponds to "rename" in Ada, "with" in Pascal */
structassign (*Ptr_Val_Par->Ptr_Comp, *Ptr_Glob);
Ptr_Val_Par->variant.var_1.Int_Comp = 5;
Next_Record->variant.var_1.Int_Comp
= Ptr_Val_Par->variant.var_1.Int_Comp;
Next_Record->Ptr_Comp = Ptr_Val_Par->Ptr_Comp;
Proc_3 (&Next_Record->Ptr_Comp);
/* Ptr_Val_Par->Ptr_Comp->Ptr_Comp
== Ptr_Glob->Ptr_Comp */
if (Next_Record->Discr == Ident_1)
/* then, executed */
{
Next_Record->variant.var_1.Int_Comp = 6;
Proc_6 (Ptr_Val_Par->variant.var_1.Enum_Comp,
&Next_Record->variant.var_1.Enum_Comp);
Next_Record->Ptr_Comp = Ptr_Glob->Ptr_Comp;
Proc_7 (Next_Record->variant.var_1.Int_Comp, 10,
&Next_Record->variant.var_1.Int_Comp);
}
else /* not executed */
structassign (*Ptr_Val_Par, *Ptr_Val_Par->Ptr_Comp);
} /* Proc_1 */
Proc_2 (Int_Par_Ref)
/******************/
/* executed once */
/* *Int_Par_Ref == 1, becomes 4 */
One_Fifty *Int_Par_Ref;
{
One_Fifty Int_Loc;
Enumeration Enum_Loc;
Int_Loc = *Int_Par_Ref + 10;
do /* executed once */
if (Ch_1_Glob == 'A')
/* then, executed */
{
Int_Loc -= 1;
*Int_Par_Ref = Int_Loc - Int_Glob;
Enum_Loc = Ident_1;
} /* if */
while (Enum_Loc != Ident_1); /* true */
} /* Proc_2 */
Proc_3 (Ptr_Ref_Par)
/******************/
/* executed once */
/* Ptr_Ref_Par becomes Ptr_Glob */
Rec_Pointer *Ptr_Ref_Par;
{
if (Ptr_Glob != Null)
/* then, executed */
*Ptr_Ref_Par = Ptr_Glob->Ptr_Comp;
Proc_7 (10, Int_Glob, &Ptr_Glob->variant.var_1.Int_Comp);
} /* Proc_3 */
Proc_4 () /* without parameters */
/*******/
/* executed once */
{
Boolean Bool_Loc;
Bool_Loc = Ch_1_Glob == 'A';
Bool_Glob = Bool_Loc | Bool_Glob;
Ch_2_Glob = 'B';
} /* Proc_4 */
Proc_5 () /* without parameters */
/*******/
/* executed once */
{
Ch_1_Glob = 'A';
Bool_Glob = false;
} /* Proc_5 */
/* Procedure for the assignment of structures, */
/* if the C compiler doesn't support this feature */
#ifdef NOSTRUCTASSIGN
memcpy (d, s, l)
register char *d;
register char *s;
register int l;
{
while (l--) *d++ = *s++;
}
#endif

View File

@ -0,0 +1,385 @@
/*
****************************************************************************
*
* "DHRYSTONE" Benchmark Program
* -----------------------------
*
* Version: C, Version 2.1
*
* File: dhry_1.c (part 2 of 3)
*
* Date: May 25, 1988
*
* Author: Reinhold P. Weicker
*
****************************************************************************
*/
#include "dhry.h"
/* Global Variables: */
Rec_Pointer Ptr_Glob,
Next_Ptr_Glob;
int Int_Glob;
Boolean Bool_Glob;
char Ch_1_Glob,
Ch_2_Glob;
int Arr_1_Glob [50];
int Arr_2_Glob [50] [50];
extern char *malloc ();
Enumeration Func_1 ();
/* forward declaration necessary since Enumeration may not simply be int */
#ifndef REG
Boolean Reg = false;
#define REG
/* REG becomes defined as empty */
/* i.e. no register variables */
#else
Boolean Reg = true;
#endif
/* variables for time measurement: */
#ifdef TIMES
struct tms time_info;
extern int times ();
/* see library function "times" */
#define Too_Small_Time 120
/* Measurements should last at least about 2 seconds */
#endif
#ifdef TIME
extern long time();
/* see library function "time" */
#define Too_Small_Time 2
/* Measurements should last at least 2 seconds */
#endif
long Begin_Time,
End_Time,
User_Time;
float Microseconds,
Dhrystones_Per_Second;
/* end of variables for time measurement */
main ()
/*****/
/* main program, corresponds to procedures */
/* Main and Proc_0 in the Ada version */
{
One_Fifty Int_1_Loc;
REG One_Fifty Int_2_Loc;
One_Fifty Int_3_Loc;
REG char Ch_Index;
Enumeration Enum_Loc;
Str_30 Str_1_Loc;
Str_30 Str_2_Loc;
REG int Run_Index;
REG int Number_Of_Runs;
/* Initializations */
Next_Ptr_Glob = (Rec_Pointer) malloc (sizeof (Rec_Type));
Ptr_Glob = (Rec_Pointer) malloc (sizeof (Rec_Type));
Ptr_Glob->Ptr_Comp = Next_Ptr_Glob;
Ptr_Glob->Discr = Ident_1;
Ptr_Glob->variant.var_1.Enum_Comp = Ident_3;
Ptr_Glob->variant.var_1.Int_Comp = 40;
strcpy (Ptr_Glob->variant.var_1.Str_Comp,
"DHRYSTONE PROGRAM, SOME STRING");
strcpy (Str_1_Loc, "DHRYSTONE PROGRAM, 1'ST STRING");
Arr_2_Glob [8][7] = 10;
/* Was missing in published program. Without this statement, */
/* Arr_2_Glob [8][7] would have an undefined value. */
/* Warning: With 16-Bit processors and Number_Of_Runs > 32000, */
/* overflow may occur for this array element. */
printf ("\n");
printf ("Dhrystone Benchmark, Version 2.1 (Language: C)\n");
printf ("\n");
if (Reg)
{
printf ("Program compiled with 'register' attribute\n");
printf ("\n");
}
else
{
printf ("Program compiled without 'register' attribute\n");
printf ("\n");
}
printf ("Please give the number of runs through the benchmark: ");
{
int n;
scanf ("%d", &n);
Number_Of_Runs = n;
}
printf ("\n");
printf ("Execution starts, %d runs through Dhrystone\n", Number_Of_Runs);
/***************/
/* Start timer */
/***************/
#ifdef TIMES
times (&time_info);
Begin_Time = (long) time_info.tms_utime;
#endif
#ifdef TIME
Begin_Time = time ( (long *) 0);
#endif
for (Run_Index = 1; Run_Index <= Number_Of_Runs; ++Run_Index)
{
Proc_5();
Proc_4();
/* Ch_1_Glob == 'A', Ch_2_Glob == 'B', Bool_Glob == true */
Int_1_Loc = 2;
Int_2_Loc = 3;
strcpy (Str_2_Loc, "DHRYSTONE PROGRAM, 2'ND STRING");
Enum_Loc = Ident_2;
Bool_Glob = ! Func_2 (Str_1_Loc, Str_2_Loc);
/* Bool_Glob == 1 */
while (Int_1_Loc < Int_2_Loc) /* loop body executed once */
{
Int_3_Loc = 5 * Int_1_Loc - Int_2_Loc;
/* Int_3_Loc == 7 */
Proc_7 (Int_1_Loc, Int_2_Loc, &Int_3_Loc);
/* Int_3_Loc == 7 */
Int_1_Loc += 1;
} /* while */
/* Int_1_Loc == 3, Int_2_Loc == 3, Int_3_Loc == 7 */
Proc_8 (Arr_1_Glob, Arr_2_Glob, Int_1_Loc, Int_3_Loc);
/* Int_Glob == 5 */
Proc_1 (Ptr_Glob);
for (Ch_Index = 'A'; Ch_Index <= Ch_2_Glob; ++Ch_Index)
/* loop body executed twice */
{
if (Enum_Loc == Func_1 (Ch_Index, 'C'))
/* then, not executed */
{
Proc_6 (Ident_1, &Enum_Loc);
strcpy (Str_2_Loc, "DHRYSTONE PROGRAM, 3'RD STRING");
Int_2_Loc = Run_Index;
Int_Glob = Run_Index;
}
}
/* Int_1_Loc == 3, Int_2_Loc == 3, Int_3_Loc == 7 */
Int_2_Loc = Int_2_Loc * Int_1_Loc;
Int_1_Loc = Int_2_Loc / Int_3_Loc;
Int_2_Loc = 7 * (Int_2_Loc - Int_3_Loc) - Int_1_Loc;
/* Int_1_Loc == 1, Int_2_Loc == 13, Int_3_Loc == 7 */
Proc_2 (&Int_1_Loc);
/* Int_1_Loc == 5 */
} /* loop "for Run_Index" */
/**************/
/* Stop timer */
/**************/
#ifdef TIMES
times (&time_info);
End_Time = (long) time_info.tms_utime;
#endif
#ifdef TIME
End_Time = time ( (long *) 0);
#endif
printf ("Execution ends\n");
printf ("\n");
printf ("Final values of the variables used in the benchmark:\n");
printf ("\n");
printf ("Int_Glob: %d\n", Int_Glob);
printf (" should be: %d\n", 5);
printf ("Bool_Glob: %d\n", Bool_Glob);
printf (" should be: %d\n", 1);
printf ("Ch_1_Glob: %c\n", Ch_1_Glob);
printf (" should be: %c\n", 'A');
printf ("Ch_2_Glob: %c\n", Ch_2_Glob);
printf (" should be: %c\n", 'B');
printf ("Arr_1_Glob[8]: %d\n", Arr_1_Glob[8]);
printf (" should be: %d\n", 7);
printf ("Arr_2_Glob[8][7]: %d\n", Arr_2_Glob[8][7]);
printf (" should be: Number_Of_Runs + 10\n");
printf ("Ptr_Glob->\n");
printf (" Ptr_Comp: %d\n", (int) Ptr_Glob->Ptr_Comp);
printf (" should be: (implementation-dependent)\n");
printf (" Discr: %d\n", Ptr_Glob->Discr);
printf (" should be: %d\n", 0);
printf (" Enum_Comp: %d\n", Ptr_Glob->variant.var_1.Enum_Comp);
printf (" should be: %d\n", 2);
printf (" Int_Comp: %d\n", Ptr_Glob->variant.var_1.Int_Comp);
printf (" should be: %d\n", 17);
printf (" Str_Comp: %s\n", Ptr_Glob->variant.var_1.Str_Comp);
printf (" should be: DHRYSTONE PROGRAM, SOME STRING\n");
printf ("Next_Ptr_Glob->\n");
printf (" Ptr_Comp: %d\n", (int) Next_Ptr_Glob->Ptr_Comp);
printf (" should be: (implementation-dependent), same as above\n");
printf (" Discr: %d\n", Next_Ptr_Glob->Discr);
printf (" should be: %d\n", 0);
printf (" Enum_Comp: %d\n", Next_Ptr_Glob->variant.var_1.Enum_Comp);
printf (" should be: %d\n", 1);
printf (" Int_Comp: %d\n", Next_Ptr_Glob->variant.var_1.Int_Comp);
printf (" should be: %d\n", 18);
printf (" Str_Comp: %s\n",
Next_Ptr_Glob->variant.var_1.Str_Comp);
printf (" should be: DHRYSTONE PROGRAM, SOME STRING\n");
printf ("Int_1_Loc: %d\n", Int_1_Loc);
printf (" should be: %d\n", 5);
printf ("Int_2_Loc: %d\n", Int_2_Loc);
printf (" should be: %d\n", 13);
printf ("Int_3_Loc: %d\n", Int_3_Loc);
printf (" should be: %d\n", 7);
printf ("Enum_Loc: %d\n", Enum_Loc);
printf (" should be: %d\n", 1);
printf ("Str_1_Loc: %s\n", Str_1_Loc);
printf (" should be: DHRYSTONE PROGRAM, 1'ST STRING\n");
printf ("Str_2_Loc: %s\n", Str_2_Loc);
printf (" should be: DHRYSTONE PROGRAM, 2'ND STRING\n");
printf ("\n");
User_Time = End_Time - Begin_Time;
if (User_Time < Too_Small_Time)
{
printf ("Measured time too small to obtain meaningful results\n");
printf ("Please increase number of runs\n");
printf ("\n");
}
else
{
#ifdef TIME
Microseconds = (float) User_Time * Mic_secs_Per_Second
/ (float) Number_Of_Runs;
Dhrystones_Per_Second = (float) Number_Of_Runs / (float) User_Time;
#else
Microseconds = (float) User_Time * Mic_secs_Per_Second
/ ((float) HZ * ((float) Number_Of_Runs));
Dhrystones_Per_Second = ((float) HZ * (float) Number_Of_Runs)
/ (float) User_Time;
#endif
printf ("Microseconds for one run through Dhrystone: ");
printf ("%6.1f \n", Microseconds);
printf ("Dhrystones per Second: ");
printf ("%6.1f \n", Dhrystones_Per_Second);
printf ("\n");
}
}
Proc_1 (Ptr_Val_Par)
/******************/
REG Rec_Pointer Ptr_Val_Par;
/* executed once */
{
REG Rec_Pointer Next_Record = Ptr_Val_Par->Ptr_Comp;
/* == Ptr_Glob_Next */
/* Local variable, initialized with Ptr_Val_Par->Ptr_Comp, */
/* corresponds to "rename" in Ada, "with" in Pascal */
structassign (*Ptr_Val_Par->Ptr_Comp, *Ptr_Glob);
Ptr_Val_Par->variant.var_1.Int_Comp = 5;
Next_Record->variant.var_1.Int_Comp
= Ptr_Val_Par->variant.var_1.Int_Comp;
Next_Record->Ptr_Comp = Ptr_Val_Par->Ptr_Comp;
Proc_3 (&Next_Record->Ptr_Comp);
/* Ptr_Val_Par->Ptr_Comp->Ptr_Comp
== Ptr_Glob->Ptr_Comp */
if (Next_Record->Discr == Ident_1)
/* then, executed */
{
Next_Record->variant.var_1.Int_Comp = 6;
Proc_6 (Ptr_Val_Par->variant.var_1.Enum_Comp,
&Next_Record->variant.var_1.Enum_Comp);
Next_Record->Ptr_Comp = Ptr_Glob->Ptr_Comp;
Proc_7 (Next_Record->variant.var_1.Int_Comp, 10,
&Next_Record->variant.var_1.Int_Comp);
}
else /* not executed */
structassign (*Ptr_Val_Par, *Ptr_Val_Par->Ptr_Comp);
} /* Proc_1 */
Proc_2 (Int_Par_Ref)
/******************/
/* executed once */
/* *Int_Par_Ref == 1, becomes 4 */
One_Fifty *Int_Par_Ref;
{
One_Fifty Int_Loc;
Enumeration Enum_Loc;
Int_Loc = *Int_Par_Ref + 10;
do /* executed once */
if (Ch_1_Glob == 'A')
/* then, executed */
{
Int_Loc -= 1;
*Int_Par_Ref = Int_Loc - Int_Glob;
Enum_Loc = Ident_1;
} /* if */
while (Enum_Loc != Ident_1); /* true */
} /* Proc_2 */
Proc_3 (Ptr_Ref_Par)
/******************/
/* executed once */
/* Ptr_Ref_Par becomes Ptr_Glob */
Rec_Pointer *Ptr_Ref_Par;
{
if (Ptr_Glob != Null)
/* then, executed */
*Ptr_Ref_Par = Ptr_Glob->Ptr_Comp;
Proc_7 (10, Int_Glob, &Ptr_Glob->variant.var_1.Int_Comp);
} /* Proc_3 */
Proc_4 () /* without parameters */
/*******/
/* executed once */
{
Boolean Bool_Loc;
Bool_Loc = Ch_1_Glob == 'A';
Bool_Glob = Bool_Loc | Bool_Glob;
Ch_2_Glob = 'B';
} /* Proc_4 */
Proc_5 () /* without parameters */
/*******/
/* executed once */
{
Ch_1_Glob = 'A';
Bool_Glob = false;
} /* Proc_5 */
/* Procedure for the assignment of structures, */
/* if the C compiler doesn't support this feature */
#ifdef NOSTRUCTASSIGN
memcpy (d, s, l)
register char *d;
register char *s;
register int l;
{
while (l--) *d++ = *s++;
}
#endif

View File

@ -0,0 +1,192 @@
/*
****************************************************************************
*
* "DHRYSTONE" Benchmark Program
* -----------------------------
*
* Version: C, Version 2.1
*
* File: dhry_2.c (part 3 of 3)
*
* Date: May 25, 1988
*
* Author: Reinhold P. Weicker
*
****************************************************************************
*/
#include "dhry.h"
#ifndef REG
#define REG
/* REG becomes defined as empty */
/* i.e. no register variables */
#endif
extern int Int_Glob;
extern char Ch_1_Glob;
Proc_6 (Enum_Val_Par, Enum_Ref_Par)
/*********************************/
/* executed once */
/* Enum_Val_Par == Ident_3, Enum_Ref_Par becomes Ident_2 */
Enumeration Enum_Val_Par;
Enumeration *Enum_Ref_Par;
{
*Enum_Ref_Par = Enum_Val_Par;
if (! Func_3 (Enum_Val_Par))
/* then, not executed */
*Enum_Ref_Par = Ident_4;
switch (Enum_Val_Par)
{
case Ident_1:
*Enum_Ref_Par = Ident_1;
break;
case Ident_2:
if (Int_Glob > 100)
/* then */
*Enum_Ref_Par = Ident_1;
else *Enum_Ref_Par = Ident_4;
break;
case Ident_3: /* executed */
*Enum_Ref_Par = Ident_2;
break;
case Ident_4: break;
case Ident_5:
*Enum_Ref_Par = Ident_3;
break;
} /* switch */
} /* Proc_6 */
Proc_7 (Int_1_Par_Val, Int_2_Par_Val, Int_Par_Ref)
/**********************************************/
/* executed three times */
/* first call: Int_1_Par_Val == 2, Int_2_Par_Val == 3, */
/* Int_Par_Ref becomes 7 */
/* second call: Int_1_Par_Val == 10, Int_2_Par_Val == 5, */
/* Int_Par_Ref becomes 17 */
/* third call: Int_1_Par_Val == 6, Int_2_Par_Val == 10, */
/* Int_Par_Ref becomes 18 */
One_Fifty Int_1_Par_Val;
One_Fifty Int_2_Par_Val;
One_Fifty *Int_Par_Ref;
{
One_Fifty Int_Loc;
Int_Loc = Int_1_Par_Val + 2;
*Int_Par_Ref = Int_2_Par_Val + Int_Loc;
} /* Proc_7 */
Proc_8 (Arr_1_Par_Ref, Arr_2_Par_Ref, Int_1_Par_Val, Int_2_Par_Val)
/*********************************************************************/
/* executed once */
/* Int_Par_Val_1 == 3 */
/* Int_Par_Val_2 == 7 */
Arr_1_Dim Arr_1_Par_Ref;
Arr_2_Dim Arr_2_Par_Ref;
int Int_1_Par_Val;
int Int_2_Par_Val;
{
REG One_Fifty Int_Index;
REG One_Fifty Int_Loc;
Int_Loc = Int_1_Par_Val + 5;
Arr_1_Par_Ref [Int_Loc] = Int_2_Par_Val;
Arr_1_Par_Ref [Int_Loc+1] = Arr_1_Par_Ref [Int_Loc];
Arr_1_Par_Ref [Int_Loc+30] = Int_Loc;
for (Int_Index = Int_Loc; Int_Index <= Int_Loc+1; ++Int_Index)
Arr_2_Par_Ref [Int_Loc] [Int_Index] = Int_Loc;
Arr_2_Par_Ref [Int_Loc] [Int_Loc-1] += 1;
Arr_2_Par_Ref [Int_Loc+20] [Int_Loc] = Arr_1_Par_Ref [Int_Loc];
Int_Glob = 5;
} /* Proc_8 */
Enumeration Func_1 (Ch_1_Par_Val, Ch_2_Par_Val)
/*************************************************/
/* executed three times */
/* first call: Ch_1_Par_Val == 'H', Ch_2_Par_Val == 'R' */
/* second call: Ch_1_Par_Val == 'A', Ch_2_Par_Val == 'C' */
/* third call: Ch_1_Par_Val == 'B', Ch_2_Par_Val == 'C' */
Capital_Letter Ch_1_Par_Val;
Capital_Letter Ch_2_Par_Val;
{
Capital_Letter Ch_1_Loc;
Capital_Letter Ch_2_Loc;
Ch_1_Loc = Ch_1_Par_Val;
Ch_2_Loc = Ch_1_Loc;
if (Ch_2_Loc != Ch_2_Par_Val)
/* then, executed */
return (Ident_1);
else /* not executed */
{
Ch_1_Glob = Ch_1_Loc;
return (Ident_2);
}
} /* Func_1 */
Boolean Func_2 (Str_1_Par_Ref, Str_2_Par_Ref)
/*************************************************/
/* executed once */
/* Str_1_Par_Ref == "DHRYSTONE PROGRAM, 1'ST STRING" */
/* Str_2_Par_Ref == "DHRYSTONE PROGRAM, 2'ND STRING" */
Str_30 Str_1_Par_Ref;
Str_30 Str_2_Par_Ref;
{
REG One_Thirty Int_Loc;
Capital_Letter Ch_Loc;
Int_Loc = 2;
while (Int_Loc <= 2) /* loop body executed once */
if (Func_1 (Str_1_Par_Ref[Int_Loc],
Str_2_Par_Ref[Int_Loc+1]) == Ident_1)
/* then, executed */
{
Ch_Loc = 'A';
Int_Loc += 1;
} /* if, while */
if (Ch_Loc >= 'W' && Ch_Loc < 'Z')
/* then, not executed */
Int_Loc = 7;
if (Ch_Loc == 'R')
/* then, not executed */
return (true);
else /* executed */
{
if (strcmp (Str_1_Par_Ref, Str_2_Par_Ref) > 0)
/* then, not executed */
{
Int_Loc += 7;
Int_Glob = Int_Loc;
return (true);
}
else /* executed */
return (false);
} /* if Ch_Loc */
} /* Func_2 */
Boolean Func_3 (Enum_Par_Val)
/***************************/
/* executed once */
/* Enum_Par_Val == Ident_3 */
Enumeration Enum_Par_Val;
{
Enumeration Enum_Loc;
Enum_Loc = Enum_Par_Val;
if (Enum_Loc == Ident_3)
/* then, executed */
return (true);
else /* not executed */
return (false);
} /* Func_3 */

View File

@ -0,0 +1,18 @@
/*
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
*/
SECTIONS {
.memory : {
. = 0x10000;
start*(.text);
*(.text);
*(*);
end = .;
}
}

View File

@ -0,0 +1,51 @@
.section .text
.global start
.global main
start:
/* print "START\n" */
lui a0,0x10000000>>12
addi a1,zero,'S'
addi a2,zero,'T'
addi a3,zero,'A'
addi a4,zero,'R'
addi a5,zero,'\n'
sw a1,0(a0)
sw a2,0(a0)
sw a3,0(a0)
sw a4,0(a0)
sw a2,0(a0)
sw a5,0(a0)
/* execute some insns for "make timing" */
lui a0,0
auipc a0,0
slli a0,a0,0
slli a0,a0,31
addi a1,zero,0
sll a0,a0,a1
addi a1,zero,31
sll a0,a0,a1
/* set stack pointer */
lui sp,(64*1024)>>12
/* jump to main C code */
jal ra,main
/* print "DONE\n" */
lui a0,0x10000000>>12
addi a1,zero,'D'
addi a2,zero,'O'
addi a3,zero,'N'
addi a4,zero,'E'
addi a5,zero,'\n'
sw a1,0(a0)
sw a2,0(a0)
sw a3,0(a0)
sw a4,0(a0)
sw a5,0(a0)
/* trap */
ebreak

View File

@ -0,0 +1,210 @@
// This is free and unencumbered software released into the public domain.
//
// Anyone is free to copy, modify, publish, use, compile, sell, or
// distribute this software, either in source code form or as a compiled
// binary, for any purpose, commercial or non-commercial, and by any
// means.
#include <stdarg.h>
#include <stdint.h>
extern long time();
extern long insn();
#ifdef USE_MYSTDLIB
extern char *malloc();
extern int printf(const char *format, ...);
extern void *memcpy(void *dest, const void *src, long n);
extern char *strcpy(char *dest, const char *src);
extern int strcmp(const char *s1, const char *s2);
char heap_memory[1024];
int heap_memory_used = 0;
#endif
long time()
{
int cycles;
asm volatile ("rdcycle %0" : "=r"(cycles));
// printf("[time() -> %d]", cycles);
return cycles;
}
long insn()
{
int insns;
asm volatile ("rdinstret %0" : "=r"(insns));
// printf("[insn() -> %d]", insns);
return insns;
}
#ifdef USE_MYSTDLIB
char *malloc(int size)
{
char *p = heap_memory + heap_memory_used;
// printf("[malloc(%d) -> %d (%d..%d)]", size, (int)p, heap_memory_used, heap_memory_used + size);
heap_memory_used += size;
if (heap_memory_used > 1024)
asm volatile ("ebreak");
return p;
}
static void printf_c(int c)
{
*((volatile int*)0x10000000) = c;
}
static void printf_s(char *p)
{
while (*p)
*((volatile int*)0x10000000) = *(p++);
}
static void printf_d(int val)
{
char buffer[32];
char *p = buffer;
if (val < 0) {
printf_c('-');
val = -val;
}
while (val || p == buffer) {
*(p++) = '0' + val % 10;
val = val / 10;
}
while (p != buffer)
printf_c(*(--p));
}
int printf(const char *format, ...)
{
int i;
va_list ap;
va_start(ap, format);
for (i = 0; format[i]; i++)
if (format[i] == '%') {
while (format[++i]) {
if (format[i] == 'c') {
printf_c(va_arg(ap,int));
break;
}
if (format[i] == 's') {
printf_s(va_arg(ap,char*));
break;
}
if (format[i] == 'd') {
printf_d(va_arg(ap,int));
break;
}
}
} else
printf_c(format[i]);
va_end(ap);
}
void *memcpy(void *aa, const void *bb, long n)
{
// printf("**MEMCPY**\n");
char *a = aa;
const char *b = bb;
while (n--) *(a++) = *(b++);
return aa;
}
char *strcpy(char* dst, const char* src)
{
char *r = dst;
while ((((uint32_t)dst | (uint32_t)src) & 3) != 0)
{
char c = *(src++);
*(dst++) = c;
if (!c) return r;
}
while (1)
{
uint32_t v = *(uint32_t*)src;
if (__builtin_expect((((v) - 0x01010101UL) & ~(v) & 0x80808080UL), 0))
{
dst[0] = v & 0xff;
if ((v & 0xff) == 0)
return r;
v = v >> 8;
dst[1] = v & 0xff;
if ((v & 0xff) == 0)
return r;
v = v >> 8;
dst[2] = v & 0xff;
if ((v & 0xff) == 0)
return r;
v = v >> 8;
dst[3] = v & 0xff;
return r;
}
*(uint32_t*)dst = v;
src += 4;
dst += 4;
}
}
int strcmp(const char *s1, const char *s2)
{
while ((((uint32_t)s1 | (uint32_t)s2) & 3) != 0)
{
char c1 = *(s1++);
char c2 = *(s2++);
if (c1 != c2)
return c1 < c2 ? -1 : +1;
else if (!c1)
return 0;
}
while (1)
{
uint32_t v1 = *(uint32_t*)s1;
uint32_t v2 = *(uint32_t*)s2;
if (__builtin_expect(v1 != v2, 0))
{
char c1, c2;
c1 = v1 & 0xff, c2 = v2 & 0xff;
if (c1 != c2) return c1 < c2 ? -1 : +1;
if (!c1) return 0;
v1 = v1 >> 8, v2 = v2 >> 8;
c1 = v1 & 0xff, c2 = v2 & 0xff;
if (c1 != c2) return c1 < c2 ? -1 : +1;
if (!c1) return 0;
v1 = v1 >> 8, v2 = v2 >> 8;
c1 = v1 & 0xff, c2 = v2 & 0xff;
if (c1 != c2) return c1 < c2 ? -1 : +1;
if (!c1) return 0;
v1 = v1 >> 8, v2 = v2 >> 8;
c1 = v1 & 0xff, c2 = v2 & 0xff;
if (c1 != c2) return c1 < c2 ? -1 : +1;
return 0;
}
if (__builtin_expect((((v1) - 0x01010101UL) & ~(v1) & 0x80808080UL), 0))
return 0;
s1 += 4;
s2 += 4;
}
}
#endif

View File

@ -0,0 +1,95 @@
// An extremely minimalist syscalls.c for newlib
// Based on riscv newlib libgloss/riscv/sys_*.c
// Written by Clifford Wolf.
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
#define UNIMPL_FUNC(_f) ".globl " #_f "\n.type " #_f ", @function\n" #_f ":\n"
asm (
".text\n"
".align 2\n"
UNIMPL_FUNC(_open)
UNIMPL_FUNC(_openat)
UNIMPL_FUNC(_lseek)
UNIMPL_FUNC(_stat)
UNIMPL_FUNC(_lstat)
UNIMPL_FUNC(_fstatat)
UNIMPL_FUNC(_isatty)
UNIMPL_FUNC(_access)
UNIMPL_FUNC(_faccessat)
UNIMPL_FUNC(_link)
UNIMPL_FUNC(_unlink)
UNIMPL_FUNC(_execve)
UNIMPL_FUNC(_getpid)
UNIMPL_FUNC(_fork)
UNIMPL_FUNC(_kill)
UNIMPL_FUNC(_wait)
UNIMPL_FUNC(_times)
UNIMPL_FUNC(_gettimeofday)
UNIMPL_FUNC(_ftime)
UNIMPL_FUNC(_utime)
UNIMPL_FUNC(_chown)
UNIMPL_FUNC(_chmod)
UNIMPL_FUNC(_chdir)
UNIMPL_FUNC(_getcwd)
UNIMPL_FUNC(_sysconf)
"j unimplemented_syscall\n"
);
void unimplemented_syscall()
{
const char *p = "Unimplemented system call called!\n";
while (*p)
*(volatile int*)0x10000000 = *(p++);
asm volatile ("ebreak");
__builtin_unreachable();
}
ssize_t _read(int file, void *ptr, size_t len)
{
// always EOF
return 0;
}
ssize_t _write(int file, const void *ptr, size_t len)
{
const void *eptr = ptr + len;
while (ptr != eptr)
*(volatile int*)0x10000000 = *(char*)(ptr++);
return len;
}
int _close(int file)
{
// close is called before _exit()
return 0;
}
int _fstat(int file, struct stat *st)
{
// fstat is called during libc startup
errno = ENOENT;
return -1;
}
void *_sbrk(ptrdiff_t incr)
{
extern unsigned char _end[]; // Defined by linker
static unsigned long heap_end;
if (heap_end == 0)
heap_end = (long)_end;
heap_end += incr;
return (void *)(heap_end - incr);
}
void _exit(int exit_status)
{
asm volatile ("ebreak");
__builtin_unreachable();
}

View File

@ -0,0 +1,126 @@
`timescale 1 ns / 1 ps
module testbench;
reg clk = 1;
reg resetn = 0;
wire trap;
always #5 clk = ~clk;
initial begin
repeat (100) @(posedge clk);
resetn <= 1;
end
wire mem_valid;
wire mem_instr;
wire mem_ready;
wire [31:0] mem_addr;
wire [31:0] mem_wdata;
wire [3:0] mem_wstrb;
reg [31:0] mem_rdata;
wire mem_la_read;
wire mem_la_write;
wire [31:0] mem_la_addr;
wire [31:0] mem_la_wdata;
wire [3:0] mem_la_wstrb;
wire trace_valid;
wire [35:0] trace_data;
picorv32 #(
.BARREL_SHIFTER(1),
.ENABLE_FAST_MUL(1),
.ENABLE_DIV(1),
.PROGADDR_RESET('h10000),
.STACKADDR('h10000),
.ENABLE_TRACE(1)
) uut (
.clk (clk ),
.resetn (resetn ),
.trap (trap ),
.mem_valid (mem_valid ),
.mem_instr (mem_instr ),
.mem_ready (mem_ready ),
.mem_addr (mem_addr ),
.mem_wdata (mem_wdata ),
.mem_wstrb (mem_wstrb ),
.mem_rdata (mem_rdata ),
.mem_la_read (mem_la_read ),
.mem_la_write(mem_la_write),
.mem_la_addr (mem_la_addr ),
.mem_la_wdata(mem_la_wdata),
.mem_la_wstrb(mem_la_wstrb),
.trace_valid (trace_valid),
.trace_data (trace_data )
);
reg [7:0] memory [0:256*1024-1];
initial $readmemh("dhry.hex", memory);
assign mem_ready = 1;
always @(posedge clk) begin
mem_rdata[ 7: 0] <= mem_la_read ? memory[mem_la_addr + 0] : 'bx;
mem_rdata[15: 8] <= mem_la_read ? memory[mem_la_addr + 1] : 'bx;
mem_rdata[23:16] <= mem_la_read ? memory[mem_la_addr + 2] : 'bx;
mem_rdata[31:24] <= mem_la_read ? memory[mem_la_addr + 3] : 'bx;
if (mem_la_write) begin
case (mem_la_addr)
32'h1000_0000: begin
`ifndef TIMING
$write("%c", mem_la_wdata);
$fflush();
`endif
end
default: begin
if (mem_la_wstrb[0]) memory[mem_la_addr + 0] <= mem_la_wdata[ 7: 0];
if (mem_la_wstrb[1]) memory[mem_la_addr + 1] <= mem_la_wdata[15: 8];
if (mem_la_wstrb[2]) memory[mem_la_addr + 2] <= mem_la_wdata[23:16];
if (mem_la_wstrb[3]) memory[mem_la_addr + 3] <= mem_la_wdata[31:24];
end
endcase
end
end
initial begin
$dumpfile("testbench.vcd");
$dumpvars(0, testbench);
end
integer trace_file;
initial begin
if ($test$plusargs("trace")) begin
trace_file = $fopen("testbench.trace", "w");
repeat (10) @(posedge clk);
while (!trap) begin
@(posedge clk);
if (trace_valid)
$fwrite(trace_file, "%x\n", trace_data);
end
$fclose(trace_file);
$display("Finished writing testbench.trace.");
end
end
always @(posedge clk) begin
if (resetn && trap) begin
repeat (10) @(posedge clk);
$display("TRAP");
$finish;
end
end
`ifdef TIMING
initial begin
repeat (100000) @(posedge clk);
$finish;
end
always @(posedge clk) begin
if (uut.dbg_next)
$display("## %-s %d", uut.dbg_ascii_instr ? uut.dbg_ascii_instr : "pcpi", uut.count_cycle);
end
`endif
endmodule

View File

@ -0,0 +1,95 @@
// A version of the dhrystone test bench that isn't using the look-ahead interface
`timescale 1 ns / 1 ps
module testbench;
reg clk = 1;
reg resetn = 0;
wire trap;
always #5 clk = ~clk;
initial begin
repeat (100) @(posedge clk);
resetn <= 1;
end
wire mem_valid;
wire mem_instr;
reg mem_ready;
wire [31:0] mem_addr;
wire [31:0] mem_wdata;
wire [3:0] mem_wstrb;
reg [31:0] mem_rdata;
picorv32 #(
.BARREL_SHIFTER(1),
.ENABLE_FAST_MUL(1),
.ENABLE_DIV(1),
.PROGADDR_RESET('h10000),
.STACKADDR('h10000)
) uut (
.clk (clk ),
.resetn (resetn ),
.trap (trap ),
.mem_valid (mem_valid ),
.mem_instr (mem_instr ),
.mem_ready (mem_ready ),
.mem_addr (mem_addr ),
.mem_wdata (mem_wdata ),
.mem_wstrb (mem_wstrb ),
.mem_rdata (mem_rdata )
);
reg [7:0] memory [0:256*1024-1];
initial $readmemh("dhry.hex", memory);
always @(posedge clk) begin
mem_ready <= 1'b0;
mem_rdata[ 7: 0] <= 'bx;
mem_rdata[15: 8] <= 'bx;
mem_rdata[23:16] <= 'bx;
mem_rdata[31:24] <= 'bx;
if (mem_valid & !mem_ready) begin
if (|mem_wstrb) begin
mem_ready <= 1'b1;
case (mem_addr)
32'h1000_0000: begin
$write("%c", mem_wdata);
$fflush();
end
default: begin
if (mem_wstrb[0]) memory[mem_addr + 0] <= mem_wdata[ 7: 0];
if (mem_wstrb[1]) memory[mem_addr + 1] <= mem_wdata[15: 8];
if (mem_wstrb[2]) memory[mem_addr + 2] <= mem_wdata[23:16];
if (mem_wstrb[3]) memory[mem_addr + 3] <= mem_wdata[31:24];
end
endcase
end
else begin
mem_ready <= 1'b1;
mem_rdata[ 7: 0] <= memory[mem_addr + 0];
mem_rdata[15: 8] <= memory[mem_addr + 1];
mem_rdata[23:16] <= memory[mem_addr + 2];
mem_rdata[31:24] <= memory[mem_addr + 3];
end
end
end
initial begin
$dumpfile("testbench_nola.vcd");
$dumpvars(0, testbench);
end
always @(posedge clk) begin
if (resetn && trap) begin
repeat (10) @(posedge clk);
$display("TRAP");
$finish;
end
end
endmodule

View File

@ -0,0 +1,2 @@
A simple test firmware. This code is in the public domain. Simply copy whatever
you can use.

View File

@ -0,0 +1,102 @@
// This is free and unencumbered software released into the public domain.
//
// Anyone is free to copy, modify, publish, use, compile, sell, or
// distribute this software, either in source code form or as a compiled
// binary, for any purpose, commercial or non-commercial, and by any
// means.
#define regnum_q0 0
#define regnum_q1 1
#define regnum_q2 2
#define regnum_q3 3
#define regnum_x0 0
#define regnum_x1 1
#define regnum_x2 2
#define regnum_x3 3
#define regnum_x4 4
#define regnum_x5 5
#define regnum_x6 6
#define regnum_x7 7
#define regnum_x8 8
#define regnum_x9 9
#define regnum_x10 10
#define regnum_x11 11
#define regnum_x12 12
#define regnum_x13 13
#define regnum_x14 14
#define regnum_x15 15
#define regnum_x16 16
#define regnum_x17 17
#define regnum_x18 18
#define regnum_x19 19
#define regnum_x20 20
#define regnum_x21 21
#define regnum_x22 22
#define regnum_x23 23
#define regnum_x24 24
#define regnum_x25 25
#define regnum_x26 26
#define regnum_x27 27
#define regnum_x28 28
#define regnum_x29 29
#define regnum_x30 30
#define regnum_x31 31
#define regnum_zero 0
#define regnum_ra 1
#define regnum_sp 2
#define regnum_gp 3
#define regnum_tp 4
#define regnum_t0 5
#define regnum_t1 6
#define regnum_t2 7
#define regnum_s0 8
#define regnum_s1 9
#define regnum_a0 10
#define regnum_a1 11
#define regnum_a2 12
#define regnum_a3 13
#define regnum_a4 14
#define regnum_a5 15
#define regnum_a6 16
#define regnum_a7 17
#define regnum_s2 18
#define regnum_s3 19
#define regnum_s4 20
#define regnum_s5 21
#define regnum_s6 22
#define regnum_s7 23
#define regnum_s8 24
#define regnum_s9 25
#define regnum_s10 26
#define regnum_s11 27
#define regnum_t3 28
#define regnum_t4 29
#define regnum_t5 30
#define regnum_t6 31
// x8 is s0 and also fp
#define regnum_fp 8
#define r_type_insn(_f7, _rs2, _rs1, _f3, _rd, _opc) \
.word (((_f7) << 25) | ((_rs2) << 20) | ((_rs1) << 15) | ((_f3) << 12) | ((_rd) << 7) | ((_opc) << 0))
#define picorv32_getq_insn(_rd, _qs) \
r_type_insn(0b0000000, 0, regnum_ ## _qs, 0b100, regnum_ ## _rd, 0b0001011)
#define picorv32_setq_insn(_qd, _rs) \
r_type_insn(0b0000001, 0, regnum_ ## _rs, 0b010, regnum_ ## _qd, 0b0001011)
#define picorv32_retirq_insn() \
r_type_insn(0b0000010, 0, 0, 0b000, 0, 0b0001011)
#define picorv32_maskirq_insn(_rd, _rs) \
r_type_insn(0b0000011, 0, regnum_ ## _rs, 0b110, regnum_ ## _rd, 0b0001011)
#define picorv32_waitirq_insn(_rd) \
r_type_insn(0b0000100, 0, 0, 0b100, regnum_ ## _rd, 0b0001011)
#define picorv32_timer_insn(_rd, _rs) \
r_type_insn(0b0000101, 0, regnum_ ## _rs, 0b110, regnum_ ## _rd, 0b0001011)

View File

@ -0,0 +1,43 @@
// This is free and unencumbered software released into the public domain.
//
// Anyone is free to copy, modify, publish, use, compile, sell, or
// distribute this software, either in source code form or as a compiled
// binary, for any purpose, commercial or non-commercial, and by any
// means.
#ifndef FIRMWARE_H
#define FIRMWARE_H
#include <stdint.h>
#include <stdbool.h>
// irq.c
uint32_t *irq(uint32_t *regs, uint32_t irqs);
// print.c
void print_chr(char ch);
void print_str(const char *p);
void print_dec(unsigned int val);
void print_hex(unsigned int val, int digits);
// hello.c
void hello(void);
// sieve.c
void sieve(void);
// multest.c
uint32_t hard_mul(uint32_t a, uint32_t b);
uint32_t hard_mulh(uint32_t a, uint32_t b);
uint32_t hard_mulhsu(uint32_t a, uint32_t b);
uint32_t hard_mulhu(uint32_t a, uint32_t b);
uint32_t hard_div(uint32_t a, uint32_t b);
uint32_t hard_divu(uint32_t a, uint32_t b);
uint32_t hard_rem(uint32_t a, uint32_t b);
uint32_t hard_remu(uint32_t a, uint32_t b);
void multest(void);
// stats.c
void stats(void);
#endif

View File

@ -0,0 +1,14 @@
// This is free and unencumbered software released into the public domain.
//
// Anyone is free to copy, modify, publish, use, compile, sell, or
// distribute this software, either in source code form or as a compiled
// binary, for any purpose, commercial or non-commercial, and by any
// means.
#include "firmware.h"
void hello(void)
{
print_str("hello world\n");
}

140
fw/picorv32/firmware/irq.c Normal file
View File

@ -0,0 +1,140 @@
// This is free and unencumbered software released into the public domain.
//
// Anyone is free to copy, modify, publish, use, compile, sell, or
// distribute this software, either in source code form or as a compiled
// binary, for any purpose, commercial or non-commercial, and by any
// means.
#include "firmware.h"
uint32_t *irq(uint32_t *regs, uint32_t irqs)
{
static unsigned int ext_irq_4_count = 0;
static unsigned int ext_irq_5_count = 0;
static unsigned int timer_irq_count = 0;
// checking compressed isa q0 reg handling
if ((irqs & 6) != 0) {
uint32_t pc = (regs[0] & 1) ? regs[0] - 3 : regs[0] - 4;
uint32_t instr = *(uint16_t*)pc;
if ((instr & 3) == 3)
instr = instr | (*(uint16_t*)(pc + 2)) << 16;
if (((instr & 3) != 3) != (regs[0] & 1)) {
print_str("Mismatch between q0 LSB and decoded instruction word! q0=0x");
print_hex(regs[0], 8);
print_str(", instr=0x");
if ((instr & 3) == 3)
print_hex(instr, 8);
else
print_hex(instr, 4);
print_str("\n");
__asm__ volatile ("ebreak");
}
}
if ((irqs & (1<<4)) != 0) {
ext_irq_4_count++;
// print_str("[EXT-IRQ-4]");
}
if ((irqs & (1<<5)) != 0) {
ext_irq_5_count++;
// print_str("[EXT-IRQ-5]");
}
if ((irqs & 1) != 0) {
timer_irq_count++;
// print_str("[TIMER-IRQ]");
}
if ((irqs & 6) != 0)
{
uint32_t pc = (regs[0] & 1) ? regs[0] - 3 : regs[0] - 4;
uint32_t instr = *(uint16_t*)pc;
if ((instr & 3) == 3)
instr = instr | (*(uint16_t*)(pc + 2)) << 16;
print_str("\n");
print_str("------------------------------------------------------------\n");
if ((irqs & 2) != 0) {
if (instr == 0x00100073 || instr == 0x9002) {
print_str("EBREAK instruction at 0x");
print_hex(pc, 8);
print_str("\n");
} else {
print_str("Illegal Instruction at 0x");
print_hex(pc, 8);
print_str(": 0x");
print_hex(instr, ((instr & 3) == 3) ? 8 : 4);
print_str("\n");
}
}
if ((irqs & 4) != 0) {
print_str("Bus error in Instruction at 0x");
print_hex(pc, 8);
print_str(": 0x");
print_hex(instr, ((instr & 3) == 3) ? 8 : 4);
print_str("\n");
}
for (int i = 0; i < 8; i++)
for (int k = 0; k < 4; k++)
{
int r = i + k*8;
if (r == 0) {
print_str("pc ");
} else
if (r < 10) {
print_chr('x');
print_chr('0' + r);
print_chr(' ');
print_chr(' ');
} else
if (r < 20) {
print_chr('x');
print_chr('1');
print_chr('0' + r - 10);
print_chr(' ');
} else
if (r < 30) {
print_chr('x');
print_chr('2');
print_chr('0' + r - 20);
print_chr(' ');
} else {
print_chr('x');
print_chr('3');
print_chr('0' + r - 30);
print_chr(' ');
}
print_hex(regs[r], 8);
print_str(k == 3 ? "\n" : " ");
}
print_str("------------------------------------------------------------\n");
print_str("Number of fast external IRQs counted: ");
print_dec(ext_irq_4_count);
print_str("\n");
print_str("Number of slow external IRQs counted: ");
print_dec(ext_irq_5_count);
print_str("\n");
print_str("Number of timer IRQs counted: ");
print_dec(timer_irq_count);
print_str("\n");
__asm__ volatile ("ebreak");
}
return regs;
}

View File

@ -0,0 +1,27 @@
#!/usr/bin/env python3
#
# This is free and unencumbered software released into the public domain.
#
# Anyone is free to copy, modify, publish, use, compile, sell, or
# distribute this software, either in source code form or as a compiled
# binary, for any purpose, commercial or non-commercial, and by any
# means.
from sys import argv
binfile = argv[1]
nwords = int(argv[2])
with open(binfile, "rb") as f:
bindata = f.read()
assert len(bindata) < 4*nwords
assert len(bindata) % 4 == 0
for i in range(nwords):
if i < len(bindata) // 4:
w = bindata[4*i : 4*i+4]
print("%02x%02x%02x%02x" % (w[3], w[2], w[1], w[0]))
else:
print("0")

View File

@ -0,0 +1,151 @@
// This is free and unencumbered software released into the public domain.
//
// Anyone is free to copy, modify, publish, use, compile, sell, or
// distribute this software, either in source code form or as a compiled
// binary, for any purpose, commercial or non-commercial, and by any
// means.
#include "firmware.h"
static uint32_t xorshift32(void) {
static uint32_t x = 314159265;
x ^= x << 13;
x ^= x >> 17;
x ^= x << 5;
return x;
}
void multest(void)
{
for (int i = 0; i < 15; i++)
{
uint32_t a = xorshift32();
uint32_t b = xorshift32();
switch (i)
{
case 0:
a = 0x80000000;
b = 0xFFFFFFFF;
break;
case 1:
a = 0;
b = 0;
break;
case 2:
a |= 0x80000000;
b = 0;
break;
case 3:
a &= 0x7FFFFFFF;
b = 0;
break;
}
uint64_t au = a, bu = b;
int64_t as = (int32_t)a, bs = (int32_t)b;
print_str("input [");
print_hex(as >> 32, 8);
print_str("] ");
print_hex(a, 8);
print_str(" [");
print_hex(bs >> 32, 8);
print_str("] ");
print_hex(b, 8);
print_chr('\n');
uint32_t h_mul, h_mulh, h_mulhsu, h_mulhu;
print_str("hard mul ");
h_mul = hard_mul(a, b);
print_hex(h_mul, 8);
print_str(" ");
h_mulh = hard_mulh(a, b);
print_hex(h_mulh, 8);
print_str(" ");
h_mulhsu = hard_mulhsu(a, b);
print_hex(h_mulhsu, 8);
print_str(" ");
h_mulhu = hard_mulhu(a, b);
print_hex(h_mulhu, 8);
print_chr('\n');
uint32_t s_mul, s_mulh, s_mulhsu, s_mulhu;
print_str("soft mul ");
s_mul = a * b;
print_hex(s_mul, 8);
print_str(" ");
s_mulh = (as * bs) >> 32;
print_hex(s_mulh, 8);
print_str(" ");
s_mulhsu = (as * bu) >> 32;
print_hex(s_mulhsu, 8);
print_str(" ");
s_mulhu = (au * bu) >> 32;
print_hex(s_mulhu, 8);
print_str(" ");
if (s_mul != h_mul || s_mulh != h_mulh || s_mulhsu != h_mulhsu || s_mulhu != h_mulhu) {
print_str("ERROR!\n");
__asm__ volatile ("ebreak");
return;
}
print_str(" OK\n");
uint32_t h_div, h_divu, h_rem, h_remu;
print_str("hard div ");
h_div = hard_div(a, b);
print_hex(h_div, 8);
print_str(" ");
h_divu = hard_divu(a, b);
print_hex(h_divu, 8);
print_str(" ");
h_rem = hard_rem(a, b);
print_hex(h_rem, 8);
print_str(" ");
h_remu = hard_remu(a, b);
print_hex(h_remu, 8);
print_chr('\n');
uint32_t s_div, s_divu, s_rem, s_remu;
print_str("soft div ");
s_div = b ? as / bs : 0xffffffff;
print_hex(s_div, 8);
print_str(" ");
s_divu = b ? au / bu : 0xffffffff;
print_hex(s_divu, 8);
print_str(" ");
s_rem = b ? as % bs : a;
print_hex(s_rem, 8);
print_str(" ");
s_remu = b ? au % bu : a;
print_hex(s_remu, 8);
print_str(" ");
if (s_div != h_div || s_divu != h_divu || s_rem != h_rem || s_remu != h_remu) {
print_str("ERROR!\n");
__asm__ volatile ("ebreak");
return;
}
print_str(" OK\n");
}
}

View File

@ -0,0 +1,41 @@
// This is free and unencumbered software released into the public domain.
//
// Anyone is free to copy, modify, publish, use, compile, sell, or
// distribute this software, either in source code form or as a compiled
// binary, for any purpose, commercial or non-commercial, and by any
// means.
#include "firmware.h"
#define OUTPORT 0x10000000
void print_chr(char ch)
{
*((volatile uint32_t*)OUTPORT) = ch;
}
void print_str(const char *p)
{
while (*p != 0)
*((volatile uint32_t*)OUTPORT) = *(p++);
}
void print_dec(unsigned int val)
{
char buffer[10];
char *p = buffer;
while (val || p == buffer) {
*(p++) = val % 10;
val = val / 10;
}
while (p != buffer) {
*((volatile uint32_t*)OUTPORT) = '0' + *(--p);
}
}
void print_hex(unsigned int val, int digits)
{
for (int i = (4*digits)-4; i >= 0; i -= 4)
*((volatile uint32_t*)OUTPORT) = "0123456789ABCDEF"[(val >> i) % 16];
}

View File

@ -0,0 +1,200 @@
/* ---- Original Script: /opt/riscv32i/riscv32-unknown-elf/lib/ldscripts/elf32lriscv.x ---- */
/* Default linker script, for normal executables */
/* Copyright (C) 2014-2017 Free Software Foundation, Inc.
Copying and distribution of this script, with or without modification,
are permitted in any medium without royalty provided the copyright
notice and this notice are preserved. */
OUTPUT_FORMAT("elf32-littleriscv", "elf32-littleriscv",
"elf32-littleriscv")
OUTPUT_ARCH(riscv)
ENTRY(_start)
SECTIONS
{
. = 0x00010000;
.text :
{
*(.text)
*(.text.unlikely .text.*_unlikely .text.unlikely.*)
*(.text.exit .text.exit.*)
*(.text.startup .text.startup.*)
*(.text.hot .text.hot.*)
*(.stub .text.* .gnu.linkonce.t.*)
/* .gnu.warning sections are handled specially by elf32.em. */
*(.gnu.warning)
}
.init :
{
KEEP (*(SORT_NONE(.init)))
}
.plt : { *(.plt) }
.iplt : { *(.iplt) }
.fini :
{
KEEP (*(SORT_NONE(.fini)))
}
PROVIDE (__etext = .);
PROVIDE (_etext = .);
PROVIDE (etext = .);
.rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
.rodata1 : { *(.rodata1) }
.sdata2 :
{
*(.sdata2 .sdata2.* .gnu.linkonce.s2.*)
}
.sbss2 : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) }
.eh_frame_hdr : { *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) }
.eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) }
.gcc_except_table : ONLY_IF_RO { *(.gcc_except_table
.gcc_except_table.*) }
.gnu_extab : ONLY_IF_RO { *(.gnu_extab*) }
/* These sections are generated by the Sun/Oracle C++ compiler. */
.exception_ranges : ONLY_IF_RO { *(.exception_ranges
.exception_ranges*) }
/* Adjust the address for the data segment. We want to adjust up to
the same address within the page on the next page up. */
. = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE));
/* Exception handling */
.eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) *(.eh_frame.*) }
.gnu_extab : ONLY_IF_RW { *(.gnu_extab) }
.gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) }
.exception_ranges : ONLY_IF_RW { *(.exception_ranges .exception_ranges*) }
/* Thread Local Storage sections */
.tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
.tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
.preinit_array :
{
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array))
PROVIDE_HIDDEN (__preinit_array_end = .);
}
.init_array :
{
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors))
PROVIDE_HIDDEN (__init_array_end = .);
}
.fini_array :
{
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors))
PROVIDE_HIDDEN (__fini_array_end = .);
}
.ctors :
{
/* gcc uses crtbegin.o to find the start of
the constructors, so we make sure it is
first. Because this is a wildcard, it
doesn't matter if the user does not
actually link against crtbegin.o; the
linker won't look for a file to match a
wildcard. The wildcard also means that it
doesn't matter which directory crtbegin.o
is in. */
KEEP (*crtbegin.o(.ctors))
KEEP (*crtbegin?.o(.ctors))
/* We don't want to include the .ctor section from
the crtend.o file until after the sorted ctors.
The .ctor section from the crtend file contains the
end of ctors marker and it must be last */
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors))
}
.dtors :
{
KEEP (*crtbegin.o(.dtors))
KEEP (*crtbegin?.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*(.dtors))
}
.jcr : { KEEP (*(.jcr)) }
.data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) }
.dynamic : { *(.dynamic) }
. = DATA_SEGMENT_RELRO_END (0, .);
.data :
{
*(.data .data.* .gnu.linkonce.d.*)
SORT(CONSTRUCTORS)
}
.data1 : { *(.data1) }
.got : { *(.got.plt) *(.igot.plt) *(.got) *(.igot) }
/* We want the small data sections together, so single-instruction offsets
can access them all, and initialized data all before uninitialized, so
we can shorten the on-disk segment size. */
.sdata :
{
__global_pointer$ = . + 0x800;
*(.srodata.cst16) *(.srodata.cst8) *(.srodata.cst4) *(.srodata.cst2) *(.srodata .srodata.*)
*(.sdata .sdata.* .gnu.linkonce.s.*)
}
_edata = .; PROVIDE (edata = .);
. = .;
__bss_start = .;
.sbss :
{
*(.dynsbss)
*(.sbss .sbss.* .gnu.linkonce.sb.*)
*(.scommon)
}
.bss :
{
*(.dynbss)
*(.bss .bss.* .gnu.linkonce.b.*)
*(COMMON)
/* Align here to ensure that the .bss section occupies space up to
_end. Align after .bss to ensure correct alignment even if the
.bss section disappears because there are no input sections.
FIXME: Why do we need it? When there is no .bss section, we don't
pad the .data section. */
. = ALIGN(. != 0 ? 32 / 8 : 1);
}
. = ALIGN(32 / 8);
. = SEGMENT_START("ldata-segment", .);
. = ALIGN(32 / 8);
_end = .; PROVIDE (end = .);
. = DATA_SEGMENT_END (.);
/* Stabs debugging sections. */
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
.stab.excl 0 : { *(.stab.excl) }
.stab.exclstr 0 : { *(.stab.exclstr) }
.stab.index 0 : { *(.stab.index) }
.stab.indexstr 0 : { *(.stab.indexstr) }
.comment 0 : { *(.comment) }
/* DWARF debug sections.
Symbols in the DWARF debugging sections are relative to the beginning
of the section so we begin them at 0. */
/* DWARF 1 */
.debug 0 : { *(.debug) }
.line 0 : { *(.line) }
/* GNU DWARF 1 extensions */
.debug_srcinfo 0 : { *(.debug_srcinfo) }
.debug_sfnames 0 : { *(.debug_sfnames) }
/* DWARF 1.1 and DWARF 2 */
.debug_aranges 0 : { *(.debug_aranges) }
.debug_pubnames 0 : { *(.debug_pubnames) }
/* DWARF 2 */
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
.debug_abbrev 0 : { *(.debug_abbrev) }
.debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end ) }
.debug_frame 0 : { *(.debug_frame) }
.debug_str 0 : { *(.debug_str) }
.debug_loc 0 : { *(.debug_loc) }
.debug_macinfo 0 : { *(.debug_macinfo) }
/* SGI/MIPS DWARF 2 extensions */
.debug_weaknames 0 : { *(.debug_weaknames) }
.debug_funcnames 0 : { *(.debug_funcnames) }
.debug_typenames 0 : { *(.debug_typenames) }
.debug_varnames 0 : { *(.debug_varnames) }
/* DWARF 3 */
.debug_pubtypes 0 : { *(.debug_pubtypes) }
.debug_ranges 0 : { *(.debug_ranges) }
/* DWARF Extension. */
.debug_macro 0 : { *(.debug_macro) }
.debug_addr 0 : { *(.debug_addr) }
.gnu.attributes 0 : { KEEP (*(.gnu.attributes)) }
/DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) }
}

View File

@ -0,0 +1,236 @@
/* ---- Original Script: /opt/riscv32i/riscv32-unknown-elf/lib/ldscripts/elf32lriscv.x ---- */
/* Default linker script, for normal executables */
/* Copyright (C) 2014-2017 Free Software Foundation, Inc.
Copying and distribution of this script, with or without modification,
are permitted in any medium without royalty provided the copyright
notice and this notice are preserved. */
OUTPUT_FORMAT("elf32-littleriscv", "elf32-littleriscv",
"elf32-littleriscv")
OUTPUT_ARCH(riscv)
ENTRY(_start)
SEARCH_DIR("/opt/riscv32i/riscv32-unknown-elf/lib");
SECTIONS
{
/* Read-only sections, merged into text segment: */
PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x10000)); . = SEGMENT_START("text-segment", 0x10000) + SIZEOF_HEADERS;
.interp : { *(.interp) }
.note.gnu.build-id : { *(.note.gnu.build-id) }
.hash : { *(.hash) }
.gnu.hash : { *(.gnu.hash) }
.dynsym : { *(.dynsym) }
.dynstr : { *(.dynstr) }
.gnu.version : { *(.gnu.version) }
.gnu.version_d : { *(.gnu.version_d) }
.gnu.version_r : { *(.gnu.version_r) }
.rela.init : { *(.rela.init) }
.rela.text : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) }
.rela.fini : { *(.rela.fini) }
.rela.rodata : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) }
.rela.data.rel.ro : { *(.rela.data.rel.ro .rela.data.rel.ro.* .rela.gnu.linkonce.d.rel.ro.*) }
.rela.data : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) }
.rela.tdata : { *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) }
.rela.tbss : { *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) }
.rela.ctors : { *(.rela.ctors) }
.rela.dtors : { *(.rela.dtors) }
.rela.got : { *(.rela.got) }
.rela.sdata : { *(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*) }
.rela.sbss : { *(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*) }
.rela.sdata2 : { *(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*) }
.rela.sbss2 : { *(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*) }
.rela.bss : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) }
.rela.iplt :
{
PROVIDE_HIDDEN (__rela_iplt_start = .);
*(.rela.iplt)
PROVIDE_HIDDEN (__rela_iplt_end = .);
}
.rela.plt :
{
*(.rela.plt)
}
.init :
{
KEEP (*(SORT_NONE(.init)))
}
.plt : { *(.plt) }
.iplt : { *(.iplt) }
.text :
{
*(.text.unlikely .text.*_unlikely .text.unlikely.*)
*(.text.exit .text.exit.*)
*(.text.startup .text.startup.*)
*(.text.hot .text.hot.*)
*(.text .stub .text.* .gnu.linkonce.t.*)
/* .gnu.warning sections are handled specially by elf32.em. */
*(.gnu.warning)
}
.fini :
{
KEEP (*(SORT_NONE(.fini)))
}
PROVIDE (__etext = .);
PROVIDE (_etext = .);
PROVIDE (etext = .);
.rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
.rodata1 : { *(.rodata1) }
.sdata2 :
{
*(.sdata2 .sdata2.* .gnu.linkonce.s2.*)
}
.sbss2 : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) }
.eh_frame_hdr : { *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) }
.eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) }
.gcc_except_table : ONLY_IF_RO { *(.gcc_except_table
.gcc_except_table.*) }
.gnu_extab : ONLY_IF_RO { *(.gnu_extab*) }
/* These sections are generated by the Sun/Oracle C++ compiler. */
.exception_ranges : ONLY_IF_RO { *(.exception_ranges
.exception_ranges*) }
/* Adjust the address for the data segment. We want to adjust up to
the same address within the page on the next page up. */
. = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE));
/* Exception handling */
.eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) *(.eh_frame.*) }
.gnu_extab : ONLY_IF_RW { *(.gnu_extab) }
.gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) }
.exception_ranges : ONLY_IF_RW { *(.exception_ranges .exception_ranges*) }
/* Thread Local Storage sections */
.tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
.tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
.preinit_array :
{
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array))
PROVIDE_HIDDEN (__preinit_array_end = .);
}
.init_array :
{
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors))
PROVIDE_HIDDEN (__init_array_end = .);
}
.fini_array :
{
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors))
PROVIDE_HIDDEN (__fini_array_end = .);
}
.ctors :
{
/* gcc uses crtbegin.o to find the start of
the constructors, so we make sure it is
first. Because this is a wildcard, it
doesn't matter if the user does not
actually link against crtbegin.o; the
linker won't look for a file to match a
wildcard. The wildcard also means that it
doesn't matter which directory crtbegin.o
is in. */
KEEP (*crtbegin.o(.ctors))
KEEP (*crtbegin?.o(.ctors))
/* We don't want to include the .ctor section from
the crtend.o file until after the sorted ctors.
The .ctor section from the crtend file contains the
end of ctors marker and it must be last */
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors))
}
.dtors :
{
KEEP (*crtbegin.o(.dtors))
KEEP (*crtbegin?.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*(.dtors))
}
.jcr : { KEEP (*(.jcr)) }
.data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) }
.dynamic : { *(.dynamic) }
. = DATA_SEGMENT_RELRO_END (0, .);
.data :
{
*(.data .data.* .gnu.linkonce.d.*)
SORT(CONSTRUCTORS)
}
.data1 : { *(.data1) }
.got : { *(.got.plt) *(.igot.plt) *(.got) *(.igot) }
/* We want the small data sections together, so single-instruction offsets
can access them all, and initialized data all before uninitialized, so
we can shorten the on-disk segment size. */
.sdata :
{
__global_pointer$ = . + 0x800;
*(.srodata.cst16) *(.srodata.cst8) *(.srodata.cst4) *(.srodata.cst2) *(.srodata .srodata.*)
*(.sdata .sdata.* .gnu.linkonce.s.*)
}
_edata = .; PROVIDE (edata = .);
. = .;
__bss_start = .;
.sbss :
{
*(.dynsbss)
*(.sbss .sbss.* .gnu.linkonce.sb.*)
*(.scommon)
}
.bss :
{
*(.dynbss)
*(.bss .bss.* .gnu.linkonce.b.*)
*(COMMON)
/* Align here to ensure that the .bss section occupies space up to
_end. Align after .bss to ensure correct alignment even if the
.bss section disappears because there are no input sections.
FIXME: Why do we need it? When there is no .bss section, we don't
pad the .data section. */
. = ALIGN(. != 0 ? 32 / 8 : 1);
}
. = ALIGN(32 / 8);
. = SEGMENT_START("ldata-segment", .);
. = ALIGN(32 / 8);
_end = .; PROVIDE (end = .);
. = DATA_SEGMENT_END (.);
/* Stabs debugging sections. */
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
.stab.excl 0 : { *(.stab.excl) }
.stab.exclstr 0 : { *(.stab.exclstr) }
.stab.index 0 : { *(.stab.index) }
.stab.indexstr 0 : { *(.stab.indexstr) }
.comment 0 : { *(.comment) }
/* DWARF debug sections.
Symbols in the DWARF debugging sections are relative to the beginning
of the section so we begin them at 0. */
/* DWARF 1 */
.debug 0 : { *(.debug) }
.line 0 : { *(.line) }
/* GNU DWARF 1 extensions */
.debug_srcinfo 0 : { *(.debug_srcinfo) }
.debug_sfnames 0 : { *(.debug_sfnames) }
/* DWARF 1.1 and DWARF 2 */
.debug_aranges 0 : { *(.debug_aranges) }
.debug_pubnames 0 : { *(.debug_pubnames) }
/* DWARF 2 */
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
.debug_abbrev 0 : { *(.debug_abbrev) }
.debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end ) }
.debug_frame 0 : { *(.debug_frame) }
.debug_str 0 : { *(.debug_str) }
.debug_loc 0 : { *(.debug_loc) }
.debug_macinfo 0 : { *(.debug_macinfo) }
/* SGI/MIPS DWARF 2 extensions */
.debug_weaknames 0 : { *(.debug_weaknames) }
.debug_funcnames 0 : { *(.debug_funcnames) }
.debug_typenames 0 : { *(.debug_typenames) }
.debug_varnames 0 : { *(.debug_varnames) }
/* DWARF 3 */
.debug_pubtypes 0 : { *(.debug_pubtypes) }
.debug_ranges 0 : { *(.debug_ranges) }
/* DWARF Extension. */
.debug_macro 0 : { *(.debug_macro) }
.debug_addr 0 : { *(.debug_addr) }
.gnu.attributes 0 : { KEEP (*(.gnu.attributes)) }
/DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) }
}

View File

@ -0,0 +1,25 @@
/*
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
*/
MEMORY {
/* the memory in the testbench is 128k in size;
* set LENGTH=96k and leave at least 32k for stack */
mem : ORIGIN = 0x00000000, LENGTH = 0x00018000
}
SECTIONS {
.memory : {
. = 0x000000;
start*(.text);
*(.text);
*(*);
end = .;
. = ALIGN(4);
} > mem
}

View File

@ -0,0 +1,84 @@
// This is free and unencumbered software released into the public domain.
//
// Anyone is free to copy, modify, publish, use, compile, sell, or
// distribute this software, either in source code form or as a compiled
// binary, for any purpose, commercial or non-commercial, and by any
// means.
// A simple Sieve of Eratosthenes
#include "firmware.h"
#define BITMAP_SIZE 64
static uint32_t bitmap[BITMAP_SIZE/32];
static uint32_t hash;
static uint32_t mkhash(uint32_t a, uint32_t b)
{
// The XOR version of DJB2
return ((a << 5) + a) ^ b;
}
static void bitmap_set(int idx)
{
bitmap[idx/32] |= 1 << (idx % 32);
}
static bool bitmap_get(int idx)
{
return (bitmap[idx/32] & (1 << (idx % 32))) != 0;
}
static void print_prime(int idx, int val)
{
if (idx < 10)
print_str(" ");
print_dec(idx);
if (idx / 10 == 1)
goto force_th;
switch (idx % 10) {
case 1: print_str("st"); break;
case 2: print_str("nd"); break;
case 3: print_str("rd"); break;
force_th:
default: print_str("th"); break;
}
print_str(" prime is ");
print_dec(val);
print_str(".\n");
hash = mkhash(hash, idx);
hash = mkhash(hash, val);
}
void sieve(void)
{
int idx = 1;
hash = 5381;
print_prime(idx++, 2);
for (int i = 0; i < BITMAP_SIZE; i++) {
if (bitmap_get(i))
continue;
print_prime(idx++, 3+2*i);
for (int j = 2*(3+2*i);; j += 3+2*i) {
if (j%2 == 0)
continue;
int k = (j-3)/2;
if (k >= BITMAP_SIZE)
break;
bitmap_set(k);
}
}
print_str("checksum: ");
print_hex(hash, 8);
if (hash == 0x1772A48F) {
print_str(" OK\n");
} else {
print_str(" ERROR\n");
__asm__ volatile ("ebreak");
}
}

View File

@ -0,0 +1,537 @@
// This is free and unencumbered software released into the public domain.
//
// Anyone is free to copy, modify, publish, use, compile, sell, or
// distribute this software, either in source code form or as a compiled
// binary, for any purpose, commercial or non-commercial, and by any
// means.
#define ENABLE_QREGS
#define ENABLE_HELLO
#define ENABLE_RVTST
#define ENABLE_SIEVE
#define ENABLE_MULTST
#define ENABLE_STATS
#ifndef ENABLE_QREGS
# undef ENABLE_RVTST
#endif
// Only save registers in IRQ wrapper that are to be saved by the caller in
// the RISC-V ABI, with the excpetion of the stack pointer. The IRQ handler
// will save the rest if necessary. I.e. skip x3, x4, x8, x9, and x18-x27.
#undef ENABLE_FASTIRQ
#include "custom_ops.S"
.section .text
.global irq
.global hello
.global sieve
.global multest
.global hard_mul
.global hard_mulh
.global hard_mulhsu
.global hard_mulhu
.global hard_div
.global hard_divu
.global hard_rem
.global hard_remu
.global stats
reset_vec:
// no more than 16 bytes here !
picorv32_waitirq_insn(zero)
picorv32_maskirq_insn(zero, zero)
j start
/* Interrupt handler
**********************************/
.balign 16
irq_vec:
/* save registers */
#ifdef ENABLE_QREGS
picorv32_setq_insn(q2, x1)
picorv32_setq_insn(q3, x2)
lui x1, %hi(irq_regs)
addi x1, x1, %lo(irq_regs)
picorv32_getq_insn(x2, q0)
sw x2, 0*4(x1)
picorv32_getq_insn(x2, q2)
sw x2, 1*4(x1)
picorv32_getq_insn(x2, q3)
sw x2, 2*4(x1)
#ifdef ENABLE_FASTIRQ
sw x5, 5*4(x1)
sw x6, 6*4(x1)
sw x7, 7*4(x1)
sw x10, 10*4(x1)
sw x11, 11*4(x1)
sw x12, 12*4(x1)
sw x13, 13*4(x1)
sw x14, 14*4(x1)
sw x15, 15*4(x1)
sw x16, 16*4(x1)
sw x17, 17*4(x1)
sw x28, 28*4(x1)
sw x29, 29*4(x1)
sw x30, 30*4(x1)
sw x31, 31*4(x1)
#else
sw x3, 3*4(x1)
sw x4, 4*4(x1)
sw x5, 5*4(x1)
sw x6, 6*4(x1)
sw x7, 7*4(x1)
sw x8, 8*4(x1)
sw x9, 9*4(x1)
sw x10, 10*4(x1)
sw x11, 11*4(x1)
sw x12, 12*4(x1)
sw x13, 13*4(x1)
sw x14, 14*4(x1)
sw x15, 15*4(x1)
sw x16, 16*4(x1)
sw x17, 17*4(x1)
sw x18, 18*4(x1)
sw x19, 19*4(x1)
sw x20, 20*4(x1)
sw x21, 21*4(x1)
sw x22, 22*4(x1)
sw x23, 23*4(x1)
sw x24, 24*4(x1)
sw x25, 25*4(x1)
sw x26, 26*4(x1)
sw x27, 27*4(x1)
sw x28, 28*4(x1)
sw x29, 29*4(x1)
sw x30, 30*4(x1)
sw x31, 31*4(x1)
#endif
#else // ENABLE_QREGS
#ifdef ENABLE_FASTIRQ
sw gp, 0*4+0x200(zero)
sw x1, 1*4+0x200(zero)
sw x2, 2*4+0x200(zero)
sw x5, 5*4+0x200(zero)
sw x6, 6*4+0x200(zero)
sw x7, 7*4+0x200(zero)
sw x10, 10*4+0x200(zero)
sw x11, 11*4+0x200(zero)
sw x12, 12*4+0x200(zero)
sw x13, 13*4+0x200(zero)
sw x14, 14*4+0x200(zero)
sw x15, 15*4+0x200(zero)
sw x16, 16*4+0x200(zero)
sw x17, 17*4+0x200(zero)
sw x28, 28*4+0x200(zero)
sw x29, 29*4+0x200(zero)
sw x30, 30*4+0x200(zero)
sw x31, 31*4+0x200(zero)
#else
sw gp, 0*4+0x200(zero)
sw x1, 1*4+0x200(zero)
sw x2, 2*4+0x200(zero)
sw x3, 3*4+0x200(zero)
sw x4, 4*4+0x200(zero)
sw x5, 5*4+0x200(zero)
sw x6, 6*4+0x200(zero)
sw x7, 7*4+0x200(zero)
sw x8, 8*4+0x200(zero)
sw x9, 9*4+0x200(zero)
sw x10, 10*4+0x200(zero)
sw x11, 11*4+0x200(zero)
sw x12, 12*4+0x200(zero)
sw x13, 13*4+0x200(zero)
sw x14, 14*4+0x200(zero)
sw x15, 15*4+0x200(zero)
sw x16, 16*4+0x200(zero)
sw x17, 17*4+0x200(zero)
sw x18, 18*4+0x200(zero)
sw x19, 19*4+0x200(zero)
sw x20, 20*4+0x200(zero)
sw x21, 21*4+0x200(zero)
sw x22, 22*4+0x200(zero)
sw x23, 23*4+0x200(zero)
sw x24, 24*4+0x200(zero)
sw x25, 25*4+0x200(zero)
sw x26, 26*4+0x200(zero)
sw x27, 27*4+0x200(zero)
sw x28, 28*4+0x200(zero)
sw x29, 29*4+0x200(zero)
sw x30, 30*4+0x200(zero)
sw x31, 31*4+0x200(zero)
#endif
#endif // ENABLE_QREGS
/* call interrupt handler C function */
lui sp, %hi(irq_stack)
addi sp, sp, %lo(irq_stack)
// arg0 = address of regs
lui a0, %hi(irq_regs)
addi a0, a0, %lo(irq_regs)
// arg1 = interrupt type
#ifdef ENABLE_QREGS
picorv32_getq_insn(a1, q1)
#else
addi a1, tp, 0
#endif
// call to C function
jal ra, irq
/* restore registers */
#ifdef ENABLE_QREGS
// new irq_regs address returned from C code in a0
addi x1, a0, 0
lw x2, 0*4(x1)
picorv32_setq_insn(q0, x2)
lw x2, 1*4(x1)
picorv32_setq_insn(q1, x2)
lw x2, 2*4(x1)
picorv32_setq_insn(q2, x2)
#ifdef ENABLE_FASTIRQ
lw x5, 5*4(x1)
lw x6, 6*4(x1)
lw x7, 7*4(x1)
lw x10, 10*4(x1)
lw x11, 11*4(x1)
lw x12, 12*4(x1)
lw x13, 13*4(x1)
lw x14, 14*4(x1)
lw x15, 15*4(x1)
lw x16, 16*4(x1)
lw x17, 17*4(x1)
lw x28, 28*4(x1)
lw x29, 29*4(x1)
lw x30, 30*4(x1)
lw x31, 31*4(x1)
#else
lw x3, 3*4(x1)
lw x4, 4*4(x1)
lw x5, 5*4(x1)
lw x6, 6*4(x1)
lw x7, 7*4(x1)
lw x8, 8*4(x1)
lw x9, 9*4(x1)
lw x10, 10*4(x1)
lw x11, 11*4(x1)
lw x12, 12*4(x1)
lw x13, 13*4(x1)
lw x14, 14*4(x1)
lw x15, 15*4(x1)
lw x16, 16*4(x1)
lw x17, 17*4(x1)
lw x18, 18*4(x1)
lw x19, 19*4(x1)
lw x20, 20*4(x1)
lw x21, 21*4(x1)
lw x22, 22*4(x1)
lw x23, 23*4(x1)
lw x24, 24*4(x1)
lw x25, 25*4(x1)
lw x26, 26*4(x1)
lw x27, 27*4(x1)
lw x28, 28*4(x1)
lw x29, 29*4(x1)
lw x30, 30*4(x1)
lw x31, 31*4(x1)
#endif
picorv32_getq_insn(x1, q1)
picorv32_getq_insn(x2, q2)
#else // ENABLE_QREGS
// new irq_regs address returned from C code in a0
addi a1, zero, 0x200
beq a0, a1, 1f
ebreak
1:
#ifdef ENABLE_FASTIRQ
lw gp, 0*4+0x200(zero)
lw x1, 1*4+0x200(zero)
lw x2, 2*4+0x200(zero)
lw x5, 5*4+0x200(zero)
lw x6, 6*4+0x200(zero)
lw x7, 7*4+0x200(zero)
lw x10, 10*4+0x200(zero)
lw x11, 11*4+0x200(zero)
lw x12, 12*4+0x200(zero)
lw x13, 13*4+0x200(zero)
lw x14, 14*4+0x200(zero)
lw x15, 15*4+0x200(zero)
lw x16, 16*4+0x200(zero)
lw x17, 17*4+0x200(zero)
lw x28, 28*4+0x200(zero)
lw x29, 29*4+0x200(zero)
lw x30, 30*4+0x200(zero)
lw x31, 31*4+0x200(zero)
#else
lw gp, 0*4+0x200(zero)
lw x1, 1*4+0x200(zero)
lw x2, 2*4+0x200(zero)
// do not restore x3 (gp)
lw x4, 4*4+0x200(zero)
lw x5, 5*4+0x200(zero)
lw x6, 6*4+0x200(zero)
lw x7, 7*4+0x200(zero)
lw x8, 8*4+0x200(zero)
lw x9, 9*4+0x200(zero)
lw x10, 10*4+0x200(zero)
lw x11, 11*4+0x200(zero)
lw x12, 12*4+0x200(zero)
lw x13, 13*4+0x200(zero)
lw x14, 14*4+0x200(zero)
lw x15, 15*4+0x200(zero)
lw x16, 16*4+0x200(zero)
lw x17, 17*4+0x200(zero)
lw x18, 18*4+0x200(zero)
lw x19, 19*4+0x200(zero)
lw x20, 20*4+0x200(zero)
lw x21, 21*4+0x200(zero)
lw x22, 22*4+0x200(zero)
lw x23, 23*4+0x200(zero)
lw x24, 24*4+0x200(zero)
lw x25, 25*4+0x200(zero)
lw x26, 26*4+0x200(zero)
lw x27, 27*4+0x200(zero)
lw x28, 28*4+0x200(zero)
lw x29, 29*4+0x200(zero)
lw x30, 30*4+0x200(zero)
lw x31, 31*4+0x200(zero)
#endif
#endif // ENABLE_QREGS
picorv32_retirq_insn()
#ifndef ENABLE_QREGS
.balign 0x200
#endif
irq_regs:
// registers are saved to this memory region during interrupt handling
// the program counter is saved as register 0
.fill 32,4
// stack for the interrupt handler
.fill 128,4
irq_stack:
/* Main program
**********************************/
start:
/* zero-initialize all registers */
addi x1, zero, 0
addi x2, zero, 0
addi x3, zero, 0
addi x4, zero, 0
addi x5, zero, 0
addi x6, zero, 0
addi x7, zero, 0
addi x8, zero, 0
addi x9, zero, 0
addi x10, zero, 0
addi x11, zero, 0
addi x12, zero, 0
addi x13, zero, 0
addi x14, zero, 0
addi x15, zero, 0
addi x16, zero, 0
addi x17, zero, 0
addi x18, zero, 0
addi x19, zero, 0
addi x20, zero, 0
addi x21, zero, 0
addi x22, zero, 0
addi x23, zero, 0
addi x24, zero, 0
addi x25, zero, 0
addi x26, zero, 0
addi x27, zero, 0
addi x28, zero, 0
addi x29, zero, 0
addi x30, zero, 0
addi x31, zero, 0
#ifdef ENABLE_HELLO
/* set stack pointer */
lui sp,(128*1024)>>12
/* call hello C code */
jal ra,hello
#endif
/* running tests from riscv-tests */
#ifdef ENABLE_RVTST
# define TEST(n) \
.global n; \
addi x1, zero, 1000; \
picorv32_timer_insn(zero, x1); \
jal zero,n; \
.global n ## _ret; \
n ## _ret:
#else
# define TEST(n) \
.global n ## _ret; \
n ## _ret:
#endif
TEST(lui)
TEST(auipc)
TEST(j)
TEST(jal)
TEST(jalr)
TEST(beq)
TEST(bne)
TEST(blt)
TEST(bge)
TEST(bltu)
TEST(bgeu)
TEST(lb)
TEST(lh)
TEST(lw)
TEST(lbu)
TEST(lhu)
TEST(sb)
TEST(sh)
TEST(sw)
TEST(addi)
TEST(slti) // also tests sltiu
TEST(xori)
TEST(ori)
TEST(andi)
TEST(slli)
TEST(srli)
TEST(srai)
TEST(add)
TEST(sub)
TEST(sll)
TEST(slt) // what is with sltu ?
TEST(xor)
TEST(srl)
TEST(sra)
TEST(or)
TEST(and)
TEST(mulh)
TEST(mulhsu)
TEST(mulhu)
TEST(mul)
TEST(div)
TEST(divu)
TEST(rem)
TEST(remu)
TEST(simple)
/* set stack pointer */
lui sp,(128*1024)>>12
/* set gp and tp */
lui gp, %hi(0xdeadbeef)
addi gp, gp, %lo(0xdeadbeef)
addi tp, gp, 0
#ifdef ENABLE_SIEVE
/* call sieve C code */
jal ra,sieve
#endif
#ifdef ENABLE_MULTST
/* call multest C code */
jal ra,multest
#endif
#ifdef ENABLE_STATS
/* call stats C code */
jal ra,stats
#endif
/* print "DONE\n" */
lui a0,0x10000000>>12
addi a1,zero,'D'
addi a2,zero,'O'
addi a3,zero,'N'
addi a4,zero,'E'
addi a5,zero,'\n'
sw a1,0(a0)
sw a2,0(a0)
sw a3,0(a0)
sw a4,0(a0)
sw a5,0(a0)
li a0, 0x20000000
li a1, 123456789
sw a1,0(a0)
/* trap */
ebreak
/* Hard mul functions for multest.c
**********************************/
hard_mul:
mul a0, a0, a1
ret
hard_mulh:
mulh a0, a0, a1
ret
hard_mulhsu:
mulhsu a0, a0, a1
ret
hard_mulhu:
mulhu a0, a0, a1
ret
hard_div:
div a0, a0, a1
ret
hard_divu:
divu a0, a0, a1
ret
hard_rem:
rem a0, a0, a1
ret
hard_remu:
remu a0, a0, a1
ret

View File

@ -0,0 +1,42 @@
// This is free and unencumbered software released into the public domain.
//
// Anyone is free to copy, modify, publish, use, compile, sell, or
// distribute this software, either in source code form or as a compiled
// binary, for any purpose, commercial or non-commercial, and by any
// means.
#include "firmware.h"
static void stats_print_dec(unsigned int val, int digits, bool zero_pad)
{
char buffer[32];
char *p = buffer;
while (val || digits > 0) {
if (val)
*(p++) = '0' + val % 10;
else
*(p++) = zero_pad ? '0' : ' ';
val = val / 10;
digits--;
}
while (p != buffer) {
if (p[-1] == ' ' && p[-2] == ' ') p[-1] = '.';
print_chr(*(--p));
}
}
void stats(void)
{
unsigned int num_cycles, num_instr;
__asm__ volatile ("rdcycle %0; rdinstret %1;" : "=r"(num_cycles), "=r"(num_instr));
print_str("Cycle counter ........");
stats_print_dec(num_cycles, 8, false);
print_str("\nInstruction counter ..");
stats_print_dec(num_instr, 8, false);
print_str("\nCPI: ");
stats_print_dec((num_cycles / num_instr), 0, false);
print_str(".");
stats_print_dec(((100 * num_cycles) / num_instr) % 100, 2, true);
print_str("\n");
}

78
fw/picorv32/picorv32.core Normal file
View File

@ -0,0 +1,78 @@
CAPI=2:
name : ::picorv32:0-r1
filesets:
rtl:
files: [picorv32.v]
file_type : verilogSource
tb:
files: [testbench.v]
file_type : verilogSource
depend:
tb_ez:
files: [testbench_ez.v]
file_type : verilogSource
tb_wb:
files: [testbench_wb.v]
file_type : verilogSource
tb_verilator:
files:
- testbench.cc : {file_type : cppSource}
targets:
default:
filesets: [rtl]
lint:
filesets: [rtl]
default_tool : verilator
tools:
verilator:
mode : lint-only
toplevel : [picorv32_axi]
test:
default_tool: icarus
filesets: [rtl, tb, "tool_verilator? (tb_verilator)"]
parameters: [COMPRESSED_ISA, axi_test, firmware, noerror, trace, vcd, verbose]
toplevel:
- "tool_verilator? (picorv32_wrapper)"
- "!tool_verilator? (testbench)"
tools:
verilator :
cli_parser : fusesoc
mode : cc
verilator_options : [-Wno-fatal, --trace]
test_ez:
default_tool: icarus
filesets: [rtl, tb_ez]
parameters: [vcd]
toplevel: [testbench]
test_wb:
default_tool: icarus
filesets: [rtl, tb_wb]
parameters: [COMPRESSED_ISA, firmware, noerror, trace, vcd]
toplevel: [testbench]
parameters:
COMPRESSED_ISA:
datatype : str
default : 1
paramtype : vlogdefine
axi_test:
datatype : bool
paramtype : plusarg
firmware:
datatype : file
paramtype : plusarg
noerror:
datatype : bool
paramtype : plusarg
trace:
datatype : bool
paramtype : plusarg
vcd:
datatype : bool
paramtype : plusarg
verbose:
datatype : bool
paramtype : plusarg

3044
fw/picorv32/picorv32.v Normal file

File diff suppressed because it is too large Load Diff

29
fw/picorv32/picosoc/.gitignore vendored Normal file
View File

@ -0,0 +1,29 @@
/spiflash_tb.vcd
/spiflash_tb.vvp
/hx8kdemo.asc
/hx8kdemo.bin
/hx8kdemo.blif
/hx8kdemo.log
/hx8kdemo.rpt
/hx8kdemo_syn.v
/hx8kdemo_syn_tb.vvp
/hx8kdemo_tb.vvp
/hx8kdemo_fw.elf
/hx8kdemo_fw.hex
/hx8kdemo_fw.bin
/hx8kdemo_sections.lds
/icebreaker.asc
/icebreaker.bin
/icebreaker.json
/icebreaker.log
/icebreaker.rpt
/icebreaker_syn.v
/icebreaker_syn_tb.vvp
/icebreaker_tb.vvp
/icebreaker_fw.elf
/icebreaker_fw.hex
/icebreaker_fw.bin
/icebreaker_sections.lds
/testbench.vcd
/cmos.log

View File

@ -0,0 +1,123 @@
CROSS=riscv32-unknown-elf-
CFLAGS=
# ---- iCE40 HX8K Breakout Board ----
hx8ksim: hx8kdemo_tb.vvp hx8kdemo_fw.hex
vvp -N $< +firmware=hx8kdemo_fw.hex
hx8ksynsim: hx8kdemo_syn_tb.vvp hx8kdemo_fw.hex
vvp -N $< +firmware=hx8kdemo_fw.hex
hx8kdemo.blif: hx8kdemo.v spimemio.v simpleuart.v picosoc.v ../picorv32.v
yosys -ql hx8kdemo.log -p 'synth_ice40 -top hx8kdemo -blif hx8kdemo.blif' $^
hx8kdemo_tb.vvp: hx8kdemo_tb.v hx8kdemo.v spimemio.v simpleuart.v picosoc.v ../picorv32.v spiflash.v
iverilog -s testbench -o $@ $^ `yosys-config --datdir/ice40/cells_sim.v`
hx8kdemo_syn_tb.vvp: hx8kdemo_tb.v hx8kdemo_syn.v spiflash.v
iverilog -s testbench -o $@ $^ `yosys-config --datdir/ice40/cells_sim.v`
hx8kdemo_syn.v: hx8kdemo.blif
yosys -p 'read_blif -wideports hx8kdemo.blif; write_verilog hx8kdemo_syn.v'
hx8kdemo.asc: hx8kdemo.pcf hx8kdemo.blif
arachne-pnr -d 8k -o hx8kdemo.asc -p hx8kdemo.pcf hx8kdemo.blif
hx8kdemo.bin: hx8kdemo.asc
icetime -d hx8k -c 12 -mtr hx8kdemo.rpt hx8kdemo.asc
icepack hx8kdemo.asc hx8kdemo.bin
hx8kprog: hx8kdemo.bin hx8kdemo_fw.bin
iceprog hx8kdemo.bin
iceprog -o 1M hx8kdemo_fw.bin
hx8kprog_fw: hx8kdemo_fw.bin
iceprog -o 1M hx8kdemo_fw.bin
hx8kdemo_sections.lds: sections.lds
$(CROSS)cpp -P -DHX8KDEMO -o $@ $^
hx8kdemo_fw.elf: hx8kdemo_sections.lds start.s firmware.c
$(CROSS)gcc $(CFLAGS) -DHX8KDEMO -march=rv32imc -Wl,-Bstatic,-T,hx8kdemo_sections.lds,--strip-debug -ffreestanding -nostdlib -o hx8kdemo_fw.elf start.s firmware.c
hx8kdemo_fw.hex: hx8kdemo_fw.elf
$(CROSS)objcopy -O verilog hx8kdemo_fw.elf hx8kdemo_fw.hex
hx8kdemo_fw.bin: hx8kdemo_fw.elf
$(CROSS)objcopy -O binary hx8kdemo_fw.elf hx8kdemo_fw.bin
# ---- iCE40 IceBreaker Board ----
icebsim: icebreaker_tb.vvp icebreaker_fw.hex
vvp -N $< +firmware=icebreaker_fw.hex
icebsynsim: icebreaker_syn_tb.vvp icebreaker_fw.hex
vvp -N $< +firmware=icebreaker_fw.hex
icebreaker.json: icebreaker.v ice40up5k_spram.v spimemio.v simpleuart.v picosoc.v ../picorv32.v
yosys -ql icebreaker.log -p 'synth_ice40 -top icebreaker -json icebreaker.json' $^
icebreaker_tb.vvp: icebreaker_tb.v icebreaker.v ice40up5k_spram.v spimemio.v simpleuart.v picosoc.v ../picorv32.v spiflash.v
iverilog -s testbench -o $@ $^ `yosys-config --datdir/ice40/cells_sim.v`
icebreaker_syn_tb.vvp: icebreaker_tb.v icebreaker_syn.v spiflash.v
iverilog -s testbench -o $@ $^ `yosys-config --datdir/ice40/cells_sim.v`
icebreaker_syn.v: icebreaker.json
yosys -p 'read_json icebreaker.json; write_verilog icebreaker_syn.v'
icebreaker.asc: icebreaker.pcf icebreaker.json
nextpnr-ice40 --freq 13 --up5k --asc icebreaker.asc --pcf icebreaker.pcf --json icebreaker.json
icebreaker.bin: icebreaker.asc
icetime -d up5k -c 12 -mtr icebreaker.rpt icebreaker.asc
icepack icebreaker.asc icebreaker.bin
icebprog: icebreaker.bin icebreaker_fw.bin
iceprog icebreaker.bin
iceprog -o 1M icebreaker_fw.bin
icebprog_fw: icebreaker_fw.bin
iceprog -o 1M icebreaker_fw.bin
icebreaker_sections.lds: sections.lds
$(CROSS)cpp -P -DICEBREAKER -o $@ $^
icebreaker_fw.elf: icebreaker_sections.lds start.s firmware.c
$(CROSS)gcc $(CFLAGS) -DICEBREAKER -march=rv32ic -Wl,-Bstatic,-T,icebreaker_sections.lds,--strip-debug -ffreestanding -nostdlib -o icebreaker_fw.elf start.s firmware.c
icebreaker_fw.hex: icebreaker_fw.elf
$(CROSS)objcopy -O verilog icebreaker_fw.elf icebreaker_fw.hex
icebreaker_fw.bin: icebreaker_fw.elf
$(CROSS)objcopy -O binary icebreaker_fw.elf icebreaker_fw.bin
# ---- Testbench for SPI Flash Model ----
spiflash_tb: spiflash_tb.vvp firmware.hex
vvp -N $<
spiflash_tb.vvp: spiflash.v spiflash_tb.v
iverilog -s testbench -o $@ $^
# ---- ASIC Synthesis Tests ----
cmos.log: spimemio.v simpleuart.v picosoc.v ../picorv32.v
yosys -l cmos.log -p 'synth -top picosoc; abc -g cmos2; opt -fast; stat' $^
# ---- Clean ----
clean:
rm -f testbench.vvp testbench.vcd spiflash_tb.vvp spiflash_tb.vcd
rm -f hx8kdemo_fw.elf hx8kdemo_fw.hex hx8kdemo_fw.bin cmos.log
rm -f icebreaker_fw.elf icebreaker_fw.hex icebreaker_fw.bin
rm -f hx8kdemo.blif hx8kdemo.log hx8kdemo.asc hx8kdemo.rpt hx8kdemo.bin
rm -f hx8kdemo_syn.v hx8kdemo_syn_tb.vvp hx8kdemo_tb.vvp
rm -f icebreaker.json icebreaker.log icebreaker.asc icebreaker.rpt icebreaker.bin
rm -f icebreaker_syn.v icebreaker_syn_tb.vvp icebreaker_tb.vvp
.PHONY: spiflash_tb clean
.PHONY: hx8kprog hx8kprog_fw hx8ksim hx8ksynsim
.PHONY: icebprog icebprog_fw icebsim icebsynsim

View File

@ -0,0 +1,114 @@
PicoSoC - A simple example SoC using PicoRV32
=============================================
![](overview.svg)
This is a simple PicoRV32 example design that can run code directly from an SPI
flash chip. It can be used as a turn-key solution for simple control tasks in
ASIC and FPGA designs.
An example implementation targeting the Lattice iCE40-HX8K Breakout Board is
included.
The flash is mapped to the memory regions starting at 0x00000000 and
0x01000000, with the SRAM overlayed for the mapping at 0x00000000. The SRAM
is just a small scratchpad memory (default 256 words, i.e. 1 kB).
The reset vector is set to 0x00100000, i.e. at 1MB into in the flash memory.
See the included demo firmware and linker script for how to build a firmware
image for this system.
Run `make hx8ksim` or `make icebsim` to run the test bench (and create `testbench.vcd`).
Run `make hx8kprog` to build the configuration bit-stream and firmware images
and upload them to a connected iCE40-HX8K Breakout Board.
Run `make icebprog` to build the configuration bit-stream and firmware images
and upload them to a connected iCEBreaker Board.
| File | Description |
| ----------------------------------- | --------------------------------------------------------------- |
| [picosoc.v](picosoc.v) | Top-level PicoSoC Verilog module |
| [spimemio.v](spimemio.v) | Memory controller that interfaces to external SPI flash |
| [simpleuart.v](simpleuart.v) | Simple UART core connected directly to SoC TX/RX lines |
| [start.s](start.s) | Assembler source for firmware.hex/firmware.bin |
| [firmware.c](firmware.c) | C source for firmware.hex/firmware.bin |
| [sections.lds](sections.lds) | Linker script for firmware.hex/firmware.bin |
| [hx8kdemo.v](hx8kdemo.v) | FPGA-based example implementation on iCE40-HX8K Breakout Board |
| [hx8kdemo.pcf](hx8kdemo.pcf) | Pin constraints for implementation on iCE40-HX8K Breakout Board |
| [hx8kdemo\_tb.v](hx8kdemo_tb.v) | Testbench for implementation on iCE40-HX8K Breakout Board |
| [icebreaker.v](icebreaker.v) | FPGA-based example implementation on iCEBreaker Board |
| [icebreaker.pcf](icebreaker.pcf) | Pin constraints for implementation on iCEBreaker Board |
| [icebreaker\_tb.v](icebreaker_tb.v) | Testbench for implementation on iCEBreaker Board |
### Memory map:
| Address Range | Description |
| ------------------------ | --------------------------------------- |
| 0x00000000 .. 0x00FFFFFF | Internal SRAM |
| 0x01000000 .. 0x01FFFFFF | External Serial Flash |
| 0x02000000 .. 0x02000003 | SPI Flash Controller Config Register |
| 0x02000004 .. 0x02000007 | UART Clock Divider Register |
| 0x02000008 .. 0x0200000B | UART Send/Recv Data Register |
| 0x03000000 .. 0xFFFFFFFF | Memory mapped user peripherals |
Reading from the addresses in the internal SRAM region beyond the end of the
physical SRAM will read from the corresponding addresses in serial flash.
Reading from the UART Send/Recv Data Register will return the last received
byte, or -1 (all 32 bits set) when the receive buffer is empty.
The UART Clock Divider Register must be set to the system clock frequency
divided by the baud rate.
The example design (hx8kdemo.v) has the 8 LEDs on the iCE40-HX8K Breakout Board
mapped to the low byte of the 32 bit word at address 0x03000000.
### SPI Flash Controller Config Register:
| Bit(s) | Description |
| -----: | --------------------------------------------------------- |
| 31 | MEMIO Enable (reset=1, set to 0 to bit bang SPI commands) |
| 30:23 | Reserved (read 0) |
| 22 | DDR Enable bit (reset=0) |
| 21 | QSPI Enable bit (reset=0) |
| 20 | CRM Enable bit (reset=0) |
| 19:16 | Read latency (dummy) cycles (reset=8) |
| 15:12 | Reserved (read 0) |
| 11:8 | IO Output enable bits in bit bang mode |
| 7:6 | Reserved (read 0) |
| 5 | Chip select (CS) line in bit bang mode |
| 4 | Serial clock line in bit bang mode |
| 3:0 | IO data bits in bit bang mode |
The following settings for CRM/DDR/QSPI modes are valid:
| CRM | QSPI | DDR | Read Command Byte | Mode Byte |
| :-: | :--: | :-: | :-------------------- | :-------: |
| 0 | 0 | 0 | 03h Read | N/A |
| 0 | 0 | 1 | BBh Dual I/O Read | FFh |
| 1 | 0 | 1 | BBh Dual I/O Read | A5h |
| 0 | 1 | 0 | EBh Quad I/O Read | FFh |
| 1 | 1 | 0 | EBh Quad I/O Read | A5h |
| 0 | 1 | 1 | EDh DDR Quad I/O Read | FFh |
| 1 | 1 | 1 | EDh DDR Quad I/O Read | A5h |
The following plot visualizes the relative performance of the different configurations:
![](performance.png)
Consult the datasheet for your SPI flash to learn which configurations are supported
by the chip and what the maximum clock frequencies are for each configuration.
For Quad I/O mode the QUAD flag in CR1V must be set before enabling Quad I/O in the
SPI master. Either set it by writing the corresponding bit in CR1NV once, or by writing
it from your device firmware at every bootup. (See `set_flash_qspi_flag()` in
`firmware.c` for an example for the latter.)
Note that some changes to the Lattice iCE40-HX8K Breakout Board are required to support
the faster configurations: (1) The flash chip must be replaced with one that supports the
faster read commands and (2) the IO2 and IO3 pins on the flash chip must be connected to
the FPGA IO pins T9 and T8 (near the center of J3).

View File

@ -0,0 +1,770 @@
/*
* PicoSoC - A simple example SoC using PicoRV32
*
* Copyright (C) 2017 Clifford Wolf <clifford@clifford.at>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
#include <stdint.h>
#include <stdbool.h>
#ifdef ICEBREAKER
# define MEM_TOTAL 0x20000 /* 128 KB */
#elif HX8KDEMO
# define MEM_TOTAL 0x200 /* 2 KB */
#else
# error "Set -DICEBREAKER or -DHX8KDEMO when compiling firmware.c"
#endif
// a pointer to this is a null pointer, but the compiler does not
// know that because "sram" is a linker symbol from sections.lds.
extern uint32_t sram;
#define reg_spictrl (*(volatile uint32_t*)0x02000000)
#define reg_uart_clkdiv (*(volatile uint32_t*)0x02000004)
#define reg_uart_data (*(volatile uint32_t*)0x02000008)
#define reg_leds (*(volatile uint32_t*)0x03000000)
// --------------------------------------------------------
extern uint32_t flashio_worker_begin;
extern uint32_t flashio_worker_end;
void flashio(uint8_t *data, int len, uint8_t wrencmd)
{
uint32_t func[&flashio_worker_end - &flashio_worker_begin];
uint32_t *src_ptr = &flashio_worker_begin;
uint32_t *dst_ptr = func;
while (src_ptr != &flashio_worker_end)
*(dst_ptr++) = *(src_ptr++);
((void(*)(uint8_t*, uint32_t, uint32_t))func)(data, len, wrencmd);
}
#ifdef HX8KDEMO
void set_flash_qspi_flag()
{
uint8_t buffer[8];
uint32_t addr_cr1v = 0x800002;
// Read Any Register (RDAR 65h)
buffer[0] = 0x65;
buffer[1] = addr_cr1v >> 16;
buffer[2] = addr_cr1v >> 8;
buffer[3] = addr_cr1v;
buffer[4] = 0; // dummy
buffer[5] = 0; // rdata
flashio(buffer, 6, 0);
uint8_t cr1v = buffer[5];
// Write Enable (WREN 06h) + Write Any Register (WRAR 71h)
buffer[0] = 0x71;
buffer[1] = addr_cr1v >> 16;
buffer[2] = addr_cr1v >> 8;
buffer[3] = addr_cr1v;
buffer[4] = cr1v | 2; // Enable QSPI
flashio(buffer, 5, 0x06);
}
void set_flash_latency(uint8_t value)
{
reg_spictrl = (reg_spictrl & ~0x007f0000) | ((value & 15) << 16);
uint32_t addr = 0x800004;
uint8_t buffer_wr[5] = {0x71, addr >> 16, addr >> 8, addr, 0x70 | value};
flashio(buffer_wr, 5, 0x06);
}
void set_flash_mode_spi()
{
reg_spictrl = (reg_spictrl & ~0x00700000) | 0x00000000;
}
void set_flash_mode_dual()
{
reg_spictrl = (reg_spictrl & ~0x00700000) | 0x00400000;
}
void set_flash_mode_quad()
{
reg_spictrl = (reg_spictrl & ~0x00700000) | 0x00200000;
}
void set_flash_mode_qddr()
{
reg_spictrl = (reg_spictrl & ~0x00700000) | 0x00600000;
}
#endif
#ifdef ICEBREAKER
void set_flash_qspi_flag()
{
uint8_t buffer[8];
// Read Configuration Registers (RDCR1 35h)
buffer[0] = 0x35;
buffer[1] = 0x00; // rdata
flashio(buffer, 2, 0);
uint8_t sr2 = buffer[1];
// Write Enable Volatile (50h) + Write Status Register 2 (31h)
buffer[0] = 0x31;
buffer[1] = sr2 | 2; // Enable QSPI
flashio(buffer, 2, 0x50);
}
void set_flash_mode_spi()
{
reg_spictrl = (reg_spictrl & ~0x007f0000) | 0x00000000;
}
void set_flash_mode_dual()
{
reg_spictrl = (reg_spictrl & ~0x007f0000) | 0x00400000;
}
void set_flash_mode_quad()
{
reg_spictrl = (reg_spictrl & ~0x007f0000) | 0x00240000;
}
void set_flash_mode_qddr()
{
reg_spictrl = (reg_spictrl & ~0x007f0000) | 0x00670000;
}
void enable_flash_crm()
{
reg_spictrl |= 0x00100000;
}
#endif
// --------------------------------------------------------
void putchar(char c)
{
if (c == '\n')
putchar('\r');
reg_uart_data = c;
}
void print(const char *p)
{
while (*p)
putchar(*(p++));
}
void print_hex(uint32_t v, int digits)
{
for (int i = 7; i >= 0; i--) {
char c = "0123456789abcdef"[(v >> (4*i)) & 15];
if (c == '0' && i >= digits) continue;
putchar(c);
digits = i;
}
}
void print_dec(uint32_t v)
{
if (v >= 1000) {
print(">=1000");
return;
}
if (v >= 900) { putchar('9'); v -= 900; }
else if (v >= 800) { putchar('8'); v -= 800; }
else if (v >= 700) { putchar('7'); v -= 700; }
else if (v >= 600) { putchar('6'); v -= 600; }
else if (v >= 500) { putchar('5'); v -= 500; }
else if (v >= 400) { putchar('4'); v -= 400; }
else if (v >= 300) { putchar('3'); v -= 300; }
else if (v >= 200) { putchar('2'); v -= 200; }
else if (v >= 100) { putchar('1'); v -= 100; }
if (v >= 90) { putchar('9'); v -= 90; }
else if (v >= 80) { putchar('8'); v -= 80; }
else if (v >= 70) { putchar('7'); v -= 70; }
else if (v >= 60) { putchar('6'); v -= 60; }
else if (v >= 50) { putchar('5'); v -= 50; }
else if (v >= 40) { putchar('4'); v -= 40; }
else if (v >= 30) { putchar('3'); v -= 30; }
else if (v >= 20) { putchar('2'); v -= 20; }
else if (v >= 10) { putchar('1'); v -= 10; }
if (v >= 9) { putchar('9'); v -= 9; }
else if (v >= 8) { putchar('8'); v -= 8; }
else if (v >= 7) { putchar('7'); v -= 7; }
else if (v >= 6) { putchar('6'); v -= 6; }
else if (v >= 5) { putchar('5'); v -= 5; }
else if (v >= 4) { putchar('4'); v -= 4; }
else if (v >= 3) { putchar('3'); v -= 3; }
else if (v >= 2) { putchar('2'); v -= 2; }
else if (v >= 1) { putchar('1'); v -= 1; }
else putchar('0');
}
char getchar_prompt(char *prompt)
{
int32_t c = -1;
uint32_t cycles_begin, cycles_now, cycles;
__asm__ volatile ("rdcycle %0" : "=r"(cycles_begin));
reg_leds = ~0;
if (prompt)
print(prompt);
while (c == -1) {
__asm__ volatile ("rdcycle %0" : "=r"(cycles_now));
cycles = cycles_now - cycles_begin;
if (cycles > 12000000) {
if (prompt)
print(prompt);
cycles_begin = cycles_now;
reg_leds = ~reg_leds;
}
c = reg_uart_data;
}
reg_leds = 0;
return c;
}
char getchar()
{
return getchar_prompt(0);
}
void cmd_print_spi_state()
{
print("SPI State:\n");
print(" LATENCY ");
print_dec((reg_spictrl >> 16) & 15);
print("\n");
print(" DDR ");
if ((reg_spictrl & (1 << 22)) != 0)
print("ON\n");
else
print("OFF\n");
print(" QSPI ");
if ((reg_spictrl & (1 << 21)) != 0)
print("ON\n");
else
print("OFF\n");
print(" CRM ");
if ((reg_spictrl & (1 << 20)) != 0)
print("ON\n");
else
print("OFF\n");
}
uint32_t xorshift32(uint32_t *state)
{
/* Algorithm "xor" from p. 4 of Marsaglia, "Xorshift RNGs" */
uint32_t x = *state;
x ^= x << 13;
x ^= x >> 17;
x ^= x << 5;
*state = x;
return x;
}
void cmd_memtest()
{
int cyc_count = 5;
int stride = 256;
uint32_t state;
volatile uint32_t *base_word = (uint32_t *) 0;
volatile uint8_t *base_byte = (uint8_t *) 0;
print("Running memtest ");
// Walk in stride increments, word access
for (int i = 1; i <= cyc_count; i++) {
state = i;
for (int word = 0; word < MEM_TOTAL / sizeof(int); word += stride) {
*(base_word + word) = xorshift32(&state);
}
state = i;
for (int word = 0; word < MEM_TOTAL / sizeof(int); word += stride) {
if (*(base_word + word) != xorshift32(&state)) {
print(" ***FAILED WORD*** at ");
print_hex(4*word, 4);
print("\n");
return;
}
}
print(".");
}
// Byte access
for (int byte = 0; byte < 128; byte++) {
*(base_byte + byte) = (uint8_t) byte;
}
for (int byte = 0; byte < 128; byte++) {
if (*(base_byte + byte) != (uint8_t) byte) {
print(" ***FAILED BYTE*** at ");
print_hex(byte, 4);
print("\n");
return;
}
}
print(" passed\n");
}
// --------------------------------------------------------
void cmd_read_flash_id()
{
uint8_t buffer[17] = { 0x9F, /* zeros */ };
flashio(buffer, 17, 0);
for (int i = 1; i <= 16; i++) {
putchar(' ');
print_hex(buffer[i], 2);
}
putchar('\n');
}
// --------------------------------------------------------
#ifdef HX8KDEMO
uint8_t cmd_read_flash_regs_print(uint32_t addr, const char *name)
{
set_flash_latency(8);
uint8_t buffer[6] = {0x65, addr >> 16, addr >> 8, addr, 0, 0};
flashio(buffer, 6, 0);
print("0x");
print_hex(addr, 6);
print(" ");
print(name);
print(" 0x");
print_hex(buffer[5], 2);
print("\n");
return buffer[5];
}
void cmd_read_flash_regs()
{
print("\n");
uint8_t sr1v = cmd_read_flash_regs_print(0x800000, "SR1V");
uint8_t sr2v = cmd_read_flash_regs_print(0x800001, "SR2V");
uint8_t cr1v = cmd_read_flash_regs_print(0x800002, "CR1V");
uint8_t cr2v = cmd_read_flash_regs_print(0x800003, "CR2V");
uint8_t cr3v = cmd_read_flash_regs_print(0x800004, "CR3V");
uint8_t vdlp = cmd_read_flash_regs_print(0x800005, "VDLP");
}
#endif
#ifdef ICEBREAKER
uint8_t cmd_read_flash_reg(uint8_t cmd)
{
uint8_t buffer[2] = {cmd, 0};
flashio(buffer, 2, 0);
return buffer[1];
}
void print_reg_bit(int val, const char *name)
{
for (int i = 0; i < 12; i++) {
if (*name == 0)
putchar(' ');
else
putchar(*(name++));
}
putchar(val ? '1' : '0');
putchar('\n');
}
void cmd_read_flash_regs()
{
putchar('\n');
uint8_t sr1 = cmd_read_flash_reg(0x05);
uint8_t sr2 = cmd_read_flash_reg(0x35);
uint8_t sr3 = cmd_read_flash_reg(0x15);
print_reg_bit(sr1 & 0x01, "S0 (BUSY)");
print_reg_bit(sr1 & 0x02, "S1 (WEL)");
print_reg_bit(sr1 & 0x04, "S2 (BP0)");
print_reg_bit(sr1 & 0x08, "S3 (BP1)");
print_reg_bit(sr1 & 0x10, "S4 (BP2)");
print_reg_bit(sr1 & 0x20, "S5 (TB)");
print_reg_bit(sr1 & 0x40, "S6 (SEC)");
print_reg_bit(sr1 & 0x80, "S7 (SRP)");
putchar('\n');
print_reg_bit(sr2 & 0x01, "S8 (SRL)");
print_reg_bit(sr2 & 0x02, "S9 (QE)");
print_reg_bit(sr2 & 0x04, "S10 ----");
print_reg_bit(sr2 & 0x08, "S11 (LB1)");
print_reg_bit(sr2 & 0x10, "S12 (LB2)");
print_reg_bit(sr2 & 0x20, "S13 (LB3)");
print_reg_bit(sr2 & 0x40, "S14 (CMP)");
print_reg_bit(sr2 & 0x80, "S15 (SUS)");
putchar('\n');
print_reg_bit(sr3 & 0x01, "S16 ----");
print_reg_bit(sr3 & 0x02, "S17 ----");
print_reg_bit(sr3 & 0x04, "S18 (WPS)");
print_reg_bit(sr3 & 0x08, "S19 ----");
print_reg_bit(sr3 & 0x10, "S20 ----");
print_reg_bit(sr3 & 0x20, "S21 (DRV0)");
print_reg_bit(sr3 & 0x40, "S22 (DRV1)");
print_reg_bit(sr3 & 0x80, "S23 (HOLD)");
putchar('\n');
}
#endif
// --------------------------------------------------------
uint32_t cmd_benchmark(bool verbose, uint32_t *instns_p)
{
uint8_t data[256];
uint32_t *words = (void*)data;
uint32_t x32 = 314159265;
uint32_t cycles_begin, cycles_end;
uint32_t instns_begin, instns_end;
__asm__ volatile ("rdcycle %0" : "=r"(cycles_begin));
__asm__ volatile ("rdinstret %0" : "=r"(instns_begin));
for (int i = 0; i < 20; i++)
{
for (int k = 0; k < 256; k++)
{
x32 ^= x32 << 13;
x32 ^= x32 >> 17;
x32 ^= x32 << 5;
data[k] = x32;
}
for (int k = 0, p = 0; k < 256; k++)
{
if (data[k])
data[p++] = k;
}
for (int k = 0, p = 0; k < 64; k++)
{
x32 = x32 ^ words[k];
}
}
__asm__ volatile ("rdcycle %0" : "=r"(cycles_end));
__asm__ volatile ("rdinstret %0" : "=r"(instns_end));
if (verbose)
{
print("Cycles: 0x");
print_hex(cycles_end - cycles_begin, 8);
putchar('\n');
print("Instns: 0x");
print_hex(instns_end - instns_begin, 8);
putchar('\n');
print("Chksum: 0x");
print_hex(x32, 8);
putchar('\n');
}
if (instns_p)
*instns_p = instns_end - instns_begin;
return cycles_end - cycles_begin;
}
// --------------------------------------------------------
#ifdef HX8KDEMO
void cmd_benchmark_all()
{
uint32_t instns = 0;
print("default ");
reg_spictrl = (reg_spictrl & ~0x00700000) | 0x00000000;
print(": ");
print_hex(cmd_benchmark(false, &instns), 8);
putchar('\n');
for (int i = 8; i > 0; i--)
{
print("dspi-");
print_dec(i);
print(" ");
set_flash_latency(i);
reg_spictrl = (reg_spictrl & ~0x00700000) | 0x00400000;
print(": ");
print_hex(cmd_benchmark(false, &instns), 8);
putchar('\n');
}
for (int i = 8; i > 0; i--)
{
print("dspi-crm-");
print_dec(i);
print(" ");
set_flash_latency(i);
reg_spictrl = (reg_spictrl & ~0x00700000) | 0x00500000;
print(": ");
print_hex(cmd_benchmark(false, &instns), 8);
putchar('\n');
}
for (int i = 8; i > 0; i--)
{
print("qspi-");
print_dec(i);
print(" ");
set_flash_latency(i);
reg_spictrl = (reg_spictrl & ~0x00700000) | 0x00200000;
print(": ");
print_hex(cmd_benchmark(false, &instns), 8);
putchar('\n');
}
for (int i = 8; i > 0; i--)
{
print("qspi-crm-");
print_dec(i);
print(" ");
set_flash_latency(i);
reg_spictrl = (reg_spictrl & ~0x00700000) | 0x00300000;
print(": ");
print_hex(cmd_benchmark(false, &instns), 8);
putchar('\n');
}
for (int i = 8; i > 0; i--)
{
print("qspi-ddr-");
print_dec(i);
print(" ");
set_flash_latency(i);
reg_spictrl = (reg_spictrl & ~0x00700000) | 0x00600000;
print(": ");
print_hex(cmd_benchmark(false, &instns), 8);
putchar('\n');
}
for (int i = 8; i > 0; i--)
{
print("qspi-ddr-crm-");
print_dec(i);
print(" ");
set_flash_latency(i);
reg_spictrl = (reg_spictrl & ~0x00700000) | 0x00700000;
print(": ");
print_hex(cmd_benchmark(false, &instns), 8);
putchar('\n');
}
print("instns : ");
print_hex(instns, 8);
putchar('\n');
}
#endif
#ifdef ICEBREAKER
void cmd_benchmark_all()
{
uint32_t instns = 0;
print("default ");
set_flash_mode_spi();
print_hex(cmd_benchmark(false, &instns), 8);
putchar('\n');
print("dual ");
set_flash_mode_dual();
print_hex(cmd_benchmark(false, &instns), 8);
putchar('\n');
// print("dual-crm ");
// enable_flash_crm();
// print_hex(cmd_benchmark(false, &instns), 8);
// putchar('\n');
print("quad ");
set_flash_mode_quad();
print_hex(cmd_benchmark(false, &instns), 8);
putchar('\n');
print("quad-crm ");
enable_flash_crm();
print_hex(cmd_benchmark(false, &instns), 8);
putchar('\n');
print("qddr ");
set_flash_mode_qddr();
print_hex(cmd_benchmark(false, &instns), 8);
putchar('\n');
print("qddr-crm ");
enable_flash_crm();
print_hex(cmd_benchmark(false, &instns), 8);
putchar('\n');
}
#endif
void cmd_echo()
{
print("Return to menu by sending '!'\n\n");
char c;
while ((c = getchar()) != '!')
putchar(c);
}
// --------------------------------------------------------
void main()
{
reg_leds = 31;
reg_uart_clkdiv = 104;
print("Booting..\n");
reg_leds = 63;
set_flash_qspi_flag();
reg_leds = 127;
while (getchar_prompt("Press ENTER to continue..\n") != '\r') { /* wait */ }
print("\n");
print(" ____ _ ____ ____\n");
print(" | _ \\(_) ___ ___/ ___| ___ / ___|\n");
print(" | |_) | |/ __/ _ \\___ \\ / _ \\| |\n");
print(" | __/| | (_| (_) |__) | (_) | |___\n");
print(" |_| |_|\\___\\___/____/ \\___/ \\____|\n");
print("\n");
print("Total memory: ");
print_dec(MEM_TOTAL / 1024);
print(" KiB\n");
print("\n");
//cmd_memtest(); // test overwrites bss and data memory
print("\n");
cmd_print_spi_state();
print("\n");
while (1)
{
print("\n");
print("Select an action:\n");
print("\n");
print(" [1] Read SPI Flash ID\n");
print(" [2] Read SPI Config Regs\n");
print(" [3] Switch to default mode\n");
print(" [4] Switch to Dual I/O mode\n");
print(" [5] Switch to Quad I/O mode\n");
print(" [6] Switch to Quad DDR mode\n");
print(" [7] Toggle continuous read mode\n");
print(" [9] Run simplistic benchmark\n");
print(" [0] Benchmark all configs\n");
print(" [M] Run Memtest\n");
print(" [S] Print SPI state\n");
print(" [e] Echo UART\n");
print("\n");
for (int rep = 10; rep > 0; rep--)
{
print("Command> ");
char cmd = getchar();
if (cmd > 32 && cmd < 127)
putchar(cmd);
print("\n");
switch (cmd)
{
case '1':
cmd_read_flash_id();
break;
case '2':
cmd_read_flash_regs();
break;
case '3':
set_flash_mode_spi();
break;
case '4':
set_flash_mode_dual();
break;
case '5':
set_flash_mode_quad();
break;
case '6':
set_flash_mode_qddr();
break;
case '7':
reg_spictrl = reg_spictrl ^ 0x00100000;
break;
case '9':
cmd_benchmark(true, 0);
break;
case '0':
cmd_benchmark_all();
break;
case 'M':
cmd_memtest();
break;
case 'S':
cmd_print_spi_state();
break;
case 'e':
cmd_echo();
break;
default:
continue;
}
break;
}
}
}

View File

@ -0,0 +1,35 @@
CAPI=2:
name : ::hx8kdemo:0
filesets:
hx8kdemo:
files: [hx8kdemo.v]
file_type : verilogSource
depend : [picosoc]
hx8ksim:
files:
- hx8kdemo_tb.v
file_type : verilogSource
depend : [spiflash, "yosys:techlibs:ice40"]
constraints:
files: [hx8kdemo.pcf]
file_type : PCF
targets:
synth:
default_tool : icestorm
filesets : [constraints, hx8kdemo]
tools:
icestorm:
arachne_pnr_options : [-d, 8k]
toplevel : [hx8kdemo]
sim:
default_tool : icarus
filesets : [hx8kdemo, hx8ksim]
tools:
xsim:
xelab_options : [--timescale, 1ns/1ps]
toplevel : [testbench]

View File

@ -0,0 +1,40 @@
# Pinout for the iCE40-HX8K Breakout Board
set_io clk J3
set_io flash_csb R12
set_io flash_clk R11
set_io flash_io0 P12
set_io flash_io1 P11
# for QSPI mode the flash chip on the iCE40-HX8K Breakout Board
# must be replaced with one that supports QSPI and the IO2 and IO3
# pins must be soldered to T9 and P8 (center on J3)
set_io flash_io2 T9
set_io flash_io3 P8
set_io ser_tx B12
set_io ser_rx B10
# left on J3
set_io debug_ser_tx T1
set_io debug_ser_rx R3
# right on J3
set_io debug_flash_csb T15
set_io debug_flash_clk R16
set_io debug_flash_io0 N12
set_io debug_flash_io1 P13
set_io debug_flash_io2 T13
set_io debug_flash_io3 T14
set_io leds[7] B5 # D9
set_io leds[6] B4 # D8
set_io leds[5] A2 # D7
set_io leds[4] A1 # D6
set_io leds[3] C5 # D5
set_io leds[2] C4 # D4
set_io leds[1] B3 # D3
set_io leds[0] C3 # D2

View File

@ -0,0 +1,139 @@
/*
* PicoSoC - A simple example SoC using PicoRV32
*
* Copyright (C) 2017 Clifford Wolf <clifford@clifford.at>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
module hx8kdemo (
input clk,
output ser_tx,
input ser_rx,
output [7:0] leds,
output flash_csb,
output flash_clk,
inout flash_io0,
inout flash_io1,
inout flash_io2,
inout flash_io3,
output debug_ser_tx,
output debug_ser_rx,
output debug_flash_csb,
output debug_flash_clk,
output debug_flash_io0,
output debug_flash_io1,
output debug_flash_io2,
output debug_flash_io3
);
reg [5:0] reset_cnt = 0;
wire resetn = &reset_cnt;
always @(posedge clk) begin
reset_cnt <= reset_cnt + !resetn;
end
wire flash_io0_oe, flash_io0_do, flash_io0_di;
wire flash_io1_oe, flash_io1_do, flash_io1_di;
wire flash_io2_oe, flash_io2_do, flash_io2_di;
wire flash_io3_oe, flash_io3_do, flash_io3_di;
SB_IO #(
.PIN_TYPE(6'b 1010_01),
.PULLUP(1'b 0)
) flash_io_buf [3:0] (
.PACKAGE_PIN({flash_io3, flash_io2, flash_io1, flash_io0}),
.OUTPUT_ENABLE({flash_io3_oe, flash_io2_oe, flash_io1_oe, flash_io0_oe}),
.D_OUT_0({flash_io3_do, flash_io2_do, flash_io1_do, flash_io0_do}),
.D_IN_0({flash_io3_di, flash_io2_di, flash_io1_di, flash_io0_di})
);
wire iomem_valid;
reg iomem_ready;
wire [3:0] iomem_wstrb;
wire [31:0] iomem_addr;
wire [31:0] iomem_wdata;
reg [31:0] iomem_rdata;
reg [31:0] gpio;
assign leds = gpio;
always @(posedge clk) begin
if (!resetn) begin
gpio <= 0;
end else begin
iomem_ready <= 0;
if (iomem_valid && !iomem_ready && iomem_addr[31:24] == 8'h 03) begin
iomem_ready <= 1;
iomem_rdata <= gpio;
if (iomem_wstrb[0]) gpio[ 7: 0] <= iomem_wdata[ 7: 0];
if (iomem_wstrb[1]) gpio[15: 8] <= iomem_wdata[15: 8];
if (iomem_wstrb[2]) gpio[23:16] <= iomem_wdata[23:16];
if (iomem_wstrb[3]) gpio[31:24] <= iomem_wdata[31:24];
end
end
end
picosoc soc (
.clk (clk ),
.resetn (resetn ),
.ser_tx (ser_tx ),
.ser_rx (ser_rx ),
.flash_csb (flash_csb ),
.flash_clk (flash_clk ),
.flash_io0_oe (flash_io0_oe),
.flash_io1_oe (flash_io1_oe),
.flash_io2_oe (flash_io2_oe),
.flash_io3_oe (flash_io3_oe),
.flash_io0_do (flash_io0_do),
.flash_io1_do (flash_io1_do),
.flash_io2_do (flash_io2_do),
.flash_io3_do (flash_io3_do),
.flash_io0_di (flash_io0_di),
.flash_io1_di (flash_io1_di),
.flash_io2_di (flash_io2_di),
.flash_io3_di (flash_io3_di),
.irq_5 (1'b0 ),
.irq_6 (1'b0 ),
.irq_7 (1'b0 ),
.iomem_valid (iomem_valid ),
.iomem_ready (iomem_ready ),
.iomem_wstrb (iomem_wstrb ),
.iomem_addr (iomem_addr ),
.iomem_wdata (iomem_wdata ),
.iomem_rdata (iomem_rdata )
);
assign debug_ser_tx = ser_tx;
assign debug_ser_rx = ser_rx;
assign debug_flash_csb = flash_csb;
assign debug_flash_clk = flash_clk;
assign debug_flash_io0 = flash_io0_di;
assign debug_flash_io1 = flash_io1_di;
assign debug_flash_io2 = flash_io2_di;
assign debug_flash_io3 = flash_io3_di;
endmodule

View File

@ -0,0 +1,108 @@
/*
* PicoSoC - A simple example SoC using PicoRV32
*
* Copyright (C) 2017 Clifford Wolf <clifford@clifford.at>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
`timescale 1 ns / 1 ps
module testbench;
reg clk;
always #5 clk = (clk === 1'b0);
localparam ser_half_period = 53;
event ser_sample;
initial begin
$dumpfile("testbench.vcd");
$dumpvars(0, testbench);
repeat (6) begin
repeat (50000) @(posedge clk);
$display("+50000 cycles");
end
$finish;
end
integer cycle_cnt = 0;
always @(posedge clk) begin
cycle_cnt <= cycle_cnt + 1;
end
wire [7:0] leds;
wire ser_rx;
wire ser_tx;
wire flash_csb;
wire flash_clk;
wire flash_io0;
wire flash_io1;
wire flash_io2;
wire flash_io3;
always @(leds) begin
#1 $display("%b", leds);
end
hx8kdemo uut (
.clk (clk ),
.leds (leds ),
.ser_rx (ser_rx ),
.ser_tx (ser_tx ),
.flash_csb(flash_csb),
.flash_clk(flash_clk),
.flash_io0(flash_io0),
.flash_io1(flash_io1),
.flash_io2(flash_io2),
.flash_io3(flash_io3)
);
spiflash spiflash (
.csb(flash_csb),
.clk(flash_clk),
.io0(flash_io0),
.io1(flash_io1),
.io2(flash_io2),
.io3(flash_io3)
);
reg [7:0] buffer;
always begin
@(negedge ser_tx);
repeat (ser_half_period) @(posedge clk);
-> ser_sample; // start bit
repeat (8) begin
repeat (ser_half_period) @(posedge clk);
repeat (ser_half_period) @(posedge clk);
buffer = {ser_tx, buffer[7:1]};
-> ser_sample; // data bit
end
repeat (ser_half_period) @(posedge clk);
repeat (ser_half_period) @(posedge clk);
-> ser_sample; // stop bit
if (buffer < 32 || buffer >= 127)
$display("Serial data: %d", buffer);
else
$display("Serial data: '%c'", buffer);
end
endmodule

View File

@ -0,0 +1,91 @@
/*
* PicoSoC - A simple example SoC using PicoRV32
*
* Copyright (C) 2017 Clifford Wolf <clifford@clifford.at>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
module ice40up5k_spram #(
// We current always use the whole SPRAM (128 kB)
parameter integer WORDS = 32768
) (
input clk,
input [3:0] wen,
input [21:0] addr,
input [31:0] wdata,
output [31:0] rdata
);
wire cs_0, cs_1;
wire [31:0] rdata_0, rdata_1;
assign cs_0 = !addr[14];
assign cs_1 = addr[14];
assign rdata = addr[14] ? rdata_1 : rdata_0;
SB_SPRAM256KA ram00 (
.ADDRESS(addr[13:0]),
.DATAIN(wdata[15:0]),
.MASKWREN({wen[1], wen[1], wen[0], wen[0]}),
.WREN(wen[1]|wen[0]),
.CHIPSELECT(cs_0),
.CLOCK(clk),
.STANDBY(1'b0),
.SLEEP(1'b0),
.POWEROFF(1'b1),
.DATAOUT(rdata_0[15:0])
);
SB_SPRAM256KA ram01 (
.ADDRESS(addr[13:0]),
.DATAIN(wdata[31:16]),
.MASKWREN({wen[3], wen[3], wen[2], wen[2]}),
.WREN(wen[3]|wen[2]),
.CHIPSELECT(cs_0),
.CLOCK(clk),
.STANDBY(1'b0),
.SLEEP(1'b0),
.POWEROFF(1'b1),
.DATAOUT(rdata_0[31:16])
);
SB_SPRAM256KA ram10 (
.ADDRESS(addr[13:0]),
.DATAIN(wdata[15:0]),
.MASKWREN({wen[1], wen[1], wen[0], wen[0]}),
.WREN(wen[1]|wen[0]),
.CHIPSELECT(cs_1),
.CLOCK(clk),
.STANDBY(1'b0),
.SLEEP(1'b0),
.POWEROFF(1'b1),
.DATAOUT(rdata_1[15:0])
);
SB_SPRAM256KA ram11 (
.ADDRESS(addr[13:0]),
.DATAIN(wdata[31:16]),
.MASKWREN({wen[3], wen[3], wen[2], wen[2]}),
.WREN(wen[3]|wen[2]),
.CHIPSELECT(cs_1),
.CLOCK(clk),
.STANDBY(1'b0),
.SLEEP(1'b0),
.POWEROFF(1'b1),
.DATAOUT(rdata_1[31:16])
);
endmodule

View File

@ -0,0 +1,36 @@
CAPI=2:
name : ::icebreaker:0
filesets:
top:
files: [icebreaker.v]
file_type : verilogSource
depend : [picosoc]
tb:
files:
- icebreaker_tb.v
file_type : verilogSource
depend : [spiflash, "yosys:techlibs:ice40"]
constraints:
files: [icebreaker.pcf]
file_type : PCF
targets:
synth:
default_tool : icestorm
filesets : [constraints, top]
tools:
icestorm:
nextpnr_options : [--freq, 13, --up5k]
pnr : next
toplevel : [icebreaker]
sim:
default_tool : icarus
filesets : [top, tb]
tools:
xsim:
xelab_options : [--timescale, 1ns/1ps]
toplevel : [testbench]

View File

@ -0,0 +1,25 @@
# 12 MHz clock
set_io clk 35
# RS232
set_io ser_rx 6
set_io ser_tx 9
# SPI Flash
set_io flash_clk 15
set_io flash_csb 16
set_io flash_io0 14
set_io flash_io1 17
set_io flash_io2 12
set_io flash_io3 13
# LEDs (PMOD 2)
set_io led1 27
set_io led2 25
set_io led3 21
set_io led4 23
set_io led5 26
# Onboard LEDs
set_io ledr_n 11
set_io ledg_n 37

View File

@ -0,0 +1,149 @@
/*
* PicoSoC - A simple example SoC using PicoRV32
*
* Copyright (C) 2017 Clifford Wolf <clifford@clifford.at>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
`ifdef PICOSOC_V
`error "icebreaker.v must be read before picosoc.v!"
`endif
`define PICOSOC_MEM ice40up5k_spram
module icebreaker (
input clk,
output ser_tx,
input ser_rx,
output led1,
output led2,
output led3,
output led4,
output led5,
output ledr_n,
output ledg_n,
output flash_csb,
output flash_clk,
inout flash_io0,
inout flash_io1,
inout flash_io2,
inout flash_io3
);
parameter integer MEM_WORDS = 32768;
reg [5:0] reset_cnt = 0;
wire resetn = &reset_cnt;
always @(posedge clk) begin
reset_cnt <= reset_cnt + !resetn;
end
wire [7:0] leds;
assign led1 = leds[1];
assign led2 = leds[2];
assign led3 = leds[3];
assign led4 = leds[4];
assign led5 = leds[5];
assign ledr_n = !leds[6];
assign ledg_n = !leds[7];
wire flash_io0_oe, flash_io0_do, flash_io0_di;
wire flash_io1_oe, flash_io1_do, flash_io1_di;
wire flash_io2_oe, flash_io2_do, flash_io2_di;
wire flash_io3_oe, flash_io3_do, flash_io3_di;
SB_IO #(
.PIN_TYPE(6'b 1010_01),
.PULLUP(1'b 0)
) flash_io_buf [3:0] (
.PACKAGE_PIN({flash_io3, flash_io2, flash_io1, flash_io0}),
.OUTPUT_ENABLE({flash_io3_oe, flash_io2_oe, flash_io1_oe, flash_io0_oe}),
.D_OUT_0({flash_io3_do, flash_io2_do, flash_io1_do, flash_io0_do}),
.D_IN_0({flash_io3_di, flash_io2_di, flash_io1_di, flash_io0_di})
);
wire iomem_valid;
reg iomem_ready;
wire [3:0] iomem_wstrb;
wire [31:0] iomem_addr;
wire [31:0] iomem_wdata;
reg [31:0] iomem_rdata;
reg [31:0] gpio;
assign leds = gpio;
always @(posedge clk) begin
if (!resetn) begin
gpio <= 0;
end else begin
iomem_ready <= 0;
if (iomem_valid && !iomem_ready && iomem_addr[31:24] == 8'h 03) begin
iomem_ready <= 1;
iomem_rdata <= gpio;
if (iomem_wstrb[0]) gpio[ 7: 0] <= iomem_wdata[ 7: 0];
if (iomem_wstrb[1]) gpio[15: 8] <= iomem_wdata[15: 8];
if (iomem_wstrb[2]) gpio[23:16] <= iomem_wdata[23:16];
if (iomem_wstrb[3]) gpio[31:24] <= iomem_wdata[31:24];
end
end
end
picosoc #(
.BARREL_SHIFTER(0),
.ENABLE_MULDIV(0),
.MEM_WORDS(MEM_WORDS)
) soc (
.clk (clk ),
.resetn (resetn ),
.ser_tx (ser_tx ),
.ser_rx (ser_rx ),
.flash_csb (flash_csb ),
.flash_clk (flash_clk ),
.flash_io0_oe (flash_io0_oe),
.flash_io1_oe (flash_io1_oe),
.flash_io2_oe (flash_io2_oe),
.flash_io3_oe (flash_io3_oe),
.flash_io0_do (flash_io0_do),
.flash_io1_do (flash_io1_do),
.flash_io2_do (flash_io2_do),
.flash_io3_do (flash_io3_do),
.flash_io0_di (flash_io0_di),
.flash_io1_di (flash_io1_di),
.flash_io2_di (flash_io2_di),
.flash_io3_di (flash_io3_di),
.irq_5 (1'b0 ),
.irq_6 (1'b0 ),
.irq_7 (1'b0 ),
.iomem_valid (iomem_valid ),
.iomem_ready (iomem_ready ),
.iomem_wstrb (iomem_wstrb ),
.iomem_addr (iomem_addr ),
.iomem_wdata (iomem_wdata ),
.iomem_rdata (iomem_rdata )
);
endmodule

View File

@ -0,0 +1,122 @@
/*
* PicoSoC - A simple example SoC using PicoRV32
*
* Copyright (C) 2017 Clifford Wolf <clifford@clifford.at>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
`timescale 1 ns / 1 ps
module testbench;
reg clk;
always #5 clk = (clk === 1'b0);
localparam ser_half_period = 53;
event ser_sample;
initial begin
$dumpfile("testbench.vcd");
$dumpvars(0, testbench);
repeat (6) begin
repeat (50000) @(posedge clk);
$display("+50000 cycles");
end
$finish;
end
integer cycle_cnt = 0;
always @(posedge clk) begin
cycle_cnt <= cycle_cnt + 1;
end
wire led1, led2, led3, led4, led5;
wire ledr_n, ledg_n;
wire [6:0] leds = {!ledg_n, !ledr_n, led5, led4, led3, led2, led1};
wire ser_rx;
wire ser_tx;
wire flash_csb;
wire flash_clk;
wire flash_io0;
wire flash_io1;
wire flash_io2;
wire flash_io3;
always @(leds) begin
#1 $display("%b", leds);
end
icebreaker #(
// We limit the amount of memory in simulation
// in order to avoid reduce simulation time
// required for intialization of RAM
.MEM_WORDS(256)
) uut (
.clk (clk ),
.led1 (led1 ),
.led2 (led2 ),
.led3 (led3 ),
.led4 (led4 ),
.led5 (led5 ),
.ledr_n (ledr_n ),
.ledg_n (ledg_n ),
.ser_rx (ser_rx ),
.ser_tx (ser_tx ),
.flash_csb(flash_csb),
.flash_clk(flash_clk),
.flash_io0(flash_io0),
.flash_io1(flash_io1),
.flash_io2(flash_io2),
.flash_io3(flash_io3)
);
spiflash spiflash (
.csb(flash_csb),
.clk(flash_clk),
.io0(flash_io0),
.io1(flash_io1),
.io2(flash_io2),
.io3(flash_io3)
);
reg [7:0] buffer;
always begin
@(negedge ser_tx);
repeat (ser_half_period) @(posedge clk);
-> ser_sample; // start bit
repeat (8) begin
repeat (ser_half_period) @(posedge clk);
repeat (ser_half_period) @(posedge clk);
buffer = {ser_tx, buffer[7:1]};
-> ser_sample; // data bit
end
repeat (ser_half_period) @(posedge clk);
repeat (ser_half_period) @(posedge clk);
-> ser_sample; // stop bit
if (buffer < 32 || buffer >= 127)
$display("Serial data: %d", buffer);
else
$display("Serial data: '%c'", buffer);
end
endmodule

View File

@ -0,0 +1,757 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="752.71472"
height="512"
viewBox="0 0 752.71472 512"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
sodipodi:docname="overview.svg">
<defs
id="defs4" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1.4"
inkscape:cx="323.81769"
inkscape:cy="196.47245"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="true"
units="px"
fit-margin-top="10"
fit-margin-right="10"
fit-margin-bottom="10"
fit-margin-left="10"
inkscape:window-width="1855"
inkscape:window-height="1056"
inkscape:window-x="65"
inkscape:window-y="24"
inkscape:window-maximized="1">
<inkscape:grid
type="xygrid"
id="grid3336"
originx="184.53606"
originy="-656.49999" />
</sodipodi:namedview>
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(184.53606,116.13779)">
<rect
style="opacity:1;fill:#b3b3d0;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.93901455;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect3338"
width="601.48956"
height="490.06097"
x="-62.083782"
y="-105.16828" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:80px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="-45.2868"
y="-60.797707"
id="text3340"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan3342"
x="-45.2868"
y="-60.797707"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:37.5px;font-family:'Arial Black';-inkscape-font-specification:'Arial Black, '">Your Chip</tspan></text>
<rect
style="opacity:1;fill:#b3e1b3;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect3344"
width="270"
height="390"
x="-32.053295"
y="-35.137794" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:80px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="-22.429668"
y="-1.2263393"
id="text3340-0"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan3342-9"
x="-22.429668"
y="-1.2263393"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:25px;font-family:'Arial Black';-inkscape-font-specification:'Arial Black, '">PicoSoC</tspan></text>
<rect
style="opacity:1;fill:#d9883a;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect3364"
width="110"
height="90"
x="-22.053295"
y="24.862207" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:80px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="35.3167"
y="56.630821"
id="text3340-0-7"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
x="35.3167"
y="56.630821"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:15px;font-family:'Arial Black';-inkscape-font-specification:'Arial Black, ';text-align:center;text-anchor:middle"
id="tspan3384">XIP SPI</tspan><tspan
sodipodi:role="line"
x="35.3167"
y="75.380821"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:15px;font-family:'Arial Black';-inkscape-font-specification:'Arial Black, ';text-align:center;text-anchor:middle"
id="tspan3390">Flash</tspan><tspan
sodipodi:role="line"
x="35.3167"
y="94.130821"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:15px;font-family:'Arial Black';-inkscape-font-specification:'Arial Black, ';text-align:center;text-anchor:middle"
id="tspan3392">Controller</tspan><tspan
sodipodi:role="line"
x="35.3167"
y="112.88082"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:15px;font-family:'Arial Black';-inkscape-font-specification:'Arial Black, ';text-align:center;text-anchor:middle"
id="tspan3386" /></text>
<rect
style="opacity:1;fill:#d9883a;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.64055121;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect3394"
width="110.35945"
height="60.359447"
x="-22.233013"
y="124.68247" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:80px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="34.602421"
y="160.34511"
id="text3340-0-7-9"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
x="34.602421"
y="160.34511"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:15px;font-family:'Arial Black';-inkscape-font-specification:'Arial Black, ';text-align:center;text-anchor:middle"
id="tspan3386-2">UART</tspan></text>
<rect
style="opacity:1;fill:#d9883a;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect3432"
width="110"
height="150"
x="-22.053295"
y="194.8622" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:80px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="33.459568"
y="261.91653"
id="text3340-0-7-9-6"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
x="33.459568"
y="261.91653"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:15px;font-family:'Arial Black';-inkscape-font-specification:'Arial Black, ';text-align:center;text-anchor:middle"
id="tspan3386-2-6">SRAM</tspan><tspan
sodipodi:role="line"
x="33.459568"
y="280.66653"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:15px;font-family:'Arial Black';-inkscape-font-specification:'Arial Black, ';text-align:center;text-anchor:middle"
id="tspan3452" /><tspan
sodipodi:role="line"
x="33.459568"
y="294.5386"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10px;font-family:'Arial Black';-inkscape-font-specification:'Arial Black, ';text-align:center;text-anchor:middle"
id="tspan3454">(default 1kB)</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:80px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="165.82141"
y="38.508293"
id="text3340-0-7-5"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
x="165.82141"
y="38.508293"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10px;font-family:'Arial Black';-inkscape-font-specification:'Arial Black, ';text-align:center;text-anchor:middle"
id="tspan3494">32 Bit System Bus</tspan></text>
<rect
style="opacity:1;fill:#d9883a;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:2.19784403;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect3496"
width="119.80215"
height="290.30978"
x="108.04526"
y="55.060112" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:80px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="156.32541"
y="79.02784"
id="text3340-0-7-9-1"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
x="156.32541"
y="79.02784"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:15px;font-family:'Arial Black';-inkscape-font-specification:'Arial Black, ';text-align:center;text-anchor:middle"
id="tspan3386-2-9">PicoRV32</tspan></text>
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 87.946684,264.8622 10,0 0,-219.999994 149.999996,0"
id="path3518"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 87.946684,154.8622 10,0"
id="path3520"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 87.946684,64.862196 10,0"
id="path3522"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 167.94668,44.862206 0,9.41744 0,0"
id="path3524"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m -22.053466,144.8622 -60,0"
id="path3526"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m -22.053466,164.8622 -60,0"
id="path3528"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m -22.053466,34.862206 -60,0"
id="path3530"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m -22.053466,54.862206 -60,0"
id="path3532"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m -22.053466,74.862196 -60,0"
id="path3534"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m -22.053466,84.862196 -60,0"
id="path3536"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m -22.053466,94.862196 -60,0"
id="path3538"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m -22.053466,104.8622 -60,0"
id="path3540"
inkscape:connector-curvature="0" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:80px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="-150.03317"
y="38.357124"
id="text4342"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4344"
x="-150.03317"
y="38.357124"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10px;font-family:'Arial Black';-inkscape-font-specification:'Arial Black, '">FLASH_SCK</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:80px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="-150.03317"
y="58.357109"
id="text4342-0"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4344-2"
x="-150.03317"
y="58.357109"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10px;font-family:'Arial Black';-inkscape-font-specification:'Arial Black, '">FLASH_CSB</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:80px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="-150.03317"
y="78.357109"
id="text4342-9"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4344-6"
x="-150.03317"
y="78.357109"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10px;font-family:'Arial Black';-inkscape-font-specification:'Arial Black, '">FLASH_IO0</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:80px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="-150.03317"
y="87.857079"
id="text4342-5"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4344-4"
x="-150.03317"
y="87.857079"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10px;font-family:'Arial Black';-inkscape-font-specification:'Arial Black, '">FLASH_IO1</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:80px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="-150.03317"
y="98.357109"
id="text4342-3"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4344-7"
x="-150.03317"
y="98.357109"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10px;font-family:'Arial Black';-inkscape-font-specification:'Arial Black, '">FLASH_IO2</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:80px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="-150.03317"
y="107.85708"
id="text4342-05"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4344-0"
x="-150.03317"
y="107.85708"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10px;font-family:'Arial Black';-inkscape-font-specification:'Arial Black, '">FLASH_IO3</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:80px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="-148.6046"
y="148.14287"
id="text4342-7"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4344-28"
x="-148.6046"
y="148.14287"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10px;font-family:'Arial Black';-inkscape-font-specification:'Arial Black, '">SERIAL_TX</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:80px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="-148.46175"
y="168.14287"
id="text4342-7-4"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4344-28-2"
x="-148.46175"
y="168.14287"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10px;font-family:'Arial Black';-inkscape-font-specification:'Arial Black, '">SERIAL_RX</tspan></text>
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m -81.821316,364.8622 349.999996,0 0,-10"
id="path4432"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m -81.821316,374.8622 359.999996,0 0,-20"
id="path4434"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m -21.821316,354.8622 0,10 0,0"
id="path4436"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m -11.821316,354.8622 0,20"
id="path4438"
inkscape:connector-curvature="0" />
<rect
style="opacity:1;fill:#c7ca58;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.96552444;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect3344-5"
width="260.74875"
height="390.03448"
x="248.3298"
y="-34.998299" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:80px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="259.57034"
y="-1.2263241"
id="text3340-0-73"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan3342-9-8"
x="259.57034"
y="-1.2263241"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:25px;font-family:'Arial Black';-inkscape-font-specification:'Arial Black, '">Your Circuit</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:80px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="-174.88274"
y="368.80356"
id="text4342-9-9"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4344-6-1"
x="-174.88274"
y="368.80356"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10px;font-family:'Arial Black';-inkscape-font-specification:'Arial Black, '">SYSTEM_CLOCK</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:80px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="-174.88274"
y="378.30356"
id="text4342-5-1"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4344-4-9"
x="-174.88274"
y="378.30356"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10px;font-family:'Arial Black';-inkscape-font-specification:'Arial Black, '">SYSTEM_RESET</tspan></text>
<rect
style="opacity:1;fill:#d46785;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.95069826;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4497"
width="218.62073"
height="60.049301"
x="278.15402"
y="24.837549" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 248.17868,44.862206 30,0"
id="path4499"
inkscape:connector-curvature="0" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:80px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans';text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="288.32541"
y="47.02784"
id="text3340-0-7-9-1-9"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
x="288.32541"
y="47.02784"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:15px;font-family:'Arial Black';-inkscape-font-specification:'Arial Black, ';text-align:start;text-anchor:start"
id="tspan3386-2-9-7">GPIO Controller</tspan></text>
<rect
style="opacity:1;fill:#d46785;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4519"
width="220"
height="120"
x="278.17868"
y="104.86222" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:80px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans';text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="290.32541"
y="127.02784"
id="text3340-0-7-9-1-9-0"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
x="290.32541"
y="127.02784"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:15px;font-family:'Arial Black';-inkscape-font-specification:'Arial Black, ';text-align:start;text-anchor:start"
id="tspan3386-2-9-7-9">Custom Block</tspan></text>
<rect
style="opacity:1;fill:#d46785;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4539"
width="220"
height="100"
x="278.17868"
y="244.8622" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:80px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans';text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="290.32541"
y="267.02783"
id="text3340-0-7-9-1-9-0-6"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
x="290.32541"
y="267.02783"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:15px;font-family:'Arial Black';-inkscape-font-specification:'Arial Black, ';text-align:start;text-anchor:start"
id="tspan3386-2-9-7-9-6">Custom Block</tspan></text>
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 258.17868,44.862206 0,219.999994 20,0"
id="path4559"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 298.17868,84.862196 0,20.000004"
id="path4561"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 308.17868,84.862196 0,20.000004"
id="path4563"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 318.17868,84.862196 0,20.000004"
id="path4565"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 328.17868,84.862196 0,20.000004"
id="path4567"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 338.17868,84.862196 0,20.000004"
id="path4569"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 348.17868,84.862196 0,20.000004"
id="path4571"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 358.17868,84.862196 0,20.000004"
id="path4573"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 368.17868,84.862196 0,20.000004"
id="path4575"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 378.17868,84.862196 0,20.000004"
id="path4577"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 388.17868,84.862196 0,20.000004"
id="path4579"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 398.17868,84.862196 0,20.000004"
id="path4581"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 408.17868,84.862196 0,20.000004"
id="path4583"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 418.17868,84.862196 0,20.000004"
id="path4585"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 428.17868,84.862196 0,20.000004"
id="path4587"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 438.17868,84.862196 0,20.000004"
id="path4589"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 448.17868,84.862196 0,20.000004"
id="path4591"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 458.17868,84.862196 0,20.000004"
id="path4593"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 468.17868,84.862196 0,20.000004"
id="path4595"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 478.17868,84.862196 0,20.000004"
id="path4597"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 488.17868,84.862196 0,20.000004"
id="path4599"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 498.17868,114.8622 60,0"
id="path4601"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 498.17868,124.8622 60,0"
id="path4603"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 498.17868,134.8622 60,0"
id="path4605"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 498.17868,144.8622 60,0"
id="path4607"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 498.17868,254.8622 60,0"
id="path4609"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 498.17868,264.8622 60,0"
id="path4611"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 498.17868,274.8622 60,0"
id="path4613"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 498.17868,284.8622 60,0"
id="path4615"
inkscape:connector-curvature="0" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:80px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="124.32541"
y="111.02784"
id="text3340-0-7-9-1-2"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
x="124.32541"
y="111.02784"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10px;font-family:'Arial Black';-inkscape-font-specification:'Arial Black, ';text-align:start;text-anchor:start"
id="tspan3386-2-9-8">- RISC-V ISA</tspan><tspan
sodipodi:role="line"
x="124.32541"
y="123.52784"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10px;font-family:'Arial Black';-inkscape-font-specification:'Arial Black, ';text-align:start;text-anchor:start"
id="tspan4637">- RV32IMC</tspan><tspan
sodipodi:role="line"
x="124.32541"
y="136.02783"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10px;font-family:'Arial Black';-inkscape-font-specification:'Arial Black, ';text-align:start;text-anchor:start"
id="tspan4639">- GNU Toolchain</tspan></text>
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 498.17868,154.85204 60,0"
id="path4601-3"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 498.17868,164.85204 60,0"
id="path4603-6"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 498.17868,174.85204 60,0"
id="path4605-7"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 498.17868,184.85204 60,0"
id="path4607-5"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 498.17868,194.60966 60,0"
id="path4601-3-3"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 498.17868,204.60966 60,0"
id="path4603-6-5"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 498.17868,214.60966 60,0"
id="path4605-7-6"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 498.07153,294.75505 60,0"
id="path4607-9"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 498.07153,304.74489 60,0"
id="path4601-3-1"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 498.07153,314.74489 60,0"
id="path4603-6-2"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 498.07153,324.74489 60,0"
id="path4605-7-7"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 498.07153,334.74489 60,0"
id="path4607-5-0"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 497.71438,29.85204 60,0"
id="path4603-6-7"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 497.71438,39.85204 60,0"
id="path4605-7-9"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 497.71438,49.85204 60,0"
id="path4607-5-2"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 497.71438,59.60966 60,0"
id="path4601-3-3-0"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 497.71438,69.60966 60,0"
id="path4603-6-5-2"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 497.71438,79.60966 60,0"
id="path4605-7-6-3"
inkscape:connector-curvature="0" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

View File

@ -0,0 +1,165 @@
#!/usr/bin/env python3
import matplotlib.pyplot as plt
import numpy as np
uncompr_text = """
default : 010f52ef
dspi-8 : 008dc82f
dspi-7 : 008d6d63
dspi-6 : 008d1297
dspi-5 : 008cb7cb
dspi-4 : 008c5cff
dspi-3 : 008c0233
dspi-2 : 008ba767
dspi-1 : 008b4c9b
dspi-crm-8 : 008af1cf
dspi-crm-7 : 008a9703
dspi-crm-6 : 008a3c37
dspi-crm-5 : 0089e16b
dspi-crm-4 : 0089869f
dspi-crm-3 : 00892bd3
dspi-crm-2 : 0088d107
dspi-crm-1 : 0088763b
qspi-8 : 004a2c6f
qspi-7 : 0049d1a3
qspi-6 : 004976d7
qspi-5 : 00491c0b
qspi-4 : 0048c13f
qspi-3 : 00486673
qspi-2 : 00480ba7
qspi-1 : 0047b0db
qspi-crm-8 : 0047560f
qspi-crm-7 : 0046fb43
qspi-crm-6 : 0046a077
qspi-crm-5 : 004645ab
qspi-crm-4 : 0045eadf
qspi-crm-3 : 00459013
qspi-crm-2 : 00453547
qspi-crm-1 : 0044da7b
qspi-ddr-8 : 00288bf5
qspi-ddr-7 : 00283129
qspi-ddr-6 : 0027d65d
qspi-ddr-5 : 00277b91
qspi-ddr-4 : 002720c5
qspi-ddr-3 : 0026c5f9
qspi-ddr-2 : 00266b2d
qspi-ddr-1 : 00261061
qspi-ddr-crm-8 : 0025b595
qspi-ddr-crm-7 : 00255ac9
qspi-ddr-crm-6 : 0024fffd
qspi-ddr-crm-5 : 0024a531
qspi-ddr-crm-4 : 00244a65
qspi-ddr-crm-3 : 0023ef99
qspi-ddr-crm-2 : 002394cd
qspi-ddr-crm-1 : 00233a01
instns : 0003df2d
"""
compr_text = """
default : 00f3d36d
dspi-8 : 008008ad
dspi-7 : 007fade1
dspi-6 : 007f5315
dspi-5 : 007ef849
dspi-4 : 007e9d7d
dspi-3 : 007e42b1
dspi-2 : 007de7e5
dspi-1 : 007d8d19
dspi-crm-8 : 007d324d
dspi-crm-7 : 007cd781
dspi-crm-6 : 007c7cb5
dspi-crm-5 : 007c21e9
dspi-crm-4 : 007bc71d
dspi-crm-3 : 007b6c51
dspi-crm-2 : 007b1185
dspi-crm-1 : 007ab6b9
qspi-8 : 00434ced
qspi-7 : 0042f221
qspi-6 : 00429755
qspi-5 : 00423c89
qspi-4 : 0041e1bd
qspi-3 : 004186f1
qspi-2 : 00412c25
qspi-1 : 0040d159
qspi-crm-8 : 0040768d
qspi-crm-7 : 00401bc1
qspi-crm-6 : 003fc0f5
qspi-crm-5 : 003f6629
qspi-crm-4 : 003f0b5d
qspi-crm-3 : 003eb091
qspi-crm-2 : 003e55c5
qspi-crm-1 : 003dfaf9
qspi-ddr-8 : 00255d87
qspi-ddr-7 : 002502bb
qspi-ddr-6 : 0024a7ef
qspi-ddr-5 : 00244d23
qspi-ddr-4 : 0023f257
qspi-ddr-3 : 0023978b
qspi-ddr-2 : 00233cbf
qspi-ddr-1 : 0022e1f3
qspi-ddr-crm-8 : 00228727
qspi-ddr-crm-7 : 00222c5b
qspi-ddr-crm-6 : 0021d18f
qspi-ddr-crm-5 : 002176c3
qspi-ddr-crm-4 : 00211bf7
qspi-ddr-crm-3 : 0020c12b
qspi-ddr-crm-2 : 0020665f
qspi-ddr-crm-1 : 00200b93
instns : 0003df2d
"""
labels = list()
uncompr_values = list()
compr_values = list()
for line in uncompr_text.split("\n"):
if line != "":
line = line.split()
if line[0] == "instns":
for i in range(len(uncompr_values)):
uncompr_values[i] = int(line[2], 16) / uncompr_values[i]
else:
labels.append(line[0])
uncompr_values.append(int(line[2], 16))
for line in compr_text.split("\n"):
if line != "":
line = line.split()
if line[0] == "instns":
for i in range(len(compr_values)):
compr_values[i] = int(line[2], 16) / compr_values[i]
else:
compr_values.append(int(line[2], 16))
print(np.array(compr_values) / np.array(uncompr_values))
values = list()
for i in range(len(compr_values)):
values.append(uncompr_values[i] / uncompr_values[0])
# values.append(compr_values[i] / compr_values[0])
values = np.array(values)
print(values)
plt.figure(figsize=(10, 5))
plt.title("Performance comparison for different PicoSoC SPI flash configurations")
plt.plot(range(len(labels)), values)
plt.xticks(range(len(labels)), labels, rotation=80)
for color, x1, x2 in [["black", 0, 0], ["red", 1, 8], ["green", 9, 16],
["red", 17, 24], ["green", 25, 32], ["red", 33, 40], ["green", 41, 48]]:
for t in plt.axes().xaxis.get_ticklabels()[x1:x2+1]:
t.set_color(color)
plt.plot([x1, x1], [0, values[x1] - 0.2], color=color)
plt.plot([x2, x2], [0, values[x2] - 0.2], color=color)
plt.plot([x1], [values[x1]], "k.")
plt.plot([x2], [values[x2]], "k.")
plt.xlim(-1, len(labels))
plt.ylim(0, 9)
plt.grid()
plt.gcf().subplots_adjust(bottom=0.3)
plt.savefig("performance.png")
# plt.show()

View File

@ -0,0 +1,27 @@
CAPI=2:
name : ::picosoc:0
filesets:
picosoc:
files:
- simpleuart.v
- spimemio.v
- picosoc.v
file_type : verilogSource
depend : [picorv32]
targets:
default:
filesets : [picosoc]
parameters : [PICORV32_REGS, PICOSOC_MEM]
parameters:
PICORV32_REGS:
datatype : str
default : picosoc_regs
paramtype : vlogdefine
PICOSOC_MEM:
datatype : str
default : picosoc_mem
paramtype : vlogdefine

View File

@ -0,0 +1,259 @@
/*
* PicoSoC - A simple example SoC using PicoRV32
*
* Copyright (C) 2017 Clifford Wolf <clifford@clifford.at>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
`ifndef PICORV32_REGS
`ifdef PICORV32_V
`error "picosoc.v must be read before picorv32.v!"
`endif
`define PICORV32_REGS picosoc_regs
`endif
`ifndef PICOSOC_MEM
`define PICOSOC_MEM picosoc_mem
`endif
// this macro can be used to check if the verilog files in your
// design are read in the correct order.
`define PICOSOC_V
module picosoc (
input clk,
input resetn,
output iomem_valid,
input iomem_ready,
output [ 3:0] iomem_wstrb,
output [31:0] iomem_addr,
output [31:0] iomem_wdata,
input [31:0] iomem_rdata,
input irq_5,
input irq_6,
input irq_7,
output ser_tx,
input ser_rx,
output flash_csb,
output flash_clk,
output flash_io0_oe,
output flash_io1_oe,
output flash_io2_oe,
output flash_io3_oe,
output flash_io0_do,
output flash_io1_do,
output flash_io2_do,
output flash_io3_do,
input flash_io0_di,
input flash_io1_di,
input flash_io2_di,
input flash_io3_di
);
parameter [0:0] BARREL_SHIFTER = 1;
parameter [0:0] ENABLE_MULDIV = 1;
parameter [0:0] ENABLE_COMPRESSED = 1;
parameter [0:0] ENABLE_COUNTERS = 1;
parameter [0:0] ENABLE_IRQ_QREGS = 0;
parameter integer MEM_WORDS = 256;
parameter [31:0] STACKADDR = (4*MEM_WORDS); // end of memory
parameter [31:0] PROGADDR_RESET = 32'h 0010_0000; // 1 MB into flash
parameter [31:0] PROGADDR_IRQ = 32'h 0000_0000;
reg [31:0] irq;
wire irq_stall = 0;
wire irq_uart = 0;
always @* begin
irq = 0;
irq[3] = irq_stall;
irq[4] = irq_uart;
irq[5] = irq_5;
irq[6] = irq_6;
irq[7] = irq_7;
end
wire mem_valid;
wire mem_instr;
wire mem_ready;
wire [31:0] mem_addr;
wire [31:0] mem_wdata;
wire [3:0] mem_wstrb;
wire [31:0] mem_rdata;
wire spimem_ready;
wire [31:0] spimem_rdata;
reg ram_ready;
wire [31:0] ram_rdata;
assign iomem_valid = mem_valid && (mem_addr[31:24] > 8'h 01);
assign iomem_wstrb = mem_wstrb;
assign iomem_addr = mem_addr;
assign iomem_wdata = mem_wdata;
wire spimemio_cfgreg_sel = mem_valid && (mem_addr == 32'h 0200_0000);
wire [31:0] spimemio_cfgreg_do;
wire simpleuart_reg_div_sel = mem_valid && (mem_addr == 32'h 0200_0004);
wire [31:0] simpleuart_reg_div_do;
wire simpleuart_reg_dat_sel = mem_valid && (mem_addr == 32'h 0200_0008);
wire [31:0] simpleuart_reg_dat_do;
wire simpleuart_reg_dat_wait;
assign mem_ready = (iomem_valid && iomem_ready) || spimem_ready || ram_ready || spimemio_cfgreg_sel ||
simpleuart_reg_div_sel || (simpleuart_reg_dat_sel && !simpleuart_reg_dat_wait);
assign mem_rdata = (iomem_valid && iomem_ready) ? iomem_rdata : spimem_ready ? spimem_rdata : ram_ready ? ram_rdata :
spimemio_cfgreg_sel ? spimemio_cfgreg_do : simpleuart_reg_div_sel ? simpleuart_reg_div_do :
simpleuart_reg_dat_sel ? simpleuart_reg_dat_do : 32'h 0000_0000;
picorv32 #(
.STACKADDR(STACKADDR),
.PROGADDR_RESET(PROGADDR_RESET),
.PROGADDR_IRQ(PROGADDR_IRQ),
.BARREL_SHIFTER(BARREL_SHIFTER),
.COMPRESSED_ISA(ENABLE_COMPRESSED),
.ENABLE_COUNTERS(ENABLE_COUNTERS),
.ENABLE_MUL(ENABLE_MULDIV),
.ENABLE_DIV(ENABLE_MULDIV),
.ENABLE_IRQ(1),
.ENABLE_IRQ_QREGS(ENABLE_IRQ_QREGS)
) cpu (
.clk (clk ),
.resetn (resetn ),
.mem_valid (mem_valid ),
.mem_instr (mem_instr ),
.mem_ready (mem_ready ),
.mem_addr (mem_addr ),
.mem_wdata (mem_wdata ),
.mem_wstrb (mem_wstrb ),
.mem_rdata (mem_rdata ),
.irq (irq )
);
spimemio spimemio (
.clk (clk),
.resetn (resetn),
.valid (mem_valid && mem_addr >= 4*MEM_WORDS && mem_addr < 32'h 0200_0000),
.ready (spimem_ready),
.addr (mem_addr[23:0]),
.rdata (spimem_rdata),
.flash_csb (flash_csb ),
.flash_clk (flash_clk ),
.flash_io0_oe (flash_io0_oe),
.flash_io1_oe (flash_io1_oe),
.flash_io2_oe (flash_io2_oe),
.flash_io3_oe (flash_io3_oe),
.flash_io0_do (flash_io0_do),
.flash_io1_do (flash_io1_do),
.flash_io2_do (flash_io2_do),
.flash_io3_do (flash_io3_do),
.flash_io0_di (flash_io0_di),
.flash_io1_di (flash_io1_di),
.flash_io2_di (flash_io2_di),
.flash_io3_di (flash_io3_di),
.cfgreg_we(spimemio_cfgreg_sel ? mem_wstrb : 4'b 0000),
.cfgreg_di(mem_wdata),
.cfgreg_do(spimemio_cfgreg_do)
);
simpleuart simpleuart (
.clk (clk ),
.resetn (resetn ),
.ser_tx (ser_tx ),
.ser_rx (ser_rx ),
.reg_div_we (simpleuart_reg_div_sel ? mem_wstrb : 4'b 0000),
.reg_div_di (mem_wdata),
.reg_div_do (simpleuart_reg_div_do),
.reg_dat_we (simpleuart_reg_dat_sel ? mem_wstrb[0] : 1'b 0),
.reg_dat_re (simpleuart_reg_dat_sel && !mem_wstrb),
.reg_dat_di (mem_wdata),
.reg_dat_do (simpleuart_reg_dat_do),
.reg_dat_wait(simpleuart_reg_dat_wait)
);
always @(posedge clk)
ram_ready <= mem_valid && !mem_ready && mem_addr < 4*MEM_WORDS;
`PICOSOC_MEM #(
.WORDS(MEM_WORDS)
) memory (
.clk(clk),
.wen((mem_valid && !mem_ready && mem_addr < 4*MEM_WORDS) ? mem_wstrb : 4'b0),
.addr(mem_addr[23:2]),
.wdata(mem_wdata),
.rdata(ram_rdata)
);
endmodule
// Implementation note:
// Replace the following two modules with wrappers for your SRAM cells.
module picosoc_regs (
input clk, wen,
input [5:0] waddr,
input [5:0] raddr1,
input [5:0] raddr2,
input [31:0] wdata,
output [31:0] rdata1,
output [31:0] rdata2
);
reg [31:0] regs [0:31];
always @(posedge clk)
if (wen) regs[waddr[4:0]] <= wdata;
assign rdata1 = regs[raddr1[4:0]];
assign rdata2 = regs[raddr2[4:0]];
endmodule
module picosoc_mem #(
parameter integer WORDS = 256
) (
input clk,
input [3:0] wen,
input [21:0] addr,
input [31:0] wdata,
output reg [31:0] rdata
);
reg [31:0] mem [0:WORDS-1];
always @(posedge clk) begin
rdata <= mem[addr];
if (wen[0]) mem[addr][ 7: 0] <= wdata[ 7: 0];
if (wen[1]) mem[addr][15: 8] <= wdata[15: 8];
if (wen[2]) mem[addr][23:16] <= wdata[23:16];
if (wen[3]) mem[addr][31:24] <= wdata[31:24];
end
endmodule

View File

@ -0,0 +1,71 @@
#ifdef ICEBREAKER
# define MEM_TOTAL 0x20000 /* 128 KB */
#elif HX8KDEMO
# define MEM_TOTAL 0x200 /* 2 KB */
#else
# error "Set -DICEBREAKER or -DHX8KDEMO when compiling firmware.c"
#endif
MEMORY
{
FLASH (rx) : ORIGIN = 0x00100000, LENGTH = 0x400000 /* entire flash, 4 MiB */
RAM (xrw) : ORIGIN = 0x00000000, LENGTH = MEM_TOTAL
}
SECTIONS {
/* The program code and other data goes into FLASH */
.text :
{
. = ALIGN(4);
*(.text) /* .text sections (code) */
*(.text*) /* .text* sections (code) */
*(.rodata) /* .rodata sections (constants, strings, etc.) */
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
*(.srodata) /* .rodata sections (constants, strings, etc.) */
*(.srodata*) /* .rodata* sections (constants, strings, etc.) */
. = ALIGN(4);
_etext = .; /* define a global symbol at end of code */
_sidata = _etext; /* This is used by the startup in order to initialize the .data secion */
} >FLASH
/* This is the initialized data section
The program executes knowing that the data is in the RAM
but the loader puts the initial values in the FLASH (inidata).
It is one task of the startup to copy the initial values from FLASH to RAM. */
.data : AT ( _sidata )
{
. = ALIGN(4);
_sdata = .; /* create a global symbol at data start; used by startup code in order to initialise the .data section in RAM */
_ram_start = .; /* create a global symbol at ram start for garbage collector */
. = ALIGN(4);
*(.data) /* .data sections */
*(.data*) /* .data* sections */
*(.sdata) /* .sdata sections */
*(.sdata*) /* .sdata* sections */
. = ALIGN(4);
_edata = .; /* define a global symbol at data end; used by startup code in order to initialise the .data section in RAM */
} >RAM
/* Uninitialized data section */
.bss :
{
. = ALIGN(4);
_sbss = .; /* define a global symbol at bss start; used by startup code */
*(.bss)
*(.bss*)
*(.sbss)
*(.sbss*)
*(COMMON)
. = ALIGN(4);
_ebss = .; /* define a global symbol at bss end; used by startup code */
} >RAM
/* this is to define the start of the heap, and make sure we have a minimum size */
.heap :
{
. = ALIGN(4);
_heap_start = .; /* define a global symbol at heap start */
} >RAM
}

View File

@ -0,0 +1,137 @@
/*
* PicoSoC - A simple example SoC using PicoRV32
*
* Copyright (C) 2017 Clifford Wolf <clifford@clifford.at>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
module simpleuart #(parameter integer DEFAULT_DIV = 1) (
input clk,
input resetn,
output ser_tx,
input ser_rx,
input [3:0] reg_div_we,
input [31:0] reg_div_di,
output [31:0] reg_div_do,
input reg_dat_we,
input reg_dat_re,
input [31:0] reg_dat_di,
output [31:0] reg_dat_do,
output reg_dat_wait
);
reg [31:0] cfg_divider;
reg [3:0] recv_state;
reg [31:0] recv_divcnt;
reg [7:0] recv_pattern;
reg [7:0] recv_buf_data;
reg recv_buf_valid;
reg [9:0] send_pattern;
reg [3:0] send_bitcnt;
reg [31:0] send_divcnt;
reg send_dummy;
assign reg_div_do = cfg_divider;
assign reg_dat_wait = reg_dat_we && (send_bitcnt || send_dummy);
assign reg_dat_do = recv_buf_valid ? recv_buf_data : ~0;
always @(posedge clk) begin
if (!resetn) begin
cfg_divider <= DEFAULT_DIV;
end else begin
if (reg_div_we[0]) cfg_divider[ 7: 0] <= reg_div_di[ 7: 0];
if (reg_div_we[1]) cfg_divider[15: 8] <= reg_div_di[15: 8];
if (reg_div_we[2]) cfg_divider[23:16] <= reg_div_di[23:16];
if (reg_div_we[3]) cfg_divider[31:24] <= reg_div_di[31:24];
end
end
always @(posedge clk) begin
if (!resetn) begin
recv_state <= 0;
recv_divcnt <= 0;
recv_pattern <= 0;
recv_buf_data <= 0;
recv_buf_valid <= 0;
end else begin
recv_divcnt <= recv_divcnt + 1;
if (reg_dat_re)
recv_buf_valid <= 0;
case (recv_state)
0: begin
if (!ser_rx)
recv_state <= 1;
recv_divcnt <= 0;
end
1: begin
if (2*recv_divcnt > cfg_divider) begin
recv_state <= 2;
recv_divcnt <= 0;
end
end
10: begin
if (recv_divcnt > cfg_divider) begin
recv_buf_data <= recv_pattern;
recv_buf_valid <= 1;
recv_state <= 0;
end
end
default: begin
if (recv_divcnt > cfg_divider) begin
recv_pattern <= {ser_rx, recv_pattern[7:1]};
recv_state <= recv_state + 1;
recv_divcnt <= 0;
end
end
endcase
end
end
assign ser_tx = send_pattern[0];
always @(posedge clk) begin
if (reg_div_we)
send_dummy <= 1;
send_divcnt <= send_divcnt + 1;
if (!resetn) begin
send_pattern <= ~0;
send_bitcnt <= 0;
send_divcnt <= 0;
send_dummy <= 1;
end else begin
if (send_dummy && !send_bitcnt) begin
send_pattern <= ~0;
send_bitcnt <= 15;
send_divcnt <= 0;
send_dummy <= 0;
end else
if (reg_dat_we && !send_bitcnt) begin
send_pattern <= {1'b1, reg_dat_di[7:0], 1'b0};
send_bitcnt <= 10;
send_divcnt <= 0;
end else
if (send_divcnt > cfg_divider && send_bitcnt) begin
send_pattern <= {1'b1, send_pattern[9:1]};
send_bitcnt <= send_bitcnt - 1;
send_divcnt <= 0;
end
end
end
endmodule

View File

@ -0,0 +1,24 @@
CAPI=2:
name : ::spiflash:0
filesets:
model:
files : [spiflash.v]
file_type : verilogSource
tb:
files : [spiflash_tb.v]
file_type : verilogSource
targets:
default:
default_tool : icarus
filesets : [model, "is_toplevel? (tb)"]
parameters : [firmware]
toplevel : [testbench]
parameters :
firmware:
datatype : file
description : Initial SPI Flash contents (in verilog hex format)
paramtype : plusarg

View File

@ -0,0 +1,409 @@
/*
* PicoSoC - A simple example SoC using PicoRV32
*
* Copyright (C) 2017 Clifford Wolf <clifford@clifford.at>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
`timescale 1 ns / 1 ps
//
// Simple SPI flash simulation model
//
// This model samples io input signals 1ns before the SPI clock edge and
// updates output signals 1ns after the SPI clock edge.
//
// Supported commands:
// AB, B9, FF, 03, BB, EB, ED
//
// Well written SPI flash data sheets:
// Cypress S25FL064L http://www.cypress.com/file/316661/download
// Cypress S25FL128L http://www.cypress.com/file/316171/download
//
// SPI flash used on iCEBreaker board:
// https://www.winbond.com/resource-files/w25q128jv%20dtr%20revb%2011042016.pdf
//
module spiflash (
input csb,
input clk,
inout io0, // MOSI
inout io1, // MISO
inout io2,
inout io3
);
localparam verbose = 0;
localparam integer latency = 8;
reg [7:0] buffer;
integer bitcount = 0;
integer bytecount = 0;
integer dummycount = 0;
reg [7:0] spi_cmd;
reg [7:0] xip_cmd = 0;
reg [23:0] spi_addr;
reg [7:0] spi_in;
reg [7:0] spi_out;
reg spi_io_vld;
reg powered_up = 0;
localparam [3:0] mode_spi = 1;
localparam [3:0] mode_dspi_rd = 2;
localparam [3:0] mode_dspi_wr = 3;
localparam [3:0] mode_qspi_rd = 4;
localparam [3:0] mode_qspi_wr = 5;
localparam [3:0] mode_qspi_ddr_rd = 6;
localparam [3:0] mode_qspi_ddr_wr = 7;
reg [3:0] mode = 0;
reg [3:0] next_mode = 0;
reg io0_oe = 0;
reg io1_oe = 0;
reg io2_oe = 0;
reg io3_oe = 0;
reg io0_dout = 0;
reg io1_dout = 0;
reg io2_dout = 0;
reg io3_dout = 0;
assign #1 io0 = io0_oe ? io0_dout : 1'bz;
assign #1 io1 = io1_oe ? io1_dout : 1'bz;
assign #1 io2 = io2_oe ? io2_dout : 1'bz;
assign #1 io3 = io3_oe ? io3_dout : 1'bz;
wire io0_delayed;
wire io1_delayed;
wire io2_delayed;
wire io3_delayed;
assign #1 io0_delayed = io0;
assign #1 io1_delayed = io1;
assign #1 io2_delayed = io2;
assign #1 io3_delayed = io3;
// 16 MB (128Mb) Flash
reg [7:0] memory [0:16*1024*1024-1];
reg [1023:0] firmware_file;
initial begin
if (!$value$plusargs("firmware=%s", firmware_file))
firmware_file = "firmware.hex";
$readmemh(firmware_file, memory);
end
task spi_action;
begin
spi_in = buffer;
if (bytecount == 1) begin
spi_cmd = buffer;
if (spi_cmd == 8'h ab)
powered_up = 1;
if (spi_cmd == 8'h b9)
powered_up = 0;
if (spi_cmd == 8'h ff)
xip_cmd = 0;
end
if (powered_up && spi_cmd == 'h 03) begin
if (bytecount == 2)
spi_addr[23:16] = buffer;
if (bytecount == 3)
spi_addr[15:8] = buffer;
if (bytecount == 4)
spi_addr[7:0] = buffer;
if (bytecount >= 4) begin
buffer = memory[spi_addr];
spi_addr = spi_addr + 1;
end
end
if (powered_up && spi_cmd == 'h bb) begin
if (bytecount == 1)
mode = mode_dspi_rd;
if (bytecount == 2)
spi_addr[23:16] = buffer;
if (bytecount == 3)
spi_addr[15:8] = buffer;
if (bytecount == 4)
spi_addr[7:0] = buffer;
if (bytecount == 5) begin
xip_cmd = (buffer == 8'h a5) ? spi_cmd : 8'h 00;
mode = mode_dspi_wr;
dummycount = latency;
end
if (bytecount >= 5) begin
buffer = memory[spi_addr];
spi_addr = spi_addr + 1;
end
end
if (powered_up && spi_cmd == 'h eb) begin
if (bytecount == 1)
mode = mode_qspi_rd;
if (bytecount == 2)
spi_addr[23:16] = buffer;
if (bytecount == 3)
spi_addr[15:8] = buffer;
if (bytecount == 4)
spi_addr[7:0] = buffer;
if (bytecount == 5) begin
xip_cmd = (buffer == 8'h a5) ? spi_cmd : 8'h 00;
mode = mode_qspi_wr;
dummycount = latency;
end
if (bytecount >= 5) begin
buffer = memory[spi_addr];
spi_addr = spi_addr + 1;
end
end
if (powered_up && spi_cmd == 'h ed) begin
if (bytecount == 1)
next_mode = mode_qspi_ddr_rd;
if (bytecount == 2)
spi_addr[23:16] = buffer;
if (bytecount == 3)
spi_addr[15:8] = buffer;
if (bytecount == 4)
spi_addr[7:0] = buffer;
if (bytecount == 5) begin
xip_cmd = (buffer == 8'h a5) ? spi_cmd : 8'h 00;
mode = mode_qspi_ddr_wr;
dummycount = latency;
end
if (bytecount >= 5) begin
buffer = memory[spi_addr];
spi_addr = spi_addr + 1;
end
end
spi_out = buffer;
spi_io_vld = 1;
if (verbose) begin
if (bytecount == 1)
$write("<SPI-START>");
$write("<SPI:%02x:%02x>", spi_in, spi_out);
end
end
endtask
task ddr_rd_edge;
begin
buffer = {buffer, io3_delayed, io2_delayed, io1_delayed, io0_delayed};
bitcount = bitcount + 4;
if (bitcount == 8) begin
bitcount = 0;
bytecount = bytecount + 1;
spi_action;
end
end
endtask
task ddr_wr_edge;
begin
io0_oe = 1;
io1_oe = 1;
io2_oe = 1;
io3_oe = 1;
io0_dout = buffer[4];
io1_dout = buffer[5];
io2_dout = buffer[6];
io3_dout = buffer[7];
buffer = {buffer, 4'h 0};
bitcount = bitcount + 4;
if (bitcount == 8) begin
bitcount = 0;
bytecount = bytecount + 1;
spi_action;
end
end
endtask
always @(csb) begin
if (csb) begin
if (verbose) begin
$display("");
$fflush;
end
buffer = 0;
bitcount = 0;
bytecount = 0;
mode = mode_spi;
io0_oe = 0;
io1_oe = 0;
io2_oe = 0;
io3_oe = 0;
end else
if (xip_cmd) begin
buffer = xip_cmd;
bitcount = 0;
bytecount = 1;
spi_action;
end
end
always @(csb, clk) begin
spi_io_vld = 0;
if (!csb && !clk) begin
if (dummycount > 0) begin
io0_oe = 0;
io1_oe = 0;
io2_oe = 0;
io3_oe = 0;
end else
case (mode)
mode_spi: begin
io0_oe = 0;
io1_oe = 1;
io2_oe = 0;
io3_oe = 0;
io1_dout = buffer[7];
end
mode_dspi_rd: begin
io0_oe = 0;
io1_oe = 0;
io2_oe = 0;
io3_oe = 0;
end
mode_dspi_wr: begin
io0_oe = 1;
io1_oe = 1;
io2_oe = 0;
io3_oe = 0;
io0_dout = buffer[6];
io1_dout = buffer[7];
end
mode_qspi_rd: begin
io0_oe = 0;
io1_oe = 0;
io2_oe = 0;
io3_oe = 0;
end
mode_qspi_wr: begin
io0_oe = 1;
io1_oe = 1;
io2_oe = 1;
io3_oe = 1;
io0_dout = buffer[4];
io1_dout = buffer[5];
io2_dout = buffer[6];
io3_dout = buffer[7];
end
mode_qspi_ddr_rd: begin
ddr_rd_edge;
end
mode_qspi_ddr_wr: begin
ddr_wr_edge;
end
endcase
if (next_mode) begin
case (next_mode)
mode_qspi_ddr_rd: begin
io0_oe = 0;
io1_oe = 0;
io2_oe = 0;
io3_oe = 0;
end
mode_qspi_ddr_wr: begin
io0_oe = 1;
io1_oe = 1;
io2_oe = 1;
io3_oe = 1;
io0_dout = buffer[4];
io1_dout = buffer[5];
io2_dout = buffer[6];
io3_dout = buffer[7];
end
endcase
mode = next_mode;
next_mode = 0;
end
end
end
always @(posedge clk) begin
if (!csb) begin
if (dummycount > 0) begin
dummycount = dummycount - 1;
end else
case (mode)
mode_spi: begin
buffer = {buffer, io0};
bitcount = bitcount + 1;
if (bitcount == 8) begin
bitcount = 0;
bytecount = bytecount + 1;
spi_action;
end
end
mode_dspi_rd, mode_dspi_wr: begin
buffer = {buffer, io1, io0};
bitcount = bitcount + 2;
if (bitcount == 8) begin
bitcount = 0;
bytecount = bytecount + 1;
spi_action;
end
end
mode_qspi_rd, mode_qspi_wr: begin
buffer = {buffer, io3, io2, io1, io0};
bitcount = bitcount + 4;
if (bitcount == 8) begin
bitcount = 0;
bytecount = bytecount + 1;
spi_action;
end
end
mode_qspi_ddr_rd: begin
ddr_rd_edge;
end
mode_qspi_ddr_wr: begin
ddr_wr_edge;
end
endcase
end
end
endmodule

View File

@ -0,0 +1,366 @@
/*
* PicoSoC - A simple example SoC using PicoRV32
*
* Copyright (C) 2017 Clifford Wolf <clifford@clifford.at>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
`timescale 1 ns / 1 ps
module testbench;
reg flash_csb = 1;
reg flash_clk = 0;
wire flash_io0;
wire flash_io1;
wire flash_io2;
wire flash_io3;
reg flash_io0_oe = 0;
reg flash_io1_oe = 0;
reg flash_io2_oe = 0;
reg flash_io3_oe = 0;
reg flash_io0_dout = 0;
reg flash_io1_dout = 0;
reg flash_io2_dout = 0;
reg flash_io3_dout = 0;
assign flash_io0 = flash_io0_oe ? flash_io0_dout : 1'bz;
assign flash_io1 = flash_io1_oe ? flash_io1_dout : 1'bz;
assign flash_io2 = flash_io2_oe ? flash_io2_dout : 1'bz;
assign flash_io3 = flash_io3_oe ? flash_io3_dout : 1'bz;
spiflash uut (
.csb(flash_csb),
.clk(flash_clk),
.io0(flash_io0),
.io1(flash_io1),
.io2(flash_io2),
.io3(flash_io3)
);
localparam [23:0] offset = 24'h100000;
localparam [31:0] word0 = 32'h 00000093;
localparam [31:0] word1 = 32'h 00000193;
reg [7:0] rdata;
integer errcount = 0;
task expect;
input [7:0] data;
begin
if (data !== rdata) begin
$display("ERROR: Got %x (%b) but expected %x (%b).", rdata, rdata, data, data);
errcount = errcount + 1;
end
end
endtask
task xfer_begin;
begin
#5;
flash_csb = 0;
$display("-- BEGIN");
#5;
end
endtask
task xfer_dummy;
begin
flash_io0_oe = 0;
flash_io1_oe = 0;
flash_io2_oe = 0;
flash_io3_oe = 0;
#5;
flash_clk = 1;
#5;
flash_clk = 0;
#5;
end
endtask
task xfer_end;
begin
#5;
flash_csb = 1;
flash_io0_oe = 0;
flash_io1_oe = 0;
flash_io2_oe = 0;
flash_io3_oe = 0;
$display("-- END");
$display("");
#5;
end
endtask
task xfer_spi;
input [7:0] data;
integer i;
begin
flash_io0_oe = 1;
flash_io1_oe = 0;
flash_io2_oe = 0;
flash_io3_oe = 0;
for (i = 0; i < 8; i=i+1) begin
flash_io0_dout = data[7-i];
#5;
flash_clk = 1;
rdata[7-i] = flash_io1;
#5;
flash_clk = 0;
end
$display("-- SPI SDR %02x %02x", data, rdata);
#5;
end
endtask
task xfer_qspi_wr;
input [7:0] data;
integer i;
begin
flash_io0_oe = 1;
flash_io1_oe = 1;
flash_io2_oe = 1;
flash_io3_oe = 1;
flash_io0_dout = data[4];
flash_io1_dout = data[5];
flash_io2_dout = data[6];
flash_io3_dout = data[7];
#5;
flash_clk = 1;
#5;
flash_clk = 0;
flash_io0_dout = data[0];
flash_io1_dout = data[1];
flash_io2_dout = data[2];
flash_io3_dout = data[3];
#5;
flash_clk = 1;
#5;
flash_clk = 0;
$display("-- QSPI SDR %02x --", data);
#5;
end
endtask
task xfer_qspi_rd;
integer i;
begin
flash_io0_oe = 0;
flash_io1_oe = 0;
flash_io2_oe = 0;
flash_io3_oe = 0;
#5;
flash_clk = 1;
rdata[4] = flash_io0;
rdata[5] = flash_io1;
rdata[6] = flash_io2;
rdata[7] = flash_io3;
#5;
flash_clk = 0;
#5;
flash_clk = 1;
rdata[0] = flash_io0;
rdata[1] = flash_io1;
rdata[2] = flash_io2;
rdata[3] = flash_io3;
#5;
flash_clk = 0;
$display("-- QSPI SDR -- %02x", rdata);
#5;
end
endtask
task xfer_qspi_ddr_wr;
input [7:0] data;
integer i;
begin
flash_io0_oe = 1;
flash_io1_oe = 1;
flash_io2_oe = 1;
flash_io3_oe = 1;
flash_io0_dout = data[4];
flash_io1_dout = data[5];
flash_io2_dout = data[6];
flash_io3_dout = data[7];
#5;
flash_clk = 1;
flash_io0_dout = data[0];
flash_io1_dout = data[1];
flash_io2_dout = data[2];
flash_io3_dout = data[3];
#5;
flash_clk = 0;
$display("-- QSPI DDR %02x --", data);
#5;
end
endtask
task xfer_qspi_ddr_rd;
integer i;
begin
flash_io0_oe = 0;
flash_io1_oe = 0;
flash_io2_oe = 0;
flash_io3_oe = 0;
#5;
flash_clk = 1;
rdata[4] = flash_io0;
rdata[5] = flash_io1;
rdata[6] = flash_io2;
rdata[7] = flash_io3;
#5;
flash_clk = 0;
rdata[0] = flash_io0;
rdata[1] = flash_io1;
rdata[2] = flash_io2;
rdata[3] = flash_io3;
$display("-- QSPI DDR -- %02x", rdata);
#5;
end
endtask
initial begin
$dumpfile("spiflash_tb.vcd");
$dumpvars(0, testbench);
$display("");
$display("Reset (FFh)");
xfer_begin;
xfer_spi(8'h ff);
xfer_end;
$display("Power Up (ABh)");
xfer_begin;
xfer_spi(8'h ab);
xfer_end;
$display("Read Data (03h)");
xfer_begin;
xfer_spi(8'h 03);
xfer_spi(offset[23:16]);
xfer_spi(offset[15:8]);
xfer_spi(offset[7:0]);
xfer_spi(8'h 00); expect(word0[7:0]);
xfer_spi(8'h 00); expect(word0[15:8]);
xfer_spi(8'h 00); expect(word0[23:16]);
xfer_spi(8'h 00); expect(word0[31:24]);
xfer_spi(8'h 00); expect(word1[7:0]);
xfer_spi(8'h 00); expect(word1[15:8]);
xfer_spi(8'h 00); expect(word1[23:16]);
xfer_spi(8'h 00); expect(word1[31:24]);
xfer_end;
$display("Quad I/O Read (EBh)");
xfer_begin;
xfer_spi(8'h eb);
xfer_qspi_wr(offset[23:16]);
xfer_qspi_wr(offset[15:8]);
xfer_qspi_wr(offset[7:0]);
xfer_qspi_wr(8'h a5);
repeat (8) xfer_dummy;
xfer_qspi_rd; expect(word0[7:0]);
xfer_qspi_rd; expect(word0[15:8]);
xfer_qspi_rd; expect(word0[23:16]);
xfer_qspi_rd; expect(word0[31:24]);
xfer_qspi_rd; expect(word1[7:0]);
xfer_qspi_rd; expect(word1[15:8]);
xfer_qspi_rd; expect(word1[23:16]);
xfer_qspi_rd; expect(word1[31:24]);
xfer_end;
$display("Continous Quad I/O Read");
xfer_begin;
xfer_qspi_wr(offset[23:16]);
xfer_qspi_wr(offset[15:8]);
xfer_qspi_wr(offset[7:0]);
xfer_qspi_wr(8'h ff);
repeat (8) xfer_dummy;
xfer_qspi_rd; expect(word0[7:0]);
xfer_qspi_rd; expect(word0[15:8]);
xfer_qspi_rd; expect(word0[23:16]);
xfer_qspi_rd; expect(word0[31:24]);
xfer_qspi_rd; expect(word1[7:0]);
xfer_qspi_rd; expect(word1[15:8]);
xfer_qspi_rd; expect(word1[23:16]);
xfer_qspi_rd; expect(word1[31:24]);
xfer_end;
$display("DDR Quad I/O Read (EDh)");
xfer_begin;
xfer_spi(8'h ed);
xfer_qspi_ddr_wr(offset[23:16]);
xfer_qspi_ddr_wr(offset[15:8]);
xfer_qspi_ddr_wr(offset[7:0]);
xfer_qspi_ddr_wr(8'h a5);
repeat (8) xfer_dummy;
xfer_qspi_ddr_rd; expect(word0[7:0]);
xfer_qspi_ddr_rd; expect(word0[15:8]);
xfer_qspi_ddr_rd; expect(word0[23:16]);
xfer_qspi_ddr_rd; expect(word0[31:24]);
xfer_qspi_ddr_rd; expect(word1[7:0]);
xfer_qspi_ddr_rd; expect(word1[15:8]);
xfer_qspi_ddr_rd; expect(word1[23:16]);
xfer_qspi_ddr_rd; expect(word1[31:24]);
xfer_end;
$display("Continous DDR Quad I/O Read");
xfer_begin;
xfer_qspi_ddr_wr(offset[23:16]);
xfer_qspi_ddr_wr(offset[15:8]);
xfer_qspi_ddr_wr(offset[7:0]);
xfer_qspi_ddr_wr(8'h ff);
repeat (8) xfer_dummy;
xfer_qspi_ddr_rd; expect(word0[7:0]);
xfer_qspi_ddr_rd; expect(word0[15:8]);
xfer_qspi_ddr_rd; expect(word0[23:16]);
xfer_qspi_ddr_rd; expect(word0[31:24]);
xfer_qspi_ddr_rd; expect(word1[7:0]);
xfer_qspi_ddr_rd; expect(word1[15:8]);
xfer_qspi_ddr_rd; expect(word1[23:16]);
xfer_qspi_ddr_rd; expect(word1[31:24]);
xfer_end;
#5;
if (errcount) begin
$display("FAIL");
$stop;
end else begin
$display("PASS");
end
end
endmodule

View File

@ -0,0 +1,579 @@
/*
* PicoSoC - A simple example SoC using PicoRV32
*
* Copyright (C) 2017 Clifford Wolf <clifford@clifford.at>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
module spimemio (
input clk, resetn,
input valid,
output ready,
input [23:0] addr,
output reg [31:0] rdata,
output flash_csb,
output flash_clk,
output flash_io0_oe,
output flash_io1_oe,
output flash_io2_oe,
output flash_io3_oe,
output flash_io0_do,
output flash_io1_do,
output flash_io2_do,
output flash_io3_do,
input flash_io0_di,
input flash_io1_di,
input flash_io2_di,
input flash_io3_di,
input [3:0] cfgreg_we,
input [31:0] cfgreg_di,
output [31:0] cfgreg_do
);
reg xfer_resetn;
reg din_valid;
wire din_ready;
reg [7:0] din_data;
reg [3:0] din_tag;
reg din_cont;
reg din_qspi;
reg din_ddr;
reg din_rd;
wire dout_valid;
wire [7:0] dout_data;
wire [3:0] dout_tag;
reg [23:0] buffer;
reg [23:0] rd_addr;
reg rd_valid;
reg rd_wait;
reg rd_inc;
assign ready = valid && (addr == rd_addr) && rd_valid;
wire jump = valid && !ready && (addr != rd_addr+4) && rd_valid;
reg softreset;
reg config_en; // cfgreg[31]
reg config_ddr; // cfgreg[22]
reg config_qspi; // cfgreg[21]
reg config_cont; // cfgreg[20]
reg [3:0] config_dummy; // cfgreg[19:16]
reg [3:0] config_oe; // cfgreg[11:8]
reg config_csb; // cfgreg[5]
reg config_clk; // cfgref[4]
reg [3:0] config_do; // cfgreg[3:0]
assign cfgreg_do[31] = config_en;
assign cfgreg_do[30:23] = 0;
assign cfgreg_do[22] = config_ddr;
assign cfgreg_do[21] = config_qspi;
assign cfgreg_do[20] = config_cont;
assign cfgreg_do[19:16] = config_dummy;
assign cfgreg_do[15:12] = 0;
assign cfgreg_do[11:8] = {flash_io3_oe, flash_io2_oe, flash_io1_oe, flash_io0_oe};
assign cfgreg_do[7:6] = 0;
assign cfgreg_do[5] = flash_csb;
assign cfgreg_do[4] = flash_clk;
assign cfgreg_do[3:0] = {flash_io3_di, flash_io2_di, flash_io1_di, flash_io0_di};
always @(posedge clk) begin
softreset <= !config_en || cfgreg_we;
if (!resetn) begin
softreset <= 1;
config_en <= 1;
config_csb <= 0;
config_clk <= 0;
config_oe <= 0;
config_do <= 0;
config_ddr <= 0;
config_qspi <= 0;
config_cont <= 0;
config_dummy <= 8;
end else begin
if (cfgreg_we[0]) begin
config_csb <= cfgreg_di[5];
config_clk <= cfgreg_di[4];
config_do <= cfgreg_di[3:0];
end
if (cfgreg_we[1]) begin
config_oe <= cfgreg_di[11:8];
end
if (cfgreg_we[2]) begin
config_ddr <= cfgreg_di[22];
config_qspi <= cfgreg_di[21];
config_cont <= cfgreg_di[20];
config_dummy <= cfgreg_di[19:16];
end
if (cfgreg_we[3]) begin
config_en <= cfgreg_di[31];
end
end
end
wire xfer_csb;
wire xfer_clk;
wire xfer_io0_oe;
wire xfer_io1_oe;
wire xfer_io2_oe;
wire xfer_io3_oe;
wire xfer_io0_do;
wire xfer_io1_do;
wire xfer_io2_do;
wire xfer_io3_do;
reg xfer_io0_90;
reg xfer_io1_90;
reg xfer_io2_90;
reg xfer_io3_90;
always @(negedge clk) begin
xfer_io0_90 <= xfer_io0_do;
xfer_io1_90 <= xfer_io1_do;
xfer_io2_90 <= xfer_io2_do;
xfer_io3_90 <= xfer_io3_do;
end
assign flash_csb = config_en ? xfer_csb : config_csb;
assign flash_clk = config_en ? xfer_clk : config_clk;
assign flash_io0_oe = config_en ? xfer_io0_oe : config_oe[0];
assign flash_io1_oe = config_en ? xfer_io1_oe : config_oe[1];
assign flash_io2_oe = config_en ? xfer_io2_oe : config_oe[2];
assign flash_io3_oe = config_en ? xfer_io3_oe : config_oe[3];
assign flash_io0_do = config_en ? (config_ddr ? xfer_io0_90 : xfer_io0_do) : config_do[0];
assign flash_io1_do = config_en ? (config_ddr ? xfer_io1_90 : xfer_io1_do) : config_do[1];
assign flash_io2_do = config_en ? (config_ddr ? xfer_io2_90 : xfer_io2_do) : config_do[2];
assign flash_io3_do = config_en ? (config_ddr ? xfer_io3_90 : xfer_io3_do) : config_do[3];
wire xfer_dspi = din_ddr && !din_qspi;
wire xfer_ddr = din_ddr && din_qspi;
spimemio_xfer xfer (
.clk (clk ),
.resetn (xfer_resetn ),
.din_valid (din_valid ),
.din_ready (din_ready ),
.din_data (din_data ),
.din_tag (din_tag ),
.din_cont (din_cont ),
.din_dspi (xfer_dspi ),
.din_qspi (din_qspi ),
.din_ddr (xfer_ddr ),
.din_rd (din_rd ),
.dout_valid (dout_valid ),
.dout_data (dout_data ),
.dout_tag (dout_tag ),
.flash_csb (xfer_csb ),
.flash_clk (xfer_clk ),
.flash_io0_oe (xfer_io0_oe ),
.flash_io1_oe (xfer_io1_oe ),
.flash_io2_oe (xfer_io2_oe ),
.flash_io3_oe (xfer_io3_oe ),
.flash_io0_do (xfer_io0_do ),
.flash_io1_do (xfer_io1_do ),
.flash_io2_do (xfer_io2_do ),
.flash_io3_do (xfer_io3_do ),
.flash_io0_di (flash_io0_di),
.flash_io1_di (flash_io1_di),
.flash_io2_di (flash_io2_di),
.flash_io3_di (flash_io3_di)
);
reg [3:0] state;
always @(posedge clk) begin
xfer_resetn <= 1;
din_valid <= 0;
if (!resetn || softreset) begin
state <= 0;
xfer_resetn <= 0;
rd_valid <= 0;
din_tag <= 0;
din_cont <= 0;
din_qspi <= 0;
din_ddr <= 0;
din_rd <= 0;
end else begin
if (dout_valid && dout_tag == 1) buffer[ 7: 0] <= dout_data;
if (dout_valid && dout_tag == 2) buffer[15: 8] <= dout_data;
if (dout_valid && dout_tag == 3) buffer[23:16] <= dout_data;
if (dout_valid && dout_tag == 4) begin
rdata <= {dout_data, buffer};
rd_addr <= rd_inc ? rd_addr + 4 : addr;
rd_valid <= 1;
rd_wait <= rd_inc;
rd_inc <= 1;
end
if (valid)
rd_wait <= 0;
case (state)
0: begin
din_valid <= 1;
din_data <= 8'h ff;
din_tag <= 0;
if (din_ready) begin
din_valid <= 0;
state <= 1;
end
end
1: begin
if (dout_valid) begin
xfer_resetn <= 0;
state <= 2;
end
end
2: begin
din_valid <= 1;
din_data <= 8'h ab;
din_tag <= 0;
if (din_ready) begin
din_valid <= 0;
state <= 3;
end
end
3: begin
if (dout_valid) begin
xfer_resetn <= 0;
state <= 4;
end
end
4: begin
rd_inc <= 0;
din_valid <= 1;
din_tag <= 0;
case ({config_ddr, config_qspi})
2'b11: din_data <= 8'h ED;
2'b01: din_data <= 8'h EB;
2'b10: din_data <= 8'h BB;
2'b00: din_data <= 8'h 03;
endcase
if (din_ready) begin
din_valid <= 0;
state <= 5;
end
end
5: begin
if (valid && !ready) begin
din_valid <= 1;
din_tag <= 0;
din_data <= addr[23:16];
din_qspi <= config_qspi;
din_ddr <= config_ddr;
if (din_ready) begin
din_valid <= 0;
state <= 6;
end
end
end
6: begin
din_valid <= 1;
din_tag <= 0;
din_data <= addr[15:8];
if (din_ready) begin
din_valid <= 0;
state <= 7;
end
end
7: begin
din_valid <= 1;
din_tag <= 0;
din_data <= addr[7:0];
if (din_ready) begin
din_valid <= 0;
din_data <= 0;
state <= config_qspi || config_ddr ? 8 : 9;
end
end
8: begin
din_valid <= 1;
din_tag <= 0;
din_data <= config_cont ? 8'h A5 : 8'h FF;
if (din_ready) begin
din_rd <= 1;
din_data <= config_dummy;
din_valid <= 0;
state <= 9;
end
end
9: begin
din_valid <= 1;
din_tag <= 1;
if (din_ready) begin
din_valid <= 0;
state <= 10;
end
end
10: begin
din_valid <= 1;
din_data <= 8'h 00;
din_tag <= 2;
if (din_ready) begin
din_valid <= 0;
state <= 11;
end
end
11: begin
din_valid <= 1;
din_tag <= 3;
if (din_ready) begin
din_valid <= 0;
state <= 12;
end
end
12: begin
if (!rd_wait || valid) begin
din_valid <= 1;
din_tag <= 4;
if (din_ready) begin
din_valid <= 0;
state <= 9;
end
end
end
endcase
if (jump) begin
rd_inc <= 0;
rd_valid <= 0;
xfer_resetn <= 0;
if (config_cont) begin
state <= 5;
end else begin
state <= 4;
din_qspi <= 0;
din_ddr <= 0;
end
din_rd <= 0;
end
end
end
endmodule
module spimemio_xfer (
input clk, resetn,
input din_valid,
output din_ready,
input [7:0] din_data,
input [3:0] din_tag,
input din_cont,
input din_dspi,
input din_qspi,
input din_ddr,
input din_rd,
output dout_valid,
output [7:0] dout_data,
output [3:0] dout_tag,
output reg flash_csb,
output reg flash_clk,
output reg flash_io0_oe,
output reg flash_io1_oe,
output reg flash_io2_oe,
output reg flash_io3_oe,
output reg flash_io0_do,
output reg flash_io1_do,
output reg flash_io2_do,
output reg flash_io3_do,
input flash_io0_di,
input flash_io1_di,
input flash_io2_di,
input flash_io3_di
);
reg [7:0] obuffer;
reg [7:0] ibuffer;
reg [3:0] count;
reg [3:0] dummy_count;
reg xfer_cont;
reg xfer_dspi;
reg xfer_qspi;
reg xfer_ddr;
reg xfer_ddr_q;
reg xfer_rd;
reg [3:0] xfer_tag;
reg [3:0] xfer_tag_q;
reg [7:0] next_obuffer;
reg [7:0] next_ibuffer;
reg [3:0] next_count;
reg fetch;
reg next_fetch;
reg last_fetch;
always @(posedge clk) begin
xfer_ddr_q <= xfer_ddr;
xfer_tag_q <= xfer_tag;
end
assign din_ready = din_valid && resetn && next_fetch;
assign dout_valid = (xfer_ddr_q ? fetch && !last_fetch : next_fetch && !fetch) && resetn;
assign dout_data = ibuffer;
assign dout_tag = xfer_tag_q;
always @* begin
flash_io0_oe = 0;
flash_io1_oe = 0;
flash_io2_oe = 0;
flash_io3_oe = 0;
flash_io0_do = 0;
flash_io1_do = 0;
flash_io2_do = 0;
flash_io3_do = 0;
next_obuffer = obuffer;
next_ibuffer = ibuffer;
next_count = count;
next_fetch = 0;
if (dummy_count == 0) begin
casez ({xfer_ddr, xfer_qspi, xfer_dspi})
3'b 000: begin
flash_io0_oe = 1;
flash_io0_do = obuffer[7];
if (flash_clk) begin
next_obuffer = {obuffer[6:0], 1'b 0};
next_count = count - |count;
end else begin
next_ibuffer = {ibuffer[6:0], flash_io1_di};
end
next_fetch = (next_count == 0);
end
3'b 01?: begin
flash_io0_oe = !xfer_rd;
flash_io1_oe = !xfer_rd;
flash_io2_oe = !xfer_rd;
flash_io3_oe = !xfer_rd;
flash_io0_do = obuffer[4];
flash_io1_do = obuffer[5];
flash_io2_do = obuffer[6];
flash_io3_do = obuffer[7];
if (flash_clk) begin
next_obuffer = {obuffer[3:0], 4'b 0000};
next_count = count - {|count, 2'b00};
end else begin
next_ibuffer = {ibuffer[3:0], flash_io3_di, flash_io2_di, flash_io1_di, flash_io0_di};
end
next_fetch = (next_count == 0);
end
3'b 11?: begin
flash_io0_oe = !xfer_rd;
flash_io1_oe = !xfer_rd;
flash_io2_oe = !xfer_rd;
flash_io3_oe = !xfer_rd;
flash_io0_do = obuffer[4];
flash_io1_do = obuffer[5];
flash_io2_do = obuffer[6];
flash_io3_do = obuffer[7];
next_obuffer = {obuffer[3:0], 4'b 0000};
next_ibuffer = {ibuffer[3:0], flash_io3_di, flash_io2_di, flash_io1_di, flash_io0_di};
next_count = count - {|count, 2'b00};
next_fetch = (next_count == 0);
end
3'b ??1: begin
flash_io0_oe = !xfer_rd;
flash_io1_oe = !xfer_rd;
flash_io0_do = obuffer[6];
flash_io1_do = obuffer[7];
if (flash_clk) begin
next_obuffer = {obuffer[5:0], 2'b 00};
next_count = count - {|count, 1'b0};
end else begin
next_ibuffer = {ibuffer[5:0], flash_io1_di, flash_io0_di};
end
next_fetch = (next_count == 0);
end
endcase
end
end
always @(posedge clk) begin
if (!resetn) begin
fetch <= 1;
last_fetch <= 1;
flash_csb <= 1;
flash_clk <= 0;
count <= 0;
dummy_count <= 0;
xfer_tag <= 0;
xfer_cont <= 0;
xfer_dspi <= 0;
xfer_qspi <= 0;
xfer_ddr <= 0;
xfer_rd <= 0;
end else begin
fetch <= next_fetch;
last_fetch <= xfer_ddr ? fetch : 1;
if (dummy_count) begin
flash_clk <= !flash_clk && !flash_csb;
dummy_count <= dummy_count - flash_clk;
end else
if (count) begin
flash_clk <= !flash_clk && !flash_csb;
obuffer <= next_obuffer;
ibuffer <= next_ibuffer;
count <= next_count;
end
if (din_valid && din_ready) begin
flash_csb <= 0;
flash_clk <= 0;
count <= 8;
dummy_count <= din_rd ? din_data : 0;
obuffer <= din_data;
xfer_tag <= din_tag;
xfer_cont <= din_cont;
xfer_dspi <= din_dspi;
xfer_qspi <= din_qspi;
xfer_ddr <= din_ddr;
xfer_rd <= din_rd;
end
end
end
endmodule

159
fw/picorv32/picosoc/start.s Normal file
View File

@ -0,0 +1,159 @@
.section .text
start:
# zero-initialize register file
addi x1, zero, 0
# x2 (sp) is initialized by reset
addi x3, zero, 0
addi x4, zero, 0
addi x5, zero, 0
addi x6, zero, 0
addi x7, zero, 0
addi x8, zero, 0
addi x9, zero, 0
addi x10, zero, 0
addi x11, zero, 0
addi x12, zero, 0
addi x13, zero, 0
addi x14, zero, 0
addi x15, zero, 0
addi x16, zero, 0
addi x17, zero, 0
addi x18, zero, 0
addi x19, zero, 0
addi x20, zero, 0
addi x21, zero, 0
addi x22, zero, 0
addi x23, zero, 0
addi x24, zero, 0
addi x25, zero, 0
addi x26, zero, 0
addi x27, zero, 0
addi x28, zero, 0
addi x29, zero, 0
addi x30, zero, 0
addi x31, zero, 0
# Update LEDs
li a0, 0x03000000
li a1, 1
sw a1, 0(a0)
# zero initialize entire scratchpad memory
li a0, 0x00000000
setmemloop:
sw a0, 0(a0)
addi a0, a0, 4
blt a0, sp, setmemloop
# Update LEDs
li a0, 0x03000000
li a1, 3
sw a1, 0(a0)
# copy data section
la a0, _sidata
la a1, _sdata
la a2, _edata
bge a1, a2, end_init_data
loop_init_data:
lw a3, 0(a0)
sw a3, 0(a1)
addi a0, a0, 4
addi a1, a1, 4
blt a1, a2, loop_init_data
end_init_data:
# Update LEDs
li a0, 0x03000000
li a1, 7
sw a1, 0(a0)
# zero-init bss section
la a0, _sbss
la a1, _ebss
bge a0, a1, end_init_bss
loop_init_bss:
sw zero, 0(a0)
addi a0, a0, 4
blt a0, a1, loop_init_bss
end_init_bss:
# Update LEDs
li a0, 0x03000000
li a1, 15
sw a1, 0(a0)
# call main
call main
loop:
j loop
.global flashio_worker_begin
.global flashio_worker_end
.balign 4
flashio_worker_begin:
# a0 ... data pointer
# a1 ... data length
# a2 ... optional WREN cmd (0 = disable)
# address of SPI ctrl reg
li t0, 0x02000000
# Set CS high, IO0 is output
li t1, 0x120
sh t1, 0(t0)
# Enable Manual SPI Ctrl
sb zero, 3(t0)
# Send optional WREN cmd
beqz a2, flashio_worker_L1
li t5, 8
andi t2, a2, 0xff
flashio_worker_L4:
srli t4, t2, 7
sb t4, 0(t0)
ori t4, t4, 0x10
sb t4, 0(t0)
slli t2, t2, 1
andi t2, t2, 0xff
addi t5, t5, -1
bnez t5, flashio_worker_L4
sb t1, 0(t0)
# SPI transfer
flashio_worker_L1:
beqz a1, flashio_worker_L3
li t5, 8
lbu t2, 0(a0)
flashio_worker_L2:
srli t4, t2, 7
sb t4, 0(t0)
ori t4, t4, 0x10
sb t4, 0(t0)
lbu t4, 0(t0)
andi t4, t4, 2
srli t4, t4, 1
slli t2, t2, 1
or t2, t2, t4
andi t2, t2, 0xff
addi t5, t5, -1
bnez t5, flashio_worker_L2
sb t2, 0(a0)
addi a0, a0, 1
addi a1, a1, -1
j flashio_worker_L1
flashio_worker_L3:
# Back to MEMIO mode
li t1, 0x80
sb t1, 3(t0)
ret
.balign 4
flashio_worker_end:

13
fw/picorv32/scripts/csmith/.gitignore vendored Normal file
View File

@ -0,0 +1,13 @@
obj_dir
riscv-fesvr
riscv-isa-sim
output_ref.txt
output_sim.txt
platform.info
test.c
test.ld
test.elf
test_ref
test.hex
testbench.vvp
testbench.vcd

View File

@ -0,0 +1,85 @@
RISCV_TOOLS_DIR = /opt/riscv32imc
RISCV_TOOLS_PREFIX = $(RISCV_TOOLS_DIR)/bin/riscv32-unknown-elf-
CSMITH_INCDIR = $(shell ls -d /usr/local/include/csmith-* | head -n1)
CC = $(RISCV_TOOLS_PREFIX)gcc
SHELL = /bin/bash
help:
@echo "Usage: make { loop | verilator | iverilog | spike }"
loop: riscv-fesvr/build.ok riscv-isa-sim/build.ok obj_dir/Vtestbench
+set -e; x() { echo "$$*" >&2; "$$@"; }; i=1; j=1; while true; do echo; echo; \
echo "---------------- $$((i++)) ($$j) ----------------"; \
x rm -f test.hex test.elf test.c test_ref test.ld output_ref.txt output_sim.txt; \
x make spike test.hex || { echo SKIP; continue; }; x rm -f output_sim.txt; \
x obj_dir/Vtestbench | grep -v '$$finish' > output_sim.txt; \
x diff -u output_ref.txt output_sim.txt; echo OK; ! ((j++)); \
done
verilator: test_ref test.hex obj_dir/Vtestbench
timeout 2 ./test_ref > output_ref.txt && cat output_ref.txt
obj_dir/Vtestbench | grep -v '$$finish' > output_sim.txt
diff -u output_ref.txt output_sim.txt
iverilog: test_ref test.hex testbench.vvp
timeout 2 ./test_ref > output_ref.txt && cat output_ref.txt
vvp -N testbench.vvp > output_sim.txt
diff -u output_ref.txt output_sim.txt
spike: riscv-fesvr/build.ok riscv-isa-sim/build.ok test_ref test.elf
timeout 2 ./test_ref > output_ref.txt && cat output_ref.txt
LD_LIBRARY_PATH="./riscv-isa-sim:./riscv-fesvr" ./riscv-isa-sim/spike test.elf > output_sim.txt
diff -u output_ref.txt output_sim.txt
riscv-fesvr/build.ok:
rm -rf riscv-fesvr
git clone https://github.com/riscv/riscv-fesvr.git riscv-fesvr
+cd riscv-fesvr && git checkout 1c02bd6 && ./configure && make && touch build.ok
riscv-isa-sim/build.ok: riscv-fesvr/build.ok
rm -rf riscv-isa-sim
git clone https://github.com/riscv/riscv-isa-sim.git riscv-isa-sim
cd riscv-isa-sim && git checkout 10ae74e
cd riscv-isa-sim && patch -p1 < ../riscv-isa-sim.diff
cd riscv-isa-sim && LDFLAGS="-L../riscv-fesvr" ./configure --with-isa=RV32IMC
+cd riscv-isa-sim && ln -s ../riscv-fesvr/fesvr . && make && touch build.ok
testbench.vvp: testbench.v ../../picorv32.v
iverilog -o testbench.vvp testbench.v ../../picorv32.v
chmod -x testbench.vvp
obj_dir/Vtestbench: testbench.v testbench.cc ../../picorv32.v
verilator --exe -Wno-fatal --cc --top-module testbench testbench.v ../../picorv32.v testbench.cc
$(MAKE) -C obj_dir -f Vtestbench.mk
test.hex: test.elf
$(RISCV_TOOLS_PREFIX)objcopy -O verilog test.elf test.hex
start.elf: start.S start.ld
$(CC) -nostdlib -o start.elf start.S -T start.ld
chmod -x start.elf
test_ref: test.c
gcc -m32 -o test_ref -w -Os -I $(CSMITH_INCDIR) test.c
test.elf: test.c syscalls.c start.S
sed -e '/SECTIONS/,+1 s/{/{ . = 0x00000000; .start : { *(.text.start) } application_entry_point = 0x00010000;/;' \
$(RISCV_TOOLS_DIR)/riscv32-unknown-elf/lib/riscv.ld > test.ld
$(CC) -o test.elf -w -Os -I $(CSMITH_INCDIR) -T test.ld test.c syscalls.c start.S
chmod -x test.elf
test.c:
echo "integer size = 4" > platform.info
echo "pointer size = 4" >> platform.info
csmith --no-packed-struct -o test.c
gawk '/Seed:/ {print$$2,$$3;}' test.c
clean:
rm -rf platform.info test.c test.ld test.elf test.hex test_ref obj_dir
rm -rf testbench.vvp testbench.vcd output_ref.txt output_sim.txt
mrproper: clean
rm -rf riscv-fesvr riscv-isa-sim
.PHONY: help loop verilator iverilog spike clean mrproper

View File

@ -0,0 +1,62 @@
diff --git a/riscv/execute.cc b/riscv/execute.cc
index 5c3fdf7..4d914b3 100644
--- a/riscv/execute.cc
+++ b/riscv/execute.cc
@@ -124,6 +124,10 @@ miss:
}
state.minstret += instret;
+ if (state.minstret > 1000000) {
+ printf("Reached limit of 1000000 instructions.\n");
+ exit(0);
+ }
n -= instret;
}
}
diff --git a/riscv/insns/c_ebreak.h b/riscv/insns/c_ebreak.h
index a17200f..f06d8d9 100644
--- a/riscv/insns/c_ebreak.h
+++ b/riscv/insns/c_ebreak.h
@@ -1,2 +1,4 @@
require_extension('C');
+
+exit(0);
throw trap_breakpoint();
diff --git a/riscv/insns/sbreak.h b/riscv/insns/sbreak.h
index c22776c..d38bd22 100644
--- a/riscv/insns/sbreak.h
+++ b/riscv/insns/sbreak.h
@@ -1 +1,2 @@
+exit(0);
throw trap_breakpoint();
diff --git a/riscv/mmu.h b/riscv/mmu.h
index b9948c5..bee1f8b 100644
--- a/riscv/mmu.h
+++ b/riscv/mmu.h
@@ -67,7 +67,8 @@ public:
if (addr & (sizeof(type##_t)-1)) \
throw trap_store_address_misaligned(addr); \
reg_t vpn = addr >> PGSHIFT; \
- if (likely(tlb_store_tag[vpn % TLB_ENTRIES] == vpn)) \
+ if (addr == 0x10000000) putchar(val), fflush(stdout); \
+ else if (likely(tlb_store_tag[vpn % TLB_ENTRIES] == vpn)) \
*(type##_t*)(tlb_data[vpn % TLB_ENTRIES] + addr) = val; \
else \
store_slow_path(addr, sizeof(type##_t), (const uint8_t*)&val); \
diff --git a/riscv/processor.cc b/riscv/processor.cc
index 3b834c5..f407543 100644
--- a/riscv/processor.cc
+++ b/riscv/processor.cc
@@ -201,9 +201,9 @@ void processor_t::set_privilege(reg_t prv)
void processor_t::take_trap(trap_t& t, reg_t epc)
{
- if (debug)
- fprintf(stderr, "core %3d: exception %s, epc 0x%016" PRIx64 "\n",
- id, t.name(), epc);
+ printf("core %3d: exception %s, epc 0x%016" PRIx64 "\n",
+ id, t.name(), epc);
+ exit(0);
// by default, trap to M-mode, unless delegated to S-mode
reg_t bit = t.cause();

View File

@ -0,0 +1,51 @@
.section .text.start
.global application_entry_point
/* zero-initialize all registers */
addi x1, zero, 0
addi x2, zero, 0
addi x3, zero, 0
addi x4, zero, 0
addi x5, zero, 0
addi x6, zero, 0
addi x7, zero, 0
addi x8, zero, 0
addi x9, zero, 0
addi x10, zero, 0
addi x11, zero, 0
addi x12, zero, 0
addi x13, zero, 0
addi x14, zero, 0
addi x15, zero, 0
addi x16, zero, 0
addi x17, zero, 0
addi x18, zero, 0
addi x19, zero, 0
addi x20, zero, 0
addi x21, zero, 0
addi x22, zero, 0
addi x23, zero, 0
addi x24, zero, 0
addi x25, zero, 0
addi x26, zero, 0
addi x27, zero, 0
addi x28, zero, 0
addi x29, zero, 0
addi x30, zero, 0
addi x31, zero, 0
/* set stack pointer */
lui sp, %hi(4*1024*1024)
addi sp, sp, %lo(4*1024*1024)
/* push zeros on the stack for argc and argv */
/* (stack is aligned to 16 bytes in riscv calling convention) */
addi sp,sp,-16
sw zero,0(sp)
sw zero,4(sp)
sw zero,8(sp)
sw zero,12(sp)
/* jump to libc init */
j application_entry_point

View File

@ -0,0 +1,95 @@
// An extremely minimalist syscalls.c for newlib
// Based on riscv newlib libgloss/riscv/sys_*.c
// Written by Clifford Wolf.
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
#define UNIMPL_FUNC(_f) ".globl " #_f "\n.type " #_f ", @function\n" #_f ":\n"
asm (
".text\n"
".align 2\n"
UNIMPL_FUNC(_open)
UNIMPL_FUNC(_openat)
UNIMPL_FUNC(_lseek)
UNIMPL_FUNC(_stat)
UNIMPL_FUNC(_lstat)
UNIMPL_FUNC(_fstatat)
UNIMPL_FUNC(_isatty)
UNIMPL_FUNC(_access)
UNIMPL_FUNC(_faccessat)
UNIMPL_FUNC(_link)
UNIMPL_FUNC(_unlink)
UNIMPL_FUNC(_execve)
UNIMPL_FUNC(_getpid)
UNIMPL_FUNC(_fork)
UNIMPL_FUNC(_kill)
UNIMPL_FUNC(_wait)
UNIMPL_FUNC(_times)
UNIMPL_FUNC(_gettimeofday)
UNIMPL_FUNC(_ftime)
UNIMPL_FUNC(_utime)
UNIMPL_FUNC(_chown)
UNIMPL_FUNC(_chmod)
UNIMPL_FUNC(_chdir)
UNIMPL_FUNC(_getcwd)
UNIMPL_FUNC(_sysconf)
"j unimplemented_syscall\n"
);
void unimplemented_syscall()
{
const char *p = "Unimplemented system call called!\n";
while (*p)
*(volatile int*)0x10000000 = *(p++);
asm volatile ("ebreak");
__builtin_unreachable();
}
ssize_t _read(int file, void *ptr, size_t len)
{
// always EOF
return 0;
}
ssize_t _write(int file, const void *ptr, size_t len)
{
const void *eptr = ptr + len;
while (ptr != eptr)
*(volatile int*)0x10000000 = *(char*)(ptr++);
return len;
}
int _close(int file)
{
// close is called before _exit()
return 0;
}
int _fstat(int file, struct stat *st)
{
// fstat is called during libc startup
errno = ENOENT;
return -1;
}
void *_sbrk(ptrdiff_t incr)
{
extern unsigned char _end[]; // Defined by linker
static unsigned long heap_end;
if (heap_end == 0)
heap_end = (long)_end;
heap_end += incr;
return (void *)(heap_end - incr);
}
void _exit(int exit_status)
{
asm volatile ("ebreak");
__builtin_unreachable();
}

View File

@ -0,0 +1,18 @@
#include "Vtestbench.h"
#include "verilated.h"
int main(int argc, char **argv, char **env)
{
Verilated::commandArgs(argc, argv);
Vtestbench* top = new Vtestbench;
top->clk = 0;
while (!Verilated::gotFinish()) {
top->clk = !top->clk;
top->eval();
}
delete top;
exit(0);
}

View File

@ -0,0 +1,100 @@
`timescale 1 ns / 1 ps
module testbench (
`ifdef VERILATOR
input clk
`endif
);
`ifndef VERILATOR
reg clk = 1;
always #5 clk = ~clk;
`endif
reg resetn = 0;
integer resetn_cnt = 0;
wire trap;
initial begin
// $dumpfile("testbench.vcd");
// $dumpvars(0, testbench);
end
always @(posedge clk) begin
if (resetn_cnt < 100)
resetn_cnt <= resetn_cnt + 1;
else
resetn <= 1;
end
wire mem_valid;
wire mem_instr;
wire mem_ready;
wire [31:0] mem_addr;
wire [31:0] mem_wdata;
wire [3:0] mem_wstrb;
wire [31:0] mem_rdata;
reg [31:0] x32 = 314159265;
reg [31:0] next_x32;
always @(posedge clk) begin
if (resetn) begin
next_x32 = x32;
next_x32 = next_x32 ^ (next_x32 << 13);
next_x32 = next_x32 ^ (next_x32 >> 17);
next_x32 = next_x32 ^ (next_x32 << 5);
x32 <= next_x32;
end
end
picorv32 #(
.COMPRESSED_ISA(1),
.ENABLE_MUL(1),
.ENABLE_DIV(1)
) uut (
.clk (clk ),
.resetn (resetn ),
.trap (trap ),
.mem_valid (mem_valid ),
.mem_instr (mem_instr ),
.mem_ready (mem_ready ),
.mem_addr (mem_addr ),
.mem_wdata (mem_wdata ),
.mem_wstrb (mem_wstrb ),
.mem_rdata (mem_rdata )
);
reg [7:0] memory [0:4*1024*1024-1];
initial $readmemh("test.hex", memory);
assign mem_ready = x32[0] && mem_valid;
assign mem_rdata[ 7: 0] = memory[mem_addr + 0];
assign mem_rdata[15: 8] = memory[mem_addr + 1];
assign mem_rdata[23:16] = memory[mem_addr + 2];
assign mem_rdata[31:24] = memory[mem_addr + 3];
always @(posedge clk) begin
if (mem_valid && mem_ready) begin
if (mem_wstrb && mem_addr == 'h10000000) begin
$write("%c", mem_wdata[ 7: 0]);
`ifndef VERILATOR
$fflush;
`endif
end else begin
if (mem_wstrb[0]) memory[mem_addr + 0] <= mem_wdata[ 7: 0];
if (mem_wstrb[1]) memory[mem_addr + 1] <= mem_wdata[15: 8];
if (mem_wstrb[2]) memory[mem_addr + 2] <= mem_wdata[23:16];
if (mem_wstrb[3]) memory[mem_addr + 3] <= mem_wdata[31:24];
end
end
end
always @(posedge clk) begin
if (resetn && trap) begin
// repeat (10) @(posedge clk);
// $display("TRAP");
$finish;
end
end
endmodule

View File

@ -0,0 +1,9 @@
firmware.d
firmware.elf
firmware.hex
firmware32.hex
firmware.o
syscalls.o
testbench.vvp
testbench.vcd
start.elf

View File

@ -0,0 +1,38 @@
RISCV_TOOLS_PREFIX = /opt/riscv32ic/bin/riscv32-unknown-elf-
CXX = $(RISCV_TOOLS_PREFIX)g++
CC = $(RISCV_TOOLS_PREFIX)gcc
AS = $(RISCV_TOOLS_PREFIX)gcc
CXXFLAGS = -MD -Os -Wall -std=c++11
CCFLAGS = -MD -Os -Wall -std=c++11
LDFLAGS = -Wl,--gc-sections
LDLIBS = -lstdc++
test: testbench.vvp firmware32.hex
vvp -N testbench.vvp
testbench.vvp: testbench.v ../../picorv32.v
iverilog -o testbench.vvp testbench.v ../../picorv32.v
chmod -x testbench.vvp
firmware32.hex: firmware.elf start.elf hex8tohex32.py
$(RISCV_TOOLS_PREFIX)objcopy -O verilog start.elf start.tmp
$(RISCV_TOOLS_PREFIX)objcopy -O verilog firmware.elf firmware.tmp
cat start.tmp firmware.tmp > firmware.hex
python3 hex8tohex32.py firmware.hex > firmware32.hex
rm -f start.tmp firmware.tmp
firmware.elf: firmware.o syscalls.o
$(CC) $(LDFLAGS) -o $@ $^ -T ../../firmware/riscv.ld $(LDLIBS)
chmod -x firmware.elf
start.elf: start.S start.ld
$(CC) -nostdlib -o start.elf start.S -T start.ld $(LDLIBS)
chmod -x start.elf
clean:
rm -f *.o *.d *.tmp start.elf
rm -f firmware.elf firmware.hex firmware32.hex
rm -f testbench.vvp testbench.vcd
-include *.d
.PHONY: test clean

View File

@ -0,0 +1,87 @@
#include <stdio.h>
#include <iostream>
#include <vector>
#include <algorithm>
class ExampleBaseClass
{
public:
ExampleBaseClass() {
std::cout << "ExampleBaseClass()" << std::endl;
}
virtual ~ExampleBaseClass() {
std::cout << "~ExampleBaseClass()" << std::endl;
}
virtual void print_something_virt() {
std::cout << "ExampleBaseClass::print_something_virt()" << std::endl;
}
void print_something_novirt() {
std::cout << "ExampleBaseClass::print_something_novirt()" << std::endl;
}
};
class ExampleSubClass : public ExampleBaseClass
{
public:
ExampleSubClass() {
std::cout << "ExampleSubClass()" << std::endl;
}
virtual ~ExampleSubClass() {
std::cout << "~ExampleSubClass()" << std::endl;
}
virtual void print_something_virt() {
std::cout << "ExampleSubClass::print_something_virt()" << std::endl;
}
void print_something_novirt() {
std::cout << "ExampleSubClass::print_something_novirt()" << std::endl;
}
};
int main()
{
printf("Hello World, C!\n");
std::cout << "Hello World, C++!" << std::endl;
ExampleBaseClass *obj = new ExampleBaseClass;
obj->print_something_virt();
obj->print_something_novirt();
delete obj;
obj = new ExampleSubClass;
obj->print_something_virt();
obj->print_something_novirt();
delete obj;
std::vector<unsigned int> some_ints;
some_ints.push_back(0x48c9b3e4);
some_ints.push_back(0x79109b6a);
some_ints.push_back(0x16155039);
some_ints.push_back(0xa3635c9a);
some_ints.push_back(0x8d2f4702);
some_ints.push_back(0x38d232ae);
some_ints.push_back(0x93924a17);
some_ints.push_back(0x62b895cc);
some_ints.push_back(0x6130d459);
some_ints.push_back(0x837c8b44);
some_ints.push_back(0x3d59b4fe);
some_ints.push_back(0x444914d8);
some_ints.push_back(0x3a3dc660);
some_ints.push_back(0xe5a121ef);
some_ints.push_back(0xff00866d);
some_ints.push_back(0xb843b879);
std::sort(some_ints.begin(), some_ints.end());
for (auto n : some_ints)
std::cout << std::hex << n << std::endl;
std::cout << "All done." << std::endl;
return 0;
}

View File

@ -0,0 +1,34 @@
#!/usr/bin/env python3
import fileinput
import itertools
ptr = 0
data = []
def write_data():
if len(data) != 0:
print("@%08x" % (ptr >> 2))
while len(data) % 4 != 0:
data.append(0)
for word_bytes in zip(*([iter(data)]*4)):
print("".join(["%02x" % b for b in reversed(word_bytes)]))
for line in fileinput.input():
if line.startswith("@"):
addr = int(line[1:], 16)
if addr > ptr+4:
write_data()
ptr = addr
data = []
while ptr % 4 != 0:
data.append(0)
ptr -= 1
else:
while ptr + len(data) < addr:
data.append(0)
else:
data += [int(tok, 16) for tok in line.split()]
write_data()

View File

@ -0,0 +1,52 @@
.section .text
.global _ftext
.global _pvstart
_pvstart:
/* zero-initialize all registers */
addi x1, zero, 0
addi x2, zero, 0
addi x3, zero, 0
addi x4, zero, 0
addi x5, zero, 0
addi x6, zero, 0
addi x7, zero, 0
addi x8, zero, 0
addi x9, zero, 0
addi x10, zero, 0
addi x11, zero, 0
addi x12, zero, 0
addi x13, zero, 0
addi x14, zero, 0
addi x15, zero, 0
addi x16, zero, 0
addi x17, zero, 0
addi x18, zero, 0
addi x19, zero, 0
addi x20, zero, 0
addi x21, zero, 0
addi x22, zero, 0
addi x23, zero, 0
addi x24, zero, 0
addi x25, zero, 0
addi x26, zero, 0
addi x27, zero, 0
addi x28, zero, 0
addi x29, zero, 0
addi x30, zero, 0
addi x31, zero, 0
/* set stack pointer */
lui sp, %hi(4*1024*1024)
addi sp, sp, %lo(4*1024*1024)
/* push zeros on the stack for argc and argv */
/* (stack is aligned to 16 bytes in riscv calling convention) */
addi sp,sp,-16
sw zero,0(sp)
sw zero,4(sp)
sw zero,8(sp)
sw zero,12(sp)
/* jump to libc init */
j _ftext

View File

@ -0,0 +1,5 @@
SECTIONS {
. = 0x00000000;
.text : { *(.text) }
_ftext = 0x00010000;
}

View File

@ -0,0 +1,95 @@
// An extremely minimalist syscalls.c for newlib
// Based on riscv newlib libgloss/riscv/sys_*.c
// Written by Clifford Wolf.
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
#define UNIMPL_FUNC(_f) ".globl " #_f "\n.type " #_f ", @function\n" #_f ":\n"
asm (
".text\n"
".align 2\n"
UNIMPL_FUNC(_open)
UNIMPL_FUNC(_openat)
UNIMPL_FUNC(_lseek)
UNIMPL_FUNC(_stat)
UNIMPL_FUNC(_lstat)
UNIMPL_FUNC(_fstatat)
UNIMPL_FUNC(_isatty)
UNIMPL_FUNC(_access)
UNIMPL_FUNC(_faccessat)
UNIMPL_FUNC(_link)
UNIMPL_FUNC(_unlink)
UNIMPL_FUNC(_execve)
UNIMPL_FUNC(_getpid)
UNIMPL_FUNC(_fork)
UNIMPL_FUNC(_kill)
UNIMPL_FUNC(_wait)
UNIMPL_FUNC(_times)
UNIMPL_FUNC(_gettimeofday)
UNIMPL_FUNC(_ftime)
UNIMPL_FUNC(_utime)
UNIMPL_FUNC(_chown)
UNIMPL_FUNC(_chmod)
UNIMPL_FUNC(_chdir)
UNIMPL_FUNC(_getcwd)
UNIMPL_FUNC(_sysconf)
"j unimplemented_syscall\n"
);
void unimplemented_syscall()
{
const char *p = "Unimplemented system call called!\n";
while (*p)
*(volatile int*)0x10000000 = *(p++);
asm volatile ("ebreak");
__builtin_unreachable();
}
ssize_t _read(int file, void *ptr, size_t len)
{
// always EOF
return 0;
}
ssize_t _write(int file, const void *ptr, size_t len)
{
const void *eptr = ptr + len;
while (ptr != eptr)
*(volatile int*)0x10000000 = *(char*)(ptr++);
return len;
}
int _close(int file)
{
// close is called before _exit()
return 0;
}
int _fstat(int file, struct stat *st)
{
// fstat is called during libc startup
errno = ENOENT;
return -1;
}
void *_sbrk(ptrdiff_t incr)
{
extern unsigned char _end[]; // Defined by linker
static unsigned long heap_end;
if (heap_end == 0)
heap_end = (long)_end;
heap_end += incr;
return (void *)(heap_end - incr);
}
void _exit(int exit_status)
{
asm volatile ("ebreak");
__builtin_unreachable();
}

View File

@ -0,0 +1,114 @@
`timescale 1 ns / 1 ps
`undef VERBOSE_MEM
`undef WRITE_VCD
`undef MEM8BIT
module testbench;
reg clk = 1;
reg resetn = 0;
wire trap;
always #5 clk = ~clk;
initial begin
repeat (100) @(posedge clk);
resetn <= 1;
end
wire mem_valid;
wire mem_instr;
reg mem_ready;
wire [31:0] mem_addr;
wire [31:0] mem_wdata;
wire [3:0] mem_wstrb;
reg [31:0] mem_rdata;
picorv32 #(
.COMPRESSED_ISA(1)
) uut (
.clk (clk ),
.resetn (resetn ),
.trap (trap ),
.mem_valid (mem_valid ),
.mem_instr (mem_instr ),
.mem_ready (mem_ready ),
.mem_addr (mem_addr ),
.mem_wdata (mem_wdata ),
.mem_wstrb (mem_wstrb ),
.mem_rdata (mem_rdata )
);
localparam MEM_SIZE = 4*1024*1024;
`ifdef MEM8BIT
reg [7:0] memory [0:MEM_SIZE-1];
initial $readmemh("firmware.hex", memory);
`else
reg [31:0] memory [0:MEM_SIZE/4-1];
initial $readmemh("firmware32.hex", memory);
`endif
always @(posedge clk) begin
mem_ready <= 0;
if (mem_valid && !mem_ready) begin
mem_ready <= 1;
mem_rdata <= 'bx;
case (1)
mem_addr < MEM_SIZE: begin
`ifdef MEM8BIT
if (|mem_wstrb) begin
if (mem_wstrb[0]) memory[mem_addr + 0] <= mem_wdata[ 7: 0];
if (mem_wstrb[1]) memory[mem_addr + 1] <= mem_wdata[15: 8];
if (mem_wstrb[2]) memory[mem_addr + 2] <= mem_wdata[23:16];
if (mem_wstrb[3]) memory[mem_addr + 3] <= mem_wdata[31:24];
end else begin
mem_rdata <= {memory[mem_addr+3], memory[mem_addr+2], memory[mem_addr+1], memory[mem_addr]};
end
`else
if (|mem_wstrb) begin
if (mem_wstrb[0]) memory[mem_addr >> 2][ 7: 0] <= mem_wdata[ 7: 0];
if (mem_wstrb[1]) memory[mem_addr >> 2][15: 8] <= mem_wdata[15: 8];
if (mem_wstrb[2]) memory[mem_addr >> 2][23:16] <= mem_wdata[23:16];
if (mem_wstrb[3]) memory[mem_addr >> 2][31:24] <= mem_wdata[31:24];
end else begin
mem_rdata <= memory[mem_addr >> 2];
end
`endif
end
mem_addr == 32'h 1000_0000: begin
$write("%c", mem_wdata[7:0]);
end
endcase
end
if (mem_valid && mem_ready) begin
`ifdef VERBOSE_MEM
if (|mem_wstrb)
$display("WR: ADDR=%x DATA=%x MASK=%b", mem_addr, mem_wdata, mem_wstrb);
else
$display("RD: ADDR=%x DATA=%x%s", mem_addr, mem_rdata, mem_instr ? " INSN" : "");
`endif
if (^mem_addr === 1'bx ||
(mem_wstrb[0] && ^mem_wdata[ 7: 0] == 1'bx) ||
(mem_wstrb[1] && ^mem_wdata[15: 8] == 1'bx) ||
(mem_wstrb[2] && ^mem_wdata[23:16] == 1'bx) ||
(mem_wstrb[3] && ^mem_wdata[31:24] == 1'bx)) begin
$display("CRITICAL UNDEF MEM TRANSACTION");
$finish;
end
end
end
`ifdef WRITE_VCD
initial begin
$dumpfile("testbench.vcd");
$dumpvars(0, testbench);
end
`endif
always @(posedge clk) begin
if (resetn && trap) begin
repeat (10) @(posedge clk);
$display("TRAP");
$finish;
end
end
endmodule

View File

@ -0,0 +1,5 @@
synth.blif
synth.log
synth.bin
synth.txt
firmware.hex

View File

@ -0,0 +1,104 @@
TOOLCHAIN_PREFIX = riscv32-unknown-elf-
ICE40_SIM_CELLS=$(shell yosys-config --datdir/ice40/cells_sim.v)
# set to 4 for simulation
FIRMWARE_COUNTER_BITS=18
all: example.bin
## -------------------
## firmware generation
firmware.elf: firmware.S firmware.c firmware.lds
$(TOOLCHAIN_PREFIX)gcc \
-DSHIFT_COUNTER_BITS=$(FIRMWARE_COUNTER_BITS) \
-march=rv32i -Os -ffreestanding -nostdlib \
-o $@ firmware.S firmware.c \
--std=gnu99 -Wl,-Bstatic,-T,firmware.lds,-Map,firmware.map,--strip-debug
chmod -x $@
firmware.bin: firmware.elf
$(TOOLCHAIN_PREFIX)objcopy -O binary $< $@
chmod -x $@
firmware.hex: firmware.bin
python3 ../../firmware/makehex.py $< 128 > $@
## ------------------------------
## main flow: synth/p&r/bitstream
synth.json: example.v ../../picorv32.v firmware.hex
yosys -v3 -l synth.log -p 'synth_ice40 -top top -json $@; write_verilog -attr2comment synth.v' $(filter %.v, $^)
example.asc: synth.json example.pcf
nextpnr-ice40 --hx8k --package ct256 --json $< --pcf example.pcf --asc $@
example.bin: example.asc
icepack $< $@
## -----------------
## icarus simulation
example_tb.vvp: example.v example_tb.v ../../picorv32.v firmware.hex
iverilog -o $@ -s testbench $(filter %.v, $^)
chmod -x $@
example_sim: example_tb.vvp
vvp -N $<
example_sim_vcd: example_tb.vvp
vvp -N $< +vcd
## ---------------------
## post-synth simulation
synth_tb.vvp: example_tb.v synth.json
iverilog -o $@ -s testbench synth.v example_tb.v $(ICE40_SIM_CELLS)
chmod -x $@
synth_sim: synth_tb.vvp
vvp -N $<
synth_sim_vcd: synth_tb.vvp
vvp -N $< +vcd
## ---------------------
## post-route simulation
route.v: example.asc example.pcf
icebox_vlog -L -n top -sp example.pcf $< > $@
route_tb.vvp: route.v example_tb.v
iverilog -o $@ -s testbench $^ $(ICE40_SIM_CELLS)
chmod -x $@
route_sim: route_tb.vvp
vvp -N $<
route_sim_vcd: route_tb.vvp
vvp -N $< +vcd
## ---------------------
## miscellaneous targets
prog_sram: example.bin
iceprog -S $<
timing: example.asc example.pcf
icetime -c 62 -tmd hx8k -P ct256 -p example.pcf -t $<
view: example.vcd
gtkwave $< example.gtkw
## ------
## el fin
clean:
rm -f firmware.elf firmware.map firmware.bin firmware.hex
rm -f synth.log synth.v synth.json route.v example.asc example.bin
rm -f example_tb.vvp synth_tb.vvp route_tb.vvp example.vcd
.PHONY: all prog_sram view clean
.PHONY: example_sim synth_sim route_sim timing
.PHONY: example_sim_vcd synth_sim_vcd route_sim_vcd

View File

@ -0,0 +1,9 @@
set_io clk J3
set_io LED0 B5
set_io LED1 B4
set_io LED2 A2
set_io LED3 A1
set_io LED4 C5
set_io LED5 C4
set_io LED6 B3
set_io LED7 C3

View File

@ -0,0 +1,80 @@
`timescale 1 ns / 1 ps
module top (
input clk,
output reg LED0, LED1, LED2, LED3, LED4, LED5, LED6, LED7
);
// -------------------------------
// Reset Generator
reg [7:0] resetn_counter = 0;
wire resetn = &resetn_counter;
always @(posedge clk) begin
if (!resetn)
resetn_counter <= resetn_counter + 1;
end
// -------------------------------
// PicoRV32 Core
wire mem_valid;
wire [31:0] mem_addr;
wire [31:0] mem_wdata;
wire [3:0] mem_wstrb;
reg mem_ready;
reg [31:0] mem_rdata;
picorv32 #(
.ENABLE_COUNTERS(0),
.LATCHED_MEM_RDATA(1),
.TWO_STAGE_SHIFT(0),
.TWO_CYCLE_ALU(1),
.CATCH_MISALIGN(0),
.CATCH_ILLINSN(0)
) cpu (
.clk (clk ),
.resetn (resetn ),
.mem_valid(mem_valid),
.mem_ready(mem_ready),
.mem_addr (mem_addr ),
.mem_wdata(mem_wdata),
.mem_wstrb(mem_wstrb),
.mem_rdata(mem_rdata)
);
// -------------------------------
// Memory/IO Interface
// 128 32bit words = 512 bytes memory
localparam MEM_SIZE = 128;
reg [31:0] memory [0:MEM_SIZE-1];
initial $readmemh("firmware.hex", memory);
always @(posedge clk) begin
mem_ready <= 0;
if (resetn && mem_valid && !mem_ready) begin
(* parallel_case *)
case (1)
!mem_wstrb && (mem_addr >> 2) < MEM_SIZE: begin
mem_rdata <= memory[mem_addr >> 2];
mem_ready <= 1;
end
|mem_wstrb && (mem_addr >> 2) < MEM_SIZE: begin
if (mem_wstrb[0]) memory[mem_addr >> 2][ 7: 0] <= mem_wdata[ 7: 0];
if (mem_wstrb[1]) memory[mem_addr >> 2][15: 8] <= mem_wdata[15: 8];
if (mem_wstrb[2]) memory[mem_addr >> 2][23:16] <= mem_wdata[23:16];
if (mem_wstrb[3]) memory[mem_addr >> 2][31:24] <= mem_wdata[31:24];
mem_ready <= 1;
end
|mem_wstrb && mem_addr == 32'h1000_0000: begin
{LED7, LED6, LED5, LED4, LED3, LED2, LED1, LED0} <= mem_wdata;
mem_ready <= 1;
end
endcase
end
end
endmodule

View File

@ -0,0 +1,30 @@
`timescale 1 ns / 1 ps
module testbench;
reg clk = 1;
always #5 clk = ~clk;
wire LED0, LED1, LED2, LED3, LED4, LED5, LED6, LED7;
top uut (
.clk(clk),
.LED0(LED0),
.LED1(LED1),
.LED2(LED2),
.LED3(LED3),
.LED4(LED4),
.LED5(LED5),
.LED6(LED6),
.LED7(LED7)
);
initial begin
if ($test$plusargs("vcd")) begin
$dumpfile("example.vcd");
$dumpvars(0, testbench);
end
$monitor(LED7, LED6, LED5, LED4, LED3, LED2, LED1, LED0);
repeat (10000) @(posedge clk);
$finish;
end
endmodule

View File

@ -0,0 +1,12 @@
.section .init
.global main
/* set stack pointer */
lui sp, %hi(512)
addi sp, sp, %lo(512)
/* call main */
jal ra, main
/* break */
ebreak

View File

@ -0,0 +1,58 @@
#include <stdint.h>
#ifndef SHIFT_COUNTER_BITS
#error SHIFT_COUNTER_BITS must be defined as 4 (for simulation) or 18 (for hardware bitstreams)!
#endif
void output(uint8_t c)
{
*(volatile char*)0x10000000 = c;
}
uint8_t gray_encode_simple(uint8_t c)
{
return c ^ (c >> 1);
}
uint8_t gray_encode_bitwise(uint8_t c)
{
unsigned int in_buf = c, out_buf = 0, bit = 1;
for (int i = 0; i < 8; i++) {
if ((in_buf & 1) ^ ((in_buf >> 1) & 1))
out_buf |= bit;
in_buf = in_buf >> 1;
bit = bit << 1;
}
return out_buf;
}
uint8_t gray_decode(uint8_t c)
{
uint8_t t = c >> 1;
while (t) {
c = c ^ t;
t = t >> 1;
}
return c;
}
void gray(uint8_t c)
{
uint8_t gray_simple = gray_encode_simple(c);
uint8_t gray_bitwise = gray_encode_bitwise(c);
uint8_t gray_decoded = gray_decode(gray_simple);
if (gray_simple != gray_bitwise || gray_decoded != c)
while (1) asm volatile ("ebreak");
output(gray_simple);
}
void main()
{
for (uint32_t counter = (2+4+32+64) << SHIFT_COUNTER_BITS;; counter++) {
asm volatile ("" : : "r"(counter));
if ((counter & ~(~0 << SHIFT_COUNTER_BITS)) == 0)
gray(counter >> SHIFT_COUNTER_BITS);
}
}

View File

@ -0,0 +1,11 @@
SECTIONS {
.memory : {
. = 0x000000;
*(.init);
*(.text);
*(*);
. = ALIGN(4);
end = .;
}
}

View File

@ -0,0 +1,12 @@
To build the example LED-blinking firmware for an HX8K Breakout Board and get
a timing report (checked against the default 12MHz oscillator):
$ make clean example.bin timing
To run all the simulation tests:
$ make clean example_sim synth_sim route_sim FIRMWARE_COUNTER_BITS=4
(You must run the `clean` target to rebuild the firmware with the updated
`FIRMWARE_COUNTER_BITS` parameter; the firmware source must be recompiled for
simulation vs hardware, but this is not tracked as a Makefile dependency.)

7
fw/picorv32/scripts/presyn/.gitignore vendored Normal file
View File

@ -0,0 +1,7 @@
firmware.bin
firmware.elf
firmware.hex
firmware.map
picorv32_presyn.v
testbench.vcd
testbench.vvp

View File

@ -0,0 +1,22 @@
TOOLCHAIN_PREFIX = /opt/riscv32ic/bin/riscv32-unknown-elf-
run: testbench.vvp firmware.hex
vvp -N testbench.vvp
firmware.hex: firmware.S firmware.c firmware.lds
$(TOOLCHAIN_PREFIX)gcc -Os -ffreestanding -nostdlib -o firmware.elf firmware.S firmware.c \
--std=gnu99 -Wl,-Bstatic,-T,firmware.lds,-Map,firmware.map,--strip-debug -lgcc
$(TOOLCHAIN_PREFIX)objcopy -O binary firmware.elf firmware.bin
python3 ../../firmware/makehex.py firmware.bin 4096 > firmware.hex
picorv32_presyn.v: picorv32_presyn.ys picorv32_regs.txt ../../picorv32.v
yosys -v0 picorv32_presyn.ys
testbench.vvp: testbench.v picorv32_presyn.v
iverilog -o testbench.vvp testbench.v picorv32_presyn.v
clean:
rm -f firmware.bin firmware.elf firmware.hex firmware.map
rm -f picorv32_presyn.v testbench.vvp testbench.vcd

View File

@ -0,0 +1,5 @@
A simple example for how to use Yosys to "pre-synthesize" PicoRV32 in
a way that can utilize an external memory module for the register file.
See also:
https://github.com/cliffordwolf/picorv32/issues/30

Some files were not shown because too many files have changed in this diff Show More