Branch 1.3

This commit is contained in:
Joseph Rahmeh 2020-11-17 10:25:18 -08:00
parent 7570549cf7
commit 2d26189faf
93 changed files with 20395 additions and 4604 deletions

View File

@ -1,4 +1,4 @@
# EL2 SweRV RISC-V Core<sup>TM</sup> 1.2 from Western Digital
# EL2 SweRV RISC-V Core<sup>TM</sup> 1.3 from Western Digital
This repository contains the SweRV EL2 Core<sup>TM</sup> design RTL
@ -24,13 +24,14 @@ Files under the [tools](tools/) directory may be available under a different lic
├── tools # Scripts/Makefiles
└── testbench # (Very) simple testbench
   ├── asm # Example assembly files
   └── hex # Canned demo hex files
   ├── hex # Canned demo hex files
   └── tests # Example tests
## Dependencies
- Verilator **(4.020 or later)** must be installed on the system if running with verilator
- Verilator **(4.102 or later)** must be installed on the system if running with verilator
- If adding/removing instructions, espresso must be installed (used by *tools/coredecode*)
- RISCV tool chain (based on gcc version 7.3 or higher) must be
- RISCV tool chain (based on gcc version 8.3 or higher) must be
installed so that it can be used to prepare RISCV binaries to run.
## Quickstart guide
@ -57,7 +58,15 @@ This will update the **default** snapshot in $RV_ROOT/configs/snapshots/default/
Add `-snapshot=dccm64`, for example, if you wish to name your build snapshot *dccm64* and refer to it during the build.
There are 4 predefined target configurations: `default`, `default_ahb`, `typical_pd` and `high_perf` that can be selected via
the `-target=name` option to swerv.config.
the `-target=name` option to swerv.config. **Note:** that the `typical_pd` target is what we base our published PPA numbers. It does not include an ICCM.
**Building an FPGA speed optimized model:**
Use ``-fpga_optimize=1`` option to ``swerv.config`` to build a model that removes clock gating logic from flop model so that the FPGA builds can run at higher speeds. **This is now the default option for
targets other than ``typical_pd``.**
**Building a Power optimized model (ASIC flows):**
Use ``-fpga_optimize=0`` option to ``swerv.config`` to build a model that **enables** clock gating logic into the flop model so that the ASIC flows get a better power footprint. **This is now the default option for
target``typical_pd``.**
This script derives the following consistent set of include files :
@ -70,6 +79,7 @@ This script derives the following consistent set of include files :
├── perl_configs.pl # Perl %configs hash for scripting
├── pic_map_auto.h # PIC memory map based on configure size
└── whisper.json # JSON file for swerv-iss
└── link.ld # default linker control file
@ -107,7 +117,7 @@ execute a short sequence of instructions that writes out "HELLO WORLD"
to the bus.
The simulation produces output on the screen like:
The simulation produces output on the screen like: u
```
VerilatorTB: Start of sim
@ -130,8 +140,6 @@ The simulation generates following files:
gtkwave or similar waveform viewers.
You can re-execute simulation using:
` ./obj_dir/Vtb_top `
or
`make -f $RV_ROOT/tools/Makefile verilator`
@ -143,20 +151,20 @@ The simulation run/build command has following generic form:
where:
```
<simulator> - can be 'verilator' (by default) 'irun' - Cadence xrun, 'vcs' - Synopsys VCS, 'vlog' Mentor Questa
if not provided, 'make' cleans work directory, builds verilator executable and runs a test.
'riviera'- Aldec Riviera-PRO. if not provided, 'make' cleans work directory, builds verilator executable and runs a test.
debug=1 - allows VCD generation for verilator and VCS and SHM waves for irun option.
<target> - predefined CPU configurations 'default' ( by default), 'default_ahb', 'typical_pd', 'high_perf'
TEST - allows to run a C (<test>.c) or assembly (<test>.s) test, hello_world is run by default
TEST_DIR - alternative to test source directory testbench/asm
TEST_DIR - alternative to test source directory testbench/asm or testbench/tests
<snapshot> - run and build executable model of custom CPU configuration, remember to provide 'snapshot' argument
for runs on custom configurations.
CONF_PARAMS - allows to provide -set options to swerv.conf script to alter predefined EL2 targets parameters
```
Example:
make -f $RV_ROOT/tools/Makefile verilator TEST=cmark
will simulate testbench/asm/cmark.c program with verilator
will build and simulate testbench/asm/cmark.c program with verilator
If you want to compile a test only, you can run:
@ -164,35 +172,43 @@ If you want to compile a test only, you can run:
make -f $RV_ROOT/tools/Makefile program.hex TEST=<test> [TEST_DIR=/path/to/dir]
The Makefile uses `$RV_ROOT/testbench/link.ld` file by default to build test executable.
The Makefile uses `snapshot/<target>/link.ld` file, generated by swerv.conf script by default to build test executable.
User can provide test specific linker file in form `<test_name>.ld` to build the test executable,
in the same directory with the test source.
User also can create a test specific makefile in form `<test_name>.makefile`, containing building instructions
how to create `program.hex` and `data.hex` files used by simulation. The private makefile should be in the same directory
as the test source.
*(`program.hex` file is loaded to instruction bus memory slave and `data.hex` file is loaded to LSU bus memory slave and
optionally to DCCM at the beginning of simulation)*.
how to create `program.hex` file used by simulation. The private makefile should be in the same directory
as the test source. See examples in `testbench/asm` directory.
Another way to alter test building process is to use `<test_name>.mki` file in test source directory. It may help to select multiple sources
to compile and/or alter compilation swiches. See examples in `testbench/tests/` directory
*(`program.hex` file is loaded to instruction and LSU bus memory slaves and
optionally to DCCM/ICCM at the beginning of simulation)*.
User can build `program.hex` file by any other means and then run simulation with following command:
make -f $RV_ROOT/tools/Makefile <simulator>
Note: You may need to delete `program.hex` file from work directory, when run a new test.
The `$RV_ROOT/testbench/asm` directory contains following tests ready to simulate:
```
hello_world - default tes to run, prints Hello World message to screen and console.log
hello_world - default test program to run, prints Hello World message to screen and console.log
hello_world_dccm - the same as above, but takes the string from preloaded DCCM.
hello_world_iccm - the same as hello_world, but loads the test code to ICCM via LSU to DMA bridge and then executes
it from there. Runs on EL2 with AXI4 buses only.
cmark - coremark benchmark running with code and data in external memories
cmark_dccm - the same as above, running data and stack from DCCM (faster)
cmark_iccm - the same as above with preloaded code to ICCM.
cmark_iccm - the same as above with preloaded code to ICCM (slower, optimized for size to fit into default ICCM).
dhry - Run dhrystone. (Scale by 1757 to get DMIPS/MHZ)
```
The `$RV_ROOT/testbench/hex` directory contains precompiled hex files of the tests, ready for simulation in case RISCV SW tools are not installed.
**Note**: The testbench has a simple synthesizable bridge that allows you to load the ICCM via load/store instructions. This is only supported for AXI4 builds.
**Building an FPGA speed optimized model:**
Use ``-set=fpga_optimize=1`` option to ``swerv.config`` to build a model that is removes clock gating logic from flop model so that the FPGA builds can run a higher speeds.
----

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 Western Digital Corporation or it's affiliates.
// Copyright 2020 Western Digital Corporation or its affiliates.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -108,14 +108,14 @@ import el2_pkg::*;
// general inputs
input logic clk,
input logic rst_l,
input logic rst_l, // This includes both top rst and debug rst
input logic dbg_rst_l,
input logic clk_override,
input logic scan_mode
);
typedef enum logic [2:0] {IDLE=3'b000, HALTING=3'b001, HALTED=3'b010, CMD_START=3'b011, CMD_WAIT=3'b100, CMD_DONE=3'b101, RESUMING=3'b110} state_t;
typedef enum logic [3:0] {IDLE=4'h0, HALTING=4'h1, HALTED=4'h2, CORE_CMD_START=4'h3, CORE_CMD_WAIT=4'h4, SB_CMD_START=4'h5, SB_CMD_SEND=4'h6, SB_CMD_RESP=4'h7, CMD_DONE=4'h8, RESUMING=4'h9} state_t;
typedef enum logic [3:0] {SBIDLE=4'h0, WAIT_RD=4'h1, WAIT_WR=4'h2, CMD_RD=4'h3, CMD_WR=4'h4, CMD_WR_ADDR=4'h5, CMD_WR_DATA=4'h6, RSP_RD=4'h7, RSP_WR=4'h8, DONE=4'h9} sb_state_t;
state_t dbg_state;
@ -132,32 +132,43 @@ import el2_pkg::*;
// data 0
logic [31:0] data0_din;
logic data0_reg_wren, data0_reg_wren0, data0_reg_wren1;
logic data0_reg_wren, data0_reg_wren0, data0_reg_wren1, data0_reg_wren2;
// data 1
logic [31:0] data1_din;
logic data1_reg_wren, data1_reg_wren0;
logic data1_reg_wren, data1_reg_wren0, data1_reg_wren1;
// abstractcs
logic abstractcs_busy_wren;
logic abstractcs_busy_din;
logic [2:0] abstractcs_error_din;
logic abstractcs_error_sel0, abstractcs_error_sel1, abstractcs_error_sel2, abstractcs_error_sel3, abstractcs_error_sel4, abstractcs_error_sel5;
logic abstractcs_error_selor;
logic abstractcs_error_sel0, abstractcs_error_sel1, abstractcs_error_sel2, abstractcs_error_sel3, abstractcs_error_sel4, abstractcs_error_sel5, abstractcs_error_sel6;
logic dbg_sb_bus_error;
// abstractauto
logic abstractauto_reg_wren;
logic [1:0] abstractauto_reg;
// dmstatus
logic dmstatus_resumeack_wren;
logic dmstatus_resumeack_din;
logic dmstatus_havereset_wren;
logic dmstatus_havereset_rst;
logic dmstatus_haveresetn_wren;
logic dmstatus_resumeack;
logic dmstatus_unavail;
logic dmstatus_running;
logic dmstatus_halted;
logic dmstatus_havereset;
logic dmstatus_havereset, dmstatus_haveresetn;
// dmcontrol
logic resumereq;
logic dmcontrol_wren, dmcontrol_wren_Q;
// command
logic command_wren;
logic execute_command_ns, execute_command;
logic command_wren, command_regno_wren;
logic command_transfer_din;
logic command_postexec_din;
logic [31:0] command_din;
logic [3:0] dbg_cmd_addr_incr;
logic [31:0] dbg_cmd_curr_addr;
logic [31:0] dbg_cmd_next_addr;
// needed to send the read data back for dmi reads
logic [31:0] dmi_reg_rdata_din;
@ -176,6 +187,7 @@ import el2_pkg::*;
logic [2:0] sbcs_sberror_din;
logic sbcs_unaligned;
logic sbcs_illegal_size;
logic [19:15] sbcs_reg_int;
// data
logic sbdata0_reg_wren0;
@ -197,6 +209,24 @@ import el2_pkg::*;
logic sbreadondata_access;
logic sbdata0wr_access;
logic sb_abmem_cmd_done_in, sb_abmem_data_done_in;
logic sb_abmem_cmd_done_en, sb_abmem_data_done_en;
logic sb_abmem_cmd_done, sb_abmem_data_done;
logic [31:0] abmem_addr;
logic abmem_addr_in_dccm_region, abmem_addr_in_iccm_region, abmem_addr_in_pic_region;
logic abmem_addr_core_local;
logic abmem_addr_external;
logic sb_cmd_pending, sb_abmem_cmd_pending;
logic sb_abmem_cmd_write;
logic [2:0] sb_abmem_cmd_size;
logic [31:0] sb_abmem_cmd_addr;
logic [31:0] sb_abmem_cmd_wdata;
logic [2:0] sb_cmd_size;
logic [31:0] sb_cmd_addr;
logic [63:0] sb_cmd_wdata;
logic sb_bus_cmd_read, sb_bus_cmd_write_addr, sb_bus_cmd_write_data;
logic sb_bus_rsp_read, sb_bus_rsp_write;
logic sb_bus_rsp_error;
@ -208,6 +238,14 @@ import el2_pkg::*;
logic [31:0] sbdata0_reg;
logic [31:0] sbdata1_reg;
logic sb_abmem_cmd_arvalid, sb_abmem_cmd_awvalid, sb_abmem_cmd_wvalid;
logic sb_abmem_read_pend;
logic sb_cmd_awvalid, sb_cmd_wvalid, sb_cmd_arvalid;
logic sb_read_pend;
logic [31:0] sb_axi_addr;
logic [63:0] sb_axi_wrdata;
logic [2:0] sb_axi_size;
logic dbg_dm_rst_l;
//clken
@ -219,10 +257,10 @@ import el2_pkg::*;
// clocking
// used for the abstract commands.
assign dbg_free_clken = dmi_reg_en | (dbg_state != IDLE) | dbg_state_en | dec_tlu_dbg_halted | clk_override;
assign dbg_free_clken = dmi_reg_en | execute_command | (dbg_state != IDLE) | dbg_state_en | dec_tlu_dbg_halted | dec_tlu_mpc_halted_only | dec_tlu_debug_mode | dbg_halt_req | clk_override;
// used for the system bus
assign sb_free_clken = dmi_reg_en | sb_state_en | (sb_state != SBIDLE) | clk_override;
assign sb_free_clken = dmi_reg_en | execute_command | sb_state_en | (sb_state != SBIDLE) | clk_override;
rvoclkhdr dbg_free_cgc (.en(dbg_free_clken), .l1clk(dbg_free_clk), .*);
rvoclkhdr sb_free_cgc (.en(sb_free_clken), .l1clk(sb_free_clk), .*);
@ -231,23 +269,25 @@ import el2_pkg::*;
// Reset logic
assign dbg_dm_rst_l = dbg_rst_l & (dmcontrol_reg[0] | scan_mode);
assign dbg_core_rst_l = ~dmcontrol_reg[1];
assign dbg_core_rst_l = ~dmcontrol_reg[1] | scan_mode;
// system bus register
// sbcs[31:29], sbcs - [22]:sbbusyerror, [21]: sbbusy, [20]:sbreadonaddr, [19:17]:sbaccess, [16]:sbautoincrement, [15]:sbreadondata, [14:12]:sberror, sbsize=32, 128=0, 64/32/16/8 are legal
assign sbcs_reg[31:29] = 3'b1;
assign sbcs_reg[28:23] = '0;
assign sbcs_reg[19:15] = {sbcs_reg_int[19], ~sbcs_reg_int[18], sbcs_reg_int[17:15]};
assign sbcs_reg[11:5] = 7'h20;
assign sbcs_reg[4:0] = 5'b01111;
assign sbcs_wren = (dmi_reg_addr == 7'h38) & dmi_reg_en & dmi_reg_wr_en & (sb_state == SBIDLE); // & (sbcs_reg[14:12] == 3'b000);
assign sbcs_wren = (dmi_reg_addr == 7'h38) & dmi_reg_en & dmi_reg_wr_en & (sb_state == SBIDLE);
assign sbcs_sbbusyerror_wren = (sbcs_wren & dmi_reg_wdata[22]) |
((sb_state != SBIDLE) & dmi_reg_en & ((dmi_reg_addr == 7'h39) | (dmi_reg_addr == 7'h3c) | (dmi_reg_addr == 7'h3d)));
(sbcs_reg[21] & dmi_reg_en & ((dmi_reg_wr_en & (dmi_reg_addr == 7'h39)) | (dmi_reg_addr == 7'h3c) | (dmi_reg_addr == 7'h3d)));
assign sbcs_sbbusyerror_din = ~(sbcs_wren & dmi_reg_wdata[22]); // Clear when writing one
rvdffs #(1) sbcs_sbbusyerror_reg (.din(sbcs_sbbusyerror_din), .dout(sbcs_reg[22]), .en(sbcs_sbbusyerror_wren), .rst_l(dbg_dm_rst_l), .clk(sb_free_clk));
rvdffs #(1) sbcs_sbbusy_reg (.din(sbcs_sbbusy_din), .dout(sbcs_reg[21]), .en(sbcs_sbbusy_wren), .rst_l(dbg_dm_rst_l), .clk(sb_free_clk));
rvdffs #(1) sbcs_sbreadonaddr_reg (.din(dmi_reg_wdata[20]), .dout(sbcs_reg[20]), .en(sbcs_wren), .rst_l(dbg_dm_rst_l), .clk(sb_free_clk));
rvdffs #(5) sbcs_misc_reg (.din(dmi_reg_wdata[19:15]), .dout(sbcs_reg[19:15]), .en(sbcs_wren), .rst_l(dbg_dm_rst_l), .clk(sb_free_clk));
rvdffs #(5) sbcs_misc_reg (.din({dmi_reg_wdata[19],~dmi_reg_wdata[18],dmi_reg_wdata[17:15]}),
.dout(sbcs_reg_int[19:15]), .en(sbcs_wren), .rst_l(dbg_dm_rst_l), .clk(sb_free_clk));
rvdffs #(3) sbcs_error_reg (.din(sbcs_sberror_din[2:0]), .dout(sbcs_reg[14:12]), .en(sbcs_sberror_wren), .rst_l(dbg_dm_rst_l), .clk(sb_free_clk));
assign sbcs_unaligned = ((sbcs_reg[19:17] == 3'b001) & sbaddress0_reg[0]) |
@ -296,6 +336,7 @@ import el2_pkg::*;
assign dmcontrol_wren = (dmi_reg_addr == 7'h10) & dmi_reg_en & dmi_reg_wr_en;
assign dmcontrol_reg[29] = '0;
assign dmcontrol_reg[27:2] = '0;
assign resumereq = dmcontrol_reg[30] & ~dmcontrol_reg[31] & dmcontrol_wren_Q;
rvdffs #(4) dmcontrolff (.din({dmi_reg_wdata[31:30],dmi_reg_wdata[28],dmi_reg_wdata[1]}), .dout({dmcontrol_reg[31:30], dmcontrol_reg[28], dmcontrol_reg[1]}), .en(dmcontrol_wren), .rst_l(dbg_dm_rst_l), .clk(dbg_free_clk));
rvdffs #(1) dmcontrol_dmactive_ff (.din(dmi_reg_wdata[0]), .dout(dmcontrol_reg[0]), .en(dmcontrol_wren), .rst_l(dbg_rst_l), .clk(dbg_free_clk));
rvdff #(1) dmcontrol_wrenff(.din(dmcontrol_wren), .dout(dmcontrol_wren_Q), .rst_l(dbg_dm_rst_l), .clk(dbg_free_clk));
@ -303,6 +344,7 @@ import el2_pkg::*;
// dmstatus register bits that are implemented
// [19:18]-havereset,[17:16]-resume ack, [9:8]-halted, [3:0]-version
// rest all the bits are zeroed out
//assign dmstatus_wren = (dmi_reg_addr[31:0] == 32'h11) & dmi_reg_en;
assign dmstatus_reg[31:20] = '0;
assign dmstatus_reg[19:18] = {2{dmstatus_havereset}};
assign dmstatus_reg[15:14] = '0;
@ -314,18 +356,18 @@ import el2_pkg::*;
assign dmstatus_reg[9:8] = {2{dmstatus_halted}};
assign dmstatus_reg[3:0] = 4'h2;
assign dmstatus_resumeack_wren = ((dbg_state == RESUMING) & dec_tlu_resume_ack) | (dmstatus_resumeack & ~dmcontrol_reg[30]);
assign dmstatus_resumeack_wren = ((dbg_state == RESUMING) & dec_tlu_resume_ack) | (dmstatus_resumeack & resumereq & dmstatus_halted);
assign dmstatus_resumeack_din = (dbg_state == RESUMING) & dec_tlu_resume_ack;
assign dmstatus_havereset_wren = (dmi_reg_addr == 7'h10) & dmi_reg_wdata[1] & dmi_reg_en & dmi_reg_wr_en;
assign dmstatus_havereset_rst = (dmi_reg_addr == 7'h10) & dmi_reg_wdata[28] & dmi_reg_en & dmi_reg_wr_en;
assign dmstatus_haveresetn_wren = (dmi_reg_addr == 7'h10) & dmi_reg_wdata[28] & dmi_reg_en & dmi_reg_wr_en & dmcontrol_reg[0]; // clear the havereset
assign dmstatus_havereset = ~dmstatus_haveresetn;
assign dmstatus_unavail = dmcontrol_reg[1] | ~rst_l;
assign dmstatus_running = ~(dmstatus_unavail | dmstatus_halted);
rvdffs #(1) dmstatus_resumeack_reg (.din(dmstatus_resumeack_din), .dout(dmstatus_resumeack), .en(dmstatus_resumeack_wren), .rst_l(dbg_dm_rst_l), .clk(dbg_free_clk));
rvdff #(1) dmstatus_halted_reg (.din(dec_tlu_dbg_halted & ~dec_tlu_mpc_halted_only), .dout(dmstatus_halted), .rst_l(dbg_dm_rst_l), .clk(dbg_free_clk));
rvdffsc #(1) dmstatus_havereset_reg (.din(1'b1), .dout(dmstatus_havereset), .en(dmstatus_havereset_wren), .clear(dmstatus_havereset_rst), .rst_l(dbg_dm_rst_l), .clk(dbg_free_clk));
rvdffs #(1) dmstatus_haveresetn_reg (.din(1'b1), .dout(dmstatus_haveresetn), .en(dmstatus_haveresetn_wren), .rst_l(rst_l), .clk(dbg_free_clk));
// haltsum0 register
assign haltsum0_reg[31:1] = '0;
@ -337,54 +379,76 @@ import el2_pkg::*;
assign abstractcs_reg[11] = '0;
assign abstractcs_reg[7:4] = '0;
assign abstractcs_reg[3:0] = 4'h2; // One data register
assign abstractcs_error_sel0 = abstractcs_reg[12] & dmi_reg_en & ((dmi_reg_wr_en & ( (dmi_reg_addr == 7'h16) | (dmi_reg_addr == 7'h17))) | (dmi_reg_addr == 7'h4));
assign abstractcs_error_sel1 = dmi_reg_en & dmi_reg_wr_en & (dmi_reg_addr == 7'h17) & ~((dmi_reg_wdata[31:24] == 8'b0) | (dmi_reg_wdata[31:24] == 8'h2));
assign abstractcs_error_sel2 = core_dbg_cmd_done & core_dbg_cmd_fail;
assign abstractcs_error_sel3 = dmi_reg_en & dmi_reg_wr_en & (dmi_reg_addr == 7'h17) & ~dmstatus_reg[9]; //(dbg_state != HALTED);
assign abstractcs_error_sel4 = (dmi_reg_addr == 7'h17) & dmi_reg_en & dmi_reg_wr_en &
((dmi_reg_wdata[22:20] != 3'b010) | ((dmi_reg_wdata[31:24] == 8'h2) && (|data1_reg[1:0]))); // Only word size is allowed
assign abstractcs_error_sel5 = (dmi_reg_addr == 7'h16) & dmi_reg_en & dmi_reg_wr_en;
assign abstractcs_error_sel0 = abstractcs_reg[12] & ~(|abstractcs_reg[10:8]) & dmi_reg_en & ((dmi_reg_wr_en & ((dmi_reg_addr == 7'h16) | (dmi_reg_addr == 7'h17)) | (dmi_reg_addr == 7'h18)) |
(dmi_reg_addr == 7'h4) | (dmi_reg_addr == 7'h5));
assign abstractcs_error_sel1 = execute_command & ~(|abstractcs_reg[10:8]) &
((~((command_reg[31:24] == 8'b0) | (command_reg[31:24] == 8'h2))) | // Illegal command
(((command_reg[22:20] == 3'b011) | (command_reg[22])) & (command_reg[31:24] == 8'h2)) | // Illegal abstract memory size (can't be DW or higher)
((command_reg[22:20] != 3'b010) & ((command_reg[31:24] == 8'h0) & command_reg[17])) | // Illegal abstract reg size
((command_reg[31:24] == 8'h0) & command_reg[18])); //postexec for abstract register access
assign abstractcs_error_sel2 = ((core_dbg_cmd_done & core_dbg_cmd_fail) | // exception from core
(execute_command & (command_reg[31:24] == 8'h0) & // unimplemented regs
(((command_reg[15:12] == 4'h1) & (command_reg[11:5] != 0)) | (command_reg[15:13] != 0)))) & ~(|abstractcs_reg[10:8]);
assign abstractcs_error_sel3 = execute_command & (dbg_state != HALTED) & ~(|abstractcs_reg[10:8]);
assign abstractcs_error_sel4 = dbg_sb_bus_error & dbg_bus_clk_en & ~(|abstractcs_reg[10:8]);// sb bus error for abstract memory command
assign abstractcs_error_sel5 = execute_command & (command_reg[31:24] == 8'h2) & ~(|abstractcs_reg[10:8]) &
(((command_reg[22:20] == 3'b001) & data1_reg[0]) | ((command_reg[22:20] == 3'b010) & (|data1_reg[1:0]))); //Unaligned address for abstract memory
assign abstractcs_error_sel6 = (dmi_reg_addr == 7'h16) & dmi_reg_en & dmi_reg_wr_en;
assign abstractcs_error_selor = abstractcs_error_sel0 | abstractcs_error_sel1 | abstractcs_error_sel2 | abstractcs_error_sel3 | abstractcs_error_sel4 | abstractcs_error_sel5;
assign abstractcs_error_din[2:0] = ({3{abstractcs_error_sel0}} & 3'b001) | // writing command or abstractcs while a command was executing. Or accessing data0
({3{abstractcs_error_sel1}} & 3'b010) | // writing a non-zero command to cmd field of command
({3{abstractcs_error_sel2}} & 3'b011) | // exception while running command
({3{abstractcs_error_sel3}} & 3'b100) | // writing a comnand when not in the halted state
({3{abstractcs_error_sel4}} & 3'b111) | // unaligned abstract memory command
({3{abstractcs_error_sel5}} & ~dmi_reg_wdata[10:8] & abstractcs_reg[10:8]) | // W1C
({3{~abstractcs_error_selor}} & abstractcs_reg[10:8]); // hold
assign abstractcs_error_din[2:0] = abstractcs_error_sel0 ? 3'b001 : // writing command or abstractcs while a command was executing. Or accessing data0
abstractcs_error_sel1 ? 3'b010 : // writing a illegal command type to cmd field of command
abstractcs_error_sel2 ? 3'b011 : // exception while running command
abstractcs_error_sel3 ? 3'b100 : // writing a comnand when not in the halted state
abstractcs_error_sel4 ? 3'b101 : // Bus error
abstractcs_error_sel5 ? 3'b111 : // unaligned or illegal size abstract memory command
abstractcs_error_sel6 ? (~dmi_reg_wdata[10:8] & abstractcs_reg[10:8]) : //W1C
abstractcs_reg[10:8]; //hold
rvdffs #(1) dmabstractcs_busy_reg (.din(abstractcs_busy_din), .dout(abstractcs_reg[12]), .en(abstractcs_busy_wren), .rst_l(dbg_dm_rst_l), .clk(dbg_free_clk));
rvdff #(3) dmabstractcs_error_reg (.din(abstractcs_error_din[2:0]), .dout(abstractcs_reg[10:8]), .rst_l(dbg_dm_rst_l), .clk(dbg_free_clk));
// abstract auto reg
assign abstractauto_reg_wren = dmi_reg_en & dmi_reg_wr_en & (dmi_reg_addr == 7'h18) & ~abstractcs_reg[12];
rvdffs #(2) dbg_abstractauto_reg (.*, .din(dmi_reg_wdata[1:0]), .dout(abstractauto_reg[1:0]), .en(abstractauto_reg_wren), .rst_l(dbg_dm_rst_l), .clk(dbg_free_clk));
// command register - implemented all the bits in this register
// command[16] = 1: write, 0: read
// Size - 2, Bits Not implemented: 23 (aamvirtual), 19-autoincrement, 18-postexec, 17-transfer
assign command_wren = (dmi_reg_addr == 7'h17) & dmi_reg_en & dmi_reg_wr_en & (dbg_state == HALTED);
assign command_din[31:0] = {dmi_reg_wdata[31:24],1'b0,dmi_reg_wdata[22:20],3'b0,dmi_reg_wdata[16:0]};
rvdffe #(32) dmcommand_reg (.*, .din(command_din[31:0]), .dout(command_reg[31:0]), .en(command_wren), .rst_l(dbg_dm_rst_l));
assign execute_command_ns = command_wren |
(dmi_reg_en & ~abstractcs_reg[12] & (((dmi_reg_addr == 7'h4) & abstractauto_reg[0]) | ((dmi_reg_addr == 7'h5) & abstractauto_reg[1])));
assign command_wren = (dmi_reg_addr == 7'h17) & dmi_reg_en & dmi_reg_wr_en;
assign command_regno_wren = command_wren | ((command_reg[31:24] == 8'h0) & command_reg[19] & (dbg_state == CMD_DONE) & ~(|abstractcs_reg[10:8])); // aarpostincrement
assign command_postexec_din = (dmi_reg_wdata[31:24] == 8'h0) & dmi_reg_wdata[18];
assign command_transfer_din = (dmi_reg_wdata[31:24] == 8'h0) & dmi_reg_wdata[17];
assign command_din[31:16] = {dmi_reg_wdata[31:24],1'b0,dmi_reg_wdata[22:19],command_postexec_din,command_transfer_din, dmi_reg_wdata[16]};
assign command_din[15:0] = command_wren ? dmi_reg_wdata[15:0] : dbg_cmd_next_addr[15:0];
rvdff #(1) execute_commandff (.*, .din(execute_command_ns), .dout(execute_command), .clk(dbg_free_clk), .rst_l(dbg_dm_rst_l));
rvdffe #(16) dmcommand_reg (.*, .din(command_din[31:16]), .dout(command_reg[31:16]), .en(command_wren), .rst_l(dbg_dm_rst_l));
rvdffe #(16) dmcommand_regno_reg (.*, .din(command_din[15:0]), .dout(command_reg[15:0]), .en(command_regno_wren), .rst_l(dbg_dm_rst_l));
// data0 reg
assign data0_reg_wren0 = (dmi_reg_en & dmi_reg_wr_en & (dmi_reg_addr == 7'h4) & (dbg_state == HALTED));
assign data0_reg_wren1 = core_dbg_cmd_done & (dbg_state == CMD_WAIT) & ~command_reg[16];
assign data0_reg_wren = data0_reg_wren0 | data0_reg_wren1;
assign data0_reg_wren0 = (dmi_reg_en & dmi_reg_wr_en & (dmi_reg_addr == 7'h4) & (dbg_state == HALTED) & ~abstractcs_reg[12]);
assign data0_reg_wren1 = core_dbg_cmd_done & (dbg_state == CORE_CMD_WAIT) & ~command_reg[16];
assign data0_reg_wren = data0_reg_wren0 | data0_reg_wren1 | data0_reg_wren2;
assign data0_din[31:0] = ({32{data0_reg_wren0}} & dmi_reg_wdata[31:0]) |
({32{data0_reg_wren1}} & core_dbg_rddata[31:0]);
({32{data0_reg_wren1}} & core_dbg_rddata[31:0]) |
({32{data0_reg_wren2}} & sb_bus_rdata[31:0]);
rvdffe #(32) dbg_data0_reg (.*, .din(data0_din[31:0]), .dout(data0_reg[31:0]), .en(data0_reg_wren), .rst_l(dbg_dm_rst_l));
// data 1
assign data1_reg_wren0 = (dmi_reg_en & dmi_reg_wr_en & (dmi_reg_addr == 7'h5) & (dbg_state == HALTED));
assign data1_reg_wren = data1_reg_wren0;
assign data1_reg_wren0 = (dmi_reg_en & dmi_reg_wr_en & (dmi_reg_addr == 7'h5) & (dbg_state == HALTED) & ~abstractcs_reg[12]);
assign data1_reg_wren1 = (dbg_state == CMD_DONE) & (command_reg[31:24] == 8'h2) & command_reg[19] & ~(|abstractcs_reg[10:8]); // aampostincrement
assign data1_reg_wren = data1_reg_wren0 | data1_reg_wren1;
assign data1_din[31:0] = ({32{data1_reg_wren0}} & dmi_reg_wdata[31:0]);
assign data1_din[31:0] = ({32{data1_reg_wren0}} & dmi_reg_wdata[31:0]) |
({32{data1_reg_wren1}} & dbg_cmd_next_addr[31:0]);
rvdffe #(32) dbg_data1_reg (.*, .din(data1_din[31:0]), .dout(data1_reg[31:0]), .en(data1_reg_wren), .rst_l(dbg_dm_rst_l));
rvdffs #(1) sb_abmem_cmd_doneff (.din(sb_abmem_cmd_done_in), .dout(sb_abmem_cmd_done), .en(sb_abmem_cmd_done_en), .clk(dbg_free_clk), .rst_l(dbg_dm_rst_l), .*);
rvdffs #(1) sb_abmem_data_doneff (.din(sb_abmem_data_done_in), .dout(sb_abmem_data_done), .en(sb_abmem_data_done_en), .clk(dbg_free_clk), .rst_l(dbg_dm_rst_l), .*);
// FSM to control the debug mode entry, command send/recieve, and Resume flow.
always_comb begin
@ -392,45 +456,74 @@ import el2_pkg::*;
dbg_state_en = 1'b0;
abstractcs_busy_wren = 1'b0;
abstractcs_busy_din = 1'b0;
dbg_halt_req = dmcontrol_wren_Q & dmcontrol_reg[31] & ~dmcontrol_reg[1]; // single pulse output to the core. Need to drive every time this register is written since core might be halted due to MPC
dbg_halt_req = dmcontrol_wren_Q & dmcontrol_reg[31]; // single pulse output to the core. Need to drive every time this register is written since core might be halted due to MPC
dbg_resume_req = 1'b0; // single pulse output to the core
dbg_sb_bus_error = 1'b0;
data0_reg_wren2 = 1'b0;
sb_abmem_cmd_done_in = 1'b0;
sb_abmem_data_done_in = 1'b0;
sb_abmem_cmd_done_en = 1'b0;
sb_abmem_data_done_en = 1'b0;
case (dbg_state)
IDLE: begin
dbg_nxtstate = (dmstatus_reg[9] | dec_tlu_mpc_halted_only) ? HALTED : HALTING; // initiate the halt command to the core
dbg_state_en = ((dmcontrol_reg[31] & ~dec_tlu_debug_mode) | dmstatus_reg[9] | dec_tlu_mpc_halted_only) & ~dmcontrol_reg[1]; // when the jtag writes the halt bit in the DM register, OR when the status indicates H
dbg_halt_req = dmcontrol_reg[31] & ~dmcontrol_reg[1]; // only when jtag has written the halt_req bit in the control. Removed debug mode qualification during MPC changes
dbg_state_en = dmcontrol_reg[31] | dmstatus_reg[9] | dec_tlu_mpc_halted_only; // when the jtag writes the halt bit in the DM register, OR when the status indicates H
dbg_halt_req = dmcontrol_reg[31]; // only when jtag has written the halt_req bit in the control. Removed debug mode qualification during MPC changes
end
HALTING : begin
dbg_nxtstate = dmcontrol_reg[1] ? IDLE : HALTED; // Goto HALTED once the core sends an ACK
dbg_state_en = dmstatus_reg[9] | dmcontrol_reg[1]; // core indicates halted
dbg_nxtstate = HALTED; // Goto HALTED once the core sends an ACK
dbg_state_en = dmstatus_reg[9] | dec_tlu_mpc_halted_only; // core indicates halted
end
HALTED: begin
// wait for halted to go away before send to resume. Else start of new command
dbg_nxtstate = (dmstatus_reg[9] & ~dmcontrol_reg[1]) ? ((dmcontrol_reg[30] & ~dmcontrol_reg[31]) ? RESUMING : CMD_START) :
dbg_nxtstate = dmstatus_reg[9] ? (resumereq ? RESUMING : (((command_reg[31:24] == 8'h2) & abmem_addr_external) ? SB_CMD_START : CORE_CMD_START)) :
(dmcontrol_reg[31] ? HALTING : IDLE); // This is MPC halted case
dbg_state_en = (dmstatus_reg[9] & dmcontrol_reg[30] & ~dmcontrol_reg[31] & dmcontrol_wren_Q) | command_wren | dmcontrol_reg[1] | ~(dmstatus_reg[9] | dec_tlu_mpc_halted_only); // need to be exclusive ???
abstractcs_busy_wren = dbg_state_en & (dbg_nxtstate == CMD_START); // write busy when a new command was written by jtag
dbg_state_en = (dmstatus_reg[9] & resumereq) | execute_command | ~(dmstatus_reg[9] | dec_tlu_mpc_halted_only);
abstractcs_busy_wren = dbg_state_en & ((dbg_nxtstate == CORE_CMD_START) | (dbg_nxtstate == SB_CMD_START)); // write busy when a new command was written by jtag
abstractcs_busy_din = 1'b1;
dbg_resume_req = dbg_state_en & (dbg_nxtstate == RESUMING); // single cycle pulse to core if resuming
end
CMD_START: begin
dbg_nxtstate = dmcontrol_reg[1] ? IDLE : (|abstractcs_reg[10:8]) ? CMD_DONE : CMD_WAIT; // new command sent to the core
dbg_state_en = dbg_cmd_valid | (|abstractcs_reg[10:8]) | dmcontrol_reg[1];
CORE_CMD_START: begin
// Don't execute the command if cmderror or transfer=0 for abstract register access
dbg_nxtstate = ((|abstractcs_reg[10:8]) | ((command_reg[31:24] == 8'h0) & ~command_reg[17])) ? CMD_DONE : CORE_CMD_WAIT; // new command sent to the core
dbg_state_en = dbg_cmd_valid | (|abstractcs_reg[10:8]) | ((command_reg[31:24] == 8'h0) & ~command_reg[17]);
end
CMD_WAIT: begin
dbg_nxtstate = dmcontrol_reg[1] ? IDLE : CMD_DONE;
dbg_state_en = core_dbg_cmd_done | dmcontrol_reg[1]; // go to done state for one cycle after completing current command
CORE_CMD_WAIT: begin
dbg_nxtstate = CMD_DONE;
dbg_state_en = core_dbg_cmd_done; // go to done state for one cycle after completing current command
end
SB_CMD_START: begin
dbg_nxtstate = (|abstractcs_reg[10:8]) ? CMD_DONE : SB_CMD_SEND;
dbg_state_en = (dbg_bus_clk_en & ~sb_cmd_pending) | (|abstractcs_reg[10:8]);
end
SB_CMD_SEND: begin
sb_abmem_cmd_done_in = 1'b1;
sb_abmem_data_done_in= 1'b1;
sb_abmem_cmd_done_en = (sb_bus_cmd_read | sb_bus_cmd_write_addr) & dbg_bus_clk_en;
sb_abmem_data_done_en= (sb_bus_cmd_read | sb_bus_cmd_write_data) & dbg_bus_clk_en;
dbg_nxtstate = SB_CMD_RESP;
dbg_state_en = (sb_abmem_cmd_done | sb_abmem_cmd_done_en) & (sb_abmem_data_done | sb_abmem_data_done_en) & dbg_bus_clk_en;
end
SB_CMD_RESP: begin
dbg_nxtstate = CMD_DONE;
dbg_state_en = (sb_bus_rsp_read | sb_bus_rsp_write) & dbg_bus_clk_en;
dbg_sb_bus_error = (sb_bus_rsp_read | sb_bus_rsp_write) & sb_bus_rsp_error & dbg_bus_clk_en;
data0_reg_wren2 = dbg_state_en & ~sb_abmem_cmd_write & ~dbg_sb_bus_error;
end
CMD_DONE: begin
dbg_nxtstate = dmcontrol_reg[1] ? IDLE : HALTED;
dbg_nxtstate = HALTED;
dbg_state_en = 1'b1;
abstractcs_busy_wren = dbg_state_en; // remove the busy bit from the abstracts ( bit 12 )
abstractcs_busy_din = 1'b0;
sb_abmem_cmd_done_in = 1'b0;
sb_abmem_data_done_in= 1'b0;
sb_abmem_cmd_done_en = 1'b1;
sb_abmem_data_done_en= 1'b1;
end
RESUMING : begin
dbg_nxtstate = IDLE;
dbg_state_en = dmstatus_reg[17] | dmcontrol_reg[1]; // resume ack has been updated in the dmstatus register
dbg_state_en = dmstatus_reg[17]; // resume ack has been updated in the dmstatus register
end
default : begin
dbg_nxtstate = IDLE;
@ -439,16 +532,23 @@ import el2_pkg::*;
abstractcs_busy_din = 1'b0;
dbg_halt_req = 1'b0; // single pulse output to the core
dbg_resume_req = 1'b0; // single pulse output to the core
dbg_sb_bus_error = 1'b0;
data0_reg_wren2 = 1'b0;
sb_abmem_cmd_done_in = 1'b0;
sb_abmem_data_done_in = 1'b0;
sb_abmem_cmd_done_en = 1'b0;
sb_abmem_data_done_en = 1'b0;
end
endcase
end // always_comb begin
assign dmi_reg_rdata_din[31:0] = ({32{dmi_reg_addr == 7'h4}} & data0_reg[31:0]) |
({32{dmi_reg_addr == 7'h5}} & data1_reg[31:0]) |
({32{dmi_reg_addr == 7'h10}} & dmcontrol_reg[31:0]) |
({32{dmi_reg_addr == 7'h10}} & {2'b0,dmcontrol_reg[29],1'b0,dmcontrol_reg[27:0]}) | // Read0 to Write only bits
({32{dmi_reg_addr == 7'h11}} & dmstatus_reg[31:0]) |
({32{dmi_reg_addr == 7'h16}} & abstractcs_reg[31:0]) |
({32{dmi_reg_addr == 7'h17}} & command_reg[31:0]) |
({32{dmi_reg_addr == 7'h18}} & {30'h0,abstractauto_reg[1:0]}) |
({32{dmi_reg_addr == 7'h40}} & haltsum0_reg[31:0]) |
({32{dmi_reg_addr == 7'h38}} & sbcs_reg[31:0]) |
({32{dmi_reg_addr == 7'h39}} & sbaddress0_reg[31:0]) |
@ -457,19 +557,34 @@ import el2_pkg::*;
rvdffs #($bits(state_t)) dbg_state_reg (.din(dbg_nxtstate), .dout({dbg_state}), .en(dbg_state_en), .rst_l(dbg_dm_rst_l & rst_l), .clk(dbg_free_clk));
// Ack will use the power on reset only otherwise there won't be any ack until dmactive is 1
rvdffs #(32) dmi_rddata_reg (.din(dmi_reg_rdata_din[31:0]), .dout(dmi_reg_rdata[31:0]), .en(dmi_reg_en), .rst_l(dbg_dm_rst_l), .clk(dbg_free_clk));
rvdffe #(32) dmi_rddata_reg (.din(dmi_reg_rdata_din[31:0]), .dout(dmi_reg_rdata[31:0]), .en(dmi_reg_en), .rst_l(dbg_dm_rst_l), .clk(clk), .*);
assign abmem_addr[31:0] = data1_reg[31:0];
assign abmem_addr_core_local = (abmem_addr_in_dccm_region | abmem_addr_in_iccm_region | abmem_addr_in_pic_region);
assign abmem_addr_external = ~abmem_addr_core_local;
assign abmem_addr_in_dccm_region = (abmem_addr[31:28] == pt.DCCM_REGION) & pt.DCCM_ENABLE;
assign abmem_addr_in_iccm_region = (abmem_addr[31:28] == pt.ICCM_REGION) & pt.ICCM_ENABLE;
assign abmem_addr_in_pic_region = (abmem_addr[31:28] == pt.PIC_REGION);
// interface for the core
assign dbg_cmd_addr[31:0] = (command_reg[31:24] == 8'h2) ? {data1_reg[31:2],2'b0} : {20'b0, command_reg[11:0]}; // Only word addresses for abstract memory
assign dbg_cmd_addr[31:0] = (command_reg[31:24] == 8'h2) ? data1_reg[31:0] : {20'b0, command_reg[11:0]};
assign dbg_cmd_wrdata[31:0] = data0_reg[31:0];
assign dbg_cmd_valid = (dbg_state == CMD_START) & ~(|abstractcs_reg[10:8]) & dma_dbg_ready;
assign dbg_cmd_valid = (dbg_state == CORE_CMD_START) & ~((|abstractcs_reg[10:8]) | ((command_reg[31:24] == 8'h0) & ~command_reg[17]) | ((command_reg[31:24] == 8'h2) & abmem_addr_external)) & dma_dbg_ready;
assign dbg_cmd_write = command_reg[16];
assign dbg_cmd_type[1:0] = (command_reg[31:24] == 8'h2) ? 2'b10 : {1'b0, (command_reg[15:12] == 4'b0)};
assign dbg_cmd_size[1:0] = command_reg[21:20];
assign dbg_cmd_addr_incr[3:0] = (command_reg[31:24] == 8'h2) ? (4'h1 << sb_abmem_cmd_size[1:0]) : 4'h1;
assign dbg_cmd_curr_addr[31:0] = (command_reg[31:24] == 8'h2) ? data1_reg[31:0] : {16'b0, command_reg[15:0]};
assign dbg_cmd_next_addr[31:0] = dbg_cmd_curr_addr[31:0] + {28'h0,dbg_cmd_addr_incr[3:0]};
// Ask DMA to stop taking bus trxns since debug request is done
assign dbg_dma_bubble = ((dbg_state == CMD_START) & ~(|abstractcs_reg[10:8])) | (dbg_state == CMD_WAIT);
assign dbg_dma_bubble = ((dbg_state == CORE_CMD_START) & ~(|abstractcs_reg[10:8])) | (dbg_state == CORE_CMD_WAIT);
assign sb_cmd_pending = (sb_state == CMD_RD) | (sb_state == CMD_WR) | (sb_state == CMD_WR_ADDR) | (sb_state == CMD_WR_DATA) | (sb_state == RSP_RD) | (sb_state == RSP_WR);
assign sb_abmem_cmd_pending = (dbg_state == SB_CMD_START) | (dbg_state == SB_CMD_SEND) | (dbg_state== SB_CMD_RESP);
// system bus FSM
always_comb begin
@ -483,7 +598,7 @@ import el2_pkg::*;
case (sb_state)
SBIDLE: begin
sb_nxtstate = sbdata0wr_access ? WAIT_WR : WAIT_RD;
sb_state_en = sbdata0wr_access | sbreadondata_access | sbreadonaddr_access;
sb_state_en = (sbdata0wr_access | sbreadondata_access | sbreadonaddr_access) & ~(|sbcs_reg[14:12]) & ~sbcs_reg[22];
sbcs_sbbusy_wren = sb_state_en; // set the single read bit if it is a singlread command
sbcs_sbbusy_din = 1'b1;
sbcs_sberror_wren = sbcs_wren & (|dmi_reg_wdata[14:12]); // write to clear the error bits
@ -491,13 +606,13 @@ import el2_pkg::*;
end
WAIT_RD: begin
sb_nxtstate = (sbcs_unaligned | sbcs_illegal_size) ? DONE : CMD_RD;
sb_state_en = dbg_bus_clk_en | sbcs_unaligned | sbcs_illegal_size;
sb_state_en = (dbg_bus_clk_en & ~sb_abmem_cmd_pending) | sbcs_unaligned | sbcs_illegal_size;
sbcs_sberror_wren = sbcs_unaligned | sbcs_illegal_size;
sbcs_sberror_din[2:0] = sbcs_unaligned ? 3'b011 : 3'b100;
end
WAIT_WR: begin
sb_nxtstate = (sbcs_unaligned | sbcs_illegal_size) ? DONE : CMD_WR;
sb_state_en = dbg_bus_clk_en | sbcs_unaligned | sbcs_illegal_size;
sb_state_en = (dbg_bus_clk_en & ~sb_abmem_cmd_pending) | sbcs_unaligned | sbcs_illegal_size;
sbcs_sberror_wren = sbcs_unaligned | sbcs_illegal_size;
sbcs_sberror_din[2:0] = sbcs_unaligned ? 3'b011 : 3'b100;
end
@ -534,8 +649,7 @@ import el2_pkg::*;
sb_state_en = 1'b1;
sbcs_sbbusy_wren = 1'b1; // reset the single read
sbcs_sbbusy_din = 1'b0;
sbaddress0_reg_wren1 = sbcs_reg[16]; // auto increment was set. Update to new address after completing the current command
sbaddress0_reg_wren1 = sbcs_reg[16] & (sbcs_reg[14:12] == 3'b0); // auto increment was set and no error. Update to new address after completing the current command
end
default : begin
sb_nxtstate = SBIDLE;
@ -551,6 +665,29 @@ import el2_pkg::*;
rvdffs #($bits(sb_state_t)) sb_state_reg (.din(sb_nxtstate), .dout({sb_state}), .en(sb_state_en), .rst_l(dbg_dm_rst_l), .clk(sb_free_clk));
assign sb_abmem_cmd_write = command_reg[16];
assign sb_abmem_cmd_size[2:0] = {1'b0, command_reg[21:20]};
assign sb_abmem_cmd_addr[31:0] = abmem_addr[31:0];
assign sb_abmem_cmd_wdata[31:0] = data0_reg[31:0];
assign sb_cmd_size[2:0] = sbcs_reg[19:17];
assign sb_cmd_wdata[63:0] = {sbdata1_reg[31:0], sbdata0_reg[31:0]};
assign sb_cmd_addr[31:0] = sbaddress0_reg[31:0];
assign sb_abmem_cmd_awvalid = (dbg_state == SB_CMD_SEND) & sb_abmem_cmd_write & ~sb_abmem_cmd_done;
assign sb_abmem_cmd_wvalid = (dbg_state == SB_CMD_SEND) & sb_abmem_cmd_write & ~sb_abmem_data_done;
assign sb_abmem_cmd_arvalid = (dbg_state == SB_CMD_SEND) & ~sb_abmem_cmd_write & ~sb_abmem_cmd_done & ~sb_abmem_data_done;
assign sb_abmem_read_pend = (dbg_state == SB_CMD_RESP) & ~sb_abmem_cmd_write;
assign sb_cmd_awvalid = ((sb_state == CMD_WR) | (sb_state == CMD_WR_ADDR));
assign sb_cmd_wvalid = ((sb_state == CMD_WR) | (sb_state == CMD_WR_DATA));
assign sb_cmd_arvalid = (sb_state == CMD_RD);
assign sb_read_pend = (sb_state == RSP_RD);
assign sb_axi_size[2:0] = (sb_abmem_cmd_awvalid | sb_abmem_cmd_wvalid | sb_abmem_cmd_arvalid | sb_abmem_read_pend) ? sb_abmem_cmd_size[2:0] : sb_cmd_size[2:0];
assign sb_axi_addr[31:0] = (sb_abmem_cmd_awvalid | sb_abmem_cmd_wvalid | sb_abmem_cmd_arvalid | sb_abmem_read_pend) ? sb_abmem_cmd_addr[31:0] : sb_cmd_addr[31:0];
assign sb_axi_wrdata[63:0] = (sb_abmem_cmd_awvalid | sb_abmem_cmd_wvalid) ? {2{sb_abmem_cmd_wdata[31:0]}} : sb_cmd_wdata[63:0];
// Generic bus response signals
assign sb_bus_cmd_read = sb_axi_arvalid & sb_axi_arready;
assign sb_bus_cmd_write_addr = sb_axi_awvalid & sb_axi_awready;
@ -561,36 +698,36 @@ import el2_pkg::*;
assign sb_bus_rsp_error = (sb_bus_rsp_read & (|(sb_axi_rresp[1:0]))) | (sb_bus_rsp_write & (|(sb_axi_bresp[1:0])));
// AXI Request signals
assign sb_axi_awvalid = (sb_state == CMD_WR) | (sb_state == CMD_WR_ADDR);
assign sb_axi_awaddr[31:0] = sbaddress0_reg[31:0];
assign sb_axi_awvalid = sb_abmem_cmd_awvalid | sb_cmd_awvalid;
assign sb_axi_awaddr[31:0] = sb_axi_addr[31:0];
assign sb_axi_awid[pt.SB_BUS_TAG-1:0] = '0;
assign sb_axi_awsize[2:0] = sbcs_reg[19:17];
assign sb_axi_awprot[2:0] = '0;
assign sb_axi_awsize[2:0] = sb_axi_size[2:0];
assign sb_axi_awprot[2:0] = 3'b001;
assign sb_axi_awcache[3:0] = 4'b1111;
assign sb_axi_awregion[3:0] = sbaddress0_reg[31:28];
assign sb_axi_awregion[3:0] = sb_axi_addr[31:28];
assign sb_axi_awlen[7:0] = '0;
assign sb_axi_awburst[1:0] = 2'b01;
assign sb_axi_awqos[3:0] = '0;
assign sb_axi_awlock = '0;
assign sb_axi_wvalid = (sb_state == CMD_WR) | (sb_state == CMD_WR_DATA);
assign sb_axi_wdata[63:0] = ({64{(sbcs_reg[19:17] == 3'h0)}} & {8{sbdata0_reg[7:0]}}) |
({64{(sbcs_reg[19:17] == 3'h1)}} & {4{sbdata0_reg[15:0]}}) |
({64{(sbcs_reg[19:17] == 3'h2)}} & {2{sbdata0_reg[31:0]}}) |
({64{(sbcs_reg[19:17] == 3'h3)}} & {sbdata1_reg[31:0],sbdata0_reg[31:0]});
assign sb_axi_wstrb[7:0] = ({8{(sbcs_reg[19:17] == 3'h0)}} & (8'h1 << sbaddress0_reg[2:0])) |
({8{(sbcs_reg[19:17] == 3'h1)}} & (8'h3 << {sbaddress0_reg[2:1],1'b0})) |
({8{(sbcs_reg[19:17] == 3'h2)}} & (8'hf << {sbaddress0_reg[2],2'b0})) |
({8{(sbcs_reg[19:17] == 3'h3)}} & 8'hff);
assign sb_axi_wvalid = sb_abmem_cmd_wvalid | sb_cmd_wvalid;
assign sb_axi_wdata[63:0] = ({64{(sb_axi_size[2:0] == 3'h0)}} & {8{sb_axi_wrdata[7:0]}}) |
({64{(sb_axi_size[2:0] == 3'h1)}} & {4{sb_axi_wrdata[15:0]}}) |
({64{(sb_axi_size[2:0] == 3'h2)}} & {2{sb_axi_wrdata[31:0]}}) |
({64{(sb_axi_size[2:0] == 3'h3)}} & {sb_axi_wrdata[63:0]});
assign sb_axi_wstrb[7:0] = ({8{(sb_axi_size[2:0] == 3'h0)}} & (8'h1 << sb_axi_addr[2:0])) |
({8{(sb_axi_size[2:0] == 3'h1)}} & (8'h3 << {sb_axi_addr[2:1],1'b0})) |
({8{(sb_axi_size[2:0] == 3'h2)}} & (8'hf << {sb_axi_addr[2],2'b0})) |
({8{(sb_axi_size[2:0] == 3'h3)}} & 8'hff);
assign sb_axi_wlast = '1;
assign sb_axi_arvalid = (sb_state == CMD_RD);
assign sb_axi_araddr[31:0] = sbaddress0_reg[31:0];
assign sb_axi_arvalid = sb_abmem_cmd_arvalid | sb_cmd_arvalid;
assign sb_axi_araddr[31:0] = sb_axi_addr[31:0];
assign sb_axi_arid[pt.SB_BUS_TAG-1:0] = '0;
assign sb_axi_arsize[2:0] = sbcs_reg[19:17];
assign sb_axi_arprot[2:0] = '0;
assign sb_axi_arsize[2:0] = sb_axi_size[2:0];
assign sb_axi_arprot[2:0] = 3'b001;
assign sb_axi_arcache[3:0] = 4'b0;
assign sb_axi_arregion[3:0] = sbaddress0_reg[31:28];
assign sb_axi_arregion[3:0] = sb_axi_addr[31:28];
assign sb_axi_arlen[7:0] = '0;
assign sb_axi_arburst[1:0] = 2'b01;
assign sb_axi_arqos[3:0] = '0;
@ -600,14 +737,17 @@ import el2_pkg::*;
assign sb_axi_bready = 1'b1;
assign sb_axi_rready = 1'b1;
assign sb_bus_rdata[63:0] = ({64{sbcs_reg[19:17] == 3'h0}} & ((sb_axi_rdata[63:0] >> 8*sbaddress0_reg[2:0]) & 64'hff)) |
({64{sbcs_reg[19:17] == 3'h1}} & ((sb_axi_rdata[63:0] >> 16*sbaddress0_reg[2:1]) & 64'hffff)) |
({64{sbcs_reg[19:17] == 3'h2}} & ((sb_axi_rdata[63:0] >> 32*sbaddress0_reg[2]) & 64'hffff_ffff)) |
({64{sbcs_reg[19:17] == 3'h3}} & sb_axi_rdata[63:0]);
assign sb_bus_rdata[63:0] = ({64{sb_axi_size == 3'h0}} & ((sb_axi_rdata[63:0] >> 8*sb_axi_addr[2:0]) & 64'hff)) |
({64{sb_axi_size == 3'h1}} & ((sb_axi_rdata[63:0] >> 16*sb_axi_addr[2:1]) & 64'hffff)) |
({64{sb_axi_size == 3'h2}} & ((sb_axi_rdata[63:0] >> 32*sb_axi_addr[2]) & 64'hffff_ffff)) |
({64{sb_axi_size == 3'h3}} & sb_axi_rdata[63:0]);
`ifdef ASSERT_ON
`ifdef RV_ASSERT_ON
// assertion.
// when the resume_ack is asserted then the dec_tlu_dbg_halted should be 0
dm_check_resume_and_halted: assert property (@(posedge clk) disable iff(~rst_l) (~dec_tlu_resume_ack | ~dec_tlu_dbg_halted));
assert_b2b_haltreq: assert property (@(posedge clk) disable iff (~(rst_l)) (##1 dbg_halt_req |=> ~dbg_halt_req)); // One cycle delay to fix weird issue around reset
assert_halt_resume_onehot: assert #0 ($onehot0({dbg_halt_req, dbg_resume_req}));
`endif
endmodule

View File

@ -209,6 +209,7 @@ csr[ csr_mpmc ] = { csr_mpmc }
csr[ csr_mcpc ] = { csr_mcpc presync postsync }
csr[ csr_meicidpl ] = { csr_meicidpl }
csr[ csr_mcgc ] = { csr_mcgc }
csr[ csr_mcountinhibit] = { csr_mcountinhibit presync postsync }
csr[ csr_mfdc ] = { csr_mfdc presync postsync }
csr[ csr_dcsr ] = { csr_dcsr }
csr[ csr_dpc ] = { csr_dpc }

View File

@ -1,6 +1,146 @@
.definition
clz = [011000000000.....001.....0010011]
ctz = [011000000001.....001.....0010011]
pcnt = [011000000010.....001.....0010011]
sext_b = [011000000100.....001.....0010011]
sext_h = [011000000101.....001.....0010011]
slo = [0010000..........001.....0110011]
sro = [0010000..........101.....0110011]
sloi = [0010000..........001.....0010011]
sroi = [0010000..........101.....0010011]
min = [0000101..........100.....0110011]
max = [0000101..........101.....0110011]
minu = [0000101..........110.....0110011]
maxu = [0000101..........111.....0110011]
andn = [0100000..........111.....0110011]
orn = [0100000..........110.....0110011]
xnor = [0100000..........100.....0110011]
pack = [0000100..........100.....0110011]
packu = [0100100..........100.....0110011]
packh = [0000100..........111.....0110011]
rol = [0110000..........001.....0110011]
ror = [0110000..........101.....0110011]
rori = [0110000..........101.....0010011]
sh1add = [0010000..........010.....0110011]
sh2add = [0010000..........100.....0110011]
sh3add = [0010000..........110.....0110011]
sbset = [0010100..........001.....0110011]
sbclr = [0100100..........001.....0110011]
sbinv = [0110100..........001.....0110011]
sbext = [0100100..........101.....0110011]
sbseti = [0010100..........001.....0010011]
sbclri = [0100100..........001.....0010011]
sbinvi = [0110100..........001.....0010011]
sbexti = [0100100..........101.....0010011]
grev = [0110100..........101.....0110011]
#grevi = [01101............101.....0010011]
grevi0 = [011010000000.....101.....0010011]
grevi1 = [011010000001.....101.....0010011]
grevi2 = [011010000010.....101.....0010011]
grevi3 = [011010000011.....101.....0010011]
grevi4 = [011010000100.....101.....0010011]
grevi5 = [011010000101.....101.....0010011]
grevi6 = [011010000110.....101.....0010011]
grevi7 = [011010000111.....101.....0010011]
grevi8 = [011010001000.....101.....0010011]
grevi9 = [011010001001.....101.....0010011]
grevi10 = [011010001010.....101.....0010011]
grevi11 = [011010001011.....101.....0010011]
grevi12 = [011010001100.....101.....0010011]
grevi13 = [011010001101.....101.....0010011]
grevi14 = [011010001110.....101.....0010011]
grevi15 = [011010001111.....101.....0010011]
grevi16 = [011010010000.....101.....0010011]
grevi17 = [011010010001.....101.....0010011]
grevi18 = [011010010010.....101.....0010011]
grevi19 = [011010010011.....101.....0010011]
grevi20 = [011010010100.....101.....0010011]
grevi21 = [011010010101.....101.....0010011]
grevi22 = [011010010110.....101.....0010011]
grevi23 = [011010010111.....101.....0010011]
#grevi24 = [011010011000.....101.....0010011] # REV8
rev8 = [011010011000.....101.....0010011]
grevi25 = [011010011001.....101.....0010011]
grevi26 = [011010011010.....101.....0010011]
grevi27 = [011010011011.....101.....0010011]
grevi28 = [011010011100.....101.....0010011]
grevi29 = [011010011101.....101.....0010011]
grevi30 = [011010011110.....101.....0010011]
#grevi31 = [011010011111.....101.....0010011] # REV
rev = [011010011111.....101.....0010011]
gorc = [0010100..........101.....0110011]
#gorci = [00101............101.....0010011]
gorci0 = [001010000000.....101.....0010011]
gorci1 = [001010000001.....101.....0010011]
gorci2 = [001010000010.....101.....0010011]
gorci3 = [001010000011.....101.....0010011]
gorci4 = [001010000100.....101.....0010011]
gorci5 = [001010000101.....101.....0010011]
gorci6 = [001010000110.....101.....0010011]
#gorci7 = [001010000111.....101.....0010011] # ORC_B
orc_b = [001010000111.....101.....0010011]
gorci8 = [001010001000.....101.....0010011]
gorci9 = [001010001001.....101.....0010011]
gorci10 = [001010001010.....101.....0010011]
gorci11 = [001010001011.....101.....0010011]
gorci12 = [001010001100.....101.....0010011]
gorci13 = [001010001101.....101.....0010011]
gorci14 = [001010001110.....101.....0010011]
gorci15 = [001010001111.....101.....0010011]
#gorci16 = [001010010000.....101.....0010011] # ORC16
orc16 = [001010010000.....101.....0010011]
gorci17 = [001010010001.....101.....0010011]
gorci18 = [001010010010.....101.....0010011]
gorci19 = [001010010011.....101.....0010011]
gorci20 = [001010010100.....101.....0010011]
gorci21 = [001010010101.....101.....0010011]
gorci22 = [001010010110.....101.....0010011]
gorci23 = [001010010111.....101.....0010011]
gorci24 = [001010011000.....101.....0010011]
gorci25 = [001010011001.....101.....0010011]
gorci26 = [001010011010.....101.....0010011]
gorci27 = [001010011011.....101.....0010011]
gorci28 = [001010011100.....101.....0010011]
gorci29 = [001010011101.....101.....0010011]
gorci30 = [001010011110.....101.....0010011]
gorci31 = [001010011111.....101.....0010011]
shfl = [0000100..........001.....0110011]
shfli = [00001000.........001.....0010011]
unshfl = [0000100..........101.....0110011]
unshfli = [00001000.........101.....0010011]
bdep = [0100100..........110.....0110011]
bext = [0000100..........110.....0110011]
clmul = [0000101..........001.....0110011]
clmulr = [0000101..........010.....0110011]
clmulh = [0000101..........011.....0110011]
crc32_b = [011000010000.....001.....0010011]
crc32_h = [011000010001.....001.....0010011]
crc32_w = [011000010010.....001.....0010011]
crc32c_b = [011000011000.....001.....0010011]
crc32c_h = [011000011001.....001.....0010011]
crc32c_w = [011000011010.....001.....0010011]
bfp = [0100100..........111.....0110011]
add = [0000000..........000.....0110011]
addi = [.................000.....0010011]
@ -206,15 +346,133 @@ rv32i = {
rem
fence
fence_i
clz
ctz
pcnt
sext_b
sext_h
slo
sro
min
max
pack
packu
packh
rol
ror
zbb
sbset
sbclr
sbinv
sbext
zbs
bext
bdep
zbe
clmul
clmulh
clmulr
zbc
grev
gorc
shfl
unshfl
zbp
crc32_b
crc32_h
crc32_w
crc32c_b
crc32c_h
crc32c_w
zbr
bfp
zbf
sh1add
sh2add
sh3add
zba
pm_alu
}
.decode
rv32i[clz] = { alu zbb rs1 rd clz }
rv32i[ctz] = { alu zbb rs1 rd ctz }
rv32i[pcnt] = { alu zbb rs1 rd pcnt }
rv32i[sext_b] = { alu zbb rs1 rd sext_b}
rv32i[sext_h] = { alu zbb rs1 rd sext_h}
rv32i[slo] = { alu zbp rs1 rs2 rd slo }
rv32i[sro] = { alu zbp rs1 rs2 rd sro }
rv32i[sloi] = { alu zbp rs1 rd shimm5 slo }
rv32i[sroi] = { alu zbp rs1 rd shimm5 sro }
rv32i[min] = { alu zbb rs1 rs2 rd sub min }
rv32i[max] = { alu zbb rs1 rs2 rd sub max }
rv32i[minu] = { alu zbb rs1 rs2 rd unsign sub min }
rv32i[maxu] = { alu zbb rs1 rs2 rd unsign sub max }
rv32i[andn] = { alu zbb zbp rs1 rs2 rd land }
rv32i[orn] = { alu zbb zbp rs1 rs2 rd lor }
rv32i[xnor] = { alu zbb zbp rs1 rs2 rd lxor }
rv32i[pack] = { alu zbb zbp rs1 rs2 rd pack }
rv32i[packu] = { alu zbb zbp rs1 rs2 rd packu }
rv32i[packh] = { alu zbb zbp rs1 rs2 rd packh }
rv32i[rol] = { alu zbb zbp rs1 rs2 rd rol }
rv32i[ror] = { alu zbb zbp rs1 rs2 rd ror }
rv32i[rori] = { alu zbb zbp rs1 rd shimm5 ror }
rv32i[sbset] = { alu zbs rs1 rs2 rd sbset }
rv32i[sbclr] = { alu zbs rs1 rs2 rd sbclr }
rv32i[sbinv] = { alu zbs rs1 rs2 rd sbinv }
rv32i[sbext] = { alu zbs rs1 rs2 rd sbext }
rv32i[sbseti] = { alu zbs rs1 rd shimm5 sbset }
rv32i[sbclri] = { alu zbs rs1 rd shimm5 sbclr }
rv32i[sbinvi] = { alu zbs rs1 rd shimm5 sbinv }
rv32i[sbexti] = { alu zbs rs1 rd shimm5 sbext }
rv32i[sh1add] = { alu zba rs1 rs2 rd sh1add}
rv32i[sh2add] = { alu zba rs1 rs2 rd sh2add}
rv32i[sh3add] = { alu zba rs1 rs2 rd sh3add}
rv32i[mul] = { mul rs1 rs2 rd low }
rv32i[mulh] = { mul rs1 rs2 rd rs1_sign rs2_sign }
rv32i[mulhu] = { mul rs1 rs2 rd }
rv32i[mulhsu] = { mul rs1 rs2 rd rs1_sign }
rv32i[bext] = { mul zbe rs1 rs2 rd bext }
rv32i[bdep] = { mul zbe rs1 rs2 rd bdep }
rv32i[clmul] = { mul zbc rs1 rs2 rd clmul }
rv32i[clmulh] = { mul zbc rs1 rs2 rd clmulh}
rv32i[clmulr] = { mul zbc rs1 rs2 rd clmulr}
rv32i[crc32_b] = { mul zbr rs1 rd crc32_b}
rv32i[crc32_h] = { mul zbr rs1 rd crc32_h}
rv32i[crc32_w] = { mul zbr rs1 rd crc32_w}
rv32i[crc32c_b] = { mul zbr rs1 rd crc32c_b}
rv32i[crc32c_h] = { mul zbr rs1 rd crc32c_h}
rv32i[crc32c_w] = { mul zbr rs1 rd crc32c_w}
rv32i[bfp] = { mul zbf rs1 rs2 rd bfp }
rv32i[grev] = { mul zbp rs1 rs2 rd grev }
rv32i[grevi{0-23}] = { mul zbp rs1 rd shimm5 grev }
rv32i[grevi{25-30}] = { mul zbp rs1 rd shimm5 grev }
rv32i[rev8] = { alu zbb zbp rs1 rd shimm5 grev } # grevi24
rv32i[rev] = { alu zbb zbp rs1 rd shimm5 grev } # grevi31
rv32i[gorc] = { mul zbp rs1 rs2 rd gorc }
rv32i[gorci{0-6}] = { mul zbp rs1 rd shimm5 gorc }
rv32i[gorci{8-15}] = { mul zbp rs1 rd shimm5 gorc }
rv32i[gorci{17-31}] = { mul zbp rs1 rd shimm5 gorc }
rv32i[orc_b] = { alu zbb zbp rs1 rd shimm5 gorc } # gorci7
rv32i[orc16] = { alu zbb zbp rs1 rd shimm5 gorc } # gorci16
rv32i[shfl] = { mul zbp rs1 rs2 rd shfl }
rv32i[shfli] = { mul zbp rs1 rd shimm5 shfl }
rv32i[unshfl] = { mul zbp rs1 rs2 rd unshfl}
rv32i[unshfli] = { mul zbp rs1 rd shimm5 unshfl}
rv32i[div] = { div rs1 rs2 rd }
rv32i[divu] = { div rs1 rs2 rd unsign }
@ -321,3 +579,4 @@ rv32i[csrwi] = { alu rd csr_write csr_imm }
.end

View File

@ -1,5 +1,5 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 Western Digital Corporation or it's affiliates.
// Copyright 2020 Western Digital Corporation or its affiliates.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -33,18 +33,20 @@ import el2_pkg::*;
`include "el2_param.vh"
)
(
input logic clk,
input logic free_clk,
input logic active_clk,
input logic clk, // Clock only while core active. Through one clock header. For flops with second clock header built in. Connected to ACTIVE_L2CLK.
input logic active_clk, // Clock only while core active. Through two clock headers. For flops without second clock header built in.
input logic free_clk, // Clock always. Through two clock headers. For flops without second clock header built in.
input logic free_l2clk, // Clock always. Through one clock header. For flops with second header built in.
input logic lsu_fastint_stall_any, // needed by lsu for 2nd pass of dma with ecc correction, stall next cycle
// fast interrupt
output logic dec_extint_stall,
output logic dec_extint_stall, // Stall on external interrupt
output logic dec_i0_decode_d,
output logic dec_i0_decode_d, // Valid instruction at D-stage and not blocked
output logic dec_pause_state_cg, // to top for active state clock gating
output logic dec_tlu_core_empty,
input logic rst_l, // reset, active low
input logic [31:1] rst_vec, // reset vector, from core pins
@ -60,7 +62,7 @@ import el2_pkg::*;
output logic o_debug_mode_status, // Core to the PMU that core is in debug mode. When core is in debug mode, the PMU should refrain from sendng a halt or run request
input logic [31:4] core_id, // CORE ID
//
// external MPC halt/run interface
input logic mpc_debug_halt_req, // Async halt request
input logic mpc_debug_run_req, // Async run request
@ -118,9 +120,9 @@ import el2_pkg::*;
input logic ifu_i0_icaf, // icache access fault
input logic [1:0] ifu_i0_icaf_type,
input logic [1:0] ifu_i0_icaf_type, // icache access fault type
input logic ifu_i0_icaf_f1, // i0 has access fault on second fetch group
input logic ifu_i0_icaf_second, // i0 has access fault on second 2B of 4B inst
input logic ifu_i0_dbecc, // icache/iccm double-bit error
input logic lsu_idle_any, // lsu idle for halting
@ -129,6 +131,7 @@ import el2_pkg::*;
input logic [pt.BTB_ADDR_HI:pt.BTB_ADDR_LO] ifu_i0_bp_index, // BP index
input logic [pt.BHT_GHR_SIZE-1:0] ifu_i0_bp_fghr, // BP FGHR
input logic [pt.BTB_BTAG_SIZE-1:0] ifu_i0_bp_btag, // BP tag
input logic [$clog2(pt.BTB_SIZE)-1:0] ifu_i0_fa_index, // Fully associt btb index
input el2_lsu_error_pkt_t lsu_error_pkt_r, // LSU exception/error packet
input logic lsu_single_ecc_error_incr, // LSU inc SB error counter
@ -214,6 +217,8 @@ import el2_pkg::*;
input logic exu_i0_br_mp_r, // mispredict
input logic exu_i0_br_middle_r, // middle of bank
// branch info from pipe1 for errors or counter updates
input logic exu_i0_br_way_r, // way hit or repl
output logic dec_i0_rs1_en_d, // Qualify GPR RS1 data
@ -227,27 +232,29 @@ import el2_pkg::*;
output el2_alu_pkt_t i0_ap, // alu packet
output logic dec_i0_alu_decode_d, // schedule on D-stage alu
output logic dec_i0_branch_d, // Branch in D-stage
output logic dec_i0_select_pc_d, // select pc onto rs1 for jal's
output logic [31:1] dec_i0_pc_d, // pc's at decode
output logic [1:0] dec_i0_rs1_bypass_en_d, // rs1 bypass enable
output logic [1:0] dec_i0_rs2_bypass_en_d, // rs2 bypass enable
output logic [3:0] dec_i0_rs1_bypass_en_d, // rs1 bypass enable
output logic [3:0] dec_i0_rs2_bypass_en_d, // rs2 bypass enable
output logic [31:0] dec_i0_rs1_bypass_data_d, // rs1 bypass data
output logic [31:0] dec_i0_rs2_bypass_data_d, // rs2 bypass data
output logic [31:0] dec_i0_result_r, // Result R-stage
output el2_lsu_pkt_t lsu_p, // lsu packet
output logic dec_qual_lsu_d, // LSU instruction at D. Use to quiet LSU operands
output el2_mul_pkt_t mul_p, // mul packet
output el2_div_pkt_t div_p, // div packet
output logic dec_div_cancel, // cancel divide operation
output logic [11:0] dec_lsu_offset_d, // 12b offset for load/store addresses
output logic dec_csr_ren_d, // csr read enable
output logic dec_csr_ren_d, // CSR read enable
output logic [31:0] dec_csr_rddata_d, // CSR read data
output logic dec_tlu_flush_lower_r, // tlu flush due to late mp, exception, rfpc, or int
output logic dec_tlu_flush_lower_wb,
output logic [31:1] dec_tlu_flush_path_r, // tlu flush target
output logic dec_tlu_i0_kill_writeb_r, // I0 is flushed, don't writeback any results to arch state
output logic dec_tlu_fence_i_r, // flush is a fence_i rfnpc, flush icache
@ -266,6 +273,8 @@ import el2_pkg::*;
output logic [pt.BTB_ADDR_HI:pt.BTB_ADDR_LO] i0_predict_index_d, // DEC predict index
output logic [pt.BTB_BTAG_SIZE-1:0] i0_predict_btag_d, // DEC predict branch tag
output logic [$clog2(pt.BTB_SIZE)-1:0] dec_fa_error_index, // Fully associt btb error index
output logic dec_lsu_valid_raw_d,
output logic [31:0] dec_tlu_mrac_ff, // CSR for memory region control
@ -275,7 +284,7 @@ import el2_pkg::*;
input logic [15:0] ifu_i0_cinst, // 16b compressed instruction
output el2_trace_pkt_t rv_trace_pkt, // trace packet
output el2_trace_pkt_t trace_rv_trace_pkt, // trace packet
// feature disable from mfdc
output logic dec_tlu_external_ldfwd_disable, // disable external load forwarding
@ -291,11 +300,12 @@ import el2_pkg::*;
output logic dec_tlu_lsu_clk_override, // override load/store clock domain gating
output logic dec_tlu_bus_clk_override, // override bus clock domain gating
output logic dec_tlu_pic_clk_override, // override PIC clock domain gating
output logic dec_tlu_picio_clk_override, // override PICIO clock domain gating
output logic dec_tlu_dccm_clk_override, // override DCCM clock domain gating
output logic dec_tlu_icm_clk_override, // override ICCM clock domain gating
output logic dec_tlu_i0_commit_cmt, // committed i0 instruction
input logic scan_mode
input logic scan_mode // Flop scan mode control
);
@ -317,6 +327,7 @@ import el2_pkg::*;
logic [31:0] dec_i0_instr_d;
logic dec_tlu_trace_disable;
logic dec_tlu_pipelining_disable;
@ -328,7 +339,6 @@ import el2_pkg::*;
logic [31:0] dec_csr_wrdata_r; // csr write data at wb
logic [11:0] dec_csr_rdaddr_d; // read address for csr
logic [31:0] dec_csr_rddata_d; // csr read data at wb
logic dec_csr_legal_d; // csr indicates legal operation
logic dec_csr_wen_unq_d; // valid csr with write - for csr legal
@ -347,7 +357,7 @@ import el2_pkg::*;
logic dec_i0_icaf_d;
logic dec_i0_dbecc_d;
logic dec_i0_icaf_f1_d;
logic dec_i0_icaf_second_d;
logic [3:0] dec_i0_trigger_match_d;
logic dec_debug_fence_d;
logic dec_nonblock_load_wen;
@ -357,10 +367,10 @@ import el2_pkg::*;
logic [pt.BTB_ADDR_HI:pt.BTB_ADDR_LO] dec_i0_bp_index;
logic [pt.BHT_GHR_SIZE-1:0] dec_i0_bp_fghr;
logic [pt.BTB_BTAG_SIZE-1:0] dec_i0_bp_btag;
logic [$clog2(pt.BTB_SIZE)-1:0] dec_i0_bp_fa_index; // Fully associt btb index
logic [31:1] dec_tlu_i0_pc_r;
logic dec_tlu_i0_kill_writeb_wb;
logic dec_tlu_flush_lower_wb;
logic dec_tlu_i0_valid_r;
logic dec_pause_state;
@ -369,18 +379,17 @@ import el2_pkg::*;
logic dec_tlu_flush_extint; // Fast ext int started
logic [31:0] dec_i0_inst_wb1;
logic [31:1] dec_i0_pc_wb1;
logic [31:0] dec_i0_inst_wb;
logic [31:1] dec_i0_pc_wb;
logic dec_tlu_i0_valid_wb1, dec_tlu_int_valid_wb1;
logic [4:0] dec_tlu_exc_cause_wb1;
logic [31:0] dec_tlu_mtval_wb1;
logic dec_tlu_i0_exc_valid_wb1;
logic [4:0] div_waddr_wb;
logic dec_div_active;
logic dec_div_active; // non-block divide is active
logic dec_debug_valid_d;
assign clk_override = dec_tlu_dec_clk_override;
@ -419,14 +428,17 @@ import el2_pkg::*;
// trace
assign rv_trace_pkt.rv_i_insn_ip = dec_i0_inst_wb1[31:0];
assign rv_trace_pkt.rv_i_address_ip = { dec_i0_pc_wb1[31:1], 1'b0};
assign rv_trace_pkt.rv_i_valid_ip = {dec_tlu_int_valid_wb1, // always int
dec_tlu_i0_valid_wb1 | dec_tlu_i0_exc_valid_wb1};
assign rv_trace_pkt.rv_i_exception_ip = {dec_tlu_int_valid_wb1, dec_tlu_i0_exc_valid_wb1};
assign rv_trace_pkt.rv_i_ecause_ip = dec_tlu_exc_cause_wb1[4:0]; // replicate across ports
assign rv_trace_pkt.rv_i_interrupt_ip = {dec_tlu_int_valid_wb1,1'b0};
assign rv_trace_pkt.rv_i_tval_ip = dec_tlu_mtval_wb1[31:0]; // replicate across ports
assign trace_rv_trace_pkt.trace_rv_i_insn_ip = dec_i0_inst_wb[31:0];
assign trace_rv_trace_pkt.trace_rv_i_address_ip = { dec_i0_pc_wb[31:1], 1'b0};
assign trace_rv_trace_pkt.trace_rv_i_valid_ip = dec_tlu_int_valid_wb1 | dec_tlu_i0_valid_wb1 | dec_tlu_i0_exc_valid_wb1;
assign trace_rv_trace_pkt.trace_rv_i_exception_ip = dec_tlu_int_valid_wb1 | dec_tlu_i0_exc_valid_wb1;
assign trace_rv_trace_pkt.trace_rv_i_ecause_ip = dec_tlu_exc_cause_wb1[4:0]; // replicate across ports
assign trace_rv_trace_pkt.trace_rv_i_interrupt_ip = dec_tlu_int_valid_wb1;
assign trace_rv_trace_pkt.trace_rv_i_tval_ip = dec_tlu_mtval_wb1[31:0]; // replicate across ports
// end trace

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 Western Digital Corporation or it's affiliates.
// Copyright 2020 Western Digital Corporation or its affiliates.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -47,7 +47,7 @@ import el2_pkg::*;
logic [31:1] w0v,w1v,w2v;
logic [31:1] gpr_wr_en;
// GPR Write Enables for power savings
// GPR Write Enables
assign gpr_wr_en[31:1] = (w0v[31:1] | w1v[31:1] | w2v[31:1]);
for ( genvar j=1; j<32; j++ ) begin : gpr
rvdffe #(32) gprff (.*, .en(gpr_wr_en[j]), .din(gpr_in[j][31:0]), .dout(gpr_out[j][31:0]));
@ -79,7 +79,7 @@ import el2_pkg::*;
end
end // always_comb begin
`ifdef ASSERT_ON
`ifdef RV_ASSERT_ON
logic write_collision_unused;
assign write_collision_unused = ( (w0v[31:1] == w1v[31:1]) & wen0 & wen1 ) |

View File

@ -1,5 +1,5 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 Western Digital Corporation or it's affiliates.
// Copyright 2020 Western Digital Corporation or its affiliates.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -29,18 +29,21 @@ import el2_pkg::*;
input logic [pt.BTB_ADDR_HI:pt.BTB_ADDR_LO] ifu_i0_bp_index, // BP index
input logic [pt.BHT_GHR_SIZE-1:0] ifu_i0_bp_fghr, // BP FGHR
input logic [pt.BTB_BTAG_SIZE-1:0] ifu_i0_bp_btag, // BP tag
input logic [$clog2(pt.BTB_SIZE)-1:0] ifu_i0_fa_index, // Fully associt btb index
input logic ifu_i0_pc4, // i0 is 4B inst else 2B
input logic ifu_i0_valid, // i0 valid from ifu
input logic ifu_i0_icaf, // i0 instruction access fault
input logic [1:0] ifu_i0_icaf_type, // i0 instruction access fault type
input logic ifu_i0_icaf_f1, // i0 has access fault on second fetch group
input logic ifu_i0_icaf_second, // i0 has access fault on second 2B of 4B inst
input logic ifu_i0_dbecc, // i0 double-bit error
input logic [31:0] ifu_i0_instr, // i0 instruction from the aligner
input logic [31:1] ifu_i0_pc, // i0 pc from the aligner
output logic dec_ib0_valid_d, // ib0 valid
output logic dec_debug_valid_d, // Debug read or write at D-stage
output logic [31:0] dec_i0_instr_d, // i0 inst at decode
@ -53,8 +56,10 @@ import el2_pkg::*;
output logic [pt.BTB_ADDR_HI:pt.BTB_ADDR_LO] dec_i0_bp_index, // i0 branch index
output logic [pt.BHT_GHR_SIZE-1:0] dec_i0_bp_fghr, // BP FGHR
output logic [pt.BTB_BTAG_SIZE-1:0] dec_i0_bp_btag, // BP tag
output logic [$clog2(pt.BTB_SIZE)-1:0] dec_i0_bp_fa_index, // Fully associt btb index
output logic dec_i0_icaf_d, // i0 instruction access fault at decode
output logic dec_i0_icaf_f1_d, // i0 instruction access fault at decode for f1 fetch group
output logic dec_i0_icaf_second_d, // i0 instruction access fault on second 2B of 4B inst
output logic [1:0] dec_i0_icaf_type_d, // i0 instruction access fault type
output logic dec_i0_dbecc_d, // i0 double-bit error at decode
output logic dec_debug_wdata_rs1_d, // put debug write data onto rs1 source: machine is halted
@ -78,12 +83,12 @@ import el2_pkg::*;
logic [34:0] ifu_i0_pcdata, pc0;
assign ifu_i0_pcdata[34:0] = { ifu_i0_icaf_f1, ifu_i0_dbecc, ifu_i0_icaf,
assign ifu_i0_pcdata[34:0] = { ifu_i0_icaf_second, ifu_i0_dbecc, ifu_i0_icaf,
ifu_i0_pc[31:1], ifu_i0_pc4 };
assign pc0[34:0] = ifu_i0_pcdata[34:0];
assign dec_i0_icaf_f1_d = pc0[34]; // icaf's can only decode as i0
assign dec_i0_icaf_second_d = pc0[34]; // icaf's can only decode as i0
assign dec_i0_dbecc_d = pc0[33];
@ -146,11 +151,14 @@ import el2_pkg::*;
assign dec_ib0_valid_d = ifu_i0_valid | debug_valid;
assign dec_debug_valid_d = debug_valid;
assign dec_i0_instr_d[31:0] = ib0[31:0];
assign dec_i0_brp = i0_brp;
assign dec_i0_bp_index = ifu_i0_bp_index;
assign dec_i0_bp_fghr = ifu_i0_bp_fghr;
assign dec_i0_bp_btag = ifu_i0_bp_btag;
assign dec_i0_bp_fa_index = ifu_i0_fa_index;
endmodule

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 Western Digital Corporation or it's affiliates.
// Copyright 2020 Western Digital Corporation or its affiliates.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -31,7 +31,7 @@ import el2_pkg::*;
input el2_trigger_pkt_t [3:0] trigger_pkt_any, // Packet from tlu. 'select':0-pc,1-Opcode 'Execute' needs to be set for dec triggers to fire. 'match'-1 do mask, 0: full match
input logic [31:1] dec_i0_pc_d, // i0 pc
output logic [3:0] dec_i0_trigger_match_d
output logic [3:0] dec_i0_trigger_match_d // Trigger match
);
logic [3:0][31:0] dec_i0_match_data;

View File

@ -173,6 +173,7 @@ always_comb begin
endcase
end
capture_dr: begin
nsr[0] = 1'b0;
case(1)
dr_en[0]: nsr = {{USER_DR_LENGTH-15{1'b0}}, idle, dmi_stat, abits, version};
dr_en[1]: nsr = {{AWIDTH{1'b0}}, rd_data, rd_status};

View File

@ -1,5 +1,5 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 Western Digital Corporation or it's affiliates.
// Copyright 2020 Western Digital Corporation or its affiliates.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -64,6 +64,7 @@ module el2_dma_ctrl #(
input logic [2:0] iccm_dma_rtag, // Tag of the DMA req
input logic [63:0] iccm_dma_rdata, // iccm data for DMA read
output logic dma_active, // DMA is busy
output logic dma_dccm_stall_any, // stall dccm pipe (bubble) so that DMA can proceed
output logic dma_iccm_stall_any, // stall iccm pipe (bubble) so that DMA can proceed
input logic dccm_ready, // dccm ready to accept DMA request
@ -154,6 +155,10 @@ module el2_dma_ctrl #(
logic [DEPTH_PTR-1:0] RdPtr, NxtRdPtr;
logic WrPtrEn, RdPtrEn, RspPtrEn;
logic [1:0] dma_dbg_sz;
logic [1:0] dma_dbg_addr;
logic [31:0] dma_dbg_mem_rddata;
logic [31:0] dma_dbg_mem_wrdata;
logic dma_dbg_cmd_error;
logic dma_dbg_cmd_done_q;
@ -193,6 +198,7 @@ module el2_dma_ctrl #(
logic fifo_full_spec_bus;
logic dbg_dma_bubble_bus;
logic stall_dma_in;
logic dma_fifo_ready;
logic wrbuf_en, wrbuf_data_en;
@ -225,14 +231,14 @@ module el2_dma_ctrl #(
// FIFO inputs
assign fifo_addr_in[31:0] = dbg_cmd_valid ? dbg_cmd_addr[31:0] : bus_cmd_addr[31:0];
assign fifo_byteen_in[7:0] = dbg_cmd_valid ? (8'h0f << 4*dbg_cmd_addr[2]) : bus_cmd_byteen[7:0];
assign fifo_byteen_in[7:0] = {8{~dbg_cmd_valid}} & bus_cmd_byteen[7:0]; // Byte enable is used only for bus requests
assign fifo_sz_in[2:0] = dbg_cmd_valid ? {1'b0,dbg_cmd_size[1:0]} : bus_cmd_sz[2:0];
assign fifo_write_in = dbg_cmd_valid ? dbg_cmd_write : bus_cmd_write;
assign fifo_posted_write_in = ~dbg_cmd_valid & bus_cmd_posted_write;
assign fifo_dbg_in = dbg_cmd_valid;
for (genvar i=0 ;i<32'(DEPTH); i++) begin: GenFifo
assign fifo_cmd_en[i] = ((bus_cmd_sent & dma_bus_clk_en) | (dbg_cmd_valid & dbg_cmd_type[1])) & (DEPTH_PTR'(i) == WrPtr[DEPTH_PTR-1:0]);
for (genvar i=0 ;i<DEPTH; i++) begin: GenFifo
assign fifo_cmd_en[i] = ((bus_cmd_sent & dma_bus_clk_en) | (dbg_cmd_valid & dbg_cmd_type[1])) & (i == WrPtr[DEPTH_PTR-1:0]);
assign fifo_data_en[i] = (((bus_cmd_sent & fifo_write_in & dma_bus_clk_en) | (dbg_cmd_valid & dbg_cmd_type[1] & dbg_cmd_write)) & (i == WrPtr[DEPTH_PTR-1:0])) |
((dma_address_error | dma_alignment_error) & (i == RdPtr[DEPTH_PTR-1:0])) |
(dccm_dma_rvalid & (i == DEPTH_PTR'(dccm_dma_rtag[2:0]))) |
@ -251,7 +257,7 @@ module el2_dma_ctrl #(
{(dma_address_error | dma_alignment_error | dma_dbg_cmd_error), dma_alignment_error};
assign fifo_data_in[i] = (fifo_error_en[i] & (|fifo_error_in[i])) ? {32'b0,fifo_addr[i]} :
((dccm_dma_rvalid & (i == DEPTH_PTR'(dccm_dma_rtag[2:0]))) ? dccm_dma_rdata[63:0] : (iccm_dma_rvalid & (i == DEPTH_PTR'(iccm_dma_rtag[2:0]))) ? iccm_dma_rdata[63:0] :
(dbg_cmd_valid ? {2{dbg_cmd_wrdata[31:0]}} : bus_cmd_wdata[63:0]));
(dbg_cmd_valid ? {2{dma_dbg_mem_wrdata[31:0]}} : bus_cmd_wdata[63:0]));
rvdffsc #(1) fifo_valid_dff (.din(1'b1), .dout(fifo_valid[i]), .en(fifo_cmd_en[i]), .clear(fifo_reset[i]), .clk(dma_free_clk), .*);
rvdffsc #(2) fifo_error_dff (.din(fifo_error_in[i]), .dout(fifo_error[i]), .en(fifo_error_en[i]), .clear(fifo_reset[i]), .clk(dma_free_clk), .*);
@ -299,7 +305,7 @@ module el2_dma_ctrl #(
// Error logic
assign dma_address_error = fifo_valid[RdPtr] & ~fifo_done[RdPtr] & ~fifo_dbg[RdPtr] & (~(dma_mem_addr_in_dccm | dma_mem_addr_in_iccm)); // request not for ICCM or DCCM
assign dma_alignment_error = fifo_valid[RdPtr] & ~fifo_done[RdPtr] & ~dma_address_error &
assign dma_alignment_error = fifo_valid[RdPtr] & ~fifo_done[RdPtr] & ~fifo_dbg[RdPtr] & ~dma_address_error &
(((dma_mem_sz_int[2:0] == 3'h1) & dma_mem_addr_int[0]) | // HW size but unaligned
((dma_mem_sz_int[2:0] == 3'h2) & (|dma_mem_addr_int[1:0])) | // W size but unaligned
((dma_mem_sz_int[2:0] == 3'h3) & (|dma_mem_addr_int[2:0])) | // DW size but unaligned
@ -310,20 +316,31 @@ module el2_dma_ctrl #(
//Dbg outputs
assign dma_dbg_ready = fifo_empty & dbg_dma_bubble_bus;
assign dma_dbg_ready = fifo_empty & dbg_dma_bubble;
assign dma_dbg_cmd_done = (fifo_valid[RspPtr] & fifo_dbg[RspPtr] & fifo_done[RspPtr]);
assign dma_dbg_rddata[31:0] = fifo_addr[RspPtr][2] ? fifo_data[RspPtr][63:32] : fifo_data[RspPtr][31:0];
assign dma_dbg_cmd_fail = |fifo_error[RspPtr];
assign dma_dbg_sz[1:0] = fifo_sz[RspPtr][1:0];
assign dma_dbg_addr[1:0] = fifo_addr[RspPtr][1:0];
assign dma_dbg_mem_rddata[31:0] = fifo_addr[RspPtr][2] ? fifo_data[RspPtr][63:32] : fifo_data[RspPtr][31:0];
assign dma_dbg_rddata[31:0] = ({32{(dma_dbg_sz[1:0] == 2'h0)}} & ((dma_dbg_mem_rddata[31:0] >> 8*dma_dbg_addr[1:0]) & 32'hff)) |
({32{(dma_dbg_sz[1:0] == 2'h1)}} & ((dma_dbg_mem_rddata[31:0] >> 16*dma_dbg_addr[1]) & 32'hffff)) |
({32{(dma_dbg_sz[1:0] == 2'h2)}} & dma_dbg_mem_rddata[31:0]);
assign dma_dbg_cmd_error = fifo_valid[RdPtr] & ~fifo_done[RdPtr] & fifo_dbg[RdPtr] &
((~(dma_mem_addr_in_dccm | dma_mem_addr_in_iccm | dma_mem_addr_in_pic)) | (dma_mem_sz_int[1:0] != 2'b10)); // Only word accesses allowed
((~(dma_mem_addr_in_dccm | dma_mem_addr_in_iccm | dma_mem_addr_in_pic)) | // Address outside of ICCM/DCCM/PIC
((dma_mem_addr_in_iccm | dma_mem_addr_in_pic) & (dma_mem_sz_int[1:0] != 2'b10))); // Only word accesses allowed for ICCM/PIC
assign dma_dbg_mem_wrdata[31:0] = ({32{dbg_cmd_size[1:0] == 2'h0}} & {4{dbg_cmd_wrdata[7:0]}}) |
({32{dbg_cmd_size[1:0] == 2'h1}} & {2{dbg_cmd_wrdata[15:0]}}) |
({32{dbg_cmd_size[1:0] == 2'h2}} & dbg_cmd_wrdata[31:0]);
// Block the decode if fifo full
assign dma_dccm_stall_any = dma_mem_req & (dma_mem_addr_in_dccm | dma_mem_addr_in_pic) & (dma_nack_count >= dma_nack_count_csr);
assign dma_iccm_stall_any = dma_mem_req & dma_mem_addr_in_iccm & (dma_nack_count >= dma_nack_count_csr);
// Used to indicate ready to debug
assign fifo_empty = ~(|(fifo_valid[DEPTH-1:0]));
assign fifo_empty = ~((|(fifo_valid[DEPTH-1:0])) | bus_cmd_sent);
// Nack counter, stall the lsu pipe if 7 nacks
assign dma_nack_count_csr[2:0] = dec_tlu_dma_qos_prty[2:0];
@ -339,8 +356,8 @@ module el2_dma_ctrl #(
assign dma_mem_tag[2:0] = 3'(RdPtr);
assign dma_mem_addr_int[31:0] = fifo_addr[RdPtr];
assign dma_mem_sz_int[2:0] = fifo_sz[RdPtr];
assign dma_mem_addr[31:0] = (dma_mem_write & (dma_mem_byteen[7:0] == 8'hf0)) ? {dma_mem_addr_int[31:3],1'b1,dma_mem_addr_int[1:0]} : dma_mem_addr_int[31:0];
assign dma_mem_sz[2:0] = (dma_mem_write & ((dma_mem_byteen[7:0] == 8'h0f) | (dma_mem_byteen[7:0] == 8'hf0))) ? 3'h2 : dma_mem_sz_int[2:0];
assign dma_mem_addr[31:0] = (dma_mem_write & ~fifo_dbg[RdPtr] & (dma_mem_byteen[7:0] == 8'hf0)) ? {dma_mem_addr_int[31:3],1'b1,dma_mem_addr_int[1:0]} : dma_mem_addr_int[31:0];
assign dma_mem_sz[2:0] = (dma_mem_write & ~fifo_dbg[RdPtr] & ((dma_mem_byteen[7:0] == 8'h0f) | (dma_mem_byteen[7:0] == 8'hf0))) ? 3'h2 : dma_mem_sz_int[2:0];
assign dma_mem_byteen[7:0] = fifo_byteen[RdPtr];
assign dma_mem_write = fifo_write[RdPtr];
assign dma_mem_wdata[63:0] = fifo_data[RdPtr];
@ -352,23 +369,27 @@ module el2_dma_ctrl #(
assign dma_pmu_any_write = (dma_dccm_req | dma_iccm_req) & dma_mem_write;
// Address check dccm
if (pt.DCCM_ENABLE) begin: Gen_dccm_enable
rvrangecheck #(.CCM_SADR(pt.DCCM_SADR),
.CCM_SIZE(pt.DCCM_SIZE)) addr_dccm_rangecheck (
.addr(dma_mem_addr_int[31:0]),
.in_range(dma_mem_addr_in_dccm),
.in_region(dma_mem_addr_in_dccm_region_nc)
);
end else begin: Gen_dccm_disable
assign dma_mem_addr_in_dccm = '0;
assign dma_mem_addr_in_dccm_region_nc = '0;
end // else: !if(pt.ICCM_ENABLE)
// Address check iccm
if (pt.ICCM_ENABLE) begin
if (pt.ICCM_ENABLE) begin: Gen_iccm_enable
rvrangecheck #(.CCM_SADR(pt.ICCM_SADR),
.CCM_SIZE(pt.ICCM_SIZE)) addr_iccm_rangecheck (
.addr(dma_mem_addr_int[31:0]),
.in_range(dma_mem_addr_in_iccm),
.in_region(dma_mem_addr_in_iccm_region_nc)
);
end
else begin
end else begin: Gen_iccm_disable
assign dma_mem_addr_in_iccm = '0;
assign dma_mem_addr_in_iccm_region_nc = '0;
end // else: !if(pt.ICCM_ENABLE)
@ -382,10 +403,9 @@ module el2_dma_ctrl #(
.in_region(dma_mem_addr_in_pic_region_nc)
);
// Inputs
rvdff #(1) fifo_full_bus_ff (.din(fifo_full_spec), .dout(fifo_full_spec_bus), .clk(dma_bus_clk), .*);
rvdff #(1) dbg_dma_bubble_ff (.din(dbg_dma_bubble), .dout(dbg_dma_bubble_bus), .clk(dma_bus_clk), .*);
rvdff_fpga #(1) fifo_full_bus_ff (.din(fifo_full_spec), .dout(fifo_full_spec_bus), .clk(dma_bus_clk), .clken(dma_bus_clk_en), .rawclk(clk), .*);
rvdff_fpga #(1) dbg_dma_bubble_ff (.din(dbg_dma_bubble), .dout(dbg_dma_bubble_bus), .clk(dma_bus_clk), .clken(dma_bus_clk_en), .rawclk(clk), .*);
rvdff #(1) dma_dbg_cmd_doneff (.din(dma_dbg_cmd_done), .dout(dma_dbg_cmd_done_q), .clk(free_clk), .*);
// Clock Gating logic
@ -394,7 +414,12 @@ module el2_dma_ctrl #(
rvoclkhdr dma_buffer_c1cgc ( .en(dma_buffer_c1_clken), .l1clk(dma_buffer_c1_clk), .* );
rvoclkhdr dma_free_cgc (.en(dma_free_clken), .l1clk(dma_free_clk), .*);
`ifdef RV_FPGA_OPTIMIZE
assign dma_bus_clk = 1'b0;
`else
rvclkhdr dma_bus_cgc (.en(dma_bus_clk_en), .l1clk(dma_bus_clk), .*);
`endif
// Write channel buffer
assign wrbuf_en = dma_axi_awvalid & dma_axi_awready;
@ -403,22 +428,22 @@ module el2_dma_ctrl #(
assign wrbuf_rst = wrbuf_cmd_sent & ~wrbuf_en;
assign wrbuf_data_rst = wrbuf_cmd_sent & ~wrbuf_data_en;
rvdffsc #(.WIDTH(1)) wrbuf_vldff(.din(1'b1), .dout(wrbuf_vld), .en(wrbuf_en), .clear(wrbuf_rst), .clk(dma_bus_clk), .*);
rvdffsc #(.WIDTH(1)) wrbuf_data_vldff(.din(1'b1), .dout(wrbuf_data_vld), .en(wrbuf_data_en), .clear(wrbuf_data_rst), .clk(dma_bus_clk), .*);
rvdffs #(.WIDTH(pt.DMA_BUS_TAG)) wrbuf_tagff(.din(dma_axi_awid[pt.DMA_BUS_TAG-1:0]), .dout(wrbuf_tag[pt.DMA_BUS_TAG-1:0]), .en(wrbuf_en), .clk(dma_bus_clk), .*);
rvdffs #(.WIDTH(3)) wrbuf_szff(.din(dma_axi_awsize[2:0]), .dout(wrbuf_sz[2:0]), .en(wrbuf_en), .clk(dma_bus_clk), .*);
rvdffsc_fpga #(.WIDTH(1)) wrbuf_vldff (.din(1'b1), .dout(wrbuf_vld), .en(wrbuf_en), .clear(wrbuf_rst), .clk(dma_bus_clk), .clken(dma_bus_clk_en), .rawclk(clk), .*);
rvdffsc_fpga #(.WIDTH(1)) wrbuf_data_vldff (.din(1'b1), .dout(wrbuf_data_vld), .en(wrbuf_data_en), .clear(wrbuf_data_rst), .clk(dma_bus_clk), .clken(dma_bus_clk_en), .rawclk(clk), .*);
rvdffs_fpga #(.WIDTH(pt.DMA_BUS_TAG)) wrbuf_tagff (.din(dma_axi_awid[pt.DMA_BUS_TAG-1:0]), .dout(wrbuf_tag[pt.DMA_BUS_TAG-1:0]), .en(wrbuf_en), .clk(dma_bus_clk), .clken(dma_bus_clk_en), .rawclk(clk), .*);
rvdffs_fpga #(.WIDTH(3)) wrbuf_szff (.din(dma_axi_awsize[2:0]), .dout(wrbuf_sz[2:0]), .en(wrbuf_en), .clk(dma_bus_clk), .clken(dma_bus_clk_en), .rawclk(clk), .*);
rvdffe #(.WIDTH(32)) wrbuf_addrff (.din(dma_axi_awaddr[31:0]), .dout(wrbuf_addr[31:0]), .en(wrbuf_en & dma_bus_clk_en), .*);
rvdffe #(.WIDTH(64)) wrbuf_dataff (.din(dma_axi_wdata[63:0]), .dout(wrbuf_data[63:0]), .en(wrbuf_data_en & dma_bus_clk_en), .*);
rvdffs #(.WIDTH(8)) wrbuf_byteenff(.din(dma_axi_wstrb[7:0]), .dout(wrbuf_byteen[7:0]), .en(wrbuf_data_en), .clk(dma_bus_clk), .*);
rvdffs_fpga #(.WIDTH(8)) wrbuf_byteenff (.din(dma_axi_wstrb[7:0]), .dout(wrbuf_byteen[7:0]), .en(wrbuf_data_en), .clk(dma_bus_clk), .clken(dma_bus_clk_en), .rawclk(clk), .*);
// Read channel buffer
assign rdbuf_en = dma_axi_arvalid & dma_axi_arready;
assign rdbuf_cmd_sent = bus_cmd_sent & ~bus_cmd_write;
assign rdbuf_rst = rdbuf_cmd_sent & ~rdbuf_en;
rvdffsc #(.WIDTH(1)) rdbuf_vldff(.din(1'b1), .dout(rdbuf_vld), .en(rdbuf_en), .clear(rdbuf_rst), .clk(dma_bus_clk), .*);
rvdffs #(.WIDTH(pt.DMA_BUS_TAG)) rdbuf_tagff(.din(dma_axi_arid[pt.DMA_BUS_TAG-1:0]), .dout(rdbuf_tag[pt.DMA_BUS_TAG-1:0]), .en(rdbuf_en), .clk(dma_bus_clk), .*);
rvdffs #(.WIDTH(3)) rdbuf_szff(.din(dma_axi_arsize[2:0]), .dout(rdbuf_sz[2:0]), .en(rdbuf_en), .clk(dma_bus_clk), .*);
rvdffsc_fpga #(.WIDTH(1)) rdbuf_vldff (.din(1'b1), .dout(rdbuf_vld), .en(rdbuf_en), .clear(rdbuf_rst), .clk(dma_bus_clk), .clken(dma_bus_clk_en), .rawclk(clk), .*);
rvdffs_fpga #(.WIDTH(pt.DMA_BUS_TAG)) rdbuf_tagff (.din(dma_axi_arid[pt.DMA_BUS_TAG-1:0]), .dout(rdbuf_tag[pt.DMA_BUS_TAG-1:0]), .en(rdbuf_en), .clk(dma_bus_clk), .clken(dma_bus_clk_en), .rawclk(clk), .*);
rvdffs_fpga #(.WIDTH(3)) rdbuf_szff (.din(dma_axi_arsize[2:0]), .dout(rdbuf_sz[2:0]), .en(rdbuf_en), .clk(dma_bus_clk), .clken(dma_bus_clk_en), .rawclk(clk), .*);
rvdffe #(.WIDTH(32)) rdbuf_addrff (.din(dma_axi_araddr[31:0]), .dout(rdbuf_addr[31:0]), .en(rdbuf_en & dma_bus_clk_en), .*);
assign dma_axi_awready = ~(wrbuf_vld & ~wrbuf_cmd_sent);
@ -442,7 +467,7 @@ module el2_dma_ctrl #(
assign axi_mstr_sel = (wrbuf_vld & wrbuf_data_vld & rdbuf_vld) ? axi_mstr_priority : (wrbuf_vld & wrbuf_data_vld);
assign axi_mstr_prty_in = ~axi_mstr_priority;
assign axi_mstr_prty_en = bus_cmd_sent;
rvdffs #(.WIDTH(1)) mstr_prtyff(.din(axi_mstr_prty_in), .dout(axi_mstr_priority), .en(axi_mstr_prty_en), .clk(dma_bus_clk), .*);
rvdffs_fpga #(.WIDTH(1)) mstr_prtyff(.din(axi_mstr_prty_in), .dout(axi_mstr_priority), .en(axi_mstr_prty_en), .clk(dma_bus_clk), .clken(dma_bus_clk_en), .rawclk(clk), .*);
assign axi_rsp_valid = fifo_valid[RspPtr] & ~fifo_dbg[RspPtr] & fifo_done_bus[RspPtr];
assign axi_rsp_rdata[63:0] = fifo_data[RspPtr];
@ -465,7 +490,10 @@ module el2_dma_ctrl #(
assign bus_rsp_valid = (dma_axi_bvalid | dma_axi_rvalid);
assign bus_rsp_sent = (dma_axi_bvalid & dma_axi_bready) | (dma_axi_rvalid & dma_axi_rready);
`ifdef ASSERT_ON
assign dma_active = wrbuf_vld | rdbuf_vld | (|fifo_valid[DEPTH-1:0]);
`ifdef RV_ASSERT_ON
for (genvar i=0; i<DEPTH; i++) begin
assert_fifo_done_and_novalid: assert #0 (~fifo_done[i] | fifo_valid[i]);

View File

@ -1,6 +1,6 @@
//********************************************************************************
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 Western Digital Corporation or it's affiliates.
// Copyright 2020 Western Digital Corporation or its affiliates.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -42,10 +42,12 @@ import el2_pkg::*;
output logic [pt.DCCM_FDATA_WIDTH-1:0] dccm_rd_data_hi,
//`ifdef pt.DCCM_ENABLE
input el2_dccm_ext_in_pkt_t [pt.DCCM_NUM_BANKS-1:0] dccm_ext_in_pkt,
//`endif
//ICCM ports
input el2_ccm_ext_in_pkt_t [pt.ICCM_NUM_BANKS-1:0] iccm_ext_in_pkt,
input logic [pt.ICCM_BITS-1:1] iccm_rw_addr,
input logic iccm_buf_correct_ecc, // ICCM is doing a single bit error correct cycle
@ -66,6 +68,8 @@ import el2_pkg::*;
input logic ic_rd_en,
input logic [63:0] ic_premux_data, // Premux data to be muxed with each way of the Icache.
input logic ic_sel_premux_data, // Premux data sel
input el2_ic_data_ext_in_pkt_t [pt.ICACHE_NUM_WAYS-1:0][pt.ICACHE_BANKS_WAY-1:0] ic_data_ext_in_pkt,
input el2_ic_tag_ext_in_pkt_t [pt.ICACHE_NUM_WAYS-1:0] ic_tag_ext_in_pkt,
input logic [pt.ICACHE_BANKS_WAY-1:0][70:0] ic_wr_data, // Data to fill to the Icache. With ECC
input logic [70:0] ic_debug_wr_data, // Debug wr cache.
@ -90,6 +94,9 @@ import el2_pkg::*;
);
logic active_clk;
rvoclkhdr active_cg ( .en(1'b1), .l1clk(active_clk), .* );
// DCCM Instantiation
if (pt.DCCM_ENABLE == 1) begin: Gen_dccm_enable
el2_lsu_dccm_mem #(.pt(pt)) dccm (

View File

@ -1,6 +1,6 @@
//********************************************************************************
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 Western Digital Corporation or it's affiliates.
// Copyright 2020 Western Digital Corporation or its affiliates.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -27,9 +27,9 @@ module el2_pic_ctrl #(
input logic clk, // Core clock
input logic free_clk, // free clock
input logic active_clk, // active clock
input logic rst_l, // Reset for all flops
input logic clk_override, // Clock over-ride for gating
input logic io_clk_override, // PIC IO Clock over-ride for gating
input logic [pt.PIC_TOTAL_INT_PLUS1-1:0] extintsrc_req, // Interrupt requests
input logic [31:0] picm_rdaddr, // Address of the register
input logic [31:0] picm_wraddr, // Address of the register
@ -69,6 +69,12 @@ localparam INTPRIORITY_BITS = 4 ;
localparam ID_BITS = 8 ;
localparam int GW_CONFIG[pt.PIC_TOTAL_INT_PLUS1-1:0] = '{default:0} ;
localparam INT_ENABLE_GRPS = (pt.PIC_TOTAL_INT_PLUS1 - 1) / 4 ;
logic [pt.PIC_TOTAL_INT_PLUS1-1:0] intenable_clk_enable ;
logic [INT_ENABLE_GRPS:0] intenable_clk_enable_grp ;
logic [INT_ENABLE_GRPS:0] gw_clk ;
logic addr_intpend_base_match;
logic raddr_config_pic_match ;
@ -112,12 +118,6 @@ logic [INTPRIORITY_BITS-1:0] maxint;
logic [INTPRIORITY_BITS-1:0] selected_int_priority;
logic [INT_GRPS-1:0] [31:0] intpend_rd_part_out ;
logic [NUM_LEVELS:NUM_LEVELS/2] [(pt.PIC_TOTAL_INT_PLUS1/2**(NUM_LEVELS/2))+1:0] [INTPRIORITY_BITS-1:0] levelx_intpend_w_prior_en;
logic [NUM_LEVELS:NUM_LEVELS/2] [(pt.PIC_TOTAL_INT_PLUS1/2**(NUM_LEVELS/2))+1:0] [ID_BITS-1:0] levelx_intpend_id;
logic [(pt.PIC_TOTAL_INT_PLUS1/2**(NUM_LEVELS/2)):0] [INTPRIORITY_BITS-1:0] l2_intpend_w_prior_en_ff;
logic [(pt.PIC_TOTAL_INT_PLUS1/2**(NUM_LEVELS/2)):0] [ID_BITS-1:0] l2_intpend_id_ff;
logic config_reg;
logic intpriord;
logic config_reg_we ;
@ -191,19 +191,24 @@ assign waddr_config_gw_base_match = (picm_waddr_ff[31:NUM_LEVELS+2] == EXT_INT
rvdff #(32) picm_radd_flop (.*, .din (picm_rdaddr), .dout(picm_raddr_ff), .clk(pic_raddr_c1_clk));
rvdff #(32) picm_wadd_flop (.*, .din (picm_wraddr), .dout(picm_waddr_ff), .clk(pic_data_c1_clk));
rvdff #(1) picm_wre_flop (.*, .din (picm_wren), .dout(picm_wren_ff), .clk(active_clk));
rvdff #(1) picm_rde_flop (.*, .din (picm_rden), .dout(picm_rden_ff), .clk(active_clk));
rvdff #(1) picm_mke_flop (.*, .din (picm_mken), .dout(picm_mken_ff), .clk(active_clk));
rvdff #(1) picm_wre_flop (.*, .din (picm_wren), .dout(picm_wren_ff), .clk(free_clk));
rvdff #(1) picm_rde_flop (.*, .din (picm_rden), .dout(picm_rden_ff), .clk(free_clk));
rvdff #(1) picm_mke_flop (.*, .din (picm_mken), .dout(picm_mken_ff), .clk(free_clk));
rvdff #(32) picm_dat_flop (.*, .din (picm_wr_data[31:0]), .dout(picm_wr_data_ff[31:0]), .clk(pic_data_c1_clk));
rvsyncss #(pt.PIC_TOTAL_INT_PLUS1-1) sync_inst
(
.clk (free_clk),
.dout(extintsrc_req_sync[pt.PIC_TOTAL_INT_PLUS1-1:1]),
.din (extintsrc_req[pt.PIC_TOTAL_INT_PLUS1-1:1]),
.*) ;
assign extintsrc_req_sync[0] = extintsrc_req[0];
genvar p ;
for (p=0; p<=INT_ENABLE_GRPS ; p++) begin : IO_CLK_GRP
if (p==INT_ENABLE_GRPS) begin : LAST_GRP
assign intenable_clk_enable_grp[p] = |intenable_clk_enable[pt.PIC_TOTAL_INT_PLUS1-1 : p*4] | io_clk_override;
rvoclkhdr intenable_c1_cgc ( .en(intenable_clk_enable_grp[p]), .l1clk(gw_clk[p]), .* );
end else begin : CLK_GRPS
assign intenable_clk_enable_grp[p] = |intenable_clk_enable[p*4+3 : p*4] | io_clk_override;
rvoclkhdr intenable_c1_cgc ( .en(intenable_clk_enable_grp[p]), .l1clk(gw_clk[p]), .* );
end
end
genvar i ;
for (i=0; i<pt.PIC_TOTAL_INT_PLUS1 ; i++) begin : SETREG
@ -223,9 +228,27 @@ for (i=0; i<pt.PIC_TOTAL_INT_PLUS1 ; i++) begin : SETREG
rvdffs #(INTPRIORITY_BITS) intpriority_ff (.*, .en( intpriority_reg_we[i]), .din (picm_wr_data_ff[INTPRIORITY_BITS-1:0]), .dout(intpriority_reg[i]), .clk(pic_pri_c1_clk));
rvdffs #(1) intenable_ff (.*, .en( intenable_reg_we[i]), .din (picm_wr_data_ff[0]), .dout(intenable_reg[i]), .clk(pic_int_c1_clk));
assign intenable_clk_enable[i] = gw_config_reg[i][1] | intenable_reg_we[i] | intenable_reg[i] | gw_clear_reg_we[i] ;
rvsyncss_fpga #(1) sync_inst
(
.gw_clk (gw_clk[i/4]),
.rawclk (clk),
.clken (intenable_clk_enable_grp[i/4]),
.dout (extintsrc_req_sync[i]),
.din (extintsrc_req[i]),
.*) ;
// if (GW_CONFIG[i]) begin
rvdffs #(2) gw_config_ff (.*, .en( gw_config_reg_we[i]), .din (picm_wr_data_ff[1:0]), .dout(gw_config_reg[i]), .clk(gw_config_c1_clk));
el2_configurable_gw config_gw_inst(.*, .clk(free_clk),
el2_configurable_gw config_gw_inst(.*,
.gw_clk(gw_clk[i/4]),
.rawclk(clk),
.clken (intenable_clk_enable_grp[i/4]),
.extintsrc_req_sync(extintsrc_req_sync[i]) ,
.meigwctrl_polarity(gw_config_reg[i][0]) ,
.meigwctrl_type(gw_config_reg[i][1]) ,
@ -248,6 +271,8 @@ for (i=0; i<pt.PIC_TOTAL_INT_PLUS1 ; i++) begin : SETREG
assign intpriority_reg[i] = {INTPRIORITY_BITS{1'b0}} ;
assign intenable_reg[i] = 1'b0 ;
assign extintsrc_req_gw[i] = 1'b0 ;
assign extintsrc_req_sync[i] = 1'b0 ;
assign intenable_clk_enable[i] = 1'b0;
end
@ -266,10 +291,14 @@ end
if (pt.PIC_2CYCLE == 1) begin : genblock
logic [NUM_LEVELS/2:0] [pt.PIC_TOTAL_INT_PLUS1+2:0] [INTPRIORITY_BITS-1:0] level_intpend_w_prior_en;
logic [NUM_LEVELS/2:0] [pt.PIC_TOTAL_INT_PLUS1+2:0] [ID_BITS-1:0] level_intpend_id;
logic [NUM_LEVELS:NUM_LEVELS/2] [(pt.PIC_TOTAL_INT_PLUS1/2**(NUM_LEVELS/2))+1:0] [INTPRIORITY_BITS-1:0] levelx_intpend_w_prior_en;
logic [NUM_LEVELS:NUM_LEVELS/2] [(pt.PIC_TOTAL_INT_PLUS1/2**(NUM_LEVELS/2))+1:0] [ID_BITS-1:0] levelx_intpend_id;
assign level_intpend_w_prior_en[0][pt.PIC_TOTAL_INT_PLUS1+2:0] = {4'b0,4'b0,4'b0,intpend_w_prior_en[pt.PIC_TOTAL_INT_PLUS1-1:0]} ;
assign level_intpend_id[0][pt.PIC_TOTAL_INT_PLUS1+2:0] = {8'b0,8'b0,8'b0,intpend_id[pt.PIC_TOTAL_INT_PLUS1-1:0]} ;
logic [(pt.PIC_TOTAL_INT_PLUS1/2**(NUM_LEVELS/2)):0] [INTPRIORITY_BITS-1:0] l2_intpend_w_prior_en_ff;
logic [(pt.PIC_TOTAL_INT_PLUS1/2**(NUM_LEVELS/2)):0] [ID_BITS-1:0] l2_intpend_id_ff;
assign levelx_intpend_w_prior_en[NUM_LEVELS/2][(pt.PIC_TOTAL_INT_PLUS1/2**(NUM_LEVELS/2))+1:0] = {{1*INTPRIORITY_BITS{1'b0}},l2_intpend_w_prior_en_ff[(pt.PIC_TOTAL_INT_PLUS1/2**(NUM_LEVELS/2)):0]} ;
assign levelx_intpend_id[NUM_LEVELS/2][(pt.PIC_TOTAL_INT_PLUS1/2**(NUM_LEVELS/2))+1:0] = {{1*ID_BITS{1'b1}},l2_intpend_id_ff[(pt.PIC_TOTAL_INT_PLUS1/2**(NUM_LEVELS/2)):0]} ;
@ -326,6 +355,7 @@ else begin : genblock
assign level_intpend_id[0][pt.PIC_TOTAL_INT_PLUS1+1:0] = {{2*ID_BITS{1'b1}},intpend_id[pt.PIC_TOTAL_INT_PLUS1-1:0]} ;
/// Do the prioritization of the interrupts here ////////////
// genvar l, m , j, k; already declared outside ifdef
for (l=0; l<NUM_LEVELS ; l++) begin : LEVEL
for (m=0; m<=(pt.PIC_TOTAL_INT_PLUS1)/(2**(l+1)) ; m++) begin : COMPARE
if ( m == (pt.PIC_TOTAL_INT_PLUS1)/(2**(l+1))) begin
@ -362,9 +392,14 @@ rvdffs #(1) config_reg_ff (.*, .clk(free_clk), .en(config_reg_we), .din (config
assign intpriord = config_reg ;
//////////////////////////////////////////////////////////////////////////
// Send the interrupt to the core if it is above the thresh-hold
//////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////
/// ClaimId Reg and Corresponding PL
///////////////////////////////////////////////////////////
//
assign pl_in_q[INTPRIORITY_BITS-1:0] = intpriord ? ~pl_in : pl_in ;
rvdff #(ID_BITS) claimid_ff (.*, .din (claimid_in[ID_BITS-1:00]), .dout(claimid[ID_BITS-1:00]), .clk(free_clk));
rvdff #(INTPRIORITY_BITS) pl_ff (.*, .din (pl_in_q[INTPRIORITY_BITS-1:0]), .dout(pl[INTPRIORITY_BITS-1:0]), .clk(free_clk));
@ -382,6 +417,8 @@ rvdff #(1) wake_up_ff (.*, .clk(free_clk), .din (mhwakeup_in), .dout(mhwakeup))
//////////////////////////////////////////////////////////////////////////
// Reads of register.
// 1- intpending
@ -471,9 +508,10 @@ endmodule // cmp_and_mux
module el2_configurable_gw (
input logic clk,
input logic gw_clk,
input logic rawclk,
input logic clken,
input logic rst_l,
input logic extintsrc_req_sync ,
input logic meigwctrl_polarity ,
input logic meigwctrl_type ,
@ -486,7 +524,8 @@ module el2_configurable_gw (
logic gw_int_pending_in , gw_int_pending ;
assign gw_int_pending_in = (extintsrc_req_sync ^ meigwctrl_polarity) | (gw_int_pending & ~meigwclr) ;
rvdff #(1) int_pend_ff (.*, .clk(clk), .din (gw_int_pending_in), .dout(gw_int_pending));
rvdff_fpga #(1) int_pend_ff (.*, .clk(gw_clk), .rawclk(rawclk), .clken(clken), .din (gw_int_pending_in), .dout(gw_int_pending));
assign extintsrc_req_config = meigwctrl_type ? ((extintsrc_req_sync ^ meigwctrl_polarity) | gw_int_pending) : (extintsrc_req_sync ^ meigwctrl_polarity) ;

View File

@ -1,5 +1,5 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 Western Digital Corporation or it's affiliates.
// Copyright 2020 Western Digital Corporation or its affiliates.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -34,14 +34,18 @@ import el2_pkg::*;
input logic [31:1] nmi_vec,
output logic core_rst_l, // This is "rst_l | dbg_rst_l"
output logic active_l2clk,
output logic free_l2clk,
output logic [31:0] trace_rv_i_insn_ip,
output logic [31:0] trace_rv_i_address_ip,
output logic [1:0] trace_rv_i_valid_ip,
output logic [1:0] trace_rv_i_exception_ip,
output logic trace_rv_i_valid_ip,
output logic trace_rv_i_exception_ip,
output logic [4:0] trace_rv_i_ecause_ip,
output logic [1:0] trace_rv_i_interrupt_ip,
output logic trace_rv_i_interrupt_ip,
output logic [31:0] trace_rv_i_tval_ip,
output logic dccm_clk_override,
output logic icm_clk_override,
output logic dec_tlu_core_ecc_disable,
@ -304,6 +308,7 @@ import el2_pkg::*;
output logic [1:0] dma_axi_rresp,
output logic dma_axi_rlast,
//// AHB LITE BUS
output logic [31:0] haddr,
output logic [2:0] hburst,
@ -366,16 +371,11 @@ import el2_pkg::*;
input logic dbg_bus_clk_en,
input logic dma_bus_clk_en,
// Debug ports
input logic dmi_reg_en, // read or write
input logic [6:0] dmi_reg_addr, // address of DM register
input logic dmi_reg_wr_en, // write instruction
input logic [31:0] dmi_reg_wdata, // write data
// outputs from the dbg back to jtag
output logic [31:0] dmi_reg_rdata,
input logic dmi_hard_reset,
input logic [pt.PIC_TOTAL_INT:1] extintsrc_req,
input logic timer_int,
@ -386,8 +386,6 @@ import el2_pkg::*;
`define ADDRWIDTH 32
logic [63:0] hwdata_nc;
//----------------------------------------------------------------------
//
@ -517,6 +515,7 @@ import el2_pkg::*;
logic [1:0] dma_axi_arburst_int;
logic dma_axi_rready_int;
// Icache debug
logic [70:0] ifu_ic_debug_rd_data; // diagnostic icache read data
logic ifu_ic_debug_rd_data_valid; // diagnostic icache read data valid
@ -528,8 +527,7 @@ import el2_pkg::*;
logic [31:0] gpr_i0_rs1_d;
logic [31:0] gpr_i0_rs2_d;
logic [31:0] dec_i0_rs1_bypass_data_d;
logic [31:0] dec_i0_rs2_bypass_data_d;
logic [31:0] dec_i0_result_r;
logic [31:0] exu_i0_result_x;
logic [31:1] exu_i0_pc_x;
logic [31:1] exu_npc_r;
@ -546,10 +544,11 @@ import el2_pkg::*;
logic dec_i0_select_pc_d;
logic [31:1] dec_i0_pc_d;
logic [1:0] dec_i0_rs1_bypass_en_d;
logic [1:0] dec_i0_rs2_bypass_en_d;
logic [3:0] dec_i0_rs1_bypass_en_d;
logic [3:0] dec_i0_rs2_bypass_en_d;
logic dec_i0_alu_decode_d;
logic dec_i0_branch_d;
logic ifu_miss_state_idle;
logic dec_tlu_flush_noredir_r;
@ -568,6 +567,7 @@ import el2_pkg::*;
el2_lsu_pkt_t lsu_p;
logic dec_qual_lsu_d;
logic dec_lsu_valid_raw_d;
logic [11:0] dec_lsu_offset_d;
@ -582,6 +582,7 @@ import el2_pkg::*;
logic lsu_load_stall_any; // This is for blocking loads
logic lsu_store_stall_any; // This is for blocking stores
logic lsu_idle_any; // doesn't include DMA
logic lsu_active; // lsu is active. used for clock
logic [31:1] lsu_fir_addr; // fast interrupt address
@ -597,11 +598,13 @@ import el2_pkg::*;
logic [31:0] lsu_nonblock_load_data;
logic dec_csr_ren_d;
logic [31:0] dec_csr_rddata_d;
logic [31:0] exu_csr_rs1_x;
logic dec_tlu_i0_commit_cmt;
logic dec_tlu_flush_lower_r;
logic dec_tlu_flush_lower_wb;
logic dec_tlu_i0_kill_writeb_r; // I0 is flushed, don't writeback any results to arch state
logic dec_tlu_fence_i_r; // flush is a fence_i rfnpc, flush icache
@ -674,7 +677,7 @@ import el2_pkg::*;
logic [1:0] ifu_i0_icaf_type;
logic ifu_i0_icaf_f1;
logic ifu_i0_icaf_second;
logic ifu_i0_dbecc;
logic iccm_dma_sb_error;
@ -683,6 +686,9 @@ import el2_pkg::*;
logic [pt.BHT_GHR_SIZE-1:0] ifu_i0_bp_fghr;
logic [pt.BTB_BTAG_SIZE-1:0] ifu_i0_bp_btag;
logic [$clog2(pt.BTB_SIZE)-1:0] ifu_i0_fa_index;
logic [$clog2(pt.BTB_SIZE)-1:0] dec_fa_error_index; // Fully associative btb error index
el2_predict_pkt_t dec_i0_predict_p_d;
@ -699,7 +705,6 @@ import el2_pkg::*;
logic [31:0] picm_wr_data;
logic [31:0] picm_rd_data;
// feature disable from mfdc
logic dec_tlu_external_ldfwd_disable; // disable external load forwarding
logic dec_tlu_bpred_disable;
@ -716,6 +721,8 @@ import el2_pkg::*;
logic dec_tlu_dccm_clk_override;
logic dec_tlu_icm_clk_override;
logic dec_tlu_picio_clk_override;
assign dccm_clk_override = dec_tlu_dccm_clk_override; // dccm memory
assign icm_clk_override = dec_tlu_icm_clk_override; // icache/iccm memory
@ -723,7 +730,7 @@ import el2_pkg::*;
logic [31:0] dbg_cmd_addr; // the address of the debug command to used by the core
logic [31:0] dbg_cmd_wrdata; // If the debug command is a write command, this has the data to be written to the CSR/GPR
logic dbg_cmd_valid; // command is being driven by the dbg module. One pulse. Only dirven when core_halted has been seen
logic dbg_cmd_valid; // commad is being driven by the dbg module. One pulse. Only dirven when core_halted has been seen
logic dbg_cmd_write; // 1: write command; 0: read_command
logic [1:0] dbg_cmd_type; // 0:gpr 1:csr 2: memory
logic [1:0] dbg_cmd_size; // size of the abstract mem access debug command
@ -776,7 +783,8 @@ import el2_pkg::*;
logic ifu_pmu_bus_trxn;
logic active_state;
logic free_clk, active_clk;
logic free_clk;
logic active_clk;
logic dec_pause_state_cg;
logic lsu_nonblock_load_data_error;
@ -787,24 +795,37 @@ import el2_pkg::*;
logic [31:2] dec_tlu_meihap;
logic dec_extint_stall;
el2_trace_pkt_t rv_trace_pkt;
el2_trace_pkt_t trace_rv_trace_pkt;
logic lsu_fastint_stall_any;
logic [7:0] pic_claimid;
logic [3:0] pic_pl, dec_tlu_meicurpl, dec_tlu_meipt;
logic mexintpend;
logic mhwakeup;
logic dma_active;
//assign lsu_fastint_stall_any = 1'b0;
assign active_state = (~dec_pause_state_cg | dec_tlu_flush_lower_r) | dec_tlu_misc_clk_override;
logic pause_state;
logic halt_state;
rvoclkhdr free_cg ( .en(1'b1), .l1clk(free_clk), .* );
rvoclkhdr active_cg ( .en(active_state), .l1clk(active_clk), .* );
logic dec_tlu_core_empty;
assign pause_state = dec_pause_state_cg & ~(dma_active | lsu_active) & dec_tlu_core_empty;
assign halt_state = o_cpu_halt_status & ~(dma_active | lsu_active);
assign active_state = (~(halt_state | pause_state) | dec_tlu_flush_lower_r | dec_tlu_flush_lower_wb) | dec_tlu_misc_clk_override;
rvoclkhdr free_cg2 ( .clk(clk), .en(1'b1), .l1clk(free_l2clk), .* );
rvoclkhdr active_cg2 ( .clk(clk), .en(active_state), .l1clk(active_l2clk), .* );
// all other clock headers are 1st level
rvoclkhdr free_cg1 ( .clk(free_l2clk), .en(1'b1), .l1clk(free_clk), .* );
rvoclkhdr active_cg1 ( .clk(active_l2clk), .en(1'b1), .l1clk(active_clk), .* );
assign core_dbg_cmd_done = dma_dbg_cmd_done | dec_dbg_cmd_done;
@ -812,6 +833,8 @@ import el2_pkg::*;
assign core_dbg_rddata[31:0] = dma_dbg_cmd_done ? dma_dbg_rddata[31:0] : dec_dbg_rddata[31:0];
el2_dbg #(.pt(pt)) dbg (
.rst_l(core_rst_l),
.clk(free_l2clk),
.clk_override(dec_tlu_misc_clk_override),
// AXI signals
@ -824,18 +847,19 @@ import el2_pkg::*;
.sb_axi_rvalid(sb_axi_rvalid_int),
.sb_axi_rdata(sb_axi_rdata_int[63:0]),
.sb_axi_rresp(sb_axi_rresp_int[1:0]),
.*
);
`ifdef ASSERT_ON
`ifdef RV_ASSERT_ON
assert_fetch_indbghalt: assert #0 (~(ifu.ifc_fetch_req_f & dec.tlu.dbg_tlu_halted_f & ~dec.tlu.dcsr_single_step_running)) else $display("ERROR: Fetching in dBG halt!");
`endif
assign core_rst_l = rst_l & (dbg_core_rst_l | scan_mode);
// ----------------- DEBUG END -----------------------------
assign core_rst_l = rst_l & (dbg_core_rst_l | scan_mode);
// fetch
el2_ifu #(.pt(pt)) ifu (
.clk(active_l2clk),
.rst_l(core_rst_l),
.dec_tlu_flush_err_wb (dec_tlu_flush_err_r ),
.dec_tlu_flush_noredir_wb (dec_tlu_flush_noredir_r ),
@ -855,17 +879,20 @@ import el2_pkg::*;
el2_dec #(.pt(pt)) dec (
.clk(active_l2clk),
.dbg_cmd_wrdata(dbg_cmd_wrdata[1:0]),
.rst_l(core_rst_l),
.*
);
el2_exu #(.pt(pt)) exu (
.clk(active_l2clk),
.rst_l(core_rst_l),
.*
);
el2_lsu #(.pt(pt)) lsu (
.clk(active_l2clk),
.rst_l(core_rst_l),
.clk_override(dec_tlu_lsu_clk_override),
.dec_tlu_i0_kill_writeb_r(dec_tlu_i0_kill_writeb_r),
@ -888,8 +915,11 @@ import el2_pkg::*;
);
el2_pic_ctrl #(.pt(pt)) pic_ctrl_inst (
.clk(free_l2clk),
.clk_override(dec_tlu_pic_clk_override),
.io_clk_override(dec_tlu_picio_clk_override),
.picm_mken (picm_mken),
.extintsrc_req({extintsrc_req[pt.PIC_TOTAL_INT:1],1'b0}),
.pl(pic_pl[3:0]),
@ -900,6 +930,7 @@ import el2_pkg::*;
.*);
el2_dma_ctrl #(.pt(pt)) dma_ctrl (
.clk(free_l2clk),
.rst_l(core_rst_l),
.clk_override(dec_tlu_misc_clk_override),
@ -927,8 +958,13 @@ import el2_pkg::*;
// AXI4 -> AHB Gasket for LSU
axi4_to_ahb #(.pt(pt),
.TAG(pt.LSU_BUS_TAG)) lsu_axi4_to_ahb (
.clk(free_l2clk),
.free_clk(free_clk),
.rst_l(core_rst_l),
.clk_override(dec_tlu_bus_clk_override),
.bus_clk_en(lsu_bus_clk_en),
.dec_tlu_force_halt(dec_tlu_force_halt),
// AXI Write Channels
.axi_awvalid(lsu_axi_awvalid),
@ -983,9 +1019,12 @@ import el2_pkg::*;
axi4_to_ahb #(.pt(pt),
.TAG(pt.IFU_BUS_TAG)) ifu_axi4_to_ahb (
.clk(clk),
.clk(free_l2clk),
.free_clk(free_clk),
.rst_l(core_rst_l),
.clk_override(dec_tlu_bus_clk_override),
.bus_clk_en(ifu_bus_clk_en),
.dec_tlu_force_halt(dec_tlu_force_halt),
// AHB-Lite signals
.ahb_haddr(haddr[31:0]),
@ -1040,8 +1079,12 @@ import el2_pkg::*;
// AXI4 -> AHB Gasket for System Bus
axi4_to_ahb #(.pt(pt),
.TAG(pt.SB_BUS_TAG)) sb_axi4_to_ahb (
.clk(free_l2clk),
.free_clk(free_clk),
.rst_l(dbg_rst_l),
.clk_override(dec_tlu_bus_clk_override),
.bus_clk_en(dbg_bus_clk_en),
.dec_tlu_force_halt(1'b0),
// AXI Write Channels
.axi_awvalid(sb_axi_awvalid),
@ -1096,6 +1139,8 @@ import el2_pkg::*;
//AHB -> AXI4 Gasket for DMA
ahb_to_axi4 #(.pt(pt),
.TAG(pt.DMA_BUS_TAG)) dma_ahb_to_axi4 (
.clk(free_l2clk),
.rst_l(core_rst_l),
.clk_override(dec_tlu_bus_clk_override),
.bus_clk_en(dma_bus_clk_en),
@ -1219,7 +1264,7 @@ import el2_pkg::*;
if (pt.BUILD_AHB_LITE == 1) begin
`ifdef ASSERT_ON
`ifdef RV_ASSERT_ON
property ahb_trxn_aligned;
@(posedge clk) disable iff(~rst_l) (lsu_htrans[1:0] != 2'b0) |-> ((lsu_hsize[2:0] == 3'h0) |
((lsu_hsize[2:0] == 3'h1) & (lsu_haddr[0] == 1'b0)) |
@ -1244,15 +1289,19 @@ if (pt.BUILD_AHB_LITE == 1) begin
// unpack packet
// also need retires_p==3
assign trace_rv_i_insn_ip[31:0] = rv_trace_pkt.rv_i_insn_ip[31:0];
assign trace_rv_i_address_ip[31:0] = rv_trace_pkt.rv_i_address_ip[31:0];
assign trace_rv_i_valid_ip[1:0] = rv_trace_pkt.rv_i_valid_ip[1:0];
assign trace_rv_i_exception_ip[1:0] = rv_trace_pkt.rv_i_exception_ip[1:0];
assign trace_rv_i_ecause_ip[4:0] = rv_trace_pkt.rv_i_ecause_ip[4:0];
assign trace_rv_i_interrupt_ip[1:0] = rv_trace_pkt.rv_i_interrupt_ip[1:0];
assign trace_rv_i_tval_ip[31:0] = rv_trace_pkt.rv_i_tval_ip[31:0];
assign trace_rv_i_insn_ip[31:0] = trace_rv_trace_pkt.trace_rv_i_insn_ip[31:0];
assign trace_rv_i_address_ip[31:0] = trace_rv_trace_pkt.trace_rv_i_address_ip[31:0];
assign trace_rv_i_valid_ip = trace_rv_trace_pkt.trace_rv_i_valid_ip;
assign trace_rv_i_exception_ip = trace_rv_trace_pkt.trace_rv_i_exception_ip;
assign trace_rv_i_ecause_ip[4:0] = trace_rv_trace_pkt.trace_rv_i_ecause_ip[4:0];
assign trace_rv_i_interrupt_ip = trace_rv_trace_pkt.trace_rv_i_interrupt_ip;
assign trace_rv_i_tval_ip[31:0] = trace_rv_trace_pkt.trace_rv_i_tval_ip[31:0];

View File

@ -1,5 +1,5 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 Western Digital Corporation or it's affiliates.
// Copyright 2020 Western Digital Corporation or its affiliates.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -37,10 +37,10 @@ import el2_pkg::*;
output logic [31:0] trace_rv_i_insn_ip,
output logic [31:0] trace_rv_i_address_ip,
output logic [1:0] trace_rv_i_valid_ip,
output logic [1:0] trace_rv_i_exception_ip,
output logic trace_rv_i_valid_ip,
output logic trace_rv_i_exception_ip,
output logic [4:0] trace_rv_i_ecause_ip,
output logic [1:0] trace_rv_i_interrupt_ip,
output logic trace_rv_i_interrupt_ip,
output logic [31:0] trace_rv_i_tval_ip,
// Bus signals
@ -290,8 +290,13 @@ import el2_pkg::*;
input logic dbg_bus_clk_en, // Clock ratio b/w cpu core clk & AHB master interface
input logic dma_bus_clk_en, // Clock ratio b/w cpu core clk & AHB slave interface
// all of these test inputs are brought to top-level; must be tied off based on usage by physical design (ie. icache or not, iccm or not, dccm or not)
input el2_dccm_ext_in_pkt_t [pt.DCCM_NUM_BANKS-1:0] dccm_ext_in_pkt,
input el2_ccm_ext_in_pkt_t [pt.ICCM_NUM_BANKS-1:0] iccm_ext_in_pkt,
input el2_ic_data_ext_in_pkt_t [pt.ICACHE_NUM_WAYS-1:0][pt.ICACHE_BANKS_WAY-1:0] ic_data_ext_in_pkt,
input el2_ic_tag_ext_in_pkt_t [pt.ICACHE_NUM_WAYS-1:0] ic_tag_ext_in_pkt,
// input logic ext_int,
input logic timer_int,
input logic soft_int,
input logic [pt.PIC_TOTAL_INT:1] extintsrc_req,
@ -301,6 +306,7 @@ import el2_pkg::*;
output logic dec_tlu_perfcnt2,
output logic dec_tlu_perfcnt3,
// ports added by the soc team
input logic jtag_tck, // JTAG clk
input logic jtag_tms, // JTAG TMS
input logic jtag_tdi, // JTAG tdi
@ -327,6 +333,8 @@ import el2_pkg::*;
input logic mbist_mode // to enable mbist
);
logic active_l2clk;
logic free_l2clk;
// DCCM ports
logic dccm_wren;
@ -386,12 +394,6 @@ import el2_pkg::*;
logic core_rst_l; // Core reset including rst_l and dbg_rst_l
logic jtag_tdoEn;
logic dmi_reg_en;
logic [6:0] dmi_reg_addr;
logic dmi_reg_wr_en;
logic [31:0] dmi_reg_wdata;
logic [31:0] dmi_reg_rdata;
logic dmi_hard_reset;
logic dccm_clk_override;
logic icm_clk_override;
@ -458,6 +460,7 @@ import el2_pkg::*;
logic dma_hresp;
// AHB
assign hrdata[63:0] = '0;
assign hready = '0;
@ -485,6 +488,7 @@ import el2_pkg::*;
`endif // `ifdef RV_BUILD_AXI4
`ifdef RV_BUILD_AHB_LITE
wire lsu_axi_awvalid;
wire lsu_axi_awready;
@ -674,18 +678,27 @@ import el2_pkg::*;
`endif // `ifdef RV_BUILD_AHB_LITE
logic dmi_reg_en;
logic [6:0] dmi_reg_addr;
logic dmi_reg_wr_en;
logic [31:0] dmi_reg_wdata;
logic [31:0] dmi_reg_rdata;
// Instantiate the el2_swerv core
el2_swerv #(.pt(pt)) swerv (
.clk(clk),
.*
);
// Instantiate the mem
el2_mem #(.pt(pt)) mem (
.clk(active_l2clk),
.rst_l(core_rst_l),
.*
);
// Instantiate the JTAG/DMI
// JTAG/DMI instance
dmi_wrapper dmi_wrapper (
// JTAG signals
.trst_n (jtag_trst_n), // JTAG reset
@ -693,21 +706,25 @@ import el2_pkg::*;
.tms (jtag_tms), // Test mode select
.tdi (jtag_tdi), // Test Data Input
.tdo (jtag_tdo), // Test Data Output
.tdoEnable (), // Test Data Output enable
.tdoEnable (),
// Processor Signals
.core_rst_n (dbg_rst_l), // Primary reset active low
.core_rst_n (dbg_rst_l), // Debug reset, active low
.core_clk (clk), // Core clock
.jtag_id (jtag_id), // 32 bit JTAG ID
.rd_data (dmi_reg_rdata), // 32 bit Read data from Processor
.reg_wr_data (dmi_reg_wdata), // 32 bit Write data to Processor
.reg_wr_addr (dmi_reg_addr), // 32 bit Write address to Processor
.reg_en (dmi_reg_en), // 1 bit Write interface bit to Processor
.reg_wr_en (dmi_reg_wr_en), // 1 bit Write enable to Processor
.dmi_hard_reset (dmi_hard_reset) //a hard reset of the DTM, causing the DTM to forget about any outstanding DMI transactions
.jtag_id (jtag_id), // JTAG ID
.rd_data (dmi_reg_rdata), // Read data from Processor
.reg_wr_data (dmi_reg_wdata), // Write data to Processor
.reg_wr_addr (dmi_reg_addr), // Write address to Processor
.reg_en (dmi_reg_en), // Write interface bit to Processor
.reg_wr_en (dmi_reg_wr_en), // Write enable to Processor
.dmi_hard_reset ()
);
`ifdef RV_ASSERT_ON
// to avoid internal assertions failure at time 0
initial begin
$assertoff(0, swerv);
@ (negedge clk) $asserton(0, swerv);
end
`endif
endmodule

View File

@ -1,5 +1,5 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 Western Digital Corporation or it's affiliates.
// Copyright 2020 Western Digital Corporation or its affiliates.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -36,21 +36,25 @@ import el2_pkg::*;
input logic [pt.BTB_ADDR_HI:pt.BTB_ADDR_LO] i0_predict_index_d, // DEC predict index
input logic [pt.BTB_BTAG_SIZE-1:0] i0_predict_btag_d, // DEC predict branch tag
input logic [31:0] lsu_result_m, // Load result M-stage
input logic [31:0] lsu_nonblock_load_data, // nonblock load data
input logic dec_i0_rs1_en_d, // Qualify GPR RS1 data
input logic dec_i0_rs2_en_d, // Qualify GPR RS2 data
input logic [31:0] gpr_i0_rs1_d, // DEC data gpr
input logic [31:0] gpr_i0_rs2_d, // DEC data gpr
input logic [31:0] dec_i0_immed_d, // DEC data immediate
input logic [31:0] dec_i0_rs1_bypass_data_d, // DEC bypass data
input logic [31:0] dec_i0_rs2_bypass_data_d, // DEC bypass data
input logic [31:0] dec_i0_result_r, // DEC result in R-stage
input logic [12:1] dec_i0_br_immed_d, // Branch immediate
input logic dec_i0_alu_decode_d, // Valid to X-stage ALU
input logic dec_i0_branch_d, // Branch in D-stage
input logic dec_i0_select_pc_d, // PC select to RS1
input logic [31:1] dec_i0_pc_d, // Instruction PC
input logic [1:0] dec_i0_rs1_bypass_en_d, // DEC bypass select 1 - X-stage, 0 - dec bypass data
input logic [1:0] dec_i0_rs2_bypass_en_d, // DEC bypass select 1 - X-stage, 0 - dec bypass data
input logic dec_csr_ren_d, // Clear I0 RS1 primary
input logic [3:0] dec_i0_rs1_bypass_en_d, // DEC bypass select 1 - X-stage, 0 - dec bypass data
input logic [3:0] dec_i0_rs2_bypass_en_d, // DEC bypass select 1 - X-stage, 0 - dec bypass data
input logic dec_csr_ren_d, // CSR read select
input logic [31:0] dec_csr_rddata_d, // CSR read data
input logic dec_qual_lsu_d, // LSU instruction at D. Use to quiet LSU operands
input el2_mul_pkt_t mul_p, // DEC {valid, operand signs, low, operand bypass}
input el2_div_pkt_t div_p, // DEC {valid, unsigned, rem}
input logic dec_div_cancel, // Cancel the divide operation
@ -105,18 +109,16 @@ import el2_pkg::*;
logic data_gate_en;
logic [31:0] i0_rs1_bypass_data_d;
logic [31:0] i0_rs2_bypass_data_d;
logic i0_rs1_bypass_en_d;
logic i0_rs2_bypass_en_d;
logic [31:0] i0_rs1_d, i0_rs2_d;
logic [31:0] muldiv_rs1_d, muldiv_rs2_d;
logic [31:0] muldiv_rs1_d;
logic [31:1] pred_correct_npc_r;
logic i0_pred_correct_upper_r;
logic [31:0] csr_rs1_in_d;
logic [31:1] i0_flush_path_upper_r;
logic x_data_en, r_data_en;
logic x_data_en, x_data_en_q1, x_data_en_q2, r_data_en, r_data_en_q2;
logic x_ctl_en, r_ctl_en;
logic [pt.BHT_GHR_SIZE-1:0] ghr_d_ns, ghr_d;
@ -130,7 +132,6 @@ import el2_pkg::*;
el2_predict_pkt_t final_predict_mp;
el2_predict_pkt_t i0_predict_newp_d;
logic flush_lower_ff;
logic flush_in_d;
logic [31:0] alu_result_x;
@ -148,6 +149,7 @@ import el2_pkg::*;
logic [31:1] i0_flush_path_x;
el2_predict_pkt_t i0_predict_p_x;
logic i0_pred_correct_upper_x;
logic i0_branch_x;
localparam PREDPIPESIZE = pt.BTB_ADDR_HI-pt.BTB_ADDR_LO+1+pt.BHT_GHR_SIZE+pt.BTB_BTAG_SIZE;
logic [PREDPIPESIZE-1:0] predpipe_d, predpipe_x, predpipe_r, final_predpipe_mp;
@ -155,52 +157,44 @@ import el2_pkg::*;
rvdffe #(31) i_flush_path_x_ff (.*, .en ( x_data_en ), .din( i0_flush_path_d[31:1] ), .dout( i0_flush_path_x[31:1] ) );
rvdffe #(32) i_csr_rs1_x_ff (.*, .en ( x_data_en ), .din( csr_rs1_in_d[31:0] ), .dout( exu_csr_rs1_x[31:0] ) );
rvdffe #($bits(el2_predict_pkt_t)) i_predictpacket_x_ff (.*, .en ( x_data_en ), .din( i0_predict_p_d ), .dout( i0_predict_p_x ) );
rvdffe #(PREDPIPESIZE) i_predpipe_x_ff (.*, .en ( x_data_en ), .din( predpipe_d ), .dout( predpipe_x ) );
rvdffe #(PREDPIPESIZE) i_predpipe_r_ff (.*, .en ( r_data_en ), .din( predpipe_x ), .dout( predpipe_r ) );
rvdffpcie #(31) i_flush_path_x_ff (.*, .clk(clk), .en ( x_data_en ), .din ( i0_flush_path_d[31:1] ), .dout( i0_flush_path_x[31:1] ) );
rvdffe #(32) i_csr_rs1_x_ff (.*, .clk(clk), .en ( x_data_en_q1 ), .din ( i0_rs1_d[31:0] ), .dout( exu_csr_rs1_x[31:0] ) );
rvdffppe #($bits(el2_predict_pkt_t)) i_predictpacket_x_ff (.*, .clk(clk), .en ( x_data_en ), .din ( i0_predict_p_d ), .dout( i0_predict_p_x ) );
rvdffe #(PREDPIPESIZE) i_predpipe_x_ff (.*, .clk(clk), .en ( x_data_en_q2 ), .din ( predpipe_d ), .dout( predpipe_x ) );
rvdffe #(PREDPIPESIZE) i_predpipe_r_ff (.*, .clk(clk), .en ( r_data_en_q2 ), .din ( predpipe_x ), .dout( predpipe_r ) );
rvdffe #(4+pt.BHT_GHR_SIZE) i_x_ff (.*, .en ( x_ctl_en ), .din ({i0_valid_d,i0_taken_d,i0_flush_upper_d,i0_pred_correct_upper_d,ghr_x_ns[pt.BHT_GHR_SIZE-1:0]} ),
rvdffe #(4+pt.BHT_GHR_SIZE) i_x_ff (.*, .clk(clk), .en ( x_ctl_en ), .din ({i0_valid_d,i0_taken_d,i0_flush_upper_d,i0_pred_correct_upper_d,ghr_x_ns[pt.BHT_GHR_SIZE-1:0]} ),
.dout({i0_valid_x,i0_taken_x,i0_flush_upper_x,i0_pred_correct_upper_x,ghr_x[pt.BHT_GHR_SIZE-1:0]} ) );
rvdffe #($bits(el2_predict_pkt_t)+7) i_r_ff0 (.*, .en ( r_ctl_en ), .din ({i0_predict_p_x ,pred_correct_npc_x[6:1],i0_pred_correct_upper_x}),
.dout({i0_pp_r ,pred_correct_npc_r[6:1],i0_pred_correct_upper_r}) );
rvdffppe #($bits(el2_predict_pkt_t)+1) i_r_ff0 (.*, .clk(clk), .en ( r_ctl_en ), .din ({i0_pred_correct_upper_x, i0_predict_p_x}),
.dout({i0_pred_correct_upper_r, i0_pp_r }) );
rvdffe #(56) i_r_ff1 (.*, .en ( r_data_en ), .din ({i0_flush_path_x[31:1] ,pred_correct_npc_x[31:7]}),
.dout({i0_flush_path_upper_r[31:1],pred_correct_npc_r[31:7]}) );
rvdffpcie #(31) i_flush_r_ff (.*, .clk(clk), .en ( r_data_en ), .din ( i0_flush_path_x[31:1] ), .dout( i0_flush_path_upper_r[31:1]) );
rvdffpcie #(31) i_npc_r_ff (.*, .clk(clk), .en ( r_data_en ), .din ( pred_correct_npc_x[31:1] ), .dout( pred_correct_npc_r[31:1] ) );
if (pt.BHT_SIZE==32 || pt.BHT_SIZE==64)
begin
rvdffs #(pt.BHT_GHR_SIZE+2) i_data_gate_ff (.*, .en( data_gate_en ), .din ({ghr_d_ns[pt.BHT_GHR_SIZE-1:0],mul_p.valid,dec_tlu_flush_lower_r}),
.dout({ghr_d[pt.BHT_GHR_SIZE-1:0] ,mul_valid_x,flush_lower_ff} ) );
end
else
begin
rvdffe #(pt.BHT_GHR_SIZE+2) i_data_gate_ff (.*, .en( data_gate_en ), .din ({ghr_d_ns[pt.BHT_GHR_SIZE-1:0],mul_p.valid,dec_tlu_flush_lower_r}),
.dout({ghr_d[pt.BHT_GHR_SIZE-1:0] ,mul_valid_x,flush_lower_ff} ) );
end
rvdffie #(pt.BHT_GHR_SIZE+2,1) i_misc_ff (.*, .clk(clk), .din ({ghr_d_ns[pt.BHT_GHR_SIZE-1:0], mul_p.valid, dec_i0_branch_d}),
.dout({ghr_d[pt.BHT_GHR_SIZE-1:0] , mul_valid_x, i0_branch_x}) );
assign data_gate_en = ( ghr_d_ns[pt.BHT_GHR_SIZE-1:0] != ghr_d[pt.BHT_GHR_SIZE-1:0]) |
( mul_p.valid != mul_valid_x ) |
( dec_tlu_flush_lower_r != flush_lower_ff );
assign predpipe_d[PREDPIPESIZE-1:0]
= {i0_predict_fghr_d, i0_predict_index_d, i0_predict_btag_d};
assign i0_rs1_bypass_en_d = dec_i0_rs1_bypass_en_d[0] | dec_i0_rs1_bypass_en_d[1];
assign i0_rs2_bypass_en_d = dec_i0_rs2_bypass_en_d[0] | dec_i0_rs2_bypass_en_d[1];
assign i0_rs1_bypass_en_d = dec_i0_rs1_bypass_en_d[0] | dec_i0_rs1_bypass_en_d[1] | dec_i0_rs1_bypass_en_d[2] | dec_i0_rs1_bypass_en_d[3];
assign i0_rs2_bypass_en_d = dec_i0_rs2_bypass_en_d[0] | dec_i0_rs2_bypass_en_d[1] | dec_i0_rs2_bypass_en_d[2] | dec_i0_rs2_bypass_en_d[3];
assign i0_rs1_bypass_data_d[31:0]=({32{dec_i0_rs1_bypass_en_d[0]}} & dec_i0_rs1_bypass_data_d[31:0]) |
({32{dec_i0_rs1_bypass_en_d[1]}} & exu_i0_result_x[31:0] );
assign i0_rs1_bypass_data_d[31:0]=({32{dec_i0_rs1_bypass_en_d[0]}} & dec_i0_result_r[31:0] ) |
({32{dec_i0_rs1_bypass_en_d[1]}} & lsu_result_m[31:0] ) |
({32{dec_i0_rs1_bypass_en_d[2]}} & exu_i0_result_x[31:0] ) |
({32{dec_i0_rs1_bypass_en_d[3]}} & lsu_nonblock_load_data[31:0]);
assign i0_rs2_bypass_data_d[31:0]=({32{dec_i0_rs2_bypass_en_d[0]}} & dec_i0_rs2_bypass_data_d[31:0]) |
({32{dec_i0_rs2_bypass_en_d[1]}} & exu_i0_result_x[31:0] );
assign i0_rs2_bypass_data_d[31:0]=({32{dec_i0_rs2_bypass_en_d[0]}} & dec_i0_result_r[31:0] ) |
({32{dec_i0_rs2_bypass_en_d[1]}} & lsu_result_m[31:0] ) |
({32{dec_i0_rs2_bypass_en_d[2]}} & exu_i0_result_x[31:0] ) |
({32{dec_i0_rs2_bypass_en_d[3]}} & lsu_nonblock_load_data[31:0]);
assign i0_rs1_d[31:0] = ({32{ i0_rs1_bypass_en_d }} & i0_rs1_bypass_data_d[31:0]) |
@ -213,26 +207,23 @@ import el2_pkg::*;
({32{ i0_rs2_bypass_en_d }} & i0_rs2_bypass_data_d[31:0]);
assign exu_lsu_rs1_d[31:0] = ({32{~i0_rs1_bypass_en_d & ~dec_extint_stall & dec_i0_rs1_en_d}} & gpr_i0_rs1_d[31:0] ) |
({32{ i0_rs1_bypass_en_d & ~dec_extint_stall }} & i0_rs1_bypass_data_d[31:0]) |
({32{ dec_extint_stall }} & {dec_tlu_meihap[31:2],2'b0});
assign exu_lsu_rs1_d[31:0] = ({32{~i0_rs1_bypass_en_d & ~dec_extint_stall & dec_i0_rs1_en_d & dec_qual_lsu_d}} & gpr_i0_rs1_d[31:0] ) |
({32{ i0_rs1_bypass_en_d & ~dec_extint_stall & dec_qual_lsu_d}} & i0_rs1_bypass_data_d[31:0]) |
({32{ dec_extint_stall & dec_qual_lsu_d}} & {dec_tlu_meihap[31:2],2'b0});
assign exu_lsu_rs2_d[31:0] = ({32{~i0_rs2_bypass_en_d & ~dec_extint_stall & dec_i0_rs2_en_d}} & gpr_i0_rs2_d[31:0] ) |
({32{ i0_rs2_bypass_en_d & ~dec_extint_stall }} & i0_rs2_bypass_data_d[31:0]);
assign exu_lsu_rs2_d[31:0] = ({32{~i0_rs2_bypass_en_d & ~dec_extint_stall & dec_i0_rs2_en_d & dec_qual_lsu_d}} & gpr_i0_rs2_d[31:0] ) |
({32{ i0_rs2_bypass_en_d & ~dec_extint_stall & dec_qual_lsu_d}} & i0_rs2_bypass_data_d[31:0]);
assign muldiv_rs1_d[31:0] = ({32{~i0_rs1_bypass_en_d & dec_i0_rs1_en_d}} & gpr_i0_rs1_d[31:0] ) |
({32{ i0_rs1_bypass_en_d }} & i0_rs1_bypass_data_d[31:0]);
assign muldiv_rs2_d[31:0] = ({32{~i0_rs2_bypass_en_d & dec_i0_rs2_en_d}} & gpr_i0_rs2_d[31:0] ) |
({32{~i0_rs2_bypass_en_d }} & dec_i0_immed_d[31:0] ) |
({32{ i0_rs2_bypass_en_d }} & i0_rs2_bypass_data_d[31:0]);
assign csr_rs1_in_d[31:0] = ( dec_csr_ren_d ) ? i0_rs1_d[31:0] : exu_csr_rs1_x[31:0];
assign x_data_en = dec_data_en[1];
assign x_data_en_q1 = dec_data_en[1] & dec_csr_ren_d;
assign x_data_en_q2 = dec_data_en[1] & dec_i0_branch_d;
assign r_data_en = dec_data_en[0];
assign r_data_en_q2 = dec_data_en[0] & i0_branch_x;
assign x_ctl_en = dec_ctl_en[1];
assign r_ctl_en = dec_ctl_en[0];
@ -240,7 +231,7 @@ import el2_pkg::*;
el2_exu_alu_ctl #(.pt(pt)) i_alu (.*,
.enable ( x_ctl_en ), // I
.enable ( x_data_en ), // I
.pp_in ( i0_predict_newp_d ), // I
.valid_in ( dec_i0_alu_decode_d ), // I
.flush_upper_x ( i0_flush_upper_x ), // I
@ -251,6 +242,7 @@ import el2_pkg::*;
.brimm_in ( dec_i0_br_immed_d[12:1] ), // I
.ap ( i0_ap ), // I
.csr_ren_in ( dec_csr_ren_d ), // I
.csr_rddata_in ( dec_csr_rddata_d[31:0] ), // I
.result_ff ( alu_result_x[31:0] ), // O
.flush_upper_out ( i0_flush_upper_d ), // O
.flush_final_out ( exu_flush_final ), // O
@ -262,9 +254,9 @@ import el2_pkg::*;
el2_exu_mul_ctl #(.pt(pt)) i_mul (.*,
.mul_p ( mul_p ), // I
.rs1_in ( muldiv_rs1_d[31:0] ), // I
.rs2_in ( muldiv_rs2_d[31:0] ), // I
.mul_p ( mul_p & {$bits(el2_mul_pkt_t){mul_p.valid}} ), // I
.rs1_in ( muldiv_rs1_d[31:0] & {32{mul_p.valid}} ), // I
.rs2_in ( i0_rs2_d[31:0] & {32{mul_p.valid}} ), // I
.result_x ( mul_result_x[31:0] )); // O
@ -273,7 +265,7 @@ import el2_pkg::*;
.cancel ( dec_div_cancel ), // I
.dp ( div_p ), // I
.dividend ( muldiv_rs1_d[31:0] ), // I
.divisor ( muldiv_rs2_d[31:0] ), // I
.divisor ( i0_rs2_d[31:0] ), // I
.finish_dly ( exu_div_wren ), // O
.out ( exu_div_result[31:0] )); // O
@ -298,7 +290,7 @@ import el2_pkg::*;
assign i0_valid_d = i0_predict_p_d.valid & dec_i0_alu_decode_d & ~dec_tlu_flush_lower_r;
assign i0_taken_d = (i0_predict_p_d.ataken & dec_i0_alu_decode_d);
if(pt.BTB_ENABLE==1) begin
// maintain GHR at D
assign ghr_d_ns[pt.BHT_GHR_SIZE-1:0]
= ({pt.BHT_GHR_SIZE{~dec_tlu_flush_lower_r & i0_valid_d}} & {ghr_d[pt.BHT_GHR_SIZE-2:0], i0_taken_d}) |
@ -314,7 +306,7 @@ import el2_pkg::*;
assign exu_i0_br_valid_r = i0_pp_r.valid;
assign exu_i0_br_mp_r = i0_pp_r.misp;
assign exu_i0_br_way_r = i0_pp_r.way;
assign exu_i0_br_hist_r[1:0] = i0_pp_r.hist[1:0];
assign exu_i0_br_hist_r[1:0] = {2{i0_pp_r.valid}} & i0_pp_r.hist[1:0];
assign exu_i0_br_error_r = i0_pp_r.br_error;
assign exu_i0_br_middle_r = i0_pp_r.pc4 ^ i0_pp_r.boffset;
assign exu_i0_br_start_error_r = i0_pp_r.br_start_error;
@ -330,6 +322,7 @@ import el2_pkg::*;
assign after_flush_eghr[pt.BHT_GHR_SIZE-1:0] = (i0_flush_upper_x & ~dec_tlu_flush_lower_r) ? ghr_d[pt.BHT_GHR_SIZE-1:0] : ghr_x[pt.BHT_GHR_SIZE-1:0];
assign exu_mp_pkt.valid = final_predict_mp.valid;
assign exu_mp_pkt.way = final_predict_mp.way;
assign exu_mp_pkt.misp = final_predict_mp.misp;
assign exu_mp_pkt.pcall = final_predict_mp.pcall;
@ -347,11 +340,30 @@ import el2_pkg::*;
exu_mp_btag[pt.BTB_BTAG_SIZE-1:0]} = final_predpipe_mp[PREDPIPESIZE-pt.BHT_GHR_SIZE-1:0];
assign exu_mp_eghr[pt.BHT_GHR_SIZE-1:0] = final_predpipe_mp[PREDPIPESIZE-1:pt.BTB_ADDR_HI-pt.BTB_ADDR_LO+pt.BTB_BTAG_SIZE+1]; // mp ghr for bht write
end // if (pt.BTB_ENABLE==1)
else begin
assign ghr_d_ns = '0;
assign ghr_x_ns = '0;
assign exu_mp_pkt = '0;
assign exu_mp_eghr = '0;
assign exu_mp_fghr = '0;
assign exu_mp_index = '0;
assign exu_mp_btag = '0;
assign exu_i0_br_hist_r = '0;
assign exu_i0_br_error_r = '0;
assign exu_i0_br_start_error_r = '0;
assign exu_i0_br_index_r = '0;
assign exu_i0_br_valid_r = '0;
assign exu_i0_br_mp_r = '0;
assign exu_i0_br_middle_r = '0;
assign exu_i0_br_fghr_r = '0;
assign exu_i0_br_way_r = '0;
end // else: !if(pt.BTB_ENABLE==1)
assign exu_flush_path_final[31:1] = (dec_tlu_flush_lower_r) ? dec_tlu_flush_path_r[31:1] : i0_flush_path_d[31:1];
assign exu_flush_path_final[31:1] = ( {31{ dec_tlu_flush_lower_r }} & dec_tlu_flush_path_r[31:1] ) |
( {31{~dec_tlu_flush_lower_r & i0_flush_upper_d}} & i0_flush_path_d[31:1] );
assign exu_npc_r[31:1] = (i0_pred_correct_upper_r) ? pred_correct_npc_r[31:1] :
i0_flush_path_upper_r[31:1];
assign exu_npc_r[31:1] = (i0_pred_correct_upper_r) ? pred_correct_npc_r[31:1] : i0_flush_path_upper_r[31:1];
endmodule // el2_exu

View File

@ -1,5 +1,5 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 Western Digital Corporation or it's affiliates.
// Copyright 2020 Western Digital Corporation or its affiliates.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -29,7 +29,8 @@ import el2_pkg::*;
input logic enable, // Clock enable
input logic valid_in, // Valid
input el2_alu_pkt_t ap, // predecodes
input logic csr_ren_in, // extra decode
input logic csr_ren_in, // CSR select
input logic [31:0] csr_rddata_in, // CSR data
input logic signed [31:0] a_in, // A operand
input logic [31:0] b_in, // B operand
input logic [31:1] pc_in, // for pc=pc+2,4 calculations
@ -47,13 +48,10 @@ import el2_pkg::*;
);
logic [31:0] zba_a_in;
logic [31:0] aout;
logic cout,ov,neg;
logic [31:0] lout;
logic [5:0] shift_amount;
logic [31:0] shift_mask;
logic [62:0] shift_extend;
logic [62:0] shift_long;
logic [31:0] sout;
logic sel_shift;
logic sel_adder;
@ -72,10 +70,148 @@ import el2_pkg::*;
// *** Start - BitManip ***
// Zbb
logic ap_clz;
logic ap_ctz;
logic ap_pcnt;
logic ap_sext_b;
logic ap_sext_h;
logic ap_min;
logic ap_max;
logic ap_pack;
logic ap_packu;
logic ap_packh;
logic ap_rol;
logic ap_ror;
logic ap_rev;
logic ap_rev8;
logic ap_orc_b;
logic ap_orc16;
logic ap_zbb;
// Zbs
logic ap_sbset;
logic ap_sbclr;
logic ap_sbinv;
logic ap_sbext;
// Zbr
logic ap_slo;
logic ap_sro;
// Zba
logic ap_sh1add;
logic ap_sh2add;
logic ap_sh3add;
logic ap_zba;
rvdffe #(31) i_pc_ff (.*, .en(enable), .din(pc_in[31:1]), .dout(pc_ff[31:1])); // any PC is run through here - doesn't have to be alu
rvdffe #(32) i_result_ff (.*, .en(enable), .din(result[31:0]), .dout(result_ff[31:0]));
if (pt.BITMANIP_ZBB == 1)
begin
assign ap_clz = ap.clz;
assign ap_ctz = ap.ctz;
assign ap_pcnt = ap.pcnt;
assign ap_sext_b = ap.sext_b;
assign ap_sext_h = ap.sext_h;
assign ap_min = ap.min;
assign ap_max = ap.max;
end
else
begin
assign ap_clz = 1'b0;
assign ap_ctz = 1'b0;
assign ap_pcnt = 1'b0;
assign ap_sext_b = 1'b0;
assign ap_sext_h = 1'b0;
assign ap_min = 1'b0;
assign ap_max = 1'b0;
end
if ( (pt.BITMANIP_ZBB == 1) | (pt.BITMANIP_ZBP == 1) )
begin
assign ap_pack = ap.pack;
assign ap_packu = ap.packu;
assign ap_packh = ap.packh;
assign ap_rol = ap.rol;
assign ap_ror = ap.ror;
assign ap_rev = ap.grev & (b_in[4:0] == 5'b11111);
assign ap_rev8 = ap.grev & (b_in[4:0] == 5'b11000);
assign ap_orc_b = ap.gorc & (b_in[4:0] == 5'b00111);
assign ap_orc16 = ap.gorc & (b_in[4:0] == 5'b10000);
assign ap_zbb = ap.zbb;
end
else
begin
assign ap_pack = 1'b0;
assign ap_packu = 1'b0;
assign ap_packh = 1'b0;
assign ap_rol = 1'b0;
assign ap_ror = 1'b0;
assign ap_rev = 1'b0;
assign ap_rev8 = 1'b0;
assign ap_orc_b = 1'b0;
assign ap_orc16 = 1'b0;
assign ap_zbb = 1'b0;
end
if (pt.BITMANIP_ZBS == 1)
begin
assign ap_sbset = ap.sbset;
assign ap_sbclr = ap.sbclr;
assign ap_sbinv = ap.sbinv;
assign ap_sbext = ap.sbext;
end
else
begin
assign ap_sbset = 1'b0;
assign ap_sbclr = 1'b0;
assign ap_sbinv = 1'b0;
assign ap_sbext = 1'b0;
end
if (pt.BITMANIP_ZBP == 1)
begin
assign ap_slo = ap.slo;
assign ap_sro = ap.sro;
end
else
begin
assign ap_slo = 1'b0;
assign ap_sro = 1'b0;
end
if (pt.BITMANIP_ZBA == 1)
begin
assign ap_sh1add = ap.sh1add;
assign ap_sh2add = ap.sh2add;
assign ap_sh3add = ap.sh3add;
assign ap_zba = ap.zba;
end
else
begin
assign ap_sh1add = 1'b0;
assign ap_sh2add = 1'b0;
assign ap_sh3add = 1'b0;
assign ap_zba = 1'b0;
end
// *** End - BitManip ***
rvdffpcie #(31) i_pc_ff (.*, .clk(clk), .en(enable), .din(pc_in[31:1]), .dout(pc_ff[31:1])); // any PC is run through here - doesn't have to be alu
rvdffe #(32) i_result_ff (.*, .clk(clk), .en(enable & valid_in), .din(result[31:0]), .dout(result_ff[31:0]));
@ -106,11 +242,17 @@ import el2_pkg::*;
// jalr => rs1=rs1, rs2=sext(offset20:1]); rd=pc+[2,4]
assign zba_a_in[31:0] = ( {32{ ap_sh1add}} & {a_in[30:0],1'b0} ) |
( {32{ ap_sh2add}} & {a_in[29:0],2'b0} ) |
( {32{ ap_sh3add}} & {a_in[28:0],3'b0} ) |
( {32{~ap_zba }} & a_in[31:0] );
logic [31:0] bm;
assign bm[31:0] = ( ap.sub ) ? ~b_in[31:0] : b_in[31:0];
assign {cout, aout[31:0]} = {1'b0, a_in[31:0]} + {1'b0, bm[31:0]} + {32'b0, ap.sub};
assign {cout, aout[31:0]} = {1'b0, zba_a_in[31:0]} + {1'b0, bm[31:0]} + {32'b0, ap.sub};
assign ov = (~a_in[31] & ~bm[31] & aout[31]) |
( a_in[31] & bm[31] & ~aout[31] );
@ -118,7 +260,6 @@ import el2_pkg::*;
assign lt = (~ap.unsign & (neg ^ ov)) |
( ap.unsign & ~cout);
assign eq = (a_in[31:0] == b_in[31:0]);
assign ne = ~eq;
assign neg = aout[31];
@ -126,39 +267,227 @@ import el2_pkg::*;
assign lout[31:0] = ( {32{csr_ren_in}} & b_in[31:0] ) |
( {32{ap.land }} & a_in[31:0] & b_in[31:0] ) |
( {32{ap.lor }} & (a_in[31:0] | b_in[31:0]) ) |
( {32{ap.lxor }} & (a_in[31:0] ^ b_in[31:0]) );
assign lout[31:0] = ( {32{csr_ren_in }} & csr_rddata_in[31:0] ) |
( {32{ap.land & ~ap_zbb}} & a_in[31:0] & b_in[31:0] ) |
( {32{ap.lor & ~ap_zbb}} & (a_in[31:0] | b_in[31:0]) ) |
( {32{ap.lxor & ~ap_zbb}} & (a_in[31:0] ^ b_in[31:0]) ) |
( {32{ap.land & ap_zbb}} & a_in[31:0] & ~b_in[31:0] ) |
( {32{ap.lor & ap_zbb}} & (a_in[31:0] | ~b_in[31:0]) ) |
( {32{ap.lxor & ap_zbb}} & (a_in[31:0] ^ ~b_in[31:0]) );
// * * * * * * * * * * * * * * * * * * BitManip : SLO,SRO * * * * * * * * * * * * * * * * * *
// * * * * * * * * * * * * * * * * * * BitManip : ROL,ROR * * * * * * * * * * * * * * * * * *
// * * * * * * * * * * * * * * * * * * BitManip : ZBEXT * * * * * * * * * * * * * * * * * *
logic [5:0] shift_amount;
logic [31:0] shift_mask;
logic [62:0] shift_extend;
logic [62:0] shift_long;
assign shift_amount[5:0] = ( { 6{ap.sll}} & (6'd32 - {1'b0,b_in[4:0]}) ) | // [5] unused
( { 6{ap.srl}} & {1'b0,b_in[4:0]} ) |
( { 6{ap.sra}} & {1'b0,b_in[4:0]} );
( { 6{ap.sra}} & {1'b0,b_in[4:0]} ) |
( { 6{ap_rol}} & (6'd32 - {1'b0,b_in[4:0]}) ) |
( { 6{ap_ror}} & {1'b0,b_in[4:0]} ) |
( { 6{ap_slo}} & (6'd32 - {1'b0,b_in[4:0]}) ) |
( { 6{ap_sro}} & {1'b0,b_in[4:0]} ) |
( { 6{ap_sbext}} & {1'b0,b_in[4:0]} );
assign shift_mask[31:0] = ( 32'hffffffff << ({5{ap.sll}} & b_in[4:0]) );
assign shift_mask[31:0] = ( 32'hffffffff << ({5{ap.sll | ap_slo}} & b_in[4:0]) );
assign shift_extend[31:0] = a_in[31:0];
assign shift_extend[62:32] = ( {31{ap.sra}} & {31{a_in[31]}} ) |
( {31{ap.sll}} & a_in[30:0] );
( {31{ap.sll}} & a_in[30:0] ) |
( {31{ap_rol}} & a_in[30:0] ) |
( {31{ap_ror}} & a_in[30:0] ) |
( {31{ap_slo}} & a_in[30:0] ) |
( {31{ap_sro}} & {31{ 1'b1 }} );
assign shift_long[62:0] = ( shift_extend[62:0] >> shift_amount[4:0] ); // 62-32 unused
assign sout[31:0] = ( shift_long[31:0] & shift_mask[31:0] );
assign sout[31:0] = ( shift_long[31:0] & shift_mask[31:0] ) | ( {32{ap_slo}} & ~shift_mask[31:0] );
// * * * * * * * * * * * * * * * * * * BitManip : CLZ,CTZ * * * * * * * * * * * * * * * * * *
logic bitmanip_clz_ctz_sel;
logic [31:0] bitmanip_a_reverse_ff;
logic [31:0] bitmanip_lzd_in;
logic [5:0] bitmanip_dw_lzd_enc;
logic [5:0] bitmanip_clz_ctz_result;
assign bitmanip_clz_ctz_sel = ap_clz | ap_ctz;
assign bitmanip_a_reverse_ff[31:0] = {a_in[0], a_in[1], a_in[2], a_in[3], a_in[4], a_in[5], a_in[6], a_in[7],
a_in[8], a_in[9], a_in[10], a_in[11], a_in[12], a_in[13], a_in[14], a_in[15],
a_in[16], a_in[17], a_in[18], a_in[19], a_in[20], a_in[21], a_in[22], a_in[23],
a_in[24], a_in[25], a_in[26], a_in[27], a_in[28], a_in[29], a_in[30], a_in[31]};
assign bitmanip_lzd_in[31:0] = ( {32{ap_clz}} & a_in[31:0] ) |
( {32{ap_ctz}} & bitmanip_a_reverse_ff[31:0]);
logic [31:0] bitmanip_lzd_os;
integer i;
logic found;
always_comb
begin
bitmanip_lzd_os[31:0] = bitmanip_lzd_in[31:0];
bitmanip_dw_lzd_enc[5:0]= 6'b0;
found = 1'b0;
for (int i=0; i<32 && found==0; i++) begin
if (bitmanip_lzd_os[31] == 1'b0) begin
bitmanip_dw_lzd_enc[5:0]= bitmanip_dw_lzd_enc[5:0] + 6'b00_0001;
bitmanip_lzd_os[31:0] = bitmanip_lzd_os[31:0] << 1;
end
else
found=1'b1;
end
end
assign bitmanip_clz_ctz_result[5:0] = {6{bitmanip_clz_ctz_sel}} & {bitmanip_dw_lzd_enc[5],( {5{~bitmanip_dw_lzd_enc[5]}} & bitmanip_dw_lzd_enc[4:0] )};
// * * * * * * * * * * * * * * * * * * BitManip : PCNT * * * * * * * * * * * * * * * * * *
logic [5:0] bitmanip_pcnt;
logic [5:0] bitmanip_pcnt_result;
integer bitmanip_pcnt_i;
always_comb
begin
bitmanip_pcnt[5:0] = 6'b0;
for (bitmanip_pcnt_i=0; bitmanip_pcnt_i<32; bitmanip_pcnt_i++)
begin
bitmanip_pcnt[5:0] = bitmanip_pcnt[5:0] + {5'b0,a_in[bitmanip_pcnt_i]};
end // FOR bitmanip_pcnt_i
end // ALWAYS_COMB
assign bitmanip_pcnt_result[5:0] = {6{ap_pcnt}} & bitmanip_pcnt[5:0];
// * * * * * * * * * * * * * * * * * * BitManip : SEXT_B,SEXT_H * * * * * * * * * * * * * * * * *
logic [31:0] bitmanip_sext_result;
assign bitmanip_sext_result[31:0] = ( {32{ap_sext_b}} & { {24{a_in[7]}} ,a_in[7:0] } ) |
( {32{ap_sext_h}} & { {16{a_in[15]}},a_in[15:0] } );
// * * * * * * * * * * * * * * * * * * BitManip : MIN,MAX,MINU,MAXU * * * * * * * * * * * * * * *
logic bitmanip_minmax_sel;
logic [31:0] bitmanip_minmax_result;
assign bitmanip_minmax_sel = ap_min | ap_max;
logic bitmanip_minmax_sel_a;
assign bitmanip_minmax_sel_a = ge ^ ap_min;
assign bitmanip_minmax_result[31:0] = ({32{bitmanip_minmax_sel & bitmanip_minmax_sel_a}} & a_in[31:0]) |
({32{bitmanip_minmax_sel & ~bitmanip_minmax_sel_a}} & b_in[31:0]);
// * * * * * * * * * * * * * * * * * * BitManip : PACK, PACKU, PACKH * * * * * * * * * * * * * * *
logic [31:0] bitmanip_pack_result;
logic [31:0] bitmanip_packu_result;
logic [31:0] bitmanip_packh_result;
assign bitmanip_pack_result[31:0] = {32{ap_pack}} & {b_in[15:0], a_in[15:0]};
assign bitmanip_packu_result[31:0] = {32{ap_packu}} & {b_in[31:16],a_in[31:16]};
assign bitmanip_packh_result[31:0] = {32{ap_packh}} & {16'b0,b_in[7:0],a_in[7:0]};
// * * * * * * * * * * * * * * * * * * BitManip : REV, REV8, ORC_B * * * * * * * * * * * * * * * *
logic [31:0] bitmanip_rev_result;
logic [31:0] bitmanip_rev8_result;
logic [31:0] bitmanip_orc_b_result;
logic [31:0] bitmanip_orc16_result;
assign bitmanip_rev_result[31:0] = {32{ap_rev}} &
{a_in[00],a_in[01],a_in[02],a_in[03],a_in[04],a_in[05],a_in[06],a_in[07],
a_in[08],a_in[09],a_in[10],a_in[11],a_in[12],a_in[13],a_in[14],a_in[15],
a_in[16],a_in[17],a_in[18],a_in[19],a_in[20],a_in[21],a_in[22],a_in[23],
a_in[24],a_in[25],a_in[26],a_in[27],a_in[28],a_in[29],a_in[30],a_in[31]};
assign bitmanip_rev8_result[31:0] = {32{ap_rev8}} & {a_in[7:0],a_in[15:8],a_in[23:16],a_in[31:24]};
// uint32_t gorc32(uint32_t rs1, uint32_t rs2)
// {
// uint32_t x = rs1;
// int shamt = rs2 & 31; ORC.B ORC16
// if (shamt & 1) x |= ((x & 0x55555555) << 1) | ((x & 0xAAAAAAAA) >> 1); 1 0
// if (shamt & 2) x |= ((x & 0x33333333) << 2) | ((x & 0xCCCCCCCC) >> 2); 1 0
// if (shamt & 4) x |= ((x & 0x0F0F0F0F) << 4) | ((x & 0xF0F0F0F0) >> 4); 1 0
// if (shamt & 8) x |= ((x & 0x00FF00FF) << 8) | ((x & 0xFF00FF00) >> 8); 0 0
// if (shamt & 16) x |= ((x & 0x0000FFFF) << 16) | ((x & 0xFFFF0000) >> 16); 0 1
// return x;
// }
// BEFORE 31 , 30 , 29 , 28 , 27 , 26, 25, 24
// shamt[0] b = a31|a30,a31|a30,a29|a28,a29|a28, a27|a26,a27|a26,a25|a24,a25|a24
// shamt[1] c = b31|b29,b30|b28,b31|b29,b30|b28, b27|b25,b26|b24,b27|b25,b26|b24
// shamt[2] d = c31|c27,c30|c26,c29|c25,c28|c24, c31|c27,c30|c26,c29|c25,c28|c24
//
// Expand d31 = c31 | c27;
// = b31 | b29 | b27 | b25;
// = a31|a30 | a29|a28 | a27|a26 | a25|a24
assign bitmanip_orc_b_result[31:0] = {32{ap_orc_b}} & { {8{| a_in[31:24]}}, {8{| a_in[23:16]}}, {8{| a_in[15:8]}}, {8{| a_in[7:0]}} };
assign bitmanip_orc16_result[31:0] = {32{ap_orc16}} & { {a_in[31:16] | a_in[15:0]}, {a_in[31:16] | a_in[15:0]} };
// * * * * * * * * * * * * * * * * * * BitManip : ZBSET, ZBCLR, ZBINV * * * * * * * * * * * * * *
logic [31:0] bitmanip_sb_1hot;
logic [31:0] bitmanip_sb_data;
assign bitmanip_sb_1hot[31:0] = ( 32'h00000001 << b_in[4:0] );
assign bitmanip_sb_data[31:0] = ( {32{ap_sbset}} & ( a_in[31:0] | bitmanip_sb_1hot[31:0]) ) |
( {32{ap_sbclr}} & ( a_in[31:0] & ~bitmanip_sb_1hot[31:0]) ) |
( {32{ap_sbinv}} & ( a_in[31:0] ^ bitmanip_sb_1hot[31:0]) );
assign sel_shift = ap.sll | ap.srl | ap.sra;
assign sel_adder = (ap.add | ap.sub) & ~ap.slt;
assign sel_shift = ap.sll | ap.srl | ap.sra | ap_slo | ap_sro | ap_rol | ap_ror;
assign sel_adder = (ap.add | ap.sub | ap_zba) & ~ap.slt & ~ap_min & ~ap_max;
assign sel_pc = ap.jal | pp_in.pcall | pp_in.pja | pp_in.pret;
assign csr_write_data[31:0]= (ap.csr_imm) ? b_in[31:0] : a_in[31:0];
@ -171,7 +500,20 @@ import el2_pkg::*;
({32{sel_adder}} & aout[31:0] ) |
({32{sel_pc}} & {pcout[31:1],1'b0} ) |
({32{ap.csr_write}} & csr_write_data[31:0] ) |
{31'b0, slt_one} ;
{31'b0, slt_one} |
({32{ap_sbext}} & {31'b0, sout[0]} ) |
{26'b0, bitmanip_clz_ctz_result[5:0]} |
{26'b0, bitmanip_pcnt_result[5:0]} |
bitmanip_sext_result[31:0] |
bitmanip_minmax_result[31:0] |
bitmanip_pack_result[31:0] |
bitmanip_packu_result[31:0] |
bitmanip_packh_result[31:0] |
bitmanip_rev_result[31:0] |
bitmanip_rev8_result[31:0] |
bitmanip_orc_b_result[31:0] |
bitmanip_orc16_result[31:0] |
bitmanip_sb_data[31:0];

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 Western Digital Corporation or it's affiliates.
// Copyright 2020 Western Digital Corporation or its affiliates.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -35,6 +35,7 @@ import el2_pkg::*;
logic mul_x_enable;
logic bit_x_enable;
logic signed [32:0] rs1_ext_in;
logic signed [32:0] rs2_ext_in;
logic [65:0] prod_x;
@ -42,8 +43,116 @@ import el2_pkg::*;
// *** Start - BitManip ***
logic bitmanip_sel_d;
logic bitmanip_sel_x;
logic [31:0] bitmanip_d;
logic [31:0] bitmanip_x;
// ZBE
logic ap_bext;
logic ap_bdep;
// ZBC
logic ap_clmul;
logic ap_clmulh;
logic ap_clmulr;
// ZBP
logic ap_grev;
logic ap_gorc;
logic ap_shfl;
logic ap_unshfl;
// ZBR
logic ap_crc32_b;
logic ap_crc32_h;
logic ap_crc32_w;
logic ap_crc32c_b;
logic ap_crc32c_h;
logic ap_crc32c_w;
// ZBF
logic ap_bfp;
if (pt.BITMANIP_ZBE == 1)
begin
assign ap_bext = mul_p.bext;
assign ap_bdep = mul_p.bdep;
end
else
begin
assign ap_bext = 1'b0;
assign ap_bdep = 1'b0;
end
if (pt.BITMANIP_ZBC == 1)
begin
assign ap_clmul = mul_p.clmul;
assign ap_clmulh = mul_p.clmulh;
assign ap_clmulr = mul_p.clmulr;
end
else
begin
assign ap_clmul = 1'b0;
assign ap_clmulh = 1'b0;
assign ap_clmulr = 1'b0;
end
if (pt.BITMANIP_ZBP == 1)
begin
assign ap_grev = mul_p.grev;
assign ap_gorc = mul_p.gorc;
assign ap_shfl = mul_p.shfl;
assign ap_unshfl = mul_p.unshfl;
end
else
begin
assign ap_grev = 1'b0;
assign ap_gorc = 1'b0;
assign ap_shfl = 1'b0;
assign ap_unshfl = 1'b0;
end
if (pt.BITMANIP_ZBR == 1)
begin
assign ap_crc32_b = mul_p.crc32_b;
assign ap_crc32_h = mul_p.crc32_h;
assign ap_crc32_w = mul_p.crc32_w;
assign ap_crc32c_b = mul_p.crc32c_b;
assign ap_crc32c_h = mul_p.crc32c_h;
assign ap_crc32c_w = mul_p.crc32c_w;
end
else
begin
assign ap_crc32_b = 1'b0;
assign ap_crc32_h = 1'b0;
assign ap_crc32_w = 1'b0;
assign ap_crc32c_b = 1'b0;
assign ap_crc32c_h = 1'b0;
assign ap_crc32c_w = 1'b0;
end
if (pt.BITMANIP_ZBF == 1)
begin
assign ap_bfp = mul_p.bfp;
end
else
begin
assign ap_bfp = 1'b0;
end
// *** End - BitManip ***
assign mul_x_enable = mul_p.valid;
assign bit_x_enable = mul_p.valid;
assign rs1_ext_in[32] = mul_p.rs1_sign & rs1_in[31];
assign rs2_ext_in[32] = mul_p.rs2_sign & rs2_in[31];
@ -59,17 +168,460 @@ import el2_pkg::*;
logic signed [32:0] rs1_x;
logic signed [32:0] rs2_x;
rvdffe #(34) i_a_x_ff (.*, .din({mul_p.low,rs1_ext_in[32:0]}), .dout({low_x,rs1_x[32:0]}), .en(mul_x_enable));
rvdffe #(33) i_b_x_ff (.*, .din( rs2_ext_in[32:0] ), .dout( rs2_x[32:0] ), .en(mul_x_enable));
rvdffe #(34) i_a_x_ff (.*, .clk(clk), .din({mul_p.low,rs1_ext_in[32:0]}), .dout({low_x,rs1_x[32:0]}), .en(mul_x_enable));
rvdffe #(33) i_b_x_ff (.*, .clk(clk), .din( rs2_ext_in[32:0] ), .dout( rs2_x[32:0] ), .en(mul_x_enable));
assign prod_x[65:0] = rs1_x * rs2_x;
assign result_x[31:0] = ( {32{~low_x}} & prod_x[63:32] ) |
( {32{ low_x}} & prod_x[31:0] );
// * * * * * * * * * * * * * * * * * * BitManip : BEXT, BDEP * * * * * * * * * * * * * * * * * *
// *** BEXT == "gather" ***
logic [31:0] bext_d;
logic bext_test_bit_d;
integer bext_i, bext_j;
always_comb
begin
bext_j = 0;
bext_test_bit_d = 1'b0;
bext_d[31:0] = 32'b0;
for (bext_i=0; bext_i<32; bext_i++)
begin
bext_test_bit_d = rs2_in[bext_i];
if (bext_test_bit_d)
begin
bext_d[bext_j] = rs1_in[bext_i];
bext_j = bext_j + 1;
end // IF bext_test_bit
end // FOR bext_i
end // ALWAYS_COMB
// *** BDEP == "scatter" ***
logic [31:0] bdep_d;
logic bdep_test_bit_d;
integer bdep_i, bdep_j;
always_comb
begin
bdep_j = 0;
bdep_test_bit_d = 1'b0;
bdep_d[31:0] = 32'b0;
for (bdep_i=0; bdep_i<32; bdep_i++)
begin
bdep_test_bit_d = rs2_in[bdep_i];
if (bdep_test_bit_d)
begin
bdep_d[bdep_i] = rs1_in[bdep_j];
bdep_j = bdep_j + 1;
end // IF bdep_test_bit
end // FOR bdep_i
end // ALWAYS_COMB
// * * * * * * * * * * * * * * * * * * BitManip : CLMUL, CLMULH, CLMULR * * * * * * * * * * * * *
logic [62:0] clmul_raw_d;
assign clmul_raw_d[62:0] = ( {63{rs2_in[00]}} & {31'b0,rs1_in[31:0] } ) ^
( {63{rs2_in[01]}} & {30'b0,rs1_in[31:0], 1'b0} ) ^
( {63{rs2_in[02]}} & {29'b0,rs1_in[31:0], 2'b0} ) ^
( {63{rs2_in[03]}} & {28'b0,rs1_in[31:0], 3'b0} ) ^
( {63{rs2_in[04]}} & {27'b0,rs1_in[31:0], 4'b0} ) ^
( {63{rs2_in[05]}} & {26'b0,rs1_in[31:0], 5'b0} ) ^
( {63{rs2_in[06]}} & {25'b0,rs1_in[31:0], 6'b0} ) ^
( {63{rs2_in[07]}} & {24'b0,rs1_in[31:0], 7'b0} ) ^
( {63{rs2_in[08]}} & {23'b0,rs1_in[31:0], 8'b0} ) ^
( {63{rs2_in[09]}} & {22'b0,rs1_in[31:0], 9'b0} ) ^
( {63{rs2_in[10]}} & {21'b0,rs1_in[31:0],10'b0} ) ^
( {63{rs2_in[11]}} & {20'b0,rs1_in[31:0],11'b0} ) ^
( {63{rs2_in[12]}} & {19'b0,rs1_in[31:0],12'b0} ) ^
( {63{rs2_in[13]}} & {18'b0,rs1_in[31:0],13'b0} ) ^
( {63{rs2_in[14]}} & {17'b0,rs1_in[31:0],14'b0} ) ^
( {63{rs2_in[15]}} & {16'b0,rs1_in[31:0],15'b0} ) ^
( {63{rs2_in[16]}} & {15'b0,rs1_in[31:0],16'b0} ) ^
( {63{rs2_in[17]}} & {14'b0,rs1_in[31:0],17'b0} ) ^
( {63{rs2_in[18]}} & {13'b0,rs1_in[31:0],18'b0} ) ^
( {63{rs2_in[19]}} & {12'b0,rs1_in[31:0],19'b0} ) ^
( {63{rs2_in[20]}} & {11'b0,rs1_in[31:0],20'b0} ) ^
( {63{rs2_in[21]}} & {10'b0,rs1_in[31:0],21'b0} ) ^
( {63{rs2_in[22]}} & { 9'b0,rs1_in[31:0],22'b0} ) ^
( {63{rs2_in[23]}} & { 8'b0,rs1_in[31:0],23'b0} ) ^
( {63{rs2_in[24]}} & { 7'b0,rs1_in[31:0],24'b0} ) ^
( {63{rs2_in[25]}} & { 6'b0,rs1_in[31:0],25'b0} ) ^
( {63{rs2_in[26]}} & { 5'b0,rs1_in[31:0],26'b0} ) ^
( {63{rs2_in[27]}} & { 4'b0,rs1_in[31:0],27'b0} ) ^
( {63{rs2_in[28]}} & { 3'b0,rs1_in[31:0],28'b0} ) ^
( {63{rs2_in[29]}} & { 2'b0,rs1_in[31:0],29'b0} ) ^
( {63{rs2_in[30]}} & { 1'b0,rs1_in[31:0],30'b0} ) ^
( {63{rs2_in[31]}} & { rs1_in[31:0],31'b0} );
// * * * * * * * * * * * * * * * * * * BitManip : GREV * * * * * * * * * * * * * * * * * *
// uint32_t grev32(uint32_t rs1, uint32_t rs2)
// {
// uint32_t x = rs1;
// int shamt = rs2 & 31;
//
// if (shamt & 1) x = ( (x & 0x55555555) << 1) | ( (x & 0xAAAAAAAA) >> 1);
// if (shamt & 2) x = ( (x & 0x33333333) << 2) | ( (x & 0xCCCCCCCC) >> 2);
// if (shamt & 4) x = ( (x & 0x0F0F0F0F) << 4) | ( (x & 0xF0F0F0F0) >> 4);
// if (shamt & 8) x = ( (x & 0x00FF00FF) << 8) | ( (x & 0xFF00FF00) >> 8);
// if (shamt & 16) x = ( (x & 0x0000FFFF) << 16) | ( (x & 0xFFFF0000) >> 16);
//
// return x;
// }
logic [31:0] grev1_d;
logic [31:0] grev2_d;
logic [31:0] grev4_d;
logic [31:0] grev8_d;
logic [31:0] grev_d;
assign grev1_d[31:0] = (rs2_in[0]) ? {rs1_in[30],rs1_in[31],rs1_in[28],rs1_in[29],rs1_in[26],rs1_in[27],rs1_in[24],rs1_in[25],
rs1_in[22],rs1_in[23],rs1_in[20],rs1_in[21],rs1_in[18],rs1_in[19],rs1_in[16],rs1_in[17],
rs1_in[14],rs1_in[15],rs1_in[12],rs1_in[13],rs1_in[10],rs1_in[11],rs1_in[08],rs1_in[09],
rs1_in[06],rs1_in[07],rs1_in[04],rs1_in[05],rs1_in[02],rs1_in[03],rs1_in[00],rs1_in[01]} : rs1_in[31:0];
assign grev2_d[31:0] = (rs2_in[1]) ? {grev1_d[29:28],grev1_d[31:30],grev1_d[25:24],grev1_d[27:26],
grev1_d[21:20],grev1_d[23:22],grev1_d[17:16],grev1_d[19:18],
grev1_d[13:12],grev1_d[15:14],grev1_d[09:08],grev1_d[11:10],
grev1_d[05:04],grev1_d[07:06],grev1_d[01:00],grev1_d[03:02]} : grev1_d[31:0];
assign grev4_d[31:0] = (rs2_in[2]) ? {grev2_d[27:24],grev2_d[31:28],grev2_d[19:16],grev2_d[23:20],
grev2_d[11:08],grev2_d[15:12],grev2_d[03:00],grev2_d[07:04]} : grev2_d[31:0];
assign grev8_d[31:0] = (rs2_in[3]) ? {grev4_d[23:16],grev4_d[31:24],grev4_d[07:00],grev4_d[15:08]} : grev4_d[31:0];
assign grev_d[31:0] = (rs2_in[4]) ? {grev8_d[15:00],grev8_d[31:16]} : grev8_d[31:0];
// * * * * * * * * * * * * * * * * * * BitManip : GORC * * * * * * * * * * * * * * * * * *
// uint32_t gorc32(uint32_t rs1, uint32_t rs2)
// {
// uint32_t x = rs1;
// int shamt = rs2 & 31;
//
// if (shamt & 1) x |= ( (x & 0x55555555) << 1) | ( (x & 0xAAAAAAAA) >> 1);
// if (shamt & 2) x |= ( (x & 0x33333333) << 2) | ( (x & 0xCCCCCCCC) >> 2);
// if (shamt & 4) x |= ( (x & 0x0F0F0F0F) << 4) | ( (x & 0xF0F0F0F0) >> 4);
// if (shamt & 8) x |= ( (x & 0x00FF00FF) << 8) | ( (x & 0xFF00FF00) >> 8);
// if (shamt & 16) x |= ( (x & 0x0000FFFF) << 16) | ( (x & 0xFFFF0000) >> 16);
//
// return x;
// }
logic [31:0] gorc1_d;
logic [31:0] gorc2_d;
logic [31:0] gorc4_d;
logic [31:0] gorc8_d;
logic [31:0] gorc_d;
assign gorc1_d[31:0] = ( {32{rs2_in[0]}} & {rs1_in[30],rs1_in[31],rs1_in[28],rs1_in[29],rs1_in[26],rs1_in[27],rs1_in[24],rs1_in[25],
rs1_in[22],rs1_in[23],rs1_in[20],rs1_in[21],rs1_in[18],rs1_in[19],rs1_in[16],rs1_in[17],
rs1_in[14],rs1_in[15],rs1_in[12],rs1_in[13],rs1_in[10],rs1_in[11],rs1_in[08],rs1_in[09],
rs1_in[06],rs1_in[07],rs1_in[04],rs1_in[05],rs1_in[02],rs1_in[03],rs1_in[00],rs1_in[01]} ) | rs1_in[31:0];
assign gorc2_d[31:0] = ( {32{rs2_in[1]}} & {gorc1_d[29:28],gorc1_d[31:30],gorc1_d[25:24],gorc1_d[27:26],
gorc1_d[21:20],gorc1_d[23:22],gorc1_d[17:16],gorc1_d[19:18],
gorc1_d[13:12],gorc1_d[15:14],gorc1_d[09:08],gorc1_d[11:10],
gorc1_d[05:04],gorc1_d[07:06],gorc1_d[01:00],gorc1_d[03:02]} ) | gorc1_d[31:0];
assign gorc4_d[31:0] = ( {32{rs2_in[2]}} & {gorc2_d[27:24],gorc2_d[31:28],gorc2_d[19:16],gorc2_d[23:20],
gorc2_d[11:08],gorc2_d[15:12],gorc2_d[03:00],gorc2_d[07:04]} ) | gorc2_d[31:0];
assign gorc8_d[31:0] = ( {32{rs2_in[3]}} & {gorc4_d[23:16],gorc4_d[31:24],gorc4_d[07:00],gorc4_d[15:08]} ) | gorc4_d[31:0];
assign gorc_d[31:0] = ( {32{rs2_in[4]}} & {gorc8_d[15:00],gorc8_d[31:16]} ) | gorc8_d[31:0];
// * * * * * * * * * * * * * * * * * * BitManip : SHFL, UNSHLF * * * * * * * * * * * * * * * * * *
// uint32_t shuffle32_stage (uint32_t src, uint32_t maskL, uint32_t maskR, int N)
// {
// uint32_t x = src & ~(maskL | maskR);
// x |= ((src << N) & maskL) | ((src >> N) & maskR);
// return x;
// }
//
//
//
// uint32_t shfl32(uint32_t rs1, uint32_t rs2)
// {
// uint32_t x = rs1;
// int shamt = rs2 & 15
//
// if (shamt & 8) x = shuffle32_stage(x, 0x00ff0000, 0x0000ff00, 8);
// if (shamt & 4) x = shuffle32_stage(x, 0x0f000f00, 0x00f000f0, 4);
// if (shamt & 2) x = shuffle32_stage(x, 0x30303030, 0xc0c0c0c0, 2);
// if (shamt & 1) x = shuffle32_stage(x, 0x44444444, 0x22222222, 1);
//
// return x;
// }
logic [31:0] shfl8_d;
logic [31:0] shfl4_d;
logic [31:0] shfl2_d;
logic [31:0] shfl_d;
assign shfl8_d[31:0] = (rs2_in[3]) ? {rs1_in[31:24],rs1_in[15:08],rs1_in[23:16],rs1_in[07:00]} : rs1_in[31:0];
assign shfl4_d[31:0] = (rs2_in[2]) ? {shfl8_d[31:28],shfl8_d[23:20],shfl8_d[27:24],shfl8_d[19:16],
shfl8_d[15:12],shfl8_d[07:04],shfl8_d[11:08],shfl8_d[03:00]} : shfl8_d[31:0];
assign shfl2_d[31:0] = (rs2_in[1]) ? {shfl4_d[31:30],shfl4_d[27:26],shfl4_d[29:28],shfl4_d[25:24],
shfl4_d[23:22],shfl4_d[19:18],shfl4_d[21:20],shfl4_d[17:16],
shfl4_d[15:14],shfl4_d[11:10],shfl4_d[13:12],shfl4_d[09:08],
shfl4_d[07:06],shfl4_d[03:02],shfl4_d[05:04],shfl4_d[01:00]} : shfl4_d[31:0];
assign shfl_d[31:0] = (rs2_in[0]) ? {shfl2_d[31],shfl2_d[29],shfl2_d[30],shfl2_d[28],shfl2_d[27],shfl2_d[25],shfl2_d[26],shfl2_d[24],
shfl2_d[23],shfl2_d[21],shfl2_d[22],shfl2_d[20],shfl2_d[19],shfl2_d[17],shfl2_d[18],shfl2_d[16],
shfl2_d[15],shfl2_d[13],shfl2_d[14],shfl2_d[12],shfl2_d[11],shfl2_d[09],shfl2_d[10],shfl2_d[08],
shfl2_d[07],shfl2_d[05],shfl2_d[06],shfl2_d[04],shfl2_d[03],shfl2_d[01],shfl2_d[02],shfl2_d[00]} : shfl2_d[31:0];
// uint32_t unshfl32(uint32_t rs1, uint32_t rs2)
// {
// uint32_t x = rs1;
// int shamt = rs2 & 15
//
// if (shamt & 1) x = shuffle32_stage(x, 0x44444444, 0x22222222, 1);
// if (shamt & 2) x = shuffle32_stage(x, 0x30303030, 0xc0c0c0c0, 2);
// if (shamt & 4) x = shuffle32_stage(x, 0x0f000f00, 0x00f000f0, 4);
// if (shamt & 8) x = shuffle32_stage(x, 0x00ff0000, 0x0000ff00, 8);
//
// return x;
// }
logic [31:0] unshfl1_d;
logic [31:0] unshfl2_d;
logic [31:0] unshfl4_d;
logic [31:0] unshfl_d;
assign unshfl1_d[31:0] = (rs2_in[0]) ? {rs1_in[31],rs1_in[29],rs1_in[30],rs1_in[28],rs1_in[27],rs1_in[25],rs1_in[26],rs1_in[24],
rs1_in[23],rs1_in[21],rs1_in[22],rs1_in[20],rs1_in[19],rs1_in[17],rs1_in[18],rs1_in[16],
rs1_in[15],rs1_in[13],rs1_in[14],rs1_in[12],rs1_in[11],rs1_in[09],rs1_in[10],rs1_in[08],
rs1_in[07],rs1_in[05],rs1_in[06],rs1_in[04],rs1_in[03],rs1_in[01],rs1_in[02],rs1_in[00]} : rs1_in[31:0];
assign unshfl2_d[31:0] = (rs2_in[1]) ? {unshfl1_d[31:30],unshfl1_d[27:26],unshfl1_d[29:28],unshfl1_d[25:24],
unshfl1_d[23:22],unshfl1_d[19:18],unshfl1_d[21:20],unshfl1_d[17:16],
unshfl1_d[15:14],unshfl1_d[11:10],unshfl1_d[13:12],unshfl1_d[09:08],
unshfl1_d[07:06],unshfl1_d[03:02],unshfl1_d[05:04],unshfl1_d[01:00]} : unshfl1_d[31:0];
assign unshfl4_d[31:0] = (rs2_in[2]) ? {unshfl2_d[31:28],unshfl2_d[23:20],unshfl2_d[27:24],unshfl2_d[19:16],
unshfl2_d[15:12],unshfl2_d[07:04],unshfl2_d[11:08],unshfl2_d[03:00]} : unshfl2_d[31:0];
assign unshfl_d[31:0] = (rs2_in[3]) ? {unshfl4_d[31:24],unshfl4_d[15:08],unshfl4_d[23:16],unshfl4_d[07:00]} : unshfl4_d[31:0];
// * * * * * * * * * * * * * * * * * * BitManip : CRC32, CRC32c * * * * * * * * * * * * * * * * *
// *** computed from https: //crccalc.com ***
//
// "a" is 8'h61 = 8'b0110_0001 (8'h61 ^ 8'hff = 8'h9e)
//
// Input must first be XORed with 32'hffff_ffff
//
//
// CRC32
//
// Input Output Input Output
// ----- -------- -------- --------
// "a" e8b7be43 ffffff9e 174841bc
// "aa" 078a19d7 ffff9e9e f875e628
// "aaaa" ad98e545 9e9e9e9e 5267a1ba
//
//
//
// CRC32c
//
// Input Output Input Output
// ----- -------- -------- --------
// "a" c1d04330 ffffff9e 3e2fbccf
// "aa" f1f2dac2 ffff9e9e 0e0d253d
// "aaaa" 6a52eeb0 9e9e9e9e 95ad114f
logic crc32_all;
logic [31:0] crc32_poly_rev;
logic [31:0] crc32c_poly_rev;
integer crc32_bi, crc32_hi, crc32_wi, crc32c_bi, crc32c_hi, crc32c_wi;
logic [31:0] crc32_bd, crc32_hd, crc32_wd, crc32c_bd, crc32c_hd, crc32c_wd;
assign crc32_all = ap_crc32_b | ap_crc32_h | ap_crc32_w | ap_crc32c_b | ap_crc32c_h | ap_crc32c_w;
assign crc32_poly_rev[31:0] = 32'hEDB88320; // bit reverse of 32'h04C11DB7
assign crc32c_poly_rev[31:0] = 32'h82F63B78; // bit reverse of 32'h1EDC6F41
always_comb
begin
crc32_bd[31:0] = rs1_in[31:0];
for (crc32_bi=0; crc32_bi<8; crc32_bi++)
begin
crc32_bd[31:0] = (crc32_bd[31:0] >> 1) ^ (crc32_poly_rev[31:0] & {32{crc32_bd[0]}});
end // FOR crc32_bi
end // ALWAYS_COMB
always_comb
begin
crc32_hd[31:0] = rs1_in[31:0];
for (crc32_hi=0; crc32_hi<16; crc32_hi++)
begin
crc32_hd[31:0] = (crc32_hd[31:0] >> 1) ^ (crc32_poly_rev[31:0] & {32{crc32_hd[0]}});
end // FOR crc32_hi
end // ALWAYS_COMB
always_comb
begin
crc32_wd[31:0] = rs1_in[31:0];
for (crc32_wi=0; crc32_wi<32; crc32_wi++)
begin
crc32_wd[31:0] = (crc32_wd[31:0] >> 1) ^ (crc32_poly_rev[31:0] & {32{crc32_wd[0]}});
end // FOR crc32_wi
end // ALWAYS_COMB
always_comb
begin
crc32c_bd[31:0] = rs1_in[31:0];
for (crc32c_bi=0; crc32c_bi<8; crc32c_bi++)
begin
crc32c_bd[31:0] = (crc32c_bd[31:0] >> 1) ^ (crc32c_poly_rev[31:0] & {32{crc32c_bd[0]}});
end // FOR crc32c_bi
end // ALWAYS_COMB
always_comb
begin
crc32c_hd[31:0] = rs1_in[31:0];
for (crc32c_hi=0; crc32c_hi<16; crc32c_hi++)
begin
crc32c_hd[31:0] = (crc32c_hd[31:0] >> 1) ^ (crc32c_poly_rev[31:0] & {32{crc32c_hd[0]}});
end // FOR crc32c_hi
end // ALWAYS_COMB
always_comb
begin
crc32c_wd[31:0] = rs1_in[31:0];
for (crc32c_wi=0; crc32c_wi<32; crc32c_wi++)
begin
crc32c_wd[31:0] = (crc32c_wd[31:0] >> 1) ^ (crc32c_poly_rev[31:0] & {32{crc32c_wd[0]}});
end // FOR crc32c_wi
end // ALWAYS_COMB
// * * * * * * * * * * * * * * * * * * BitManip : BFP * * * * * * * * * * * * * * * * * *
logic [4:0] bfp_len;
logic [4:0] bfp_off;
logic [31:0] bfp_len_mask_;
logic [15:0] bfp_preshift_data;
logic [63:0] bfp_shift_data;
logic [63:0] bfp_shift_mask;
logic [31:0] bfp_result_d;
assign bfp_len[3:0] = rs2_in[27:24];
assign bfp_len[4] = (bfp_len[3:0] == 4'b0); // If LEN field is zero, then LEN=16
assign bfp_off[4:0] = rs2_in[20:16];
assign bfp_len_mask_[31:0] = 32'hffff_ffff << bfp_len[4:0];
assign bfp_preshift_data[15:0]= rs2_in[15:0] & ~bfp_len_mask_[15:0];
assign bfp_shift_data[63:0] = {16'b0,bfp_preshift_data[15:0], 16'b0,bfp_preshift_data[15:0]} << bfp_off[4:0];
assign bfp_shift_mask[63:0] = {bfp_len_mask_[31:0], bfp_len_mask_[31:0]} << bfp_off[4:0];
assign bfp_result_d[31:0] = bfp_shift_data[63:32] | (rs1_in[31:0] & bfp_shift_mask[63:32]);
// * * * * * * * * * * * * * * * * * * BitManip : Common logic * * * * * * * * * * * * * * * * * *
assign bitmanip_sel_d = ap_bext | ap_bdep | ap_clmul | ap_clmulh | ap_clmulr | ap_grev | ap_gorc | ap_shfl | ap_unshfl | crc32_all | ap_bfp;
assign bitmanip_d[31:0] = ( {32{ap_bext}} & bext_d[31:0] ) |
( {32{ap_bdep}} & bdep_d[31:0] ) |
( {32{ap_clmul}} & clmul_raw_d[31:0] ) |
( {32{ap_clmulh}} & {1'b0,clmul_raw_d[62:32]} ) |
( {32{ap_clmulr}} & clmul_raw_d[62:31] ) |
( {32{ap_grev}} & grev_d[31:0] ) |
( {32{ap_gorc}} & gorc_d[31:0] ) |
( {32{ap_shfl}} & shfl_d[31:0] ) |
( {32{ap_unshfl}} & unshfl_d[31:0] ) |
( {32{ap_crc32_b}} & crc32_bd[31:0] ) |
( {32{ap_crc32_h}} & crc32_hd[31:0] ) |
( {32{ap_crc32_w}} & crc32_wd[31:0] ) |
( {32{ap_crc32c_b}} & crc32c_bd[31:0] ) |
( {32{ap_crc32c_h}} & crc32c_hd[31:0] ) |
( {32{ap_crc32c_w}} & crc32c_wd[31:0] ) |
( {32{ap_bfp}} & bfp_result_d[31:0] );
rvdffe #(33) i_bitmanip_ff (.*, .clk(clk), .din({bitmanip_sel_d,bitmanip_d[31:0]}), .dout({bitmanip_sel_x,bitmanip_x[31:0]}), .en(bit_x_enable));
assign result_x[31:0] = ( {32{~bitmanip_sel_x & ~low_x}} & prod_x[63:32] ) |
( {32{~bitmanip_sel_x & low_x}} & prod_x[31:0] ) |
bitmanip_x[31:0];
endmodule // el2_exu_mul_ctl

63
design/flist.formal Normal file
View File

@ -0,0 +1,63 @@
#-*-dotf-*-
$RV_ROOT/design/include/el2_def.sv
+incdir+$RV_ROOT/design/lib
+incdir+$RV_ROOT/design/include
+incdir+$RV_ROOT/design/dmi
//|+incdir+$SYNOPSYS_SYN_ROOT/dw/sim_ver
//|-y $SYNOPSYS_SYN_ROOT/dw/sim_ver
//|
//|$SYNOPSYS_SYN_ROOT/dw/sim_ver/DW01_addsub.v
//|$SYNOPSYS_SYN_ROOT/dw/sim_ver/DW_lzd.v
//|$SYNOPSYS_SYN_ROOT/dw/sim_ver/DW_minmax.v
//|$SYNOPSYS_SYN_ROOT/dw/sim_ver/DW02_mult.v
+incdir+/wdc/apps/mentor/questa/formal/2019.2/share/MODIFIED/dw
+incdir+/wdc/apps/mentor/questa/formal/2019.2/share/MODIFIED/dw/dw_datapath
/wdc/apps/mentor/questa/formal/2019.2/share/MODIFIED/dw/dw.remodel.v
$RV_ROOT/design/el2_swerv_wrapper.sv
$RV_ROOT/design/el2_mem.sv
$RV_ROOT/design/el2_pic_ctrl.sv
$RV_ROOT/design/el2_swerv.sv
$RV_ROOT/design/el2_dma_ctrl.sv
$RV_ROOT/design/ifu/el2_ifu_aln_ctl.sv
$RV_ROOT/design/ifu/el2_ifu_compress_ctl.sv
$RV_ROOT/design/ifu/el2_ifu_ifc_ctl.sv
$RV_ROOT/design/ifu/el2_ifu_bp_ctl.sv
$RV_ROOT/design/ifu/el2_ifu_ic_mem.sv
$RV_ROOT/design/ifu/el2_ifu_mem_ctl.sv
$RV_ROOT/design/ifu/el2_ifu_iccm_mem.sv
$RV_ROOT/design/ifu/el2_ifu.sv
$RV_ROOT/design/dec/el2_dec_decode_ctl.sv
$RV_ROOT/design/dec/el2_dec_gpr_ctl.sv
$RV_ROOT/design/dec/el2_dec_ib_ctl.sv
$RV_ROOT/design/dec/el2_dec_tlu_ctl.sv
$RV_ROOT/design/dec/el2_dec_trigger.sv
$RV_ROOT/design/dec/el2_dec.sv
$RV_ROOT/design/exu/el2_exu_alu_ctl.sv
$RV_ROOT/design/exu/el2_exu_mul_ctl.sv
$RV_ROOT/design/exu/el2_exu_div_ctl.sv
$RV_ROOT/design/exu/el2_exu.sv
$RV_ROOT/design/lsu/el2_lsu.sv
$RV_ROOT/design/lsu/el2_lsu_clkdomain.sv
$RV_ROOT/design/lsu/el2_lsu_addrcheck.sv
$RV_ROOT/design/lsu/el2_lsu_lsc_ctl.sv
$RV_ROOT/design/lsu/el2_lsu_stbuf.sv
$RV_ROOT/design/lsu/el2_lsu_bus_buffer.sv
$RV_ROOT/design/lsu/el2_lsu_bus_intf.sv
$RV_ROOT/design/lsu/el2_lsu_ecc.sv
$RV_ROOT/design/lsu/el2_lsu_dccm_mem.sv
$RV_ROOT/design/lsu/el2_lsu_dccm_ctl.sv
$RV_ROOT/design/lsu/el2_lsu_trigger.sv
$RV_ROOT/design/dbg/el2_dbg.sv
$RV_ROOT/design/dmi/dmi_wrapper.v
$RV_ROOT/design/dmi/dmi_jtag_to_core_sync.v
$RV_ROOT/design/dmi/rvjtag_tap.v
$RV_ROOT/design/lib/el2_lib.sv
$RV_ROOT/design/lib/beh_lib.sv
$RV_ROOT/design/lib/mem_lib.sv
$RV_ROOT/design/lib/ahb_to_axi4.sv
$RV_ROOT/design/lib/axi4_to_ahb.sv

61
design/flist.questa Normal file
View File

@ -0,0 +1,61 @@
#-*-dotf-*-
# $RV_ROOT/workspace/work/snapshots/default/common_defines.vh
# $RV_ROOT/configs/snapshots/default/common_defines.vh
$RV_ROOT/workspace/work/snapshots/default/common_defines.vh
$RV_ROOT/design/include/el2_def.sv
# +incdir+$RV_ROOT/workspace/work/snapshots/default
# +incdir+$RV_ROOT/configs/snapshots/default
+incdir+$RV_ROOT/workspace/work/snapshots/default
+incdir+$RV_ROOT/design/lib
+incdir+$RV_ROOT/design/include
+incdir+$RV_ROOT/design/dmi
+incdir+$SYNOPSYS_SYN_ROOT/dw/sim_ver
-y $SYNOPSYS_SYN_ROOT/dw/sim_ver
$RV_ROOT/design/el2_swerv_wrapper.sv
$RV_ROOT/design/el2_mem.sv
$RV_ROOT/design/el2_pic_ctrl.sv
$RV_ROOT/design/el2_swerv.sv
$RV_ROOT/design/el2_dma_ctrl.sv
$RV_ROOT/design/ifu/el2_ifu_aln_ctl.sv
$RV_ROOT/design/ifu/el2_ifu_compress_ctl.sv
$RV_ROOT/design/ifu/el2_ifu_ifc_ctl.sv
$RV_ROOT/design/ifu/el2_ifu_bp_ctl.sv
$RV_ROOT/design/ifu/el2_ifu_ic_mem.sv
$RV_ROOT/design/ifu/el2_ifu_mem_ctl.sv
$RV_ROOT/design/ifu/el2_ifu_iccm_mem.sv
$RV_ROOT/design/ifu/el2_ifu.sv
$RV_ROOT/design/dec/el2_dec_decode_ctl.sv
$RV_ROOT/design/dec/el2_dec_gpr_ctl.sv
$RV_ROOT/design/dec/el2_dec_ib_ctl.sv
$RV_ROOT/design/dec/el2_dec_tlu_ctl.sv
$RV_ROOT/design/dec/el2_dec_trigger.sv
$RV_ROOT/design/dec/el2_dec.sv
$RV_ROOT/design/exu/el2_exu_alu_ctl.sv
$RV_ROOT/design/exu/el2_exu_mul_ctl.sv
$RV_ROOT/design/exu/el2_exu_div_ctl.sv
$RV_ROOT/design/exu/el2_exu.sv
$RV_ROOT/design/lsu/el2_lsu.sv
$RV_ROOT/design/lsu/el2_lsu_clkdomain.sv
$RV_ROOT/design/lsu/el2_lsu_addrcheck.sv
$RV_ROOT/design/lsu/el2_lsu_lsc_ctl.sv
$RV_ROOT/design/lsu/el2_lsu_stbuf.sv
$RV_ROOT/design/lsu/el2_lsu_bus_buffer.sv
$RV_ROOT/design/lsu/el2_lsu_bus_intf.sv
$RV_ROOT/design/lsu/el2_lsu_ecc.sv
$RV_ROOT/design/lsu/el2_lsu_dccm_mem.sv
$RV_ROOT/design/lsu/el2_lsu_dccm_ctl.sv
$RV_ROOT/design/lsu/el2_lsu_trigger.sv
$RV_ROOT/design/dbg/el2_dbg.sv
$RV_ROOT/design/dmi/dmi_wrapper.v
$RV_ROOT/design/dmi/dmi_jtag_to_core_sync.v
$RV_ROOT/design/dmi/rvjtag_tap.v
$RV_ROOT/design/lib/el2_lib.sv
$RV_ROOT/design/lib/beh_lib.sv
$RV_ROOT/design/lib/mem_lib.sv
$RV_ROOT/design/lib/ahb_to_axi4.sv
$RV_ROOT/design/lib/axi4_to_ahb.sv

View File

@ -1,6 +1,6 @@
//********************************************************************************
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 Western Digital Corporation or it's affiliates.
// Copyright 2020 Western Digital Corporation or its affiliates.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -25,12 +25,12 @@ import el2_pkg::*;
`include "el2_param.vh"
)
(
input logic free_clk,
input logic active_clk,
input logic clk,
input logic rst_l,
input logic free_l2clk, // Clock always. Through one clock header. For flops with second header built in.
input logic active_clk, // Clock only while core active. Through two clock headers. For flops without second clock header built in.
input logic clk, // Clock only while core active. Through one clock header. For flops with second clock header built in. Connected to ACTIVE_L2CLK.
input logic rst_l, // reset, active low
input logic dec_i0_decode_d,
input logic dec_i0_decode_d, // Valid instruction at D and not blocked
input logic exu_flush_final, // flush, includes upper and lower
input logic dec_tlu_i0_commit_cmt , // committed i0
@ -87,7 +87,6 @@ import el2_pkg::*;
input logic [63:0] ifu_axi_rdata,
input logic [1:0] ifu_axi_rresp,
input logic ifu_bus_clk_en,
input logic dma_iccm_req,
@ -160,24 +159,24 @@ import el2_pkg::*;
output logic ifu_pmu_bus_trxn, // iside bus transactions
output logic ifu_i0_icaf, // Instructio 0 access fault. From Aligner to Decode
output logic ifu_i0_icaf, // Instruction 0 access fault. From Aligner to Decode
output logic [1:0] ifu_i0_icaf_type, // Instruction 0 access fault type
output logic ifu_i0_valid, // Instructio 0 valid. From Aligner to Decode
output logic ifu_i0_icaf_f1, // Instruction 0 has access fault on second fetch group
output logic ifu_i0_valid, // Instruction 0 valid. From Aligner to Decode
output logic ifu_i0_icaf_second, // Instruction 0 has access fault on second 2B of 4B inst
output logic ifu_i0_dbecc, // Instruction 0 has double bit ecc error
output logic iccm_dma_sb_error, // Single Bit ECC error from a DMA access
output logic[31:0] ifu_i0_instr, // Instructio 0 . From Aligner to Decode
output logic[31:1] ifu_i0_pc, // Instructio 0 pc. From Aligner to Decode
output logic ifu_i0_pc4, // Instructio 0 is 4 byte. From Aligner to Decode
output logic[31:0] ifu_i0_instr, // Instruction 0 . From Aligner to Decode
output logic[31:1] ifu_i0_pc, // Instruction 0 pc. From Aligner to Decode
output logic ifu_i0_pc4, // Instruction 0 is 4 byte. From Aligner to Decode
output logic ifu_miss_state_idle, // There is no outstanding miss. Cache miss state is idle.
output el2_br_pkt_t i0_brp, // Instructio 0 branch packet. From Aligner to Decode
output el2_br_pkt_t i0_brp, // Instruction 0 branch packet. From Aligner to Decode
output logic [pt.BTB_ADDR_HI:pt.BTB_ADDR_LO] ifu_i0_bp_index, // BP index
output logic [pt.BHT_GHR_SIZE-1:0] ifu_i0_bp_fghr, // BP FGHR
output logic [pt.BTB_BTAG_SIZE-1:0] ifu_i0_bp_btag, // BP tag
output logic [$clog2(pt.BTB_SIZE)-1:0] ifu_i0_fa_index, // Fully associt btb index
input el2_predict_pkt_t exu_mp_pkt, // mispredict packet
input logic [pt.BHT_GHR_SIZE-1:0] exu_mp_eghr, // execute ghr
@ -188,11 +187,13 @@ import el2_pkg::*;
input el2_br_tlu_pkt_t dec_tlu_br0_r_pkt, // slot0 update/error pkt
input logic [pt.BHT_GHR_SIZE-1:0] exu_i0_br_fghr_r, // fghr to bp
input logic [pt.BTB_ADDR_HI:pt.BTB_ADDR_LO] exu_i0_br_index_r, // bp index
input logic [$clog2(pt.BTB_SIZE)-1:0] dec_fa_error_index, // Fully associt btb error index
input dec_tlu_flush_lower_wb,
output logic [15:0] ifu_i0_cinst,
/// Icache debug
input el2_cache_debug_pkt_t dec_tlu_ic_diag_pkt ,
output logic ifu_ic_debug_rd_data_valid,
@ -220,22 +221,16 @@ import el2_pkg::*;
logic ic_write_stall;
logic ic_dma_active;
logic ifc_dma_access_ok;
logic ic_access_fault_f;
logic [1:0] ic_access_fault_f;
logic [1:0] ic_access_fault_type_f;
logic ifu_ic_mb_empty;
logic ic_hit_f;
// fetch control
el2_ifu_ifc_ctl #(.pt(pt)) ifc (.*
);
logic [1:0] ifu_bp_way_f; // way indication; right justified
logic ifu_bp_hit_taken_f; // kill next fetch; taken target found
logic [31:1] ifu_bp_btb_target_f; // predicted target PC
logic ifu_bp_inst_mask_f; // tell ic which valids to kill because of a taken branch; right justified
logic [1:0] ifu_bp_hist1_f; // history counters for all 4 potential branches; right justified
logic [1:0] ifu_bp_hist0_f; // history counters for all 4 potential branches; right justified
logic [11:0] ifu_bp_poffset_f; // predicted target
@ -243,9 +238,28 @@ import el2_pkg::*;
logic [1:0] ifu_bp_pc4_f; // pc4 indication; right justified
logic [1:0] ifu_bp_valid_f; // branch valid, right justified
logic [pt.BHT_GHR_SIZE-1:0] ifu_bp_fghr_f;
logic [1:0] [$clog2(pt.BTB_SIZE)-1:0] ifu_bp_fa_index_f;
// fetch control
el2_ifu_ifc_ctl #(.pt(pt)) ifc (.*
);
// branch predictor
if (pt.BTB_ENABLE==1) begin : bpred
el2_ifu_bp_ctl #(.pt(pt)) bp (.*);
end
else begin : bpred
assign ifu_bp_hit_taken_f = '0;
// verif wires
logic btb_wr_en_way0, btb_wr_en_way1,dec_tlu_error_wb;
logic [16+pt.BTB_BTAG_SIZE:0] btb_wr_data;
assign btb_wr_en_way0 = '0;
assign btb_wr_en_way1 = '0;
assign btb_wr_data = '0;
assign dec_tlu_error_wb ='0;
assign ifu_bp_inst_mask_f = 1'b1;
end
logic [1:0] ic_fetch_val_f;
@ -253,7 +267,7 @@ import el2_pkg::*;
logic [31:0] ifu_fetch_data_f;
logic ifc_fetch_req_f;
logic ifc_fetch_req_f_raw;
logic iccm_rd_ecc_double_err; // This fetch has an iccm double error.
logic [1:0] iccm_rd_ecc_double_err; // This fetch has an iccm double error.
logic ifu_async_error_start;
@ -269,7 +283,10 @@ import el2_pkg::*;
logic ifc_region_acc_fault_bf; // Access fault. in ICCM region but offset is outside defined ICCM.
// aligner
el2_ifu_aln_ctl #(.pt(pt)) aln (.*);
el2_ifu_aln_ctl #(.pt(pt)) aln (
.*
);
// icache
@ -316,29 +333,29 @@ import el2_pkg::*;
logic exu_flush_final_d1;
assign mppc_ns[31:1] = `EXU.i0_flush_upper_x ? `EXU.exu_i0_pc_x : `EXU.dec_i0_pc_d;
assign mppc_ns[0] = 1'b0;
rvdff #(33) mdseal_ff (.*, .din({mppc_ns[31:0], exu_flush_final}), .dout({mppc[31:0], exu_flush_final_d1}));
rvdff #(33) junk_ff (.*, .clk(active_clk), .din({mppc_ns[31:0], exu_flush_final}), .dout({mppc[31:0], exu_flush_final_d1}));
logic tmp_bnk;
assign tmp_bnk = bp.btb_sel_f[1];
assign tmp_bnk = bpred.bp.btb_sel_f[1];
always @(negedge clk) begin
if(`DEC.tlu.mcyclel[31:0] == 32'h0000_0010) begin
$display("BTB_CONFIG: %d",pt.BTB_ARRAY_DEPTH*4);
$display("BTB_CONFIG: %d",pt.BTB_SIZE);
`ifndef BP_NOGSHARE
$display("BHT_CONFIG: %d gshare: 1",pt.BHT_ARRAY_DEPTH*4);
$display("BHT_CONFIG: %d gshare: 1",pt.BHT_SIZE);
`else
$display("BHT_CONFIG: %d gshare: 0",pt.BHT_ARRAY_DEPTH*4);
$display("BHT_CONFIG: %d gshare: 0",pt.BHT_SIZE);
`endif
$display("RS_CONFIG: %d", pt.RET_STACK_SIZE);
end
if(exu_flush_final_d1 & ~(dec_tlu_br0_r_pkt.br_error | dec_tlu_br0_r_pkt.br_start_error) & (exu_mp_pkt.misp | exu_mp_pkt.ataken))
$display("%7d BTB_MP : index: %0h bank: %0h call: %b ret: %b ataken: %b hist: %h valid: %b tag: %h targ: %h eghr: %b pred: %b ghr_index: %h brpc: %h way: %h", `DEC.tlu.mcyclel[31:0]+32'ha, exu_mp_addr[pt.BTB_ADDR_HI:pt.BTB_ADDR_LO], 1'b0, exu_mp_call, exu_mp_ret, exu_mp_ataken, exu_mp_hist[1:0], exu_mp_valid, exu_mp_btag[pt.BTB_BTAG_SIZE-1:0], {exu_flush_path_final[31:1], 1'b0}, exu_mp_eghr[pt.BHT_GHR_SIZE-1:0], exu_mp_valid, bp.bht_wr_addr0, mppc[31:0], exu_mp_pkt.way);
$display("%7d BTB_MP : index: %0h bank: %0h call: %b ret: %b ataken: %b hist: %h valid: %b tag: %h targ: %h eghr: %b pred: %b ghr_index: %h brpc: %h way: %h", `DEC.tlu.mcyclel[31:0]+32'ha, exu_mp_addr[pt.BTB_ADDR_HI:pt.BTB_ADDR_LO], 1'b0, exu_mp_call, exu_mp_ret, exu_mp_ataken, exu_mp_hist[1:0], exu_mp_valid, exu_mp_btag[pt.BTB_BTAG_SIZE-1:0], {exu_flush_path_final[31:1], 1'b0}, exu_mp_eghr[pt.BHT_GHR_SIZE-1:0], exu_mp_valid, bpred.bp.bht_wr_addr0, mppc[31:0], exu_mp_pkt.way);
for(int i = 0; i < 8; i++) begin
if(ifu_bp_valid_f[i] & ifc_fetch_req_f)
$display("%7d BTB_HIT : index: %0h bank: %0h call: %b ret: %b taken: %b strength: %b tag: %h targ: %0h ghr: %4b ghr_index: %h way: %h", `DEC.tlu.mcyclel[31:0]+32'ha,btb_rd_addr_f[pt.BTB_ADDR_HI:pt.BTB_ADDR_LO],bp.btb_sel_f[1], bp.btb_rd_call_f, bp.btb_rd_ret_f, ifu_bp_hist1_f[tmp_bnk], ifu_bp_hist0_f[tmp_bnk], bp.fetch_rd_tag_f[pt.BTB_BTAG_SIZE-1:0], {ifu_bp_btb_target_f[31:1], 1'b0}, bp.fghr[pt.BHT_GHR_SIZE-1:0], bp.bht_rd_addr_f, ifu_bp_way_f[tmp_bnk]);
$display("%7d BTB_HIT : index: %0h bank: %0h call: %b ret: %b taken: %b strength: %b tag: %h targ: %0h ghr: %4b ghr_index: %h way: %h", `DEC.tlu.mcyclel[31:0]+32'ha,btb_rd_addr_f[pt.BTB_ADDR_HI:pt.BTB_ADDR_LO],bpred.bp.btb_sel_f[1], bpred.bp.btb_rd_call_f, bpred.bp.btb_rd_ret_f, ifu_bp_hist1_f[tmp_bnk], ifu_bp_hist0_f[tmp_bnk], bpred.bp.fetch_rd_tag_f[pt.BTB_BTAG_SIZE-1:0], {ifu_bp_btb_target_f[31:1], 1'b0}, bpred.bp.fghr[pt.BHT_GHR_SIZE-1:0], bpred.bp.bht_rd_addr_f, ifu_bp_way_f[tmp_bnk]);
end
if(dec_tlu_br0_r_pkt.valid & ~(dec_tlu_br0_r_pkt.br_error | dec_tlu_br0_r_pkt.br_start_error))
$display("%7d BTB_UPD0: ghr_index: %0h bank: %0h hist: %h way: %h", `DEC.tlu.mcyclel[31:0]+32'ha,bp.br0_hashed_wb[pt.BHT_ADDR_HI:pt.BHT_ADDR_LO],{dec_tlu_br0_r_pkt.middle}, dec_tlu_br0_r_pkt.hist, dec_tlu_br0_r_pkt.way);
$display("%7d BTB_UPD0: ghr_index: %0h bank: %0h hist: %h way: %h", `DEC.tlu.mcyclel[31:0]+32'ha,bpred.bp.br0_hashed_wb[pt.BHT_ADDR_HI:pt.BHT_ADDR_LO],{dec_tlu_br0_r_pkt.middle}, dec_tlu_br0_r_pkt.hist, dec_tlu_br0_r_pkt.way);
if(dec_tlu_br0_r_pkt.br_error | dec_tlu_br0_r_pkt.br_start_error)
$display("%7d BTB_ERR0: index: %0h bank: %0h start: %b rfpc: %h way: %h", `DEC.tlu.mcyclel[31:0]+32'ha,exu_i0_br_index_r[pt.BTB_ADDR_HI:pt.BTB_ADDR_LO],1'b0, dec_tlu_br0_r_pkt.br_start_error, {exu_flush_path_final[31:1], 1'b0}, dec_tlu_br0_r_pkt.way);

View File

@ -1,6 +1,6 @@
//********************************************************************************
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 Western Digital Corporation or it's affiliates.
// Copyright 2020 Western Digital Corporation or its affiliates.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -25,31 +25,21 @@ import el2_pkg::*;
)
(
input logic scan_mode,
input logic rst_l,
input logic clk,
input logic active_clk,
input logic scan_mode, // Flop scan mode control
input logic rst_l, // reset, active low
input logic clk, // Clock only while core active. Through one clock header. For flops with second clock header built in. Connected to ACTIVE_L2CLK.
input logic active_clk, // Clock only while core active. Through two clock headers. For flops without second clock header built in.
input logic ifu_async_error_start, // ecc/parity related errors with current fetch - not sent down the pipe
input logic iccm_rd_ecc_double_err, // This fetch has a double ICCM ecc error.
input logic [1:0] iccm_rd_ecc_double_err, // This fetch has a double ICCM ecc error.
input logic ic_access_fault_f, // Instruction access fault for the current fetch.
input logic [1:0] ic_access_fault_f, // Instruction access fault for the current fetch.
input logic [1:0] ic_access_fault_type_f, // Instruction access fault types
input logic [pt.BHT_GHR_SIZE-1:0] ifu_bp_fghr_f, // fetch GHR
input logic [31:1] ifu_bp_btb_target_f, // predicted RET target
input logic [11:0] ifu_bp_poffset_f, // predicted target offset
input logic [1:0] ifu_bp_hist0_f, // history counters for all 4 potential branches, bit 1, right justified
input logic [1:0] ifu_bp_hist1_f, // history counters for all 4 potential branches, bit 1, right justified
input logic [1:0] ifu_bp_pc4_f, // pc4 indication, right justified
input logic [1:0] ifu_bp_way_f, // way indication, right justified
input logic [1:0] ifu_bp_valid_f, // branch valid, right justified
input logic [1:0] ifu_bp_ret_f, // predicted ret indication, right justified
input logic exu_flush_final, // Flush from the pipeline.
input logic dec_i0_decode_d,
input logic dec_i0_decode_d, // Valid instruction at D-stage and not blocked
input logic [31:0] ifu_fetch_data_f, // fetch data in memory format - not right justified
@ -61,7 +51,7 @@ import el2_pkg::*;
output logic ifu_i0_valid, // Instruction 0 is valid
output logic ifu_i0_icaf, // Instruction 0 has access fault
output logic [1:0] ifu_i0_icaf_type, // Instruction 0 access fault type
output logic ifu_i0_icaf_f1, // Instruction 0 has access fault on second fetch group
output logic ifu_i0_icaf_second, // Instruction 0 has access fault on second 2B of 4B inst
output logic ifu_i0_dbecc, // Instruction 0 has double bit ecc error
output logic [31:0] ifu_i0_instr, // Instruction 0
@ -70,10 +60,28 @@ import el2_pkg::*;
output logic ifu_fb_consume1, // Consumed one buffer. To fetch control fetch for buffer mass balance
output logic ifu_fb_consume2, // Consumed two buffers.To fetch control fetch for buffer mass balance
input logic [pt.BHT_GHR_SIZE-1:0] ifu_bp_fghr_f, // fetch GHR
input logic [31:1] ifu_bp_btb_target_f, // predicted RET target
input logic [11:0] ifu_bp_poffset_f, // predicted target offset
input logic [1:0] [$clog2(pt.BTB_SIZE)-1:0] ifu_bp_fa_index_f, // predicted branch index (fully associative option)
input logic [1:0] ifu_bp_hist0_f, // history counters for all 4 potential branches, bit 1, right justified
input logic [1:0] ifu_bp_hist1_f, // history counters for all 4 potential branches, bit 1, right justified
input logic [1:0] ifu_bp_pc4_f, // pc4 indication, right justified
input logic [1:0] ifu_bp_way_f, // way indication, right justified
input logic [1:0] ifu_bp_valid_f, // branch valid, right justified
input logic [1:0] ifu_bp_ret_f, // predicted ret indication, right justified
output el2_br_pkt_t i0_brp, // Branch packet for I0.
output logic [pt.BTB_ADDR_HI:pt.BTB_ADDR_LO] ifu_i0_bp_index, // BP index
output logic [pt.BHT_GHR_SIZE-1:0] ifu_i0_bp_fghr, // BP FGHR
output logic [pt.BTB_BTAG_SIZE-1:0] ifu_i0_bp_btag, // BP tag
output logic [$clog2(pt.BTB_SIZE)-1:0] ifu_i0_fa_index, // Fully associt btb index
output logic ifu_pmu_instr_aligned, // number of inst aligned this cycle
output logic [15:0] ifu_i0_cinst // 16b compress inst for i0
@ -90,11 +98,6 @@ import el2_pkg::*;
logic [1:0] f0val_in, f0val;
logic [1:0] sf1val, sf0val;
logic [31:1] f2pc_in, f2pc;
logic [31:1] f1pc_in, f1pc;
logic [31:1] f0pc_in, f0pc;
logic [31:1] sf1pc;
logic [31:0] aligndata;
logic first4B, first2B;
@ -105,8 +108,6 @@ import el2_pkg::*;
logic f2_valid, sf1_valid, sf0_valid;
logic [31:0] ifirst;
logic [31:1] f0pc_plus1;
logic [31:1] f1pc_plus1;
logic [1:0] alignval;
logic [31:1] firstpc, secondpc;
@ -119,6 +120,8 @@ import el2_pkg::*;
logic [1:0] f1hist0;
logic [1:0] f0hist0;
logic [1:0][$clog2(pt.BTB_SIZE)-1:0] f0index, f1index, alignindex;
logic [1:0] f1ictype;
logic [1:0] f0ictype;
@ -146,10 +149,10 @@ import el2_pkg::*;
logic [31:1] f1prett;
logic [31:1] f0prett;
logic f1dbecc;
logic f0dbecc;
logic f1icaf;
logic f0icaf;
logic [1:0] f1dbecc;
logic [1:0] f0dbecc;
logic [1:0] f1icaf;
logic [1:0] f0icaf;
logic [1:0] aligndbecc;
logic [1:0] alignicaf;
@ -159,10 +162,6 @@ import el2_pkg::*;
logic first_legal;
logic f2_wr_en;
logic f0_shift_wr_en;
logic f1_shift_wr_en;
logic [1:0] wrptr, wrptr_in;
logic [1:0] rdptr, rdptr_in;
logic [2:0] qwen;
@ -185,16 +184,17 @@ import el2_pkg::*;
logic [2:0] qren;
logic consume_fb1, consume_fb0;
logic [1:1] icaf_eff;
logic [1:0] icaf_eff;
localparam BRDATA_SIZE = 12;
localparam BRDATA_WIDTH = 6;
localparam BRDATA_SIZE = pt.BTB_ENABLE ? 16+($clog2(pt.BTB_SIZE)*2*pt.BTB_FULLYA) : 2;
localparam BRDATA_WIDTH = pt.BTB_ENABLE ? 8+($clog2(pt.BTB_SIZE)*pt.BTB_FULLYA) : 1;
logic [BRDATA_SIZE-1:0] brdata_in, brdata2, brdata1, brdata0;
logic [BRDATA_SIZE-1:0] brdata1eff, brdata0eff;
logic [BRDATA_SIZE-1:0] brdata1final, brdata0final;
localparam MHI = 46+pt.BHT_GHR_SIZE;
localparam MSIZE = 47+pt.BHT_GHR_SIZE;
localparam MHI = 1+(pt.BTB_ENABLE * (43+pt.BHT_GHR_SIZE));
localparam MSIZE = 2+(pt.BTB_ENABLE * (43+pt.BHT_GHR_SIZE));
logic [MHI:0] misc_data_in, misc2, misc1, misc0;
logic [MHI:0] misc1eff, misc0eff;
@ -204,40 +204,45 @@ import el2_pkg::*;
assign error_stall_in = (error_stall | ifu_async_error_start) & ~exu_flush_final;
rvdff #(1) error_stallff (.*, .clk(active_clk), .din(error_stall_in), .dout(error_stall));
rvdff #(.WIDTH(7)) bundle1ff (.*,
.clk(active_clk),
.din ({wrptr_in[1:0],rdptr_in[1:0],q2off_in,q1off_in,q0off_in}),
.dout({wrptr[1:0], rdptr[1:0], q2off, q1off, q0off})
);
rvdff #(2) wrpff (.*, .clk(active_clk), .din(wrptr_in[1:0]), .dout(wrptr[1:0]));
rvdff #(2) rdpff (.*, .clk(active_clk), .din(rdptr_in[1:0]), .dout(rdptr[1:0]));
rvdffie #(.WIDTH(7),.OVERRIDE(1)) bundle2ff (.*,
.din ({error_stall_in,f2val_in[1:0],f1val_in[1:0],f0val_in[1:0]}),
.dout({error_stall, f2val[1:0], f1val[1:0], f0val[1:0] })
);
rvdff #(2) f2valff (.*, .clk(active_clk), .din(f2val_in[1:0]), .dout(f2val[1:0]));
rvdff #(2) f1valff (.*, .clk(active_clk), .din(f1val_in[1:0]), .dout(f1val[1:0]));
rvdff #(2) f0valff (.*, .clk(active_clk), .din(f0val_in[1:0]), .dout(f0val[1:0]));
if(pt.BTB_ENABLE==1) begin
rvdffe #(BRDATA_SIZE) brdata2ff (.*, .clk(clk), .en(qwen[2]), .din(brdata_in[BRDATA_SIZE-1:0]), .dout(brdata2[BRDATA_SIZE-1:0]));
rvdffe #(BRDATA_SIZE) brdata1ff (.*, .clk(clk), .en(qwen[1]), .din(brdata_in[BRDATA_SIZE-1:0]), .dout(brdata1[BRDATA_SIZE-1:0]));
rvdffe #(BRDATA_SIZE) brdata0ff (.*, .clk(clk), .en(qwen[0]), .din(brdata_in[BRDATA_SIZE-1:0]), .dout(brdata0[BRDATA_SIZE-1:0]));
rvdffe #(MSIZE) misc2ff (.*, .clk(clk), .en(qwen[2]), .din(misc_data_in[MHI:0]), .dout(misc2[MHI:0]));
rvdffe #(MSIZE) misc1ff (.*, .clk(clk), .en(qwen[1]), .din(misc_data_in[MHI:0]), .dout(misc1[MHI:0]));
rvdffe #(MSIZE) misc0ff (.*, .clk(clk), .en(qwen[0]), .din(misc_data_in[MHI:0]), .dout(misc0[MHI:0]));
end
else begin
rvdff #(1) q2offsetff (.*, .clk(active_clk), .din(q2off_in), .dout(q2off));
rvdff #(1) q1offsetff (.*, .clk(active_clk), .din(q1off_in), .dout(q1off));
rvdff #(1) q0offsetff (.*, .clk(active_clk), .din(q0off_in), .dout(q0off));
rvdffe #(31) f2pcff (.*, .en(f2_wr_en), .din(f2pc_in[31:1]), .dout(f2pc[31:1]));
rvdffe #(31) f1pcff (.*, .en(f1_shift_wr_en), .din(f1pc_in[31:1]), .dout(f1pc[31:1]));
rvdffe #(31) f0pcff (.*, .en(f0_shift_wr_en), .din(f0pc_in[31:1]), .dout(f0pc[31:1]));
rvdffe #(BRDATA_SIZE) brdata2ff (.*, .en(qwen[2]), .din(brdata_in[BRDATA_SIZE-1:0]), .dout(brdata2[BRDATA_SIZE-1:0]));
rvdffe #(BRDATA_SIZE) brdata1ff (.*, .en(qwen[1]), .din(brdata_in[BRDATA_SIZE-1:0]), .dout(brdata1[BRDATA_SIZE-1:0]));
rvdffe #(BRDATA_SIZE) brdata0ff (.*, .en(qwen[0]), .din(brdata_in[BRDATA_SIZE-1:0]), .dout(brdata0[BRDATA_SIZE-1:0]));
rvdffe #(MSIZE) misc2ff (.*, .en(qwen[2]), .din(misc_data_in[MHI:0]), .dout(misc2[MHI:0]));
rvdffe #(MSIZE) misc1ff (.*, .en(qwen[1]), .din(misc_data_in[MHI:0]), .dout(misc1[MHI:0]));
rvdffe #(MSIZE) misc0ff (.*, .en(qwen[0]), .din(misc_data_in[MHI:0]), .dout(misc0[MHI:0]));
rvdffie #((MSIZE*3)+(BRDATA_SIZE*3)) miscff (.*,
.din({qwen[2] ? {misc_data_in[MHI:0], brdata_in[BRDATA_SIZE-1:0]} : {misc2[MHI:0], brdata2[BRDATA_SIZE-1:0]},
qwen[1] ? {misc_data_in[MHI:0], brdata_in[BRDATA_SIZE-1:0]} : {misc1[MHI:0], brdata1[BRDATA_SIZE-1:0]},
qwen[0] ? {misc_data_in[MHI:0], brdata_in[BRDATA_SIZE-1:0]} : {misc0[MHI:0], brdata0[BRDATA_SIZE-1:0]}}),
.dout({misc2[MHI:0],misc1[MHI:0],misc0[MHI:0],
brdata2[BRDATA_SIZE-1:0], brdata1[BRDATA_SIZE-1:0], brdata0[BRDATA_SIZE-1:0]})
);
end
rvdffe #(32) q2ff (.*, .en(qwen[2]), .din(ifu_fetch_data_f[31:0]), .dout(q2[31:0]));
rvdffe #(32) q1ff (.*, .en(qwen[1]), .din(ifu_fetch_data_f[31:0]), .dout(q1[31:0]));
rvdffe #(32) q0ff (.*, .en(qwen[0]), .din(ifu_fetch_data_f[31:0]), .dout(q0[31:0]));
logic [31:1] q2pc, q1pc, q0pc;
rvdffe #(31) q2pcff (.*, .clk(clk), .en(qwen[2]), .din(ifu_fetch_pc[31:1]), .dout(q2pc[31:1]));
rvdffe #(31) q1pcff (.*, .clk(clk), .en(qwen[1]), .din(ifu_fetch_pc[31:1]), .dout(q1pc[31:1]));
rvdffe #(31) q0pcff (.*, .clk(clk), .en(qwen[0]), .din(ifu_fetch_pc[31:1]), .dout(q0pc[31:1]));
assign f2_wr_en = fetch_to_f2;
assign f1_shift_wr_en = fetch_to_f1 | shift_f2_f1 | f1_shift_2B;
assign f0_shift_wr_en = fetch_to_f0 | shift_f2_f0 | shift_f1_f0 | shift_2B | shift_4B;
rvdffe #(32) q2ff (.*, .clk(clk), .en(qwen[2]), .din(ifu_fetch_data_f[31:0]), .dout(q2[31:0]));
rvdffe #(32) q1ff (.*, .clk(clk), .en(qwen[1]), .din(ifu_fetch_data_f[31:0]), .dout(q1[31:0]));
rvdffe #(32) q0ff (.*, .clk(clk), .en(qwen[0]), .din(ifu_fetch_data_f[31:0]), .dout(q0[31:0]));
// new queue control logic
@ -297,40 +302,64 @@ import el2_pkg::*;
// misc data that is associated with each fetch buffer
assign misc_data_in[MHI:0] = { iccm_rd_ecc_double_err,
ic_access_fault_f,
if(pt.BTB_ENABLE==1)
assign misc_data_in[MHI:0] = {
ic_access_fault_type_f[1:0],
ifu_bp_btb_target_f[31:1],
ifu_bp_poffset_f[11:0],
ifu_bp_fghr_f[pt.BHT_GHR_SIZE-1:0]
};
else
assign misc_data_in[MHI:0] = {
ic_access_fault_type_f[1:0]
};
assign {misc1eff[MHI:0],misc0eff[MHI:0]} = (({MSIZE*2{qren[0]}} & {misc1[MHI:0],misc0[MHI:0]}) |
({MSIZE*2{qren[1]}} & {misc2[MHI:0],misc1[MHI:0]}) |
({MSIZE*2{qren[2]}} & {misc0[MHI:0],misc2[MHI:0]}));
assign { f1dbecc,
f1icaf,
if(pt.BTB_ENABLE==1) begin
assign {
f1ictype[1:0],
f1prett[31:1],
f1poffset[11:0],
f1fghr[pt.BHT_GHR_SIZE-1:0]
} = misc1eff[MHI:0];
assign { f0dbecc,
f0icaf,
assign {
f0ictype[1:0],
f0prett[31:1],
f0poffset[11:0],
f0fghr[pt.BHT_GHR_SIZE-1:0]
} = misc0eff[MHI:0];
if(pt.BTB_FULLYA) begin
assign brdata_in[BRDATA_SIZE-1:0] = {
ifu_bp_hist1_f[1],ifu_bp_hist0_f[1],ifu_bp_pc4_f[1],ifu_bp_way_f[1],ifu_bp_valid_f[1],ifu_bp_ret_f[1],
ifu_bp_hist1_f[0],ifu_bp_hist0_f[0],ifu_bp_pc4_f[0],ifu_bp_way_f[0],ifu_bp_valid_f[0],ifu_bp_ret_f[0]
ifu_bp_fa_index_f[1], iccm_rd_ecc_double_err[1],ic_access_fault_f[1],ifu_bp_hist1_f[1],ifu_bp_hist0_f[1],ifu_bp_pc4_f[1],ifu_bp_way_f[1],ifu_bp_valid_f[1],ifu_bp_ret_f[1],
ifu_bp_fa_index_f[0], iccm_rd_ecc_double_err[0],ic_access_fault_f[0],ifu_bp_hist1_f[0],ifu_bp_hist0_f[0],ifu_bp_pc4_f[0],ifu_bp_way_f[0],ifu_bp_valid_f[0],ifu_bp_ret_f[0]
};
assign {f0index[1],f0dbecc[1],f0icaf[1],f0hist1[1],f0hist0[1],f0pc4[1],f0way[1],f0brend[1],f0ret[1],
f0index[0],f0dbecc[0],f0icaf[0],f0hist1[0],f0hist0[0],f0pc4[0],f0way[0],f0brend[0],f0ret[0]} = brdata0final[BRDATA_SIZE-1:0];
assign {f1index[1],f1dbecc[1],f1icaf[1],f1hist1[1],f1hist0[1],f1pc4[1],f1way[1],f1brend[1],f1ret[1],
f1index[0],f1dbecc[0],f1icaf[0],f1hist1[0],f1hist0[0],f1pc4[0],f1way[0],f1brend[0],f1ret[0]} = brdata1final[BRDATA_SIZE-1:0];
end
else begin
assign brdata_in[BRDATA_SIZE-1:0] = {
iccm_rd_ecc_double_err[1],ic_access_fault_f[1],ifu_bp_hist1_f[1],ifu_bp_hist0_f[1],ifu_bp_pc4_f[1],ifu_bp_way_f[1],ifu_bp_valid_f[1],ifu_bp_ret_f[1],
iccm_rd_ecc_double_err[0],ic_access_fault_f[0],ifu_bp_hist1_f[0],ifu_bp_hist0_f[0],ifu_bp_pc4_f[0],ifu_bp_way_f[0],ifu_bp_valid_f[0],ifu_bp_ret_f[0]
};
assign {f0dbecc[1],f0icaf[1],f0hist1[1],f0hist0[1],f0pc4[1],f0way[1],f0brend[1],f0ret[1],
f0dbecc[0],f0icaf[0],f0hist1[0],f0hist0[0],f0pc4[0],f0way[0],f0brend[0],f0ret[0]} = brdata0final[BRDATA_SIZE-1:0];
assign {f1dbecc[1],f1icaf[1],f1hist1[1],f1hist0[1],f1pc4[1],f1way[1],f1brend[1],f1ret[1],
f1dbecc[0],f1icaf[0],f1hist1[0],f1hist0[0],f1pc4[0],f1way[0],f1brend[0],f1ret[0]} = brdata1final[BRDATA_SIZE-1:0];
end
@ -344,11 +373,37 @@ import el2_pkg::*;
assign brdata1final[BRDATA_SIZE-1:0] = (({BRDATA_SIZE{q1sel[0]}} & { brdata1eff[2*BRDATA_WIDTH-1:0]}) |
({BRDATA_SIZE{q1sel[1]}} & {{BRDATA_WIDTH{1'b0}},brdata1eff[BRDATA_SIZE-1:BRDATA_WIDTH]}));
assign {f0hist1[1],f0hist0[1],f0pc4[1],f0way[1],f0brend[1],f0ret[1],
f0hist1[0],f0hist0[0],f0pc4[0],f0way[0],f0brend[0],f0ret[0]} = brdata0final[BRDATA_SIZE-1:0];
end // if (pt.BTB_ENABLE==1)
else begin
assign {
f1ictype[1:0]
} = misc1eff[MHI:0];
assign {f1hist1[1],f1hist0[1],f1pc4[1],f1way[1],f1brend[1],f1ret[1],
f1hist1[0],f1hist0[0],f1pc4[0],f1way[0],f1brend[0],f1ret[0]} = brdata1final[BRDATA_SIZE-1:0];
assign {
f0ictype[1:0]
} = misc0eff[MHI:0];
assign brdata_in[BRDATA_SIZE-1:0] = {
iccm_rd_ecc_double_err[1],ic_access_fault_f[1],
iccm_rd_ecc_double_err[0],ic_access_fault_f[0]
};
assign {f0dbecc[1],f0icaf[1],
f0dbecc[0],f0icaf[0]} = brdata0final[BRDATA_SIZE-1:0];
assign {f1dbecc[1],f1icaf[1],
f1dbecc[0],f1icaf[0]} = brdata1final[BRDATA_SIZE-1:0];
assign {brdata1eff[BRDATA_SIZE-1:0],brdata0eff[BRDATA_SIZE-1:0]} = (({BRDATA_SIZE*2{qren[0]}} & {brdata1[BRDATA_SIZE-1:0],brdata0[BRDATA_SIZE-1:0]}) |
({BRDATA_SIZE*2{qren[1]}} & {brdata2[BRDATA_SIZE-1:0],brdata1[BRDATA_SIZE-1:0]}) |
({BRDATA_SIZE*2{qren[2]}} & {brdata0[BRDATA_SIZE-1:0],brdata2[BRDATA_SIZE-1:0]}));
assign brdata0final[BRDATA_SIZE-1:0] = (({BRDATA_SIZE{q0sel[0]}} & { brdata0eff[2*BRDATA_WIDTH-1:0]}) |
({BRDATA_SIZE{q0sel[1]}} & {{BRDATA_WIDTH{1'b0}},brdata0eff[BRDATA_SIZE-1:BRDATA_WIDTH]}));
assign brdata1final[BRDATA_SIZE-1:0] = (({BRDATA_SIZE{q1sel[0]}} & { brdata1eff[2*BRDATA_WIDTH-1:0]}) |
({BRDATA_SIZE{q1sel[1]}} & {{BRDATA_WIDTH{1'b0}},brdata1eff[BRDATA_SIZE-1:BRDATA_WIDTH]}));
end // else: !if(pt.BTB_ENABLE==1)
// possible states of { sf0_valid, sf1_valid, f2_valid }
@ -391,28 +446,6 @@ import el2_pkg::*;
( sf0_valid & sf1_valid & ~f2_valid & ifvalid);
assign f0pc_plus1[31:1] = f0pc[31:1] + 31'd1;
assign f1pc_plus1[31:1] = f1pc[31:1] + 31'd1;
assign f2pc_in[31:1] = ifu_fetch_pc[31:1];
assign sf1pc[31:1] = ({31{ f1_shift_2B}} & f1pc_plus1[31:1]) |
({31{~f1_shift_2B}} & f1pc[31:1] );
assign f1pc_in[31:1] = ({31{ fetch_to_f1 }} & ifu_fetch_pc[31:1]) |
({31{ shift_f2_f1}} & f2pc[31:1] ) |
({31{~fetch_to_f1 & ~shift_f2_f1}} & sf1pc[31:1] );
assign f0pc_in[31:1] = ({31{ fetch_to_f0 }} & ifu_fetch_pc[31:1]) |
({31{ shift_f2_f0 }} & f2pc[31:1] ) |
({31{ shift_f1_f0}} & sf1pc[31:1] ) |
({31{~fetch_to_f0 & ~shift_f2_f0 & ~shift_f1_f0}} & f0pc_plus1[31:1] );
assign f2val_in[1:0] = ({2{ fetch_to_f2 & ~exu_flush_final}} & ifu_fetch_val[1:0]) |
({2{~fetch_to_f2 & ~shift_f2_f1 & ~shift_f2_f0 & ~exu_flush_final}} & f2val[1:0] );
@ -434,11 +467,6 @@ import el2_pkg::*;
({2{ shift_f1_f0 & ~exu_flush_final}} & sf1val[1:0] ) |
({2{~fetch_to_f0 & ~shift_f2_f0 & ~shift_f1_f0 & ~exu_flush_final}} & sf0val[1:0] );
assign {q1eff[31:0],q0eff[31:0]} = (({64{qren[0]}} & {q1[31:0],q0[31:0]}) |
({64{qren[1]}} & {q2[31:0],q1[31:0]}) |
({64{qren[2]}} & {q0[31:0],q2[31:0]}));
@ -448,6 +476,16 @@ import el2_pkg::*;
assign q1final[15:0] = ({16{q1sel[0]}} & q1eff[15:0] ) |
({16{q1sel[1]}} & q1eff[31:16]);
logic [31:1] q0pceff, q0pcfinal;
logic [31:1] q1pceff;
assign {q1pceff[31:1],q0pceff[31:1]} = (({62{qren[0]}} & {q1pc[31:1],q0pc[31:1]}) |
({62{qren[1]}} & {q2pc[31:1],q1pc[31:1]}) |
({62{qren[2]}} & {q0pc[31:1],q2pc[31:1]}));
assign q0pcfinal[31:1] = ({31{q0sel[0]}} & ( q0pceff[31:1])) |
({31{q0sel[1]}} & ( q0pceff[31:1] + 31'd1));
assign aligndata[31:0] = ({32{ f0val[1] }} & {q0final[31:0]}) |
({32{~f0val[1] & f0val[0]}} & {q1final[15:0],q0final[15:0]});
@ -455,19 +493,26 @@ import el2_pkg::*;
assign alignval[1:0] = ({ 2{ f0val[1] }} & {2'b11}) |
({ 2{~f0val[1] & f0val[0]}} & {f1val[0],1'b1});
assign alignicaf[1:0] = ({ 2{ f0val[1] }} & {{2{f0icaf}}}) |
({ 2{~f0val[1] & f0val[0]}} & {f1icaf,f0icaf});
assign alignicaf[1:0] = ({ 2{ f0val[1] }} & f0icaf[1:0] ) |
({ 2{~f0val[1] & f0val[0]}} & {f1icaf[0],f0icaf[0]});
assign aligndbecc[1:0] = ({ 2{ f0val[1] }} & {{2{f0dbecc}}}) |
({ 2{~f0val[1] & f0val[0]}} & {f1dbecc,f0dbecc});
assign aligndbecc[1:0] = ({ 2{ f0val[1] }} & f0dbecc[1:0] ) |
({ 2{~f0val[1] & f0val[0]}} & {f1dbecc[0],f0dbecc[0]});
if (pt.BTB_ENABLE==1) begin
// for branch prediction
assign alignbrend[1:0] = ({ 2{ f0val[1] }} & f0brend[1:0] ) |
({ 2{~f0val[1] & f0val[0]}} & {f1brend[0],f0brend[0]});
assign alignpc4[1:0] = ({ 2{ f0val[1] }} & f0pc4[1:0] ) |
({ 2{~f0val[1] & f0val[0]}} & {f1pc4[0],f0pc4[0]});
if(pt.BTB_FULLYA) begin
assign alignindex[0] = f0index[0];
assign alignindex[1] = f0val[1] ? f0index[1] : f1index[0];
end
assign alignret[1:0] = ({ 2{ f0val[1] }} & f0ret[1:0] ) |
({ 2{~f0val[1] & f0val[0]}} & {f1ret[0],f0ret[0]});
@ -481,20 +526,23 @@ import el2_pkg::*;
assign alignhist0[1:0] = ({ 2{ f0val[1] }} & f0hist0[1:0] ) |
({ 2{~f0val[1] & f0val[0]}} & {f1hist0[0],f0hist0[0]});
assign secondpc[31:1] = ({31{ f0val[1] }} & (q0pceff[31:1] + 31'd1)) |
// you need the base pc for 2nd one only (4B max, 2B for the 1st and 2B for the 2nd)
({31{~f0val[1] & f0val[0]}} & q1pceff[31:1] );
assign firstpc[31:1] = q0pcfinal[31:1];
end // if (pt.BTB_ENABLE==1)
assign alignfromf1[1] = ~f0val[1] & f0val[0];
assign secondpc[31:1] = ({31{ f0val[1] }} & f0pc_plus1[31:1]) |
({31{~f0val[1] & f0val[0]}} & f1pc[31:1] );
assign ifu_i0_pc[31:1] = q0pcfinal[31:1];
assign ifu_i0_pc[31:1] = f0pc[31:1];
assign firstpc[31:1] = f0pc[31:1];
assign ifu_i0_pc4 = first4B;
assign ifu_i0_cinst[15:0] = aligndata[15:0];
assign first4B = (aligndata[1:0] == 2'b11);
@ -510,9 +558,9 @@ import el2_pkg::*;
assign ifu_i0_icaf_type[1:0] = (first4B & ~f0val[1] & f0val[0] & ~alignicaf[0] & ~aligndbecc[0]) ? f1ictype[1:0] : f0ictype[1:0];
assign icaf_eff[1] = alignicaf[1] | aligndbecc[1];
assign icaf_eff[1:0] = alignicaf[1:0] | aligndbecc[1:0];
assign ifu_i0_icaf_f1 = first4B & icaf_eff[1] & alignfromf1[1];
assign ifu_i0_icaf_second = first4B & ~icaf_eff[0] & icaf_eff[1];
assign ifu_i0_dbecc = (first4B & (|aligndbecc[1:0])) |
(first2B & aligndbecc[0] );
@ -521,23 +569,38 @@ import el2_pkg::*;
assign ifirst[31:0] = aligndata[31:0];
assign ifu_i0_instr[31:0] = ({32{first4B}} & ifirst[31:0]) |
({32{first2B}} & uncompress0[31:0]);
assign ifu_i0_instr[31:0] = ({32{first4B & alignval[1]}} & ifirst[31:0]) |
({32{first2B & alignval[0]}} & uncompress0[31:0]);
if(pt.BTB_ENABLE==1) begin
// if you detect br does not start on instruction boundary
el2_btb_addr_hash #(.pt(pt)) firsthash (.pc(firstpc [pt.BTB_INDEX3_HI:pt.BTB_INDEX1_LO]), .hash(firstpc_hash [pt.BTB_ADDR_HI:pt.BTB_ADDR_LO]));
el2_btb_addr_hash #(.pt(pt)) secondhash(.pc(secondpc[pt.BTB_INDEX3_HI:pt.BTB_INDEX1_LO]), .hash(secondpc_hash[pt.BTB_ADDR_HI:pt.BTB_ADDR_LO]));
el2_btb_addr_hash #(.pt(pt)) firsthash (.pc(firstpc [pt.BTB_INDEX3_HI:pt.BTB_INDEX1_LO]),
.hash(firstpc_hash [pt.BTB_ADDR_HI:pt.BTB_ADDR_LO]));
el2_btb_addr_hash #(.pt(pt)) secondhash(.pc(secondpc[pt.BTB_INDEX3_HI:pt.BTB_INDEX1_LO]),
.hash(secondpc_hash[pt.BTB_ADDR_HI:pt.BTB_ADDR_LO]));
if(pt.BTB_BTAG_FOLD) begin : btbfold
el2_btb_tag_hash_fold #(.pt(pt)) first_brhash (.pc(firstpc [pt.BTB_ADDR_HI+pt.BTB_BTAG_SIZE+pt.BTB_BTAG_SIZE:pt.BTB_ADDR_HI+1]), .hash(firstbrtag_hash [pt.BTB_BTAG_SIZE-1:0]));
el2_btb_tag_hash_fold #(.pt(pt)) second_brhash(.pc(secondpc[pt.BTB_ADDR_HI+pt.BTB_BTAG_SIZE+pt.BTB_BTAG_SIZE:pt.BTB_ADDR_HI+1]), .hash(secondbrtag_hash[pt.BTB_BTAG_SIZE-1:0]));
if(pt.BTB_FULLYA) begin
assign firstbrtag_hash = firstpc;
assign secondbrtag_hash = secondpc;
end
else begin
el2_btb_tag_hash #(.pt(pt)) first_brhash (.pc(firstpc [pt.BTB_ADDR_HI+pt.BTB_BTAG_SIZE+pt.BTB_BTAG_SIZE+pt.BTB_BTAG_SIZE:pt.BTB_ADDR_HI+1]), .hash(firstbrtag_hash [pt.BTB_BTAG_SIZE-1:0]));
el2_btb_tag_hash #(.pt(pt)) second_brhash(.pc(secondpc[pt.BTB_ADDR_HI+pt.BTB_BTAG_SIZE+pt.BTB_BTAG_SIZE+pt.BTB_BTAG_SIZE:pt.BTB_ADDR_HI+1]), .hash(secondbrtag_hash[pt.BTB_BTAG_SIZE-1:0]));
if(pt.BTB_BTAG_FOLD) begin : btbfold
el2_btb_tag_hash_fold #(.pt(pt)) first_brhash (.pc(firstpc [pt.BTB_ADDR_HI+pt.BTB_BTAG_SIZE+pt.BTB_BTAG_SIZE:pt.BTB_ADDR_HI+1]),
.hash(firstbrtag_hash [pt.BTB_BTAG_SIZE-1:0]));
el2_btb_tag_hash_fold #(.pt(pt)) second_brhash(.pc(secondpc[pt.BTB_ADDR_HI+pt.BTB_BTAG_SIZE+pt.BTB_BTAG_SIZE:pt.BTB_ADDR_HI+1]),
.hash(secondbrtag_hash[pt.BTB_BTAG_SIZE-1:0]));
end
else begin
el2_btb_tag_hash #(.pt(pt)) first_brhash (.pc(firstpc [pt.BTB_ADDR_HI+pt.BTB_BTAG_SIZE+pt.BTB_BTAG_SIZE+pt.BTB_BTAG_SIZE:pt.BTB_ADDR_HI+1]),
.hash(firstbrtag_hash [pt.BTB_BTAG_SIZE-1:0]));
el2_btb_tag_hash #(.pt(pt)) second_brhash(.pc(secondpc[pt.BTB_ADDR_HI+pt.BTB_BTAG_SIZE+pt.BTB_BTAG_SIZE+pt.BTB_BTAG_SIZE:pt.BTB_ADDR_HI+1]),
.hash(secondbrtag_hash[pt.BTB_BTAG_SIZE-1:0]));
end
end // else: !if(pt.BTB_FULLYA)
// start_indexing - you want pc to be based on where the end of branch is prediction
// normal indexing pc based that's incorrect now for pc4 cases it's pc4 + 2
@ -578,6 +641,11 @@ end
i0_brp.br_error = (i0_brp.valid & i0_brp_pc4 & first2B) |
(i0_brp.valid & ~i0_brp_pc4 & first4B);
if(pt.BTB_FULLYA)
ifu_i0_fa_index = (first2B | alignbrend[0]) ? alignindex[0] : alignindex[1];
else
ifu_i0_fa_index = '0;
end
@ -589,11 +657,18 @@ end
assign ifu_i0_bp_btag[pt.BTB_BTAG_SIZE-1:0] = (first2B | alignbrend[0]) ? firstbrtag_hash[pt.BTB_BTAG_SIZE-1:0] :
secondbrtag_hash[pt.BTB_BTAG_SIZE-1:0];
end
else begin
assign i0_brp = '0;
assign ifu_i0_bp_index = '0;
assign ifu_i0_bp_fghr = '0;
assign ifu_i0_bp_btag = '0;
end // else: !if(pt.BTB_ENABLE==1)
// decompress
el2_ifu_compress_ctl compress0 (.din(aligndata[15:0]), .dout(uncompress0[31:0]));
// quiet inputs for 4B inst
el2_ifu_compress_ctl compress0 (.din((first2B) ? aligndata[15:0] : '0), .dout(uncompress0[31:0]));
@ -604,8 +679,6 @@ end
// compute how many bytes are being shifted from f0
// assign shift_0B = ~i0_shift;
assign shift_2B = i0_shift & first2B;
assign shift_4B = i0_shift & first4B;

View File

@ -1,6 +1,6 @@
//********************************************************************************
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 Western Digital Corporation or it's affiliates.
// Copyright 2020 Western Digital Corporation or its affiliates.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -32,7 +32,6 @@ import el2_pkg::*;
(
input logic clk,
input logic active_clk,
input logic rst_l,
input logic ic_hit_f, // Icache hit, enables F address capture
@ -44,6 +43,8 @@ import el2_pkg::*;
input logic [pt.BHT_GHR_SIZE-1:0] exu_i0_br_fghr_r, // fghr to bp
input logic [pt.BTB_ADDR_HI:pt.BTB_ADDR_LO] exu_i0_br_index_r, // bp index
input logic [$clog2(pt.BTB_SIZE)-1:0] dec_fa_error_index, // Fully associative btb error index
input logic dec_tlu_flush_lower_wb, // used to move EX4 RS to EX1 and F
input logic dec_tlu_flush_leak_one_wb, // don't hit for leak one fetches
@ -72,10 +73,21 @@ import el2_pkg::*;
output logic [1:0] ifu_bp_valid_f, // branch valid, right justified
output logic [11:0] ifu_bp_poffset_f, // predicted target
output logic [1:0] [$clog2(pt.BTB_SIZE)-1:0] ifu_bp_fa_index_f, // predicted branch index (fully associative option)
input logic scan_mode
);
localparam TAG_START=16+pt.BTB_BTAG_SIZE;
localparam BTB_DWIDTH = pt.BTB_TOFFSET_SIZE+pt.BTB_BTAG_SIZE+5;
localparam BTB_DWIDTH_TOP = int'(pt.BTB_TOFFSET_SIZE)+int'(pt.BTB_BTAG_SIZE)+4;
localparam BTB_FA_INDEX = $clog2(pt.BTB_SIZE)-1;
localparam FA_CMP_LOWER = $clog2(pt.ICACHE_LN_SZ);
localparam FA_TAG_END_UPPER= 5+int'(pt.BTB_TOFFSET_SIZE)+int'(FA_CMP_LOWER)-1; // must cast to int or vcs build fails
localparam FA_TAG_START_LOWER = 3+int'(pt.BTB_TOFFSET_SIZE)+int'(FA_CMP_LOWER);
localparam FA_TAG_END_LOWER = 5+int'(pt.BTB_TOFFSET_SIZE);
localparam TAG_START=BTB_DWIDTH-1;
localparam PC4=4;
localparam BOFF=3;
localparam CALL=2;
@ -88,6 +100,7 @@ import el2_pkg::*;
localparam NUM_BHT_LOOP_OUTER_LO = (pt.BHT_ARRAY_DEPTH > 16 ) ?pt.BHT_ADDR_LO+4 : pt.BHT_ADDR_LO;
localparam BHT_NO_ADDR_MATCH = ( pt.BHT_ARRAY_DEPTH <= 16 );
logic exu_mp_valid_write;
logic exu_mp_ataken;
logic exu_mp_valid; // conditional branch mispredict
@ -120,13 +133,12 @@ import el2_pkg::*;
logic rs_push, rs_pop, rs_hold;
logic [pt.BTB_ADDR_HI:pt.BTB_ADDR_LO] btb_rd_addr_p1_f, btb_wr_addr, btb_rd_addr_f;
logic [pt.BTB_BTAG_SIZE-1:0] btb_wr_tag, fetch_rd_tag_f, fetch_rd_tag_p1_f;
logic [16+pt.BTB_BTAG_SIZE:0] btb_wr_data;
logic [BTB_DWIDTH-1:0] btb_wr_data;
logic btb_wr_en_way0, btb_wr_en_way1;
logic dec_tlu_error_wb, btb_valid, dec_tlu_br0_middle_wb;
logic [pt.BTB_ADDR_HI:pt.BTB_ADDR_LO] btb_error_addr_wb;
logic branch_error_collision_f, fetch_mp_collision_f, branch_error_collision_p1_f, fetch_mp_collision_p1_f;
logic branch_error_bank_conflict_f;
@ -142,17 +154,17 @@ import el2_pkg::*;
logic leak_one_f, leak_one_f_d1;
logic [LRU_SIZE-1:0][16+pt.BTB_BTAG_SIZE:0] btb_bank0_rd_data_way0_out ;
logic [LRU_SIZE-1:0][BTB_DWIDTH-1:0] btb_bank0_rd_data_way0_out ;
logic [LRU_SIZE-1:0][16+pt.BTB_BTAG_SIZE:0] btb_bank0_rd_data_way1_out ;
logic [LRU_SIZE-1:0][BTB_DWIDTH-1:0] btb_bank0_rd_data_way1_out ;
logic [16+pt.BTB_BTAG_SIZE:0] btb_bank0_rd_data_way0_f ;
logic [16+pt.BTB_BTAG_SIZE:0] btb_bank0_rd_data_way1_f ;
logic [BTB_DWIDTH-1:0] btb_bank0_rd_data_way0_f ;
logic [BTB_DWIDTH-1:0] btb_bank0_rd_data_way1_f ;
logic [16+pt.BTB_BTAG_SIZE:0] btb_bank0_rd_data_way0_p1_f ;
logic [16+pt.BTB_BTAG_SIZE:0] btb_bank0_rd_data_way1_p1_f ;
logic [BTB_DWIDTH-1:0] btb_bank0_rd_data_way0_p1_f ;
logic [BTB_DWIDTH-1:0] btb_bank0_rd_data_way1_p1_f ;
logic [16+pt.BTB_BTAG_SIZE:0] btb_vbank0_rd_data_f, btb_vbank1_rd_data_f;
logic [BTB_DWIDTH-1:0] btb_vbank0_rd_data_f, btb_vbank1_rd_data_f;
logic final_h;
logic btb_fg_crossing_f;
@ -167,10 +179,10 @@ import el2_pkg::*;
logic [31:2] fetch_addr_p1_f;
logic exu_mp_way, exu_mp_way_f, dec_tlu_br0_way_wb, dec_tlu_way_wb, dec_tlu_way_wb_f;
logic [16+pt.BTB_BTAG_SIZE:0] btb_bank0e_rd_data_f, btb_bank0e_rd_data_p1_f;
logic exu_mp_way, exu_mp_way_f, dec_tlu_br0_way_wb, dec_tlu_way_wb;
logic [BTB_DWIDTH-1:0] btb_bank0e_rd_data_f, btb_bank0e_rd_data_p1_f;
logic [16+pt.BTB_BTAG_SIZE:0] btb_bank0o_rd_data_f;
logic [BTB_DWIDTH-1:0] btb_bank0o_rd_data_f;
logic [1:0] tag_match_way0_expanded_f, tag_match_way1_expanded_f;
@ -178,7 +190,7 @@ import el2_pkg::*;
logic [1:0] bht_bank0_rd_data_f;
logic [1:0] bht_bank1_rd_data_f;
logic [1:0] bht_bank0_rd_data_p1_f;
logic exu_flush_final_d1;
genvar j, i;
assign exu_mp_valid = exu_mp_pkt.misp & ~leak_one_f; // conditional branch mispredict
assign exu_mp_boffset = exu_mp_pkt.boffset; // branch offset
@ -229,6 +241,12 @@ logic exu_flush_final_d1;
assign branch_error_bank_conflict_f = branch_error_collision_f & dec_tlu_error_wb;
assign branch_error_bank_conflict_p1_f = branch_error_collision_p1_f & dec_tlu_error_wb;
// set on leak one, hold until next flush without leak one
assign leak_one_f = (dec_tlu_flush_leak_one_wb & dec_tlu_flush_lower_wb) | (leak_one_f_d1 & ~dec_tlu_flush_lower_wb);
logic exu_flush_final_d1;
if(!pt.BTB_FULLYA) begin
assign fetch_mp_collision_f = ( (exu_mp_btag[pt.BTB_BTAG_SIZE-1:0] == fetch_rd_tag_f[pt.BTB_BTAG_SIZE-1:0]) &
exu_mp_valid & ifc_fetch_req_f &
(exu_mp_addr[pt.BTB_ADDR_HI:pt.BTB_ADDR_LO] == btb_rd_addr_f[pt.BTB_ADDR_HI:pt.BTB_ADDR_LO])
@ -237,26 +255,18 @@ logic exu_flush_final_d1;
exu_mp_valid & ifc_fetch_req_f &
(exu_mp_addr[pt.BTB_ADDR_HI:pt.BTB_ADDR_LO] == btb_rd_addr_p1_f[pt.BTB_ADDR_HI:pt.BTB_ADDR_LO])
);
// set on leak one, hold until next flush without leak one
assign leak_one_f = (dec_tlu_flush_leak_one_wb & dec_tlu_flush_lower_wb) | (leak_one_f_d1 & ~dec_tlu_flush_lower_wb);
rvdff #(4) coll_ff (.*, .clk(active_clk),
.din({exu_flush_final, exu_mp_way, dec_tlu_way_wb, leak_one_f}),
.dout({exu_flush_final_d1, exu_mp_way_f, dec_tlu_way_wb_f, leak_one_f_d1}));
// 2 -way SA, figure out the way hit and mux accordingly
assign tag_match_way0_f = btb_bank0_rd_data_way0_f[BV] & (btb_bank0_rd_data_way0_f[TAG_START:17] == fetch_rd_tag_f[pt.BTB_BTAG_SIZE-1:0]) &
~(dec_tlu_way_wb_f & branch_error_bank_conflict_f) & ifc_fetch_req_f & ~leak_one_f;
~(dec_tlu_way_wb & branch_error_bank_conflict_f) & ifc_fetch_req_f & ~leak_one_f;
assign tag_match_way1_f = btb_bank0_rd_data_way1_f[BV] & (btb_bank0_rd_data_way1_f[TAG_START:17] == fetch_rd_tag_f[pt.BTB_BTAG_SIZE-1:0]) &
~(dec_tlu_way_wb_f & branch_error_bank_conflict_f) & ifc_fetch_req_f & ~leak_one_f;
~(dec_tlu_way_wb & branch_error_bank_conflict_f) & ifc_fetch_req_f & ~leak_one_f;
assign tag_match_way0_p1_f = btb_bank0_rd_data_way0_p1_f[BV] & (btb_bank0_rd_data_way0_p1_f[TAG_START:17] == fetch_rd_tag_p1_f[pt.BTB_BTAG_SIZE-1:0]) &
~(dec_tlu_way_wb_f & branch_error_bank_conflict_p1_f) & ifc_fetch_req_f & ~leak_one_f;
~(dec_tlu_way_wb & branch_error_bank_conflict_p1_f) & ifc_fetch_req_f & ~leak_one_f;
assign tag_match_way1_p1_f = btb_bank0_rd_data_way1_p1_f[BV] & (btb_bank0_rd_data_way1_p1_f[TAG_START:17] == fetch_rd_tag_p1_f[pt.BTB_BTAG_SIZE-1:0]) &
~(dec_tlu_way_wb_f & branch_error_bank_conflict_p1_f) & ifc_fetch_req_f & ~leak_one_f;
~(dec_tlu_way_wb & branch_error_bank_conflict_p1_f) & ifc_fetch_req_f & ~leak_one_f;
// Both ways could hit, use the offset bit to reorder
@ -276,21 +286,22 @@ logic exu_flush_final_d1;
assign wayhit_f[1:0] = tag_match_way0_expanded_f[1:0] | tag_match_way1_expanded_f[1:0];
assign wayhit_p1_f[1:0] = tag_match_way0_expanded_p1_f[1:0] | tag_match_way1_expanded_p1_f[1:0];
assign btb_bank0o_rd_data_f[16+pt.BTB_BTAG_SIZE:0] = ( ({17+pt.BTB_BTAG_SIZE{tag_match_way0_expanded_f[1]}} & btb_bank0_rd_data_way0_f[16+pt.BTB_BTAG_SIZE:0]) |
({17+pt.BTB_BTAG_SIZE{tag_match_way1_expanded_f[1]}} & btb_bank0_rd_data_way1_f[16+pt.BTB_BTAG_SIZE:0]) );
assign btb_bank0e_rd_data_f[16+pt.BTB_BTAG_SIZE:0] = ( ({17+pt.BTB_BTAG_SIZE{tag_match_way0_expanded_f[0]}} & btb_bank0_rd_data_way0_f[16+pt.BTB_BTAG_SIZE:0]) |
({17+pt.BTB_BTAG_SIZE{tag_match_way1_expanded_f[0]}} & btb_bank0_rd_data_way1_f[16+pt.BTB_BTAG_SIZE:0]) );
assign btb_bank0o_rd_data_f[BTB_DWIDTH-1:0] = ( ({17+pt.BTB_BTAG_SIZE{tag_match_way0_expanded_f[1]}} & btb_bank0_rd_data_way0_f[BTB_DWIDTH-1:0]) |
({17+pt.BTB_BTAG_SIZE{tag_match_way1_expanded_f[1]}} & btb_bank0_rd_data_way1_f[BTB_DWIDTH-1:0]) );
assign btb_bank0e_rd_data_f[BTB_DWIDTH-1:0] = ( ({17+pt.BTB_BTAG_SIZE{tag_match_way0_expanded_f[0]}} & btb_bank0_rd_data_way0_f[BTB_DWIDTH-1:0]) |
({17+pt.BTB_BTAG_SIZE{tag_match_way1_expanded_f[0]}} & btb_bank0_rd_data_way1_f[BTB_DWIDTH-1:0]) );
assign btb_bank0e_rd_data_p1_f[16+pt.BTB_BTAG_SIZE:0] = ( ({17+pt.BTB_BTAG_SIZE{tag_match_way0_expanded_p1_f[0]}} & btb_bank0_rd_data_way0_p1_f[16+pt.BTB_BTAG_SIZE:0]) |
({17+pt.BTB_BTAG_SIZE{tag_match_way1_expanded_p1_f[0]}} & btb_bank0_rd_data_way1_p1_f[16+pt.BTB_BTAG_SIZE:0]) );
assign btb_bank0e_rd_data_p1_f[BTB_DWIDTH-1:0] = ( ({17+pt.BTB_BTAG_SIZE{tag_match_way0_expanded_p1_f[0]}} & btb_bank0_rd_data_way0_p1_f[BTB_DWIDTH-1:0]) |
({17+pt.BTB_BTAG_SIZE{tag_match_way1_expanded_p1_f[0]}} & btb_bank0_rd_data_way1_p1_f[BTB_DWIDTH-1:0]) );
// virtual bank order
assign btb_vbank0_rd_data_f[16+pt.BTB_BTAG_SIZE:0] = ( ({17+pt.BTB_BTAG_SIZE{fetch_start_f[0]}} & btb_bank0e_rd_data_f[16+pt.BTB_BTAG_SIZE:0]) |
({17+pt.BTB_BTAG_SIZE{fetch_start_f[1]}} & btb_bank0o_rd_data_f[16+pt.BTB_BTAG_SIZE:0]) );
assign btb_vbank1_rd_data_f[16+pt.BTB_BTAG_SIZE:0] = ( ({17+pt.BTB_BTAG_SIZE{fetch_start_f[0]}} & btb_bank0o_rd_data_f[16+pt.BTB_BTAG_SIZE:0]) |
({17+pt.BTB_BTAG_SIZE{fetch_start_f[1]}} & btb_bank0e_rd_data_p1_f[16+pt.BTB_BTAG_SIZE:0]) );
assign btb_vbank0_rd_data_f[BTB_DWIDTH-1:0] = ( ({17+pt.BTB_BTAG_SIZE{fetch_start_f[0]}} & btb_bank0e_rd_data_f[BTB_DWIDTH-1:0]) |
({17+pt.BTB_BTAG_SIZE{fetch_start_f[1]}} & btb_bank0o_rd_data_f[BTB_DWIDTH-1:0]) );
assign btb_vbank1_rd_data_f[BTB_DWIDTH-1:0] = ( ({17+pt.BTB_BTAG_SIZE{fetch_start_f[0]}} & btb_bank0o_rd_data_f[BTB_DWIDTH-1:0]) |
({17+pt.BTB_BTAG_SIZE{fetch_start_f[1]}} & btb_bank0e_rd_data_p1_f[BTB_DWIDTH-1:0]) );
assign way_raw[1:0] = tag_match_vway1_expanded_f[1:0] | (~vwayhit_f[1:0] & btb_vlru_rd_f[1:0]);
// --------------------------------------------------------------------------------
// --------------------------------------------------------------------------------
@ -306,8 +317,12 @@ logic exu_flush_final_d1;
assign mp_wrlru_b0[LRU_SIZE-1:0] = mp_wrindex_dec[LRU_SIZE-1:0] & {LRU_SIZE{exu_mp_valid}};
genvar j, i;
assign btb_lru_b0_hold[LRU_SIZE-1:0] = ~mp_wrlru_b0[LRU_SIZE-1:0] & ~fetch_wrlru_b0[LRU_SIZE-1:0];
// Forward the mp lru information to the fetch, avoids multiple way hits later
assign use_mp_way = fetch_mp_collision_f;
assign use_mp_way_p1 = fetch_mp_collision_p1_f;
assign lru_update_valid_f = (vwayhit_f[0] | vwayhit_f[1]) & ifc_fetch_req_f & ~leak_one_f;
@ -317,18 +332,13 @@ logic exu_flush_final_d1;
assign fetch_wrlru_p1_b0[LRU_SIZE-1:0] = fetch_wrindex_p1_dec[LRU_SIZE-1:0] &
{LRU_SIZE{lru_update_valid_f}};
assign btb_lru_b0_hold[LRU_SIZE-1:0] = ~mp_wrlru_b0[LRU_SIZE-1:0] & ~fetch_wrlru_b0[LRU_SIZE-1:0];
// Forward the mp lru information to the fetch, avoids multiple way hits later
assign use_mp_way = fetch_mp_collision_f;
assign use_mp_way_p1 = fetch_mp_collision_p1_f;
assign btb_lru_b0_ns[LRU_SIZE-1:0] = ( (btb_lru_b0_hold[LRU_SIZE-1:0] & btb_lru_b0_f[LRU_SIZE-1:0]) |
(mp_wrlru_b0[LRU_SIZE-1:0] & {LRU_SIZE{~exu_mp_way}}) |
(fetch_wrlru_b0[LRU_SIZE-1:0] & {LRU_SIZE{tag_match_way0_f}}) |
(fetch_wrlru_p1_b0[LRU_SIZE-1:0] & {LRU_SIZE{tag_match_way0_p1_f}}) );
assign btb_lru_rd_f = use_mp_way ? exu_mp_way_f : |(fetch_wrindex_dec[LRU_SIZE-1:0] & btb_lru_b0_f[LRU_SIZE-1:0]);
assign btb_lru_rd_p1_f = use_mp_way_p1 ? exu_mp_way_f : |(fetch_wrindex_p1_dec[LRU_SIZE-1:0] & btb_lru_b0_f[LRU_SIZE-1:0]);
@ -340,12 +350,12 @@ logic exu_flush_final_d1;
assign tag_match_vway1_expanded_f[1:0] = ( ({2{fetch_start_f[0]}} & {tag_match_way1_expanded_f[1:0]}) |
({2{fetch_start_f[1]}} & {tag_match_way1_expanded_p1_f[0], tag_match_way1_expanded_f[1]}) );
assign way_raw[1:0] = tag_match_vway1_expanded_f[1:0] | (~vwayhit_f[1:0] & btb_vlru_rd_f[1:0]);
rvdffe #(LRU_SIZE) btb_lru_ff (.*, .en(ifc_fetch_req_f | exu_mp_valid),
.din(btb_lru_b0_ns[(LRU_SIZE)-1:0]),
.dout(btb_lru_b0_f[(LRU_SIZE)-1:0]));
end // if (!pt.BTB_FULLYA)
// Detect end of cache line and mask as needed
logic eoc_near;
logic eoc_mask;
@ -353,8 +363,6 @@ logic exu_flush_final_d1;
assign eoc_mask = ~eoc_near| (|(~ifc_fetch_addr_f[2:1]));
assign vwayhit_f[1:0] = ( ({2{fetch_start_f[0]}} & {wayhit_f[1:0]}) |
({2{fetch_start_f[1]}} & {wayhit_p1_f[0], wayhit_f[1]})) & {eoc_mask, 1'b1};
// --------------------------------------------------------------------------------
// --------------------------------------------------------------------------------
@ -456,7 +464,10 @@ logic exu_flush_final_d1;
({pt.BHT_GHR_SIZE{~exu_flush_final_d1 & ifc_fetch_req_f & ic_hit_f & ~leak_one_f_d1}} & merged_ghr[pt.BHT_GHR_SIZE-1:0]) |
({pt.BHT_GHR_SIZE{~exu_flush_final_d1 & ~(ifc_fetch_req_f & ic_hit_f & ~leak_one_f_d1)}} & fghr[pt.BHT_GHR_SIZE-1:0]));
rvdff #(pt.BHT_GHR_SIZE) fetchghr (.*, .clk(active_clk), .din(fghr_ns[pt.BHT_GHR_SIZE-1:0]), .dout(fghr[pt.BHT_GHR_SIZE-1:0]));
rvdffie #(.WIDTH(pt.BHT_GHR_SIZE+3),.OVERRIDE(1)) fetchghr (.*,
.din ({exu_flush_final, exu_mp_way, leak_one_f, fghr_ns[pt.BHT_GHR_SIZE-1:0]}),
.dout({exu_flush_final_d1, exu_mp_way_f, leak_one_f_d1, fghr[pt.BHT_GHR_SIZE-1:0]}));
assign ifu_bp_fghr_f[pt.BHT_GHR_SIZE-1:0] = fghr[pt.BHT_GHR_SIZE-1:0];
@ -502,7 +513,8 @@ assign use_fa_plus = (~bht_dir_f[0] & ~fetch_start_f[0] & ~btb_rd_pc4_f);
assign bp_total_branch_offset_f = bloc_f[1] ^ btb_rd_pc4_f;
logic [31:2] adder_pc_in_f, ifc_fetch_adder_prior;
rvdffe #(30) faddrf_ff (.*, .en(ifc_fetch_req_f & ~ifu_bp_hit_taken_f & ic_hit_f), .din(ifc_fetch_addr_f[31:2]), .dout(ifc_fetch_adder_prior[31:2]));
rvdfflie #(.WIDTH(30), .LEFT(19)) faddrf_ff (.*, .en(ifc_fetch_req_f & ~ifu_bp_hit_taken_f & ic_hit_f), .din(ifc_fetch_addr_f[31:2]), .dout(ifc_fetch_adder_prior[31:2]));
assign ifu_bp_poffset_f[11:0] = btb_rd_tgt_f[11:0];
@ -514,8 +526,9 @@ assign use_fa_plus = (~bht_dir_f[0] & ~fetch_start_f[0] & ~btb_rd_pc4_f);
.offset(btb_rd_tgt_f[11:0]),
.dout(bp_btb_target_adder_f[31:1])
);
// mux in the return stack address here for a predicted return assuming the RS is valid
assign ifu_bp_btb_target_f[31:1] = (btb_rd_ret_f & ~btb_rd_call_f & rets_out[0][0]) ? rets_out[0][31:1] : bp_btb_target_adder_f[31:1];
// mux in the return stack address here for a predicted return assuming the RS is valid, quite if no prediction
assign ifu_bp_btb_target_f[31:1] = (({31{btb_rd_ret_f & ~btb_rd_call_f & rets_out[0][0] & ifu_bp_hit_taken_f}} & rets_out[0][31:1]) |
({31{~(btb_rd_ret_f & ~btb_rd_call_f & rets_out[0][0]) & ifu_bp_hit_taken_f}} & bp_btb_target_adder_f[31:1]) );
// ----------------------------------------------------------------------
@ -539,7 +552,7 @@ assign use_fa_plus = (~bht_dir_f[0] & ~fetch_start_f[0] & ~btb_rd_pc4_f);
assign rsenable[0] = ~rs_hold;
for (i=0; i<32'(pt.RET_STACK_SIZE); i++) begin : retstack
for (i=0; i<pt.RET_STACK_SIZE; i++) begin : retstack
// for the last entry in the stack, we don't have a pop position
if(i==pt.RET_STACK_SIZE-1) begin
@ -570,18 +583,21 @@ assign use_fa_plus = (~bht_dir_f[0] & ~fetch_start_f[0] & ~btb_rd_pc4_f);
assign btb_wr_tag[pt.BTB_BTAG_SIZE-1:0] = exu_mp_btag[pt.BTB_BTAG_SIZE-1:0];
if(!pt.BTB_FULLYA) begin
if(pt.BTB_BTAG_FOLD) begin : btbfold
el2_btb_tag_hash_fold #(.pt(pt)) rdtagf (.hash(fetch_rd_tag_f[pt.BTB_BTAG_SIZE-1:0]), .pc({ifc_fetch_addr_f[pt.BTB_ADDR_HI+pt.BTB_BTAG_SIZE+pt.BTB_BTAG_SIZE:pt.BTB_ADDR_HI+1]}));
el2_btb_tag_hash_fold #(.pt(pt)) rdtagp1f(.hash(fetch_rd_tag_p1_f[pt.BTB_BTAG_SIZE-1:0]), .pc({fetch_addr_p1_f[ pt.BTB_ADDR_HI+pt.BTB_BTAG_SIZE+pt.BTB_BTAG_SIZE:pt.BTB_ADDR_HI+1]}));
el2_btb_tag_hash_fold #(.pt(pt)) rdtagf (.hash(fetch_rd_tag_f[pt.BTB_BTAG_SIZE-1:0]),
.pc({ifc_fetch_addr_f[pt.BTB_ADDR_HI+pt.BTB_BTAG_SIZE+pt.BTB_BTAG_SIZE:pt.BTB_ADDR_HI+1]}));
el2_btb_tag_hash_fold #(.pt(pt)) rdtagp1f(.hash(fetch_rd_tag_p1_f[pt.BTB_BTAG_SIZE-1:0]),
.pc({fetch_addr_p1_f[ pt.BTB_ADDR_HI+pt.BTB_BTAG_SIZE+pt.BTB_BTAG_SIZE:pt.BTB_ADDR_HI+1]}));
end
else begin
el2_btb_tag_hash #(.pt(pt)) rdtagf(.hash(fetch_rd_tag_f[pt.BTB_BTAG_SIZE-1:0]), .pc({ifc_fetch_addr_f[pt.BTB_ADDR_HI+pt.BTB_BTAG_SIZE+pt.BTB_BTAG_SIZE+pt.BTB_BTAG_SIZE:pt.BTB_ADDR_HI+1]}));
el2_btb_tag_hash #(.pt(pt)) rdtagp1f(.hash(fetch_rd_tag_p1_f[pt.BTB_BTAG_SIZE-1:0]), .pc({fetch_addr_p1_f[pt.BTB_ADDR_HI+pt.BTB_BTAG_SIZE+pt.BTB_BTAG_SIZE+pt.BTB_BTAG_SIZE:pt.BTB_ADDR_HI+1]}));
el2_btb_tag_hash #(.pt(pt)) rdtagf(.hash(fetch_rd_tag_f[pt.BTB_BTAG_SIZE-1:0]),
.pc({ifc_fetch_addr_f[pt.BTB_ADDR_HI+pt.BTB_BTAG_SIZE+pt.BTB_BTAG_SIZE+pt.BTB_BTAG_SIZE:pt.BTB_ADDR_HI+1]}));
el2_btb_tag_hash #(.pt(pt)) rdtagp1f(.hash(fetch_rd_tag_p1_f[pt.BTB_BTAG_SIZE-1:0]),
.pc({fetch_addr_p1_f[pt.BTB_ADDR_HI+pt.BTB_BTAG_SIZE+pt.BTB_BTAG_SIZE+pt.BTB_BTAG_SIZE:pt.BTB_ADDR_HI+1]}));
end
assign btb_wr_data[16+pt.BTB_BTAG_SIZE:0] = {btb_wr_tag[pt.BTB_BTAG_SIZE-1:0], exu_mp_tgt[11:0], exu_mp_pc4, exu_mp_boffset, exu_mp_call | exu_mp_ja, exu_mp_ret | exu_mp_ja, btb_valid} ;
assign exu_mp_valid_write = exu_mp_valid & exu_mp_ataken;
assign btb_wr_en_way0 = ( ({{~exu_mp_way & exu_mp_valid_write & ~dec_tlu_error_wb}}) |
({{~dec_tlu_way_wb & dec_tlu_error_wb}}));
@ -589,6 +605,16 @@ end
({{dec_tlu_way_wb & dec_tlu_error_wb}}));
assign btb_wr_addr[pt.BTB_ADDR_HI:pt.BTB_ADDR_LO] = dec_tlu_error_wb ? btb_error_addr_wb[pt.BTB_ADDR_HI:pt.BTB_ADDR_LO] : exu_mp_addr[pt.BTB_ADDR_HI:pt.BTB_ADDR_LO];
assign vwayhit_f[1:0] = ( ({2{fetch_start_f[0]}} & {wayhit_f[1:0]}) |
({2{fetch_start_f[1]}} & {wayhit_p1_f[0], wayhit_f[1]})) & {eoc_mask, 1'b1};
end // if (!pt.BTB_FULLYA)
assign btb_wr_data[BTB_DWIDTH-1:0] = {btb_wr_tag[pt.BTB_BTAG_SIZE-1:0], exu_mp_tgt[pt.BTB_TOFFSET_SIZE-1:0], exu_mp_pc4, exu_mp_boffset,
exu_mp_call | exu_mp_ja, exu_mp_ret | exu_mp_ja, btb_valid} ;
assign exu_mp_valid_write = exu_mp_valid & exu_mp_ataken & ~exu_mp_pkt.valid;
logic [1:0] bht_wr_data0, bht_wr_data2;
logic [1:0] bht_wr_en0, bht_wr_en2;
@ -622,46 +648,172 @@ end
// BTB
// Entry -> tag[pt.BTB_BTAG_SIZE-1:0], toffset[11:0], pc4, boffset, call, ret, valid
if(!pt.BTB_FULLYA) begin
for (j=0 ; j<32'(LRU_SIZE) ; j++) begin : BTB_FLOPS
for (j=0 ; j<LRU_SIZE ; j++) begin : BTB_FLOPS
// Way 0
rvdffe #(17+pt.BTB_BTAG_SIZE) btb_bank0_way0 (.*,
.en(((btb_wr_addr[pt.BTB_ADDR_HI:pt.BTB_ADDR_LO] == j) & btb_wr_en_way0)),
.din (btb_wr_data[16+pt.BTB_BTAG_SIZE:0]),
.din (btb_wr_data[BTB_DWIDTH-1:0]),
.dout (btb_bank0_rd_data_way0_out[j]));
// Way 1
rvdffe #(17+pt.BTB_BTAG_SIZE) btb_bank0_way1 (.*,
.en(((btb_wr_addr[pt.BTB_ADDR_HI:pt.BTB_ADDR_LO] == j) & btb_wr_en_way1)),
.din (btb_wr_data[16+pt.BTB_BTAG_SIZE:0]),
.din (btb_wr_data[BTB_DWIDTH-1:0]),
.dout (btb_bank0_rd_data_way1_out[j]));
end
always_comb begin : BTB_rd_mux
btb_bank0_rd_data_way0_f[16+pt.BTB_BTAG_SIZE:0] = '0 ;
btb_bank0_rd_data_way1_f[16+pt.BTB_BTAG_SIZE:0] = '0 ;
btb_bank0_rd_data_way0_p1_f[16+pt.BTB_BTAG_SIZE:0] = '0 ;
btb_bank0_rd_data_way1_p1_f[16+pt.BTB_BTAG_SIZE:0] = '0 ;
btb_bank0_rd_data_way0_f[BTB_DWIDTH-1:0] = '0 ;
btb_bank0_rd_data_way1_f[BTB_DWIDTH-1:0] = '0 ;
btb_bank0_rd_data_way0_p1_f[BTB_DWIDTH-1:0] = '0 ;
btb_bank0_rd_data_way1_p1_f[BTB_DWIDTH-1:0] = '0 ;
for (int j=0; j< LRU_SIZE; j++) begin
if (btb_rd_addr_f[pt.BTB_ADDR_HI:pt.BTB_ADDR_LO] == (pt.BTB_ADDR_HI-pt.BTB_ADDR_LO+1)'(j)) begin
btb_bank0_rd_data_way0_f[16+pt.BTB_BTAG_SIZE:0] = btb_bank0_rd_data_way0_out[j];
btb_bank0_rd_data_way1_f[16+pt.BTB_BTAG_SIZE:0] = btb_bank0_rd_data_way1_out[j];
btb_bank0_rd_data_way0_f[BTB_DWIDTH-1:0] = btb_bank0_rd_data_way0_out[j];
btb_bank0_rd_data_way1_f[BTB_DWIDTH-1:0] = btb_bank0_rd_data_way1_out[j];
end
end
for (int j=0; j< LRU_SIZE; j++) begin
if (btb_rd_addr_p1_f[pt.BTB_ADDR_HI:pt.BTB_ADDR_LO] == (pt.BTB_ADDR_HI-pt.BTB_ADDR_LO+1)'(j)) begin
btb_bank0_rd_data_way0_p1_f[16+pt.BTB_BTAG_SIZE:0] = btb_bank0_rd_data_way0_out[j];
btb_bank0_rd_data_way1_p1_f[16+pt.BTB_BTAG_SIZE:0] = btb_bank0_rd_data_way1_out[j];
btb_bank0_rd_data_way0_p1_f[BTB_DWIDTH-1:0] = btb_bank0_rd_data_way0_out[j];
btb_bank0_rd_data_way1_p1_f[BTB_DWIDTH-1:0] = btb_bank0_rd_data_way1_out[j];
end
end
end
end // if (!pt.BTB_FULLYA)
if(pt.BTB_FULLYA) begin : fa
logic found1, hit0, hit1;
logic btb_used_reset, write_used;
logic [$clog2(pt.BTB_SIZE)-1:0] btb_fa_wr_addr0, hit0_index, hit1_index;
logic [pt.BTB_SIZE-1:0] btb_tag_hit, btb_offset_0, btb_offset_1, btb_used_ns, btb_used,
wr0_en, btb_upper_hit;
logic [pt.BTB_SIZE-1:0][BTB_DWIDTH-1:0] btbdata;
// Fully Associative tag hash uses bits 31:3. Bits 2:1 are the offset bits used for the 4 tag comp banks
// Full tag used to speed up lookup. There is one 31:3 cmp per entry, and 4 2:1 cmps per entry.
logic [FA_CMP_LOWER-1:1] ifc_fetch_addr_p1_f;
assign ifc_fetch_addr_p1_f[FA_CMP_LOWER-1:1] = ifc_fetch_addr_f[FA_CMP_LOWER-1:1] + 1'b1;
assign fetch_mp_collision_f = ( (exu_mp_btag[pt.BTB_BTAG_SIZE-1:0] == ifc_fetch_addr_f[31:1]) &
exu_mp_valid & ifc_fetch_req_f & ~exu_mp_pkt.way);
assign fetch_mp_collision_p1_f = ( (exu_mp_btag[pt.BTB_BTAG_SIZE-1:0] == {ifc_fetch_addr_f[31:FA_CMP_LOWER], ifc_fetch_addr_p1_f[FA_CMP_LOWER-1:1]}) &
exu_mp_valid & ifc_fetch_req_f & ~exu_mp_pkt.way);
always_comb begin
btb_vbank0_rd_data_f = '0;
btb_vbank1_rd_data_f = '0;
btb_tag_hit = '0;
btb_upper_hit = '0;
btb_offset_0 = '0;
btb_offset_1 = '0;
found1 = 1'b0;
hit0 = 1'b0;
hit1 = 1'b0;
hit0_index = '0;
hit1_index = '0;
btb_fa_wr_addr0 = '0;
for(int i=0; i<pt.BTB_SIZE; i++) begin
// Break the cmp into chunks for lower area.
// Chunk1: FA 31:6 or 31:5 depending on icache line size
// Chunk2: FA 5:1 or 4:1 depending on icache line size
btb_upper_hit[i] = (btbdata[i][BTB_DWIDTH_TOP:FA_TAG_END_UPPER] == ifc_fetch_addr_f[31:FA_CMP_LOWER]) & btbdata[i][0] & ~wr0_en[i];
btb_offset_0[i] = (btbdata[i][FA_TAG_START_LOWER:FA_TAG_END_LOWER] == ifc_fetch_addr_f[FA_CMP_LOWER-1:1]) & btb_upper_hit[i];
btb_offset_1[i] = (btbdata[i][FA_TAG_START_LOWER:FA_TAG_END_LOWER] == ifc_fetch_addr_p1_f[FA_CMP_LOWER-1:1]) & btb_upper_hit[i];
if(~hit0) begin
if(btb_offset_0[i]) begin
hit0_index[BTB_FA_INDEX:0] = (BTB_FA_INDEX+1)'(i);
// hit unless we are also writing this entry at the same time
hit0 = 1'b1;
end
end
if(~hit1) begin
if(btb_offset_1[i]) begin
hit1_index[BTB_FA_INDEX:0] = (BTB_FA_INDEX+1)'(i);
hit1 = 1'b1;
end
end
// Mux out the 2 potential branches
if(btb_offset_0[i] == 1'b1)
btb_vbank0_rd_data_f[BTB_DWIDTH-1:0] = fetch_mp_collision_f ? btb_wr_data : btbdata[i];
if(btb_offset_1[i] == 1'b1)
btb_vbank1_rd_data_f[BTB_DWIDTH-1:0] = fetch_mp_collision_p1_f ? btb_wr_data : btbdata[i];
// find the first zero from bit zero in the used vector, this is the write address
if(~found1) begin
if(~btb_used[i]) begin
btb_fa_wr_addr0[BTB_FA_INDEX:0] = i[BTB_FA_INDEX:0];
found1 = 1'b1;
end
end
end
end // always_comb begin
`ifdef RV_ASSERT_ON
btbhitonehot0: assert #0 ($onehot0(btb_offset_0));
btbhitonehot1: assert #0 ($onehot0(btb_offset_1));
`endif
assign vwayhit_f[1:0] = {hit1, hit0} & {eoc_mask, 1'b1};
// way bit is reused as the predicted bit
assign way_raw[1:0] = vwayhit_f[1:0] | {fetch_mp_collision_p1_f, fetch_mp_collision_f};
for (j=0 ; j<pt.BTB_SIZE ; j++) begin : BTB_FAFLOPS
assign wr0_en[j] = ((btb_fa_wr_addr0[BTB_FA_INDEX:0] == j) & (exu_mp_valid_write & ~exu_mp_pkt.way)) |
((dec_fa_error_index == j) & dec_tlu_error_wb);
rvdffe #(BTB_DWIDTH) btb_fa (.*, .clk(clk),
.en (wr0_en[j]),
.din (btb_wr_data[BTB_DWIDTH-1:0]),
.dout(btbdata[j]));
end // block: BTB_FAFLOPS
assign ifu_bp_fa_index_f[1] = hit1 ? hit1_index : '0;
assign ifu_bp_fa_index_f[0] = hit0 ? hit0_index : '0;
assign btb_used_reset = &btb_used[pt.BTB_SIZE-1:0];
assign btb_used_ns[pt.BTB_SIZE-1:0] = ({pt.BTB_SIZE{vwayhit_f[1]}} & (32'b1 << hit1_index[BTB_FA_INDEX:0])) |
({pt.BTB_SIZE{vwayhit_f[0]}} & (32'b1 << hit0_index[BTB_FA_INDEX:0])) |
({pt.BTB_SIZE{exu_mp_valid_write & ~exu_mp_pkt.way & ~dec_tlu_error_wb}} & (32'b1 << btb_fa_wr_addr0[BTB_FA_INDEX:0])) |
({pt.BTB_SIZE{btb_used_reset}} & {pt.BTB_SIZE{1'b0}}) |
({pt.BTB_SIZE{~btb_used_reset & dec_tlu_error_wb}} & (btb_used[pt.BTB_SIZE-1:0] & ~(32'b1 << dec_fa_error_index[BTB_FA_INDEX:0]))) |
(~{pt.BTB_SIZE{btb_used_reset | dec_tlu_error_wb}} & btb_used[pt.BTB_SIZE-1:0]);
assign write_used = btb_used_reset | ifu_bp_hit_taken_f | exu_mp_valid_write | dec_tlu_error_wb;
rvdffe #(pt.BTB_SIZE) btb_usedf (.*, .clk(clk),
.en (write_used),
.din (btb_used_ns[pt.BTB_SIZE-1:0]),
.dout(btb_used[pt.BTB_SIZE-1:0]));
end // block: fa
//-----------------------------------------------------------------------------
// BHT
@ -676,11 +828,12 @@ end
logic [1:0] [(pt.BHT_ARRAY_DEPTH/NUM_BHT_LOOP)-1:0][NUM_BHT_LOOP-1:0] bht_bank_sel ;
for ( i=0; i<2; i++) begin : BANKS
for (genvar k=0 ; k < 32'((pt.BHT_ARRAY_DEPTH)/NUM_BHT_LOOP) ; k++) begin : BHT_CLK_GROUP
for (genvar k=0 ; k < (pt.BHT_ARRAY_DEPTH)/NUM_BHT_LOOP ; k++) begin : BHT_CLK_GROUP
assign bht_bank_clken[i][k] = (bht_wr_en0[i] & ((bht_wr_addr0[pt.BHT_ADDR_HI: NUM_BHT_LOOP_OUTER_LO]==k) | BHT_NO_ADDR_MATCH)) |
(bht_wr_en2[i] & ((bht_wr_addr2[pt.BHT_ADDR_HI: NUM_BHT_LOOP_OUTER_LO]==k) | BHT_NO_ADDR_MATCH));
rvclkhdr bht_bank_grp_cgc ( .en(bht_bank_clken[i][k]), .l1clk(bht_bank_clk[i][k]), .* );
`ifndef RV_FPGA_OPTIMIZE
rvclkhdr bht_bank_grp_cgc ( .en(bht_bank_clken[i][k]), .l1clk(bht_bank_clk[i][k]), .* ); // ifndef RV_FPGA_OPTIMIZE
`endif
for (j=0 ; j<NUM_BHT_LOOP ; j++) begin : BHT_FLOPS
assign bht_bank_sel[i][k][j] = (bht_wr_en0[i] & (bht_wr_addr0[NUM_BHT_LOOP_INNER_HI :pt.BHT_ADDR_LO] == j) & ((bht_wr_addr0[pt.BHT_ADDR_HI: NUM_BHT_LOOP_OUTER_LO]==k) | BHT_NO_ADDR_MATCH)) |
@ -690,9 +843,11 @@ end
bht_wr_data0[1:0] ;
rvdffs #(2) bht_bank (.*,
rvdffs_fpga #(2) bht_bank (.*,
.clk (bht_bank_clk[i][k]),
.en (bht_bank_sel[i][k][j]),
.rawclk (clk),
.clken (bht_bank_sel[i][k][j]),
.din (bht_bank_wr_data[i][k][j]),
.dout (bht_bank_rd_data_out[i][(16*k)+j]));
@ -716,9 +871,6 @@ end
end // block: BHT_rd_mux
function [1:0] countones;
input [1:0] valid;
@ -728,25 +880,5 @@ countones[1:0] = {2'b0, valid[1]} +
{2'b0, valid[0]};
end
endfunction
function [2:0] newlru; // updated lru
input [2:0] lru;// current lru
input [1:0] used;// hit way
begin
newlru[2] = (lru[2] & ~used[0]) | (~used[1] & ~used[0]);
newlru[1] = (~used[1] & ~used[0]) | (used[0]);
newlru[0] = (~lru[2] & lru[1] & ~used[1] & ~used[0]) | (~lru[1] & ~lru[0] & used[0]) | (
~lru[2] & lru[0] & used[0]) | (lru[0] & ~used[1] & ~used[0]);
end
endfunction //
function [1:0] lru2way; // new repl way taking invalid ways into account
input [2:0] lru; // current lru
input [2:0] v; // current way valids
begin
lru2way[1] = (~lru[2] & lru[1] & ~lru[0] & v[1] & v[0]) | (lru[2] & lru[0] & v[1] & v[0]) | (~v[2] & v[1] & v[0]);
lru2way[0] = (lru[2] & ~lru[0] & v[2] & v[0]) | (~v[1] & v[0]);
end
endfunction
endmodule // el2_ifu_bp_ctl

View File

@ -1,6 +1,6 @@
//********************************************************************************
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 Western Digital Corporation or it's affiliates.
// Copyright 2020 Western Digital Corporation or its affiliates.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -23,8 +23,8 @@ import el2_pkg::*;
`include "el2_param.vh"
)
(
input logic [15:0] din,
output logic [31:0] dout
input logic [15:0] din, // 16-bit compressed instruction
output logic [31:0] dout // 32-bit uncompressed instruction
);

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
//********************************************************************************
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 Western Digital Corporation or it's affiliates.
// Copyright 2020 Western Digital Corporation or its affiliates.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -24,22 +24,24 @@ import el2_pkg::*;
#(
`include "el2_param.vh"
)(
input logic clk,
input logic rst_l,
input logic clk_override,
input logic clk, // Clock only while core active. Through one clock header. For flops with second clock header built in. Connected to ACTIVE_L2CLK.
input logic active_clk, // Clock only while core active. Through two clock headers. For flops without second clock header built in.
input logic rst_l, // reset, active low
input logic clk_override, // Override non-functional clock gating
input logic iccm_wren,
input logic iccm_rden,
input logic [pt.ICCM_BITS-1:1] iccm_rw_addr,
input logic iccm_wren, // ICCM write enable
input logic iccm_rden, // ICCM read enable
input logic [pt.ICCM_BITS-1:1] iccm_rw_addr, // ICCM read/write address
input logic iccm_buf_correct_ecc, // ICCM is doing a single bit error correct cycle
input logic iccm_correction_state, // We are under a correction - This is needed to guard replacements when hit
input logic [2:0] iccm_wr_size,
input logic [77:0] iccm_wr_data,
input logic iccm_correction_state, // ICCM under a correction - This is needed to guard replacements when hit
input logic [2:0] iccm_wr_size, // ICCM write size
input logic [77:0] iccm_wr_data, // ICCM write data
input el2_ccm_ext_in_pkt_t [pt.ICCM_NUM_BANKS-1:0] iccm_ext_in_pkt, // External packet
output logic [63:0] iccm_rd_data,
output logic [77:0] iccm_rd_data_ecc,
input logic scan_mode
output logic [63:0] iccm_rd_data, // ICCM read data
output logic [77:0] iccm_rd_data_ecc, // ICCM read ecc
input logic scan_mode // Scan mode control
);
@ -72,15 +74,32 @@ import el2_pkg::*;
logic redundant_data1_en;
logic r0_addr_en, r1_addr_en;
// Testing persistent flip
// logic [3:0] not_iccm_bank_dout;
// logic [15:3] ecc_insert_flip_in, ecc_insert_flip;
// logic flip_en, flip_match, flip_match_q;
//
// assign flip_in = (iccm_rw_addr[3:2] != 2'b00); // dont flip when bank0 - this is to make some progress in DMA streaming cases
// assign flip_en = iccm_rden;
//
// rvdffs #(1) flipmatch (.*,
// .clk(clk),
// .din(flip_in),
// .en(flip_en),
// .dout(flip_match_q));
//
// end of testing flip
assign addr_incr[1:0] = (iccm_wr_size[1:0] == 2'b11) ? 2'b10: 2'b01;
assign addr_bank_inc[pt.ICCM_BITS-1 : 1] = iccm_rw_addr[pt.ICCM_BITS-1 : 1] + addr_incr[1:0];
for (genvar i=0; i<32'(pt.ICCM_NUM_BANKS)/2; i++) begin: mem_bank_data
for (genvar i=0; i<pt.ICCM_NUM_BANKS/2; i++) begin: mem_bank_data
assign iccm_bank_wr_data_vec[(2*i)] = iccm_wr_data[38:0];
assign iccm_bank_wr_data_vec[(2*i)+1] = iccm_wr_data[77:39];
end
for (genvar i=0; i<32'(pt.ICCM_NUM_BANKS); i++) begin: mem_bank
for (genvar i=0; i<pt.ICCM_NUM_BANKS; i++) begin: mem_bank
assign wren_bank[i] = iccm_wren & ((iccm_rw_addr[pt.ICCM_BANK_HI:2] == i) | (addr_bank_inc[pt.ICCM_BANK_HI:2] == i));
assign iccm_bank_wr_data[i] = iccm_bank_wr_data_vec[i];
assign rden_bank[i] = iccm_rden & ( (iccm_rw_addr[pt.ICCM_BANK_HI:2] == i) | (addr_bank_inc[pt.ICCM_BANK_HI:2] == i));
@ -98,7 +117,18 @@ import el2_pkg::*;
.WE(wren_bank[i]),
.ADR(addr_bank[i]),
.D(iccm_bank_wr_data[i][38:0]),
.Q(iccm_bank_dout[i][38:0])
.Q(iccm_bank_dout[i][38:0]),
.ROP ( ),
// These are used by SoC
.TEST1(iccm_ext_in_pkt[i].TEST1),
.RME(iccm_ext_in_pkt[i].RME),
.RM(iccm_ext_in_pkt[i].RM),
.LS(iccm_ext_in_pkt[i].LS),
.DS(iccm_ext_in_pkt[i].DS),
.SD(iccm_ext_in_pkt[i].SD) ,
.TEST_RNM(iccm_ext_in_pkt[i].TEST_RNM),
.BC1(iccm_ext_in_pkt[i].BC1),
.BC2(iccm_ext_in_pkt[i].BC2)
);
`else
@ -111,7 +141,18 @@ import el2_pkg::*;
.WE(wren_bank[i]),
.ADR(addr_bank[i]),
.D(iccm_bank_wr_data[i][38:0]),
.Q(iccm_bank_dout[i][38:0])
.Q(iccm_bank_dout[i][38:0]),
.ROP ( ),
// These are used by SoC
.TEST1(iccm_ext_in_pkt[i].TEST1),
.RME(iccm_ext_in_pkt[i].RME),
.RM(iccm_ext_in_pkt[i].RM),
.LS(iccm_ext_in_pkt[i].LS),
.DS(iccm_ext_in_pkt[i].DS),
.SD(iccm_ext_in_pkt[i].SD) ,
.TEST_RNM(iccm_ext_in_pkt[i].TEST_RNM),
.BC1(iccm_ext_in_pkt[i].BC1),
.BC2(iccm_ext_in_pkt[i].BC2)
);
end // block: iccm
@ -124,7 +165,18 @@ import el2_pkg::*;
.WE(wren_bank[i]),
.ADR(addr_bank[i]),
.D(iccm_bank_wr_data[i][38:0]),
.Q(iccm_bank_dout[i][38:0])
.Q(iccm_bank_dout[i][38:0]),
.ROP ( ),
// These are used by SoC
.TEST1(iccm_ext_in_pkt[i].TEST1),
.RME(iccm_ext_in_pkt[i].RME),
.RM(iccm_ext_in_pkt[i].RM),
.LS(iccm_ext_in_pkt[i].LS),
.DS(iccm_ext_in_pkt[i].DS),
.SD(iccm_ext_in_pkt[i].SD) ,
.TEST_RNM(iccm_ext_in_pkt[i].TEST_RNM),
.BC1(iccm_ext_in_pkt[i].BC1),
.BC2(iccm_ext_in_pkt[i].BC2)
);
end // block: iccm
@ -137,7 +189,18 @@ import el2_pkg::*;
.WE(wren_bank[i]),
.ADR(addr_bank[i]),
.D(iccm_bank_wr_data[i][38:0]),
.Q(iccm_bank_dout[i][38:0])
.Q(iccm_bank_dout[i][38:0]),
.ROP ( ),
// These are used by SoC
.TEST1(iccm_ext_in_pkt[i].TEST1),
.RME(iccm_ext_in_pkt[i].RME),
.RM(iccm_ext_in_pkt[i].RM),
.LS(iccm_ext_in_pkt[i].LS),
.DS(iccm_ext_in_pkt[i].DS),
.SD(iccm_ext_in_pkt[i].SD) ,
.TEST_RNM(iccm_ext_in_pkt[i].TEST_RNM),
.BC1(iccm_ext_in_pkt[i].BC1),
.BC2(iccm_ext_in_pkt[i].BC2)
);
end // block: iccm
@ -149,7 +212,18 @@ import el2_pkg::*;
.WE(wren_bank[i]),
.ADR(addr_bank[i]),
.D(iccm_bank_wr_data[i][38:0]),
.Q(iccm_bank_dout[i][38:0])
.Q(iccm_bank_dout[i][38:0]),
.ROP ( ),
// These are used by SoC
.TEST1(iccm_ext_in_pkt[i].TEST1),
.RME(iccm_ext_in_pkt[i].RME),
.RM(iccm_ext_in_pkt[i].RM),
.LS(iccm_ext_in_pkt[i].LS),
.DS(iccm_ext_in_pkt[i].DS),
.SD(iccm_ext_in_pkt[i].SD) ,
.TEST_RNM(iccm_ext_in_pkt[i].TEST_RNM),
.BC1(iccm_ext_in_pkt[i].BC1),
.BC2(iccm_ext_in_pkt[i].BC2)
);
end // block: iccm
@ -161,7 +235,18 @@ import el2_pkg::*;
.WE(wren_bank[i]),
.ADR(addr_bank[i]),
.D(iccm_bank_wr_data[i][38:0]),
.Q(iccm_bank_dout[i][38:0])
.Q(iccm_bank_dout[i][38:0]),
.ROP ( ),
// These are used by SoC
.TEST1(iccm_ext_in_pkt[i].TEST1),
.RME(iccm_ext_in_pkt[i].RME),
.RM(iccm_ext_in_pkt[i].RM),
.LS(iccm_ext_in_pkt[i].LS),
.DS(iccm_ext_in_pkt[i].DS),
.SD(iccm_ext_in_pkt[i].SD) ,
.TEST_RNM(iccm_ext_in_pkt[i].TEST_RNM),
.BC1(iccm_ext_in_pkt[i].BC1),
.BC2(iccm_ext_in_pkt[i].BC2)
);
end // block: iccm
@ -173,7 +258,18 @@ import el2_pkg::*;
.WE(wren_bank[i]),
.ADR(addr_bank[i]),
.D(iccm_bank_wr_data[i][38:0]),
.Q(iccm_bank_dout[i][38:0])
.Q(iccm_bank_dout[i][38:0]),
.ROP ( ),
// These are used by SoC
.TEST1(iccm_ext_in_pkt[i].TEST1),
.RME(iccm_ext_in_pkt[i].RME),
.RM(iccm_ext_in_pkt[i].RM),
.LS(iccm_ext_in_pkt[i].LS),
.DS(iccm_ext_in_pkt[i].DS),
.SD(iccm_ext_in_pkt[i].SD) ,
.TEST_RNM(iccm_ext_in_pkt[i].TEST_RNM),
.BC1(iccm_ext_in_pkt[i].BC1),
.BC2(iccm_ext_in_pkt[i].BC2)
);
end // block: iccm
@ -185,7 +281,18 @@ import el2_pkg::*;
.WE(wren_bank[i]),
.ADR(addr_bank[i]),
.D(iccm_bank_wr_data[i][38:0]),
.Q(iccm_bank_dout[i][38:0])
.Q(iccm_bank_dout[i][38:0]),
.ROP ( ),
// These are used by SoC
.TEST1(iccm_ext_in_pkt[i].TEST1),
.RME(iccm_ext_in_pkt[i].RME),
.RM(iccm_ext_in_pkt[i].RM),
.LS(iccm_ext_in_pkt[i].LS),
.DS(iccm_ext_in_pkt[i].DS),
.SD(iccm_ext_in_pkt[i].SD) ,
.TEST_RNM(iccm_ext_in_pkt[i].TEST_RNM),
.BC1(iccm_ext_in_pkt[i].BC1),
.BC2(iccm_ext_in_pkt[i].BC2)
);
end // block: iccm
@ -197,7 +304,18 @@ import el2_pkg::*;
.WE(wren_bank[i]),
.ADR(addr_bank[i]),
.D(iccm_bank_wr_data[i][38:0]),
.Q(iccm_bank_dout[i][38:0])
.Q(iccm_bank_dout[i][38:0]),
.ROP ( ),
// These are used by SoC
.TEST1(iccm_ext_in_pkt[i].TEST1),
.RME(iccm_ext_in_pkt[i].RME),
.RM(iccm_ext_in_pkt[i].RM),
.LS(iccm_ext_in_pkt[i].LS),
.DS(iccm_ext_in_pkt[i].DS),
.SD(iccm_ext_in_pkt[i].SD) ,
.TEST_RNM(iccm_ext_in_pkt[i].TEST_RNM),
.BC1(iccm_ext_in_pkt[i].BC1),
.BC2(iccm_ext_in_pkt[i].BC2)
);
end // block: iccm
@ -209,7 +327,18 @@ import el2_pkg::*;
.WE(wren_bank[i]),
.ADR(addr_bank[i]),
.D(iccm_bank_wr_data[i][38:0]),
.Q(iccm_bank_dout[i][38:0])
.Q(iccm_bank_dout[i][38:0]),
.ROP ( ),
// These are used by SoC
.TEST1(iccm_ext_in_pkt[i].TEST1),
.RME(iccm_ext_in_pkt[i].RME),
.RM(iccm_ext_in_pkt[i].RM),
.LS(iccm_ext_in_pkt[i].LS),
.DS(iccm_ext_in_pkt[i].DS),
.SD(iccm_ext_in_pkt[i].SD) ,
.TEST_RNM(iccm_ext_in_pkt[i].TEST_RNM),
.BC1(iccm_ext_in_pkt[i].BC1),
.BC2(iccm_ext_in_pkt[i].BC2)
);
end // block: iccm
@ -221,7 +350,18 @@ import el2_pkg::*;
.WE(wren_bank[i]),
.ADR(addr_bank[i]),
.D(iccm_bank_wr_data[i][38:0]),
.Q(iccm_bank_dout[i][38:0])
.Q(iccm_bank_dout[i][38:0]),
.ROP ( ),
// These are used by SoC
.TEST1(iccm_ext_in_pkt[i].TEST1),
.RME(iccm_ext_in_pkt[i].RME),
.RM(iccm_ext_in_pkt[i].RM),
.LS(iccm_ext_in_pkt[i].LS),
.DS(iccm_ext_in_pkt[i].DS),
.SD(iccm_ext_in_pkt[i].SD) ,
.TEST_RNM(iccm_ext_in_pkt[i].TEST_RNM),
.BC1(iccm_ext_in_pkt[i].BC1),
.BC2(iccm_ext_in_pkt[i].BC2)
);
end // block: iccm
@ -235,12 +375,12 @@ import el2_pkg::*;
((addr_bank_inc[pt.ICCM_BITS-1:2]== redundant_address[0][pt.ICCM_BITS-1:2]) & (addr_bank_inc[3:2] == i))));
rvdff #(1) selred0 (.*,
.clk(clk),
.clk(active_clk),
.din(sel_red0[i]),
.dout(sel_red0_q[i]));
rvdff #(1) selred1 (.*,
.clk(clk),
.clk(active_clk),
.din(sel_red1[i]),
.dout(sel_red1_q[i]));
@ -250,7 +390,6 @@ import el2_pkg::*;
({39{sel_red0_q[i]}} & redundant_data[0][38:0]) |
({39{~sel_red0_q[i] & ~sel_red1_q[i]}} & iccm_bank_dout[i][38:0]);
end : mem_bank
// This section does the redundancy for tolerating single bit errors
// 2x 39 bit data values with address[hi:2] and a valid bit is needed to CAM and sub out the reads/writes to the particular locations
@ -261,31 +400,31 @@ import el2_pkg::*;
assign redundant_lru_in = iccm_buf_correct_ecc ? ~redundant_lru : (|sel_red0[pt.ICCM_NUM_BANKS-1:0]) ? 1'b1 : 1'b0;
rvdffs #() red_lru (.*, // LRU flop for the redundant replacements
.clk(clk),
.clk(active_clk),
.en(redundant_lru_en),
.din(redundant_lru_in),
.dout(redundant_lru));
rvdffs #(pt.ICCM_BITS-2) r0_address (.*, // Redundant Row 0 address
.clk(clk),
.clk(active_clk),
.en(r0_addr_en),
.din(iccm_rw_addr[pt.ICCM_BITS-1:2]),
.dout(redundant_address[0][pt.ICCM_BITS-1:2]));
rvdffs #(pt.ICCM_BITS-2) r1_address (.*, // Redundant Row 0 address
.clk(clk),
.clk(active_clk),
.en(r1_addr_en),
.din(iccm_rw_addr[pt.ICCM_BITS-1:2]),
.dout(redundant_address[1][pt.ICCM_BITS-1:2]));
rvdffs #(1) r0_valid (.*,
.clk(clk), // Redundant Row 0 Valid
.clk(active_clk), // Redundant Row 0 Valid
.en(r0_addr_en),
.din(1'b1),
.dout(redundant_valid[0]));
rvdffs #(1) r1_valid (.*, // Redundant Row 1 Valid
.clk(clk),
.clk(active_clk),
.en(r1_addr_en),
.din(1'b1),
.dout(redundant_valid[1]));
@ -302,7 +441,7 @@ import el2_pkg::*;
assign redundant_data0_in[38:0] = (((iccm_rw_addr[2] == redundant_address[0][2]) & iccm_rw_addr[2]) | (redundant_address[0][2] & (iccm_wr_size[1:0] == 2'b11))) ? iccm_wr_data[77:39] : iccm_wr_data[38:0];
rvdffs #(39) r0_data (.*, // Redundant Row 1 data
.clk(clk),
.clk(active_clk),
.en(redundant_data0_en),
.din(redundant_data0_in[38:0]),
.dout(redundant_data[0][38:0]));
@ -313,14 +452,14 @@ import el2_pkg::*;
assign redundant_data1_in[38:0] = (((iccm_rw_addr[2] == redundant_address[1][2]) & iccm_rw_addr[2]) | (redundant_address[1][2] & (iccm_wr_size[1:0] == 2'b11))) ? iccm_wr_data[77:39] : iccm_wr_data[38:0];
rvdffs #(39) r1_data (.*, // Redundant Row 1 data
.clk(clk),
.clk(active_clk),
.en(redundant_data1_en),
.din(redundant_data1_in[38:0]),
.dout(redundant_data[1][38:0]));
rvdffs #(pt.ICCM_BANK_HI) rd_addr_lo_ff (.*, .din(iccm_rw_addr [pt.ICCM_BANK_HI:1]), .dout(iccm_rd_addr_lo_q[pt.ICCM_BANK_HI:1]), .en(1'b1)); // bit 0 of address is always 0
rvdffs #(pt.ICCM_BANK_BITS) rd_addr_hi_ff (.*, .din(addr_bank_inc[pt.ICCM_BANK_HI:2]), .dout(iccm_rd_addr_hi_q[pt.ICCM_BANK_HI:2]), .en(1'b1));
rvdffs #(pt.ICCM_BANK_HI) rd_addr_lo_ff (.*, .clk(active_clk), .din(iccm_rw_addr [pt.ICCM_BANK_HI:1]), .dout(iccm_rd_addr_lo_q[pt.ICCM_BANK_HI:1]), .en(1'b1)); // bit 0 of address is always 0
rvdffs #(pt.ICCM_BANK_BITS) rd_addr_hi_ff (.*, .clk(active_clk), .din(addr_bank_inc[pt.ICCM_BANK_HI:2]), .dout(iccm_rd_addr_hi_q[pt.ICCM_BANK_HI:2]), .en(1'b1));
assign iccm_rd_data_pre[63:0] = {iccm_bank_dout_fn[iccm_rd_addr_hi_q][31:0], iccm_bank_dout_fn[iccm_rd_addr_lo_q[pt.ICCM_BANK_HI:2]][31:0]};
assign iccm_data[63:0] = 64'({16'b0, (iccm_rd_data_pre[63:0] >> (16*iccm_rd_addr_lo_q[1]))});

View File

@ -1,5 +1,5 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 Western Digital Corporation or it's affiliates.
// Copyright 2020 Western Digital Corporation or its affiliates.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -26,9 +26,8 @@ import el2_pkg::*;
`include "el2_param.vh"
)
(
input logic clk,
input logic free_clk,
input logic active_clk,
input logic clk, // Clock only while core active. Through one clock header. For flops with second clock header built in. Connected to ACTIVE_L2CLK.
input logic free_l2clk, // Clock always. Through one clock header. For flops with second header built in.
input logic rst_l, // reset enable, from core pin
input logic scan_mode, // scan
@ -76,7 +75,7 @@ import el2_pkg::*;
logic fb_full_f_ns, fb_full_f;
logic fb_right, fb_right2, fb_left, wfm, idle;
logic sel_last_addr_bf, sel_btb_addr_bf, sel_next_addr_bf;
logic sel_last_addr_bf, sel_next_addr_bf;
logic miss_f, miss_a;
logic flush_fb, dma_iccm_stall_any_f;
logic mb_empty_mod, goto_idle, leave_idle;
@ -95,13 +94,15 @@ import el2_pkg::*;
logic dma_stall;
assign dma_stall = ic_dma_active | dma_iccm_stall_any_f;
rvdff #(2) ran_ff (.*, .clk(free_clk), .din({dma_iccm_stall_any, miss_f}), .dout({dma_iccm_stall_any_f, miss_a}));
// Fetch address mux
// - flush
// - Miss *or* flush during WFM (icache miss buffer is blocking)
// - Sequential
if(pt.BTB_ENABLE==1) begin
logic sel_btb_addr_bf;
assign sel_last_addr_bf = ~exu_flush_final & (~ifc_fetch_req_f | ~ic_hit_f);
assign sel_btb_addr_bf = ~exu_flush_final & ifc_fetch_req_f & ifu_bp_hit_taken_f & ic_hit_f;
@ -114,6 +115,17 @@ import el2_pkg::*;
({31{sel_next_addr_bf}} & {fetch_addr_next[31:1]})); // SEQ path
end // if (pt.BTB_ENABLE=1)
else begin
assign sel_last_addr_bf = ~exu_flush_final & (~ifc_fetch_req_f | ~ic_hit_f);
assign sel_next_addr_bf = ~exu_flush_final & ifc_fetch_req_f & ic_hit_f;
assign fetch_addr_bf[31:1] = ( ({31{exu_flush_final}} & exu_flush_path_final[31:1]) | // FLUSH path
({31{sel_last_addr_bf}} & ifc_fetch_addr_f[31:1]) | // MISS path
({31{sel_next_addr_bf}} & {fetch_addr_next[31:1]})); // SEQ path
end
assign fetch_addr_next[31:1] = {({ifc_fetch_addr_f[31:2]} + 31'b1), fetch_addr_next_1 };
assign line_wrap = (fetch_addr_next[pt.ICACHE_TAG_INDEX_LO] ^ ifc_fetch_addr_f[pt.ICACHE_TAG_INDEX_LO]);
@ -186,8 +198,9 @@ import el2_pkg::*;
assign idle = state == IDLE ;
assign wfm = state == WFM ;
rvdff #(2) fsm_ff (.*, .clk(active_clk), .din({next_state[1:0]}), .dout({state[1:0]}));
rvdff #(5) fbwrite_ff (.*, .clk(active_clk), .din({fb_full_f_ns, fb_write_ns[3:0]}), .dout({fb_full_f, fb_write_f[3:0]}));
rvdffie #(10) fbwrite_ff (.*, .clk(free_l2clk),
.din( {dma_iccm_stall_any, miss_f, ifc_fetch_req_bf, next_state[1:0], fb_full_f_ns, fb_write_ns[3:0]}),
.dout({dma_iccm_stall_any_f, miss_a, ifc_fetch_req_f, state[1:0], fb_full_f, fb_write_f[3:0]}));
assign ifu_pmu_fetch_stall = wfm |
(ifc_fetch_req_bf_raw &
@ -195,11 +208,10 @@ import el2_pkg::*;
dma_stall));
rvdff #(1) req_ff (.*, .clk(active_clk), .din(ifc_fetch_req_bf), .dout(ifc_fetch_req_f));
assign ifc_fetch_addr_bf[31:1] = fetch_addr_bf[31:1];
rvdffe #(31) faddrf1_ff (.*, .en(fetch_bf_en), .din(fetch_addr_bf[31:1]), .dout(ifc_fetch_addr_f[31:1]));
rvdffpcie #(31) faddrf1_ff (.*, .en(fetch_bf_en), .din(fetch_addr_bf[31:1]), .dout(ifc_fetch_addr_f[31:1]));
if (pt.ICCM_ENABLE) begin

View File

@ -1,6 +1,6 @@
//********************************************************************************
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 Western Digital Corporation or it's affiliates.
// Copyright 2020 Western Digital Corporation or its affiliates.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -27,10 +27,10 @@ import el2_pkg::*;
`include "el2_param.vh"
)
(
input logic clk,
input logic free_clk, // free clock always except during pause
input logic active_clk, // Active always except during pause
input logic rst_l,
input logic clk, // Clock only while core active. Through one clock header. For flops with second clock header built in. Connected to ACTIVE_L2CLK.
input logic active_clk, // Clock only while core active. Through two clock headers. For flops without second clock header built in.
input logic free_l2clk, // Clock always. Through one clock header. For flops with second header built in.
input logic rst_l, // reset, active low
input logic exu_flush_final, // Flush from the pipeline., includes flush lower
input logic dec_tlu_flush_lower_wb, // Flush lower from the pipeline.
@ -160,10 +160,10 @@ import el2_pkg::*;
input logic [1:0] ifu_fetch_val,
// IFU control signals
output logic ic_hit_f, // Hit in Icache(if Icache access) or ICCM access( ICCM always has ic_hit_f)
output logic ic_access_fault_f, // Access fault (bus error or ICCM access in region but out of offset range).
output logic [1:0] ic_access_fault_f, // Access fault (bus error or ICCM access in region but out of offset range).
output logic [1:0] ic_access_fault_type_f, // Access fault types
output logic iccm_rd_ecc_single_err, // This fetch has a single ICCM ecc error.
output logic iccm_rd_ecc_double_err, // This fetch has a double ICCM ecc error.
output logic [1:0] iccm_rd_ecc_double_err, // This fetch has a double ICCM ecc error.
output logic ic_error_start, // This has any I$ errors ( data/tag/ecc/parity )
output logic ifu_async_error_start, // Or of the sb iccm, and all the icache errors sent to aligner to stop
@ -184,7 +184,6 @@ import el2_pkg::*;
input logic scan_mode
);
// Create different defines for ICACHE and ICCM enable combinations
localparam NUM_OF_BEATS = 8 ;
@ -219,6 +218,7 @@ import el2_pkg::*;
logic ifu_wr_data_comb_err ;
logic ifu_byp_data_err_new;
logic [1:0] ifu_byp_data_err_f;
logic ifu_wr_cumulative_err_data;
logic ifu_wr_cumulative_err;
logic ifu_wr_data_comb_err_ff;
@ -229,7 +229,7 @@ import el2_pkg::*;
logic ifc_iccm_access_f ;
logic ifc_region_acc_fault_f;
logic ifc_region_acc_fault_final_f;
logic ifc_bus_acc_fault_f;
logic [1:0] ifc_bus_acc_fault_f;
logic ic_act_miss_f;
logic ic_miss_under_miss_f;
logic ic_ignore_2nd_miss_f;
@ -312,14 +312,12 @@ import el2_pkg::*;
logic ifu_pmu_bus_busy_in;
logic ic_debug_ict_array_sel_in;
logic ic_debug_ict_array_sel_ff;
logic debug_data_clk;
logic debug_data_clken;
logic last_data_recieved_in ;
logic last_data_recieved_ff ;
logic ifu_bus_rvalid ;
logic ifu_bus_rvalid_ff ;
logic ifu_bus_rvalid_unq ;
logic ifu_bus_rvalid_unq_ff ;
logic ifu_bus_arready_unq ;
logic ifu_bus_arready_unq_ff ;
@ -355,7 +353,7 @@ import el2_pkg::*;
logic [pt.IFU_BUS_TAG-1:0] other_tag ;
logic [(2*pt.ICACHE_NUM_BEATS)-1:0] [31:0] ic_miss_buff_data;
logic [63:0] ic_miss_buff_half;
logic scnd_miss_req, scnd_miss_req_q, scnd_miss_req_ff2;
logic scnd_miss_req, scnd_miss_req_q;
logic scnd_miss_req_in;
@ -435,6 +433,7 @@ import el2_pkg::*;
logic ic_crit_wd_rdy; // Critical fetch is ready to be bypassed.
logic ifu_bp_hit_taken_q_f;
logic ifu_bus_rvalid_unq;
logic bus_cmd_beat_en;
@ -445,9 +444,14 @@ import el2_pkg::*;
assign fetch_bf_f_c1_clken = ifc_fetch_req_bf_raw | ifc_fetch_req_f | miss_pending | exu_flush_final | scnd_miss_req;
assign debug_c1_clken = ic_debug_rd_en | ic_debug_wr_en ;
// C1 - 1 clock pulse for data
`ifdef RV_FPGA_OPTIMIZE
assign fetch_bf_f_c1_clk = 1'b0;
assign debug_c1_clk = 1'b0;
`else
rvclkhdr fetch_bf_f_c1_cgc ( .en(fetch_bf_f_c1_clken), .l1clk(fetch_bf_f_c1_clk), .* );
rvclkhdr debug_c1_cgc ( .en(debug_c1_clken), .l1clk(debug_c1_clk), .* );
`endif
// ------ end clock gating section ------------------------
@ -529,7 +533,7 @@ import el2_pkg::*;
end
endcase
end
rvdffs #(($bits(miss_state_t))) miss_state_ff (.clk(free_clk), .din(miss_nxtstate), .dout({miss_state}), .en(miss_state_en), .*);
rvdffs #(($bits(miss_state_t))) miss_state_ff (.clk(active_clk), .din(miss_nxtstate), .dout({miss_state}), .en(miss_state_en), .*);
logic sel_hold_imb ;
@ -554,14 +558,14 @@ import el2_pkg::*;
assign sel_hold_imb_scnd =((miss_state == SCND_MISS) | ic_miss_under_miss_f) & ~flush_final_f ;
assign way_status_mb_scnd_in[pt.ICACHE_STATUS_BITS-1:0] = (miss_state == SCND_MISS) ? way_status_mb_scnd_ff[pt.ICACHE_STATUS_BITS-1:0] : {way_status[pt.ICACHE_STATUS_BITS-1:0]} ;
assign tagv_mb_scnd_in[pt.ICACHE_NUM_WAYS-1:0] = (miss_state == SCND_MISS) ? tagv_mb_scnd_ff[pt.ICACHE_NUM_WAYS-1:0] : ({ic_tag_valid[pt.ICACHE_NUM_WAYS-1:0]} & {pt.ICACHE_NUM_WAYS{~reset_all_tags}});
assign tagv_mb_scnd_in[pt.ICACHE_NUM_WAYS-1:0] = (miss_state == SCND_MISS) ? tagv_mb_scnd_ff[pt.ICACHE_NUM_WAYS-1:0] : ({ic_tag_valid[pt.ICACHE_NUM_WAYS-1:0]} & {pt.ICACHE_NUM_WAYS{~reset_all_tags & ~exu_flush_final}});
assign uncacheable_miss_scnd_in = sel_hold_imb_scnd ? uncacheable_miss_scnd_ff : ifc_fetch_uncacheable_bf ;
rvdff #(1) unc_miss_scnd_ff (.*, .clk(fetch_bf_f_c1_clk), .din (uncacheable_miss_scnd_in), .dout(uncacheable_miss_scnd_ff));
rvdff #(31) imb_f_scnd_ff (.*, .clk(fetch_bf_f_c1_clk), .din ({imb_scnd_in[31:1]}), .dout({imb_scnd_ff[31:1]}));
rvdff #(pt.ICACHE_STATUS_BITS) mb_rep_wayf2_scnd_ff (.*, .clk(fetch_bf_f_c1_clk), .din ({way_status_mb_scnd_in[pt.ICACHE_STATUS_BITS-1:0]}), .dout({way_status_mb_scnd_ff[pt.ICACHE_STATUS_BITS-1:0]}));
rvdff #(pt.ICACHE_NUM_WAYS) mb_tagv_scnd_ff (.*, .clk(fetch_bf_f_c1_clk), .din ({tagv_mb_scnd_in[pt.ICACHE_NUM_WAYS-1:0]}), .dout({tagv_mb_scnd_ff[pt.ICACHE_NUM_WAYS-1:0]}));
rvdff_fpga #(1) unc_miss_scnd_ff (.*, .clk(fetch_bf_f_c1_clk), .clken(fetch_bf_f_c1_clken), .rawclk(clk), .din (uncacheable_miss_scnd_in), .dout(uncacheable_miss_scnd_ff));
rvdffpcie #(31) imb_f_scnd_ff (.*, .en(fetch_bf_f_c1_clken), .din ({imb_scnd_in[31:1]}), .dout({imb_scnd_ff[31:1]}));
rvdff_fpga #(pt.ICACHE_STATUS_BITS) mb_rep_wayf2_scnd_ff (.*, .clk(fetch_bf_f_c1_clk), .clken(fetch_bf_f_c1_clken), .rawclk(clk), .din ({way_status_mb_scnd_in[pt.ICACHE_STATUS_BITS-1:0]}), .dout({way_status_mb_scnd_ff[pt.ICACHE_STATUS_BITS-1:0]}));
rvdff_fpga #(pt.ICACHE_NUM_WAYS) mb_tagv_scnd_ff (.*, .clk(fetch_bf_f_c1_clk), .clken(fetch_bf_f_c1_clken), .rawclk(clk), .din ({tagv_mb_scnd_in[pt.ICACHE_NUM_WAYS-1:0]}), .dout({tagv_mb_scnd_ff[pt.ICACHE_NUM_WAYS-1:0]}));
@ -597,45 +601,40 @@ import el2_pkg::*;
miss_pending ? way_status_mb_ff[pt.ICACHE_STATUS_BITS-1:0] :
{way_status[pt.ICACHE_STATUS_BITS-1:0]} ;
assign tagv_mb_in[pt.ICACHE_NUM_WAYS-1:0] = scnd_miss_req ? (tagv_mb_scnd_ff[pt.ICACHE_NUM_WAYS-1:0] | ({pt.ICACHE_NUM_WAYS {scnd_miss_index_match}} & replace_way_mb_any[pt.ICACHE_NUM_WAYS-1:0])) :
miss_pending ? tagv_mb_ff[pt.ICACHE_NUM_WAYS-1:0] : ({ic_tag_valid[pt.ICACHE_NUM_WAYS-1:0]} & {pt.ICACHE_NUM_WAYS{~reset_all_tags}}) ;
miss_pending ? tagv_mb_ff[pt.ICACHE_NUM_WAYS-1:0] : ({ic_tag_valid[pt.ICACHE_NUM_WAYS-1:0]} & {pt.ICACHE_NUM_WAYS{~reset_all_tags & ~exu_flush_final}}) ;
assign reset_ic_in = miss_pending & ~scnd_miss_req_q & (reset_all_tags | reset_ic_ff) ;
rvdff #(1) reset_ic_f (.*, .clk(free_clk), .din (reset_ic_in), .dout(reset_ic_ff));
rvdff #(1) uncache_ff (.*, .clk(active_clk), .din (ifc_fetch_uncacheable_bf), .dout(fetch_uncacheable_ff));
rvdff #(31) ifu_fetch_addr_f_ff (.*,
.clk (fetch_bf_f_c1_clk),
.din ({ifc_fetch_addr_bf[31:1]}),
.dout({ifu_fetch_addr_int_f[31:1]}));
rvdffpcie #(31) ifu_fetch_addr_f_ff (.*, .en(fetch_bf_f_c1_clken), .din ({ifc_fetch_addr_bf[31:1]}), .dout({ifu_fetch_addr_int_f[31:1]}));
assign vaddr_f[pt.ICACHE_BEAT_ADDR_HI:1] = ifu_fetch_addr_int_f[pt.ICACHE_BEAT_ADDR_HI:1] ;
rvdff #(1) unc_miss_ff (.*, .clk(fetch_bf_f_c1_clk), .din (uncacheable_miss_in), .dout(uncacheable_miss_ff));
rvdff #(31) imb_f_ff (.*, .clk(fetch_bf_f_c1_clk), .din ({imb_in[31:1]}), .dout({imb_ff[31:1]}));
rvdffpcie #(31) imb_f_ff (.*, .en(fetch_bf_f_c1_clken), .din (imb_in[31:1]), .dout(imb_ff[31:1]));
rvdff_fpga #(1) unc_miss_ff (.*, .clk(fetch_bf_f_c1_clk), .clken(fetch_bf_f_c1_clken), .rawclk(clk), .din ( uncacheable_miss_in), .dout( uncacheable_miss_ff));
assign miss_addr_in[31:pt.ICACHE_BEAT_ADDR_HI+1] = (~miss_pending ) ? imb_ff[31:pt.ICACHE_BEAT_ADDR_HI+1] :
( scnd_miss_req_q ) ? imb_scnd_ff[31:pt.ICACHE_BEAT_ADDR_HI+1] : miss_addr[31:pt.ICACHE_BEAT_ADDR_HI+1] ;
rvdff #(31-pt.ICACHE_BEAT_ADDR_HI) miss_f_ff (.*, .clk(busclk_reset), .din ({miss_addr_in[31:pt.ICACHE_BEAT_ADDR_HI+1]}), .dout({miss_addr[31:pt.ICACHE_BEAT_ADDR_HI+1]}));
rvdfflie #(.WIDTH(31-pt.ICACHE_BEAT_ADDR_HI),.LEFT(31-pt.ICACHE_BEAT_ADDR_HI-8)) miss_f_ff (.*, .en(bus_ifu_bus_clk_en | ic_act_miss_f | dec_tlu_force_halt), .din ({miss_addr_in[31:pt.ICACHE_BEAT_ADDR_HI+1]}), .dout({miss_addr[31:pt.ICACHE_BEAT_ADDR_HI+1]}));
rvdff #(pt.ICACHE_STATUS_BITS) mb_rep_wayf2_ff (.*, .clk(fetch_bf_f_c1_clk), .din ({way_status_mb_in[pt.ICACHE_STATUS_BITS-1:0]}), .dout({way_status_mb_ff[pt.ICACHE_STATUS_BITS-1:0]}));
rvdff #(pt.ICACHE_NUM_WAYS) mb_tagv_ff (.*, .clk(fetch_bf_f_c1_clk), .din ({tagv_mb_in[pt.ICACHE_NUM_WAYS-1:0]}), .dout({tagv_mb_ff[pt.ICACHE_NUM_WAYS-1:0]}));
rvdff_fpga #(pt.ICACHE_STATUS_BITS) mb_rep_wayf2_ff (.*, .clk(fetch_bf_f_c1_clk), .clken(fetch_bf_f_c1_clken), .rawclk(clk), .din ({way_status_mb_in[pt.ICACHE_STATUS_BITS-1:0]}), .dout({way_status_mb_ff[pt.ICACHE_STATUS_BITS-1:0]}));
rvdff_fpga #(pt.ICACHE_NUM_WAYS) mb_tagv_ff (.*, .clk(fetch_bf_f_c1_clk), .clken(fetch_bf_f_c1_clken), .rawclk(clk), .din ({tagv_mb_in[pt.ICACHE_NUM_WAYS-1:0]}), .dout({tagv_mb_ff[pt.ICACHE_NUM_WAYS-1:0]}));
assign ifc_fetch_req_qual_bf = ifc_fetch_req_bf & ~((miss_state == CRIT_WRD_RDY) & flush_final_f) & ~stream_miss_f ;// & ~exu_flush_final ;
rvdff #(1) fetch_req_f_ff (.*, .clk(active_clk), .din(ifc_fetch_req_qual_bf), .dout(ifc_fetch_req_f_raw));
assign ifc_fetch_req_f = ifc_fetch_req_f_raw & ~exu_flush_final ;
rvdff #(1) ifu_iccm_acc_ff (.*, .clk(fetch_bf_f_c1_clk), .din(ifc_iccm_access_bf), .dout(ifc_iccm_access_f));
rvdff #(1) ifu_iccm_reg_acc_ff (.*, .clk(fetch_bf_f_c1_clk), .din(ifc_region_acc_fault_final_bf), .dout(ifc_region_acc_fault_final_f));
rvdff #(1) rgn_acc_ff (.*, .clk(fetch_bf_f_c1_clk), .din(ifc_region_acc_fault_bf), .dout(ifc_region_acc_fault_f));
rvdff_fpga #(1) ifu_iccm_acc_ff (.*, .clk(fetch_bf_f_c1_clk), .clken(fetch_bf_f_c1_clken), .rawclk(clk), .din(ifc_iccm_access_bf), .dout(ifc_iccm_access_f));
rvdff_fpga #(1) ifu_iccm_reg_acc_ff (.*, .clk(fetch_bf_f_c1_clk), .clken(fetch_bf_f_c1_clken), .rawclk(clk), .din(ifc_region_acc_fault_final_bf), .dout(ifc_region_acc_fault_final_f));
rvdff_fpga #(1) rgn_acc_ff (.*, .clk(fetch_bf_f_c1_clk), .clken(fetch_bf_f_c1_clken), .rawclk(clk), .din(ifc_region_acc_fault_bf), .dout(ifc_region_acc_fault_f));
assign ifu_ic_req_addr_f[31:3] = {miss_addr[31:pt.ICACHE_BEAT_ADDR_HI+1] , ic_req_addr_bits_hi_3[pt.ICACHE_BEAT_ADDR_HI:3] };
@ -654,7 +653,6 @@ import el2_pkg::*;
assign ic_rw_addr[31:1] = ifu_ic_rw_int_addr[31:1] ;
rvdff #(1) sel_mb_ff (.*, .clk(free_clk), .din (sel_mb_addr), .dout(sel_mb_addr_ff));
if (pt.ICACHE_ECC == 1) begin: icache_ecc_1
logic [6:0] ic_wr_ecc;
@ -669,7 +667,7 @@ if (pt.ICACHE_ECC == 1) begin: icache_ecc_1
.din (ic_miss_buff_half[63:0]),
.ecc_out(ic_miss_buff_ecc[6:0]));
for (genvar i=0; i < 32'(pt.ICACHE_BANKS_WAY) ; i++) begin : ic_wr_data_loop
for (genvar i=0; i < pt.ICACHE_BANKS_WAY ; i++) begin : ic_wr_data_loop
assign ic_wr_data[i][70:0] = ic_wr_16bytes_data[((71*i)+70): (71*i)];
end
@ -682,13 +680,15 @@ if (pt.ICACHE_ECC == 1) begin: icache_ecc_1
assign ifu_ic_debug_rd_data_in[70:0] = ic_debug_ict_array_sel_ff ? {2'b0,ictag_debug_rd_data[25:21],32'b0,ictag_debug_rd_data[20:0],{7-pt.ICACHE_STATUS_BITS{1'b0}}, way_status[pt.ICACHE_STATUS_BITS-1:0],3'b0,ic_debug_tag_val_rd_out} :
ic_debug_rd_data[70:0];
rvdff #(71) ifu_debug_data_ff (.*, .clk (debug_data_clk),
rvdffe #(71) ifu_debug_data_ff (.*,
.en (debug_data_clken),
.din ({
ifu_ic_debug_rd_data_in[70:0]
}),
.dout({
ifu_ic_debug_rd_data[70:0]
}));
})
);
assign ic_wr_16bytes_data[141:0] = ifu_bus_rid_ff[0] ? {ic_wr_ecc[6:0] , ifu_bus_rdata_ff[63:0] , ic_miss_buff_ecc[6:0] , ic_miss_buff_half[63:0] } :
{ic_miss_buff_ecc[6:0] , ic_miss_buff_half[63:0] , ic_wr_ecc[6:0] , ifu_bus_rdata_ff[63:0] } ;
@ -709,7 +709,7 @@ else begin : icache_parity_1
for (genvar i=0; i < pt.ICACHE_BANKS_WAY ; i++) begin : ic_wr_data_loop
assign ic_wr_data[i][67:0] = ic_wr_16bytes_data[((68*i)+67): (68*i)];
assign ic_wr_data[i][70:0] = {3'b0, ic_wr_16bytes_data[((68*i)+67): (68*i)]};
end
@ -722,13 +722,15 @@ else begin : icache_parity_1
assign ifu_ic_debug_rd_data_in[70:0] = ic_debug_ict_array_sel_ff ? {6'b0,ictag_debug_rd_data[21],32'b0,ictag_debug_rd_data[20:0],{7-pt.ICACHE_STATUS_BITS{1'b0}},way_status[pt.ICACHE_STATUS_BITS-1:0],3'b0,ic_debug_tag_val_rd_out} :
ic_debug_rd_data[70:0] ;
rvdff #(71) ifu_debug_data_ff (.*, .clk (debug_data_clk),
rvdffe #(71) ifu_debug_data_ff (.*,
.en (debug_data_clken),
.din ({
ifu_ic_debug_rd_data_in[70:0]
}),
.dout({
ifu_ic_debug_rd_data[70:0]
}));
})
);
assign ic_wr_16bytes_data[135:0] = ifu_bus_rid_ff[0] ? {ic_wr_parity[3:0] , ifu_bus_rdata_ff[63:0] , ic_miss_buff_parity[3:0] , ic_miss_buff_half[63:0] } :
{ic_miss_buff_parity[3:0] , ic_miss_buff_half[63:0] , ic_wr_parity[3:0] , ifu_bus_rdata_ff[63:0] } ;
@ -740,11 +742,9 @@ end
assign ifu_wr_cumulative_err = (ifu_wr_data_comb_err | ifu_wr_data_comb_err_ff) & ~reset_beat_cnt;
assign ifu_wr_cumulative_err_data = ifu_wr_data_comb_err | ifu_wr_data_comb_err_ff ;
rvdff #(1) cumul_err_ff (.*, .clk(free_clk), .din (ifu_wr_cumulative_err), .dout(ifu_wr_data_comb_err_ff));
assign sel_byp_data = (ic_crit_wd_rdy | (miss_state == STREAM) | (miss_state == CRIT_BYP_OK)) & ~ifu_byp_data_err_new;
assign sel_ic_data = ~(ic_crit_wd_rdy | (miss_state == STREAM) | (miss_state == CRIT_BYP_OK)) & ~fetch_req_iccm_f ;
assign sel_byp_data = (ic_crit_wd_rdy | (miss_state == STREAM) | (miss_state == CRIT_BYP_OK));
assign sel_ic_data = ~(ic_crit_wd_rdy | (miss_state == STREAM) | (miss_state == CRIT_BYP_OK) | (miss_state == MISS_WAIT)) & ~fetch_req_iccm_f & ~ifc_region_acc_fault_final_f;
if (pt.ICCM_ICACHE==1) begin: iccm_icache
assign sel_iccm_data = fetch_req_iccm_f ;
@ -779,14 +779,14 @@ if (pt.NO_ICCM_NO_ICACHE == 1 ) begin: no_iccm_no_icache
end
assign ifc_bus_acc_fault_f = ic_byp_hit_f & ifu_byp_data_err_new ;
assign ifc_bus_acc_fault_f[1:0] = {2{ic_byp_hit_f}} & ifu_byp_data_err_f[1:0] ;
assign ic_data_f[31:0] = ic_final_data[31:0];
rvdff #(1) flush_final_ff (.*, .clk(free_clk), .din({exu_flush_final}), .dout({flush_final_f}));
assign fetch_req_f_qual = ic_hit_f & ~exu_flush_final;
assign ic_access_fault_f = (ifc_region_acc_fault_final_f | ifc_bus_acc_fault_f) & ~exu_flush_final;
assign ic_access_fault_type_f[1:0] = iccm_rd_ecc_double_err ? 2'b01 :
assign ic_access_fault_f[1:0] = ({2{ifc_region_acc_fault_final_f}} | ifc_bus_acc_fault_f[1:0]) & {2{~exu_flush_final}};
assign ic_access_fault_type_f[1:0] = |iccm_rd_ecc_double_err ? 2'b01 :
ifc_region_acc_fault_f ? 2'b10 :
ifc_region_acc_fault_memory_f ? 2'b11 : 2'b00 ;
@ -802,28 +802,33 @@ assign two_byte_instr = (ic_data_f[1:0] != 2'b11 ) ;
logic [63:0] ic_miss_buff_data_in;
assign ic_miss_buff_data_in[63:0] = ifu_bus_rsp_rdata[63:0];
for (genvar i=0; i<32'(pt.ICACHE_NUM_BEATS); i++) begin : wr_flop
assign write_fill_data[i] = bus_ifu_wr_en & ( (pt.IFU_BUS_TAG)'(i) == ifu_bus_rsp_tag[pt.IFU_BUS_TAG-1:0]);
rvclkhdr data_c1_cgc ( .en(write_fill_data[i]), .l1clk(wr_data_c1_clk[i]), .* );
rvdff #(32) byp_data_0_ff (.*,
.clk (wr_data_c1_clk[i]),
.din (ic_miss_buff_data_in[31:0]),
.dout(ic_miss_buff_data[i*2][31:0]));
for (genvar i=0; i<pt.ICACHE_NUM_BEATS; i++) begin : wr_flop
rvdff #(32) byp_data_1_ff (.*,
.clk (wr_data_c1_clk[i]),
assign write_fill_data[i] = bus_ifu_wr_en & ( (pt.IFU_BUS_TAG)'(i) == ifu_bus_rsp_tag[pt.IFU_BUS_TAG-1:0]);
rvdffe #(32) byp_data_0_ff (.*,
.en (write_fill_data[i]),
.din (ic_miss_buff_data_in[31:0]),
.dout(ic_miss_buff_data[i*2][31:0])
);
rvdffe #(32) byp_data_1_ff (.*,
.en (write_fill_data[i]),
.din (ic_miss_buff_data_in[63:32]),
.dout(ic_miss_buff_data[i*2+1][31:0]));
.dout(ic_miss_buff_data[i*2+1][31:0])
);
assign ic_miss_buff_data_valid_in[i] = write_fill_data[i] ? 1'b1 : (ic_miss_buff_data_valid[i] & ~ic_act_miss_f) ;
rvdff #(1) byp_data_valid_ff (.*,
.clk (free_clk),
.clk (active_clk),
.din (ic_miss_buff_data_valid_in[i]),
.dout(ic_miss_buff_data_valid[i]));
assign ic_miss_buff_data_error_in[i] = write_fill_data[i] ? bus_ifu_wr_data_error : (ic_miss_buff_data_error[i] & ~ic_act_miss_f) ;
rvdff #(1) byp_data_error_ff (.*,
.clk (free_clk),
.clk (active_clk),
.din (ic_miss_buff_data_error_in[i] ),
.dout(ic_miss_buff_data_error[i]));
end
@ -852,7 +857,6 @@ assign two_byte_instr = (ic_data_f[1:0] != 2'b11 ) ;
( crit_wd_byp_ok_ff & ~uncacheable_miss_ff & ~exu_flush_final & ~ifu_bp_hit_taken_q_f) |
(ic_crit_wd_rdy_new_ff & ~fetch_req_icache_f & crit_wd_byp_ok_ff & ~exu_flush_final) ;
rvdff #(1) crit_wd_new_ff (.*, .clk(free_clk), .din(ic_crit_wd_rdy_new_in), .dout(ic_crit_wd_rdy_new_ff));
assign byp_fetch_index[pt.ICACHE_BEAT_ADDR_HI:1] = ifu_fetch_addr_int_f[pt.ICACHE_BEAT_ADDR_HI:1] ;
assign byp_fetch_index_0[pt.ICACHE_BEAT_ADDR_HI:2] = {ifu_fetch_addr_int_f[pt.ICACHE_BEAT_ADDR_HI:3],1'b0} ;
@ -866,6 +870,13 @@ assign two_byte_instr = (ic_data_f[1:0] != 2'b11 ) ;
( ifu_fetch_addr_int_f[2] & ~ifu_fetch_addr_int_f[1] & ic_miss_buff_data_error[byp_fetch_index[pt.ICACHE_BEAT_ADDR_HI:3]] ) |
( ifu_fetch_addr_int_f[2] & ifu_fetch_addr_int_f[1] & (ic_miss_buff_data_error[byp_fetch_index_inc[pt.ICACHE_BEAT_ADDR_HI:3]] | ic_miss_buff_data_error[byp_fetch_index[pt.ICACHE_BEAT_ADDR_HI:3]] )) ;
assign ifu_byp_data_err_f[1:0] = (ic_miss_buff_data_error[byp_fetch_index[pt.ICACHE_BEAT_ADDR_HI:3]] ) ? 2'b11 :
( ifu_fetch_addr_int_f[2] & ifu_fetch_addr_int_f[1] & ~(ic_miss_buff_data_error[byp_fetch_index[pt.ICACHE_BEAT_ADDR_HI:3]] ) & (~miss_wrap_f & ic_miss_buff_data_error[byp_fetch_index_inc[pt.ICACHE_BEAT_ADDR_HI:3]])) ? 2'b10 : 2'b00;
assign ic_byp_data_only_pre_new[79:0] = ({80{~ifu_fetch_addr_int_f[2]}} & {ic_miss_buff_data[byp_fetch_index_inc_0][15:0],ic_miss_buff_data[byp_fetch_index_1][31:0] , ic_miss_buff_data[byp_fetch_index_0][31:0]}) |
({80{ ifu_fetch_addr_int_f[2]}} & {ic_miss_buff_data[byp_fetch_index_inc_1][15:0],ic_miss_buff_data[byp_fetch_index_inc_0][31:0] , ic_miss_buff_data[byp_fetch_index_1][31:0]}) ;
@ -901,7 +912,8 @@ assign ic_miss_buff_half[63:0] = {ic_miss_buff_data[{other_tag,1'b1}],ic_miss
/////////////////////////////////////////////////////////////////////////////////////
assign ic_rd_parity_final_err = ic_tag_perr & sel_ic_data & ~(ifc_region_acc_fault_final_f | ifc_bus_acc_fault_f) ;
assign ic_rd_parity_final_err = ic_tag_perr & ~exu_flush_final & sel_ic_data & ~(ifc_region_acc_fault_final_f | (|ifc_bus_acc_fault_f)) &
(fetch_req_icache_f & ~reset_all_tags & (~miss_pending | (miss_state==HIT_U_MISS)) & ~sel_mb_addr_ff);
logic [pt.ICACHE_NUM_WAYS-1:0] perr_err_inv_way;
logic [pt.ICACHE_INDEX_HI:pt.ICACHE_TAG_INDEX_LO] perr_ic_index_ff;
@ -910,13 +922,12 @@ logic perr_sb_write_status ;
rvdffs #(pt.ICACHE_INDEX_HI-pt.ICACHE_TAG_INDEX_LO+1) perr_dat_ff (.clk(active_clk), .din(ifu_ic_rw_int_addr_ff[pt.ICACHE_INDEX_HI:pt.ICACHE_TAG_INDEX_LO]), .dout(perr_ic_index_ff[pt.ICACHE_INDEX_HI : pt.ICACHE_TAG_INDEX_LO]), .en(perr_sb_write_status), .*);
rvdffe #(.WIDTH(pt.ICACHE_INDEX_HI-pt.ICACHE_TAG_INDEX_LO+1),.OVERRIDE(1)) perr_dat_ff (.din(ifu_ic_rw_int_addr_ff[pt.ICACHE_INDEX_HI:pt.ICACHE_TAG_INDEX_LO]), .dout(perr_ic_index_ff[pt.ICACHE_INDEX_HI : pt.ICACHE_TAG_INDEX_LO]), .en(perr_sb_write_status), .*);
assign perr_err_inv_way[pt.ICACHE_NUM_WAYS-1:0] = {pt.ICACHE_NUM_WAYS{perr_sel_invalidate}} ;
assign iccm_correct_ecc = (perr_state == ECC_CORR);
assign dma_sb_err_state = (perr_state == DMA_SB_ERR);
assign iccm_buf_correct_ecc = iccm_correct_ecc & ~dma_sb_err_state_ff;
rvdff #((1)) dma_sb_err_ff (.clk(active_clk), .din(dma_sb_err_state), .dout(dma_sb_err_state_ff), .*);
@ -965,7 +976,8 @@ logic perr_sb_write_status ;
end
endcase
end
rvdffs #(($bits(perr_state_t))) perr_state_ff (.clk(free_clk), .din(perr_nxtstate), .dout({perr_state}), .en(perr_state_en), .*);
rvdffs #(($bits(perr_state_t))) perr_state_ff (.clk(active_clk), .din(perr_nxtstate), .dout({perr_state}), .en(perr_state_en), .*);
//////////////////////////////////// Create stop fetch State Machine /////////////////////////
//////////////////////////////////// Create stop fetch State Machine /////////////////////////
@ -1013,29 +1025,30 @@ logic perr_sb_write_status ;
end
endcase
end
rvdffs #(($bits(err_stop_state_t))) err_stop_state_ff (.clk(free_clk), .din(err_stop_nxtstate), .dout({err_stop_state}), .en(err_stop_state_en), .*);
rvdffs #(($bits(err_stop_state_t))) err_stop_state_ff (.clk(active_clk), .din(err_stop_nxtstate), .dout({err_stop_state}), .en(err_stop_state_en), .*);
assign bus_ifu_bus_clk_en = ifu_bus_clk_en ;
rvclkhdr bus_clk_f(.en(bus_ifu_bus_clk_en),
.l1clk(busclk), .*);
`ifdef RV_FPGA_OPTIMIZE
assign busclk = 1'b0;
assign busclk_force = 1'b0;
`else
rvclkhdr bus_clk_f(.en(bus_ifu_bus_clk_en), .l1clk(busclk), .*);
rvclkhdr bus_clk(.en(bus_ifu_bus_clk_en | dec_tlu_force_halt), .l1clk(busclk_force), .*);
`endif
rvclkhdr bus_clk(.en(bus_ifu_bus_clk_en | dec_tlu_force_halt),
.l1clk(busclk_force), .*);
rvdff #(1) bus_clken_ff (.*, .clk(free_clk), .din(bus_ifu_bus_clk_en), .dout(bus_ifu_bus_clk_en_ff));
rvdff #(1) scnd_mss_req_ff (.*, .clk(free_clk), .din(scnd_miss_req_in), .dout(scnd_miss_req_q));
rvdff #(1) scnd_mss_req_ff2 (.*, .clk(free_clk), .din(scnd_miss_req), .dout(scnd_miss_req_ff2));
assign scnd_miss_req = scnd_miss_req_q & ~exu_flush_final;
assign ifc_bus_ic_req_ff_in = (ic_act_miss_f | bus_cmd_req_hold | ifu_bus_cmd_valid) & ~dec_tlu_force_halt & ~((bus_cmd_beat_count== {pt.ICACHE_BEAT_BITS{1'b1}}) & ifu_bus_cmd_valid & ifu_bus_cmd_ready & miss_pending);
rvdff #(1) bus_ic_req_ff2(.*, .clk(busclk_force), .din(ifc_bus_ic_req_ff_in), .dout(ifu_bus_cmd_valid));
rvdff_fpga #(1) bus_ic_req_ff2(.*, .clk(busclk_force), .clken(bus_ifu_bus_clk_en | dec_tlu_force_halt), .rawclk(clk), .din(ifc_bus_ic_req_ff_in), .dout(ifu_bus_cmd_valid));
assign bus_cmd_req_in = (ic_act_miss_f | bus_cmd_req_hold) & ~bus_cmd_sent & ~dec_tlu_force_halt ; // hold until first command sent
// changes for making the bus blocking
rvdff #(1) bus_cmd_req_ff (.*, .clk(free_clk), .din(bus_cmd_req_in), .dout(bus_cmd_req_hold));
// AXI command signals
@ -1044,7 +1057,7 @@ logic perr_sb_write_status ;
assign ifu_axi_arid[pt.IFU_BUS_TAG-1:0] = ((pt.IFU_BUS_TAG)'(bus_rd_addr_count[pt.ICACHE_BEAT_BITS-1:0])) & {pt.IFU_BUS_TAG{ifu_bus_cmd_valid}};
assign ifu_axi_araddr[31:0] = {ifu_ic_req_addr_f[31:3],3'b0} & {32{ifu_bus_cmd_valid}};
assign ifu_axi_arsize[2:0] = 3'b011;
assign ifu_axi_arprot[2:0] = '0;
assign ifu_axi_arprot[2:0] = 3'b101;
assign ifu_axi_arcache[3:0] = 4'b1111;
assign ifu_axi_arregion[3:0] = ifu_ic_req_addr_f[31:28];
assign ifu_axi_arlen[7:0] = '0;
@ -1077,12 +1090,12 @@ logic perr_sb_write_status ;
assign ifu_bus_rvalid_unq = ifu_axi_rvalid ;
assign ifu_bus_arvalid = ifu_axi_arvalid ;
rvdff #(1) bus_rdy_ff (.*, .clk(busclk), .din(ifu_bus_arready_unq), .dout(ifu_bus_arready_unq_ff));
rvdff #(1) bus_rsp_vld_ff (.*, .clk(busclk), .din(ifu_bus_rvalid_unq), .dout(ifu_bus_rvalid_unq_ff));
rvdff #(1) bus_cmd_ff (.*, .clk(busclk), .din(ifu_bus_arvalid), .dout(ifu_bus_arvalid_ff));
rvdff #(2) bus_rsp_cmd_ff (.*, .clk(busclk), .din(ifu_axi_rresp[1:0]), .dout(ifu_bus_rresp_ff[1:0]));
rvdff #(64) bus_data_ff (.*, .clk(busclk), .din(ifu_axi_rdata[63:0]), .dout(ifu_bus_rdata_ff[63:0]));
rvdff #(pt.IFU_BUS_TAG) bus_rsp_tag_ff (.*, .clk(busclk), .din(ifu_axi_rid[pt.IFU_BUS_TAG-1:0]),.dout(ifu_bus_rid_ff[pt.IFU_BUS_TAG-1:0]));
rvdff_fpga #(1) bus_rdy_ff (.*, .clk(busclk), .clken(bus_ifu_bus_clk_en), .rawclk(clk), .din(ifu_bus_arready_unq), .dout(ifu_bus_arready_unq_ff));
rvdff_fpga #(1) bus_rsp_vld_ff (.*, .clk(busclk), .clken(bus_ifu_bus_clk_en), .rawclk(clk), .din(ifu_bus_rvalid_unq), .dout(ifu_bus_rvalid_unq_ff));
rvdff_fpga #(1) bus_cmd_ff (.*, .clk(busclk), .clken(bus_ifu_bus_clk_en), .rawclk(clk), .din(ifu_bus_arvalid), .dout(ifu_bus_arvalid_ff));
rvdff_fpga #(2) bus_rsp_cmd_ff (.*, .clk(busclk), .clken(bus_ifu_bus_clk_en), .rawclk(clk), .din(ifu_axi_rresp[1:0]), .dout(ifu_bus_rresp_ff[1:0]));
rvdff_fpga #(pt.IFU_BUS_TAG) bus_rsp_tag_ff (.*, .clk(busclk), .clken(bus_ifu_bus_clk_en), .rawclk(clk), .din(ifu_axi_rid[pt.IFU_BUS_TAG-1:0]),.dout(ifu_bus_rid_ff[pt.IFU_BUS_TAG-1:0]));
rvdffe #(64) bus_data_ff (.*, .clk(clk), .din(ifu_axi_rdata[63:0]), .dout(ifu_bus_rdata_ff[63:0]), .en(ifu_bus_clk_en & ifu_axi_rvalid));
assign ifu_bus_cmd_ready = ifu_axi_arready ;
assign ifu_bus_rsp_valid = ifu_axi_rvalid ;
@ -1099,11 +1112,7 @@ logic perr_sb_write_status ;
// Create write signals so we can write to the miss-buffer directly from
// the bus.
// Create write signals so we can write to the miss-buffer directly from the bus.
assign ifu_bus_rvalid = ifu_bus_rsp_valid & bus_ifu_bus_clk_en ;
@ -1122,10 +1131,9 @@ logic perr_sb_write_status ;
({pt.ICACHE_BEAT_BITS{bus_inc_data_beat_cnt}} & (bus_data_beat_count[pt.ICACHE_BEAT_BITS-1:0] + {{pt.ICACHE_BEAT_BITS-1{1'b0}},1'b1})) |
({pt.ICACHE_BEAT_BITS{bus_hold_data_beat_cnt}} & bus_data_beat_count[pt.ICACHE_BEAT_BITS-1:0]);
rvdff #(pt.ICACHE_BEAT_BITS) bus_mb_beat_count_ff (.*, .clk(free_clk), .din ({bus_new_data_beat_count[pt.ICACHE_BEAT_BITS-1:0]}), .dout({bus_data_beat_count[pt.ICACHE_BEAT_BITS-1:0]}));
assign last_data_recieved_in = (bus_ifu_wr_en_ff & bus_last_data_beat & ~scnd_miss_req) | (last_data_recieved_ff & ~ic_act_miss_f) ;
rvdff #(1) last_beat_ff (.*, .clk(free_clk), .din (last_data_recieved_in), .dout(last_data_recieved_ff));
// Request Address Count
@ -1134,7 +1142,7 @@ logic perr_sb_write_status ;
( bus_cmd_sent ) ? (bus_rd_addr_count[pt.ICACHE_BEAT_BITS-1:0] + 3'b001) :
bus_rd_addr_count[pt.ICACHE_BEAT_BITS-1:0];
rvdff #(pt.ICACHE_BEAT_BITS) bus_rd_addr_ff (.*, .clk(busclk_reset), .din ({bus_new_rd_addr_count[pt.ICACHE_BEAT_BITS-1:0]}), .dout({bus_rd_addr_count[pt.ICACHE_BEAT_BITS-1:0]}));
rvdff_fpga #(pt.ICACHE_BEAT_BITS) bus_rd_addr_ff (.*, .clk(busclk_reset), .clken (bus_ifu_bus_clk_en | ic_act_miss_f | dec_tlu_force_halt), .rawclk(clk), .din ({bus_new_rd_addr_count[pt.ICACHE_BEAT_BITS-1:0]}), .dout({bus_rd_addr_count[pt.ICACHE_BEAT_BITS-1:0]}));
@ -1150,11 +1158,15 @@ logic perr_sb_write_status ;
({pt.ICACHE_BEAT_BITS{bus_inc_cmd_beat_cnt}} & (bus_cmd_beat_count[pt.ICACHE_BEAT_BITS-1:0] + {{pt.ICACHE_BEAT_BITS-1{1'b0}}, 1'b1})) |
({pt.ICACHE_BEAT_BITS{bus_hold_cmd_beat_cnt}} & bus_cmd_beat_count[pt.ICACHE_BEAT_BITS-1:0]) ;
rvclkhdr bus_clk_reset(.en(bus_ifu_bus_clk_en | ic_act_miss_f | dec_tlu_force_halt),
.l1clk(busclk_reset), .*);
`ifdef RV_FPGA_OPTIMIZE
assign busclk_reset = 1'b0;
`else
rvclkhdr bus_clk_reset(.en(bus_ifu_bus_clk_en | ic_act_miss_f | dec_tlu_force_halt), .l1clk(busclk_reset), .*);
`endif
rvdffs #(pt.ICACHE_BEAT_BITS) bus_cmd_beat_ff (.*, .clk(busclk_reset), .en (bus_cmd_beat_en), .din ({bus_new_cmd_beat_count[pt.ICACHE_BEAT_BITS-1:0]}),
rvdffs_fpga #(pt.ICACHE_BEAT_BITS) bus_cmd_beat_ff (.*, .clk(busclk_reset), .clken (bus_ifu_bus_clk_en | ic_act_miss_f | dec_tlu_force_halt), .rawclk(clk), .en (bus_cmd_beat_en), .din ({bus_new_cmd_beat_count[pt.ICACHE_BEAT_BITS-1:0]}),
.dout({bus_cmd_beat_count[pt.ICACHE_BEAT_BITS-1:0]}));
@ -1166,12 +1178,26 @@ logic perr_sb_write_status ;
assign bus_ifu_wr_en_ff_wo_err = ifu_bus_rvalid_ff & miss_pending & ~uncacheable_miss_ff;
rvdff #(1) act_miss_ff (.*, .clk(free_clk), .din (ic_act_miss_f), .dout(ic_act_miss_f_delayed));
rvdffie #(10) misc_ff
( .*,
.clk(free_l2clk),
.din( {ic_act_miss_f, ifu_wr_cumulative_err,exu_flush_final, ic_crit_wd_rdy_new_in,bus_ifu_bus_clk_en, scnd_miss_req_in,bus_cmd_req_in, last_data_recieved_in,
ifc_dma_access_ok_d, dma_iccm_req}),
.dout({ic_act_miss_f_delayed,ifu_wr_data_comb_err_ff, flush_final_f,ic_crit_wd_rdy_new_ff,bus_ifu_bus_clk_en_ff,scnd_miss_req_q, bus_cmd_req_hold,last_data_recieved_ff,
ifc_dma_access_ok_prev,dma_iccm_req_f})
);
rvdffie #(.WIDTH(pt.ICACHE_BEAT_BITS+5),.OVERRIDE(1)) misc1_ff
( .*,
.clk(free_l2clk),
.din( {reset_ic_in,sel_mb_addr, bus_new_data_beat_count[pt.ICACHE_BEAT_BITS-1:0],ifc_region_acc_fault_memory_bf,ic_debug_rd_en, ic_debug_rd_en_ff}),
.dout({reset_ic_ff,sel_mb_addr_ff,bus_data_beat_count[pt.ICACHE_BEAT_BITS-1:0], ifc_region_acc_fault_memory_f, ic_debug_rd_en_ff,ifu_ic_debug_rd_data_valid})
);
assign reset_tag_valid_for_miss = ic_act_miss_f_delayed & (miss_state == CRIT_BYP_OK) & ~uncacheable_miss_ff;
assign bus_ifu_wr_data_error = |ifu_bus_rsp_opc[1:0] & ifu_bus_rvalid & miss_pending;
assign bus_ifu_wr_data_error_ff = |ifu_bus_rresp_ff[1:0] & ifu_bus_rvalid_ff & miss_pending;
rvdff #(1) dma_ok_prev_ff (.*, .clk(free_clk), .din(ifc_dma_access_ok_d), .dout(ifc_dma_access_ok_prev));
assign ic_crit_wd_rdy = ic_crit_wd_rdy_new_in | ic_crit_wd_rdy_new_ff ;
assign last_beat = bus_last_data_beat & bus_ifu_wr_en_ff;
@ -1182,7 +1208,6 @@ logic perr_sb_write_status ;
assign ifc_dma_access_ok_d = ifc_dma_access_ok & ~iccm_correct_ecc & ~iccm_dma_sb_error;
assign ifc_dma_access_q_ok = ifc_dma_access_ok & ~iccm_correct_ecc & ifc_dma_access_ok_prev & (perr_state == ERR_IDLE) & ~iccm_dma_sb_error;
assign iccm_ready = ifc_dma_access_q_ok ;
rvdff #(1) dma_req_ff (.*, .clk(free_clk), .din (dma_iccm_req), .dout(dma_iccm_req_f));
logic [1:0] iccm_ecc_word_enable;
@ -1233,13 +1258,19 @@ logic perr_sb_write_status ;
assign iccm_dma_rdata_in[63:0] = iccm_dma_ecc_error_in ? {2{dma_mem_addr[31:0]}} : {iccm_dma_rdata_1_muxed[31:0], iccm_corrected_data[0]};
assign iccm_dma_ecc_error_in = |(iccm_double_ecc_error[1:0]);
rvdff #(3) dma_tag_ff1 (.*, .clk(free_clk), .din(dma_mem_tag[2:0]), .dout(dma_mem_tag_ff[2:0]));
rvdff #(3) dma_tag_ff2 (.*, .clk(free_clk), .din(dma_mem_tag_ff[2:0]), .dout(iccm_dma_rtag[2:0]));
rvdff #(2) dma_addr_bt3_ff (.*, .clk(free_clk), .din(dma_mem_addr[3:2]), .dout(dma_mem_addr_ff[3:2]));
rvdff #(1) ccm_rdy_in_ff (.*, .clk(free_clk), .din(iccm_dma_rden), .dout(iccm_dma_rvalid_in));
rvdff #(1) ccm_rdy_ff (.*, .clk(free_clk), .din(iccm_dma_rvalid_in), .dout(iccm_dma_rvalid));
rvdff #(1) ccm_err_ff (.*, .clk(free_clk), .din(iccm_dma_ecc_error_in), .dout(iccm_dma_ecc_error));
rvdff #(64)dma_data_ff (.*, .clk(free_clk), .din(iccm_dma_rdata_in[63:0]), .dout(iccm_dma_rdata[63:0]));
rvdffe #(64) dma_data_ff (.*, .clk(clk), .en(iccm_dma_rvalid_in), .din(iccm_dma_rdata_in[63:0]), .dout(iccm_dma_rdata[63:0]));
rvdffie #(11) dma_misc_bits (.*, .clk(free_l2clk), .din({dma_mem_tag[2:0],
dma_mem_tag_ff[2:0],
dma_mem_addr[3:2],
iccm_dma_rden,
iccm_dma_rvalid_in,
iccm_dma_ecc_error_in }),
.dout({dma_mem_tag_ff[2:0],
iccm_dma_rtag[2:0],
dma_mem_addr_ff[3:2],
iccm_dma_rvalid_in,
iccm_dma_rvalid,
iccm_dma_ecc_error }));
assign iccm_rw_addr[pt.ICCM_BITS-1:1] = ( ifc_dma_access_q_ok & dma_iccm_req & ~iccm_correct_ecc) ? dma_mem_addr[pt.ICCM_BITS-1:1] :
(~(ifc_dma_access_q_ok & dma_iccm_req) & iccm_correct_ecc) ? {iccm_ecc_corr_index_ff[pt.ICCM_BITS-1:2],1'b0} : ifc_fetch_addr_bf[pt.ICCM_BITS-1:1] ;
@ -1271,21 +1302,30 @@ logic perr_sb_write_status ;
end
assign iccm_rd_ecc_single_err = (|iccm_single_ecc_error[1:0] ) & ifc_iccm_access_f & ifc_fetch_req_f;
assign iccm_rd_ecc_double_err = (|iccm_double_ecc_error[1:0] ) & ifc_iccm_access_f;
assign iccm_rd_ecc_double_err[1:0] = ~ifu_fetch_addr_int_f[1] ? ({iccm_double_ecc_error[0], iccm_double_ecc_error[0]} ) & {2{ifc_iccm_access_f}} :
({iccm_double_ecc_error[1], iccm_double_ecc_error[0]} ) & {2{ifc_iccm_access_f}} ;
assign iccm_corrected_data_f_mux[31:0] = iccm_single_ecc_error[0] ? iccm_corrected_data[0] : iccm_corrected_data[1];
assign iccm_corrected_ecc_f_mux[6:0] = iccm_single_ecc_error[0] ? iccm_corrected_ecc[0] : iccm_corrected_ecc[1];
assign iccm_ecc_write_status = ((iccm_rd_ecc_single_err & ~iccm_rd_ecc_single_err_ff) & ~exu_flush_final) | iccm_dma_sb_error;
assign iccm_rd_ecc_single_err_hold_in = (iccm_rd_ecc_single_err | iccm_rd_ecc_single_err_ff) & ~exu_flush_final ; // & ~(perr_state == ERR_IDLE);
assign iccm_rd_ecc_single_err_hold_in = (iccm_rd_ecc_single_err | iccm_rd_ecc_single_err_ff) & ~exu_flush_final ;
assign iccm_error_start = iccm_rd_ecc_single_err;
assign iccm_ecc_corr_index_in[pt.ICCM_BITS-1:2] = iccm_single_ecc_error[0] ? iccm_rw_addr_f[pt.ICCM_BITS-1:2] : iccm_rw_addr_f[pt.ICCM_BITS-1:2] + 1'b1 ;
rvdff #(pt.ICCM_BITS-2) iccm_index_f (.*, .clk(free_clk), .din(iccm_rw_addr[pt.ICCM_BITS-1:2]), .dout(iccm_rw_addr_f[pt.ICCM_BITS-1:2]));
rvdff #((1)) ecc_rr_ff (.clk(free_clk), .din(iccm_rd_ecc_single_err_hold_in), .dout(iccm_rd_ecc_single_err_ff), .*);
rvdffs #((32)) ecc_dat0_ff (.clk(free_clk), .din(iccm_corrected_data_f_mux[31:0]), .dout(iccm_ecc_corr_data_ff[31:0]), .en(iccm_ecc_write_status), .*);
rvdffs #((7)) ecc_dat1_ff (.clk(free_clk), .din(iccm_corrected_ecc_f_mux[6:0]), .dout(iccm_ecc_corr_data_ff[38:32]), .en(iccm_ecc_write_status), .*);
rvdffs #((pt.ICCM_BITS-2))ecc_ind0_ff (.clk(free_clk), .din(iccm_ecc_corr_index_in[pt.ICCM_BITS-1:2]), .dout(iccm_ecc_corr_index_ff[pt.ICCM_BITS-1:2]),.en(iccm_ecc_write_status), .*);
rvdffie #(pt.ICCM_BITS-1) iccm_index_f (.*, .clk(free_l2clk), .din({iccm_rw_addr[pt.ICCM_BITS-1:2],
iccm_rd_ecc_single_err_hold_in
}),
.dout({iccm_rw_addr_f[pt.ICCM_BITS-1:2],
iccm_rd_ecc_single_err_ff}));
rvdffe #((39+(pt.ICCM_BITS-2))) ecc_dat0_ff (
.clk(clk),
.din({iccm_corrected_ecc_f_mux[6:0], iccm_corrected_data_f_mux[31:0],iccm_ecc_corr_index_in[pt.ICCM_BITS-1:2]}),
.dout({iccm_ecc_corr_data_ff[38:0] ,iccm_ecc_corr_index_ff[pt.ICCM_BITS-1:2]}),
.en(iccm_ecc_write_status),
.*
);
end else begin : iccm_disabled
assign iccm_dma_rvalid = 1'b0 ;
@ -1300,7 +1340,7 @@ end
assign iccm_rd_ecc_single_err = 1'b0 ;
assign iccm_rd_ecc_double_err = 1'b0 ;
assign iccm_rd_ecc_double_err = '0 ;
assign iccm_rd_ecc_single_err_ff = 1'b0 ;
assign iccm_error_start = 1'b0;
assign iccm_ecc_corr_index_ff[pt.ICCM_BITS-1:2] = '0;
@ -1318,7 +1358,6 @@ end
////// ICCM signals
// Use the equation below for more power savings.
assign ic_rd_en = (ifc_fetch_req_bf & ~ifc_fetch_uncacheable_bf & ~ifc_iccm_access_bf &
~(((miss_state == STREAM) & ~miss_state_en) |
((miss_state == CRIT_BYP_OK) & ~miss_state_en) |
@ -1328,7 +1367,6 @@ end
((miss_state == CRIT_BYP_OK) & miss_state_en & (miss_nxtstate == MISS_WAIT)) )) |
( ifc_fetch_req_bf & exu_flush_final & ~ifc_fetch_uncacheable_bf & ~ifc_iccm_access_bf ) ;
logic ic_real_rd_wp_unused;
assign ic_real_rd_wp_unused = (ifc_fetch_req_bf & ~ifc_iccm_access_bf & ~ifc_region_acc_fault_final_bf & ~dec_tlu_fence_i_wb & ~stream_miss_f & ~ic_act_miss_f &
~(((miss_state == STREAM) & ~miss_state_en) |
@ -1345,7 +1383,6 @@ assign ic_real_rd_wp_unused = (ifc_fetch_req_bf & ~ifc_iccm_access_bf & ~i
assign ic_wr_en[pt.ICACHE_NUM_WAYS-1:0] = bus_ic_wr_en[pt.ICACHE_NUM_WAYS-1:0] & {pt.ICACHE_NUM_WAYS{write_ic_16_bytes}};
assign ic_write_stall = write_ic_16_bytes & ~((((miss_state== CRIT_BYP_OK) | ((miss_state==STREAM) & ~(exu_flush_final | ifu_bp_hit_taken_q_f | stream_eol_f ))) & ~(bus_ifu_wr_en_ff & last_beat & ~uncacheable_miss_ff)));
rvdff #(1) reset_all_tag_ff (.*, .clk(active_clk), .din(dec_tlu_fence_i_wb), .dout(reset_all_tags));
@ -1361,26 +1398,36 @@ if (pt.ICACHE_ENABLE == 1 ) begin: icache_enabled
ifu_status_wr_addr[pt.ICACHE_INDEX_HI:pt.ICACHE_TAG_INDEX_LO];
// status
rvdff #(pt.ICACHE_TAG_LO-pt.ICACHE_TAG_INDEX_LO) status_wr_addr_ff (.*, .clk(free_clk), .din(ifu_status_wr_addr_w_debug[pt.ICACHE_INDEX_HI:pt.ICACHE_TAG_INDEX_LO]),
.dout(ifu_status_wr_addr_ff[pt.ICACHE_INDEX_HI:pt.ICACHE_TAG_INDEX_LO]));
assign way_status_wr_en_w_debug = way_status_wr_en | (ic_debug_wr_en & ic_debug_tag_array);
rvdff #(1) status_wren_ff (.*, .clk(free_clk), .din(way_status_wr_en_w_debug), .dout(way_status_wr_en_ff));
assign way_status_new_w_debug[pt.ICACHE_STATUS_BITS-1:0] = (ic_debug_wr_en & ic_debug_tag_array) ? (pt.ICACHE_STATUS_BITS == 1) ? ic_debug_wr_data[4] : ic_debug_wr_data[6:4] :
way_status_new[pt.ICACHE_STATUS_BITS-1:0] ;
rvdff #(pt.ICACHE_STATUS_BITS) status_data_ff (.*, .clk(free_clk), .din(way_status_new_w_debug[pt.ICACHE_STATUS_BITS-1:0]), .dout(way_status_new_ff[pt.ICACHE_STATUS_BITS-1:0]));
rvdffie #(.WIDTH(pt.ICACHE_TAG_LO-pt.ICACHE_TAG_INDEX_LO+1+pt.ICACHE_STATUS_BITS),.OVERRIDE(1)) status_misc_ff
(.*,
.clk(free_l2clk),
.din({ ifu_status_wr_addr_w_debug[pt.ICACHE_INDEX_HI:pt.ICACHE_TAG_INDEX_LO], way_status_wr_en_w_debug, way_status_new_w_debug[pt.ICACHE_STATUS_BITS-1:0]}),
.dout({ifu_status_wr_addr_ff[pt.ICACHE_INDEX_HI:pt.ICACHE_TAG_INDEX_LO], way_status_wr_en_ff, way_status_new_ff[pt.ICACHE_STATUS_BITS-1:0]} )
);
logic [(pt.ICACHE_TAG_DEPTH/8)-1 : 0] way_status_clken;
logic [(pt.ICACHE_TAG_DEPTH/8)-1 : 0] way_status_clk;
for (genvar i=0 ; i<32'(pt.ICACHE_TAG_DEPTH)/8 ; i++) begin : CLK_GRP_WAY_STATUS
for (genvar i=0 ; i<pt.ICACHE_TAG_DEPTH/8 ; i++) begin : CLK_GRP_WAY_STATUS
assign way_status_clken[i] = (ifu_status_wr_addr_ff[pt.ICACHE_INDEX_HI:pt.ICACHE_TAG_INDEX_LO+3] == i );
`ifdef RV_FPGA_OPTIMIZE
assign way_status_clk[i] = 1'b0;
`else
rvclkhdr way_status_cgc ( .en(way_status_clken[i]), .l1clk(way_status_clk[i]), .* );
`endif
for (genvar j=0 ; j<8 ; j++) begin : WAY_STATUS
rvdffs #(pt.ICACHE_STATUS_BITS) ic_way_status (.*,
rvdffs_fpga #(pt.ICACHE_STATUS_BITS) ic_way_status (.*,
.clk(way_status_clk[i]),
.clken(way_status_clken[i]),
.rawclk(clk),
.en(((ifu_status_wr_addr_ff[pt.ICACHE_TAG_INDEX_LO+2:pt.ICACHE_TAG_INDEX_LO] == j) & way_status_wr_en_ff)),
.din(way_status_new_ff[pt.ICACHE_STATUS_BITS-1:0]),
.dout(way_status_out[8*i+j]));
@ -1389,7 +1436,7 @@ if (pt.ICACHE_ENABLE == 1 ) begin: icache_enabled
always_comb begin : way_status_out_mux
way_status[pt.ICACHE_STATUS_BITS-1:0] = '0 ;
for (int j=0; j< 32'(pt.ICACHE_TAG_DEPTH); j++) begin : status_mux_loop
for (int j=0; j< pt.ICACHE_TAG_DEPTH; j++) begin : status_mux_loop
if (ifu_ic_rw_int_addr_ff[pt.ICACHE_INDEX_HI:pt.ICACHE_TAG_INDEX_LO] == (pt.ICACHE_TAG_LO-pt.ICACHE_TAG_INDEX_LO)'(j)) begin : mux_out
way_status[pt.ICACHE_STATUS_BITS-1:0] = way_status_out[j];
end
@ -1399,28 +1446,28 @@ if (pt.ICACHE_ENABLE == 1 ) begin: icache_enabled
assign ifu_ic_rw_int_addr_w_debug[pt.ICACHE_INDEX_HI:pt.ICACHE_TAG_INDEX_LO] = ((ic_debug_rd_en | ic_debug_wr_en ) & ic_debug_tag_array) ?
ic_debug_addr[pt.ICACHE_INDEX_HI:pt.ICACHE_TAG_INDEX_LO] :
ifu_ic_rw_int_addr[pt.ICACHE_INDEX_HI:pt.ICACHE_TAG_INDEX_LO];
rvdff #(pt.ICACHE_TAG_LO-pt.ICACHE_TAG_INDEX_LO) tag_addr_ff (.*, .clk(free_clk),
.din(ifu_ic_rw_int_addr_w_debug[pt.ICACHE_INDEX_HI:pt.ICACHE_TAG_INDEX_LO]),
.dout(ifu_ic_rw_int_addr_ff[pt.ICACHE_INDEX_HI:pt.ICACHE_TAG_INDEX_LO]));
assign ifu_tag_wren_w_debug[pt.ICACHE_NUM_WAYS-1:0] = ifu_tag_wren[pt.ICACHE_NUM_WAYS-1:0] | ic_debug_tag_wr_en[pt.ICACHE_NUM_WAYS-1:0] ;
rvdff #(pt.ICACHE_NUM_WAYS) tag_v_we_ff (.*, .clk(free_clk),
.din(ifu_tag_wren_w_debug[pt.ICACHE_NUM_WAYS-1:0]),
.dout(ifu_tag_wren_ff[pt.ICACHE_NUM_WAYS-1:0]));
assign ic_valid_w_debug = (ic_debug_wr_en & ic_debug_tag_array) ? ic_debug_wr_data[0] : ic_valid;
rvdff #(1) tag_v_ff (.*, .clk(free_clk),
.din(ic_valid_w_debug),
.dout(ic_valid_ff));
rvdffie #(pt.ICACHE_TAG_LO-pt.ICACHE_TAG_INDEX_LO+pt.ICACHE_NUM_WAYS+1) tag_addr_ff (.*,
.clk(free_l2clk),
.din({ifu_ic_rw_int_addr_w_debug[pt.ICACHE_INDEX_HI:pt.ICACHE_TAG_INDEX_LO],
ifu_tag_wren_w_debug[pt.ICACHE_NUM_WAYS-1:0],
ic_valid_w_debug}),
.dout({ifu_ic_rw_int_addr_ff[pt.ICACHE_INDEX_HI:pt.ICACHE_TAG_INDEX_LO],
ifu_tag_wren_ff[pt.ICACHE_NUM_WAYS-1:0],
ic_valid_ff})
);
logic [pt.ICACHE_NUM_WAYS-1:0] [pt.ICACHE_TAG_DEPTH-1:0] ic_tag_valid_out ;
logic [(pt.ICACHE_TAG_DEPTH/32)-1:0] [pt.ICACHE_NUM_WAYS-1:0] tag_valid_clken ;
logic [(pt.ICACHE_TAG_DEPTH/32)-1:0] [pt.ICACHE_NUM_WAYS-1:0] tag_valid_clk ;
for (genvar i=0 ; i<32'(pt.ICACHE_TAG_DEPTH)/32 ; i++) begin : CLK_GRP_TAG_VALID
for (genvar j=0; j<32'(pt.ICACHE_NUM_WAYS); j++) begin : way_clken
for (genvar i=0 ; i<pt.ICACHE_TAG_DEPTH/32 ; i++) begin : CLK_GRP_TAG_VALID
for (genvar j=0; j<pt.ICACHE_NUM_WAYS; j++) begin : way_clken
if (pt.ICACHE_TAG_DEPTH == 32 ) begin
assign tag_valid_clken[i][j] = ifu_tag_wren_ff[j] | perr_err_inv_way[j] | reset_all_tags;
end else begin
@ -1428,11 +1475,19 @@ assign ifu_ic_rw_int_addr_w_debug[pt.ICACHE_INDEX_HI:pt.ICACHE_TAG_INDEX_LO] = (
((perr_ic_index_ff [pt.ICACHE_INDEX_HI:pt.ICACHE_TAG_INDEX_LO+5] == i ) & perr_err_inv_way[j]) | reset_all_tags);
end
`ifdef RV_FPGA_OPTIMIZE
assign tag_valid_clk[i][j] = 1'b0;
`else
rvclkhdr way_status_cgc ( .en(tag_valid_clken[i][j]), .l1clk(tag_valid_clk[i][j]), .* );
`endif
for (genvar k=0 ; k<32 ; k++) begin : TAG_VALID
rvdffs #(1) ic_way_tagvalid_dup (.*,
rvdffs_fpga #(1) ic_way_tagvalid_dup (.*,
.clk(tag_valid_clk[i][j]),
.clken(tag_valid_clken[i][j]),
.rawclk(clk),
.en(((ifu_ic_rw_int_addr_ff[pt.ICACHE_INDEX_HI:pt.ICACHE_TAG_INDEX_LO] == (k + 32*i)) & ifu_tag_wren_ff[j] ) |
((perr_ic_index_ff [pt.ICACHE_INDEX_HI:pt.ICACHE_TAG_INDEX_LO] == (k + 32*i)) & perr_err_inv_way[j]) | reset_all_tags),
.din(ic_valid_ff & ~reset_all_tags & ~perr_sel_invalidate),
@ -1482,10 +1537,10 @@ assign ifu_ic_rw_int_addr_w_debug[pt.ICACHE_INDEX_HI:pt.ICACHE_TAG_INDEX_LO] = (
assign replace_way_mb_any[0] = (~way_status_mb_ff[1] & ~way_status_mb_ff[0] & (&tagv_mb_ff[3:0])) |
(~tagv_mb_ff[0] ) ;
assign way_status_hit_new[pt.ICACHE_STATUS_BITS-1:0] = ({3{ic_rd_hit[0]}} & {way_status[2] , 1'b1 , 1'b1}) |
({3{ic_rd_hit[1]}} & {way_status[2] , 1'b0 , 1'b1}) |
({3{ic_rd_hit[2]}} & {1'b1 ,way_status[1] , 1'b0}) |
({3{ic_rd_hit[3]}} & {1'b0 ,way_status[1] , 1'b0}) ;
assign way_status_hit_new[pt.ICACHE_STATUS_BITS-1:0] = ({3{~exu_flush_final & ic_rd_hit[0]}} & {way_status[2] , 1'b1 , 1'b1}) |
({3{~exu_flush_final & ic_rd_hit[1]}} & {way_status[2] , 1'b0 , 1'b1}) |
({3{~exu_flush_final & ic_rd_hit[2]}} & {1'b1 ,way_status[1] , 1'b0}) |
({3{~exu_flush_final & ic_rd_hit[3]}} & {1'b0 ,way_status[1] , 1'b0}) ;
assign way_status_rep_new[pt.ICACHE_STATUS_BITS-1:0] = ({3{replace_way_mb_any[0]}} & {way_status_mb_ff[2] , 1'b1 , 1'b1}) |
({3{replace_way_mb_any[1]}} & {way_status_mb_ff[2] , 1'b0 , 1'b1}) |
@ -1506,7 +1561,7 @@ assign ifu_ic_rw_int_addr_w_debug[pt.ICACHE_INDEX_HI:pt.ICACHE_TAG_INDEX_LO] = (
assign way_status_wr_en = (bus_ifu_wr_en_ff_q & last_beat) | ic_act_hit_f;
for (genvar i=0; i<32'(pt.ICACHE_NUM_WAYS); i++) begin : bus_wren_loop
for (genvar i=0; i<pt.ICACHE_NUM_WAYS; i++) begin : bus_wren_loop
assign bus_wren[i] = bus_ifu_wr_en_ff_q & replace_way_mb_any[i] & miss_pending ;
assign bus_wren_last[i] = bus_ifu_wr_en_ff_wo_err & replace_way_mb_any[i] & miss_pending & bus_last_data_beat;
assign ifu_tag_wren[i] = bus_wren_last[i] | wren_reset_miss[i];
@ -1528,7 +1583,7 @@ end else begin: icache_disabled
end
assign ic_tag_valid[pt.ICACHE_NUM_WAYS-1:0] = ic_tag_valid_unq[pt.ICACHE_NUM_WAYS-1:0] & {pt.ICACHE_NUM_WAYS{(~fetch_uncacheable_ff & ifc_fetch_req_f) }} ;
assign ic_tag_valid[pt.ICACHE_NUM_WAYS-1:0] = ic_tag_valid_unq[pt.ICACHE_NUM_WAYS-1:0] & {pt.ICACHE_NUM_WAYS{(~fetch_uncacheable_ff & ifc_fetch_req_f_raw) }} ;
assign ic_debug_tag_val_rd_out = |(ic_tag_valid_unq[pt.ICACHE_NUM_WAYS-1:0] & ic_debug_way_ff[pt.ICACHE_NUM_WAYS-1:0] & {pt.ICACHE_NUM_WAYS{ic_debug_rd_en_ff}}) ;
///////////////////////////////////////////
// PMU signals
@ -1536,19 +1591,21 @@ end
assign ifu_pmu_ic_miss_in = ic_act_miss_f ;
assign ifu_pmu_ic_hit_in = ic_act_hit_f ;
assign ifu_pmu_bus_error_in = ifc_bus_acc_fault_f;
assign ifu_pmu_bus_error_in = |ifc_bus_acc_fault_f;
assign ifu_pmu_bus_trxn_in = bus_cmd_sent ;
assign ifu_pmu_bus_busy_in = ifu_bus_arvalid_ff & ~ifu_bus_arready_ff & miss_pending ;
rvdff #(5) ifu_pmu_sigs_ff (.*,
.clk (active_clk),
.din ({ifu_pmu_ic_miss_in,
rvdffie #(9) ifu_pmu_sigs_ff (.*,
.clk (free_l2clk),
.din ({ifc_fetch_uncacheable_bf, ifc_fetch_req_qual_bf, dma_sb_err_state, dec_tlu_fence_i_wb,
ifu_pmu_ic_miss_in,
ifu_pmu_ic_hit_in,
ifu_pmu_bus_error_in,
ifu_pmu_bus_busy_in,
ifu_pmu_bus_trxn_in
}),
.dout({ifu_pmu_ic_miss,
.dout({fetch_uncacheable_ff, ifc_fetch_req_f_raw, dma_sb_err_state_ff, reset_all_tags,
ifu_pmu_ic_miss,
ifu_pmu_ic_hit,
ifu_pmu_bus_error,
ifu_pmu_bus_busy,
@ -1577,7 +1634,8 @@ assign ic_debug_tag_wr_en[pt.ICACHE_NUM_WAYS-1:0] = {pt.ICACHE_NUM_WAYS{ic_debug
assign ic_debug_ict_array_sel_in = ic_debug_rd_en & ic_debug_tag_array ;
rvdff #(01+pt.ICACHE_NUM_WAYS) ifu_debug_sel_ff (.*, .clk (debug_c1_clk),
rvdff_fpga #(01+pt.ICACHE_NUM_WAYS) ifu_debug_sel_ff (.*, .clk (debug_c1_clk),
.clken(debug_c1_clken), .rawclk(clk),
.din ({ic_debug_ict_array_sel_in,
ic_debug_way[pt.ICACHE_NUM_WAYS-1:0]
}),
@ -1586,25 +1644,10 @@ rvdff #(01+pt.ICACHE_NUM_WAYS) ifu_debug_sel_ff (.*, .clk (debug_c1_clk),
}));
rvdff #(1) ifu_debug_rd_en_ff (.*,.clk(free_clk),
.din ({
ic_debug_rd_en
}),
.dout({
ic_debug_rd_en_ff
}));
assign debug_data_clken = ic_debug_rd_en_ff;
rvclkhdr debug_data_c1_cgc ( .en(debug_data_clken), .l1clk(debug_data_clk), .* );
rvdff #(1) ifu_debug_valid_ff (.*, .clk(free_clk),
.din ({
ic_debug_rd_en_ff
}),
.dout({
ifu_ic_debug_rd_data_valid
}));
@ -1623,7 +1666,6 @@ rvdff #(1) ifu_debug_valid_ff (.*, .clk(free_clk),
assign ifc_region_acc_fault_final_bf = ifc_region_acc_fault_bf | ifc_region_acc_fault_memory_bf;
rvdff #(1) acc_f_m_ff (.*, .clk(free_clk), .din ( ifc_region_acc_fault_memory_bf ), .dout( ifc_region_acc_fault_memory_f ));

View File

@ -1,6 +1,6 @@
//********************************************************************************
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 Western Digital Corporation or it's affiliates.
// Copyright 2020 Western Digital Corporation or its affiliates.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -41,11 +41,10 @@ module el2_ifu_tb_memread;
clk=0;
rst_l=0;
// initialize the reads and populate the istruction arrays
// initialize the reads and populate the instruction arrays
$readmemh ("left64k", compressed );
$readmemh ("right64k", expected );
$dumpfile ("top.vcd");
$dumpvars;
$dumpon;

View File

@ -4,13 +4,13 @@
package el2_pkg;
typedef struct packed {
logic [1:0] rv_i_valid_ip;
logic [31:0] rv_i_insn_ip;
logic [31:0] rv_i_address_ip;
logic [1:0] rv_i_exception_ip;
logic [4:0] rv_i_ecause_ip;
logic [1:0] rv_i_interrupt_ip;
logic [31:0] rv_i_tval_ip;
logic trace_rv_i_valid_ip;
logic [31:0] trace_rv_i_insn_ip;
logic [31:0] trace_rv_i_address_ip;
logic trace_rv_i_exception_ip;
logic [4:0] trace_rv_i_ecause_ip;
logic trace_rv_i_interrupt_ip;
logic [31:0] trace_rv_i_tval_ip;
} el2_trace_pkt_t;
@ -76,36 +76,41 @@ typedef struct packed {
logic valid;
logic br_error;
logic br_start_error;
logic [31:1] prett;
logic pcall;
logic pret;
logic pja;
logic way;
logic pret;
// for power use the pret bit to clock the prett field
logic [31:1] prett;
} el2_predict_pkt_t;
typedef struct packed {
logic legal;
// unlikely to change
logic icaf;
logic icaf_f1;
logic icaf_second;
logic [1:0] icaf_type;
logic fence_i;
logic [3:0] i0trigger;
el2_inst_pkt_t pmu_i0_itype; // pmu - instruction type
logic pmu_i0_br_unpred; // pmu
logic pmu_divide;
// likely to change
logic legal;
logic pmu_lsu_misaligned;
el2_inst_pkt_t pmu_i0_itype; // pmu - instruction type
} el2_trap_pkt_t;
typedef struct packed {
logic [4:0] i0rd;
logic i0load;
logic i0store;
// unlikely to change
logic i0div;
logic i0v;
logic i0valid;
logic csrwen;
logic csrwonly;
logic [11:0] csrwaddr;
// likely to change
logic [4:0] i0rd;
logic i0load;
logic i0store;
logic i0v;
logic i0valid;
} el2_dest_pkt_t;
typedef struct packed {
@ -122,6 +127,31 @@ typedef struct packed {
typedef struct packed {
logic clz;
logic ctz;
logic pcnt;
logic sext_b;
logic sext_h;
logic slo;
logic sro;
logic min;
logic max;
logic pack;
logic packu;
logic packh;
logic rol;
logic ror;
logic grev;
logic gorc;
logic zbb;
logic sbset;
logic sbclr;
logic sbinv;
logic sbext;
logic sh1add;
logic sh2add;
logic sh3add;
logic zba;
logic land;
logic lor;
logic lxor;
@ -145,6 +175,9 @@ typedef struct packed {
typedef struct packed {
logic fast_int;
/* verilator lint_off SYMRSVDWORD */
logic stack;
/* verilator lint_on SYMRSVDWORD */
logic by;
logic half;
logic word;
@ -160,15 +193,61 @@ typedef struct packed {
} el2_lsu_pkt_t;
typedef struct packed {
logic exc_valid;
logic single_ecc_error;
logic inst_type; //0: Load, 1: Store
//logic dma_valid;
logic exc_type; //0: MisAligned, 1: Access Fault
logic [3:0] mscause;
logic [31:0] addr;
logic single_ecc_error;
logic exc_valid;
} el2_lsu_error_pkt_t;
typedef struct packed {
logic clz;
logic ctz;
logic pcnt;
logic sext_b;
logic sext_h;
logic slo;
logic sro;
logic min;
logic max;
logic pack;
logic packu;
logic packh;
logic rol;
logic ror;
logic grev;
logic gorc;
logic zbb;
logic sbset;
logic sbclr;
logic sbinv;
logic sbext;
logic zbs;
logic bext;
logic bdep;
logic zbe;
logic clmul;
logic clmulh;
logic clmulr;
logic zbc;
logic shfl;
logic unshfl;
logic zbp;
logic crc32_b;
logic crc32_h;
logic crc32_w;
logic crc32c_b;
logic crc32c_h;
logic crc32c_w;
logic zbr;
logic bfp;
logic zbf;
logic sh1add;
logic sh2add;
logic sh3add;
logic zba;
logic alu;
logic rs1;
logic rs2;
@ -233,6 +312,7 @@ typedef struct packed {
logic clmulh;
logic clmulr;
logic grev;
logic gorc;
logic shfl;
logic unshfl;
logic crc32_b;
@ -320,6 +400,6 @@ typedef struct packed {
logic icache_rd_valid;
logic icache_wr_valid;
} el2_cache_debug_pkt_t;
//`endif
endpackage // el2_pkg

View File

@ -1,5 +1,5 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 Western Digital Corporation or it's affiliates.
// Copyright 2020 Western Digital Corporation or its affiliates.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -119,8 +119,8 @@ import el2_pkg::*;
// signals needed for the read data coming back from the core and to block any further commands as AHB is a blocking bus
logic buf_rdata_en;
logic ahb_bus_addr_clk_en, buf_rdata_clk_en;
logic ahb_clk, ahb_addr_clk, buf_rdata_clk;
logic ahb_addr_clk_en, buf_rdata_clk_en;
logic bus_clk, ahb_addr_clk, buf_rdata_clk;
// Command buffer is the holding station where we convert to AXI and send to core
logic cmdbuf_wr_en, cmdbuf_rst;
logic cmdbuf_full;
@ -130,8 +130,6 @@ import el2_pkg::*;
logic [31:0] cmdbuf_addr;
logic [63:0] cmdbuf_wdata;
logic bus_clk;
// FSM to control the bus states and when to block the hready and load the command buffer
always_comb begin
buf_nxtstate = IDLE;
@ -163,7 +161,7 @@ import el2_pkg::*;
endcase
end // always_comb begin
rvdffs #($bits(state_t)) state_reg (.*, .din(buf_nxtstate), .dout({buf_state}), .en(buf_state_en), .clk(ahb_clk));
rvdffs_fpga #($bits(state_t)) state_reg (.*, .din(buf_nxtstate), .dout({buf_state}), .en(buf_state_en), .clk(bus_clk), .clken(bus_clk_en), .rawclk(clk));
assign master_wstrb[7:0] = ({8{ahb_hsize_q[2:0] == 3'b0}} & (8'b1 << ahb_haddr_q[2:0])) |
({8{ahb_hsize_q[2:0] == 3'b1}} & (8'b11 << ahb_haddr_q[2:0])) |
@ -188,24 +186,16 @@ import el2_pkg::*;
(ahb_hresp_q & ~ahb_hready_q);
// Buffer signals - needed for the read data and ECC error response
rvdff #(.WIDTH(64)) buf_rdata_ff (.din(axi_rdata[63:0]), .dout(buf_rdata[63:0]), .clk(buf_rdata_clk), .*);
rvdff #(.WIDTH(1)) buf_read_error_ff(.din(buf_read_error_in), .dout(buf_read_error), .clk(ahb_clk), .*); // buf_read_error will be high only one cycle
rvdff_fpga #(.WIDTH(64)) buf_rdata_ff (.din(axi_rdata[63:0]), .dout(buf_rdata[63:0]), .clk(buf_rdata_clk), .clken(buf_rdata_clk_en), .rawclk(clk), .*);
rvdff_fpga #(.WIDTH(1)) buf_read_error_ff(.din(buf_read_error_in), .dout(buf_read_error), .clk(bus_clk), .clken(bus_clk_en), .rawclk(clk), .*); // buf_read_error will be high only one cycle
// All the Master signals are captured before presenting it to the command buffer. We check for Hresp before sending it to the cmd buffer.
rvdff #(.WIDTH(1)) hresp_ff (.din(ahb_hresp), .dout(ahb_hresp_q), .clk(ahb_clk), .*);
rvdff #(.WIDTH(1)) hready_ff (.din(ahb_hready), .dout(ahb_hready_q), .clk(ahb_clk), .*);
rvdff #(.WIDTH(2)) htrans_ff (.din(ahb_htrans_in[1:0]), .dout(ahb_htrans_q[1:0]), .clk(ahb_clk), .*);
rvdff #(.WIDTH(3)) hsize_ff (.din(ahb_hsize[2:0]), .dout(ahb_hsize_q[2:0]), .clk(ahb_addr_clk), .*);
rvdff #(.WIDTH(1)) hwrite_ff (.din(ahb_hwrite), .dout(ahb_hwrite_q), .clk(ahb_addr_clk), .*);
rvdff #(.WIDTH(32)) haddr_ff (.din(ahb_haddr[31:0]), .dout(ahb_haddr_q[31:0]), .clk(ahb_addr_clk), .*);
// Clock header logic
assign ahb_bus_addr_clk_en = bus_clk_en & (ahb_hready & ahb_htrans[1]);
assign buf_rdata_clk_en = bus_clk_en & buf_rdata_en;
rvclkhdr ahb_cgc (.en(bus_clk_en), .l1clk(ahb_clk), .*);
rvclkhdr ahb_addr_cgc (.en(ahb_bus_addr_clk_en), .l1clk(ahb_addr_clk), .*);
rvclkhdr buf_rdata_cgc (.en(buf_rdata_clk_en), .l1clk(buf_rdata_clk), .*);
rvdff_fpga #(.WIDTH(1)) hresp_ff (.din(ahb_hresp), .dout(ahb_hresp_q), .clk(bus_clk), .clken(bus_clk_en), .rawclk(clk), .*);
rvdff_fpga #(.WIDTH(1)) hready_ff (.din(ahb_hready), .dout(ahb_hready_q), .clk(bus_clk), .clken(bus_clk_en), .rawclk(clk), .*);
rvdff_fpga #(.WIDTH(2)) htrans_ff (.din(ahb_htrans_in[1:0]), .dout(ahb_htrans_q[1:0]), .clk(bus_clk), .clken(bus_clk_en), .rawclk(clk), .*);
rvdff_fpga #(.WIDTH(3)) hsize_ff (.din(ahb_hsize[2:0]), .dout(ahb_hsize_q[2:0]), .clk(ahb_addr_clk), .clken(ahb_addr_clk_en), .rawclk(clk), .*);
rvdff_fpga #(.WIDTH(1)) hwrite_ff (.din(ahb_hwrite), .dout(ahb_hwrite_q), .clk(ahb_addr_clk), .clken(ahb_addr_clk_en), .rawclk(clk), .*);
rvdff_fpga #(.WIDTH(32)) haddr_ff (.din(ahb_haddr[31:0]), .dout(ahb_haddr_q[31:0]), .clk(ahb_addr_clk), .clken(ahb_addr_clk_en), .rawclk(clk), .*);
// Address check dccm
rvrangecheck #(.CCM_SADR(pt.DCCM_SADR),
@ -240,12 +230,12 @@ import el2_pkg::*;
assign cmdbuf_rst = (((axi_awvalid & axi_awready) | (axi_arvalid & axi_arready)) & ~cmdbuf_wr_en) | (ahb_hresp & ~cmdbuf_write);
assign cmdbuf_full = (cmdbuf_vld & ~((axi_awvalid & axi_awready) | (axi_arvalid & axi_arready)));
rvdffsc #(.WIDTH(1)) cmdbuf_vldff (.din(1'b1), .dout(cmdbuf_vld), .en(cmdbuf_wr_en), .clear(cmdbuf_rst), .clk(bus_clk), .*);
rvdffs #(.WIDTH(1)) cmdbuf_writeff (.din(ahb_hwrite_q), .dout(cmdbuf_write), .en(cmdbuf_wr_en), .clk(bus_clk), .*);
rvdffs #(.WIDTH(2)) cmdbuf_sizeff (.din(ahb_hsize_q[1:0]), .dout(cmdbuf_size[1:0]), .en(cmdbuf_wr_en), .clk(bus_clk), .*);
rvdffs #(.WIDTH(8)) cmdbuf_wstrbff (.din(master_wstrb[7:0]), .dout(cmdbuf_wstrb[7:0]), .en(cmdbuf_wr_en), .clk(bus_clk), .*);
rvdffe #(.WIDTH(32)) cmdbuf_addrff (.din(ahb_haddr_q[31:0]), .dout(cmdbuf_addr[31:0]), .en(cmdbuf_wr_en), .clk(bus_clk), .*);
rvdffe #(.WIDTH(64)) cmdbuf_wdataff (.din(ahb_hwdata[63:0]), .dout(cmdbuf_wdata[63:0]), .en(cmdbuf_wr_en), .clk(bus_clk), .*);
rvdffsc_fpga #(.WIDTH(1)) cmdbuf_vldff (.din(1'b1), .dout(cmdbuf_vld), .en(cmdbuf_wr_en), .clear(cmdbuf_rst), .clk(bus_clk), .clken(bus_clk_en), .rawclk(clk), .*);
rvdffs_fpga #(.WIDTH(1)) cmdbuf_writeff (.din(ahb_hwrite_q), .dout(cmdbuf_write), .en(cmdbuf_wr_en), .clk(bus_clk), .clken(bus_clk_en), .rawclk(clk), .*);
rvdffs_fpga #(.WIDTH(2)) cmdbuf_sizeff (.din(ahb_hsize_q[1:0]), .dout(cmdbuf_size[1:0]), .en(cmdbuf_wr_en), .clk(bus_clk), .clken(bus_clk_en), .rawclk(clk), .*);
rvdffs_fpga #(.WIDTH(8)) cmdbuf_wstrbff (.din(master_wstrb[7:0]), .dout(cmdbuf_wstrb[7:0]), .en(cmdbuf_wr_en), .clk(bus_clk), .clken(bus_clk_en), .rawclk(clk), .*);
rvdffe #(.WIDTH(32)) cmdbuf_addrff (.din(ahb_haddr_q[31:0]), .dout(cmdbuf_addr[31:0]), .en(cmdbuf_wr_en & bus_clk_en), .clk(clk), .*);
rvdffe #(.WIDTH(64)) cmdbuf_wdataff (.din(ahb_hwdata[63:0]), .dout(cmdbuf_wdata[63:0]), .en(cmdbuf_wr_en & bus_clk_en), .clk(clk), .*);
// AXI Write Command Channel
assign axi_awvalid = cmdbuf_vld & cmdbuf_write;
@ -274,11 +264,22 @@ import el2_pkg::*;
assign axi_rready = 1'b1;
// Clock header logic
rvclkhdr bus_cgc (.en(bus_clk_en), .l1clk(bus_clk), .*);
assign ahb_addr_clk_en = bus_clk_en & (ahb_hready & ahb_htrans[1]);
assign buf_rdata_clk_en = bus_clk_en & buf_rdata_en;
`ifdef ASSERT_ON
`ifdef RV_FPGA_OPTIMIZE
assign bus_clk = 1'b0;
assign ahb_addr_clk = 1'b0;
assign buf_rdata_clk = 1'b0;
`else
rvclkhdr bus_cgc (.en(bus_clk_en), .l1clk(bus_clk), .*);
rvclkhdr ahb_addr_cgc (.en(ahb_addr_clk_en), .l1clk(ahb_addr_clk), .*);
rvclkhdr buf_rdata_cgc (.en(buf_rdata_clk_en), .l1clk(buf_rdata_clk), .*);
`endif
`ifdef RV_ASSERT_ON
property ahb_error_protocol;
@(posedge ahb_clk) (ahb_hready & ahb_hresp) |-> (~$past(ahb_hready) & $past(ahb_hresp));
@(posedge bus_clk) (ahb_hready & ahb_hresp) |-> (~$past(ahb_hready) & $past(ahb_hresp));
endproperty
assert_ahb_error_protocol: assert property (ahb_error_protocol) else
$display("Bus Error with hReady isn't preceded with Bus Error without hready");

View File

@ -1,5 +1,5 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 Western Digital Corporation or it's affiliates.
// Copyright 2020 Western Digital Corporation or its affiliates.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -28,10 +28,12 @@ import el2_pkg::*;
,parameter TAG = 1) (
input clk,
input free_clk,
input rst_l,
input scan_mode,
input bus_clk_en,
input clk_override,
input dec_tlu_force_halt,
// AXI signals
// AXI Write Channels
@ -105,9 +107,6 @@ import el2_pkg::*;
logic [63:0] wrbuf_data;
logic [7:0] wrbuf_byteen;
logic bus_write_clk_en;
logic bus_clk, bus_write_clk;
logic master_valid;
logic master_ready;
logic [TAG-1:0] master_tag;
@ -169,15 +168,15 @@ import el2_pkg::*;
logic [31:0] last_bus_addr;
// Clocks
logic buf_clken, slvbuf_clken;
logic ahbm_addr_clken;
logic buf_clken;
logic ahbm_data_clken;
logic buf_clk, slvbuf_clk;
logic ahbm_clk;
logic ahbm_addr_clk;
logic buf_clk;
logic bus_clk;
logic ahbm_data_clk;
logic dec_tlu_force_halt_bus, dec_tlu_force_halt_bus_ns, dec_tlu_force_halt_bus_q;
// Function to get the length from byte enable
function automatic logic [1:0] get_write_size;
input logic [7:0] byteen;
@ -210,6 +209,7 @@ import el2_pkg::*;
logic [2:0] start_ptr;
logic found;
found = '0;
//get_nxtbyte_ptr[2:0] = current_byte_ptr[2:0];
start_ptr[2:0] = get_next ? (current_byte_ptr[2:0] + 3'b1) : current_byte_ptr[2:0];
for (int j=0; j<8; j++) begin
if (~found) begin
@ -219,12 +219,16 @@ import el2_pkg::*;
end
endfunction // get_nextbyte_ptr
// Create bus synchronized version of force halt
assign dec_tlu_force_halt_bus = dec_tlu_force_halt | dec_tlu_force_halt_bus_q;
assign dec_tlu_force_halt_bus_ns = ~bus_clk_en & dec_tlu_force_halt_bus;
rvdff #(.WIDTH(1)) force_halt_busff(.din(dec_tlu_force_halt_bus_ns), .dout(dec_tlu_force_halt_bus_q), .clk(free_clk), .*);
// Write buffer
assign wrbuf_en = axi_awvalid & axi_awready & master_ready;
assign wrbuf_data_en = axi_wvalid & axi_wready & master_ready;
assign wrbuf_cmd_sent = master_valid & master_ready & (master_opc[2:1] == 2'b01);
assign wrbuf_rst = wrbuf_cmd_sent & ~wrbuf_en;
assign wrbuf_rst = (wrbuf_cmd_sent & ~wrbuf_en) | dec_tlu_force_halt_bus;
assign axi_awready = ~(wrbuf_vld & ~wrbuf_cmd_sent) & master_ready;
assign axi_wready = ~(wrbuf_data_vld & ~wrbuf_cmd_sent) & master_ready;
@ -251,13 +255,6 @@ import el2_pkg::*;
assign axi_rdata[63:0] = slave_rdata[63:0];
assign slave_ready = axi_bready & axi_rready;
// Clock header logic
assign bus_write_clk_en = bus_clk_en & ((axi_awvalid & axi_awready) | (axi_wvalid & axi_wready));
rvclkhdr bus_cgc (.en(bus_clk_en), .l1clk(bus_clk), .*);
rvclkhdr bus_write_cgc (.en(bus_write_clk_en), .l1clk(bus_write_clk), .*);
// FIFO state machine
always_comb begin
buf_nxtstate = IDLE;
@ -378,7 +375,7 @@ import el2_pkg::*;
endcase
end
assign buf_rst = 1'b0;
assign buf_rst = dec_tlu_force_halt_bus;
assign cmd_done_rst = slave_valid_pre;
assign buf_addr_in[31:3] = master_addr[31:3];
assign buf_addr_in[2:0] = (buf_aligned_in & (master_opc[2:1] == 2'b01)) ? get_write_addr(master_byteen[7:0]) : master_addr[2:0];
@ -393,7 +390,8 @@ import el2_pkg::*;
(master_byteen[7:0] == 8'hf) | (master_byteen[7:0] == 8'hf0) | (master_byteen[7:0] == 8'hff)));
// Generate the ahb signals
assign ahb_haddr[31:0] = bypass_en ? {master_addr[31:3],buf_cmd_byte_ptr[2:0]} : {buf_addr[31:3],buf_cmd_byte_ptr[2:0]};
assign ahb_haddr[31:3] = bypass_en ? master_addr[31:3] : buf_addr[31:3];
assign ahb_haddr[2:0] = {3{(ahb_htrans == 2'b10)}} & buf_cmd_byte_ptr[2:0]; // Trxn should be aligned during IDLE
assign ahb_hsize[2:0] = bypass_en ? {1'b0, ({2{buf_aligned_in}} & buf_size_in[1:0])} :
{1'b0, ({2{buf_aligned}} & buf_size[1:0])}; // Send the full size for aligned trxn
assign ahb_hburst[2:0] = 3'b0;
@ -402,7 +400,7 @@ import el2_pkg::*;
assign ahb_hwrite = bypass_en ? (master_opc[2:1] == 2'b01) : buf_write;
assign ahb_hwdata[63:0] = buf_data[63:0];
assign slave_valid = slave_valid_pre;
assign slave_valid = slave_valid_pre;// & (~slvbuf_posted_write | slvbuf_error);
assign slave_opc[3:2] = slvbuf_write ? 2'b11 : 2'b00;
assign slave_opc[1:0] = {2{slvbuf_error}} & 2'b10;
assign slave_rdata[63:0] = slvbuf_error ? {2{last_bus_addr[31:0]}} : ((buf_state == DONE) ? buf_data[63:0] : ahb_hrdata_q[63:0]);
@ -411,53 +409,57 @@ import el2_pkg::*;
assign last_addr_en = (ahb_htrans[1:0] != 2'b0) & ahb_hready & ahb_hwrite ;
rvdffsc #(.WIDTH(1)) wrbuf_vldff (.din(1'b1), .dout(wrbuf_vld), .en(wrbuf_en), .clear(wrbuf_rst), .clk(bus_clk), .*);
rvdffsc #(.WIDTH(1)) wrbuf_data_vldff(.din(1'b1), .dout(wrbuf_data_vld), .en(wrbuf_data_en), .clear(wrbuf_rst), .clk(bus_clk), .*);
rvdffs #(.WIDTH(TAG)) wrbuf_tagff (.din(axi_awid[TAG-1:0]), .dout(wrbuf_tag[TAG-1:0]), .en(wrbuf_en), .clk(bus_clk), .*);
rvdffs #(.WIDTH(3)) wrbuf_sizeff (.din(axi_awsize[2:0]), .dout(wrbuf_size[2:0]), .en(wrbuf_en), .clk(bus_clk), .*);
rvdffe #(.WIDTH(32)) wrbuf_addrff (.din(axi_awaddr[31:0]), .dout(wrbuf_addr[31:0]), .en(wrbuf_en), .clk(bus_clk), .*);
rvdffe #(.WIDTH(64)) wrbuf_dataff (.din(axi_wdata[63:0]), .dout(wrbuf_data[63:0]), .en(wrbuf_data_en), .clk(bus_clk), .*);
rvdffs #(.WIDTH(8)) wrbuf_byteenff (.din(axi_wstrb[7:0]), .dout(wrbuf_byteen[7:0]), .en(wrbuf_data_en), .clk(bus_clk), .*);
rvdffsc_fpga #(.WIDTH(1)) wrbuf_vldff (.din(1'b1), .dout(wrbuf_vld), .en(wrbuf_en), .clear(wrbuf_rst), .clk(bus_clk), .clken(bus_clk_en), .rawclk(clk), .*);
rvdffsc_fpga #(.WIDTH(1)) wrbuf_data_vldff(.din(1'b1), .dout(wrbuf_data_vld), .en(wrbuf_data_en), .clear(wrbuf_rst), .clk(bus_clk), .clken(bus_clk_en), .rawclk(clk), .*);
rvdffs_fpga #(.WIDTH(TAG)) wrbuf_tagff (.din(axi_awid[TAG-1:0]), .dout(wrbuf_tag[TAG-1:0]), .en(wrbuf_en), .clk(bus_clk), .clken(bus_clk_en), .rawclk(clk), .*);
rvdffs_fpga #(.WIDTH(3)) wrbuf_sizeff (.din(axi_awsize[2:0]), .dout(wrbuf_size[2:0]), .en(wrbuf_en), .clk(bus_clk), .clken(bus_clk_en), .rawclk(clk), .*);
rvdffe #(.WIDTH(32)) wrbuf_addrff (.din(axi_awaddr[31:0]), .dout(wrbuf_addr[31:0]), .en(wrbuf_en & bus_clk_en), .clk(clk), .*);
rvdffe #(.WIDTH(64)) wrbuf_dataff (.din(axi_wdata[63:0]), .dout(wrbuf_data[63:0]), .en(wrbuf_data_en & bus_clk_en), .clk(clk), .*);
rvdffs_fpga #(.WIDTH(8)) wrbuf_byteenff (.din(axi_wstrb[7:0]), .dout(wrbuf_byteen[7:0]), .en(wrbuf_data_en), .clk(bus_clk), .clken(bus_clk_en), .rawclk(clk), .*);
rvdffs #(.WIDTH(32)) last_bus_addrff (.din(ahb_haddr[31:0]), .dout(last_bus_addr[31:0]), .en(last_addr_en), .clk(ahbm_clk), .*);
rvdffs_fpga #(.WIDTH(32)) last_bus_addrff (.din(ahb_haddr[31:0]), .dout(last_bus_addr[31:0]), .en(last_addr_en), .clk(bus_clk), .clken(bus_clk_en), .rawclk(clk), .*);
rvdffsc #(.WIDTH($bits(state_t))) buf_state_ff (.din(buf_nxtstate), .dout({buf_state}), .en(buf_state_en), .clear(buf_rst), .clk(ahbm_clk), .*);
rvdffs #(.WIDTH(1)) buf_writeff (.din(buf_write_in), .dout(buf_write), .en(buf_wr_en), .clk(buf_clk), .*);
rvdffs #(.WIDTH(TAG)) buf_tagff (.din(buf_tag_in[TAG-1:0]), .dout(buf_tag[TAG-1:0]), .en(buf_wr_en), .clk(buf_clk), .*);
rvdffe #(.WIDTH(32)) buf_addrff (.din(buf_addr_in[31:0]), .dout(buf_addr[31:0]), .en(buf_wr_en & bus_clk_en), .*);
rvdffs #(.WIDTH(2)) buf_sizeff (.din(buf_size_in[1:0]), .dout(buf_size[1:0]), .en(buf_wr_en), .clk(buf_clk), .*);
rvdffs #(.WIDTH(1)) buf_alignedff (.din(buf_aligned_in), .dout(buf_aligned), .en(buf_wr_en), .clk(buf_clk), .*);
rvdffs #(.WIDTH(8)) buf_byteenff (.din(buf_byteen_in[7:0]), .dout(buf_byteen[7:0]), .en(buf_wr_en), .clk(buf_clk), .*);
rvdffe #(.WIDTH(64)) buf_dataff (.din(buf_data_in[63:0]), .dout(buf_data[63:0]), .en(buf_data_wr_en & bus_clk_en), .*);
rvdffsc_fpga #(.WIDTH($bits(state_t))) buf_state_ff (.din(buf_nxtstate), .dout({buf_state}), .en(buf_state_en), .clear(buf_rst), .clk(bus_clk), .clken(bus_clk_en), .rawclk(clk), .*);
rvdffs_fpga #(.WIDTH(1)) buf_writeff (.din(buf_write_in), .dout(buf_write), .en(buf_wr_en), .clk(buf_clk), .clken(buf_clken), .rawclk(clk), .*);
rvdffs_fpga #(.WIDTH(TAG)) buf_tagff (.din(buf_tag_in[TAG-1:0]), .dout(buf_tag[TAG-1:0]), .en(buf_wr_en), .clk(buf_clk), .clken(buf_clken), .rawclk(clk), .*);
rvdffe #(.WIDTH(32)) buf_addrff (.din(buf_addr_in[31:0]), .dout(buf_addr[31:0]), .en(buf_wr_en & bus_clk_en), .clk(clk), .*);
rvdffs_fpga #(.WIDTH(2)) buf_sizeff (.din(buf_size_in[1:0]), .dout(buf_size[1:0]), .en(buf_wr_en), .clk(buf_clk), .clken(buf_clken), .rawclk(clk), .*);
rvdffs_fpga #(.WIDTH(1)) buf_alignedff (.din(buf_aligned_in), .dout(buf_aligned), .en(buf_wr_en), .clk(buf_clk), .clken(buf_clken), .rawclk(clk), .*);
rvdffs_fpga #(.WIDTH(8)) buf_byteenff (.din(buf_byteen_in[7:0]), .dout(buf_byteen[7:0]), .en(buf_wr_en), .clk(buf_clk), .clken(buf_clken), .rawclk(clk), .*);
rvdffe #(.WIDTH(64)) buf_dataff (.din(buf_data_in[63:0]), .dout(buf_data[63:0]), .en(buf_data_wr_en & bus_clk_en), .clk(clk), .*);
rvdffs #(.WIDTH(1)) slvbuf_writeff (.din(buf_write), .dout(slvbuf_write), .en(slvbuf_wr_en), .clk(buf_clk), .*);
rvdffs #(.WIDTH(TAG)) slvbuf_tagff (.din(buf_tag[TAG-1:0]), .dout(slvbuf_tag[TAG-1:0]), .en(slvbuf_wr_en), .clk(buf_clk), .*);
rvdffs #(.WIDTH(1)) slvbuf_errorff (.din(slvbuf_error_in), .dout(slvbuf_error), .en(slvbuf_error_en), .clk(ahbm_clk), .*);
rvdffs_fpga #(.WIDTH(1)) slvbuf_writeff (.din(buf_write), .dout(slvbuf_write), .en(slvbuf_wr_en), .clk(buf_clk), .clken(buf_clken), .rawclk(clk), .*);
rvdffs_fpga #(.WIDTH(TAG)) slvbuf_tagff (.din(buf_tag[TAG-1:0]), .dout(slvbuf_tag[TAG-1:0]), .en(slvbuf_wr_en), .clk(buf_clk), .clken(buf_clken), .rawclk(clk), .*);
rvdffs_fpga #(.WIDTH(1)) slvbuf_errorff (.din(slvbuf_error_in), .dout(slvbuf_error), .en(slvbuf_error_en), .clk(bus_clk), .clken(bus_clk_en), .rawclk(clk), .*);
rvdffsc #(.WIDTH(1)) buf_cmd_doneff (.din(1'b1), .en(cmd_done), .dout(cmd_doneQ), .clear(cmd_done_rst), .clk(ahbm_clk), .*);
rvdffs #(.WIDTH(3)) buf_cmd_byte_ptrff (.din(buf_cmd_byte_ptr[2:0]), .dout(buf_cmd_byte_ptrQ[2:0]), .en(buf_cmd_byte_ptr_en), .clk(ahbm_clk), .*);
rvdffsc_fpga #(.WIDTH(1)) buf_cmd_doneff (.din(1'b1), .dout(cmd_doneQ), .en(cmd_done), .clear(cmd_done_rst), .clk(bus_clk), .clken(bus_clk_en), .rawclk(clk), .*);
rvdffs_fpga #(.WIDTH(3)) buf_cmd_byte_ptrff (.din(buf_cmd_byte_ptr[2:0]), .dout(buf_cmd_byte_ptrQ[2:0]), .en(buf_cmd_byte_ptr_en), .clk(bus_clk), .clken(bus_clk_en), .rawclk(clk), .*);
rvdff #(.WIDTH(1)) hready_ff (.din(ahb_hready), .dout(ahb_hready_q), .clk(ahbm_clk), .*);
rvdff #(.WIDTH(2)) htrans_ff (.din(ahb_htrans[1:0]), .dout(ahb_htrans_q[1:0]), .clk(ahbm_clk), .*);
rvdff #(.WIDTH(1)) hwrite_ff (.din(ahb_hwrite), .dout(ahb_hwrite_q), .clk(ahbm_addr_clk), .*);
rvdff #(.WIDTH(1)) hresp_ff (.din(ahb_hresp), .dout(ahb_hresp_q), .clk(ahbm_clk), .*);
rvdff #(.WIDTH(64)) hrdata_ff (.din(ahb_hrdata[63:0]), .dout(ahb_hrdata_q[63:0]), .clk(ahbm_data_clk), .*);
rvdff_fpga #(.WIDTH(1)) hready_ff (.din(ahb_hready), .dout(ahb_hready_q), .clk(bus_clk), .clken(bus_clk_en), .rawclk(clk), .*);
rvdff_fpga #(.WIDTH(2)) htrans_ff (.din(ahb_htrans[1:0]), .dout(ahb_htrans_q[1:0]), .clk(bus_clk), .clken(bus_clk_en), .rawclk(clk), .*);
rvdff_fpga #(.WIDTH(1)) hwrite_ff (.din(ahb_hwrite), .dout(ahb_hwrite_q), .clk(bus_clk), .clken(bus_clk_en), .rawclk(clk), .*);
rvdff_fpga #(.WIDTH(1)) hresp_ff (.din(ahb_hresp), .dout(ahb_hresp_q), .clk(bus_clk), .clken(bus_clk_en), .rawclk(clk), .*);
rvdff_fpga #(.WIDTH(64)) hrdata_ff (.din(ahb_hrdata[63:0]), .dout(ahb_hrdata_q[63:0]), .clk(ahbm_data_clk), .clken(ahbm_data_clken), .rawclk(clk), .*);
// Clock headers
// clock enables for ahbm addr/data
assign buf_clken = bus_clk_en & (buf_wr_en | slvbuf_wr_en | clk_override);
assign ahbm_addr_clken = bus_clk_en & ((ahb_hready & ahb_htrans[1]) | clk_override);
assign ahbm_data_clken = bus_clk_en & ((buf_state != IDLE) | clk_override);
`ifdef RV_FPGA_OPTIMIZE
assign bus_clk = 1'b0;
assign buf_clk = 1'b0;
assign ahbm_data_clk = 1'b0;
`else
rvclkhdr bus_cgc (.en(bus_clk_en), .l1clk(bus_clk), .*);
rvclkhdr buf_cgc (.en(buf_clken), .l1clk(buf_clk), .*);
rvclkhdr ahbm_cgc (.en(bus_clk_en), .l1clk(ahbm_clk), .*);
rvclkhdr ahbm_addr_cgc (.en(ahbm_addr_clken), .l1clk(ahbm_addr_clk), .*);
rvclkhdr ahbm_data_cgc (.en(ahbm_data_clken), .l1clk(ahbm_data_clk), .*);
`endif
`ifdef ASSERT_ON
`ifdef RV_ASSERT_ON
property ahb_trxn_aligned;
@(posedge ahbm_clk) ahb_htrans[1] |-> ((ahb_hsize[2:0] == 3'h0) |
@(posedge bus_clk) ahb_htrans[1] |-> ((ahb_hsize[2:0] == 3'h0) |
((ahb_hsize[2:0] == 3'h1) & (ahb_haddr[0] == 1'b0)) |
((ahb_hsize[2:0] == 3'h2) & (ahb_haddr[1:0] == 2'b0)) |
((ahb_hsize[2:0] == 3'h3) & (ahb_haddr[2:0] == 3'b0)));
@ -466,7 +468,7 @@ import el2_pkg::*;
$display("Assertion ahb_trxn_aligned failed: ahb_htrans=2'h%h, ahb_hsize=3'h%h, ahb_haddr=32'h%h",ahb_htrans[1:0], ahb_hsize[2:0], ahb_haddr[31:0]);
property ahb_error_protocol;
@(posedge ahbm_clk) (ahb_hready & ahb_hresp) |-> (~$past(ahb_hready) & $past(ahb_hresp));
@(posedge bus_clk) (ahb_hready & ahb_hresp) |-> (~$past(ahb_hready) & $past(ahb_hresp));
endproperty
assert_ahb_error_protocol: assert property (ahb_error_protocol) else
$display("Bus Error with hReady isn't preceded with Bus Error without hready");

View File

@ -1,5 +1,5 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 Western Digital Corporation or it's affiliates.
// Copyright 2020 Western Digital Corporation or its affiliates.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -29,7 +29,7 @@ if (SHORT == 1) begin
assign dout = din;
end
else begin
`ifdef CLOCKGATE
`ifdef RV_CLOCKGATE
always @(posedge tb_top.clk) begin
#0 $strobe("CG: %0t %m din %x dout %x clk %b width %d",$time,din,dout,clk,WIDTH);
end
@ -85,7 +85,85 @@ else begin
end
endmodule
module rvdffe #( parameter WIDTH=1, SHORT=0 )
// _fpga versions
module rvdff_fpga #( parameter WIDTH=1, SHORT=0 )
(
input logic [WIDTH-1:0] din,
input logic clk,
input logic clken,
input logic rawclk,
input logic rst_l,
output logic [WIDTH-1:0] dout
);
if (SHORT == 1) begin
assign dout = din;
end
else begin
`ifdef RV_FPGA_OPTIMIZE
rvdffs #(WIDTH) dffs (.clk(rawclk), .en(clken), .*);
`else
rvdff #(WIDTH) dff (.*);
`endif
end
endmodule
// rvdff with 2:1 input mux to flop din iff sel==1
module rvdffs_fpga #( parameter WIDTH=1, SHORT=0 )
(
input logic [WIDTH-1:0] din,
input logic en,
input logic clk,
input logic clken,
input logic rawclk,
input logic rst_l,
output logic [WIDTH-1:0] dout
);
if (SHORT == 1) begin : genblock
assign dout = din;
end
else begin : genblock
`ifdef RV_FPGA_OPTIMIZE
rvdffs #(WIDTH) dffs (.clk(rawclk), .en(clken & en), .*);
`else
rvdffs #(WIDTH) dffs (.*);
`endif
end
endmodule
// rvdff with en and clear
module rvdffsc_fpga #( parameter WIDTH=1, SHORT=0 )
(
input logic [WIDTH-1:0] din,
input logic en,
input logic clear,
input logic clk,
input logic clken,
input logic rawclk,
input logic rst_l,
output logic [WIDTH-1:0] dout
);
logic [WIDTH-1:0] din_new;
if (SHORT == 1) begin
assign dout = din;
end
else begin
`ifdef RV_FPGA_OPTIMIZE
rvdffs #(WIDTH) dffs (.clk(rawclk), .din(din[WIDTH-1:0] & {WIDTH{~clear}}),.en((en | clear) & clken), .*);
`else
rvdffsc #(WIDTH) dffsc (.*);
`endif
end
endmodule
module rvdffe #( parameter WIDTH=1, SHORT=0, OVERRIDE=0 )
(
input logic [WIDTH-1:0] din,
input logic en,
@ -104,8 +182,8 @@ if (SHORT == 1) begin : genblock
end
else begin : genblock
`ifndef PHYSICAL
if (WIDTH >= 8) begin: genblock
`ifndef RV_PHYSICAL
if (WIDTH >= 8 || OVERRIDE==1) begin: genblock
`endif
`ifdef RV_FPGA_OPTIMIZE
@ -115,15 +193,226 @@ else begin : genblock
rvdff #(WIDTH) dff (.*, .clk(l1clk));
`endif
`ifndef PHYSICAL
`ifndef RV_PHYSICAL
end
else
$error("%m: rvdffe width must be >= 8");
$error("%m: rvdffe must be WIDTH >= 8");
`endif
end // else: !if(SHORT == 1)
endmodule // rvdffe
module rvdffpcie #( parameter WIDTH=31 )
(
input logic [WIDTH-1:0] din,
input logic clk,
input logic rst_l,
input logic en,
input logic scan_mode,
output logic [WIDTH-1:0] dout
);
`ifndef RV_PHYSICAL
if (WIDTH == 31) begin: genblock
`endif
`ifdef RV_FPGA_OPTIMIZE
rvdffs #(WIDTH) dff ( .* );
`else
rvdfflie #(.WIDTH(WIDTH), .LEFT(19)) dff (.*);
`endif
`ifndef RV_PHYSICAL
end
else
$error("%m: rvdffpcie width must be 31");
`endif
endmodule
// format: { LEFT, EXTRA }
// LEFT # of bits will be done with rvdffie, all else EXTRA with rvdffe
module rvdfflie #( parameter WIDTH=16, LEFT=8 )
(
input logic [WIDTH-1:0] din,
input logic clk,
input logic rst_l,
input logic en,
input logic scan_mode,
output logic [WIDTH-1:0] dout
);
localparam EXTRA = WIDTH-LEFT;
localparam LMSB = WIDTH-1;
localparam LLSB = LMSB-LEFT+1;
localparam XMSB = LLSB-1;
localparam XLSB = LLSB-EXTRA;
`ifndef RV_PHYSICAL
if (WIDTH >= 16 && LEFT >= 8 && EXTRA >= 8) begin: genblock
`endif
`ifdef RV_FPGA_OPTIMIZE
rvdffs #(WIDTH) dff ( .* );
`else
rvdffiee #(LEFT) dff_left (.*, .din(din[LMSB:LLSB]), .dout(dout[LMSB:LLSB]));
rvdffe #(EXTRA) dff_extra (.*, .din(din[XMSB:XLSB]), .dout(dout[XMSB:XLSB]));
`endif
`ifndef RV_PHYSICAL
end
else
$error("%m: rvdfflie musb be WIDTH >= 16 && LEFT >= 8 && EXTRA >= 8");
`endif
endmodule
// special power flop for predict packet
// format: { LEFT, RIGHT==31 }
// LEFT # of bits will be done with rvdffe; RIGHT is enabled by LEFT[LSB] & en
module rvdffppe #( parameter WIDTH=32 )
(
input logic [WIDTH-1:0] din,
input logic clk,
input logic rst_l,
input logic en,
input logic scan_mode,
output logic [WIDTH-1:0] dout
);
localparam RIGHT = 31;
localparam LEFT = WIDTH - RIGHT;
localparam LMSB = WIDTH-1;
localparam LLSB = LMSB-LEFT+1;
localparam RMSB = LLSB-1;
localparam RLSB = LLSB-RIGHT;
`ifndef RV_PHYSICAL
if (WIDTH>=32 && LEFT>=8 && RIGHT>=8) begin: genblock
`endif
`ifdef RV_FPGA_OPTIMIZE
rvdffs #(WIDTH) dff ( .* );
`else
rvdffe #(LEFT) dff_left (.*, .din(din[LMSB:LLSB]), .dout(dout[LMSB:LLSB]));
rvdffe #(RIGHT) dff_right (.*, .din(din[RMSB:RLSB]), .dout(dout[RMSB:RLSB]), .en(en & din[LLSB])); // qualify with pret
`endif
`ifndef RV_PHYSICAL
end
else
$error("%m: must be WIDTH>=32 && LEFT>=8 && RIGHT>=8");
`endif
endmodule
module rvdffie #( parameter WIDTH=1, OVERRIDE=0 )
(
input logic [WIDTH-1:0] din,
input logic clk,
input logic rst_l,
input logic scan_mode,
output logic [WIDTH-1:0] dout
);
logic l1clk;
logic en;
`ifndef RV_PHYSICAL
if (WIDTH >= 8 || OVERRIDE==1) begin: genblock
`endif
assign en = |(din ^ dout);
`ifdef RV_FPGA_OPTIMIZE
rvdffs #(WIDTH) dff ( .* );
`else
rvclkhdr clkhdr ( .* );
rvdff #(WIDTH) dff (.*, .clk(l1clk));
`endif
`ifndef RV_PHYSICAL
end
else
$error("%m: rvdffie must be WIDTH >= 8");
`endif
endmodule
// ie flop but it has an .en input
module rvdffiee #( parameter WIDTH=1, OVERRIDE=0 )
(
input logic [WIDTH-1:0] din,
input logic clk,
input logic rst_l,
input logic scan_mode,
input logic en,
output logic [WIDTH-1:0] dout
);
logic l1clk;
logic final_en;
`ifndef RV_PHYSICAL
if (WIDTH >= 8 || OVERRIDE==1) begin: genblock
`endif
assign final_en = (|(din ^ dout)) & en;
`ifdef RV_FPGA_OPTIMIZE
rvdffs #(WIDTH) dff ( .*, .en(final_en) );
`else
rvdffe #(WIDTH) dff (.*, .en(final_en));
`endif
`ifndef RV_PHYSICAL
end
else
$error("%m: rvdffie width must be >= 8");
`endif
endmodule
module rvsyncss #(parameter WIDTH = 251)
(
input logic clk,
@ -139,6 +428,23 @@ module rvsyncss #(parameter WIDTH = 251)
endmodule // rvsyncss
module rvsyncss_fpga #(parameter WIDTH = 251)
(
input logic gw_clk,
input logic rawclk,
input logic clken,
input logic rst_l,
input logic [WIDTH-1:0] din,
output logic [WIDTH-1:0] dout
);
logic [WIDTH-1:0] din_ff1;
rvdff_fpga #(WIDTH) sync_ff1 (.*, .clk(gw_clk), .rawclk(rawclk), .clken(clken), .din (din[WIDTH-1:0]), .dout(din_ff1[WIDTH-1:0]));
rvdff_fpga #(WIDTH) sync_ff2 (.*, .clk(gw_clk), .rawclk(rawclk), .clken(clken), .din (din_ff1[WIDTH-1:0]), .dout(dout[WIDTH-1:0]));
endmodule // rvsyncss
module rvlsadder
(
input logic [31:0] rs1,
@ -468,6 +774,7 @@ module `TEC_RV_ICG
endmodule
`ifndef RV_FPGA_OPTIMIZE
module rvclkhdr
(
input logic en,
@ -477,11 +784,12 @@ module rvclkhdr
);
logic SE;
assign SE = scan_mode;
assign SE = 0;
`TEC_RV_ICG clkhdr ( .*, .EN(en), .CK(clk), .Q(l1clk));
endmodule // rvclkhdr
`endif
module rvoclkhdr
(
@ -492,7 +800,7 @@ module rvoclkhdr
);
logic SE;
assign SE = scan_mode;
assign SE = 0;
`ifdef RV_FPGA_OPTIMIZE
assign l1clk = clk;

View File

@ -16,7 +16,17 @@
`define EL2_LOCAL_RAM_TEST_IO \
input logic WE, \
input logic ME, \
input logic CLK
input logic CLK, \
input logic TEST1, \
input logic RME, \
input logic [3:0] RM, \
input logic LS, \
input logic DS, \
input logic SD, \
input logic TEST_RNM, \
input logic BC1, \
input logic BC2, \
output logic ROP
`define EL2_RAM(depth, width) \
module ram_``depth``x``width( \
@ -26,11 +36,22 @@ module ram_``depth``x``width( \
`EL2_LOCAL_RAM_TEST_IO \
); \
reg [(width-1):0] ram_core [(depth-1):0]; \
\
`ifdef GTLSIM \
integer i; \
initial begin \
for (i=0; i<depth; i=i+1) \
ram_core[i] = '0; \
end \
`endif \
always @(posedge CLK) begin \
`ifdef GTLSIM \
if (ME && WE) ram_core[ADR] <= D; \
`else \
if (ME && WE) begin ram_core[ADR] <= D; Q <= 'x; end \
`endif \
if (ME && ~WE) Q <= ram_core[ADR]; \
end \
assign ROP = ME; \
\
endmodule
@ -42,12 +63,22 @@ module ram_be_``depth``x``width( \
`EL2_LOCAL_RAM_TEST_IO \
); \
reg [(width-1):0] ram_core [(depth-1):0]; \
\
`ifdef GTLSIM \
integer i; \
initial begin \
for (i=0; i<depth; i=i+1) \
ram_core[i] = '0; \
end \
`endif \
always @(posedge CLK) begin \
if (ME && WE) ram_core[ADR] = D & WEM | ~WEM & ram_core[ADR];\
`ifdef GTLSIM \
if (ME && WE) ram_core[ADR] <= D & WEM | ~WEM & ram_core[ADR]; \
`else \
if (ME && WE) begin ram_core[ADR] <= D & WEM | ~WEM & ram_core[ADR]; Q <= 'x; end \
`endif \
if (ME && ~WE) Q <= ram_core[ADR]; \
end \
\
assign ROP = ME; \
\
endmodule
@ -61,7 +92,11 @@ output logic [(width-1):0] Q,
reg [(width-1):0] ram_core [(depth-1):0];
always @(posedge CLK) begin
if (ME && WE) ram_core[ADR] = D;
`ifdef GTLSIM
if (ME && WE) ram_core[ADR] <= D;
`else
if (ME && WE) begin ram_core[ADR] <= D; Q <= 'x; end
`endif
if (ME && ~WE) Q <= ram_core[ADR];
end
endmodule
@ -172,6 +207,7 @@ endmodule
`EL2_RAM_BE(256, 52)
`EL2_RAM_BE(128, 52)
`EL2_RAM_BE(64, 52)
`EL2_RAM_BE(32, 52)
`EL2_RAM_BE(4096, 104)
`EL2_RAM_BE(2048, 104)
`EL2_RAM_BE(1024, 104)
@ -179,6 +215,7 @@ endmodule
`EL2_RAM_BE(256, 104)
`EL2_RAM_BE(128, 104)
`EL2_RAM_BE(64, 104)
`EL2_RAM_BE(32, 104)
`EL2_RAM_BE(4096, 44)
`EL2_RAM_BE(2048, 44)
`EL2_RAM_BE(1024, 44)
@ -186,6 +223,7 @@ endmodule
`EL2_RAM_BE(256, 44)
`EL2_RAM_BE(128, 44)
`EL2_RAM_BE(64, 44)
`EL2_RAM_BE(32, 44)
`EL2_RAM_BE(4096, 88)
`EL2_RAM_BE(2048, 88)
`EL2_RAM_BE(1024, 88)
@ -193,6 +231,8 @@ endmodule
`EL2_RAM_BE(256, 88)
`EL2_RAM_BE(128, 88)
`EL2_RAM_BE(64, 88)
`EL2_RAM_BE(32, 88)
`EL2_RAM(64, 39)
`undef EL2_RAM

View File

@ -1,5 +1,5 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 Western Digital Corporation or it's affiliates.
// Copyright 2020 Western Digital Corporation or its affiliates.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -43,7 +43,6 @@ import el2_pkg::*;
input logic dec_tlu_sideeffect_posted_disable, // disable the posted sideeffect load store to the bus
input logic dec_tlu_core_ecc_disable, // disable the generation of the ecc
input logic [31:0] exu_lsu_rs1_d, // address rs operand
input logic [31:0] exu_lsu_rs2_d, // store data
input logic [11:0] dec_lsu_offset_d, // address offset operand
@ -58,6 +57,7 @@ import el2_pkg::*;
output logic lsu_store_stall_any, // This is for blocking stores in the decode
output logic lsu_fastint_stall_any, // Stall the fastint in decode-1 stage
output logic lsu_idle_any, // lsu buffers are empty and no instruction in the pipeline. Doesn't include DMA
output logic lsu_active, // Used to turn off top level clk
output logic [31:1] lsu_fir_addr, // fast interrupt address
output logic [1:0] lsu_fir_error, // Error during fast interrupt lookup
@ -78,7 +78,6 @@ import el2_pkg::*;
output logic [pt.LSU_NUM_NBLOAD_WIDTH-1:0] lsu_nonblock_load_data_tag, // the tag of the non block load sending the data/error
output logic [31:0] lsu_nonblock_load_data, // Data of the non block load
output logic lsu_pmu_load_external_m, // PMU : Bus loads
output logic lsu_pmu_store_external_m, // PMU : Bus loads
output logic lsu_pmu_misaligned_m, // PMU : misaligned
@ -175,14 +174,13 @@ import el2_pkg::*;
output logic [63:0] dccm_dma_rdata, // lsu data for DMA dccm read
output logic dccm_ready, // lsu ready for DMA access
input logic scan_mode, // scan
input logic clk,
input logic free_clk,
input logic rst_l
input logic scan_mode, // scan mode
input logic clk, // Clock only while core active. Through one clock header. For flops with second clock header built in. Connected to ACTIVE_L2CLK.
input logic active_clk, // Clock only while core active. Through two clock headers. For flops without second clock header built in.
input logic rst_l // reset, active low
);
logic lsu_dccm_rden_m;
logic lsu_dccm_rden_r;
logic [31:0] store_data_m;
@ -224,6 +222,7 @@ import el2_pkg::*;
logic addr_in_dccm_d, addr_in_dccm_m, addr_in_dccm_r;
logic addr_in_pic_d, addr_in_pic_m, addr_in_pic_r;
logic ldst_dual_d, ldst_dual_m, ldst_dual_r;
logic addr_external_m;
logic stbuf_reqvld_any;
@ -249,7 +248,6 @@ import el2_pkg::*;
logic lsu_bus_buffer_pend_any;
logic lsu_bus_buffer_empty_any;
logic lsu_bus_buffer_full_any;
logic lsu_bus_idle_any;
logic lsu_busreq_m;
logic [31:0] bus_read_data_m;
@ -262,6 +260,8 @@ import el2_pkg::*;
logic [pt.DCCM_ECC_WIDTH-1:0] dma_dccm_wdata_ecc_lo, dma_dccm_wdata_ecc_hi;
// Clocks
logic lsu_busm_clken;
logic lsu_bus_obuf_c1_clken;
logic lsu_c1_m_clk, lsu_c1_r_clk;
logic lsu_c2_m_clk, lsu_c2_r_clk;
logic lsu_store_c1_m_clk, lsu_store_c1_r_clk;
@ -288,9 +288,10 @@ import el2_pkg::*;
// There can't be any inpipe forwarding from non-dma packet to dma packet since they can be flushed so we can't have st in r when dma is in m
assign dma_mem_tag_d[2:0] = dma_mem_tag[2:0];
assign ldst_nodma_mtor = (lsu_pkt_m.valid & ~lsu_pkt_m.dma & (addr_in_dccm_m | addr_in_pic_m) & lsu_pkt_m.store);
assign dccm_ready = ~(dec_lsu_valid_raw_d | ldst_nodma_mtor | ld_single_ecc_error_r_ff);
assign dma_dccm_wen = dma_dccm_req & dma_mem_write & addr_in_dccm_d;
assign dma_dccm_wen = dma_dccm_req & dma_mem_write & addr_in_dccm_d & dma_mem_sz[1]; // Perform DMA writes only for word/dword
assign dma_pic_wen = dma_dccm_req & dma_mem_write & addr_in_pic_d;
assign {dma_dccm_wdata_hi[31:0], dma_dccm_wdata_lo[31:0]} = dma_mem_wdata[63:0] >> {dma_mem_addr[2:0], 3'b000}; // Shift the dma data to lower bits to make it consistent to lsu stores
@ -299,16 +300,19 @@ import el2_pkg::*;
assign flush_m_up = dec_tlu_flush_lower_r;
assign flush_r = dec_tlu_i0_kill_writeb_r;
// lsu idle
// lsu halt idle. This is used for entering the halt mode. Also, DMA accesses are allowed during fence.
// Indicates non-idle if there is a instruction valid in d-r or read/write buffers are non-empty since they can come with error
// Store buffer now have only non-dma dccm stores
// stbuf_empty not needed since it has only dccm stores
assign lsu_idle_any = ~((lsu_pkt_m.valid & ~lsu_pkt_m.dma) |
(lsu_pkt_r.valid & ~lsu_pkt_r.dma)) &
lsu_bus_buffer_empty_any & lsu_bus_idle_any;
lsu_bus_buffer_empty_any;
assign lsu_active = (lsu_pkt_m.valid | lsu_pkt_r.valid | ld_single_ecc_error_r_ff) | ~lsu_bus_buffer_empty_any; // This includes DMA. Used for gating top clock
// Instantiate the store buffer
assign store_stbuf_reqvld_r = lsu_pkt_r.valid & lsu_pkt_r.store & addr_in_dccm_r & ~flush_r & ~lsu_pkt_r.dma;
assign store_stbuf_reqvld_r = lsu_pkt_r.valid & lsu_pkt_r.store & addr_in_dccm_r & ~flush_r & (~lsu_pkt_r.dma | ((lsu_pkt_r.by | lsu_pkt_r.half) & ~lsu_double_ecc_error_r));
// Disable Forwarding for now
assign lsu_cmpen_m = lsu_pkt_m.valid & (lsu_pkt_m.load | lsu_pkt_m.store) & (addr_in_dccm_m | addr_in_pic_m);
@ -316,6 +320,11 @@ import el2_pkg::*;
// Bus signals
assign lsu_busreq_m = lsu_pkt_m.valid & ((lsu_pkt_m.load | lsu_pkt_m.store) & addr_external_m) & ~flush_m_up & ~lsu_exc_m & ~lsu_pkt_m.fast_int;
// Dual signals
assign ldst_dual_d = (lsu_addr_d[2] != end_addr_d[2]);
assign ldst_dual_m = (lsu_addr_m[2] != end_addr_m[2]);
assign ldst_dual_r = (lsu_addr_r[2] != end_addr_r[2]);
// PMU signals
assign lsu_pmu_misaligned_m = lsu_pkt_m.valid & ((lsu_pkt_m.half & lsu_addr_m[0]) | (lsu_pkt_m.word & (|lsu_addr_m[1:0])));
assign lsu_pmu_load_external_m = lsu_pkt_m.valid & lsu_pkt_m.load & addr_external_m;
@ -358,18 +367,24 @@ import el2_pkg::*;
// Bus interface
el2_lsu_bus_intf #(.pt(pt)) bus_intf (
.lsu_addr_m(lsu_addr_m[31:0] & {32{addr_external_m & lsu_pkt_m.valid}}),
.lsu_addr_r(lsu_addr_r[31:0] & {32{lsu_busreq_r}}),
.end_addr_m(end_addr_m[31:0] & {32{addr_external_m & lsu_pkt_m.valid}}),
.end_addr_r(end_addr_r[31:0] & {32{lsu_busreq_r}}),
.store_data_r(store_data_r[31:0] & {32{lsu_busreq_r}}),
.*
);
//Flops
rvdff #(3) dma_mem_tag_mff (.*, .din(dma_mem_tag_d[2:0]), .dout(dma_mem_tag_m[2:0]), .clk(lsu_c1_m_clk));
rvdff #(2) lsu_raw_fwd_r_ff (.*, .din({lsu_raw_fwd_hi_m, lsu_raw_fwd_lo_m}), .dout({lsu_raw_fwd_hi_r, lsu_raw_fwd_lo_r}), .clk(lsu_c2_r_clk));
`ifdef ASSERT_ON
`ifdef RV_ASSERT_ON
logic [1:0] store_data_bypass_sel;
assign store_data_bypass_sel[1:0] = {lsu_p.store_data_bypass_d, lsu_p.store_data_bypass_m};
property exception_no_lsu_flush;
@(posedge clk) disable iff(~rst_l) lsu_lsc_ctl.lsu_error_pkt_m.exc_valid |-> ##[1:2] (flush_r );
endproperty

View File

@ -1,5 +1,5 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 Western Digital Corporation or it's affiliates.
// Copyright 2020 Western Digital Corporation or its affiliates.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -34,9 +34,9 @@ import el2_pkg::*;
input logic [31:0] end_addr_d, // end address for lsu
input el2_lsu_pkt_t lsu_pkt_d, // packet in d
input logic [31:0] dec_tlu_mrac_ff, // CSR read
input logic [3:0] rs1_region_d,
input logic [3:0] rs1_region_d, // address rs operand [31:28]
input logic [31:0] rs1_d,
input logic [31:0] rs1_d, // address rs operand
output logic is_sideeffects_m, // is sideffects space
output logic addr_in_dccm_d, // address in dccm
@ -50,7 +50,7 @@ import el2_pkg::*;
output logic fir_dccm_access_error_d, // Fast interrupt dccm access error
output logic fir_nondccm_access_error_d,// Fast interrupt dccm access error
input logic scan_mode
input logic scan_mode // Scan mode
);
@ -116,7 +116,7 @@ import el2_pkg::*;
);
assign start_addr_dccm_or_pic = start_addr_in_dccm_region_d | start_addr_in_pic_region_d;
assign base_reg_dccm_or_pic = (rs1_region_d[3:0] == pt.DCCM_REGION) | (rs1_region_d[3:0] == pt.PIC_REGION);
assign base_reg_dccm_or_pic = ((rs1_region_d[3:0] == pt.DCCM_REGION) & pt.DCCM_ENABLE) | (rs1_region_d[3:0] == pt.PIC_REGION);
assign addr_in_dccm_d = (start_addr_in_dccm_d & end_addr_in_dccm_d);
assign addr_in_pic_d = (start_addr_in_pic_d & end_addr_in_pic_d);
@ -154,7 +154,7 @@ import el2_pkg::*;
assign regpred_access_fault_d = (start_addr_dccm_or_pic ^ base_reg_dccm_or_pic); // 5. Region predication access fault: Base Address in DCCM/PIC and Final address in non-DCCM/non-PIC region or vice versa
assign picm_access_fault_d = (addr_in_pic_d & ((start_addr_d[1:0] != 2'b0) | ~lsu_pkt_d.word)); // 6. Ld/St access to picm are not word aligned or word size
if (pt.DCCM_REGION == pt.PIC_REGION) begin
if (pt.DCCM_ENABLE & (pt.DCCM_REGION == pt.PIC_REGION)) begin
assign unmapped_access_fault_d = ((start_addr_in_dccm_region_d & ~(start_addr_in_dccm_d | start_addr_in_pic_d)) | // 0. Addr in dccm/pic region but not in dccm/pic offset
(end_addr_in_dccm_region_d & ~(end_addr_in_dccm_d | end_addr_in_pic_d)) | // 0. Addr in dccm/pic region but not in dccm/pic offset
(start_addr_in_dccm_d & end_addr_in_pic_d) | // 0. DCCM -> PIC cross when DCCM/PIC in same region

View File

@ -1,5 +1,5 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 Western Digital Corporation or it's affiliates.
// Copyright 2020 Western Digital Corporation or its affiliates.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -28,15 +28,18 @@ import el2_pkg::*;
#(
`include "el2_param.vh"
)(
input logic clk,
input logic rst_l,
input logic scan_mode,
input logic clk, // Clock only while core active. Through one clock header. For flops with second clock header built in. Connected to ACTIVE_L2CLK.
input logic clk_override, // Override non-functional clock gating
input logic rst_l, // reset, active low
input logic scan_mode, // scan mode
input logic dec_tlu_external_ldfwd_disable, // disable load to load forwarding for externals
input logic dec_tlu_wb_coalescing_disable, // disable write buffer coalescing
input logic dec_tlu_sideeffect_posted_disable, // Don't block the sideeffect load store to the bus
input logic dec_tlu_force_halt,
// various clocks needed for the bus reads and writes
input logic lsu_bus_obuf_c1_clken,
input logic lsu_busm_clken,
input logic lsu_c2_r_clk,
input logic lsu_bus_ibuf_c1_clk,
input logic lsu_bus_obuf_c1_clk,
@ -68,12 +71,11 @@ import el2_pkg::*;
input logic ldst_dual_m, // load/store is unaligned at 32 bit boundary
input logic ldst_dual_r, // load/store is unaligned at 32 bit boundary
input logic [7:0] ldst_byteen_ext_m,
input logic [7:0] ldst_byteen_ext_m, // HI and LO signals
output logic lsu_bus_buffer_pend_any, // bus buffer has a pending bus entry
output logic lsu_bus_buffer_full_any, // bus buffer is full
output logic lsu_bus_buffer_empty_any, // bus buffer is empty
output logic lsu_bus_idle_any, // No pending responses from the bus
output logic [3:0] ld_byte_hit_buf_lo, ld_byte_hit_buf_hi, // Byte enables for forwarding data
output logic [31:0] ld_fwddata_buf_lo, ld_fwddata_buf_hi, // load forwarding data
@ -92,7 +94,6 @@ import el2_pkg::*;
output logic [pt.LSU_NUM_NBLOAD_WIDTH-1:0] lsu_nonblock_load_data_tag, // the tag of the non block load sending the data/error
output logic [31:0] lsu_nonblock_load_data, // Data of the non block load
// PMU events
output logic lsu_pmu_bus_trxn,
output logic lsu_pmu_bus_misaligned,
@ -149,7 +150,6 @@ import el2_pkg::*;
);
// For Ld: IDLE -> WAIT -> CMD -> RESP -> DONE_PARTIAL(?) -> DONE_WAIT(?) -> DONE -> IDLE
// For St: IDLE -> WAIT -> CMD -> RESP(?) -> IDLE
typedef enum logic [2:0] {IDLE=3'b000, WAIT=3'b001, CMD=3'b010, RESP=3'b011, DONE_PARTIAL=3'b100, DONE_WAIT=3'b101, DONE=3'b110} state_t;
@ -178,7 +178,7 @@ import el2_pkg::*;
logic [31:0] lsu_nonblock_load_data_hi, lsu_nonblock_load_data_lo, lsu_nonblock_data_unalgn;
logic [1:0] lsu_nonblock_addr_offset;
logic [1:0] lsu_nonblock_sz;
logic lsu_nonblock_unsign, lsu_nonblock_dual;
logic lsu_nonblock_unsign;
logic lsu_nonblock_load_data_ready;
logic [DEPTH-1:0] CmdPtr0Dec, CmdPtr1Dec;
@ -191,10 +191,7 @@ import el2_pkg::*;
logic [3:0] buf_numvld_any, buf_numvld_wrcmd_any, buf_numvld_cmd_any, buf_numvld_pend_any;
logic any_done_wait_state;
logic bus_sideeffect_pend;
logic [7:0] bus_pend_trxn, bus_pend_trxnQ, bus_pend_trxn_ns;
logic lsu_bus_cntr_overflow;
logic bus_coalescing_disable;
logic mdbhd_en;
logic bus_addr_match_pending;
logic bus_cmd_sent, bus_cmd_ready;
@ -219,7 +216,6 @@ import el2_pkg::*;
logic [DEPTH-1:0][DEPTH_LOG2-1:0] buf_dualtag;
logic [DEPTH-1:0] buf_ldfwd;
logic [DEPTH-1:0][DEPTH_LOG2-1:0] buf_ldfwdtag;
//logic [DEPTH-1:0] buf_nb;
logic [DEPTH-1:0] buf_error;
logic [DEPTH-1:0][31:0] buf_data;
logic [DEPTH-1:0][DEPTH-1:0] buf_age, buf_age_younger;
@ -234,7 +230,6 @@ import el2_pkg::*;
logic [DEPTH-1:0] buf_dual_in;
logic [DEPTH-1:0] buf_samedw_in;
logic [DEPTH-1:0] buf_nomerge_in;
//logic [DEPTH-1:0] buf_nb_in;
logic [DEPTH-1:0] buf_sideeffect_in;
logic [DEPTH-1:0] buf_unsign_in;
logic [DEPTH-1:0][1:0] buf_sz_in;
@ -263,7 +258,6 @@ import el2_pkg::*;
logic ibuf_nomerge;
logic [DEPTH_LOG2-1:0] ibuf_tag;
logic [DEPTH_LOG2-1:0] ibuf_dualtag;
//logic ibuf_nb;
logic ibuf_sideeffect;
logic ibuf_unsign;
logic ibuf_write;
@ -313,6 +307,7 @@ import el2_pkg::*;
logic obuf_rst;
logic obuf_write_in;
logic obuf_nosend_in;
logic obuf_rdrsp_pend_en;
logic obuf_rdrsp_pend_in;
logic obuf_sideeffect_in;
logic obuf_aligned_in;
@ -338,7 +333,7 @@ import el2_pkg::*;
logic lsu_axi_rvalid_q, lsu_axi_rready_q;
logic [pt.LSU_BUS_TAG-1:0] lsu_axi_bid_q, lsu_axi_rid_q;
logic [1:0] lsu_axi_bresp_q, lsu_axi_rresp_q;
logic [DEPTH_LOG2-1:0] lsu_imprecise_error_store_tag;
logic [pt.LSU_BUS_TAG-1:0] lsu_imprecise_error_store_tag;
logic [63:0] lsu_axi_rdata_q;
//------------------------------------------------------------------------------
@ -360,7 +355,7 @@ import el2_pkg::*;
// Buffer hit logic for bus load forwarding
assign ldst_byteen_hi_m[3:0] = ldst_byteen_ext_m[7:4];
assign ldst_byteen_lo_m[3:0] = ldst_byteen_ext_m[3:0];
for (genvar i=0; i<32'(DEPTH); i++) begin
for (genvar i=0; i<DEPTH; i++) begin
assign ld_addr_hitvec_lo[i] = (lsu_addr_m[31:2] == buf_addr[i][31:2]) & buf_write[i] & (buf_state[i] != IDLE) & lsu_busreq_m;
assign ld_addr_hitvec_hi[i] = (end_addr_m[31:2] == buf_addr[i][31:2]) & buf_write[i] & (buf_state[i] != IDLE) & lsu_busreq_m;
end
@ -368,7 +363,7 @@ import el2_pkg::*;
for (genvar j=0; j<4; j++) begin
assign ld_byte_hit_buf_lo[j] = |(ld_byte_hitvecfn_lo[j]) | ld_byte_ibuf_hit_lo[j];
assign ld_byte_hit_buf_hi[j] = |(ld_byte_hitvecfn_hi[j]) | ld_byte_ibuf_hit_hi[j];
for (genvar i=0; i<32'(DEPTH); i++) begin
for (genvar i=0; i<DEPTH; i++) begin
assign ld_byte_hitvec_lo[j][i] = ld_addr_hitvec_lo[i] & buf_byteen[i][j] & ldst_byteen_lo_m[j];
assign ld_byte_hitvec_hi[j][i] = ld_addr_hitvec_hi[i] & buf_byteen[i][j] & ldst_byteen_hi_m[j];
@ -389,7 +384,7 @@ import el2_pkg::*;
always_comb begin
ld_fwddata_buf_lo[31:0] = {{8{ld_byte_ibuf_hit_lo[3]}},{8{ld_byte_ibuf_hit_lo[2]}},{8{ld_byte_ibuf_hit_lo[1]}},{8{ld_byte_ibuf_hit_lo[0]}}} & ibuf_data[31:0];
ld_fwddata_buf_hi[31:0] = {{8{ld_byte_ibuf_hit_hi[3]}},{8{ld_byte_ibuf_hit_hi[2]}},{8{ld_byte_ibuf_hit_hi[1]}},{8{ld_byte_ibuf_hit_hi[0]}}} & ibuf_data[31:0];
for (int i=0; i<32'(DEPTH); i++) begin
for (int i=0; i<DEPTH; i++) begin
ld_fwddata_buf_lo[7:0] |= {8{ld_byte_hitvecfn_lo[0][i]}} & buf_data[i][7:0];
ld_fwddata_buf_lo[15:8] |= {8{ld_byte_hitvecfn_lo[1][i]}} & buf_data[i][15:8];
ld_fwddata_buf_lo[23:16] |= {8{ld_byte_hitvecfn_lo[2][i]}} & buf_data[i][23:16];
@ -428,7 +423,7 @@ import el2_pkg::*;
assign ibuf_wr_en = lsu_busreq_r & lsu_commit_r & ~ibuf_byp;
assign ibuf_rst = (ibuf_drain_vld & ~ibuf_wr_en) | dec_tlu_force_halt;
assign ibuf_force_drain = lsu_busreq_m & ~lsu_busreq_r & ibuf_valid & (lsu_pkt_m.load | (ibuf_addr[31:2] != lsu_addr_m[31:2])); // Move the ibuf to buf if there is a non-colaescable ld/st in m but nothing in r
assign ibuf_drain_vld = ibuf_valid & (((ibuf_wr_en | (ibuf_timer == TIMER_LOG2'(TIMER_MAX))) & ~(ibuf_merge_en & ibuf_merge_in)) | ibuf_byp | ibuf_force_drain | ibuf_sideeffect | ~ibuf_write | bus_coalescing_disable);
assign ibuf_drain_vld = ibuf_valid & (((ibuf_wr_en | (ibuf_timer == TIMER_MAX)) & ~(ibuf_merge_en & ibuf_merge_in)) | ibuf_byp | ibuf_force_drain | ibuf_sideeffect | ~ibuf_write | bus_coalescing_disable);
assign ibuf_tag_in[DEPTH_LOG2-1:0] = (ibuf_merge_en & ibuf_merge_in) ? ibuf_tag[DEPTH_LOG2-1:0] : (ldst_dual_r ? WrPtr1_r : WrPtr0_r);
assign ibuf_dualtag_in[DEPTH_LOG2-1:0] = WrPtr0_r;
assign ibuf_sz_in[1:0] = {lsu_pkt_r.word, lsu_pkt_r.half};
@ -438,7 +433,7 @@ import el2_pkg::*;
assign ibuf_data_in[(8*i)+7:(8*i)] = (ibuf_merge_en & ibuf_merge_in) ? (ldst_byteen_lo_r[i] ? store_data_lo_r[(8*i)+7:(8*i)] : ibuf_data[(8*i)+7:(8*i)]) :
(ldst_dual_r ? store_data_hi_r[(8*i)+7:(8*i)] : store_data_lo_r[(8*i)+7:(8*i)]);
end
assign ibuf_timer_in = ibuf_wr_en ? '0 : (ibuf_timer < TIMER_LOG2'(TIMER_MAX)) ? (ibuf_timer + 1'b1) : ibuf_timer;
assign ibuf_timer_in = ibuf_wr_en ? '0 : (ibuf_timer < TIMER_MAX) ? (ibuf_timer + 1'b1) : ibuf_timer;
assign ibuf_merge_en = lsu_busreq_r & lsu_commit_r & lsu_pkt_r.store & ibuf_valid & ibuf_write & (lsu_addr_r[31:2] == ibuf_addr[31:2]) & ~is_sideeffects_r & ~bus_coalescing_disable;
@ -457,7 +452,6 @@ import el2_pkg::*;
rvdffs #(.WIDTH(1)) ibuf_dualff (.din(ldst_dual_r), .dout(ibuf_dual), .en(ibuf_wr_en), .clk(lsu_bus_ibuf_c1_clk), .*);
rvdffs #(.WIDTH(1)) ibuf_samedwff (.din(ldst_samedw_r), .dout(ibuf_samedw), .en(ibuf_wr_en), .clk(lsu_bus_ibuf_c1_clk), .*);
rvdffs #(.WIDTH(1)) ibuf_nomergeff (.din(no_dword_merge_r), .dout(ibuf_nomerge), .en(ibuf_wr_en), .clk(lsu_bus_ibuf_c1_clk), .*);
//rvdffs #(.WIDTH(1)) ibuf_nbff (.din(lsu_nonblock_load_valid_r), .dout(ibuf_nb), .en(ibuf_wr_en), .clk(lsu_bus_ibuf_c1_clk), .*);
rvdffs #(.WIDTH(1)) ibuf_sideeffectff (.din(is_sideeffects_r), .dout(ibuf_sideeffect), .en(ibuf_wr_en), .clk(lsu_bus_ibuf_c1_clk), .*);
rvdffs #(.WIDTH(1)) ibuf_unsignff (.din(lsu_pkt_r.unsign), .dout(ibuf_unsign), .en(ibuf_wr_en), .clk(lsu_bus_ibuf_c1_clk), .*);
rvdffs #(.WIDTH(1)) ibuf_writeff (.din(lsu_pkt_r.store), .dout(ibuf_write), .en(ibuf_wr_en), .clk(lsu_bus_ibuf_c1_clk), .*);
@ -477,16 +471,16 @@ import el2_pkg::*;
// Output buffer logic starts here
//------------------------------------------------------------------------------
assign obuf_wr_wait = (buf_numvld_wrcmd_any[3:0] == 4'b1) & (buf_numvld_cmd_any[3:0] == 4'b1) & (obuf_wr_timer != TIMER_LOG2'(TIMER_MAX)) &
assign obuf_wr_wait = (buf_numvld_wrcmd_any[3:0] == 4'b1) & (buf_numvld_cmd_any[3:0] == 4'b1) & (obuf_wr_timer != TIMER_MAX) &
~bus_coalescing_disable & ~buf_nomerge[CmdPtr0] & ~buf_sideeffect[CmdPtr0] & ~obuf_force_wr_en;
assign obuf_wr_timer_in = obuf_wr_en ? 3'b0: (((buf_numvld_cmd_any > 4'b0) & (obuf_wr_timer < TIMER_LOG2'(TIMER_MAX))) ? (obuf_wr_timer + 1'b1) : obuf_wr_timer);
assign obuf_wr_timer_in = obuf_wr_en ? 3'b0: (((buf_numvld_cmd_any > 4'b0) & (obuf_wr_timer < TIMER_MAX)) ? (obuf_wr_timer + 1'b1) : obuf_wr_timer);
assign obuf_force_wr_en = lsu_busreq_m & ~lsu_busreq_r & ~ibuf_valid & (buf_numvld_cmd_any[3:0] == 4'b1) & (lsu_addr_m[31:2] != buf_addr[CmdPtr0][31:2]); // Entry in m can't merge with entry going to obuf and there is no entry in between
assign ibuf_buf_byp = ibuf_byp & (buf_numvld_pend_any[3:0] == 4'b0) & (~lsu_pkt_r.store | no_dword_merge_r);
assign obuf_wr_en = ((ibuf_buf_byp & lsu_commit_r & ~(is_sideeffects_r & bus_sideeffect_pend)) |
((buf_state[CmdPtr0] == CMD) & found_cmdptr0 & ~buf_cmd_state_bus_en[CmdPtr0] & ~(buf_sideeffect[CmdPtr0] & bus_sideeffect_pend) &
(~(buf_dual[CmdPtr0] & buf_samedw[CmdPtr0] & ~buf_write[CmdPtr0]) | found_cmdptr1 | buf_nomerge[CmdPtr0] | obuf_force_wr_en))) &
(bus_cmd_ready | ~obuf_valid | obuf_nosend) & ~obuf_wr_wait & ~lsu_bus_cntr_overflow & ~bus_addr_match_pending & lsu_bus_clk_en;
(bus_cmd_ready | ~obuf_valid | obuf_nosend) & ~obuf_wr_wait & ~bus_addr_match_pending & lsu_bus_clk_en;
assign obuf_rst = ((bus_cmd_sent | (obuf_valid & obuf_nosend)) & ~obuf_wr_en & lsu_bus_clk_en) | dec_tlu_force_halt;
@ -505,10 +499,10 @@ import el2_pkg::*;
(obuf_sz_in[0] & ~obuf_addr_in[0]) |
(obuf_sz_in[1] & ~(|obuf_addr_in[1:0])));
assign obuf_rdrsp_pend_in = (~(obuf_wr_en & ~obuf_nosend_in) & obuf_rdrsp_pend & ~(bus_rsp_read & (bus_rsp_read_tag == obuf_rdrsp_tag))) |
((bus_cmd_sent & ~obuf_write) & ~dec_tlu_force_halt) ;
assign obuf_rdrsp_pend_in = ((~(obuf_wr_en & ~obuf_nosend_in) & obuf_rdrsp_pend & ~(bus_rsp_read & (bus_rsp_read_tag == obuf_rdrsp_tag))) | (bus_cmd_sent & ~obuf_write)) & ~dec_tlu_force_halt;
assign obuf_rdrsp_pend_en = lsu_bus_clk_en | dec_tlu_force_halt;
assign obuf_rdrsp_tag_in[pt.LSU_BUS_TAG-1:0] = (bus_cmd_sent & ~obuf_write) ? obuf_tag0[pt.LSU_BUS_TAG-1:0] : obuf_rdrsp_tag[pt.LSU_BUS_TAG-1:0];
// No ld to ld fwd for aligned & atomic64
// No ld to ld fwd for aligned
assign obuf_nosend_in = (obuf_addr_in[31:3] == obuf_addr[31:3]) & obuf_aligned_in & ~obuf_sideeffect & ~obuf_write & ~obuf_write_in & ~dec_tlu_external_ldfwd_disable &
((obuf_valid & ~obuf_nosend) | (obuf_rdrsp_pend & ~(bus_rsp_read & (bus_rsp_read_tag == obuf_rdrsp_tag))));
@ -518,7 +512,7 @@ import el2_pkg::*;
(buf_addr[CmdPtr1][2] ? {buf_byteen[CmdPtr1],4'b0} : {4'b0,buf_byteen[CmdPtr1]});
assign obuf_data0_in[63:0] = ibuf_buf_byp ? (lsu_addr_r[2] ? {store_data_lo_r[31:0],32'b0} : {32'b0,store_data_lo_r[31:0]}) :
(buf_addr[CmdPtr0][2] ? {buf_data[CmdPtr0],32'b0} : {32'b0,buf_data[CmdPtr0]});
assign obuf_data1_in[63:0] = ibuf_buf_byp ? (lsu_addr_r[2] ? {store_data_hi_r[31:0],32'b0} :{32'b0,store_data_hi_r[31:0]}) :
assign obuf_data1_in[63:0] = ibuf_buf_byp ? (end_addr_r[2] ? {store_data_hi_r[31:0],32'b0} :{32'b0,store_data_hi_r[31:0]}) :
(buf_addr[CmdPtr1][2] ? {buf_data[CmdPtr1],32'b0} : {32'b0,buf_data[CmdPtr1]});
for (genvar i=0 ;i<8; i++) begin
@ -529,28 +523,27 @@ import el2_pkg::*;
// No store obuf merging for AXI since all stores are sent non-posted. Can't track the second id right now
assign obuf_merge_en = ((CmdPtr0 != CmdPtr1) & found_cmdptr0 & found_cmdptr1 & (buf_state[CmdPtr0] == CMD) & (buf_state[CmdPtr1] == CMD) &
~buf_cmd_state_bus_en[CmdPtr0] & ~buf_sideeffect[CmdPtr0] &
((buf_write[CmdPtr0] & buf_write[CmdPtr1] & (buf_addr[CmdPtr0][31:3] == buf_addr[CmdPtr1][31:3]) & ~bus_coalescing_disable & ~pt.BUILD_AXI_NATIVE) |
(~buf_write[CmdPtr0] & buf_dual[CmdPtr0] & ~buf_dualhi[CmdPtr0] & buf_samedw[CmdPtr0]))) | // CmdPtr0/CmdPtr1 are for same load which is within a DW
(~buf_write[CmdPtr0] & buf_dual[CmdPtr0] & ~buf_dualhi[CmdPtr0] & buf_samedw[CmdPtr0])) | // CmdPtr0/CmdPtr1 are for same load which is within a DW
(ibuf_buf_byp & ldst_samedw_r & ldst_dual_r);
rvdff #(.WIDTH(1)) obuf_wren_ff (.din(obuf_wr_en), .dout(obuf_wr_enQ), .clk(lsu_busm_clk), .*);
rvdff_fpga #(.WIDTH(1)) obuf_wren_ff (.din(obuf_wr_en), .dout(obuf_wr_enQ), .clk(lsu_busm_clk), .clken(lsu_busm_clken), .rawclk(clk), .*);
rvdffsc #(.WIDTH(1)) obuf_valid_ff (.din(1'b1), .dout(obuf_valid), .en(obuf_wr_en), .clear(obuf_rst), .clk(lsu_free_c2_clk), .*);
rvdffs #(.WIDTH(1)) obuf_nosend_ff (.din(obuf_nosend_in), .dout(obuf_nosend), .en(obuf_wr_en), .clk(lsu_free_c2_clk), .*);
rvdff #(.WIDTH(1)) obuf_cmd_done_ff (.din(obuf_cmd_done_in), .dout(obuf_cmd_done), .clk(lsu_busm_clk), .*);
rvdff #(.WIDTH(1)) obuf_data_done_ff (.din(obuf_data_done_in), .dout(obuf_data_done), .clk(lsu_busm_clk), .*);
rvdff #(.WIDTH(1)) obuf_rdrsp_pend_ff(.din(obuf_rdrsp_pend_in), .dout(obuf_rdrsp_pend), .clk(lsu_busm_clk), .*);
rvdff #(.WIDTH(pt.LSU_BUS_TAG)) obuf_rdrsp_tagff (.din(obuf_rdrsp_tag_in), .dout(obuf_rdrsp_tag), .clk(lsu_busm_clk), .*);
rvdffs #(.WIDTH(pt.LSU_BUS_TAG)) obuf_tag0ff (.din(obuf_tag0_in), .dout(obuf_tag0), .en(obuf_wr_en), .clk(lsu_bus_obuf_c1_clk), .*);
rvdffs #(.WIDTH(pt.LSU_BUS_TAG)) obuf_tag1ff (.din(obuf_tag1_in), .dout(obuf_tag1), .en(obuf_wr_en), .clk(lsu_bus_obuf_c1_clk), .*);
rvdffs #(.WIDTH(1)) obuf_mergeff (.din(obuf_merge_in), .dout(obuf_merge), .en(obuf_wr_en), .clk(lsu_bus_obuf_c1_clk), .*);
rvdffs #(.WIDTH(1)) obuf_writeff (.din(obuf_write_in), .dout(obuf_write), .en(obuf_wr_en), .clk(lsu_bus_obuf_c1_clk), .*);
rvdffs #(.WIDTH(1)) obuf_sideeffectff (.din(obuf_sideeffect_in), .dout(obuf_sideeffect), .en(obuf_wr_en), .clk(lsu_bus_obuf_c1_clk), .*);
rvdffs #(.WIDTH(2)) obuf_szff (.din(obuf_sz_in[1:0]), .dout(obuf_sz), .en(obuf_wr_en), .clk(lsu_bus_obuf_c1_clk), .*);
rvdffs #(.WIDTH(1)) obuf_rdrsp_pend_ff(.din(obuf_rdrsp_pend_in), .dout(obuf_rdrsp_pend), .en(obuf_rdrsp_pend_en), .clk(lsu_free_c2_clk), .*);
rvdff_fpga #(.WIDTH(1)) obuf_cmd_done_ff (.din(obuf_cmd_done_in), .dout(obuf_cmd_done), .clk(lsu_busm_clk), .clken(lsu_busm_clken), .rawclk(clk), .*);
rvdff_fpga #(.WIDTH(1)) obuf_data_done_ff (.din(obuf_data_done_in), .dout(obuf_data_done), .clk(lsu_busm_clk), .clken(lsu_busm_clken), .rawclk(clk), .*);
rvdff_fpga #(.WIDTH(pt.LSU_BUS_TAG)) obuf_rdrsp_tagff (.din(obuf_rdrsp_tag_in), .dout(obuf_rdrsp_tag), .clk(lsu_busm_clk), .clken(lsu_busm_clken), .rawclk(clk), .*);
rvdffs_fpga #(.WIDTH(pt.LSU_BUS_TAG)) obuf_tag0ff (.din(obuf_tag0_in), .dout(obuf_tag0), .en(obuf_wr_en), .clk(lsu_bus_obuf_c1_clk), .clken(lsu_bus_obuf_c1_clken), .rawclk(clk), .*);
rvdffs_fpga #(.WIDTH(pt.LSU_BUS_TAG)) obuf_tag1ff (.din(obuf_tag1_in), .dout(obuf_tag1), .en(obuf_wr_en), .clk(lsu_bus_obuf_c1_clk), .clken(lsu_bus_obuf_c1_clken), .rawclk(clk), .*);
rvdffs_fpga #(.WIDTH(1)) obuf_mergeff (.din(obuf_merge_in), .dout(obuf_merge), .en(obuf_wr_en), .clk(lsu_bus_obuf_c1_clk), .clken(lsu_bus_obuf_c1_clken), .rawclk(clk), .*);
rvdffs_fpga #(.WIDTH(1)) obuf_writeff (.din(obuf_write_in), .dout(obuf_write), .en(obuf_wr_en), .clk(lsu_bus_obuf_c1_clk), .clken(lsu_bus_obuf_c1_clken), .rawclk(clk), .*);
rvdffs_fpga #(.WIDTH(1)) obuf_sideeffectff (.din(obuf_sideeffect_in), .dout(obuf_sideeffect), .en(obuf_wr_en), .clk(lsu_bus_obuf_c1_clk), .clken(lsu_bus_obuf_c1_clken), .rawclk(clk), .*);
rvdffs_fpga #(.WIDTH(2)) obuf_szff (.din(obuf_sz_in[1:0]), .dout(obuf_sz), .en(obuf_wr_en), .clk(lsu_bus_obuf_c1_clk), .clken(lsu_bus_obuf_c1_clken), .rawclk(clk), .*);
rvdffs_fpga #(.WIDTH(8)) obuf_byteenff (.din(obuf_byteen_in[7:0]), .dout(obuf_byteen), .en(obuf_wr_en), .clk(lsu_bus_obuf_c1_clk), .clken(lsu_bus_obuf_c1_clken), .rawclk(clk), .*);
rvdffe #(.WIDTH(32)) obuf_addrff (.din(obuf_addr_in[31:0]), .dout(obuf_addr), .en(obuf_wr_en), .*);
rvdffs #(.WIDTH(8)) obuf_byteenff (.din(obuf_byteen_in[7:0]), .dout(obuf_byteen), .en(obuf_wr_en), .clk(lsu_bus_obuf_c1_clk), .*);
rvdffe #(.WIDTH(64)) obuf_dataff (.din(obuf_data_in[63:0]), .dout(obuf_data), .en(obuf_wr_en), .*);
rvdff #(.WIDTH(TIMER_LOG2)) obuf_timerff (.din(obuf_wr_timer_in), .dout(obuf_wr_timer), .clk(lsu_busm_clk), .*);
rvdff_fpga #(.WIDTH(TIMER_LOG2)) obuf_timerff (.din(obuf_wr_timer_in), .dout(obuf_wr_timer), .clk(lsu_busm_clk), .clken(lsu_busm_clken), .rawclk(clk), .*);
//------------------------------------------------------------------------------
@ -565,27 +558,27 @@ import el2_pkg::*;
found_wrptr1 = '0;
// Find first write pointer
for (int i=0; i<32'(DEPTH); i++) begin
for (int i=0; i<DEPTH; i++) begin
if (~found_wrptr0) begin
WrPtr0_m[DEPTH_LOG2-1:0] = DEPTH_LOG2'(i);
found_wrptr0 = (buf_state[i] == IDLE) & ~((ibuf_valid & (32'(ibuf_tag) == i)) |
(lsu_busreq_r & ((32'(WrPtr0_r) == i) | (ldst_dual_r & (32'(WrPtr1_r) == i)))));
found_wrptr0 = (buf_state[i] == IDLE) & ~((ibuf_valid & (ibuf_tag == i)) |
(lsu_busreq_r & ((WrPtr0_r == i) | (ldst_dual_r & (WrPtr1_r == i)))));
end
end
// Find second write pointer
for (int i=0; i<32'(DEPTH); i++) begin
for (int i=0; i<DEPTH; i++) begin
if (~found_wrptr1) begin
WrPtr1_m[DEPTH_LOG2-1:0] = DEPTH_LOG2'(i);
found_wrptr1 = (buf_state[i] == IDLE) & ~((ibuf_valid & (32'(ibuf_tag) == i)) |
(lsu_busreq_m & (32'(WrPtr0_m) == i)) |
(lsu_busreq_r & ((32'(WrPtr0_r) == i) | (ldst_dual_r & (32'(WrPtr1_r) == i)))));
found_wrptr1 = (buf_state[i] == IDLE) & ~((ibuf_valid & (ibuf_tag == i)) |
(lsu_busreq_m & (WrPtr0_m == i)) |
(lsu_busreq_r & ((WrPtr0_r == i) | (ldst_dual_r & (WrPtr1_r == i)))));
end
end
end
// Get the command ptr
for (genvar i=0; i<32'(DEPTH); i++) begin
for (genvar i=0; i<DEPTH; i++) begin
// These should be one-hot
assign CmdPtr0Dec[i] = ~(|buf_age[i]) & (buf_state[i] == CMD) & ~buf_cmd_state_bus_en[i];
assign CmdPtr1Dec[i] = ~(|(buf_age[i] & ~CmdPtr0Dec)) & ~CmdPtr0Dec[i] & (buf_state[i] == CMD) & ~buf_cmd_state_bus_en[i];
@ -594,14 +587,13 @@ import el2_pkg::*;
assign found_cmdptr0 = |CmdPtr0Dec;
assign found_cmdptr1 = |CmdPtr1Dec;
assign CmdPtr0 = f_Enc8to3(8'(CmdPtr0Dec[DEPTH-1:0]));
assign CmdPtr1 = f_Enc8to3(8'(CmdPtr1Dec[DEPTH-1:0]));
assign RspPtr = f_Enc8to3(8'(RspPtrDec[DEPTH-1:0]));
// Age vector
for (genvar i=0; i<32'(DEPTH); i++) begin: GenAgeVec
for (genvar j=0; j<32'(DEPTH); j++) begin
for (genvar i=0; i<DEPTH; i++) begin: GenAgeVec
for (genvar j=0; j<DEPTH; j++) begin
assign buf_age_in[i][j] = (((buf_state[i] == IDLE) & buf_state_en[i]) &
(((buf_state[j] == WAIT) | ((buf_state[j] == CMD) & ~buf_cmd_state_bus_en[j])) | // Set age bit for older entries
(ibuf_drain_vld & lsu_busreq_r & (ibuf_byp | ldst_dual_r) & (i == WrPtr0_r) & (j == ibuf_tag)) | // Set case for dual lo
@ -609,7 +601,7 @@ import el2_pkg::*;
buf_age[i][j];
assign buf_age[i][j] = buf_ageQ[i][j] & ~((buf_state[j] == CMD) & buf_cmd_state_bus_en[j]); // Reset case
assign buf_age[i][j] = buf_ageQ[i][j] & ~((buf_state[j] == CMD) & buf_cmd_state_bus_en[j]) & ~dec_tlu_force_halt; // Reset case
assign buf_age_younger[i][j] = (i == j) ? 1'b0: (~buf_age[i][j] & (buf_state[j] != IDLE)); // Younger entries
end
@ -623,7 +615,7 @@ import el2_pkg::*;
(ibuf_drain_vld & lsu_busreq_r & (ibuf_byp | ldst_dual_r) & (DEPTH_LOG2'(i) == WrPtr0_r) & (DEPTH_LOG2'(j) == ibuf_tag)) | // Set case for dual lo
(ibuf_byp & lsu_busreq_r & ldst_dual_r & (DEPTH_LOG2'(i) == WrPtr1_r) & (DEPTH_LOG2'(j) == WrPtr0_r)));
assign buf_rspage_in[i][j] = buf_rspage_set[i][j] | buf_rspage[i][j];
assign buf_rspage[i][j] = buf_rspageQ[i][j] & ~((buf_state[j] == DONE) | (buf_state[j] == IDLE)); // Reset case
assign buf_rspage[i][j] = buf_rspageQ[i][j] & ~((buf_state[j] == DONE) | (buf_state[j] == IDLE)) & ~dec_tlu_force_halt; // Reset case
assign buf_rsp_pickage[i][j] = buf_rspageQ[i][j] & (buf_state[j] == DONE_WAIT);
end
end
@ -631,7 +623,7 @@ import el2_pkg::*;
//------------------------------------------------------------------------------
// Buffer logic
//------------------------------------------------------------------------------
for (genvar i=0; i<32'(DEPTH); i++) begin
for (genvar i=0; i<DEPTH; i++) begin
assign ibuf_drainvec_vld[i] = (ibuf_drain_vld & (i == ibuf_tag));
assign buf_byteen_in[i] = ibuf_drainvec_vld[i] ? ibuf_byteen_out[3:0] : ((ibuf_byp & ldst_dual_r & (i == WrPtr1_r)) ? ldst_byteen_hi_r[3:0] : ldst_byteen_lo_r[3:0]);
@ -641,7 +633,6 @@ import el2_pkg::*;
assign buf_nomerge_in[i] = ibuf_drainvec_vld[i] ? (ibuf_nomerge | ibuf_force_drain) : no_dword_merge_r;
assign buf_dualhi_in[i] = ibuf_drainvec_vld[i] ? ibuf_dual : (ibuf_byp & ldst_dual_r & (i == WrPtr1_r)); // If it's dual, ibuf will always have the high
assign buf_dualtag_in[i] = ibuf_drainvec_vld[i] ? ibuf_dualtag : ((ibuf_byp & ldst_dual_r & (i == WrPtr1_r)) ? WrPtr0_r : WrPtr1_r);
//assign buf_nb_in[i] = ibuf_drainvec_vld[i] ? ibuf_nb : lsu_nonblock_load_valid_r;
assign buf_sideeffect_in[i] = ibuf_drainvec_vld[i] ? ibuf_sideeffect : is_sideeffects_r;
assign buf_unsign_in[i] = ibuf_drainvec_vld[i] ? ibuf_unsign : lsu_pkt_r.unsign;
assign buf_sz_in[i] = ibuf_drainvec_vld[i] ? ibuf_sz : {lsu_pkt_r.word, lsu_pkt_r.half};
@ -651,15 +642,14 @@ import el2_pkg::*;
always_comb begin
buf_nxtstate[i] = IDLE;
buf_state_en[i] = '0;
buf_cmd_state_bus_en[i] = '0;
buf_resp_state_bus_en[i] = '0;
buf_state_bus_en[i] = '0;
buf_wr_en[i] = '0;
buf_data_in[i] = '0;
buf_data_en[i] = '0;
buf_error_en[i] = '0;
buf_rst[i] = '0;
buf_ldfwd_en[i] = '0;
buf_rst[i] = dec_tlu_force_halt;
buf_ldfwd_en[i] = dec_tlu_force_halt;
buf_ldfwd_in[i] = '0;
buf_ldfwdtag_in[i] = '0;
@ -671,10 +661,12 @@ import el2_pkg::*;
buf_wr_en[i] = buf_state_en[i];
buf_data_en[i] = buf_state_en[i];
buf_data_in[i] = (ibuf_drain_vld & (i == ibuf_tag)) ? ibuf_data_out[31:0] : store_data_lo_r[31:0];
buf_cmd_state_bus_en[i] = '0;
end
WAIT: begin
buf_nxtstate[i] = dec_tlu_force_halt ? IDLE : CMD;
buf_state_en[i] = lsu_bus_clk_en | dec_tlu_force_halt;
buf_cmd_state_bus_en[i] = '0;
end
CMD: begin
buf_nxtstate[i] = dec_tlu_force_halt ? IDLE : (obuf_nosend & bus_rsp_read & (bus_rsp_read_tag == obuf_rdrsp_tag)) ? DONE_WAIT : RESP;
@ -689,7 +681,7 @@ import el2_pkg::*;
buf_data_in[i] = buf_error_en[i] ? bus_rsp_rdata[31:0] : (buf_addr[i][2] ? bus_rsp_rdata[63:32] : bus_rsp_rdata[31:0]);
end
RESP: begin
buf_nxtstate[i] = (dec_tlu_force_halt | (buf_write[i] & ~(pt.BUILD_AXI_NATIVE & bus_rsp_write_error))) ? IDLE : // Side-effect writes will be non-posted
buf_nxtstate[i] = (dec_tlu_force_halt | (buf_write[i] & ~bus_rsp_write_error)) ? IDLE : // Side-effect writes will be non-posted
(buf_dual[i] & ~buf_samedw[i] & ~buf_write[i] & (buf_state[buf_dualtag[i]] != DONE_PARTIAL)) ? DONE_PARTIAL : // Goto DONE_PARTIAL if this is the first return of dual
(buf_ldfwd[i] | any_done_wait_state |
(buf_dual[i] & ~buf_samedw[i] & ~buf_write[i] & buf_ldfwd[buf_dualtag[i]] &
@ -704,19 +696,21 @@ import el2_pkg::*;
// Need to capture the error for stores as well for AXI
buf_error_en[i] = buf_state_bus_en[i] & lsu_bus_clk_en & ((bus_rsp_read_error & (bus_rsp_read_tag == (pt.LSU_BUS_TAG)'(i))) |
(bus_rsp_read_error & buf_ldfwd[i] & (bus_rsp_read_tag == (pt.LSU_BUS_TAG)'(buf_ldfwdtag[i]))) |
(bus_rsp_write_error & pt.BUILD_AXI_NATIVE & (bus_rsp_write_tag == (pt.LSU_BUS_TAG)'(i))));
(bus_rsp_write_error & (bus_rsp_write_tag == (pt.LSU_BUS_TAG)'(i))));
buf_data_in[i][31:0] = (buf_state_en[i] & ~buf_error_en[i]) ? (buf_addr[i][2] ? bus_rsp_rdata[63:32] : bus_rsp_rdata[31:0]) : bus_rsp_rdata[31:0];
buf_cmd_state_bus_en[i] = '0;
end
DONE_PARTIAL: begin // Other part of dual load hasn't returned
buf_nxtstate[i] = dec_tlu_force_halt ? IDLE : (buf_ldfwd[i] | buf_ldfwd[buf_dualtag[i]] | any_done_wait_state) ? DONE_WAIT : DONE;
buf_state_bus_en[i] = bus_rsp_read & ((bus_rsp_read_tag == (pt.LSU_BUS_TAG)'(buf_dualtag[i])) |
//(buf_ldfwd[i] & (bus_rsp_read_tag == (pt.LSU_BUS_TAG)'(buf_ldfwdtag[i]))) |
(buf_ldfwd[buf_dualtag[i]] & (bus_rsp_read_tag == (pt.LSU_BUS_TAG)'(buf_ldfwdtag[buf_dualtag[i]]))));
buf_state_en[i] = (buf_state_bus_en[i] & lsu_bus_clk_en) | dec_tlu_force_halt;
buf_cmd_state_bus_en[i] = '0;
end
DONE_WAIT: begin // WAIT state if there are multiple outstanding nb returns
buf_nxtstate[i] = dec_tlu_force_halt ? IDLE : DONE;
buf_state_en[i] = ((RspPtr == DEPTH_LOG2'(i)) | (buf_dual[i] & (buf_dualtag[i] == RspPtr))) | dec_tlu_force_halt;
buf_cmd_state_bus_en[i] = '0;
end
DONE: begin
buf_nxtstate[i] = IDLE;
@ -724,11 +718,11 @@ import el2_pkg::*;
buf_state_en[i] = 1'b1;
buf_ldfwd_in[i] = 1'b0;
buf_ldfwd_en[i] = buf_state_en[i];
buf_cmd_state_bus_en[i] = '0;
end
default : begin
buf_nxtstate[i] = IDLE;
buf_state_en[i] = '0;
buf_cmd_state_bus_en[i] = '0;
buf_resp_state_bus_en[i] = '0;
buf_state_bus_en[i] = '0;
buf_wr_en[i] = '0;
@ -736,6 +730,7 @@ import el2_pkg::*;
buf_data_en[i] = '0;
buf_error_en[i] = '0;
buf_rst[i] = '0;
buf_cmd_state_bus_en[i] = '0;
end
endcase
end
@ -750,7 +745,6 @@ import el2_pkg::*;
rvdffs #(.WIDTH(1)) buf_dualhiff (.din(buf_dualhi_in[i]), .dout(buf_dualhi[i]), .en(buf_wr_en[i]), .clk(lsu_bus_buf_c1_clk), .*);
rvdffs #(.WIDTH(1)) buf_ldfwdff (.din(buf_ldfwd_in[i]), .dout(buf_ldfwd[i]), .en(buf_ldfwd_en[i]), .clk(lsu_bus_buf_c1_clk), .*);
rvdffs #(.WIDTH(DEPTH_LOG2)) buf_ldfwdtagff (.din(buf_ldfwdtag_in[i]), .dout(buf_ldfwdtag[i]), .en(buf_ldfwd_en[i]), .clk(lsu_bus_buf_c1_clk), .*);
// rvdffs #(.WIDTH(1)) buf_nbff (.din(buf_nb_in[i]), .dout(buf_nb[i]), .en(buf_wr_en[i]), .clk(lsu_bus_buf_c1_clk), .*);
rvdffs #(.WIDTH(1)) buf_sideeffectff (.din(buf_sideeffect_in[i]), .dout(buf_sideeffect[i]), .en(buf_wr_en[i]), .clk(lsu_bus_buf_c1_clk), .*);
rvdffs #(.WIDTH(1)) buf_unsignff (.din(buf_unsign_in[i]), .dout(buf_unsign[i]), .en(buf_wr_en[i]), .clk(lsu_bus_buf_c1_clk), .*);
rvdffs #(.WIDTH(1)) buf_writeff (.din(buf_write_in[i]), .dout(buf_write[i]), .en(buf_wr_en[i]), .clk(lsu_bus_buf_c1_clk), .*);
@ -764,14 +758,14 @@ import el2_pkg::*;
// buffer full logic
always_comb begin
buf_numvld_any[3:0] = 4'(({3'b0,lsu_busreq_m} << ldst_dual_m) +
({3'b0,lsu_busreq_r} << ldst_dual_r) +
{3'b0,ibuf_valid});
buf_numvld_any[3:0] = ({1'b0,lsu_busreq_m} << ldst_dual_m) +
({1'b0,lsu_busreq_r} << ldst_dual_r) +
ibuf_valid;
buf_numvld_wrcmd_any[3:0] = 4'b0;
buf_numvld_cmd_any[3:0] = 4'b0;
buf_numvld_pend_any[3:0] = 4'b0;
any_done_wait_state = 1'b0;
for (int i=0; i<32'(DEPTH); i++) begin
for (int i=0; i<DEPTH; i++) begin
buf_numvld_any[3:0] += {3'b0, (buf_state[i] != IDLE)};
buf_numvld_wrcmd_any[3:0] += {3'b0, (buf_write[i] & (buf_state[i] == CMD) & ~buf_cmd_state_bus_en[i])};
buf_numvld_cmd_any[3:0] += {3'b0, ((buf_state[i] == CMD) & ~buf_cmd_state_bus_en[i])};
@ -781,7 +775,7 @@ import el2_pkg::*;
end
assign lsu_bus_buffer_pend_any = (buf_numvld_pend_any != 0);
assign lsu_bus_buffer_full_any = (ldst_dual_d & dec_lsu_valid_raw_d) ? (buf_numvld_any[3:0] >= (DEPTH-1)) : (buf_numvld_any[3:0] == 4'(DEPTH));
assign lsu_bus_buffer_full_any = (ldst_dual_d & dec_lsu_valid_raw_d) ? (buf_numvld_any[3:0] >= (DEPTH-1)) : (buf_numvld_any[3:0] == DEPTH);
assign lsu_bus_buffer_empty_any = ~(|buf_state[DEPTH-1:0]) & ~ibuf_valid & ~obuf_valid;
@ -797,9 +791,9 @@ import el2_pkg::*;
lsu_nonblock_load_data_tag[DEPTH_LOG2-1:0] = '0;
lsu_nonblock_load_data_lo[31:0] = '0;
lsu_nonblock_load_data_hi[31:0] = '0;
for (int i=0; i<32'(DEPTH); i++) begin
for (int i=0; i<DEPTH; i++) begin
// Use buf_rst[i] instead of buf_state_en[i] for timing
lsu_nonblock_load_data_ready |= (buf_state[i] == DONE) & ~(pt.BUILD_AXI_NATIVE & buf_write[i]);
lsu_nonblock_load_data_ready |= (buf_state[i] == DONE) & ~buf_write[i];
lsu_nonblock_load_data_error |= (buf_state[i] == DONE) & buf_error[i] & ~buf_write[i];
lsu_nonblock_load_data_tag[DEPTH_LOG2-1:0] |= DEPTH_LOG2'(i) & {DEPTH_LOG2{((buf_state[i] == DONE) & ~buf_write[i] & (~buf_dual[i] | ~buf_dualhi[i]))}};
lsu_nonblock_load_data_lo[31:0] |= buf_data[i][31:0] & {32{((buf_state[i] == DONE) & ~buf_write[i] & (~buf_dual[i] | ~buf_dualhi[i]))}};
@ -810,7 +804,6 @@ import el2_pkg::*;
assign lsu_nonblock_addr_offset[1:0] = buf_addr[lsu_nonblock_load_data_tag][1:0];
assign lsu_nonblock_sz[1:0] = buf_sz[lsu_nonblock_load_data_tag][1:0];
assign lsu_nonblock_unsign = buf_unsign[lsu_nonblock_load_data_tag];
assign lsu_nonblock_dual = buf_dual[lsu_nonblock_load_data_tag];
assign lsu_nonblock_data_unalgn[31:0] = 32'({lsu_nonblock_load_data_hi[31:0], lsu_nonblock_load_data_lo[31:0]} >> 8*lsu_nonblock_addr_offset[1:0]);
assign lsu_nonblock_load_data_valid = lsu_nonblock_load_data_ready & ~lsu_nonblock_load_data_error;
@ -823,7 +816,7 @@ import el2_pkg::*;
// Determine if there is a pending return to sideeffect load/store
always_comb begin
bus_sideeffect_pend = obuf_valid & obuf_sideeffect & dec_tlu_sideeffect_posted_disable;
for (int i=0; i<32'(DEPTH); i++) begin
for (int i=0; i<DEPTH; i++) begin
bus_sideeffect_pend |= ((buf_state[i] == RESP) & buf_sideeffect[i] & dec_tlu_sideeffect_posted_disable);
end
end
@ -831,8 +824,8 @@ import el2_pkg::*;
// We have no ordering rules for AXI. Need to check outstanding trxns to same address for AXI
always_comb begin
bus_addr_match_pending = '0;
for (int i=0; i<32'(DEPTH); i++) begin
bus_addr_match_pending |= (pt.BUILD_AXI_NATIVE & obuf_valid & (obuf_addr[31:3] == buf_addr[i][31:3]) & (buf_state[i] == RESP) & ~((obuf_tag0 == (pt.LSU_BUS_TAG)'(i)) | (obuf_merge & (obuf_tag1 == (pt.LSU_BUS_TAG)'(i)))));
for (int i=0; i<DEPTH; i++) begin
bus_addr_match_pending |= (obuf_valid & (obuf_addr[31:3] == buf_addr[i][31:3]) & (buf_state[i] == RESP) & ~((obuf_tag0 == (pt.LSU_BUS_TAG)'(i)) | (obuf_merge & (obuf_tag1 == (pt.LSU_BUS_TAG)'(i)))));
end
end
@ -855,7 +848,7 @@ import el2_pkg::*;
assign lsu_axi_awid[pt.LSU_BUS_TAG-1:0] = (pt.LSU_BUS_TAG)'(obuf_tag0);
assign lsu_axi_awaddr[31:0] = obuf_sideeffect ? obuf_addr[31:0] : {obuf_addr[31:3],3'b0};
assign lsu_axi_awsize[2:0] = obuf_sideeffect ? {1'b0, obuf_sz[1:0]} : 3'b011;
assign lsu_axi_awprot[2:0] = '0;
assign lsu_axi_awprot[2:0] = 3'b001;
assign lsu_axi_awcache[3:0] = obuf_sideeffect ? 4'b0 : 4'b1111;
assign lsu_axi_awregion[3:0] = obuf_addr[31:28];
assign lsu_axi_awlen[7:0] = '0;
@ -872,7 +865,7 @@ import el2_pkg::*;
assign lsu_axi_arid[pt.LSU_BUS_TAG-1:0] = (pt.LSU_BUS_TAG)'(obuf_tag0);
assign lsu_axi_araddr[31:0] = obuf_sideeffect ? obuf_addr[31:0] : {obuf_addr[31:3],3'b0};
assign lsu_axi_arsize[2:0] = obuf_sideeffect ? {1'b0, obuf_sz[1:0]} : 3'b011;
assign lsu_axi_arprot[2:0] = '0;
assign lsu_axi_arprot[2:0] = 3'b001;
assign lsu_axi_arcache[3:0] = obuf_sideeffect ? 4'b0 : 4'b1111;
assign lsu_axi_arregion[3:0] = obuf_addr[31:28];
assign lsu_axi_arlen[7:0] = '0;
@ -886,7 +879,7 @@ import el2_pkg::*;
always_comb begin
lsu_imprecise_error_store_any = '0;
lsu_imprecise_error_store_tag = '0;
for (int i=0; i<32'(DEPTH); i++) begin
for (int i=0; i<DEPTH; i++) begin
lsu_imprecise_error_store_any |= lsu_bus_clk_en_q & (buf_state[i] == DONE) & buf_error[i] & buf_write[i];
lsu_imprecise_error_store_tag |= DEPTH_LOG2'(i) & {DEPTH_LOG2{((buf_state[i] == DONE) & buf_error[i] & buf_write[i])}};
end
@ -894,36 +887,29 @@ import el2_pkg::*;
assign lsu_imprecise_error_load_any = lsu_nonblock_load_data_error & ~lsu_imprecise_error_store_any; // This is to make sure we send only one imprecise error for load/store
assign lsu_imprecise_error_addr_any[31:0] = lsu_imprecise_error_store_any ? buf_addr[lsu_imprecise_error_store_tag] : buf_addr[lsu_nonblock_load_data_tag];
// Count the number of pending trxns for fence (doesn't apply to AXI)
assign bus_pend_trxnQ[7:0] = 8'b0;
assign bus_pend_trxn[7:0] = 8'b0;
assign bus_pend_trxn_ns[7:0] = 8'b0;
assign lsu_bus_cntr_overflow = 1'b0;
assign lsu_bus_idle_any = 1'b1;
// PMU signals
assign lsu_pmu_bus_trxn = (lsu_axi_awvalid & lsu_axi_awready) | (lsu_axi_wvalid & lsu_axi_wready) | (lsu_axi_arvalid & lsu_axi_arready);
assign lsu_pmu_bus_misaligned = lsu_busreq_r & ldst_dual_r & lsu_commit_r;
assign lsu_pmu_bus_error = lsu_imprecise_error_load_any | lsu_imprecise_error_store_any;
assign lsu_pmu_bus_busy = (lsu_axi_awvalid & ~lsu_axi_awready) | (lsu_axi_wvalid & ~lsu_axi_wready) | (lsu_axi_arvalid & ~lsu_axi_arready);
rvdff #(.WIDTH(1)) lsu_axi_awvalid_ff (.din(lsu_axi_awvalid), .dout(lsu_axi_awvalid_q), .clk(lsu_busm_clk), .*);
rvdff #(.WIDTH(1)) lsu_axi_awready_ff (.din(lsu_axi_awready), .dout(lsu_axi_awready_q), .clk(lsu_busm_clk), .*);
rvdff #(.WIDTH(1)) lsu_axi_wvalid_ff (.din(lsu_axi_wvalid), .dout(lsu_axi_wvalid_q), .clk(lsu_busm_clk), .*);
rvdff #(.WIDTH(1)) lsu_axi_wready_ff (.din(lsu_axi_wready), .dout(lsu_axi_wready_q), .clk(lsu_busm_clk), .*);
rvdff #(.WIDTH(1)) lsu_axi_arvalid_ff (.din(lsu_axi_arvalid), .dout(lsu_axi_arvalid_q), .clk(lsu_busm_clk), .*);
rvdff #(.WIDTH(1)) lsu_axi_arready_ff (.din(lsu_axi_arready), .dout(lsu_axi_arready_q), .clk(lsu_busm_clk), .*);
rvdff_fpga #(.WIDTH(1)) lsu_axi_awvalid_ff (.din(lsu_axi_awvalid), .dout(lsu_axi_awvalid_q), .clk(lsu_busm_clk), .clken(lsu_busm_clken), .rawclk(clk), .*);
rvdff_fpga #(.WIDTH(1)) lsu_axi_awready_ff (.din(lsu_axi_awready), .dout(lsu_axi_awready_q), .clk(lsu_busm_clk), .clken(lsu_busm_clken), .rawclk(clk), .*);
rvdff_fpga #(.WIDTH(1)) lsu_axi_wvalid_ff (.din(lsu_axi_wvalid), .dout(lsu_axi_wvalid_q), .clk(lsu_busm_clk), .clken(lsu_busm_clken), .rawclk(clk), .*);
rvdff_fpga #(.WIDTH(1)) lsu_axi_wready_ff (.din(lsu_axi_wready), .dout(lsu_axi_wready_q), .clk(lsu_busm_clk), .clken(lsu_busm_clken), .rawclk(clk), .*);
rvdff_fpga #(.WIDTH(1)) lsu_axi_arvalid_ff (.din(lsu_axi_arvalid), .dout(lsu_axi_arvalid_q), .clk(lsu_busm_clk), .clken(lsu_busm_clken), .rawclk(clk), .*);
rvdff_fpga #(.WIDTH(1)) lsu_axi_arready_ff (.din(lsu_axi_arready), .dout(lsu_axi_arready_q), .clk(lsu_busm_clk), .clken(lsu_busm_clken), .rawclk(clk), .*);
rvdff #(.WIDTH(1)) lsu_axi_bvalid_ff (.din(lsu_axi_bvalid), .dout(lsu_axi_bvalid_q), .clk(lsu_busm_clk), .*);
rvdff #(.WIDTH(1)) lsu_axi_bready_ff (.din(lsu_axi_bready), .dout(lsu_axi_bready_q), .clk(lsu_busm_clk), .*);
rvdff #(.WIDTH(2)) lsu_axi_bresp_ff (.din(lsu_axi_bresp[1:0]), .dout(lsu_axi_bresp_q[1:0]), .clk(lsu_busm_clk), .*);
rvdff #(.WIDTH(pt.LSU_BUS_TAG)) lsu_axi_bid_ff (.din(lsu_axi_bid[pt.LSU_BUS_TAG-1:0]),.dout(lsu_axi_bid_q[pt.LSU_BUS_TAG-1:0]),.clk(lsu_busm_clk), .*);
rvdffe #(.WIDTH(64)) lsu_axi_rdata_ff (.din(lsu_axi_rdata[63:0]), .dout(lsu_axi_rdata_q[63:0]), .en(lsu_axi_rvalid & lsu_bus_clk_en), .*);
rvdff_fpga #(.WIDTH(1)) lsu_axi_bvalid_ff (.din(lsu_axi_bvalid), .dout(lsu_axi_bvalid_q), .clk(lsu_busm_clk), .clken(lsu_busm_clken), .rawclk(clk), .*);
rvdff_fpga #(.WIDTH(1)) lsu_axi_bready_ff (.din(lsu_axi_bready), .dout(lsu_axi_bready_q), .clk(lsu_busm_clk), .clken(lsu_busm_clken), .rawclk(clk), .*);
rvdff_fpga #(.WIDTH(2)) lsu_axi_bresp_ff (.din(lsu_axi_bresp[1:0]), .dout(lsu_axi_bresp_q[1:0]), .clk(lsu_busm_clk), .clken(lsu_busm_clken), .rawclk(clk), .*);
rvdff_fpga #(.WIDTH(pt.LSU_BUS_TAG)) lsu_axi_bid_ff (.din(lsu_axi_bid[pt.LSU_BUS_TAG-1:0]),.dout(lsu_axi_bid_q[pt.LSU_BUS_TAG-1:0]),.clk(lsu_busm_clk), .clken(lsu_busm_clken), .rawclk(clk), .*);
rvdffe #(.WIDTH(64)) lsu_axi_rdata_ff (.din(lsu_axi_rdata[63:0]), .dout(lsu_axi_rdata_q[63:0]), .en((lsu_axi_rvalid | clk_override) & lsu_bus_clk_en), .*);
rvdff #(.WIDTH(1)) lsu_axi_rvalid_ff (.din(lsu_axi_rvalid), .dout(lsu_axi_rvalid_q), .clk(lsu_busm_clk), .*);
rvdff #(.WIDTH(1)) lsu_axi_rready_ff (.din(lsu_axi_rready), .dout(lsu_axi_rready_q), .clk(lsu_busm_clk), .*);
rvdff #(.WIDTH(2)) lsu_axi_rresp_ff (.din(lsu_axi_rresp[1:0]), .dout(lsu_axi_rresp_q[1:0]), .clk(lsu_busm_clk), .*);
rvdff #(.WIDTH(pt.LSU_BUS_TAG)) lsu_axi_rid_ff (.din(lsu_axi_rid[pt.LSU_BUS_TAG-1:0]),.dout(lsu_axi_rid_q[pt.LSU_BUS_TAG-1:0]),.clk(lsu_busm_clk), .*);
rvdff_fpga #(.WIDTH(1)) lsu_axi_rvalid_ff (.din(lsu_axi_rvalid), .dout(lsu_axi_rvalid_q), .clk(lsu_busm_clk), .clken(lsu_busm_clken), .rawclk(clk), .*);
rvdff_fpga #(.WIDTH(1)) lsu_axi_rready_ff (.din(lsu_axi_rready), .dout(lsu_axi_rready_q), .clk(lsu_busm_clk), .clken(lsu_busm_clken), .rawclk(clk), .*);
rvdff_fpga #(.WIDTH(2)) lsu_axi_rresp_ff (.din(lsu_axi_rresp[1:0]), .dout(lsu_axi_rresp_q[1:0]), .clk(lsu_busm_clk), .clken(lsu_busm_clken), .rawclk(clk), .*);
rvdff_fpga #(.WIDTH(pt.LSU_BUS_TAG)) lsu_axi_rid_ff (.din(lsu_axi_rid[pt.LSU_BUS_TAG-1:0]),.dout(lsu_axi_rid_q[pt.LSU_BUS_TAG-1:0]),.clk(lsu_busm_clk), .clken(lsu_busm_clken), .rawclk(clk), .*);
rvdff #(.WIDTH(DEPTH_LOG2)) lsu_WrPtr0_rff (.din(WrPtr0_m), .dout(WrPtr0_r), .clk(lsu_c2_r_clk), .*);
rvdff #(.WIDTH(DEPTH_LOG2)) lsu_WrPtr1_rff (.din(WrPtr1_m), .dout(WrPtr1_r), .clk(lsu_c2_r_clk), .*);
@ -931,15 +917,19 @@ import el2_pkg::*;
rvdff #(.WIDTH(1)) lsu_busreq_rff (.din(lsu_busreq_m & ~flush_r & ~ld_full_hit_m), .dout(lsu_busreq_r), .clk(lsu_c2_r_clk), .*);
rvdff #(.WIDTH(1)) lsu_nonblock_load_valid_rff (.din(lsu_nonblock_load_valid_m), .dout(lsu_nonblock_load_valid_r), .clk(lsu_c2_r_clk), .*);
`ifdef ASSERT_ON
`ifdef RV_ASSERT_ON
for (genvar i=0; i<4; i++) begin: GenByte
assert_ld_byte_hitvecfn_lo_onehot: assert #0 ($onehot0(ld_byte_hitvecfn_lo[i][DEPTH-1:0]));
assert_ld_byte_hitvecfn_hi_onehot: assert #0 ($onehot0(ld_byte_hitvecfn_hi[i][DEPTH-1:0]));
end
assert_CmdPtr0Dec_onehot: assert #0 ($onehot0(CmdPtr0Dec[DEPTH-1:0]));
assert_CmdPtr1Dec_onehot: assert #0 ($onehot0(CmdPtr1Dec[DEPTH-1:0]));
for (genvar i=0; i<DEPTH; i++) begin: GenAssertAge
assert_bufempty_agevec: assert #0 (~(lsu_bus_buffer_empty_any & |(buf_age[i])));
end
assert_CmdPtr0Dec_onehot: assert #0 ($onehot0(CmdPtr0Dec[DEPTH-1:0] & ~{DEPTH{dec_tlu_force_halt}}));
assert_CmdPtr1Dec_onehot: assert #0 ($onehot0(CmdPtr1Dec[DEPTH-1:0] & ~{DEPTH{dec_tlu_force_halt}}));
`endif

View File

@ -1,5 +1,5 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 Western Digital Corporation or it's affiliates.
// Copyright 2020 Western Digital Corporation or its affiliates.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -27,23 +27,26 @@ import el2_pkg::*;
#(
`include "el2_param.vh"
)(
input logic clk,
input logic rst_l,
input logic scan_mode,
input logic clk, // Clock only while core active. Through one clock header. For flops with second clock header built in. Connected to ACTIVE_L2CLK.
input logic clk_override, // Override non-functional clock gating
input logic rst_l, // reset, active low
input logic scan_mode, // scan mode
input logic dec_tlu_external_ldfwd_disable, // disable load to load forwarding for externals
input logic dec_tlu_wb_coalescing_disable, // disable write buffer coalescing
input logic dec_tlu_sideeffect_posted_disable, // disable the posted sideeffect load store to the bus
// various clocks needed for the bus reads and writes
input logic lsu_c1_m_clk,
input logic lsu_c1_r_clk,
input logic lsu_c2_r_clk,
input logic lsu_bus_ibuf_c1_clk,
input logic lsu_bus_obuf_c1_clk,
input logic lsu_bus_buf_c1_clk,
input logic lsu_free_c2_clk,
input logic free_clk,
input logic lsu_busm_clk,
input logic lsu_bus_obuf_c1_clken, // obuf clock enable
input logic lsu_busm_clken, // bus clock enable
input logic lsu_c1_r_clk, // r pipe single pulse clock
input logic lsu_c2_r_clk, // r pipe double pulse clock
input logic lsu_bus_ibuf_c1_clk, // ibuf single pulse clock
input logic lsu_bus_obuf_c1_clk, // obuf single pulse clock
input logic lsu_bus_buf_c1_clk, // buf single pulse clock
input logic lsu_free_c2_clk, // free clock double pulse clock
input logic active_clk, // Clock only while core active. Through two clock headers. For flops without second clock header built in.
input logic lsu_busm_clk, // bus clock
input logic dec_lsu_valid_raw_d, // Raw valid for address computation
input logic lsu_busreq_m, // bus request is in m
@ -51,11 +54,9 @@ import el2_pkg::*;
input el2_lsu_pkt_t lsu_pkt_m, // lsu packet flowing down the pipe
input el2_lsu_pkt_t lsu_pkt_r, // lsu packet flowing down the pipe
input logic [31:0] lsu_addr_d, // lsu address flowing down the pipe
input logic [31:0] lsu_addr_m, // lsu address flowing down the pipe
input logic [31:0] lsu_addr_r, // lsu address flowing down the pipe
input logic [31:0] end_addr_d, // lsu address flowing down the pipe
input logic [31:0] end_addr_m, // lsu address flowing down the pipe
input logic [31:0] end_addr_r, // lsu address flowing down the pipe
@ -66,12 +67,12 @@ import el2_pkg::*;
input logic is_sideeffects_m, // lsu attribute is side_effects
input logic flush_m_up, // flush
input logic flush_r, // flush
input logic ldst_dual_d, ldst_dual_m, ldst_dual_r,
output logic lsu_busreq_r, // bus request is in r
output logic lsu_bus_buffer_pend_any, // bus buffer has a pending bus entry
output logic lsu_bus_buffer_full_any, // write buffer is full
output logic lsu_bus_buffer_empty_any, // write buffer is empty
output logic lsu_bus_idle_any, // NO pending responses from the bus
output logic [31:0] bus_read_data_m, // the bus return data
@ -139,7 +140,6 @@ import el2_pkg::*;
input logic [pt.LSU_BUS_TAG-1:0] lsu_axi_rid,
input logic [63:0] lsu_axi_rdata,
input logic [1:0] lsu_axi_rresp,
input logic lsu_axi_rlast,
input logic lsu_bus_clk_en
@ -148,7 +148,6 @@ import el2_pkg::*;
logic lsu_bus_clk_en_q;
logic ldst_dual_d, ldst_dual_m, ldst_dual_r;
logic [3:0] ldst_byteen_m, ldst_byteen_r;
logic [7:0] ldst_byteen_ext_m, ldst_byteen_ext_r;
@ -185,7 +184,6 @@ import el2_pkg::*;
assign ldst_byteen_m[3:0] = ({4{lsu_pkt_m.by}} & 4'b0001) |
({4{lsu_pkt_m.half}} & 4'b0011) |
({4{lsu_pkt_m.word}} & 4'b1111);
assign ldst_dual_d = (lsu_addr_d[2] != end_addr_d[2]);
// Read/Write Buffer
el2_lsu_bus_buffer #(.pt(pt)) bus_buffer (
@ -263,15 +261,13 @@ import el2_pkg::*;
// Fifo flops
rvdff #(.WIDTH(1)) clken_ff (.din(lsu_bus_clk_en), .dout(lsu_bus_clk_en_q), .clk(free_clk), .*);
rvdff #(.WIDTH(1)) clken_ff (.din(lsu_bus_clk_en), .dout(lsu_bus_clk_en_q), .clk(active_clk), .*);
rvdff #(.WIDTH(1)) ldst_dual_mff (.din(ldst_dual_d), .dout(ldst_dual_m), .clk(lsu_c1_m_clk), .*);
rvdff #(.WIDTH(1)) ldst_dual_rff (.din(ldst_dual_m), .dout(ldst_dual_r), .clk(lsu_c1_r_clk), .*);
rvdff #(.WIDTH(1)) is_sideeffects_rff (.din(is_sideeffects_m), .dout(is_sideeffects_r), .clk(lsu_c1_r_clk), .*);
rvdff #(4) lsu_byten_rff (.*, .din(ldst_byteen_m[3:0]), .dout(ldst_byteen_r[3:0]), .clk(lsu_c1_r_clk));
`ifdef ASSERT_ON
`ifdef RV_ASSERT_ON
// Assertion to check AXI write address is aligned to size
property lsu_axi_awaddr_aligned;
@ -296,7 +292,7 @@ import el2_pkg::*;
// Assertion to check awvalid stays stable during entire bus clock
property lsu_axi_awvalid_stable;
@(posedge clk) disable iff(~rst_l) (lsu_axi_awvalid != $past(lsu_axi_awvalid)) |-> $past(lsu_bus_clk_en);
@(posedge clk) disable iff(~rst_l) (lsu_axi_awvalid != $past(lsu_axi_awvalid)) |-> ($past(lsu_bus_clk_en) | dec_tlu_force_halt);
endproperty
assert_lsu_axi_awvalid_stable: assert property (lsu_axi_awvalid_stable) else
$display("LSU AXI awvalid changed in middle of bus clock");
@ -338,7 +334,7 @@ import el2_pkg::*;
// Assertion to check awvalid stays stable during entire bus clock
property lsu_axi_arvalid_stable;
@(posedge clk) disable iff(~rst_l) (lsu_axi_arvalid != $past(lsu_axi_arvalid)) |-> $past(lsu_bus_clk_en);
@(posedge clk) disable iff(~rst_l) (lsu_axi_arvalid != $past(lsu_axi_arvalid)) |-> ($past(lsu_bus_clk_en) | dec_tlu_force_halt);
endproperty
assert_lsu_axi_arvalid_stable: assert property (lsu_axi_arvalid_stable) else
$display("LSU AXI awvalid changed in middle of bus clock");

View File

@ -1,4 +1,4 @@
// Copyright 2020 Western Digital Corporation or it's affiliates.
// Copyright 2020 Western Digital Corporation or its affiliates.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -28,13 +28,13 @@ import el2_pkg::*;
#(
`include "el2_param.vh"
)(
input logic clk, // clock
input logic free_clk, // clock
input logic rst_l, // reset
input logic clk, // Clock only while core active. Through one clock header. For flops with second clock header built in. Connected to ACTIVE_L2CLK.
input logic active_clk, // Clock only while core active. Through two clock headers. For flops without second clock header built in.
input logic rst_l, // reset, active low
input logic dec_tlu_force_halt, // This will be high till TLU goes to debug halt
// Inputs
input logic clk_override, // chciken bit to turn off clock gating
input logic addr_in_dccm_m, // address in dccm
input logic dma_dccm_req, // dma is active
input logic ldst_stbuf_reqvld_r, // allocating in to the store queue
@ -53,6 +53,9 @@ import el2_pkg::*;
input el2_lsu_pkt_t lsu_pkt_r, // lsu packet in r
// Outputs
output logic lsu_bus_obuf_c1_clken, // obuf clock enable
output logic lsu_busm_clken, // bus clock enable
output logic lsu_c1_m_clk, // m pipe single pulse clock
output logic lsu_c1_r_clk, // r pipe single pulse clock
@ -68,19 +71,19 @@ import el2_pkg::*;
output logic lsu_bus_buf_c1_clk, // ibuf clock
output logic lsu_busm_clk, // bus clock
output logic lsu_free_c2_clk,
output logic lsu_free_c2_clk, // free double pulse clock
input logic scan_mode
input logic scan_mode // Scan mode
);
logic lsu_c1_d_clken, lsu_c1_m_clken, lsu_c1_r_clken;
logic lsu_c1_m_clken, lsu_c1_r_clken;
logic lsu_c2_m_clken, lsu_c2_r_clken;
logic lsu_c1_d_clken_q, lsu_c1_m_clken_q, lsu_c1_r_clken_q;
logic lsu_c1_m_clken_q, lsu_c1_r_clken_q;
logic lsu_store_c1_m_clken, lsu_store_c1_r_clken;
logic lsu_stbuf_c1_clken;
logic lsu_bus_ibuf_c1_clken, lsu_bus_obuf_c1_clken, lsu_bus_buf_c1_clken;
logic lsu_bus_ibuf_c1_clken, lsu_bus_buf_c1_clken;
logic lsu_free_c1_clken, lsu_free_c1_clken_q, lsu_free_c2_clken;
@ -88,8 +91,7 @@ import el2_pkg::*;
// Clock Enable logic
//-------------------------------------------------------------------------------------------
assign lsu_c1_d_clken = lsu_p.valid | dma_dccm_req | clk_override;
assign lsu_c1_m_clken = lsu_pkt_d.valid | lsu_c1_d_clken_q | clk_override;
assign lsu_c1_m_clken = lsu_p.valid | dma_dccm_req | clk_override;
assign lsu_c1_r_clken = lsu_pkt_m.valid | lsu_c1_m_clken_q | clk_override;
assign lsu_c2_m_clken = lsu_c1_m_clken | lsu_c1_m_clken_q | clk_override;
@ -101,16 +103,15 @@ import el2_pkg::*;
assign lsu_stbuf_c1_clken = ldst_stbuf_reqvld_r | stbuf_reqvld_any | stbuf_reqvld_flushed_any | clk_override;
assign lsu_bus_ibuf_c1_clken = lsu_busreq_r | clk_override;
assign lsu_bus_obuf_c1_clken = (lsu_bus_buffer_pend_any | lsu_busreq_r | clk_override) & lsu_bus_clk_en;
assign lsu_bus_buf_c1_clken = ~lsu_bus_buffer_empty_any | lsu_busreq_r | clk_override;
assign lsu_bus_buf_c1_clken = ~lsu_bus_buffer_empty_any | lsu_busreq_r | dec_tlu_force_halt | clk_override;
assign lsu_free_c1_clken = (lsu_p.valid | lsu_pkt_d.valid | lsu_pkt_m.valid | lsu_pkt_r.valid) |
~lsu_bus_buffer_empty_any | ~lsu_stbuf_empty_any | clk_override;
assign lsu_free_c2_clken = lsu_free_c1_clken | lsu_free_c1_clken_q | clk_override;
// Flops
rvdff #(1) lsu_free_c1_clkenff (.din(lsu_free_c1_clken), .dout(lsu_free_c1_clken_q), .clk(free_clk), .*);
rvdff #(1) lsu_free_c1_clkenff (.din(lsu_free_c1_clken), .dout(lsu_free_c1_clken_q), .clk(active_clk), .*);
rvdff #(1) lsu_c1_d_clkenff (.din(lsu_c1_d_clken), .dout(lsu_c1_d_clken_q), .clk(lsu_free_c2_clk), .*);
rvdff #(1) lsu_c1_m_clkenff (.din(lsu_c1_m_clken), .dout(lsu_c1_m_clken_q), .clk(lsu_free_c2_clk), .*);
rvdff #(1) lsu_c1_r_clkenff (.din(lsu_c1_r_clken), .dout(lsu_c1_r_clken_q), .clk(lsu_free_c2_clk), .*);
@ -126,10 +127,17 @@ import el2_pkg::*;
rvoclkhdr lsu_stbuf_c1_cgc ( .en(lsu_stbuf_c1_clken), .l1clk(lsu_stbuf_c1_clk), .* );
rvoclkhdr lsu_bus_ibuf_c1_cgc ( .en(lsu_bus_ibuf_c1_clken), .l1clk(lsu_bus_ibuf_c1_clk), .* );
rvclkhdr lsu_bus_obuf_c1_cgc ( .en(lsu_bus_obuf_c1_clken), .l1clk(lsu_bus_obuf_c1_clk), .* );
rvoclkhdr lsu_bus_buf_c1_cgc ( .en(lsu_bus_buf_c1_clken), .l1clk(lsu_bus_buf_c1_clk), .* );
rvclkhdr lsu_busm_cgc (.en(lsu_bus_clk_en), .l1clk(lsu_busm_clk), .*);
assign lsu_busm_clken = (~lsu_bus_buffer_empty_any | lsu_busreq_r | clk_override) & lsu_bus_clk_en;
`ifdef RV_FPGA_OPTIMIZE
assign lsu_busm_clk = 1'b0;
assign lsu_bus_obuf_c1_clk = 1'b0;
`else
rvclkhdr lsu_bus_obuf_c1_cgc ( .en(lsu_bus_obuf_c1_clken), .l1clk(lsu_bus_obuf_c1_clk), .* );
rvclkhdr lsu_busm_cgc (.en(lsu_busm_clken), .l1clk(lsu_busm_clk), .*);
`endif
rvoclkhdr lsu_free_cgc (.en(lsu_free_c2_clken), .l1clk(lsu_free_c2_clk), .*);

View File

@ -1,5 +1,5 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 Western Digital Corporation or it's affiliates.
// Copyright 2020 Western Digital Corporation or its affiliates.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -34,28 +34,32 @@ import el2_pkg::*;
(
input logic lsu_c2_m_clk, // clocks
input logic lsu_c2_r_clk, // clocks
input logic lsu_c1_r_clk,
input logic lsu_store_c1_r_clk,
input logic lsu_free_c2_clk,
input logic clk,
input logic lsu_c1_r_clk, // clocks
input logic lsu_store_c1_r_clk, // clocks
input logic lsu_free_c2_clk, // clocks
input logic clk_override, // Override non-functional clock gating
input logic clk, // Clock only while core active. Through one clock header. For flops with second clock header built in. Connected to ACTIVE_L2CLK.
input logic rst_l,
input logic rst_l, // reset, active low
input el2_lsu_pkt_t lsu_pkt_r,// lsu packets
input el2_lsu_pkt_t lsu_pkt_m,// lsu packets
input el2_lsu_pkt_t lsu_pkt_d,
input el2_lsu_pkt_t lsu_pkt_d,// lsu packets
input logic addr_in_dccm_d, // address maps to dccm
input logic addr_in_pic_d, // address maps to pic
input logic addr_in_pic_m, // address maps to pic
input logic addr_in_dccm_m, addr_in_dccm_r,
input logic addr_in_pic_r,
input logic addr_in_dccm_m, addr_in_dccm_r, // address in dccm per pipe stage
input logic addr_in_pic_r, // address in pic per pipe stage
input logic lsu_raw_fwd_lo_r, lsu_raw_fwd_hi_r,
input logic lsu_commit_r,
input logic lsu_commit_r, // lsu instruction in r commits
input logic ldst_dual_m, ldst_dual_r,// load/store is unaligned at 32 bit boundary per pipe stage
input logic [31:0] lsu_addr_d, // starting byte address for loads
input logic [pt.DCCM_BITS-1:0] lsu_addr_m, // starting byte address for loads
input logic [31:0] lsu_addr_r, // starting byte address for loads
// lsu address down the pipe
input logic [31:0] lsu_addr_d,
input logic [pt.DCCM_BITS-1:0] lsu_addr_m,
input logic [31:0] lsu_addr_r,
// lsu address down the pipe - needed to check unaligned
input logic [pt.DCCM_BITS-1:0] end_addr_d,
input logic [pt.DCCM_BITS-1:0] end_addr_m,
input logic [pt.DCCM_BITS-1:0] end_addr_r,
@ -98,14 +102,14 @@ import el2_pkg::*;
input logic [pt.DCCM_DATA_WIDTH-1:0] sec_data_hi_m, // corrected dccm data
input logic [pt.DCCM_DATA_WIDTH-1:0] sec_data_lo_m, // corrected dccm data
input logic [31:0] store_data_m,
input logic dma_dccm_wen,
input logic dma_pic_wen,
input logic [2:0] dma_mem_tag_m,
input logic [31:0] dma_mem_addr, // DMA address
input logic [31:0] store_data_m, // Store data M-stage
input logic dma_dccm_wen, // Perform DMA writes only for word/dword
input logic dma_pic_wen, // Perform PIC writes
input logic [2:0] dma_mem_tag_m, // DMA Buffer entry number M-stage
input logic [31:0] dma_mem_addr, // DMA request address
input logic [63:0] dma_mem_wdata, // DMA write data
input logic [31:0] dma_dccm_wdata_lo,
input logic [31:0] dma_dccm_wdata_hi,
input logic [31:0] dma_dccm_wdata_lo, // Shift the dma data to lower bits to make it consistent to lsu stores
input logic [31:0] dma_dccm_wdata_hi, // Shift the dma data to lower bits to make it consistent to lsu stores
input logic [pt.DCCM_ECC_WIDTH-1:0] dma_dccm_wdata_ecc_hi, // ECC bits for the DMA wdata
input logic [pt.DCCM_ECC_WIDTH-1:0] dma_dccm_wdata_ecc_lo, // ECC bits for the DMA wdata
@ -183,11 +187,12 @@ import el2_pkg::*;
logic [63:0] picm_rd_data_r;
logic [63:32] lsu_ld_data_r_nc, lsu_ld_data_corr_r_nc;
logic [2:0] dma_mem_tag_r;
logic stbuf_fwddata_en;
assign dccm_dma_rvalid = lsu_pkt_r.valid & lsu_pkt_r.load & lsu_pkt_r.dma;
assign dccm_dma_ecc_error = lsu_double_ecc_error_r;
assign dccm_dma_rtag[2:0] = dma_mem_tag_r[2:0];
assign dccm_dma_rdata[63:0] = lsu_rdata_corr_r;
assign dccm_dma_rdata[63:0] = ldst_dual_r ? lsu_rdata_corr_r[63:0] : {2{lsu_rdata_corr_r[31:0]}};
assign {lsu_ld_data_r_nc[63:32], lsu_ld_data_r[31:0]} = lsu_rdata_r[63:0] >> 8*lsu_addr_r[1:0];
assign {lsu_ld_data_corr_r_nc[63:32], lsu_ld_data_corr_r[31:0]} = lsu_rdata_corr_r[63:0] >> 8*lsu_addr_r[1:0];
@ -196,21 +201,22 @@ import el2_pkg::*;
assign dccm_rdata_corr_r[63:0] = {sec_data_hi_r[31:0],sec_data_lo_r[31:0]};
assign stbuf_fwddata_r[63:0] = {stbuf_fwddata_hi_r[31:0], stbuf_fwddata_lo_r[31:0]};
assign stbuf_fwdbyteen_r[7:0] = {stbuf_fwdbyteen_hi_r[3:0], stbuf_fwdbyteen_lo_r[3:0]};
assign stbuf_fwddata_en = (|stbuf_fwdbyteen_hi_m[3:0]) | (|stbuf_fwdbyteen_lo_m[3:0]) | clk_override;
for (genvar i=0; i<8; i++) begin: GenDMAData
assign lsu_rdata_corr_r[(8*i)+7:8*i] = stbuf_fwdbyteen_r[i] ? stbuf_fwddata_r[(8*i)+7:8*i] :
(addr_in_pic_r ? picm_rd_data_r[(8*i)+7:8*i] : dccm_rdata_corr_r[(8*i)+7:8*i]);
(addr_in_pic_r ? picm_rd_data_r[(8*i)+7:8*i] : ({8{addr_in_dccm_r}} & dccm_rdata_corr_r[(8*i)+7:8*i]));
assign lsu_rdata_r[(8*i)+7:8*i] = stbuf_fwdbyteen_r[i] ? stbuf_fwddata_r[(8*i)+7:8*i] :
(addr_in_pic_r ? picm_rd_data_r[(8*i)+7:8*i] : dccm_rdata_r[(8*i)+7:8*i]);
(addr_in_pic_r ? picm_rd_data_r[(8*i)+7:8*i] : ({8{addr_in_dccm_r}} & dccm_rdata_r[(8*i)+7:8*i]));
end
rvdffe #(pt.DCCM_DATA_WIDTH) dccm_rdata_hi_r_ff (.*, .din(dccm_rdata_hi_m[pt.DCCM_DATA_WIDTH-1:0]), .dout(dccm_rdata_hi_r[pt.DCCM_DATA_WIDTH-1:0]), .en(lsu_dccm_rden_m));
rvdffe #(pt.DCCM_DATA_WIDTH) dccm_rdata_lo_r_ff (.*, .din(dccm_rdata_lo_m[pt.DCCM_DATA_WIDTH-1:0]), .dout(dccm_rdata_lo_r[pt.DCCM_DATA_WIDTH-1:0]), .en(lsu_dccm_rden_m));
rvdffe #(pt.DCCM_DATA_WIDTH) dccm_rdata_hi_r_ff (.*, .din(dccm_rdata_hi_m[pt.DCCM_DATA_WIDTH-1:0]), .dout(dccm_rdata_hi_r[pt.DCCM_DATA_WIDTH-1:0]), .en((lsu_dccm_rden_m & ldst_dual_m) | clk_override));
rvdffe #(pt.DCCM_DATA_WIDTH) dccm_rdata_lo_r_ff (.*, .din(dccm_rdata_lo_m[pt.DCCM_DATA_WIDTH-1:0]), .dout(dccm_rdata_lo_r[pt.DCCM_DATA_WIDTH-1:0]), .en(lsu_dccm_rden_m | clk_override));
rvdffe #(2*pt.DCCM_ECC_WIDTH) dccm_data_ecc_r_ff (.*, .din({dccm_data_ecc_hi_m[pt.DCCM_ECC_WIDTH-1:0], dccm_data_ecc_lo_m[pt.DCCM_ECC_WIDTH-1:0]}),
.dout({dccm_data_ecc_hi_r[pt.DCCM_ECC_WIDTH-1:0], dccm_data_ecc_lo_r[pt.DCCM_ECC_WIDTH-1:0]}), .en(lsu_dccm_rden_m));
.dout({dccm_data_ecc_hi_r[pt.DCCM_ECC_WIDTH-1:0], dccm_data_ecc_lo_r[pt.DCCM_ECC_WIDTH-1:0]}), .en(lsu_dccm_rden_m | clk_override));
rvdff #(8) stbuf_fwdbyteen_ff (.*, .din({stbuf_fwdbyteen_hi_m[3:0], stbuf_fwdbyteen_lo_m[3:0]}), .dout({stbuf_fwdbyteen_hi_r[3:0], stbuf_fwdbyteen_lo_r[3:0]}), .clk(lsu_c2_r_clk));
rvdff #(64) stbuf_fwddata_ff (.*, .din({stbuf_fwddata_hi_m[31:0], stbuf_fwddata_lo_m[31:0]}), .dout({stbuf_fwddata_hi_r[31:0], stbuf_fwddata_lo_r[31:0]}), .clk(lsu_c2_r_clk));
rvdff #(32) picm_rddata_rff (.*, .din(picm_rd_data_m[31:0]), .dout(picm_rd_data_r[31:0]), .clk(lsu_c2_r_clk));
rvdffe #(64) stbuf_fwddata_ff (.*, .din({stbuf_fwddata_hi_m[31:0], stbuf_fwddata_lo_m[31:0]}), .dout({stbuf_fwddata_hi_r[31:0], stbuf_fwddata_lo_r[31:0]}), .en(stbuf_fwddata_en));
rvdffe #(32) picm_rddata_rff (.*, .din(picm_rd_data_m[31:0]), .dout(picm_rd_data_r[31:0]), .en(addr_in_pic_m | clk_override));
rvdff #(3) dma_mem_tag_rff (.*, .din(dma_mem_tag_m[2:0]), .dout(dma_mem_tag_r[2:0]), .clk(lsu_c1_r_clk));
end else begin: L2U_Plus1_0
@ -225,7 +231,7 @@ import el2_pkg::*;
assign dccm_dma_rvalid = lsu_pkt_m.valid & lsu_pkt_m.load & lsu_pkt_m.dma;
assign dccm_dma_ecc_error = lsu_double_ecc_error_m;
assign dccm_dma_rtag[2:0] = dma_mem_tag_m[2:0];
assign dccm_dma_rdata[63:0] = lsu_rdata_corr_m;
assign dccm_dma_rdata[63:0] = ldst_dual_m ? lsu_rdata_corr_m[63:0] : {2{lsu_rdata_corr_m[31:0]}};
assign {lsu_ld_data_m_nc[63:32], lsu_ld_data_m[31:0]} = lsu_rdata_m[63:0] >> 8*lsu_addr_m[1:0];
assign {lsu_ld_data_corr_m_nc[63:32], lsu_ld_data_corr_m[31:0]} = lsu_rdata_corr_m[63:0] >> 8*lsu_addr_m[1:0];
@ -236,13 +242,13 @@ import el2_pkg::*;
for (genvar i=0; i<8; i++) begin: GenLoop
assign lsu_rdata_corr_m[(8*i)+7:8*i] = stbuf_fwdbyteen_m[i] ? stbuf_fwddata_m[(8*i)+7:8*i] :
(addr_in_pic_m ? picm_rd_data_m[(8*i)+7:8*i] : dccm_rdata_corr_m[(8*i)+7:8*i]);
(addr_in_pic_m ? picm_rd_data_m[(8*i)+7:8*i] : ({8{addr_in_dccm_m}} & dccm_rdata_corr_m[(8*i)+7:8*i]));
assign lsu_rdata_m[(8*i)+7:8*i] = stbuf_fwdbyteen_m[i] ? stbuf_fwddata_m[(8*i)+7:8*i] :
(addr_in_pic_m ? picm_rd_data_m[(8*i)+7:8*i] : dccm_rdata_m[(8*i)+7:8*i]);
(addr_in_pic_m ? picm_rd_data_m[(8*i)+7:8*i] : ({8{addr_in_dccm_m}} & dccm_rdata_m[(8*i)+7:8*i]));
end
rvdff #(32) lsu_ld_data_corr_rff(.*, .din(lsu_ld_data_corr_m[31:0]), .dout(lsu_ld_data_corr_r[31:0]), .clk(lsu_c2_r_clk));
rvdffe #(32) lsu_ld_data_corr_rff(.*, .din(lsu_ld_data_corr_m[31:0]), .dout(lsu_ld_data_corr_r[31:0]), .en((lsu_pkt_m.valid & lsu_pkt_m.load & (addr_in_pic_m | addr_in_dccm_m)) | clk_override));
end
assign kill_ecc_corr_lo_r = (((lsu_addr_d[pt.DCCM_BITS-1:2] == lsu_addr_r[pt.DCCM_BITS-1:2]) | (end_addr_d[pt.DCCM_BITS-1:2] == lsu_addr_r[pt.DCCM_BITS-1:2])) & lsu_pkt_d.valid & lsu_pkt_d.store & lsu_pkt_d.dma & addr_in_dccm_d) |
@ -330,7 +336,7 @@ import el2_pkg::*;
end
rvdff #(1) dccm_wren_ff (.*, .din(lsu_stbuf_commit_any), .dout(dccm_wren_Q), .clk(lsu_free_c2_clk)); // ECC load errors writing to dccm shouldn't fwd to stores in pipe
rvdffe #(32) dccm_wrdata_ff (.*, .din(stbuf_data_any[31:0]), .dout(dccm_wr_data_Q[31:0]), .en(lsu_stbuf_commit_any), .clk(clk));
rvdffe #(32) dccm_wrdata_ff (.*, .din(stbuf_data_any[31:0]), .dout(dccm_wr_data_Q[31:0]), .en(lsu_stbuf_commit_any | clk_override), .clk(clk));
rvdff #(1) dccm_wrbyp_dm_loff (.*, .din(dccm_wr_bypass_d_m_lo), .dout(dccm_wr_bypass_d_m_lo_Q), .clk(lsu_free_c2_clk));
rvdff #(1) dccm_wrbyp_dm_hiff (.*, .din(dccm_wr_bypass_d_m_hi), .dout(dccm_wr_bypass_d_m_hi_Q), .clk(lsu_free_c2_clk));
rvdff #(32) store_data_rff (.*, .din(store_data_m[31:0]), .dout(store_data_r[31:0]), .clk(lsu_store_c1_r_clk));
@ -356,7 +362,7 @@ import el2_pkg::*;
end
assign store_data_r[31:0] = 32'({store_data_hi_r[31:0],store_data_lo_r[31:0]} >> 8*lsu_addr_r[1:0]) & store_data_mask[31:0];
rvdff #(pt.DCCM_DATA_WIDTH) store_data_hi_rff (.*, .din(store_data_hi_r_in[pt.DCCM_DATA_WIDTH-1:0]), .dout(store_data_hi_r[pt.DCCM_DATA_WIDTH-1:0]), .clk(lsu_store_c1_r_clk));
rvdffe #(pt.DCCM_DATA_WIDTH) store_data_hi_rff (.*, .din(store_data_hi_r_in[pt.DCCM_DATA_WIDTH-1:0]), .dout(store_data_hi_r[pt.DCCM_DATA_WIDTH-1:0]), .en((ldst_dual_m & lsu_pkt_m.valid & lsu_pkt_m.store) | clk_override), .clk(clk));
rvdff #(pt.DCCM_DATA_WIDTH) store_data_lo_rff (.*, .din(store_data_lo_r_in[pt.DCCM_DATA_WIDTH-1:0]), .dout(store_data_lo_r[pt.DCCM_DATA_WIDTH-1:0]), .clk(lsu_store_c1_r_clk));
end
@ -383,10 +389,6 @@ import el2_pkg::*;
if (pt.DCCM_ENABLE == 1) begin: Gen_dccm_enable
rvdff #(1) dccm_rden_mff (.*, .din(lsu_dccm_rden_d), .dout(lsu_dccm_rden_m), .clk(lsu_c2_m_clk));
rvdff #(1) dccm_rden_rff (.*, .din(lsu_dccm_rden_m), .dout(lsu_dccm_rden_r), .clk(lsu_c2_r_clk));
end else begin: Gen_dccm_disable
assign lsu_dccm_rden_m = '0;
assign lsu_dccm_rden_r = '0;
end
// ECC correction flops since dccm write happens next cycle
// We are writing to dccm in r+1 for ecc correction since fast_int needs to be blocked in decode - 1. We can probably write in r for plus0 configuration since we know ecc error in M.
@ -394,12 +396,21 @@ import el2_pkg::*;
rvdff #(1) ld_double_ecc_error_rff (.*, .din(lsu_double_ecc_error_r), .dout(lsu_double_ecc_error_r_ff), .clk(lsu_free_c2_clk));
rvdff #(1) ld_single_ecc_error_hi_rff (.*, .din(ld_single_ecc_error_hi_r_ns), .dout(ld_single_ecc_error_hi_r_ff), .clk(lsu_free_c2_clk));
rvdff #(1) ld_single_ecc_error_lo_rff (.*, .din(ld_single_ecc_error_lo_r_ns), .dout(ld_single_ecc_error_lo_r_ff), .clk(lsu_free_c2_clk));
rvdffe #(pt.DCCM_BITS) ld_sec_addr_hi_rff (.*, .din(end_addr_r[pt.DCCM_BITS-1:0]), .dout(ld_sec_addr_hi_r_ff[pt.DCCM_BITS-1:0]), .en(ld_single_ecc_error_r), .clk(clk));
rvdffe #(pt.DCCM_BITS) ld_sec_addr_lo_rff (.*, .din(lsu_addr_r[pt.DCCM_BITS-1:0]), .dout(ld_sec_addr_lo_r_ff[pt.DCCM_BITS-1:0]), .en(ld_single_ecc_error_r), .clk(clk));
rvdffe #(pt.DCCM_BITS) ld_sec_addr_hi_rff (.*, .din(end_addr_r[pt.DCCM_BITS-1:0]), .dout(ld_sec_addr_hi_r_ff[pt.DCCM_BITS-1:0]), .en(ld_single_ecc_error_r | clk_override), .clk(clk));
rvdffe #(pt.DCCM_BITS) ld_sec_addr_lo_rff (.*, .din(lsu_addr_r[pt.DCCM_BITS-1:0]), .dout(ld_sec_addr_lo_r_ff[pt.DCCM_BITS-1:0]), .en(ld_single_ecc_error_r | clk_override), .clk(clk));
`ifdef LSU_ASSERT_ON
assert_ecc_kill_lo: assert #0 (~(ld_single_ecc_error_lo_r & kill_ecc_corr_lo_r));
assert_ecc_kill_hi: assert #0 (~(ld_single_ecc_error_hi_r & kill_ecc_corr_hi_r));
end else begin: Gen_dccm_disable
assign lsu_dccm_rden_m = '0;
assign lsu_dccm_rden_r = '0;
assign lsu_double_ecc_error_r_ff = 1'b0;
assign ld_single_ecc_error_hi_r_ff = 1'b0;
assign ld_single_ecc_error_lo_r_ff = 1'b0;
assign ld_sec_addr_hi_r_ff[pt.DCCM_BITS-1:0] = '0;
assign ld_sec_addr_lo_r_ff[pt.DCCM_BITS-1:0] = '0;
end
`ifdef RV_ASSERT_ON
// Load single ECC error correction implies commit/dma
property ld_single_ecc_error_commit;

View File

@ -1,5 +1,5 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 Western Digital Corporation or it's affiliates.
// Copyright 2020 Western Digital Corporation or its affiliates.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -27,14 +27,27 @@
// //********************************************************************************
`define EL2_LOCAL_DCCM_RAM_TEST_PORTS .TEST1(dccm_ext_in_pkt[i].TEST1), \
.RME(dccm_ext_in_pkt[i].RME), \
.RM(dccm_ext_in_pkt[i].RM), \
.LS(dccm_ext_in_pkt[i].LS), \
.DS(dccm_ext_in_pkt[i].DS), \
.SD(dccm_ext_in_pkt[i].SD), \
.TEST_RNM(dccm_ext_in_pkt[i].TEST_RNM), \
.BC1(dccm_ext_in_pkt[i].BC1), \
.BC2(dccm_ext_in_pkt[i].BC2), \
module el2_lsu_dccm_mem
import el2_pkg::*;
#(
`include "el2_param.vh"
)(
input logic clk, // clock
input logic rst_l,
input logic clk_override, // clock override
input logic clk, // Clock only while core active. Through one clock header. For flops with second clock header built in. Connected to ACTIVE_L2CLK.
input logic active_clk, // Clock only while core active. Through two clock headers. For flops without second clock header built in.
input logic rst_l, // reset, active low
input logic clk_override, // Override non-functional clock gating
input logic dccm_wren, // write enable
input logic dccm_rden, // read enable
@ -44,6 +57,7 @@ import el2_pkg::*;
input logic [pt.DCCM_BITS-1:0] dccm_rd_addr_hi, // read address for the upper bank in case of a misaligned access
input logic [pt.DCCM_FDATA_WIDTH-1:0] dccm_wr_data_lo, // write data
input logic [pt.DCCM_FDATA_WIDTH-1:0] dccm_wr_data_hi, // write data
input el2_dccm_ext_in_pkt_t [pt.DCCM_NUM_BANKS-1:0] dccm_ext_in_pkt, // the dccm packet from the soc
output logic [pt.DCCM_FDATA_WIDTH-1:0] dccm_rd_data_lo, // read data from the lo bank
output logic [pt.DCCM_FDATA_WIDTH-1:0] dccm_rd_data_hi, // read data from the hi bank
@ -78,10 +92,9 @@ import el2_pkg::*;
assign dccm_rd_data_lo[pt.DCCM_FDATA_WIDTH-1:0] = dccm_bank_dout[dccm_rd_addr_lo_q[pt.DCCM_WIDTH_BITS+:pt.DCCM_BANK_BITS]][pt.DCCM_FDATA_WIDTH-1:0];
assign dccm_rd_data_hi[pt.DCCM_FDATA_WIDTH-1:0] = dccm_bank_dout[dccm_rd_addr_hi_q[DCCM_WIDTH_BITS+:pt.DCCM_BANK_BITS]][pt.DCCM_FDATA_WIDTH-1:0];
// Generate even/odd address
// 8 Banks, 16KB each (2048 x 72)
for (genvar i=0; i<32'(pt.DCCM_NUM_BANKS); i++) begin: mem_bank
for (genvar i=0; i<pt.DCCM_NUM_BANKS; i++) begin: mem_bank
assign wren_bank[i] = dccm_wren & ((dccm_wr_addr_hi[2+:pt.DCCM_BANK_BITS] == i) | (dccm_wr_addr_lo[2+:pt.DCCM_BANK_BITS] == i));
assign rden_bank[i] = dccm_rden & ((dccm_rd_addr_hi[2+:pt.DCCM_BANK_BITS] == i) | (dccm_rd_addr_lo[2+:pt.DCCM_BANK_BITS] == i));
assign addr_bank[i][(pt.DCCM_BANK_BITS+DCCM_WIDTH_BITS)+:DCCM_INDEX_BITS] = wren_bank[i] ? (((dccm_wr_addr_hi[2+:pt.DCCM_BANK_BITS] == i) & wr_unaligned) ?
@ -98,6 +111,7 @@ import el2_pkg::*;
// end clock gating section
`ifdef VERILATOR
el2_ram #(DCCM_INDEX_DEPTH,39) ram (
// Primary ports
.ME(dccm_clken[i]),
@ -106,10 +120,13 @@ import el2_pkg::*;
.ADR(addr_bank[i]),
.D(wr_data_bank[i][pt.DCCM_FDATA_WIDTH-1:0]),
.Q(dccm_bank_dout[i][pt.DCCM_FDATA_WIDTH-1:0]),
.ROP ( ),
// These are used by SoC
`EL2_LOCAL_DCCM_RAM_TEST_PORTS
.*
);
`else
if (DCCM_INDEX_DEPTH == 32768) begin : dccm
ram_32768x39 dccm_bank (
// Primary ports
@ -119,6 +136,9 @@ import el2_pkg::*;
.ADR(addr_bank[i]),
.D(wr_data_bank[i][pt.DCCM_FDATA_WIDTH-1:0]),
.Q(dccm_bank_dout[i][pt.DCCM_FDATA_WIDTH-1:0]),
.ROP ( ),
// These are used by SoC
`EL2_LOCAL_DCCM_RAM_TEST_PORTS
.*
);
end
@ -131,6 +151,9 @@ import el2_pkg::*;
.ADR(addr_bank[i]),
.D(wr_data_bank[i][pt.DCCM_FDATA_WIDTH-1:0]),
.Q(dccm_bank_dout[i][pt.DCCM_FDATA_WIDTH-1:0]),
.ROP ( ),
// These are used by SoC
`EL2_LOCAL_DCCM_RAM_TEST_PORTS
.*
);
end
@ -143,6 +166,9 @@ import el2_pkg::*;
.ADR(addr_bank[i]),
.D(wr_data_bank[i][pt.DCCM_FDATA_WIDTH-1:0]),
.Q(dccm_bank_dout[i][pt.DCCM_FDATA_WIDTH-1:0]),
.ROP ( ),
// These are used by SoC
`EL2_LOCAL_DCCM_RAM_TEST_PORTS
.*
);
end
@ -155,6 +181,9 @@ import el2_pkg::*;
.ADR(addr_bank[i]),
.D(wr_data_bank[i][pt.DCCM_FDATA_WIDTH-1:0]),
.Q(dccm_bank_dout[i][pt.DCCM_FDATA_WIDTH-1:0]),
.ROP ( ),
// These are used by SoC
`EL2_LOCAL_DCCM_RAM_TEST_PORTS
.*
);
end
@ -167,6 +196,9 @@ import el2_pkg::*;
.ADR(addr_bank[i]),
.D(wr_data_bank[i][pt.DCCM_FDATA_WIDTH-1:0]),
.Q(dccm_bank_dout[i][pt.DCCM_FDATA_WIDTH-1:0]),
.ROP ( ),
// These are used by SoC
`EL2_LOCAL_DCCM_RAM_TEST_PORTS
.*
);
end
@ -179,6 +211,9 @@ import el2_pkg::*;
.ADR(addr_bank[i]),
.D(wr_data_bank[i][pt.DCCM_FDATA_WIDTH-1:0]),
.Q(dccm_bank_dout[i][pt.DCCM_FDATA_WIDTH-1:0]),
.ROP ( ),
// These are used by SoC
`EL2_LOCAL_DCCM_RAM_TEST_PORTS
.*
);
end
@ -191,6 +226,9 @@ import el2_pkg::*;
.ADR(addr_bank[i]),
.D(wr_data_bank[i][pt.DCCM_FDATA_WIDTH-1:0]),
.Q(dccm_bank_dout[i][pt.DCCM_FDATA_WIDTH-1:0]),
.ROP ( ),
// These are used by SoC
`EL2_LOCAL_DCCM_RAM_TEST_PORTS
.*
);
end
@ -203,6 +241,9 @@ import el2_pkg::*;
.ADR(addr_bank[i]),
.D(wr_data_bank[i][pt.DCCM_FDATA_WIDTH-1:0]),
.Q(dccm_bank_dout[i][pt.DCCM_FDATA_WIDTH-1:0]),
.ROP ( ),
// These are used by SoC
`EL2_LOCAL_DCCM_RAM_TEST_PORTS
.*
);
end
@ -215,15 +256,34 @@ import el2_pkg::*;
.ADR(addr_bank[i]),
.D(wr_data_bank[i][pt.DCCM_FDATA_WIDTH-1:0]),
.Q(dccm_bank_dout[i][pt.DCCM_FDATA_WIDTH-1:0]),
.ROP ( ),
// These are used by SoC
`EL2_LOCAL_DCCM_RAM_TEST_PORTS
.*
);
end
`endif // VERILATOR
else if (DCCM_INDEX_DEPTH == 128) begin : dccm
ram_128x39 dccm_bank (
// Primary ports
.ME(dccm_clken[i]),
.CLK(clk),
.WE(wren_bank[i]),
.ADR(addr_bank[i]),
.D(wr_data_bank[i][pt.DCCM_FDATA_WIDTH-1:0]),
.Q(dccm_bank_dout[i][pt.DCCM_FDATA_WIDTH-1:0]),
.ROP ( ),
// These are used by SoC
`EL2_LOCAL_DCCM_RAM_TEST_PORTS
.*
);
end
`endif
end : mem_bank
// Flops
rvdffs #(pt.DCCM_BANK_BITS) rd_addr_lo_ff (.*, .din(dccm_rd_addr_lo[DCCM_WIDTH_BITS+:pt.DCCM_BANK_BITS]), .dout(dccm_rd_addr_lo_q[DCCM_WIDTH_BITS+:pt.DCCM_BANK_BITS]), .en(1'b1));
rvdffs #(pt.DCCM_BANK_BITS) rd_addr_hi_ff (.*, .din(dccm_rd_addr_hi[DCCM_WIDTH_BITS+:pt.DCCM_BANK_BITS]), .dout(dccm_rd_addr_hi_q[DCCM_WIDTH_BITS+:pt.DCCM_BANK_BITS]), .en(1'b1));
rvdff #(pt.DCCM_BANK_BITS) rd_addr_lo_ff (.*, .din(dccm_rd_addr_lo[DCCM_WIDTH_BITS+:pt.DCCM_BANK_BITS]), .dout(dccm_rd_addr_lo_q[DCCM_WIDTH_BITS+:pt.DCCM_BANK_BITS]), .clk(active_clk));
rvdff #(pt.DCCM_BANK_BITS) rd_addr_hi_ff (.*, .din(dccm_rd_addr_hi[DCCM_WIDTH_BITS+:pt.DCCM_BANK_BITS]), .dout(dccm_rd_addr_hi_q[DCCM_WIDTH_BITS+:pt.DCCM_BANK_BITS]), .clk(active_clk));
`undef EL2_LOCAL_DCCM_RAM_TEST_PORTS

View File

@ -1,5 +1,5 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 Western Digital Corporation or it's affiliates.
// Copyright 2020 Western Digital Corporation or its affiliates.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -31,10 +31,11 @@ import el2_pkg::*;
`include "el2_param.vh"
)
(
input logic clk,
input logic lsu_c2_r_clk, // clocks
input logic rst_l,
input logic scan_mode, // scan
input logic clk, // Clock only while core active. Through one clock header. For flops with second clock header built in. Connected to ACTIVE_L2CLK.
input logic lsu_c2_r_clk, // clock
input logic clk_override, // Override non-functional clock gating
input logic rst_l, // reset, active low
input logic scan_mode, // scan mode
input el2_lsu_pkt_t lsu_pkt_m, // packet in m
input el2_lsu_pkt_t lsu_pkt_r, // packet in r
@ -49,11 +50,11 @@ import el2_pkg::*;
input logic [pt.DCCM_DATA_WIDTH-1:0] dccm_rdata_hi_r, // data from the dccm
input logic [pt.DCCM_DATA_WIDTH-1:0] dccm_rdata_lo_r, // data from the dccm
input logic [pt.DCCM_ECC_WIDTH-1:0] dccm_data_ecc_hi_r, // data from the dccm + ecc
input logic [pt.DCCM_ECC_WIDTH-1:0] dccm_data_ecc_lo_r,
output logic [pt.DCCM_DATA_WIDTH-1:0] sec_data_hi_r,
output logic [pt.DCCM_DATA_WIDTH-1:0] sec_data_lo_r,
output logic [pt.DCCM_DATA_WIDTH-1:0] sec_data_hi_r_ff,
output logic [pt.DCCM_DATA_WIDTH-1:0] sec_data_lo_r_ff,
input logic [pt.DCCM_ECC_WIDTH-1:0] dccm_data_ecc_lo_r, // data from the dccm + ecc
output logic [pt.DCCM_DATA_WIDTH-1:0] sec_data_hi_r, // corrected dccm data R-stage
output logic [pt.DCCM_DATA_WIDTH-1:0] sec_data_lo_r, // corrected dccm data R-stage
output logic [pt.DCCM_DATA_WIDTH-1:0] sec_data_hi_r_ff, // corrected dccm data R+1 stage
output logic [pt.DCCM_DATA_WIDTH-1:0] sec_data_lo_r_ff, // corrected dccm data R+1 stage
input logic ld_single_ecc_error_r, // ld has a single ecc error
input logic ld_single_ecc_error_r_ff, // ld has a single ecc error
@ -65,18 +66,18 @@ import el2_pkg::*;
input logic [pt.DCCM_DATA_WIDTH-1:0] dccm_rdata_lo_m, // raw data from mem
input logic [pt.DCCM_ECC_WIDTH-1:0] dccm_data_ecc_hi_m, // ecc read out from mem
input logic [pt.DCCM_ECC_WIDTH-1:0] dccm_data_ecc_lo_m, // ecc read out from mem
output logic [pt.DCCM_DATA_WIDTH-1:0] sec_data_hi_m,
output logic [pt.DCCM_DATA_WIDTH-1:0] sec_data_lo_m,
output logic [pt.DCCM_DATA_WIDTH-1:0] sec_data_hi_m, // corrected dccm data M-stage
output logic [pt.DCCM_DATA_WIDTH-1:0] sec_data_lo_m, // corrected dccm data M-stage
input logic dma_dccm_wen,
input logic [31:0] dma_dccm_wdata_lo,
input logic [31:0] dma_dccm_wdata_hi,
input logic dma_dccm_wen, // Perform DMA writes only for word/dword
input logic [31:0] dma_dccm_wdata_lo, // Shifted dma data to lower bits to make it consistent to lsu stores
input logic [31:0] dma_dccm_wdata_hi, // Shifted dma data to lower bits to make it consistent to lsu stores
output logic [pt.DCCM_ECC_WIDTH-1:0] dma_dccm_wdata_ecc_hi, // ECC bits for the DMA wdata
output logic [pt.DCCM_ECC_WIDTH-1:0] dma_dccm_wdata_ecc_lo, // ECC bits for the DMA wdata
output logic [pt.DCCM_ECC_WIDTH-1:0] stbuf_ecc_any,
output logic [pt.DCCM_ECC_WIDTH-1:0] sec_data_ecc_hi_r_ff,
output logic [pt.DCCM_ECC_WIDTH-1:0] sec_data_ecc_lo_r_ff,
output logic [pt.DCCM_ECC_WIDTH-1:0] stbuf_ecc_any, // Encoded data with ECC bits
output logic [pt.DCCM_ECC_WIDTH-1:0] sec_data_ecc_hi_r_ff, // Encoded data with ECC bits
output logic [pt.DCCM_ECC_WIDTH-1:0] sec_data_ecc_lo_r_ff, // Encoded data with ECC bits
output logic single_ecc_error_hi_r, // sec detected
output logic single_ecc_error_lo_r, // sec detected on lower dccm bank
@ -107,13 +108,12 @@ import el2_pkg::*;
if (pt.LOAD_TO_USE_PLUS1 == 1) begin: L2U_Plus1_1
logic ldst_dual_m, ldst_dual_r;
logic is_ldst_m;
logic is_ldst_hi_m, is_ldst_lo_m;
logic is_ldst_hi_r, is_ldst_lo_r;
assign ldst_dual_r = (lsu_addr_r[2] != end_addr_r[2]);
assign is_ldst_r = lsu_pkt_r.valid & (lsu_pkt_r.load | lsu_pkt_r.store) & addr_in_dccm_r & lsu_dccm_rden_r;
assign is_ldst_lo_r = is_ldst_r & ~dec_tlu_core_ecc_disable;
assign is_ldst_hi_r = is_ldst_r & (ldst_dual_r | lsu_pkt_r.dma) & ~dec_tlu_core_ecc_disable; // Always check the ECC Hi/Lo for DMA since we don't align for DMA
assign is_ldst_hi_r = is_ldst_r & ldst_dual_r & ~dec_tlu_core_ecc_disable; // Always check the ECC Hi/Lo for DMA since we don't align for DMA
assign is_ldst_hi_any = is_ldst_hi_r;
assign dccm_rdata_hi_any[pt.DCCM_DATA_WIDTH-1:0] = dccm_rdata_hi_r[pt.DCCM_DATA_WIDTH-1:0];
@ -163,14 +163,14 @@ import el2_pkg::*;
rvdff #(1) lsu_double_ecc_err_r (.din(lsu_double_ecc_error_m), .dout(lsu_double_ecc_error_r), .clk(lsu_c2_r_clk), .*);
rvdff #(.WIDTH(1)) ldst_sec_lo_rff (.din(single_ecc_error_lo_any), .dout(single_ecc_error_lo_r), .clk(lsu_c2_r_clk), .*);
rvdff #(.WIDTH(1)) ldst_sec_hi_rff (.din(single_ecc_error_hi_any), .dout(single_ecc_error_hi_r), .clk(lsu_c2_r_clk), .*);
rvdff #(.WIDTH(pt.DCCM_DATA_WIDTH)) sec_data_hi_rff (.din(sec_data_hi_m[pt.DCCM_DATA_WIDTH-1:0]), .dout(sec_data_hi_r[pt.DCCM_DATA_WIDTH-1:0]), .clk(lsu_c2_r_clk), .*);
rvdff #(.WIDTH(pt.DCCM_DATA_WIDTH)) sec_data_lo_rff (.din(sec_data_lo_m[pt.DCCM_DATA_WIDTH-1:0]), .dout(sec_data_lo_r[pt.DCCM_DATA_WIDTH-1:0]), .clk(lsu_c2_r_clk), .*);
rvdffe #(.WIDTH(pt.DCCM_DATA_WIDTH)) sec_data_hi_rff (.din(sec_data_hi_m[pt.DCCM_DATA_WIDTH-1:0]), .dout(sec_data_hi_r[pt.DCCM_DATA_WIDTH-1:0]), .en(lsu_single_ecc_error_m | clk_override), .*);
rvdffe #(.WIDTH(pt.DCCM_DATA_WIDTH)) sec_data_lo_rff (.din(sec_data_lo_m[pt.DCCM_DATA_WIDTH-1:0]), .dout(sec_data_lo_r[pt.DCCM_DATA_WIDTH-1:0]), .en(lsu_single_ecc_error_m | clk_override), .*);
end
// Logic for ECC generation during write
assign dccm_wdata_lo_any[pt.DCCM_DATA_WIDTH-1:0] = ld_single_ecc_error_r_ff ? sec_data_lo_r_ff[pt.DCCM_DATA_WIDTH-1:0] : (dma_dccm_wen ? dma_dccm_wdata_lo[pt.DCCM_DATA_WIDTH-1:0] : stbuf_data_any[pt.DCCM_DATA_WIDTH-1:0]);
assign dccm_wdata_hi_any[pt.DCCM_DATA_WIDTH-1:0] = ld_single_ecc_error_r_ff ? sec_data_hi_r_ff[pt.DCCM_DATA_WIDTH-1:0] : (dma_dccm_wen ? dma_dccm_wdata_hi[pt.DCCM_DATA_WIDTH-1:0] : stbuf_data_any[pt.DCCM_DATA_WIDTH-1:0]);
assign dccm_wdata_hi_any[pt.DCCM_DATA_WIDTH-1:0] = ld_single_ecc_error_r_ff ? sec_data_hi_r_ff[pt.DCCM_DATA_WIDTH-1:0] : (dma_dccm_wen ? dma_dccm_wdata_hi[pt.DCCM_DATA_WIDTH-1:0] : 32'h0);
assign sec_data_ecc_hi_r_ff[pt.DCCM_ECC_WIDTH-1:0] = dccm_wdata_ecc_hi_any[pt.DCCM_ECC_WIDTH-1:0];
assign sec_data_ecc_lo_r_ff[pt.DCCM_ECC_WIDTH-1:0] = dccm_wdata_ecc_lo_any[pt.DCCM_ECC_WIDTH-1:0];
@ -232,11 +232,10 @@ import el2_pkg::*;
assign double_ecc_error_hi_any = '0;
assign single_ecc_error_lo_any = '0;
assign double_ecc_error_lo_any = '0;
assign stbuf_ecc_any[pt.DCCM_ECC_WIDTH-1:0] = '0;
end
rvdffe #(.WIDTH(pt.DCCM_DATA_WIDTH)) sec_data_hi_rplus1ff (.din(sec_data_hi_r[pt.DCCM_DATA_WIDTH-1:0]), .dout(sec_data_hi_r_ff[pt.DCCM_DATA_WIDTH-1:0]), .en(ld_single_ecc_error_r), .clk(clk), .*);
rvdffe #(.WIDTH(pt.DCCM_DATA_WIDTH)) sec_data_lo_rplus1ff (.din(sec_data_lo_r[pt.DCCM_DATA_WIDTH-1:0]), .dout(sec_data_lo_r_ff[pt.DCCM_DATA_WIDTH-1:0]), .en(ld_single_ecc_error_r), .clk(clk), .*);
rvdffe #(.WIDTH(pt.DCCM_DATA_WIDTH)) sec_data_hi_rplus1ff (.din(sec_data_hi_r[pt.DCCM_DATA_WIDTH-1:0]), .dout(sec_data_hi_r_ff[pt.DCCM_DATA_WIDTH-1:0]), .en(ld_single_ecc_error_r | clk_override), .clk(clk), .*);
rvdffe #(.WIDTH(pt.DCCM_DATA_WIDTH)) sec_data_lo_rplus1ff (.din(sec_data_lo_r[pt.DCCM_DATA_WIDTH-1:0]), .dout(sec_data_lo_r_ff[pt.DCCM_DATA_WIDTH-1:0]), .en(ld_single_ecc_error_r | clk_override), .clk(clk), .*);
endmodule // el2_lsu_ecc

View File

@ -1,5 +1,5 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 Western Digital Corporation or it's affiliates.
// Copyright 2020 Western Digital Corporation or its affiliates.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -30,7 +30,9 @@ import el2_pkg::*;
#(
`include "el2_param.vh"
)(
input logic rst_l,
input logic rst_l, // reset, active low
input logic clk_override, // Override non-functional clock gating
input logic clk, // Clock only while core active. Through one clock header. For flops with second clock header built in. Connected to ACTIVE_L2CLK.
// clocks per pipe
input logic lsu_c1_m_clk,
@ -39,28 +41,31 @@ import el2_pkg::*;
input logic lsu_c2_r_clk,
input logic lsu_store_c1_m_clk,
input logic [31:0] lsu_ld_data_r,
input logic [31:0] lsu_ld_data_corr_r, // ECC corrected data
input logic lsu_single_ecc_error_r,
input logic lsu_double_ecc_error_r,
input logic [31:0] lsu_ld_data_r, // Load data R-stage
input logic [31:0] lsu_ld_data_corr_r, // ECC corrected data R-stage
input logic lsu_single_ecc_error_r, // ECC single bit error R-stage
input logic lsu_double_ecc_error_r, // ECC double bit error R-stage
input logic [31:0] lsu_ld_data_m,
input logic lsu_single_ecc_error_m,
input logic lsu_double_ecc_error_m,
input logic [31:0] lsu_ld_data_m, // Load data M-stage
input logic lsu_single_ecc_error_m, // ECC single bit error M-stage
input logic lsu_double_ecc_error_m, // ECC double bit error M-stage
input logic flush_m_up,
input logic flush_r,
input logic flush_m_up, // Flush M and D stage
input logic flush_r, // Flush R-stage
input logic ldst_dual_d, // load/store is unaligned at 32 bit boundary D-stage
input logic ldst_dual_m, // load/store is unaligned at 32 bit boundary M-stage
input logic ldst_dual_r, // load/store is unaligned at 32 bit boundary R-stage
input logic [31:0] exu_lsu_rs1_d, // address
input logic [31:0] exu_lsu_rs2_d, // store data
input el2_lsu_pkt_t lsu_p, // lsu control packet
input logic dec_lsu_valid_raw_d, // Raw valid for address computation
input logic [11:0] dec_lsu_offset_d,
input logic [11:0] dec_lsu_offset_d, // 12b offset for load/store addresses
input logic [31:0] picm_mask_data_m,
input logic [31:0] bus_read_data_m,
output logic [31:0] lsu_result_m,
input logic [31:0] picm_mask_data_m, // PIC data M-stage
input logic [31:0] bus_read_data_m, // the bus return data
output logic [31:0] lsu_result_m, // lsu load data
output logic [31:0] lsu_result_corr_r, // This is the ECC corrected data going to RF
// lsu address down the pipe
output logic [31:0] lsu_addr_d,
@ -73,12 +78,12 @@ import el2_pkg::*;
// store data down the pipe
output logic [31:0] store_data_m,
input logic [31:0] dec_tlu_mrac_ff,
output logic lsu_exc_m,
output logic is_sideeffects_m,
output logic lsu_commit_r,
output logic lsu_single_ecc_error_incr,
output el2_lsu_error_pkt_t lsu_error_pkt_r,
input logic [31:0] dec_tlu_mrac_ff, // CSR for memory region control
output logic lsu_exc_m, // Access or misaligned fault
output logic is_sideeffects_m, // is sideffects space
output logic lsu_commit_r, // lsu instruction in r commits
output logic lsu_single_ecc_error_incr,// LSU inc SB error counter
output el2_lsu_error_pkt_t lsu_error_pkt_r, // lsu exception packet
output logic [31:1] lsu_fir_addr, // fast interrupt address
output logic [1:0] lsu_fir_error, // Error during fast interrupt lookup
@ -106,10 +111,11 @@ import el2_pkg::*;
output el2_lsu_pkt_t lsu_pkt_m,
output el2_lsu_pkt_t lsu_pkt_r,
input logic scan_mode
input logic scan_mode // Scan mode
);
logic [31:3] end_addr_pre_m, end_addr_pre_r;
logic [31:0] full_addr_d;
logic [31:0] full_end_addr_d;
logic [31:0] lsu_rs1_d;
@ -147,7 +153,6 @@ import el2_pkg::*;
assign rs1_d[31:0] = (lsu_pkt_d.load_ldst_bypass_d) ? lsu_result_m[31:0] : rs1_d_raw[31:0];
// generate the ls address
// need to refine this is memory is only 128KB
rvlsadder lsadder (.rs1(rs1_d[31:0]),
.offset(offset_d[11:0]),
.dout(full_addr_d[31:0])
@ -205,7 +210,9 @@ import el2_pkg::*;
assign lsu_fir_error_m[1:0] = fir_nondccm_access_error_m ? 2'b11 : (fir_dccm_access_error_m ? 2'b10 : ((lsu_pkt_m.fast_int & lsu_double_ecc_error_m) ? 2'b01 : 2'b00));
rvdff #($bits(el2_lsu_error_pkt_t)) lsu_error_pkt_rff(.*, .din(lsu_error_pkt_m), .dout(lsu_error_pkt_r), .clk(lsu_c2_r_clk));
rvdff #(1) lsu_exc_valid_rff (.*, .din(lsu_error_pkt_m.exc_valid), .dout(lsu_error_pkt_r.exc_valid), .clk(lsu_c2_r_clk));
rvdff #(1) lsu_single_ecc_error_rff(.*, .din(lsu_error_pkt_m.single_ecc_error), .dout(lsu_error_pkt_r.single_ecc_error), .clk(lsu_c2_r_clk));
rvdffe #($bits(el2_lsu_error_pkt_t)-2) lsu_error_pkt_rff (.*, .din(lsu_error_pkt_m[$bits(el2_lsu_error_pkt_t)-1:2]), .dout(lsu_error_pkt_r[$bits(el2_lsu_error_pkt_t)-1:2]), .en(lsu_error_pkt_m.exc_valid | lsu_error_pkt_m.single_ecc_error | clk_override));
rvdff #(2) lsu_fir_error_rff (.*, .din(lsu_fir_error_m[1:0]), .dout(lsu_fir_error[1:0]), .clk(lsu_c2_r_clk));
end
@ -247,7 +254,7 @@ import el2_pkg::*;
assign lsu_ld_datafn_r[31:0] = addr_external_r ? bus_read_data_r[31:0] : lsu_ld_data_r[31:0];
assign lsu_ld_datafn_corr_r[31:0] = addr_external_r ? bus_read_data_r[31:0] : lsu_ld_data_corr_r[31:0];
// this is really R stage but don't want to make all the changes to support M,R buses
// this is really R stage signal
assign lsu_result_m[31:0] = ({32{ lsu_pkt_r.unsign & lsu_pkt_r.by }} & {24'b0,lsu_ld_datafn_r[7:0]}) |
({32{ lsu_pkt_r.unsign & lsu_pkt_r.half}} & {16'b0,lsu_ld_datafn_r[15:0]}) |
({32{~lsu_pkt_r.unsign & lsu_pkt_r.by }} & {{24{ lsu_ld_datafn_r[7]}}, lsu_ld_datafn_r[7:0]}) |
@ -304,8 +311,14 @@ import el2_pkg::*;
rvdff #(32) samff (.*, .din(lsu_addr_d[31:0]), .dout(lsu_addr_m[31:0]), .clk(lsu_c1_m_clk));
rvdff #(32) sarff (.*, .din(lsu_addr_m[31:0]), .dout(lsu_addr_r[31:0]), .clk(lsu_c1_r_clk));
rvdff #(32) end_addr_mff (.*, .din(end_addr_d[31:0]), .dout(end_addr_m[31:0]), .clk(lsu_c1_m_clk));
rvdff #(32) end_addr_rff (.*, .din(end_addr_m[31:0]), .dout(end_addr_r[31:0]), .clk(lsu_c1_r_clk));
assign end_addr_m[31:3] = ldst_dual_m ? end_addr_pre_m[31:3] : lsu_addr_m[31:3]; // This is for power saving
assign end_addr_r[31:3] = ldst_dual_r ? end_addr_pre_r[31:3] : lsu_addr_r[31:3]; // This is for power saving
rvdffe #(29) end_addr_hi_mff (.*, .din(end_addr_d[31:3]), .dout(end_addr_pre_m[31:3]), .en((lsu_pkt_d.valid & ldst_dual_d) | clk_override));
rvdffe #(29) end_addr_hi_rff (.*, .din(end_addr_m[31:3]), .dout(end_addr_pre_r[31:3]), .en((lsu_pkt_m.valid & ldst_dual_m) | clk_override));
rvdff #(3) end_addr_lo_mff (.*, .din(end_addr_d[2:0]), .dout(end_addr_m[2:0]), .clk(lsu_c1_m_clk));
rvdff #(3) end_addr_lo_rff (.*, .din(end_addr_m[2:0]), .dout(end_addr_r[2:0]), .clk(lsu_c1_r_clk));
rvdff #(1) addr_in_dccm_mff(.din(addr_in_dccm_d), .dout(addr_in_dccm_m), .clk(lsu_c1_m_clk), .*);
rvdff #(1) addr_in_dccm_rff(.din(addr_in_dccm_m), .dout(addr_in_dccm_r), .clk(lsu_c1_r_clk), .*);
@ -323,6 +336,6 @@ import el2_pkg::*;
rvdff #(1) fir_dccm_access_error_mff (.din(fir_dccm_access_error_d), .dout(fir_dccm_access_error_m), .clk(lsu_c1_m_clk), .*);
rvdff #(1) fir_nondccm_access_error_mff (.din(fir_nondccm_access_error_d), .dout(fir_nondccm_access_error_m), .clk(lsu_c1_m_clk), .*);
rvdff #(32) bus_read_data_r_ff (.*, .din(bus_read_data_m[31:0]), .dout(bus_read_data_r[31:0]), .clk(lsu_c1_r_clk));
rvdffe #(32) bus_read_data_r_ff (.*, .din(bus_read_data_m[31:0]), .dout(bus_read_data_r[31:0]), .en(addr_external_m | clk_override));
endmodule

View File

@ -1,5 +1,5 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 Western Digital Corporation or it's affiliates.
// Copyright 2020 Western Digital Corporation or its affiliates.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -36,8 +36,6 @@ import el2_pkg::*;
input logic clk, // core clock
input logic rst_l, // reset
input logic lsu_c1_m_clk, // clock
input logic lsu_c1_r_clk, // lsu pipe clock
input logic lsu_stbuf_c1_clk, // stbuf clock
input logic lsu_free_c2_clk, // free clk
@ -61,28 +59,29 @@ import el2_pkg::*;
output logic lsu_stbuf_empty_any, // stbuf is empty
output logic ldst_stbuf_reqvld_r, // needed for clocking
input logic [pt.LSU_SB_BITS-1:0] lsu_addr_d, // lsu address
input logic [31:0] lsu_addr_m,
input logic [31:0] lsu_addr_r,
input logic [pt.LSU_SB_BITS-1:0] lsu_addr_d, // lsu address D-stage
input logic [31:0] lsu_addr_m, // lsu address M-stage
input logic [31:0] lsu_addr_r, // lsu address R-stage
input logic [pt.LSU_SB_BITS-1:0] end_addr_d, // lsu end addrress - needed to check unaligned
input logic [31:0] end_addr_m,
input logic [31:0] end_addr_r,
input logic [pt.LSU_SB_BITS-1:0] end_addr_d, // lsu end address D-stage - needed to check unaligned
input logic [31:0] end_addr_m, // lsu end address M-stage - needed to check unaligned
input logic [31:0] end_addr_r, // lsu end address R-stage - needed to check unaligned
input logic ldst_dual_d, ldst_dual_m, ldst_dual_r,
input logic addr_in_dccm_m, // address is in dccm
input logic addr_in_dccm_r, // address is in dccm
// Forwarding signals
input logic lsu_cmpen_m, // needed for forwarding stbuf - load
input el2_lsu_pkt_t lsu_pkt_m,
input el2_lsu_pkt_t lsu_pkt_r,
input el2_lsu_pkt_t lsu_pkt_m, // LSU packet M-stage
input el2_lsu_pkt_t lsu_pkt_r, // LSU packet R-stage
output logic [pt.DCCM_DATA_WIDTH-1:0] stbuf_fwddata_hi_m, // stbuf data
output logic [pt.DCCM_DATA_WIDTH-1:0] stbuf_fwddata_lo_m,
output logic [pt.DCCM_BYTE_WIDTH-1:0] stbuf_fwdbyteen_hi_m,
output logic [pt.DCCM_BYTE_WIDTH-1:0] stbuf_fwdbyteen_lo_m,
output logic [pt.DCCM_DATA_WIDTH-1:0] stbuf_fwddata_lo_m, // stbuf data
output logic [pt.DCCM_BYTE_WIDTH-1:0] stbuf_fwdbyteen_hi_m, // stbuf data
output logic [pt.DCCM_BYTE_WIDTH-1:0] stbuf_fwdbyteen_lo_m, // stbuf data
input logic scan_mode
input logic scan_mode // Scan mode
);
@ -115,15 +114,13 @@ import el2_pkg::*;
logic [DEPTH_LOG2-1:0] WrPtr, RdPtr;
logic [DEPTH_LOG2-1:0] NxtWrPtr, NxtRdPtr;
logic [DEPTH_LOG2-1:0] WrPtrPlus1, WrPtrPlus2, RdPtrPlus1;
logic ldst_dual_d, ldst_dual_m, ldst_dual_r;
logic dual_stbuf_write_r;
logic isdccmst_m, isdccmst_r;
logic [3:0] stbuf_numvld_any, stbuf_specvld_any;
logic [1:0] stbuf_specvld_m, stbuf_specvld_r;//, stbuf_eccvld_m, stbuf_eccvld_r;
logic [1:0] stbuf_specvld_m, stbuf_specvld_r;
logic cmpen_hi_m, cmpen_lo_m;
logic [pt.LSU_SB_BITS-1:$clog2(BYTE_WIDTH)] cmpaddr_hi_m, cmpaddr_lo_m;
// variables to detect matching from the store queue
@ -165,12 +162,11 @@ import el2_pkg::*;
assign WrPtrPlus2[DEPTH_LOG2-1:0] = WrPtr[DEPTH_LOG2-1:0] + 2'b10;
// ecc error on both hi/lo
assign ldst_dual_d = (lsu_addr_d[2] != end_addr_d[2]);
assign dual_stbuf_write_r = ldst_dual_r & store_stbuf_reqvld_r;
assign ldst_stbuf_reqvld_r = (lsu_commit_r & store_stbuf_reqvld_r); //|
assign ldst_stbuf_reqvld_r = ((lsu_commit_r | lsu_pkt_r.dma) & store_stbuf_reqvld_r);
// Store Buffer coalescing
for (genvar i=0; i<32'(DEPTH); i++) begin: FindMatchEntry
for (genvar i=0; i<DEPTH; i++) begin: FindMatchEntry
assign store_matchvec_lo_r[i] = (stbuf_addr[i][pt.LSU_SB_BITS-1:$clog2(BYTE_WIDTH)] == lsu_addr_r[pt.LSU_SB_BITS-1:$clog2(BYTE_WIDTH)]) & stbuf_vld[i] & ~stbuf_dma_kill[i] & ~stbuf_reset[i];
assign store_matchvec_hi_r[i] = (stbuf_addr[i][pt.LSU_SB_BITS-1:$clog2(BYTE_WIDTH)] == end_addr_r[pt.LSU_SB_BITS-1:$clog2(BYTE_WIDTH)]) & stbuf_vld[i] & ~stbuf_dma_kill[i] & dual_stbuf_write_r & ~stbuf_reset[i];
end: FindMatchEntry
@ -179,13 +175,14 @@ import el2_pkg::*;
assign store_coalesce_hi_r = |store_matchvec_hi_r[DEPTH-1:0];
if (pt.DCCM_ENABLE == 1) begin: Gen_dccm_enable
// Allocate new in this entry if :
// 1. wrptr, single allocate, lo did not coalesce
// 2. wrptr, double allocate, lo ^ hi coalesced
// 3. wrptr + 1, double alloacte, niether lo or hi coalesced
// Also update if there is a hi or a lo coalesce to this entry
// Store Buffer instantiation
for (genvar i=0; i<32'(DEPTH); i++) begin: GenStBuf
for (genvar i=0; i<DEPTH; i++) begin: GenStBuf
assign stbuf_wr_en[i] = ldst_stbuf_reqvld_r & (
( (i == WrPtr[DEPTH_LOG2-1:0]) & ~store_coalesce_lo_r) | // Allocate : new Lo
( (i == WrPtr[DEPTH_LOG2-1:0]) & dual_stbuf_write_r & ~store_coalesce_hi_r) | // Allocate : only 1 new Write Either
@ -213,9 +210,15 @@ import el2_pkg::*;
rvdffsc #(.WIDTH(BYTE_WIDTH)) stbuf_byteenff (.din(stbuf_byteenin[i][BYTE_WIDTH-1:0]), .dout(stbuf_byteen[i][BYTE_WIDTH-1:0]), .en(stbuf_wr_en[i]), .clear(stbuf_reset[i]), .clk(lsu_stbuf_c1_clk), .*);
rvdffe #(.WIDTH(DATA_WIDTH)) stbuf_dataff (.din(stbuf_datain[i][DATA_WIDTH-1:0]), .dout(stbuf_data[i][DATA_WIDTH-1:0]), .en(stbuf_wr_en[i]), .*);
end
rvdff #(.WIDTH(1)) ldst_dual_mff (.din(ldst_dual_d), .dout(ldst_dual_m), .clk(lsu_c1_m_clk), .*);
rvdff #(.WIDTH(1)) ldst_dual_rff (.din(ldst_dual_m), .dout(ldst_dual_r), .clk(lsu_c1_r_clk), .*);
end else begin: Gen_dccm_disable
assign stbuf_wr_en[DEPTH-1:0] = '0;
assign stbuf_reset[DEPTH-1:0] = '0;
assign stbuf_vld[DEPTH-1:0] = '0;
assign stbuf_dma_kill[DEPTH-1:0] = '0;
assign stbuf_addr[DEPTH-1:0] = '0;
assign stbuf_byteen[DEPTH-1:0] = '0;
assign stbuf_data[DEPTH-1:0] = '0;
end
// Store Buffer drain logic
assign stbuf_reqvld_flushed_any = stbuf_vld[RdPtr] & stbuf_dma_kill[RdPtr];
@ -233,7 +236,7 @@ import el2_pkg::*;
always_comb begin
stbuf_numvld_any[3:0] = '0;
for (int i=0; i<32'(DEPTH); i++) begin
for (int i=0; i<DEPTH; i++) begin
stbuf_numvld_any[3:0] += {3'b0, stbuf_vld[i]};
end
end
@ -250,24 +253,22 @@ import el2_pkg::*;
assign lsu_stbuf_empty_any = (stbuf_numvld_any[3:0] == 4'b0);
// Load forwarding logic from the store queue
assign cmpen_hi_m = lsu_cmpen_m & ldst_dual_m;
assign cmpaddr_hi_m[pt.LSU_SB_BITS-1:$clog2(BYTE_WIDTH)] = end_addr_m[pt.LSU_SB_BITS-1:$clog2(BYTE_WIDTH)];
assign cmpen_lo_m = lsu_cmpen_m;
assign cmpaddr_lo_m[pt.LSU_SB_BITS-1:$clog2(BYTE_WIDTH)] = lsu_addr_m[pt.LSU_SB_BITS-1:$clog2(BYTE_WIDTH)];
always_comb begin: GenLdFwd
stbuf_fwdbyteen_hi_pre_m[BYTE_WIDTH-1:0] = '0;
stbuf_fwdbyteen_lo_pre_m[BYTE_WIDTH-1:0] = '0;
for (int i=0; i<32'(DEPTH); i++) begin
for (int i=0; i<DEPTH; i++) begin
stbuf_match_hi[i] = (stbuf_addr[i][pt.LSU_SB_BITS-1:$clog2(BYTE_WIDTH)] == cmpaddr_hi_m[pt.LSU_SB_BITS-1:$clog2(BYTE_WIDTH)]) & stbuf_vld[i] & ~stbuf_dma_kill[i] & addr_in_dccm_m;
stbuf_match_lo[i] = (stbuf_addr[i][pt.LSU_SB_BITS-1:$clog2(BYTE_WIDTH)] == cmpaddr_lo_m[pt.LSU_SB_BITS-1:$clog2(BYTE_WIDTH)]) & stbuf_vld[i] & ~stbuf_dma_kill[i] & addr_in_dccm_m;
// Kill the store buffer entry if there is a dma store since it already updated the dccm
stbuf_dma_kill_en[i] = (stbuf_match_hi[i] | stbuf_match_lo[i]) & lsu_pkt_m.valid & lsu_pkt_m.dma & lsu_pkt_m.store;
for (int j=0; j<32'(BYTE_WIDTH); j++) begin
for (int j=0; j<BYTE_WIDTH; j++) begin
stbuf_fwdbyteenvec_hi[i][j] = stbuf_match_hi[i] & stbuf_byteen[i][j] & stbuf_vld[i];
stbuf_fwdbyteen_hi_pre_m[j] |= stbuf_fwdbyteenvec_hi[i][j];
@ -281,7 +282,7 @@ import el2_pkg::*;
stbuf_fwddata_hi_pre_m[31:0] = '0;
stbuf_fwddata_lo_pre_m[31:0] = '0;
for (int i=0; i<32'(DEPTH); i++) begin
for (int i=0; i<DEPTH; i++) begin
stbuf_fwddata_hi_pre_m[31:0] |= {32{stbuf_match_hi[i]}} & stbuf_data[i][31:0];
stbuf_fwddata_lo_pre_m[31:0] |= {32{stbuf_match_lo[i]}} & stbuf_data[i][31:0];
@ -305,7 +306,7 @@ import el2_pkg::*;
assign ld_addr_rhit_hi_lo = (lsu_addr_m[31:2] == end_addr_r[31:2]) & lsu_pkt_r.valid & lsu_pkt_r.store & ~lsu_pkt_r.dma & dual_stbuf_write_r;
assign ld_addr_rhit_hi_hi = (end_addr_m[31:2] == end_addr_r[31:2]) & lsu_pkt_r.valid & lsu_pkt_r.store & ~lsu_pkt_r.dma & dual_stbuf_write_r;
for (genvar i=0; i<32'(BYTE_WIDTH); i++) begin
for (genvar i=0; i<BYTE_WIDTH; i++) begin
assign ld_byte_rhit_lo_lo[i] = ld_addr_rhit_lo_lo & ldst_byteen_lo_r[i];
assign ld_byte_rhit_lo_hi[i] = ld_addr_rhit_lo_hi & ldst_byteen_lo_r[i];
assign ld_byte_rhit_hi_lo[i] = ld_addr_rhit_hi_lo & ldst_byteen_hi_r[i];
@ -335,11 +336,11 @@ import el2_pkg::*;
rvdffs #(.WIDTH(DEPTH_LOG2)) WrPtrff (.din(NxtWrPtr[DEPTH_LOG2-1:0]), .dout(WrPtr[DEPTH_LOG2-1:0]), .en(WrPtrEn), .clk(lsu_stbuf_c1_clk), .*);
rvdffs #(.WIDTH(DEPTH_LOG2)) RdPtrff (.din(NxtRdPtr[DEPTH_LOG2-1:0]), .dout(RdPtr[DEPTH_LOG2-1:0]), .en(RdPtrEn), .clk(lsu_stbuf_c1_clk), .*);
`ifdef ASSERT_ON
`ifdef RV_ASSERT_ON
assert_stbuf_overflow: assert #0 (stbuf_specvld_any[2:0] <= DEPTH);
property stbuf_wren_store_dccm;
@(posedge clk) disable iff(~rst_l) (|stbuf_wr_en[DEPTH-1:0]) |-> (lsu_pkt_r.valid & lsu_pkt_r.store & addr_in_dccm_r & ~lsu_pkt_r.dma);
@(posedge clk) disable iff(~rst_l) (|stbuf_wr_en[DEPTH-1:0]) |-> (lsu_pkt_r.valid & lsu_pkt_r.store & addr_in_dccm_r);
endproperty
assert_stbuf_wren_store_dccm: assert property (stbuf_wren_store_dccm) else
$display("Illegal store buffer write");

View File

@ -1,5 +1,5 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 Western Digital Corporation or it's affiliates.
// Copyright 2020 Western Digital Corporation or its affiliates.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -35,21 +35,31 @@ import el2_pkg::*;
output logic [3:0] lsu_trigger_match_m // match result
);
logic trigger_enable;
logic [3:0][31:0] lsu_match_data;
logic [3:0] lsu_trigger_data_match;
logic [31:0] store_data_trigger_m;
logic [31:0] ldst_addr_trigger_m;
assign store_data_trigger_m[31:0] = {({16{lsu_pkt_m.word}} & store_data_m[31:16]),({8{(lsu_pkt_m.half | lsu_pkt_m.word)}} & store_data_m[15:8]), store_data_m[7:0]};
// Generate the trigger enable (This is for power)
always_comb begin
trigger_enable = 1'b0;
for (int i=0; i<4; i++) begin
trigger_enable |= trigger_pkt_any[i].m;
end
end
assign store_data_trigger_m[31:0] = {({16{lsu_pkt_m.word}} & store_data_m[31:16]),({8{(lsu_pkt_m.half | lsu_pkt_m.word)}} & store_data_m[15:8]), store_data_m[7:0]} & {32{trigger_enable}};
assign ldst_addr_trigger_m[31:0] = lsu_addr_m[31:0] & {32{trigger_enable}};
for (genvar i=0; i<4; i++) begin
assign lsu_match_data[i][31:0] = ({32{~trigger_pkt_any[i].select}} & lsu_addr_m[31:0]) |
assign lsu_match_data[i][31:0] = ({32{~trigger_pkt_any[i].select}} & ldst_addr_trigger_m[31:0]) |
({32{trigger_pkt_any[i].select & trigger_pkt_any[i].store}} & store_data_trigger_m[31:0]);
rvmaskandmatch trigger_match (.mask(trigger_pkt_any[i].tdata2[31:0]), .data(lsu_match_data[i][31:0]), .masken(trigger_pkt_any[i].match), .match(lsu_trigger_data_match[i]));
assign lsu_trigger_match_m[i] = lsu_pkt_m.valid & ~lsu_pkt_m.dma &
assign lsu_trigger_match_m[i] = lsu_pkt_m.valid & ~lsu_pkt_m.dma & trigger_enable &
((trigger_pkt_any[i].store & lsu_pkt_m.store) | (trigger_pkt_any[i].load & lsu_pkt_m.load & ~trigger_pkt_any[i].select)) &
lsu_trigger_data_match[i];
end

Binary file not shown.

View File

@ -1,11 +1,38 @@
# EL2 SweRV RISC-V Core<sup>TM</sup> 1.2 from Western Digital
# EL2 SweRV RISC-V Core<sup>TM</sup> 1.3 from Western Digital
* Multiple debug module compliance deviations and bugs reported by Codasip
* Updates to debug module to level compliance to version 0.13.2 of debug spec
* Trigger chaining compliance fixes
* Power optimization improvements and clock gating improvements
* Significantly lower power in sleep as well as normal operation.
* Enhanced debug memory abstract command to access internal as well as external memories
* Added bit-manipulation support for Zba, Zbb, Zbc, Zbe, Zbf, Zbp, Zbr, Zbs (Jan 29, 2020 Draft spec).
* Zbs and Zbb are enabled by default. Use -set=bitmanip+zb*=1 to enable other sub-extensions.
* Enhancements and additional configurations options for a faster divider
* JTAG controller intial state issue fixed
* Branch predictor fully-associative mode fo 8,16,32 entries.
* Corner case bugs fixes related to
* Bus protocol corner cases (ahb)
* Fetch bus error recording improved accuracy
* Branch predictor pathological timing cases fixes
* Fast interrupt with DCCM ECC errors priority bug
* MPC & PMU protocol cleanup
* Performance counter bug fixes (counting branch prediction events)
* Triggers and ECC correctable error overflows bug fixes
* Demo test-bench updates
* Handling bigger test sizes using associative arrays in external memory slaves,
* simplified test building process and CCM loading functions (only program.hex is generated, no data.hex)
* Improved Makefile and example tests (see README)
* Generating crt0 and link.ld from swerv.config
# EL2 SweRV RISC-V Core<sup>TM</sup> 1.2 from Western Digital
## Release Notes
* Modified MSCAUSE encoding to be consistent with current internal specification
* Added internal timers
# EL2 SweRV RISC-V Core<sup>TM</sup> 1.1 from Western Digital
## Release Notes

26
testbench/SimJTAG.cc Normal file
View File

@ -0,0 +1,26 @@
// See LICENSE.SiFive for license details.
#include <cstdlib>
#include "remote_bitbang.h"
remote_bitbang_t* jtag;
extern "C" int jtag_tick
(
unsigned char * jtag_TCK,
unsigned char * jtag_TMS,
unsigned char * jtag_TDI,
unsigned char * jtag_TRSTn,
unsigned char * srstn,
unsigned char jtag_TDO
)
{
if (!jtag) {
// TODO: Pass in real port number
jtag = new remote_bitbang_t(0);
}
jtag->tick(jtag_TCK, jtag_TMS, jtag_TDI, jtag_TRSTn, srstn, jtag_TDO);
return jtag->done() ? (jtag->exit_code() << 1 | 1) : 0;
}

89
testbench/SimJTAG.v Normal file
View File

@ -0,0 +1,89 @@
// See LICENSE.SiFive for license details.
//VCS coverage exclude_file
import "DPI-C" function int jtag_tick
(
output bit jtag_TCK,
output bit jtag_TMS,
output bit jtag_TDI,
output bit jtag_TRSTn,
output bit sysrstn,
input bit jtag_TDO
);
module SimJTAG #(
parameter TICK_DELAY = 50
)(
input clock,
input reset,
input enable,
input init_done,
output jtag_TCK,
output jtag_TMS,
output jtag_TDI,
output jtag_TRSTn,
output srstn,
input jtag_TDO_data,
input jtag_TDO_driven,
output [31:0] exit
);
reg [31:0] tickCounterReg;
wire [31:0] tickCounterNxt;
assign tickCounterNxt = (tickCounterReg == 0) ? TICK_DELAY : (tickCounterReg - 1);
bit r_reset;
wire [31:0] random_bits = $random;
wire #0.1 __jtag_TDO = jtag_TDO_driven ?
jtag_TDO_data : random_bits[0];
bit __jtag_TCK;
bit __jtag_TMS;
bit __jtag_TDI;
bit __jtag_TRSTn;
int __exit;
bit sysrstn=1;
reg init_done_sticky;
assign #0.1 jtag_TCK = __jtag_TCK;
assign #0.1 jtag_TMS = __jtag_TMS;
assign #0.1 jtag_TDI = __jtag_TDI;
assign #0.1 jtag_TRSTn = __jtag_TRSTn;
assign srstn = sysrstn;
assign #0.1 exit = __exit;
always @(posedge clock) begin
r_reset <= reset;
if (reset || r_reset) begin
__exit = 0;
tickCounterReg <= TICK_DELAY;
init_done_sticky <= 1'b0;
__jtag_TCK = !__jtag_TCK;
end else begin
init_done_sticky <= init_done | init_done_sticky;
if (enable && init_done_sticky) begin
tickCounterReg <= tickCounterNxt;
if (tickCounterReg == 0) begin
__exit = jtag_tick(
__jtag_TCK,
__jtag_TMS,
__jtag_TDI,
__jtag_TRSTn,
sysrstn,
__jtag_TDO);
end
end // if (enable && init_done_sticky)
end // else: !if(reset || r_reset)
end // always @ (posedge clock)
endmodule

View File

@ -33,17 +33,20 @@ output logic HRESP,
output logic [63:0] HRDATA
);
parameter MEM_SIZE_DW = 8192;
parameter MAILBOX_ADDR = 32'hD0580000;
localparam MEM_SIZE = MEM_SIZE_DW*8;
logic Write;
logic [31:0] Last_HADDR;
logic write;
logic [31:0] laddr, addr;
logic [7:0] strb_lat;
logic [63:0] rdata;
bit [7:0] mem [0:MEM_SIZE-1];
//bit [7:0] mem [int];
//int kuku[int];
bit [7:0] mem [bit[31:0]];
bit [7:0] wscnt;
int dws = 0;
int iws = 0;
bit dws_rand;
bit iws_rand;
bit ok;
// Wires
wire [63:0] WriteData = HWDATA;
@ -51,23 +54,23 @@ wire [7:0] strb = HSIZE == 3'b000 ? 8'h1 << HADDR[2:0] :
HSIZE == 3'b001 ? 8'h3 << {HADDR[2:1],1'b0} :
HSIZE == 3'b010 ? 8'hf << {HADDR[2],2'b0} : 8'hff;
wire[31:0] addr = HADDR & (MEM_SIZE-1);
wire[31:0] laddr = Last_HADDR & (MEM_SIZE-1);
wire mailbox_write = Write && Last_HADDR==MAILBOX_ADDR;
wire mailbox_write = write && laddr==MAILBOX_ADDR;
initial begin
if ($value$plusargs("iws=%d", iws));
if ($value$plusargs("dws=%d", dws));
dws_rand = dws < 0;
iws_rand = iws < 0;
end
wire [63:0] mem_dout = {mem[{addr[31:3],3'd7}],
mem[{addr[31:3],3'd6}],
mem[{addr[31:3],3'd5}],
mem[{addr[31:3],3'd4}],
mem[{addr[31:3],3'd3}],
mem[{addr[31:3],3'd2}],
mem[{addr[31:3],3'd1}],
mem[{addr[31:3],3'd0}]};
always @ (negedge HCLK ) begin
if (Write) begin
if(HREADY)
addr = HADDR;
if (write & HREADY) begin
if(strb_lat[7]) mem[{laddr[31:3],3'd7}] = HWDATA[63:56];
if(strb_lat[6]) mem[{laddr[31:3],3'd6}] = HWDATA[55:48];
if(strb_lat[5]) mem[{laddr[31:3],3'd5}] = HWDATA[47:40];
@ -77,25 +80,54 @@ always @ (negedge HCLK ) begin
if(strb_lat[1]) mem[{laddr[31:3],3'd1}] = HWDATA[15:08];
if(strb_lat[0]) mem[{laddr[31:3],3'd0}] = HWDATA[07:00];
end
if(HREADY & HSEL & |HTRANS) begin
`ifdef VERILATOR
if(iws_rand & ~HPROT[0])
iws = $random & 15;
if(dws_rand & HPROT[0])
dws = $random & 15;
`else
if(iws_rand & ~HPROT[0])
ok = std::randomize(iws) with {iws dist {0:=10, [1:3]:/2, [4:15]:/1};};
if(dws_rand & HPROT[0])
ok = std::randomize(dws) with {dws dist {0:=10, [1:3]:/2, [4:15]:/1};};
`endif
end
end
assign HREADYOUT = 1;
assign HRDATA = HREADY ? rdata : ~rdata;
assign HREADYOUT = wscnt == 0;
assign HRESP = 0;
always @(posedge HCLK or negedge HRESETn) begin
if(~HRESETn) begin
Last_HADDR <= 32'b0;
Write <= 1'b0;
HRDATA <= '0;
end else begin
Last_HADDR <= HADDR;
Write <= HWRITE & |HTRANS;
laddr <= 32'b0;
write <= 1'b0;
rdata <= '0;
wscnt <= 0;
end
else begin
if(HREADY & HSEL) begin
laddr <= HADDR;
write <= HWRITE & |HTRANS;
if(|HTRANS & ~HWRITE)
HRDATA <= mem_dout;
rdata <= {mem[{addr[31:3],3'd7}],
mem[{addr[31:3],3'd6}],
mem[{addr[31:3],3'd5}],
mem[{addr[31:3],3'd4}],
mem[{addr[31:3],3'd3}],
mem[{addr[31:3],3'd2}],
mem[{addr[31:3],3'd1}],
mem[{addr[31:3],3'd0}]};
strb_lat <= strb;
end
end
if(HREADY & HSEL & |HTRANS)
wscnt <= HPROT[0] ? dws[7:0] : iws[7:0];
else if(wscnt != 0)
wscnt <= wscnt-1;
end
endmodule
@ -142,14 +174,11 @@ output reg [TAGW-1:0] bid
parameter MAILBOX_ADDR = 32'hD0580000;
parameter MEM_SIZE_DW = 8192;
bit [7:0] mem [0:MEM_SIZE_DW*8-1];
bit [7:0] mem [bit[31:0]];
bit [63:0] memdata;
wire [31:0] waddr, raddr;
wire [63:0] WriteData;
wire mailbox_write;
assign raddr = araddr & (MEM_SIZE_DW*8-1);
assign waddr = awaddr & (MEM_SIZE_DW*8-1);
assign mailbox_write = awvalid && awaddr==MAILBOX_ADDR && rst_l;
assign WriteData = wdata;
@ -169,17 +198,17 @@ always @ ( posedge aclk or negedge rst_l) begin
end
always @ ( negedge aclk) begin
if(arvalid) memdata <= {mem[raddr+7], mem[raddr+6], mem[raddr+5], mem[raddr+4],
mem[raddr+3], mem[raddr+2], mem[raddr+1], mem[raddr]};
if(arvalid) memdata <= {mem[araddr+7], mem[araddr+6], mem[araddr+5], mem[araddr+4],
mem[araddr+3], mem[araddr+2], mem[araddr+1], mem[araddr]};
if(awvalid) begin
if(wstrb[7]) mem[waddr+7] = wdata[63:56];
if(wstrb[6]) mem[waddr+6] = wdata[55:48];
if(wstrb[5]) mem[waddr+5] = wdata[47:40];
if(wstrb[4]) mem[waddr+4] = wdata[39:32];
if(wstrb[3]) mem[waddr+3] = wdata[31:24];
if(wstrb[2]) mem[waddr+2] = wdata[23:16];
if(wstrb[1]) mem[waddr+1] = wdata[15:08];
if(wstrb[0]) mem[waddr+0] = wdata[07:00];
if(wstrb[7]) mem[awaddr+7] = wdata[63:56];
if(wstrb[6]) mem[awaddr+6] = wdata[55:48];
if(wstrb[5]) mem[awaddr+5] = wdata[47:40];
if(wstrb[4]) mem[awaddr+4] = wdata[39:32];
if(wstrb[3]) mem[awaddr+3] = wdata[31:24];
if(wstrb[2]) mem[awaddr+2] = wdata[23:16];
if(wstrb[1]) mem[awaddr+1] = wdata[15:08];
if(wstrb[0]) mem[awaddr+0] = wdata[07:00];
end
end
@ -193,3 +222,4 @@ assign rlast = 1'b1;
endmodule
`endif

View File

@ -1,35 +1,6 @@
#include "defines.h"
#define ITERATIONS 1
extern int STACK;
void main();
#define STDOUT 0xd0580000
__asm (".section .text");
__asm (".global _start");
__asm ("_start:");
// Enable Caches in MRAC
__asm ("li t0, 0x5f555555");
__asm ("csrw 0x7c0, t0");
// Set stack pointer.
__asm ("la sp, STACK");
__asm ("jal main");
// Write 0xff to STDOUT for TB to termiate test.
__asm (".global _finish");
__asm ("_finish:");
__asm ("li t0, 0xd0580000");
__asm ("addi t1, zero, 0xff");
__asm ("sb t1, 0(t0)");
__asm ("beq x0, x0, _finish");
__asm (".rept 10");
__asm ("nop");
__asm (".endr");
/*
@ -1200,7 +1171,7 @@ MAIN_RETURN_TYPE main(int argc, char *argv[]) {
ee_printf("Total time (secs): %d\n",time_in_secs(total_time));
if (time_in_secs(total_time) > 0)
// ee_printf("Iterations/Sec : %d\n",default_num_contexts*results[0].iterations/time_in_secs(total_time));
ee_printf("Iterat/Sec/MHz : %d.%d\n",1000*default_num_contexts*results[0].iterations/time_in_secs(total_time),
ee_printf("Iterat/Sec/MHz : %d.%02d\n",1000*default_num_contexts*results[0].iterations/time_in_secs(total_time),
100000*default_num_contexts*results[0].iterations/time_in_secs(total_time) % 100);
#endif
if (time_in_secs(total_time) < 10) {
@ -2182,213 +2153,6 @@ void portable_fini(core_portable *p)
}
#include <stdarg.h>
// Special address. Writing (store byte instruction) to this address
// causes the simulator to write to the console.
volatile char __whisper_console_io = 0;
static int
whisperPutc(char c)
{
// __whisper_console_io = c;
// __whisper_console_io = c;
*(volatile char*)(STDOUT) = c;
return c;
}
static int
whisperPuts(const char* s)
{
while (*s)
whisperPutc(*s++);
return 1;
}
static int
whisperPrintDecimal(int value)
{
char buffer[20];
int charCount = 0;
unsigned neg = value < 0;
if (neg)
{
value = -value;
whisperPutc('-');
}
do
{
char c = '0' + (value % 10);
value = value / 10;
buffer[charCount++] = c;
}
while (value);
char* p = buffer + charCount - 1;
for (unsigned i = 0; i < charCount; ++i)
whisperPutc(*p--);
if (neg)
charCount++;
return charCount;
}
static int
whisperPrintInt(int value, int base)
{
if (base == 10)
return whisperPrintDecimal(value);
char buffer[20];
int charCount = 0;
unsigned uu = value;
if (base == 8)
{
do
{
char c = '0' + (uu & 7);
buffer[charCount++] = c;
uu >>= 3;
}
while (uu);
}
else if (base == 16)
{
do
{
int digit = uu & 0xf;
char c = digit < 10 ? '0' + digit : 'a' + digit;
buffer[charCount++] = c;
uu >>= 4;
}
while (uu);
}
else
return -1;
char* p = buffer + charCount - 1;
for (unsigned i = 0; i < charCount; ++i)
whisperPutc(*p--);
return charCount;
}
int
whisperPrintfImpl(const char* format, va_list ap)
{
int count = 0; // Printed character count
for (const char* fp = format; *fp; fp++)
{
if (*fp != '%')
{
whisperPutc(*fp);
++count;
continue;
}
++fp; // Skip %
if (*fp == 0)
break;
if (*fp == '%')
{
whisperPutc('%');
continue;
}
if (*fp == '-')
{
fp++; // Pad right not yet implemented.
}
while (*fp == '0')
{
fp++; // Pad zero not yet implented.
}
if (*fp == '*')
{
int width = va_arg(ap, int);
fp++; // Width not yet implemented.
}
else
{
while (*fp >= '0' && *fp <= '9')
++fp; // Width not yet implemented.
}
switch (*fp)
{
case 'd':
count += whisperPrintDecimal(va_arg(ap, int));
break;
case 'u':
count += whisperPrintDecimal((unsigned) va_arg(ap, unsigned));
break;
case 'x':
case 'X':
count += whisperPrintInt(va_arg(ap, int), 16);
break;
case 'o':
count += whisperPrintInt(va_arg(ap, int), 8);
break;
case 'c':
whisperPutc(va_arg(ap, int));
++count;
break;
case 's':
count += whisperPuts(va_arg(ap, char*));
break;
}
}
return count;
}
int
whisperPrintf(const char* format, ...)
{
va_list ap;
va_start(ap, format);
int code = whisperPrintfImpl(format, ap);
va_end(ap);
return code;
}
int
printf(const char* format, ...)
{
va_list ap;
va_start(ap, format);
int code = whisperPrintfImpl(format, ap);
va_end(ap);
return code;
}
void* memset(void* s, int c, size_t n)
{
asm("mv t0, a0");

1
testbench/asm/cmark.ld Symbolic link
View File

@ -0,0 +1 @@
hello_world.ld

2
testbench/asm/cmark.mki Normal file
View File

@ -0,0 +1,2 @@
TEST_CFLAGS = -finline-limit=400 -mbranch-cost=1 -Ofast -fno-code-hoisting -funroll-all-loops
OFILES = crt0.o printf.o cmark.o

View File

@ -0,0 +1 @@
cmark.mki

View File

@ -1,17 +1,18 @@
OUTPUT_ARCH( "riscv" )
ENTRY(_start)
MEMORY {
EXTCODE : ORIGIN = 0, LENGTH = 0x10000
EXTDATA : ORIGIN = 0x10000, LENGTH = 0x10000
ICCM : ORIGIN = 0xee000000, LENGTH = 0x80000
DCCM : ORIGIN = 0xf0040000, LENGTH = 0x10000
}
SECTIONS {
.text_init : {*(.text_init)} > EXTCODE
init_end = .;
.data.ctl : AT(0x1ffec) { LONG(ADDR(.text)); LONG(text_end); LONG(LOADADDR(.text)); LONG(0xf0040000); LONG(STACK)}>EXTDATA
.text : AT(init_end) { *(.text) *(.text.startup)} > ICCM
text_end = .;
.data : AT(0x10000) { *(.*data) *(.rodata*) STACK = ALIGN(16) + 0x8000;} > DCCM
.text : { crt0.o (.text*) }
_end = .;
. = 0xee000000 ;
.text.init : { cmark.o (.text*) }
. = 0xd0580000;
.data.io . : { *(.data.io) }
. = 0xf0040000;
.data : { *(.*data) *(.rodata*) *(.sbss) STACK = ALIGN(16) + 0x1000;}
.bss : { *(.bss) }
. = 0xfffffff0;
.iccm.ctl : { LONG(0xee000000); LONG(0xee008000) }
. = 0xfffffff8;
.data.ctl : { LONG(0xf0040000); LONG(STACK) }
}

View File

@ -0,0 +1,2 @@
TEST_CFLAGS = -g -O3 -funroll-all-loops
OFILES = crt0.o printf.o cmark.o

48
testbench/asm/crt0.s Normal file
View File

@ -0,0 +1,48 @@
# SPDX-License-Identifier: Apache-2.0
# Copyright 2020 Western Digital Corporation or its affiliates.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
// startup code to support HLL programs
#include "defines.h"
.section .text.init
.global _start
_start:
// enable caching, except region 0xd
li t0, 0x59555555
csrw 0x7c0, t0
la sp, STACK
call main
.global _finish
_finish:
la t0, tohost
li t1, 0xff
sb t1, 0(t0) // DemoTB test termination
li t1, 1
sw t1, 0(t0) // Whisper test termination
beq x0, x0, _finish
.rept 10
nop
.endr
.section .data.io
.global tohost
tohost: .word 0

View File

@ -0,0 +1,12 @@
OUTPUT_ARCH( "riscv" )
ENTRY(_start)
SECTIONS {
. = 0x80000000;
.text : { *(.text*) }
_end = .;
.data : { *(.*data) *(.rodata*) *(.sbss) STACK = ALIGN(16) + 0x1000;}
.bss : { *(.bss) }
. = 0xd0580000;
.data.io . : { *(.data.io) }
}

View File

@ -1,12 +1,14 @@
OUTPUT_ARCH( "riscv" )
ENTRY(_start)
SECTIONS {
.text : { *(.text*) }
_end = .;
. = 0x1fff8;
.data.ctl : { LONG(0xf0040000); LONG(STACK) }
. = 0xd0580000;
.data.io . : { *(.data.io) }
. = 0xf0040000;
.data : AT(0x10000) { *(.*data) *(.rodata*) STACK = ALIGN(16) + 0x8000;}
.data : { *(.*data) *(.rodata*) *(.sbss) STACK = ALIGN(16) + 0x1000;}
.bss : { *(.bss) }
. = 0xfffffff8;
.data.ctl : { LONG(0xf0040000); LONG(STACK) }
}

310
testbench/asm/printf.c Normal file
View File

@ -0,0 +1,310 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 Western Digital Corporation or its affiliates.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#include <stdarg.h>
#include <stdint.h>
extern volatile char tohost;
static int
whisperPutc(char c)
{
tohost = c;
return c;
}
static int
whisperPuts(const char* s)
{
while (*s)
whisperPutc(*s++);
return 1;
}
static int
whisperPrintUnsigned(unsigned value, int width, char pad)
{
char buffer[20];
int charCount = 0;
do
{
char c = '0' + (value % 10);
value = value / 10;
buffer[charCount++] = c;
}
while (value);
for (int i = charCount; i < width; ++i)
whisperPutc(pad);
char* p = buffer + charCount - 1;
for (int i = 0; i < charCount; ++i)
whisperPutc(*p--);
return charCount;
}
static int
whisperPrintDecimal(int value, int width, char pad)
{
char buffer[20];
int charCount = 0;
unsigned neg = value < 0;
if (neg)
{
value = -value;
whisperPutc('-');
width--;
}
do
{
char c = '0' + (value % 10);
value = value / 10;
buffer[charCount++] = c;
}
while (value);
for (int i = charCount; i < width; ++i)
whisperPutc(pad);
char* p = buffer + charCount - 1;
for (int i = 0; i < charCount; ++i)
whisperPutc(*p--);
if (neg)
charCount++;
return charCount;
}
static int
whisperPrintInt(int value, int width, int pad, int base)
{
if (base == 10)
return whisperPrintDecimal(value, width, pad);
char buffer[20];
int charCount = 0;
unsigned uu = value;
if (base == 8)
{
do
{
char c = '0' + (uu & 7);
buffer[charCount++] = c;
uu >>= 3;
}
while (uu);
}
else if (base == 16)
{
do
{
int digit = uu & 0xf;
char c = digit < 10 ? '0' + digit : 'a' + digit - 10;
buffer[charCount++] = c;
uu >>= 4;
}
while (uu);
}
else
return -1;
char* p = buffer + charCount - 1;
for (unsigned i = 0; i < charCount; ++i)
whisperPutc(*p--);
return charCount;
}
/*
// Print with g format
static int
whisperPrintDoubleG(double value)
{
return 0;
}
// Print with f format
static int
whisperPrintDoubleF(double value)
{
return 0;
}
*/
int
whisperPrintfImpl(const char* format, va_list ap)
{
int count = 0; // Printed character count
for (const char* fp = format; *fp; fp++)
{
char pad = ' ';
int width = 0; // Field width
if (*fp != '%')
{
whisperPutc(*fp);
++count;
continue;
}
++fp; // Skip %
if (*fp == 0)
break;
if (*fp == '%')
{
whisperPutc('%');
continue;
}
while (*fp == '0')
{
pad = '0';
fp++; // Pad zero not yet implented.
}
if (*fp == '-')
{
fp++; // Pad right not yet implemented.
}
if (*fp == '*')
{
int outWidth = va_arg(ap, int);
fp++; // Width not yet implemented.
}
else if (*fp >= '0' && *fp <= '9')
{ // Width not yet implemented.
while (*fp >= '0' && *fp <= '9')
width = width * 10 + (*fp++ - '0');
}
switch (*fp)
{
case 'd':
count += whisperPrintDecimal(va_arg(ap, int), width, pad);
break;
case 'u':
count += whisperPrintUnsigned((unsigned) va_arg(ap, unsigned), width, pad);
break;
case 'x':
case 'X':
count += whisperPrintInt(va_arg(ap, int), width, pad, 16);
break;
case 'o':
count += whisperPrintInt(va_arg(ap, int), width, pad, 8);
break;
case 'c':
whisperPutc(va_arg(ap, int));
++count;
break;
case 's':
count += whisperPuts(va_arg(ap, char*));
break;
/*
case 'g':
count += whisperPrintDoubleG(va_arg(ap, double));
break;
case 'f':
count += whisperPrintDoubleF(va_arg(ap, double));
*/
}
}
return count;
}
int
whisperPrintf(const char* format, ...)
{
va_list ap;
va_start(ap, format);
int code = whisperPrintfImpl(format, ap);
va_end(ap);
return code;
}
int
putchar(int c)
{
return whisperPutc(c);
}
struct FILE;
int
putc(int c, struct FILE* f)
{
return whisperPutc(c);
}
int
puts(const char* s)
{
return whisperPuts(s);
}
int
printf(const char* format, ...)
{
va_list ap;
va_start(ap, format);
int code = whisperPrintfImpl(format, ap);
va_end(ap);
return code;
}
// function to read cpu mcycle csr for performance measurements
// simplified version
uint64_t get_mcycle(){
unsigned int mcyclel;
unsigned int mcycleh0 = 0, mcycleh1=1;
uint64_t cycles;
while(mcycleh0 != mcycleh1) {
asm volatile ("csrr %0,mcycleh" : "=r" (mcycleh0) );
asm volatile ("csrr %0,mcycle" : "=r" (mcyclel) );
asm volatile ("csrr %0,mcycleh" : "=r" (mcycleh1) );
}
cycles = mcycleh1;
return (cycles << 32) | mcyclel;
}

374
testbench/dasm.svi Normal file
View File

@ -0,0 +1,374 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2019 Western Digital Corporation or its affiliates.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Run time disassembler functions
// supports RISCV extentions I, C, M
bit[31:0] gpr[32];
// main DASM function
function string dasm(input[31:0] opcode, input[31:0] pc, input[4:0] regn, input[31:0] regv);
if(regn) gpr[regn] = regv;
if( opcode[1:0] == 2'b11 ) return dasm32(opcode, pc);
else return dasm16(opcode, pc);
endfunction
///////////////// 16 bits instructions ///////////////////////
function string dasm16( input[31:0] opcode, input[31:0] pc);
case(opcode[1:0])
0: return dasm16_0(opcode);
1: return dasm16_1(opcode, pc);
2: return dasm16_2(opcode);
endcase
return $sformatf(".short 0x%h", opcode[15:0]);
endfunction
function string dasm16_0( input[31:0] opcode);
case(opcode[15:13])
3'b000: return dasm16_ciw(opcode);
3'b001: return {"c.fld", dasm16_cl(opcode)};
3'b010: return {"c.lw", dasm16_cl(opcode)};
3'b011: return {"c.flw", dasm16_cl(opcode)};
3'b101: return {"c.fsd", dasm16_cl(opcode)};
3'b110: return {"c.sw", dasm16_cl(opcode)};
3'b111: return {"c.fsw", dasm16_cl(opcode)};
endcase
return $sformatf(".short 0x%h", opcode[15:0]);
endfunction
function string dasm16_ciw( input[31:0] opcode);
int imm;
imm=0;
if(opcode[15:0] == 0) return ".short 0";
{imm[5:4],imm[9:6],imm[2],imm[3]} = opcode[12:5];
return $sformatf("c.addi4spn %s, 0x%0h", abi_reg[opcode[4:2]+8], imm);
endfunction
function string dasm16_cl( input[31:0] opcode);
int imm;
imm=0;
imm[5:3] = opcode[12:10];
imm[7:6] = opcode[6:5];
return $sformatf(" %s, %0d(%s) [%h]", abi_reg[opcode[4:2]+8], imm, abi_reg[opcode[9:7]+8], gpr[opcode[9:7]+8]+imm);
endfunction
function string dasm16_1( input[31:0] opcode, input[31:0] pc);
case(opcode[15:13])
3'b000: return opcode[11:7]==0 ? "c.nop" : {"c.addi",dasm16_ci(opcode)};
3'b001: return {"c.jal", dasm16_cj(opcode, pc)};
3'b010: return {"c.li", dasm16_ci(opcode)};
3'b011: return dasm16_1_3(opcode);
3'b100: return dasm16_cr(opcode);
3'b101: return {"c.j", dasm16_cj(opcode, pc)};
3'b110: return {"c.beqz", dasm16_cb(opcode, pc)};
3'b111: return {"c.bnez", dasm16_cb(opcode, pc)};
endcase
endfunction
function string dasm16_ci( input[31:0] opcode);
int imm;
imm=0;
imm[4:0] = opcode[6:2];
if(opcode[12]) imm [31:5] = '1;
return $sformatf(" %s, %0d", abi_reg[opcode[11:7]], imm);
endfunction
function string dasm16_cj( input[31:0] opcode, input[31:0] pc);
bit[31:0] imm;
imm=0;
{imm[11],imm[4],imm[9:8],imm[10],imm[6], imm[7],imm[3:1], imm[5]} = opcode[12:2];
if(opcode[12]) imm [31:12] = '1;
return $sformatf(" 0x%h", imm+pc);
endfunction
function string dasm16_cb( input[31:0] opcode, input[31:0] pc);
bit[31:0] imm;
imm=0;
{imm[11],imm[4:3]} = opcode[12:10];
{imm[7], imm[6],imm[2:1], imm[5]} = opcode[6:2];
if(opcode[12]) imm [31:9] = '1;
return $sformatf(" %s, 0x%h",abi_reg[opcode[9:7]+8], imm+pc);
endfunction
function string dasm16_cr( input[31:0] opcode);
bit[31:0] imm;
imm = 0;
imm[4:0] = opcode[6:2];
if(opcode[5]) imm [31:5] = '1;
case(opcode[11:10])
0: return $sformatf("c.srli %s, %0d", abi_reg[opcode[9:7]+8], imm[5:0]);
1: return $sformatf("c.srai %s, %0d", abi_reg[opcode[9:7]+8], imm[5:0]);
2: return $sformatf("c.andi %s, 0x%h", abi_reg[opcode[9:7]+8], imm);
endcase
case(opcode[6:5])
0: return $sformatf("c.sub %s, %s", abi_reg[opcode[9:7]+8], abi_reg[opcode[4:2]+8]);
1: return $sformatf("c.xor %s, %s", abi_reg[opcode[9:7]+8], abi_reg[opcode[4:2]+8]);
2: return $sformatf("c.or %s, %s", abi_reg[opcode[9:7]+8], abi_reg[opcode[4:2]+8]);
3: return $sformatf("c.and %s, %s", abi_reg[opcode[9:7]+8], abi_reg[opcode[4:2]+8]);
endcase
endfunction
function string dasm16_1_3( input[31:0] opcode);
int imm;
imm=0;
if(opcode[11:7] == 2) begin
{imm[4], imm[6],imm[8:7], imm[5]} = opcode[6:2];
if(opcode[12]) imm [31:9] = '1;
return $sformatf("c.addi16sp %0d", imm);
end
else begin
// {imm[4], imm[6],imm[8:7], imm[5]} = opcode[6:2];
imm[16:12] = opcode[6:2];
if(opcode[12]) imm [31:17] = '1;
return $sformatf("c.lui %3s, 0x%h", abi_reg[opcode[11:7]], imm);
end
endfunction
function string dasm16_2( input[31:0] opcode);
case(opcode[15:13])
3'b000: return {"c.slli", dasm16_ci(opcode)};
3'b001: return {"c.fldsp", dasm16_cls(opcode,1)};
3'b010: return {"c.lwsp", dasm16_cls(opcode)};
3'b011: return {"c.flwsp", dasm16_cls(opcode)};
3'b101: return {"c.fsdsp", dasm16_css(opcode,1)};
3'b110: return {"c.swsp", dasm16_css(opcode)};
3'b111: return {"c.fswsp", dasm16_css(opcode)};
endcase
if(opcode[12]) begin
if(opcode[12:2] == 0) return "c.ebreak";
else if(opcode[6:2] == 0) return $sformatf("c.jalr %s", abi_reg[opcode[11:7]]);
else return $sformatf("c.add %s, %s", abi_reg[opcode[11:7]], abi_reg[opcode[6:2]]);
end
else begin
if(opcode[6:2] == 0) return $sformatf("c.jr %s", abi_reg[opcode[11:7]]);
else return $sformatf("c.mv %s, %s", abi_reg[opcode[11:7]], abi_reg[opcode[6:2]]);
end
endfunction
function string dasm16_cls( input[31:0] opcode, input sh1=0);
bit[31:0] imm;
imm=0;
if(sh1) {imm[4:3],imm[8:6]} = opcode[6:2];
else {imm[4:2],imm[7:6]} = opcode[6:2];
imm[5] = opcode[12];
return $sformatf(" %s, 0x%0h [%h]", abi_reg[opcode[11:7]], imm, gpr[2]+imm);
endfunction
function string dasm16_css( input[31:0] opcode, input sh1=0);
bit[31:0] imm;
imm=0;
if(sh1) {imm[5:3],imm[8:6]} = opcode[12:7];
else {imm[5:2],imm[7:6]} = opcode[12:7];
return $sformatf(" %s, 0x%0h [%h]", abi_reg[opcode[6:2]], imm, gpr[2]+imm);
endfunction
///////////////// 32 bit instructions ///////////////////////
function string dasm32( input[31:0] opcode, input[31:0] pc);
case(opcode[6:0])
7'b0110111: return {"lui", dasm32_u(opcode)};
7'b0010111: return {"auipc", dasm32_u(opcode)};
7'b1101111: return {"jal", dasm32_j(opcode,pc)};
7'b1100111: return {"jalr", dasm32_jr(opcode,pc)};
7'b1100011: return dasm32_b(opcode,pc);
7'b0000011: return dasm32_l(opcode);
7'b0100011: return dasm32_s(opcode);
7'b0010011: return dasm32_ai(opcode);
7'b0110011: return dasm32_ar(opcode);
7'b0001111: return {"fence", dasm32_fence(opcode)};
7'b1110011: return dasm32_e(opcode);
endcase
return $sformatf(".long 0x%h", opcode);
endfunction
function string dasm32_u( input[31:0] opcode);
bit[31:0] imm;
imm=0;
imm[31:12] = opcode[31:12];
return $sformatf(" %s, 0x%0h", abi_reg[opcode[11:7]], imm);
endfunction
function string dasm32_j( input[31:0] opcode, input[31:0] pc);
int imm;
imm=0;
{imm[20], imm[10:1], imm[11], imm[19:12]} = opcode[31:12];
if(opcode[31]) imm[31:20] = '1;
return $sformatf(" %s, 0x%0h",abi_reg[opcode[11:7]], imm+pc);
endfunction
function string dasm32_jr( input[31:0] opcode, input[31:0] pc);
int imm;
imm=0;
imm[11:1] = opcode[31:19];
if(opcode[31]) imm[31:12] = '1;
return $sformatf(" %s, %s, 0x%0h",abi_reg[opcode[11:7]], abi_reg[opcode[19:15]], imm+pc);
endfunction
function string dasm32_b( input[31:0] opcode, input[31:0] pc);
int imm;
string mn;
imm=0;
{imm[12],imm[10:5]} = opcode[31:25];
{imm[4:1],imm[11]} = opcode[11:7];
if(opcode[31]) imm[31:12] = '1;
case(opcode[14:12])
0: mn = "beq";
1: mn = "bne";
2,3 : return $sformatf(".long 0x%h", opcode);
4: mn = "blt";
5: mn = "bge";
6: mn = "bltu";
7: mn = "bgeu";
endcase
return $sformatf("%s %s, %s, 0x%0h", mn, abi_reg[opcode[11:7]], abi_reg[opcode[19:15]], imm+pc);
endfunction
function string dasm32_l( input[31:0] opcode);
int imm;
string mn;
imm=0;
imm[11:0] = opcode[31:20];
if(opcode[31]) imm[31:12] = '1;
case(opcode[14:12])
0: mn = "lb";
1: mn = "lh";
2: mn = "lw";
4: mn = "lbu";
5: mn = "lhu";
default : return $sformatf(".long 0x%h", opcode);
endcase
return $sformatf("%s %s, %0d(%s) [%h]", mn, abi_reg[opcode[11:7]], imm, abi_reg[opcode[19:15]], imm+gpr[opcode[19:15]]);
endfunction
function string dasm32_s( input[31:0] opcode);
int imm;
string mn;
imm=0;
imm[11:5] = opcode[31:25];
imm[4:0] = opcode[11:7];
if(opcode[31]) imm[31:12] = '1;
case(opcode[14:12])
0: mn = "sb";
1: mn = "sh";
2: mn = "sw";
default : return $sformatf(".long 0x%h", opcode);
endcase
return $sformatf("%s %s, %0d(%s) [%h]", mn, abi_reg[opcode[24:20]], imm, abi_reg[opcode[19:15]], imm+gpr[opcode[19:15]]);
endfunction
function string dasm32_ai( input[31:0] opcode);
int imm;
string mn;
imm=0;
imm[11:0] = opcode[31:20];
if(opcode[31]) imm[31:12] = '1;
case(opcode[14:12])
0: mn = "addi";
2: mn = "slti";
3: mn = "sltiu";
4: mn = "xori";
6: mn = "ori";
7: mn = "andi";
default: return dasm32_si(opcode);
endcase
return $sformatf("%s %s, %s, %0d", mn, abi_reg[opcode[11:7]], abi_reg[opcode[19:15]], imm);
endfunction
function string dasm32_si( input[31:0] opcode);
int imm;
string mn;
imm = opcode[24:20];
case(opcode[14:12])
1: mn = "slli";
5: mn = opcode[30] ? "srli": "srai";
endcase
return $sformatf("%s %s, %s, %0d", mn, abi_reg[opcode[11:7]], abi_reg[opcode[19:15]], imm);
endfunction
function string dasm32_ar( input[31:0] opcode);
string mn;
if(opcode[25])
case(opcode[14:12])
0: mn = "mul";
1: mn = "mulh";
2: mn = "mulhsu";
3: mn = "mulhu";
4: mn = "div";
5: mn = "divu";
6: mn = "rem";
7: mn = "remu";
endcase
else
case(opcode[14:12])
0: mn = opcode[30]? "sub":"add";
1: mn = "sll";
2: mn = "slt";
3: mn = "sltu";
4: mn = "xor";
5: mn = opcode[30]? "sra" :"srl";
6: mn = "or";
7: mn = "and";
endcase
return $sformatf("%s %s, %s, %s", mn, abi_reg[opcode[11:7]], abi_reg[opcode[19:15]], abi_reg[opcode[24:20]]);
endfunction
function string dasm32_fence( input[31:0] opcode);
return opcode[12] ? ".i" : "";
endfunction
function string dasm32_e(input[31:0] opcode);
if(opcode[31:7] == 0) return "ecall";
else if({opcode[31:21],opcode [19:7]} == 0) return "ebreak";
else
case(opcode[14:12])
1: return {"csrrw", dasm32_csr(opcode)};
2: return {"csrrs", dasm32_csr(opcode)};
3: return {"csrrc", dasm32_csr(opcode)};
5: return {"csrrwi", dasm32_csr(opcode, 1)};
6: return {"csrrsi", dasm32_csr(opcode, 1)};
7: return {"csrrci", dasm32_csr(opcode, 1)};
endcase
endfunction
function string dasm32_csr(input[31:0] opcode, input im=0);
bit[11:0] csr;
csr = opcode[31:20];
if(im) begin
return $sformatf(" %s, csr_%0h, 0x%h", abi_reg[opcode[11:7]], csr, opcode[19:15]);
end
else begin
return $sformatf(" %s, csr_%0h, %s", abi_reg[opcode[11:7]], csr, abi_reg[opcode[19:15]]);
end
endfunction

View File

@ -1,5 +1,7 @@
+libext+.v+.sv
//-y $SYNOPSYS_SYN_ROOT/dw/sim_ver
+define+RV_OPENSOURCE
+incdir+$RV_ROOT/testbench
$RV_ROOT/design/el2_swerv_wrapper.sv
$RV_ROOT/design/el2_mem.sv
$RV_ROOT/design/el2_pic_ctrl.sv

2251
testbench/hex/cmark.hex Executable file

File diff suppressed because it is too large Load Diff

2251
testbench/hex/cmark_dccm.hex Executable file

File diff suppressed because it is too large Load Diff

2254
testbench/hex/cmark_iccm.hex Executable file

File diff suppressed because it is too large Load Diff

26
testbench/hex/hello_world.hex Executable file
View File

@ -0,0 +1,26 @@
@80000000
73 10 20 B0 73 10 20 B8 B7 00 00 EE 73 90 50 30
B7 50 55 5F 93 80 50 55 73 90 00 7C B7 01 58 D0
17 02 00 00 13 02 E2 0E 83 02 02 00 23 80 51 00
05 02 E3 9B 02 FE B7 01 58 D0 93 02 F0 0F 23 80
51 00 E3 0A 00 FE 01 00 01 00 01 00 01 00 01 00
01 00 01 00 01 00 01 00 01 00 01 00 01 00 01 00
01 00 01 00 01 00 01 00 01 00 01 00 01 00 01 00
01 00 01 00 01 00 01 00 01 00 01 00 01 00 01 00
01 00 01 00 01 00 01 00 01 00 01 00 01 00 01 00
01 00 01 00 01 00 01 00 01 00 01 00 01 00 01 00
01 00 01 00 01 00 01 00 01 00 01 00 01 00 01 00
01 00 01 00 01 00 01 00 01 00 01 00 01 00 01 00
01 00 01 00 01 00 01 00 01 00 01 00 01 00 01 00
01 00 01 00 01 00 01 00 01 00 01 00 01 00 01 00
01 00 01 00 01 00 01 00 01 00 01 00 01 00 01 00
01 00 01 00 01 00 01 00 01 00 01 00 01 00 01 00
01 00 01 00 01 00 01 00 01 00 01 00 01 00
@8000010E
2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D
2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D
2D 2D 0A 48 65 6C 6C 6F 20 57 6F 72 6C 64 20 66
72 6F 6D 20 53 77 65 52 56 20 45 4C 32 20 40 57
44 43 20 21 21 0A 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D
2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D
2D 2D 2D 2D 2D 2D 2D 2D 0A 00

View File

@ -0,0 +1,28 @@
@00000000
73 10 20 B0 73 10 20 B8 B7 00 00 EE 73 90 50 30
B7 50 55 5F 93 80 50 55 73 90 00 7C B7 01 58 D0
17 02 04 F0 13 02 02 FE 83 02 02 00 23 80 51 00
05 02 E3 9B 02 FE B7 01 58 D0 93 02 F0 0F 23 80
51 00 E3 0A 00 FE 01 00 01 00 01 00 01 00 01 00
01 00 01 00 01 00 01 00 01 00 01 00 01 00 01 00
01 00 01 00 01 00 01 00 01 00 01 00 01 00 01 00
01 00 01 00 01 00 01 00 01 00 01 00 01 00 01 00
01 00 01 00 01 00 01 00 01 00 01 00 01 00 01 00
01 00 01 00 01 00 01 00 01 00 01 00 01 00 01 00
01 00 01 00 01 00 01 00 01 00 01 00 01 00 01 00
01 00 01 00 01 00 01 00 01 00 01 00 01 00 01 00
01 00 01 00 01 00 01 00 01 00 01 00 01 00 01 00
01 00 01 00 01 00 01 00 01 00 01 00 01 00 01 00
01 00 01 00 01 00 01 00 01 00 01 00 01 00 01 00
01 00 01 00 01 00 01 00 01 00 01 00 01 00 01 00
01 00 01 00 01 00 01 00 01 00 01 00 01 00
@F0040000
2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D
2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D
2D 2D 0A 48 65 6C 6C 6F 20 57 6F 72 6C 64 20 66
72 6F 6D 20 53 77 65 52 56 20 45 4C 32 20 40 57
44 43 20 21 21 0A 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D
2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D
2D 2D 2D 2D 2D 2D 2D 2D 0A 00
@FFFFFFF8
00 00 04 F0 70 10 04 F0

View File

@ -0,0 +1,32 @@
@00000000
B7 50 55 5F 93 80 50 55 73 90 00 7C 91 41 73 90
91 7F B7 01 00 EE 17 02 01 00 13 02 62 06 97 02
01 00 93 82 E2 08 03 23 02 00 23 A0 61 00 11 02
91 01 E3 6A 52 FE 0F 10 00 00 97 00 00 EE E7 80
60 FC B7 01 58 D0 93 02 F0 0F 23 80 51 00 E3 0A
00 FE 01 00 01 00 01 00 01 00 01 00 01 00 01 00
01 00 01 00 01 00 01 00 01 00 01 00 01 00 01 00
01 00 01 00 01 00 01 00 01 00 01 00 01 00 01 00
01 00 01 00 01 00 01 00 01 00 01 00 01 00 01 00
01 00 01 00 01 00 01 00 01 00 01 00 01 00 01 00
01 00 01 00 01 00 01 00 01 00 01 00 01 00 01 00
01 00 01 00 01 00 01 00 01 00 01 00 01 00 01 00
01 00 01 00 01 00 01 00 01 00 01 00 01 00 01 00
01 00 01 00 01 00 01 00 01 00 01 00 01 00 01 00
01 00 01 00 01 00 01 00 01 00 01 00 01 00 01 00
01 00 01 00 01 00 01 00 01 00 01 00 01 00 01 00
01 00 01 00 01 00 01 00 01 00 01 00 01 00 01 00
01 00 01 00 01 00 01 00 01 00
@00010000
2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D
2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D
2D 2D 2D 2D 2D 2D 2D 2D 0A 48 65 6C 6C 6F 20 57
6F 72 6C 64 20 66 72 6F 6D 20 53 77 65 52 56 20
45 4C 32 20 49 43 43 4D 20 20 40 57 44 43 20 21
21 0A 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D
2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D
2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 0A 00
@0001007C
B7 01 58 D0 17 02 01 12 13 02 C2 FF 83 02 02 00
23 80 51 00 05 02 E3 9B 02 FE 82 80 00 00 00 00
01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00

View File

@ -1,4 +1,4 @@
database -open waves -into waves.shm -default
probe -create tb_top -depth all -database waves
probe -create tb_top -depth all -database waves -memories -all
run
exit

209
testbench/remote_bitbang.cc Normal file
View File

@ -0,0 +1,209 @@
// See LICENSE.Berkeley for license details.
#include <arpa/inet.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <algorithm>
#include <cassert>
#include <cstdio>
#include <cstdlib>
#include "remote_bitbang.h"
/////////// remote_bitbang_t
remote_bitbang_t::remote_bitbang_t(uint16_t port) :
err(0),
socket_fd(0),
client_fd(0),
recv_start(0),
recv_end(0)
{
socket_fd = socket(AF_INET, SOCK_STREAM, 0);
if (socket_fd == -1) {
fprintf(stderr, "remote_bitbang failed to make socket: %s (%d)\n",
strerror(errno), errno);
abort();
}
fcntl(socket_fd, F_SETFL, O_NONBLOCK);
int reuseaddr = 1;
if (setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr,
sizeof(int)) == -1) {
fprintf(stderr, "remote_bitbang failed setsockopt: %s (%d)\n",
strerror(errno), errno);
abort();
}
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = htons(port);
if (::bind(socket_fd, (struct sockaddr *) &addr, sizeof(addr)) == -1) {
fprintf(stderr, "remote_bitbang failed to bind socket: %s (%d)\n",
strerror(errno), errno);
abort();
}
if (listen(socket_fd, 1) == -1) {
fprintf(stderr, "remote_bitbang failed to listen on socket: %s (%d)\n",
strerror(errno), errno);
abort();
}
socklen_t addrlen = sizeof(addr);
if (getsockname(socket_fd, (struct sockaddr *) &addr, &addrlen) == -1) {
fprintf(stderr, "remote_bitbang getsockname failed: %s (%d)\n",
strerror(errno), errno);
abort();
}
tck = 1;
tms = 1;
tdi = 1;
trstn = 1;
quit = 0;
srstn = 1;
fprintf(stderr, "This emulator compiled with JTAG Remote Bitbang client. To enable, use +jtag_rbb_enable=1.\n");
fprintf(stderr, "Listening on port %d\n",
ntohs(addr.sin_port));
}
void remote_bitbang_t::accept()
{
fprintf(stderr,"Attempting to accept client socket\n");
int again = 1;
while (again != 0) {
client_fd = ::accept(socket_fd, NULL, NULL);
if (client_fd == -1) {
if (errno == EAGAIN) {
// No client waiting to connect right now.
} else {
fprintf(stderr, "failed to accept on socket: %s (%d)\n", strerror(errno),
errno);
again = 0;
abort();
}
} else {
fcntl(client_fd, F_SETFL, O_NONBLOCK);
fprintf(stderr, "Accepted successfully.");
again = 0;
}
}
}
void remote_bitbang_t::tick(
unsigned char * jtag_tck,
unsigned char * jtag_tms,
unsigned char * jtag_tdi,
unsigned char * jtag_trstn,
unsigned char * sysrstn,
unsigned char jtag_tdo
)
{
if (client_fd > 0) {
tdo = jtag_tdo;
execute_command();
} else {
this->accept();
}
* jtag_tck = tck;
* jtag_tms = tms;
* jtag_tdi = tdi;
* jtag_trstn = trstn;
* sysrstn = srstn;
}
void remote_bitbang_t::reset(char cmd){
trstn = ((cmd - 'r') & 2) ? 0 : 1;
srstn = ((cmd - 'r') & 1) ? 0 : 1;
}
void remote_bitbang_t::set_pins(char _tck, char _tms, char _tdi){
tck = _tck;
tms = _tms;
tdi = _tdi;
}
void remote_bitbang_t::execute_command()
{
char command;
int again = 1;
while (again) {
ssize_t num_read = read(client_fd, &command, sizeof(command));
if (num_read == -1) {
if (errno == EAGAIN) {
// We'll try again the next call.
//fprintf(stderr, "Received no command. Will try again on the next call\n");
} else {
fprintf(stderr, "remote_bitbang failed to read on socket: %s (%d)\n",
strerror(errno), errno);
again = 0;
abort();
}
} else if (num_read == 0) {
fprintf(stderr, "No Command Received.\n");
again = 1;
} else {
again = 0;
}
}
//fprintf(stderr, "Received a command %c\n", command);
int dosend = 0;
char tosend = '?';
switch (command) {
case 'B': /* fprintf(stderr, "*BLINK*\n"); */ break;
case 'b': /* fprintf(stderr, "_______\n"); */ break;
case 'r':
case 's':
case 'u':
case 't': reset(command); break;
case '0': set_pins(0, 0, 0); break;
case '1': set_pins(0, 0, 1); break;
case '2': set_pins(0, 1, 0); break;
case '3': set_pins(0, 1, 1); break;
case '4': set_pins(1, 0, 0); break;
case '5': set_pins(1, 0, 1); break;
case '6': set_pins(1, 1, 0); break;
case '7': set_pins(1, 1, 1); break;
case 'R': dosend = 1; tosend = tdo ? '1' : '0'; break;
case 'Q': quit = 1; break;
default:
fprintf(stderr, "remote_bitbang got unsupported command '%c'\n",
command);
}
if (dosend){
while (1) {
ssize_t bytes = write(client_fd, &tosend, sizeof(tosend));
if (bytes == -1) {
fprintf(stderr, "failed to write to socket: %s (%d)\n", strerror(errno), errno);
abort();
}
if (bytes > 0) {
break;
}
}
}
if (quit) {
// The remote disconnected.
fprintf(stderr, "Remote end disconnected\n");
close(client_fd);
client_fd = 0;
}
}

View File

@ -0,0 +1,61 @@
// See LICENSE.Berkeley for license details.
#ifndef REMOTE_BITBANG_H
#define REMOTE_BITBANG_H
#include <stdint.h>
#include <sys/types.h>
class remote_bitbang_t
{
public:
// Create a new server, listening for connections from localhost on the given
// port.
remote_bitbang_t(uint16_t port);
// Do a bit of work.
void tick(unsigned char * jtag_tck,
unsigned char * jtag_tms,
unsigned char * jtag_tdi,
unsigned char * jtag_trstn,
unsigned char * sysrstn,
unsigned char jtag_tdo);
unsigned char done() {return quit;}
int exit_code() {return err;}
private:
int err;
unsigned char tck;
unsigned char tms;
unsigned char tdi;
unsigned char trstn;
unsigned char srstn;
unsigned char tdo;
unsigned char quit;
int socket_fd;
int client_fd;
static const ssize_t buf_size = 64 * 1024;
char recv_buf[buf_size];
ssize_t recv_start, recv_end;
// Check for a client connecting, and accept if there is one.
void accept();
// Execute any commands the client has for us.
// But we only execute 1 because we need time for the
// simulation to run.
void execute_command();
// Reset. .
void reset(char cmd);
void set_pins(char _tck, char _tms, char _tdi);
};
#endif

View File

@ -13,10 +13,13 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//
`ifdef VERILATOR
module tb_top ( input bit core_clk );
`else
`ifndef VERILATOR
module tb_top;
`else
module tb_top ( input bit core_clk );
`endif
`ifndef VERILATOR
bit core_clk;
`endif
logic rst_l;
@ -65,10 +68,10 @@ module tb_top;
logic [31:0] trace_rv_i_insn_ip;
logic [31:0] trace_rv_i_address_ip;
logic [1:0] trace_rv_i_valid_ip;
logic [1:0] trace_rv_i_exception_ip;
logic trace_rv_i_valid_ip;
logic trace_rv_i_exception_ip;
logic [4:0] trace_rv_i_ecause_ip;
logic [1:0] trace_rv_i_interrupt_ip;
logic trace_rv_i_interrupt_ip;
logic [31:0] trace_rv_i_tval_ip;
logic o_debug_mode_status;
@ -92,15 +95,15 @@ module tb_top;
logic mpc_debug_run_ack;
logic debug_brkpt_status;
bit [31:0] cycleCnt;
int cycleCnt;
logic mailbox_data_val;
wire dma_hready_out;
int commit_count;
logic wb_valid[1:0];
logic [4:0] wb_dest[1:0];
logic [31:0] wb_data[1:0];
logic wb_valid;
logic [4:0] wb_dest;
logic [31:0] wb_data;
`ifdef RV_BUILD_AXI4
//-------------------------- LSU AXI signals--------------------------
@ -307,6 +310,7 @@ module tb_top;
`endif
wire[63:0] WriteData;
string abi_reg[32]; // ABI register names
assign mailbox_write = lmem.mailbox_write;
@ -345,40 +349,75 @@ module tb_top;
// trace monitor
always @(posedge core_clk) begin
wb_valid[0] <= rvtop.swerv.dec.dec_i0_wen_r;
wb_dest[0] <= rvtop.swerv.dec.dec_i0_waddr_r;
wb_data[0] <= rvtop.swerv.dec.dec_i0_wdata_r;
if (trace_rv_i_valid_ip !== 0) begin
wb_valid <= rvtop.swerv.dec.dec_i0_wen_r;
wb_dest <= rvtop.swerv.dec.dec_i0_waddr_r;
wb_data <= rvtop.swerv.dec.dec_i0_wdata_r;
if (trace_rv_i_valid_ip) begin
$fwrite(tp,"%b,%h,%h,%0h,%0h,3,%b,%h,%h,%b\n", trace_rv_i_valid_ip, 0, trace_rv_i_address_ip,
0, trace_rv_i_insn_ip,trace_rv_i_exception_ip,trace_rv_i_ecause_ip,
trace_rv_i_tval_ip,trace_rv_i_interrupt_ip);
// Basic trace - no exception register updates
// #1 0 ee000000 b0201073 c 0b02 00000000
for (int i=0; i<1; i++)
if (trace_rv_i_valid_ip[i]==1) begin
commit_count++;
$fwrite (el, "%10d : %6s 0 %h %h %s\n", cycleCnt, $sformatf("#%0d",commit_count),
trace_rv_i_address_ip[31+i*32 -:32], trace_rv_i_insn_ip[31+i*32-:32],
(wb_dest[i] !=0 && wb_data[0])? $sformatf("r%0d=%h", wb_dest[i], wb_data[i]) : "");
end
$fwrite (el, "%10d : %8s 0 %h %h%13s ; %s\n", cycleCnt, $sformatf("#%0d",commit_count),
trace_rv_i_address_ip, trace_rv_i_insn_ip,
(wb_dest !=0 && wb_valid)? $sformatf("%s=%h", abi_reg[wb_dest], wb_data) : " ",
dasm(trace_rv_i_insn_ip, trace_rv_i_address_ip, wb_dest & {5{wb_valid}}, wb_data)
);
end
if(rvtop.swerv.dec.dec_nonblock_load_wen)
$fwrite (el, "%10d : %32s=%h ; nbL\n", cycleCnt, abi_reg[rvtop.swerv.dec.dec_nonblock_load_waddr], rvtop.swerv.dec.lsu_nonblock_load_data);
if(rvtop.swerv.dec.exu_div_wren)
$fwrite (el, "%10d : %32s=%h ; nbD\n", cycleCnt, abi_reg[rvtop.swerv.dec.div_waddr_wb], rvtop.swerv.dec.exu_div_result);
end
initial begin
abi_reg[0] = "zero";
abi_reg[1] = "ra";
abi_reg[2] = "sp";
abi_reg[3] = "gp";
abi_reg[4] = "tp";
abi_reg[5] = "t0";
abi_reg[6] = "t1";
abi_reg[7] = "t2";
abi_reg[8] = "s0";
abi_reg[9] = "s1";
abi_reg[10] = "a0";
abi_reg[11] = "a1";
abi_reg[12] = "a2";
abi_reg[13] = "a3";
abi_reg[14] = "a4";
abi_reg[15] = "a5";
abi_reg[16] = "a6";
abi_reg[17] = "a7";
abi_reg[18] = "s2";
abi_reg[19] = "s3";
abi_reg[20] = "s4";
abi_reg[21] = "s5";
abi_reg[22] = "s6";
abi_reg[23] = "s7";
abi_reg[24] = "s8";
abi_reg[25] = "s9";
abi_reg[26] = "s10";
abi_reg[27] = "s11";
abi_reg[28] = "t3";
abi_reg[29] = "t4";
abi_reg[30] = "t5";
abi_reg[31] = "t6";
// tie offs
jtag_id[31:28] = 4'b1;
jtag_id[27:12] = '0;
jtag_id[11:1] = 11'h45;
reset_vector = 32'h0;
reset_vector = `RV_RESET_VEC;
nmi_vector = 32'hee000000;
nmi_int = 0;
$readmemh("data.hex", lmem.mem);
$readmemh("program.hex", lmem.mem);
$readmemh("program.hex", imem.mem);
tp = $fopen("trace_port.csv","w");
el = $fopen("exec.log","w");
$fwrite (el, "//Cycle : #inst 0 pc opcode reg regnum value\n");
$fwrite (el, "// Cycle : #inst 0 pc opcode reg=value ; mnemonic\n");
fd = $fopen("console.log","w");
commit_count = 0;
preload_dccm();
@ -691,6 +730,12 @@ el2_swerv_wrapper rvtop (
.dec_tlu_perfcnt2 (),
.dec_tlu_perfcnt3 (),
// remove mems DFT pins for opensource
.dccm_ext_in_pkt ('0),
.iccm_ext_in_pkt ('0),
.ic_data_ext_in_pkt ('0),
.ic_tag_ext_in_pkt ('0),
.soft_int ('0),
.core_id ('0),
.scan_mode ( 1'b0 ), // To enable scan mode
@ -900,16 +945,15 @@ axi_lsu_dma_bridge # (`RV_LSU_BUS_TAG,`RV_LSU_BUS_TAG ) bridge(
task preload_iccm;
bit[31:0] data;
bit[31:0] addr, eaddr, saddr, faddr;
int adr;
bit[31:0] addr, eaddr, saddr;
/*
addresses:
0xffec - ICCM start address to load
0xfff0 - ICCM end address to load
0xfff4 - imem start address
0xfffffff0 - ICCM start address to load
0xfffffff4 - ICCM end address to load
*/
addr = 'hffec;
addr = 'hffff_fff0;
saddr = {lmem.mem[addr+3],lmem.mem[addr+2],lmem.mem[addr+1],lmem.mem[addr]};
if ( (saddr < `RV_ICCM_SADR) || (saddr > `RV_ICCM_EADR)) return;
`ifndef RV_ICCM_ENABLE
@ -918,54 +962,50 @@ if ( (saddr < `RV_ICCM_SADR) || (saddr > `RV_ICCM_EADR)) return;
$display("********************************************************");
$finish;
`endif
init_iccm;
addr = 'hfff0;
addr += 4;
eaddr = {lmem.mem[addr+3],lmem.mem[addr+2],lmem.mem[addr+1],lmem.mem[addr]};
addr = 'hfff4;
faddr = {lmem.mem[addr+3],lmem.mem[addr+2],lmem.mem[addr+1],lmem.mem[addr]};
$display("ICCM pre-load from %h to %h", saddr, eaddr);
for(addr= saddr; addr <= eaddr; addr+=4) begin
adr = faddr & 'hffff;
data = {imem.mem[adr+3],imem.mem[adr+2],imem.mem[adr+1],imem.mem[adr]};
data = {imem.mem[addr+3],imem.mem[addr+2],imem.mem[addr+1],imem.mem[addr]};
slam_iccm_ram(addr, data == 0 ? 0 : {riscv_ecc32(data),data});
faddr+=4;
end
endtask
task preload_dccm;
bit[31:0] data;
bit[31:0] addr, eaddr;
int adr;
bit[31:0] addr, saddr, eaddr;
/*
addresses:
0xfff8 - DCCM start address to load
0xfffc - ICCM end address to load
0x0 - lmem start addres to load from
0xffff_fff8 - DCCM start address to load
0xffff_fffc - DCCM end address to load
*/
addr = 'hfff8;
eaddr = {lmem.mem[addr+3],lmem.mem[addr+2],lmem.mem[addr+1],lmem.mem[addr]};
if (eaddr != `RV_DCCM_SADR) return;
addr = 'hffff_fff8;
saddr = {lmem.mem[addr+3],lmem.mem[addr+2],lmem.mem[addr+1],lmem.mem[addr]};
if (saddr < `RV_DCCM_SADR || saddr > `RV_DCCM_EADR) return;
`ifndef RV_DCCM_ENABLE
$display("********************************************************");
$display("DCCM preload: there is no DCCM in SweRV, terminating !!!");
$display("********************************************************");
$finish;
`endif
addr = 'hfffc;
addr += 4;
eaddr = {lmem.mem[addr+3],lmem.mem[addr+2],lmem.mem[addr+1],lmem.mem[addr]};
$display("DCCM pre-load from %h to %h", `RV_DCCM_SADR, eaddr);
$display("DCCM pre-load from %h to %h", saddr, eaddr);
for(addr=`RV_DCCM_SADR; addr <= eaddr; addr+=4) begin
adr = addr & 'hffff;
data = {lmem.mem[adr+3],lmem.mem[adr+2],lmem.mem[adr+1],lmem.mem[adr]};
for(addr=saddr; addr <= eaddr; addr+=4) begin
data = {lmem.mem[addr+3],lmem.mem[addr+2],lmem.mem[addr+1],lmem.mem[addr]};
slam_dccm_ram(addr, data == 0 ? 0 : {riscv_ecc32(data),data});
end
endtask
`define ICCM_PATH `RV_TOP.mem.iccm.iccm
`ifdef VERILATOR
`define DRAM(bk) rvtop.mem.Gen_dccm_enable.dccm.mem_bank[bk].ram.ram_core
@ -1116,5 +1156,8 @@ function int get_iccm_bank(input[31:0] addr, output int bank_idx);
`endif
endfunction
/* verilator lint_off CASEINCOMPLETE */
`include "dasm.svi"
/* verilator lint_on CASEINCOMPLETE */
endmodule

View File

@ -0,0 +1,14 @@
export TEST = cmark
#export CONF_PARAMS= -set=btb_size=512 -set=bht_size=2048 -set=iccm_size=128
export CONF_PARAMS= -set=btb_size=512 -set=bht_size=2048 -set=iccm_enable=0
export OFILES = crt0.o cmark.o printf.o
export BUILD_PATH = $(shell pwd)/snapshots/default
export TEST_CFLAGS = -finline-limit=400 -mbranch-cost=1 -Ofast -fno-code-hoisting -funroll-all-loops
program.hex:
$(MAKE) -e -f $(RV_ROOT)/tools/make.common $(BUILD_PATH)/defines.h
$(MAKE) -e -f $(RV_ROOT)/tools/make.common $@
.DEFAULT:
$(MAKE) -e program.hex
$(MAKE) -e -f $(RV_ROOT)/tools/make.common $@

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,262 @@
#include <stdarg.h>
#include "defines.h"
static int
whisperPutc(char c)
{
// __whisper_console_io = c;
// __whisper_console_io = c;
*(volatile char*)(RV_SERIALIO) = c;
return c;
}
static int
whisperPuts(const char* s)
{
while (*s)
whisperPutc(*s++);
return 1;
}
static int
whisperPrintUnsigned(unsigned value, int width, char pad)
{
char buffer[20];
int charCount = 0;
do
{
char c = '0' + (value % 10);
value = value / 10;
buffer[charCount++] = c;
}
while (value);
for (int i = charCount; i < width; ++i)
whisperPutc(pad);
char* p = buffer + charCount - 1;
for (int i = 0; i < charCount; ++i)
whisperPutc(*p--);
return charCount;
}
static int
whisperPrintDecimal(int value, int width, char pad)
{
char buffer[20];
int charCount = 0;
unsigned neg = value < 0;
if (neg)
{
value = -value;
whisperPutc('-');
width--;
}
do
{
char c = '0' + (value % 10);
value = value / 10;
buffer[charCount++] = c;
}
while (value);
for (int i = charCount; i < width; ++i)
whisperPutc(pad);
char* p = buffer + charCount - 1;
for (int i = 0; i < charCount; ++i)
whisperPutc(*p--);
if (neg)
charCount++;
return charCount;
}
static int
whisperPrintInt(int value, int width, int pad, int base)
{
if (base == 10)
return whisperPrintDecimal(value, width, pad);
char buffer[20];
int charCount = 0;
unsigned uu = value;
if (base == 8)
{
do
{
char c = '0' + (uu & 7);
buffer[charCount++] = c;
uu >>= 3;
}
while (uu);
}
else if (base == 16)
{
do
{
int digit = uu & 0xf;
char c = digit < 10 ? '0' + digit : 'a' + digit - 10;
buffer[charCount++] = c;
uu >>= 4;
}
while (uu);
}
else
return -1;
char* p = buffer + charCount - 1;
for (unsigned i = 0; i < charCount; ++i)
whisperPutc(*p--);
return charCount;
}
#if 0
// Print with g format
static int
whisperPrintDoubleG(double value)
{
return 0;
}
// Print with f format
static int
whisperPrintDoubleF(double value)
{
return 0;
}
#endif
int
whisperPrintfImpl(const char* format, va_list ap)
{
int count = 0; // Printed character count
for (const char* fp = format; *fp; fp++)
{
char pad = ' ';
int width = 0; // Field width
if (*fp != '%')
{
whisperPutc(*fp);
++count;
continue;
}
++fp; // Skip %
if (*fp == 0)
break;
if (*fp == '%')
{
whisperPutc('%');
continue;
}
while (*fp == '0')
{
pad = '0';
fp++; // Pad zero not yet implented.
}
if (*fp == '-')
{
fp++; // Pad right not yet implemented.
}
if (*fp == '*')
{
int outWidth = va_arg(ap, int);
fp++; // Width not yet implemented.
}
else if (*fp >= '0' && *fp <= '9')
{ // Width not yet implemented.
while (*fp >= '0' && *fp <= '9')
width = width * 10 + (*fp++ - '0');
}
switch (*fp)
{
case 'd':
count += whisperPrintDecimal(va_arg(ap, int), width, pad);
break;
case 'u':
count += whisperPrintUnsigned((unsigned) va_arg(ap, unsigned), width, pad);
break;
case 'x':
case 'X':
count += whisperPrintInt(va_arg(ap, int), width, pad, 16);
break;
case 'o':
count += whisperPrintInt(va_arg(ap, int), width, pad, 8);
break;
case 'c':
whisperPutc(va_arg(ap, int));
++count;
break;
case 's':
count += whisperPuts(va_arg(ap, char*));
break;
#if 0
case 'g':
count += whisperPrintDoubleG(va_arg(ap, double));
break;
case 'f':
count += whisperPrintDoubleF(va_arg(ap, double));
#endif
}
}
return count;
}
int
whisperPrintf(const char* format, ...)
{
va_list ap;
va_start(ap, format);
int code = whisperPrintfImpl(format, ap);
va_end(ap);
return code;
}
int
printf(const char* format, ...)
{
va_list ap;
va_start(ap, format);
int code = whisperPrintfImpl(format, ap);
va_end(ap);
return code;
}

View File

@ -0,0 +1,7 @@
This is dhrystone, compiled according to the spec:
1. Files dhry_1.c and dhry2_.c compiled separately.
2. No inlining.
to run in demo TB:
make -f $RV_ROOT/tools/Makefile [<simulator>] TEST=dhry

1
testbench/tests/dhry/crt0.s Symbolic link
View File

@ -0,0 +1 @@
../../asm/crt0.s

437
testbench/tests/dhry/dhry.h Normal file
View File

@ -0,0 +1,437 @@
#pragma once
/*
****************************************************************************
*
* "DHRYSTONE" Benchmark Program
* -----------------------------
*
* Version: C, Version 2.1
*
* File: dhry.h (part 1 of 3)
*
* Date: May 25, 1988
*
* Author: Reinhold P. Weicker
* Siemens AG, E STE 35
* Postfach 3240
* 8520 Erlangen
* Germany (West)
* Phone: [xxx-49]-9131-7-20330
* (8-17 Central European Time)
* Usenet: ..!mcvax!unido!estevax!weicker
*
* Original Version (in Ada) published in
* "Communications of the ACM" vol. 27., no. 10 (Oct. 1984),
* pp. 1013 - 1030, together with the statistics
* on which the distribution of statements etc. is based.
*
* In this C version, the following C library functions are used:
* - strcpy, strcmp (inside the measurement loop)
* - printf, scanf (outside the measurement loop)
* In addition, Berkeley UNIX system calls "times ()" or "time ()"
* are used for execution time measurement. For measurements
* on other systems, these calls have to be changed.
*
* Collection of Results:
* Reinhold Weicker (address see above) and
*
* Rick Richardson
* PC Research. Inc.
* 94 Apple Orchard Drive
* Tinton Falls, NJ 07724
* Phone: (201) 389-8963 (9-17 EST)
* Usenet: ...!uunet!pcrat!rick
*
* Please send results to Rick Richardson and/or Reinhold Weicker.
* Complete information should be given on hardware and software used.
* Hardware information includes: Machine type, CPU, type and size
* of caches; for microprocessors: clock frequency, memory speed
* (number of wait states).
* Software information includes: Compiler (and runtime library)
* manufacturer and version, compilation switches, OS version.
* The Operating System version may give an indication about the
* compiler; Dhrystone itself performs no OS calls in the measurement loop.
*
* The complete output generated by the program should be mailed
* such that at least some checks for correctness can be made.
*
***************************************************************************
*
* History: This version C/2.1 has been made for two reasons:
*
* 1) There is an obvious need for a common C version of
* Dhrystone, since C is at present the most popular system
* programming language for the class of processors
* (microcomputers, minicomputers) where Dhrystone is used most.
* There should be, as far as possible, only one C version of
* Dhrystone such that results can be compared without
* restrictions. In the past, the C versions distributed
* by Rick Richardson (Version 1.1) and by Reinhold Weicker
* had small (though not significant) differences.
*
* 2) As far as it is possible without changes to the Dhrystone
* statistics, optimizing compilers should be prevented from
* removing significant statements.
*
* This C version has been developed in cooperation with
* Rick Richardson (Tinton Falls, NJ), it incorporates many
* ideas from the "Version 1.1" distributed previously by
* him over the UNIX network Usenet.
* I also thank Chaim Benedelac (National Semiconductor),
* David Ditzel (SUN), Earl Killian and John Mashey (MIPS),
* Alan Smith and Rafael Saavedra-Barrera (UC at Berkeley)
* for their help with comments on earlier versions of the
* benchmark.
*
* Changes: In the initialization part, this version follows mostly
* Rick Richardson's version distributed via Usenet, not the
* version distributed earlier via floppy disk by Reinhold Weicker.
* As a concession to older compilers, names have been made
* unique within the first 8 characters.
* Inside the measurement loop, this version follows the
* version previously distributed by Reinhold Weicker.
*
* At several places in the benchmark, code has been added,
* but within the measurement loop only in branches that
* are not executed. The intention is that optimizing compilers
* should be prevented from moving code out of the measurement
* loop, or from removing code altogether. Since the statements
* that are executed within the measurement loop have NOT been
* changed, the numbers defining the "Dhrystone distribution"
* (distribution of statements, operand types and locality)
* still hold. Except for sophisticated optimizing compilers,
* execution times for this version should be the same as
* for previous versions.
*
* Since it has proven difficult to subtract the time for the
* measurement loop overhead in a correct way, the loop check
* has been made a part of the benchmark. This does have
* an impact - though a very minor one - on the distribution
* statistics which have been updated for this version.
*
* All changes within the measurement loop are described
* and discussed in the companion paper "Rationale for
* Dhrystone version 2".
*
* Because of the self-imposed limitation that the order and
* distribution of the executed statements should not be
* changed, there are still cases where optimizing compilers
* may not generate code for some statements. To a certain
* degree, this is unavoidable for small synthetic benchmarks.
* Users of the benchmark are advised to check code listings
* whether code is generated for all statements of Dhrystone.
*
* Version 2.1 is identical to version 2.0 distributed via
* the UNIX network Usenet in March 1988 except that it corrects
* some minor deficiencies that were found by users of version 2.0.
* The only change within the measurement loop is that a
* non-executed "else" part was added to the "if" statement in
* Func_3, and a non-executed "else" part removed from Proc_3.
*
***************************************************************************
*
* Defines: The following "Defines" are possible:
* -DREG=register (default: Not defined)
* As an approximation to what an average C programmer
* might do, the "register" storage class is applied
* (if enabled by -DREG=register)
* - for local variables, if they are used (dynamically)
* five or more times
* - for parameters if they are used (dynamically)
* six or more times
* Note that an optimal "register" strategy is
* compiler-dependent, and that "register" declarations
* do not necessarily lead to faster execution.
* -DNOSTRUCTASSIGN (default: Not defined)
* Define if the C compiler does not support
* assignment of structures.
* -DNOENUMS (default: Not defined)
* Define if the C compiler does not support
* enumeration types.
* -DTIMES (default)
* -DTIME
* The "times" function of UNIX (returning process times)
* or the "time" function (returning wallclock time)
* is used for measurement.
* For single user machines, "time ()" is adequate. For
* multi-user machines where you cannot get single-user
* access, use the "times ()" function. If you have
* neither, use a stopwatch in the dead of night.
* "printf"s are provided marking the points "Start Timer"
* and "Stop Timer". DO NOT use the UNIX "time(1)"
* command, as this will measure the total time to
* run this program, which will (erroneously) include
* the time to allocate storage (malloc) and to perform
* the initialization.
* -DHZ=nnn
* In Berkeley UNIX, the function "times" returns process
* time in 1/HZ seconds, with HZ = 60 for most systems.
* CHECK YOUR SYSTEM DESCRIPTION BEFORE YOU JUST APPLY
* A VALUE.
*
***************************************************************************
*
* Compilation model and measurement (IMPORTANT):
*
* This C version of Dhrystone consists of three files:
* - dhry.h (this file, containing global definitions and comments)
* - dhry_1.c (containing the code corresponding to Ada package Pack_1)
* - dhry_2.c (containing the code corresponding to Ada package Pack_2)
*
* The following "ground rules" apply for measurements:
* - Separate compilation
* - No procedure merging
* - Otherwise, compiler optimizations are allowed but should be indicated
* - Default results are those without register declarations
* See the companion paper "Rationale for Dhrystone Version 2" for a more
* detailed discussion of these ground rules.
*
* For 16-Bit processors (e.g. 80186, 80286), times for all compilation
* models ("small", "medium", "large" etc.) should be given if possible,
* together with a definition of these models for the compiler system used.
*
**************************************************************************
*
* Dhrystone (C version) statistics:
*
* [Comment from the first distribution, updated for version 2.
* Note that because of language differences, the numbers are slightly
* different from the Ada version.]
*
* The following program contains statements of a high level programming
* language (here: C) in a distribution considered representative:
*
* assignments 52 (51.0 %)
* control statements 33 (32.4 %)
* procedure, function calls 17 (16.7 %)
*
* 103 statements are dynamically executed. The program is balanced with
* respect to the three aspects:
*
* - statement type
* - operand type
* - operand locality
* operand global, local, parameter, or constant.
*
* The combination of these three aspects is balanced only approximately.
*
* 1. Statement Type:
* ----------------- number
*
* V1 = V2 9
* (incl. V1 = F(..)
* V = Constant 12
* Assignment, 7
* with array element
* Assignment, 6
* with record component
* --
* 34 34
*
* X = Y +|-|"&&"|"|" Z 5
* X = Y +|-|"==" Constant 6
* X = X +|- 1 3
* X = Y *|/ Z 2
* X = Expression, 1
* two operators
* X = Expression, 1
* three operators
* --
* 18 18
*
* if .... 14
* with "else" 7
* without "else" 7
* executed 3
* not executed 4
* for ... 7 | counted every time
* while ... 4 | the loop condition
* do ... while 1 | is evaluated
* switch ... 1
* break 1
* declaration with 1
* initialization
* --
* 34 34
*
* P (...) procedure call 11
* user procedure 10
* library procedure 1
* X = F (...)
* function call 6
* user function 5
* library function 1
* --
* 17 17
* ---
* 103
*
* The average number of parameters in procedure or function calls
* is 1.82 (not counting the function values aX *
*
* 2. Operators
* ------------
* number approximate
* percentage
*
* Arithmetic 32 50.8
*
* + 21 33.3
* - 7 11.1
* * 3 4.8
* / (int div) 1 1.6
*
* Comparison 27 42.8
*
* == 9 14.3
* /= 4 6.3
* > 1 1.6
* < 3 4.8
* >= 1 1.6
* <= 9 14.3
*
* Logic 4 6.3
*
* && (AND-THEN) 1 1.6
* | (OR) 1 1.6
* ! (NOT) 2 3.2
*
* -- -----
* 63 100.1
*
*
* 3. Operand Type (counted once per operand reference):
* ---------------
* number approximate
* percentage
*
* Integer 175 72.3 %
* Character 45 18.6 %
* Pointer 12 5.0 %
* String30 6 2.5 %
* Array 2 0.8 %
* Record 2 0.8 %
* --- -------
* 242 100.0 %
*
* When there is an access path leading to the final operand (e.g. a record
* component), only the final data type on the access path is counted.
*
*
* 4. Operand Locality:
* -------------------
* number approximate
* percentage
*
* local variable 114 47.1 %
* global variable 22 9.1 %
* parameter 45 18.6 %
* value 23 9.5 %
* reference 22 9.1 %
* function result 6 2.5 %
* constant 55 22.7 %
* --- -------
* 242 100.0 %
*
*
* The program does not compute anything meaningful, but it is syntactically
* and semantically correct. All variables have a value assigned to them
* before they are used as a source operand.
*
* There has been no explicit effort to account for the effects of a
* cache, or to balance the use of long or short displacements for code or
* data.
*
***************************************************************************
*/
/* Compiler and system dependent definitions: */
#ifndef TIME
#undef TIMES
#define TIMES
#endif
/* Use times(2) time function unless */
/* explicitly defined otherwise */
#ifdef MSC_CLOCK
#undef HZ
#undef TIMES
#include <time.h>
#define HZ CLK_TCK
#endif
/* Use Microsoft C hi-res clock */
#ifdef TIMES
#include <sys/types.h>
#include <sys/times.h>
#ifndef HZ
#define HZ 100
#endif
/* for "times" */
#endif
#define Mic_secs_Per_Second 1000000.0
/* Berkeley UNIX C returns process times in seconds/HZ */
#ifdef NOSTRUCTASSIGN
#define structassign(d, s) memcpy(&(d), &(s), sizeof(d))
#else
#define structassign(d, s) d = s
#endif
#ifdef NOENUM
#define Ident_1 0
#define Ident_2 1
#define Ident_3 2
#define Ident_4 3
#define Ident_5 4
typedef int Enumeration;
#else
typedef enum {Ident_1, Ident_2, Ident_3, Ident_4, Ident_5}
Enumeration;
#endif
/* for boolean and enumeration types in Ada, Pascal */
/* General definitions: */
//#include <stdio.h>
/* for strcpy, strcmp */
#define Null 0
/* Value of a Null pointer */
#define true 1
#define false 0
typedef int One_Thirty;
typedef int One_Fifty;
typedef char Capital_Letter;
typedef int Boolean;
typedef char Str_30 [31];
typedef int Arr_1_Dim [50];
typedef int Arr_2_Dim [50] [50];
typedef struct record
{
struct record *Ptr_Comp;
Enumeration Discr;
union {
struct {
Enumeration Enum_Comp;
int Int_Comp;
char Str_Comp [31];
} var_1;
struct {
Enumeration E_Comp_2;
char Str_2_Comp [31];
} var_2;
struct {
char Ch_1_Comp;
char Ch_2_Comp;
} var_3;
} variant;
} Rec_Type, *Rec_Pointer;

View File

@ -0,0 +1,2 @@
OFILES = crt0.o dhry_1.o dhry_2.o printf.o
TEST_CFLAGS = -g -O3

View File

@ -0,0 +1,462 @@
#define SWERV
/*
****************************************************************************
*
* "DHRYSTONE" Benchmark Program
* -----------------------------
*
* Version: C, Version 2.1
*
* File: dhry_1.c (part 2 of 3)
*
* Date: May 25, 1988
*
* Author: Reinhold P. Weicker
*
****************************************************************************
*/
#ifdef SWERV
#include <stdio.h>
#include <stdint.h>
extern uint64_t get_mcycle();
#endif
#include "dhry.h"
/* Global Variables: */
Rec_Pointer Ptr_Glob,
Next_Ptr_Glob;
int Int_Glob;
Boolean Bool_Glob;
char Ch_1_Glob,
Ch_2_Glob;
int Arr_1_Glob [50];
int Arr_2_Glob [50] [50];
Enumeration Func_1 ();
/* forward declaration necessary since Enumeration may not simply be int */
#ifndef REG
Boolean Reg = false;
#define REG
/* REG becomes defined as empty */
/* i.e. no register variables */
#else
Boolean Reg = true;
#endif
/* variables for time measurement: */
#ifdef TIMES
struct tms time_info;
#define Too_Small_Time (2*HZ)
/* Measurements should last at least about 2 seconds */
#endif
#ifdef TIME
extern long time();
/* see library function "time" */
#define Too_Small_Time 2
/* Measurements should last at least 2 seconds */
#endif
#ifdef MSC_CLOCK
extern clock_t clock();
#define Too_Small_Time (2*HZ)
#endif
long
Begin_Time,
End_Time,
User_Time;
float Microseconds,
Dhrystones_Per_Second;
/* end of variables for time measurement */
extern char* strcpy(char*, const char*);
extern Boolean Func_2 (Str_30, Str_30);
extern void Proc_7 (One_Fifty Int_1_Par_Val, One_Fifty Int_2_Par_Val,
One_Fifty *Int_Par_Ref);
extern void Proc_8 (Arr_1_Dim Arr_1_Par_Ref, Arr_2_Dim Arr_2_Par_Ref,
int Int_1_Par_Val, int Int_2_Par_Val);
extern void Proc_6 (Enumeration Enum_Val_Par,
Enumeration *Enum_Ref_Par);
void Proc_5();
void Proc_4();
void Proc_1(Rec_Pointer Ptr_Val_Par);
void Proc_2(One_Fifty *Int_Par_Ref);
void Proc_3(Rec_Pointer *Ptr_Ref_Par);
int
main ()
/*****/
/* main program, corresponds to procedures */
/* Main and Proc_0 in the Ada version */
{
One_Fifty Int_1_Loc;
REG One_Fifty Int_2_Loc;
One_Fifty Int_3_Loc;
REG char Ch_Index;
Enumeration Enum_Loc;
Str_30 Str_1_Loc;
Str_30 Str_2_Loc;
REG int Run_Index;
REG int Number_Of_Runs;
/* Initializations */
Rec_Type rec0;
Rec_Type rec1;
Next_Ptr_Glob = &rec0;
Ptr_Glob = &rec1;
Ptr_Glob->Ptr_Comp = Next_Ptr_Glob;
Ptr_Glob->Discr = Ident_1;
Ptr_Glob->variant.var_1.Enum_Comp = Ident_3;
Ptr_Glob->variant.var_1.Int_Comp = 40;
strcpy (Ptr_Glob->variant.var_1.Str_Comp,
"DHRYSTONE PROGRAM, SOME STRING");
strcpy (Str_1_Loc, "DHRYSTONE PROGRAM, 1'ST STRING");
Arr_2_Glob [8][7] = 10;
/* Was missing in published program. Without this statement, */
/* Arr_2_Glob [8][7] would have an undefined value. */
/* Warning: With 16-Bit processors and Number_Of_Runs > 32000, */
/* overflow may occur for this array element. */
printf ("\n");
printf ("Dhrystone Benchmark, Version 2.1 (Language: C)\n");
printf ("\n");
if (Reg)
{
printf ("Program compiled with 'register' attribute\n");
printf ("\n");
}
else
{
printf ("Program compiled without 'register' attribute\n");
printf ("\n");
}
#ifndef SWERV
printf ("Please give the number of runs through the benchmark: ");
{
int n = 1000;
scanf ("%d", &n);
Number_Of_Runs = n;
}
printf ("\n");
#else
// We do not have scanf. Hardwire number of runs.
Number_Of_Runs = 1000;
#endif
printf ("Execution starts, %d runs through Dhrystone\n", Number_Of_Runs);
/***************/
/* Start timer */
/***************/
#ifdef SWERV
Begin_Time = get_mcycle();
#else
#ifdef TIMES
times (&time_info);
Begin_Time = (long) time_info.tms_utime;
#endif
#ifdef TIME
Begin_Time = time ( (long *) 0);
#endif
#ifdef MSC_CLOCK
Begin_Time = clock();
#endif
#endif
__asm("__perf_start:");
for (Run_Index = 1; Run_Index <= Number_Of_Runs; ++Run_Index)
{
__asm("__loop_start:");
Proc_5();
Proc_4();
/* Ch_1_Glob == 'A', Ch_2_Glob == 'B', Bool_Glob == true */
Int_1_Loc = 2;
Int_2_Loc = 3;
strcpy (Str_2_Loc, "DHRYSTONE PROGRAM, 2'ND STRING");
Enum_Loc = Ident_2;
Bool_Glob = ! Func_2 (Str_1_Loc, Str_2_Loc);
/* Bool_Glob == 1 */
while (Int_1_Loc < Int_2_Loc) /* loop body executed once */
{
Int_3_Loc = 5 * Int_1_Loc - Int_2_Loc;
/* Int_3_Loc == 7 */
Proc_7 (Int_1_Loc, Int_2_Loc, &Int_3_Loc);
/* Int_3_Loc == 7 */
Int_1_Loc += 1;
} /* while */
/* Int_1_Loc == 3, Int_2_Loc == 3, Int_3_Loc == 7 */
Proc_8 (Arr_1_Glob, Arr_2_Glob, Int_1_Loc, Int_3_Loc);
/* Int_Glob == 5 */
Proc_1 (Ptr_Glob);
for (Ch_Index = 'A'; Ch_Index <= Ch_2_Glob; ++Ch_Index)
/* loop body executed twice */
{
if (Enum_Loc == Func_1 (Ch_Index, 'C'))
/* then, not executed */
{
Proc_6 (Ident_1, &Enum_Loc);
strcpy (Str_2_Loc, "DHRYSTONE PROGRAM, 3'RD STRING");
Int_2_Loc = Run_Index;
Int_Glob = Run_Index;
}
}
/* Int_1_Loc == 3, Int_2_Loc == 3, Int_3_Loc == 7 */
Int_2_Loc = Int_2_Loc * Int_1_Loc;
Int_1_Loc = Int_2_Loc / Int_3_Loc;
Int_2_Loc = 7 * (Int_2_Loc - Int_3_Loc) - Int_1_Loc;
/* Int_1_Loc == 1, Int_2_Loc == 13, Int_3_Loc == 7 */
Proc_2 (&Int_1_Loc);
/* Int_1_Loc == 5 */
} /* loop "for Run_Index" */
__asm("__perf_end:");
/**************/
/* Stop timer */
/**************/
#ifdef SWERV
End_Time = get_mcycle();
printf("End_time=%d\n", (int) End_Time);
#else
#ifdef TIMES
times (&time_info);
End_Time = (long) time_info.tms_utime;
#endif
#ifdef TIME
End_Time = time ( (long *) 0);
#endif
#ifdef MSC_CLOCK
End_Time = clock();
#endif
#endif
printf ("Execution ends\n");
printf ("\n");
printf ("Final values of the variables used in the benchmark:\n");
printf ("\n");
printf ("Int_Glob: %d\n", Int_Glob);
printf (" should be: %d\n", 5);
printf ("Bool_Glob: %d\n", Bool_Glob);
printf (" should be: %d\n", 1);
printf ("Ch_1_Glob: %c\n", Ch_1_Glob);
printf (" should be: %c\n", 'A');
printf ("Ch_2_Glob: %c\n", Ch_2_Glob);
printf (" should be: %c\n", 'B');
printf ("Arr_1_Glob[8]: %d\n", Arr_1_Glob[8]);
printf (" should be: %d\n", 7);
printf ("Arr_2_Glob[8][7]: %d\n", Arr_2_Glob[8][7]);
printf (" should be: Number_Of_Runs + 10\n");
printf ("Ptr_Glob->\n");
printf (" Ptr_Comp: %d\n", (int) Ptr_Glob->Ptr_Comp);
printf (" should be: (implementation-dependent)\n");
printf (" Discr: %d\n", Ptr_Glob->Discr);
printf (" should be: %d\n", 0);
printf (" Enum_Comp: %d\n", Ptr_Glob->variant.var_1.Enum_Comp);
printf (" should be: %d\n", 2);
printf (" Int_Comp: %d\n", Ptr_Glob->variant.var_1.Int_Comp);
printf (" should be: %d\n", 17);
printf (" Str_Comp: %s\n", Ptr_Glob->variant.var_1.Str_Comp);
printf (" should be: DHRYSTONE PROGRAM, SOME STRING\n");
printf ("Next_Ptr_Glob->\n");
printf (" Ptr_Comp: %d\n", (int) Next_Ptr_Glob->Ptr_Comp);
printf (" should be: (implementation-dependent), same as above\n");
printf (" Discr: %d\n", Next_Ptr_Glob->Discr);
printf (" should be: %d\n", 0);
printf (" Enum_Comp: %d\n", Next_Ptr_Glob->variant.var_1.Enum_Comp);
printf (" should be: %d\n", 1);
printf (" Int_Comp: %d\n", Next_Ptr_Glob->variant.var_1.Int_Comp);
printf (" should be: %d\n", 18);
printf (" Str_Comp: %s\n",
Next_Ptr_Glob->variant.var_1.Str_Comp);
printf (" should be: DHRYSTONE PROGRAM, SOME STRING\n");
printf ("Int_1_Loc: %d\n", Int_1_Loc);
printf (" should be: %d\n", 5);
printf ("Int_2_Loc: %d\n", Int_2_Loc);
printf (" should be: %d\n", 13);
printf ("Int_3_Loc: %d\n", Int_3_Loc);
printf (" should be: %d\n", 7);
printf ("Enum_Loc: %d\n", Enum_Loc);
printf (" should be: %d\n", 1);
printf ("Str_1_Loc: %s\n", Str_1_Loc);
printf (" should be: DHRYSTONE PROGRAM, 1'ST STRING\n");
printf ("Str_2_Loc: %s\n", Str_2_Loc);
printf (" should be: DHRYSTONE PROGRAM, 2'ND STRING\n");
printf ("\n");
User_Time = End_Time - Begin_Time;
if (User_Time < Too_Small_Time)
{
printf ("User time %d\n", User_Time);
printf ("Measured time too small to obtain meaningful results\n");
printf ("Please increase number of runs\n");
printf ("\n");
}
else
{
#ifdef SWERV
printf ("Run time = %d clocks for %d Dhrystones\n", User_Time, Number_Of_Runs );
printf ("Dhrystones per Second per MHz: ");
printf ("%d.%02d", 1000000*Number_Of_Runs/User_Time,(100000000*Number_Of_Runs/User_Time) % 100);
#else
#ifdef TIME
Microseconds = (float) User_Time * Mic_secs_Per_Second
/ (float) Number_Of_Runs;
Dhrystones_Per_Second = (float) Number_Of_Runs / (float) User_Time;
#else
Microseconds = (float) User_Time * Mic_secs_Per_Second
/ ((float) HZ * ((float) Number_Of_Runs));
Dhrystones_Per_Second = ((float) HZ * (float) Number_Of_Runs)
/ (float) User_Time;
#endif
printf ("Microseconds for one run through Dhrystone: ");
printf ("%6.1f \n", Microseconds);
printf ("Dhrystones per Second: ");
printf ("%6.1f \n", Dhrystones_Per_Second);
#endif
printf ("\n");
}
}
void
Proc_1 (Ptr_Val_Par)
/******************/
REG Rec_Pointer Ptr_Val_Par;
/* executed once */
{
REG Rec_Pointer Next_Record = Ptr_Val_Par->Ptr_Comp;
/* == Ptr_Glob_Next */
/* Local variable, initialized with Ptr_Val_Par->Ptr_Comp, */
/* corresponds to "rename" in Ada, "with" in Pascal */
structassign (*Ptr_Val_Par->Ptr_Comp, *Ptr_Glob);
Ptr_Val_Par->variant.var_1.Int_Comp = 5;
Next_Record->variant.var_1.Int_Comp
= Ptr_Val_Par->variant.var_1.Int_Comp;
Next_Record->Ptr_Comp = Ptr_Val_Par->Ptr_Comp;
Proc_3 (&Next_Record->Ptr_Comp);
/* Ptr_Val_Par->Ptr_Comp->Ptr_Comp
== Ptr_Glob->Ptr_Comp */
if (Next_Record->Discr == Ident_1)
/* then, executed */
{
Next_Record->variant.var_1.Int_Comp = 6;
Proc_6 (Ptr_Val_Par->variant.var_1.Enum_Comp,
&Next_Record->variant.var_1.Enum_Comp);
Next_Record->Ptr_Comp = Ptr_Glob->Ptr_Comp;
Proc_7 (Next_Record->variant.var_1.Int_Comp, 10,
&Next_Record->variant.var_1.Int_Comp);
}
else /* not executed */
structassign (*Ptr_Val_Par, *Ptr_Val_Par->Ptr_Comp);
} /* Proc_1 */
void
Proc_2 (Int_Par_Ref)
/******************/
/* executed once */
/* *Int_Par_Ref == 1, becomes 4 */
One_Fifty *Int_Par_Ref;
{
One_Fifty Int_Loc;
Enumeration Enum_Loc;
Int_Loc = *Int_Par_Ref + 10;
do /* executed once */
if (Ch_1_Glob == 'A')
/* then, executed */
{
Int_Loc -= 1;
*Int_Par_Ref = Int_Loc - Int_Glob;
Enum_Loc = Ident_1;
} /* if */
while (Enum_Loc != Ident_1); /* true */
} /* Proc_2 */
void
Proc_3 (Ptr_Ref_Par)
/******************/
/* executed once */
/* Ptr_Ref_Par becomes Ptr_Glob */
Rec_Pointer *Ptr_Ref_Par;
{
if (Ptr_Glob != Null)
/* then, executed */
*Ptr_Ref_Par = Ptr_Glob->Ptr_Comp;
Proc_7 (10, Int_Glob, &Ptr_Glob->variant.var_1.Int_Comp);
} /* Proc_3 */
void
Proc_4 () /* without parameters */
/*******/
/* executed once */
{
Boolean Bool_Loc;
Bool_Loc = Ch_1_Glob == 'A';
Bool_Glob = Bool_Loc | Bool_Glob;
Ch_2_Glob = 'B';
} /* Proc_4 */
void
Proc_5 () /* without parameters */
/*******/
/* executed once */
{
Ch_1_Glob = 'A';
Bool_Glob = false;
} /* Proc_5 */
/* Procedure for the assignment of structures, */
/* if the C compiler doesn't support this feature */
#ifdef NOSTRUCTASSIGN
memcpy (d, s, l)
register char *d;
register char *s;
register int l;
{
while (l--) *d++ = *s++;
}
#endif

View File

@ -0,0 +1,212 @@
/*
****************************************************************************
*
* "DHRYSTONE" Benchmark Program
* -----------------------------
*
* Version: C, Version 2.1
*
* File: dhry_2.c (part 3 of 3)
*
* Date: May 25, 1988
*
* Author: Reinhold P. Weicker
*
****************************************************************************
*/
#include "dhry.h"
#ifndef REG
#define REG
/* REG becomes defined as empty */
/* i.e. no register variables */
#endif
extern int Int_Glob;
extern char Ch_1_Glob;
int
strcmp(const char* s1, const char* s2)
{
while (*s1 && *s1 == *s2)
{
s1++;
s2++;
}
if (*s1 == *s2)
return 0;
return *s1 > *s2? 1 : -1;
}
Boolean Func_3 (Enumeration Enum_Par_Val);
void
Proc_6 (Enum_Val_Par, Enum_Ref_Par)
/*********************************/
/* executed once */
/* Enum_Val_Par == Ident_3, Enum_Ref_Par becomes Ident_2 */
Enumeration Enum_Val_Par;
Enumeration *Enum_Ref_Par;
{
*Enum_Ref_Par = Enum_Val_Par;
if (! Func_3 (Enum_Val_Par))
/* then, not executed */
*Enum_Ref_Par = Ident_4;
switch (Enum_Val_Par)
{
case Ident_1:
*Enum_Ref_Par = Ident_1;
break;
case Ident_2:
if (Int_Glob > 100)
/* then */
*Enum_Ref_Par = Ident_1;
else *Enum_Ref_Par = Ident_4;
break;
case Ident_3: /* executed */
*Enum_Ref_Par = Ident_2;
break;
case Ident_4: break;
case Ident_5:
*Enum_Ref_Par = Ident_3;
break;
} /* switch */
} /* Proc_6 */
void
Proc_7 (Int_1_Par_Val, Int_2_Par_Val, Int_Par_Ref)
/**********************************************/
/* executed three times */
/* first call: Int_1_Par_Val == 2, Int_2_Par_Val == 3, */
/* Int_Par_Ref becomes 7 */
/* second call: Int_1_Par_Val == 10, Int_2_Par_Val == 5, */
/* Int_Par_Ref becomes 17 */
/* third call: Int_1_Par_Val == 6, Int_2_Par_Val == 10, */
/* Int_Par_Ref becomes 18 */
One_Fifty Int_1_Par_Val;
One_Fifty Int_2_Par_Val;
One_Fifty *Int_Par_Ref;
{
One_Fifty Int_Loc;
Int_Loc = Int_1_Par_Val + 2;
*Int_Par_Ref = Int_2_Par_Val + Int_Loc;
} /* Proc_7 */
void
Proc_8 (Arr_1_Par_Ref, Arr_2_Par_Ref, Int_1_Par_Val, Int_2_Par_Val)
/*********************************************************************/
/* executed once */
/* Int_Par_Val_1 == 3 */
/* Int_Par_Val_2 == 7 */
Arr_1_Dim Arr_1_Par_Ref;
Arr_2_Dim Arr_2_Par_Ref;
int Int_1_Par_Val;
int Int_2_Par_Val;
{
REG One_Fifty Int_Index;
REG One_Fifty Int_Loc;
Int_Loc = Int_1_Par_Val + 5;
Arr_1_Par_Ref [Int_Loc] = Int_2_Par_Val;
Arr_1_Par_Ref [Int_Loc+1] = Arr_1_Par_Ref [Int_Loc];
Arr_1_Par_Ref [Int_Loc+30] = Int_Loc;
for (Int_Index = Int_Loc; Int_Index <= Int_Loc+1; ++Int_Index)
Arr_2_Par_Ref [Int_Loc] [Int_Index] = Int_Loc;
Arr_2_Par_Ref [Int_Loc] [Int_Loc-1] += 1;
Arr_2_Par_Ref [Int_Loc+20] [Int_Loc] = Arr_1_Par_Ref [Int_Loc];
Int_Glob = 5;
} /* Proc_8 */
Enumeration Func_1 (Ch_1_Par_Val, Ch_2_Par_Val)
/*************************************************/
/* executed three times */
/* first call: Ch_1_Par_Val == 'H', Ch_2_Par_Val == 'R' */
/* second call: Ch_1_Par_Val == 'A', Ch_2_Par_Val == 'C' */
/* third call: Ch_1_Par_Val == 'B', Ch_2_Par_Val == 'C' */
Capital_Letter Ch_1_Par_Val;
Capital_Letter Ch_2_Par_Val;
{
Capital_Letter Ch_1_Loc;
Capital_Letter Ch_2_Loc;
Ch_1_Loc = Ch_1_Par_Val;
Ch_2_Loc = Ch_1_Loc;
if (Ch_2_Loc != Ch_2_Par_Val)
/* then, executed */
return (Ident_1);
else /* not executed */
{
Ch_1_Glob = Ch_1_Loc;
return (Ident_2);
}
} /* Func_1 */
Boolean Func_2 (Str_1_Par_Ref, Str_2_Par_Ref)
/*************************************************/
/* executed once */
/* Str_1_Par_Ref == "DHRYSTONE PROGRAM, 1'ST STRING" */
/* Str_2_Par_Ref == "DHRYSTONE PROGRAM, 2'ND STRING" */
Str_30 Str_1_Par_Ref;
Str_30 Str_2_Par_Ref;
{
REG One_Thirty Int_Loc;
Capital_Letter Ch_Loc;
Int_Loc = 2;
while (Int_Loc <= 2) /* loop body executed once */
if (Func_1 (Str_1_Par_Ref[Int_Loc],
Str_2_Par_Ref[Int_Loc+1]) == Ident_1)
/* then, executed */
{
Ch_Loc = 'A';
Int_Loc += 1;
} /* if, while */
if (Ch_Loc >= 'W' && Ch_Loc < 'Z')
/* then, not executed */
Int_Loc = 7;
if (Ch_Loc == 'R')
/* then, not executed */
return (true);
else /* executed */
{
if (strcmp (Str_1_Par_Ref, Str_2_Par_Ref) > 0)
/* then, not executed */
{
Int_Loc += 7;
Int_Glob = Int_Loc;
return (true);
}
else /* executed */
return (false);
} /* if Ch_Loc */
} /* Func_2 */
Boolean Func_3 (Enum_Par_Val)
/***************************/
/* executed once */
/* Enum_Par_Val == Ident_3 */
Enumeration Enum_Par_Val;
{
Enumeration Enum_Loc;
Enum_Loc = Enum_Par_Val;
if (Enum_Loc == Ident_3)
/* then, executed */
return (true);
else /* not executed */
return (false);
} /* Func_3 */

View File

@ -0,0 +1 @@
../../asm/printf.c

View File

@ -0,0 +1,11 @@
export TEST = hello_world
export OFILES = crt0.o hello_world.o
export BUILD_PATH = $(shell pwd)/snapshots/default
program.hex:
$(MAKE) -e -f $(RV_ROOT)/tools/make.common $(BUILD_PATH)/defines.h
$(MAKE) -e -f $(RV_ROOT)/tools/make.common $@
.DEFAULT:
$(MAKE) -e program.hex
$(MAKE) -e -f $(RV_ROOT)/tools/make.common $@

View File

@ -0,0 +1,42 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2019 Western Digital Corporation or its affiliates.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Assembly code for Hello World
// Not using only ALU ops for creating the string
#include "defines.h"
.section .text
.global main
main:
li x3, RV_SERIALIO
la x4, hw_data
loop:
lb x5, 0(x4)
sb x5, 0(x3)
addi x4, x4, 1
bnez x5, loop
ret
.data
hw_data:
.ascii "----------------------------------\n"
.ascii "Hello World from SweRV EL2 @WDC !!\n"
.ascii "----------------------------------\n"
.byte 0

View File

@ -14,6 +14,11 @@
# limitations under the License.
#
CONF_PARAMS = -set build_axi4
TEST_CFLAGS = -g -O3 -funroll-all-loops
ABI = -mabi=ilp32 -march=rv32imac
# Check for RV_ROOT
ifeq (,$(wildcard ${RV_ROOT}/configs/swerv.config))
$(error env var RV_ROOT does not point to a valid dir! Exiting!)
@ -29,6 +34,7 @@ IRUN = xrun
VCS = vcs
VLOG = qverilog
VERILATOR = verilator
RIVEIRA = riviera
GCC_PREFIX = riscv64-unknown-elf
BUILD_DIR = snapshots/${snapshot}
TBDIR = ${RV_ROOT}/testbench
@ -37,24 +43,44 @@ TBDIR = ${RV_ROOT}/testbench
TEST = hello_world
# Define test name
ifneq (,$(wildcard $(TBDIR)/asm/$(TEST).s))
TEST_DIR = ${TBDIR}/asm
else
ifneq (,$(wildcard $(TBDIR)/asm/$(TEST).c))
TEST_DIR = ${TBDIR}/asm
else
ifneq (,$(wildcard $(TBDIR)/tests/$(TEST)))
TEST_DIR = $(TBDIR)/tests/$(TEST)
else
TEST_DIR = ${TBDIR}/asm
endif
endif
endif
HEX_DIR = ${TBDIR}/hex
OFILES = $(TEST).o
ifdef debug
DEBUG_PLUS = +dumpon
IRUN_DEBUG = -access +rc
IRUN_DEBUG_RUN = -input ${RV_ROOT}/testbench/input.tcl
VCS_DEBUG = -debug_access
VERILATOR_DEBUG = --trace
RIVIERA_DEBUG = +access +r
endif
# provide specific link file
ifeq (,$(wildcard $(TEST_DIR)/$(TEST).ld))
LINK = $(TBDIR)/link.ld
LINK = $(BUILD_DIR)/link.ld
else
LINK = $(TEST_DIR)/$(TEST).ld
endif
VPATH = $(TEST_DIR) $(BUILD_DIR) $(TBDIR)
-include $(TEST_DIR)/$(TEST).mki
TBFILES = $(TBDIR)/tb_top.sv $(TBDIR)/ahb_sif.sv
defines = $(BUILD_DIR)/common_defines.vh
@ -69,27 +95,32 @@ CFLAGS += "-std=c++11"
# Optimization for better performance; alternative is nothing for
# slower runtime (faster compiles) -O2 for faster runtime (slower
# compiles), or -O for balance.
VERILATOR_MAKE_FLAGS = OPT_FAST="-O2"
VERILATOR_MAKE_FLAGS = OPT_FAST="-Os"
# Targets
all: clean verilator
clean:
rm -rf *.log *.s *.hex *.dis *.tbl irun* vcs* simv* snapshots swerv* \
verilator* *.exe obj* *.o ucli.key vc_hdrs.h csrc *.csv work
verilator* *.exe obj* *.o ucli.key vc_hdrs.h csrc *.csv work\
work dataset.asdb library.cfg vsimsa.cfg riviera-build wave.asdb
############ Model Builds ###############################
# If define files do not exist, then run swerv.config.
${BUILD_DIR}/defines.h:
BUILD_PATH=${BUILD_DIR} ${RV_ROOT}/configs/swerv.config -target=$(target) $(CONF_PARAMS)
verilator-build: ${TBFILES} ${BUILD_DIR}/defines.h test_tb_top.cpp
echo '`undef ASSERT_ON' >> ${BUILD_DIR}/common_defines.vh
$(VERILATOR) '-UASSERT_ON' --cc -CFLAGS ${CFLAGS} $(defines) \
echo '`undef RV_ASSERT_ON' >> ${BUILD_DIR}/common_defines.vh
$(VERILATOR) --cc -CFLAGS ${CFLAGS} $(defines) \
$(includes) -I${RV_ROOT}/testbench -f ${RV_ROOT}/testbench/flist \
-Wno-WIDTH -Wno-UNOPTFLAT ${TBFILES} --top-module tb_top \
-exe test_tb_top.cpp --autoflush $(VERILATOR_DEBUG)
cp ${RV_ROOT}/testbench/test_tb_top.cpp obj_dir/
$(MAKE) -C obj_dir/ -f Vtb_top.mk $(VERILATOR_MAKE_FLAGS)
$(MAKE) -j -e -C obj_dir/ -f Vtb_top.mk $(VERILATOR_MAKE_FLAGS)
touch verilator-build
vcs-build: ${TBFILES} ${BUILD_DIR}/defines.h
@ -106,60 +137,79 @@ irun-build: ${TBFILES} ${BUILD_DIR}/defines.h
-incdir ${RV_ROOT}/design/lib -incdir ${RV_ROOT}/design/include \
-vlog_ext +.vh+.h $(defines) -incdir $(BUILD_DIR) \
-f ${RV_ROOT}/testbench/flist -top tb_top ${TBFILES} \
-I${RV_ROOT}/testbench -elaborate -snapshot ${snapshot}
-I${RV_ROOT}/testbench -elaborate -snapshot ${snapshot} $(profile)
touch irun-build
riviera-build: ${TBFILES} ${BUILD_DIR}/defines.h
vlib work
vlog -work work \
-err VCP2694 W1 \
+incdir+${RV_ROOT}/design/lib \
+incdir+${RV_ROOT}/design/include \
+incdir+${BUILD_DIR} \
-y ${RV_ROOT}/design/lib +libext+.v+.vh \
$(defines) \
-f ${RV_ROOT}/testbench/flist \
${TBFILES}
touch riviera-build
############ TEST Simulation ###############################
verilator: program.hex verilator-build
./obj_dir/Vtb_top
irun: program.hex irun-build
$(IRUN) -64bit -abvglobalfailurelimit 1 +lic_queue -licqueue \
-status -xmlibdirpath . -xmlibdirname swerv.build \
-snapshot ${snapshot} -r $(snapshot) $(IRUN_DEBUG_RUN)
-snapshot ${snapshot} -r $(snapshot) $(IRUN_DEBUG_RUN) $(profile)
vcs: program.hex vcs-build
./simv $(DEBUG_PLUS) +vcs+lic+wait -l vcs.log
vlog: program.hex ${TBFILES} ${BUILD_DIR}/defines.h
$(VLOG) -l vlog.log -sv -mfcu +incdir+${BUILD_DIR}+${RV_ROOT}/design/include+${RV_ROOT}/design/lib\
$(defines) -f ${RV_ROOT}/testbench/flist ${TBFILES} -R ${DEBUG_PLUS}
$(defines) -f ${RV_ROOT}/testbench/flist ${TBFILES} -R +nowarn3829 +nowarn2583 ${DEBUG_PLUS}
riviera: program.hex riviera-build
vsim -c -lib work ${DEBUG_PLUS} ${RIVIERA_DEBUG} tb_top -do "run -all; exit" -l riviera.log
############ TEST build ###############################
ifeq ($(shell which $(GCC_PREFIX)-gcc 2> /dev/null),)
program.hex: ${BUILD_DIR}/defines.h
@echo " !!! No $(GCC_PREFIX)-gcc in path, using canned hex files !!"
cp ${HEX_DIR}/$(TEST).program.hex program.hex
cp ${HEX_DIR}/$(TEST).data.hex data.hex
cp ${HEX_DIR}/$(TEST).hex program.hex
else
ifneq (,$(wildcard $(TEST_DIR)/$(TEST).makefile))
program.hex:
@echo Building $(TEST) via $(TEST_DIR)/$(TEST).makefile
$(MAKE) -f $(TEST_DIR)/$(TEST).makefile
else
program.hex: $(TEST).o $(LINK)
program.hex: $(OFILES) $(LINK)
@echo Building $(TEST)
$(GCC_PREFIX)-ld -m elf32lriscv --discard-none -T$(LINK) -o $(TEST).exe $(TEST).o
$(GCC_PREFIX)-objcopy -O verilog --only-section ".data*" --change-section-lma .data*-0x10000 $(TEST).exe data.hex
$(GCC_PREFIX)-objcopy -O verilog --only-section ".text*" $(TEST).exe program.hex
$(GCC_PREFIX)-gcc -Wl,-m,elf32lriscv -Wl,--discard-none -T$(LINK) -o $(TEST).exe $(OFILES) -nostartfiles -nostdlib $(TEST_LIBS)
$(GCC_PREFIX)-objcopy -O verilog $(TEST).exe program.hex
$(GCC_PREFIX)-objdump -S $(TEST).exe > $(TEST).dis
$(GCC_PREFIX)-nm -f posix -C $(TEST).exe > $(TEST).tbl
@echo Completed building $(TEST)
%.o : %.s ${BUILD_DIR}/defines.h
$(GCC_PREFIX)-cpp -I${BUILD_DIR} $< > $(TEST).cpp.s
$(GCC_PREFIX)-as -march=rv32gc $(TEST).cpp.s -o $(TEST).o
$(GCC_PREFIX)-cpp -I${BUILD_DIR} $< > $*.cpp.s
$(GCC_PREFIX)-as ${ABI} $*.cpp.s -o $@
TEST_CFLAGS = -g -O3 -funroll-all-loops
ABI = -mabi=ilp32 -march=rv32imc
%.o : %.c ${BUILD_DIR}/defines.h
$(GCC_PREFIX)-gcc -I${BUILD_DIR} ${TEST_CFLAGS} ${ABI} -nostdlib -c $< -o $@
$(GCC_PREFIX)-gcc ${includes} ${TEST_CFLAGS} -DCOMPILER_FLAGS="\"${TEST_CFLAGS}\"" ${ABI} -nostdlib -c $< -o $@
endif
endif
help:
@echo Make sure the environment variable RV_ROOT is set.
@echo Possible targets: verilator vcs irun vlog help clean all verilator-build irun-build vcs-build program.hex
@echo Possible targets: verilator vcs irun vlog riviera help clean all verilator-build irun-build vcs-build riviera-build program.hex
.PHONY: help clean verilator vcs irun vlog riviera
.PHONY: help clean verilator vcs irun vlog

View File

@ -1,19 +1,4 @@
#!/usr/bin/perl
# SPDX-License-Identifier: Apache-2.0
# Copyright 2020 Western Digital Corporation or its affiliates.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
use Getopt::Long;

View File

@ -1,19 +1,4 @@
#!/usr/bin/perl
# SPDX-License-Identifier: Apache-2.0
# Copyright 2020 Western Digital Corporation or its affiliates.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
use Getopt::Long;

View File

@ -1,19 +1,4 @@
#!/usr/bin/perl
# SPDX-License-Identifier: Apache-2.0
# Copyright 2020 Western Digital Corporation or its affiliates.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
use Getopt::Long;

View File

@ -1,19 +1,4 @@
#!/usr/bin/perl
# SPDX-License-Identifier: Apache-2.0
# Copyright 2020 Western Digital Corporation or its affiliates.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
use Getopt::Long;

View File

@ -30,7 +30,7 @@ print (" if ( m == (TOTAL_INT)/(2**(".$next_level."))) begin \n");
print (" assign level_intpend_w_prior_en_".$next_level."[m+1] = '0 ;\n");
print (" assign level_intpend_id_".$next_level."[m+1] = '0 ;\n");
print (" end\n");
print (" el2_cmp_and_mux #(\n");
print (" cmp_and_mux #(\n");
print (" .ID_BITS(ID_BITS),\n");
print (" .INTPRIORITY_BITS(INTPRIORITY_BITS)) cmp_l".$next_level." (\n");
print (" .a_id(level_intpend_id[0][2*m]),\n");
@ -51,7 +51,7 @@ print (" if ( m == (TOTAL_INT)/(2**(".$next_level."))) begin \n");
print (" assign level_intpend_w_prior_en_".$next_level."[m+1] = '0 ;\n");
print (" assign level_intpend_id_".$next_level."[m+1] = '0 ;\n");
print (" end\n");
print (" el2_cmp_and_mux #(\n");
print (" cmp_and_mux #(\n");
print (" .ID_BITS(ID_BITS),\n");
print (" .INTPRIORITY_BITS(INTPRIORITY_BITS)) cmp_l".$next_level." (\n");
print (" .a_id(level_intpend_id_".$l."[2*m]),\n");
@ -85,7 +85,7 @@ print (" if ( m == (TOTAL_INT)/(2**(".$next_level."))) begin \n");
print (" assign levelx_intpend_w_prior_en_".$next_level."[m+1] = '0 ;\n");
print (" assign levelx_intpend_id_".$next_level."[m+1] = '0 ;\n");
print (" end\n");
print (" el2_cmp_and_mux #(\n");
print (" cmp_and_mux #(\n");
print (" .ID_BITS(ID_BITS),\n");
print (" .INTPRIORITY_BITS(INTPRIORITY_BITS)) cmp_l".$next_level." (\n");
print (" .a_id(levelx_intpend_id[$tmp][2*m]),\n");
@ -106,7 +106,7 @@ print (" if ( m == (TOTAL_INT)/(2**(".$next_level."))) begin \n");
print (" assign levelx_intpend_w_prior_en_".$next_level."[m+1] = '0 ;\n");
print (" assign levelx_intpend_id_".$next_level."[m+1] = '0 ;\n");
print (" end\n");
print (" el2_cmp_and_mux #(\n");
print (" cmp_and_mux #(\n");
print (" .ID_BITS(ID_BITS),\n");
print (" .INTPRIORITY_BITS(INTPRIORITY_BITS)) cmp_l".$next_level." (\n");
print (" .a_id(levelx_intpend_id_".$l."[2*m]),\n");
@ -130,7 +130,7 @@ print (" if ( m == (TOTAL_INT)/(2**(".$next_level."))) begin \n");
print (" assign level_intpend_w_prior_en_".$next_level."[m+1] = '0 ;\n");
print (" assign level_intpend_id_".$next_level."[m+1] = '0 ;\n");
print (" end\n");
print (" el2_cmp_and_mux #(\n");
print (" cmp_and_mux #(\n");
print (" .ID_BITS(ID_BITS),\n");
print (" .INTPRIORITY_BITS(INTPRIORITY_BITS)) cmp_l".$next_level." (\n");
print (" .a_id(level_intpend_id[0][2*m]),\n");
@ -151,7 +151,7 @@ print (" if ( m == (TOTAL_INT)/(2**(".$next_level."))) begin \n");
print (" assign level_intpend_w_prior_en_".$next_level."[m+1] = '0 ;\n");
print (" assign level_intpend_id_".$next_level."[m+1] = '0 ;\n");
print (" end\n");
print (" el2_cmp_and_mux #(\n");
print (" cmp_and_mux #(\n");
print (" .ID_BITS(ID_BITS),\n");
print (" .INTPRIORITY_BITS(INTPRIORITY_BITS)) cmp_l".$next_level." (\n");
print (" .a_id(level_intpend_id_".$l."[2*m]),\n");