`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