add picosoc example with simple GPIO LED

This commit is contained in:
Luke Valenty
2018-07-23 11:50:04 -07:00
parent 15695c0fb9
commit 6a73fe00a9
15 changed files with 5360 additions and 0 deletions

15
examples/picosoc/.gitignore vendored Normal file
View File

@@ -0,0 +1,15 @@
/spiflash_tb.vcd
/spiflash_tb.vvp
/firmware.elf
/firmware.hex
/firmware.bin
/hardware.asc
/hardware.bin
/hardware.blif
/hardware.log
/hardware.rpt
/hardware_syn.v
/hardware_syn_tb.vvp
/hardware_tb.vvp
/testbench.vcd
/cmos.log

30
examples/picosoc/Makefile Normal file
View File

@@ -0,0 +1,30 @@
upload: hardware.bin firmware.bin
tinyprog -p hardware.bin -u firmware.bin
hardware.blif: hardware.v spimemio.v simpleuart.v picosoc.v picorv32.v
yosys -ql hardware.log -p 'synth_ice40 -top hardware -blif hardware.blif' $^
hardware.asc: hardware.pcf hardware.blif
arachne-pnr -d 8k -P cm81 -o hardware.asc -p hardware.pcf hardware.blif
hardware.bin: hardware.asc
icetime -d hx8k -c 12 -mtr hardware.rpt hardware.asc
icepack hardware.asc hardware.bin
firmware.elf: sections.lds start.S firmware.c
riscv32-unknown-elf-gcc -march=rv32imc -nostartfiles -Wl,-Bstatic,-T,sections.lds,--strip-debug,-Map=firmware.map,--cref -ffreestanding -nostdlib -o firmware.elf start.S firmware.c
firmware.bin: firmware.elf
riscv32-unknown-elf-objcopy -O binary firmware.elf /dev/stdout > firmware.bin
clean:
rm -f firmware.elf firmware.hex firmware.bin firmware.o firmware.map \
hardware.blif hardware.log hardware.asc hardware.rpt hardware.bin

View File

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

View File

@@ -0,0 +1,43 @@
#include <stdint.h>
#include <stdbool.h>
// 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 _sidata, _sdata, _edata, _sbss, _ebss,_heap_start;
uint32_t set_irq_mask(uint32_t mask); asm (
".global set_irq_mask\n"
"set_irq_mask:\n"
".word 0x0605650b\n"
"ret\n"
);
void main() {
set_irq_mask(0xff);
// zero out .bss section
for (uint32_t *dest = &_sbss; dest < &_ebss;) {
*dest++ = 0;
}
// switch to dual IO mode
reg_spictrl = (reg_spictrl & ~0x007F0000) | 0x00400000;
// blink the user LED
uint32_t led_timer = 0;
while (1) {
reg_leds = led_timer >> 16;
led_timer = led_timer + 1;
}
}

View File

