URL
https://opencores.org/ocsvn/an-fpga-implementation-of-low-latency-noc-based-mpsoc/an-fpga-implementation-of-low-latency-noc-based-mpsoc/trunk
Subversion Repositories an-fpga-implementation-of-low-latency-noc-based-mpsoc
[/] [an-fpga-implementation-of-low-latency-noc-based-mpsoc/] [trunk/] [mpsoc/] [src_processor/] [mor1kx-5.0/] [rtl/] [verilog/] [mor1kx_fetch_cappuccino.v] - Rev 50
Go to most recent revision | Compare with Previous | Blame | View Log
/* **************************************************************************** This Source Code Form is subject to the terms of the Open Hardware Description License, v. 1.0. If a copy of the OHDL was not distributed with this file, You can obtain one at http://juliusbaxter.net/ohdl/ohdl.txt Description: mor1kx fetch/address stage unit basically an interface to the ibus/icache subsystem that can react to exception and branch signals. Copyright (C) 2012 Authors Author(s): Julius Baxter <juliusbaxter@gmail.com> Stefan Kristiansson <stefan.kristiansson@saunalahti.fi> ***************************************************************************** */ `include "mor1kx-defines.v" module mor1kx_fetch_cappuccino #( parameter OPTION_OPERAND_WIDTH = 32, parameter OPTION_RESET_PC = {{(OPTION_OPERAND_WIDTH-13){1'b0}}, `OR1K_RESET_VECTOR,8'd0}, parameter OPTION_RF_ADDR_WIDTH = 5, parameter FEATURE_INSTRUCTIONCACHE = "NONE", parameter OPTION_ICACHE_BLOCK_WIDTH = 5, parameter OPTION_ICACHE_SET_WIDTH = 9, parameter OPTION_ICACHE_WAYS = 2, parameter OPTION_ICACHE_LIMIT_WIDTH = 32, parameter FEATURE_IMMU = "NONE", parameter FEATURE_IMMU_HW_TLB_RELOAD = "NONE", parameter OPTION_IMMU_SET_WIDTH = 6, parameter OPTION_IMMU_WAYS = 1 ) ( input clk, input rst, // SPR interface input [15:0] spr_bus_addr_i, input spr_bus_we_i, input spr_bus_stb_i, input [OPTION_OPERAND_WIDTH-1:0] spr_bus_dat_i, output [OPTION_OPERAND_WIDTH-1:0] spr_bus_dat_ic_o, output spr_bus_ack_ic_o, output [OPTION_OPERAND_WIDTH-1:0] spr_bus_dat_immu_o, output spr_bus_ack_immu_o, input ic_enable, input immu_enable_i, input supervisor_mode_i, output ic_hit_o, // interface to ibus input ibus_err_i, input ibus_ack_i, input [`OR1K_INSN_WIDTH-1:0] ibus_dat_i, output ibus_req_o, output [OPTION_OPERAND_WIDTH-1:0] ibus_adr_o, output ibus_burst_o, // pipeline control input input padv_i, input padv_ctrl_i, // needed for immu spr // interface to decode unit output reg [OPTION_OPERAND_WIDTH-1:0] pc_decode_o, output reg [`OR1K_INSN_WIDTH-1:0] decode_insn_o, output reg fetch_valid_o, output [OPTION_RF_ADDR_WIDTH-1:0] fetch_rfa_adr_o, output [OPTION_RF_ADDR_WIDTH-1:0] fetch_rfb_adr_o, output fetch_rf_adr_valid_o, // branch/jump indication input decode_branch_i, input [OPTION_OPERAND_WIDTH-1:0] decode_branch_target_i, input ctrl_branch_exception_i, input [OPTION_OPERAND_WIDTH-1:0] ctrl_branch_except_pc_i, input du_restart_i, input [OPTION_OPERAND_WIDTH-1:0] du_restart_pc_i, input decode_op_brcond_i, input branch_mispredict_i, input [OPTION_OPERAND_WIDTH-1:0] execute_mispredict_target_i, // pipeline flush input from control unit input pipeline_flush_i, // rfe instruction is being performed input doing_rfe_i, // instruction ibus error indication out output reg decode_except_ibus_err_o, // IMMU exceptions output reg decode_except_itlb_miss_o, output reg decode_except_ipagefault_o, output reg fetch_exception_taken_o ); // registers reg [OPTION_OPERAND_WIDTH-1:0] pc_fetch; reg [OPTION_OPERAND_WIDTH-1:0] pc_addr; reg ctrl_branch_exception_r; wire bus_access_done; wire ctrl_branch_exception_edge; wire stall_fetch_valid; wire addr_valid; reg flush; wire flushing; reg nop_ack; reg imem_err; wire imem_ack; wire [`OR1K_INSN_WIDTH-1:0] imem_dat; wire ic_ack; wire [`OR1K_INSN_WIDTH-1:0] ic_dat; wire ic_refill; wire ic_refill_req; wire ic_refill_done; wire ic_invalidate; wire [OPTION_OPERAND_WIDTH-1:0] ic_addr; wire [OPTION_OPERAND_WIDTH-1:0] ic_addr_match; wire ic_access; wire [OPTION_OPERAND_WIDTH-1:0] immu_phys_addr; wire immu_cache_inhibit; wire pagefault; wire tlb_miss; wire except_itlb_miss; wire except_ipagefault; wire immu_busy; wire tlb_reload_req; reg tlb_reload_ack; wire [OPTION_OPERAND_WIDTH-1:0] tlb_reload_addr; reg [OPTION_OPERAND_WIDTH-1:0] tlb_reload_data; wire tlb_reload_pagefault; wire tlb_reload_busy; reg fetching_brcond; reg fetching_mispredicted_branch; wire mispredict_stall; reg exception_while_tlb_reload; wire except_ipagefault_clear; assign bus_access_done = (imem_ack | imem_err | nop_ack) & !immu_busy & !tlb_reload_busy; assign ctrl_branch_exception_edge = ctrl_branch_exception_i & !ctrl_branch_exception_r; /* used to keep fetch_valid_o high during stall */ assign stall_fetch_valid = !padv_i & fetch_valid_o; assign addr_valid = bus_access_done & padv_i & !(except_itlb_miss | except_ipagefault) | decode_except_itlb_miss_o & ctrl_branch_exception_i | decode_except_ipagefault_o & ctrl_branch_exception_i | doing_rfe_i; assign except_itlb_miss = tlb_miss & immu_enable_i & bus_access_done & !mispredict_stall & !doing_rfe_i; assign except_ipagefault = pagefault & immu_enable_i & bus_access_done & !mispredict_stall & !doing_rfe_i | tlb_reload_pagefault; assign fetch_rfa_adr_o = imem_dat[`OR1K_RA_SELECT]; assign fetch_rfb_adr_o = imem_dat[`OR1K_RB_SELECT]; assign fetch_rf_adr_valid_o = bus_access_done & padv_i; // Signal to indicate that the ongoing bus access should be flushed always @(posedge clk `OR_ASYNC_RST) if (rst) flush <= 0; else if (bus_access_done & padv_i | du_restart_i) flush <= 0; else if (pipeline_flush_i) flush <= 1; // pipeline_flush_i comes on the same edge as branch_except_occur during // rfe, but on an edge later when an exception occurs, but we always need // to keep on flushing when the branch signal comes in. assign flushing = pipeline_flush_i | ctrl_branch_exception_edge | flush; // Branch misprediction stall logic always @(posedge clk `OR_ASYNC_RST) if (rst) fetching_brcond <= 0; else if (pipeline_flush_i) fetching_brcond <= 0; else if (decode_op_brcond_i & addr_valid) fetching_brcond <= 1; else if (bus_access_done & padv_i | du_restart_i) fetching_brcond <= 0; always @(posedge clk `OR_ASYNC_RST) if (rst) fetching_mispredicted_branch <= 0; else if (pipeline_flush_i) fetching_mispredicted_branch <= 0; else if (bus_access_done & padv_i | du_restart_i) fetching_mispredicted_branch <= 0; else if (fetching_brcond & branch_mispredict_i & padv_i) fetching_mispredicted_branch <= 1; assign mispredict_stall = fetching_mispredicted_branch | branch_mispredict_i & fetching_brcond; always @(posedge clk `OR_ASYNC_RST) if (rst) ctrl_branch_exception_r <= 1'b0; else ctrl_branch_exception_r <= ctrl_branch_exception_i; // calculate address stage pc always @(*) if (rst) pc_addr = OPTION_RESET_PC; else if (du_restart_i) pc_addr = du_restart_pc_i; else if (ctrl_branch_exception_i & !fetch_exception_taken_o) pc_addr = ctrl_branch_except_pc_i; else if (branch_mispredict_i | fetching_mispredicted_branch) pc_addr = execute_mispredict_target_i; else if (decode_branch_i) pc_addr = decode_branch_target_i; else pc_addr = pc_fetch + 4; // Register fetch pc from address stage always @(posedge clk `OR_ASYNC_RST) if (rst) pc_fetch <= OPTION_RESET_PC; else if (addr_valid | du_restart_i) pc_fetch <= pc_addr; // fetch_exception_taken_o generation always @(posedge clk `OR_ASYNC_RST) if (rst) fetch_exception_taken_o <= 1'b0; else if (fetch_exception_taken_o) fetch_exception_taken_o <= 1'b0; else if (ctrl_branch_exception_i & bus_access_done & padv_i) fetch_exception_taken_o <= 1'b1; else fetch_exception_taken_o <= 1'b0; // fetch_valid_o generation always @(posedge clk `OR_ASYNC_RST) if (rst) fetch_valid_o <= 1'b0; else if (pipeline_flush_i) fetch_valid_o <= 1'b0; else if (bus_access_done & padv_i & !mispredict_stall & !immu_busy & !tlb_reload_busy | stall_fetch_valid) fetch_valid_o <= 1'b1; else fetch_valid_o <= 1'b0; // Register instruction coming in always @(posedge clk `OR_ASYNC_RST) if (rst) decode_insn_o <= {`OR1K_OPCODE_NOP,26'd0}; else if (imem_err | flushing) decode_insn_o <= {`OR1K_OPCODE_NOP,26'd0}; else if (bus_access_done & padv_i & !mispredict_stall) decode_insn_o <= imem_dat; // Register PC for later stages always @(posedge clk) if (bus_access_done & padv_i & !mispredict_stall) pc_decode_o <= pc_fetch; always @(posedge clk `OR_ASYNC_RST) if (rst) decode_except_ibus_err_o <= 0; else if (du_restart_i) decode_except_ibus_err_o <= 0; else if (imem_err) decode_except_ibus_err_o <= 1; else if (decode_except_ibus_err_o & ctrl_branch_exception_i) decode_except_ibus_err_o <= 0; always @(posedge clk `OR_ASYNC_RST) if (rst) decode_except_itlb_miss_o <= 0; else if (du_restart_i) decode_except_itlb_miss_o <= 0; else if (tlb_reload_busy) decode_except_itlb_miss_o <= 0; else if (except_itlb_miss) decode_except_itlb_miss_o <= 1; else if (decode_except_itlb_miss_o & ctrl_branch_exception_i) decode_except_itlb_miss_o <= 0; assign except_ipagefault_clear = decode_except_ipagefault_o & ctrl_branch_exception_i; always @(posedge clk `OR_ASYNC_RST) if (rst) decode_except_ipagefault_o <= 0; else if (du_restart_i) decode_except_ipagefault_o <= 0; else if (except_ipagefault) decode_except_ipagefault_o <= 1; else if (except_ipagefault_clear) decode_except_ipagefault_o <= 0; // Bus access logic localparam [2:0] IDLE = 0, READ = 1, TLB_RELOAD = 2, IC_REFILL = 3; reg [2:0] state; reg [OPTION_OPERAND_WIDTH-1:0] ibus_adr; wire [OPTION_OPERAND_WIDTH-1:0] next_ibus_adr; reg [`OR1K_INSN_WIDTH-1:0] ibus_dat; reg ibus_req; reg ibus_ack; wire ibus_access; // // Under certain circumstances, there is a need to insert an nop // into the pipeline in order for it to move forward. // Here those conditions are handled and an acknowledged signal // is generated. // always @(posedge clk `OR_ASYNC_RST) if (rst) nop_ack <= 0; else nop_ack <= padv_i & !bus_access_done & !(ibus_req & ibus_access) & ((immu_enable_i & (tlb_miss | pagefault) & !tlb_reload_busy) | ctrl_branch_exception_edge & !tlb_reload_busy | exception_while_tlb_reload & !tlb_reload_busy | tlb_reload_pagefault | mispredict_stall); assign ibus_access = (!ic_access | tlb_reload_busy | ic_invalidate) & !ic_refill | (state != IDLE) & (state != IC_REFILL) | ibus_ack; assign imem_ack = ibus_access ? ibus_ack : ic_ack; assign imem_dat = (nop_ack | except_itlb_miss | except_ipagefault) ? {`OR1K_OPCODE_NOP,26'd0} : ibus_access ? ibus_dat : ic_dat; assign ibus_adr_o = ibus_adr; assign ibus_req_o = ibus_req; assign ibus_burst_o = !ibus_access & ic_refill & !ic_refill_done; assign next_ibus_adr = (OPTION_ICACHE_BLOCK_WIDTH == 5) ? {ibus_adr[31:5], ibus_adr[4:0] + 5'd4} : // 32 byte {ibus_adr[31:4], ibus_adr[3:0] + 4'd4}; // 16 byte always @(posedge clk `OR_ASYNC_RST) if (rst) imem_err <= 0; else imem_err <= ibus_err_i; always @(posedge clk) begin ibus_ack <= 0; exception_while_tlb_reload <= 0; tlb_reload_ack <= 0; case (state) IDLE: begin ibus_req <= 0; if (padv_i & ibus_access & !ibus_ack & !imem_err & !nop_ack) begin if (tlb_reload_req) begin ibus_adr <= tlb_reload_addr; ibus_req <= 1; state <= TLB_RELOAD; end else if (immu_enable_i) begin ibus_adr <= immu_phys_addr; if (!tlb_miss & !pagefault & !immu_busy) begin ibus_req <= 1; state <= READ; end end else if (!ctrl_branch_exception_i | doing_rfe_i) begin ibus_adr <= pc_fetch; ibus_req <= 1; state <= READ; end end else if (ic_refill_req) begin ibus_adr <= ic_addr_match; ibus_req <= 1; state <= IC_REFILL; end end IC_REFILL: begin ibus_req <= 1; if (ibus_ack_i) begin ibus_adr <= next_ibus_adr; if (ic_refill_done) begin ibus_req <= 0; state <= IDLE; end end if (ibus_err_i) begin ibus_req <= 0; state <= IDLE; end end READ: begin ibus_ack <= ibus_ack_i; ibus_dat <= ibus_dat_i; if (ibus_ack_i | ibus_err_i) begin ibus_req <= 0; state <= IDLE; end end TLB_RELOAD: begin if (ctrl_branch_exception_i) exception_while_tlb_reload <= 1; ibus_adr <= tlb_reload_addr; tlb_reload_data <= ibus_dat_i; tlb_reload_ack <= ibus_ack_i & tlb_reload_req; if (!tlb_reload_req) state <= IDLE; ibus_req <= tlb_reload_req; if (ibus_ack_i | tlb_reload_ack) ibus_req <= 0; end default: state <= IDLE; endcase // case (state) if (rst) begin ibus_req <= 0; state <= IDLE; end end assign ic_addr = (addr_valid | du_restart_i) ? pc_addr : pc_fetch; assign ic_addr_match = immu_enable_i ? immu_phys_addr : pc_fetch; generate if (FEATURE_INSTRUCTIONCACHE!="NONE") begin : icache_gen reg ic_enable_r; always @(posedge clk `OR_ASYNC_RST) if (rst) ic_enable_r <= 0; else if (ic_enable & !ibus_req) ic_enable_r <= 1; else if (!ic_enable & !ic_refill) ic_enable_r <= 0; wire ic_enabled = ic_enable & ic_enable_r; wire ic_refill_allowed = (!((tlb_miss | pagefault) & immu_enable_i) & !ctrl_branch_exception_i & !pipeline_flush_i & !mispredict_stall | doing_rfe_i) & !tlb_reload_busy & !immu_busy; wire ic_req = padv_i & !decode_except_ibus_err_o & !decode_except_itlb_miss_o & !except_itlb_miss & !decode_except_ipagefault_o & !except_ipagefault & ic_access & ic_refill_allowed; if (OPTION_ICACHE_LIMIT_WIDTH == OPTION_OPERAND_WIDTH) begin assign ic_access = ic_enabled & !(immu_cache_inhibit & immu_enable_i); end else if (OPTION_ICACHE_LIMIT_WIDTH < OPTION_OPERAND_WIDTH) begin assign ic_access = ic_enabled & ic_addr_match[OPTION_OPERAND_WIDTH-1: OPTION_ICACHE_LIMIT_WIDTH] == 0 & !(immu_cache_inhibit & immu_enable_i); end else begin initial begin $display("ERROR: OPTION_ICACHE_LIMIT_WIDTH > OPTION_OPERAND_WIDTH"); $finish(); end end /* mor1kx_icache AUTO_TEMPLATE ( // Outputs .cpu_ack_o (ic_ack), .cpu_dat_o (ic_dat[OPTION_OPERAND_WIDTH-1:0]), .spr_bus_dat_o (spr_bus_dat_ic_o), .spr_bus_ack_o (spr_bus_ack_ic_o), .refill_o (ic_refill), .refill_req_o (ic_refill_req), .refill_done_o (ic_refill_done), .invalidate_o (ic_invalidate), // Inputs .rst (rst), .ic_imem_err_i (imem_err), .ic_access_i (ic_access), .cpu_adr_i (ic_addr), .cpu_adr_match_i (ic_addr_match), .cpu_req_i (ic_req), .wradr_i (ibus_adr), .wrdat_i (ibus_dat_i), .we_i (ibus_ack_i), );*/ mor1kx_icache #( .OPTION_ICACHE_BLOCK_WIDTH(OPTION_ICACHE_BLOCK_WIDTH), .OPTION_ICACHE_SET_WIDTH(OPTION_ICACHE_SET_WIDTH), .OPTION_ICACHE_WAYS(OPTION_ICACHE_WAYS), .OPTION_ICACHE_LIMIT_WIDTH(OPTION_ICACHE_LIMIT_WIDTH) ) mor1kx_icache (/*AUTOINST*/ // Outputs .refill_o (ic_refill), // Templated .refill_req_o (ic_refill_req), // Templated .refill_done_o (ic_refill_done), // Templated .invalidate_o (ic_invalidate), // Templated .cpu_ack_o (ic_ack), // Templated .cpu_dat_o (ic_dat[OPTION_OPERAND_WIDTH-1:0]), // Templated .spr_bus_dat_o (spr_bus_dat_ic_o), // Templated .spr_bus_ack_o (spr_bus_ack_ic_o), // Templated .cache_hit_o (ic_hit_o), // Inputs .clk (clk), .rst (rst), // Templated .ic_imem_err_i (imem_err), .ic_access_i (ic_access), // Templated .cpu_adr_i (ic_addr), // Templated .cpu_adr_match_i (ic_addr_match), // Templated .cpu_req_i (ic_req), // Templated .wradr_i (ibus_adr), // Templated .wrdat_i (ibus_dat_i), // Templated .we_i (ibus_ack_i), // Templated .spr_bus_addr_i (spr_bus_addr_i[15:0]), .spr_bus_we_i (spr_bus_we_i), .spr_bus_stb_i (spr_bus_stb_i), .spr_bus_dat_i (spr_bus_dat_i[OPTION_OPERAND_WIDTH-1:0])); end else begin // block: icache_gen assign ic_access = 0; assign ic_refill = 0; assign ic_refill_req = 1'b0; assign ic_refill_done = 0; assign ic_ack = 0; assign ic_hit_o = 0; assign ic_dat = 0; assign ic_invalidate = 0; assign spr_bus_dat_ic_o = 0; assign spr_bus_ack_ic_o = 0; end endgenerate generate if (FEATURE_IMMU!="NONE") begin : immu_gen wire [OPTION_OPERAND_WIDTH-1:0] virt_addr = ic_addr; wire immu_spr_bus_stb; wire immu_enable; // small hack to delay immu spr reads by one cycle // ideally the spr accesses should work so that the address is presented // in execute stage and the delayed data should be available in control // stage, but this is not how things currently work. assign immu_spr_bus_stb = spr_bus_stb_i & (!padv_ctrl_i | spr_bus_we_i); assign immu_enable = immu_enable_i & !pipeline_flush_i & !mispredict_stall; /* mor1kx_immu AUTO_TEMPLATE ( .enable_i (immu_enable), .busy_o (immu_busy), .phys_addr_o (immu_phys_addr), .cache_inhibit_o (immu_cache_inhibit), .tlb_miss_o (tlb_miss), .tlb_reload_req_o (tlb_reload_req), .tlb_reload_addr_o (tlb_reload_addr), .tlb_reload_pagefault_o (tlb_reload_pagefault), .tlb_reload_ack_i (tlb_reload_ack), .tlb_reload_data_i (tlb_reload_data), .tlb_reload_busy_o (tlb_reload_busy), .tlb_reload_pagefault_clear_i (except_ipagefault_clear), .pagefault_o (pagefault), .spr_bus_dat_o (spr_bus_dat_immu_o), .spr_bus_ack_o (spr_bus_ack_immu_o), .spr_bus_stb_i (immu_spr_bus_stb), .virt_addr_i (virt_addr), .virt_addr_match_i (pc_fetch), ); */ mor1kx_immu #( .FEATURE_IMMU_HW_TLB_RELOAD(FEATURE_IMMU_HW_TLB_RELOAD), .OPTION_OPERAND_WIDTH(OPTION_OPERAND_WIDTH), .OPTION_IMMU_SET_WIDTH(OPTION_IMMU_SET_WIDTH), .OPTION_IMMU_WAYS(OPTION_IMMU_WAYS) ) mor1kx_immu (/*AUTOINST*/ // Outputs .busy_o (immu_busy), // Templated .phys_addr_o (immu_phys_addr), // Templated .cache_inhibit_o (immu_cache_inhibit), // Templated .tlb_miss_o (tlb_miss), // Templated .pagefault_o (pagefault), // Templated .tlb_reload_req_o (tlb_reload_req), // Templated .tlb_reload_addr_o (tlb_reload_addr), // Templated .tlb_reload_pagefault_o (tlb_reload_pagefault), // Templated .tlb_reload_busy_o (tlb_reload_busy), // Templated .spr_bus_dat_o (spr_bus_dat_immu_o), // Templated .spr_bus_ack_o (spr_bus_ack_immu_o), // Templated // Inputs .clk (clk), .rst (rst), .enable_i (immu_enable), // Templated .virt_addr_i (virt_addr), // Templated .virt_addr_match_i (pc_fetch), // Templated .supervisor_mode_i (supervisor_mode_i), .tlb_reload_ack_i (tlb_reload_ack), // Templated .tlb_reload_data_i (tlb_reload_data), // Templated .tlb_reload_pagefault_clear_i (except_ipagefault_clear), // Templated .spr_bus_addr_i (spr_bus_addr_i[15:0]), .spr_bus_we_i (spr_bus_we_i), .spr_bus_stb_i (immu_spr_bus_stb), // Templated .spr_bus_dat_i (spr_bus_dat_i[OPTION_OPERAND_WIDTH-1:0])); end else begin assign immu_cache_inhibit = 0; assign immu_busy = 0; assign tlb_miss = 0; assign pagefault = 0; assign tlb_reload_busy = 0; assign tlb_reload_req = 0; assign tlb_reload_pagefault = 0; end endgenerate endmodule // mor1kx_fetch_cappuccino
Go to most recent revision | Compare with Previous | Blame | View Log