/* Copyright (c) 2006-2011 by Lattice Semiconductor Corporation Name: lm8_top.v Description: Top level module Permission: Lattice Semiconductor grants permission to use this code for use in synthesis for any Lattice programmable logic product. Other use of this code, including the selling or duplication of any portion is strictly prohibited. Disclaimer: This VHDL or Verilog source code is intended as a design reference which illustrates how these types of functions can be implemented. It is the user's responsibility to verify their design for consistency and functionality through the use of formal verification methods. Lattice Semiconductor provides no warranty regarding the use or functionality of this code. Lattice Semiconductor Corporation 5555 NE Moore Court Hillsboro, OR 97124 U.S.A TEL: 1-800-Lattice (USA and Canada) 408-826-6000 (other locations) web: http://www.latticesemi.com/ email: techsupport@latticesemi.com */ `ifndef SIMULATION `include "pmi_def.v" `endif `define LM8_CSR_IP 'd0 `define LM8_CSR_IM 'd1 `define LM8_CSR_IE 'd2 `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 = "XO2", 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_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 parameter INTERRUPTS = 8 // Number of interrupts ) ( 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 [INTERRUPTS-1:0] interrupts, output intr_ack ); 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_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 (INTERRUPTS) ) 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 (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[INTERRUPTS-1:0]), .prom_ready (prom_ready), .instr (instr[17:0]) ); // PROM Support wire [17:0] instr_mem_out; reg first_fetch; 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 // Scratchpad and I/O Support wire [7:0] internal_sp_dout; wire ext_wr, ext_cyc, external_sp; reg [7:0] save_data, save_data_nxt; reg ext_ready; reg ext_wb_state, ext_wb_state_nxt; 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 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