@@ -0,0 +1,80 @@
Memory Configuration
Name Origin Length Attributes
FLASH 0x0000000000050000 0x0000000000100000 xr
RAM 0x0000000000000000 0x0000000000002000 xrw
*default* 0x0000000000000000 0xffffffffffffffff
Linker script and memory map
.text 0x0000000000050000 0x1dc
0x0000000000050000 . = ALIGN (0x4)
*(.text)
.text 0x0000000000050000 0x16a /tmp/ccBvQ25N.o
.text 0x000000000005016a 0x72 /tmp/cchneX8U.o
0x000000000005016a set_irq_mask
0x0000000000050170 main
*(.text*)
*(.rodata)
*(.rodata*)
*(.srodata)
*(.srodata*)
*(.eh_frame)
*(.eh_frame*)
0x00000000000501dc . = ALIGN (0x4)
0x00000000000501dc _etext = .
0x00000000000501dc _sidata = _etext
.rela.dyn 0x00000000000501dc 0x0
.rela.text 0x00000000000501dc 0x0 /tmp/ccBvQ25N.o
.data 0x0000000000000000 0x14 load address 0x00000000000501dc
0x0000000000000000 . = ALIGN (0x4)
0x0000000000000000 _sdata = .
0x0000000000000000 _ram_start = .
*(.data)
.data 0x0000000000000000 0x14 /tmp/ccBvQ25N.o
.data 0x0000000000000014 0x0 /tmp/cchneX8U.o
*(.data*)
*(.sdata)
*(.sdata*)
*(.init_array)
*(.init_array*)
0x0000000000000014 . = ALIGN (0x4)
0x0000000000000014 _edata = .
.bss 0x0000000000000014 0x0 load address 0x00000000000501f0
0x0000000000000014 . = ALIGN (0x4)
0x0000000000000014 _sbss = .
*(.bss)
.bss 0x0000000000000014 0x0 /tmp/ccBvQ25N.o
.bss 0x0000000000000014 0x0 /tmp/cchneX8U.o
*(.bss*)
*(.sbss)
*(.sbss*)
*(COMMON)
0x0000000000000014 . = ALIGN (0x4)
0x0000000000000014 _ebss = .
.heap 0x0000000000000014 0x0
0x0000000000000014 . = ALIGN (0x4)
0x0000000000000014 _heap_start = .
LOAD /tmp/ccBvQ25N.o
LOAD /tmp/cchneX8U.o
OUTPUT(firmware.elf elf32-littleriscv)
.comment 0x0000000000000000 0x11
.comment 0x0000000000000000 0x11 /tmp/cchneX8U.o
0x12 (size before relaxing)
Cross Reference Table
Symbol File
_ebss /tmp/cchneX8U.o
_sbss /tmp/cchneX8U.o
debug /tmp/ccBvQ25N.o
main /tmp/cchneX8U.o
/tmp/ccBvQ25N.o
set_irq_mask /tmp/cchneX8U.o

View File

@@ -0,0 +1,94 @@
###############################################################################
#
# TinyFPGA BX constraint file (.pcf)
#
###############################################################################
#
# Copyright (c) 2018, Luke Valenty
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# The views and conclusions contained in the software and documentation are those
# of the authors and should not be interpreted as representing official policies,
# either expressed or implied, of the <project name> project.
#
###############################################################################
####
# TinyFPGA BX information: https://github.com/tinyfpga/TinyFPGA-BX/
####
# Left side of board
set_io --warn-no-port pin_1 A2
set_io --warn-no-port pin_2 A1
set_io --warn-no-port pin_3 B1
set_io --warn-no-port pin_4 C2
set_io --warn-no-port pin_5 C1
set_io --warn-no-port pin_6 D2
set_io --warn-no-port pin_7 D1
set_io --warn-no-port pin_8 E2
set_io --warn-no-port pin_9 E1
set_io --warn-no-port pin_10 G2
set_io --warn-no-port pin_11 H1
set_io --warn-no-port pin_12 J1
set_io --warn-no-port pin_13 H2
# Right side of board
set_io --warn-no-port pin_14 H9
set_io --warn-no-port pin_15 D9
set_io --warn-no-port pin_16 D8
set_io --warn-no-port pin_17 C9
set_io --warn-no-port pin_18 A9
set_io --warn-no-port pin_19 B8
set_io --warn-no-port pin_20 A8
set_io --warn-no-port pin_21 B7
set_io --warn-no-port pin_22 A7
set_io --warn-no-port pin_23 B6
set_io --warn-no-port pin_24 A6
# SPI flash interface on bottom of board
set_io flash_csb F7
set_io flash_clk G7
set_io flash_io0 G6
set_io flash_io1 H7
set_io flash_io2 H4
set_io flash_io3 J8
# General purpose pins on bottom of board
set_io --warn-no-port pin_25 G1
set_io --warn-no-port pin_26 J3
set_io --warn-no-port pin_27 J4
set_io --warn-no-port pin_28 G9
set_io --warn-no-port pin_29 J9
set_io --warn-no-port pin_30 E8
set_io --warn-no-port pin_31 J2
# LED
set_io --warn-no-port user_led B3
# USB
set_io pin_pu A3
set_io pin_usbp B4
set_io pin_usbn A4
# 16MHz clock
set_io clk_16mhz B2

163
examples/picosoc/hardware.v Normal file
View File

