gateware: Initial import of all common parts

Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
changes/37/20537/1
Sylvain Munaut 2020-09-14 10:01:45 +02:00
parent 1599a58344
commit 21b03baf47
25 changed files with 5648 additions and 0 deletions

15
.gitmodules vendored Normal file
View File

@ -0,0 +1,15 @@
[submodule "gateware/build"]
path = gateware/build
url = https://github.com/no2fpga/no2build.git
[submodule "gateware/cores/no2e1"]
path = gateware/cores/no2e1
url = https://github.com/no2fpga/no2e1.git
[submodule "gateware/cores/no2ice40"]
path = gateware/cores/no2ice40
url = https://github.com/no2fpga/no2ice40.git
[submodule "gateware/cores/no2misc"]
path = gateware/cores/no2misc
url = https://github.com/no2fpga/no2misc.git
[submodule "gateware/cores/no2usb"]
path = gateware/cores/no2usb
url = https://github.com/no2fpga/no2usb.git

19
gateware/README.md Normal file
View File

@ -0,0 +1,19 @@
E1 related gateware
===================
This directory contains the iCE40 gateware for various boards hosted
in this repository.
Licensing
---------
Most of the cores/HDL in here is licensed under one of the CERL OHL 2.0
license. See the `doc/` subdirectory for the full license texts and refer
to each file header to know the license applicable to each file.
Some files have been imported from other projects with compatible licenses.
Refer to each file header for the proper copyright and license information.
The repository also includes submodules which have their own licensing
and copyright terms.

1
gateware/build Submodule

@ -0,0 +1 @@
Subproject commit e9d0d86baff55e1341ccd0ab510eb7e17f9c0fb7

3
gateware/common/fw/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
*.elf
*.bin
*.hex

View File

@ -0,0 +1,22 @@
CROSS = riscv-none-embed-
CC := $(CROSS)gcc
OBJCOPY := $(CROSS)objcopy
CFLAGS=-Wall -Os -march=rv32i -mabi=ilp32 -ffreestanding -flto -nostartfiles -fomit-frame-pointer -Wl,--gc-section
all: boot.hex
boot.elf: lnk-boot.lds boot.S
$(CC) $(CFLAGS) -Wl,-Bstatic,-T,lnk-boot.lds,--strip-debug -DAPP_FLASH_ADDR=0x000a0000 -o $@ boot.S
%.bin: %.elf
$(OBJCOPY) -O binary $< $@
%.hex: %.bin
./bin2hex.py $< $@
clean:
rm -f *.bin *.hex *.elf *.o
.PHONY: clean

22
gateware/common/fw/bin2hex.py Executable file
View File

@ -0,0 +1,22 @@
#!/usr/bin/env python3
#
# Converts binary into something that can be used by `readmemh`
#
# Copyright (C) 2020 Sylvain Munaut <tnt@246tNt.com>
# SPDX-License-Identifier: MIT
#
import struct
import sys
def main(argv0, in_name, out_name):
with open(in_name, 'rb') as in_fh, open(out_name, 'w') as out_fh:
while True:
b = in_fh.read(4)
if len(b) < 4:
break
out_fh.write('%08x\n' % struct.unpack('<I', b))
if __name__ == '__main__':
main(*sys.argv)

144
gateware/common/fw/boot.S Normal file
View File

@ -0,0 +1,144 @@
/*
* boot.S
*
* SPI boot code
*
* Copyright (C) 2020 Sylvain Munaut <tnt@246tNt.com>
* SPDX-License-Identifier: MIT
*/
#ifndef APP_FLASH_ADDR
#define APP_FLASH_ADDR 0x00100000
#endif
#ifndef APP_SRAM_ADDR
#define APP_SRAM_ADDR 0x00020000
#endif
#ifndef APP_SIZE
#define APP_SIZE 0x00010000
#endif
.section .text.start
.global _start
_start:
// SPI init
jal spi_init
// Read from flash to SRAM
li a0, APP_SRAM_ADDR
li a1, APP_SIZE
li a2, APP_FLASH_ADDR
jal spi_flash_read
// Setup reboot code
li t0, 0x0002006f
sw t0, 0(zero)
// Jump to main code
j APP_SRAM_ADDR
.equ SPI_BASE, 0x80000000
.equ SPICR0, 4 * 0x08
.equ SPICR1, 4 * 0x09
.equ SPICR2, 4 * 0x0a
.equ SPIBR, 4 * 0x0b
.equ SPISR, 4 * 0x0c
.equ SPITXDR, 4 * 0x0d
.equ SPIRXDR, 4 * 0x0e
.equ SPICSR, 4 * 0x0f
spi_init:
li a0, SPI_BASE
li a1, 0xff
sw a1, SPICR0(a0)
li a1, 0x80
sw a1, SPICR1(a0)
li a1, 0xc0
sw a1, SPICR2(a0)
li a1, 0x03
sw a1, SPIBR(a0)
li a1, 0x0f
sw a1, SPICSR(a0)
ret
// Params:
// a0 - destination pointer
// a1 - length (bytes)
// a2 - flash offset
//
spi_flash_read:
// Save params
mv s0, a0
mv s1, a1
mv s2, ra
// Setup CS
li t0, SPI_BASE
li t1, 0x0e
sw t1, SPICSR(t0)
// Send command
li a0, 0x03
jal _spi_do_one
srli a0, a2, 16
and a0, a0, 0xff
jal _spi_do_one
srli a0, a2, 8
and a0, a0, 0xff
jal _spi_do_one
and a0, a2, 0xff
jal _spi_do_one
// Read loop
_spi_loop:
li a0, 0x00
jal _spi_do_one
sb a0, 0(s0)
addi s0, s0, 1
addi s1, s1, -1
bne s1, zero, _spi_loop
// Release CS
li t0, SPI_BASE
li t1, 0x0f
sw t1, SPICSR(t0)
// Done
jr s2
// Params: a0 - Data to TX
// Returns: a0 - RX data
// Clobbers t0, t1
_spi_do_one:
li t0, SPI_BASE
li t1, 0x08
// Write TX data
sw a0, SPITXDR(t0)
// Wait for RXRDY
1:
lw a0, SPISR(t0)
and a0, a0, t1
bne a0, t1, 1b
// Read RX data
lw a0, SPIRXDR(t0)
// Done
ret

