/* Copyright (c) 2006-2011 by Lattice Semiconductor Corporation Copyright (c) 2012-2013 by Alan Hightower Name: lm16_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. Mico16 is a derived work of Lattice Mico8. Thus the terms of use are governed by original Mico8 license above. Disclaimer: This 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. No warranty is provided regarding the use or functionality of this code. http://www.latticesemi.com/ http://www.retrotronics.org/ */ // Require an MMU for > 16 bit `ifndef SIMULATION `include "pmi_def.v" `endif `define LM16_CSR_IP 'd0 `define LM16_CSR_IM 'd1 `define LM16_CSR_IE 'd2 `include "lm16_interrupt.v" `include "lm16_io_cntl.v" `include "lm16_flow_cntl.v" `include "lm16_idec.v" `include "lm16_alu.v" `include "lm16_core.v" module lm16 #( parameter LATTICE_FAMILY = "MachXO2", 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 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 = 0, // Call stack has 8 entries parameter CFG_CALL_STACK_16 = 0, // Call stack has 16 entries parameter CFG_CALL_STACK_32 = 1, // Call stack has 32 entries parameter INTERRUPTS = 8 // Number of interrupts ) ( input clk_i, input rst_i, // Wishbone Master input D_ACK_I, input [7:0] D_DAT_I, output reg D_CYC_O, output reg D_STB_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, // Interrupts 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 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); 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_din; wire ext_mem_ready; lm16_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) ) lm16_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_i), .ext_mem_din (internal_sp_dout), .ext_io_din (ext_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") ) lm16_rom ( .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 posedge rst_i) begin if (rst_i) first_fetch <= #1 1'b0; else if (first_fetch == 1'b0) first_fetch <= #1 prom_enable; end // External bus interface wire [7:0] internal_sp_dout; reg [7:0] ext_din; 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_i) D_ACK_I_d <= #1 1'b0; else D_ACK_I_d <= #1 D_ACK_I; end always @(*) begin if ((D_ACK_I_d == 1'b0) && ((ext_addr_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 @(*) begin if (ext_addr_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 = {{(32 - CFG_EXT_SIZE){1'b0}}, ext_addr}; D_DAT_O = ext_dout; D_SEL_O = 1'b1; D_WE_O = ext_io_wr; 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_WE_O = 1'b0; end if (ext_wb_state) ext_ready = D_ACK_I; else ext_ready = 1'b0; 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), .Reset (1'b0) ); assign ext_mem_ready = ((ext_io_rd | ext_io_wr) ? ext_ready : 1'b1; always @(posedge clk_i) begin if (rst_i) 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_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