@@ -0,0 +1,163 @@
/*
* 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 hardware (
input clk_16mhz,
// onboard USB interface
output pin_pu,
output pin_usbp,
output pin_usbn,
// hardware UART
output pin_1,
input pin_2,
// onboard LED
output user_led,
// onboard SPI flash interface
output flash_csb,
output flash_clk,
inout flash_io0,
inout flash_io1,
inout flash_io2,
inout flash_io3
);
assign pin_pu = 1'b1;
assign pin_usbp = 1'b0;
assign pin_usbn = 1'b0;
wire clk = clk_16mhz;
///////////////////////////////////
// Power-on Reset
///////////////////////////////////
reg [5:0] reset_cnt = 0;
wire resetn = &reset_cnt;
always @(posedge clk) begin
reset_cnt <= reset_cnt + !resetn;
end
///////////////////////////////////
// SPI Flash Interface
///////////////////////////////////
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})
);
///////////////////////////////////
// Peripheral Bus
///////////////////////////////////
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 user_led = gpio[0];
always @(posedge clk) begin
if (!resetn) begin
gpio <= 0;
end else begin
iomem_ready <= 0;
///////////////////////////
// GPIO Peripheral
///////////////////////////
if (iomem_valid && !iomem_ready && iomem_addr[31:24] == 8'h03) 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
///////////////////////////
// Template Peripheral
///////////////////////////
if (iomem_valid && !iomem_ready && iomem_addr[31:24] == 8'h04) begin
iomem_ready <= 1;
iomem_rdata <= 32'h0;
end
end
end
picosoc #(
.PROGADDR_RESET(32'h0005_0000), // beginning of user space in SPI flash
.PROGADDR_IRQ(32'h0005_0010),
.MEM_WORDS(2048) // use 2KBytes of block RAM by default
) soc (
.clk (clk ),
.resetn (resetn ),
.ser_tx (pin_1 ),
.ser_rx (pin_2 ),
.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

2977
examples/picosoc/picorv32.v Normal file
View File

File diff suppressed because it is too large Load Diff

240
examples/picosoc/picosoc.v Normal file
View File

@@ -0,0 +1,240 @@
/*
* 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 PICORV32_V
`error "picosoc.v must be read before picorv32.v!"
`endif
`define PICORV32_REGS picosoc_regs
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 integer MEM_WORDS = 256;
parameter [31:0] STACKADDR = (4*MEM_WORDS); // end of memory
parameter [31:0] PROGADDR_RESET = 32'h 0005_0000; // 1 MB into flash
parameter [31:0] PROGADDR_IRQ = 32'h 0005_0010; // 1 MB into flash
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(1),
.COMPRESSED_ISA(1),
.ENABLE_MUL(1),
.ENABLE_DIV(1),
.ENABLE_IRQ(1),
.ENABLE_IRQ_QREGS(1)
) cpu (
.clk (clk ),
.resetn (resetn ),
.mem_valid (mem_valid ),
.mem_instr (mem_instr ),
.mem_ready (mem_ready ),
.mem_addr (mem_addr ),
.mem_wdata (mem_wdata ),
.mem_wstrb (mem_wstrb ),
.mem_rdata (mem_rdata ),
.irq (irq )
);
spimemio spimemio (
.clk (clk),
.resetn (resetn),
.valid (mem_valid && mem_addr >= 4*MEM_WORDS && mem_addr < 32'h 0200_0000),
.ready (spimem_ready),
.addr (mem_addr[23:0]),
.rdata (spimem_rdata),
.flash_csb (flash_csb ),
.flash_clk (flash_clk ),
.flash_io0_oe (flash_io0_oe),
.flash_io1_oe (flash_io1_oe),
.flash_io2_oe (flash_io2_oe),
.flash_io3_oe (flash_io3_oe),
.flash_io0_do (flash_io0_do),
.flash_io1_do (flash_io1_do),
.flash_io2_do (flash_io2_do),
.flash_io3_do (flash_io3_do),
.flash_io0_di (flash_io0_di),
.flash_io1_di (flash_io1_di),
.flash_io2_di (flash_io2_di),
.flash_io3_di (flash_io3_di),
.cfgreg_we(spimemio_cfgreg_sel ? mem_wstrb : 4'b 0000),
.cfgreg_di(mem_wdata),
.cfgreg_do(spimemio_cfgreg_do)
);
simpleuart simpleuart (
.clk (clk ),
.resetn (resetn ),
.ser_tx (ser_tx ),
.ser_rx (ser_rx ),
.reg_div_we (simpleuart_reg_div_sel ? mem_wstrb : 4'b 0000),
.reg_div_di (mem_wdata),
.reg_div_do (simpleuart_reg_div_do),
.reg_dat_we (simpleuart_reg_dat_sel ? mem_wstrb[0] : 1'b 0),
.reg_dat_re (simpleuart_reg_dat_sel && !mem_wstrb),
.reg_dat_di (mem_wdata),
.reg_dat_do (simpleuart_reg_dat_do),
.reg_dat_wait(simpleuart_reg_dat_wait)
);
always @(posedge clk)
ram_ready <= mem_valid && !mem_ready && mem_addr < 4*MEM_WORDS;
picosoc_mem #(.WORDS(MEM_WORDS)) memory (
.clk(clk),
.wen((mem_valid && !mem_ready && mem_addr < 4*MEM_WORDS) ? mem_wstrb : 4'b0),
.addr(mem_addr[23:2]),
.wdata(mem_wdata),
.rdata(ram_rdata)
);
endmodule
// Implementation note:
// Replace the following two modules with wrappers for your SRAM cells.
module picosoc_regs (
input clk, wen,
input [5:0] waddr,
input [5:0] raddr1,
input [5:0] raddr2,
input [31:0] wdata,
output [31:0] rdata1,
output [31:0] rdata2
);
reg [31:0] regs [0:31];
always @(posedge clk)
if (wen) regs[waddr[4:0]] <= wdata;
assign rdata1 = regs[raddr1[4:0]];
assign rdata2 = regs[raddr2[4:0]];
endmodule
module picosoc_mem #(
parameter integer WORDS = 256
) (
input clk,
input [3:0] wen,
input [21:0] addr,
input [31:0] wdata,
output reg [31:0] rdata
);
reg [31:0] mem [0:WORDS-1];
always @(posedge clk) begin
rdata <= mem[addr];
if (wen[0]) mem[addr][ 7: 0] <= wdata[ 7: 0];
if (wen[1]) mem[addr][15: 8] <= wdata[15: 8];
if (wen[2]) mem[addr][23:16] <= wdata[23:16];
if (wen[3]) mem[addr][31:24] <= wdata[31:24];
end
endmodule

View File

@@ -0,0 +1,213 @@
/* 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
{
/* Stuff in .text.sram is located in SRAM */
. = 0x00000000;
.text.sram : {
*(.text.sram)
}
text_sram_end = .;
/* In "flashpmem" mode everything above 1MB in the flash is */
/* mapped directly into the processor address space */
. = 0x00050000;
.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, .);
/* everything below is goind to be in SRAM */
. = text_sram_end;
.data :
{
*(.data .data.* .gnu.linkonce.d.*)
SORT(CONSTRUCTORS)
}
.data1 : { *(.data1) }
.got : { *(.got.plt) *(.igot.plt) *(.got) *(.igot) }
/* We want the small data sections together, so single-instruction offsets
can access them all, and initialized data all before uninitialized, so
we can shorten the on-disk segment size. */
.sdata :
{
__global_pointer$ = . + 0x800;
*(.srodata.cst16) *(.srodata.cst8) *(.srodata.cst4) *(.srodata.cst2) *(.srodata .srodata.*)
*(.sdata .sdata.* .gnu.linkonce.s.*)
}
_edata = .; PROVIDE (edata = .);
. = .;
__bss_start = .;
.sbss :
{
*(.dynsbss)
*(.sbss .sbss.* .gnu.linkonce.sb.*)
*(.scommon)
}
.bss :
{
*(.dynbss)
*(.bss .bss.* .gnu.linkonce.b.*)
*(COMMON)
/* Align here to ensure that the .bss section occupies space up to
_end. Align after .bss to ensure correct alignment even if the
.bss section disappears because there are no input sections.
FIXME: Why do we need it? When there is no .bss section, we don't
pad the .data section. */
. = ALIGN(. != 0 ? 32 / 8 : 1);
}
. = ALIGN(32 / 8);
. = SEGMENT_START("ldata-segment", .);
. = ALIGN(32 / 8);
_end = .; PROVIDE (end = .);
. = DATA_SEGMENT_END (.);
/* Stabs debugging sections. */
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
.stab.excl 0 : { *(.stab.excl) }
.stab.exclstr 0 : { *(.stab.exclstr) }
.stab.index 0 : { *(.stab.index) }
.stab.indexstr 0 : { *(.stab.indexstr) }
.comment 0 : { *(.comment) }
/* DWARF debug sections.
Symbols in the DWARF debugging sections are relative to the beginning
of the section so we begin them at 0. */
/* DWARF 1 */
.debug 0 : { *(.debug) }
.line 0 : { *(.line) }
/* GNU DWARF 1 extensions */
.debug_srcinfo 0 : { *(.debug_srcinfo) }
.debug_sfnames 0 : { *(.debug_sfnames) }
/* DWARF 1.1 and DWARF 2 */
.debug_aranges 0 : { *(.debug_aranges) }
.debug_pubnames 0 : { *(.debug_pubnames) }
/* DWARF 2 */
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
.debug_abbrev 0 : { *(.debug_abbrev) }
.debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end ) }
.debug_frame 0 : { *(.debug_frame) }
.debug_str 0 : { *(.debug_str) }
.debug_loc 0 : { *(.debug_loc) }
.debug_macinfo 0 : { *(.debug_macinfo) }
/* SGI/MIPS DWARF 2 extensions */
.debug_weaknames 0 : { *(.debug_weaknames) }
.debug_funcnames 0 : { *(.debug_funcnames) }
.debug_typenames 0 : { *(.debug_typenames) }
.debug_varnames 0 : { *(.debug_varnames) }
/* DWARF 3 */
.debug_pubtypes 0 : { *(.debug_pubtypes) }
.debug_ranges 0 : { *(.debug_ranges) }
/* DWARF Extension. */
.debug_macro 0 : { *(.debug_macro) }
.debug_addr 0 : { *(.debug_addr) }
.gnu.attributes 0 : { KEEP (*(.gnu.attributes)) }
/DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) }
}