View File

@ -0,0 +1,14 @@
MEMORY
{
ROM (rx) : ORIGIN = 0x00000000, LENGTH = 0x0400
}
ENTRY(_start)
SECTIONS {
.text :
{
. = ALIGN(4);
*(.text.start)
*(.text)
*(.text*)
} >ROM
}

View File

@ -0,0 +1,162 @@
/*
* dfu_helper.v
*
* vim: ts=4 sw=4
*
* Copyright (C) 2020 Sylvain Munaut <tnt@246tNt.com>
* SPDX-License-Identifier: CERN-OHL-P-2.0
*/
`default_nettype none
module dfu_helper #(
parameter integer TIMER_WIDTH = 24,
parameter integer BTN_MODE = 3, // [2] Use btn_tick, [1] Include IO buffer, [0] Invert (active-low)
parameter integer DFU_MODE = 0 // 0 = For user app, 1 = For bootloader
)(
// External control
input wire [1:0] boot_sel,
input wire boot_now,
// Button
input wire btn_pad,
input wire btn_tick,
// Outputs
output wire btn_val,
output reg rst_req,
// Clock
input wire clk,
input wire rst
);
// Signals
// -------
// Button
wire btn_iob;
wire btn_v;
wire btn_r;
wire btn_f;
// Timer and arming logic
reg armed;
reg [TIMER_WIDTH-1:0] timer;
(* keep="true" *) wire timer_act;
// Boot logic
reg [1:0] wb_sel;
reg wb_req;
reg wb_now;
// Button logic
// ------------
// IOB
generate
if (BTN_MODE[1])
SB_IO #(
.PIN_TYPE(6'b000000), // Reg input, no output
.PULLUP(1'b1),
.IO_STANDARD("SB_LVCMOS")
) btn_iob_I (
.PACKAGE_PIN(btn_pad),
.INPUT_CLK (clk),
.D_IN_0 (btn_iob)
);
else
assign btn_iob = btn_pad;
endgenerate
// Deglitch
glitch_filter #(
.L(BTN_MODE[2] ? 2 : 4),
.RST_VAL(BTN_MODE[0]),
.WITH_SYNCHRONIZER(1),
.WITH_SAMP_COND(BTN_MODE[2])
) btn_flt_I (
.in (btn_iob ^ BTN_MODE[0]),
.samp_cond(btn_tick),
.val (btn_v),
.rise (btn_r),
.fall (btn_f),
.clk (clk),
`ifdef SIM
.rst (rst)
`else
// Don't reset so we let the filter settle before
// the rest of the logic engages
.rst (1'b0)
`endif
);
assign btn_val = btn_v;
// Arming & Timer
// --------------
assign timer_act = btn_v ^ armed;
always @(posedge clk or posedge rst)
if (rst)
armed <= 1'b0;
else
armed <= armed | timer[TIMER_WIDTH-2];
always @(posedge clk or posedge rst)
if (rst)
timer <= 0;
else
timer <= timer_act ? { TIMER_WIDTH{1'b0} } : (timer + { { (TIMER_WIDTH-1){1'b0} }, ~timer[TIMER_WIDTH-1] });
// Boot Logic
// ----------
// Decision
always @(posedge clk or posedge rst)
if (rst) begin
wb_sel <= 2'b00;
wb_req <= 1'b0;
rst_req <= 1'b0;
end else if (~wb_req) begin
if (boot_now) begin
// External boot request
wb_sel <= boot_sel;
wb_req <= 1'b1;
rst_req <= 1'b0;
end else begin
if (DFU_MODE == 1) begin
// We're in a DFU bootloader, any button press results in
// boot to application
wb_sel <= 2'b10;
wb_req <= wb_now | (armed & btn_f);
rst_req <= 1'b0;
end else begin
// We're in user application, short press resets the
// logic, long press triggers DFU reboot
wb_sel <= 2'b01;
wb_req <= wb_now | (armed & btn_f & timer[TIMER_WIDTH-1]);
rst_req <= rst_req | (armed & btn_f & ~timer[TIMER_WIDTH-1]);
end
end
end
// Ensure select bits are set before the boot pulse
always @(posedge clk or posedge rst)
if (rst)
wb_now <= 1'b0;
else
wb_now <= wb_req;
// IP core
SB_WARMBOOT warmboot (
.BOOT(wb_now),
.S0(wb_sel[0]),
.S1(wb_sel[1])
);
endmodule // dfu_helper

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,544 @@
/*
* soc_base.v
*
* vim: ts=4 sw=4
*
* Minimal common base for the E1 project SoC
*
* Copyright (C) 2019-2020 Sylvain Munaut <tnt@246tNt.com>
* SPDX-License-Identifier: CERN-OHL-S-2.0
*/
`default_nettype none
module soc_base #(
parameter integer WB_N = 1,
parameter integer E1_N = 1,
parameter E1_UNIT_HAS_RX = 1'b1,
parameter E1_UNIT_HAS_TX = 1'b1,
parameter integer E1_LIU = 0
)(
// E1 pads
// Raw PHY
input wire [E1_N-1:0] e1_rx_hi_p,
input wire [E1_N-1:0] e1_rx_hi_n,
input wire [E1_N-1:0] e1_rx_lo_p,
input wire [E1_N-1:0] e1_rx_lo_n,
output wire [E1_N-1:0] e1_tx_hi,
output wire [E1_N-1:0] e1_tx_lo,
// LIU
input wire [E1_N-1:0] e1_rx_data,
input wire [E1_N-1:0] e1_rx_clk,
output wire [E1_N-1:0] e1_tx_data,
output wire [E1_N-1:0] e1_tx_clk,
// USB
inout wire usb_dp,
inout wire usb_dn,
output wire usb_pu,
// Flash SPI (raw)
input wire flash_mosi_i,
output wire flash_mosi_o,
output wire flash_mosi_oe,
input wire flash_miso_i,
output wire flash_miso_o,
output wire flash_miso_oe,
input wire flash_clk_i,
output wire flash_clk_o,
output wire flash_clk_oe,
output wire flash_csn_o,
// Debug UART
input wire dbg_rx,
output wire dbg_tx,
// RGB LEDs
output wire [2:0] rgb,
// External Master Wishbone bus (CPU -> Peripheral)
output wire [15:0] wb_m_addr,
input wire [(WB_N*32)-1:0] wb_m_rdata,
output wire [31:0] wb_m_wdata,
output wire [ 3:0] wb_m_wmsk,
output wire wb_m_we,
output wire [ WB_N -1:0] wb_m_cyc,
input wire [ WB_N -1:0] wb_m_ack,
// Ticks
output wire [E1_N-1:0] tick_e1_rx,
output wire [E1_N-1:0] tick_e1_tx,
output wire tick_usb_sof,
// Clock / Reset
input wire clk_sys,
input wire rst_sys,
input wire clk_48m,
input wire rst_48m
);
genvar i;
localparam integer WB_LN = 8;
localparam integer WB_TN = WB_N + WB_LN;
localparam integer WB_DW = 32;
localparam integer WB_MW = WB_DW / 8;
localparam integer WB_AW = 16;
localparam integer WB_AI = 2;
// Signals
// -------
// Picorv32 native bus
wire pb_valid;
wire pb_instr;
wire pb_ready;
wire [31:0] pb_addr;
wire [31:0] pb_rdata;
wire [31:0] pb_wdata;
wire [ 3:0] pb_wstrb;
// SoC RAM
// BRAM
wire [ 7:0] bram_addr;
wire [31:0] bram_rdata;
wire [31:0] bram_wdata;
wire [ 3:0] bram_wmsk;
wire bram_we;
// SPRAM
wire [14:0] spram_addr;
wire [31:0] spram_rdata;
wire [31:0] spram_wdata;
wire [ 3:0] spram_wmsk;
wire spram_we;
// Peripheral wishbone
wire [WB_AW-1:0] wb_addr;
wire [WB_DW-1:0] wb_rdata [0:WB_LN-1];
wire [WB_DW-1:0] wb_wdata;
wire [WB_MW-1:0] wb_wmsk;
wire wb_we;
wire [WB_TN-1:0] wb_cyc;
wire [WB_TN-1:0] wb_ack;
wire [(WB_DW*WB_TN)-1:0] wb_rdata_flat;
// USB
// Wishbone ( @ 48 MHz )
wire [11:0] ub_addr;
wire [15:0] ub_rdata;
wire [15:0] ub_wdata;
wire ub_we;
wire ub_cyc;
wire ub_ack;
// EP interface
wire [ 8:0] ep_tx_addr_0;
wire [31:0] ep_tx_data_0;
wire ep_tx_we_0;
wire [ 8:0] ep_rx_addr_0;
wire [31:0] ep_rx_data_1;
wire ep_rx_re_0;
// SoF
wire usb_sof;
// Wishbone bus E1 to IO buffers
wire [13:0] wb_e1_addr;
wire [31:0] wb_e1_rdata;
wire [31:0] wb_e1_wdata;
wire [ 3:0] wb_e1_wmsk;
wire wb_e1_we;
wire wb_e1_cyc;
wire wb_e1_ack;
// E1 buffer interface
wire [(E1_N*8)-1:0] e1_buf_rx_data;
wire [(E1_N*5)-1:0] e1_buf_rx_ts;
wire [(E1_N*4)-1:0] e1_buf_rx_frame;
wire [(E1_N*7)-1:0] e1_buf_rx_mf;
wire [ E1_N -1:0] e1_buf_rx_we;
wire [ E1_N -1:0] e1_buf_rx_rdy;
wire [(E1_N*8)-1:0] e1_buf_tx_data;
wire [(E1_N*5)-1:0] e1_buf_tx_ts;
wire [(E1_N*4)-1:0] e1_buf_tx_frame;
wire [(E1_N*7)-1:0] e1_buf_tx_mf;
wire [ E1_N -1:0] e1_buf_tx_re;
wire [ E1_N -1:0] e1_buf_tx_rdy;
// SoC core
// --------
// Local CPU reset
reg pb_rst_n;
always @(posedge clk_sys or posedge rst_sys)
if (rst_sys)
pb_rst_n <= 1'b0;
else
pb_rst_n <= 1'b1;
// CPU
picorv32 #(
.PROGADDR_RESET(32'h 0000_0000),
.STACKADDR(32'h 0000_0400),
.BARREL_SHIFTER(0),
`ifdef BOARD_E1_TRACER
.TWO_CYCLE_COMPARE(0),
.TWO_CYCLE_ALU(0),
`else
.TWO_CYCLE_COMPARE(0),
.TWO_CYCLE_ALU(1),
`endif
.COMPRESSED_ISA(0),
.ENABLE_COUNTERS(0),
.ENABLE_MUL(0),
.ENABLE_DIV(0),
.ENABLE_IRQ(0),
.ENABLE_IRQ_QREGS(0),
.CATCH_MISALIGN(0),
.CATCH_ILLINSN(0)
) cpu_I (
.clk (clk_sys),
.resetn (pb_rst_n),
.mem_valid (pb_valid),
.mem_instr (pb_instr),
.mem_ready (pb_ready),
.mem_addr (pb_addr),
.mem_wdata (pb_wdata),
.mem_wstrb (pb_wstrb),
.mem_rdata (pb_rdata)
);
// CPU bridge
soc_picorv32_bridge #(
.WB_N (WB_TN),
.WB_DW (32),
.WB_AW (16),
.WB_AI ( 2),
.WB_REG( 0)
) bridge_I (
.pb_addr (pb_addr),
.pb_rdata (pb_rdata),
.pb_wdata (pb_wdata),
.pb_wstrb (pb_wstrb),
.pb_valid (pb_valid),
.pb_ready (pb_ready),
.bram_addr (bram_addr),
.bram_rdata (bram_rdata),
.bram_wdata (bram_wdata),
.bram_wmsk (bram_wmsk),
.bram_we (bram_we),
.spram_addr (spram_addr),
.spram_rdata(spram_rdata),
.spram_wdata(spram_wdata),
.spram_wmsk (spram_wmsk),
.spram_we (spram_we),
.wb_addr (wb_addr),
.wb_rdata (wb_rdata_flat),
.wb_wdata (wb_wdata),
.wb_wmsk (wb_wmsk),
.wb_we (wb_we),
.wb_cyc (wb_cyc),
.wb_ack (wb_ack),
.clk (clk_sys),
.rst (rst_sys)
);
for (i=0; i<WB_LN; i=i+1)
assign wb_rdata_flat[i*WB_DW+:WB_DW] = wb_rdata[i];
// Boot memory - 1k
soc_bram #(
.AW(8),
.INIT_FILE("boot.hex"),
) bram_I (
.addr (bram_addr),
.rdata(bram_rdata),
.wdata(bram_wdata),
.wmsk (bram_wmsk),
.we (bram_we),
.clk (clk_sys)
);
// Main SoC memory - 64k
soc_spram #(
.AW(14)
) spram_I (
.addr (spram_addr[13:0]),
.rdata(spram_rdata),
.wdata(spram_wdata),
.wmsk (spram_wmsk),
.we (spram_we),
.clk (clk_sys)
);
// Peripheral wishbone export
assign wb_m_addr = wb_addr;
assign wb_m_wdata = wb_wdata;
assign wb_m_wmsk = wb_wmsk;
assign wb_m_we = wb_we;
assign wb_m_cyc = wb_cyc[WB_TN-1:WB_LN];
assign wb_rdata_flat[(WB_TN*WB_DW)-1:(WB_LN*WB_DW)] = wb_m_rdata;
assign wb_ack[WB_TN-1:WB_LN] = wb_m_ack;
// SPI [0]
// ---
ice40_spi_wb #(
.N_CS(1),
.WITH_IOB(0),
.UNIT(0)
) spi_I (
.sio_mosi_i (flash_mosi_i),
.sio_mosi_o (flash_mosi_o),
.sio_mosi_oe(flash_mosi_oe),
.sio_miso_i (flash_miso_i),
.sio_miso_o (flash_miso_o),
.sio_miso_oe(flash_miso_oe),
.sio_clk_i (flash_clk_i),
.sio_clk_o (flash_clk_o),
.sio_clk_oe (flash_clk_oe),
.sio_csn_o (flash_csn_o),
.sio_csn_oe (),
.wb_addr (wb_addr[3:0]),
.wb_rdata (wb_rdata[0]),
.wb_wdata (wb_wdata),
.wb_we (wb_we),
.wb_cyc (wb_cyc[0]),
.wb_ack (wb_ack[0]),
.clk (clk_sys),
.rst (rst_sys)
);
// Debug UART [1]
// ----------
uart_wb #(
.DIV_WIDTH(12),
.DW(WB_DW)
) uart_I (
.uart_tx (dbg_tx),
.uart_rx (dbg_rx),
.wb_addr (wb_addr[1:0]),
.wb_rdata (wb_rdata[1]),
.wb_wdata (wb_wdata),
.wb_we (wb_we),
.wb_cyc (wb_cyc[1]),
.wb_ack (wb_ack[1]),
.clk (clk_sys),
.rst (rst_sys)
);
// RGB LEDs [2]
// --------
ice40_rgb_wb #(
.CURRENT_MODE("0b1"),
.RGB0_CURRENT("0b000001"),
.RGB1_CURRENT("0b000001"),
.RGB2_CURRENT("0b000001")
) rgb_I (
.pad_rgb (rgb),
.wb_addr (wb_addr[4:0]),
.wb_rdata (wb_rdata[2]),
.wb_wdata (wb_wdata),
.wb_we (wb_we),
.wb_cyc (wb_cyc[2]),
.wb_ack (wb_ack[2]),
.clk (clk_sys),
.rst (rst_sys)
);
// USB [3]
// ---
// Core instance ( @ 48 MHz )
usb #(
.EPDW(32)
) usb_I (
.pad_dp (usb_dp),
.pad_dn (usb_dn),
.pad_pu (usb_pu),
.ep_tx_addr_0(ep_tx_addr_0),
.ep_tx_data_0(ep_tx_data_0),
.ep_tx_we_0 (ep_tx_we_0),
.ep_rx_addr_0(ep_rx_addr_0),
.ep_rx_data_1(ep_rx_data_1),
.ep_rx_re_0 (ep_rx_re_0),
.ep_clk (clk_sys),
.wb_addr (ub_addr),
.wb_rdata (ub_rdata),
.wb_wdata (ub_wdata),
.wb_we (ub_we),
.wb_cyc (ub_cyc),
.wb_ack (ub_ack),
.sof (usb_sof),
.clk (clk_48m),
.rst (rst_48m)
);
// Cross clock bridge
xclk_wb #(
.DW(16),
.AW(12)
) wb_48m_xclk_I (
.s_addr (wb_addr[11:0]),
.s_rdata(wb_rdata[3][15:0]),
.s_wdata(wb_wdata[15:0]),
.s_we (wb_we),
.s_cyc (wb_cyc[3]),
.s_ack (wb_ack[3]),
.s_clk (clk_sys),
.m_addr (ub_addr),
.m_rdata(ub_rdata),
.m_wdata(ub_wdata),
.m_we (ub_we),
.m_cyc (ub_cyc),
.m_ack (ub_ack),
.m_clk (clk_48m),
.rst (rst_sys)
);
assign wb_rdata[3][31:16] = 16'h0000;
// Cross clock SoF
xclk_strobe sof_xclk_I (
.in_stb (usb_sof),
.in_clk (clk_48m),
.out_stb(tick_usb_sof),
.out_clk(clk_sys),
.rst (rst_sys)
);
// IO buffers & DMA
// ----------------
// [4] USB EP buffer
// [5] E1 SPRAM buffer
// [6] DMA
soc_iobuf iobuf_I (
.wb_cpu_addr (wb_addr),
.wb_cpu_rdata(wb_rdata[4]),
.wb_cpu_wdata(wb_wdata),
.wb_cpu_wmsk (wb_wmsk),
.wb_cpu_we (wb_we),
.wb_cpu_cyc (wb_cyc[6:4]),
.wb_cpu_ack (wb_ack[6:4]),
.wb_e1_addr (wb_e1_addr),
.wb_e1_rdata (wb_e1_rdata),
.wb_e1_wdata (wb_e1_wdata),
.wb_e1_wmsk (wb_e1_wmsk),
.wb_e1_we (wb_e1_we),
.wb_e1_cyc (wb_e1_cyc),
.wb_e1_ack (wb_e1_ack),
.ep_tx_addr_0(ep_tx_addr_0),
.ep_tx_data_0(ep_tx_data_0),
.ep_tx_we_0 (ep_tx_we_0),
.ep_rx_addr_0(ep_rx_addr_0),
.ep_rx_data_1(ep_rx_data_1),
.ep_rx_re_0 (ep_rx_re_0),
.clk (clk_sys),
.rst (rst_sys)
);
assign wb_rdata[5] = 32'h00000000;
assign wb_rdata[6] = 32'h00000000;
// E1 [7]
// --
// E1 wishbone module
e1_wb #(
.N(E1_N),
.UNIT_HAS_RX(E1_UNIT_HAS_RX),
.UNIT_HAS_TX(E1_UNIT_HAS_TX),
.LIU(E1_LIU),
.MFW(7)
) e1_I (
.pad_rx_hi_p (e1_rx_hi_p),
.pad_rx_hi_n (e1_rx_hi_n),
.pad_rx_lo_p (e1_rx_lo_p),
.pad_rx_lo_n (e1_rx_lo_n),
.pad_tx_hi (e1_tx_hi),
.pad_tx_lo (e1_tx_lo),
.pad_rx_data (e1_rx_data),
.pad_rx_clk (e1_rx_clk),
.pad_tx_data (e1_tx_data),
.pad_tx_clk (e1_tx_clk),
.buf_rx_data (e1_buf_rx_data),
.buf_rx_ts (e1_buf_rx_ts),
.buf_rx_frame(e1_buf_rx_frame),
.buf_rx_mf (e1_buf_rx_mf),
.buf_rx_we (e1_buf_rx_we),
.buf_rx_rdy (e1_buf_rx_rdy),
.buf_tx_data (e1_buf_tx_data),
.buf_tx_ts (e1_buf_tx_ts),
.buf_tx_frame(e1_buf_tx_frame),
.buf_tx_mf (e1_buf_tx_mf),
.buf_tx_re (e1_buf_tx_re),
.buf_tx_rdy (e1_buf_tx_rdy),
.wb_addr (wb_addr[7:0]),
.wb_rdata (wb_rdata[7][15:0]),
.wb_wdata (wb_wdata[15:0]),
.wb_we (wb_we),
.wb_cyc (wb_cyc[7]),
.wb_ack (wb_ack[7]),
.irq (),
.tick_rx (tick_e1_rx),
.tick_tx (tick_e1_tx),
.clk (clk_sys),
.rst (rst_sys)
);
assign wb_rdata[7][31:16] = 16'h0000;
// E1 buffer interface to Wishbone
e1_buf_if_wb #(
.N(E1_N),
.UNIT_HAS_RX(E1_UNIT_HAS_RX),
.UNIT_HAS_TX(E1_UNIT_HAS_TX),
.MFW(7),
.DW(32)
) e1_buf_I (
.wb_addr (wb_e1_addr),
.wb_rdata (wb_e1_rdata),
.wb_wdata (wb_e1_wdata),
.wb_wmsk (wb_e1_wmsk),
.wb_we (wb_e1_we),
.wb_cyc (wb_e1_cyc),
.wb_ack (wb_e1_ack),
.buf_rx_data (e1_buf_rx_data),
.buf_rx_ts (e1_buf_rx_ts),
.buf_rx_frame(e1_buf_rx_frame),
.buf_rx_mf (e1_buf_rx_mf),
.buf_rx_we (e1_buf_rx_we),
.buf_rx_rdy (e1_buf_rx_rdy),
.buf_tx_data (e1_buf_tx_data),
.buf_tx_ts (e1_buf_tx_ts),
.buf_tx_frame(e1_buf_tx_frame),
.buf_tx_mf (e1_buf_tx_mf),
.buf_tx_re (e1_buf_tx_re),
.buf_tx_rdy (e1_buf_tx_rdy),
.clk (clk_sys),
.rst (rst_sys)
);
endmodule // soc_base

