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 (
|
||||