mirror of
https://github.com/Polprzewodnikowy/SummerCart64.git
synced 2025-01-11 12:09:08 +01:00
whatever
This commit is contained in:
parent
2172c7ff15
commit
e61d06275d
4
.gitmodules
vendored
4
.gitmodules
vendored
@ -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
|
||||
|
0
fw/v1/.gitignore → fw/.gitignore
vendored
0
fw/v1/.gitignore → fw/.gitignore
vendored
@ -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
31
fw/btldr/Makefile
Normal 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
|
40
fw/btldr/SC64_PicoRV32I.ld
Normal file
40
fw/btldr/SC64_PicoRV32I.ld
Normal 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
48
fw/btldr/bin2v.py
Normal 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
BIN
fw/btldr/btldr.bin
Normal file
Binary file not shown.
17
fw/btldr/btldr.c
Normal file
17
fw/btldr/btldr.c
Normal 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
BIN
fw/btldr/btldr.elf
Normal file
Binary file not shown.
23
fw/btldr/btldr.hex
Normal file
23
fw/btldr/btldr.hex
Normal 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
BIN
fw/btldr/btldr.o
Normal file
Binary file not shown.
111
fw/btldr/btldr.sv
Normal file
111
fw/btldr/btldr.sv
Normal 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
94
fw/btldr/custom_ops.S
Normal 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
82
fw/btldr/startup.S
Normal 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
BIN
fw/btldr/startup.o
Normal file
Binary file not shown.
37
fw/picorv32/.gitignore
vendored
Normal file
37
fw/picorv32/.gitignore
vendored
Normal 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
184
fw/picorv32/Makefile
Normal 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
735
fw/picorv32/README.md
Normal 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 |
|
||||
|
69
fw/picorv32/dhrystone/Makefile
Normal file
69
fw/picorv32/dhrystone/Makefile
Normal 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
|
||||
|
1
fw/picorv32/dhrystone/README
Normal file
1
fw/picorv32/dhrystone/README
Normal file
@ -0,0 +1 @@
|
||||
The Dhrystone benchmark and a verilog testbench to run it.
|
423
fw/picorv32/dhrystone/dhry.h
Normal file
423
fw/picorv32/dhrystone/dhry.h
Normal 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;
|
||||
|
||||
|
427
fw/picorv32/dhrystone/dhry_1.c
Normal file
427
fw/picorv32/dhrystone/dhry_1.c
Normal 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
|
||||
|
||||
|
385
fw/picorv32/dhrystone/dhry_1_orig.c
Normal file
385
fw/picorv32/dhrystone/dhry_1_orig.c
Normal 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
|
||||
|
||||
|
192
fw/picorv32/dhrystone/dhry_2.c
Normal file
192
fw/picorv32/dhrystone/dhry_2.c
Normal 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 */
|
||||
|
18
fw/picorv32/dhrystone/sections.lds
Normal file
18
fw/picorv32/dhrystone/sections.lds
Normal 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 = .;
|
||||
}
|
||||
}
|
51
fw/picorv32/dhrystone/start.S
Normal file
51
fw/picorv32/dhrystone/start.S
Normal 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
|
||||
|
210
fw/picorv32/dhrystone/stdlib.c
Normal file
210
fw/picorv32/dhrystone/stdlib.c
Normal 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
|
||||
|
95
fw/picorv32/dhrystone/syscalls.c
Normal file
95
fw/picorv32/dhrystone/syscalls.c
Normal 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();
|
||||
}
|
||||
|
126
fw/picorv32/dhrystone/testbench.v
Normal file
126
fw/picorv32/dhrystone/testbench.v
Normal 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
|
95
fw/picorv32/dhrystone/testbench_nola.v
Normal file
95
fw/picorv32/dhrystone/testbench_nola.v
Normal 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
|
2
fw/picorv32/firmware/README
Normal file
2
fw/picorv32/firmware/README
Normal file
@ -0,0 +1,2 @@
|
||||
A simple test firmware. This code is in the public domain. Simply copy whatever
|
||||
you can use.
|
102
fw/picorv32/firmware/custom_ops.S
Normal file
102
fw/picorv32/firmware/custom_ops.S
Normal 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)
|
||||
|
43
fw/picorv32/firmware/firmware.h
Normal file
43
fw/picorv32/firmware/firmware.h
Normal 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
|
14
fw/picorv32/firmware/hello.c
Normal file
14
fw/picorv32/firmware/hello.c
Normal 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
140
fw/picorv32/firmware/irq.c
Normal 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;
|
||||
}
|
||||
|
27
fw/picorv32/firmware/makehex.py
Normal file
27
fw/picorv32/firmware/makehex.py
Normal 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")
|
||||
|
151
fw/picorv32/firmware/multest.c
Normal file
151
fw/picorv32/firmware/multest.c
Normal 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");
|
||||
}
|
||||
}
|
||||
|
41
fw/picorv32/firmware/print.c
Normal file
41
fw/picorv32/firmware/print.c
Normal 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];
|
||||
}
|
||||
|
200
fw/picorv32/firmware/riscv.ld
Normal file
200
fw/picorv32/firmware/riscv.ld
Normal 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_*) }
|
||||
}
|
236
fw/picorv32/firmware/riscv.ld.orig
Normal file
236
fw/picorv32/firmware/riscv.ld.orig
Normal 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_*) }
|
||||
}
|
25
fw/picorv32/firmware/sections.lds
Normal file
25
fw/picorv32/firmware/sections.lds
Normal 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
|
||||
}
|
84
fw/picorv32/firmware/sieve.c
Normal file
84
fw/picorv32/firmware/sieve.c
Normal 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");
|
||||
}
|
||||
}
|
||||
|
537
fw/picorv32/firmware/start.S
Normal file
537
fw/picorv32/firmware/start.S
Normal 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
|
||||
|
42
fw/picorv32/firmware/stats.c
Normal file
42
fw/picorv32/firmware/stats.c
Normal 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
78
fw/picorv32/picorv32.core
Normal 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
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
29
fw/picorv32/picosoc/.gitignore
vendored
Normal 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
|
||||
|
123
fw/picorv32/picosoc/Makefile
Normal file
123
fw/picorv32/picosoc/Makefile
Normal 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
|
114
fw/picorv32/picosoc/README.md
Normal file
114
fw/picorv32/picosoc/README.md
Normal 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).
|
||||
|
770
fw/picorv32/picosoc/firmware.c
Normal file
770
fw/picorv32/picosoc/firmware.c
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
35
fw/picorv32/picosoc/hx8kdemo.core
Normal file
35
fw/picorv32/picosoc/hx8kdemo.core
Normal 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]
|
40
fw/picorv32/picosoc/hx8kdemo.pcf
Normal file
40
fw/picorv32/picosoc/hx8kdemo.pcf
Normal 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
|
||||
|
139
fw/picorv32/picosoc/hx8kdemo.v
Normal file
139
fw/picorv32/picosoc/hx8kdemo.v
Normal 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
|
108
fw/picorv32/picosoc/hx8kdemo_tb.v
Normal file
108
fw/picorv32/picosoc/hx8kdemo_tb.v
Normal 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
|
91
fw/picorv32/picosoc/ice40up5k_spram.v
Normal file
91
fw/picorv32/picosoc/ice40up5k_spram.v
Normal 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
|
36
fw/picorv32/picosoc/icebreaker.core
Normal file
36
fw/picorv32/picosoc/icebreaker.core
Normal 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]
|
25
fw/picorv32/picosoc/icebreaker.pcf
Normal file
25
fw/picorv32/picosoc/icebreaker.pcf
Normal 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
|
149
fw/picorv32/picosoc/icebreaker.v
Normal file
149
fw/picorv32/picosoc/icebreaker.v
Normal 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
|
122
fw/picorv32/picosoc/icebreaker_tb.v
Normal file
122
fw/picorv32/picosoc/icebreaker_tb.v
Normal 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
|
757
fw/picorv32/picosoc/overview.svg
Normal file
757
fw/picorv32/picosoc/overview.svg
Normal 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 |
BIN
fw/picorv32/picosoc/performance.png
Normal file
BIN
fw/picorv32/picosoc/performance.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 61 KiB |
165
fw/picorv32/picosoc/performance.py
Normal file
165
fw/picorv32/picosoc/performance.py
Normal 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()
|
27
fw/picorv32/picosoc/picosoc.core
Normal file
27
fw/picorv32/picosoc/picosoc.core
Normal 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
|
259
fw/picorv32/picosoc/picosoc.v
Normal file
259
fw/picorv32/picosoc/picosoc.v
Normal 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
|
||||
|
71
fw/picorv32/picosoc/sections.lds
Normal file
71
fw/picorv32/picosoc/sections.lds
Normal 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
|
||||
}
|
137
fw/picorv32/picosoc/simpleuart.v
Normal file
137
fw/picorv32/picosoc/simpleuart.v
Normal 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
|
24
fw/picorv32/picosoc/spiflash.core
Normal file
24
fw/picorv32/picosoc/spiflash.core
Normal 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
|
409
fw/picorv32/picosoc/spiflash.v
Normal file
409
fw/picorv32/picosoc/spiflash.v
Normal 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
|
366
fw/picorv32/picosoc/spiflash_tb.v
Normal file
366
fw/picorv32/picosoc/spiflash_tb.v
Normal 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
|
579
fw/picorv32/picosoc/spimemio.v
Normal file
579
fw/picorv32/picosoc/spimemio.v
Normal 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
159
fw/picorv32/picosoc/start.s
Normal 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
13
fw/picorv32/scripts/csmith/.gitignore
vendored
Normal 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
|
85
fw/picorv32/scripts/csmith/Makefile
Normal file
85
fw/picorv32/scripts/csmith/Makefile
Normal 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
|
||||
|
62
fw/picorv32/scripts/csmith/riscv-isa-sim.diff
Normal file
62
fw/picorv32/scripts/csmith/riscv-isa-sim.diff
Normal 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();
|
51
fw/picorv32/scripts/csmith/start.S
Normal file
51
fw/picorv32/scripts/csmith/start.S
Normal 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
|
||||
|
95
fw/picorv32/scripts/csmith/syscalls.c
Normal file
95
fw/picorv32/scripts/csmith/syscalls.c
Normal 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();
|
||||
}
|
||||
|
18
fw/picorv32/scripts/csmith/testbench.cc
Normal file
18
fw/picorv32/scripts/csmith/testbench.cc
Normal 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);
|
||||
}
|
||||
|
100
fw/picorv32/scripts/csmith/testbench.v
Normal file
100
fw/picorv32/scripts/csmith/testbench.v
Normal 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
|
9
fw/picorv32/scripts/cxxdemo/.gitignore
vendored
Normal file
9
fw/picorv32/scripts/cxxdemo/.gitignore
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
firmware.d
|
||||
firmware.elf
|
||||
firmware.hex
|
||||
firmware32.hex
|
||||
firmware.o
|
||||
syscalls.o
|
||||
testbench.vvp
|
||||
testbench.vcd
|
||||
start.elf
|
38
fw/picorv32/scripts/cxxdemo/Makefile
Normal file
38
fw/picorv32/scripts/cxxdemo/Makefile
Normal 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
|
87
fw/picorv32/scripts/cxxdemo/firmware.cc
Normal file
87
fw/picorv32/scripts/cxxdemo/firmware.cc
Normal 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;
|
||||
}
|
34
fw/picorv32/scripts/cxxdemo/hex8tohex32.py
Normal file
34
fw/picorv32/scripts/cxxdemo/hex8tohex32.py
Normal 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()
|
||||
|
52
fw/picorv32/scripts/cxxdemo/start.S
Normal file
52
fw/picorv32/scripts/cxxdemo/start.S
Normal 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
|
5
fw/picorv32/scripts/cxxdemo/start.ld
Normal file
5
fw/picorv32/scripts/cxxdemo/start.ld
Normal file
@ -0,0 +1,5 @@
|
||||
SECTIONS {
|
||||
. = 0x00000000;
|
||||
.text : { *(.text) }
|
||||
_ftext = 0x00010000;
|
||||
}
|
95
fw/picorv32/scripts/cxxdemo/syscalls.c
Normal file
95
fw/picorv32/scripts/cxxdemo/syscalls.c
Normal 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();
|
||||
}
|
||||
|
114
fw/picorv32/scripts/cxxdemo/testbench.v
Normal file
114
fw/picorv32/scripts/cxxdemo/testbench.v
Normal 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
|
5
fw/picorv32/scripts/icestorm/.gitignore
vendored
Normal file
5
fw/picorv32/scripts/icestorm/.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
synth.blif
|
||||
synth.log
|
||||
synth.bin
|
||||
synth.txt
|
||||
firmware.hex
|
104
fw/picorv32/scripts/icestorm/Makefile
Normal file
104
fw/picorv32/scripts/icestorm/Makefile
Normal 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
|
9
fw/picorv32/scripts/icestorm/example.pcf
Normal file
9
fw/picorv32/scripts/icestorm/example.pcf
Normal 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
|
80
fw/picorv32/scripts/icestorm/example.v
Normal file
80
fw/picorv32/scripts/icestorm/example.v
Normal 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
|
30
fw/picorv32/scripts/icestorm/example_tb.v
Normal file
30
fw/picorv32/scripts/icestorm/example_tb.v
Normal 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
|
12
fw/picorv32/scripts/icestorm/firmware.S
Normal file
12
fw/picorv32/scripts/icestorm/firmware.S
Normal 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
|
58
fw/picorv32/scripts/icestorm/firmware.c
Normal file
58
fw/picorv32/scripts/icestorm/firmware.c
Normal 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);
|
||||
}
|
||||
}
|
11
fw/picorv32/scripts/icestorm/firmware.lds
Normal file
11
fw/picorv32/scripts/icestorm/firmware.lds
Normal file
@ -0,0 +1,11 @@
|
||||
SECTIONS {
|
||||
.memory : {
|
||||
. = 0x000000;
|
||||
*(.init);
|
||||
*(.text);
|
||||
*(*);
|
||||
. = ALIGN(4);
|
||||
end = .;
|
||||
}
|
||||
}
|
||||
|
12
fw/picorv32/scripts/icestorm/readme.md
Normal file
12
fw/picorv32/scripts/icestorm/readme.md
Normal 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
7
fw/picorv32/scripts/presyn/.gitignore
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
firmware.bin
|
||||
firmware.elf
|
||||
firmware.hex
|
||||
firmware.map
|
||||
picorv32_presyn.v
|
||||
testbench.vcd
|
||||
testbench.vvp
|
22
fw/picorv32/scripts/presyn/Makefile
Normal file
22
fw/picorv32/scripts/presyn/Makefile
Normal 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
|
||||
|
5
fw/picorv32/scripts/presyn/README
Normal file
5
fw/picorv32/scripts/presyn/README
Normal 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
Loading…
x
Reference in New Issue
Block a user