276 lines
6.6 KiB
Verilog
276 lines
6.6 KiB
Verilog
`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;
|
|
|
|
assign wb_ext_ack = wb_ext_gpio_ack;
|
|
assign wb_ext_rdt = wb_ext_gpio_rdt;
|
|
|
|
// 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_rst(i_rst),
|
|
.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 memory #(
|
|
parameter memfile = "",
|
|
parameter depth = 256,
|
|
parameter sim = 1'b0,
|
|
localparam aw = `CLOG2(depth)
|
|
)(
|
|
input wire i_clk,
|
|
input wire i_rst,
|
|
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];
|
|
wire [aw-1:0] mem_adr;
|
|
assign mem_adr = (i_wen==1'b1) ? i_waddr :
|
|
i_raddr;
|
|
|
|
// Second port wishbone
|
|
wire [31:0] wb_adr;
|
|
wire [31:0] wb_dat;
|
|
reg [31:0] wb_rdt;
|
|
wire [3:0] wb_sel;
|
|
wire wb_cyc;
|
|
wire wb_we;
|
|
wire wb_stb;
|
|
reg wb_ack;
|
|
reg wb_req_d;
|
|
wire cmd_reset;
|
|
// Driven by JTAG
|
|
jtag_wb_bridge #(
|
|
.chain(1),
|
|
.byte_aligned(1)
|
|
) jtag_wb (
|
|
.i_clk(i_clk),
|
|
.i_rst(i_rst),
|
|
|
|
.o_wb_adr(wb_adr),
|
|
.o_wb_dat(wb_dat),
|
|
.o_wb_sel(wb_sel),
|
|
.o_wb_we(wb_we),
|
|
.o_wb_cyc(wb_cyc),
|
|
.o_wb_stb(wb_stb),
|
|
.i_wb_rdt(wb_rdt),
|
|
.i_wb_ack(wb_ack),
|
|
.o_cmd_reset(cmd_reset)
|
|
);
|
|
|
|
assign o_core_reset = cmd_reset;
|
|
|
|
// Read/Write
|
|
always @(posedge i_clk) begin
|
|
if (i_rst) begin
|
|
wb_req_d <= 1'b0;
|
|
wb_ack <= 1'b0;
|
|
wb_rdt <= 32'h00000000;
|
|
o_rdata <= 32'h00000000;
|
|
end else begin
|
|
if (i_wen)
|
|
mem[mem_adr] <= i_wdata;
|
|
o_rdata <= mem[mem_adr];
|
|
|
|
wb_req_d <= wb_stb && wb_cyc;
|
|
wb_ack <= wb_req_d;
|
|
if (wb_we && wb_stb && wb_cyc)
|
|
mem[wb_adr[aw-1:0]] <= wb_dat[7:0];
|
|
wb_rdt <= {24'h000000, mem[wb_adr[aw-1:0]]};
|
|
end
|
|
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
|