litex/verilog/lm32/lm32_instruction_unit.v

890 lines
30 KiB
Verilog

// ==================================================================
// >>>>>>>>>>>>>>>>>>>>>>> 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_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_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 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 : clogb2(bytes_per_line)-1-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_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_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_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
/////////////////////////////////////////////////////
// Functions
/////////////////////////////////////////////////////
`include "lm32_functions.v"
/////////////////////////////////////////////////////
// Instantiations
/////////////////////////////////////////////////////
// Instruction ROM
`ifdef CFG_IROM_ENABLED
pmi_ram_dp_true
#(
// ----- Parameters -------
.pmi_family (`LATTICE_FAMILY),
//.pmi_addr_depth_a (1 << (clogb2(`CFG_IROM_LIMIT/4-`CFG_IROM_BASE_ADDRESS/4+1)-1)),
//.pmi_addr_width_a ((clogb2(`CFG_IROM_LIMIT/4-`CFG_IROM_BASE_ADDRESS/4+1)-1)),
//.pmi_data_width_a (`LM32_WORD_WIDTH),
//.pmi_addr_depth_b (1 << (clogb2(`CFG_IROM_LIMIT/4-`CFG_IROM_BASE_ADDRESS/4+1)-1)),
//.pmi_addr_width_b ((clogb2(`CFG_IROM_LIMIT/4-`CFG_IROM_BASE_ADDRESS/4+1)-1)),
//.pmi_data_width_b (`LM32_WORD_WIDTH),
.pmi_addr_depth_a (`CFG_IROM_LIMIT/4-`CFG_IROM_BASE_ADDRESS/4+1),
.pmi_addr_width_a (clogb2_v1(`CFG_IROM_LIMIT/4-`CFG_IROM_BASE_ADDRESS/4+1)),
.pmi_data_width_a (`LM32_WORD_WIDTH),
.pmi_addr_depth_b (`CFG_IROM_LIMIT/4-`CFG_IROM_BASE_ADDRESS/4+1),
.pmi_addr_width_b (clogb2_v1(`CFG_IROM_LIMIT/4-`CFG_IROM_BASE_ADDRESS/4+1)),
.pmi_data_width_b (`LM32_WORD_WIDTH),
.pmi_regmode_a ("noreg"),
.pmi_regmode_b ("noreg"),
.pmi_gsr ("enable"),
.pmi_resetmode ("sync"),
.pmi_init_file (`CFG_IROM_INIT_FILE),
.pmi_init_file_format (`CFG_IROM_INIT_FILE_FORMAT),
.module_type ("pmi_ram_dp_true")
)
ram (
// ----- Inputs -------
.ClockA (clk_i),
.ClockB (clk_i),
.ResetA (rst_i),
.ResetB (rst_i),
.DataInA ({32{1'b0}}),
.DataInB (irom_store_data_m),
.AddressA (pc_a[(clogb2(`CFG_IROM_LIMIT/4-`CFG_IROM_BASE_ADDRESS/4+1)-1)+2-1:2]),
.AddressB (irom_address_xm[(clogb2(`CFG_IROM_LIMIT/4-`CFG_IROM_BASE_ADDRESS/4+1)-1)+2-1:2]),
.ClockEnA (!stall_a),
.ClockEnB (!stall_x || !stall_m),
.WrA (`FALSE),
.WrB (irom_we_xm),
// ----- Outputs -------
.QA (irom_data_f),
.QB (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),
.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_IROM_ENABLED
&& (irom_select_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;
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
`ifdef CFG_DEBUG_ENABLED
`ifdef CFG_ALTERNATE_EBA
if (at_debug == `TRUE)
pc_f <= (`CFG_DEBA_RESET-4)/4;
else
pc_f <= (`CFG_EBA_RESET-4)/4;
`else
pc_f <= (`CFG_EBA_RESET-4)/4;
`endif
`else
pc_f <= (`CFG_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