//   ==================================================================
//   >>>>>>>>>>>>>>>>>>>>>>> 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
