gateware: Initial import of the FPGA gateware
Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
This commit is contained in:
parent
bf1310fd5d
commit
c85dc29b06
|
@ -0,0 +1,12 @@
|
|||
[submodule "gateware/build"]
|
||||
path = gateware/build
|
||||
url = https://github.com/no2fpga/no2build
|
||||
[submodule "gateware/cores/no2ice40"]
|
||||
path = gateware/cores/no2ice40
|
||||
url = https://github.com/no2fpga/no2ice40
|
||||
[submodule "gateware/cores/no2misc"]
|
||||
path = gateware/cores/no2misc
|
||||
url = https://github.com/no2fpga/no2misc
|
||||
[submodule "gateware/cores/no2usb"]
|
||||
path = gateware/cores/no2usb
|
||||
url = https://github.com/no2fpga/no2usb
|
|
@ -0,0 +1,60 @@
|
|||
# Project config
|
||||
PROJ=xmas-snoopy
|
||||
|
||||
PROJ_DEPS := no2ice40 no2misc no2usb
|
||||
PROJ_RTL_SRCS := $(addprefix rtl/, \
|
||||
led_ctrl.v \
|
||||
picorv32_ice40_regs.v \
|
||||
picorv32.v \
|
||||
pmu.v \
|
||||
soc_bram.v \
|
||||
soc_picorv32_base.v \
|
||||
soc_picorv32_bridge.v \
|
||||
soc_spram.v \
|
||||
soc_usb_buf_bridge.v \
|
||||
sysmgr_1.v \
|
||||
xclk_cnt.v \
|
||||
xclk_pulse.v \
|
||||
)
|
||||
|
||||
PROJ_SIM_SRCS := $(addprefix sim/, \
|
||||
spiflash.v \
|
||||
sysmgr_sim.v \
|
||||
)
|
||||
PROJ_SIM_SRCS += rtl/top.v
|
||||
|
||||
PROJ_TESTBENCHES=\
|
||||
led_ctrl_tb \
|
||||
top_tb \
|
||||
$(NULL)
|
||||
PROJ_PREREQ = \
|
||||
$(BUILD_TMP)/boot.hex \
|
||||
$(NULL)
|
||||
PROJ_TOP_SRC := rtl/top.v
|
||||
PROJ_TOP_MOD := top
|
||||
|
||||
# Target config
|
||||
BOARD ?= xmas-snoopy
|
||||
DEVICE := up5k
|
||||
PACKAGE := sg48
|
||||
|
||||
# Toolchain options
|
||||
YOSYS_SYNTH_ARGS := -dsp -dffe_min_ce_use 4
|
||||
NEXTPNR_SEED ?= 1
|
||||
NEXTPNR_ARGS := --no-promote-globals --seed $(NEXTPNR_SEED) --pre-pack data/clocks.py
|
||||
ICEPACK_ARGS :=
|
||||
|
||||
# Include default rules
|
||||
NO2BUILD_DIR ?= build
|
||||
include $(NO2BUILD_DIR)/project-rules.mk
|
||||
|
||||
# Custom rules
|
||||
fw_boot_build:
|
||||
|
||||
../firmware/boot/boot.hex: fw_boot_build
|
||||
make -C ../firmware/boot boot.hex
|
||||
|
||||
$(BUILD_TMP)/boot.hex: ../firmware/boot/boot.hex
|
||||
cp $< $@
|
||||
|
||||
.PHONY: fw_boot_build
|
|
@ -0,0 +1 @@
|
|||
Subproject commit ab34622c8220a45f6b084b793a945e28eac2def4
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 97413633237ef5ad899f04e0b4b22679c5f6f6bb
|
|
@ -0,0 +1 @@
|
|||
Subproject commit a494fc73cf5466f34ec040f3e9ab3e341a305114
|
|
@ -0,0 +1 @@
|
|||
Subproject commit fdf42a6571a4ae49556626e6fffca1582796f7e8
|
|
@ -0,0 +1,4 @@
|
|||
ctx.addClock("clk_led", 6)
|
||||
ctx.addClock("clk_sys", 24)
|
||||
ctx.addClock("clk_usb", 48)
|
||||
ctx.addClock("pmu_I.btn_clk", 20) # Just to avoid screwing the histogram
|
|
@ -0,0 +1,49 @@
|
|||
# SPI
|
||||
set_io -nowarn -pullup yes spi_io[0] 14
|
||||
set_io -nowarn -pullup yes spi_io[1] 17
|
||||
set_io -nowarn -pullup yes spi_io[2] 20
|
||||
set_io -nowarn -pullup yes spi_io[3] 13
|
||||
set_io -nowarn -pullup yes spi_clk 15
|
||||
set_io -nowarn -pullup yes spi_cs_n 16
|
||||
|
||||
# USB
|
||||
set_io -nowarn -pullup no usb_dp 19
|
||||
set_io -nowarn -pullup no usb_dn 18
|
||||
set_io -nowarn -pullup no usb_pu 21
|
||||
|
||||
# Power
|
||||
set_io -nowarn -pullup yes pwr_usb_n 45
|
||||
set_io -nowarn -pullup yes pwr_chg_n 44
|
||||
set_io -nowarn -pullup no pwr_off 47
|
||||
|
||||
# Buttons
|
||||
set_io -nowarn -pullup yes btn[0] 46
|
||||
set_io -nowarn -pullup yes btn[1] 48
|
||||
|
||||
# I2C
|
||||
set_io -nowarn -pullup yes -pullup_resistor 10K scl 10
|
||||
set_io -nowarn -pullup yes -pullup_resistor 10K sda 11
|
||||
|
||||
# Speaker
|
||||
set_io -nowarn -pullup no hp_p 4
|
||||
set_io -nowarn -pullup no hp_n 3
|
||||
|
||||
# LED matrix
|
||||
set_io -nowarn -pullup no led_a[0] 42
|
||||
set_io -nowarn -pullup no led_a[1] 43
|
||||
set_io -nowarn -pullup no led_a[2] 23
|
||||
set_io -nowarn -pullup no led_a[3] 25
|
||||
set_io -nowarn -pullup no led_a[4] 26
|
||||
set_io -nowarn -pullup no led_a[5] 27
|
||||
set_io -nowarn -pullup no led_a[6] 28
|
||||
set_io -nowarn -pullup no led_a[7] 31
|
||||
set_io -nowarn -pullup no led_a[8] 32
|
||||
set_io -nowarn -pullup no led_a[9] 34
|
||||
set_io -nowarn -pullup no led_a[10] 35
|
||||
set_io -nowarn -pullup no led_a[11] 36
|
||||
set_io -nowarn -pullup no led_a[12] 37
|
||||
set_io -nowarn -pullup no led_a[13] 38
|
||||
|
||||
set_io -nowarn led_c[0] 39
|
||||
set_io -nowarn led_c[1] 40
|
||||
set_io -nowarn led_c[2] 41
|
|
@ -0,0 +1,460 @@
|
|||
/*
|
||||
* led_ctrl.v
|
||||
*
|
||||
* vim: ts=4 sw=4
|
||||
*
|
||||
* LED controller
|
||||
*
|
||||
* Copyright (C) 2023 Sylvain Munaut <tnt@246tNt.com>
|
||||
* SPDX-License-Identifier: CERN-OHL-P-2.0
|
||||
*/
|
||||
|
||||
`default_nettype none
|
||||
|
||||
module led_ctrl (
|
||||
// LED matrix
|
||||
output wire [13:0] led_a,
|
||||
output wire [2:0] led_c,
|
||||
|
||||
input wire led_clk,
|
||||
input wire led_rst,
|
||||
|
||||
// Status output
|
||||
output reg trig_out,
|
||||
|
||||
// Wishbone
|
||||
input wire [15:0] wb_addr,
|
||||
output reg [31:0] wb_rdata,
|
||||
input wire [31:0] wb_wdata,
|
||||
input wire wb_we,
|
||||
input wire wb_cyc,
|
||||
output reg wb_ack,
|
||||
|
||||
input wire wb_clk,
|
||||
input wire wb_rst
|
||||
);
|
||||
|
||||
//
|
||||
// 6 MHz LED clock
|
||||
//
|
||||
// 16 time slots of 129 cycles -> ~ 2900 Hz PWM rate
|
||||
//
|
||||
// For each time slot :
|
||||
// - Anode sel : 4b
|
||||
// - Start cycle : 7b \__ For each Cathode
|
||||
// - Stop cycle : 7b / x3
|
||||
//
|
||||
// Both the 'Start' and 'Stop' cycle are counted as active
|
||||
// so start=0 and stop=127 means active for 128 cycles.
|
||||
// To be completely off jus set stop < start
|
||||
//
|
||||
// 256 entries in EBR = 16 frames of 16 time slots
|
||||
// Each frame is played 96 times, leading to about ~ 30 fps
|
||||
//
|
||||
|
||||
// Signals
|
||||
// -------
|
||||
|
||||
// Bus access
|
||||
wire bus_clr_rd;
|
||||
wire bus_clr_wr;
|
||||
|
||||
reg bus_we_csr;
|
||||
reg bus_we_mem;
|
||||
|
||||
// CSR
|
||||
reg ctrl_scan_ena;
|
||||
reg ctrl_drv_rgbleden;
|
||||
reg ctrl_drv_curren;
|
||||
reg [3:0] ctrl_trig_frame;
|
||||
reg ctrl_trig_ena;
|
||||
reg ctrl_trig_clr;
|
||||
|
||||
wire [3:0] stat_cur_frame;
|
||||
|
||||
// Frame memory
|
||||
wire [7:0] fmw_addr;
|
||||
wire [47:0] fmw_data;
|
||||
wire [47:0] fmw_mask;
|
||||
wire fmw_ena;
|
||||
|
||||
wire [7:0] fmr_addr;
|
||||
wire [47:0] fmr_data;
|
||||
wire fmr_ena;
|
||||
|
||||
// Control
|
||||
reg [4:0] led_off_sync;
|
||||
wire led_off_0;
|
||||
wire led_off_1;
|
||||
wire led_off_2;
|
||||
|
||||
// Trigger
|
||||
wire trig_upd;
|
||||
wire trig_clr;
|
||||
reg [3:0] trig_frame;
|
||||
reg trig_ena;
|
||||
wire trig_match;
|
||||
|
||||
// Cycle counter
|
||||
wire tick_0;
|
||||
reg tick_1;
|
||||
reg tick_2;
|
||||
|
||||
reg [7:0] cycle_cnt_0;
|
||||
wire [6:0] cycle_0;
|
||||
reg [6:0] cycle_1;
|
||||
|
||||
// Subframe counter
|
||||
reg [3:0] subframe_0;
|
||||
wire subframe_last_0;
|
||||
wire subframe_ce_0;
|
||||
|
||||
// Play counter
|
||||
reg [7:0] play_cnt_0;
|
||||
wire play_last_0;
|
||||
wire play_ce_0;
|
||||
|
||||
// Frame
|
||||
reg [3:0] frame_0;
|
||||
wire frame_ce_0;
|
||||
|
||||
// PWM
|
||||
wire [6:0] cyc_start_1[0:2];
|
||||
wire [6:0] cyc_stop_1[0:2];
|
||||
|
||||
reg [2:0] sig_start_1;
|
||||
reg [2:0] sig_stop_1;
|
||||
|
||||
reg [2:0] started_2;
|
||||
reg [2:0] stopped_2;
|
||||
|
||||
// Anode/Cathode
|
||||
wire [3:0] led_a_1;
|
||||
reg [13:0] led_a_2;
|
||||
|
||||
reg [2:0] led_c_3;
|
||||
|
||||
|
||||
// Bus interface
|
||||
// -------------
|
||||
|
||||
// Ack
|
||||
always @(posedge wb_clk)
|
||||
wb_ack <= wb_cyc & ~wb_ack;
|
||||
|
||||
// Clear signals
|
||||
assign bus_clr_rd = wb_ack | ~wb_cyc;
|
||||
assign bus_clr_wr = wb_ack | ~wb_cyc | ~wb_we;
|
||||
|
||||
// Reads
|
||||
always @(posedge wb_clk)
|
||||
if (bus_clr_rd)
|
||||
wb_rdata <= 32'h00000000;
|
||||
else
|
||||
wb_rdata <= {
|
||||
trig_out, /* [31] */
|
||||
ctrl_trig_ena, /* [30] */
|
||||
2'b00, /* [29:28] */
|
||||
ctrl_trig_frame, /* [27:24] */
|
||||
4'b0000, /* [23:20] */
|
||||
stat_cur_frame, /* [19:16] */
|
||||
13'h0000, /* [15: 3] */
|
||||
ctrl_drv_curren, /* [ 2] */
|
||||
ctrl_drv_rgbleden, /* [ 1] */
|
||||
ctrl_scan_ena /* [ 0] */
|
||||
};
|
||||
|
||||
xclk_cnt #(
|
||||
.WIDTH(4)
|
||||
) xclk_frame_I (
|
||||
.i_val (frame_0),
|
||||
.i_clk (led_clk),
|
||||
.o_val (stat_cur_frame),
|
||||
.o_clk (wb_clk),
|
||||
.rst (led_clk | wb_clk)
|
||||
);
|
||||
|
||||
// Write strobes
|
||||
always @(posedge wb_clk)
|
||||
if (bus_clr_wr) begin
|
||||
bus_we_csr <= 1'b0;
|
||||
bus_we_mem <= 1'b0;
|
||||
end else begin
|
||||
bus_we_csr <= ~wb_addr[9];
|
||||
bus_we_mem <= wb_addr[9];
|
||||
end
|
||||
|
||||
// Writes to CSR
|
||||
always @(posedge wb_clk or posedge wb_rst)
|
||||
if (wb_rst) begin
|
||||
ctrl_scan_ena <= 1'b0;
|
||||
ctrl_drv_rgbleden <= 1'b0;
|
||||
ctrl_drv_curren <= 1'b0;
|
||||
ctrl_trig_frame <= 4'h0;
|
||||
ctrl_trig_ena <= 1'b0;
|
||||
end else if (bus_we_csr) begin
|
||||
ctrl_scan_ena <= wb_wdata[0];
|
||||
ctrl_drv_rgbleden <= wb_wdata[1];
|
||||
ctrl_drv_curren <= wb_wdata[2];
|
||||
ctrl_trig_frame <= wb_wdata[27:24];
|
||||
ctrl_trig_ena <= wb_wdata[30];
|
||||
end
|
||||
|
||||
always @(posedge wb_clk)
|
||||
ctrl_trig_clr <= bus_we_csr & wb_wdata[31];
|
||||
|
||||
// Writes to Frame Memory
|
||||
assign fmw_addr = wb_addr[8:1];
|
||||
assign fmw_ena = bus_we_mem;
|
||||
|
||||
assign fmw_data = {
|
||||
2'b00, /* [47:46] n/a */
|
||||
wb_wdata[22:16], /* [45:39] cyc_start[2] */
|
||||
wb_wdata[30:24], /* [38:32] cyc_stop [2] */
|
||||
wb_wdata[ 6: 0], /* [31:25] cyc_start[1] */
|
||||
wb_wdata[14: 8], /* [24:18] cyc_stop [1] */
|
||||
wb_wdata[22:16], /* [17:11] cyc_start[0] */
|
||||
wb_wdata[30:24], /* [10: 4] cyc_stop [0] */
|
||||
wb_wdata[ 3: 0] /* [ 3: 0] anode_sel */
|
||||
};
|
||||
|
||||
assign fmw_mask = {
|
||||
2'b11, /* [47:46] n/a */
|
||||
{7{~wb_addr[0]}}, /* [45:39] cyc_start[2] */
|
||||
{7{~wb_addr[0]}}, /* [38:32] cyc_stop [2] */
|
||||
{7{~wb_addr[0]}}, /* [31:25] cyc_start[1] */
|
||||
{7{~wb_addr[0]}}, /* [24:18] cyc_stop [1] */
|
||||
{7{ wb_addr[0]}}, /* [17:11] cyc_start[0] */
|
||||
{7{ wb_addr[0]}}, /* [10: 4] cyc_stop [0] */
|
||||
{4{ wb_addr[0]}} /* [ 3: 0] anode_sel */
|
||||
};
|
||||
|
||||
|
||||
// Frame memory
|
||||
// ------------
|
||||
|
||||
ice40_ebr #(
|
||||
.READ_MODE (0),
|
||||
.WRITE_MODE (0)
|
||||
) frame_mem_I[2:0] (
|
||||
.wr_addr (fmw_addr),
|
||||
.wr_data (fmw_data),
|
||||
.wr_mask (fmw_mask),
|
||||
.wr_ena (fmw_ena),
|
||||
.wr_clk (wb_clk),
|
||||
.rd_addr (fmr_addr),
|
||||
.rd_data (fmr_data),
|
||||
.rd_ena (fmr_ena),
|
||||
.rd_clk (led_clk)
|
||||
);
|
||||
|
||||
|
||||
// LED clock domain control
|
||||
// ------------------------
|
||||
|
||||
// Enable
|
||||
always @(posedge led_clk or posedge led_rst)
|
||||
if (led_rst)
|
||||
led_off_sync <= 5'b11111;
|
||||
else
|
||||
led_off_sync <= { led_off_sync[3:0], ~ctrl_scan_ena };
|
||||
|
||||
assign led_off_0 = led_off_sync[2];
|
||||
assign led_off_1 = led_off_sync[3];
|
||||
assign led_off_2 = led_off_sync[4];
|
||||
|
||||
// Trigger
|
||||
xclk_pulse xclk_trig_upd_I (
|
||||
.i_stb (bus_we_csr),
|
||||
.i_clk (wb_clk),
|
||||
.o_stb (trig_upd),
|
||||
.o_clk (led_clk),
|
||||
.rst (led_rst | wb_rst)
|
||||
);
|
||||
|
||||
xclk_pulse xclk_trig_clr_I (
|
||||
.i_stb (ctrl_trig_clr),
|
||||
.i_clk (wb_clk),
|
||||
.o_stb (trig_clr),
|
||||
.o_clk (led_clk),
|
||||
.rst (led_rst | wb_rst)
|
||||
);
|
||||
|
||||
always @(posedge led_clk or posedge led_rst)
|
||||
if (led_rst) begin
|
||||
trig_frame <= 4'h0;
|
||||
trig_ena <= 1'b0;
|
||||
end else if (trig_upd) begin
|
||||
trig_frame <= ctrl_trig_frame;
|
||||
trig_ena <= ctrl_trig_ena;
|
||||
end
|
||||
|
||||
assign trig_match = trig_ena & (trig_frame == frame_0) & frame_ce_0;
|
||||
|
||||
always @(posedge led_clk or posedge led_rst)
|
||||
if (led_rst)
|
||||
trig_out <= 1'b0;
|
||||
else
|
||||
trig_out <= (trig_out | trig_match) & ~trig_clr;
|
||||
|
||||
|
||||
// Cycle counter
|
||||
// -------------
|
||||
|
||||
// Counter
|
||||
always @(posedge led_clk or posedge led_off_0)
|
||||
if (led_off_0)
|
||||
cycle_cnt_0 <= 8'h80;
|
||||
else
|
||||
cycle_cnt_0 <= tick_0 ? 8'h00 : (cycle_cnt_0 + 1);
|
||||
|
||||
// Cycle
|
||||
assign cycle_0 = cycle_cnt_0[6:0];
|
||||
|
||||
always @(posedge led_clk)
|
||||
cycle_1 <= cycle_0;
|
||||
|
||||
// Ticks
|
||||
assign tick_0 = cycle_cnt_0[7] & ~led_off_0;
|
||||
|
||||
always @(posedge led_clk)
|
||||
{ tick_2, tick_1 } <= { tick_1, tick_0 };
|
||||
|
||||
|
||||
// Subframe counter
|
||||
// ----------------
|
||||
|
||||
always @(posedge led_clk or posedge led_off_0)
|
||||
if (led_off_0)
|
||||
subframe_0 <= 4'h0;
|
||||
else if (subframe_ce_0)
|
||||
subframe_0 <= subframe_0 + 1;
|
||||
|
||||
assign subframe_last_0 = (subframe_0 == 4'hf);
|
||||
assign subframe_ce_0 = tick_0;
|
||||
|
||||
|
||||
// Play counter
|
||||
// ------------
|
||||
|
||||
always @(posedge led_clk or posedge led_off_0)
|
||||
if (led_off_0)
|
||||
play_cnt_0 <= 0;
|
||||
else if (play_ce_0)
|
||||
play_cnt_0 <= play_last_0 ? 8'd94 : (play_cnt_0 - 1);
|
||||
|
||||
assign play_last_0 = play_cnt_0[7];
|
||||
assign play_ce_0 = tick_0 & subframe_last_0;
|
||||
|
||||
|
||||
// Frame counter
|
||||
// -------------
|
||||
|
||||
always @(posedge led_clk or posedge led_off_0)
|
||||
if (led_off_0)
|
||||
frame_0 <= 0;
|
||||
else if (frame_ce_0)
|
||||
frame_0 <= frame_0 + 1;
|
||||
|
||||
assign frame_ce_0 = tick_0 & subframe_last_0 & play_last_0;
|
||||
|
||||
|
||||
// Frame Memory Lookup
|
||||
// -------------------
|
||||
|
||||
assign fmr_addr = { frame_0, subframe_0 };
|
||||
assign fmr_ena = tick_0;
|
||||
|
||||
assign cyc_start_1[2] = fmr_data[45:39];
|
||||
assign cyc_stop_1[2] = fmr_data[38:32];
|
||||
|
||||
assign cyc_start_1[1] = fmr_data[31:25];
|
||||
assign cyc_stop_1[1] = fmr_data[24:18];
|
||||
|
||||
assign cyc_start_1[0] = fmr_data[17:11];
|
||||
assign cyc_stop_1[0] = fmr_data[10: 4];
|
||||
|
||||
assign led_a_1 = fmr_data[3:0];
|
||||
|
||||
|
||||
// PWM
|
||||
// ---
|
||||
|
||||
genvar i;
|
||||
generate
|
||||
for (i=0; i<3; i=i+1)
|
||||
begin
|
||||
// Comparators (stop is offset !)
|
||||
always @(*)
|
||||
sig_start_1[i] = cyc_start_1[i] == cycle_1;
|
||||
|
||||
always @(posedge led_clk)
|
||||
sig_stop_1[i] <= (cyc_stop_1[i] == cycle_1) & ~tick_1;
|
||||
|
||||
// State register
|
||||
always @(posedge led_clk or posedge led_off_1)
|
||||
begin
|
||||
if (led_off_1) begin
|
||||
started_2[i] <= 1'b0;
|
||||
stopped_2[i] <= 1'b0;
|
||||
end else begin
|
||||
started_2[i] <= (started_2[i] | sig_start_1[i]) & ~tick_1;
|
||||
stopped_2[i] <= (stopped_2[i] | sig_stop_1[i]) & ~tick_1;
|
||||
end
|
||||
end
|
||||
|
||||
// Final decision
|
||||
always @(posedge led_clk or posedge led_off_2)
|
||||
if (led_off_2)
|
||||
led_c_3[i] <= 1'b0;
|
||||
else
|
||||
led_c_3[i] <= started_2[i] & ~stopped_2[i];
|
||||
end
|
||||
endgenerate
|
||||
|
||||
|
||||
// Anode driver
|
||||
// ------------
|
||||
|
||||
// Decode and gating
|
||||
always @(posedge led_clk or posedge led_off_1)
|
||||
if (led_off_1)
|
||||
led_a_2 <= 0;
|
||||
else begin
|
||||
led_a_2 <= 0;
|
||||
led_a_2[led_a_1] <= ~tick_1;
|
||||
end
|
||||
|
||||
// IOBs
|
||||
SB_IO #(
|
||||
// .PIN_TYPE(6'b0101_01), // PIN_OUTPUT_REGISTERED, PIN_INPUT
|
||||
.PIN_TYPE(6'b1101_01), // PIN_OUTPUT_REGISTERED_ENABLE_REGISTERED, PIN_INPUT
|
||||
.PULLUP(1'b0)
|
||||
) led_anode_drv_I[13:0] (
|
||||
.PACKAGE_PIN (led_a),
|
||||
.OUTPUT_CLK (led_clk),
|
||||
.OUTPUT_ENABLE (led_a_2),
|
||||
.D_OUT_0 (1'b1)
|
||||
);
|
||||
|
||||
|
||||
// Cathode driver
|
||||
// --------------
|
||||
|
||||
SB_RGBA_DRV #(
|
||||
.CURRENT_MODE("0b1"),
|
||||
.RGB0_CURRENT("0b000011"), /* Green : 4 mA */
|
||||
.RGB1_CURRENT("0b000111"), /* Pink : 6 mA */
|
||||
.RGB2_CURRENT("0b001111") /* Blue : 8 mA */
|
||||
) led_cathode_drv_I (
|
||||
.RGBLEDEN (ctrl_drv_rgbleden),
|
||||
.RGB0PWM (led_c_3[0]),
|
||||
.RGB1PWM (led_c_3[1]),
|
||||
.RGB2PWM (led_c_3[2]),
|
||||
.CURREN (ctrl_drv_curren),
|
||||
.RGB0 (led_c[0]),
|
||||
.RGB1 (led_c[1]),
|
||||
.RGB2 (led_c[2])
|
||||
);
|
||||
|
||||
endmodule // led_ctrl
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* picorv32_ice40_regs.v
|
||||
*
|
||||
* vim: ts=4 sw=4
|
||||
*
|
||||
* Implementation of register file for the PicoRV32 on iCE40
|
||||
*
|
||||
* Copyright (C) 2020 Sylvain Munaut <tnt@246tNt.com>
|
||||
* SPDX-License-Identifier: CERN-OHL-P-2.0
|
||||
*/
|
||||
|
||||
`default_nettype none
|
||||
|
||||
module picorv32_ice40_regs (
|
||||
input wire clk,
|
||||
input wire wen,
|
||||
input wire [5:0] waddr,
|
||||
input wire [5:0] raddr1,
|
||||
input wire [5:0] raddr2,
|
||||
input wire [31:0] wdata,
|
||||
output wire [31:0] rdata1,
|
||||
output wire [31:0] rdata2
|
||||
);
|
||||
|
||||
ice40_ebr #(
|
||||
.READ_MODE(0),
|
||||
.WRITE_MODE(0),
|
||||
.MASK_WORKAROUND(0),
|
||||
.NEG_WR_CLK(0),
|
||||
.NEG_RD_CLK(1)
|
||||
) regs[3:0] (
|
||||
.wr_addr ({ 4{2'b00, waddr} }),
|
||||
.wr_data ({ 2{wdata} }),
|
||||
.wr_mask (64'h0000000000000000),
|
||||
.wr_ena (wen),
|
||||
.wr_clk (clk),
|
||||
.rd_addr ({2'b00, raddr2, 2'b00, raddr2, 2'b00, raddr1, 2'b00, raddr1}),
|
||||
.rd_data ({rdata2, rdata1}),
|
||||
.rd_ena (1'b1),
|
||||
.rd_clk (clk)
|
||||
);
|
||||
|
||||
endmodule // picorv32_ice40_regs
|
|
@ -0,0 +1,278 @@
|
|||
/*
|
||||
* pmu.v
|
||||
*
|
||||
* vim: ts=4 sw=4
|
||||
*
|
||||
* Platorm Management Unit
|
||||
*
|
||||
* Copyright (C) 2023 Sylvain Munaut <tnt@246tNt.com>
|
||||
* SPDX-License-Identifier: CERN-OHL-P-2.0
|
||||
*/
|
||||
|
||||
`default_nettype none
|
||||
|
||||
module pmu (
|
||||
// Wishbone
|
||||
input wire [15:0] wb_addr,
|
||||
output reg [31:0] wb_rdata,
|
||||
input wire [31:0] wb_wdata,
|
||||
input wire wb_we,
|
||||
input wire wb_cyc,
|
||||
output reg wb_ack,
|
||||
|
||||
// Buttons
|
||||
input wire [ 1:0] btn,
|
||||
|
||||
// Power control
|
||||
input wire pwr_usb_n,
|
||||
input wire pwr_chg_n,
|
||||
output wire pwr_off,
|
||||
|
||||
// Clock control
|
||||
output wire sys_start,
|
||||
output wire sys_stop,
|
||||
output reg usb_ena,
|
||||
|
||||
// Wake up signal
|
||||
input wire wakeup,
|
||||
|
||||
// Clock / Reset
|
||||
input wire clk,
|
||||
input wire rst
|
||||
);
|
||||
|
||||
integer i;
|
||||
|
||||
// Signals
|
||||
// -------
|
||||
|
||||
// Bus interface
|
||||
wire bus_clr_rd;
|
||||
wire bus_clr_wr;
|
||||
wire bus_is_suspend;
|
||||
reg [3:0] bus_ack_dly;
|
||||
reg bus_we;
|
||||
|
||||
// Control signals
|
||||
reg ctrl_sys_shutdown;
|
||||
reg ctrl_sys_suspend;
|
||||
reg ctrl_usb_off;
|
||||
reg ctrl_usb_on;
|
||||
|
||||
// Buttons
|
||||
wire btn_clk;
|
||||
wire [1:0] btn_iob;
|
||||
reg [2:0] btn_sync [0:1];
|
||||
reg [4:0] btn_cnt [0:1];
|
||||
reg [1:0] btn_val;
|
||||
reg [1:0] btn_val_wb;
|
||||
reg [16:0] btn_long_cnt [0:1];
|
||||
reg [1:0] btn_long;
|
||||
|
||||
// Reboot
|
||||
reg boot_wb_now;
|
||||
reg [1:0] boot_wb_sel;
|
||||
|
||||
reg boot_now;
|
||||
reg [1:0] boot_sel;
|
||||
|
||||
// Power/Clock Status/Control
|
||||
wire iob_pwr_usb_n;
|
||||
wire iob_pwr_chg_n;
|
||||
reg stat_pwr_usb;
|
||||
reg stat_pwr_chg;
|
||||
|
||||
wire pwr_off_trig;
|
||||
reg pwr_off_i = 1'b0;
|
||||
|
||||
|
||||
// Bus interface
|
||||
// -------------
|
||||
|
||||
// Clears
|
||||
assign bus_clr_rd = wb_ack | ~wb_cyc;
|
||||
assign bus_clr_wr = wb_ack | ~wb_cyc | ~wb_we;
|
||||
|
||||
// Ack
|
||||
always @(posedge clk)
|
||||
wb_ack <= wb_cyc & (~bus_is_suspend | bus_ack_dly[3]) & ~wb_ack;
|
||||
|
||||
assign bus_is_suspend = wb_we & wb_wdata[6];
|
||||
|
||||
always @(posedge clk)
|
||||
if (bus_clr_wr)
|
||||
bus_ack_dly <= 0;
|
||||
else
|
||||
bus_ack_dly <= bus_ack_dly + 1;
|
||||
|
||||
// Reads
|
||||
always @(posedge clk)
|
||||
if (bus_clr_rd)
|
||||
wb_rdata <= 32'h00000000;
|
||||
else
|
||||
wb_rdata <= {
|
||||
27'd0,
|
||||
usb_ena,
|
||||
stat_pwr_usb,
|
||||
stat_pwr_chg,
|
||||
btn_val_wb[1],
|
||||
btn_val_wb[0]
|
||||
};
|
||||
|
||||
// Writes
|
||||
always @(posedge clk)
|
||||
if (bus_clr_wr) begin
|
||||
bus_we <= 1'b0;
|
||||
ctrl_sys_shutdown <= 1'b0;
|
||||
ctrl_sys_suspend <= 1'b0;
|
||||
ctrl_usb_off <= 1'b0;
|
||||
ctrl_usb_on <= 1'b0;
|
||||
end else begin
|
||||
bus_we <= 1'b1;
|
||||
ctrl_sys_shutdown <= wb_wdata[7];
|
||||
ctrl_sys_suspend <= wb_wdata[6];
|
||||
ctrl_usb_off <= wb_wdata[5];
|
||||
ctrl_usb_on <= wb_wdata[4];
|
||||
end
|
||||
|
||||
always @(posedge clk or posedge rst)
|
||||
if (rst) begin
|
||||
boot_wb_now <= 1'b0;
|
||||
boot_wb_sel <= 2'b00;
|
||||
end else if (bus_we) begin
|
||||
boot_wb_now <= wb_wdata[2];
|
||||
boot_wb_sel <= wb_wdata[1:0];
|
||||
end
|
||||
|
||||
|
||||
// Buttons
|
||||
// -------
|
||||
|
||||
// Oscillator for button logic
|
||||
(* ROUTE_THROUGH_FABRIC=1 *)
|
||||
SB_LFOSC btn_osc (
|
||||
.CLKLFPU (1'b1),
|
||||
.CLKLFEN (1'b1),
|
||||
.CLKLF (btn_clk)
|
||||
);
|
||||
|
||||
// IOBs
|
||||
SB_IO #(
|
||||
.PIN_TYPE(6'b000001), // PIN_OUTPUT_NONE, PIN_INPUT
|
||||
.PULLUP(1'b1),
|
||||
.IO_STANDARD("SB_LVCMOS")
|
||||
) btn_iob_I[1:0] (
|
||||
.PACKAGE_PIN (btn),
|
||||
.D_IN_0 (btn_iob)
|
||||
);
|
||||
|
||||
// Synchronizer
|
||||
initial
|
||||
for (i=0; i<2; i=i+1)
|
||||
btn_sync[i] = 1;
|
||||
|
||||
always @(posedge btn_clk)
|
||||
for (i=0; i<2; i=i+1)
|
||||
btn_sync[i] <= { btn_sync[i][1:0], btn_iob[i] };
|
||||
|
||||
// Small counter for debounce
|
||||
initial
|
||||
for (i=0; i<2; i=i+1)
|
||||
btn_cnt[i] = 0;
|
||||
|
||||
always @(posedge btn_clk)
|
||||
for (i=0; i<2; i=i+1)
|
||||
btn_cnt[i] <= btn_sync[i][2] ? (btn_cnt[i] + {4'h0, btn_cnt[i][4]}) : 5'h10;
|
||||
|
||||
always @(*)
|
||||
for (i=0; i<2; i=i+1)
|
||||
btn_val[i] = btn_cnt[i][4];
|
||||
|
||||
// Synchronize value in sys clock domain
|
||||
always @(posedge clk)
|
||||
for (i=0; i<2; i=i+1)
|
||||
btn_val_wb[i] <= btn_val[i];
|
||||
|
||||
// Long counter to detect very long presses
|
||||
// ( ~6.5 sec )
|
||||
initial
|
||||
for (i=0; i<2; i=i+1)
|
||||
btn_long_cnt[i] = 0;
|
||||
|
||||
always @(posedge btn_clk)
|
||||
for (i=0; i<2; i=i+1)
|
||||
btn_long_cnt[i] <= (btn_long_cnt[i] + btn_val[i]) & {17{btn_val[i]}};
|
||||
|
||||
always @(*)
|
||||
for (i=0; i<2; i=i+1)
|
||||
btn_long[i] = btn_long_cnt[i][16];
|
||||
|
||||
|
||||
// Reboot
|
||||
// ------
|
||||
|
||||
// Command from wb or button force
|
||||
always @(*)
|
||||
begin
|
||||
if (btn_long[0]) begin
|
||||
boot_now = 1'b1;
|
||||
boot_sel = 2'b01;
|
||||
end else begin
|
||||
boot_now = boot_wb_now;
|
||||
boot_sel = boot_wb_sel;
|
||||
end
|
||||
end
|
||||
|
||||
// Core
|
||||
SB_WARMBOOT warmboot (
|
||||
.BOOT (boot_now),
|
||||
.S0 (boot_sel[0]),
|
||||
.S1 (boot_sel[1])
|
||||
);
|
||||
|
||||
|
||||
// Power / Clock control
|
||||
// ---------------------
|
||||
|
||||
// Synchronizers for status
|
||||
SB_IO #(
|
||||
.PIN_TYPE(6'b000000), // PIN_OUTPUT_NONE, PIN_INPUT_REGISTERED
|
||||
.PULLUP(1'b1),
|
||||
.IO_STANDARD("SB_LVCMOS")
|
||||
) stat_iob_I[1:0] (
|
||||
.PACKAGE_PIN ({ pwr_usb_n, pwr_chg_n}),
|
||||
.INPUT_CLK (clk),
|
||||
.D_IN_0 ({iob_pwr_usb_n, iob_pwr_chg_n})
|
||||
);
|
||||
|
||||
always @(posedge clk)
|
||||
begin
|
||||
stat_pwr_usb <= ~iob_pwr_usb_n;
|
||||
stat_pwr_chg <= ~iob_pwr_chg_n;
|
||||
end
|
||||
|
||||
// Enable system clock on wakeup
|
||||
assign sys_start = wakeup;
|
||||
|
||||
// Disable system clock on requests
|
||||
assign sys_stop = ctrl_sys_suspend;
|
||||
|
||||
// Power-off on long press and on requests
|
||||
assign pwr_off_trig = btn_long[1] | ctrl_sys_shutdown;
|
||||
|
||||
always @(posedge pwr_off_trig or posedge rst)
|
||||
if (rst)
|
||||
pwr_off_i <= 1'b0;
|
||||
else
|
||||
pwr_off_i <= 1'b1;
|
||||
|
||||
assign pwr_off = pwr_off_i;
|
||||
|
||||
// USB ena
|
||||
always @(posedge clk)
|
||||
if (rst)
|
||||
usb_ena <= 1'b0;
|
||||
else
|
||||
usb_ena <= (usb_ena | ctrl_usb_on) & ~ctrl_usb_off;
|
||||
|
||||
endmodule // pmu
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* 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 SIZE = 256,
|
||||
parameter integer AW = $clog2(SIZE),
|
||||
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
|
||||
);
|
||||
|
||||
(* no_rw_check *)
|
||||
reg [31:0] mem [0:SIZE-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
|
|
@ -0,0 +1,163 @@
|
|||
/*
|
||||
* soc_picorv32_base.v
|
||||
*
|
||||
* vim: ts=4 sw=4
|
||||
*
|
||||
* Copyright (C) 2019-2022 Sylvain Munaut <tnt@246tNt.com>
|
||||
* SPDX-License-Identifier: CERN-OHL-P-2.0
|
||||
*/
|
||||
|
||||
`default_nettype none
|
||||
|
||||
module soc_picorv32_base #(
|
||||
parameter integer WB_N = 6,
|
||||
parameter integer WB_DW = 32,
|
||||
parameter integer WB_AW = 16,
|
||||
parameter integer BRAM_AW = 8, /* Default 1k */
|
||||
parameter integer SPRAM_AW = 14, /* 0 => none, 14 => 64k, 15 => 128k */
|
||||
|
||||
/* auto */
|
||||
parameter integer WB_MW = WB_DW / 8,
|
||||
parameter integer WB_RW = WB_DW * WB_N,
|
||||
parameter integer WB_AI = $clog2(WB_MW)
|
||||
)(
|
||||
// Wishbone
|
||||
output wire [WB_AW-1:0] wb_addr,
|
||||
input wire [WB_RW-1:0] wb_rdata,
|
||||
output wire [WB_DW-1:0] wb_wdata,
|
||||
output wire [WB_MW-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
|
||||
// -------
|
||||
|
||||
// Memory bus
|
||||
wire mem_valid;
|
||||
wire mem_instr;
|
||||
wire mem_ready;
|
||||
wire [31:0] mem_addr;
|
||||
wire [31:0] mem_rdata;
|
||||
wire [31:0] mem_wdata;
|
||||
wire [ 3:0] mem_wstrb;
|
||||
|
||||
// RAM
|
||||
// BRAM
|
||||
wire [14: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;
|
||||
|
||||
|
||||
// CPU
|
||||
// ---
|
||||
|
||||
picorv32 #(
|
||||
.PROGADDR_RESET(32'h 0000_0000),
|
||||
.STACKADDR(4 << BRAM_AW),
|
||||
.BARREL_SHIFTER(1),
|
||||
.COMPRESSED_ISA(0),
|
||||
.ENABLE_COUNTERS(0),
|
||||
.ENABLE_FAST_MUL(1),
|
||||
.ENABLE_MUL(0),
|
||||
.ENABLE_DIV(0),
|
||||
.ENABLE_IRQ(0),
|
||||
.ENABLE_IRQ_QREGS(0),
|
||||
.CATCH_MISALIGN(0),
|
||||
.CATCH_ILLINSN(0)
|
||||
) cpu_I (
|
||||
.clk (clk),
|
||||
.resetn (~rst),
|
||||
.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)
|
||||
);
|
||||
|
||||
|
||||
// Bus interface
|
||||
// -------------
|
||||
|
||||
soc_picorv32_bridge #(
|
||||
.WB_N (WB_N),
|
||||
.WB_DW(WB_DW),
|
||||
.WB_AW(WB_AW),
|
||||
.WB_AI(WB_AI)
|
||||
) pb_I (
|
||||
.pb_addr (mem_addr),
|
||||
.pb_rdata (mem_rdata),
|
||||
.pb_wdata (mem_wdata),
|
||||
.pb_wstrb (mem_wstrb),
|
||||
.pb_valid (mem_valid),
|
||||
.pb_ready (mem_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_wdata (wb_wdata),
|
||||
.wb_wmsk (wb_wmsk),
|
||||
.wb_rdata (wb_rdata),
|
||||
.wb_cyc (wb_cyc),
|
||||
.wb_we (wb_we),
|
||||
.wb_ack (wb_ack),
|
||||
.clk (clk),
|
||||
.rst (rst)
|
||||
);
|
||||
|
||||
|
||||
// Local memory
|
||||
// ------------
|
||||
|
||||
// BRAM memory
|
||||
soc_bram #(
|
||||
.SIZE(1 << BRAM_AW),
|
||||
.INIT_FILE("boot.hex")
|
||||
) bram_I (
|
||||
.addr (bram_addr[BRAM_AW-1:0]),
|
||||
.rdata (bram_rdata),
|
||||
.wdata (bram_wdata),
|
||||
.wmsk (bram_wmsk),
|
||||
.we (bram_we),
|
||||
.clk (clk)
|
||||
);
|
||||
|
||||
// SPRAM memory
|
||||
generate
|
||||
if (SPRAM_AW > 0)
|
||||
soc_spram #(
|
||||
.AW(SPRAM_AW)
|
||||
) spram_I (
|
||||
.addr (spram_addr[SPRAM_AW-1:0]),
|
||||
.rdata (spram_rdata),
|
||||
.wdata (spram_wdata),
|
||||
.wmsk (spram_wmsk),
|
||||
.we (spram_we),
|
||||
.clk (clk)
|
||||
);
|
||||
endgenerate
|
||||
|
||||
endmodule // soc_picorv32_base
|
|
@ -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 [14: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 -> 0x0001ffff
|
||||
// SPRAM : 0x00020000 -> 0x0003ffff
|
||||
|
||||
assign bram_addr = pb_addr[16: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
|
|
@ -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
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* soc_usb_buf_bridge.v
|
||||
*
|
||||
* vim: ts=4 sw=4
|
||||
*
|
||||
* Copyright (C) 2023 Sylvain Munaut <tnt@246tNt.com>
|
||||
* SPDX-License-Identifier: CERN-OHL-P-2.0
|
||||
*/
|
||||
|
||||
`default_nettype none
|
||||
|
||||
module soc_usb_buf_bridge (
|
||||
// Wishbone (from SoC)
|
||||
input wire [15:0] wb_addr,
|
||||
output reg [31:0] wb_rdata,
|
||||
input wire [31:0] wb_wdata,
|
||||
input wire [ 3:0] wb_wmsk,
|
||||
input wire wb_we,
|
||||
input wire wb_cyc,
|
||||
output reg wb_ack,
|
||||
|
||||
// USB EP buffer
|
||||
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
|
||||
);
|
||||
|
||||
// Ack
|
||||
always @(posedge clk)
|
||||
wb_ack <= wb_cyc & ~wb_ack;
|
||||
|
||||
// Address
|
||||
assign ep_tx_addr_0 = wb_addr[8:0];
|
||||
assign ep_rx_addr_0 = wb_addr[8:0];
|
||||
|
||||
// Read Enable
|
||||
assign ep_rx_re_0 = wb_cyc;
|
||||
|
||||
// Read
|
||||
always @(*)
|
||||
if (~wb_ack)
|
||||
wb_rdata = 32'h00000000;
|
||||
else
|
||||
wb_rdata = ep_rx_data_1;
|
||||
|
||||
// Write data
|
||||
assign ep_tx_data_0 = wb_wdata;
|
||||
|
||||
// Write enable
|
||||
assign ep_tx_we_0 = wb_ack & wb_we;
|
||||
|
||||
endmodule // soc_usb_buf_bridge
|
|
@ -0,0 +1,209 @@
|
|||
/*
|
||||
* sysmgr.v
|
||||
*
|
||||
* vim: ts=4 sw=4
|
||||
*
|
||||
* System Clock / Reset generation
|
||||
*
|
||||
* Copyright (C) 2023 Sylvain Munaut <tnt@246tNt.com>
|
||||
* SPDX-License-Identifier: CERN-OHL-P-2.0
|
||||
*/
|
||||
|
||||
`default_nettype none
|
||||
|
||||
module sysmgr (
|
||||
// Control
|
||||
input wire sys_start,
|
||||
input wire sys_stop,
|
||||
input wire usb_ena,
|
||||
|
||||
// LED clock ( 6 MHz )
|
||||
output wire clk_led,
|
||||
output wire rst_led,
|
||||
|
||||
// System clock ( 24 MHz )
|
||||
output wire clk_sys,
|
||||
output wire rst_sys,
|
||||
|
||||
// USB ( 48 MHz )
|
||||
output wire clk_usb,
|
||||
output wire rst_usb
|
||||
);
|
||||
|
||||
// Signals
|
||||
// -------
|
||||
|
||||
wire clk_osc;
|
||||
wire clk_base;
|
||||
|
||||
wire pll_lock;
|
||||
|
||||
reg [3:0] clk_div;
|
||||
reg clk_usb_i;
|
||||
reg clk_sys_i;
|
||||
wire clk_led_i;
|
||||
|
||||
reg [3:0] rst_cnt;
|
||||
wire rst_i;
|
||||
wire rst_gbuf;
|
||||
|
||||
reg [2:0] sys_start_s;
|
||||
reg [2:0] sys_stop_s;
|
||||
|
||||
wire usb_rst_trig;
|
||||
reg [3:0] usb_rst_cnt;
|
||||
wire usb_rst_i;
|
||||
reg [3:0] usb_off_dly;
|
||||
|
||||
reg sys_off;
|
||||
wire usb_off;
|
||||
|
||||
|
||||
// SB_HFOSC
|
||||
// -------
|
||||
// Generates 12 MHz
|
||||
|
||||
(* ROUTE_THROUGH_FABRIC = 1 *)
|
||||
SB_HFOSC #(
|
||||
.CLKHF_DIV("0b10")
|
||||
) osc_I (
|
||||
.CLKHFPU(1'b1),
|
||||
.CLKHFEN(1'b1),
|
||||
.CLKHF(clk_osc)
|
||||
);
|
||||
|
||||
|
||||
// PLL
|
||||
// ---
|
||||
|
||||
SB_PLL40_CORE #(
|
||||
.DIVR (4'b0000),
|
||||
.DIVF (7'b0111111),
|
||||
.DIVQ (3'b011),
|
||||
.FILTER_RANGE (3'b001),
|
||||
.FEEDBACK_PATH ("SIMPLE"),
|
||||
.DELAY_ADJUSTMENT_MODE_FEEDBACK ("FIXED"),
|
||||
.FDA_FEEDBACK (4'b0000),
|
||||
.SHIFTREG_DIV_MODE (2'b00),
|
||||
.PLLOUT_SELECT ("GENCLK"),
|
||||
.ENABLE_ICEGATE (1'b0)
|
||||
) pll_I (
|
||||
.REFERENCECLK (clk_osc),
|
||||
.PLLOUTCORE (clk_base),
|
||||
.PLLOUTGLOBAL (),
|
||||
.EXTFEEDBACK (1'b0),
|
||||
.DYNAMICDELAY (8'h00),
|
||||
.RESETB (1'b1),
|
||||
.BYPASS (1'b0),
|
||||
.LATCHINPUTVALUE (1'b0),
|
||||
.LOCK (pll_lock),
|
||||
.SDI (1'b0),
|
||||
.SDO (),
|
||||
.SCLK (1'b0)
|
||||
);
|
||||
|
||||
|
||||
// Dividers
|
||||
// --------
|
||||
|
||||
// Counter
|
||||
always @(posedge clk_base)
|
||||
clk_div <= clk_div + 1;
|
||||
|
||||
// USB is div-by-2 + gated
|
||||
always @(posedge clk_base)
|
||||
clk_usb_i <= clk_div[0] & ~usb_off;
|
||||
|
||||
// SYS is div-by-4 + gated
|
||||
always @(posedge clk_base)
|
||||
clk_sys_i <= clk_div[1] & ~sys_off;
|
||||
|
||||
// LED is div-by-16
|
||||
assign clk_led_i = clk_div[3];
|
||||
|
||||
// Global buffers
|
||||
SB_GB clk_usb_gbuf_I (
|
||||
.USER_SIGNAL_TO_GLOBAL_BUFFER(clk_usb_i),
|
||||
.GLOBAL_BUFFER_OUTPUT(clk_usb)
|
||||
);
|
||||
|
||||
SB_GB clk_sys_gbuf_I (
|
||||
.USER_SIGNAL_TO_GLOBAL_BUFFER(clk_sys_i),
|
||||
.GLOBAL_BUFFER_OUTPUT(clk_sys)
|
||||
);
|
||||
|
||||
SB_GB clk_led_gbuf_I (
|
||||
.USER_SIGNAL_TO_GLOBAL_BUFFER(clk_led_i),
|
||||
.GLOBAL_BUFFER_OUTPUT(clk_led)
|
||||
);
|
||||
|
||||
|
||||
// USB Enable
|
||||
// ----------
|
||||
|
||||
// Delay falling latch signal
|
||||
always @(posedge clk_base)
|
||||
usb_off_dly <= usb_ena ? 4'b0000 : { usb_off_dly[2:0], 1'b1 };
|
||||
|
||||
assign usb_off = usb_off_dly[3];
|
||||
|
||||
|
||||
// USB Reset
|
||||
// ---------
|
||||
|
||||
// Reset trigger
|
||||
assign usb_rst_trig = ~usb_ena | ~pll_lock;
|
||||
|
||||
// Reset counter
|
||||
always @(posedge clk_usb or posedge usb_rst_trig)
|
||||
if (usb_rst_trig)
|
||||
usb_rst_cnt <= 4'h8;
|
||||
else
|
||||
usb_rst_cnt <= usb_rst_cnt + usb_rst_i;
|
||||
|
||||
assign usb_rst_i = usb_rst_cnt[3];
|
||||
|
||||
// Global buffer
|
||||
SB_GB rst_usb_gbuf_I (
|
||||
.USER_SIGNAL_TO_GLOBAL_BUFFER(usb_rst_i),
|
||||
.GLOBAL_BUFFER_OUTPUT(rst_usb)
|
||||
);
|
||||
|
||||
|
||||
// SYS Enable
|
||||
// ----------
|
||||
|
||||
// Synch triggers
|
||||
always @(posedge clk_base)
|
||||
begin
|
||||
sys_start_s <= { ~sys_start_s[1] & sys_start_s[0], sys_start_s[0], sys_start };
|
||||
sys_stop_s <= { ~sys_stop_s[1] & sys_stop_s[0], sys_stop_s[0], sys_stop };
|
||||
end
|
||||
|
||||
always @(posedge clk_base)
|
||||
sys_off <= (sys_off & ~rst_i & ~sys_start_s[2]) | sys_stop_s[2];
|
||||
|
||||
|
||||
// Reset LED / SYS
|
||||
// ---------------
|
||||
|
||||
// Counter
|
||||
always @(posedge clk_led or negedge pll_lock)
|
||||
if (~pll_lock)
|
||||
rst_cnt <= 4'h8;
|
||||
else
|
||||
rst_cnt <= rst_cnt + rst_i;
|
||||
|
||||
assign rst_i = rst_cnt[3];
|
||||
|
||||
// Global buffer
|
||||
SB_GB rst_gbuf_I (
|
||||
.USER_SIGNAL_TO_GLOBAL_BUFFER(rst_i),
|
||||
.GLOBAL_BUFFER_OUTPUT(rst_gbuf)
|
||||
);
|
||||
|
||||
// Distribution
|
||||
assign rst_led = rst_gbuf;
|
||||
assign rst_sys = rst_gbuf;
|
||||
|
||||
endmodule // sysmgr
|
|
@ -0,0 +1,203 @@
|
|||
/*
|
||||
* sysmgr.v
|
||||
*
|
||||
* vim: ts=4 sw=4
|
||||
*
|
||||
* System Clock / Reset generation
|
||||
*
|
||||
* Copyright (C) 2023 Sylvain Munaut <tnt@246tNt.com>
|
||||
* SPDX-License-Identifier: CERN-OHL-P-2.0
|
||||
*/
|
||||
|
||||
`default_nettype none
|
||||
|
||||
module sysmgr (
|
||||
// Control
|
||||
input wire sys_start,
|
||||
input wire sys_stop,
|
||||
input wire usb_ena,
|
||||
|
||||
// LED clock ( 6 MHz )
|
||||
output wire clk_led,
|
||||
output wire rst_led,
|
||||
|
||||
// System clock ( 24 MHz )
|
||||
output wire clk_sys,
|
||||
output wire rst_sys,
|
||||
|
||||
// USB ( 48 MHz )
|
||||
output wire clk_usb,
|
||||
output wire rst_usb
|
||||
);
|
||||
|
||||
// Signals
|
||||
// -------
|
||||
|
||||
wire clk_osc;
|
||||
wire clk_base;
|
||||
|
||||
wire pll_lock;
|
||||
|
||||
reg [2:0] clk_div;
|
||||
reg clk_sys_i;
|
||||
wire clk_led_i;
|
||||
|
||||
reg [3:0] rst_cnt;
|
||||
wire rst_i;
|
||||
wire rst_gbuf;
|
||||
|
||||
reg [2:0] sys_start_s;
|
||||
reg [2:0] sys_stop_s;
|
||||
|
||||
wire usb_rst_trig;
|
||||
reg [3:0] usb_rst_cnt;
|
||||
wire usb_rst_i;
|
||||
reg [3:0] usb_off_dly;
|
||||
|
||||
wire sys_off;
|
||||
wire usb_off;
|
||||
|
||||
|
||||
// SB_HFOSC
|
||||
// -------
|
||||
// Generates 12 MHz
|
||||
|
||||
(* ROUTE_THROUGH_FABRIC = 1 *)
|
||||
SB_HFOSC #(
|
||||
.CLKHF_DIV("0b10")
|
||||
) osc_I (
|
||||
.CLKHFPU(1'b1),
|
||||
.CLKHFEN(1'b1),
|
||||
.CLKHF(clk_osc)
|
||||
);
|
||||
|
||||
|
||||
// PLL
|
||||
// ---
|
||||
|
||||
SB_PLL40_2F_CORE #(
|
||||
.DIVR (4'b0000),
|
||||
.DIVF (7'b0111111),
|
||||
.DIVQ (3'b100),
|
||||
.FILTER_RANGE (3'b001),
|
||||
.FEEDBACK_PATH ("SIMPLE"),
|
||||
.DELAY_ADJUSTMENT_MODE_FEEDBACK ("FIXED"),
|
||||
.FDA_FEEDBACK (4'b0000),
|
||||
.SHIFTREG_DIV_MODE (2'b00),
|
||||
.PLLOUT_SELECT_PORTA ("GENCLK"),
|
||||
.PLLOUT_SELECT_PORTB ("GENCLK"),
|
||||
.ENABLE_ICEGATE_PORTA (1'b1),
|
||||
.ENABLE_ICEGATE_PORTB (1'b0),
|
||||
) pll_I (
|
||||
.REFERENCECLK (clk_osc),
|
||||
.PLLOUTCOREB (),
|
||||
.PLLOUTGLOBALB (clk_usb),
|
||||
.PLLOUTCOREA (clk_base),
|
||||
.PLLOUTGLOBALA (),
|
||||
.EXTFEEDBACK (1'b0),
|
||||
.DYNAMICDELAY (8'h00),
|
||||
.RESETB (1'b1),
|
||||
.BYPASS (1'b0),
|
||||
.LATCHINPUTVALUE (usb_off),
|
||||
.LOCK (pll_lock),
|
||||
.SDI (1'b0),
|
||||
.SDO (),
|
||||
.SCLK (1'b0)
|
||||
);
|
||||
|
||||
|
||||
// Dividers
|
||||
// --------
|
||||
|
||||
// Counter
|
||||
always @(posedge clk_base)
|
||||
clk_div <= clk_div + 1;
|
||||
|
||||
// SYS is div-by-2 + gated
|
||||
always @(posedge clk_base)
|
||||
clk_sys_i <= clk_div[0] & ~sys_off;
|
||||
|
||||
// LED is div-by-8
|
||||
assign clk_led_i = clk_div[2];
|
||||
|
||||
// Global buffers
|
||||
SB_GB clk_sys_gbuf_I (
|
||||
.USER_SIGNAL_TO_GLOBAL_BUFFER(clk_sys_i),
|
||||
.GLOBAL_BUFFER_OUTPUT(clk_sys)
|
||||
);
|
||||
|
||||
SB_GB clk_led_gbuf_I (
|
||||
.USER_SIGNAL_TO_GLOBAL_BUFFER(clk_led_i),
|
||||
.GLOBAL_BUFFER_OUTPUT(clk_led)
|
||||
);
|
||||
|
||||
|
||||
// USB Enable
|
||||
// ----------
|
||||
|
||||
// Delay falling latch signal
|
||||
always @(posedge clk_base)
|
||||
usb_off_dly <= usb_ena ? 4'b0000 : { usb_off_dly[2:0], 1'b1 };
|
||||
|
||||
assign usb_off = usb_off_dly[3];
|
||||
|
||||
|
||||
// USB Reset
|
||||
// ---------
|
||||
|
||||
// Reset trigger
|
||||
assign usb_rst_trig = ~usb_ena | ~pll_lock;
|
||||
|
||||
// Reset counter
|
||||
always @(posedge clk_usb or posedge usb_rst_trig)
|
||||
if (usb_rst_trig)
|
||||
usb_rst_cnt <= 4'h8;
|
||||
else
|
||||
usb_rst_cnt <= usb_rst_cnt + usb_rst_i;
|
||||
|
||||
assign usb_rst_i = usb_rst_cnt[3];
|
||||
|
||||
// Global buffer
|
||||
SB_GB rst_usb_gbuf_I (
|
||||
.USER_SIGNAL_TO_GLOBAL_BUFFER(usb_rst_i),
|
||||
.GLOBAL_BUFFER_OUTPUT(rst_usb)
|
||||
);
|
||||
|
||||
|
||||
// SYS Enable
|
||||
// ----------
|
||||
|
||||
// Synch triggers
|
||||
always @(posedge clk_base)
|
||||
begin
|
||||
sys_start_s <= { ~sys_start_s[1] & sys_start_s[0], sys_start_s[0], sys_start };
|
||||
sys_stop_s <= { ~sys_stop_s[1] & sys_stop_s[0], sys_stop_s[0], sys_stop };
|
||||
end
|
||||
|
||||
always @(posedge clk_base)
|
||||
sys_off <= (sys_off & ~rst_i & ~sys_start_s[2]) | sys_stop_s[2];
|
||||
|
||||
|
||||
// Reset LED / SYS
|
||||
// ---------------
|
||||
|
||||
// Counter
|
||||
always @(posedge clk_led or negedge pll_lock)
|
||||
if (~pll_lock)
|
||||
rst_cnt <= 4'h8;
|
||||
else
|
||||
rst_cnt <= rst_cnt + rst_i;
|
||||
|
||||
assign rst_i = rst_cnt[3];
|
||||
|
||||
// Global buffer
|
||||
SB_GB rst_gbuf_I (
|
||||
.USER_SIGNAL_TO_GLOBAL_BUFFER(rst_i),
|
||||
.GLOBAL_BUFFER_OUTPUT(rst_gbuf)
|
||||
);
|
||||
|
||||
// Distribution
|
||||
assign rst_led = rst_gbuf;
|
||||
assign rst_sys = rst_gbuf;
|
||||
|
||||
endmodule // sysmgr
|
|
@ -0,0 +1,197 @@
|
|||
/*
|
||||
* sysmgr.v
|
||||
*
|
||||
* vim: ts=4 sw=4
|
||||
*
|
||||
* System Clock / Reset generation
|
||||
*
|
||||
* Copyright (C) 2023 Sylvain Munaut <tnt@246tNt.com>
|
||||
* SPDX-License-Identifier: CERN-OHL-P-2.0
|
||||
*/
|
||||
|
||||
`default_nettype none
|
||||
|
||||
module sysmgr (
|
||||
// Control
|
||||
input wire sys_start,
|
||||
input wire sys_stop,
|
||||
input wire usb_ena,
|
||||
|
||||
// LED clock ( 6 MHz )
|
||||
output wire clk_led,
|
||||
output wire rst_led,
|
||||
|
||||
// System clock ( 24 MHz )
|
||||
output wire clk_sys,
|
||||
output wire rst_sys,
|
||||
|
||||
// USB ( 48 MHz )
|
||||
output wire clk_usb,
|
||||
output wire rst_usb
|
||||
);
|
||||
|
||||
// Signals
|
||||
// -------
|
||||
|
||||
wire clk_base;
|
||||
|
||||
wire pll_lock;
|
||||
|
||||
reg [2:0] clk_div;
|
||||
reg clk_sys_i;
|
||||
wire clk_led_i;
|
||||
|
||||
reg [7:0] rst_cnt = 8'h00;
|
||||
reg rst_i;
|
||||
wire rst_gbuf;
|
||||
|
||||
reg [2:0] sys_start_s;
|
||||
reg [2:0] sys_stop_s;
|
||||
|
||||
wire usb_rst_trig;
|
||||
reg [3:0] usb_rst_cnt;
|
||||
wire usb_rst_i;
|
||||
|
||||
reg [3:0] usb_ena_dly;
|
||||
wire usb_ena_i;
|
||||
|
||||
reg sys_off;
|
||||
|
||||
|
||||
// SB_HFOSC
|
||||
// -------
|
||||
// Generates 48 MHz
|
||||
|
||||
(* ROUTE_THROUGH_FABRIC = 1 *)
|
||||
SB_HFOSC #(
|
||||
.CLKHF_DIV("0b00")
|
||||
) osc_I (
|
||||
.CLKHFPU(1'b1),
|
||||
.CLKHFEN(1'b1),
|
||||
.CLKHF(clk_base)
|
||||
);
|
||||
|
||||
|
||||
// PLL
|
||||
// ---
|
||||
|
||||
SB_PLL40_CORE #(
|
||||
.DIVR (4'b0000),
|
||||
.DIVF (7'b0111111),
|
||||
.DIVQ (3'b100),
|
||||
.FILTER_RANGE (3'b001),
|
||||
.FEEDBACK_PATH ("SIMPLE"),
|
||||
.DELAY_ADJUSTMENT_MODE_FEEDBACK ("FIXED"),
|
||||
.FDA_FEEDBACK (4'b0000),
|
||||
.SHIFTREG_DIV_MODE (2'b00),
|
||||
.PLLOUT_SELECT ("GENCLK"),
|
||||
.ENABLE_ICEGATE (1'b0)
|
||||
) pll_I (
|
||||
.REFERENCECLK (clk_div[1]),
|
||||
.PLLOUTCORE (),
|
||||
.PLLOUTGLOBAL (clk_usb),
|
||||
.EXTFEEDBACK (1'b0),
|
||||
.DYNAMICDELAY (8'h00),
|
||||
.RESETB (usb_ena_i),
|
||||
.BYPASS (1'b0),
|
||||
.LATCHINPUTVALUE (1'b0),
|
||||
.LOCK (pll_lock),
|
||||
.SDI (1'b0),
|
||||
.SDO (),
|
||||
.SCLK (1'b0)
|
||||
);
|
||||
|
||||
|
||||
// Dividers
|
||||
// --------
|
||||
|
||||
// Counter
|
||||
always @(posedge clk_base)
|
||||
clk_div <= clk_div + 1;
|
||||
|
||||
// SYS is div-by-2 + gated
|
||||
always @(posedge clk_base)
|
||||
clk_sys_i <= clk_div[0] & ~sys_off;
|
||||
|
||||
// LED is div-by-8
|
||||
assign clk_led_i = clk_div[2];
|
||||
|
||||
// Global buffers
|
||||
SB_GB clk_sys_gbuf_I (
|
||||
.USER_SIGNAL_TO_GLOBAL_BUFFER(clk_sys_i),
|
||||
.GLOBAL_BUFFER_OUTPUT(clk_sys)
|
||||
);
|
||||
|
||||
SB_GB clk_led_gbuf_I (
|
||||
.USER_SIGNAL_TO_GLOBAL_BUFFER(clk_led_i),
|
||||
.GLOBAL_BUFFER_OUTPUT(clk_led)
|
||||
);
|
||||
|
||||
|
||||
// USB Enable
|
||||
// ----------
|
||||
|
||||
// Delay falling latch signal
|
||||
always @(posedge clk_base)
|
||||
usb_ena_dly <= usb_ena ? 4'b1111 : { usb_ena_dly[2:0], 1'b0 };
|
||||
|
||||
assign usb_ena_i = usb_ena_dly[3];
|
||||
|
||||
|
||||
// USB Reset
|
||||
// ---------
|
||||
|
||||
// Reset trigger
|
||||
assign usb_rst_trig = ~usb_ena | ~pll_lock;
|
||||
|
||||
// Reset counter
|
||||
always @(posedge clk_usb or posedge usb_rst_trig)
|
||||
if (usb_rst_trig)
|
||||
usb_rst_cnt <= 4'h8;
|
||||
else
|
||||
usb_rst_cnt <= usb_rst_cnt + usb_rst_i;
|
||||
|
||||
assign usb_rst_i = usb_rst_cnt[3];
|
||||
|
||||
// Global buffer
|
||||
SB_GB rst_usb_gbuf_I (
|
||||
.USER_SIGNAL_TO_GLOBAL_BUFFER(usb_rst_i),
|
||||
.GLOBAL_BUFFER_OUTPUT(rst_usb)
|
||||
);
|
||||
|
||||
|
||||
// SYS Enable
|
||||
// ----------
|
||||
|
||||
// Synch triggers
|
||||
always @(posedge clk_base)
|
||||
begin
|
||||
sys_start_s <= { ~sys_start_s[1] & sys_start_s[0], sys_start_s[0], sys_start };
|
||||
sys_stop_s <= { ~sys_stop_s[1] & sys_stop_s[0], sys_stop_s[0], sys_stop };
|
||||
end
|
||||
|
||||
always @(posedge clk_base)
|
||||
sys_off <= (sys_off & ~rst_i & ~sys_start_s[2]) | sys_stop_s[2];
|
||||
|
||||
|
||||
// Reset LED / SYS
|
||||
// ---------------
|
||||
|
||||
// Counter
|
||||
always @(posedge clk_led)
|
||||
rst_cnt <= rst_cnt + rst_i;
|
||||
|
||||
always @(posedge clk_led)
|
||||
rst_i <= (rst_cnt[7:4] != 4'hf);
|
||||
|
||||
// Global buffer
|
||||
SB_GB rst_gbuf_I (
|
||||
.USER_SIGNAL_TO_GLOBAL_BUFFER(rst_i),
|
||||
.GLOBAL_BUFFER_OUTPUT(rst_gbuf)
|
||||
);
|
||||
|
||||
// Distribution
|
||||
assign rst_led = rst_gbuf;
|
||||
assign rst_sys = rst_gbuf;
|
||||
|
||||
endmodule // sysmgr
|
|
@ -0,0 +1,332 @@
|
|||
/*
|
||||
* top.v
|
||||
*
|
||||
* vim: ts=4 sw=4
|
||||
*
|
||||
* Copyright (C) 2019-2020 Sylvain Munaut <tnt@246tNt.com>
|
||||
* SPDX-License-Identifier: CERN-OHL-P-2.0
|
||||
*/
|
||||
|
||||
`default_nettype none
|
||||
|
||||
module top (
|
||||
// SPI
|
||||
inout wire [3:0] spi_io,
|
||||
output wire spi_clk,
|
||||
output wire spi_cs_n,
|
||||
|
||||
// USB
|
||||
inout wire usb_dp,
|
||||
inout wire usb_dn,
|
||||
output wire usb_pu,
|
||||
|
||||
// Power
|
||||
input wire pwr_usb_n,
|
||||
input wire pwr_chg_n,
|
||||
output wire pwr_off,
|
||||
|
||||
// Buttons
|
||||
input wire [1:0] btn,
|
||||
|
||||
// I2C
|
||||
inout wire scl,
|
||||
inout wire sda,
|
||||
|
||||
// Speaker
|
||||
output wire hp_p,
|
||||
output wire hp_n,
|
||||
|
||||
// LED matrix
|
||||
output wire [13:0] led_a,
|
||||
output wire [2:0] led_c
|
||||
);
|
||||
|
||||
localparam integer WN = 6;
|
||||
genvar i;
|
||||
|
||||
|
||||
// Signals
|
||||
// -------
|
||||
|
||||
// Wishbone
|
||||
wire [15:0] wb_addr;
|
||||
wire [31:0] wb_rdata [0:WN-1];
|
||||
wire [31:0] wb_wdata;
|
||||
wire [3:0] wb_wmsk;
|
||||
wire [WN-1:0] wb_cyc;
|
||||
wire wb_we;
|
||||
wire [WN-1:0] wb_ack;
|
||||
|
||||
wire [(32*WN)-1:0] wb_rdata_flat;
|
||||
|
||||
// I2C
|
||||
wire i2c_scl_oe;
|
||||
wire i2c_scl_i;
|
||||
wire i2c_sda_oe;
|
||||
wire i2c_sda_i;
|
||||
|
||||
// USB Core
|
||||
// Wishbone in 48 MHz domain
|
||||
wire [11:0] ub_addr;
|
||||
wire [15:0] ub_wdata;
|
||||
wire [15:0] ub_rdata;
|
||||
wire ub_cyc;
|
||||
wire ub_we;
|
||||
wire ub_ack;
|
||||
|
||||
// EP Buffer
|
||||
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;
|
||||
|
||||
// Clock Control
|
||||
wire wakeup;
|
||||
wire sys_start;
|
||||
wire sys_stop;
|
||||
wire usb_ena;
|
||||
|
||||
// Clock / Reset
|
||||
wire clk_led;
|
||||
wire rst_led;
|
||||
wire clk_sys;
|
||||
wire rst_sys;
|
||||
wire clk_usb;
|
||||
wire rst_usb;
|
||||
|
||||
|
||||
// SoC
|
||||
// ---
|
||||
|
||||
soc_picorv32_base #(
|
||||
.WB_N (WN),
|
||||
.WB_DW (32),
|
||||
.WB_AW (16),
|
||||
.BRAM_AW (8), // 1k BRAM
|
||||
.SPRAM_AW (14) // 64k SPRAM
|
||||
) base_I (
|
||||
.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<WN; i=i+1)
|
||||
assign wb_rdata_flat[i*32+:32] = wb_rdata[i];
|
||||
|
||||
|
||||
// PMU [0]
|
||||
// ---
|
||||
|
||||
pmu pmu_I (
|
||||
.wb_addr (wb_addr[15:0]),
|
||||
.wb_rdata (wb_rdata[0]),
|
||||
.wb_wdata (wb_wdata),
|
||||
.wb_we (wb_we),
|
||||
.wb_cyc (wb_cyc[0]),
|
||||
.wb_ack (wb_ack[0]),
|
||||
.btn (btn),
|
||||
.pwr_usb_n (pwr_usb_n),
|
||||
.pwr_chg_n (pwr_chg_n),
|
||||
.pwr_off (pwr_off),
|
||||
.sys_start (sys_start),
|
||||
.sys_stop (sys_stop),
|
||||
.usb_ena (usb_ena),
|
||||
.wakeup (wakeup),
|
||||
.clk (clk_sys),
|
||||
.rst (rst_sys)
|
||||
);
|
||||
|
||||
|
||||
// SPI [1]
|
||||
// ---
|
||||
|
||||
ice40_spi_wb #(
|
||||
.N_CS(1),
|
||||
.WITH_IOB(1),
|
||||
.UNIT(0)
|
||||
) spi_I (
|
||||
.pad_mosi (spi_io[0]),
|
||||
.pad_miso (spi_io[1]),
|
||||
.pad_clk (spi_clk),
|
||||
.pad_csn (spi_cs_n),
|
||||
.wb_addr (wb_addr[3: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)
|
||||
);
|
||||
|
||||
assign spi_io[3:2] = 4'bzz;
|
||||
|
||||
|
||||
// I2C [2]
|
||||
// ---
|
||||
|
||||
// Controller
|
||||
i2c_master_wb #(
|
||||
.DW(4),
|
||||
.TW(15),
|
||||
.CLOCK_STRETCH(1),
|
||||
.FIFO_DEPTH(0)
|
||||
) i2c_I (
|
||||
.scl_oe (i2c_scl_oe),
|
||||
.scl_i (i2c_scl_i),
|
||||
.sda_oe (i2c_sda_oe),
|
||||
.sda_i (i2c_sda_i),
|
||||
.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)
|
||||
);
|
||||
|
||||
// IOBs
|
||||
SB_IO #(
|
||||
.PIN_TYPE(6'b110100),
|
||||
.PULLUP(1'b1),
|
||||
.IO_STANDARD("SB_LVCMOS")
|
||||
) i2c_iob_I[1:0] (
|
||||
.PACKAGE_PIN ({scl, sda}),
|
||||
.INPUT_CLK (clk_sys),
|
||||
.OUTPUT_CLK (clk_sys),
|
||||
.OUTPUT_ENABLE({i2c_scl_oe, i2c_sda_oe}),
|
||||
.D_OUT_0 (1'b0),
|
||||
.D_IN_0 ({i2c_scl_i, i2c_sda_i})
|
||||
);
|
||||
|
||||
|
||||
// USB Buffer [3]
|
||||
// ----------
|
||||
|
||||
soc_usb_buf_bridge usb_buf_I (
|
||||
.wb_addr (wb_addr),
|
||||
.wb_rdata (wb_rdata[3]),
|
||||
.wb_wdata (wb_wdata),
|
||||
.wb_wmsk (wb_wmsk),
|
||||
.wb_we (wb_we),
|
||||
.wb_cyc (wb_cyc[3]),
|
||||
.wb_ack (wb_ack[3]),
|
||||
.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)
|
||||
);
|
||||
|
||||
|
||||
// USB core [4]
|
||||
// --------
|
||||
|
||||
// Cross-clock
|
||||
xclk_wb #(
|
||||
.DW(16),
|
||||
.AW(12)
|
||||
) wb_48m_xclk_I (
|
||||
.s_addr (wb_addr[11:0]),
|
||||
.s_wdata (wb_wdata[15:0]),
|
||||
.s_rdata (wb_rdata[4][15:0]),
|
||||
.s_cyc (wb_cyc[4]),
|
||||
.s_ack (wb_ack[4]),
|
||||
.s_we (wb_we),
|
||||
.s_clk (clk_sys),
|
||||
.m_addr (ub_addr),
|
||||
.m_wdata (ub_wdata),
|
||||
.m_rdata (ub_rdata),
|
||||
.m_cyc (ub_cyc),
|
||||
.m_ack (ub_ack),
|
||||
.m_we (ub_we),
|
||||
.m_clk (clk_usb),
|
||||
.rst (rst_usb)
|
||||
);
|
||||
|
||||
assign wb_rdata[4][31:16] = 0;
|
||||
|
||||
// Core
|
||||
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),
|
||||
.clk (clk_usb),
|
||||
.rst (rst_usb)
|
||||
);
|
||||
|
||||
|
||||
// LED matrix controller [5]
|
||||
// ---------------------
|
||||
|
||||
led_ctrl led_I (
|
||||
.led_a (led_a),
|
||||
.led_c (led_c),
|
||||
.led_clk (clk_led),
|
||||
.led_rst (rst_led),
|
||||
.trig_out (wakeup),
|
||||
.wb_addr (wb_addr[15:0]),
|
||||
.wb_rdata (wb_rdata[5]),
|
||||
.wb_wdata (wb_wdata),
|
||||
.wb_we (wb_we),
|
||||
.wb_cyc (wb_cyc[5]),
|
||||
.wb_ack (wb_ack[5]),
|
||||
.wb_clk (clk_sys),
|
||||
.wb_rst (rst_sys)
|
||||
);
|
||||
|
||||
|
||||
// CRG
|
||||
// ---
|
||||
|
||||
`ifdef SIM
|
||||
sysmgr_sim crg_I (
|
||||
`else
|
||||
sysmgr crg_I (
|
||||
`endif
|
||||
.sys_start (sys_start),
|
||||
.sys_stop (sys_stop),
|
||||
.usb_ena (usb_ena),
|
||||
.clk_led (clk_led),
|
||||
.rst_led (rst_led),
|
||||
.clk_sys (clk_sys),
|
||||
.rst_sys (rst_sys),
|
||||
.clk_usb (clk_usb),
|
||||
.rst_usb (rst_usb)
|
||||
);
|
||||
|
||||
|
||||
// Unused
|
||||
// ------
|
||||
|
||||
assign hp_p = clk_sys;
|
||||
assign hp_n = 1'bz;
|
||||
|
||||
endmodule // top
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* xclk_cnt.v
|
||||
*
|
||||
* vim: ts=4 sw=4
|
||||
*
|
||||
* Helper to pass a counter value from one domain to another
|
||||
* (assuming the counter is increment/decrement/wrap only !)
|
||||
*
|
||||
* Copyright (C) 2023 Sylvain Munaut <tnt@246tNt.com>
|
||||
* SPDX-License-Identifier: CERN-OHL-P-2.0
|
||||
*/
|
||||
|
||||
`default_nettype none
|
||||
|
||||
module xclk_cnt #(
|
||||
parameter integer WIDTH = 4
|
||||
)(
|
||||
input wire [WIDTH-1:0] i_val,
|
||||
input wire i_clk,
|
||||
output wire [WIDTH-1:0] o_val,
|
||||
input wire o_clk,
|
||||
input wire rst
|
||||
);
|
||||
|
||||
// Encode to gray in source domain
|
||||
|
||||
// Capture in destination domain
|
||||
|
||||
// Decode from gray in destination domain
|
||||
|
||||
// FIXME
|
||||
assign o_val = i_val;
|
||||
|
||||
endmodule // xclk_cnt
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* xclk_pulse.v
|
||||
*
|
||||
* vim: ts=4 sw=4
|
||||
*
|
||||
* Helper to cross a pulse from one clock domain to another
|
||||
*
|
||||
* Copyright (C) 2023 Sylvain Munaut <tnt@246tNt.com>
|
||||
* SPDX-License-Identifier: CERN-OHL-P-2.0
|
||||
*/
|
||||
|
||||
`default_nettype none
|
||||
|
||||
module xclk_pulse (
|
||||
input wire i_stb,
|
||||
input wire i_clk,
|
||||
output wire o_stb,
|
||||
input wire o_clk,
|
||||
input wire rst
|
||||
);
|
||||
|
||||
reg i_toggle;
|
||||
reg [2:0] o_sync;
|
||||
|
||||
always @(posedge i_clk or posedge rst)
|
||||
if (rst)
|
||||
i_toggle <= 1'b0;
|
||||
else
|
||||
i_toggle <= i_toggle ^ i_stb;
|
||||
|
||||
always @(posedge o_clk or posedge rst)
|
||||
if (rst)
|
||||
o_sync <= 3'b000;
|
||||
else
|
||||
o_sync <= { o_sync[1] ^ o_sync[0], o_sync[0], i_toggle };
|
||||
|
||||
assign o_stb = o_sync[2];
|
||||
|
||||
endmodule // xclk_pulse
|
|
@ -0,0 +1,154 @@
|
|||
/*
|
||||
* led_ctrl_tb.v
|
||||
*
|
||||
* vim: ts=4 sw=4
|
||||
*
|
||||
* Copyright (C) 2022-2023 Sylvain Munaut <tnt@246tNt.com>
|
||||
* SPDX-License-Identifier: CERN-OHL-P-2.0
|
||||
*/
|
||||
|
||||
`default_nettype none
|
||||
`timescale 1ns / 100ps
|
||||
|
||||
module led_ctrl_tb;
|
||||
|
||||
// Signals
|
||||
// -------
|
||||
|
||||
// DUT
|
||||
wire [13:0] led_a;
|
||||
wire [2:0] led_c;
|
||||
|
||||
wire trig_out;
|
||||
|
||||
// Wishbone interface
|
||||
reg [31:0] wb_wdata;
|
||||
wire [31:0] wb_rdata;
|
||||
reg [15:0] wb_addr;
|
||||
reg wb_we;
|
||||
reg wb_cyc;
|
||||
wire wb_ack;
|
||||
|
||||
// Clocks / Sync
|
||||
reg pll_lock = 1'b0;
|
||||
|
||||
reg led_clk = 1'b0;
|
||||
wire led_rst;
|
||||
reg [3:0] led_rst_cnt = 4'h8;
|
||||
|
||||
reg wb_clk = 1'b0;
|
||||
wire wb_rst;
|
||||
reg [3:0] wb_rst_cnt = 4'h8;
|
||||
|
||||
|
||||
// Recording setup
|
||||
// ---------------
|
||||
|
||||
initial begin
|
||||
$dumpfile("led_ctrl_tb.vcd");
|
||||
$dumpvars(0,led_ctrl_tb);
|
||||
end
|
||||
|
||||
|
||||
// DUT
|
||||
// ---
|
||||
|
||||
led_ctrl dut_I (
|
||||
.led_a (led_a),
|
||||
.led_c (led_c),
|
||||
.led_clk (led_clk),
|
||||
.led_rst (led_rst),
|
||||
.trig_out (trig_out),
|
||||
.wb_addr (wb_addr),
|
||||
.wb_rdata (wb_rdata),
|
||||
.wb_wdata (wb_wdata),
|
||||
.wb_we (wb_we),
|
||||
.wb_cyc (wb_cyc),
|
||||
.wb_ack (wb_ack),
|
||||
.wb_clk (wb_clk),
|
||||
.wb_rst (wb_rst)
|
||||
);
|
||||
|
||||
|
||||
// Stimulus
|
||||
// --------
|
||||
|
||||
task wb_write;
|
||||
input [15:0] addr;
|
||||
input [31:0] data;
|
||||
begin
|
||||
wb_addr <= addr;
|
||||
wb_wdata <= data;
|
||||
wb_we <= 1'b1;
|
||||
wb_cyc <= 1'b1;
|
||||
|
||||
while (~wb_ack)
|
||||
@(posedge wb_clk);
|
||||
|
||||
wb_addr <= 4'hx;
|
||||
wb_wdata <= 32'hxxxxxxxx;
|
||||
wb_we <= 1'bx;
|
||||
wb_cyc <= 1'b0;
|
||||
|
||||
@(posedge wb_clk);
|
||||
end
|
||||
endtask
|
||||
|
||||
initial begin
|
||||
// Defaults
|
||||
wb_addr <= 4'hx;
|
||||
wb_wdata <= 32'hxxxxxxxx;
|
||||
wb_we <= 1'bx;
|
||||
wb_cyc <= 1'b0;
|
||||
|
||||
@(negedge wb_rst);
|
||||
@(negedge led_rst);
|
||||
@(posedge wb_clk);
|
||||
|
||||
// Write to frame memory
|
||||
// Anode 4
|
||||
// C0 [00-7f] (all ON)
|
||||
// C1 (all OFF)
|
||||
// C2 [40-4f] (16 cycles)
|
||||
wb_write(16'h0200, 32'h7f_00_00_04);
|
||||
wb_write(16'h0201, 32'h4f_40_00_7f);
|
||||
|
||||
wb_write(16'h0202, 32'h01_01_00_0a);
|
||||
wb_write(16'h0203, 32'h01_00_00_01);
|
||||
|
||||
// Enable
|
||||
wb_write(16'h0000, 32'hc0000007);
|
||||
end
|
||||
|
||||
|
||||
// Clock / Reset
|
||||
// -------------
|
||||
|
||||
// Clocks
|
||||
initial begin
|
||||
# 200 pll_lock = 1'b1;
|
||||
# 1000000 $finish;
|
||||
//# 35000000 $finish;
|
||||
end
|
||||
|
||||
always #20 wb_clk = ~wb_clk; // 25 MHz
|
||||
always #83 led_clk = ~led_clk; // 6 MHz
|
||||
|
||||
// Reset
|
||||
always @(posedge wb_clk or negedge pll_lock)
|
||||
if (~pll_lock)
|
||||
wb_rst_cnt <= 4'h8;
|
||||
else if (wb_rst_cnt[3])
|
||||
wb_rst_cnt <= wb_rst_cnt + 1;
|
||||
|
||||
assign wb_rst = wb_rst_cnt[3];
|
||||
|
||||
always @(posedge led_clk or negedge pll_lock)
|
||||
if (~pll_lock)
|
||||
led_rst_cnt <= 4'h8;
|
||||
else if (led_rst_cnt[3])
|
||||
led_rst_cnt <= led_rst_cnt + 1;
|
||||
|
||||
assign led_rst = led_rst_cnt[3];
|
||||
|
||||
endmodule
|
|
@ -0,0 +1,425 @@
|
|||
/*
|
||||
* PicoSoC - A simple example SoC using PicoRV32
|
||||
*
|
||||
* Copyright (C) 2017 Clifford Wolf <clifford@clifford.at>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
`timescale 1 ns / 1 ps
|
||||
|
||||
//
|
||||
// Simple SPI flash simulation model
|
||||
//
|
||||
// This model samples io input signals 1ns before the SPI clock edge and
|
||||
// updates output signals 1ns after the SPI clock edge.
|
||||
//
|
||||
// Supported commands:
|
||||
// AB, B9, FF, 03, BB, EB, ED
|
||||
//
|
||||
// Well written SPI flash data sheets:
|
||||
// Cypress S25FL064L http://www.cypress.com/file/316661/download
|
||||
// Cypress S25FL128L http://www.cypress.com/file/316171/download
|
||||
//
|
||||
// SPI flash used on iCEBreaker board:
|
||||
// https://www.winbond.com/resource-files/w25q128jv%20dtr%20revb%2011042016.pdf
|
||||
//
|
||||
|
||||
module spiflash (
|
||||
input csb,
|
||||
input clk,
|
||||
inout io0, // MOSI
|
||||
inout io1, // MISO
|
||||
inout io2,
|
||||
inout io3
|
||||
);
|
||||
localparam verbose = 1;
|
||||
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 = 1;
|
||||
|
||||
localparam [3:0] mode_spi = 1;
|
||||
localparam [3:0] mode_dspi_rd = 2;
|
||||
localparam [3:0] mode_dspi_wr = 3;
|
||||
localparam [3:0] mode_qspi_rd = 4;
|
||||
localparam [3:0] mode_qspi_wr = 5;
|
||||
localparam [3:0] mode_qspi_ddr_rd = 6;
|
||||
localparam [3:0] mode_qspi_ddr_wr = 7;
|
||||
|
||||
reg [3:0] mode = 0;
|
||||
reg [3:0] next_mode = 0;
|
||||
|
||||
reg io0_oe = 0;
|
||||
reg io1_oe = 0;
|
||||
reg io2_oe = 0;
|
||||
reg io3_oe = 0;
|
||||
|
||||
reg io0_dout = 0;
|
||||
reg io1_dout = 0;
|
||||
reg io2_dout = 0;
|
||||
reg io3_dout = 0;
|
||||
|
||||
assign #1 io0 = io0_oe ? io0_dout : 1'bz;
|
||||
assign #1 io1 = io1_oe ? io1_dout : 1'bz;
|
||||
assign #1 io2 = io2_oe ? io2_dout : 1'bz;
|
||||
assign #1 io3 = io3_oe ? io3_dout : 1'bz;
|
||||
|
||||
wire io0_delayed;
|
||||
wire io1_delayed;
|
||||
wire io2_delayed;
|
||||
wire io3_delayed;
|
||||
|
||||
assign #1 io0_delayed = io0;
|
||||
assign #1 io1_delayed = io1;
|
||||
assign #1 io2_delayed = io2;
|
||||
assign #1 io3_delayed = io3;
|
||||
|
||||
// 16 MB (128Mb) Flash
|
||||
reg [7:0] memory [0:16*1024*1024-1];
|
||||
|
||||
reg [1023:0] firmware_file;
|
||||
initial begin
|
||||
if (!$value$plusargs("firmware=%s", firmware_file))
|
||||
firmware_file = "firmware.hex";
|
||||
$readmemh(firmware_file, memory);
|
||||
end
|
||||
|
||||
task spi_action;
|
||||
begin
|
||||
spi_in = buffer;
|
||||
|
||||
if (bytecount == 1) begin
|
||||
spi_cmd = buffer;
|
||||
|
||||
if (spi_cmd == 8'h ab)
|
||||
powered_up = 1;
|
||||
|
||||
if (spi_cmd == 8'h b9)
|
||||
powered_up = 0;
|
||||
|
||||
if (spi_cmd == 8'h ff)
|
||||
xip_cmd = 0;
|
||||
end
|
||||
|
||||
if (powered_up && spi_cmd == 'h 03) begin
|
||||
if (bytecount == 2)
|
||||
spi_addr[23:16] = buffer;
|
||||
|
||||
if (bytecount == 3)
|
||||
spi_addr[15:8] = buffer;
|
||||
|
||||
if (bytecount == 4)
|
||||
spi_addr[7:0] = buffer;
|
||||
|
||||
if (bytecount >= 4) begin
|
||||
buffer = memory[spi_addr];
|
||||
spi_addr = spi_addr + 1;
|
||||
end
|
||||
end
|
||||
|
||||
if (powered_up && spi_cmd == 'h 0b) 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 >= 5) 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
|
|
@ -0,0 +1,167 @@
|
|||
/*
|
||||
* sysmgr_sim.v
|
||||
*
|
||||
* vim: ts=4 sw=4
|
||||
*
|
||||
* System Clock / Reset generation (simulated)
|
||||
*
|
||||
* Copyright (C) 2023 Sylvain Munaut <tnt@246tNt.com>
|
||||
* SPDX-License-Identifier: CERN-OHL-P-2.0
|
||||
*/
|
||||
|
||||
`default_nettype none
|
||||
|
||||
module sysmgr_sim (
|
||||
// Control
|
||||
input wire sys_start,
|
||||
input wire sys_stop,
|
||||
input wire usb_ena,
|
||||
|
||||
// LED clock ( 6 MHz )
|
||||
output wire clk_led,
|
||||
output wire rst_led,
|
||||
|
||||
// System clock ( 24 MHz )
|
||||
output wire clk_sys,
|
||||
output wire rst_sys,
|
||||
|
||||
// USB ( 48 MHz )
|
||||
output wire clk_usb,
|
||||
output wire rst_usb
|
||||
);
|
||||
|
||||
// Signals
|
||||
// -------
|
||||
|
||||
reg clk_base = 1'b0;
|
||||
|
||||
wire pll_lock;
|
||||
|
||||
reg [2:0] clk_div = 3'b000;
|
||||
reg clk_sys_i;
|
||||
wire clk_led_i;
|
||||
|
||||
reg [7:0] rst_cnt = 8'h00;
|
||||
reg rst_i = 1;
|
||||
wire rst_gbuf;
|
||||
|
||||
reg [2:0] sys_start_s;
|
||||
reg [2:0] sys_stop_s;
|
||||
|
||||
wire usb_rst_trig;
|
||||
reg [3:0] usb_rst_cnt;
|
||||
wire usb_rst_i;
|
||||
|
||||
reg [3:0] usb_ena_dly;
|
||||
wire usb_ena_i;
|
||||
|
||||
reg sys_off;
|
||||
|
||||
|
||||
// SB_HFOSC
|
||||
// -------
|
||||
// Generates 48 MHz
|
||||
|
||||
always #10.42 clk_base = ~clk_base;
|
||||
|
||||
|
||||
// PLL
|
||||
// ---
|
||||
|
||||
assign clk_usb = usb_ena_i & clk_base;
|
||||
assign pll_lock = usb_ena_i;
|
||||
|
||||
|
||||
// Dividers
|
||||
// --------
|
||||
|
||||
// Counter
|
||||
always @(posedge clk_base)
|
||||
clk_div <= clk_div + 1;
|
||||
|
||||
// SYS is div-by-2 + gated
|
||||
always @(posedge clk_base)
|
||||
clk_sys_i <= clk_div[0] & ~sys_off;
|
||||
|
||||
// LED is div-by-8
|
||||
assign clk_led_i = clk_div[2];
|
||||
|
||||
// Global buffers
|
||||
SB_GB clk_sys_gbuf_I (
|
||||
.USER_SIGNAL_TO_GLOBAL_BUFFER(clk_sys_i),
|
||||
.GLOBAL_BUFFER_OUTPUT(clk_sys)
|
||||
);
|
||||
|
||||
SB_GB clk_led_gbuf_I (
|
||||
.USER_SIGNAL_TO_GLOBAL_BUFFER(clk_led_i),
|
||||
.GLOBAL_BUFFER_OUTPUT(clk_led)
|
||||
);
|
||||
|
||||
|
||||
// USB Enable
|
||||
// ----------
|
||||
|
||||
// Delay falling latch signal
|
||||
always @(posedge clk_base)
|
||||
usb_ena_dly <= usb_ena ? 4'b1111 : { usb_ena_dly[2:0], 1'b0 };
|
||||
|
||||
assign usb_ena_i = usb_ena_dly[3];
|
||||
|
||||
|
||||
// USB Reset
|
||||
// ---------
|
||||
|
||||
// Reset trigger
|
||||
assign usb_rst_trig = ~usb_ena | ~pll_lock;
|
||||
|
||||
// Reset counter
|
||||
always @(posedge clk_usb or posedge usb_rst_trig)
|
||||
if (usb_rst_trig)
|
||||
usb_rst_cnt <= 4'h8;
|
||||
else
|
||||
usb_rst_cnt <= usb_rst_cnt + usb_rst_i;
|
||||
|
||||
assign usb_rst_i = usb_rst_cnt[3];
|
||||
|
||||
// Global buffer
|
||||
SB_GB rst_usb_gbuf_I (
|
||||
.USER_SIGNAL_TO_GLOBAL_BUFFER(usb_rst_i),
|
||||
.GLOBAL_BUFFER_OUTPUT(rst_usb)
|
||||
);
|
||||
|
||||
|
||||
// SYS Enable
|
||||
// ----------
|
||||
|
||||
// Synch triggers
|
||||
always @(posedge clk_base)
|
||||
begin
|
||||
sys_start_s <= { ~sys_start_s[1] & sys_start_s[0], sys_start_s[0], sys_start };
|
||||
sys_stop_s <= { ~sys_stop_s[1] & sys_stop_s[0], sys_stop_s[0], sys_stop };
|
||||
end
|
||||
|
||||
always @(posedge clk_base)
|
||||
sys_off <= (sys_off & ~rst_i & ~sys_start_s[2]) | sys_stop_s[2];
|
||||
|
||||
|
||||
// Reset LED / SYS
|
||||
// ---------------
|
||||
|
||||
// Counter
|
||||
always @(posedge clk_led)
|
||||
rst_cnt <= rst_cnt + rst_i;
|
||||
|
||||
always @(posedge clk_led)
|
||||
rst_i <= (rst_cnt[7:4] != 4'hf);
|
||||
|
||||
// Global buffer
|
||||
SB_GB rst_gbuf_I (
|
||||
.USER_SIGNAL_TO_GLOBAL_BUFFER(rst_i),
|
||||
.GLOBAL_BUFFER_OUTPUT(rst_gbuf)
|
||||
);
|
||||
|
||||
// Distribution
|
||||
assign rst_led = rst_gbuf;
|
||||
assign rst_sys = rst_gbuf;
|
||||
|
||||
endmodule // sysmgr
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* top_tb.v
|
||||
*
|
||||
* vim: ts=4 sw=4
|
||||
*
|
||||
* Copyright (C) 2023 Sylvain Munaut <tnt@246tNt.com>
|
||||
* SPDX-License-Identifier: CERN-OHL-P-2.0
|
||||
*/
|
||||
|
||||
`default_nettype none
|
||||
|
||||
module top_tb;
|
||||
|
||||
// Signals
|
||||
// -------
|
||||
|
||||
wire [3:0] spi_io;
|
||||
wire spi_cs_n;
|
||||
wire spi_clk;
|
||||
|
||||
wire usb_dp;
|
||||
wire usb_dn;
|
||||
wire usb_pu;
|
||||
|
||||
|
||||
// Setup recording
|
||||
// ---------------
|
||||
|
||||
initial begin
|
||||
$dumpfile("top_tb.vcd");
|
||||
$dumpvars(0,top_tb);
|
||||
# 2000000 $finish;
|
||||
end
|
||||
|
||||
|
||||
// DUT
|
||||
// ---
|
||||
|
||||
top dut_I (
|
||||
.spi_io (spi_io),
|
||||
.spi_clk (spi_clk),
|
||||
.spi_cs_n (spi_cs_n),
|
||||
.usb_dp (usb_dp),
|
||||
.usb_dn (usb_dn),
|
||||
.usb_pu (usb_pu)
|
||||
);
|
||||
|
||||
|
||||
// Support
|
||||
// -------
|
||||
|
||||
pullup(usb_dp);
|
||||
pullup(usb_dn);
|
||||
|
||||
spiflash flash_I (
|
||||
.csb (spi_cs_n),
|
||||
.clk (spi_clk),
|
||||
.io0 (spi_io[0]),
|
||||
.io1 (spi_io[1]),
|
||||
.io2 (spi_io[2]),
|
||||
.io3 (spi_io[3])
|
||||
);
|
||||
|
||||
endmodule // top_tb
|
Loading…
Reference in New Issue