Working CPP way of writing data
This commit is contained in:
414
rtl/core/mcu.v
Normal file
414
rtl/core/mcu.v
Normal file
@@ -0,0 +1,414 @@
|
||||
`timescale 1ns/1ps
|
||||
`include "../util/clog2.vh"
|
||||
|
||||
module mcu #(
|
||||
parameter memfile = "",
|
||||
parameter memsize = 8192,
|
||||
parameter sim = 1'b0
|
||||
)(
|
||||
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 regs = 32+WITH_CSR*4;
|
||||
localparam rf_width = 8;
|
||||
|
||||
wire rst;
|
||||
wire rst_mem_reason;
|
||||
wire timer_irq;
|
||||
assign rst = i_rst | rst_mem_reason;
|
||||
assign timer_irq = 1'b0;
|
||||
|
||||
// Busses
|
||||
// CPU->memory
|
||||
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;
|
||||
wire wb_mem_ack;
|
||||
// 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;
|
||||
// CPU->RF
|
||||
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;
|
||||
// combined RF and mem bus to actual RAM
|
||||
wire [`CLOG2(memsize)-1:0] sram_waddr;
|
||||
wire [rf_width-1:0] sram_wdata;
|
||||
wire sram_wen;
|
||||
wire [`CLOG2(memsize)-1:0] sram_raddr;
|
||||
wire [rf_width-1:0] sram_rdata;
|
||||
wire sram_ren;
|
||||
|
||||
// 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;
|
||||
|
||||
// SERV core with mux splitting dbus into mem and ext and
|
||||
// arbiter combining mem and ibus
|
||||
// separate rst line to let other hardware keep core under reset
|
||||
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(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),
|
||||
.i_wb_mem_ack(wb_mem_ack),
|
||||
|
||||
//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),
|
||||
|
||||
//RF IF
|
||||
.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)
|
||||
);
|
||||
|
||||
// WB arbiter combining RF and mem interfaces into 1
|
||||
// Last 128 bytes are used for registers
|
||||
servile_rf_mem_if #(
|
||||
.depth(memsize),
|
||||
.rf_regs(regs)
|
||||
) rf_mem_if (
|
||||
.i_clk (i_clk),
|
||||
.i_rst (i_rst),
|
||||
|
||||
.i_waddr(rf_waddr),
|
||||
.i_wdata(rf_wdata),
|
||||
.i_wen(rf_wen),
|
||||
.i_raddr(rf_raddr),
|
||||
.o_rdata(rf_rdata),
|
||||
.i_ren(rf_ren),
|
||||
|
||||
.o_sram_waddr(sram_waddr),
|
||||
.o_sram_wdata(sram_wdata),
|
||||
.o_sram_wen(sram_wen),
|
||||
.o_sram_raddr(sram_raddr),
|
||||
.i_sram_rdata(sram_rdata),
|
||||
// .o_sram_ren(sram_ren),
|
||||
|
||||
.i_wb_adr(wb_mem_adr[`CLOG2(memsize)-1:2]),
|
||||
.i_wb_stb(wb_mem_stb),
|
||||
.i_wb_we(wb_mem_we) ,
|
||||
.i_wb_sel(wb_mem_sel),
|
||||
.i_wb_dat(wb_mem_dat),
|
||||
.o_wb_rdt(wb_mem_rdt),
|
||||
.o_wb_ack(wb_mem_ack)
|
||||
);
|
||||
|
||||
memory #(
|
||||
.memfile(memfile),
|
||||
.depth(memsize),
|
||||
.sim(sim)
|
||||
) mem (
|
||||
.i_clk(i_clk),
|
||||
.i_waddr(sram_waddr),
|
||||
.i_wdata(sram_wdata),
|
||||
.i_wen(sram_wen),
|
||||
.i_raddr(sram_raddr),
|
||||
.o_rdata(sram_rdata),
|
||||
.o_core_reset(rst_mem_reason)
|
||||
);
|
||||
|
||||
wb_gpio_banks #(
|
||||
.BASE_ADDR(32'h40000000),
|
||||
.NUM_BANKS(4)
|
||||
) gpio (
|
||||
.i_wb_clk(i_clk),
|
||||
.i_wb_rst(rst),
|
||||
.i_wb_dat(wb_ext_dat),
|
||||
.i_wb_adr(wb_ext_adr),
|
||||
.i_wb_we(wb_ext_we),
|
||||
.i_wb_stb(wb_ext_stb),
|
||||
.i_wb_sel(wb_ext_sel),
|
||||
.o_wb_rdt(wb_ext_rdt),
|
||||
.o_wb_ack(wb_ext_ack),
|
||||
.i_gpio(GPI),
|
||||
.o_gpio(GPO)
|
||||
);
|
||||
|
||||
endmodule
|
||||
|
||||
module jtag_mem_protocol #(
|
||||
parameter aw = 8,
|
||||
parameter chain = 1
|
||||
)(
|
||||
input wire i_clk,
|
||||
input wire i_rst,
|
||||
input wire [7:0] i_mem_rdata,
|
||||
output reg o_mem_wen,
|
||||
output reg [7:0] o_mem_wdata,
|
||||
output reg [aw-1:0] o_mem_waddr,
|
||||
output reg [aw-1:0] o_mem_raddr,
|
||||
output reg o_core_reset
|
||||
);
|
||||
localparam FRAME_BITS = 42;
|
||||
|
||||
// Frame format (LSB-first on JTAG shift stream):
|
||||
// [0] : core reset
|
||||
// [1] : write (1=write, 0=read)
|
||||
// [33:2] : address
|
||||
// [41:34] : data
|
||||
wire [31:0] cmd_addr_full;
|
||||
wire cmd_reset;
|
||||
wire cmd_write;
|
||||
wire [7:0] cmd_data;
|
||||
|
||||
// JTAG interface wires
|
||||
wire jtag_tck;
|
||||
wire jtag_tdi;
|
||||
wire jtag_drck;
|
||||
wire jtag_capture;
|
||||
wire jtag_shift;
|
||||
wire jtag_update;
|
||||
wire jtag_runtest;
|
||||
wire jtag_reset;
|
||||
wire jtag_sel;
|
||||
|
||||
// JTAG clock-domain regs
|
||||
reg [FRAME_BITS-1:0] shift_q;
|
||||
reg [FRAME_BITS-1:0] cmd_jtag_q;
|
||||
reg update_toggle_jtag_q;
|
||||
reg [FRAME_BITS-1:0] resp_meta_q;
|
||||
reg [FRAME_BITS-1:0] resp_sync_q;
|
||||
|
||||
// Core clock-domain CDC regs
|
||||
reg update_toggle_meta_q;
|
||||
reg update_toggle_sync_q;
|
||||
reg update_toggle_sync_d_q;
|
||||
reg [FRAME_BITS-1:0] cmd_meta_q;
|
||||
reg [FRAME_BITS-1:0] cmd_sync_q;
|
||||
|
||||
// Core clock-domain protocol state
|
||||
reg [FRAME_BITS-1:0] resp_core_q;
|
||||
reg read_pending_q;
|
||||
reg [31:0] read_addr_full_q;
|
||||
|
||||
assign cmd_reset = cmd_sync_q[0];
|
||||
assign cmd_write = cmd_sync_q[1];
|
||||
assign cmd_addr_full = cmd_sync_q[33:2];
|
||||
assign cmd_data = cmd_sync_q[41:34];
|
||||
|
||||
jtag_if #(
|
||||
.chain(chain)
|
||||
) jtag (
|
||||
.i_tdo(shift_q[0]),
|
||||
.o_tck(jtag_tck),
|
||||
.o_tdi(jtag_tdi),
|
||||
.o_drck(jtag_drck),
|
||||
.o_capture(jtag_capture),
|
||||
.o_shift(jtag_shift),
|
||||
.o_update(jtag_update),
|
||||
.o_runtest(jtag_runtest),
|
||||
.o_reset(jtag_reset),
|
||||
.o_sel(jtag_sel)
|
||||
);
|
||||
|
||||
// JTAG domain: shift register and update event capture.
|
||||
always @(posedge jtag_drck or posedge jtag_reset or posedge i_rst) begin
|
||||
if (jtag_reset || i_rst) begin
|
||||
shift_q <= {FRAME_BITS{1'b0}};
|
||||
resp_meta_q <= {FRAME_BITS{1'b0}};
|
||||
resp_sync_q <= {FRAME_BITS{1'b0}};
|
||||
end else begin
|
||||
resp_meta_q <= resp_core_q;
|
||||
resp_sync_q <= resp_meta_q;
|
||||
|
||||
if (jtag_sel && jtag_capture) begin
|
||||
shift_q <= resp_sync_q;
|
||||
end else if (jtag_sel && jtag_shift) begin
|
||||
shift_q <= {jtag_tdi, shift_q[FRAME_BITS-1:1]};
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
always @(posedge jtag_update or posedge jtag_reset or posedge i_rst) begin
|
||||
if (jtag_reset || i_rst) begin
|
||||
cmd_jtag_q <= {FRAME_BITS{1'b0}};
|
||||
update_toggle_jtag_q <= 1'b0;
|
||||
end else if (jtag_sel) begin
|
||||
cmd_jtag_q <= shift_q;
|
||||
update_toggle_jtag_q <= ~update_toggle_jtag_q;
|
||||
end
|
||||
end
|
||||
|
||||
// Core domain: receive command and execute against RAM port-B.
|
||||
always @(posedge i_clk or posedge i_rst) begin
|
||||
if (i_rst) begin
|
||||
update_toggle_meta_q <= 1'b0;
|
||||
update_toggle_sync_q <= 1'b0;
|
||||
update_toggle_sync_d_q <= 1'b0;
|
||||
cmd_meta_q <= {FRAME_BITS{1'b0}};
|
||||
cmd_sync_q <= {FRAME_BITS{1'b0}};
|
||||
o_mem_wen <= 1'b0;
|
||||
o_mem_wdata <= 8'h00;
|
||||
o_mem_waddr <= {aw{1'b0}};
|
||||
o_mem_raddr <= {aw{1'b0}};
|
||||
o_core_reset <= 1'b0;
|
||||
resp_core_q <= {FRAME_BITS{1'b0}};
|
||||
read_pending_q <= 1'b0;
|
||||
read_addr_full_q <= 32'h0000_0000;
|
||||
end else begin
|
||||
// Defaults are one-cycle strobes for write/reset.
|
||||
o_mem_wen <= 1'b0;
|
||||
o_core_reset <= 1'b0;
|
||||
|
||||
update_toggle_meta_q <= update_toggle_jtag_q;
|
||||
update_toggle_sync_q <= update_toggle_meta_q;
|
||||
update_toggle_sync_d_q <= update_toggle_sync_q;
|
||||
cmd_meta_q <= cmd_jtag_q;
|
||||
cmd_sync_q <= cmd_meta_q;
|
||||
|
||||
// Complete pending read (port-B read is synchronous).
|
||||
if (read_pending_q) begin
|
||||
read_pending_q <= 1'b0;
|
||||
resp_core_q[0] <= 1'b0;
|
||||
resp_core_q[1] <= 1'b0;
|
||||
resp_core_q[33:2] <= read_addr_full_q;
|
||||
resp_core_q[41:34] <= i_mem_rdata;
|
||||
end
|
||||
|
||||
// New JTAG command arrived.
|
||||
if (update_toggle_sync_q ^ update_toggle_sync_d_q) begin
|
||||
if (cmd_reset) begin
|
||||
o_core_reset <= 1'b1;
|
||||
end
|
||||
|
||||
if (cmd_write) begin
|
||||
o_mem_waddr <= cmd_addr_full[aw-1:0];
|
||||
o_mem_wdata <= cmd_data;
|
||||
o_mem_wen <= 1'b1;
|
||||
resp_core_q[0] <= cmd_reset;
|
||||
resp_core_q[1] <= 1'b1;
|
||||
resp_core_q[33:2] <= cmd_addr_full;
|
||||
resp_core_q[41:34] <= cmd_data;
|
||||
end else begin
|
||||
o_mem_raddr <= cmd_addr_full[aw-1:0];
|
||||
read_pending_q <= 1'b1;
|
||||
read_addr_full_q <= cmd_addr_full;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// Keep lint quiet for currently-unused JTAG outputs.
|
||||
wire _unused_tck;
|
||||
wire _unused_runtest;
|
||||
assign _unused_tck = jtag_tck;
|
||||
assign _unused_runtest = jtag_runtest;
|
||||
endmodule
|
||||
|
||||
module memory #(
|
||||
parameter memfile = "",
|
||||
parameter depth = 256,
|
||||
parameter sim = 1'b0,
|
||||
localparam aw = `CLOG2(depth)
|
||||
)(
|
||||
input wire i_clk,
|
||||
input wire [aw-1:0] i_waddr,
|
||||
input wire [7:0] i_wdata,
|
||||
input wire i_wen,
|
||||
input wire [aw-1:0] i_raddr,
|
||||
output reg [7:0] o_rdata,
|
||||
output wire o_core_reset
|
||||
);
|
||||
// The actual memory
|
||||
reg [7:0]mem [0:depth-1];
|
||||
|
||||
// Second interface
|
||||
wire wen_b;
|
||||
wire [7:0] wdata_b;
|
||||
wire [aw-1:0] waddr_b;
|
||||
reg [7:0] rdata_b;
|
||||
wire [aw-1:0] raddr_b;
|
||||
jtag_mem_protocol #(
|
||||
.aw(aw),
|
||||
.chain(1)
|
||||
) jtag_mem (
|
||||
.i_clk(i_clk),
|
||||
.i_rst(1'b0),
|
||||
.i_mem_rdata(rdata_b),
|
||||
.o_mem_wen(wen_b),
|
||||
.o_mem_wdata(wdata_b),
|
||||
.o_mem_waddr(waddr_b),
|
||||
.o_mem_raddr(raddr_b),
|
||||
.o_core_reset(o_core_reset)
|
||||
);
|
||||
|
||||
// Read/Write
|
||||
always @(posedge i_clk) begin
|
||||
// main interface
|
||||
if (i_wen)
|
||||
mem[i_waddr] <= i_wdata;
|
||||
o_rdata <= mem[i_raddr];
|
||||
// second interface
|
||||
if (wen_b)
|
||||
mem[waddr_b] <= wdata_b;
|
||||
rdata_b <= mem[raddr_b];
|
||||
end
|
||||
|
||||
// Preload memory
|
||||
integer i;
|
||||
initial begin
|
||||
if(sim==1'b1) begin
|
||||
for (i = 0; i < depth; i = i + 1)
|
||||
mem[i] = 8'h00;
|
||||
end
|
||||
if(|memfile) begin
|
||||
$display("Preloading %m from %s", memfile);
|
||||
$readmemh(memfile, mem);
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
Reference in New Issue
Block a user