View File

@@ -0,0 +1,66 @@
MEMORY
{
FLASH (rx) : ORIGIN = 0x00050000, LENGTH = 0x100000 /* entire flash, 1 MiB */
RAM (xrw) : ORIGIN = 0x00000000, LENGTH = 0x002000 /* 8 KB */
}
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.) */
*(.eh_frame)
*(.eh_frame*)
. = 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 */
*(.data) /* .data sections */
*(.data*) /* .data* sections */
*(.sdata) /* .sdata sections */
*(.sdata*) /* .sdata* sections */
*(.init_array) /* .sdata sections */
*(.init_array*) /* .sdata* sections */
. = ALIGN(4);
_edata = .; /* define a global symbol at data end; used by startup code in order to initialise the .data section in RAM */
} >RAM
/* Uninitialized data section */
.bss :
{
. = ALIGN(4);
_sbss = .; /* define a global symbol at bss start; used by startup code */
*(.bss)
*(.bss*)
*(.sbss)
*(.sbss*)
*(COMMON)
. = ALIGN(4);
_ebss = .; /* define a global symbol at bss end; used by startup code */
} >RAM
/* this is to define the start of the heap, and make sure we have a minimum size */
.heap :
{
. = ALIGN(4);
_heap_start = .; /* define a global symbol at heap start */
} >RAM
}

