Added everything from the other system

This commit is contained in:
2026-02-28 21:46:59 +01:00
parent 907f244b24
commit cf483decad
34 changed files with 1601 additions and 57 deletions

48
cores/system/mcu/mcu.core Normal file
View File

@@ -0,0 +1,48 @@
CAPI=2:
name: joppeb:system:mcu:1.0
description: basic RISC-V MCU system
filesets:
rtl:
depend:
- "^award-winning:serv:servile:1.4.0"
- joppeb:util:clog2
- joppeb:wb:jtag_wb_bridge
- joppeb:wb:wb_gpio_banks
- joppeb:wb:wb_timer
- joppeb:wb:wb_arbiter
- joppeb:wb:wb_mux
files:
- rtl/mcu.v
- rtl/mcu_peripherals.v
file_type: verilogSource
targets:
default:
filesets:
- rtl
toplevel: mcu
parameters:
- memfile
- memsize
- sim
- jtag
parameters:
memfile:
datatype: str
description: Memory initialization file passed to the internal RAM
paramtype: vlogparam
memsize:
datatype: int
description: Internal RAM size in bytes
paramtype: vlogparam
sim:
datatype: int
description: Enable simulation-friendly RAM initialization behavior
paramtype: vlogparam
jtag:
datatype: int
description: Enable the JTAG Wishbone bridge and arbiter path
paramtype: vlogparam

382
cores/system/mcu/rtl/mcu.v Normal file
View File

