| // ================================================================== |
| // >>>>>>>>>>>>>>>>>>>>>>> COPYRIGHT NOTICE <<<<<<<<<<<<<<<<<<<<<<<<< |
| // ------------------------------------------------------------------ |
| // Copyright (c) 2006-2011 by Lattice Semiconductor Corporation |
| // ALL RIGHTS RESERVED |
| // ------------------------------------------------------------------ |
| // |
| // IMPORTANT: THIS FILE IS AUTO-GENERATED BY THE LATTICEMICO SYSTEM. |
| // |
| // Permission: |
| // |
| // Lattice Semiconductor grants permission to use this code |
| // pursuant to the terms of the Lattice Semiconductor Corporation |
| // Open Source License Agreement. |
| // |
| // Disclaimer: |
| // |
| // Lattice Semiconductor provides no warranty regarding the use or |
| // functionality of this code. It is the user's responsibility to |
| // verify the user's design for consistency and functionality through |
| // the use of formal verification methods. |
| // |
| // -------------------------------------------------------------------- |
| // |
| // Lattice Semiconductor Corporation |
| // 5555 NE Moore Court |
| // Hillsboro, OR 97214 |
| // U.S.A |
| // |
| // TEL: 1-800-Lattice (USA and Canada) |
| // 503-286-8001 (other locations) |
| // |
| // web: http://www.latticesemi.com/ |
| // email: techsupport@latticesemi.com |
| // |
| // -------------------------------------------------------------------- |
| // FILE DETAILS |
| // Project : LatticeMico32 |
| // File : lm32_instruction_unit.v |
| // Title : Instruction unit |
| // Dependencies : lm32_include.v |
| // Version : 6.1.17 |
| // : Initial Release |
| // Version : 7.0SP2, 3.0 |
| // : No Change |
| // Version : 3.1 |
| // : Support for static branch prediction is added. Fetching of |
| // : instructions can also be altered by branches predicted in D |
| // : stage of pipeline, and mispredicted branches in the X and M |
| // : stages of the pipeline. |
| // Version : 3.2 |
| // : EBRs use SYNC resets instead of ASYNC resets. |
| // Version : 3.3 |
| // : Support for a non-cacheable Instruction Memory that has a |
| // : single-cycle access latency. This memory can be accessed by |
| // : data port of LM32 (so that debugger has access to it). |
| // Version : 3.4 |
| // : No change |
| // Version : 3.5 |
| // : Bug fix: Inline memory is correctly generated if it is not a |
| // : power-of-two. |
| // : Bug fix: Fixed a bug that caused LM32 (configured without |
| // : instruction cache) to lock up in to an infinite loop due to a |
| // : instruction bus error when EBA was set to instruction inline |
| // : memory. |
| // Version : 3.8 |
| // : Feature: Support for dynamically switching EBA to DEBA via a |
| // : GPIO. |
| // ============================================================================= |
| |
| `include "lm32_include.v" |
| |
| ///////////////////////////////////////////////////// |
| // Module interface |
| ///////////////////////////////////////////////////// |
| |
| module lm32_instruction_unit ( |
| // ----- Inputs ------- |
| clk_i, |
| rst_i, |
| `ifdef CFG_DEBUG_ENABLED |
| `ifdef CFG_ALTERNATE_EBA |
| at_debug, |
| `endif |
| `endif |
| // From pipeline |
| stall_a, |
| stall_f, |
| stall_d, |
| stall_x, |
| stall_m, |
| valid_f, |
| valid_d, |
| kill_f, |
| branch_predict_taken_d, |
| branch_predict_address_d, |
| `ifdef CFG_FAST_UNCONDITIONAL_BRANCH |
| branch_taken_x, |
| branch_target_x, |
| `endif |
| exception_m, |
| branch_taken_m, |
| branch_mispredict_taken_m, |
| branch_target_m, |
| `ifdef CFG_ICACHE_ENABLED |
| iflush, |
| `endif |
| `ifdef CFG_DCACHE_ENABLED |
| dcache_restart_request, |
| dcache_refill_request, |
| dcache_refilling, |
| `endif |
| `ifdef CFG_IROM_ENABLED |
| irom_store_data_m, |
| irom_address_xm, |
| irom_we_xm, |
| `endif |
| `ifdef CFG_MMU_ENABLED |
| itlb_enable, |
| tlbpaddr, |
| tlbvaddr, |
| itlb_update, |
| itlb_flush, |
| itlb_invalidate, |
| `endif |
| `ifdef CFG_IWB_ENABLED |
| // From Wishbone |
| i_dat_i, |
| i_ack_i, |
| i_err_i, |
| `endif |
| `ifdef CFG_HW_DEBUG_ENABLED |
| jtag_read_enable, |
| jtag_write_enable, |
| jtag_write_data, |
| jtag_address, |
| `endif |
| // ----- Outputs ------- |
| // To pipeline |
| pc_f, |
| pc_d, |
| pc_x, |
| pc_m, |
| pc_w, |
| `ifdef CFG_ICACHE_ENABLED |
| icache_stall_request, |
| icache_restart_request, |
| icache_refill_request, |
| icache_refilling, |
| `endif |
| `ifdef CFG_IROM_ENABLED |
| irom_data_m, |
| `endif |
| `ifdef CFG_MMU_ENABLED |
| itlb_stall_request, |
| itlb_miss_vfn, |
| itlb_miss_x, |
| `endif |
| `ifdef CFG_IWB_ENABLED |
| // To Wishbone |
| i_dat_o, |
| i_adr_o, |
| i_cyc_o, |
| i_sel_o, |
| i_stb_o, |
| i_we_o, |
| i_cti_o, |
| i_lock_o, |
| i_bte_o, |
| `endif |
| `ifdef CFG_HW_DEBUG_ENABLED |
| jtag_read_data, |
| jtag_access_complete, |
| `endif |
| `ifdef CFG_BUS_ERRORS_ENABLED |
| bus_error_d, |
| `endif |
| `ifdef CFG_EBR_POSEDGE_REGISTER_FILE |
| instruction_f, |
| `endif |
| instruction_d |
| ); |
| |
| ///////////////////////////////////////////////////// |
| // Parameters |
| ///////////////////////////////////////////////////// |
| |
| parameter eba_reset = `CFG_EBA_RESET; |
| parameter associativity = 1; // Associativity of the cache (Number of ways) |
| parameter sets = 512; // Number of sets |
| parameter bytes_per_line = 16; // Number of bytes per cache line |
| parameter base_address = 0; // Base address of cachable memory |
| parameter limit = 0; // Limit (highest address) of cachable memory |
| |
| // For bytes_per_line == 4, we set 1 so part-select range isn't reversed, even though not really used |
| localparam addr_offset_width = bytes_per_line == 4 ? 1 : `CLOG2(bytes_per_line)-2; |
| localparam addr_offset_lsb = 2; |
| localparam addr_offset_msb = (addr_offset_lsb+addr_offset_width-1); |
| |
| ///////////////////////////////////////////////////// |
| // Inputs |
| ///////////////////////////////////////////////////// |
| |
| input clk_i; // Clock |
| input rst_i; // Reset |
| |
| `ifdef CFG_DEBUG_ENABLED |
| `ifdef CFG_ALTERNATE_EBA |
| input at_debug; // GPIO input that maps EBA to DEBA |
| `endif |
| `endif |
| |
| input stall_a; // Stall A stage instruction |
| input stall_f; // Stall F stage instruction |
| input stall_d; // Stall D stage instruction |
| input stall_x; // Stall X stage instruction |
| input stall_m; // Stall M stage instruction |
| input valid_f; // Instruction in F stage is valid |
| input valid_d; // Instruction in D stage is valid |
| input kill_f; // Kill instruction in F stage |
| |
| input branch_predict_taken_d; // Branch is predicted taken in D stage |
| input [`LM32_PC_RNG] branch_predict_address_d; // Branch target address |
| |
| `ifdef CFG_FAST_UNCONDITIONAL_BRANCH |
| input branch_taken_x; // Branch instruction in X stage is taken |
| input [`LM32_PC_RNG] branch_target_x; // Target PC of X stage branch instruction |
| `endif |
| input exception_m; |
| input branch_taken_m; // Branch instruction in M stage is taken |
| input branch_mispredict_taken_m; // Branch instruction in M stage is mispredicted as taken |
| input [`LM32_PC_RNG] branch_target_m; // Target PC of M stage branch instruction |
| |
| `ifdef CFG_ICACHE_ENABLED |
| input iflush; // Flush instruction cache |
| `endif |
| `ifdef CFG_DCACHE_ENABLED |
| input dcache_restart_request; // Restart instruction that caused a data cache miss |
| input dcache_refill_request; // Request to refill data cache |
| input dcache_refilling; |
| `endif |
| |
| `ifdef CFG_IROM_ENABLED |
| input [`LM32_WORD_RNG] irom_store_data_m; // Data from load-store unit |
| input [`LM32_WORD_RNG] irom_address_xm; // Address from load-store unit |
| input irom_we_xm; // Indicates if memory operation is load or store |
| `endif |
| |
| `ifdef CFG_MMU_ENABLED |
| input itlb_enable; // Instruction TLB enable |
| input [`LM32_WORD_RNG] tlbpaddr; // TLBPADDR CSR |
| input [`LM32_WORD_RNG] tlbvaddr; // TLBVADDR CSR |
| input itlb_update; // Instruction TLB update request |
| input itlb_flush; // Instruction TLB flush request |
| input itlb_invalidate; // Instruction TLB invalidate request |
| `endif |
| |
| `ifdef CFG_IWB_ENABLED |
| input [`LM32_WORD_RNG] i_dat_i; // Instruction Wishbone interface read data |
| input i_ack_i; // Instruction Wishbone interface acknowledgement |
| input i_err_i; // Instruction Wishbone interface error |
| `endif |
| |
| `ifdef CFG_HW_DEBUG_ENABLED |
| input jtag_read_enable; // JTAG read memory request |
| input jtag_write_enable; // JTAG write memory request |
| input [`LM32_BYTE_RNG] jtag_write_data; // JTAG wrirte data |
| input [`LM32_WORD_RNG] jtag_address; // JTAG read/write address |
| `endif |
| |
| ///////////////////////////////////////////////////// |
| // Outputs |
| ///////////////////////////////////////////////////// |
| |
| output [`LM32_PC_RNG] pc_f; // F stage PC |
| reg [`LM32_PC_RNG] pc_f; |
| output [`LM32_PC_RNG] pc_d; // D stage PC |
| reg [`LM32_PC_RNG] pc_d; |
| output [`LM32_PC_RNG] pc_x; // X stage PC |
| reg [`LM32_PC_RNG] pc_x; |
| output [`LM32_PC_RNG] pc_m; // M stage PC |
| reg [`LM32_PC_RNG] pc_m; |
| output [`LM32_PC_RNG] pc_w; // W stage PC |
| reg [`LM32_PC_RNG] pc_w; |
| |
| `ifdef CFG_ICACHE_ENABLED |
| output icache_stall_request; // Instruction cache stall request |
| wire icache_stall_request; |
| output icache_restart_request; // Request to restart instruction that cached instruction cache miss |
| wire icache_restart_request; |
| output icache_refill_request; // Instruction cache refill request |
| wire icache_refill_request; |
| output icache_refilling; // Indicates the icache is refilling |
| wire icache_refilling; |
| `endif |
| |
| `ifdef CFG_IROM_ENABLED |
| output [`LM32_WORD_RNG] irom_data_m; // Data to load-store unit on load |
| wire [`LM32_WORD_RNG] irom_data_m; |
| `endif |
| |
| `ifdef CFG_MMU_ENABLED |
| output itlb_stall_request; // Instruction TLB stall request |
| wire itlb_stall_request; |
| output [`LM32_WORD_RNG] itlb_miss_vfn; // Virtual frame number of missed instruction |
| wire [`LM32_WORD_RNG] itlb_miss_vfn; |
| output itlb_miss_x; // Indicates if an instruction TLB miss occured in X stage |
| wire itlb_miss_x; |
| `endif |
| |
| `ifdef CFG_IWB_ENABLED |
| output [`LM32_WORD_RNG] i_dat_o; // Instruction Wishbone interface write data |
| `ifdef CFG_HW_DEBUG_ENABLED |
| reg [`LM32_WORD_RNG] i_dat_o; |
| `else |
| wire [`LM32_WORD_RNG] i_dat_o; |
| `endif |
| output [`LM32_WORD_RNG] i_adr_o; // Instruction Wishbone interface address |
| reg [`LM32_WORD_RNG] i_adr_o; |
| output i_cyc_o; // Instruction Wishbone interface cycle |
| reg i_cyc_o; |
| output [`LM32_BYTE_SELECT_RNG] i_sel_o; // Instruction Wishbone interface byte select |
| `ifdef CFG_HW_DEBUG_ENABLED |
| reg [`LM32_BYTE_SELECT_RNG] i_sel_o; |
| `else |
| wire [`LM32_BYTE_SELECT_RNG] i_sel_o; |
| `endif |
| output i_stb_o; // Instruction Wishbone interface strobe |
| reg i_stb_o; |
| output i_we_o; // Instruction Wishbone interface write enable |
| `ifdef CFG_HW_DEBUG_ENABLED |
| reg i_we_o; |
| `else |
| wire i_we_o; |
| `endif |
| output [`LM32_CTYPE_RNG] i_cti_o; // Instruction Wishbone interface cycle type |
| reg [`LM32_CTYPE_RNG] i_cti_o; |
| output i_lock_o; // Instruction Wishbone interface lock bus |
| reg i_lock_o; |
| output [`LM32_BTYPE_RNG] i_bte_o; // Instruction Wishbone interface burst type |
| wire [`LM32_BTYPE_RNG] i_bte_o; |
| `endif |
| |
| `ifdef CFG_HW_DEBUG_ENABLED |
| output [`LM32_BYTE_RNG] jtag_read_data; // Data read for JTAG interface |
| reg [`LM32_BYTE_RNG] jtag_read_data; |
| output jtag_access_complete; // Requested memory access by JTAG interface is complete |
| wire jtag_access_complete; |
| `endif |
| |
| `ifdef CFG_BUS_ERRORS_ENABLED |
| output bus_error_d; // Indicates a bus error occured while fetching the instruction |
| reg bus_error_d; |
| `endif |
| `ifdef CFG_EBR_POSEDGE_REGISTER_FILE |
| output [`LM32_INSTRUCTION_RNG] instruction_f; // F stage instruction (only to have register indices extracted from) |
| wire [`LM32_INSTRUCTION_RNG] instruction_f; |
| `endif |
| output [`LM32_INSTRUCTION_RNG] instruction_d; // D stage instruction to be decoded |
| reg [`LM32_INSTRUCTION_RNG] instruction_d; |
| |
| ///////////////////////////////////////////////////// |
| // Internal nets and registers |
| ///////////////////////////////////////////////////// |
| |
| reg [`LM32_PC_RNG] pc_a; // A stage PC |
| |
| `ifdef LM32_CACHE_ENABLED |
| reg [`LM32_PC_RNG] restart_address; // Address to restart from after a cache miss |
| `endif |
| |
| `ifdef CFG_ICACHE_ENABLED |
| wire icache_read_enable_f; // Indicates if instruction cache miss is valid |
| wire [`LM32_PC_RNG] icache_refill_address; // Address that caused cache miss |
| `ifdef CFG_MMU_ENABLED |
| wire [`LM32_PC_RNG] icache_physical_refill_address; // Physical address that caused cache miss |
| `endif |
| reg icache_refill_ready; // Indicates when next word of refill data is ready to be written to cache |
| reg [`LM32_INSTRUCTION_RNG] icache_refill_data; // Next word of refill data, fetched from Wishbone |
| wire [`LM32_INSTRUCTION_RNG] icache_data_f; // Instruction fetched from instruction cache |
| wire [`LM32_CTYPE_RNG] first_cycle_type; // First Wishbone cycle type |
| wire [`LM32_CTYPE_RNG] next_cycle_type; // Next Wishbone cycle type |
| wire last_word; // Indicates if this is the last word in the cache line |
| wire [`LM32_PC_RNG] first_address; // First cache refill address |
| `else |
| `ifdef CFG_IWB_ENABLED |
| reg [`LM32_INSTRUCTION_RNG] wb_data_f; // Instruction fetched from Wishbone |
| `endif |
| `endif |
| `ifdef CFG_IROM_ENABLED |
| wire irom_select_a; // Indicates if A stage PC maps to a ROM address |
| reg irom_select_f; // Indicates if F stage PC maps to a ROM address |
| wire [`LM32_INSTRUCTION_RNG] irom_data_f; // Instruction fetched from ROM |
| `endif |
| `ifdef CFG_EBR_POSEDGE_REGISTER_FILE |
| `else |
| wire [`LM32_INSTRUCTION_RNG] instruction_f; // F stage instruction |
| `endif |
| `ifdef CFG_BUS_ERRORS_ENABLED |
| reg bus_error_f; // Indicates if a bus error occured while fetching the instruction in the F stage |
| `endif |
| |
| `ifdef CFG_HW_DEBUG_ENABLED |
| reg jtag_access; // Indicates if a JTAG WB access is in progress |
| `endif |
| |
| `ifdef CFG_ALTERNATE_EBA |
| reg alternate_eba_taken; |
| `endif |
| |
| `ifdef CFG_MMU_ENABLED |
| wire [`LM32_PC_RNG] physical_pc_f; // F stage physical PC |
| wire itlb_miss_f; // Indicates if an instruction TLB miss occured in F stage |
| `endif |
| |
| ///////////////////////////////////////////////////// |
| // Functions |
| ///////////////////////////////////////////////////// |
| |
| ///////////////////////////////////////////////////// |
| // Instantiations |
| ///////////////////////////////////////////////////// |
| |
| // Instruction ROM |
| `ifdef CFG_IROM_ENABLED |
| `define LM32_IROM_WIDTH `CLOG2(`CFG_IROM_LIMIT/4-`CFG_IROM_BASE_ADDRESS/4+1) |
| `define LM32_IROM_RNG (`LM32_IROM_WIDTH-1+2):2 |
| |
| lm32_dp_ram #( |
| .data_width (`LM32_WORD_WIDTH), |
| .address_width (`LM32_IROM_WIDTH), |
| .init_file (`CFG_IROM_INIT_FILE) |
| ) ram ( |
| // ----- Inputs ------- |
| .clk_a (clk_i), |
| .clk_b (clk_i), |
| .ce_a (!stall_a), |
| .ce_b (!stall_x || !stall_m), |
| .addr_a (pc_a[`LM32_IROM_RNG]), |
| .addr_b (irom_address_xm[`LM32_IROM_RNG]), |
| .di_a ({32{1'b0}}), |
| .di_b (irom_store_data_m), |
| .we_a (`FALSE), |
| .we_b (irom_we_xm), |
| // ----- Outputs ------- |
| .do_a (irom_data_f), |
| .do_b (irom_data_m) |
| ); |
| `endif |
| |
| `ifdef CFG_ICACHE_ENABLED |
| // Instruction cache |
| lm32_icache #( |
| .associativity (associativity), |
| .sets (sets), |
| .bytes_per_line (bytes_per_line), |
| .base_address (base_address), |
| .limit (limit) |
| ) icache ( |
| // ----- Inputs ----- |
| .clk_i (clk_i), |
| .rst_i (rst_i), |
| .stall_a (stall_a), |
| .stall_f (stall_f), |
| .branch_predict_taken_d (branch_predict_taken_d), |
| .valid_d (valid_d), |
| .address_a (pc_a), |
| .address_f (pc_f), |
| `ifdef CFG_MMU_ENABLED |
| .physical_address_f (physical_pc_f), |
| `endif |
| .read_enable_f (icache_read_enable_f), |
| .refill_ready (icache_refill_ready), |
| .refill_data (icache_refill_data), |
| .iflush (iflush), |
| // ----- Outputs ----- |
| .stall_request (icache_stall_request), |
| .restart_request (icache_restart_request), |
| .refill_request (icache_refill_request), |
| .refill_address (icache_refill_address), |
| `ifdef CFG_MMU_ENABLED |
| .physical_refill_address(icache_physical_refill_address), |
| `endif |
| .refilling (icache_refilling), |
| .inst (icache_data_f) |
| ); |
| `endif |
| |
| `ifdef CFG_MMU_ENABLED |
| // Instruction TLB |
| lm32_itlb itlb ( |
| // ----- Inputs ----- |
| .clk_i (clk_i), |
| .rst_i (rst_i), |
| .enable (itlb_enable), |
| .stall_a (stall_a), |
| .stall_f (stall_f), |
| .stall_d (stall_d), |
| .stall_x (stall_x), |
| .pc_a (pc_a), |
| .pc_f (pc_f), |
| .pc_x (pc_x), |
| .read_enable_f (icache_read_enable_f), |
| .tlbpaddr (tlbpaddr), |
| .tlbvaddr (tlbvaddr), |
| .update (itlb_update), |
| .flush (itlb_flush), |
| .invalidate (itlb_invalidate), |
| // ----- Outputs ----- |
| .physical_pc_f (physical_pc_f), |
| .stall_request (itlb_stall_request), |
| .miss_vfn (itlb_miss_vfn), |
| .miss_f (itlb_miss_f), |
| .miss_x (itlb_miss_x) |
| ); |
| `endif |
| |
| ///////////////////////////////////////////////////// |
| // Combinational Logic |
| ///////////////////////////////////////////////////// |
| |
| `ifdef CFG_ICACHE_ENABLED |
| // Generate signal that indicates when instruction cache misses are valid |
| assign icache_read_enable_f = (valid_f == `TRUE) |
| && (kill_f == `FALSE) |
| `ifdef CFG_DCACHE_ENABLED |
| && (dcache_restart_request == `FALSE) |
| `endif |
| `ifdef CFG_IROM_ENABLED |
| && (irom_select_f == `FALSE) |
| `endif |
| `ifdef CFG_MMU_ENABLED |
| && (itlb_miss_f == `FALSE) |
| `endif |
| ; |
| `endif |
| |
| // Compute address of next instruction to fetch |
| always @(*) |
| begin |
| // The request from the latest pipeline stage must take priority |
| `ifdef CFG_DCACHE_ENABLED |
| if (dcache_restart_request == `TRUE) |
| pc_a = restart_address; |
| else |
| `endif |
| if (branch_taken_m == `TRUE) |
| if ((branch_mispredict_taken_m == `TRUE) && (exception_m == `FALSE)) |
| pc_a = pc_x; |
| else |
| pc_a = branch_target_m; |
| `ifdef CFG_FAST_UNCONDITIONAL_BRANCH |
| else if (branch_taken_x == `TRUE) |
| pc_a = branch_target_x; |
| `endif |
| else |
| if ( (valid_d == `TRUE) && (branch_predict_taken_d == `TRUE) ) |
| pc_a = branch_predict_address_d; |
| else |
| `ifdef CFG_ICACHE_ENABLED |
| if (icache_restart_request == `TRUE) |
| pc_a = restart_address; |
| else |
| `endif |
| pc_a = pc_f + 1'b1; |
| end |
| |
| // Select where instruction should be fetched from |
| `ifdef CFG_IROM_ENABLED |
| assign irom_select_a = ({pc_a, 2'b00} >= `CFG_IROM_BASE_ADDRESS) && ({pc_a, 2'b00} <= `CFG_IROM_LIMIT); |
| `endif |
| |
| // Select instruction from selected source |
| `ifdef CFG_ICACHE_ENABLED |
| `ifdef CFG_IROM_ENABLED |
| assign instruction_f = irom_select_f == `TRUE ? irom_data_f : icache_data_f; |
| `else |
| assign instruction_f = icache_data_f; |
| `endif |
| `else |
| `ifdef CFG_IROM_ENABLED |
| `ifdef CFG_IWB_ENABLED |
| assign instruction_f = irom_select_f == `TRUE ? irom_data_f : wb_data_f; |
| `else |
| assign instruction_f = irom_data_f; |
| `endif |
| `else |
| assign instruction_f = wb_data_f; |
| `endif |
| `endif |
| |
| // Unused/constant Wishbone signals |
| `ifdef CFG_IWB_ENABLED |
| `ifdef CFG_HW_DEBUG_ENABLED |
| `else |
| assign i_dat_o = 32'd0; |
| assign i_we_o = `FALSE; |
| assign i_sel_o = 4'b1111; |
| `endif |
| assign i_bte_o = `LM32_BTYPE_LINEAR; |
| `endif |
| |
| `ifdef CFG_ICACHE_ENABLED |
| // Determine parameters for next cache refill Wishbone access |
| generate |
| case (bytes_per_line) |
| 4: |
| begin |
| assign first_cycle_type = `LM32_CTYPE_END; |
| assign next_cycle_type = `LM32_CTYPE_END; |
| assign last_word = `TRUE; |
| `ifdef CFG_MMU_ENABLED |
| assign first_address = icache_physical_refill_address; |
| `else |
| assign first_address = icache_refill_address; |
| `endif |
| end |
| 8: |
| begin |
| assign first_cycle_type = `LM32_CTYPE_INCREMENTING; |
| assign next_cycle_type = `LM32_CTYPE_END; |
| assign last_word = i_adr_o[addr_offset_msb:addr_offset_lsb] == 1'b1; |
| `ifdef CFG_MMU_ENABLED |
| assign first_address = {icache_physical_refill_address[`LM32_PC_WIDTH+2-1:addr_offset_msb+1], {addr_offset_width{1'b0}}}; |
| `else |
| assign first_address = {icache_refill_address[`LM32_PC_WIDTH+2-1:addr_offset_msb+1], {addr_offset_width{1'b0}}}; |
| `endif |
| end |
| default: |
| begin |
| assign first_cycle_type = `LM32_CTYPE_INCREMENTING; |
| assign next_cycle_type = i_adr_o[addr_offset_msb:addr_offset_lsb+1] == {addr_offset_width-1{1'b1}} ? `LM32_CTYPE_END : `LM32_CTYPE_INCREMENTING; |
| assign last_word = (&i_adr_o[addr_offset_msb:addr_offset_lsb]) == 1'b1; |
| `ifdef CFG_MMU_ENABLED |
| assign first_address = {icache_physical_refill_address[`LM32_PC_WIDTH+2-1:addr_offset_msb+1], {addr_offset_width{1'b0}}}; |
| `else |
| assign first_address = {icache_refill_address[`LM32_PC_WIDTH+2-1:addr_offset_msb+1], {addr_offset_width{1'b0}}}; |
| `endif |
| end |
| endcase |
| endgenerate |
| `endif |
| |
| ///////////////////////////////////////////////////// |
| // Sequential Logic |
| ///////////////////////////////////////////////////// |
| |
| // PC |
| always @(posedge clk_i `CFG_RESET_SENSITIVITY) |
| begin |
| if (rst_i == `TRUE) |
| begin |
| `ifdef CFG_DEBUG_ENABLED |
| `ifdef CFG_ALTERNATE_EBA |
| if (at_debug == `TRUE) |
| pc_f <= (`CFG_DEBA_RESET-4)/4; |
| else |
| pc_f <= (eba_reset-4)/4; |
| `else |
| pc_f <= (eba_reset-4)/4; |
| `endif |
| `else |
| pc_f <= (eba_reset-4)/4; |
| `endif |
| pc_d <= {`LM32_PC_WIDTH{1'b0}}; |
| pc_x <= {`LM32_PC_WIDTH{1'b0}}; |
| pc_m <= {`LM32_PC_WIDTH{1'b0}}; |
| pc_w <= {`LM32_PC_WIDTH{1'b0}}; |
| end |
| else |
| begin |
| if (stall_f == `FALSE) |
| pc_f <= pc_a; |
| if (stall_d == `FALSE) |
| pc_d <= pc_f; |
| if (stall_x == `FALSE) |
| pc_x <= pc_d; |
| if (stall_m == `FALSE) |
| pc_m <= pc_x; |
| pc_w <= pc_m; |
| end |
| end |
| |
| `ifdef LM32_CACHE_ENABLED |
| // Address to restart from after a cache miss has been handled |
| always @(posedge clk_i `CFG_RESET_SENSITIVITY) |
| begin |
| if (rst_i == `TRUE) |
| restart_address <= {`LM32_PC_WIDTH{1'b0}}; |
| else |
| begin |
| `ifdef CFG_DCACHE_ENABLED |
| `ifdef CFG_ICACHE_ENABLED |
| // D-cache restart address must take priority, otherwise instructions will be lost |
| if (dcache_refill_request == `TRUE) |
| restart_address <= pc_w; |
| else if ((icache_refill_request == `TRUE) && (!dcache_refilling) && (!dcache_restart_request)) |
| restart_address <= icache_refill_address; |
| `else |
| if (dcache_refill_request == `TRUE) |
| restart_address <= pc_w; |
| `endif |
| `else |
| `ifdef CFG_ICACHE_ENABLED |
| if (icache_refill_request == `TRUE) |
| restart_address <= icache_refill_address; |
| `endif |
| `endif |
| end |
| end |
| `endif |
| |
| // Record where instruction was fetched from |
| `ifdef CFG_IROM_ENABLED |
| always @(posedge clk_i `CFG_RESET_SENSITIVITY) |
| begin |
| if (rst_i == `TRUE) |
| irom_select_f <= `FALSE; |
| else |
| begin |
| if (stall_f == `FALSE) |
| irom_select_f <= irom_select_a; |
| end |
| end |
| `endif |
| |
| `ifdef CFG_HW_DEBUG_ENABLED |
| assign jtag_access_complete = (i_cyc_o == `TRUE) && ((i_ack_i == `TRUE) || (i_err_i == `TRUE)) && (jtag_access == `TRUE); |
| always @(*) |
| begin |
| case (jtag_address[1:0]) |
| 2'b00: jtag_read_data = i_dat_i[`LM32_BYTE_3_RNG]; |
| 2'b01: jtag_read_data = i_dat_i[`LM32_BYTE_2_RNG]; |
| 2'b10: jtag_read_data = i_dat_i[`LM32_BYTE_1_RNG]; |
| 2'b11: jtag_read_data = i_dat_i[`LM32_BYTE_0_RNG]; |
| endcase |
| end |
| `endif |
| |
| `ifdef CFG_IWB_ENABLED |
| // Instruction Wishbone interface |
| `ifdef CFG_ICACHE_ENABLED |
| always @(posedge clk_i `CFG_RESET_SENSITIVITY) |
| begin |
| if (rst_i == `TRUE) |
| begin |
| i_cyc_o <= `FALSE; |
| i_stb_o <= `FALSE; |
| i_adr_o <= {`LM32_WORD_WIDTH{1'b0}}; |
| i_cti_o <= `LM32_CTYPE_END; |
| i_lock_o <= `FALSE; |
| icache_refill_data <= {`LM32_INSTRUCTION_WIDTH{1'b0}}; |
| icache_refill_ready <= `FALSE; |
| `ifdef CFG_BUS_ERRORS_ENABLED |
| bus_error_f <= `FALSE; |
| `endif |
| `ifdef CFG_HW_DEBUG_ENABLED |
| i_we_o <= `FALSE; |
| i_sel_o <= 4'b1111; |
| jtag_access <= `FALSE; |
| `endif |
| end |
| else |
| begin |
| icache_refill_ready <= `FALSE; |
| // Is a cycle in progress? |
| if (i_cyc_o == `TRUE) |
| begin |
| // Has cycle completed? |
| if ((i_ack_i == `TRUE) || (i_err_i == `TRUE)) |
| begin |
| `ifdef CFG_HW_DEBUG_ENABLED |
| if (jtag_access == `TRUE) |
| begin |
| i_cyc_o <= `FALSE; |
| i_stb_o <= `FALSE; |
| i_we_o <= `FALSE; |
| jtag_access <= `FALSE; |
| end |
| else |
| `endif |
| begin |
| if (last_word == `TRUE) |
| begin |
| // Cache line fill complete |
| i_cyc_o <= `FALSE; |
| i_stb_o <= `FALSE; |
| i_lock_o <= `FALSE; |
| end |
| // Fetch next word in cache line |
| i_adr_o[addr_offset_msb:addr_offset_lsb] <= i_adr_o[addr_offset_msb:addr_offset_lsb] + 1'b1; |
| i_cti_o <= next_cycle_type; |
| // Write fetched data into instruction cache |
| icache_refill_ready <= `TRUE; |
| icache_refill_data <= i_dat_i; |
| end |
| end |
| `ifdef CFG_BUS_ERRORS_ENABLED |
| if (i_err_i == `TRUE) |
| begin |
| bus_error_f <= `TRUE; |
| $display ("Instruction bus error. Address: %x", i_adr_o); |
| end |
| `endif |
| end |
| else |
| begin |
| if ((icache_refill_request == `TRUE) && (icache_refill_ready == `FALSE)) |
| begin |
| // Read first word of cache line |
| `ifdef CFG_HW_DEBUG_ENABLED |
| i_sel_o <= 4'b1111; |
| `endif |
| i_adr_o <= {first_address, 2'b00}; |
| i_cyc_o <= `TRUE; |
| i_stb_o <= `TRUE; |
| i_cti_o <= first_cycle_type; |
| //i_lock_o <= `TRUE; |
| `ifdef CFG_BUS_ERRORS_ENABLED |
| bus_error_f <= `FALSE; |
| `endif |
| end |
| `ifdef CFG_HW_DEBUG_ENABLED |
| else |
| begin |
| if ((jtag_read_enable == `TRUE) || (jtag_write_enable == `TRUE)) |
| begin |
| case (jtag_address[1:0]) |
| 2'b00: i_sel_o <= 4'b1000; |
| 2'b01: i_sel_o <= 4'b0100; |
| 2'b10: i_sel_o <= 4'b0010; |
| 2'b11: i_sel_o <= 4'b0001; |
| endcase |
| i_adr_o <= jtag_address; |
| i_dat_o <= {4{jtag_write_data}}; |
| i_cyc_o <= `TRUE; |
| i_stb_o <= `TRUE; |
| i_we_o <= jtag_write_enable; |
| i_cti_o <= `LM32_CTYPE_END; |
| jtag_access <= `TRUE; |
| end |
| end |
| `endif |
| `ifdef CFG_BUS_ERRORS_ENABLED |
| // Clear bus error when exception taken, otherwise they would be |
| // continually generated if exception handler is cached |
| `ifdef CFG_FAST_UNCONDITIONAL_BRANCH |
| if (branch_taken_x == `TRUE) |
| bus_error_f <= `FALSE; |
| `endif |
| if (branch_taken_m == `TRUE) |
| bus_error_f <= `FALSE; |
| `endif |
| end |
| end |
| end |
| `else |
| always @(posedge clk_i `CFG_RESET_SENSITIVITY) |
| begin |
| if (rst_i == `TRUE) |
| begin |
| i_cyc_o <= `FALSE; |
| i_stb_o <= `FALSE; |
| i_adr_o <= {`LM32_WORD_WIDTH{1'b0}}; |
| i_cti_o <= `LM32_CTYPE_END; |
| i_lock_o <= `FALSE; |
| wb_data_f <= {`LM32_INSTRUCTION_WIDTH{1'b0}}; |
| `ifdef CFG_BUS_ERRORS_ENABLED |
| bus_error_f <= `FALSE; |
| `endif |
| end |
| else |
| begin |
| // Is a cycle in progress? |
| if (i_cyc_o == `TRUE) |
| begin |
| // Has cycle completed? |
| if((i_ack_i == `TRUE) || (i_err_i == `TRUE)) |
| begin |
| // Cycle complete |
| i_cyc_o <= `FALSE; |
| i_stb_o <= `FALSE; |
| // Register fetched instruction |
| wb_data_f <= i_dat_i; |
| end |
| `ifdef CFG_BUS_ERRORS_ENABLED |
| if (i_err_i == `TRUE) |
| begin |
| bus_error_f <= `TRUE; |
| $display ("Instruction bus error. Address: %x", i_adr_o); |
| end |
| `endif |
| end |
| else |
| begin |
| // Wait for an instruction fetch from an external address |
| if ( (stall_a == `FALSE) |
| `ifdef CFG_IROM_ENABLED |
| && (irom_select_a == `FALSE) |
| `endif |
| ) |
| begin |
| // Fetch instruction |
| `ifdef CFG_HW_DEBUG_ENABLED |
| i_sel_o <= 4'b1111; |
| `endif |
| i_adr_o <= {pc_a, 2'b00}; |
| i_cyc_o <= `TRUE; |
| i_stb_o <= `TRUE; |
| `ifdef CFG_BUS_ERRORS_ENABLED |
| bus_error_f <= `FALSE; |
| `endif |
| end |
| else |
| begin |
| if ( (stall_a == `FALSE) |
| `ifdef CFG_IROM_ENABLED |
| && (irom_select_a == `TRUE) |
| `endif |
| ) |
| begin |
| `ifdef CFG_BUS_ERRORS_ENABLED |
| bus_error_f <= `FALSE; |
| `endif |
| end |
| end |
| end |
| end |
| end |
| `endif |
| `endif |
| |
| // Instruction register |
| always @(posedge clk_i `CFG_RESET_SENSITIVITY) |
| begin |
| if (rst_i == `TRUE) |
| begin |
| instruction_d <= {`LM32_INSTRUCTION_WIDTH{1'b0}}; |
| `ifdef CFG_BUS_ERRORS_ENABLED |
| bus_error_d <= `FALSE; |
| `endif |
| end |
| else |
| begin |
| if (stall_d == `FALSE) |
| begin |
| instruction_d <= instruction_f; |
| `ifdef CFG_BUS_ERRORS_ENABLED |
| bus_error_d <= bus_error_f; |
| `endif |
| end |
| end |
| end |
| |
| endmodule |