View File

@@ -0,0 +1,137 @@
/*
* PicoSoC - A simple example SoC using PicoRV32
*
* Copyright (C) 2017 Clifford Wolf <clifford@clifford.at>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
module simpleuart (
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 <= 1;
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

403
examples/picosoc/spiflash.v Normal file
View File

@@ -0,0 +1,403 @@
/*
* 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
//
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];
initial begin
$readmemh("firmware.hex", 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

579
examples/picosoc/spimemio.v Normal file
View File

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

219
examples/picosoc/start.S Normal file
View File

@@ -0,0 +1,219 @@
// 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 "custom_ops.S"
.section .data
.balign 4
irq_handler_addr:
.word 0x0000000000000000
soft_q2:
.word 0x0000000000000000
soft_q3:
.word 0x0000000000000000
soft_q0:
.word 0
soft_q1:
.word 0
.section .text
reset_vec:
// no more than 8 bytes here !
j start
.global debug
.balign 16
irq_vec:
/* save registers */
//picorv32_setq_insn(q2, x1)
//picorv32_setq_insn(q3, x2)
sw x1, 4(zero)
sw x2, 8(zero)
picorv32_getq_insn(x1, q0)
sw x1, 12(zero)
picorv32_getq_insn(x1, q1)
sw x1, 16(zero)
// x2 is the stack pointer
lui x2, %hi(4096 - 4*32)
addi x2, x2, %lo(4096 - 4*32)
picorv32_getq_insn(x1, q0)
sw x1, 0*4(x2)
//picorv32_getq_insn(x1, q2)
lw x1, 4(zero)
sw x1, 1*4(x2)
//picorv32_getq_insn(x1, q3)
lw x1, 8(zero)
sw x1, 2*4(x2)
sw x3, 3*4(x2)
sw x4, 4*4(x2)
sw x5, 5*4(x2)
sw x6, 6*4(x2)
sw x7, 7*4(x2)
sw x8, 8*4(x2)
sw x9, 9*4(x2)
sw x10, 10*4(x2)
sw x11, 11*4(x2)
sw x12, 12*4(x2)
sw x13, 13*4(x2)
sw x14, 14*4(x2)
sw x15, 15*4(x2)
sw x16, 16*4(x2)
sw x17, 17*4(x2)
sw x18, 18*4(x2)
sw x19, 19*4(x2)
sw x20, 20*4(x2)
sw x21, 21*4(x2)
sw x22, 22*4(x2)
sw x23, 23*4(x2)
sw x24, 24*4(x2)
sw x25, 25*4(x2)
sw x26, 26*4(x2)
sw x27, 27*4(x2)
sw x28, 28*4(x2)
sw x29, 29*4(x2)
sw x30, 30*4(x2)
sw x31, 31*4(x2)
/* call interrupt handler C function */
// arg0 = interrupt type bitmask
picorv32_getq_insn(a0, q1)
// arg1 = pointer to stored registers
mv a1, x2
// load irq handler address to x1 (ra)
lw x1, 0(zero)
// call to C function
beq x0, x1, 1f
jalr x1, x1, 0
1:
/* restore registers */
lw x1, 0*4(x2)
picorv32_setq_insn(q0, x1)
lw x1, 1*4(x2)
picorv32_setq_insn(q1, x1)
lw x1, 2*4(x2)
//picorv32_setq_insn(q2, x1)
sw x1, 4(zero)
lw x3, 3*4(x2)
lw x4, 4*4(x2)
lw x5, 5*4(x2)
lw x6, 6*4(x2)
lw x7, 7*4(x2)
lw x8, 8*4(x2)
lw x9, 9*4(x2)
lw x10, 10*4(x2)
lw x11, 11*4(x2)
lw x12, 12*4(x2)
lw x13, 13*4(x2)
lw x14, 14*4(x2)
lw x15, 15*4(x2)
lw x16, 16*4(x2)
lw x17, 17*4(x2)
lw x18, 18*4(x2)
lw x19, 19*4(x2)
lw x20, 20*4(x2)
lw x21, 21*4(x2)
lw x22, 22*4(x2)
lw x23, 23*4(x2)
lw x24, 24*4(x2)
lw x25, 25*4(x2)
lw x26, 26*4(x2)
lw x27, 27*4(x2)
lw x28, 28*4(x2)
lw x29, 29*4(x2)
lw x30, 30*4(x2)
lw x31, 31*4(x2)
picorv32_getq_insn(x1, q1)
//picorv32_getq_insn(x2, q2)
lw x2, 4(zero)
//mv a0, x2
//call debug
nop
nop
nop
picorv32_retirq_insn()
/* 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
call main
loop:
j loop