// =============================================================================
//                           COPYRIGHT NOTICE
// Copyright 2006 (c) Lattice Semiconductor Corporation
// ALL RIGHTS RESERVED
// This confidential and proprietary software may be used only as authorised by
// a licensing agreement from Lattice Semiconductor Corporation.
// The entire notice above must be reproduced on all authorized copies and
// copies may only be made to the extent permitted by a licensing agreement from
// Lattice Semiconductor Corporation.
//
// Lattice Semiconductor Corporation        TEL : 1-800-Lattice (USA and Canada)
// 5555 NE Moore Court                            408-826-6000 (other locations)
// Hillsboro, OR 97124                     web  : http://www.latticesemi.com/
// U.S.A                                   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.
// =============================================================================

`include "lm32_include.v"

/////////////////////////////////////////////////////
// Module interface
/////////////////////////////////////////////////////

module lm32_instruction_unit (
    // ----- Inputs -------
    clk_i,
    rst_i,
    // 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_IWB_ENABLED
    // From Wishbone
    i_dat_i,
    i_ack_i,
    i_err_i,
    i_rty_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_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_IRAM_ENABLED
    iram_i_adr_o,
    iram_i_dat_i,
    iram_i_en_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;                   // Reset value for EBA CSR
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 eba_reset_minus_4 = eba_reset - 4;
localparam addr_offset_width = bytes_per_line == 4 ? 1 : clogb2(bytes_per_line)-1-2;
localparam addr_offset_lsb = 2;
localparam addr_offset_msb = (addr_offset_lsb+addr_offset_width-1);

/////////////////////////////////////////////////////
// Inputs
/////////////////////////////////////////////////////
`ifdef CFG_IRAM_ENABLED
output [31:0] iram_i_adr_o;
input [31:0]  iram_i_dat_i;
   output     iram_i_en_o;
   
`endif

input clk_i;                                            // Clock
input rst_i;                                            // Reset

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_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
input i_rty_i;                                          // Instruction Wishbone interface retry
`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_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
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_IRAM_ENABLED
wire iram_select_a;                                     // Indicates if A stage PC maps to a ROM address
   reg 			     iram_select_f;
   
`endif
`ifdef CFG_EBR_POSEDGE_REGISTER_FILE
`else
wire [`LM32_INSTRUCTION_RNG] instruction_f;             // F stage instruction
`endif

`ifdef CFG_BUS_ERRORS_ENABLED 
 `ifdef CFG_IWB_ENABLED
   // Indicates if a bus error occured while fetching the instruction in the F stage
   reg 			     bus_error_f;          
 `endif
`endif
`ifndef CFG_IWB_ENABLED
   wire 		     bus_error_f = 0;
`endif
   
`ifdef CFG_HW_DEBUG_ENABLED
reg jtag_access;                                        // Indicates if a JTAG WB access is in progress
`endif

/////////////////////////////////////////////////////
// Functions
/////////////////////////////////////////////////////

`include "lm32_functions.v"

/////////////////////////////////////////////////////
// Instantiations
/////////////////////////////////////////////////////


`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),
    .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),
    .refilling              (icache_refilling),
    .inst                   (icache_data_f)
    );
`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_IRAM_ENABLED 
				    && (iram_select_f == `FALSE)
 `endif       
				    ;
`endif // CFG_ICACHE_ENABLED

// 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_IRAM_ENABLED
   assign iram_select_a = 1'b1;
   assign iram_i_en_o = !stall_a;
   assign iram_i_adr_o = {pc_a, 2'b00}; 
`endif

`ifdef CFG_IRAM_ENABLED

   reg [31:0] prev_instruction_f;
   reg 	      iram_i_en_d0;

   always@(posedge clk_i) 
     if(rst_i) begin
	iram_i_en_d0 <= 0;
     end else begin
	iram_i_en_d0 <= !stall_a;
	if(iram_i_en_d0)
	  prev_instruction_f <= iram_i_dat_i;
     end
   
   
   assign instruction_f = (!iram_i_en_d0) ? prev_instruction_f : iram_i_dat_i;

//   assign instruction_f = iram_i_dat_i;
  
   
`else
                     
// Select instruction from selected source
`ifdef CFG_ICACHE_ENABLED
assign instruction_f = icache_data_f;
`else
assign instruction_f = wb_data_f;
`endif

`endif // !`ifdef CFG_IRAM_ENABLED
   
// 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;
assign first_address = icache_refill_address;
    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;
assign first_address = {icache_refill_address[`LM32_PC_WIDTH+2-1:addr_offset_msb+1], {addr_offset_width{1'b0}}};
    end
    16:
    begin
assign first_cycle_type = `LM32_CTYPE_INCREMENTING;
assign next_cycle_type = i_adr_o[addr_offset_msb] == 1'b1 ? `LM32_CTYPE_END : `LM32_CTYPE_INCREMENTING;
assign last_word = i_adr_o[addr_offset_msb:addr_offset_lsb] == 2'b11;
assign first_address = {icache_refill_address[`LM32_PC_WIDTH+2-1:addr_offset_msb+1], {addr_offset_width{1'b0}}};
    end
    endcase
endgenerate
`endif
                     
/////////////////////////////////////////////////////
// Sequential Logic
/////////////////////////////////////////////////////

// PC 
always @(posedge clk_i `CFG_RESET_SENSITIVITY)
begin
    if (rst_i == `TRUE)
    begin
        pc_f <= eba_reset_minus_4[`LM32_PC_RNG];
        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_IRAM_ENABLED
always @(posedge clk_i `CFG_RESET_SENSITIVITY)
begin
    if (rst_i == `TRUE)
        iram_select_f <= `FALSE;
    else
    begin
        if (stall_f == `FALSE)
            iram_select_f <= iram_select_a;
    end
end
`endif

`ifdef CFG_HW_DEBUG_ENABLED
   `ifndef CFG_IRAM_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 // case (jtag_address[1:0])
end
   `endif
`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
		  `ifndef CFG_IRAM_ENABLED
		  if (i_err_i == `TRUE)
		    begin
                       bus_error_f <= `TRUE;
                       $display ("Instruction bus error. Address: %x", i_adr_o);
		    end
		  `endif
  `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
		  `ifndef CFG_IRAM_ENABLED
		  if (i_err_i == `TRUE)
		    begin
                       bus_error_f <= `TRUE;
                       $display ("Instruction bus error. Address: %x", i_adr_o);
		       
		    end
		  `endif
  `endif
               end
             else
               begin
		  // Wait for an instruction fetch from an external address 
		  if (   (stall_a == `FALSE) 
  `ifdef CFG_IRAM_ENABLED 
			 && (iram_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_IRAM_ENABLED 
			      && (iram_select_a == `TRUE)
  `endif       
			      )
			 begin
  `ifdef CFG_BUS_ERRORS_ENABLED
			    bus_error_f <= `FALSE;
  `endif
			 end
		    end
               end
	  end
     end
 `endif
`endif // CFG_IWB_ENABLED

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