View File

@ -0,0 +1,38 @@
/*
* soc_bram.v
*
* vim: ts=4 sw=4
*
* Copyright (C) 2020 Sylvain Munaut <tnt@246tNt.com>
* SPDX-License-Identifier: CERN-OHL-P-2.0
*/
`default_nettype none
module soc_bram #(
parameter integer AW = 8,
parameter INIT_FILE = ""
)(
input wire [AW-1:0] addr,
output reg [31:0] rdata,
input wire [31:0] wdata,
input wire [ 3:0] wmsk,
input wire we,
input wire clk
);
reg [31:0] mem [0:(1<<AW)-1];
initial
if (INIT_FILE != "")
$readmemh(INIT_FILE, mem);
always @(posedge clk) begin
rdata <= mem[addr];
if (we & ~wmsk[0]) mem[addr][ 7: 0] <= wdata[ 7: 0];
if (we & ~wmsk[1]) mem[addr][15: 8] <= wdata[15: 8];
if (we & ~wmsk[2]) mem[addr][23:16] <= wdata[23:16];
if (we & ~wmsk[3]) mem[addr][31:24] <= wdata[31:24];
end
endmodule // soc_bram

View File

@ -0,0 +1,261 @@
/*
* soc_iobuf.v
*
* vim: ts=4 sw=4
*
* Copyright (C) 2019-2020 Sylvain Munaut <tnt@246tNt.com>
* SPDX-License-Identifier: CERN-OHL-S-2.0
*/
`default_nettype none
module soc_iobuf (
// Wishbone slave (from CPU)
input wire [15:0] wb_cpu_addr,
output wire [31:0] wb_cpu_rdata,
input wire [31:0] wb_cpu_wdata,
input wire [ 3:0] wb_cpu_wmsk,
input wire wb_cpu_we,
input wire [ 2:0] wb_cpu_cyc, // 0=EP buf, 1=SPRAM, 2=DMA
output wire [ 2:0] wb_cpu_ack,
// Wishbone slave (from E1)
input wire [13:0] wb_e1_addr,
output wire [31:0] wb_e1_rdata,
input wire [31:0] wb_e1_wdata,
input wire [ 3:0] wb_e1_wmsk,
input wire wb_e1_we,
input wire wb_e1_cyc,
output wire wb_e1_ack,
// USB EP-Buf master
output wire [ 8:0] ep_tx_addr_0,
output wire [31:0] ep_tx_data_0,
output wire ep_tx_we_0,
output wire [ 8:0] ep_rx_addr_0,
input wire [31:0] ep_rx_data_1,
output wire ep_rx_re_0,
/* Clock / Reset */
input wire clk,
input wire rst
);
// Signals
// -------
// SPRAM
wire [13:0] spr_addr;
wire [31:0] spr_rdata;
wire [31:0] spr_wdata;
wire [ 3:0] spr_wmsk;
wire spr_we;
wire spr_cyc;
wire spr_ack;
wire [13:0] spr0_addr;
wire [31:0] spr0_rdata;
wire [31:0] spr0_wdata;
wire [ 3:0] spr0_wmsk;
wire spr0_we;
wire spr0_cyc;
wire spr0_ack;
wire [13:0] spr1_addr;
wire [31:0] spr1_rdata;
wire [31:0] spr1_wdata;
wire [ 3:0] spr1_wmsk;
wire spr1_we;
wire spr1_cyc;
wire spr1_ack;
wire [13:0] spr2_addr;
wire [31:0] spr2_rdata;
wire [31:0] spr2_wdata;
wire [ 3:0] spr2_wmsk;
wire spr2_we;
wire spr2_cyc;
wire spr2_ack;
// EP Buffer
wire [ 8:0] epb_addr;
wire [31:0] epb_rdata;
wire [31:0] epb_wdata;
wire epb_we;
wire epb_cyc;
wire epb_ack;
wire [ 8:0] epb0_addr;
wire [31:0] epb0_rdata;
wire [31:0] epb0_wdata;
wire epb0_we;
wire epb0_cyc;
wire epb0_ack;
wire [ 8:0] epb1_addr;
wire [31:0] epb1_rdata;
wire [31:0] epb1_wdata;
wire epb1_we;
wire epb1_cyc;
wire epb1_ack;
// DMA
wire [31:0] wb_rdata_dma;
// SPRAM
// -----
// Instance
ice40_spram_wb #(
.DW(32),
.AW(14),
.ZERO_RDATA(0)
) spram_I (
.wb_addr (spr_addr),
.wb_rdata(spr_rdata),
.wb_wdata(spr_wdata),
.wb_wmsk (spr_wmsk),
.wb_we (spr_we),
.wb_cyc (spr_cyc),
.wb_ack (spr_ack),
.clk (clk),
.rst (rst)
);
// Arbiter
wb_arbiter #(
.N(3),
.DW(32),
.AW(14)
) spram_arb_I (
.s_addr ({spr2_addr, spr1_addr, spr0_addr}),
.s_rdata({spr2_rdata, spr1_rdata, spr0_rdata}),
.s_wdata({spr2_wdata, spr1_wdata, spr0_wdata}),
.s_wmsk ({spr2_wmsk, spr1_wmsk, spr0_wmsk}),
.s_we ({spr2_we, spr1_we, spr0_we}),
.s_cyc ({spr2_cyc, spr1_cyc, spr0_cyc}),
.s_ack ({spr2_ack, spr1_ack, spr0_ack}),
.m_addr (spr_addr),
.m_rdata(spr_rdata),
.m_wdata(spr_wdata),
.m_wmsk (spr_wmsk),
.m_we (spr_we),
.m_cyc (spr_cyc),
.m_ack (spr_ack),
.clk (clk),
.rst (rst)
);
// EP buffer
// ---------
// Instance
wb_epbuf #(
.AW(9),
.DW(32)
) epbuf_I (
.wb_addr (epb_addr),
.wb_rdata (epb_rdata),
.wb_wdata (epb_wdata),
.wb_we (epb_we),
.wb_cyc (epb_cyc),
.wb_ack (epb_ack),
.ep_tx_addr_0(ep_tx_addr_0),
.ep_tx_data_0(ep_tx_data_0),
.ep_tx_we_0 (ep_tx_we_0),
.ep_rx_addr_0(ep_rx_addr_0),
.ep_rx_data_1(ep_rx_data_1),
.ep_rx_re_0 (ep_rx_re_0),
.clk (clk),
.rst (rst)
);
// Arbiter
wb_arbiter #(
.N(2),
.DW(32),
.AW(9)
) epbam_arb_I (
.s_addr ({epb1_addr, epb0_addr}),
.s_rdata({epb1_rdata, epb0_rdata}),
.s_wdata({epb1_wdata, epb0_wdata}),
.s_wmsk (8'hff),
.s_we ({epb1_we, epb0_we}),
.s_cyc ({epb1_cyc, epb0_cyc}),
.s_ack ({epb1_ack, epb0_ack}),
.m_addr (epb_addr),
.m_rdata(epb_rdata),
.m_wdata(epb_wdata),
.m_we (epb_we),
.m_cyc (epb_cyc),
.m_ack (epb_ack),
.clk (clk),
.rst (rst)
);
// DMA
// ---
wb_dma #(
.A0W(14),
.A1W(9),
.DW(32)
) dma_I (
.m0_addr (spr2_addr),
.m0_rdata (spr2_rdata),
.m0_wdata (spr2_wdata),
.m0_we (spr2_we),
.m0_cyc (spr2_cyc),
.m0_ack (spr2_ack),
.m1_addr (epb1_addr),
.m1_rdata (epb1_rdata),
.m1_wdata (epb1_wdata),
.m1_we (epb1_we),
.m1_cyc (epb1_cyc),
.m1_ack (epb1_ack),
.ctl_addr (wb_cpu_addr[1:0]),
.ctl_rdata(wb_rdata_dma),
.ctl_wdata(wb_cpu_wdata),
.ctl_we (wb_cpu_we),
.ctl_cyc (wb_cpu_cyc[2]),
.ctl_ack (wb_cpu_ack[2]),
.clk (clk),
.rst (rst)
);
assign spr2_wmsk = 4'h0;
// External accesses
// -----------------
// CPU
assign spr1_addr = wb_cpu_addr[13:0];
assign spr1_wdata = wb_cpu_wdata;
assign spr1_wmsk = wb_cpu_wmsk;
assign spr1_we = wb_cpu_we;
assign spr1_cyc = wb_cpu_cyc[1];
assign wb_cpu_ack[1] = spr1_ack;
assign epb0_addr = wb_cpu_addr[8:0];
assign epb0_wdata = wb_cpu_wdata;
assign epb0_we = wb_cpu_we;
assign epb0_cyc = wb_cpu_cyc[0];
assign wb_cpu_ack[0] = epb0_ack;
assign wb_cpu_rdata = spr1_rdata | epb0_rdata | wb_rdata_dma;
// E1
assign spr0_addr = wb_e1_addr;
assign spr0_wdata = wb_e1_wdata;
assign spr0_wmsk = wb_e1_wmsk;
assign spr0_we = wb_e1_we;
assign spr0_cyc = wb_e1_cyc;
assign wb_e1_rdata = spr0_rdata;
assign wb_e1_ack = spr0_ack;
endmodule // soc_iobuf

