Add RISC-V timer to example soc, and tweak ULX3S config

This commit is contained in:
Luke Wren 2022-10-07 03:11:30 +01:00
parent a18c3018e1
commit 8721bd3deb
6 changed files with 211 additions and 35 deletions

View File

@ -62,6 +62,7 @@ activity_led #(
);
example_soc #(
.CLK_MHZ (12),
.EXTENSION_A (1),
.EXTENSION_C (0),
.EXTENSION_M (1),
@ -72,6 +73,7 @@ example_soc #(
.EXTENSION_ZBKB (0),
.EXTENSION_ZIFENCEI (0),
.EXTENSION_XH3BEXTM (0),
.EXTENSION_XH3PMPM (0),
.EXTENSION_XH3POWER (0),
.CSR_COUNTER (0),
.U_MODE (0),

View File

@ -17,7 +17,7 @@ wire clk_sys;
wire pll_sys_locked;
wire rst_n_sys;
pll_25_40 pll_sys (
pll_25_50 pll_sys (
.clkin (clk_osc),
.clkout0 (clk_sys),
.locked (pll_sys_locked)
@ -32,19 +32,29 @@ fpga_reset #(
);
example_soc #(
.DTM_TYPE ("ECP5"),
.SRAM_DEPTH (1 << 15),
.DTM_TYPE ("ECP5"),
.SRAM_DEPTH (1 << 15),
.CLK_MHZ (50),
.EXTENSION_M (1),
.EXTENSION_A (1),
.EXTENSION_C (0),
.EXTENSION_ZBA (0),
.EXTENSION_ZBB (0),
.EXTENSION_ZBC (0),
.EXTENSION_ZBS (0),
.CSR_COUNTER (0),
.MUL_FAST (1),
.MULDIV_UNROLL (1)
.EXTENSION_M (1),
.EXTENSION_A (1),
.EXTENSION_C (0),
.EXTENSION_ZBA (0),
.EXTENSION_ZBB (0),
.EXTENSION_ZBC (0),
.EXTENSION_ZBS (0),
.EXTENSION_ZBKB (0),
.EXTENSION_ZIFENCEI (1),
.EXTENSION_XH3BEXTM (0),
.EXTENSION_XH3PMPM (0),
.EXTENSION_XH3POWER (0),
.CSR_COUNTER (1),
.MUL_FAST (1),
.MUL_FASTER (0),
.MULH_FAST (0),
.MULDIV_UNROLL (1),
.FAST_BRANCHCMP (1),
.BRANCH_PREDICTOR (1)
) soc_u (
.clk (clk_sys),
.rst_n (rst_n_sys),

View File

@ -9,8 +9,9 @@
`default_nettype none
module example_soc #(
parameter DTM_TYPE = "JTAG", // can be "JTAG" or "ECP5"
parameter SRAM_DEPTH = 1 << 15, // default 32 kwords -> 128 kB
parameter DTM_TYPE = "JTAG", // Can be "JTAG" or "ECP5"
parameter SRAM_DEPTH = 1 << 15, // Default 32 kwords -> 128 kB
parameter CLK_MHZ = 12, // For timer timebase
`include "hazard3_config.vh"
) (
@ -262,6 +263,8 @@ hazard3_cpu_1port #(
.EXTENSION_ZBKB (EXTENSION_ZBKB),
.EXTENSION_ZIFENCEI (EXTENSION_ZIFENCEI),
.EXTENSION_XH3BEXTM (EXTENSION_XH3BEXTM),
.EXTENSION_XH3IRQ (EXTENSION_XH3IRQ),
.EXTENSION_XH3PMPM (EXTENSION_XH3PMPM),
.EXTENSION_XH3POWER (EXTENSION_XH3POWER),
.CSR_COUNTER (CSR_COUNTER),
.U_MODE (U_MODE),
@ -538,30 +541,43 @@ uart_mini uart_u (
.dreq (/* unused */)
);
// hazard3_riscv_timer timer_u (
// .clk (clk),
// .rst_n (rst_n),
// Microsecond timebase for timer
// .psel (timer_psel),
// .penable (timer_penable),
// .pwrite (timer_pwrite),
// .paddr (timer_paddr),
// .pwdata (timer_pwdata),
// .prdata (timer_prdata),
// .pready (timer_pready),
// .pslverr (timer_pslverr),
reg [$clog2(CLK_MHZ)-1:0] timer_tick_ctr;
reg timer_tick;
// .dbg_halt (&hart_halted),
always @ (posedge clk or negedge rst_n) begin
if (!rst_n) begin
timer_tick_ctr <= {$clog2(CLK_MHZ){1'b0}};
timer_tick <= 1'b0;
end else begin
if (|timer_tick_ctr) begin
timer_tick_ctr <= timer_tick_ctr - 1'b1;
end else begin
timer_tick_ctr <= CLK_MHZ - 1;
end
timer_tick <= ~|timer_tick_ctr;
end
end
// // Tie high for 64-cycle timebase:
// .tick (1'b1),
hazard3_riscv_timer timer_u (
.clk (clk),
.rst_n (rst_n),
// .timer_irq (timer_irq)
// );
.psel (timer_psel),
.penable (timer_penable),
.pwrite (timer_pwrite),
.paddr (timer_paddr),
.pwdata (timer_pwdata),
.prdata (timer_prdata),
.pready (timer_pready),
.pslverr (timer_pslverr),
assign timer_pslverr = 1'b0;
assign timer_pready = 1'b1;
assign timer_prdata = 32'h0;
assign timer_irq = 1'b0;
.dbg_halt (&hart_halted),
.tick (timer_tick),
.timer_irq (timer_irq)
);
endmodule

View File

@ -0,0 +1,2 @@
file hazard3_riscv_timer.v
file ../../../hdl/debug/cdc/hazard3_sync_1bit.v

View File

@ -0,0 +1,142 @@
/*****************************************************************************\
| Copyright (C) 2022 Luke Wren |
| SPDX-License-Identifier: Apache-2.0 |
\*****************************************************************************/
`default_nettype none
// Basic implementation of standard 64-bit RISC-V timer with 32-bit APB.
// TICK_IS_NRZ = 1: tick is an NRZ signal that is asynchronous to clk.
// TICK_IS_NRZ = 0: tick is a level-sensitive signal that is synchronous to clk.
module hazard3_riscv_timer #(
parameter TICK_IS_NRZ = 0
) (
input wire clk,
input wire rst_n,
input wire [15:0] paddr,
input wire psel,
input wire penable,
input wire pwrite,
input wire [31:0] pwdata,
output reg [31:0] prdata,
output wire pready,
output wire pslverr,
input wire dbg_halt,
input wire tick,
output reg timer_irq
);
localparam ADDR_CTRL = 16'h0000;
localparam ADDR_MTIME = 16'h0008;
localparam ADDR_MTIMEH = 16'h000c;
localparam ADDR_MTIMECMP = 16'h0010;
localparam ADDR_MTIMECMPH = 16'h0014;
// ----------------------------------------------------------------------------
// Timer tick logic
wire tick_event;
generate
if (TICK_IS_NRZ) begin: edge_detect
wire tick_nrz_sync;
hazard3_sync_1bit tick_sync_u (
.clk (clk),
.rst_n (rst_n),
.i (tick_nrz),
.o (tick_nrz_sync)
);
reg tick_nrz_prev;
always @ (posedge clk or negedge rst_n) begin
if (!rst_n) begin
tick_nrz_prev <= 1'b0;
end else begin
tick_nrz_prev <= tick_nrz_sync;
end
end
assign tick_event = tick_nrz_sync ^ tick_nrz_sync_prev;
end else begin: no_edge_detect
assign tick_event = tick;
end
endgenerate
reg ctrl_en;
wire tick_now = tick_event && ctrl_en && !dbg_halt;
// ----------------------------------------------------------------------------
// Counter registers
wire bus_write = pwrite && psel && penable;
wire bus_read = !pwrite && psel && penable;
always @ (posedge clk or negedge rst_n) begin
if (!rst_n) begin
ctrl_en <= 1'b1;
end else if (bus_write && paddr == ADDR_CTRL) begin
ctrl_en <= pwdata[0];
end
end
reg [63:0] mtime;
always @ (posedge clk or negedge rst_n) begin
if (!rst_n) begin
mtime <= 64'h0;
end else begin
if (tick_now)
mtime <= mtime + 1'b1;
if (bus_write && paddr == ADDR_MTIME)
mtime[31:0] <= pwdata;
if (bus_write && paddr == ADDR_MTIMEH)
mtime[63:32] <= pwdata;
end
end
// mtimecmp is stored inverted for minor LUT savings on iCE40
reg [63:0] mtimecmp;
wire [64:0] cmp_diff = {1'b0, mtime} + {1'b0, mtimecmp} + 65'd1;
always @ (posedge clk or negedge rst_n) begin
if (!rst_n) begin
mtimecmp <= 64'h0;
timer_irq <= 1'b0;
end else begin
if (bus_write && paddr == ADDR_MTIMECMP)
mtimecmp[31:0] <= ~pwdata;
if (bus_write && paddr == ADDR_MTIMECMPH)
mtimecmp[63:32] <= ~pwdata;
timer_irq <= cmp_diff[64];
end
end
always @ (*) begin
case (paddr)
ADDR_CTRL: prdata = {31'h0, ctrl_en};
ADDR_MTIME: prdata = mtime[31:0];
ADDR_MTIMEH: prdata = mtime[63:32];
ADDR_MTIMECMP: prdata = ~mtimecmp[31:0];
ADDR_MTIMECMPH: prdata = ~mtimecmp[63:32];
default: prdata = 32'h0;
endcase
end
assign pready = 1'b1;
assign pslverr = 1'b0;
endmodule
`ifndef YOSYS
`default_nettype none
`endif

View File

@ -8,6 +8,10 @@ list $HDL/hazard3.f
list $HDL/debug/dtm/hazard3_jtag_dtm.f
list $HDL/debug/dm/hazard3_dm.f
# RISC-V timer
list peri/hazard3_riscv_timer.f
# Generic SoC components from libfpga
file ../libfpga/common/reset_sync.v