`include "../pmi_def.v" `include "../system_conf.v" `include "lm8_include.v" `include "lm8_interrupt.v" `include "lm8_io_cntl.v" `include "lm8_flow_cntl.v" `include "lm8_idec.v" `include "lm8_alu.v" `include "lm8_core.v" module lm8 #( parameter LATTICE_FAMILY = "XO", parameter CFG_PROM_INIT_FILE = "none", parameter CFG_PROM_INIT_FILE_FORMAT = "hex", parameter CFG_PROM_SIZE = 4096, // PROM size (no. of instructions) parameter CFG_PROM_BASE_ADDRESS = 32'h0, // PROM Base Address parameter CFG_SP_INIT_FILE = "none", parameter CFG_SP_INIT_FILE_FORMAT = "binary", parameter SP_SIZE = 256, // Scratchpad size (no. of bytes) parameter SP_BASE_ADDRESS = 32'h0, // Scratchpad Base Address parameter CFG_IO_BASE_ADDRESS = 32'h8000_0000, // IO Base Address parameter CFG_EXT_SIZE_8 = 0, // Page Pointer is 1 byte parameter CFG_EXT_SIZE_16 = 1, // Page Pointer is 2 bytes parameter CFG_EXT_SIZE_32 = 0, // Page Pointer is 3 bytes parameter CFG_REGISTER_16 = 1, // 16 general-purpose registers parameter CFG_REGISTER_32 = 0, // 32 general-purpose registers parameter CFG_CALL_STACK_8 = 1, // Call stack has 8 entries parameter CFG_CALL_STACK_16 = 0, // Call stack has 16 entries parameter CFG_CALL_STACK_32 = 0 // Call stack has 32 entries ) ( input clk_i, input rst_i, // Data WISHBONE Bus input D_ACK_I, input D_ERR_I, input D_RTY_I, input [7:0] D_DAT_I, output reg D_CYC_O, output reg D_STB_O, output reg [2:0] D_CTI_O, output reg [1:0] D_BTE_O, output reg D_WE_O, output reg D_SEL_O, output reg [7:0] D_DAT_O, output reg [31:0] D_ADR_O, output reg D_LOCK_O, // Interrupt input [7:0] interrupts ); parameter CFG_EXT_SIZE = (CFG_EXT_SIZE_8 == 1) ? 8 : (CFG_EXT_SIZE_16 == 1) ? 16 : 32; parameter CFG_CALL_STACK = (CFG_CALL_STACK_8 == 1) ? 8 : (CFG_CALL_STACK_16 == 1) ? 16 : 32; localparam PROM_AW = clogb2(CFG_PROM_SIZE); localparam SP_AW = clogb2(SP_SIZE); localparam ALIGN_SP_BASE = (SP_AW == 32) ? SP_BASE_ADDRESS : ((32'hffff_ffff << SP_AW) & SP_BASE_ADDRESS); localparam ALIGN_IO_BASE = (CFG_EXT_SIZE == 32) ? CFG_IO_BASE_ADDRESS : ((32'hffff_ffff << CFG_EXT_SIZE) & CFG_IO_BASE_ADDRESS); localparam PGM_STACK_AW = clogb2(CFG_CALL_STACK); localparam INTERNAL_SP_CHECK = (SP_BASE_ADDRESS & ((1<> SP_AW; wire [PROM_AW-1:0] prom_addr; wire [PROM_AW-1:0] pc; wire [17:0] instr; wire prom_enable; wire prom_ready; wire [CFG_EXT_SIZE-1:0] ext_addr; wire ext_addr_cyc; wire [7:0] ext_dout; wire ext_mem_wr; wire ext_mem_rd; wire ext_io_wr; wire ext_io_rd; wire [7:0] ext_mem_din; wire [7:0] ext_io_din; wire ext_mem_ready; /* Reset Synchronizer */ wire rst_i_n; reg rff1; reg rst_n; assign rst_i_n = ~rst_i; always @(posedge clk_i or negedge rst_i_n) begin if (!rst_i_n) {rst_n, rff1} <= 2'b00; else {rst_n, rff1} <= {rff1, 1'b1}; end lm8_core #( .FAMILY_NAME (LATTICE_FAMILY), .EXT_AW (CFG_EXT_SIZE), .PROM_WB (0), .PROM_AW (PROM_AW), .PROM_AD (CFG_PROM_SIZE), .REGISTERS_16 (CFG_REGISTER_16), .PGM_STACK_AW (PGM_STACK_AW), .PGM_STACK_AD (CFG_CALL_STACK), .INTERRUPTS (8) ) u1_isp8_core ( // Outputs .ext_addr (ext_addr[CFG_EXT_SIZE-1:0]), .ext_addr_cyc (ext_addr_cyc), .ext_dout (ext_dout[7:0]), .ext_mem_wr (ext_mem_wr), .ext_mem_rd (ext_mem_rd), .ext_io_wr (ext_io_wr), .ext_io_rd (ext_io_rd), .intr_ack (), .prom_enable (prom_enable), .prom_addr (prom_addr[PROM_AW-1:0]), .pc (pc[PROM_AW-1:0]), // Inputs .clk (clk_i), .rst_n (rst_n), .ext_mem_din (ext_mem_din[7:0]), .ext_io_din (ext_io_din[7:0]), .ext_mem_ready (ext_mem_ready), .interrupts (interrupts), .prom_ready (prom_ready), .instr (instr[17:0]) ); reg [PROM_AW-1+2:0] prom_waddr, prom_raddr; reg [17:0] prom_wdata; /* PROM Support */ generate wire [17:0] instr_mem_out; reg first_fetch, first_fetch_nxt; pmi_ram_dq #( .pmi_addr_depth (CFG_PROM_SIZE), .pmi_addr_width (PROM_AW), .pmi_data_width (18), .pmi_regmode ("noreg"), .pmi_gsr ("disable"), .pmi_resetmode ("async"), .pmi_init_file (CFG_PROM_INIT_FILE), .pmi_init_file_format (CFG_PROM_INIT_FILE_FORMAT), .pmi_family (LATTICE_FAMILY), .module_type ("pmi_ram_dq") ) u1_isp8_prom ( .Address (prom_addr[PROM_AW-1:0]), .Data (18'b0), .Clock (clk_i), .ClockEn (prom_enable), .WE (1'b0), .Reset (1'b0), .Q (instr_mem_out) ); assign instr = first_fetch ? instr_mem_out : 18'b0; assign prom_ready = first_fetch ? 1'b1 : 1'b0; always @(posedge clk_i or negedge rst_n) begin if (rst_n == 1'b0) first_fetch <= #1 1'b0; else if (first_fetch == 1'b0) first_fetch <= #1 prom_enable; end endgenerate /*---------------------------------------------------------------------- Scratchpad and I/O Support ----------------------------------------------------------------------*/ wire [7:0] internal_sp_dout; wire ext_wr, ext_cyc, external_sp; reg [7:0] ext_din; reg [7:0] save_data, save_data_nxt; reg [31:0] sp_rd_addr, sp_rd_addr_nxt; reg ext_ready; reg ext_wb_state, ext_wb_state_nxt; generate reg D_ACK_I_d; always @(posedge clk_i) begin if (rst_n == 1'b0) D_ACK_I_d <= #1 1'b0; else D_ACK_I_d <= #1 D_ACK_I; end always @(/*AUTOSENSE*/D_ACK_I or D_ACK_I_d or ext_cyc or ext_wb_state) begin if ((D_ACK_I_d == 1'b0) && ((ext_cyc && (ext_wb_state == 1'b0)) || (ext_wb_state && (D_ACK_I == 0)))) ext_wb_state_nxt = 1'b1; else ext_wb_state_nxt = 1'b0; end always @(/*AUTOSENSE*/D_ACK_I or ext_addr or ext_cyc or ext_dout or ext_io_rd or ext_io_wr or ext_wb_state or ext_wr) begin if (ext_cyc || ext_wb_state) begin D_CYC_O = 1'b1; D_STB_O = 1'b1; if (ext_io_rd || ext_io_wr) D_ADR_O = ALIGN_IO_BASE | {{(32 - CFG_EXT_SIZE){1'b0}}, ext_addr}; else D_ADR_O = ALIGN_SP_BASE | {{(32 - CFG_EXT_SIZE){1'b0}}, ext_addr}; D_DAT_O = ext_dout; D_SEL_O = 1'b1; D_CTI_O = 3'b000; D_BTE_O = 2'b00; D_WE_O = ext_wr; D_LOCK_O = 1'b0; end else begin D_CYC_O = 1'b0; D_STB_O = 1'b0; D_ADR_O = 32'b0; D_DAT_O = ext_dout; D_SEL_O = 1'b0; D_CTI_O = 3'b000; D_BTE_O = 2'b00; D_WE_O = 1'b0; D_LOCK_O = 1'b0; end if (ext_wb_state) ext_ready = D_ACK_I; else ext_ready = 1'b0; end endgenerate generate if (CFG_EXT_SIZE <= SP_AW) begin assign external_sp = 1'b0; assign ext_cyc = ((ext_io_rd | ext_io_wr) ? ext_addr_cyc : 1'b0); assign ext_wr = ext_io_wr; assign ext_mem_ready = ((ext_io_rd | ext_io_wr) ? ext_ready : (ext_mem_rd | ext_mem_wr) ? 1'b1 : 1'b0); assign ext_mem_din = internal_sp_dout; end else begin assign external_sp = ext_addr[CFG_EXT_SIZE-1:SP_AW] != INTERNAL_SP_CHECK; assign ext_cyc = ((ext_io_rd | ext_io_wr) ? ext_addr_cyc : (ext_mem_rd | ext_mem_wr) & external_sp); assign ext_wr = ext_io_wr | ext_mem_wr; assign ext_mem_ready = ((ext_io_rd | ext_io_wr) ? ext_ready : ((ext_mem_rd | ext_mem_wr) ? (external_sp ? ext_ready : 1'b1) : 1'b0)); assign ext_mem_din = external_sp ? ext_io_din : internal_sp_dout; end pmi_ram_dq #( .pmi_addr_depth (SP_SIZE), .pmi_addr_width (SP_AW), .pmi_data_width (8), .pmi_regmode ("noreg"), .pmi_gsr ("disable"), .pmi_resetmode ("async"), .pmi_init_file (CFG_SP_INIT_FILE), .pmi_init_file_format (CFG_SP_INIT_FILE_FORMAT), .pmi_family (LATTICE_FAMILY), .module_type ("pmi_ram_dq") ) u1_scratchpad ( // Outputs .Q (internal_sp_dout), // Inputs .Data (ext_dout), .Address (ext_addr[SP_AW-1:0]), .Clock (clk_i), .ClockEn (1'b1), .WE ((ext_mem_wr) & ~external_sp), .Reset (1'b0) ); endgenerate always @(posedge clk_i) begin if (rst_n == 1'b0) begin ext_wb_state <= #1 1'b0; save_data <= #1 8'b0; end else begin ext_wb_state <= #1 ext_wb_state_nxt; save_data <= #1 save_data_nxt; end end always @(D_ACK_I or save_data or D_DAT_I) begin if (D_ACK_I) save_data_nxt = D_DAT_I; else save_data_nxt = save_data; end assign ext_io_din = ext_wb_state ? D_DAT_I : save_data; function integer clogb2; input [31:0] value; reg [31:0] i; reg [31:0] temp; begin temp = 0; i = 0; for (i = 0; temp < value; i = i + 1) temp = 1 << i; clogb2 = i - 1; end endfunction endmodule