OpenCores
URL https://opencores.org/ocsvn/aor3000/aor3000/trunk

Subversion Repositories aor3000

[/] [aor3000/] [trunk/] [rtl/] [block/] [block_cp0.v] - Rev 2

Compare with Previous | Blame | View Log

/*
 * This file is subject to the terms and conditions of the BSD License. See
 * the file "LICENSE" in the main directory of this archive for more details.
 *
 * Copyright (C) 2014 Aleksander Osman
 */
 
`include "defines.v"
 
module block_cp0(
    input               clk,
    input               rst_n,
 
    //
    output reg          config_switch_caches,
    output reg          config_isolate_cache,
    output              config_coproc0_usable,
    output              config_coproc1_usable,
    output              config_kernel_mode,
 
    //
    input               exe_cmd_mtc0,
    input       [31:0]  exe_instr,
    input       [31:0]  exe_b,
 
    input               exe_cmd_rfe,
    input               exe_cmd_tlbr,
    input               exe_cmd_tlbwi,
    input               exe_cmd_tlbwr,
 
    //
    output      [31:0]  coproc0_output,
 
    //
    output      [5:0]   tlbw_index,
    output      [49:0]  tlbw_value,
 
    //
    output reg  [5:0]   tlbr_index,
 
    input               tlb_ram_read_result_ready,
    input       [49:0]  tlb_ram_read_result,
 
    //
    input               tlbp_update,
    input               tlbp_hit,
    input       [5:0]   tlbp_index,
 
    //
    output              micro_flush_do,
    output reg  [5:0]   entryhi_asid,
 
    //
    input               sr_cm_set,
    input               sr_cm_clear,
 
    //
    input       [5:0]   interrupt_vector,
 
    //
    output              exception_start,
    output      [31:0]  exception_start_pc,
 
    //
    input               mem_stalled,
    input       [6:0]   mem_cmd,
    input       [31:0]  mem_instr,
    input       [31:0]  mem_pc_plus4,
    input       [1:0]   mem_branched,
    input       [31:0]  mem_branch_address,
    input       [31:0]  mem_badvpn
); /* verilator public_module */
 
//------------------------------------------------------------------------------
 
reg [5:0]  sr_ku_ie;            //kernel/user and interrupt enable
reg        sr_bev;              //boot exception vector
reg        sr_cm;               //last d-cache load hit; used in d-cache isolated
reg [7:0]  sr_im;               //interrupt mask
reg [3:0]  sr_coproc_usable;    //coprocessor usable
reg        sr_reverse_endian;
reg        sr_tlb_shutdown;
reg        sr_parity_error;
reg        sr_parity_zero;
 
always @(posedge clk or negedge rst_n) begin
    if(rst_n == 1'b0)                                   sr_ku_ie <= 6'b0;
    else if(exe_cmd_mtc0 && exe_instr[15:11] == 5'd12)  sr_ku_ie <= exe_b[5:0];
    else if(exe_cmd_rfe)                                sr_ku_ie <= { sr_ku_ie[5:4], sr_ku_ie[5:2] };
    else if(exception_start)                            sr_ku_ie <= { sr_ku_ie[3:0], 2'b00 };
end
 
always @(posedge clk or negedge rst_n) begin
    if(rst_n == 1'b0)                                   sr_cm <= `FALSE;
    else if(exe_cmd_mtc0 && exe_instr[15:11] == 5'd12)  sr_cm <= exe_b[19];
    else if(sr_cm_clear)                                sr_cm <= `FALSE; //first sr_cm_clear important
    else if(sr_cm_set)                                  sr_cm <= `TRUE;
end
 
always @(posedge clk or negedge rst_n) begin if(rst_n == 1'b0) sr_coproc_usable      <= 4'b0;   else if(exe_cmd_mtc0 && exe_instr[15:11] == 5'd12) sr_coproc_usable     <= exe_b[31:28]; end
always @(posedge clk or negedge rst_n) begin if(rst_n == 1'b0) sr_reverse_endian     <= `FALSE; else if(exe_cmd_mtc0 && exe_instr[15:11] == 5'd12) sr_reverse_endian    <= exe_b[25];    end
always @(posedge clk or negedge rst_n) begin if(rst_n == 1'b0) sr_bev                <= `TRUE;  else if(exe_cmd_mtc0 && exe_instr[15:11] == 5'd12) sr_bev               <= exe_b[22];    end
always @(posedge clk or negedge rst_n) begin if(rst_n == 1'b0) sr_tlb_shutdown       <= `FALSE; else if(exe_cmd_mtc0 && exe_instr[15:11] == 5'd12) sr_tlb_shutdown      <= exe_b[21];    end
always @(posedge clk or negedge rst_n) begin if(rst_n == 1'b0) sr_parity_error       <= `FALSE; else if(exe_cmd_mtc0 && exe_instr[15:11] == 5'd12) sr_parity_error      <= exe_b[20];    end
always @(posedge clk or negedge rst_n) begin if(rst_n == 1'b0) sr_parity_zero        <= `FALSE; else if(exe_cmd_mtc0 && exe_instr[15:11] == 5'd12) sr_parity_zero       <= exe_b[18];    end
always @(posedge clk or negedge rst_n) begin if(rst_n == 1'b0) config_switch_caches  <= `FALSE; else if(exe_cmd_mtc0 && exe_instr[15:11] == 5'd12) config_switch_caches <= exe_b[17];    end
always @(posedge clk or negedge rst_n) begin if(rst_n == 1'b0) config_isolate_cache  <= `FALSE; else if(exe_cmd_mtc0 && exe_instr[15:11] == 5'd12) config_isolate_cache <= exe_b[16];    end
always @(posedge clk or negedge rst_n) begin if(rst_n == 1'b0) sr_im                 <= 8'h00;  else if(exe_cmd_mtc0 && exe_instr[15:11] == 5'd12) sr_im                <= exe_b[15:8];  end
 
assign config_kernel_mode    = ~(sr_ku_ie[1]);
assign config_coproc0_usable = sr_coproc_usable[0];
assign config_coproc1_usable = sr_coproc_usable[1];
 
//------------------------------------------------------------------------------
 
reg        cause_bd;            //branch delay
reg [1:0]  cause_ce;            //coproc error
reg [1:0]  cause_ip_writable;   //interrupt pending ([1:0] writable)
reg [4:0]  cause_exccode;       //exccode
reg [31:0] epc;
reg [31:0] badvaddr;
 
reg [5:0] interrupt_vector_reg;
always @(posedge clk or negedge rst_n) begin
    if(rst_n == 1'b0)   interrupt_vector_reg <= 6'd0;
    else                interrupt_vector_reg <= interrupt_vector;
end
 
wire [7:0] cause_ip = { interrupt_vector_reg, cause_ip_writable };
 
always @(posedge clk or negedge rst_n) begin
    if(rst_n == 1'b0)                                   cause_bd <= `FALSE;
    else if(exe_cmd_mtc0 && exe_instr[15:11] == 5'd13)  cause_bd <= exe_b[31];
    else if(exception_start)                            cause_bd <= (exception_not_interrupt && mem_branched == 2'd2) || (exception_interrupt && mem_branched == 2'd1);
end
 
always @(posedge clk or negedge rst_n) begin
    if(rst_n == 1'b0)                                   cause_ce <= 2'd0;
    else if(exe_cmd_mtc0 && exe_instr[15:11] == 5'd13)  cause_ce <= exe_b[29:28];
    else if(exception_coprocessor_error)                cause_ce <= mem_instr[27:26];
    else if(exception_start)                            cause_ce <= 2'd0;
end
 
always @(posedge clk or negedge rst_n) begin
    if(rst_n == 1'b0)                                   cause_ip_writable <= 2'd0;
    else if(exe_cmd_mtc0 && exe_instr[15:11] == 5'd13)  cause_ip_writable <= exe_b[9:8];
    else if(exception_start)                            cause_ip_writable <= 2'd0;
end
 
always @(posedge clk or negedge rst_n) begin
    if(rst_n == 1'b0)                                   cause_exccode <= 5'd31;
    else if(exe_cmd_mtc0 && exe_instr[15:11] == 5'd13)  cause_exccode <= exe_b[6:2];
    else if(exception_start)                            cause_exccode <= exception_cause;
end
 
always @(posedge clk or negedge rst_n) begin
    if(rst_n == 1'b0)                                   epc <= 32'd0;
    else if(exception_start)                            epc <= exception_epc;
end
 
always @(posedge clk or negedge rst_n) begin
    if(rst_n == 1'b0)                                   badvaddr <= 32'd0;
    else if(exception_badvaddr_update)                  badvaddr <= mem_badvpn;
end
 
//------------------------------------------------------------------------------
 
reg        tlb_probe;
reg [5:0]  tlb_random;
reg [10:0] tlb_ptebase;
reg [18:0] tlb_badvpn;
 
reg [19:0]  entryhi_vpn;
reg [19:0]  entrylo_pfn;
reg         entrylo_n;
reg         entrylo_d;
reg         entrylo_v;
reg         entrylo_g;
 
always @(posedge clk or negedge rst_n) begin
    if(rst_n == 1'b0)                                   entryhi_vpn <= 20'd0;
    else if(exception_badvaddr_update)                  entryhi_vpn <= mem_badvpn[31:12];
    else if(exe_cmd_mtc0 && exe_instr[15:11] == 5'd10)  entryhi_vpn <= exe_b[31:12];
    else if(tlb_ram_read_result_ready)                  entryhi_vpn <= tlb_ram_read_result[19:0];
end
always @(posedge clk or negedge rst_n) begin
    if(rst_n == 1'b0)                                   entryhi_asid <= 6'd0;
    else if(exe_cmd_mtc0 && exe_instr[15:11] == 5'd10)  entryhi_asid <= exe_b[11:6];
    else if(tlb_ram_read_result_ready)                  entryhi_asid <= tlb_ram_read_result[45:40];
end
always @(posedge clk or negedge rst_n) begin
    if(rst_n == 1'b0)                                   entrylo_pfn <= 20'd0;
    else if(exe_cmd_mtc0 && exe_instr[15:11] == 5'd2)   entrylo_pfn <= exe_b[31:12];
    else if(tlb_ram_read_result_ready)                  entrylo_pfn <= tlb_ram_read_result[39:20];
end
always @(posedge clk or negedge rst_n) begin
    if(rst_n == 1'b0)                                   entrylo_n <= `FALSE;
    else if(exe_cmd_mtc0 && exe_instr[15:11] == 5'd2)   entrylo_n <= exe_b[11];
    else if(tlb_ram_read_result_ready)                  entrylo_n <= tlb_ram_read_result[46];
end
always @(posedge clk or negedge rst_n) begin
    if(rst_n == 1'b0)                                   entrylo_d <= `FALSE;
    else if(exe_cmd_mtc0 && exe_instr[15:11] == 5'd2)   entrylo_d <= exe_b[10];
    else if(tlb_ram_read_result_ready)                  entrylo_d <= tlb_ram_read_result[47];
end
always @(posedge clk or negedge rst_n) begin
    if(rst_n == 1'b0)                                   entrylo_v <= `FALSE;
    else if(exe_cmd_mtc0 && exe_instr[15:11] == 5'd2)   entrylo_v <= exe_b[9];
    else if(tlb_ram_read_result_ready)                  entrylo_v <= tlb_ram_read_result[48];
end
always @(posedge clk or negedge rst_n) begin
    if(rst_n == 1'b0)                                   entrylo_g <= `FALSE;
    else if(exe_cmd_mtc0 && exe_instr[15:11] == 5'd2)   entrylo_g <= exe_b[8];
    else if(tlb_ram_read_result_ready)                  entrylo_g <= tlb_ram_read_result[49];
end
 
always @(posedge clk or negedge rst_n) begin
    if(rst_n == 1'b0)                                   tlb_ptebase <= 11'd0;
    else if(exe_cmd_mtc0 && exe_instr[15:11] == 5'd4)   tlb_ptebase <= exe_b[31:21];
end
 
always @(posedge clk or negedge rst_n) begin
    if(rst_n == 1'b0)                                   tlb_badvpn <= 19'd0;
    else if(exception_badvaddr_update)                  tlb_badvpn <= mem_badvpn[30:12];
end
 
always @(posedge clk or negedge rst_n) begin
    if(rst_n == 1'b0)                                   tlbr_index <= 6'd0;
    else if(exe_cmd_mtc0 && exe_instr[15:11] == 5'd0)   tlbr_index <= exe_b[13:8];
    else if(tlbp_update)                                tlbr_index <= (tlbp_hit)? tlbp_index : 6'd0;
end
always @(posedge clk or negedge rst_n) begin
    if(rst_n == 1'b0)                                   tlb_probe <= `FALSE;
    else if(exe_cmd_mtc0 && exe_instr[15:11] == 5'd0)   tlb_probe <= exe_b[31];
    else if(tlbp_update)                                tlb_probe <= ~(tlbp_hit);
end
 
always @(posedge clk or negedge rst_n) begin
    if(rst_n == 1'b0)                                   tlb_random <= 6'd63;
    else if(exe_cmd_tlbwr)                              tlb_random <= (tlb_random <= 6'd08)? 6'd63 : tlb_random - 6'd1;
end
 
reg [5:0] entryhi_asid_last;
always @(posedge clk or negedge rst_n) begin
    if(rst_n == 1'b0)   entryhi_asid_last <= 6'd0;
    else                entryhi_asid_last <= entryhi_asid;
end
 
assign micro_flush_do = (entryhi_asid_last != entryhi_asid) || exe_cmd_tlbwi || exe_cmd_tlbwr;
 
assign tlbw_index = (exe_cmd_tlbwi)? tlbr_index : tlb_random;
assign tlbw_value = (tlb_ram_read_result_ready)?
    { tlb_ram_read_result[49], tlb_ram_read_result[48], tlb_ram_read_result[47], tlb_ram_read_result[46], tlb_ram_read_result[45:40], tlb_ram_read_result[39:20], tlb_ram_read_result[19:0] } :
    { entrylo_g, entrylo_v, entrylo_d, entrylo_n, entryhi_asid, entrylo_pfn, entryhi_vpn };
 
//------------------------------------------------------------------------------
 
assign coproc0_output =
    (tlb_ram_read_result_ready && exe_instr[15:11] == 5'd2)?
                                    { tlb_ram_read_result[39:20], tlb_ram_read_result[46], tlb_ram_read_result[47], tlb_ram_read_result[48], tlb_ram_read_result[49], 8'd0 } :  //entry low just after tlbr
    (tlb_ram_read_result_ready && exe_instr[15:11] == 5'd10)?
                                    { tlb_ram_read_result[19:0], tlb_ram_read_result[45:40], 6'd0 } :                                                                           //entry high just after tlbr
 
    (exe_instr[15:11] == 5'd0)?     { tlb_probe, 17'd0, tlbr_index, 8'd0 } :                                    //tlb index
    (exe_instr[15:11] == 5'd1)?     { 18'd0, tlb_random, 8'd0 } :                                               //tlb random
    (exe_instr[15:11] == 5'd2)?     { entrylo_pfn, entrylo_n, entrylo_d, entrylo_v, entrylo_g, 8'd0 } :         //entry low
    (exe_instr[15:11] == 5'd4)?     { tlb_ptebase, tlb_badvpn, 2'b0 } :                                         //tlb context
    (exe_instr[15:11] == 5'd8)?     badvaddr :                                                                  //bad vaddr
    (exe_instr[15:11] == 5'd10)?    { entryhi_vpn, entryhi_asid, 6'd0 } :                                       //entry high
    (exe_instr[15:11] == 5'd12)?    { sr_coproc_usable, 2'b0, sr_reverse_endian, 2'b0, sr_bev, sr_tlb_shutdown, sr_parity_error, sr_cm, sr_parity_zero,
                                      config_switch_caches, config_isolate_cache, sr_im, 2'b0, sr_ku_ie } :     //SR
    (exe_instr[15:11] == 5'd13)?    { cause_bd, 1'b0, cause_ce, 12'd0, cause_ip, 1'b0, cause_exccode, 2'b0 } :  //cause
    (exe_instr[15:11] == 5'd14)?    epc :                                                                       //epc
    (exe_instr[15:11] == 5'd15)?    { 16'd0, 8'h02, 8'h30 } :                                                   //PRId
                                    32'd0;
 
//------------------------------------------------------------------------------
 
//input       [6:0]   mem_cmd,
//input               mem_branched,
//input       [31:0]  mem_badvpn
 
reg mem_stalled_last;
always @(posedge clk or negedge rst_n) begin
    if(rst_n == 1'b0)   mem_stalled_last <= `FALSE;
    else                mem_stalled_last <= mem_stalled;
end
 
wire exception_interrupt         = sr_ku_ie[0] && (cause_ip & sr_im) != 8'd0 && (mem_cmd != `CMD_null || (mem_stalled_last && ~(mem_stalled))) && ~(exception_not_interrupt) && ~(mem_stalled);
wire exception_badvaddr_update   = mem_cmd == `CMD_exc_load_tlb || mem_cmd == `CMD_exc_store_tlb || mem_cmd == `CMD_exc_tlb_load_miss || mem_cmd == `CMD_exc_tlb_store_miss || mem_cmd == `CMD_exc_tlb_modif;
wire exception_coprocessor_error = mem_cmd == `CMD_exc_coproc_unusable;
 
wire exception_not_interrupt = exception_coprocessor_error || exception_badvaddr_update || mem_cmd == `CMD_exc_int_overflow || mem_cmd == `CMD_break || mem_cmd == `CMD_syscall ||
                               mem_cmd == `CMD_exc_load_addr_err || mem_cmd == `CMD_exc_store_addr_err || mem_cmd == `CMD_exc_reserved_instr;
 
assign exception_start = exception_not_interrupt || exception_interrupt;
 
wire [31:0] exception_epc =
    (exception_interrupt && mem_branched == 2'd2)?  mem_branch_address :
    (exception_interrupt && mem_branched == 2'd0)?  mem_pc_plus4 :
    (mem_branched == 2'd2)?                         mem_pc_plus4 - 32'd8 :
                                                    mem_pc_plus4 - 32'd4;
 
wire [4:0] exception_cause =
    (mem_cmd == `CMD_exc_tlb_modif)?                                        5'd1 :
    (mem_cmd == `CMD_exc_load_tlb  || mem_cmd == `CMD_exc_tlb_load_miss)?   5'd2 :
    (mem_cmd == `CMD_exc_store_tlb || mem_cmd == `CMD_exc_tlb_store_miss)?  5'd3 :
    (mem_cmd == `CMD_exc_load_addr_err)?                                    5'd4 :
    (mem_cmd == `CMD_exc_store_addr_err)?                                   5'd5 :
    (mem_cmd == `CMD_syscall)?                                              5'd8 :
    (mem_cmd == `CMD_break)?                                                5'd9 :
    (mem_cmd == `CMD_exc_reserved_instr)?                                   5'd10 :
    (mem_cmd == `CMD_exc_coproc_unusable)?                                  5'd11 :
    (mem_cmd == `CMD_exc_int_overflow)?                                     5'd12 :
                                                                            5'd0;  //interrupt
 
assign exception_start_pc =
    (sr_bev && (mem_cmd == `CMD_exc_tlb_load_miss || mem_cmd == `CMD_exc_tlb_store_miss))?  32'hBFC00100 :
    (mem_cmd == `CMD_exc_tlb_load_miss || mem_cmd == `CMD_exc_tlb_store_miss)?              32'h80000000 :
    (sr_bev)?                                                                               32'hBFC00180 :
                                                                                            32'h80000080;
 
//------------------------------------------------------------------------------
// synthesis translate_off
wire _unused_ok = &{ 1'b0, exe_instr[31:16], exe_instr[10:0], exe_cmd_tlbr, exe_cmd_tlbwr, mem_instr[31:28], mem_instr[25:0], 1'b0 };
// synthesis translate_on
//------------------------------------------------------------------------------
 
endmodule
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.