mirror of
https://github.com/tinyfpga/TinyFPGA-BX.git
synced 2025-10-24 11:30:50 -07:00
add picosoc example with simple GPIO LED
This commit is contained in:
15
examples/picosoc/.gitignore
vendored
Normal file
15
examples/picosoc/.gitignore
vendored
Normal 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
30
examples/picosoc/Makefile
Normal 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
|
||||
|
||||
|
||||
|
||||
|
||||
101
examples/picosoc/custom_ops.S
Normal file
101
examples/picosoc/custom_ops.S
Normal 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)
|
||||
43
examples/picosoc/firmware.c
Normal file
43
examples/picosoc/firmware.c
Normal 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;
|
||||
}
|
||||
}
|
||||
80
examples/picosoc/firmware.map
Normal file
80
examples/picosoc/firmware.map
Normal 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
|
||||
94
examples/picosoc/hardware.pcf
Normal file
94
examples/picosoc/hardware.pcf
Normal 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
163
examples/picosoc/hardware.v
Normal 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
2977
examples/picosoc/picorv32.v
Normal file
File diff suppressed because it is too large
Load Diff
240
examples/picosoc/picosoc.v
Normal file
240
examples/picosoc/picosoc.v
Normal 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
|
||||
|
||||
213
examples/picosoc/riscv_flash.ld
Normal file
213
examples/picosoc/riscv_flash.ld
Normal 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_*) }
|
||||
}
|
||||
|
||||
66
examples/picosoc/sections.lds
Normal file
66
examples/picosoc/sections.lds
Normal 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
|
||||
}
|
||||
137
examples/picosoc/simpleuart.v
Normal file
137
examples/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 (
|
||||
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
403
examples/picosoc/spiflash.v
Normal 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
579
examples/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
|
||||
219
examples/picosoc/start.S
Normal file
219
examples/picosoc/start.S
Normal 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
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user