View File

@ -0,0 +1,186 @@
/*
* soc_picorv32_bridge.v
*
* vim: ts=4 sw=4
*
* Copyright (C) 2020 Sylvain Munaut <tnt@246tNt.com>
* SPDX-License-Identifier: CERN-OHL-P-2.0
*/
`default_nettype none
module soc_picorv32_bridge #(
parameter integer WB_N = 8,
parameter integer WB_DW = 32,
parameter integer WB_AW = 16,
parameter integer WB_AI = 2,
parameter integer WB_REG = 0 // [0] = cyc / [1] = addr/wdata/wstrb / [2] = ack/rdata
)(
/* PicoRV32 bus */
input wire [31:0] pb_addr,
output wire [31:0] pb_rdata,
input wire [31:0] pb_wdata,
input wire [ 3:0] pb_wstrb,
input wire pb_valid,
output wire pb_ready,
/* BRAM */
output wire [ 7:0] bram_addr,
input wire [31:0] bram_rdata,
output wire [31:0] bram_wdata,
output wire [ 3:0] bram_wmsk,
output wire bram_we,
/* SPRAM */
output wire [14:0] spram_addr,
input wire [31:0] spram_rdata,
output wire [31:0] spram_wdata,
output wire [ 3:0] spram_wmsk,
output wire spram_we,
/* Wishbone buses */
output wire [WB_AW-1:0] wb_addr,
input wire [(WB_DW*WB_N)-1:0] wb_rdata,
output wire [WB_DW-1:0] wb_wdata,
output wire [(WB_DW/8)-1:0] wb_wmsk,
output wire wb_we,
output wire [WB_N-1:0] wb_cyc,
input wire [WB_N-1:0] wb_ack,
/* Clock / Reset */
input wire clk,
input wire rst
);
// Signals
// -------
wire ram_sel;
reg ram_rdy;
wire [31:0] ram_rdata;
(* keep *) wire [WB_N-1:0] wb_match;
(* keep *) wire wb_cyc_rst;
reg [31:0] wb_rdata_or;
wire [31:0] wb_rdata_out;
wire wb_rdy;
// RAM access
// ----------
// BRAM : 0x00000000 -> 0x000003ff
// SPRAM : 0x00020000 -> 0x0003ffff
assign bram_addr = pb_addr[ 9:2];
assign spram_addr = pb_addr[16:2];
assign bram_wdata = pb_wdata;
assign spram_wdata = pb_wdata;
assign bram_wmsk = ~pb_wstrb;
assign spram_wmsk = ~pb_wstrb;
assign bram_we = pb_valid & ~pb_addr[31] & |pb_wstrb & ~pb_addr[17];
assign spram_we = pb_valid & ~pb_addr[31] & |pb_wstrb & pb_addr[17];
assign ram_rdata = ~pb_addr[31] ? (pb_addr[17] ? spram_rdata : bram_rdata) : 32'h00000000;
assign ram_sel = pb_valid & ~pb_addr[31];
always @(posedge clk)
ram_rdy <= ram_sel && ~ram_rdy;
// Wishbone
// --------
// wb[x] = 0x8x000000 - 0x8xffffff
// Access Cycle
genvar i;
for (i=0; i<WB_N; i=i+1)
assign wb_match[i] = (pb_addr[27:24] == i);
if (WB_REG & 1) begin
// Register
reg [WB_N-1:0] wb_cyc_reg;
always @(posedge clk)
if (wb_cyc_rst)
wb_cyc_reg <= 0;
else
wb_cyc_reg <= wb_match & ~wb_ack;
assign wb_cyc = wb_cyc_reg;
end else begin
// Direct connection
assign wb_cyc = wb_cyc_rst ? { WB_N{1'b0} } : wb_match;
end
// Addr / Write-Data / Write-Mask / Write-Enable
if (WB_REG & 2) begin
// Register
reg [WB_AW-1:0] wb_addr_reg;
reg [WB_DW-1:0] wb_wdata_reg;
reg [(WB_DW/8)-1:0] wb_wmsk_reg;
reg wb_we_reg;
always @(posedge clk)
begin
wb_addr_reg <= pb_addr[WB_AW+WB_AI-1:WB_AI];
wb_wdata_reg <= pb_wdata[WB_DW-1:0];
wb_wmsk_reg <= ~pb_wstrb[(WB_DW/8)-1:0];
wb_we_reg <= |pb_wstrb;
end
assign wb_addr = wb_addr_reg;
assign wb_wdata = wb_wdata_reg;
assign wb_wmsk = wb_wmsk_reg;
assign wb_we = wb_we_reg;
end else begin
// Direct connection
assign wb_addr = pb_addr[WB_AW+WB_AI-1:WB_AI];
assign wb_wdata = pb_wdata[WB_DW-1:0];
assign wb_wmsk = pb_wstrb[(WB_DW/8)-1:0];
assign wb_we = |pb_wstrb;
end
// Ack / Read-Data
always @(*)
begin : wb_or
integer i;
wb_rdata_or = 0;
for (i=0; i<WB_N; i=i+1)
wb_rdata_or[WB_DW-1:0] = wb_rdata_or[WB_DW-1:0] | wb_rdata[WB_DW*i+:WB_DW];
end
if (WB_REG & 4) begin
// Register
reg wb_rdy_reg;
reg [31:0] wb_rdata_reg;
always @(posedge clk)
wb_rdy_reg <= |wb_ack;
always @(posedge clk)
if (wb_cyc_rst)
wb_rdata_reg <= 32'h00000000;
else
wb_rdata_reg <= wb_rdata_or;
assign wb_cyc_rst = ~pb_valid | ~pb_addr[31] | wb_rdy_reg;
assign wb_rdy = wb_rdy_reg;
assign wb_rdata_out = wb_rdata_reg;
end else begin
// Direct connection
assign wb_cyc_rst = ~pb_valid | ~pb_addr[31];
assign wb_rdy = |wb_ack;
assign wb_rdata_out = wb_rdata_or;
end
// Final data combining
// --------------------
assign pb_rdata = ram_rdata | wb_rdata_out;
assign pb_ready = ram_rdy | wb_rdy;
endmodule // soc_picorv32_bridge

View File

@ -0,0 +1,43 @@
/*
* soc_spram.v
*
* vim: ts=4 sw=4
*
* Copyright (C) 2020 Sylvain Munaut <tnt@246tNt.com>
* SPDX-License-Identifier: CERN-OHL-P-2.0
*/
`default_nettype none
module soc_spram #(
parameter integer AW = 14
)(
input wire [AW-1:0] addr,
output wire [31:0] rdata,
input wire [31:0] wdata,
input wire [ 3:0] wmsk,
input wire we,
input wire clk
);
wire [7:0] msk_nibble = {
wmsk[3], wmsk[3],
wmsk[2], wmsk[2],
wmsk[1], wmsk[1],
wmsk[0], wmsk[0]
};
ice40_spram_gen #(
.ADDR_WIDTH(AW),
.DATA_WIDTH(32)
) spram_I (
.addr(addr),
.rd_data(rdata),
.rd_ena(1'b1),
.wr_data(wdata),
.wr_mask(msk_nibble),
.wr_ena(we),
.clk(clk)
);
endmodule // soc_spram

View File

@ -0,0 +1,127 @@
/*
* wb_arbiter.v
*
* vim: ts=4 sw=4
*
* Copyright (C) 2020 Sylvain Munaut <tnt@246tNt.com>
* SPDX-License-Identifier: CERN-OHL-P-2.0
*/
`default_nettype none
module wb_arbiter #(
parameter integer N = 3,
parameter integer DW = 32,
parameter integer AW = 16,