@@ -0,0 +1,382 @@
`timescale 1ns/1ps
`include "clog2.vh"
module mcu #(
parameter memfile = "",
parameter memsize = 8192,
parameter sim = 1'b0,
parameter jtag = 1
)(
input wire i_clk,
input wire i_rst,
input wire [31:0] i_GPI_A,
input wire [31:0] i_GPI_B,
input wire [31:0] i_GPI_C,
input wire [31:0] i_GPI_D,
output wire [31:0] o_GPO_A,
output wire [31:0] o_GPO_B,
output wire [31:0] o_GPO_C,
output wire [31:0] o_GPO_D
);
localparam WITH_CSR = 1;
localparam rf_width = 8;
wire rst;
wire rst_wb;
wire rst_mem_peripherals;
wire rst_cmd_jtag;
wire timer_irq;
assign rst = i_rst | rst_mem_peripherals | rst_cmd_jtag;
// Keep the Wishbone path alive during JTAG "core reset" so memory can be programmed.
assign rst_wb = i_rst;
// Busses
// CPU<->memory interconnect (CPU is a WB master)
wire [31:0] wb_mem_adr;
wire [31:0] wb_mem_dat;
wire [3:0] wb_mem_sel;
wire wb_mem_we;
wire wb_mem_stb;
wire [31:0] wb_mem_rdt_cpu;
wire wb_mem_ack_cpu;
// Interconnect->memory (shared WB slave side)
wire [31:0] wb_mem_adr_s;
wire [31:0] wb_mem_dat_s;
wire [3:0] wb_mem_sel_s;
wire wb_mem_we_s;
wire wb_mem_stb_s;
wire [31:0] wb_mem_rdt_s;
wire wb_mem_ack_s;
// CPU->peripherals
wire [31:0] wb_ext_adr;
wire [31:0] wb_ext_dat;
wire [3:0] wb_ext_sel;
wire wb_ext_we;
wire wb_ext_stb;
wire [31:0] wb_ext_rdt;
wire wb_ext_ack;
// GPIO
wire [4*32-1:0] GPO;
wire [4*32-1:0] GPI;
assign o_GPO_A = GPO[32*1-1:32*0];
assign o_GPO_B = GPO[32*2-1:32*1];
assign o_GPO_C = GPO[32*3-1:32*2];
assign o_GPO_D = GPO[32*4-1:32*3];
assign GPI[32*1-1:32*0] = i_GPI_A;
assign GPI[32*2-1:32*1] = i_GPI_B;
assign GPI[32*3-1:32*2] = i_GPI_C;
assign GPI[32*4-1:32*3] = i_GPI_D;
cpu #(
.sim(sim),
.WITH_CSR(WITH_CSR),
.rf_width(rf_width)
) cpu (
.i_clk(i_clk),
.i_rst(rst),
.i_timer_irq(timer_irq),
//Memory interface
.o_wb_mem_adr(wb_mem_adr),
.o_wb_mem_dat(wb_mem_dat),
.o_wb_mem_sel(wb_mem_sel),
.o_wb_mem_we(wb_mem_we),
.o_wb_mem_stb(wb_mem_stb),
.i_wb_mem_rdt(wb_mem_rdt_cpu),
.i_wb_mem_ack(wb_mem_ack_cpu),
//Extension interface
.o_wb_ext_adr(wb_ext_adr),
.o_wb_ext_dat(wb_ext_dat),
.o_wb_ext_sel(wb_ext_sel),
.o_wb_ext_we(wb_ext_we),
.o_wb_ext_stb(wb_ext_stb),
.i_wb_ext_rdt(wb_ext_rdt),
.i_wb_ext_ack(wb_ext_ack)
);
generate
if (jtag) begin : gen_jtag_wb
wire [31:0] wb_jtag_adr;
wire [31:0] wb_jtag_dat;
wire [3:0] wb_jtag_sel;
wire wb_jtag_we;
wire wb_jtag_cyc;
wire wb_jtag_stb;
wire [31:0] wb_jtag_rdt;
wire wb_jtag_ack;
wire [2*32-1:0] wbm_adr_i;
wire [2*32-1:0] wbm_dat_i;
wire [2*4-1:0] wbm_sel_i;
wire [1:0] wbm_we_i;
wire [1:0] wbm_cyc_i;
wire [1:0] wbm_stb_i;
wire [2*3-1:0] wbm_cti_i;
wire [2*2-1:0] wbm_bte_i;
wire [2*32-1:0] wbm_dat_o;
wire [1:0] wbm_ack_o;
wire [1:0] wbm_err_o;
wire [1:0] wbm_rty_o;
assign wbm_adr_i = {wb_jtag_adr, wb_mem_adr};
assign wbm_dat_i = {wb_jtag_dat, wb_mem_dat};
assign wbm_sel_i = {wb_jtag_sel, wb_mem_sel};
assign wbm_we_i = {wb_jtag_we, wb_mem_we};
assign wbm_cyc_i = {wb_jtag_cyc, wb_mem_stb};
assign wbm_stb_i = {wb_jtag_stb, wb_mem_stb};
assign wbm_cti_i = 6'b0;
assign wbm_bte_i = 4'b0;
assign wb_mem_rdt_cpu = wbm_dat_o[31:0];
assign wb_mem_ack_cpu = wbm_ack_o[0];
assign wb_jtag_rdt = wbm_dat_o[63:32];
assign wb_jtag_ack = wbm_ack_o[1];
wb_arbiter #(
.dw(32),
.aw(32),
.num_masters(2)
) wb_mem_arbiter (
.wb_clk_i(i_clk),
.wb_rst_i(rst_wb),
.wbm_adr_i(wbm_adr_i),
.wbm_dat_i(wbm_dat_i),
.wbm_sel_i(wbm_sel_i),
.wbm_we_i(wbm_we_i),
.wbm_cyc_i(wbm_cyc_i),
.wbm_stb_i(wbm_stb_i),
.wbm_cti_i(wbm_cti_i),
.wbm_bte_i(wbm_bte_i),
.wbm_dat_o(wbm_dat_o),
.wbm_ack_o(wbm_ack_o),
.wbm_err_o(wbm_err_o),
.wbm_rty_o(wbm_rty_o),
.wbs_adr_o(wb_mem_adr_s),
.wbs_dat_o(wb_mem_dat_s),
.wbs_sel_o(wb_mem_sel_s),
.wbs_we_o(wb_mem_we_s),
.wbs_cyc_o(),
.wbs_stb_o(wb_mem_stb_s),
.wbs_cti_o(),
.wbs_bte_o(),
.wbs_dat_i(wb_mem_rdt_s),
.wbs_ack_i(wb_mem_ack_s),
.wbs_err_i(1'b0),
.wbs_rty_i(1'b0)
);
jtag_wb_bridge #(
.chain(1)
) jtag_wb (
.i_clk(i_clk),
.i_rst(i_rst),
.o_wb_adr(wb_jtag_adr),
.o_wb_dat(wb_jtag_dat),
.o_wb_sel(wb_jtag_sel),
.o_wb_we(wb_jtag_we),
.o_wb_cyc(wb_jtag_cyc),
.o_wb_stb(wb_jtag_stb),
.i_wb_rdt(wb_jtag_rdt),
.i_wb_ack(wb_jtag_ack),
.o_cmd_reset(rst_cmd_jtag)
);
end else begin : gen_no_jtag_wb
assign wb_mem_adr_s = wb_mem_adr;
assign wb_mem_dat_s = wb_mem_dat;
assign wb_mem_sel_s = wb_mem_sel;
assign wb_mem_we_s = wb_mem_we;
assign wb_mem_stb_s = wb_mem_stb;
assign wb_mem_rdt_cpu = wb_mem_rdt_s;
assign wb_mem_ack_cpu = wb_mem_ack_s;
assign rst_cmd_jtag = 1'b0;
end
endgenerate
memory #(
.memfile(memfile),
.memsize(memsize),
.sim(sim)
) memory (
.i_clk(i_clk),
.i_rst(i_rst),
.i_wb_rst(rst_wb),
.i_wb_adr(wb_mem_adr_s),
.i_wb_dat(wb_mem_dat_s),
.i_wb_sel(wb_mem_sel_s),
.i_wb_we(wb_mem_we_s),
.i_wb_stb(wb_mem_stb_s),
.o_wb_rdt(wb_mem_rdt_s),
.o_wb_ack(wb_mem_ack_s)
);
mcu_peripherals peripherals (
.i_clk(i_clk),
.i_rst(rst),
.i_wb_adr(wb_ext_adr),
.i_wb_dat(wb_ext_dat),
.i_wb_sel(wb_ext_sel),
.i_wb_we(wb_ext_we),
.i_wb_stb(wb_ext_stb),
.o_wb_rdt(wb_ext_rdt),
.o_wb_ack(wb_ext_ack),
// Peripheral IO
.i_gpio(GPI),
.o_gpio(GPO),
.o_timer_irq(timer_irq),
.o_core_reset(rst_mem_peripherals)
);
endmodule
module cpu #(
parameter sim = 1'b0,
parameter WITH_CSR = 1,
parameter rf_width = 8
)(
input wire i_clk,
input wire i_rst,
input wire i_timer_irq,
// CPU->memory
output wire [31:0] o_wb_mem_adr,
output wire [31:0] o_wb_mem_dat,
output wire [3:0] o_wb_mem_sel,
output wire o_wb_mem_we,
output wire o_wb_mem_stb,
input wire [31:0] i_wb_mem_rdt,
input wire i_wb_mem_ack,
// CPU->peripherals
output wire [31:0] o_wb_ext_adr,
output wire [31:0] o_wb_ext_dat,
output wire [3:0] o_wb_ext_sel,
output wire o_wb_ext_we,
output wire o_wb_ext_stb,
input wire [31:0] i_wb_ext_rdt,
input wire i_wb_ext_ack
);
wire [6+WITH_CSR:0] rf_waddr;
wire [rf_width-1:0] rf_wdata;
wire rf_wen;
wire [6+WITH_CSR:0] rf_raddr;
wire [rf_width-1:0] rf_rdata;
wire rf_ren;
// SERV core with mux splitting dbus into mem and ext and
// arbiter combining mem and ibus.
servile #(
.reset_pc(32'h0000_0000),
.reset_strategy("MINI"),
.rf_width(rf_width),
.sim(sim),
.with_csr(WITH_CSR),
.with_c(0),
.with_mdu(0)
) servile (
.i_clk(i_clk),
.i_rst(i_rst),
.i_timer_irq(i_timer_irq),
.o_wb_mem_adr(o_wb_mem_adr),
.o_wb_mem_dat(o_wb_mem_dat),
.o_wb_mem_sel(o_wb_mem_sel),
.o_wb_mem_we(o_wb_mem_we),
.o_wb_mem_stb(o_wb_mem_stb),
.i_wb_mem_rdt(i_wb_mem_rdt),
.i_wb_mem_ack(i_wb_mem_ack),
.o_wb_ext_adr(o_wb_ext_adr),
.o_wb_ext_dat(o_wb_ext_dat),
.o_wb_ext_sel(o_wb_ext_sel),
.o_wb_ext_we(o_wb_ext_we),
.o_wb_ext_stb(o_wb_ext_stb),
.i_wb_ext_rdt(i_wb_ext_rdt),
.i_wb_ext_ack(i_wb_ext_ack),
.o_rf_waddr(rf_waddr),
.o_rf_wdata(rf_wdata),
.o_rf_wen(rf_wen),
.o_rf_raddr(rf_raddr),
.o_rf_ren(rf_ren),
.i_rf_rdata(rf_rdata)
);
serv_rf_ram #(
.width(rf_width),
.csr_regs(WITH_CSR*4)
) rf_ram (
.i_clk(i_clk),
.i_waddr(rf_waddr),
.i_wdata(rf_wdata),
.i_wen(rf_wen),
.i_raddr(rf_raddr),
.i_ren(rf_ren),
.o_rdata(rf_rdata)
);
endmodule
module memory #(
parameter memfile = "",
parameter memsize = 8192,
parameter sim = 1'b0
)(
input wire i_clk,
input wire i_rst,
input wire i_wb_rst,
input wire [31:0] i_wb_adr,
input wire [31:0] i_wb_dat,
input wire [3:0] i_wb_sel,
input wire i_wb_we,
input wire i_wb_stb,
output wire [31:0] o_wb_rdt,
output wire o_wb_ack
);
localparam mem_depth = memsize/4;
localparam mem_aw = `CLOG2(mem_depth);
reg [31:0] mem [0:mem_depth-1] /* verilator public */;
reg [31:0] wb_rdt_r;
reg wb_ack_r;
wire [mem_aw-1:0] wb_word_adr = i_wb_adr[mem_aw+1:2];
assign o_wb_rdt = wb_rdt_r;
assign o_wb_ack = wb_ack_r;
always @(posedge i_clk) begin
if (i_rst || i_wb_rst) begin
wb_ack_r <= 1'b0;
wb_rdt_r <= 32'b0;
end else begin
wb_ack_r <= i_wb_stb & ~wb_ack_r;
if (i_wb_stb & ~wb_ack_r) begin
wb_rdt_r <= mem[wb_word_adr];
if (i_wb_we) begin
if (i_wb_sel[0]) mem[wb_word_adr][7:0] <= i_wb_dat[7:0];
if (i_wb_sel[1]) mem[wb_word_adr][15:8] <= i_wb_dat[15:8];
if (i_wb_sel[2]) mem[wb_word_adr][23:16] <= i_wb_dat[23:16];
if (i_wb_sel[3]) mem[wb_word_adr][31:24] <= i_wb_dat[31:24];
end
end
end
end
integer i;
initial begin
if (sim == 1'b1) begin
for (i = 0; i < mem_depth; i = i + 1)
mem[i] = 32'h00000000;
end
if (|memfile) begin
$display("Preloading %m from %s", memfile);
$readmemh(memfile, mem);
end
wb_rdt_r = 32'b0;
wb_ack_r = 1'b0;
end
endmodule

View File

@@ -0,0 +1,126 @@
`timescale 1ns/1ps
module mcu_peripherals (
input wire i_clk,
input wire i_rst,
input wire [31:0] i_wb_adr,
input wire [31:0] i_wb_dat,
input wire [3:0] i_wb_sel,
input wire i_wb_we,
input wire i_wb_stb,
output wire [31:0] o_wb_rdt,
output wire o_wb_ack,
input wire [4*32-1:0] i_gpio,
output wire [4*32-1:0] o_gpio,
output wire o_timer_irq,
output wire o_core_reset
);
localparam [31:0] GPIO_BASE_ADDR = 32'h4000_0000;
localparam [31:0] GPIO_ADDR_MASK = 32'hFFFF_0000;
localparam [31:0] TIMER_BASE_ADDR = 32'h4001_0000;
localparam [31:0] TIMER_ADDR_MASK = 32'hFFFF_0000;
assign o_core_reset = 1'b0;
wire [2*32-1:0] wbs_adr;
wire [2*32-1:0] wbs_dat_w;
wire [2*4-1:0] wbs_sel;
wire [1:0] wbs_we;
wire [1:0] wbs_cyc;
wire [1:0] wbs_stb;
wire [2*3-1:0] wbs_cti;
wire [2*2-1:0] wbs_bte;
wire [2*32-1:0] wbs_dat_r;
wire [1:0] wbs_ack;
wire [31:0] gpio_wbs_adr = wbs_adr[0*32 +: 32];
wire [31:0] gpio_wbs_dat_w = wbs_dat_w[0*32 +: 32];
wire [3:0] gpio_wbs_sel = wbs_sel[0*4 +: 4];
wire gpio_wbs_we = wbs_we[0];
wire gpio_wbs_cyc = wbs_cyc[0];
wire gpio_wbs_stb = wbs_stb[0];
wire [31:0] gpio_wbs_dat_r;
wire gpio_wbs_ack;
wire [31:0] timer_wbs_dat_w = wbs_dat_w[1*32 +: 32];
wire timer_wbs_we = wbs_we[1];
wire timer_wbs_cyc = wbs_cyc[1];
wire timer_wbs_stb = wbs_stb[1];
wire [31:0] timer_wbs_dat_r;
wire timer_wbs_ack;
wb_mux #(
.dw(32),
.aw(32),
.num_slaves(2),
.MATCH_ADDR({TIMER_BASE_ADDR, GPIO_BASE_ADDR}),
.MATCH_MASK({TIMER_ADDR_MASK, GPIO_ADDR_MASK})
) ext_mux (
.wb_clk_i(i_clk),
.wb_rst_i(i_rst),
.wbm_adr_i(i_wb_adr),
.wbm_dat_i(i_wb_dat),
.wbm_sel_i(i_wb_sel),
.wbm_we_i(i_wb_we),
.wbm_cyc_i(i_wb_stb),
.wbm_stb_i(i_wb_stb),
.wbm_cti_i(3'b000),
.wbm_bte_i(2'b00),
.wbm_dat_o(o_wb_rdt),
.wbm_ack_o(o_wb_ack),
.wbm_err_o(),
.wbm_rty_o(),
.wbs_adr_o(wbs_adr),
.wbs_dat_o(wbs_dat_w),
.wbs_sel_o(wbs_sel),
.wbs_we_o(wbs_we),
.wbs_cyc_o(wbs_cyc),
.wbs_stb_o(wbs_stb),
.wbs_cti_o(wbs_cti),
.wbs_bte_o(wbs_bte),
.wbs_dat_i(wbs_dat_r),
.wbs_ack_i(wbs_ack),
.wbs_err_i(2'b00),
.wbs_rty_i(2'b00)
);
wb_gpio_banks #(
.BASE_ADDR(GPIO_BASE_ADDR),
.NUM_BANKS(4)
) gpio (
.i_wb_clk(i_clk),
.i_wb_rst(i_rst),
.i_wb_dat(gpio_wbs_dat_w),
.i_wb_adr(gpio_wbs_adr),
.i_wb_we(gpio_wbs_we),
.i_wb_stb(gpio_wbs_stb & gpio_wbs_cyc),
.i_wb_sel(gpio_wbs_sel),
.o_wb_rdt(gpio_wbs_dat_r),
.o_wb_ack(gpio_wbs_ack),
.i_gpio(i_gpio),
.o_gpio(o_gpio)
);
assign wbs_dat_r[0*32 +: 32] = gpio_wbs_dat_r;
assign wbs_ack[0] = gpio_wbs_ack;
wb_countdown_timer timer (
.i_clk(i_clk),
.i_rst(i_rst),
.o_irq(o_timer_irq),
.i_wb_dat(timer_wbs_dat_w),
.o_wb_dat(timer_wbs_dat_r),
.i_wb_we(timer_wbs_we),
.i_wb_cyc(timer_wbs_cyc),
.i_wb_stb(timer_wbs_stb),
.o_wb_ack(timer_wbs_ack)
);
assign wbs_dat_r[1*32 +: 32] = timer_wbs_dat_r;
assign wbs_ack[1] = timer_wbs_ack;
endmodule

View File

@@ -1,6 +1,8 @@
`timescale 1ns/1ps
module toplevel(
module toplevel #(
parameter sim = 0
)(
input wire aclk,
input wire aresetn,
@@ -11,6 +13,7 @@ module toplevel(
output wire[7:0] LED
);
`include "conv.vh"
// Clocking
wire clk_100;
@@ -25,56 +28,75 @@ module toplevel(
.clk_out(clk_15)
);
wire wb_rst;
assign wb_rst = ~aresetn;
wire [31:0] wb_adr;
wire [31:0] wb_dat_w;
wire [31:0] wb_dat_r;
wire [3:0] wb_sel;
wire wb_we;
wire wb_cyc;
wire wb_stb;
wire wb_ack;
wire wb_cmd_reset;
// Reset conditioning for button input:
// - asynchronous assert when button is pressed (aresetn=0)
// - synchronous, debounced deassert in clk_15 domain
localparam [17:0] RESET_RELEASE_CYCLES = sim ? 18'd16 : 18'd150000; // ~10 ms @ 15 MHz on hardware
reg [17:0] rst_cnt = 18'd0;
reg sys_reset_r = 1'b1;
always @(posedge clk_15 or negedge aresetn) begin
if (!aresetn) begin
rst_cnt <= 18'd0;
sys_reset_r <= 1'b1;
end else if (sys_reset_r) begin
if (rst_cnt == RESET_RELEASE_CYCLES - 1'b1)
sys_reset_r <= 1'b0;
else
rst_cnt <= rst_cnt + 1'b1;
end
end
wire sys_reset = sys_reset_r;
wire sys_resetn = !sys_reset_r;
wire [31:0] gpio_out;
wire gpio_rst;
assign gpio_rst = wb_rst;
wire [31:0] GPIO_A;
wire [31:0] GPIO_B;
wire [31:0] GPIO_C;
wire [31:0] GPIO_D;
jtag_wb_bridge u_jtag_wb_bridge (
wire test;
mcu #(
.memfile("../sw/sweep/sweep.hex"),
.sim(sim),
.jtag(1)
) mcu (
.i_clk(clk_15),
.i_rst(wb_rst),
.o_wb_adr(wb_adr),
.o_wb_dat(wb_dat_w),
.o_wb_sel(wb_sel),
.o_wb_we(wb_we),
.o_wb_cyc(wb_cyc),
.o_wb_stb(wb_stb),
.i_wb_rdt(wb_dat_r),
.i_wb_ack(wb_ack),
.o_cmd_reset(wb_cmd_reset)
.i_rst(sys_reset),
.i_GPI_A(GPIO_A),
.i_GPI_B(GPIO_B),
.i_GPI_C(GPIO_C),
.i_GPI_D(GPIO_D),
.o_GPO_A(GPIO_A),
.o_GPO_B(GPIO_B),
.o_GPO_C(GPIO_C),
.o_GPO_D(GPIO_D)
);
wb_gpio #(
.address(32'h00000000)
) u_wb_gpio (
.i_wb_clk(clk_15),
.i_wb_rst(gpio_rst),
.i_wb_adr(wb_adr),
.i_wb_dat(wb_dat_w),
.i_wb_sel(wb_sel),
.i_wb_we(wb_we),
.i_wb_stb(wb_cyc & wb_stb),
.i_gpio(gpio_out),
.o_wb_rdt(wb_dat_r),
.o_wb_ack(wb_ack),
.o_gpio(gpio_out)
wire [15:0] sin_q15;
wire clk_en;
nco_q15 #(
.CLK_HZ(15_000_000),
.FS_HZ(80_000)
) nco (
.clk (clk_15),
.rst_n (sys_resetn),
.freq_hz(GPIO_A),
.sin_q15(sin_q15),
.cos_q15(),
.clk_en (clk_en)
);
assign led_green = aresetn;
assign led_red = wb_cmd_reset;
assign LED = gpio_out[7:0];
assign r2r = gpio_out[13:8];
reg [5:0] dac_code;
always @(posedge clk_15) begin
dac_code <= q15_to_uq16(sin_q15) >> 10;
end
assign r2r = dac_code;
assign LED = GPIO_B[7:0];
assign led_green = GPIO_C[0];
assign led_red = GPIO_C[1];
endmodule

8
cores/system/test/sw/.gitignore vendored Normal file
View File

@@ -0,0 +1,8 @@
*.o
*.hex
*.bin
*.map
*.elf.asm
*.elf
*.coe
*.mif

View File

@@ -0,0 +1,47 @@
TOOLCHAIN_PREFIX ?= riscv64-elf-
CC := $(TOOLCHAIN_PREFIX)gcc
OBJCOPY := $(TOOLCHAIN_PREFIX)objcopy
OBJDUMP := $(TOOLCHAIN_PREFIX)objdump
SIZE := $(TOOLCHAIN_PREFIX)size
TARGET := sweep
SRCS_C := sweep.c
SRCS_S := start.s
OBJS := $(SRCS_C:.c=.o) $(SRCS_S:.s=.o)
ARCH_FLAGS := -march=rv32i_zicsr -mabi=ilp32
CFLAGS := $(ARCH_FLAGS) -Os -ffreestanding -fno-builtin -Wall -Wextra
ASFLAGS := $(ARCH_FLAGS)
LDFLAGS := $(ARCH_FLAGS) -nostdlib -nostartfiles -Wl,-Bstatic,-Tlink.ld,--gc-sections,-Map,$(TARGET).map
.PHONY: all clean disasm size
all: $(TARGET).elf $(TARGET).bin $(TARGET).hex $(TARGET).elf.asm
$(TARGET).elf: $(OBJS) link.ld
$(CC) $(LDFLAGS) -o $@ $(OBJS)
%.o: %.c
$(CC) $(CFLAGS) -c -o $@ $<
%.o: %.s
$(CC) $(ASFLAGS) -c -o $@ $<
$(TARGET).bin: $(TARGET).elf
$(OBJCOPY) -O binary $< $@
$(TARGET).hex: $(TARGET).bin
hexdump -v -e '1/4 "%08x\n"' $< > $@
$(TARGET).elf.asm: $(TARGET).elf
$(OBJDUMP) -d -S $< > $@
disasm: $(TARGET).elf.asm
size: $(TARGET).elf
$(SIZE) $<
clean:
rm -f $(TARGET).elf $(TARGET).bin $(TARGET).hex $(TARGET).coe $(TARGET).mif \
$(TARGET).elf.asm $(TARGET).map $(OBJS)

View File

@@ -0,0 +1,35 @@
OUTPUT_ARCH("riscv")
ENTRY(_start)
MEMORY
{
RAM (rwx) : ORIGIN = 0x00000000, LENGTH = 8192
}
SECTIONS
{
.text :
{
KEEP(*(.text.init))
*(.text .text.*)
*(.rodata .rodata.*)
} > RAM
.data :
{
*(.data .data.*)
} > RAM
.bss (NOLOAD) :
{
__bss_start = .;
*(.bss .bss.*)
*(.sbss .sbss.*)
*(.scommon)
*(COMMON)
__bss_end = .;
} > RAM
. = ALIGN(4);
__stack_top = ORIGIN(RAM) + LENGTH(RAM);
}

View File

@@ -0,0 +1,99 @@
.section .text.init
.globl _start
.type _start, @function
_start:
la sp, __stack_top
# Zero .bss
la t0, __bss_start
la t1, __bss_end
1:
bgeu t0, t1, 2f
sw zero, 0(t0)
addi t0, t0, 4
j 1b
2:
call main
3:
j 3b
.size _start, .-_start
.section .text
.globl trap_entry
.type trap_entry, @function
trap_entry:
# Save full integer context (except x0/x2) because an interrupt can
# preempt code with live values in any register, not just caller-saved.
addi sp, sp, -128
sw ra, 124(sp)
sw gp, 120(sp)
sw tp, 116(sp)
sw t0, 112(sp)
sw t1, 108(sp)
sw t2, 104(sp)
sw s0, 100(sp)
sw s1, 96(sp)
sw a0, 92(sp)
sw a1, 88(sp)
sw a2, 84(sp)
sw a3, 80(sp)
sw a4, 76(sp)
sw a5, 72(sp)
sw a6, 68(sp)
sw a7, 64(sp)
sw s2, 60(sp)
sw s3, 56(sp)
sw s4, 52(sp)
sw s5, 48(sp)
sw s6, 44(sp)
sw s7, 40(sp)
sw s8, 36(sp)
sw s9, 32(sp)
sw s10, 28(sp)
sw s11, 24(sp)
sw t3, 20(sp)
sw t4, 16(sp)
sw t5, 12(sp)
sw t6, 8(sp)
csrr t0, mcause
li t1, 0x80000007 # machine timer interrupt (RV32)
bne t0, t1, 1f
call timer_isr # C function that ACKs/clears the timer so i_timer_irq goes low
1:
lw t6, 8(sp)
lw t5, 12(sp)
lw t4, 16(sp)
lw t3, 20(sp)
lw s11, 24(sp)
lw s10, 28(sp)
lw s9, 32(sp)
lw s8, 36(sp)
lw s7, 40(sp)
lw s6, 44(sp)
lw s5, 48(sp)
lw s4, 52(sp)
lw s3, 56(sp)
lw s2, 60(sp)
lw a7, 64(sp)
lw a6, 68(sp)
lw a5, 72(sp)
lw a4, 76(sp)
lw a3, 80(sp)
lw a2, 84(sp)
lw a1, 88(sp)
lw a0, 92(sp)
lw s1, 96(sp)
lw s0, 100(sp)
lw t2, 104(sp)
lw t1, 108(sp)
lw t0, 112(sp)
lw tp, 116(sp)
lw gp, 120(sp)
lw ra, 124(sp)
addi sp, sp, 128
mret

View File

@@ -0,0 +1,45 @@
#include <stdint.h>
#define GPIO_BASE 0x40000000u
static volatile uint32_t * const R_FREQ = (volatile uint32_t *)(GPIO_BASE+0);
static volatile uint32_t * const LEDS = (volatile uint32_t *)(GPIO_BASE+4);
static volatile uint32_t * const LEDGR = (volatile uint32_t *)(GPIO_BASE+8);
#define TIMER_BASE 0x40010000u
static volatile uint32_t * const TIMER = (volatile uint32_t *)(TIMER_BASE+0);
#define MSTATUS_MIE (1u << 3)
#define MIE_MTIE (1u << 7)
extern void trap_entry();
static inline void irq_init() {
/* mtvec first */
asm volatile ("csrw mtvec, %0" :: "r"(trap_entry));
/* enable machine timer interrupt */
asm volatile ("csrs mie, %0" :: "r"(MIE_MTIE));
/* global enable last */
asm volatile ("csrs mstatus, %0" :: "r"(MSTATUS_MIE));
}
void timer_isr(){
static int set = 0;
*TIMER = 1840000*8;
*LEDGR = ~(*LEDGR);
}
void main(){
irq_init();
*LEDGR = 3;
*TIMER = 1840000*2;
for(;;){
for(int i=1000; i<10000; i++){
*R_FREQ = i;
for(int j=0; j<80; j++) asm volatile("nop");
}
}
}

View File

@@ -7,12 +7,18 @@ filesets:
rtl:
depend:
- joppeb:primitive:clkgen
- joppeb:wb:jtag_wb_bridge
- joppeb:wb:wb_gpio
- joppeb:system:mcu
- joppeb:signal:nco_q15
- joppeb:util:conv
files:
- rtl/toplevel.v
file_type: verilogSource
sw:
files:
- sw/sweep/sweep.hex
file_type: user
mimas:
files:
- mimas.ucf : {file_type : UCF}
@@ -28,6 +34,7 @@ targets:
filesets:
- rtl
- mimas
- sw
toplevel: toplevel
parameters:
- FPGA_SPARTAN6=true

View File

@@ -2,6 +2,7 @@
`define CLOG2_VH
// Verilog-2001 compatible ceil(log2(x)) macro (matches $clog2 semantics).
`ifndef CLOG2
`define CLOG2(x) \
(((x) <= 1) ? 0 : \
((x) <= 2) ? 1 : \
@@ -37,3 +38,4 @@
((x) <= 2147483648) ? 31 : 32)
`endif
`endif

16
cores/util/conv/conv.core Normal file
View File

@@ -0,0 +1,16 @@
CAPI=2:
name: joppeb:util:conv:1.0
description: Verilog conversion helper header
filesets:
include:
files:
- conv.vh:
is_include_file: true
file_type: verilogSource
targets:
default:
filesets:
- include

16
cores/util/conv/conv.vh Normal file
View File

@@ -0,0 +1,16 @@
`ifndef CONV_VH
`define CONV_VH
// =============================================================================
// Convert Q1.15 to a biased UQ0.16 signal
// =============================================================================
function [15:0] q15_to_uq16;
input [15:0] q15;
reg [16:0] biased;
begin
biased = q15 + 17'sd32768;
q15_to_uq16 = biased[15:0];
end
endfunction
`endif

View File

@@ -52,6 +52,7 @@ module formal_wb_master_checker (
// R3: Once a request starts, hold it stable until the slave responds
if(
f_past_valid &&
!$past(i_rst || i_wb_rst) &&
$past(i_wb_cyc && i_wb_stb && !o_wb_ack) &&
!o_wb_ack &&
!(i_rst || i_wb_rst)

View File

@@ -3,7 +3,7 @@ mode prove
depth 8
[engines]
smtbmc z3
abc pdr
[script]
{{"-formal"|gen_reads}}

View File

@@ -505,8 +505,8 @@ module jtag_wb_bridge #(
// Mark active command complete
act_valid <= 1'b0;
// If there is a queued command, promote and start it
if (q_valid) begin
// If there is a queued command and the WB port is idle, promote it now.
if (q_valid && !wb_busy) begin
act_valid <= 1'b1;
act_opcode <= q_opcode;
act_addr <= q_addr;

View File

@@ -32,7 +32,7 @@ $(SHARED_LIB): $(LIB_OBJS)
$(CXX) -shared $(LDFLAGS) -o $@ $(LIB_OBJS) $(LIBS)
$(TARGET): $(APP_OBJS) $(STATIC_LIB)
$(CXX) $(LDFLAGS) -o $@ $(APP_OBJS) -L. -ljtag_wb_bridge $(LIBS)
$(CXX) $(LDFLAGS) -o $@ $(APP_OBJS) -L. $(STATIC_LIB) $(LIBS)
%.o: %.cpp
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $<

View File

@@ -107,7 +107,7 @@ bool JtagWishboneBridge::ping() {
ping_value = static_cast<uint8_t>(response & 0xffu);
if (ping_value != 0xa5) {
char msg[96];
std::snprintf(msg, sizeof(msg), "ping mismatch: expected 0xa4, got 0x%02x", ping_value);
std::snprintf(msg, sizeof(msg), "ping mismatch: expected 0xa5, got 0x%02x", ping_value);
return setError(msg);
}
last_error_.clear();

View File

@@ -31,15 +31,10 @@ int main(int argc, char** argv) {
return -1;
}
uint8_t ping_value = 0;
if (!bridge.ping()) {
std::printf("PING command failed: %s\n", bridge.lastError().c_str());
return -1;
}
if (ping_value != 0xa5u) {
std::printf("PING response was not right: %02x\n", ping_value);
return -1;
}
const std::string file = parser.getString("file");
FILE* f = std::fopen(file.c_str(), "rb");

View File

@@ -5,4 +5,4 @@ with JtagBridge() as bridge:
bridge.clear_flags()
bridge.ping()
bridge.write32(0x0, 0xAA)
bridge.write8(0x0, 0xAA)

View File

@@ -0,0 +1,138 @@
/**
* Module: arbiter
*
* Description:
* A look ahead, round-robing parameterized arbiter.
*
* <> request
* each bit is controlled by an actor and each actor can 'request' ownership
* of the shared resource by bring high its request bit.
*
* <> grant
* when an actor has been given ownership of shared resource its 'grant' bit
* is driven high
*
* <> select
* binary representation of the grant signal (optional use)
*
* <> active
* is brought high by the arbiter when (any) actor has been given ownership
* of shared resource.
*
*
* Created: Sat Jun 1 20:26:44 EDT 2013
*
* Author: Berin Martini // berin.martini@gmail.com
*/
`ifndef _arbiter_ `define _arbiter_
`include "clog2.vh"
module arbiter
#(parameter
NUM_PORTS = 6,
SEL_WIDTH = ((NUM_PORTS > 1) ? `CLOG2(NUM_PORTS) : 1))
(input wire clk,
input wire rst,
input wire [NUM_PORTS-1:0] request,
output reg [NUM_PORTS-1:0] grant,
output reg [SEL_WIDTH-1:0] select,
output reg active
);
/**
* Local parameters
*/
localparam WRAP_LENGTH = 2*NUM_PORTS;
// Find First 1 - Start from MSB and count downwards, returns 0 when no
// bit set
function [SEL_WIDTH-1:0] ff1 (
input [NUM_PORTS-1:0] in
);
reg set;
integer i;
begin
set = 1'b0;
ff1 = 'b0;
for (i = 0; i < NUM_PORTS; i = i + 1) begin
if (in[i] & ~set) begin
set = 1'b1;
ff1 = i[0 +: SEL_WIDTH];
end
end
end
endfunction
`ifdef VERBOSE
initial $display("Bus arbiter with %d units", NUM_PORTS);
`endif
/**
* Internal signals
*/
integer yy;
wire next;
wire [NUM_PORTS-1:0] order;
reg [NUM_PORTS-1:0] token;
wire [NUM_PORTS-1:0] token_lookahead [NUM_PORTS-1:0];
wire [WRAP_LENGTH-1:0] token_wrap;
/**
* Implementation
*/
assign token_wrap = {token, token};
assign next = ~|(token & request);
always @(posedge clk)
grant <= token & request;
always @(posedge clk)
select <= ff1(token & request);
always @(posedge clk)
active <= |(token & request);
always @(posedge clk)
if (rst) token <= 'b1;
else if (next) begin
for (yy = 0; yy < NUM_PORTS; yy = yy + 1) begin : TOKEN_
if (order[yy]) begin
token <= token_lookahead[yy];
end
end
end
genvar xx;
generate
for (xx = 0; xx < NUM_PORTS; xx = xx + 1) begin : ORDER_
assign token_lookahead[xx] = token_wrap[xx +: NUM_PORTS];
assign order[xx] = |(token_lookahead[xx] & request);
end
endgenerate
endmodule
`endif // `ifndef _arbiter_

View File

@@ -0,0 +1,101 @@
/* wb_arbiter. Part of wb_intercon
*
* ISC License
*
* Copyright (C) 2013-2019 Olof Kindgren <olof.kindgren@gmail.com>
*
* 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.
*/
/*
Wishbone arbiter, burst-compatible
Simple round-robin arbiter for multiple Wishbone masters
*/
`include "clog2.vh"
module wb_arbiter
#(parameter dw = 32,
parameter aw = 32,
parameter num_hosts = 0,
parameter num_masters = num_hosts)
(
input wire wb_clk_i,
input wire wb_rst_i,
// Wishbone Master Interface
input wire [num_masters*aw-1:0] wbm_adr_i,
input wire [num_masters*dw-1:0] wbm_dat_i,
input wire [num_masters*4-1:0] wbm_sel_i,
input wire [num_masters-1:0] wbm_we_i,
input wire [num_masters-1:0] wbm_cyc_i,
input wire [num_masters-1:0] wbm_stb_i,
input wire [num_masters*3-1:0] wbm_cti_i,
input wire [num_masters*2-1:0] wbm_bte_i,
output wire [num_masters*dw-1:0] wbm_dat_o,
output wire [num_masters-1:0] wbm_ack_o,
output wire [num_masters-1:0] wbm_err_o,
output wire [num_masters-1:0] wbm_rty_o,
// Wishbone Slave interface
output wire [aw-1:0] wbs_adr_o,
output wire [dw-1:0] wbs_dat_o,
output wire [3:0] wbs_sel_o,
output wire wbs_we_o,
output wire wbs_cyc_o,
output wire wbs_stb_o,
output wire [2:0] wbs_cti_o,
output wire [1:0] wbs_bte_o,
input wire [dw-1:0] wbs_dat_i,
input wire wbs_ack_i,
input wire wbs_err_i,
input wire wbs_rty_i);
///////////////////////////////////////////////////////////////////////////////
// Parameters
///////////////////////////////////////////////////////////////////////////////
//Use parameter instead of localparam to work around a bug in Xilinx ISE
parameter master_sel_bits = num_masters > 1 ? `CLOG2(num_masters) : 1;
wire [num_masters-1:0] grant;
wire [master_sel_bits-1:0] master_sel;
wire active;
arbiter
#(.NUM_PORTS (num_masters))
arbiter0
(.clk (wb_clk_i),
.rst (wb_rst_i),
.request (wbm_cyc_i),
.grant (grant),
.select (master_sel),
.active (active));
/* verilator lint_off WIDTH */
//Mux active master
assign wbs_adr_o = wbm_adr_i[master_sel*aw+:aw];
assign wbs_dat_o = wbm_dat_i[master_sel*dw+:dw];
assign wbs_sel_o = wbm_sel_i[master_sel*4+:4];
assign wbs_we_o = wbm_we_i [master_sel];
assign wbs_cyc_o = wbm_cyc_i[master_sel] & active;
assign wbs_stb_o = wbm_stb_i[master_sel];
assign wbs_cti_o = wbm_cti_i[master_sel*3+:3];
assign wbs_bte_o = wbm_bte_i[master_sel*2+:2];
assign wbm_dat_o = {num_masters{wbs_dat_i}};
assign wbm_ack_o = ((wbs_ack_i & active) << master_sel);
assign wbm_err_o = ((wbs_err_i & active) << master_sel);
assign wbm_rty_o = ((wbs_rty_i & active) << master_sel);
/* verilator lint_on WIDTH */
endmodule // wb_arbiter

View File

@@ -0,0 +1,42 @@
CAPI=2:
name: joppeb:wb:wb_arbiter:1.0
description: Wishbone round-robin arbiter
filesets:
rtl:
depend:
- joppeb:util:clog2
files:
- rtl/arbiter.v
- rtl/wb_arbiter.v
file_type: verilogSource
targets:
default:
filesets:
- rtl
toplevel: wb_arbiter
parameters:
- dw
- aw
- num_hosts
- num_masters
parameters:
dw:
datatype: int
description: Wishbone data width
paramtype: vlogparam
aw:
datatype: int
description: Wishbone address width
paramtype: vlogparam
num_hosts:
datatype: int
description: Deprecated alias for num_masters
paramtype: vlogparam
num_masters:
datatype: int
description: Number of wishbone masters
paramtype: vlogparam

View File

@@ -8,6 +8,7 @@ filesets:
files:
- rtl/wb_gpio.v
file_type: verilogSource
formal_rtl:
depend:
- joppeb:wb:formal_checker
@@ -26,6 +27,7 @@ targets:
toplevel: wb_gpio
parameters:
- address
formal:
default_tool: symbiyosys
filesets:

View File

@@ -0,0 +1,63 @@
`default_nettype none
module wb_gpio_banks #(
parameter integer NUM_BANKS = 4,
parameter [31:0] BASE_ADDR = 32'h8000_0000
) (
input wire i_wb_clk,
input wire i_wb_rst,
input wire [31:0] i_wb_adr,
input wire [31:0] i_wb_dat,
input wire [3:0] i_wb_sel,
input wire i_wb_we,
input wire i_wb_stb,
input wire [NUM_BANKS*32-1:0] i_gpio,
output reg [31:0] o_wb_rdt,
output reg o_wb_ack,
output wire [NUM_BANKS*32-1:0] o_gpio
);
wire [NUM_BANKS-1:0] bank_sel;
wire [NUM_BANKS-1:0] bank_stb;
wire [NUM_BANKS*32-1:0] bank_rdt;
wire [NUM_BANKS-1:0] bank_ack;
genvar gi;
generate
for (gi = 0; gi < NUM_BANKS; gi = gi + 1) begin : gen_gpio
localparam [31:0] BANK_ADDR = BASE_ADDR + (gi * 4);
assign bank_sel[gi] = (i_wb_adr == BANK_ADDR);
assign bank_stb[gi] = i_wb_stb & bank_sel[gi];
wb_gpio #(
.address(BANK_ADDR)
) u_gpio (
.i_wb_clk(i_wb_clk),
.i_wb_rst(i_wb_rst),
.i_wb_adr(i_wb_adr),
.i_wb_dat(i_wb_dat),
.i_wb_sel(i_wb_sel),
.i_wb_we(i_wb_we),
.i_wb_stb(bank_stb[gi]),
.i_gpio(i_gpio[gi*32 +: 32]),
.o_wb_rdt(bank_rdt[gi*32 +: 32]),
.o_wb_ack(bank_ack[gi]),
.o_gpio(o_gpio[gi*32 +: 32])
);
end
endgenerate
integer bi;
always @* begin
o_wb_rdt = 32'h0000_0000;
o_wb_ack = 1'b0;
for (bi = 0; bi < NUM_BANKS; bi = bi + 1) begin
if (bank_sel[bi]) begin
o_wb_rdt = bank_rdt[bi*32 +: 32];
o_wb_ack = bank_ack[bi];
end
end
end
endmodule

View File

@@ -0,0 +1,31 @@
CAPI=2:
name: joppeb:wb:wb_gpio_banks:1.0
description: Wishbone GPIO bank wrapper
filesets:
rtl:
depend:
- joppeb:wb:wb_gpio
files:
- rtl/wb_gpio_banks.v
file_type: verilogSource
targets:
default:
filesets:
- rtl
toplevel: wb_gpio_banks
parameters:
- NUM_BANKS
- BASE_ADDR
parameters:
NUM_BANKS:
datatype: int
description: Number of GPIO banks to instantiate
paramtype: vlogparam
BASE_ADDR:
datatype: int
description: Base wishbone address for bank 0
paramtype: vlogparam

View File

@@ -0,0 +1,145 @@
/* wb_mux. Part of wb_intercon
*
* ISC License
*
* Copyright (C) 2013-2019 Olof Kindgren <olof.kindgren@gmail.com>
*
* 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.
*/
/*
Wishbone multiplexer, burst-compatible
Simple mux with an arbitrary number of slaves.
The parameters MATCH_ADDR and MATCH_MASK are flattened arrays
aw*NUM_SLAVES sized arrays that are used to calculate the
active slave. slave i is selected when
(wb_adr_i & MATCH_MASK[(i+1)*aw-1:i*aw] is equal to
MATCH_ADDR[(i+1)*aw-1:i*aw]
If several regions are overlapping, the slave with the lowest
index is selected. This can be used to have fallback
functionality in the last slave, in case no other slave was
selected.
If no match is found, the wishbone transaction will stall and
an external watchdog is required to abort the transaction
Todo:
Registered master/slave connections
Rewrite with System Verilog 2D arrays when tools support them
*/
`include "clog2.vh"
module wb_mux
#(parameter dw = 32, // Data width
parameter aw = 32, // Address width
parameter num_devices = 2, // Number of devices
parameter num_slaves = num_devices, // Number of devices (deprecated)
parameter [num_slaves*aw-1:0] MATCH_ADDR = 0,
parameter [num_slaves*aw-1:0] MATCH_MASK = 0)
(
input wire wb_clk_i,
input wire wb_rst_i,
// Master Interface
input wire [aw-1:0] wbm_adr_i,
input wire [dw-1:0] wbm_dat_i,
input wire [3:0] wbm_sel_i,
input wire wbm_we_i,
input wire wbm_cyc_i,
input wire wbm_stb_i,
input wire [2:0] wbm_cti_i,
input wire [1:0] wbm_bte_i,
output wire [dw-1:0] wbm_dat_o,
output wire wbm_ack_o,
output wire wbm_err_o,
output wire wbm_rty_o,
// Wishbone Slave interface
output wire [num_slaves*aw-1:0] wbs_adr_o,
output wire [num_slaves*dw-1:0] wbs_dat_o,
output wire [num_slaves*4-1:0] wbs_sel_o,
output wire [num_slaves-1:0] wbs_we_o,
output wire [num_slaves-1:0] wbs_cyc_o,
output wire [num_slaves-1:0] wbs_stb_o,
output wire [num_slaves*3-1:0] wbs_cti_o,
output wire [num_slaves*2-1:0] wbs_bte_o,
input wire [num_slaves*dw-1:0] wbs_dat_i,
input wire [num_slaves-1:0] wbs_ack_i,
input wire [num_slaves-1:0] wbs_err_i,
input wire [num_slaves-1:0] wbs_rty_i);
///////////////////////////////////////////////////////////////////////////////
// Master/slave connection
///////////////////////////////////////////////////////////////////////////////
//Use parameter instead of localparam to work around a bug in Xilinx ISE
parameter slave_sel_bits = num_slaves > 1 ? `CLOG2(num_slaves) : 1;
reg wbm_err;
wire [slave_sel_bits-1:0] slave_sel;
wire [num_slaves-1:0] match;
genvar idx;
generate
for(idx=0; idx<num_slaves ; idx=idx+1) begin : addr_match
assign match[idx] = (wbm_adr_i & MATCH_MASK[idx*aw+:aw]) == MATCH_ADDR[idx*aw+:aw];
end
endgenerate
//
// Find First 1 - Start from MSB and count downwards, returns 0 when no bit set
//
function [slave_sel_bits-1:0] ff1;
input [num_slaves-1:0] in;
integer i;
begin
ff1 = 0;
for (i = num_slaves-1; i >= 0; i=i-1) begin
if (in[i])
/* verilator lint_off WIDTH */
ff1 = i;
/* verilator lint_on WIDTH */
end
end
endfunction
assign slave_sel = ff1(match);
always @(posedge wb_clk_i)
wbm_err <= wbm_cyc_i & !(|match);
assign wbs_adr_o = {num_slaves{wbm_adr_i}};
assign wbs_dat_o = {num_slaves{wbm_dat_i}};
assign wbs_sel_o = {num_slaves{wbm_sel_i}};
assign wbs_we_o = {num_slaves{wbm_we_i}};
/* verilator lint_off WIDTH */
// Expand master CYC to slave bus width before shifting to one-hot select.
// Shifting a 1-bit signal would otherwise zero out all but slave 0.
assign wbs_cyc_o = match & ({num_slaves{wbm_cyc_i}} << slave_sel);
/* verilator lint_on WIDTH */
assign wbs_stb_o = {num_slaves{wbm_stb_i}};
assign wbs_cti_o = {num_slaves{wbm_cti_i}};
assign wbs_bte_o = {num_slaves{wbm_bte_i}};
assign wbm_dat_o = wbs_dat_i[slave_sel*dw+:dw];
assign wbm_ack_o = wbs_ack_i[slave_sel];
assign wbm_err_o = wbs_err_i[slave_sel] | wbm_err;
assign wbm_rty_o = wbs_rty_i[slave_sel];
endmodule

View File

@@ -0,0 +1,51 @@
CAPI=2:
name: joppeb:wb:wb_mux:1.0
description: Wishbone address decoder and multiplexer
filesets:
rtl:
depend:
- joppeb:util:clog2
files:
- rtl/wb_mux.v
file_type: verilogSource
targets:
default:
filesets:
- rtl
toplevel: wb_mux
parameters:
- dw
- aw
- num_devices
- num_slaves
- MATCH_ADDR
- MATCH_MASK
parameters:
dw:
datatype: int
description: Wishbone data width
paramtype: vlogparam
aw:
datatype: int
description: Wishbone address width
paramtype: vlogparam
num_devices:
datatype: int
description: Deprecated alias for num_slaves
paramtype: vlogparam
num_slaves:
datatype: int
description: Number of wishbone slaves
paramtype: vlogparam
MATCH_ADDR:
datatype: int
description: Flattened slave address match table
paramtype: vlogparam
MATCH_MASK:
datatype: int
description: Flattened slave address mask table
paramtype: vlogparam

View File

@@ -0,0 +1,74 @@
`timescale 1ns/1ps
module wb_countdown_timer #(
parameter WIDTH = 32, // counter width (<=32 makes bus mapping easy)
parameter DIVIDER = 0 // optional prescaler: tick every 2^DIVIDER cycles
)(
input wire i_clk,
input wire i_rst,
output reg o_irq,
input wire [31:0] i_wb_dat,
output reg [31:0] o_wb_dat,
input wire i_wb_we,
input wire i_wb_cyc,
input wire i_wb_stb,
output wire o_wb_ack
);
// One-cycle acknowledge on any valid WB access
// (classic, zero-wait-state peripheral)
assign o_wb_ack = i_wb_cyc & i_wb_stb;
// Internal countdown and prescaler
reg [WIDTH-1:0] counter;
reg [DIVIDER:0] presc; // enough bits to count up to 2^DIVIDER-1
wire tick = (DIVIDER == 0) ? 1'b1 : (presc[DIVIDER] == 1'b1);
// Readback: expose the current counter value
always @(*) begin
o_wb_dat = 32'd0;
o_wb_dat[WIDTH-1:0] = counter;
end
// Main logic
always @(posedge i_clk) begin
if (i_rst) begin
counter <= {WIDTH{1'b0}};
presc <= { (DIVIDER+1){1'b0} };
o_irq <= 1'b0;
end else begin
// Default prescaler behavior
if (DIVIDER != 0) begin
if (counter != 0 && !o_irq)
presc <= presc + 1'b1;
else
presc <= { (DIVIDER+1){1'b0} };
end
// Wishbone write: load counter and clear IRQ
if (o_wb_ack && i_wb_we) begin
counter <= i_wb_dat[WIDTH-1:0];
o_irq <= 1'b0;
// reset prescaler on (re)start or stop
presc <= { (DIVIDER+1){1'b0} };
end else begin
// Countdown when running (counter>0), not already IRQ'd
if (!o_irq && counter != 0) begin
if (tick) begin
if (counter == 1) begin
counter <= {WIDTH{1'b0}};
o_irq <= 1'b1; // sticky until next write
presc <= { (DIVIDER+1){1'b0} };
end else begin
counter <= counter - 1'b1;
end
end
end
end
end
end
endmodule

View File

@@ -0,0 +1,29 @@
CAPI=2:
name: joppeb:wb:wb_timer:1.0
description: Wishbone countdown timer peripheral
filesets:
rtl:
files:
- rtl/wb_timer.v
file_type: verilogSource
targets:
default:
filesets:
- rtl
toplevel: wb_countdown_timer
parameters:
- WIDTH
- DIVIDER
parameters:
WIDTH:
datatype: int
description: Counter width in bits
paramtype: vlogparam
DIVIDER:
datatype: int
description: Prescaler divider as a power of two exponent
paramtype: vlogparam