SweRV 1.1

This commit is contained in:
Joseph Rahmeh 2019-06-04 07:57:48 -07:00
parent 6ccfce0957
commit c0f7e509cc
78 changed files with 32564 additions and 0 deletions

14
configs/README.md Normal file
View File

@ -0,0 +1,14 @@
# SweRV RISC-V core from Western Digital
## Configuration
### Contents
Name | Description
---------------------- | ------------------------------
swerv.config | Configuration script for SweRV
This script will generate a consistent st of `defines/#defines needed for the design and testbench.
A perl hash (*perl_configs.pl*) and a JSON format for SweRV-iss are also generated.
While the defines fines may be modified by hand, it is recommended that this script be used to generate a consistent set.

View File

@ -0,0 +1,170 @@
// NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE
// This is an automatically generated file by joseph.rahmeh on Tue Jun 4 07:50:46 PDT 2019
//
// cmd: swerv -snapshot=default -ahb_lite
//
`define RV_INST_ACCESS_MASK5 'hffffffff
`define RV_DATA_ACCESS_ENABLE4 1'h0
`define RV_INST_ACCESS_ENABLE3 1'h0
`define RV_INST_ACCESS_ENABLE0 1'h0
`define RV_INST_ACCESS_MASK3 'hffffffff
`define RV_DATA_ACCESS_ENABLE5 1'h0
`define RV_DATA_ACCESS_MASK5 'hffffffff
`define RV_DATA_ACCESS_ADDR3 'h00000000
`define RV_INST_ACCESS_ENABLE7 1'h0
`define RV_DATA_ACCESS_ADDR6 'h00000000
`define RV_INST_ACCESS_MASK7 'hffffffff
`define RV_INST_ACCESS_ENABLE6 1'h0
`define RV_INST_ACCESS_ENABLE5 1'h0
`define RV_DATA_ACCESS_ADDR4 'h00000000
`define RV_DATA_ACCESS_ADDR7 'h00000000
`define RV_DATA_ACCESS_MASK3 'hffffffff
`define RV_INST_ACCESS_MASK4 'hffffffff
`define RV_DATA_ACCESS_ADDR1 'h00000000
`define RV_INST_ACCESS_ADDR4 'h00000000
`define RV_INST_ACCESS_ADDR3 'h00000000
`define RV_DATA_ACCESS_ENABLE1 1'h0
`define RV_DATA_ACCESS_ADDR0 'h00000000
`define RV_DATA_ACCESS_MASK0 'hffffffff
`define RV_DATA_ACCESS_MASK6 'hffffffff
`define RV_INST_ACCESS_ADDR7 'h00000000
`define RV_INST_ACCESS_MASK0 'hffffffff
`define RV_DATA_ACCESS_ADDR5 'h00000000
`define RV_DATA_ACCESS_ADDR2 'h00000000
`define RV_DATA_ACCESS_MASK4 'hffffffff
`define RV_DATA_ACCESS_MASK1 'hffffffff
`define RV_INST_ACCESS_ADDR0 'h00000000
`define RV_INST_ACCESS_ADDR2 'h00000000
`define RV_DATA_ACCESS_ENABLE0 1'h0
`define RV_DATA_ACCESS_ENABLE2 1'h0
`define RV_DATA_ACCESS_ENABLE7 1'h0
`define RV_INST_ACCESS_ENABLE4 1'h0
`define RV_DATA_ACCESS_MASK7 'hffffffff
`define RV_INST_ACCESS_ADDR5 'h00000000
`define RV_INST_ACCESS_ENABLE1 1'h0
`define RV_DATA_ACCESS_MASK2 'hffffffff
`define RV_INST_ACCESS_MASK6 'hffffffff
`define RV_DATA_ACCESS_ENABLE3 1'h0
`define RV_INST_ACCESS_ADDR6 'h00000000
`define RV_INST_ACCESS_MASK2 'hffffffff
`define RV_INST_ACCESS_ENABLE2 1'h0
`define RV_DATA_ACCESS_ENABLE6 1'h0
`define RV_INST_ACCESS_ADDR1 'h00000000
`define RV_INST_ACCESS_MASK1 'hffffffff
`define RV_DEC_INSTBUF_DEPTH 4
`define RV_DMA_BUF_DEPTH 4
`define RV_LSU_NUM_NBLOAD 8
`define RV_LSU_STBUF_DEPTH 8
`define RV_LSU_NUM_NBLOAD_WIDTH 3
`define RV_IFU_BUS_TAG 3
`define RV_LSU_BUS_TAG 4
`define RV_SB_BUS_TAG 1
`define RV_DMA_BUS_TAG 1
`define RV_DCCM_WIDTH_BITS 2
`define RV_DCCM_REGION 4'hf
`define RV_DCCM_RESERVED 'h1000
`define RV_DCCM_SIZE 64
`define RV_DCCM_DATA_WIDTH 32
`define RV_DCCM_NUM_BANKS_8
`define RV_DCCM_FDATA_WIDTH 39
`define RV_DCCM_BYTE_WIDTH 4
`define RV_DCCM_DATA_CELL ram_2048x39
`define RV_DCCM_ENABLE 1
`define RV_DCCM_BITS 16
`define RV_DCCM_OFFSET 28'h40000
`define RV_DCCM_ECC_WIDTH 7
`define RV_DCCM_SIZE_64
`define RV_DCCM_ROWS 2048
`define RV_DCCM_BANK_BITS 3
`define RV_DCCM_NUM_BANKS 8
`define RV_DCCM_INDEX_BITS 11
`define RV_LSU_SB_BITS 16
`define RV_DCCM_EADR 32'hf004ffff
`define RV_DCCM_SADR 32'hf0040000
`define RV_RESET_VEC 'h80000000
`define RV_RET_STACK_SIZE 4
`define RV_XLEN 32
`define RV_TARGET default
`define RV_BTB_BTAG_FOLD 1
`define RV_BTB_INDEX3_HI 9
`define RV_BTB_INDEX1_LO 4
`define RV_BTB_ADDR_HI 5
`define RV_BTB_ADDR_LO 4
`define RV_BTB_INDEX1_HI 5
`define RV_BTB_INDEX2_HI 7
`define RV_BTB_INDEX2_LO 6
`define RV_BTB_ARRAY_DEPTH 4
`define RV_BTB_BTAG_SIZE 9
`define RV_BTB_SIZE 32
`define RV_BTB_INDEX3_LO 8
`define RV_ICCM_NUM_BANKS 8
`define RV_ICCM_BITS 19
`define RV_ICCM_BANK_BITS 3
`define RV_ICCM_ROWS 16384
`define RV_ICCM_OFFSET 10'he000000
`define RV_ICCM_REGION 4'he
`define RV_ICCM_SADR 32'hee000000
`define RV_ICCM_RESERVED 'h1000
`define RV_ICCM_DATA_CELL ram_16384x39
`define RV_ICCM_INDEX_BITS 14
`define RV_ICCM_NUM_BANKS_8
`define RV_ICCM_SIZE 512
`define RV_ICCM_EADR 32'hee07ffff
`define RV_ICCM_SIZE_512
`define RV_ICACHE_SIZE 16
`define RV_ICACHE_TAG_HIGH 12
`define RV_ICACHE_IC_ROWS 256
`define RV_ICACHE_TADDR_HIGH 5
`define RV_ICACHE_TAG_LOW 6
`define RV_ICACHE_TAG_CELL ram_64x21
`define RV_ICACHE_IC_DEPTH 8
`define RV_ICACHE_IC_INDEX 8
`define RV_ICACHE_ENABLE 1
`define RV_ICACHE_DATA_CELL ram_256x34
`define RV_ICACHE_TAG_DEPTH 64
`define RV_EXTERNAL_PROG 'hb0000000
`define RV_EXTERNAL_DATA_1 'h00000000
`define RV_DEBUG_SB_MEM 'hb0580000
`define RV_EXTERNAL_DATA 'hc0580000
`define RV_SERIALIO 'hd0580000
`define RV_NMI_VEC 'h11110000
`define RV_BHT_HASH_STRING {ghr[3:2] ^ {ghr[3+1], {4-1-2{1'b0} } },hashin[5:4]^ghr[2-1:0]}
`define RV_BHT_ADDR_HI 7
`define RV_BHT_GHR_RANGE 4:0
`define RV_BHT_GHR_SIZE 5
`define RV_BHT_GHR_PAD2 fghr[4:3],2'b0
`define RV_BHT_SIZE 128
`define RV_BHT_ADDR_LO 4
`define RV_BHT_ARRAY_DEPTH 16
`define RV_BHT_GHR_PAD fghr[4],3'b0
`define RV_NUMIREGS 32
`define RV_PIC_BITS 15
`define RV_PIC_REGION 4'hf
`define RV_PIC_INT_WORDS 1
`define RV_PIC_TOTAL_INT_PLUS1 9
`define RV_PIC_MEIP_OFFSET 'h1000
`define RV_PIC_BASE_ADDR 32'hf00c0000
`define RV_PIC_MEIGWCTRL_OFFSET 'h4000
`define RV_PIC_MEIPL_OFFSET 'h0000
`define RV_PIC_TOTAL_INT 8
`define RV_PIC_SIZE 32
`define RV_PIC_MEIE_OFFSET 'h2000
`define RV_PIC_OFFSET 10'hc0000
`define RV_PIC_MEIPT_OFFSET 'h3004
`define RV_PIC_MPICCFG_OFFSET 'h3000
`define RV_PIC_MEIGWCLR_OFFSET 'h5000
`define CLOCK_PERIOD 100
`define CPU_TOP `RV_TOP.swerv
`define TOP tb_top
`define RV_BUILD_AHB_LITE 1
`define RV_TOP `TOP.rvtop
`define DATAWIDTH 64
`define RV_STERR_ROLLBACK 0
`define RV_EXT_ADDRWIDTH 32
`define RV_EXT_DATAWIDTH 64
`define SDVT_AHB 1
`define RV_LDERR_ROLLBACK 1
`define ASSERT_ON
`define TEC_RV_ICG clockhdr
`define REGWIDTH 32
`undef ASSERT_ON

View File

@ -0,0 +1,132 @@
// NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE
// This is an automatically generated file by joseph.rahmeh on Tue Jun 4 07:50:46 PDT 2019
//
// cmd: swerv -snapshot=default -ahb_lite
//
#define RV_INST_ACCESS_MASK5 0xffffffff
#define RV_DATA_ACCESS_ENABLE4 0x0
#define RV_INST_ACCESS_ENABLE3 0x0
#define RV_INST_ACCESS_ENABLE0 0x0
#define RV_INST_ACCESS_MASK3 0xffffffff
#define RV_DATA_ACCESS_ENABLE5 0x0
#define RV_DATA_ACCESS_MASK5 0xffffffff
#define RV_DATA_ACCESS_ADDR3 0x00000000
#define RV_INST_ACCESS_ENABLE7 0x0
#define RV_DATA_ACCESS_ADDR6 0x00000000
#define RV_INST_ACCESS_MASK7 0xffffffff
#define RV_INST_ACCESS_ENABLE6 0x0
#define RV_INST_ACCESS_ENABLE5 0x0
#define RV_DATA_ACCESS_ADDR4 0x00000000
#define RV_DATA_ACCESS_ADDR7 0x00000000
#define RV_DATA_ACCESS_MASK3 0xffffffff
#define RV_INST_ACCESS_MASK4 0xffffffff
#define RV_DATA_ACCESS_ADDR1 0x00000000
#define RV_INST_ACCESS_ADDR4 0x00000000
#define RV_INST_ACCESS_ADDR3 0x00000000
#define RV_DATA_ACCESS_ENABLE1 0x0
#define RV_DATA_ACCESS_ADDR0 0x00000000
#define RV_DATA_ACCESS_MASK0 0xffffffff
#define RV_DATA_ACCESS_MASK6 0xffffffff
#define RV_INST_ACCESS_ADDR7 0x00000000
#define RV_INST_ACCESS_MASK0 0xffffffff
#define RV_DATA_ACCESS_ADDR5 0x00000000
#define RV_DATA_ACCESS_ADDR2 0x00000000
#define RV_DATA_ACCESS_MASK4 0xffffffff
#define RV_DATA_ACCESS_MASK1 0xffffffff
#define RV_INST_ACCESS_ADDR0 0x00000000
#define RV_INST_ACCESS_ADDR2 0x00000000
#define RV_DATA_ACCESS_ENABLE0 0x0
#define RV_DATA_ACCESS_ENABLE2 0x0
#define RV_DATA_ACCESS_ENABLE7 0x0
#define RV_INST_ACCESS_ENABLE4 0x0
#define RV_DATA_ACCESS_MASK7 0xffffffff
#define RV_INST_ACCESS_ADDR5 0x00000000
#define RV_INST_ACCESS_ENABLE1 0x0
#define RV_DATA_ACCESS_MASK2 0xffffffff
#define RV_INST_ACCESS_MASK6 0xffffffff
#define RV_DATA_ACCESS_ENABLE3 0x0
#define RV_INST_ACCESS_ADDR6 0x00000000
#define RV_INST_ACCESS_MASK2 0xffffffff
#define RV_INST_ACCESS_ENABLE2 0x0
#define RV_DATA_ACCESS_ENABLE6 0x0
#define RV_INST_ACCESS_ADDR1 0x00000000
#define RV_INST_ACCESS_MASK1 0xffffffff
#define RV_IFU_BUS_TAG 3
#define RV_LSU_BUS_TAG 4
#define RV_SB_BUS_TAG 1
#define RV_DMA_BUS_TAG 1
#define RV_DCCM_WIDTH_BITS 2
#define RV_DCCM_REGION 0xf
#define RV_DCCM_RESERVED 0x1000
#define RV_DCCM_SIZE 64
#define RV_DCCM_DATA_WIDTH 32
#define RV_DCCM_NUM_BANKS_8
#define RV_DCCM_FDATA_WIDTH 39
#define RV_DCCM_BYTE_WIDTH 4
#define RV_DCCM_DATA_CELL ram_2048x39
#define RV_DCCM_ENABLE 1
#define RV_DCCM_BITS 16
#define RV_DCCM_OFFSET 0x40000
#define RV_DCCM_ECC_WIDTH 7
#define RV_DCCM_SIZE_64
#define RV_DCCM_ROWS 2048
#define RV_DCCM_BANK_BITS 3
#define RV_DCCM_NUM_BANKS 8
#define RV_DCCM_INDEX_BITS 11
#define RV_LSU_SB_BITS 16
#define RV_DCCM_EADR 0xf004ffff
#define RV_DCCM_SADR 0xf0040000
#ifndef RV_RESET_VEC
#define RV_RESET_VEC 0x80000000
#endif
#define RV_XLEN 32
#define RV_TARGET default
#define RV_ICCM_NUM_BANKS 8
#define RV_ICCM_BITS 19
#define RV_ICCM_BANK_BITS 3
#define RV_ICCM_ROWS 16384
#define RV_ICCM_OFFSET 0xe000000
#define RV_ICCM_REGION 0xe
#define RV_ICCM_SADR 0xee000000
#define RV_ICCM_RESERVED 0x1000
#define RV_ICCM_DATA_CELL ram_16384x39
#define RV_ICCM_INDEX_BITS 14
#define RV_ICCM_NUM_BANKS_8
#define RV_ICCM_SIZE 512
#define RV_ICCM_EADR 0xee07ffff
#define RV_ICCM_SIZE_512
#define RV_EXTERNAL_PROG 0xb0000000
#define RV_EXTERNAL_DATA_1 0x00000000
#define RV_DEBUG_SB_MEM 0xb0580000
#define RV_EXTERNAL_DATA 0xc0580000
#define RV_SERIALIO 0xd0580000
#ifndef RV_NMI_VEC
#define RV_NMI_VEC 0x11110000
#endif
#define RV_PIC_BITS 15
#define RV_PIC_REGION 0xf
#define RV_PIC_INT_WORDS 1
#define RV_PIC_TOTAL_INT_PLUS1 9
#define RV_PIC_MEIP_OFFSET 0x1000
#define RV_PIC_BASE_ADDR 0xf00c0000
#define RV_PIC_MEIGWCTRL_OFFSET 0x4000
#define RV_PIC_MEIPL_OFFSET 0x0000
#define RV_PIC_TOTAL_INT 8
#define RV_PIC_SIZE 32
#define RV_PIC_MEIE_OFFSET 0x2000
#define RV_PIC_OFFSET 0xc0000
#define RV_PIC_MEIPT_OFFSET 0x3004
#define RV_PIC_MPICCFG_OFFSET 0x3000
#define RV_PIC_MEIGWCLR_OFFSET 0x5000
#define CLOCK_PERIOD 100
#define CPU_TOP `RV_TOP.swerv
#define TOP tb_top
#define RV_BUILD_AHB_LITE 1
#define RV_TOP `TOP.rvtop
#define DATAWIDTH 64
#define RV_STERR_ROLLBACK 0
#define RV_EXT_ADDRWIDTH 32
#define RV_EXT_DATAWIDTH 64
#define SDVT_AHB 1
#define RV_LDERR_ROLLBACK 1
#define ASSERT_ON

View File

@ -0,0 +1,11 @@
// NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE
// This is an automatically generated file by joseph.rahmeh on Tue Jun 4 07:50:46 PDT 2019
//
// cmd: swerv -snapshot=default -ahb_lite
//
`include "common_defines.vh"
`undef ASSERT_ON
`undef TEC_RV_ICG
`define TEC_RV_ICG CKLNQD12BWP35P140
`define PHYSICAL 1

View File

@ -0,0 +1,566 @@
# NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE
# This is an automatically generated file by joseph.rahmeh on Tue Jun 4 07:50:46 PDT 2019
#
# cmd: swerv -snapshot=default -ahb_lite
#
# To use this in a perf script, use 'require $RV_ROOT/configs/config.pl'
# Reference the hash via $config{name}..
%config = (
'protection' => {
'inst_access_mask5' => '0xffffffff',
'data_access_enable4' => '0x0',
'inst_access_enable3' => '0x0',
'inst_access_enable0' => '0x0',
'inst_access_mask3' => '0xffffffff',
'data_access_enable5' => '0x0',
'data_access_mask5' => '0xffffffff',
'data_access_addr3' => '0x00000000',
'inst_access_enable7' => '0x0',
'data_access_addr6' => '0x00000000',
'inst_access_mask7' => '0xffffffff',
'inst_access_enable6' => '0x0',
'inst_access_enable5' => '0x0',
'data_access_addr4' => '0x00000000',
'data_access_addr7' => '0x00000000',
'data_access_mask3' => '0xffffffff',
'inst_access_mask4' => '0xffffffff',
'data_access_addr1' => '0x00000000',
'inst_access_addr4' => '0x00000000',
'inst_access_addr3' => '0x00000000',
'data_access_enable1' => '0x0',
'data_access_addr0' => '0x00000000',
'data_access_mask0' => '0xffffffff',
'data_access_mask6' => '0xffffffff',
'inst_access_addr7' => '0x00000000',
'inst_access_mask0' => '0xffffffff',
'data_access_addr5' => '0x00000000',
'data_access_addr2' => '0x00000000',
'data_access_mask4' => '0xffffffff',
'data_access_mask1' => '0xffffffff',
'inst_access_addr0' => '0x00000000',
'inst_access_addr2' => '0x00000000',
'data_access_enable0' => '0x0',
'data_access_enable2' => '0x0',
'data_access_enable7' => '0x0',
'inst_access_enable4' => '0x0',
'data_access_mask7' => '0xffffffff',
'inst_access_addr5' => '0x00000000',
'inst_access_enable1' => '0x0',
'data_access_mask2' => '0xffffffff',
'inst_access_mask6' => '0xffffffff',
'data_access_enable3' => '0x0',
'inst_access_addr6' => '0x00000000',
'inst_access_mask2' => '0xffffffff',
'inst_access_enable2' => '0x0',
'data_access_enable6' => '0x0',
'inst_access_addr1' => '0x00000000',
'inst_access_mask1' => '0xffffffff'
},
'core' => {
'dec_instbuf_depth' => '4',
'dma_buf_depth' => '4',
'lsu_num_nbload' => '8',
'lsu_stbuf_depth' => '8',
'lsu_num_nbload_width' => '3'
},
'bus' => {
'ifu_bus_tag' => '3',
'lsu_bus_tag' => 4,
'sb_bus_tag' => '1',
'dma_bus_tag' => '1'
},
'dccm' => {
'dccm_width_bits' => 2,
'dccm_region' => '0xf',
'dccm_reserved' => '0x1000',
'dccm_size' => 64,
'dccm_data_width' => 32,
'dccm_num_banks_8' => '',
'dccm_fdata_width' => 39,
'dccm_byte_width' => '4',
'dccm_data_cell' => 'ram_2048x39',
'dccm_enable' => '1',
'dccm_bits' => 16,
'dccm_offset' => '0x40000',
'dccm_ecc_width' => 7,
'dccm_size_64' => '',
'dccm_rows' => '2048',
'dccm_bank_bits' => 3,
'dccm_num_banks' => '8',
'dccm_index_bits' => 11,
'lsu_sb_bits' => 16,
'dccm_eadr' => '0xf004ffff',
'dccm_sadr' => '0xf0040000'
},
'reset_vec' => '0x80000000',
'retstack' => {
'ret_stack_size' => '4'
},
'triggers' => [
{
'poke_mask' => [
'0x081818c7',
'0xffffffff',
'0x00000000'
],
'reset' => [
'0x23e00000',
'0x00000000',
'0x00000000'
],
'mask' => [
'0x081818c7',
'0xffffffff',
'0x00000000'
]
},
{
'poke_mask' => [
'0x081818c7',
'0xffffffff',
'0x00000000'
],
'reset' => [
'0x23e00000',
'0x00000000',
'0x00000000'
],
'mask' => [
'0x081818c7',
'0xffffffff',
'0x00000000'
]
},
{
'poke_mask' => [
'0x081818c7',
'0xffffffff',
'0x00000000'
],
'reset' => [
'0x23e00000',
'0x00000000',
'0x00000000'
],
'mask' => [
'0x081818c7',
'0xffffffff',
'0x00000000'
]
},
{
'poke_mask' => [
'0x081818c7',
'0xffffffff',
'0x00000000'
],
'reset' => [
'0x23e00000',
'0x00000000',
'0x00000000'
],
'mask' => [
'0x081818c7',
'0xffffffff',
'0x00000000'
]
}
],
'xlen' => 32,
'verilator' => '',
'target' => 'default',
'max_mmode_perf_event' => '50',
'btb' => {
'btb_btag_fold' => 1,
'btb_index3_hi' => 9,
'btb_index1_lo' => '4',
'btb_addr_hi' => 5,
'btb_addr_lo' => '4',
'btb_index1_hi' => 5,
'btb_index2_hi' => 7,
'btb_index2_lo' => 6,
'btb_array_depth' => 4,
'btb_btag_size' => 9,
'btb_size' => 32,
'btb_index3_lo' => 8
},
'iccm' => {
'iccm_num_banks' => '8',
'iccm_bits' => 19,
'iccm_bank_bits' => 3,
'iccm_rows' => '16384',
'iccm_offset' => '0xe000000',
'iccm_region' => '0xe',
'iccm_sadr' => '0xee000000',
'iccm_reserved' => '0x1000',
'iccm_data_cell' => 'ram_16384x39',
'iccm_index_bits' => 14,
'iccm_num_banks_8' => '',
'iccm_size' => 512,
'iccm_eadr' => '0xee07ffff',
'iccm_size_512' => ''
},
'icache' => {
'icache_size' => 16,
'icache_tag_high' => 12,
'icache_ic_rows' => '256',
'icache_taddr_high' => 5,
'icache_tag_low' => '6',
'icache_tag_cell' => 'ram_64x21',
'icache_ic_depth' => 8,
'icache_ic_index' => 8,
'icache_enable' => '1',
'icache_data_cell' => 'ram_256x34',
'icache_tag_depth' => 64
},
'physical' => '1',
'memmap' => {
'external_prog' => '0xb0000000',
'external_data_1' => '0x00000000',
'debug_sb_mem' => '0xb0580000',
'external_data' => '0xc0580000',
'serialio' => '0xd0580000'
},
'nmi_vec' => '0x11110000',
'num_mmode_perf_regs' => '4',
'bht' => {
'bht_hash_string' => '{ghr[3:2] ^ {ghr[3+1], {4-1-2{1\'b0} } },hashin[5:4]^ghr[2-1:0]}',
'bht_addr_hi' => 7,
'bht_ghr_range' => '4:0',
'bht_ghr_size' => 5,
'bht_ghr_pad2' => 'fghr[4:3],2\'b0',
'bht_size' => 128,
'bht_addr_lo' => '4',
'bht_array_depth' => 16,
'bht_ghr_pad' => 'fghr[4],3\'b0'
},
'numiregs' => '32',
'even_odd_trigger_chains' => 'true',
'pic' => {
'pic_bits' => 15,
'pic_region' => '0xf',
'pic_int_words' => 1,
'pic_total_int_plus1' => 9,
'pic_meip_offset' => '0x1000',
'pic_base_addr' => '0xf00c0000',
'pic_meigwctrl_offset' => '0x4000',
'pic_meipl_offset' => '0x0000',
'pic_total_int' => 8,
'pic_size' => 32,
'pic_meie_offset' => '0x2000',
'pic_offset' => '0xc0000',
'pic_meipt_offset' => '0x3004',
'pic_mpiccfg_offset' => '0x3000',
'pic_meigwclr_offset' => '0x5000'
},
'testbench' => {
'clock_period' => '100',
'CPU_TOP' => '`RV_TOP.swerv',
'TOP' => 'tb_top',
'build_ahb_lite' => '1',
'RV_TOP' => '`TOP.rvtop',
'datawidth' => '64',
'sterr_rollback' => '0',
'ext_addrwidth' => '32',
'ext_datawidth' => '64',
'SDVT_AHB' => '1',
'lderr_rollback' => '1',
'assert_on' => ''
},
'tec_rv_icg' => 'clockhdr',
'csr' => {
'pmpaddr9' => {
'exists' => 'false'
},
'dicad1' => {
'reset' => '0x0',
'number' => '0x7ca',
'comment' => 'Cache diagnostics.',
'debug' => 'true',
'exists' => 'true',
'mask' => '0x3'
},
'pmpcfg0' => {
'exists' => 'false'
},
'mhpmcounter4h' => {
'reset' => '0x0',
'exists' => 'true',
'mask' => '0xffffffff'
},
'dicago' => {
'reset' => '0x0',
'number' => '0x7cb',
'comment' => 'Cache diagnostics.',
'debug' => 'true',
'exists' => 'true',
'mask' => '0x0'
},
'mie' => {
'reset' => '0x0',
'exists' => 'true',
'mask' => '0x40000888'
},
'misa' => {
'reset' => '0x40001104',
'exists' => 'true',
'mask' => '0x0'
},
'mhpmcounter6h' => {
'reset' => '0x0',
'exists' => 'true',
'mask' => '0xffffffff'
},
'meicpct' => {
'reset' => '0x0',
'number' => '0xbca',
'comment' => 'External claim id/priority capture.',
'exists' => 'true',
'mask' => '0x0'
},
'mimpid' => {
'reset' => '0x1',
'exists' => 'true',
'mask' => '0x0'
},
'mcpc' => {
'reset' => '0x0',
'number' => '0x7c2',
'exists' => 'true',
'mask' => '0x0'
},
'mhpmevent4' => {
'reset' => '0x0',
'exists' => 'true',
'mask' => '0xffffffff'
},
'pmpaddr8' => {
'exists' => 'false'
},
'pmpcfg3' => {
'exists' => 'false'
},
'marchid' => {
'reset' => '0x0000000b',
'exists' => 'true',
'mask' => '0x0'
},
'pmpaddr5' => {
'exists' => 'false'
},
'mfdc' => {
'reset' => '0x00070000',
'number' => '0x7f9',
'exists' => 'true',
'mask' => '0x000707ff'
},
'mhpmevent6' => {
'reset' => '0x0',
'exists' => 'true',
'mask' => '0xffffffff'
},
'mvendorid' => {
'reset' => '0x45',
'exists' => 'true',
'mask' => '0x0'
},
'pmpaddr4' => {
'exists' => 'false'
},
'dcsr' => {
'poke_mask' => '0x00008dcc',
'reset' => '0x40000003',
'exists' => 'true',
'mask' => '0x00008c04'
},
'cycle' => {
'exists' => 'false'
},
'pmpaddr12' => {
'exists' => 'false'
},
'pmpaddr3' => {
'exists' => 'false'
},
'mhpmcounter3h' => {
'reset' => '0x0',
'exists' => 'true',
'mask' => '0xffffffff'
},
'time' => {
'exists' => 'false'
},
'meicidpl' => {
'reset' => '0x0',
'number' => '0xbcb',
'comment' => 'External interrupt claim id priority level.',
'exists' => 'true',
'mask' => '0xf'
},
'pmpaddr14' => {
'exists' => 'false'
},
'pmpaddr13' => {
'exists' => 'false'
},
'pmpaddr1' => {
'exists' => 'false'
},
'mhpmcounter6' => {
'reset' => '0x0',
'exists' => 'true',
'mask' => '0xffffffff'
},
'dicad0' => {
'reset' => '0x0',
'number' => '0x7c9',
'comment' => 'Cache diagnostics.',
'debug' => 'true',
'exists' => 'true',
'mask' => '0xffffffff'
},
'meipt' => {
'reset' => '0x0',
'number' => '0xbc9',
'comment' => 'External interrupt priority threshold.',
'exists' => 'true',
'mask' => '0xf'
},
'pmpaddr15' => {
'exists' => 'false'
},
'mhpmcounter5' => {
'reset' => '0x0',
'exists' => 'true',
'mask' => '0xffffffff'
},
'pmpcfg1' => {
'exists' => 'false'
},
'pmpaddr10' => {
'exists' => 'false'
},
'pmpaddr0' => {
'exists' => 'false'
},
'pmpcfg2' => {
'exists' => 'false'
},
'pmpaddr2' => {
'exists' => 'false'
},
'mpmc' => {
'reset' => '0x0',
'number' => '0x7c6',
'comment' => 'Core pause: Implemented as read only.',
'exists' => 'true',
'mask' => '0x0'
},
'dmst' => {
'reset' => '0x0',
'number' => '0x7c4',
'comment' => 'Memory synch trigger: Flush caches in debug mode.',
'debug' => 'true',
'exists' => 'true',
'mask' => '0x0'
},
'instret' => {
'exists' => 'false'
},
'mhpmevent3' => {
'reset' => '0x0',
'exists' => 'true',
'mask' => '0xffffffff'
},
'dicawics' => {
'reset' => '0x0',
'number' => '0x7c8',
'comment' => 'Cache diagnostics.',
'debug' => 'true',
'exists' => 'true',
'mask' => '0x0130fffc'
},
'mip' => {
'poke_mask' => '0x40000888',
'reset' => '0x0',
'exists' => 'true',
'mask' => '0x0'
},
'mhpmcounter5h' => {
'reset' => '0x0',
'exists' => 'true',
'mask' => '0xffffffff'
},
'micect' => {
'reset' => '0x0',
'number' => '0x7f0',
'exists' => 'true',
'mask' => '0xffffffff'
},
'miccmect' => {
'reset' => '0x0',
'number' => '0x7f1',
'exists' => 'true',
'mask' => '0xffffffff'
},
'mhpmevent5' => {
'reset' => '0x0',
'exists' => 'true',
'mask' => '0xffffffff'
},
'mhpmcounter3' => {
'reset' => '0x0',
'exists' => 'true',
'mask' => '0xffffffff'
},
'pmpaddr6' => {
'exists' => 'false'
},
'pmpaddr11' => {
'exists' => 'false'
},
'mcgc' => {
'poke_mask' => '0x000001ff',
'reset' => '0x0',
'number' => '0x7f8',
'exists' => 'true',
'mask' => '0x000001ff'
},
'mhpmcounter4' => {
'reset' => '0x0',
'exists' => 'true',
'mask' => '0xffffffff'
},
'mdccmect' => {
'reset' => '0x0',
'number' => '0x7f2',
'exists' => 'true',
'mask' => '0xffffffff'
},
'pmpaddr7' => {
'exists' => 'false'
},
'meicurpl' => {
'reset' => '0x0',
'number' => '0xbcc',
'comment' => 'External interrupt current priority level.',
'exists' => 'true',
'mask' => '0xf'
},
'mstatus' => {
'reset' => '0x1800',
'exists' => 'true',
'mask' => '0x88'
},
'tselect' => {
'reset' => '0x0',
'exists' => 'true',
'mask' => '0x3'
}
},
'regwidth' => '32',
'harts' => 1
);
1;

View File

@ -0,0 +1,173 @@
// argv=9
// TOTAL_INT=9 NUM_LEVELS=4
`ifdef RV_PIC_2CYCLE
// LEVEL0
logic [TOTAL_INT+2:0] [INTPRIORITY_BITS-1:0] level_intpend_w_prior_en_1;
logic [TOTAL_INT+2:0] [ID_BITS-1:0] level_intpend_id_1;
for (m=0; m<=(TOTAL_INT)/(2**(1)) ; m++) begin : COMPARE0
if ( m == (TOTAL_INT)/(2**(1))) begin
assign level_intpend_w_prior_en_1[m+1] = '0 ;
assign level_intpend_id_1[m+1] = '0 ;
end
cmp_and_mux #(
.ID_BITS(ID_BITS),
.INTPRIORITY_BITS(INTPRIORITY_BITS)) cmp_l1 (
.a_id(level_intpend_id[0][2*m]),
.a_priority(level_intpend_w_prior_en[0][2*m]),
.b_id(level_intpend_id[0][2*m+1]),
.b_priority(level_intpend_w_prior_en[0][2*m+1]),
.out_id(level_intpend_id_1[m]),
.out_priority(level_intpend_w_prior_en_1[m])) ;
end
// LEVEL1
logic [TOTAL_INT+2:0] [INTPRIORITY_BITS-1:0] level_intpend_w_prior_en_2;
logic [TOTAL_INT+2:0] [ID_BITS-1:0] level_intpend_id_2;
for (m=0; m<=(TOTAL_INT)/(2**(2)) ; m++) begin : COMPARE1
if ( m == (TOTAL_INT)/(2**(2))) begin
assign level_intpend_w_prior_en_2[m+1] = '0 ;
assign level_intpend_id_2[m+1] = '0 ;
end
cmp_and_mux #(
.ID_BITS(ID_BITS),
.INTPRIORITY_BITS(INTPRIORITY_BITS)) cmp_l2 (
.a_id(level_intpend_id_1[2*m]),
.a_priority(level_intpend_w_prior_en_1[2*m]),
.b_id(level_intpend_id_1[2*m+1]),
.b_priority(level_intpend_w_prior_en_1[2*m+1]),
.out_id(level_intpend_id_2[m]),
.out_priority(level_intpend_w_prior_en_2[m])) ;
end
for (i=0; i<=TOTAL_INT/2**(NUM_LEVELS/2) ; i++) begin : MIDDLE_FLOPS
rvdff #(INTPRIORITY_BITS) level2_intpend_prior_reg (.*, .din (level_intpend_w_prior_en_2[i]), .dout(l2_intpend_w_prior_en_ff[i]), .clk(active_clk));
rvdff #(ID_BITS) level2_intpend_id_reg (.*, .din (level_intpend_id_2[i]), .dout(l2_intpend_id_ff[i]), .clk(active_clk));
end
// LEVEL2
logic [TOTAL_INT+2:0] [INTPRIORITY_BITS-1:0] levelx_intpend_w_prior_en_3;
logic [TOTAL_INT+2:0] [ID_BITS-1:0] levelx_intpend_id_3;
for (m=0; m<=(TOTAL_INT)/(2**(3)) ; m++) begin : COMPARE2
if ( m == (TOTAL_INT)/(2**(3))) begin
assign levelx_intpend_w_prior_en_3[m+1] = '0 ;
assign levelx_intpend_id_3[m+1] = '0 ;
end
cmp_and_mux #(
.ID_BITS(ID_BITS),
.INTPRIORITY_BITS(INTPRIORITY_BITS)) cmp_l3 (
.a_id(levelx_intpend_id[2][2*m]),
.a_priority(levelx_intpend_w_prior_en[2][2*m]),
.b_id(levelx_intpend_id[2][2*m+1]),
.b_priority(levelx_intpend_w_prior_en[2][2*m+1]),
.out_id(levelx_intpend_id_3[m]),
.out_priority(levelx_intpend_w_prior_en_3[m])) ;
end
// LEVEL3
logic [TOTAL_INT+2:0] [INTPRIORITY_BITS-1:0] levelx_intpend_w_prior_en_4;
logic [TOTAL_INT+2:0] [ID_BITS-1:0] levelx_intpend_id_4;
for (m=0; m<=(TOTAL_INT)/(2**(4)) ; m++) begin : COMPARE3
if ( m == (TOTAL_INT)/(2**(4))) begin
assign levelx_intpend_w_prior_en_4[m+1] = '0 ;
assign levelx_intpend_id_4[m+1] = '0 ;
end
cmp_and_mux #(
.ID_BITS(ID_BITS),
.INTPRIORITY_BITS(INTPRIORITY_BITS)) cmp_l4 (
.a_id(levelx_intpend_id_3[2*m]),
.a_priority(levelx_intpend_w_prior_en_3[2*m]),
.b_id(levelx_intpend_id_3[2*m+1]),
.b_priority(levelx_intpend_w_prior_en_3[2*m+1]),
.out_id(levelx_intpend_id_4[m]),
.out_priority(levelx_intpend_w_prior_en_4[m])) ;
end
assign claimid_in[ID_BITS-1:0] = levelx_intpend_id_4[0] ; // This is the last level output
assign selected_int_priority[INTPRIORITY_BITS-1:0] = levelx_intpend_w_prior_en_4[0] ;
`else
// LEVEL0
logic [TOTAL_INT+2:0] [INTPRIORITY_BITS-1:0] level_intpend_w_prior_en_1;
logic [TOTAL_INT+2:0] [ID_BITS-1:0] level_intpend_id_1;
for (m=0; m<=(TOTAL_INT)/(2**(1)) ; m++) begin : COMPARE0
if ( m == (TOTAL_INT)/(2**(1))) begin
assign level_intpend_w_prior_en_1[m+1] = '0 ;
assign level_intpend_id_1[m+1] = '0 ;
end
cmp_and_mux #(
.ID_BITS(ID_BITS),
.INTPRIORITY_BITS(INTPRIORITY_BITS)) cmp_l1 (
.a_id(level_intpend_id[0][2*m]),
.a_priority(level_intpend_w_prior_en[0][2*m]),
.b_id(level_intpend_id[0][2*m+1]),
.b_priority(level_intpend_w_prior_en[0][2*m+1]),
.out_id(level_intpend_id_1[m]),
.out_priority(level_intpend_w_prior_en_1[m])) ;
end
// LEVEL1
logic [TOTAL_INT+2:0] [INTPRIORITY_BITS-1:0] level_intpend_w_prior_en_2;
logic [TOTAL_INT+2:0] [ID_BITS-1:0] level_intpend_id_2;
for (m=0; m<=(TOTAL_INT)/(2**(2)) ; m++) begin : COMPARE1
if ( m == (TOTAL_INT)/(2**(2))) begin
assign level_intpend_w_prior_en_2[m+1] = '0 ;
assign level_intpend_id_2[m+1] = '0 ;
end
cmp_and_mux #(
.ID_BITS(ID_BITS),
.INTPRIORITY_BITS(INTPRIORITY_BITS)) cmp_l2 (
.a_id(level_intpend_id_1[2*m]),
.a_priority(level_intpend_w_prior_en_1[2*m]),
.b_id(level_intpend_id_1[2*m+1]),
.b_priority(level_intpend_w_prior_en_1[2*m+1]),
.out_id(level_intpend_id_2[m]),
.out_priority(level_intpend_w_prior_en_2[m])) ;
end
// LEVEL2
logic [TOTAL_INT+2:0] [INTPRIORITY_BITS-1:0] level_intpend_w_prior_en_3;
logic [TOTAL_INT+2:0] [ID_BITS-1:0] level_intpend_id_3;
for (m=0; m<=(TOTAL_INT)/(2**(3)) ; m++) begin : COMPARE2
if ( m == (TOTAL_INT)/(2**(3))) begin
assign level_intpend_w_prior_en_3[m+1] = '0 ;
assign level_intpend_id_3[m+1] = '0 ;
end
cmp_and_mux #(
.ID_BITS(ID_BITS),
.INTPRIORITY_BITS(INTPRIORITY_BITS)) cmp_l3 (
.a_id(level_intpend_id_2[2*m]),
.a_priority(level_intpend_w_prior_en_2[2*m]),
.b_id(level_intpend_id_2[2*m+1]),
.b_priority(level_intpend_w_prior_en_2[2*m+1]),
.out_id(level_intpend_id_3[m]),
.out_priority(level_intpend_w_prior_en_3[m])) ;
end
// LEVEL3
logic [TOTAL_INT+2:0] [INTPRIORITY_BITS-1:0] level_intpend_w_prior_en_4;
logic [TOTAL_INT+2:0] [ID_BITS-1:0] level_intpend_id_4;
for (m=0; m<=(TOTAL_INT)/(2**(4)) ; m++) begin : COMPARE3
if ( m == (TOTAL_INT)/(2**(4))) begin
assign level_intpend_w_prior_en_4[m+1] = '0 ;
assign level_intpend_id_4[m+1] = '0 ;
end
cmp_and_mux #(
.ID_BITS(ID_BITS),
.INTPRIORITY_BITS(INTPRIORITY_BITS)) cmp_l4 (
.a_id(level_intpend_id_3[2*m]),
.a_priority(level_intpend_w_prior_en_3[2*m]),
.b_id(level_intpend_id_3[2*m+1]),
.b_priority(level_intpend_w_prior_en_3[2*m+1]),
.out_id(level_intpend_id_4[m]),
.out_priority(level_intpend_w_prior_en_4[m])) ;
end
assign claimid_in[ID_BITS-1:0] = level_intpend_id_4[0] ; // This is the last level output
assign selected_int_priority[INTPRIORITY_BITS-1:0] = level_intpend_w_prior_en_4[0] ;
`endif

View File

@ -0,0 +1,31 @@
// mask[3:0] = { 4'b1000 - 30b mask,4'b0100 - 31b mask, 4'b0010 - 28b mask, 4'b0001 - 32b mask }
always_comb begin
case (address[14:0])
15'b011000000000000 : mask[3:0] = 4'b0100;
15'b100000000000100 : mask[3:0] = 4'b1000;
15'b100000000001000 : mask[3:0] = 4'b1000;
15'b100000000001100 : mask[3:0] = 4'b1000;
15'b100000000010000 : mask[3:0] = 4'b1000;
15'b100000000010100 : mask[3:0] = 4'b1000;
15'b100000000011000 : mask[3:0] = 4'b1000;
15'b100000000011100 : mask[3:0] = 4'b1000;
15'b100000000100000 : mask[3:0] = 4'b1000;
15'b010000000000100 : mask[3:0] = 4'b0100;
15'b010000000001000 : mask[3:0] = 4'b0100;
15'b010000000001100 : mask[3:0] = 4'b0100;
15'b010000000010000 : mask[3:0] = 4'b0100;
15'b010000000010100 : mask[3:0] = 4'b0100;
15'b010000000011000 : mask[3:0] = 4'b0100;
15'b010000000011100 : mask[3:0] = 4'b0100;
15'b010000000100000 : mask[3:0] = 4'b0100;
15'b000000000000100 : mask[3:0] = 4'b0010;
15'b000000000001000 : mask[3:0] = 4'b0010;
15'b000000000001100 : mask[3:0] = 4'b0010;
15'b000000000010000 : mask[3:0] = 4'b0010;
15'b000000000010100 : mask[3:0] = 4'b0010;
15'b000000000011000 : mask[3:0] = 4'b0010;
15'b000000000011100 : mask[3:0] = 4'b0010;
15'b000000000100000 : mask[3:0] = 4'b0010;
default : mask[3:0] = 4'b0001;
endcase
end

View File

@ -0,0 +1,395 @@
{
"memmap" : {
"cosnoleio" : "0xd0580000"
},
"nmi_vec" : "0x11110000",
"dccm" : {
"region" : "0xf",
"offset" : "0x40000",
"size" : "0x10000"
},
"num_mmode_perf_regs" : "4",
"load_error_rollback" : "1",
"reset_vec" : "0x80000000",
"triggers" : [
{
"poke_mask" : [
"0x081818c7",
"0xffffffff",
"0x00000000"
],
"reset" : [
"0x23e00000",
"0x00000000",
"0x00000000"
],
"mask" : [
"0x081818c7",
"0xffffffff",
"0x00000000"
]
},
{
"poke_mask" : [
"0x081818c7",
"0xffffffff",
"0x00000000"
],
"reset" : [
"0x23e00000",
"0x00000000",
"0x00000000"
],
"mask" : [
"0x081818c7",
"0xffffffff",
"0x00000000"
]
},
{
"poke_mask" : [
"0x081818c7",
"0xffffffff",
"0x00000000"
],
"reset" : [
"0x23e00000",
"0x00000000",
"0x00000000"
],
"mask" : [
"0x081818c7",
"0xffffffff",
"0x00000000"
]
},
{
"poke_mask" : [
"0x081818c7",
"0xffffffff",
"0x00000000"
],
"reset" : [
"0x23e00000",
"0x00000000",
"0x00000000"
],
"mask" : [
"0x081818c7",
"0xffffffff",
"0x00000000"
]
}
],
"xlen" : 32,
"pic" : {
"meigwctrl_offset" : "0x4000",
"region" : "0xf",
"total_int" : 8,
"size" : "0x8000",
"mpiccfg_offset" : "0x3000",
"meigwclr_offset" : "0x5000",
"total_int_plus1" : 9,
"meipt_offset" : "0x3004",
"int_words" : 1,
"meie_offset" : "0x2000",
"bits" : 15,
"meip_offset" : "0x1000",
"meipl_offset" : "0x0000",
"offset" : "0xc0000"
},
"store_error_rollback" : "0",
"even_odd_trigger_chains" : "true",
"max_mmode_perf_event" : "50",
"csr" : {
"pmpaddr9" : {
"exists" : "false"
},
"dicad1" : {
"reset" : "0x0",
"number" : "0x7ca",
"comment" : "Cache diagnostics.",
"debug" : "true",
"exists" : "true",
"mask" : "0x3"
},
"pmpcfg0" : {
"exists" : "false"
},
"mhpmcounter4h" : {
"reset" : "0x0",
"exists" : "true",
"mask" : "0xffffffff"
},
"dicago" : {
"reset" : "0x0",
"number" : "0x7cb",
"comment" : "Cache diagnostics.",
"debug" : "true",
"exists" : "true",
"mask" : "0x0"
},
"mie" : {
"reset" : "0x0",
"exists" : "true",
"mask" : "0x40000888"
},
"misa" : {
"reset" : "0x40001104",
"exists" : "true",
"mask" : "0x0"
},
"mhpmcounter6h" : {
"reset" : "0x0",
"exists" : "true",
"mask" : "0xffffffff"
},
"meicpct" : {
"reset" : "0x0",
"number" : "0xbca",
"comment" : "External claim id/priority capture.",
"exists" : "true",
"mask" : "0x0"
},
"mimpid" : {
"reset" : "0x1",
"exists" : "true",
"mask" : "0x0"
},
"mcpc" : {
"reset" : "0x0",
"number" : "0x7c2",
"exists" : "true",
"mask" : "0x0"
},
"mhpmevent4" : {
"reset" : "0x0",
"exists" : "true",
"mask" : "0xffffffff"
},
"pmpaddr8" : {
"exists" : "false"
},
"pmpcfg3" : {
"exists" : "false"
},
"marchid" : {
"reset" : "0x0000000b",
"exists" : "true",
"mask" : "0x0"
},
"pmpaddr5" : {
"exists" : "false"
},
"mfdc" : {
"reset" : "0x00070000",
"number" : "0x7f9",
"exists" : "true",
"mask" : "0x000707ff"
},
"mhpmevent6" : {
"reset" : "0x0",
"exists" : "true",
"mask" : "0xffffffff"
},
"mvendorid" : {
"reset" : "0x45",
"exists" : "true",
"mask" : "0x0"
},
"pmpaddr4" : {
"exists" : "false"
},
"dcsr" : {
"poke_mask" : "0x00008dcc",
"reset" : "0x40000003",
"exists" : "true",
"mask" : "0x00008c04"
},
"cycle" : {
"exists" : "false"
},
"pmpaddr12" : {
"exists" : "false"
},
"pmpaddr3" : {
"exists" : "false"
},
"mhpmcounter3h" : {
"reset" : "0x0",
"exists" : "true",
"mask" : "0xffffffff"
},
"time" : {
"exists" : "false"
},
"meicidpl" : {
"reset" : "0x0",
"number" : "0xbcb",
"comment" : "External interrupt claim id priority level.",
"exists" : "true",
"mask" : "0xf"
},
"pmpaddr14" : {
"exists" : "false"
},
"pmpaddr13" : {
"exists" : "false"
},
"pmpaddr1" : {
"exists" : "false"
},
"mhpmcounter6" : {
"reset" : "0x0",
"exists" : "true",
"mask" : "0xffffffff"
},
"dicad0" : {
"reset" : "0x0",
"number" : "0x7c9",
"comment" : "Cache diagnostics.",
"debug" : "true",
"exists" : "true",
"mask" : "0xffffffff"
},
"meipt" : {
"reset" : "0x0",
"number" : "0xbc9",
"comment" : "External interrupt priority threshold.",
"exists" : "true",
"mask" : "0xf"
},
"pmpaddr15" : {
"exists" : "false"
},
"mhpmcounter5" : {
"reset" : "0x0",
"exists" : "true",
"mask" : "0xffffffff"
},
"pmpcfg1" : {
"exists" : "false"
},
"pmpaddr10" : {
"exists" : "false"
},
"pmpaddr0" : {
"exists" : "false"
},
"pmpcfg2" : {
"exists" : "false"
},
"pmpaddr2" : {
"exists" : "false"
},
"mpmc" : {
"reset" : "0x0",
"number" : "0x7c6",
"comment" : "Core pause: Implemented as read only.",
"exists" : "true",
"mask" : "0x0"
},
"dmst" : {
"reset" : "0x0",
"number" : "0x7c4",
"comment" : "Memory synch trigger: Flush caches in debug mode.",
"debug" : "true",
"exists" : "true",
"mask" : "0x0"
},
"instret" : {
"exists" : "false"
},
"mhpmevent3" : {
"reset" : "0x0",
"exists" : "true",
"mask" : "0xffffffff"
},
"dicawics" : {
"reset" : "0x0",
"number" : "0x7c8",
"comment" : "Cache diagnostics.",
"debug" : "true",
"exists" : "true",
"mask" : "0x0130fffc"
},
"mip" : {
"poke_mask" : "0x40000888",
"reset" : "0x0",
"exists" : "true",
"mask" : "0x0"
},
"mhpmcounter5h" : {
"reset" : "0x0",
"exists" : "true",
"mask" : "0xffffffff"
},
"micect" : {
"reset" : "0x0",
"number" : "0x7f0",
"exists" : "true",
"mask" : "0xffffffff"
},
"miccmect" : {
"reset" : "0x0",
"number" : "0x7f1",
"exists" : "true",
"mask" : "0xffffffff"
},
"mhpmevent5" : {
"reset" : "0x0",
"exists" : "true",
"mask" : "0xffffffff"
},
"mhpmcounter3" : {
"reset" : "0x0",
"exists" : "true",
"mask" : "0xffffffff"
},
"pmpaddr6" : {
"exists" : "false"
},
"pmpaddr11" : {
"exists" : "false"
},
"mcgc" : {
"poke_mask" : "0x000001ff",
"reset" : "0x0",
"number" : "0x7f8",
"exists" : "true",
"mask" : "0x000001ff"
},
"mhpmcounter4" : {
"reset" : "0x0",
"exists" : "true",
"mask" : "0xffffffff"
},
"mdccmect" : {
"reset" : "0x0",
"number" : "0x7f2",
"exists" : "true",
"mask" : "0xffffffff"
},
"pmpaddr7" : {
"exists" : "false"
},
"meicurpl" : {
"reset" : "0x0",
"number" : "0xbcc",
"comment" : "External interrupt current priority level.",
"exists" : "true",
"mask" : "0xf"
},
"mstatus" : {
"reset" : "0x1800",
"exists" : "true",
"mask" : "0x88"
},
"tselect" : {
"reset" : "0x0",
"exists" : "true",
"mask" : "0x3"
}
},
"harts" : 1
}

1706
configs/swerv.config Executable file

File diff suppressed because it is too large Load Diff

626
design/dbg/dbg.sv Normal file
View File

@ -0,0 +1,626 @@
// 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.
//********************************************************************************
// $Id$
//
// Function: Top level SWERV core file to control the debug mode
// Comments: Responsible to put the rest of the core in quiesce mode,
// Send the commands/address. sends WrData and Recieve read Data.
// And then Resume the core to do the normal mode
// Author :
//********************************************************************************
module dbg (
// outputs to the core for command and data interface
output logic [31:0] dbg_cmd_addr,
output logic [31:0] dbg_cmd_wrdata,
output logic dbg_cmd_valid,
output logic dbg_cmd_write, // 1: write command, 0: read_command
output logic [1:0] dbg_cmd_type, // 0:gpr 1:csr 2: memory
output logic [1:0] dbg_cmd_size, // size of the abstract mem access debug command
output logic dbg_core_rst_l, // core reset from dm
// inputs back from the core/dec
input logic [31:0] core_dbg_rddata,
input logic core_dbg_cmd_done, // This will be treated like a valid signal
input logic core_dbg_cmd_fail, // Exception during command run
// Signals to dma to get a bubble
output logic dbg_dma_bubble, // Debug needs a bubble to send a valid
input logic dma_dbg_ready, // DMA is ready to accept debug request
// interface with the rest of the core to halt/resume handshaking
output logic dbg_halt_req, // This is a pulse
output logic dbg_resume_req, // Debug sends a resume requests. Pulse
input logic dec_tlu_debug_mode, // Core is in debug mode
input logic dec_tlu_dbg_halted, // The core has finished the queiscing sequence. Core is halted now
input logic dec_tlu_mpc_halted_only, // Only halted due to MPC
input logic dec_tlu_resume_ack, // core sends back an ack for the resume (pulse)
// inputs from the JTAG
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
// output
output logic [31:0] dmi_reg_rdata, // read data
// output logic dmi_reg_ack,
// AXI signals
// AXI Write Channels
output logic sb_axi_awvalid,
input logic sb_axi_awready,
output logic [`RV_SB_BUS_TAG-1:0] sb_axi_awid,
output logic [31:0] sb_axi_awaddr,
output logic [3:0] sb_axi_awregion,
output logic [7:0] sb_axi_awlen,
output logic [2:0] sb_axi_awsize,
output logic [1:0] sb_axi_awburst,
output logic sb_axi_awlock,
output logic [3:0] sb_axi_awcache,
output logic [2:0] sb_axi_awprot,
output logic [3:0] sb_axi_awqos,
output logic sb_axi_wvalid,
input logic sb_axi_wready,
output logic [63:0] sb_axi_wdata,
output logic [7:0] sb_axi_wstrb,
output logic sb_axi_wlast,
input logic sb_axi_bvalid,
output logic sb_axi_bready,
input logic [1:0] sb_axi_bresp,
input logic [`RV_SB_BUS_TAG-1:0] sb_axi_bid,
// AXI Read Channels
output logic sb_axi_arvalid,
input logic sb_axi_arready,
output logic [`RV_SB_BUS_TAG-1:0] sb_axi_arid,
output logic [31:0] sb_axi_araddr,
output logic [3:0] sb_axi_arregion,
output logic [7:0] sb_axi_arlen,
output logic [2:0] sb_axi_arsize,
output logic [1:0] sb_axi_arburst,
output logic sb_axi_arlock,
output logic [3:0] sb_axi_arcache,
output logic [2:0] sb_axi_arprot,
output logic [3:0] sb_axi_arqos,
input logic sb_axi_rvalid,
output logic sb_axi_rready,
input logic [`RV_SB_BUS_TAG-1:0] sb_axi_rid,
input logic [63:0] sb_axi_rdata,
input logic [1:0] sb_axi_rresp,
input logic sb_axi_rlast,
input logic dbg_bus_clk_en,
// general inputs
input logic clk,
input logic free_clk,
input logic rst_l,
input logic clk_override,
input logic scan_mode
);
`include "global.h"
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] {SBIDLE=4'b0, WAIT=4'b1, CMD_RD=4'b10, CMD_WR=4'b11, CMD_WR_ADDR=4'b100, CMD_WR_DATA=4'b101, RSP_RD=4'b110, RSP_WR=4'b111, DONE=4'b1000} sb_state_t;
state_t dbg_state;
state_t dbg_nxtstate;
logic dbg_state_en;
// these are the registers that the debug module implements
logic [31:0] dmstatus_reg; // [26:24]-dmerr, [17:16]-resume ack, [9:8]-halted, [3:0]-version
logic [31:0] dmcontrol_reg; // dmcontrol register has only 6 bits implemented. 31: haltreq, 30: resumereq, 29: haltreset, 28: ackhavereset, 1: ndmreset, 0: dmactive.
logic [31:0] command_reg;
logic [31:0] abstractcs_reg; // bits implemted are [12] - busy and [10:8]= command error
logic [31:0] haltsum0_reg;
logic [31:0] data0_reg;
logic [31:0] data1_reg;
// data 0
logic [31:0] data0_din;
logic data0_reg_wren, data0_reg_wren0, data0_reg_wren1;
// data 1
logic [31:0] data1_din;
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;
// dmstatus
//logic dmstatus_wren;
logic dmstatus_dmerr_wren;
logic dmstatus_resumeack_wren;
logic dmstatus_resumeack_din;
logic dmstatus_havereset_wren;
logic dmstatus_havereset_rst;
logic dmstatus_resumeack;
logic dmstatus_halted;
logic dmstatus_havereset;
// dmcontrol
logic dmcontrol_wren, dmcontrol_wren_Q;
// command
logic command_wren;
// needed to send the read data back for dmi reads
logic [31:0] dmi_reg_rdata_din;
sb_state_t sb_state;
sb_state_t sb_nxtstate;
logic sb_state_en;
//System bus section
logic sbcs_wren;
logic sbcs_sbbusy_wren;
logic sbcs_sbbusy_din;
logic sbcs_sbbusyerror_wren;
logic sbcs_sbbusyerror_din;
logic sbcs_sberror_wren;
logic [2:0] sbcs_sberror_din;
logic sbcs_unaligned;
logic sbcs_illegal_size;
// data
logic sbdata0_reg_wren0;
logic sbdata0_reg_wren1;
logic sbdata0_reg_wren;
logic [31:0] sbdata0_din;
logic sbdata1_reg_wren0;
logic sbdata1_reg_wren1;
logic sbdata1_reg_wren;
logic [31:0] sbdata1_din;
logic sbaddress0_reg_wren0;
logic sbaddress0_reg_wren1;
logic sbaddress0_reg_wren;
logic [31:0] sbaddress0_reg_din;
logic [3:0] sbaddress0_incr;
logic sbreadonaddr_access;
logic sbreadondata_access;
logic sbdata0wr_access;
logic sb_axi_awvalid_q, sb_axi_awready_q;
logic sb_axi_wvalid_q, sb_axi_wready_q;
logic sb_axi_arvalid_q, sb_axi_arready_q;
logic sb_axi_bvalid_q, sb_axi_bready_q;
logic sb_axi_rvalid_q, sb_axi_rready_q;
logic [1:0] sb_axi_bresp_q, sb_axi_rresp_q;
logic [63:0] sb_axi_rdata_q;
logic [63:0] sb_bus_rdata;
//registers
logic [31:0] sbcs_reg;
logic [31:0] sbaddress0_reg;
logic [31:0] sbdata0_reg;
logic [31:0] sbdata1_reg;
logic dbg_dm_rst_l;
//clken
logic dbg_free_clken;
logic dbg_free_clk;
logic sb_free_clken;
logic sb_free_clk;
logic bus_clken;
logic bus_clk;
// 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;
// used for the system bus
assign sb_free_clken = dmi_reg_en | sb_state_en | (sb_state != SBIDLE) | clk_override;
assign bus_clken = (sb_axi_awvalid | sb_axi_wvalid | sb_axi_arvalid | sb_axi_bvalid | sb_axi_rvalid | clk_override) & dbg_bus_clk_en;
rvclkhdr dbg_free_cgc (.en(dbg_free_clken), .l1clk(dbg_free_clk), .*);
rvclkhdr sb_free_cgc (.en(sb_free_clken), .l1clk(sb_free_clk), .*);
rvclkhdr bus_cgc (.en(bus_clken), .l1clk(bus_clk), .*);
// end clocking section
// Reset logic
assign dbg_dm_rst_l = rst_l & (dmcontrol_reg[0] | scan_mode);
assign dbg_core_rst_l = ~dmcontrol_reg[1];
// 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[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_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)));
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 #(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]) |
((sbcs_reg[19:17] == 3'b010) & (|sbaddress0_reg[1:0])) |
((sbcs_reg[19:17] == 3'b011) & (|sbaddress0_reg[2:0]));
assign sbcs_illegal_size = sbcs_reg[19]; // Anything bigger than 64 bits is illegal
assign sbaddress0_incr[3:0] = ({4{(sbcs_reg[19:17] == 3'b000)}} & 4'b0001) |
({4{(sbcs_reg[19:17] == 3'b001)}} & 4'b0010) |
({4{(sbcs_reg[19:17] == 3'b010)}} & 4'b0100) |
({4{(sbcs_reg[19:17] == 3'b100)}} & 4'b1000);
// sbdata
//assign sbdata0_reg_wren0 = dmi_reg_en & dmi_reg_wr_en & (dmi_reg_addr == 32'h3c);
assign sbdata0_reg_wren0 = dmi_reg_en & dmi_reg_wr_en & (dmi_reg_addr == 7'h3c); // write data only when single read is 0
assign sbdata0_reg_wren1 = (sb_state == RSP_RD) & sb_state_en & ~sbcs_sberror_wren;
assign sbdata0_reg_wren = sbdata0_reg_wren0 | sbdata0_reg_wren1;
assign sbdata1_reg_wren0 = dmi_reg_en & dmi_reg_wr_en & (dmi_reg_addr == 7'h3d); // write data only when single read is 0;
assign sbdata1_reg_wren1 = (sb_state == RSP_RD) & sb_state_en & ~sbcs_sberror_wren;
assign sbdata1_reg_wren = sbdata1_reg_wren0 | sbdata1_reg_wren1;
assign sbdata0_din[31:0] = ({32{sbdata0_reg_wren0}} & dmi_reg_wdata[31:0]) |
({32{sbdata0_reg_wren1}} & sb_bus_rdata[31:0]);
assign sbdata1_din[31:0] = ({32{sbdata1_reg_wren0}} & dmi_reg_wdata[31:0]) |
({32{sbdata1_reg_wren1}} & sb_bus_rdata[63:32]);
rvdffe #(32) dbg_sbdata0_reg (.*, .din(sbdata0_din[31:0]), .dout(sbdata0_reg[31:0]), .en(sbdata0_reg_wren), .rst_l(dbg_dm_rst_l));
rvdffe #(32) dbg_sbdata1_reg (.*, .din(sbdata1_din[31:0]), .dout(sbdata1_reg[31:0]), .en(sbdata1_reg_wren), .rst_l(dbg_dm_rst_l));
// sbaddress
assign sbaddress0_reg_wren0 = dmi_reg_en & dmi_reg_wr_en & (dmi_reg_addr == 7'h39);
assign sbaddress0_reg_wren = sbaddress0_reg_wren0 | sbaddress0_reg_wren1;
assign sbaddress0_reg_din[31:0]= ({32{sbaddress0_reg_wren0}} & dmi_reg_wdata[31:0]) |
({32{sbaddress0_reg_wren1}} & (sbaddress0_reg[31:0] + {28'b0,sbaddress0_incr[3:0]}));
rvdffe #(32) dbg_sbaddress0_reg (.*, .din(sbaddress0_reg_din[31:0]), .dout(sbaddress0_reg[31:0]), .en(sbaddress0_reg_wren), .rst_l(dbg_dm_rst_l));
assign sbreadonaddr_access = dmi_reg_en & dmi_reg_wr_en & (dmi_reg_addr == 7'h39) & sbcs_reg[20]; // if readonaddr is set the next command will start upon writing of addr0
assign sbreadondata_access = dmi_reg_en & ~dmi_reg_wr_en & (dmi_reg_addr == 7'h3c) & sbcs_reg[15]; // if readondata is set the next command will start upon reading of data0
assign sbdata0wr_access = dmi_reg_en & dmi_reg_wr_en & (dmi_reg_addr == 7'h3c); // write to sbdata0 will start write command to system bus
// memory mapped registers
// dmcontrol register has only 6 bits implemented. 31: haltreq, 30: resumereq, 29: haltreset, 28: ackhavereset, 1: ndmreset, 0: dmactive.
// rest all the bits are zeroed out
// dmactive flop is reset based on core rst_l, all other flops use dm_rst_l
assign dmcontrol_wren = (dmi_reg_addr == 7'h10) & dmi_reg_en & dmi_reg_wr_en;
assign dmcontrol_reg[27:2] = '0;
rvdffs #(5) dmcontrolff (.din({dmi_reg_wdata[31:28],dmi_reg_wdata[1]}), .dout({dmcontrol_reg[31: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(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));
// 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 == 32'h11) & dmi_reg_en;
assign dmstatus_reg[31:20] = '0;
assign dmstatus_reg[19:18] = {2{dmstatus_havereset}};
assign dmstatus_reg[15:10] = '0;
assign dmstatus_reg[7] = '1;
assign dmstatus_reg[6:4] = '0;
assign dmstatus_reg[17:16] = {2{dmstatus_resumeack}};
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_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;
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));
// haltsum0 register
assign haltsum0_reg[31:1] = '0;
assign haltsum0_reg[0] = dmstatus_halted;
// abstractcs register
// bits implemted are [12] - busy and [10:8]= command error
assign abstractcs_reg[31:13] = '0;
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) & (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'b001) & data1_reg[0]) |
((dmi_reg_wdata[22:20] == 3'b010) & (|data1_reg[1:0])) |
dmi_reg_wdata[22] | (dmi_reg_wdata[22:20] == 3'b011)
);
assign abstractcs_error_sel5 = (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
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));
// command register - implemented all the bits in this register
// command[16] = 1: write, 0: read
assign command_wren = (dmi_reg_addr == 7'h17) & dmi_reg_en & dmi_reg_wr_en & (dbg_state == HALTED);
rvdffe #(32) dmcommand_reg (.*, .din(dmi_reg_wdata[31:0]), .dout(command_reg[31:0]), .en(command_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_din[31:0] = ({32{data0_reg_wren0}} & dmi_reg_wdata[31:0]) |
({32{data0_reg_wren1}} & core_dbg_rddata[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_wren1 = 1'b0; // core_dbg_cmd_done & (dbg_state == CMD_WAIT) & ~command_reg[16];
assign data1_reg_wren = data1_reg_wren0 | data1_reg_wren1;
assign data1_din[31:0] = ({32{data1_reg_wren0}} & dmi_reg_wdata[31:0]);
//({32{data0_reg_wren1}} & core_dbg_rddata[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));
// FSM to control the debug mode entry, command send/recieve, and Resume flow.
always_comb begin
dbg_nxtstate = IDLE;
dbg_state_en = 1'b0;
abstractcs_busy_wren = 1'b0;
abstractcs_busy_din = 1'b0;
dbg_halt_req = dmcontrol_wren_Q & dmcontrol_reg[31]; // single pulse output to the core
dbg_resume_req = 1'b0; // single pulse output to the core
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 Halted
dbg_halt_req = dmcontrol_reg[31]; // Removed debug mode qualification during MPC changes
//dbg_halt_req = dmcontrol_reg[31] & ~dec_tlu_debug_mode; // only when jtag has written the halt_req bit in the control
end
HALTING : begin
dbg_nxtstate = HALTED; // Goto HALTED once the core sends an ACK
dbg_state_en = dmstatus_reg[9]; // 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) :
(dmcontrol_reg[31] ? HALTING : IDLE); // This is MPC halted case
//dbg_nxtstate = dmcontrol_reg[1] ? IDLE : (dmcontrol_reg[30] & ~dmcontrol_reg[31]) ? RESUMING : CMD_START; // wait for halted to go away before send to resume. Else start of new command
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);
abstractcs_busy_wren = dbg_state_en & (dbg_nxtstate == 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 = (|abstractcs_reg[10:8]) ? CMD_DONE : CMD_WAIT; // new command sent to the core
dbg_state_en = dbg_cmd_valid | (|abstractcs_reg[10:8]);
end
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
CMD_DONE: begin
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;
end
RESUMING : begin
dbg_nxtstate = IDLE;
dbg_state_en = dmstatus_reg[17]; // resume ack has been updated in the dmstatus register
end
default : begin
dbg_nxtstate = IDLE;
dbg_state_en = 1'b0;
abstractcs_busy_wren = 1'b0;
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
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'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'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]) |
({32{dmi_reg_addr == 7'h3c}} & sbdata0_reg[31:0]) |
({32{dmi_reg_addr == 7'h3d}} & sbdata1_reg[31:0]);
rvdffs #($bits(state_t)) dbg_state_reg (.din(dbg_nxtstate), .dout({dbg_state}), .en(dbg_state_en), .rst_l(dbg_dm_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
// rvdff #(1) dmi_ack_reg (.din(dmi_reg_en), .dout(dmi_reg_ack), .rst_l(rst_l), .clk(free_clk));
rvdffs #(32) dmi_rddata_reg(.din(dmi_reg_rdata_din), .dout(dmi_reg_rdata), .en(dmi_reg_en), .rst_l(dbg_dm_rst_l), .clk(dbg_free_clk));
// 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_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_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];
// 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);
// system bus FSM
always_comb begin
sb_nxtstate = SBIDLE;
sb_state_en = 1'b0;
sbcs_sbbusy_wren = 1'b0;
sbcs_sbbusy_din = 1'b0;
sbcs_sberror_wren = 1'b0;
sbcs_sberror_din[2:0] = 3'b0;
sbaddress0_reg_wren1 = 1'b0;
case (sb_state)
SBIDLE: begin
sb_nxtstate = WAIT;
sb_state_en = sbdata0wr_access | sbreadondata_access | sbreadonaddr_access;
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
sbcs_sberror_din[2:0] = ~dmi_reg_wdata[14:12] & sbcs_reg[14:12];
end
WAIT: begin
sb_nxtstate = (sbcs_unaligned | sbcs_illegal_size) ? DONE : (sbcs_reg[15] | sbcs_reg[20]) ? CMD_RD : CMD_WR;
sb_state_en = dbg_bus_clk_en | 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
CMD_RD : begin
sb_nxtstate = RSP_RD;
sb_state_en = sb_axi_arvalid_q & sb_axi_arready_q & dbg_bus_clk_en;
end
CMD_WR : begin
sb_nxtstate = (sb_axi_awready_q & sb_axi_wready_q) ? RSP_WR : (sb_axi_awready_q ? CMD_WR_DATA : CMD_WR_ADDR);
sb_state_en = ((sb_axi_awvalid_q & sb_axi_awready_q) | (sb_axi_wvalid_q & sb_axi_wready_q)) & dbg_bus_clk_en;
end
CMD_WR_ADDR : begin
sb_nxtstate = RSP_WR;
sb_state_en = sb_axi_awvalid_q & sb_axi_awready_q & dbg_bus_clk_en;
end
CMD_WR_DATA : begin
sb_nxtstate = RSP_WR;
sb_state_en = sb_axi_wvalid_q & sb_axi_wready_q & dbg_bus_clk_en;
end
RSP_RD: begin
sb_nxtstate = DONE;
sb_state_en = sb_axi_rvalid_q & sb_axi_rready_q & dbg_bus_clk_en;
sbcs_sberror_wren = sb_state_en & sb_axi_rresp_q[1];
sbcs_sberror_din[2:0] = 3'b010;
end
RSP_WR: begin
sb_nxtstate = DONE;
sb_state_en = sb_axi_bvalid_q & sb_axi_bready_q & dbg_bus_clk_en;
sbcs_sberror_wren = sb_state_en & sb_axi_bresp_q[1];
sbcs_sberror_din[2:0] = 3'b010;
end
DONE: begin
sb_nxtstate = SBIDLE;
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
end
default : begin
sb_nxtstate = SBIDLE;
sb_state_en = 1'b0;
sbcs_sbbusy_wren = 1'b0;
sbcs_sbbusy_din = 1'b0;
sbcs_sberror_wren = 1'b0;
sbcs_sberror_din[2:0] = 3'b0;
sbaddress0_reg_wren1 = 1'b0;
end
endcase
end // always_comb begin
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));
//rvdff #(.WIDTH(1)) bus_clken_ff (.din(dbg_bus_clk_en), .dout(dbg_bus_clk_en_q), .rst_l(dbg_dm_rst_l), .clk(dbg_sb_c2_free_clk), .*);
rvdffs #(.WIDTH(1)) axi_awvalid_ff (.din(sb_axi_awvalid), .dout(sb_axi_awvalid_q), .en(dbg_bus_clk_en), .rst_l(dbg_dm_rst_l), .clk(sb_free_clk), .*);
rvdffs #(.WIDTH(1)) axi_awready_ff (.din(sb_axi_awready), .dout(sb_axi_awready_q), .en(dbg_bus_clk_en), .rst_l(dbg_dm_rst_l), .clk(sb_free_clk), .*);
rvdffs #(.WIDTH(1)) axi_wvalid_ff (.din(sb_axi_wvalid), .dout(sb_axi_wvalid_q), .en(dbg_bus_clk_en), .rst_l(dbg_dm_rst_l), .clk(sb_free_clk), .*);
rvdffs #(.WIDTH(1)) axi_wready_ff (.din(sb_axi_wready), .dout(sb_axi_wready_q), .en(dbg_bus_clk_en), .rst_l(dbg_dm_rst_l), .clk(sb_free_clk), .*);
rvdffs #(.WIDTH(1)) axi_arvalid_ff (.din(sb_axi_arvalid), .dout(sb_axi_arvalid_q), .en(dbg_bus_clk_en), .rst_l(dbg_dm_rst_l), .clk(sb_free_clk), .*);
rvdffs #(.WIDTH(1)) axi_arready_ff (.din(sb_axi_arready), .dout(sb_axi_arready_q), .en(dbg_bus_clk_en), .rst_l(dbg_dm_rst_l), .clk(sb_free_clk), .*);
rvdffs #(.WIDTH(1)) axi_bvalid_ff (.din(sb_axi_bvalid), .dout(sb_axi_bvalid_q), .en(dbg_bus_clk_en), .rst_l(dbg_dm_rst_l), .clk(sb_free_clk), .*);
rvdffs #(.WIDTH(1)) axi_bready_ff (.din(sb_axi_bready), .dout(sb_axi_bready_q), .en(dbg_bus_clk_en), .rst_l(dbg_dm_rst_l), .clk(sb_free_clk), .*);
rvdff #(.WIDTH(2)) axi_bresp_ff (.din(sb_axi_bresp[1:0]), .dout(sb_axi_bresp_q[1:0]), .rst_l(dbg_dm_rst_l), .clk(bus_clk), .*);
rvdffs #(.WIDTH(1)) axi_rvalid_ff (.din(sb_axi_rvalid), .dout(sb_axi_rvalid_q), .en(dbg_bus_clk_en), .rst_l(dbg_dm_rst_l), .clk(sb_free_clk), .*);
rvdffs #(.WIDTH(1)) axi_rready_ff (.din(sb_axi_rready), .dout(sb_axi_rready_q), .en(dbg_bus_clk_en), .rst_l(dbg_dm_rst_l), .clk(sb_free_clk), .*);
rvdff #(.WIDTH(2)) axi_rresp_ff (.din(sb_axi_rresp[1:0]), .dout(sb_axi_rresp_q[1:0]), .rst_l(dbg_dm_rst_l), .clk(bus_clk), .*);
rvdff #(.WIDTH(64)) axi_rdata_ff (.din(sb_axi_rdata[63:0]), .dout(sb_axi_rdata_q[63:0]), .rst_l(dbg_dm_rst_l), .clk(bus_clk), .*);
// AXI Request signals
assign sb_axi_awvalid = ((sb_state == CMD_WR) | (sb_state == CMD_WR_ADDR)) & ~(sb_axi_awvalid_q & sb_axi_awready_q);
assign sb_axi_awaddr[31:0] = sbaddress0_reg[31:0];
assign sb_axi_awid[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_awcache[3:0] = 4'b1111;
assign sb_axi_awregion[3:0] = sbaddress0_reg[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)) & ~(sb_axi_wvalid_q & sb_axi_wready_q);
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_wlast = '1;
assign sb_axi_arvalid = (sb_state == CMD_RD) & ~(sb_axi_arvalid_q & sb_axi_arready_q);
assign sb_axi_araddr[31:0] = {sbaddress0_reg[31:3],3'b0};
assign sb_axi_arid[SB_BUS_TAG-1:0] = '0;
assign sb_axi_arsize[2:0] = 3'b011;
assign sb_axi_arprot[2:0] = '0;
assign sb_axi_arcache[3:0] = 4'b0;
assign sb_axi_arregion[3:0] = sbaddress0_reg[31:28];
assign sb_axi_arlen[7:0] = '0;
assign sb_axi_arburst[1:0] = 2'b01;
assign sb_axi_arqos[3:0] = '0;
assign sb_axi_arlock = '0;
// AXI Response signals
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_q[63:0] >> 8*sbaddress0_reg[2:0]) & 64'hff)) |
({64{sbcs_reg[19:17] == 3'h1}} & ((sb_axi_rdata_q[63:0] >> 16*sbaddress0_reg[2:1]) & 64'hffff)) |
({64{sbcs_reg[19:17] == 3'h2}} & ((sb_axi_rdata_q[63:0] >> 32*sbaddress0_reg[2]) & 64'hffff_ffff)) |
({64{sbcs_reg[19:17] == 3'h3}} & sb_axi_rdata_q[63:0]);
`ifdef 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));
`endif
endmodule

254
design/dec/cdecode Normal file
View File

@ -0,0 +1,254 @@
.definition
# invalid rs2=0
c.add0 = [1001.....1....10]
c.add1 = [1001......1...10]
c.add2 = [1001.......1..10]
c.add3 = [1001........1.10]
c.add4 = [1001.........110]
# invalid rs2=0
c.mv0 = [1000.....1....10]
c.mv1 = [1000......1...10]
c.mv2 = [1000.......1..10]
c.mv3 = [1000........1.10]
c.mv4 = [1000.........110]
# invalid if rs1=0
c.jalr0 = [10011....0000010]
c.jalr1 = [1001.1...0000010]
c.jalr2 = [1001..1..0000010]
c.jalr3 = [1001...1.0000010]
c.jalr4 = [1001....10000010]
c.addi = [000...........01]
# invalid imm=0
c.addi16sp0 = [011100010.....01]
c.addi16sp1 = [011.000101....01]
c.addi16sp2 = [011.00010.1...01]
c.addi16sp3 = [011.00010..1..01]
c.addi16sp4 = [011.00010...1.01]
c.addi16sp5 = [011.00010....101]
# invalid uimm=0
c.addi4spn0 = [0001..........00]
c.addi4spn1 = [000.1.........00]
c.addi4spn2 = [000..1........00]
c.addi4spn3 = [000...1.......00]
c.addi4spn4 = [000....1......00]
c.addi4spn5 = [000.....1.....00]
c.addi4spn6 = [000......1....00]
c.addi4spn7 = [000.......1...00]
c.and = [100011...11...01]
c.andi = [100.10........01]
c.beqz = [110...........01]
c.bnez = [111...........01]
c.ebreak = [1001000000000010]
c.j = [101...........01]
c.jal = [001...........01]
c.jr0 = [10001....0000010]
c.jr1 = [1000.1...0000010]
c.jr2 = [1000..1..0000010]
c.jr3 = [1000...1.0000010]
c.jr4 = [1000....10000010]
c.li = [010...........01]
# invalid rd=x2 or imm=0
c.lui0 = [01111.........01]
c.lui1 = [0111.1........01]
c.lui2 = [0111..1.......01]
c.lui3 = [0111...0......01]
c.lui4 = [0111....1.....01]
c.lui5 = [011.1....1....01]
c.lui6 = [011..1...1....01]
c.lui7 = [011...1..1....01]
c.lui8 = [011....0.1....01]
c.lui9 = [011.....11....01]
c.lui10= [011.1.....1...01]
c.lui11= [011..1....1...01]
c.lui12 = [011...1...1...01]
c.lui13 = [011....0..1...01]
c.lui14 = [011.....1.1...01]
c.lui15 = [011.1......1..01]
c.lui16 = [011..1.....1..01]
c.lui17 = [011...1....1..01]
c.lui18 = [011....0...1..01]
c.lui19 = [011.....1..1..01]
c.lui20 = [011.1.......1.01]
c.lui21 = [011..1......1.01]
c.lui22 = [011...1.....1.01]
c.lui23 = [011....0....1.01]
c.lui24 = [011.....1...1.01]
c.lui25 = [011.1........101]
c.lui26 = [011..1.......101]
c.lui27 = [011...1......101]
c.lui28 = [011....0.....101]
c.lui29 = [011.....1....101]
c.lw = [010...........00]
c.lwsp = [010...........10]
c.or = [100011...10...01]
# bit 5 of the shift must be 0 to be legal
c.slli = [0000..........10]
c.srai = [100001........01]
c.srli = [100000........01]
c.sub = [100011...00...01]
c.sw = [110...........00]
c.swsp = [110...........10]
c.xor = [100011...01...01]
.input
rv32c = {
i[15]
i[14]
i[13]
i[12]
i[11]
i[10]
i[9]
i[8]
i[7]
i[6]
i[5]
i[4]
i[3]
i[2]
i[1]
i[0]
}
.output
rv32c = {
rdrd
rdrs1
rs2rs2
rdprd
rdprs1
rs2prs2
rs2prd
uimm9_2
ulwimm6_2
ulwspimm7_2
rdeq2
rdeq1
rs1eq2
sbroffset8_1
simm9_4
simm5_0
sjaloffset11_1
sluimm17_12
uimm5_0
uswimm6_2
uswspimm7_2
o[31]
o[30]
o[29]
o[28]
o[27]
o[26]
o[25]
o[24]
o[23]
o[22]
o[21]
o[20]
o[19]
o[18]
o[17]
o[16]
o[15]
o[14]
o[13]
o[12]
o[11]
o[10]
o[9]
o[8]
o[7]
o[6]
o[5]
o[4]
o[3]
o[2]
o[1]
o[0]
}
# assign rs2d[4:0] = i[6:2];
#
# assign rdd[4:0] = i[11:7];
#
# assign rdpd[4:0] = {2'b01, i[9:7]};
#
# assign rs2pd[4:0] = {2'b01, i[4:2]};
.decode
rv32c[c.add{0-4}] = { rdrd rdrs1 rs2rs2 o[5] o[4] o[1] o[0] }
rv32c[c.mv{0-4}] = { rdrd rs2rs2 o[5] o[4] o[1] o[0] }
rv32c[c.addi] = { rdrd rdrs1 simm5_0 o[4] o[1] o[0] }
rv32c[c.addi16sp{0-5}] = { rdeq2 rs1eq2 simm9_4 o[4] o[1] o[0] }
rv32c[c.addi4spn{0-7}] = { rs2prd rs1eq2 uimm9_2 o[4] o[1] o[0] }
rv32c[c.and] = { rdprd rdprs1 rs2prs2 o[14] o[13] o[12] o[5] o[4] o[1] o[0] }
rv32c[c.andi] = { rdprd rdprs1 simm5_0 o[14] o[13] o[12] o[4] o[1] o[0] }
rv32c[c.beqz] = { rdprs1 sbroffset8_1 o[6] o[5] o[1] o[0] }
rv32c[c.bnez] = { rdprs1 sbroffset8_1 o[12] o[6] o[5] o[1] o[0] }
rv32c[c.ebreak] = { o[20] o[6] o[5] o[4] o[1] o[0] }
rv32c[c.j] = { sjaloffset11_1 o[6] o[5] o[3] o[2] o[1] o[0] }
rv32c[c.jal] = { sjaloffset11_1 rdeq1 o[6] o[5] o[3] o[2] o[1] o[0] }
rv32c[c.jalr{0-4}] = { rdeq1 rdrs1 o[6] o[5] o[2] o[1] o[0] }
rv32c[c.jr{0-4}] = { rdrs1 o[6] o[5] o[2] o[1] o[0] }
rv32c[c.li] = { rdrd simm5_0 o[4] o[1] o[0] }
rv32c[c.lui{0-29}] = { rdrd sluimm17_12 o[5] o[4] o[2] o[1] o[0] }
rv32c[c.lw] = { rs2prd rdprs1 ulwimm6_2 o[13] o[1] o[0] }
rv32c[c.lwsp] = { rdrd rs1eq2 ulwspimm7_2 o[13] o[1] o[0] }
rv32c[c.or] = { rdprd rdprs1 rs2prs2 o[14] o[13] o[5] o[4] o[1] o[0] }
rv32c[c.slli] = { rdrd rdrs1 uimm5_0 o[12] o[4] o[1] o[0] }
rv32c[c.srai] = { rdprd rdprs1 uimm5_0 o[30] o[14] o[12] o[4] o[1] o[0] }
rv32c[c.srli] = { rdprd rdprs1 uimm5_0 o[14] o[12] o[4] o[1] o[0] }
rv32c[c.sub] = { rdprd rdprs1 rs2prs2 o[30] o[5] o[4] o[1] o[0] }
rv32c[c.sw] = { rdprs1 rs2prs2 uswimm6_2 o[13] o[5] o[1] o[0] }
rv32c[c.swsp] = { rs2rs2 rs1eq2 uswspimm7_2 o[13] o[5] o[1] o[0] }
rv32c[c.xor] = { rdprd rdprs1 rs2prs2 o[14] o[5] o[4] o[1] o[0] }
.end

229
design/dec/csrdecode Normal file
View File

@ -0,0 +1,229 @@
.definition
csr_misa = [001100000001]
csr_mvendorid = [111100010001]
csr_marchid = [111100010010]
csr_mimpid = [111100010011]
csr_mhartid = [111100010100]
csr_mstatus = [001100000000]
csr_mtvec = [001100000101]
csr_mip = [001101000100]
csr_mie = [001100000100]
csr_mcyclel = [101100000000]
csr_mcycleh = [101110000000]
csr_minstretl = [101100000010]
csr_minstreth = [101110000010]
csr_mscratch = [001101000000]
csr_mepc = [001101000001]
csr_mcause = [001101000010]
csr_mtval = [001101000011]
csr_mrac = [011111000000]
csr_dmst = [011111000100]
csr_mdeau = [101111000000]
csr_mdseac = [111111000000]
csr_meivt = [101111001000]
csr_meihap = [111111001000]
csr_meipt = [101111001001]
csr_meipt = [101111001001]
csr_meicpct = [101111001010]
csr_meicurpl = [101111001100]
csr_meicidpl = [101111001011]
csr_dcsr = [011110110000]
csr_dpc = [011110110001]
csr_dicawics = [011111001000]
csr_dicad0 = [011111001001]
csr_dicad1 = [011111001010]
csr_dicago = [011111001011]
csr_mtsel = [011110100000]
csr_mtdata1 = [011110100001]
csr_mtdata2 = [011110100010]
csr_mhpmc3 = [101100000011]
csr_mhpmc4 = [101100000100]
csr_mhpmc5 = [101100000101]
csr_mhpmc6 = [101100000110]
csr_mhpmc3h = [101110000011]
csr_mhpmc4h = [101110000100]
csr_mhpmc5h = [101110000101]
csr_mhpmc6h = [101110000110]
csr_mhpme3 = [001100100011]
csr_mhpme4 = [001100100100]
csr_mhpme5 = [001100100101]
csr_mhpme6 = [001100100110]
csr_micect = [011111110000]
csr_miccmect = [011111110001]
csr_mdccmect = [011111110010]
csr_mpmc = [011111000110]
csr_mcgc = [011111111000]
csr_mcpc = [011111000010]
csr_mfdc = [011111111001]
csr_mgpmc = [011111010000]
csr_perfva = [101100000111]
csr_perfvb = [101100001...]
csr_perfvc = [10110001....]
csr_perfvd = [101110000111]
csr_perfve = [101110001...]
csr_perfvf = [10111001....]
csr_perfvg = [001100100111]
csr_perfvh = [001100101...]
csr_perfvi = [00110011....]
.input
csr = {
dec_csr_rdaddr_d[11]
dec_csr_rdaddr_d[10]
dec_csr_rdaddr_d[9]
dec_csr_rdaddr_d[8]
dec_csr_rdaddr_d[7]
dec_csr_rdaddr_d[6]
dec_csr_rdaddr_d[5]
dec_csr_rdaddr_d[4]
dec_csr_rdaddr_d[3]
dec_csr_rdaddr_d[2]
dec_csr_rdaddr_d[1]
dec_csr_rdaddr_d[0]
}
.output
csr = {
csr_misa
csr_mvendorid
csr_marchid
csr_mimpid
csr_mhartid
csr_mstatus
csr_mtvec
csr_mip
csr_mie
csr_mcyclel
csr_mcycleh
csr_minstretl
csr_minstreth
csr_mscratch
csr_mepc
csr_mcause
csr_mtval
csr_mrac
csr_dmst
csr_mdeau
csr_mdseac
csr_meihap
csr_meivt
csr_meipt
csr_meicpct
csr_meicurpl
csr_meicidpl
csr_dcsr
csr_mpmc
csr_mcgc
csr_mcpc
csr_mfdc
csr_dpc
csr_mtsel
csr_mtdata1
csr_mtdata2
csr_mhpmc3
csr_mhpmc4
csr_mhpmc5
csr_mhpmc6
csr_mhpmc3h
csr_mhpmc4h
csr_mhpmc5h
csr_mhpmc6h
csr_mhpme3
csr_mhpme4
csr_mhpme5
csr_mhpme6
csr_mgpmc
csr_perfva
csr_perfvb
csr_perfvc
csr_perfvd
csr_perfve
csr_perfvf
csr_perfvg
csr_perfvh
csr_perfvi
csr_micect
csr_miccmect
csr_mdccmect
csr_dicawics
csr_dicad0
csr_dicad1
csr_dicago
valid_only
presync
postsync
}
.decode
csr[ csr_misa ] = { csr_misa }
csr[ csr_mvendorid ] = { csr_mvendorid }
csr[ csr_marchid ] = { csr_marchid }
csr[ csr_mimpid ] = { csr_mimpid }
csr[ csr_mhartid ] = { csr_mhartid }
csr[ csr_mstatus ] = { csr_mstatus postsync }
csr[ csr_mtvec ] = { csr_mtvec postsync}
csr[ csr_mip ] = { csr_mip }
csr[ csr_mie ] = { csr_mie }
csr[ csr_mcyclel ] = { csr_mcyclel }
csr[ csr_mcycleh ] = { csr_mcycleh }
csr[ csr_minstretl ] = { csr_minstretl presync }
csr[ csr_minstreth ] = { csr_minstreth presync }
csr[ csr_mscratch ] = { csr_mscratch }
csr[ csr_mepc ] = { csr_mepc postsync}
csr[ csr_mcause ] = { csr_mcause }
csr[ csr_mtval ] = { csr_mtval }
csr[ csr_mrac ] = { csr_mrac postsync }
csr[ csr_dmst ] = { csr_dmst postsync}
csr[ csr_mdeau ] = { csr_mdeau }
csr[ csr_mdseac ] = { csr_mdseac }
csr[ csr_meipt ] = { csr_meipt }
csr[ csr_meihap ] = { csr_meihap }
csr[ csr_meivt ] = { csr_meivt }
csr[ csr_meicurpl ] = { csr_meicurpl }
csr[ csr_meicpct ] = { csr_meicpct }
csr[ csr_meicidpl ] = { csr_meicidpl }
csr[ csr_mpmc ] = { csr_mpmc }
csr[ csr_mcgc ] = { csr_mcgc }
csr[ csr_mgpmc ] = { csr_mgpmc presync postsync }
csr[ csr_mcpc ] = { csr_mcpc presync postsync }
csr[ csr_mfdc ] = { csr_mfdc presync postsync }
csr[ csr_dcsr ] = { csr_dcsr }
csr[ csr_dpc ] = { csr_dpc }
csr[ csr_mtsel ] = { csr_mtsel }
csr[ csr_mtdata1 ] = { csr_mtdata1 postsync }
csr[ csr_mtdata2 ] = { csr_mtdata2 postsync }
csr[ csr_mhpmc3 ] = { csr_mhpmc3 presync }
csr[ csr_mhpmc4 ] = { csr_mhpmc4 presync }
csr[ csr_mhpmc5 ] = { csr_mhpmc5 presync }
csr[ csr_mhpmc6 ] = { csr_mhpmc6 presync }
csr[ csr_mhpmc3h ] = { csr_mhpmc3h presync }
csr[ csr_mhpmc4h ] = { csr_mhpmc4h presync }
csr[ csr_mhpmc5h ] = { csr_mhpmc5h presync }
csr[ csr_mhpmc6h ] = { csr_mhpmc6h presync }
csr[ csr_mhpme3 ] = { csr_mhpme3 }
csr[ csr_mhpme4 ] = { csr_mhpme4 }
csr[ csr_mhpme5 ] = { csr_mhpme5 }
csr[ csr_mhpme6 ] = { csr_mhpme6 }
csr[ csr_micect ] = { csr_micect }
csr[ csr_miccmect ] = { csr_miccmect }
csr[ csr_mdccmect ] = { csr_mdccmect }
csr[ csr_dicawics ] = { csr_dicawics }
csr[ csr_dicad0 ] = { csr_dicad0 }
csr[ csr_dicad1 ] = { csr_dicad1 }
csr[ csr_dicago ] = { csr_dicago }
csr[ csr_perfva ] = { valid_only }
csr[ csr_perfvb ] = { valid_only }
csr[ csr_perfvc ] = { valid_only }
csr[ csr_perfvd ] = { valid_only }
csr[ csr_perfve ] = { valid_only }
csr[ csr_perfvf ] = { valid_only }
csr[ csr_perfvg ] = { valid_only }
csr[ csr_perfvh ] = { valid_only }
csr[ csr_perfvi ] = { valid_only }
.end

579
design/dec/dec.sv Normal file
View File

@ -0,0 +1,579 @@
// 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.
// dec: decode unit - decode, bypassing, ARF, interrupts
//
//********************************************************************************
// $Id$
//
//
// Function: Decode
// Comments: Decode, dependency scoreboard, ARF
//
//
// A -> D -> EX1 ... WB
//
//********************************************************************************
module dec
import swerv_types::*;
(
input logic clk,
input logic free_clk,
input logic active_clk,
output logic dec_pause_state_cg, // pause state for clock-gating
input logic rst_l, // reset, active low
input logic [31:1] rst_vec, // reset vector, from core pins
input logic nmi_int, // NMI pin
input logic [31:1] nmi_vec, // NMI vector, from pins
input logic i_cpu_halt_req, // Asynchronous Halt request to CPU
input logic i_cpu_run_req, // Asynchronous Restart request to CPU
output logic o_cpu_halt_status, // Halt status of core (pmu/fw)
output logic o_cpu_halt_ack, // Halt request ack
output logic o_cpu_run_ack, // Run request ack
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
// external MPC halt/run interface
input logic mpc_debug_halt_req, // Async halt request
input logic mpc_debug_run_req, // Async run request
input logic mpc_reset_run_req, // Run/halt after reset
output logic mpc_debug_halt_ack, // Halt ack
output logic mpc_debug_run_ack, // Run ack
output logic debug_brkpt_status, // debug breakpoint
output logic dec_ib0_valid_eff_d, // effective valid taking decode into account
output logic dec_ib1_valid_eff_d,
input logic exu_pmu_i0_br_misp, // slot 0 branch misp
input logic exu_pmu_i0_br_ataken, // slot 0 branch actual taken
input logic exu_pmu_i0_pc4, // slot 0 4 byte branch
input logic exu_pmu_i1_br_misp, // slot 1 branch misp
input logic exu_pmu_i1_br_ataken, // slot 1 branch actual taken
input logic exu_pmu_i1_pc4, // slot 1 4 byte branch
input logic lsu_nonblock_load_valid_dc3, // valid nonblock load at dc3
input logic [`RV_LSU_NUM_NBLOAD_WIDTH-1:0] lsu_nonblock_load_tag_dc3, // -> corresponding tag
input logic lsu_nonblock_load_inv_dc5, // invalidate request for nonblock load dc5
input logic [`RV_LSU_NUM_NBLOAD_WIDTH-1:0] lsu_nonblock_load_inv_tag_dc5, // -> corresponding tag
input logic lsu_nonblock_load_data_valid, // valid nonblock load data back
input logic lsu_nonblock_load_data_error, // nonblock load bus error
input logic [`RV_LSU_NUM_NBLOAD_WIDTH-1:0] lsu_nonblock_load_data_tag, // -> corresponding tag
input logic [31:0] lsu_nonblock_load_data, // nonblock load data
input logic lsu_pmu_bus_trxn, // D side bus transaction
input logic lsu_pmu_bus_misaligned, // D side bus misaligned
input logic lsu_pmu_bus_error, // D side bus error
input logic lsu_pmu_bus_busy, // D side bus busy
input logic lsu_pmu_misaligned_dc3, // D side load or store misaligned
input logic [1:0] ifu_pmu_instr_aligned, // aligned instructions
input logic ifu_pmu_align_stall, // aligner stalled
input logic ifu_pmu_fetch_stall, // fetch unit stalled
input logic ifu_pmu_ic_miss, // icache miss
input logic ifu_pmu_ic_hit, // icache hit
input logic ifu_pmu_bus_error, // Instruction side bus error
input logic ifu_pmu_bus_busy, // Instruction side bus busy
input logic ifu_pmu_bus_trxn, // Instruction side bus transaction
input logic [3:0] lsu_trigger_match_dc3,
input logic dbg_cmd_valid, // debugger abstract command valid
input logic [1:0] dbg_cmd_size, // size of the abstract mem access debug command
input logic dbg_cmd_write, // command is a write
input logic [1:0] dbg_cmd_type, // command type
input logic [31:0] dbg_cmd_addr, // command address
input logic [1:0] dbg_cmd_wrdata, // command write data, for fence/fence_i
input logic ifu_i0_icaf, // icache access fault
input logic ifu_i1_icaf,
input logic ifu_i0_icaf_f1, // i0 has access fault on second fetch group
input logic ifu_i1_icaf_f1,
input logic ifu_i0_perr, // icache parity error
input logic ifu_i1_perr,
input logic ifu_i0_sbecc, // icache/iccm single-bit error
input logic ifu_i1_sbecc,
input logic ifu_i0_dbecc, // icache/iccm double-bit error
input logic ifu_i1_dbecc,
input logic lsu_freeze_dc3, // freeze pipe: decode -> dc3
input logic lsu_idle_any, // lsu idle for fence instructions
input logic lsu_halt_idle_any, // lsu idle for halting
input br_pkt_t i0_brp, // branch packet
input br_pkt_t i1_brp,
input lsu_error_pkt_t lsu_error_pkt_dc3, // LSU exception/error packet
input logic lsu_imprecise_error_load_any, // LSU imprecise load bus error
input logic lsu_imprecise_error_store_any, // LSU imprecise store bus error
input logic [31:0] lsu_imprecise_error_addr_any, // LSU imprecise bus error address
input logic lsu_freeze_external_ints_dc3, // load to side effect region
input logic exu_i0_flush_lower_e4, // slot 0 flush for mp
input logic exu_i1_flush_lower_e4, // slot 1 flush for mp
input logic [31:1] exu_i0_flush_path_e4, // slot 0 flush target for mp
input logic [31:1] exu_i1_flush_path_e4, // slot 1 flush target for mp
input logic [15:0] ifu_illegal_inst, // 16b opcode for illegal inst
input logic exu_div_stall, // stall decode for div executing
input logic [31:0] exu_div_result, // final div result
input logic exu_div_finish, // cycle div finishes
input logic [31:0] exu_mul_result_e3, // 32b mul result
input logic [31:0] exu_csr_rs1_e1, // rs1 for csr instruction
input logic [31:0] lsu_result_dc3, // load result
input logic [31:0] lsu_result_corr_dc4, // corrected load result
input logic lsu_load_stall_any, // This is for blocking loads
input logic lsu_store_stall_any, // This is for blocking stores
input logic dma_dccm_stall_any, // stall any load/store at decode, pmu event
input logic dma_iccm_stall_any, // iccm stalled, pmu event
input logic iccm_dma_sb_error, // ICCM DMA single bit error
input logic exu_i0_flush_final, // slot0 flush
input logic exu_i1_flush_final, // slot1 flush
input logic [31:1] exu_npc_e4, // next PC
input logic exu_flush_final, // final flush
input logic [31:0] exu_i0_result_e1, // alu result e1
input logic [31:0] exu_i1_result_e1,
input logic [31:0] exu_i0_result_e4, // alu result e4
input logic [31:0] exu_i1_result_e4,
input logic ifu_i0_valid, ifu_i1_valid, // fetch valids to instruction buffer
input logic [31:0] ifu_i0_instr, ifu_i1_instr, // fetch inst's to instruction buffer
input logic [31:1] ifu_i0_pc, ifu_i1_pc, // pc's for instruction buffer
input logic ifu_i0_pc4, ifu_i1_pc4, // indication of 4B or 2B for corresponding inst
input logic [31:1] exu_i0_pc_e1, // pc's for e1 from the alu's
input logic [31:1] exu_i1_pc_e1,
input logic mexintpend, // External interrupt pending
input logic timer_int, // Timer interrupt pending (from pin)
input logic [7:0] pic_claimid, // PIC claimid
input logic [3:0] pic_pl, // PIC priv level
input logic mhwakeup, // High priority wakeup
output logic [3:0] dec_tlu_meicurpl, // to PIC, Current priv level
output logic [3:0] dec_tlu_meipt, // to PIC
`ifdef RV_ICACHE_ECC
input logic [41:0] ifu_ic_debug_rd_data, // diagnostic icache read data
`else
input logic [33:0] ifu_ic_debug_rd_data, // diagnostic icache read data
`endif
input logic ifu_ic_debug_rd_data_valid, // diagnostic icache read data valid
output cache_debug_pkt_t dec_tlu_ic_diag_pkt, // packet of DICAWICS, DICAD0/1, DICAGO info for icache diagnostics
// Debug start
input logic dbg_halt_req, // DM requests a halt
input logic dbg_resume_req, // DM requests a resume
input logic ifu_miss_state_idle, // I-side miss buffer empty
output logic dec_tlu_flush_noredir_wb , // Tell fetch to idle on this flush
output logic dec_tlu_mpc_halted_only, // Core is halted only due to MPC
output logic dec_tlu_dbg_halted, // Core is halted and ready for debug command
output logic dec_tlu_pmu_fw_halted, // Core is halted due to Power management unit or firmware halt
output logic dec_tlu_debug_mode, // Core is in debug mode
output logic dec_tlu_resume_ack, // Resume acknowledge
output logic dec_tlu_flush_leak_one_wb, // single step
output logic dec_tlu_flush_err_wb, // iside perr/ecc rfpc
output logic dec_tlu_stall_dma, // stall dma access when there's a halt request
output logic dec_debug_wdata_rs1_d, // insert debug write data into rs1 at decode
output logic [31:0] dec_dbg_rddata, // debug command read data
output logic dec_dbg_cmd_done, // abstract command is done
output logic dec_dbg_cmd_fail, // abstract command failed (illegal reg address)
output trigger_pkt_t [3:0] trigger_pkt_any, // info needed by debug trigger blocks
// Debug end
// branch info from pipe0 for errors or counter updates
input logic [`RV_BTB_ADDR_HI:`RV_BTB_ADDR_LO] exu_i0_br_index_e4, // index
input logic [1:0] exu_i0_br_hist_e4, // history
input logic [1:0] exu_i0_br_bank_e4, // bank
input logic exu_i0_br_error_e4, // error
input logic exu_i0_br_start_error_e4, // start error
input logic exu_i0_br_valid_e4, // valid
input logic exu_i0_br_mp_e4, // mispredict
input logic exu_i0_br_middle_e4, // middle of bank
input logic [`RV_BHT_GHR_RANGE] exu_i0_br_fghr_e4, // FGHR when predicted
// branch info from pipe1 for errors or counter updates
input logic [`RV_BTB_ADDR_HI:`RV_BTB_ADDR_LO] exu_i1_br_index_e4, // index
input logic [1:0] exu_i1_br_hist_e4, // history
input logic [1:0] exu_i1_br_bank_e4, // bank
input logic exu_i1_br_error_e4, // error
input logic exu_i1_br_start_error_e4, // start error
input logic exu_i1_br_valid_e4, // valid
input logic exu_i1_br_mp_e4, // mispredict
input logic exu_i1_br_middle_e4, // middle of bank
input logic [`RV_BHT_GHR_RANGE] exu_i1_br_fghr_e4, // FGHR when predicted
`ifdef RV_BTB_48
input logic [1:0] exu_i1_br_way_e4, // way hit or repl
input logic [1:0] exu_i0_br_way_e4, // way hit or repl
`else
input logic exu_i1_br_way_e4, // way hit or repl
input logic exu_i0_br_way_e4, // way hit or repl
`endif
output logic [31:0] gpr_i0_rs1_d, // gpr rs1 data
output logic [31:0] gpr_i0_rs2_d, // gpr rs2 data
output logic [31:0] gpr_i1_rs1_d,
output logic [31:0] gpr_i1_rs2_d,
output logic [31:0] dec_i0_immed_d, // immediate data
output logic [31:0] dec_i1_immed_d,
output logic [12:1] dec_i0_br_immed_d, // br immediate data
output logic [12:1] dec_i1_br_immed_d,
output alu_pkt_t i0_ap, // alu packet
output alu_pkt_t i1_ap,
output logic dec_i0_alu_decode_d, // alu schedule on primary alu
output logic dec_i1_alu_decode_d,
output logic dec_i0_select_pc_d, // select pc onto rs1 for jal's
output logic dec_i1_select_pc_d,
output logic [31:1] dec_i0_pc_d, dec_i1_pc_d, // pc's at decode
output logic dec_i0_rs1_bypass_en_d, // rs1 bypass enable
output logic dec_i0_rs2_bypass_en_d, // rs2 bypass enable
output logic dec_i1_rs1_bypass_en_d,
output logic dec_i1_rs2_bypass_en_d,
output logic [31:0] i0_rs1_bypass_data_d, // rs1 bypass data
output logic [31:0] i0_rs2_bypass_data_d, // rs2 bypass data
output logic [31:0] i1_rs1_bypass_data_d,
output logic [31:0] i1_rs2_bypass_data_d,
output logic dec_ib3_valid_d, // ib3 buffer valid
output logic dec_ib2_valid_d, // ib2 buffer valid
output lsu_pkt_t lsu_p, // lsu packet
output mul_pkt_t mul_p, // mul packet
output div_pkt_t div_p, // div packet
output logic [11:0] dec_lsu_offset_d, // 12b offset for load/store addresses
output logic dec_i0_lsu_d, // is load/store
output logic dec_i1_lsu_d,
output logic flush_final_e3, // final flush
output logic i0_flush_final_e3, // final flush from i0
output logic dec_csr_ren_d, // csr read enable
output logic dec_tlu_cancel_e4, // Cancel lsu op at DC4 due to future trigger hit
output logic dec_tlu_flush_lower_wb, // tlu flush due to late mp, exception, rfpc, or int
output logic [31:1] dec_tlu_flush_path_wb, // tlu flush target
output logic dec_tlu_i0_kill_writeb_wb, // I0 is flushed, don't writeback any results to arch state
output logic dec_tlu_i1_kill_writeb_wb, // I1 is flushed, don't writeback any results to arch state
output logic dec_tlu_fence_i_wb, // flush is a fence_i rfnpc, flush icache
output logic dec_i0_mul_d, // chose which gpr value to use
output logic dec_i1_mul_d,
output logic dec_i0_div_d, // chose which gpr value to use
output logic dec_i1_div_d,
output logic dec_i1_valid_e1, // i1 valid at e1 stage
output logic dec_div_decode_e4, // div at e4 stage
output logic [31:1] pred_correct_npc_e2, // npc if prediction is correct at e2 stage
output logic dec_i0_rs1_bypass_en_e3, // rs1 bypass enable e3
output logic dec_i0_rs2_bypass_en_e3, // rs2 bypass enable e3
output logic dec_i1_rs1_bypass_en_e3,
output logic dec_i1_rs2_bypass_en_e3,
output logic [31:0] i0_rs1_bypass_data_e3, // rs1 bypass data e3
output logic [31:0] i0_rs2_bypass_data_e3, // rs2 bypass data e3
output logic [31:0] i1_rs1_bypass_data_e3,
output logic [31:0] i1_rs2_bypass_data_e3,
output logic dec_i0_sec_decode_e3, // secondary decode e3
output logic dec_i1_sec_decode_e3,
output logic [31:1] dec_i0_pc_e3, // pc at e3
output logic [31:1] dec_i1_pc_e3,
output logic dec_i0_rs1_bypass_en_e2, // rs1 bypass enable e2
output logic dec_i0_rs2_bypass_en_e2, // rs2 bypass enable e2
output logic dec_i1_rs1_bypass_en_e2,
output logic dec_i1_rs2_bypass_en_e2,
output logic [31:0] i0_rs1_bypass_data_e2, // rs1 bypass data e2
output logic [31:0] i0_rs2_bypass_data_e2, // rs2 bypass data e2
output logic [31:0] i1_rs1_bypass_data_e2,
output logic [31:0] i1_rs2_bypass_data_e2,
output br_tlu_pkt_t dec_tlu_br0_wb_pkt, // slot 0 branch predictor update packet
output br_tlu_pkt_t dec_tlu_br1_wb_pkt, // slot 1 branch predictor update packet
output logic [1:0] dec_tlu_perfcnt0, // toggles when perf counter 0 has an event inc
output logic [1:0] dec_tlu_perfcnt1, // toggles when perf counter 1 has an event inc
output logic [1:0] dec_tlu_perfcnt2, // toggles when perf counter 2 has an event inc
output logic [1:0] dec_tlu_perfcnt3, // toggles when perf counter 3 has an event inc
output predict_pkt_t i0_predict_p_d, // prediction packet to alus
output predict_pkt_t i1_predict_p_d,
output logic dec_i0_lsu_decode_d, // load/store decode
output logic [31:0] i0_result_e4_eff, // alu result e4
output logic [31:0] i1_result_e4_eff,
output logic dec_tlu_i0_valid_e4, // slot 0 instruction is valid at e4
output logic dec_tlu_i1_valid_e4, // slot 1 instruction is valid at e4, implies i0_valid_e4
output logic [31:0] i0_result_e2, // i0 result data e2
output logic [31:0] dec_tlu_mrac_ff, // CSR for memory region control
output logic [31:1] dec_tlu_i0_pc_e4, // pc e4
output logic [31:1] dec_tlu_i1_pc_e4,
output logic [4:2] dec_i0_data_en, // clock-gate control logic
output logic [4:1] dec_i0_ctl_en,
output logic [4:2] dec_i1_data_en,
output logic [4:1] dec_i1_ctl_en,
output logic dec_nonblock_load_freeze_dc2, // lsu must freeze nonblock load due to younger dependency in pipe
input logic [15:0] ifu_i0_cinst, // 16b compressed instruction
input logic [15:0] ifu_i1_cinst,
output trace_pkt_t trace_rv_trace_pkt, // trace packet
// feature disable from mfdc
output logic dec_tlu_sideeffect_posted_disable, // disable posted writes to side-effect address
output logic dec_tlu_core_ecc_disable, // disable core ECC
output logic dec_tlu_sec_alu_disable, // disable secondary ALU
output logic dec_tlu_non_blocking_disable, // disable non blocking loads
output logic dec_tlu_fast_div_disable, // disable fast divider
output logic dec_tlu_bpred_disable, // disable branch prediction
output logic dec_tlu_wb_coalescing_disable, // disable writebuffer coalescing
output logic dec_tlu_ld_miss_byp_wb_disable, // disable loads miss bypass write buffer
output logic [2:0] dec_tlu_dma_qos_prty, // DMA QoS priority coming from MFDC [18:16]
// clock gating overrides from mcgc
output logic dec_tlu_misc_clk_override, // override misc clock domain gating
output logic dec_tlu_exu_clk_override, // override exu clock domain gating
output logic dec_tlu_ifu_clk_override, // override fetch clock domain gating
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_dccm_clk_override, // override DCCM clock domain gating
output logic dec_tlu_icm_clk_override, // override ICCM clock domain gating
input logic scan_mode
);
localparam GPR_BANKS = 1;
localparam GPR_BANKS_LOG2 = (GPR_BANKS == 1) ? 1 : $clog2(GPR_BANKS);
logic dec_tlu_dec_clk_override; // to and from dec blocks
logic clk_override;
logic dec_ib1_valid_d;
logic dec_ib0_valid_d;
logic [1:0] dec_pmu_instr_decoded;
logic dec_pmu_decode_stall;
logic dec_pmu_presync_stall;
logic dec_pmu_postsync_stall;
logic dec_tlu_wr_pause_wb; // CSR write to pause reg is at WB.
logic dec_i0_rs1_en_d;
logic dec_i0_rs2_en_d;
logic dec_fence_pending; // tell TLU to stall DMA
logic [4:0] dec_i0_rs1_d;
logic [4:0] dec_i0_rs2_d;
logic dec_i1_rs1_en_d;
logic dec_i1_rs2_en_d;
logic [4:0] dec_i1_rs1_d;
logic [4:0] dec_i1_rs2_d;
logic [31:0] dec_i0_instr_d, dec_i1_instr_d;
logic dec_tlu_pipelining_disable;
logic dec_tlu_dual_issue_disable;
logic [4:0] dec_i0_waddr_wb;
logic dec_i0_wen_wb;
logic [31:0] dec_i0_wdata_wb;
logic [4:0] dec_i1_waddr_wb;
logic dec_i1_wen_wb;
logic [31:0] dec_i1_wdata_wb;
logic dec_csr_wen_wb; // csr write enable at wb
logic [11:0] dec_csr_rdaddr_d; // read address for csr
logic [11:0] dec_csr_wraddr_wb; // write address for csryes
logic [31:0] dec_csr_wrdata_wb; // csr write data at wb
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
logic dec_csr_any_unq_d; // valid csr - for csr legal
logic dec_csr_stall_int_ff; // csr is mie/mstatus
trap_pkt_t dec_tlu_packet_e4;
logic dec_i0_pc4_d, dec_i1_pc4_d;
logic dec_tlu_presync_d;
logic dec_tlu_postsync_d;
logic dec_tlu_debug_stall;
logic [31:0] dec_illegal_inst;
// GPR Bank ID write signals
logic wen_bank_id;
logic [GPR_BANKS_LOG2-1:0] wr_bank_id;
logic dec_i0_icaf_d;
logic dec_i1_icaf_d;
logic dec_i0_perr_d;
logic dec_i1_perr_d;
logic dec_i0_sbecc_d;
logic dec_i1_sbecc_d;
logic dec_i0_dbecc_d;
logic dec_i1_dbecc_d;
logic dec_i0_icaf_f1_d;
logic dec_i0_decode_d;
logic dec_i1_decode_d;
logic [3:0] dec_i0_trigger_match_d;
logic [3:0] dec_i1_trigger_match_d;
logic dec_debug_fence_d;
logic dec_nonblock_load_wen;
logic [4:0] dec_nonblock_load_waddr;
logic dec_tlu_flush_pause_wb;
logic dec_i0_load_e4;
logic dec_pause_state;
br_pkt_t dec_i0_brp;
br_pkt_t dec_i1_brp;
assign clk_override = dec_tlu_dec_clk_override;
assign dec_dbg_rddata[31:0] = dec_i0_wdata_wb[31:0];
dec_ib_ctl instbuff (.*
);
dec_decode_ctl decode (.*);
dec_tlu_ctl tlu (.*);
// Temp hookups
assign wen_bank_id = '0;
assign wr_bank_id = '0;
dec_gpr_ctl #(.GPR_BANKS(GPR_BANKS),
.GPR_BANKS_LOG2(GPR_BANKS_LOG2)) arf (.*,
// inputs
.raddr0(dec_i0_rs1_d[4:0]), .rden0(dec_i0_rs1_en_d),
.raddr1(dec_i0_rs2_d[4:0]), .rden1(dec_i0_rs2_en_d),
.raddr2(dec_i1_rs1_d[4:0]), .rden2(dec_i1_rs1_en_d),
.raddr3(dec_i1_rs2_d[4:0]), .rden3(dec_i1_rs2_en_d),
.waddr0(dec_i0_waddr_wb[4:0]), .wen0(dec_i0_wen_wb), .wd0(dec_i0_wdata_wb[31:0]),
.waddr1(dec_i1_waddr_wb[4:0]), .wen1(dec_i1_wen_wb), .wd1(dec_i1_wdata_wb[31:0]),
.waddr2(dec_nonblock_load_waddr[4:0]), .wen2(dec_nonblock_load_wen), .wd2(lsu_nonblock_load_data[31:0]),
// outputs
.rd0(gpr_i0_rs1_d[31:0]), .rd1(gpr_i0_rs2_d[31:0]),
.rd2(gpr_i1_rs1_d[31:0]), .rd3(gpr_i1_rs2_d[31:0])
);
// Trigger
dec_trigger dec_trigger (.*);
// trace
logic [15:0] dec_i0_cinst_d;
logic [15:0] dec_i1_cinst_d;
logic [31:0] dec_i0_inst_wb1;
logic [31:0] dec_i1_inst_wb1;
logic [31:1] dec_i0_pc_wb1;
logic [31:1] dec_i1_pc_wb1;
logic dec_tlu_i1_valid_wb1, 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, dec_tlu_i1_exc_valid_wb1;
// also need retires_p==3
assign trace_rv_trace_pkt.trace_rv_i_insn_ip = { 32'b0, dec_i1_inst_wb1[31:0], dec_i0_inst_wb1[31:0] };
assign trace_rv_trace_pkt.trace_rv_i_address_ip = { 32'b0, dec_i1_pc_wb1[31:1], 1'b0, dec_i0_pc_wb1[31:1], 1'b0 };
assign trace_rv_trace_pkt.trace_rv_i_valid_ip = {dec_tlu_int_valid_wb1, // always int
dec_tlu_i1_valid_wb1 | dec_tlu_i1_exc_valid_wb1, // not interrupts
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_i1_exc_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,2'b0};
assign trace_rv_trace_pkt.trace_rv_i_tval_ip = dec_tlu_mtval_wb1[31:0]; // replicate across ports
// end trace
endmodule // dec

2660
design/dec/dec_decode_ctl.sv Normal file

File diff suppressed because it is too large Load Diff

113
design/dec/dec_gpr_ctl.sv Normal file
View File

@ -0,0 +1,113 @@
// 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.
module dec_gpr_ctl #(parameter GPR_BANKS = 1,
GPR_BANKS_LOG2 = 1) (
input logic active_clk,
input logic [4:0] raddr0, // logical read addresses
input logic [4:0] raddr1,
input logic [4:0] raddr2,
input logic [4:0] raddr3,
input logic rden0, // read enables
input logic rden1,
input logic rden2,
input logic rden3,
input logic [4:0] waddr0, // logical write addresses
input logic [4:0] waddr1,
input logic [4:0] waddr2,
input logic wen0, // write enables
input logic wen1,
input logic wen2,
input logic [31:0] wd0, // write data
input logic [31:0] wd1,
input logic [31:0] wd2,
input logic wen_bank_id, // write enable for banks
input logic [GPR_BANKS_LOG2-1:0] wr_bank_id, // read enable for banks
input logic clk,
input logic rst_l,
output logic [31:0] rd0, // read data
output logic [31:0] rd1,
output logic [31:0] rd2,
output logic [31:0] rd3,
input logic scan_mode
);
logic [GPR_BANKS-1:0][31:1] [31:0] gpr_out; // 31 x 32 bit GPRs
logic [31:1] [31:0] gpr_in;
logic [31:1] w0v,w1v,w2v;
logic [31:1] gpr_wr_en;
logic [GPR_BANKS-1:0][31:1] gpr_bank_wr_en;
logic [GPR_BANKS_LOG2-1:0] gpr_bank_id;
//assign gpr_bank_id[GPR_BANKS_LOG2-1:0] = '0;
rvdffs #(GPR_BANKS_LOG2) bankid_ff (.*, .clk(active_clk), .en(wen_bank_id), .din(wr_bank_id[GPR_BANKS_LOG2-1:0]), .dout(gpr_bank_id[GPR_BANKS_LOG2-1:0]));
// GPR Write Enables for power savings
assign gpr_wr_en[31:1] = (w0v[31:1] | w1v[31:1] | w2v[31:1]);
for (genvar i=0; i<GPR_BANKS; i++) begin: gpr_banks
assign gpr_bank_wr_en[i][31:1] = gpr_wr_en[31:1] & {31{gpr_bank_id[GPR_BANKS_LOG2-1:0] == i}};
for ( genvar j=1; j<32; j++ ) begin : gpr
rvdffe #(32) gprff (.*, .en(gpr_bank_wr_en[i][j]), .din(gpr_in[j][31:0]), .dout(gpr_out[i][j][31:0]));
end : gpr
end: gpr_banks
// the read out
always_comb begin
rd0[31:0] = 32'b0;
rd1[31:0] = 32'b0;
rd2[31:0] = 32'b0;
rd3[31:0] = 32'b0;
w0v[31:1] = 31'b0;
w1v[31:1] = 31'b0;
w2v[31:1] = 31'b0;
gpr_in[31:1] = '0;
// GPR Read logic
for (int i=0; i<GPR_BANKS; i++) begin
for (int j=1; j<32; j++ ) begin
rd0[31:0] |= ({32{rden0 & (raddr0[4:0]== 5'(j)) & (gpr_bank_id[GPR_BANKS_LOG2-1:0] == 1'(i))}} & gpr_out[i][j][31:0]);
rd1[31:0] |= ({32{rden1 & (raddr1[4:0]== 5'(j)) & (gpr_bank_id[GPR_BANKS_LOG2-1:0] == 1'(i))}} & gpr_out[i][j][31:0]);
rd2[31:0] |= ({32{rden2 & (raddr2[4:0]== 5'(j)) & (gpr_bank_id[GPR_BANKS_LOG2-1:0] == 1'(i))}} & gpr_out[i][j][31:0]);
rd3[31:0] |= ({32{rden3 & (raddr3[4:0]== 5'(j)) & (gpr_bank_id[GPR_BANKS_LOG2-1:0] == 1'(i))}} & gpr_out[i][j][31:0]);
end
end
// GPR Write logic
for (int j=1; j<32; j++ ) begin
w0v[j] = wen0 & (waddr0[4:0]== 5'(j) );
w1v[j] = wen1 & (waddr1[4:0]== 5'(j) );
w2v[j] = wen2 & (waddr2[4:0]== 5'(j) );
gpr_in[j] = ({32{w0v[j]}} & wd0[31:0]) |
({32{w1v[j]}} & wd1[31:0]) |
({32{w2v[j]}} & wd2[31:0]);
end
end // always_comb begin
`ifdef ASSERT_ON
// asserting that no 2 ports will write to the same gpr simultaneously
assert_multiple_wen_to_same_gpr: assert #0 (~( ((w0v[31:1] == w1v[31:1]) & wen0 & wen1) | ((w0v[31:1] == w2v[31:1]) & wen0 & wen2) | ((w1v[31:1] == w2v[31:1]) & wen1 & wen2) ) );
`endif
endmodule

463
design/dec/dec_ib_ctl.sv Normal file
View File

@ -0,0 +1,463 @@
// 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.
module dec_ib_ctl
import swerv_types::*;
(
input logic free_clk, // free clk
input logic active_clk, // active clk if not halt / pause
input logic dbg_cmd_valid, // valid dbg cmd
input logic dbg_cmd_write, // dbg cmd is write
input logic [1:0] dbg_cmd_type, // dbg type
input logic [1:0] dbg_cmd_size, // 00 - 1B, 01 - 2B, 10 - 4B, 11 - reserved
input logic [31:0] dbg_cmd_addr, // expand to 31:0
input logic exu_flush_final, // all flush sources: primary/secondary alu's, trap
input logic dec_ib0_valid_eff_d, // effective valid taking decode into account
input logic dec_ib1_valid_eff_d,
input br_pkt_t i0_brp, // i0 branch packet from aligner
input br_pkt_t i1_brp,
input logic ifu_i0_pc4, // i0 is 4B inst else 2B
input logic ifu_i1_pc4,
input logic ifu_i0_valid, // i0 valid from ifu
input logic ifu_i1_valid,
input logic ifu_i0_icaf, // i0 instruction access fault
input logic ifu_i1_icaf,
input logic ifu_i0_icaf_f1, // i0 has access fault on second fetch group
input logic ifu_i1_icaf_f1,
input logic ifu_i0_perr, // i0 instruction parity error
input logic ifu_i1_perr,
input logic ifu_i0_sbecc, // i0 single-bit error
input logic ifu_i1_sbecc,
input logic ifu_i0_dbecc, // i0 double-bit error
input logic ifu_i1_dbecc,
input logic [31:0] ifu_i0_instr, // i0 instruction from the aligner
input logic [31:0] ifu_i1_instr,
input logic [31:1] ifu_i0_pc, // i0 pc from the aligner
input logic [31:1] ifu_i1_pc,
input logic dec_i0_decode_d, // i0 decode
input logic dec_i1_decode_d,
input logic rst_l, // test stuff
input logic clk,
output logic dec_ib3_valid_d, // ib3 valid
output logic dec_ib2_valid_d, // ib2 valid
output logic dec_ib1_valid_d, // ib1 valid
output logic dec_ib0_valid_d, // ib0 valid
output logic [31:0] dec_i0_instr_d, // i0 inst at decode
output logic [31:0] dec_i1_instr_d, // i1 inst at decode
output logic [31:1] dec_i0_pc_d, // i0 pc at decode
output logic [31:1] dec_i1_pc_d,
output logic dec_i0_pc4_d, // i0 is 4B inst else 2B
output logic dec_i1_pc4_d,
output br_pkt_t dec_i0_brp, // i0 branch packet at decode
output br_pkt_t dec_i1_brp,
output logic dec_i0_icaf_d, // i0 instruction access fault at decode
output logic dec_i1_icaf_d,
output logic dec_i0_icaf_f1_d, // i0 instruction access fault at decode for f1 fetch group
output logic dec_i0_perr_d, // i0 instruction parity error at decode
output logic dec_i1_perr_d,
output logic dec_i0_sbecc_d, // i0 single-bit error at decode
output logic dec_i1_sbecc_d,
output logic dec_i0_dbecc_d, // i0 double-bit error at decode
output logic dec_i1_dbecc_d,
output logic dec_debug_wdata_rs1_d, // put debug write data onto rs1 source: machine is halted
output logic dec_debug_fence_d, // debug fence inst
input logic [15:0] ifu_i0_cinst, // 16b compressed inst from aligner
input logic [15:0] ifu_i1_cinst,
output logic [15:0] dec_i0_cinst_d, // 16b compress inst at decode
output logic [15:0] dec_i1_cinst_d,
input logic scan_mode
);
`include "global.h"
logic flush_final;
logic [3:0] ibval_in, ibval;
logic [31:0] ib3_in, ib2_in, ib1_in, ib0_in;
logic [31:0] ib3, ib2, ib1, ib0;
logic [36:0] pc3_in, pc2_in, pc1_in, pc0_in;
logic [36:0] pc3, pc2, pc1, pc0;
logic [15:0] cinst3_in, cinst2_in, cinst1_in, cinst0_in;
logic [15:0] cinst3, cinst2, cinst1, cinst0;
logic write_i1_ib3, write_i0_ib3;
logic write_i1_ib2, write_i0_ib2;
logic write_i1_ib1, write_i0_ib1;
logic write_i0_ib0;
logic shift2, shift1, shift0;
logic shift_ib1_ib0, shift_ib2_ib1, shift_ib3_ib2;
logic shift_ib2_ib0;
logic shift_ib3_ib1;
logic ifu_i0_val, ifu_i1_val;
logic debug_valid;
logic [4:0] dreg;
logic [11:0] dcsr;
logic [31:0] ib0_debug_in;
// logic debug_read_mem;
// logic debug_write_mem;
logic debug_read;
logic debug_write;
logic debug_read_gpr;
logic debug_write_gpr;
logic debug_read_csr;
logic debug_write_csr;
rvdff #(1) flush_upperff (.*, .clk(free_clk), .din(exu_flush_final), .dout(flush_final));
logic [3:0] ibvalid;
logic [3:0] i0_wen;
logic [3:1] i1_wen;
logic [3:0] shift_ibval;
logic [3:0] ibwrite;
assign ibvalid[3:0] = ibval[3:0] | i0_wen[3:0] | {i1_wen[3:1],1'b0};
assign ibval_in[3:0] = (({4{shift0}} & ibvalid[3:0]) |
({4{shift1}} & {1'b0, ibvalid[3:1]}) |
({4{shift2}} & {2'b0, ibvalid[3:2]})) & ~{4{flush_final}};
rvdff #(4) ibvalff (.*, .clk(active_clk), .din(ibval_in[3:0]), .dout(ibval[3:0]));
// only valid if there is room
if (DEC_INSTBUF_DEPTH==4) begin
assign ifu_i0_val = ifu_i0_valid & ~ibval[3] & ~flush_final;
assign ifu_i1_val = ifu_i1_valid & ~ibval[2] & ~flush_final;
end
else begin
assign ifu_i0_val = ifu_i0_valid & (~dec_ib0_valid_eff_d | ~dec_ib1_valid_eff_d) & ~flush_final;
assign ifu_i1_val = ifu_i1_valid & (~dec_ib0_valid_eff_d & ~dec_ib1_valid_eff_d) & ~flush_final;
end
assign i0_wen[0] = ~ibval[0] & (ifu_i0_val | debug_valid);
assign i0_wen[1] = ibval[0] & ~ibval[1] & ifu_i0_val;
assign i0_wen[2] = ibval[1] & ~ibval[2] & ifu_i0_val;
assign i0_wen[3] = ibval[2] & ~ibval[3] & ifu_i0_val;
assign i1_wen[1] = ~ibval[0] & ifu_i1_val;
assign i1_wen[2] = ibval[0] & ~ibval[1] & ifu_i1_val;
assign i1_wen[3] = ibval[1] & ~ibval[2] & ifu_i1_val;
// start trace
if (DEC_INSTBUF_DEPTH==4) begin
assign cinst3_in[15:0] = ({16{write_i0_ib3}} & ifu_i0_cinst[15:0]) |
({16{write_i1_ib3}} & ifu_i1_cinst[15:0]);
rvdffe #(16) cinst3ff (.*, .en(ibwrite[3]), .din(cinst3_in[15:0]), .dout(cinst3[15:0]));
assign cinst2_in[15:0] = ({16{write_i0_ib2}} & ifu_i0_cinst[15:0]) |
({16{write_i1_ib2}} & ifu_i1_cinst[15:0]) |
({16{shift_ib3_ib2}} & cinst3[15:0]);
rvdffe #(16) cinst2ff (.*, .en(ibwrite[2]), .din(cinst2_in[15:0]), .dout(cinst2[15:0]));
end // if (DEC_INSTBUF_DEPTH==4)
else begin
assign cinst3 = '0;
assign cinst2 = '0;
end
assign cinst1_in[15:0] = ({16{write_i0_ib1}} & ifu_i0_cinst[15:0]) |
({16{write_i1_ib1}} & ifu_i1_cinst[15:0]) |
({16{shift_ib2_ib1}} & cinst2[15:0]) |
({16{shift_ib3_ib1}} & cinst3[15:0]);
rvdffe #(16) cinst1ff (.*, .en(ibwrite[1]), .din(cinst1_in[15:0]), .dout(cinst1[15:0]));
assign cinst0_in[15:0] = ({16{write_i0_ib0}} & ifu_i0_cinst[15:0]) |
({16{shift_ib1_ib0}} & cinst1[15:0]) |
({16{shift_ib2_ib0}} & cinst2[15:0]);
rvdffe #(16) cinst0ff (.*, .en(ibwrite[0]), .din(cinst0_in[15:0]), .dout(cinst0[15:0]));
assign dec_i0_cinst_d[15:0] = cinst0[15:0];
assign dec_i1_cinst_d[15:0] = cinst1[15:0];
// end trace
// pc tracking
assign ibwrite[3:0] = { write_i0_ib3 | write_i1_ib3,
write_i0_ib2 | write_i1_ib2 | shift_ib3_ib2,
write_i0_ib1 | write_i1_ib1 | shift_ib2_ib1 | shift_ib3_ib1,
write_i0_ib0 | shift_ib1_ib0 | shift_ib2_ib0
};
logic [36:0] ifu_i1_pcdata, ifu_i0_pcdata;
assign ifu_i1_pcdata[36:0] = { ifu_i1_icaf_f1, ifu_i1_dbecc, ifu_i1_sbecc, ifu_i1_perr, ifu_i1_icaf,
ifu_i1_pc[31:1], ifu_i1_pc4 };
assign ifu_i0_pcdata[36:0] = { ifu_i0_icaf_f1, ifu_i0_dbecc, ifu_i0_sbecc, ifu_i0_perr, ifu_i0_icaf,
ifu_i0_pc[31:1], ifu_i0_pc4 };
if (DEC_INSTBUF_DEPTH==4) begin
assign pc3_in[36:0] = ({37{write_i0_ib3}} & ifu_i0_pcdata[36:0]) |
({37{write_i1_ib3}} & ifu_i1_pcdata[36:0]);
rvdffe #(37) pc3ff (.*, .en(ibwrite[3]), .din(pc3_in[36:0]), .dout(pc3[36:0]));
assign pc2_in[36:0] = ({37{write_i0_ib2}} & ifu_i0_pcdata[36:0]) |
({37{write_i1_ib2}} & ifu_i1_pcdata[36:0]) |
({37{shift_ib3_ib2}} & pc3[36:0]);
rvdffe #(37) pc2ff (.*, .en(ibwrite[2]), .din(pc2_in[36:0]), .dout(pc2[36:0]));
end // if (DEC_INSTBUF_DEPTH==4)
else begin
assign pc3 = '0;
assign pc2 = '0;
end
assign pc1_in[36:0] = ({37{write_i0_ib1}} & ifu_i0_pcdata[36:0]) |
({37{write_i1_ib1}} & ifu_i1_pcdata[36:0]) |
({37{shift_ib2_ib1}} & pc2[36:0]) |
({37{shift_ib3_ib1}} & pc3[36:0]);
rvdffe #(37) pc1ff (.*, .en(ibwrite[1]), .din(pc1_in[36:0]), .dout(pc1[36:0]));
assign pc0_in[36:0] = ({37{write_i0_ib0}} & ifu_i0_pcdata[36:0]) |
({37{shift_ib1_ib0}} & pc1[36:0]) |
({37{shift_ib2_ib0}} & pc2[36:0]);
rvdffe #(37) pc0ff (.*, .en(ibwrite[0]), .din(pc0_in[36:0]), .dout(pc0[36:0]));
assign dec_i0_icaf_f1_d = pc0[36]; // icaf's can only decode as i0
assign dec_i1_dbecc_d = pc1[35];
assign dec_i0_dbecc_d = pc0[35];
assign dec_i1_sbecc_d = pc1[34];
assign dec_i0_sbecc_d = pc0[34];
assign dec_i1_perr_d = pc1[33];
assign dec_i0_perr_d = pc0[33];
assign dec_i1_icaf_d = pc1[32];
assign dec_i0_icaf_d = pc0[32];
assign dec_i1_pc_d[31:1] = pc1[31:1];
assign dec_i0_pc_d[31:1] = pc0[31:1];
assign dec_i1_pc4_d = pc1[0];
assign dec_i0_pc4_d = pc0[0];
// branch prediction
logic [$bits(br_pkt_t)-1:0] bp3_in,bp3,bp2_in,bp2,bp1_in,bp1,bp0_in,bp0;
if (DEC_INSTBUF_DEPTH==4) begin
assign bp3_in = ({$bits(br_pkt_t){write_i0_ib3}} & i0_brp) |
({$bits(br_pkt_t){write_i1_ib3}} & i1_brp);
rvdffe #($bits(br_pkt_t)) bp3ff (.*, .en(ibwrite[3]), .din(bp3_in), .dout(bp3));
assign bp2_in = ({$bits(br_pkt_t){write_i0_ib2}} & i0_brp) |
({$bits(br_pkt_t){write_i1_ib2}} & i1_brp) |
({$bits(br_pkt_t){shift_ib3_ib2}} & bp3);
rvdffe #($bits(br_pkt_t)) bp2ff (.*, .en(ibwrite[2]), .din(bp2_in), .dout(bp2));
end // if (DEC_INSTBUF_DEPTH==4)
else begin
assign bp3 = '0;
assign bp2 = '0;
end
assign bp1_in = ({$bits(br_pkt_t){write_i0_ib1}} & i0_brp) |
({$bits(br_pkt_t){write_i1_ib1}} & i1_brp) |
({$bits(br_pkt_t){shift_ib2_ib1}} & bp2) |
({$bits(br_pkt_t){shift_ib3_ib1}} & bp3);
rvdffe #($bits(br_pkt_t)) bp1ff (.*, .en(ibwrite[1]), .din(bp1_in), .dout(bp1));
assign bp0_in = ({$bits(br_pkt_t){write_i0_ib0}} & i0_brp) |
({$bits(br_pkt_t){shift_ib1_ib0}} & bp1) |
({$bits(br_pkt_t){shift_ib2_ib0}} & bp2);
rvdffe #($bits(br_pkt_t)) bp0ff (.*, .en(ibwrite[0]), .din(bp0_in), .dout(bp0));
// instruction buffers
if (DEC_INSTBUF_DEPTH==4) begin
assign ib3_in[31:0] = ({32{write_i0_ib3}} & ifu_i0_instr[31:0]) |
({32{write_i1_ib3}} & ifu_i1_instr[31:0]);
rvdffe #(32) ib3ff (.*, .en(ibwrite[3]), .din(ib3_in[31:0]), .dout(ib3[31:0]));
assign ib2_in[31:0] = ({32{write_i0_ib2}} & ifu_i0_instr[31:0]) |
({32{write_i1_ib2}} & ifu_i1_instr[31:0]) |
({32{shift_ib3_ib2}} & ib3[31:0]);
rvdffe #(32) ib2ff (.*, .en(ibwrite[2]), .din(ib2_in[31:0]), .dout(ib2[31:0]));
end // if (DEC_INSTBUF_DEPTH==4)
else begin
assign ib3 = '0;
assign ib2 = '0;
end
assign ib1_in[31:0] = ({32{write_i0_ib1}} & ifu_i0_instr[31:0]) |
({32{write_i1_ib1}} & ifu_i1_instr[31:0]) |
({32{shift_ib2_ib1}} & ib2[31:0]) |
({32{shift_ib3_ib1}} & ib3[31:0]);
rvdffe #(32) ib1ff (.*, .en(ibwrite[1]), .din(ib1_in[31:0]), .dout(ib1[31:0]));
// GPR accesses
// put reg to read on rs1
// read -> or %x0, %reg,%x0 {000000000000,reg[4:0],110000000110011}
// put write date on rs1
// write -> or %reg, %x0, %x0 {00000000000000000110,reg[4:0],0110011}
// CSR accesses
// csr is of form rd, csr, rs1
// read -> csrrs %x0, %csr, %x0 {csr[11:0],00000010000001110011}
// put write data on rs1
// write -> csrrw %x0, %csr, %x0 {csr[11:0],00000001000001110011}
// abstract memory command not done here
assign debug_valid = dbg_cmd_valid & (dbg_cmd_type[1:0] != 2'h2);
assign debug_read = debug_valid & ~dbg_cmd_write;
assign debug_write = debug_valid & dbg_cmd_write;
assign debug_read_gpr = debug_read & (dbg_cmd_type[1:0]==2'h0);
assign debug_write_gpr = debug_write & (dbg_cmd_type[1:0]==2'h0);
assign debug_read_csr = debug_read & (dbg_cmd_type[1:0]==2'h1);
assign debug_write_csr = debug_write & (dbg_cmd_type[1:0]==2'h1);
assign dreg[4:0] = dbg_cmd_addr[4:0];
assign dcsr[11:0] = dbg_cmd_addr[11:0];
assign ib0_debug_in[31:0] = ({32{debug_read_gpr}} & {12'b000000000000,dreg[4:0],15'b110000000110011}) |
({32{debug_write_gpr}} & {20'b00000000000000000110,dreg[4:0],7'b0110011}) |
({32{debug_read_csr}} & {dcsr[11:0],20'b00000010000001110011}) |
({32{debug_write_csr}} & {dcsr[11:0],20'b00000001000001110011});
// machine is in halted state, pipe empty, write will always happen next cycle
rvdff #(1) debug_wdata_rs1ff (.*, .clk(free_clk), .din(debug_write_gpr | debug_write_csr), .dout(dec_debug_wdata_rs1_d));
// special fence csr for use only in debug mode
logic debug_fence_in;
assign debug_fence_in = debug_write_csr & (dcsr[11:0] == 12'h7c4);
rvdff #(1) debug_fence_ff (.*, .clk(free_clk), .din(debug_fence_in), .dout(dec_debug_fence_d));
assign ib0_in[31:0] = ({32{write_i0_ib0}} & ((debug_valid) ? ib0_debug_in[31:0] : ifu_i0_instr[31:0])) |
({32{shift_ib1_ib0}} & ib1[31:0]) |
({32{shift_ib2_ib0}} & ib2[31:0]);
rvdffe #(32) ib0ff (.*, .en(ibwrite[0]), .din(ib0_in[31:0]), .dout(ib0[31:0]));
assign dec_ib3_valid_d = ibval[3];
assign dec_ib2_valid_d = ibval[2];
assign dec_ib1_valid_d = ibval[1];
assign dec_ib0_valid_d = ibval[0];
assign dec_i0_instr_d[31:0] = ib0[31:0];
assign dec_i1_instr_d[31:0] = ib1[31:0];
assign dec_i0_brp = bp0;
assign dec_i1_brp = bp1;
assign shift1 = dec_i0_decode_d & ~dec_i1_decode_d;
assign shift2 = dec_i0_decode_d & dec_i1_decode_d;
assign shift0 = ~dec_i0_decode_d;
// compute shifted ib valids to determine where to write
assign shift_ibval[3:0] = ({4{shift1}} & {1'b0, ibval[3:1] }) |
({4{shift2}} & {2'b0, ibval[3:2]}) |
({4{shift0}} & ibval[3:0]);
assign write_i0_ib0 = ~shift_ibval[0] & (ifu_i0_val | debug_valid);
assign write_i0_ib1 = shift_ibval[0] & ~shift_ibval[1] & ifu_i0_val;
assign write_i0_ib2 = shift_ibval[1] & ~shift_ibval[2] & ifu_i0_val;
assign write_i0_ib3 = shift_ibval[2] & ~shift_ibval[3] & ifu_i0_val;
assign write_i1_ib1 = ~shift_ibval[0] & ifu_i1_val;
assign write_i1_ib2 = shift_ibval[0] & ~shift_ibval[1] & ifu_i1_val;
assign write_i1_ib3 = shift_ibval[1] & ~shift_ibval[2] & ifu_i1_val;
assign shift_ib1_ib0 = shift1 & ibval[1];
assign shift_ib2_ib1 = shift1 & ibval[2];
assign shift_ib3_ib2 = shift1 & ibval[3];
assign shift_ib2_ib0 = shift2 & ibval[2];
assign shift_ib3_ib1 = shift2 & ibval[3];
endmodule

2570
design/dec/dec_tlu_ctl.sv Normal file

File diff suppressed because it is too large Load Diff

57
design/dec/dec_trigger.sv Normal file
View File

@ -0,0 +1,57 @@
// 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.
//********************************************************************************
// $Id$
//
//
// Owner:
// Function: DEC Trigger Logic
// Comments:
//
//********************************************************************************
module dec_trigger
import swerv_types::*;
(
input logic clk,
input logic rst_l,
input 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
input logic [31:1] dec_i1_pc_d, // i1 pc
output logic [3:0] dec_i0_trigger_match_d,
output logic [3:0] dec_i1_trigger_match_d
);
logic [3:0][31:0] dec_i0_match_data;
logic [3:0] dec_i0_trigger_data_match;
logic [3:0][31:0] dec_i1_match_data;
logic [3:0] dec_i1_trigger_data_match;
for (genvar i=0; i<4; i++) begin
assign dec_i0_match_data[i][31:0] = ({32{~trigger_pkt_any[i].select & trigger_pkt_any[i].execute}} & {dec_i0_pc_d[31:1], trigger_pkt_any[i].tdata2[0]}); // select=0; do a PC match
assign dec_i1_match_data[i][31:0] = ({32{~trigger_pkt_any[i].select & trigger_pkt_any[i].execute}} & {dec_i1_pc_d[31:1], trigger_pkt_any[i].tdata2[0]} ); // select=0; do a PC match
rvmaskandmatch trigger_i0_match (.mask(trigger_pkt_any[i].tdata2[31:0]), .data(dec_i0_match_data[i][31:0]), .masken(trigger_pkt_any[i].match), .match(dec_i0_trigger_data_match[i]));
rvmaskandmatch trigger_i1_match (.mask(trigger_pkt_any[i].tdata2[31:0]), .data(dec_i1_match_data[i][31:0]), .masken(trigger_pkt_any[i].match), .match(dec_i1_trigger_data_match[i]));
assign dec_i0_trigger_match_d[i] = trigger_pkt_any[i].execute & trigger_pkt_any[i].m & dec_i0_trigger_data_match[i];
assign dec_i1_trigger_match_d[i] = trigger_pkt_any[i].execute & trigger_pkt_any[i].m & dec_i1_trigger_data_match[i];
end
endmodule // dec_trigger

322
design/dec/decode Normal file
View File

@ -0,0 +1,322 @@
.definition
add = [0000000..........000.....0110011]
addi = [.................000.....0010011]
sub = [0100000..........000.....0110011]
and = [0000000..........111.....0110011]
andi = [.................111.....0010011]
or = [0000000..........110.....0110011]
ori = [.................110.....0010011]
xor = [0000000..........100.....0110011]
xori = [.................100.....0010011]
sll = [0000000..........001.....0110011]
slli = [0000000..........001.....0010011]
sra = [0100000..........101.....0110011]
srai = [0100000..........101.....0010011]
srl = [0000000..........101.....0110011]
srli = [0000000..........101.....0010011]
lui = [.........................0110111]
auipc= [.........................0010111]
slt = [0000000..........010.....0110011]
sltu = [0000000..........011.....0110011]
slti = [.................010.....0010011]
sltiu= [.................011.....0010011]
beq = [.................000.....1100011]
bne = [.................001.....1100011]
bge = [.................101.....1100011]
blt = [.................100.....1100011]
bgeu = [.................111.....1100011]
bltu = [.................110.....1100011]
jal = [.........................1101111]
jalr = [.................000.....1100111]
lb = [.................000.....0000011]
lh = [.................001.....0000011]
lw = [.................010.....0000011]
sb = [.................000.....0100011]
sh = [.................001.....0100011]
sw = [.................010.....0100011]
lbu = [.................100.....0000011]
lhu = [.................101.....0000011]
fence = [0000........00000000000000001111]
fence.i = [00000000000000000001000000001111]
ebreak = [00000000000100000000000001110011]
ecall = [00000000000000000000000001110011]
mret = [00110000001000000000000001110011]
wfi = [00010000010100000000000001110011]
csrrc_ro = [............00000011.....1110011]
csrrc_rw0 = [............1....011.....1110011]
csrrc_rw1 = [.............1...011.....1110011]
csrrc_rw2 = [..............1..011.....1110011]
csrrc_rw3 = [...............1.011.....1110011]
csrrc_rw4 = [................1011.....1110011]
csrrci_ro = [............00000111.....1110011]
csrrci_rw0 = [............1....111.....1110011]
csrrci_rw1 = [.............1...111.....1110011]
csrrci_rw2 = [..............1..111.....1110011]
csrrci_rw3 = [...............1.111.....1110011]
csrrci_rw4 = [................1111.....1110011]
csrrs_ro = [............00000010.....1110011]
csrrs_rw0 = [............1....010.....1110011]
csrrs_rw1 = [.............1...010.....1110011]
csrrs_rw2 = [..............1..010.....1110011]
csrrs_rw3 = [...............1.010.....1110011]
csrrs_rw4 = [................1010.....1110011]
csrrsi_ro = [............00000110.....1110011]
csrrsi_rw0 = [............1....110.....1110011]
csrrsi_rw1 = [.............1...110.....1110011]
csrrsi_rw2 = [..............1..110.....1110011]
csrrsi_rw3 = [...............1.110.....1110011]
csrrsi_rw4 = [................1110.....1110011]
csrw = [.................001000001110011]
csrrw0 = [.................001....11110011]
csrrw1 = [.................001...1.1110011]
csrrw2 = [.................001..1..1110011]
csrrw3 = [.................001.1...1110011]
csrrw4 = [.................0011....1110011]
csrwi = [.................101000001110011]
csrrwi0 = [.................101....11110011]
csrrwi1 = [.................101...1.1110011]
csrrwi2 = [.................101..1..1110011]
csrrwi3 = [.................101.1...1110011]
csrrwi4 = [.................1011....1110011]
mul = [0000001..........000.....0110011]
mulh = [0000001..........001.....0110011]
mulhsu = [0000001..........010.....0110011]
mulhu = [0000001..........011.....0110011]
div = [0000001..........100.....0110011]
divu = [0000001..........101.....0110011]
rem = [0000001..........110.....0110011]
remu = [0000001..........111.....0110011]
.input
rv32i = {
i[31]
i[30]
i[29]
i[28]
i[27]
i[26]
i[25]
i[24]
i[23]
i[22]
i[21]
i[20]
i[19]
i[18]
i[17]
i[16]
i[15]
i[14]
i[13]
i[12]
i[11]
i[10]
i[9]
i[8]
i[7]
i[6]
i[5]
i[4]
i[3]
i[2]
i[1]
i[0]
}
.output
rv32i = {
alu
rs1
rs2
imm12
rd
shimm5
imm20
pc
load
store
lsu
add
sub
land
lor
lxor
sll
sra
srl
slt
unsign
condbr
beq
bne
bge
blt
jal
by
half
word
csr_read
csr_clr
csr_set
csr_write
csr_imm
presync
postsync
ebreak
ecall
mret
mul
rs1_sign
rs2_sign
low
div
rem
fence
fence_i
pm_alu
}
.decode
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[div] = { div rs1 rs2 rd presync postsync}
rv32i[divu] = { div rs1 rs2 rd unsign presync postsync}
rv32i[rem] = { div rs1 rs2 rd presync postsync rem}
rv32i[remu] = { div rs1 rs2 rd unsign presync postsync rem}
rv32i[add] = { alu rs1 rs2 rd add pm_alu }
rv32i[addi] = { alu rs1 imm12 rd add pm_alu }
rv32i[sub] = { alu rs1 rs2 rd sub pm_alu }
rv32i[and] = { alu rs1 rs2 rd land pm_alu }
rv32i[andi] = { alu rs1 imm12 rd land pm_alu }
rv32i[or] = { alu rs1 rs2 rd lor pm_alu }
rv32i[ori] = { alu rs1 imm12 rd lor pm_alu }
rv32i[xor] = { alu rs1 rs2 rd lxor pm_alu }
rv32i[xori] = { alu rs1 imm12 rd lxor pm_alu }
rv32i[sll] = { alu rs1 rs2 rd sll pm_alu }
rv32i[slli] = { alu rs1 shimm5 rd sll pm_alu }
rv32i[sra] = { alu rs1 rs2 rd sra pm_alu }
rv32i[srai] = { alu rs1 shimm5 rd sra pm_alu }
rv32i[srl] = { alu rs1 rs2 rd srl pm_alu }
rv32i[srli] = { alu rs1 shimm5 rd srl pm_alu }
rv32i[lui] = { alu imm20 rd lor pm_alu }
rv32i[auipc] = { alu imm20 pc rd add pm_alu }
rv32i[slt] = { alu rs1 rs2 rd sub slt pm_alu }
rv32i[sltu] = { alu rs1 rs2 rd sub slt unsign pm_alu }
rv32i[slti] = { alu rs1 imm12 rd sub slt pm_alu }
rv32i[sltiu] = { alu rs1 imm12 rd sub slt unsign pm_alu }
rv32i[beq] = { alu rs1 rs2 sub condbr beq }
rv32i[bne] = { alu rs1 rs2 sub condbr bne }
rv32i[bge] = { alu rs1 rs2 sub condbr bge }
rv32i[blt] = { alu rs1 rs2 sub condbr blt }
rv32i[bgeu] = { alu rs1 rs2 sub condbr bge unsign }
rv32i[bltu] = { alu rs1 rs2 sub condbr blt unsign }
rv32i[jal] = { alu imm20 rd pc jal }
rv32i[jalr] = { alu rs1 rd imm12 jal }
rv32i[lb] = { lsu load rs1 rd by }
rv32i[lh] = { lsu load rs1 rd half }
rv32i[lw] = { lsu load rs1 rd word }
rv32i[lbu] = { lsu load rs1 rd by unsign }
rv32i[lhu] = { lsu load rs1 rd half unsign }
rv32i[sb] = { lsu store rs1 rs2 by }
rv32i[sh] = { lsu store rs1 rs2 half }
rv32i[sw] = { lsu store rs1 rs2 word }
rv32i[fence] = { alu lor fence presync}
# fence.i has fence effect in addtion to flush I$ and redirect
rv32i[fence.i] = { alu lor fence fence_i presync postsync}
# nops for now
rv32i[ebreak] = { alu rs1 imm12 rd lor ebreak postsync}
rv32i[ecall] = { alu rs1 imm12 rd lor ecall postsync}
rv32i[mret] = { alu rs1 imm12 rd lor mret postsync}
rv32i[wfi] = { alu rs1 imm12 rd lor pm_alu }
# csr means read
# csr_read - put csr on rs2 and rs1 0's
rv32i[csrrc_ro] = { alu rd csr_read lor }
# put csr on rs2 and make rs1 0's into alu. Save rs1 for csr_clr later
rv32i[csrrc_rw{0-4}] = { alu rd csr_read rs1 csr_clr lor presync postsync }
rv32i[csrrci_ro] = { alu rd csr_read lor }
rv32i[csrrci_rw{0-4}] = { alu rd csr_read rs1 csr_clr csr_imm lor presync postsync }
rv32i[csrrs_ro] = { alu rd csr_read lor }
rv32i[csrrs_rw{0-4}] = { alu rd csr_read rs1 csr_set lor presync postsync }
rv32i[csrrsi_ro] = { alu rd csr_read lor }
rv32i[csrrsi_rw{0-4}] = { alu rd csr_read rs1 csr_set csr_imm lor presync postsync }
rv32i[csrrw{0-4}] = { alu rd csr_read rs1 csr_write lor presync postsync }
rv32i[csrrwi{0-4}] = { alu rd csr_read rs1 csr_write csr_imm lor presync postsync }
# optimize csr write only - pipelined
rv32i[csrw] = { alu rd rs1 csr_write }
rv32i[csrwi] = { alu rd csr_write csr_imm }
.end

697
design/dma_ctrl.sv Normal file
View File

@ -0,0 +1,697 @@
// 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.
//********************************************************************************
// $Id$
//
// Function: Top level SWERV core file
// Comments:
//
//********************************************************************************
module dma_ctrl (
input logic clk,
input logic free_clk,
input logic rst_l,
input logic dma_bus_clk_en, // slave bus clock enable
input logic clk_override,
// AXI signals
// AXI Write Channels
input logic dma_axi_awvalid,
output logic dma_axi_awready,
input logic [`RV_DMA_BUS_TAG-1:0] dma_axi_awid,
input logic [31:0] dma_axi_awaddr,
input logic [2:0] dma_axi_awsize,
input logic [2:0] dma_axi_awprot,
input logic [7:0] dma_axi_awlen,
input logic [1:0] dma_axi_awburst,
input logic dma_axi_wvalid,
output logic dma_axi_wready,
input logic [63:0] dma_axi_wdata,
input logic [7:0] dma_axi_wstrb,
input logic dma_axi_wlast,
output logic dma_axi_bvalid,
input logic dma_axi_bready,
output logic [1:0] dma_axi_bresp,
output logic [`RV_DMA_BUS_TAG-1:0] dma_axi_bid,
// AXI Read Channels
input logic dma_axi_arvalid,
output logic dma_axi_arready,
input logic [`RV_DMA_BUS_TAG-1:0] dma_axi_arid,
input logic [31:0] dma_axi_araddr,
input logic [2:0] dma_axi_arsize,
input logic [2:0] dma_axi_arprot,
input logic [7:0] dma_axi_arlen,
input logic [1:0] dma_axi_arburst,
output logic dma_axi_rvalid,
input logic dma_axi_rready,
output logic [`RV_DMA_BUS_TAG-1:0] dma_axi_rid,
output logic [63:0] dma_axi_rdata,
output logic [1:0] dma_axi_rresp,
output logic dma_axi_rlast,
output logic dma_slv_algn_err,
// Debug signals
input logic [31:0] dbg_cmd_addr,
input logic [31:0] dbg_cmd_wrdata,
input logic dbg_cmd_valid,
input logic dbg_cmd_write, // 1: write command, 0: read_command
input logic [1:0] dbg_cmd_type, // 0:gpr 1:csr 2: memory
input logic [1:0] dbg_cmd_size, // size of the abstract mem access debug command
input logic dbg_dma_bubble, // Debug needs a bubble to send a valid
output logic dma_dbg_ready, // DMA is ready to accept debug request
output logic dma_dbg_cmd_done,
output logic dma_dbg_cmd_fail,
output logic [31:0] dma_dbg_rddata,
// Core side signals
output logic dma_dccm_req, // DMA dccm request (only one of dccm/iccm will be set)
output logic dma_iccm_req, // DMA iccm request
output logic [31:0] dma_mem_addr, // DMA request address
output logic [2:0] dma_mem_sz, // DMA request size
output logic dma_mem_write, // DMA write to dccm/iccm
output logic [63:0] dma_mem_wdata, // DMA write data
input logic dccm_dma_rvalid, // dccm data valid for DMA read
input logic dccm_dma_ecc_error, // ECC error on DMA read
input logic [63:0] dccm_dma_rdata, // dccm data for DMA read
input logic iccm_dma_rvalid, // iccm data valid for DMA read
input logic iccm_dma_ecc_error, // ECC error on DMA read
input logic [63:0] iccm_dma_rdata, // iccm data for DMA read
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
input logic iccm_ready, // iccm ready to accept DMA request
input logic dec_tlu_stall_dma, // stall dma accesses, tlu is attempting to enter halt/debug mode
input logic [2:0] dec_tlu_dma_qos_prty, // DMA QoS priority coming from MFDC [18:15]
input logic scan_mode
);
`include "global.h"
localparam DEPTH = DMA_BUF_DEPTH;
localparam DEPTH_PTR = $clog2(DEPTH);
localparam NACK_COUNT = 7;
logic [DEPTH-1:0] fifo_valid;
logic [DEPTH-1:0][1:0] fifo_error;
logic [DEPTH-1:0] fifo_dccm_valid;
logic [DEPTH-1:0] fifo_iccm_valid;
logic [DEPTH-1:0] fifo_data_valid;
logic [DEPTH-1:0] fifo_data_bus_valid;
logic [DEPTH-1:0] fifo_error_bus;
logic [DEPTH-1:0] fifo_rpend;
logic [DEPTH-1:0] fifo_done; // DMA trxn is done in core
logic [DEPTH-1:0] fifo_done_bus; // DMA trxn is done in core synced to bus
logic [DEPTH-1:0] fifo_rsp_done; // DMA response sent to bus
logic [DEPTH-1:0][31:0] fifo_addr;
logic [DEPTH-1:0][2:0] fifo_sz;
logic [DEPTH-1:0] fifo_write;
logic [DEPTH-1:0] fifo_posted_write;
logic [DEPTH-1:0] fifo_dbg;
logic [DEPTH-1:0][63:0] fifo_data;
logic [DEPTH-1:0][DMA_BUS_TAG-1:0] fifo_tag;
logic [DEPTH-1:0] fifo_cmd_en;
logic [DEPTH-1:0] fifo_valid_en;
logic [DEPTH-1:0] fifo_data_en;
logic [DEPTH-1:0] fifo_data_bus_en;
logic [DEPTH-1:0] fifo_pend_en;
logic [DEPTH-1:0] fifo_done_en;
logic [DEPTH-1:0] fifo_done_bus_en;
logic [DEPTH-1:0] fifo_error_en;
logic [DEPTH-1:0] fifo_error_bus_en;
//logic [DEPTH-1:0] fifo_rsp_done_en;
logic [DEPTH-1:0] fifo_reset;
logic [DEPTH-1:0][1:0] fifo_error_in;
logic [DEPTH-1:0][63:0] fifo_data_in;
logic fifo_write_in;
logic fifo_posted_write_in;
logic fifo_dbg_in;
logic [31:0] fifo_addr_in;
logic [2:0] fifo_sz_in;
logic [DEPTH_PTR-1:0] RspPtr, PrevRspPtr, NxtRspPtr;
logic [DEPTH_PTR-1:0] WrPtr, NxtWrPtr;
logic [DEPTH_PTR-1:0] RdPtr, NxtRdPtr;
logic [DEPTH_PTR-1:0] RdPtr_Q1, RdPtr_Q2, RdPtr_Q3;
logic WrPtrEn, RdPtrEn, RspPtrEn;
logic dma_dbg_cmd_error_in;
logic dma_dbg_cmd_done_q;
logic fifo_full, fifo_full_spec, fifo_empty;
logic dma_address_error, dma_alignment_error;
logic [3:0] num_fifo_vld;
logic dma_mem_req;
logic dma_addr_in_dccm;
logic dma_addr_in_iccm;
logic dma_addr_in_pic;
logic dma_addr_in_pic_region_nc;
logic dma_addr_in_dccm_region_nc;
logic dma_addr_in_iccm_region_nc;
logic [2:0] dma_nack_count_csr;
logic [2:0] dma_nack_count, dma_nack_count_d;
logic dma_buffer_c1_clken;
logic dma_free_clken;
logic dma_buffer_c1_clk;
logic dma_free_clk;
logic dma_bus_clk;
logic wrbuf_en, wrbuf_data_en;
logic wrbuf_cmd_sent, wrbuf_rst, wrbuf_data_rst;
logic wrbuf_vld;
logic wrbuf_data_vld;
logic wrbuf_posted;
logic [DMA_BUS_TAG-1:0] wrbuf_tag;
logic [2:0] wrbuf_size;
logic [31:0] wrbuf_addr;
logic [63:0] wrbuf_data;
logic [7:0] wrbuf_byteen;
logic rdbuf_en;
logic rdbuf_cmd_sent, rdbuf_rst;
logic rdbuf_vld;
logic [DMA_BUS_TAG-1:0] rdbuf_tag;
logic [2:0] rdbuf_size;
logic [31:0] rdbuf_addr;
logic axi_mstr_valid, axi_mstr_valid_q;
logic axi_mstr_write;
logic axi_mstr_posted_write;
logic [DMA_BUS_TAG-1:0] axi_mstr_tag;
logic [31:0] axi_mstr_addr;
logic [2:0] axi_mstr_size;
logic [63:0] axi_mstr_wdata;
logic [7:0] axi_mstr_wstrb;
logic axi_mstr_prty_in, axi_mstr_prty_en;
logic axi_mstr_priority;
logic axi_mstr_sel;
logic axi_slv_valid;
logic axi_slv_sent, axi_slv_sent_q;
logic axi_slv_write;
logic axi_slv_posted_write;
logic [DMA_BUS_TAG-1:0] axi_slv_tag;
logic [1:0] axi_slv_error;
logic [63:0] axi_slv_rdata;
logic dma_bus_clk_en_q;
logic fifo_full_spec_bus;
logic dbg_dma_bubble_bus;
logic dec_tlu_stall_dma_bus;
logic dma_fifo_ready;
//------------------------LOGIC STARTS HERE---------------------------------
// FIFO inputs
assign fifo_addr_in[31:0] = dbg_cmd_valid ? dbg_cmd_addr[31:0] : axi_mstr_addr[31:0];
assign fifo_sz_in[2:0] = dbg_cmd_valid ? {1'b0,dbg_cmd_size[1:0]} : axi_mstr_size[2:0];
assign fifo_write_in = dbg_cmd_valid ? dbg_cmd_write : axi_mstr_write;
assign fifo_posted_write_in = axi_mstr_valid & axi_mstr_posted_write;
assign fifo_dbg_in = dbg_cmd_valid;
//assign fifo_error_in[1:0] = dccm_dma_rvalid ? {1'b0,dccm_dma_ecc_error} : iccm_dma_rvalid ? {1'b0,iccm_dma_ecc_error} : {(dma_address_error | dma_alignment_error | dma_dbg_cmd_error_in), dma_alignment_error};
//assign fifo_data_in[63:0] = dccm_dma_rvalid ? dccm_dma_rdata[63:0] : (iccm_dma_rvalid ? iccm_dma_rdata[63:0] :
// (dbg_cmd_valid ? {2{dbg_cmd_wrdata[31:0]}} : axi_mstr_wdata[63:0]));
for (genvar i=0 ;i<DEPTH; i++) begin: GenFifo
assign fifo_valid_en[i] = axi_mstr_valid & (i == WrPtr[DEPTH_PTR-1:0]);
assign fifo_cmd_en[i] = ((axi_mstr_valid & dma_bus_clk_en) | (dbg_cmd_valid & dbg_cmd_type[1])) &
(i == WrPtr[DEPTH_PTR-1:0]);
assign fifo_data_en[i] = (((axi_mstr_valid & (axi_mstr_write | dma_address_error | dma_alignment_error) & dma_bus_clk_en) |
(dbg_cmd_valid & dbg_cmd_type[1] & dbg_cmd_write)) & (i == WrPtr[DEPTH_PTR-1:0])) |
((dccm_dma_rvalid & (i == RdPtr_Q3[DEPTH_PTR-1:0]))| (iccm_dma_rvalid & (i == RdPtr_Q2[DEPTH_PTR-1:0])));
assign fifo_data_bus_en[i] = (fifo_data_en[i] | fifo_data_valid[i]) & dma_bus_clk_en;
assign fifo_pend_en[i] = (dma_dccm_req | dma_iccm_req) & ~dma_mem_write & (i == RdPtr[DEPTH_PTR-1:0]);
assign fifo_error_en[i] = fifo_cmd_en[i] | (((dccm_dma_rvalid & dccm_dma_ecc_error & (i == RdPtr_Q3[DEPTH_PTR-1:0])) | (iccm_dma_rvalid & iccm_dma_ecc_error & (i == RdPtr_Q2[DEPTH_PTR-1:0]))));
assign fifo_error_bus_en[i] = (((|fifo_error_in[i][1:0]) & fifo_error_en[i]) | (|fifo_error[i])) & dma_bus_clk_en;
assign fifo_done_en[i] = (((|fifo_error[i]) | ((dma_dccm_req | dma_iccm_req) & dma_mem_write)) & (i == RdPtr[DEPTH_PTR-1:0])) |
((dccm_dma_rvalid & (i == RdPtr_Q3[DEPTH_PTR-1:0])) | (iccm_dma_rvalid & (i == RdPtr_Q2[DEPTH_PTR-1:0])));
assign fifo_done_bus_en[i] = (fifo_done_en[i] | fifo_done[i]) & dma_bus_clk_en;
//assign fifo_rsp_done_en[i] = fifo_valid[i] & ((axi_slv_sent & dma_bus_clk_en) | dma_dbg_cmd_done) & (i == RspPtr[DEPTH_PTR-1:0]);
//assign fifo_reset[i] = (fifo_done[i] | fifo_done_en[i]) & (fifo_rsp_done[i] | fifo_rsp_done_en[i]);
assign fifo_reset[i] = ((axi_slv_sent & dma_bus_clk_en) | dma_dbg_cmd_done) & (i == RspPtr[DEPTH_PTR-1:0]);
assign fifo_error_in[i] = (dccm_dma_rvalid & (i == RdPtr_Q3[DEPTH_PTR-1:0])) ? {1'b0,dccm_dma_ecc_error} : (iccm_dma_rvalid & (i == RdPtr_Q2[DEPTH_PTR-1:0])) ? {1'b0,iccm_dma_ecc_error} :
{(dma_address_error | dma_alignment_error | dma_dbg_cmd_error_in), dma_alignment_error};
assign fifo_data_in[i] = (fifo_error_en[i] & (|fifo_error_in[i])) ? (fifo_cmd_en[i] ? {32'b0,axi_mstr_addr[31:0]} : {32'b0,fifo_addr[i]}) :
((dccm_dma_rvalid & (i == RdPtr_Q3[DEPTH_PTR-1:0])) ? dccm_dma_rdata[63:0] : (iccm_dma_rvalid & (i == RdPtr_Q2[DEPTH_PTR-1:0])) ? iccm_dma_rdata[63:0] :
(dbg_cmd_valid ? {2{dbg_cmd_wrdata[31:0]}} : axi_mstr_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), .*);
rvdffsc #(1) fifo_error_bus_dff (.din(1'b1), .dout(fifo_error_bus[i]), .en(fifo_error_bus_en[i]), .clear(fifo_reset[i]), .clk(dma_free_clk), .*);
rvdffs #(1) fifo_dccm_valid_dff (.din((dma_addr_in_dccm | dma_addr_in_pic)), .dout(fifo_dccm_valid[i]), .en(fifo_cmd_en[i]), .clk(dma_buffer_c1_clk), .*);
rvdffs #(1) fifo_iccm_valid_dff (.din(dma_addr_in_iccm), .dout(fifo_iccm_valid[i]), .en(fifo_cmd_en[i]), .clk(dma_buffer_c1_clk), .*);
rvdffsc #(1) fifo_data_valid_dff (.din(1'b1), .dout(fifo_data_valid[i]), .en(fifo_data_en[i]), .clear(fifo_reset[i]), .clk(dma_free_clk), .*);
rvdffsc #(1) fifo_data_bus_valid_dff (.din(1'b1), .dout(fifo_data_bus_valid[i]), .en(fifo_data_bus_en[i]), .clear(fifo_reset[i]), .clk(dma_free_clk), .*);
rvdffsc #(1) fifo_rpend_dff (.din(1'b1), .dout(fifo_rpend[i]), .en(fifo_pend_en[i]), .clear(fifo_reset[i]), .clk(dma_free_clk), .*);
rvdffsc #(1) fifo_done_dff (.din(1'b1), .dout(fifo_done[i]), .en(fifo_done_en[i]), .clear(fifo_reset[i]), .clk(dma_free_clk), .*);
rvdffsc #(1) fifo_done_bus_dff (.din(1'b1), .dout(fifo_done_bus[i]), .en(fifo_done_bus_en[i]), .clear(fifo_reset[i]), .clk(dma_free_clk), .*);
//rvdffsc #(1) fifo_rsp_done_dff (.din(1'b1), .dout(fifo_rsp_done[i]), .en(fifo_rsp_done_en[i]), .clear(fifo_reset[i]), .clk(dma_free_clk), .*);
rvdffe #(32) fifo_addr_dff (.din(fifo_addr_in[31:0]), .dout(fifo_addr[i]), .en(fifo_cmd_en[i]), .*);
rvdffs #(3) fifo_sz_dff (.din(fifo_sz_in[2:0]), .dout(fifo_sz[i]), .en(fifo_cmd_en[i]), .clk(dma_buffer_c1_clk), .*);
rvdffs #(1) fifo_write_dff (.din(fifo_write_in), .dout(fifo_write[i]), .en(fifo_cmd_en[i]), .clk(dma_buffer_c1_clk), .*);
rvdffs #(1) fifo_posted_write_dff (.din(fifo_posted_write_in), .dout(fifo_posted_write[i]), .en(fifo_cmd_en[i]), .clk(dma_buffer_c1_clk), .*);
rvdffs #(1) fifo_dbg_dff (.din(fifo_dbg_in), .dout(fifo_dbg[i]), .en(fifo_cmd_en[i]), .clk(dma_buffer_c1_clk), .*);
rvdffe #(64) fifo_data_dff (.din(fifo_data_in[i]), .dout(fifo_data[i]), .en(fifo_data_en[i]), .*);
rvdffs #(DMA_BUS_TAG) fifo_tag_dff(.din(axi_mstr_tag[DMA_BUS_TAG-1:0]), .dout(fifo_tag[i][DMA_BUS_TAG-1:0]), .en(fifo_cmd_en[i]), .clk(dma_buffer_c1_clk), .*);
end
// Pointer logic
assign NxtWrPtr[DEPTH_PTR-1:0] = WrPtr[DEPTH_PTR-1:0] + 1'b1;
assign NxtRdPtr[DEPTH_PTR-1:0] = RdPtr[DEPTH_PTR-1:0] + 1'b1;
assign NxtRspPtr[DEPTH_PTR-1:0] = RspPtr[DEPTH_PTR-1:0] + 1'b1;
// Don't increment the ptr for posted writes if 1)fifo error (it will increment only with response) 2) response done (this is the full case)
//assign RspPtr[DEPTH_PTR-1:0] = (dma_dbg_cmd_done_q | axi_slv_sent_q) ? (PrevRspPtr[DEPTH_PTR-1:0] + 1'b1) : PrevRspPtr[DEPTH_PTR-1:0];
//assign RspPtr[DEPTH_PTR-1:0] = (dma_dbg_cmd_done_q | axi_slv_sent_q |
// (fifo_valid[PrevRspPtr] & fifo_write[PrevRspPtr] & fifo_posted_write[PrevRspPtr] & ~(|fifo_error[PrevRspPtr]) & ~fifo_rsp_done[PrevRspPtr])) ? (PrevRspPtr[DEPTH_PTR-1:0] + 1'b1) : PrevRspPtr[DEPTH_PTR-1:0];
assign WrPtrEn = |fifo_cmd_en[DEPTH-1:0];
assign RdPtrEn = (dma_dccm_req | dma_iccm_req) | ((|fifo_error[RdPtr]) & ~fifo_done[RdPtr]);
//assign RdPtrEn = |(fifo_done_en[DEPTH-1:0] & ~fifo_done[DEPTH-1:0]);
assign RspPtrEn = (dma_dbg_cmd_done | (axi_slv_sent & dma_bus_clk_en));
//assign RspPtrEn = dma_bus_clk_en | dma_dbg_cmd_done_q;
rvdffs #(DEPTH_PTR) WrPtr_dff(.din(NxtWrPtr[DEPTH_PTR-1:0]), .dout(WrPtr[DEPTH_PTR-1:0]), .en(WrPtrEn), .clk(dma_free_clk), .*);
rvdffs #(DEPTH_PTR) RdPtr_dff(.din(NxtRdPtr[DEPTH_PTR-1:0]), .dout(RdPtr[DEPTH_PTR-1:0]), .en(RdPtrEn), .clk(dma_free_clk), .*);
rvdffs #(DEPTH_PTR) RspPtr_dff(.din(NxtRspPtr[DEPTH_PTR-1:0]), .dout(RspPtr[DEPTH_PTR-1:0]), .en(RspPtrEn), .clk(dma_free_clk), .*);
//rvdffs #(DEPTH_PTR) RspPtr_dff(.din(RspPtr[DEPTH_PTR-1:0]), .dout(PrevRspPtr[DEPTH_PTR-1:0]), .en(RspPtrEn), .clk(dma_free_clk), .*);
rvdff #(DEPTH_PTR) RdPtrQ1_dff(.din(RdPtr[DEPTH_PTR-1:0]), .dout(RdPtr_Q1[DEPTH_PTR-1:0]), .clk(dma_free_clk), .*);
rvdff #(DEPTH_PTR) RdPtrQ2_dff(.din(RdPtr_Q1[DEPTH_PTR-1:0]), .dout(RdPtr_Q2[DEPTH_PTR-1:0]), .clk(dma_free_clk), .*);
rvdff #(DEPTH_PTR) RdPtrQ3_dff(.din(RdPtr_Q2[DEPTH_PTR-1:0]), .dout(RdPtr_Q3[DEPTH_PTR-1:0]), .clk(dma_free_clk), .*);
// Miscellaneous signals
assign fifo_full = fifo_full_spec_bus;
always_comb begin
num_fifo_vld[3:0] = 4'b0;
for (int i=0; i<DEPTH; i++) begin
num_fifo_vld[3:0] += {3'b0,(fifo_valid_en[i] | fifo_valid[i])};
end
end
assign fifo_full_spec = ((num_fifo_vld[3:0] == DEPTH) & ~(|fifo_reset[DEPTH-1:0]));
assign dma_fifo_ready = ~(fifo_full | dbg_dma_bubble_bus | dec_tlu_stall_dma_bus);
// Error logic
assign dma_address_error = axi_mstr_valid & (~(dma_addr_in_dccm | dma_addr_in_iccm)); // request not for ICCM or DCCM
assign dma_alignment_error = axi_mstr_valid & ~dma_address_error &
(((axi_mstr_size[2:0] == 3'h1) & (axi_mstr_addr[0] | (axi_mstr_write & (axi_mstr_wstrb[axi_mstr_addr[2:0]+:2] != 2'b11)))) | // HW size but unaligned
((axi_mstr_size[2:0] == 3'h2) & ((|axi_mstr_addr[1:0]) | (axi_mstr_write & (axi_mstr_wstrb[axi_mstr_addr[2:0]+:4] != 4'hf)))) | // W size but unaligned
((axi_mstr_size[2:0] == 3'h3) & ((|axi_mstr_addr[2:0]) | (axi_mstr_write & (axi_mstr_wstrb[7:0] != 8'hff)))) | // DW size but unaligned
(dma_addr_in_iccm & ~((axi_mstr_size[1:0] == 2'b10) | (axi_mstr_size[1:0] == 2'b11))) | // ICCM access not word size
(dma_addr_in_dccm & axi_mstr_write & ~((axi_mstr_size[1:0] == 2'b10) | (axi_mstr_size[1:0] == 2'b11)))); // DCCM write not word size
//Dbg outputs
assign dma_dbg_ready = fifo_empty & dbg_dma_bubble;
assign dma_dbg_cmd_done = (fifo_valid[RspPtr] & fifo_dbg[RspPtr] & (fifo_write[RspPtr] | fifo_data_valid[RspPtr] | (|fifo_error[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_cmd_error_in = dbg_cmd_valid & (dbg_cmd_type[1:0] == 2'b10) &
((~(dma_addr_in_dccm | dma_addr_in_iccm | dma_addr_in_pic)) | (dbg_cmd_size[1:0] != 2'b10)); // Only word accesses allowed
//(dma_addr_in_iccm & ~((dbg_cmd_size[1:0] == 2'b10) | (dbg_cmd_size[1:0] == 2'b11))));
// Block the decode if fifo full
assign dma_dccm_stall_any = dma_mem_req & fifo_dccm_valid[RdPtr] & (dma_nack_count >= dma_nack_count_csr);
assign dma_iccm_stall_any = dma_mem_req & fifo_iccm_valid[RdPtr] & (dma_nack_count >= dma_nack_count_csr);
// Used to indicate ready to debug
assign fifo_empty = ~(|(fifo_valid_en[DEPTH-1:0] | fifo_valid[DEPTH-1:0]) | axi_mstr_valid | axi_slv_sent_q); // We want RspPtr to settle before accepting debug command
// Nack counter, stall the lsu pipe if 7 nacks
assign dma_nack_count_csr[2:0] = dec_tlu_dma_qos_prty[2:0];
assign dma_nack_count_d[2:0] = (dma_nack_count[2:0] >= dma_nack_count_csr[2:0]) ? ({3{~(dma_dccm_req | dma_iccm_req)}} & dma_nack_count[2:0]) :
(dma_mem_req & ~(dma_dccm_req | dma_iccm_req)) ? (dma_nack_count[2:0] + 1'b1) : 3'b0;
rvdffs #(3) nack_count_dff(.din(dma_nack_count_d[2:0]), .dout(dma_nack_count[2:0]), .en(dma_mem_req), .clk(dma_free_clk), .*);
// Core outputs
assign dma_mem_req = fifo_valid[RdPtr] & ~fifo_rpend[RdPtr] & ~fifo_done[RdPtr] & ~(|fifo_error[RdPtr]) & (~fifo_write[RdPtr] | fifo_data_valid[RdPtr]);
assign dma_dccm_req = dma_mem_req & fifo_dccm_valid[RdPtr] & dccm_ready;
assign dma_iccm_req = dma_mem_req & fifo_iccm_valid[RdPtr] & iccm_ready;
assign dma_mem_addr[31:0] = fifo_addr[RdPtr];
assign dma_mem_sz[2:0] = fifo_sz[RdPtr];
assign dma_mem_write = fifo_write[RdPtr];
assign dma_mem_wdata[63:0] = fifo_data[RdPtr];
// Address check dccm
rvrangecheck #(.CCM_SADR(`RV_DCCM_SADR),
.CCM_SIZE(`RV_DCCM_SIZE)) addr_dccm_rangecheck (
.addr(fifo_addr_in[31:0]),
.in_range(dma_addr_in_dccm),
.in_region(dma_addr_in_dccm_region_nc)
);
// Address check iccm
`ifdef RV_ICCM_ENABLE
rvrangecheck #(.CCM_SADR(`RV_ICCM_SADR),
.CCM_SIZE(`RV_ICCM_SIZE)) addr_iccm_rangecheck (
.addr(fifo_addr_in[31:0]),
.in_range(dma_addr_in_iccm),
.in_region(dma_addr_in_iccm_region_nc)
);
`else
assign dma_addr_in_iccm = '0;
assign dma_addr_in_iccm_region_nc = '0;
`endif
// PIC memory address check
rvrangecheck #(.CCM_SADR(`RV_PIC_BASE_ADDR),
.CCM_SIZE(`RV_PIC_SIZE)) addr_pic_rangecheck (
.addr(fifo_addr_in[31:0]),
.in_range(dma_addr_in_pic),
.in_region(dma_addr_in_pic_region_nc)
);
// Inputs
rvdff #(1) ahbs_bus_clken_ff (.din(dma_bus_clk_en), .dout(dma_bus_clk_en_q), .clk(free_clk), .*);
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 #(1) dec_tlu_stall_dma_ff (.din(dec_tlu_stall_dma), .dout(dec_tlu_stall_dma_bus), .clk(dma_bus_clk), .*);
rvdff #(1) dma_dbg_cmd_doneff (.din(dma_dbg_cmd_done), .dout(dma_dbg_cmd_done_q), .clk(free_clk), .*);
// Clock Gating logic
assign dma_buffer_c1_clken = (axi_mstr_valid & dma_bus_clk_en) | dbg_cmd_valid | dec_tlu_stall_dma | clk_override;
assign dma_free_clken = (axi_mstr_valid | axi_mstr_valid_q | axi_slv_valid | axi_slv_sent_q | dbg_cmd_valid | dma_dbg_cmd_done | dma_dbg_cmd_done_q | (|fifo_valid[DEPTH-1:0]) | wrbuf_vld | rdbuf_vld | dec_tlu_stall_dma | clk_override);
rvclkhdr dma_buffer_c1cgc ( .en(dma_buffer_c1_clken), .l1clk(dma_buffer_c1_clk), .* );
rvclkhdr dma_free_cgc (.en(dma_free_clken), .l1clk(dma_free_clk), .*);
rvclkhdr dma_bus_cgc (.en(dma_bus_clk_en), .l1clk(dma_bus_clk), .*);
// Write channel buffer
assign wrbuf_en = dma_axi_awvalid & dma_axi_awready;
assign wrbuf_data_en = dma_axi_wvalid & dma_axi_wready;
assign wrbuf_cmd_sent = axi_mstr_valid & axi_mstr_write;
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(1)) wrbuf_postedff(.din(1'b0), .dout(wrbuf_posted), .en(wrbuf_en), .clk(dma_bus_clk), .*);
rvdffs #(.WIDTH(DMA_BUS_TAG)) wrbuf_tagff(.din(dma_axi_awid[DMA_BUS_TAG-1:0]), .dout(wrbuf_tag[DMA_BUS_TAG-1:0]), .en(wrbuf_en), .clk(dma_bus_clk), .*);
rvdffs #(.WIDTH(3)) wrbuf_sizeff(.din(dma_axi_awsize[2:0]), .dout(wrbuf_size[2:0]), .en(wrbuf_en), .clk(dma_bus_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), .*);
// Read channel buffer
assign rdbuf_en = dma_axi_arvalid & dma_axi_arready;
assign rdbuf_cmd_sent = axi_mstr_valid & ~axi_mstr_write & dma_fifo_ready;
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(DMA_BUS_TAG)) rdbuf_tagff(.din(dma_axi_arid[DMA_BUS_TAG-1:0]), .dout(rdbuf_tag[DMA_BUS_TAG-1:0]), .en(rdbuf_en), .clk(dma_bus_clk), .*);
rvdffs #(.WIDTH(3)) rdbuf_sizeff(.din(dma_axi_arsize[2:0]), .dout(rdbuf_size[2:0]), .en(rdbuf_en), .clk(dma_bus_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);
assign dma_axi_wready = ~(wrbuf_data_vld & ~wrbuf_cmd_sent);
assign dma_axi_arready = ~(rdbuf_vld & ~rdbuf_cmd_sent);
//Generate a single request from read/write channel
assign axi_mstr_valid = ((wrbuf_vld & wrbuf_data_vld) | rdbuf_vld) & dma_fifo_ready;
assign axi_mstr_tag[DMA_BUS_TAG-1:0] = axi_mstr_sel ? wrbuf_tag[DMA_BUS_TAG-1:0] : rdbuf_tag[DMA_BUS_TAG-1:0];
assign axi_mstr_write = axi_mstr_sel;
assign axi_mstr_posted_write = axi_mstr_sel & wrbuf_posted;
assign axi_mstr_addr[31:0] = axi_mstr_sel ? wrbuf_addr[31:0] : rdbuf_addr[31:0];
assign axi_mstr_size[2:0] = axi_mstr_sel ? wrbuf_size[2:0] : rdbuf_size[2:0];
assign axi_mstr_wdata[63:0] = wrbuf_data[63:0];
assign axi_mstr_wstrb[7:0] = wrbuf_byteen[7:0];
// Sel=1 -> write has higher priority
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 = axi_mstr_valid;
rvdffs #(.WIDTH(1)) mstr_prtyff(.din(axi_mstr_prty_in), .dout(axi_mstr_priority), .en(axi_mstr_prty_en), .clk(dma_bus_clk), .*);
rvdff #(.WIDTH(1)) axi_mstr_validff (.din(axi_mstr_valid), .dout(axi_mstr_valid_q), .clk(dma_bus_clk), .*);
rvdff #(.WIDTH(1)) axi_slv_sentff (.din(axi_slv_sent), .dout(axi_slv_sent_q), .clk(dma_bus_clk), .*);
//assign axi_slv_valid = fifo_valid[RspPtr] & ~fifo_rsp_done[RspPtr] & ~fifo_dbg[RspPtr] &
// ((fifo_write[RspPtr] & fifo_done_bus[RspPtr]) | (~fifo_write[RspPtr] & fifo_data_bus_valid[RspPtr]) | fifo_error_bus[RspPtr]);
assign axi_slv_valid = fifo_valid[RspPtr] & ~fifo_dbg[RspPtr] & fifo_done_bus[RspPtr];
assign axi_slv_tag[DMA_BUS_TAG-1:0] = fifo_tag[RspPtr];
//assign axi_slv_rdata[63:0] = (|fifo_error[RspPtr]) ? {32'b0,fifo_addr[RspPtr]} : fifo_data[RspPtr];
assign axi_slv_rdata[63:0] = fifo_data[RspPtr];
assign axi_slv_write = fifo_write[RspPtr];
assign axi_slv_posted_write = axi_slv_write & fifo_posted_write[RspPtr];
assign axi_slv_error[1:0] = fifo_error[RspPtr][0] ? 2'b10 : (fifo_error[RspPtr][1] ? 2'b11 : 2'b0);
// AXI response channel signals
assign dma_axi_bvalid = axi_slv_valid & axi_slv_write;
assign dma_axi_bresp[1:0] = axi_slv_error[1:0];
assign dma_axi_bid[DMA_BUS_TAG-1:0] = axi_slv_tag[DMA_BUS_TAG-1:0];
assign dma_axi_rvalid = axi_slv_valid & ~axi_slv_write;
assign dma_axi_rresp[1:0] = axi_slv_error;
assign dma_axi_rid[DMA_BUS_TAG-1:0] = axi_slv_tag[DMA_BUS_TAG-1:0];
assign dma_axi_rdata[63:0] = axi_slv_rdata[63:0];
assign dma_axi_rlast = 1'b1;
assign axi_slv_sent = (dma_axi_bvalid & dma_axi_bready) | (dma_axi_rvalid & dma_axi_rready);
assign dma_slv_algn_err = fifo_error[RspPtr][1];
`ifdef ASSERT_ON
//assert_nack_count: assert #0 (dma_nack_count[2:0] < 3'h4);
for (genvar i=0; i<DEPTH; i++) begin
//assert_picm_rspdone_and_novalid: assert #0 (~fifo_rsp_done[i] | fifo_valid[i]);
assert_done_and_novalid: assert #0 (~fifo_done[i] | fifo_valid[i]);
end
// Assertion to check AXI write address is aligned to size
property dma_axi_write_trxn_aligned;
@(posedge dma_bus_clk) dma_axi_awvalid |-> ((dma_axi_awsize[2:0] == 3'h0) |
((dma_axi_awsize[2:0] == 3'h1) & (dma_axi_awaddr[0] == 1'b0)) |
((dma_axi_awsize[2:0] == 3'h2) & (dma_axi_awaddr[1:0] == 2'b0)) |
((dma_axi_awsize[2:0] == 3'h3) & (dma_axi_awaddr[2:0] == 3'b0)));
endproperty
// assert_dma_write_trxn_aligned: assert property (dma_axi_write_trxn_aligned) else
// $display("Assertion dma_axi_write_trxn_aligned failed: dma_axi_awvalid=1'b%b, dma_axi_awsize=3'h%h, dma_axi_awaddr=32'h%h",dma_axi_awvalid, dma_axi_awsize[2:0], dma_axi_awaddr[31:0]);
// Assertion to check AXI read address is aligned to size
property dma_axi_read_trxn_aligned;
@(posedge dma_bus_clk) dma_axi_arvalid |-> ((dma_axi_arsize[2:0] == 3'h0) |
((dma_axi_arsize[2:0] == 3'h1) & (dma_axi_araddr[0] == 1'b0)) |
((dma_axi_arsize[2:0] == 3'h2) & (dma_axi_araddr[1:0] == 2'b0)) |
((dma_axi_arsize[2:0] == 3'h3) & (dma_axi_araddr[2:0] == 3'b0)));
endproperty
// assert_dma_read_trxn_aligned: assert property (dma_axi_read_trxn_aligned) else
// $display("Assertion dma_axi_read_trxn_aligned failed: dma_axi_arvalid=1'b%b, dma_axi_arsize=3'h%h, dma_axi_araddr=32'h%h",dma_axi_arvalid, dma_axi_arsize[2:0], dma_axi_araddr[31:0]);
// Assertion to check write size is 8 byte or less
property dma_axi_awsize_check;
@(posedge dma_bus_clk) disable iff(~rst_l) (dma_axi_awvalid & dma_axi_awready) |-> (dma_axi_awsize[2] == 1'b0);
endproperty
assert_dma_axi_awsize_check: assert property (dma_axi_awsize_check) else
$display("DMA AXI awsize is illegal. Size greater than 8B not supported");
// Assertion to check there are no burst commands
property dma_axi_awlen_check;
@(posedge dma_bus_clk) disable iff(~rst_l) (dma_axi_awvalid & dma_axi_awready) |-> (dma_axi_awlen[7:0] == 8'b0);
endproperty
assert_dma_axi_awlen_check: assert property (dma_axi_awlen_check) else
$display("DMA AXI awlen is illegal. Length greater than 0 not supported");
// Assertion to check write size is 8 byte or less
property dma_axi_arsize_check;
@(posedge dma_bus_clk) disable iff(~rst_l) (dma_axi_arvalid & dma_axi_arready) |-> (dma_axi_arsize[2] == 1'b0);
endproperty
assert_dma_axi_arsize_check: assert property (dma_axi_arsize_check) else
$display("DMA AXI arsize is illegal, Size bigger than 8B not supported");
// Assertion to check there are no burst commands
property dma_axi_arlen_check;
@(posedge dma_bus_clk) disable iff(~rst_l) (dma_axi_arvalid & dma_axi_arready) |-> (dma_axi_arlen[7:0] == 8'b0);
endproperty
assert_dma_axi_arlen_check: assert property (dma_axi_arlen_check) else
$display("DMA AXI arlen greater than 0 not supported.");
// Assertion to check cmd valid stays stable during entire bus clock
property dma_axi_awvalid_stable;
@(posedge clk) disable iff(~rst_l) (dma_axi_awvalid != $past(dma_axi_awvalid)) |-> $past(dma_bus_clk_en);
endproperty
assert_dma_axi_awvalid_stable: assert property (dma_axi_awvalid_stable) else
$display("DMA AXI awvalid changed in middle of bus clock");
// Assertion to check cmd ready stays stable during entire bus clock
property dma_axi_awready_stable;
@(posedge clk) disable iff(~rst_l) (dma_axi_awready != $past(dma_axi_awready)) |-> $past(dma_bus_clk_en);
endproperty
assert_dma_axi_awready_stable: assert property (dma_axi_awready_stable) else
$display("DMA AXI awready changed in middle of bus clock");
// Assertion to check cmd tag stays stable during entire bus clock
property dma_axi_awid_stable;
@(posedge clk) disable iff(~rst_l) (dma_axi_awvalid & (dma_axi_awid[DMA_BUS_TAG-1:0] != $past(dma_axi_awid[DMA_BUS_TAG-1:0]))) |-> $past(dma_bus_clk_en);
endproperty
assert_dma_axi_awid_stable: assert property (dma_axi_awid_stable) else
$display("DMA AXI awid changed in middle of bus clock");
// Assertion to check cmd addr stays stable during entire bus clock
property dma_axi_awaddr_stable;
@(posedge clk) disable iff(~rst_l) (dma_axi_awvalid & (dma_axi_awaddr[31:0] != $past(dma_axi_awaddr[31:0]))) |-> $past(dma_bus_clk_en);
endproperty
assert_dma_axi_awaddr_stable: assert property (dma_axi_awaddr_stable) else
$display("DMA AXI awaddr changed in middle of bus clock");
// Assertion to check cmd length stays stable during entire bus clock
property dma_axi_awsize_stable;
@(posedge clk) disable iff(~rst_l) (dma_axi_awvalid & (dma_axi_awsize[2:0] != $past(dma_axi_awsize[2:0]))) |-> $past(dma_bus_clk_en);
endproperty
assert_dma_axi_awsize_stable: assert property (dma_axi_awsize_stable) else
$display("DMA AXI awsize changed in middle of bus clock");
// Assertion to check cmd valid stays stable during entire bus clock
property dma_axi_wvalid_stable;
@(posedge clk) disable iff(~rst_l) (dma_axi_wvalid != $past(dma_axi_wvalid)) |-> $past(dma_bus_clk_en);
endproperty
assert_dma_axi_wvalid_stable: assert property (dma_axi_wvalid_stable) else
$display("DMA AXI wvalid changed in middle of bus clock");
// Assertion to check cmd ready stays stable during entire bus clock
property dma_axi_wready_stable;
@(posedge clk) disable iff(~rst_l) (dma_axi_wready != $past(dma_axi_wready)) |-> $past(dma_bus_clk_en);
endproperty
assert_dma_axi_wready_stable: assert property (dma_axi_wready_stable) else
$display("DMA AXI wready changed in middle of bus clock");
// Assertion to check cmd wbe stays stable during entire bus clock
property dma_axi_wstrb_stable;
@(posedge clk) disable iff(~rst_l) (dma_axi_wvalid & (dma_axi_wstrb[7:0] != $past(dma_axi_wstrb[7:0]))) |-> $past(dma_bus_clk_en);
endproperty
assert_dma_axi_wstrb_stable: assert property (dma_axi_wstrb_stable) else
$display("DMA AXI wstrb changed in middle of bus clock");
// Assertion to check cmd wdata stays stable during entire bus clock
property dma_axi_wdata_stable;
@(posedge clk) disable iff(~rst_l) (dma_axi_wvalid & (dma_axi_wdata[63:0] != $past(dma_axi_wdata[63:0]))) |-> $past(dma_bus_clk_en);
endproperty
assert_dma_axi_wdata_stable: assert property (dma_axi_wdata_stable) else
$display("DMA AXI wdata changed in middle of bus clock");
// Assertion to check cmd valid stays stable during entire bus clock
property dma_axi_arvalid_stable;
@(posedge clk) disable iff(~rst_l) (dma_axi_arvalid != $past(dma_axi_arvalid)) |-> $past(dma_bus_clk_en);
endproperty
assert_dma_axi_arvalid_stable: assert property (dma_axi_arvalid_stable) else
$display("DMA AXI arvalid changed in middle of bus clock");
// Assertion to check cmd ready stays stable during entire bus clock
property dma_axi_arready_stable;
@(posedge clk) disable iff(~rst_l) (dma_axi_arready != $past(dma_axi_arready)) |-> $past(dma_bus_clk_en);
endproperty
assert_dma_axi_arready_stable: assert property (dma_axi_arready_stable) else
$display("DMA AXI arready changed in middle of bus clock");
// Assertion to check cmd tag stays stable during entire bus clock
property dma_axi_arid_stable;
@(posedge clk) disable iff(~rst_l) (dma_axi_arvalid & (dma_axi_arid[DMA_BUS_TAG-1:0] != $past(dma_axi_arid[DMA_BUS_TAG-1:0]))) |-> $past(dma_bus_clk_en);
endproperty
assert_dma_axi_arid_stable: assert property (dma_axi_arid_stable) else
$display("DMA AXI arid changed in middle of bus clock");
// Assertion to check cmd addr stays stable during entire bus clock
property dma_axi_araddr_stable;
@(posedge clk) disable iff(~rst_l) (dma_axi_arvalid & (dma_axi_araddr[31:0] != $past(dma_axi_araddr[31:0]))) |-> $past(dma_bus_clk_en);
endproperty
assert_dma_axi_araddr_stable: assert property (dma_axi_araddr_stable) else
$display("DMA AXI araddr changed in middle of bus clock");
// Assertion to check cmd length stays stable during entire bus clock
property dma_axi_arsize_stable;
@(posedge clk) disable iff(~rst_l) (dma_axi_arvalid & (dma_axi_arsize[2:0] != $past(dma_axi_arsize[2:0]))) |-> $past(dma_bus_clk_en);
endproperty
assert_dma_axi_arsize_stable: assert property (dma_axi_arsize_stable) else
$display("DMA AXI arsize changed in middle of bus clock");
//Assertion to check write rsp valid stays stable during entire bus clock
property dma_axi_bvalid_stable;
@(posedge clk) disable iff(~rst_l) (dma_axi_bvalid != $past(dma_axi_bvalid)) |-> $past(dma_bus_clk_en);
endproperty
assert_dma_axi_bvalid_stable: assert property (dma_axi_bvalid_stable) else
$display("DMA AXI bvalid changed in middle of bus clock");
// //Assertion to check write rsp ready stays stable during entire bus clock
// property dma_axi_bready_stable;
// @(posedge clk) (dma_axi_bready != $past(dma_axi_bready)) |-> $past(dma_bus_clk_en);
// endproperty
// assert_dma_axi_bready_stable: assert property (dma_axi_bready_stable) else
// $display("DMA AXI bready changed in middle of bus clock");
//Assertion to check write rsp stays stable during entire bus clock
property dma_axi_bresp_stable;
@(posedge clk) disable iff(~rst_l) (dma_axi_bvalid & (dma_axi_bresp[1:0] != $past(dma_axi_bresp[1:0]))) |-> $past(dma_bus_clk_en);
endproperty
assert_dma_axi_bresp_stable: assert property (dma_axi_bresp_stable) else
$display("DMA AXI bvalid changed in middle of bus clock");
// Assertion to check write rsp tag stays stable during entire bus clock
property dma_axi_bid_stable;
@(posedge clk) disable iff(~rst_l) (dma_axi_bvalid & (dma_axi_bid[DMA_BUS_TAG-1:0] != $past(dma_axi_bid[DMA_BUS_TAG-1:0]))) |-> $past(dma_bus_clk_en);
endproperty
assert_dma_axi_bid_stable: assert property (dma_axi_bid_stable) else
$display("DMA AXI bid changed in middle of bus clock");
//Assertion to check write rsp valid stays stable during entire bus clock
property dma_axi_rvalid_stable;
@(posedge clk) disable iff(~rst_l) (dma_axi_rvalid != $past(dma_axi_rvalid)) |-> $past(dma_bus_clk_en);
endproperty
assert_dma_axi_rvalid_stable: assert property (dma_axi_rvalid_stable) else
$display("DMA AXI bvalid changed in middle of bus clock");
// //Assertion to check write rsp ready stays stable during entire bus clock
// property dma_axi_rready_stable;
// @(posedge clk) (dma_axi_rready != $past(dma_axi_rready)) |-> $past(dma_bus_clk_en);
// endproperty
// assert_dma_axi_rready_stable: assert property (dma_axi_rready_stable) else
// $display("DMA AXI bready changed in middle of bus clock");
//Assertion to check write rsp stays stable during entire bus clock
property dma_axi_rresp_stable;
@(posedge clk) disable iff(~rst_l) (dma_axi_rvalid & (dma_axi_rresp[1:0] != $past(dma_axi_rresp[1:0]))) |-> $past(dma_bus_clk_en);
endproperty
assert_dma_axi_rresp_stable: assert property (dma_axi_rresp_stable) else
$display("DMA AXI bvalid changed in middle of bus clock");
// Assertion to check write rsp tag stays stable during entire bus clock
property dma_axi_rid_stable;
@(posedge clk) disable iff(~rst_l) (dma_axi_rvalid & (dma_axi_rid[DMA_BUS_TAG-1:0] != $past(dma_axi_rid[DMA_BUS_TAG-1:0]))) |-> $past(dma_bus_clk_en);
endproperty
assert_dma_axi_rid_stable: assert property (dma_axi_rid_stable) else
$display("DMA AXI bid changed in middle of bus clock");
`endif
endmodule // dma_ctrl

View File

@ -0,0 +1,65 @@
// 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.
//------------------------------------------------------------------------------------
// This module Synchronizes the signals between JTAG (TCK) and
// processor (clk)
//
//-------------------------------------------------------------------------------------
module dmi_jtag_to_core_sync (
// JTAG signals
input rd_en, // 1 bit Read Enable
input wr_en, // 1 bit Write enable
// Processor Signals
input rst_n, // Core clock
input clk, // Core reset
output reg_en, // 1 bit Write interface bit to Processor
output reg_wr_en // 1 bit Write enable to Processor
);
wire c_rd_en;
wire c_wr_en;
//Assign statements
assign reg_en = c_wr_en | c_rd_en;
assign reg_wr_en = c_wr_en;
reg [2:0] rden, wren;
// synchronizers
always @ ( posedge clk or negedge rst_n) begin
if(!rst_n) begin
rden <= '0;
wren <= '0;
end
else begin
rden <= {rden[1:0], rd_en};
wren <= {wren[1:0], wr_en};
end
end
assign c_rd_en = rden[1] & ~rden[2];
assign c_wr_en = wren[1] & ~wren[2];
endmodule

91
design/dmi/dmi_wrapper.v Normal file
View File

@ -0,0 +1,91 @@
// 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.
//------------------------------------------------------------------------------------
//
// Copyright Western Digital, 2019
// Owner : Anusha Narayanamoorthy
// Description:
// Wrapper module for JTAG_TAP and DMI synchronizer
//
//-------------------------------------------------------------------------------------
module dmi_wrapper(
input scan_mode, // scan mode
// JTAG signals
input trst_n, // JTAG reset
input tck, // JTAG clock
input tms, // Test mode select
input tdi, // Test Data Input
output tdo, // Test Data Output
output tdoEnable, // Test Data Output enable
// Processor Signals
input core_rst_n, // Core reset
input core_clk, // Core clock
input [31:1] jtag_id, // JTAG ID
input [31:0] rd_data, // 32 bit Read data from Processor
output [31:0] reg_wr_data, // 32 bit Write data to Processor
output [6:0] reg_wr_addr, // 7 bit reg address to Processor
output reg_en, // 1 bit Read enable to Processor
output reg_wr_en, // 1 bit Write enable to Processor
output dmi_hard_reset
);
//Wire Declaration
wire rd_en;
wire wr_en;
wire dmireset;
//jtag_tap instantiation
rvjtag_tap i_jtag_tap(
.trst(trst_n), // dedicated JTAG TRST (active low) pad signal or asynchronous active low power on reset
.tck(tck), // dedicated JTAG TCK pad signal
.tms(tms), // dedicated JTAG TMS pad signal
.tdi(tdi), // dedicated JTAG TDI pad signal
.tdo(tdo), // dedicated JTAG TDO pad signal
.tdoEnable(tdoEnable), // enable for TDO pad
.wr_data(reg_wr_data), // 32 bit Write data
.wr_addr(reg_wr_addr), // 7 bit Write address
.rd_en(rd_en), // 1 bit read enable
.wr_en(wr_en), // 1 bit Write enable
.rd_data(rd_data), // 32 bit Read data
.rd_status(2'b0),
.idle(3'h0), // no need to wait to sample data
.dmi_stat(2'b0), // no need to wait or error possible
.version(4'h1), // debug spec 0.13 compliant
.jtag_id(jtag_id),
.dmi_hard_reset(dmi_hard_reset),
.dmi_reset(dmireset)
);
// dmi_jtag_to_core_sync instantiation
dmi_jtag_to_core_sync i_dmi_jtag_to_core_sync(
.wr_en(wr_en), // 1 bit Write enable
.rd_en(rd_en), // 1 bit Read enable
.rst_n(core_rst_n),
.clk(core_clk),
.reg_en(reg_en), // 1 bit Write interface bit
.reg_wr_en(reg_wr_en) // 1 bit Write enable
);
endmodule

223
design/dmi/rvjtag_tap.sv Normal file
View File

@ -0,0 +1,223 @@
// 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
module rvjtag_tap #(
parameter AWIDTH = 7
)
(
input trst,
input tck,
input tms,
input tdi,
output reg tdo,
output tdoEnable,
output [31:0] wr_data,
output [AWIDTH-1:0] wr_addr,
output wr_en,
output rd_en,
input [31:0] rd_data,
input [1:0] rd_status,
output reg dmi_reset,
output reg dmi_hard_reset,
input [2:0] idle,
input [1:0] dmi_stat,
/*
-- revisionCode : 4'h0;
-- manufacturersIdCode : 11'h45;
-- deviceIdCode : 16'h0001;
-- order MSB .. LSB -> [4 bit version or revision] [16 bit part number] [11 bit manufacturer id] [value of 1'b1 in LSB]
*/
input [31:1] jtag_id,
input [3:0] version
);
localparam USER_DR_LENGTH = AWIDTH + 34;
reg [USER_DR_LENGTH-1:0] sr, nsr, dr;
///////////////////////////////////////////////////////
// Tap controller
///////////////////////////////////////////////////////
logic[3:0] state, nstate;
logic [4:0] ir;
wire jtag_reset;
wire shift_dr;
wire pause_dr;
wire update_dr;
wire capture_dr;
wire shift_ir;
wire pause_ir ;
wire update_ir ;
wire capture_ir;
wire[1:0] dr_en;
wire devid_sel;
wire [5:0] abits;
assign abits = AWIDTH[5:0];
localparam TEST_LOGIC_RESET_STATE = 0;
localparam RUN_TEST_IDLE_STATE = 1;
localparam SELECT_DR_SCAN_STATE = 2;
localparam CAPTURE_DR_STATE = 3;
localparam SHIFT_DR_STATE = 4;
localparam EXIT1_DR_STATE = 5;
localparam PAUSE_DR_STATE = 6;
localparam EXIT2_DR_STATE = 7;
localparam UPDATE_DR_STATE = 8;
localparam SELECT_IR_SCAN_STATE = 9;
localparam CAPTURE_IR_STATE = 10;
localparam SHIFT_IR_STATE = 11;
localparam EXIT1_IR_STATE = 12;
localparam PAUSE_IR_STATE = 13;
localparam EXIT2_IR_STATE = 14;
localparam UPDATE_IR_STATE = 15;
always_comb begin
nstate = state;
case(state)
TEST_LOGIC_RESET_STATE: nstate = tms ? TEST_LOGIC_RESET_STATE : RUN_TEST_IDLE_STATE;
RUN_TEST_IDLE_STATE: nstate = tms ? SELECT_DR_SCAN_STATE : RUN_TEST_IDLE_STATE;
SELECT_DR_SCAN_STATE: nstate = tms ? SELECT_IR_SCAN_STATE : CAPTURE_DR_STATE;
CAPTURE_DR_STATE: nstate = tms ? EXIT1_DR_STATE : SHIFT_DR_STATE;
SHIFT_DR_STATE: nstate = tms ? EXIT1_DR_STATE : SHIFT_DR_STATE;
EXIT1_DR_STATE: nstate = tms ? UPDATE_DR_STATE : PAUSE_DR_STATE;
PAUSE_DR_STATE: nstate = tms ? EXIT2_DR_STATE : PAUSE_DR_STATE;
EXIT2_DR_STATE: nstate = tms ? UPDATE_DR_STATE : SHIFT_DR_STATE;
UPDATE_DR_STATE: nstate = tms ? SELECT_DR_SCAN_STATE : RUN_TEST_IDLE_STATE;
SELECT_IR_SCAN_STATE: nstate = tms ? TEST_LOGIC_RESET_STATE : CAPTURE_IR_STATE;
CAPTURE_IR_STATE: nstate = tms ? EXIT1_IR_STATE : SHIFT_IR_STATE;
SHIFT_IR_STATE: nstate = tms ? EXIT1_IR_STATE : SHIFT_IR_STATE;
EXIT1_IR_STATE: nstate = tms ? UPDATE_IR_STATE : PAUSE_IR_STATE;
PAUSE_IR_STATE: nstate = tms ? EXIT2_IR_STATE : PAUSE_IR_STATE;
EXIT2_IR_STATE: nstate = tms ? UPDATE_IR_STATE : SHIFT_IR_STATE;
UPDATE_IR_STATE: nstate = tms ? SELECT_DR_SCAN_STATE : RUN_TEST_IDLE_STATE;
default: nstate = TEST_LOGIC_RESET_STATE;
endcase
end
always @ (posedge tck or negedge trst) begin
if(!trst) state <= TEST_LOGIC_RESET_STATE;
else state <= nstate;
end
assign jtag_reset = state == TEST_LOGIC_RESET_STATE;
assign shift_dr = state == SHIFT_DR_STATE;
assign pause_dr = state == PAUSE_DR_STATE;
assign update_dr = state == UPDATE_DR_STATE;
assign capture_dr = state == CAPTURE_DR_STATE;
assign shift_ir = state == SHIFT_IR_STATE;
assign pause_ir = state == PAUSE_IR_STATE;
assign update_ir = state == UPDATE_IR_STATE;
assign capture_ir = state == CAPTURE_IR_STATE;
assign tdoEnable = shift_dr | shift_ir;
///////////////////////////////////////////////////////
// IR register
///////////////////////////////////////////////////////
always @ (negedge tck or negedge trst) begin
if (!trst) ir <= 5'b1;
else begin
if (jtag_reset) ir <= 5'b1;
else if (update_ir) ir <= (sr[4:0] == '0) ? 5'h1f :sr[4:0];
end
end
assign devid_sel = ir == 5'b00001;
assign dr_en[0] = ir == 5'b10000;
assign dr_en[1] = ir == 5'b10001;
///////////////////////////////////////////////////////
// Shift register
///////////////////////////////////////////////////////
always @ (posedge tck or negedge trst) begin
if(!trst)begin
sr <= '0;
end
else begin
sr <= nsr;
end
end
// SR next value
always_comb begin
nsr = sr;
case(1)
shift_dr: begin
case(1)
dr_en[1]: nsr = {tdi, sr[USER_DR_LENGTH-1:1]};
dr_en[0],
devid_sel: nsr = {{USER_DR_LENGTH-32{1'b0}},tdi, sr[31:1]};
default: nsr = {{USER_DR_LENGTH-1{1'b0}},tdi}; // bypass
endcase
end
capture_dr: begin
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};
devid_sel: nsr = {{USER_DR_LENGTH-32{1'b0}}, jtag_id, 1'b1};
endcase
end
shift_ir: nsr = {{USER_DR_LENGTH-5{1'b0}},tdi, sr[4:1]};
capture_ir: nsr = {{USER_DR_LENGTH-1{1'b0}},1'b1};
endcase
end
// TDO retiming
always @ (negedge tck ) tdo <= sr[0];
// DMI CS register
always @ (posedge tck or negedge trst) begin
if(!trst) begin
dmi_hard_reset <= 1'b0;
dmi_reset <= 1'b0;
end
else if (update_dr & dr_en[0]) begin
dmi_hard_reset <= sr[17];
dmi_reset <= sr[16];
end
else begin
dmi_hard_reset <= 1'b0;
dmi_reset <= 1'b0;
end
end
// DR register
always @ (posedge tck or negedge trst) begin
if(!trst)
dr <= '0;
else begin
if (update_dr & dr_en[1])
dr <= sr;
else
dr <= {dr[USER_DR_LENGTH-1:2],2'b0};
end
end
assign {wr_addr, wr_data, wr_en, rd_en} = dr;
endmodule

839
design/exu/exu.sv Normal file
View File

@ -0,0 +1,839 @@
// 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.
module exu
import swerv_types::*;
(
input logic clk, // Top level clock
input logic active_clk, // Level 1 active clock
input logic clk_override, // Override multiply clock enables
input logic rst_l, // Reset
input logic scan_mode, // Scan control
input logic lsu_freeze_dc3, // Freeze pipe from D to DC3
input logic dec_tlu_fast_div_disable, // Disable divide small number optimization
input logic [4:2] dec_i0_data_en, // Slot I0 clock enable {e1, e2, e3 }, one cycle pulse
input logic [4:1] dec_i0_ctl_en, // Slot I0 clock enable {e1, e2, e3, e4}, two cycle pulse
input logic [4:2] dec_i1_data_en, // Slot I1 clock enable {e1, e2, e3 }, one cycle pulse
input logic [4:1] dec_i1_ctl_en, // Slot I1 clock enable {e1, e2, e3, e4}, two cycle pulse
input logic dec_debug_wdata_rs1_d, // Debug select to primary I0 RS1
input logic [31:0] dbg_cmd_wrdata, // Debug data to primary I0 RS1
input logic [31:0] lsu_result_dc3, // Load result
input predict_pkt_t i0_predict_p_d, // DEC branch predict packet
input predict_pkt_t i1_predict_p_d, // DEC branch predict packet
input logic dec_i0_rs1_bypass_en_e2, // DEC bypass bus select for E2 stage
input logic dec_i0_rs2_bypass_en_e2, // DEC bypass bus select for E2 stage
input logic dec_i1_rs1_bypass_en_e2, // DEC bypass bus select for E2 stage
input logic dec_i1_rs2_bypass_en_e2, // DEC bypass bus select for E2 stage
input logic [31:0] i0_rs1_bypass_data_e2, // DEC bypass bus
input logic [31:0] i0_rs2_bypass_data_e2, // DEC bypass bus
input logic [31:0] i1_rs1_bypass_data_e2, // DEC bypass bus
input logic [31:0] i1_rs2_bypass_data_e2, // DEC bypass bus
input logic dec_i0_rs1_bypass_en_e3, // DEC bypass bus select for E3 stage
input logic dec_i0_rs2_bypass_en_e3, // DEC bypass bus select for E3 stage
input logic dec_i1_rs1_bypass_en_e3, // DEC bypass bus select for E3 stage
input logic dec_i1_rs2_bypass_en_e3, // DEC bypass bus select for E3 stage
input logic [31:0] i0_rs1_bypass_data_e3, // DEC bypass bus
input logic [31:0] i0_rs2_bypass_data_e3, // DEC bypass bus
input logic [31:0] i1_rs1_bypass_data_e3, // DEC bypass bus
input logic [31:0] i1_rs2_bypass_data_e3, // DEC bypass bus
input logic dec_i0_sec_decode_e3, // Secondary ALU valid
input logic dec_i1_sec_decode_e3, // Secondary ALU valid
input logic [31:1] dec_i0_pc_e3, // Secondary ALU PC
input logic [31:1] dec_i1_pc_e3, // Secondary ALU PC
input logic [31:1] pred_correct_npc_e2, // DEC NPC for correctly predicted branch
input logic dec_i1_valid_e1, // I1 valid E1
input logic dec_i0_mul_d, // Select for Multiply GPR value
input logic dec_i1_mul_d, // Select for Multiply GPR value
input logic dec_i0_div_d, // Select for Divide GPR value
input logic dec_i1_div_d, // Select for Divide GPR value
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] gpr_i1_rs1_d, // DEC data gpr
input logic [31:0] gpr_i1_rs2_d, // DEC data gpr
input logic [31:0] dec_i1_immed_d, // DEC data immediate
input logic [31:0] i0_rs1_bypass_data_d, // DEC bypass data
input logic [31:0] i0_rs2_bypass_data_d, // DEC bypass data
input logic [31:0] i1_rs1_bypass_data_d, // DEC bypass data
input logic [31:0] i1_rs2_bypass_data_d, // DEC bypass data
input logic [12:1] dec_i0_br_immed_d, // Branch immediate
input logic [12:1] dec_i1_br_immed_d, // Branch immediate
input alu_pkt_t i0_ap, // DEC alu {valid,predecodes}
input alu_pkt_t i1_ap, // DEC alu {valid,predecodes}
input logic dec_i0_alu_decode_d, // Valid to Primary ALU
input logic dec_i1_alu_decode_d, // Valid to Primary ALU
input logic dec_i0_select_pc_d, // PC select to RS1
input logic dec_i1_select_pc_d, // PC select to RS1
input logic [31:1] dec_i0_pc_d, dec_i1_pc_d, // Instruction PC
input logic dec_i0_rs1_bypass_en_d, // DEC bypass select
input logic dec_i0_rs2_bypass_en_d, // DEC bypass select
input logic dec_i1_rs1_bypass_en_d, // DEC bypass select
input logic dec_i1_rs2_bypass_en_d, // DEC bypass select
input logic dec_tlu_flush_lower_wb, // Flush divide and secondary ALUs
input logic [31:1] dec_tlu_flush_path_wb, // Redirect target
input logic dec_tlu_i0_valid_e4, // Valid for GHR
input logic dec_tlu_i1_valid_e4, // Valid for GHR
output logic [31:0] exu_i0_result_e1, // Primary ALU result to DEC
output logic [31:0] exu_i1_result_e1, // Primary ALU result to DEC
output logic [31:1] exu_i0_pc_e1, // Primary PC result to DEC
output logic [31:1] exu_i1_pc_e1, // Primary PC result to DEC
output logic [31:0] exu_i0_result_e4, // Secondary ALU result
output logic [31:0] exu_i1_result_e4, // Secondary ALU result
output logic exu_i0_flush_final, // I0 flush to DEC
output logic exu_i1_flush_final, // I1 flush to DEC
input mul_pkt_t mul_p, // DEC {valid, operand signs, low, operand bypass}
input div_pkt_t div_p, // DEC {valid, unsigned, rem}
input logic dec_i0_lsu_d, // Bypass control for LSU operand bus
input logic dec_i1_lsu_d, // Bypass control for LSU operand bus
input logic dec_csr_ren_d, // Clear I0 RS1 primary
output logic [31:0] exu_lsu_rs1_d, // LSU operand
output logic [31:0] exu_lsu_rs2_d, // LSU operand
output logic [31:0] exu_csr_rs1_e1, // RS1 source for a CSR instruction
output logic exu_flush_final, // Pipe is being flushed this cycle
output logic [31:1] exu_flush_path_final, // Target for the oldest flush source
output logic [31:0] exu_mul_result_e3, // Multiply result
output logic [31:0] exu_div_result, // Divide result
output logic exu_div_finish, // Divide is finished
output logic exu_div_stall, // Divide is running
output logic [31:1] exu_npc_e4, // Divide NPC
output logic exu_i0_flush_lower_e4, // to TLU - lower branch flush
output logic exu_i1_flush_lower_e4, // to TLU - lower branch flush
output logic [31:1] exu_i0_flush_path_e4, // to TLU - lower branch flush path
output logic [31:1] exu_i1_flush_path_e4, // to TLU - lower branch flush path
output predict_pkt_t exu_mp_pkt, // Mispredict branch packet
output logic [`RV_BHT_GHR_RANGE] exu_mp_eghr, // Mispredict global history
output logic [1:0] exu_i0_br_hist_e4, // to DEC I0 branch history
output logic [1:0] exu_i0_br_bank_e4, // to DEC I0 branch bank
output logic exu_i0_br_error_e4, // to DEC I0 branch error
output logic exu_i0_br_start_error_e4, // to DEC I0 branch start error
output logic [`RV_BTB_ADDR_HI:`RV_BTB_ADDR_LO] exu_i0_br_index_e4, // to DEC I0 branch index
output logic exu_i0_br_valid_e4, // to DEC I0 branch valid
output logic exu_i0_br_mp_e4, // to DEC I0 branch mispredict
`ifdef RV_BTB_48
output logic [1:0] exu_i0_br_way_e4, // to DEC I0 branch way
`else
output logic exu_i0_br_way_e4, // to DEC I0 branch way
`endif
output logic exu_i0_br_middle_e4, // to DEC I0 branch middle
output logic [`RV_BHT_GHR_RANGE] exu_i0_br_fghr_e4, // to DEC I0 branch fghr
output logic exu_i0_br_ret_e4, // to DEC I0 branch return
output logic exu_i0_br_call_e4, // to DEC I0 branch call
output logic [1:0] exu_i1_br_hist_e4, // to DEC I1 branch history
output logic [1:0] exu_i1_br_bank_e4, // to DEC I1 branch bank
output logic exu_i1_br_error_e4, // to DEC I1 branch error
output logic exu_i1_br_start_error_e4, // to DEC I1 branch start error
output logic [`RV_BTB_ADDR_HI:`RV_BTB_ADDR_LO] exu_i1_br_index_e4, // to DEC I1 branch index
output logic exu_i1_br_valid_e4, // to DEC I1 branch valid
output logic exu_i1_br_mp_e4, // to DEC I1 branch mispredict
`ifdef RV_BTB_48
output logic [1:0] exu_i1_br_way_e4, // to DEC I1 branch way
`else
output logic exu_i1_br_way_e4, // to DEC I1 branch way
`endif
output logic exu_i1_br_middle_e4, // to DEC I1 branch middle
output logic [`RV_BHT_GHR_RANGE] exu_i1_br_fghr_e4, // to DEC I1 branch fghr
output logic exu_i1_br_ret_e4, // to DEC I1 branch return
output logic exu_i1_br_call_e4, // to DEC I1 branch call
output logic exu_flush_upper_e2, // flush upper, either i0 or i1
output rets_pkt_t exu_rets_e1_pkt, // to IFU - I0+I1 {call, return, pc}
output rets_pkt_t exu_rets_e4_pkt, // to IFU - I0+I1 {call, return, pc}
output logic exu_pmu_i0_br_misp, // to PMU - I0 E4 branch mispredict
output logic exu_pmu_i0_br_ataken, // to PMU - I0 E4 taken
output logic exu_pmu_i0_pc4, // to PMU - I0 E4 PC
output logic exu_pmu_i1_br_misp, // to PMU - I1 E4 branch mispredict
output logic exu_pmu_i1_br_ataken, // to PMU - I1 E4 taken
output logic exu_pmu_i1_pc4 // to PMU - I1 E4 PC
);
logic [31:0] i0_rs1_d,i0_rs2_d,i1_rs1_d,i1_rs2_d;
logic exu_i0_flush_upper_e1;
logic [31:1] exu_i0_flush_path_e1;
logic exu_i1_flush_upper_e1;
logic [31:1] exu_i1_flush_path_e1;
logic [31:0] i0_rs1_final_d;
logic [31:1] exu_flush_path_e2;
logic [31:0] mul_rs1_d, mul_rs2_d;
logic [31:0] div_rs1_d, div_rs2_d;
logic i1_valid_e2;
logic [31:1] npc_e4;
logic [31:1] div_npc;
logic [31:0] i0_rs1_e1, i0_rs2_e1;
logic [31:0] i0_rs1_e2, i0_rs2_e2;
logic [31:0] i0_rs1_e3, i0_rs2_e3;
logic [12:1] i0_br_immed_e1, i0_br_immed_e2, i0_br_immed_e3;
logic [31:0] i1_rs1_e1, i1_rs2_e1;
logic [31:0] i1_rs1_e2, i1_rs2_e2;
logic [31:0] i1_rs1_e3, i1_rs2_e3;
logic [12:1] i1_br_immed_e1, i1_br_immed_e2, i1_br_immed_e3;
logic [31:0] i0_rs1_e2_final, i0_rs2_e2_final;
logic [31:0] i1_rs1_e2_final, i1_rs2_e2_final;
logic [31:0] i0_rs1_e3_final, i0_rs2_e3_final;
logic [31:0] i1_rs1_e3_final, i1_rs2_e3_final;
logic [31:1] i0_alu_pc_nc, i1_alu_pc_nc;
logic [31:1] exu_flush_path_e1;
logic exu_i0_flush_upper_e2, exu_i1_flush_upper_e2;
logic i1_valid_e3, i1_valid_e4;
logic [31:1] pred_correct_npc_e3, pred_correct_npc_e4;
logic exu_i0_flush_upper_e3;
logic exu_i0_flush_upper_e4;
logic i1_pred_correct_upper_e1, i0_pred_correct_upper_e1;
logic i1_pred_correct_upper_e2, i0_pred_correct_upper_e2;
logic i1_pred_correct_upper_e3, i0_pred_correct_upper_e3;
logic i1_pred_correct_upper_e4, i0_pred_correct_upper_e4;
logic i1_pred_correct_lower_e4, i0_pred_correct_lower_e4;
logic i1_valid_e4_eff;
logic i1_sec_decode_e4, i0_sec_decode_e4;
logic i1_pred_correct_e4_eff, i0_pred_correct_e4_eff;
logic [31:1] i1_flush_path_e4_eff, i0_flush_path_e4_eff;
logic [31:0] csr_rs1_in_d;
logic [31:1] i1_flush_path_upper_e2, i0_flush_path_upper_e2;
logic [31:1] i1_flush_path_upper_e3, i0_flush_path_upper_e3;
logic [31:1] i1_flush_path_upper_e4, i0_flush_path_upper_e4;
logic div_valid_e1;
logic div_finish_early;
logic freeze;
alu_pkt_t i0_ap_e1, i0_ap_e2, i0_ap_e3, i0_ap_e4;
alu_pkt_t i1_ap_e1, i1_ap_e2, i1_ap_e3, i1_ap_e4;
assign freeze = lsu_freeze_dc3;
assign i0_rs1_d[31:0] = ({32{~dec_i0_rs1_bypass_en_d}} & ((dec_debug_wdata_rs1_d) ? dbg_cmd_wrdata[31:0] : gpr_i0_rs1_d[31:0])) |
({32{~dec_i0_rs1_bypass_en_d & dec_i0_select_pc_d}} & { dec_i0_pc_d[31:1], 1'b0}) | // for jal's
({32{ dec_i0_rs1_bypass_en_d}} & i0_rs1_bypass_data_d[31:0]);
assign i0_rs1_final_d[31:0] = ({32{~dec_csr_ren_d}} & i0_rs1_d[31:0]);
assign i0_rs2_d[31:0] = ({32{~dec_i0_rs2_bypass_en_d}} & gpr_i0_rs2_d[31:0]) |
({32{~dec_i0_rs2_bypass_en_d}} & dec_i0_immed_d[31:0]) |
({32{ dec_i0_rs2_bypass_en_d}} & i0_rs2_bypass_data_d[31:0]);
assign i1_rs1_d[31:0] = ({32{~dec_i1_rs1_bypass_en_d}} & gpr_i1_rs1_d[31:0]) |
({32{~dec_i1_rs1_bypass_en_d & dec_i1_select_pc_d}} & { dec_i1_pc_d[31:1], 1'b0}) | // pc orthogonal with rs1
({32{ dec_i1_rs1_bypass_en_d}} & i1_rs1_bypass_data_d[31:0]);
assign i1_rs2_d[31:0] = ({32{~dec_i1_rs2_bypass_en_d}} & gpr_i1_rs2_d[31:0]) |
({32{~dec_i1_rs2_bypass_en_d}} & dec_i1_immed_d[31:0]) |
({32{ dec_i1_rs2_bypass_en_d}} & i1_rs2_bypass_data_d[31:0]);
assign exu_lsu_rs1_d[31:0] = ({32{ ~dec_i0_rs1_bypass_en_d & dec_i0_lsu_d }} & gpr_i0_rs1_d[31:0] ) |
({32{ ~dec_i1_rs1_bypass_en_d & ~dec_i0_lsu_d & dec_i1_lsu_d}} & gpr_i1_rs1_d[31:0] ) |
({32{ dec_i0_rs1_bypass_en_d & dec_i0_lsu_d }} & i0_rs1_bypass_data_d[31:0]) |
({32{ dec_i1_rs1_bypass_en_d & ~dec_i0_lsu_d & dec_i1_lsu_d}} & i1_rs1_bypass_data_d[31:0]);
assign exu_lsu_rs2_d[31:0] = ({32{ ~dec_i0_rs2_bypass_en_d & dec_i0_lsu_d }} & gpr_i0_rs2_d[31:0] ) |
({32{ ~dec_i1_rs2_bypass_en_d & ~dec_i0_lsu_d & dec_i1_lsu_d}} & gpr_i1_rs2_d[31:0] ) |
({32{ dec_i0_rs2_bypass_en_d & dec_i0_lsu_d }} & i0_rs2_bypass_data_d[31:0]) |
({32{ dec_i1_rs2_bypass_en_d & ~dec_i0_lsu_d & dec_i1_lsu_d}} & i1_rs2_bypass_data_d[31:0]);
assign mul_rs1_d[31:0] = ({32{ ~dec_i0_rs1_bypass_en_d & dec_i0_mul_d }} & gpr_i0_rs1_d[31:0] ) |
({32{ ~dec_i1_rs1_bypass_en_d & ~dec_i0_mul_d & dec_i1_mul_d}} & gpr_i1_rs1_d[31:0] ) |
({32{ dec_i0_rs1_bypass_en_d & dec_i0_mul_d }} & i0_rs1_bypass_data_d[31:0]) |
({32{ dec_i1_rs1_bypass_en_d & ~dec_i0_mul_d & dec_i1_mul_d}} & i1_rs1_bypass_data_d[31:0]);
assign mul_rs2_d[31:0] = ({32{ ~dec_i0_rs2_bypass_en_d & dec_i0_mul_d }} & gpr_i0_rs2_d[31:0] ) |
({32{ ~dec_i1_rs2_bypass_en_d & ~dec_i0_mul_d & dec_i1_mul_d}} & gpr_i1_rs2_d[31:0] ) |
({32{ dec_i0_rs2_bypass_en_d & dec_i0_mul_d }} & i0_rs2_bypass_data_d[31:0]) |
({32{ dec_i1_rs2_bypass_en_d & ~dec_i0_mul_d & dec_i1_mul_d}} & i1_rs2_bypass_data_d[31:0]);
assign div_rs1_d[31:0] = ({32{ ~dec_i0_rs1_bypass_en_d & dec_i0_div_d }} & gpr_i0_rs1_d[31:0]) |
({32{ ~dec_i1_rs1_bypass_en_d & ~dec_i0_div_d & dec_i1_div_d}} & gpr_i1_rs1_d[31:0]) |
({32{ dec_i0_rs1_bypass_en_d & dec_i0_div_d }} & i0_rs1_bypass_data_d[31:0]) |
({32{ dec_i1_rs1_bypass_en_d & ~dec_i0_div_d & dec_i1_div_d}} & i1_rs1_bypass_data_d[31:0]);
assign div_rs2_d[31:0] = ({32{ ~dec_i0_rs2_bypass_en_d & dec_i0_div_d }} & gpr_i0_rs2_d[31:0]) |
({32{ ~dec_i1_rs2_bypass_en_d & ~dec_i0_div_d & dec_i1_div_d}} & gpr_i1_rs2_d[31:0]) |
({32{ dec_i0_rs2_bypass_en_d & dec_i0_div_d }} & i0_rs2_bypass_data_d[31:0]) |
({32{ dec_i1_rs2_bypass_en_d & ~dec_i0_div_d & dec_i1_div_d}} & i1_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_e1[31:0];
logic i0_e1_data_en, i0_e2_data_en, i0_e3_data_en;
logic i0_e1_ctl_en, i0_e2_ctl_en, i0_e3_ctl_en, i0_e4_ctl_en;
assign {i0_e1_data_en, i0_e2_data_en, i0_e3_data_en } = dec_i0_data_en[4:2];
assign {i0_e1_ctl_en, i0_e2_ctl_en, i0_e3_ctl_en, i0_e4_ctl_en } = dec_i0_ctl_en[4:1];
logic i1_e1_data_en, i1_e2_data_en, i1_e3_data_en;
logic i1_e1_ctl_en, i1_e2_ctl_en, i1_e3_ctl_en, i1_e4_ctl_en;
assign {i1_e1_data_en, i1_e2_data_en, i1_e3_data_en} = dec_i1_data_en[4:2];
assign {i1_e1_ctl_en, i1_e2_ctl_en, i1_e3_ctl_en, i1_e4_ctl_en} = dec_i1_ctl_en[4:1];
rvdffe #(32) csr_rs1_ff (.*, .en(i0_e1_data_en), .din(csr_rs1_in_d[31:0]), .dout(exu_csr_rs1_e1[31:0]));
exu_mul_ctl mul_e1 (.*,
.clk_override ( clk_override ), // I
.freeze ( freeze ), // I
.mp ( mul_p ), // I
.a ( mul_rs1_d[31:0] ), // I
.b ( mul_rs2_d[31:0] ), // I
.out ( exu_mul_result_e3[31:0] )); // O
exu_div_ctl div_e1 (.*,
.flush_lower ( dec_tlu_flush_lower_wb ), // I
.dp ( div_p ), // I
.dividend ( div_rs1_d[31:0] ), // I
.divisor ( div_rs2_d[31:0] ), // I
.valid_ff_e1 ( div_valid_e1 ), // O
.div_stall ( exu_div_stall ), // O
.finish_early ( div_finish_early ), // O
.finish ( exu_div_finish ), // O
.out ( exu_div_result[31:0] )); // O
predict_pkt_t i0_predict_newp_d, i1_predict_newp_d;
always_comb begin
i0_predict_newp_d = i0_predict_p_d;
i0_predict_newp_d.boffset = dec_i0_pc_d[1]; // from the start of inst
i0_predict_newp_d.index[`RV_BTB_ADDR_HI:`RV_BTB_ADDR_LO] = i0_predict_p_d.index[`RV_BTB_ADDR_HI:`RV_BTB_ADDR_LO]; // from the end of inst
i0_predict_newp_d.bank[1:0] = i0_predict_p_d.bank[1:0];
i1_predict_newp_d = i1_predict_p_d;
i1_predict_newp_d.boffset = dec_i1_pc_d[1];
i1_predict_newp_d.index[`RV_BTB_ADDR_HI:`RV_BTB_ADDR_LO] = i1_predict_p_d.index[`RV_BTB_ADDR_HI:`RV_BTB_ADDR_LO];
i1_predict_newp_d.bank[1:0] = i1_predict_p_d.bank[1:0];
end
predict_pkt_t i0_predict_p_e1, i0_predict_p_e4;
predict_pkt_t i1_predict_p_e1, i1_predict_p_e4;
assign exu_pmu_i0_br_misp = i0_predict_p_e4.misp & ~exu_div_finish; // qual with divide
assign exu_pmu_i0_br_ataken = i0_predict_p_e4.ataken & ~exu_div_finish; // qual with divide
assign exu_pmu_i0_pc4 = i0_predict_p_e4.pc4 | exu_div_finish; // divides are always 4B
assign exu_pmu_i1_br_misp = i1_predict_p_e4.misp;
assign exu_pmu_i1_br_ataken = i1_predict_p_e4.ataken;
assign exu_pmu_i1_pc4 = i1_predict_p_e4.pc4;
exu_alu_ctl i0_alu_e1 (.*,
.freeze ( freeze ), // I
.enable ( i0_e1_ctl_en ), // I
.predict_p ( i0_predict_newp_d ), // I
.valid ( dec_i0_alu_decode_d ), // I
.flush ( exu_flush_final ), // I
.a ( i0_rs1_final_d[31:0] ), // I
.b ( i0_rs2_d[31:0] ), // I
.pc ( dec_i0_pc_d[31:1] ), // I
.brimm ( dec_i0_br_immed_d[12:1] ), // I
.ap ( i0_ap_e1 ), // I
.out ( exu_i0_result_e1[31:0] ), // O
.flush_upper ( exu_i0_flush_upper_e1 ), // O : will be 0 if freeze this cycle
.flush_path ( exu_i0_flush_path_e1[31:1] ), // O
.predict_p_ff ( i0_predict_p_e1 ), // O
.pc_ff ( exu_i0_pc_e1[31:1] ), // O
.pred_correct ( i0_pred_correct_upper_e1 ) // O
);
exu_alu_ctl i1_alu_e1 (.*,
.freeze ( freeze ), // I
.enable ( i1_e1_ctl_en ), // I
.predict_p ( i1_predict_newp_d ), // I
.valid ( dec_i1_alu_decode_d ), // I
.flush ( exu_flush_final ), // I
.a ( i1_rs1_d[31:0] ), // I
.b ( i1_rs2_d[31:0] ), // I
.pc ( dec_i1_pc_d[31:1] ), // I
.brimm ( dec_i1_br_immed_d[12:1] ), // I
.ap ( i1_ap_e1 ), // I
.out ( exu_i1_result_e1[31:0] ), // O
.flush_upper ( exu_i1_flush_upper_e1 ), // O : will be 0 if freeze this cycle
.flush_path ( exu_i1_flush_path_e1[31:1] ), // O
.predict_p_ff ( i1_predict_p_e1 ), // O
.pc_ff ( exu_i1_pc_e1[31:1] ), // O
.pred_correct ( i1_pred_correct_upper_e1 ) // O
);
predict_pkt_t i0_pp_e2, i0_pp_e3, i0_pp_e4_in;
rvdffe #($bits(predict_pkt_t)) i0_pp_e2_ff (.*, .en(i0_e2_ctl_en), .din(i0_predict_p_e1),.dout(i0_pp_e2) );
rvdffe #($bits(predict_pkt_t)) i0_pp_e3_ff (.*, .en(i0_e3_ctl_en), .din(i0_pp_e2),.dout(i0_pp_e3) );
predict_pkt_t i1_pp_e2, i1_pp_e3, i1_pp_e4_in;
rvdffe #($bits(predict_pkt_t)) i1_pp_e2_ff (.*, .en(i1_e2_ctl_en), .din(i1_predict_p_e1),.dout(i1_pp_e2) );
rvdffe #($bits(predict_pkt_t)) i1_pp_e3_ff (.*, .en(i1_e3_ctl_en), .din(i1_pp_e2),.dout(i1_pp_e3) );
// set the predict_pkt to 0's if freeze, goes to secondary alu's
assign i0_pp_e4_in = (freeze) ? '0 : i0_pp_e3;
assign i1_pp_e4_in = (freeze) ? '0 : i1_pp_e3;
rvdffe #($bits(alu_pkt_t)) i0_ap_e1_ff (.*, .en(i0_e1_ctl_en), .din(i0_ap), .dout(i0_ap_e1) );
rvdffe #($bits(alu_pkt_t)) i0_ap_e2_ff (.*, .en(i0_e2_ctl_en), .din(i0_ap_e1),.dout(i0_ap_e2) );
rvdffe #($bits(alu_pkt_t)) i0_ap_e3_ff (.*, .en(i0_e3_ctl_en), .din(i0_ap_e2),.dout(i0_ap_e3) );
rvdffe #($bits(alu_pkt_t)) i0_ap_e4_ff (.*, .en(i0_e4_ctl_en), .din(i0_ap_e3),.dout(i0_ap_e4) );
rvdffe #($bits(alu_pkt_t)) i1_ap_e1_ff (.*, .en(i1_e1_ctl_en), .din(i1_ap), .dout(i1_ap_e1) );
rvdffe #($bits(alu_pkt_t)) i1_ap_e2_ff (.*, .en(i1_e2_ctl_en), .din(i1_ap_e1),.dout(i1_ap_e2) );
rvdffe #($bits(alu_pkt_t)) i1_ap_e3_ff (.*, .en(i1_e3_ctl_en), .din(i1_ap_e2),.dout(i1_ap_e3) );
rvdffe #($bits(alu_pkt_t)) i1_ap_e4_ff (.*, .en(i1_e4_ctl_en), .din(i1_ap_e3),.dout(i1_ap_e4) );
assign exu_rets_e1_pkt.pc0_call = i0_predict_p_e1.pcall & i0_predict_p_e1.valid & ~i0_predict_p_e1.br_error;
assign exu_rets_e1_pkt.pc1_call = i1_predict_p_e1.pcall & i1_predict_p_e1.valid & ~i1_predict_p_e1.br_error;
assign exu_rets_e1_pkt.pc0_ret = i0_predict_p_e1.pret & i0_predict_p_e1.valid & ~i0_predict_p_e1.br_error;
assign exu_rets_e1_pkt.pc1_ret = i1_predict_p_e1.pret & i1_predict_p_e1.valid & ~i1_predict_p_e1.br_error;
assign exu_rets_e1_pkt.pc0_pc4 = i0_predict_p_e1.pc4;
assign exu_rets_e1_pkt.pc1_pc4 = i1_predict_p_e1.pc4;
rvdffe #(76) i0_src_e1_ff (.*,
.en(i0_e1_data_en),
.din( {i0_rs1_d[31:0], i0_rs2_d[31:0], dec_i0_br_immed_d[12:1]}),
.dout({i0_rs1_e1[31:0], i0_rs2_e1[31:0], i0_br_immed_e1[12:1]})
);
rvdffe #(76) i0_src_e2_ff (.*,
.en(i0_e2_data_en),
.din( {i0_rs1_e1[31:0], i0_rs2_e1[31:0], i0_br_immed_e1[12:1]}),
.dout({i0_rs1_e2[31:0], i0_rs2_e2[31:0], i0_br_immed_e2[12:1]})
);
rvdffe #(76) i0_src_e3_ff (.*,
.en(i0_e3_data_en),
.din( {i0_rs1_e2_final[31:0], i0_rs2_e2_final[31:0], i0_br_immed_e2[12:1]}),
.dout({i0_rs1_e3[31:0], i0_rs2_e3[31:0], i0_br_immed_e3[12:1]})
);
rvdffe #(76) i1_src_e1_ff (.*,
.en(i1_e1_data_en),
.din( {i1_rs1_d[31:0], i1_rs2_d[31:0], dec_i1_br_immed_d[12:1]}),
.dout({i1_rs1_e1[31:0], i1_rs2_e1[31:0], i1_br_immed_e1[12:1]})
);
rvdffe #(76) i1_src_e2_ff (.*,
.en(i1_e2_data_en),
.din( {i1_rs1_e1[31:0], i1_rs2_e1[31:0], i1_br_immed_e1[12:1]}),
.dout({i1_rs1_e2[31:0], i1_rs2_e2[31:0], i1_br_immed_e2[12:1]})
);
rvdffe #(76) i1_src_e3_ff (.*,
.en(i1_e3_data_en),
.din( {i1_rs1_e2_final[31:0], i1_rs2_e2_final[31:0], i1_br_immed_e2[12:1]}),
.dout({i1_rs1_e3[31:0], i1_rs2_e3[31:0], i1_br_immed_e3[12:1]})
);
assign i0_rs1_e2_final[31:0] = (dec_i0_rs1_bypass_en_e2) ? i0_rs1_bypass_data_e2[31:0] : i0_rs1_e2[31:0];
assign i0_rs2_e2_final[31:0] = (dec_i0_rs2_bypass_en_e2) ? i0_rs2_bypass_data_e2[31:0] : i0_rs2_e2[31:0];
assign i1_rs1_e2_final[31:0] = (dec_i1_rs1_bypass_en_e2) ? i1_rs1_bypass_data_e2[31:0] : i1_rs1_e2[31:0];
assign i1_rs2_e2_final[31:0] = (dec_i1_rs2_bypass_en_e2) ? i1_rs2_bypass_data_e2[31:0] : i1_rs2_e2[31:0];
assign i0_rs1_e3_final[31:0] = (dec_i0_rs1_bypass_en_e3) ? i0_rs1_bypass_data_e3[31:0] : i0_rs1_e3[31:0];
assign i0_rs2_e3_final[31:0] = (dec_i0_rs2_bypass_en_e3) ? i0_rs2_bypass_data_e3[31:0] : i0_rs2_e3[31:0];
assign i1_rs1_e3_final[31:0] = (dec_i1_rs1_bypass_en_e3) ? i1_rs1_bypass_data_e3[31:0] : i1_rs1_e3[31:0];
assign i1_rs2_e3_final[31:0] = (dec_i1_rs2_bypass_en_e3) ? i1_rs2_bypass_data_e3[31:0] : i1_rs2_e3[31:0];
// E1 GHR
// fill in the ptaken for secondary branches.
logic [`RV_BHT_GHR_RANGE] ghr_e4_ns, ghr_e4;
logic [`RV_BHT_GHR_RANGE] ghr_e1_ns, ghr_e1;
logic i0_taken_e1, i1_taken_e1, dec_i0_alu_decode_e1, dec_i1_alu_decode_e1, i0_valid_e1, i1_valid_e1, i0_ataken_e1, i1_ataken_e1, exu_flush_final_f;
assign i0_valid_e1 = ~exu_flush_final & ~exu_flush_final_f & (i0_predict_p_e1.valid | i0_predict_p_e1.misp);
assign i1_valid_e1 = ~exu_flush_final & ~exu_flush_final_f & (i1_predict_p_e1.valid | i1_predict_p_e1.misp) & ~exu_i0_flush_upper_e1;
assign i0_ataken_e1 = i0_predict_p_e1.ataken;
assign i1_ataken_e1 = i1_predict_p_e1.ataken;
assign i0_taken_e1 = (i0_ataken_e1 & dec_i0_alu_decode_e1) | (i0_predict_p_e1.hist[1] & ~dec_i0_alu_decode_e1);
assign i1_taken_e1= (i1_ataken_e1 & dec_i1_alu_decode_e1) | (i1_predict_p_e1.hist[1] & ~dec_i1_alu_decode_e1);
assign ghr_e1_ns[`RV_BHT_GHR_RANGE] = ( ({`RV_BHT_GHR_SIZE{~dec_tlu_flush_lower_wb & i0_valid_e1 & (i0_predict_p_e1.misp | ~i1_valid_e1)}} & {ghr_e1[`RV_BHT_GHR_SIZE-2:0], i0_taken_e1}) |
`ifdef RV_BHT_GHR_SIZE_2
({`RV_BHT_GHR_SIZE{~dec_tlu_flush_lower_wb & i0_valid_e1 & ~i0_predict_p_e1.misp & i1_valid_e1}} & { i0_taken_e1, i1_taken_e1}) |
`else
({`RV_BHT_GHR_SIZE{~dec_tlu_flush_lower_wb & i0_valid_e1 & ~i0_predict_p_e1.misp & i1_valid_e1}} & {ghr_e1[`RV_BHT_GHR_SIZE-3:0], i0_taken_e1, i1_taken_e1}) |
`endif
({`RV_BHT_GHR_SIZE{~dec_tlu_flush_lower_wb & ~i0_valid_e1 & ~i0_predict_p_e1.br_error & i1_valid_e1}} & {ghr_e1[`RV_BHT_GHR_SIZE-2:0], i1_taken_e1}) |
({`RV_BHT_GHR_SIZE{dec_tlu_flush_lower_wb}} & ghr_e4[`RV_BHT_GHR_RANGE]) |
({`RV_BHT_GHR_SIZE{~dec_tlu_flush_lower_wb & ~i0_valid_e1 & ~i1_valid_e1}} & ghr_e1[`RV_BHT_GHR_RANGE]) );
rvdffs #(`RV_BHT_GHR_SIZE) e1ghrff (.*, .clk(active_clk), .en(~freeze), .din({ghr_e1_ns[`RV_BHT_GHR_RANGE]}), .dout({ghr_e1[`RV_BHT_GHR_RANGE]}));
rvdffs #(2) e1ghrdecff (.*, .clk(active_clk), .en(~freeze), .din({dec_i0_alu_decode_d, dec_i1_alu_decode_d}), .dout({dec_i0_alu_decode_e1, dec_i1_alu_decode_e1}));
// E4 GHR
// the ataken is filled in by e1 stage if e1 stage executes the branch, otherwise by e4 stage.
logic i0_valid_e4, i1_pred_valid_e4;
assign i0_valid_e4 = dec_tlu_i0_valid_e4 & ((i0_predict_p_e4.valid) | i0_predict_p_e4.misp);
assign i1_pred_valid_e4 = dec_tlu_i1_valid_e4 & ((i1_predict_p_e4.valid) | i1_predict_p_e4.misp) & ~exu_i0_flush_upper_e4;
assign ghr_e4_ns[`RV_BHT_GHR_RANGE] = ( ({`RV_BHT_GHR_SIZE{i0_valid_e4 & (i0_predict_p_e4.misp | ~i1_pred_valid_e4)}} & {ghr_e4[`RV_BHT_GHR_SIZE-2:0], i0_predict_p_e4.ataken}) |
`ifdef RV_BHT_GHR_SIZE_2
({`RV_BHT_GHR_SIZE{i0_valid_e4 & ~i0_predict_p_e4.misp & i1_pred_valid_e4}} & { i0_predict_p_e4.ataken, i1_predict_p_e4.ataken}) |
`else
({`RV_BHT_GHR_SIZE{i0_valid_e4 & ~i0_predict_p_e4.misp & i1_pred_valid_e4}} & {ghr_e4[`RV_BHT_GHR_SIZE-3:0], i0_predict_p_e4.ataken, i1_predict_p_e4.ataken}) |
`endif
({`RV_BHT_GHR_SIZE{~i0_valid_e4 & ~i0_predict_p_e4.br_error & i1_pred_valid_e4}} & {ghr_e4[`RV_BHT_GHR_SIZE-2:0], i1_predict_p_e4.ataken}) |
({`RV_BHT_GHR_SIZE{~i0_valid_e4 & ~i1_pred_valid_e4}} & ghr_e4[`RV_BHT_GHR_RANGE]) );
rvdff #(`RV_BHT_GHR_SIZE) e4ghrff (.*, .clk(active_clk), .din({ghr_e4_ns[`RV_BHT_GHR_RANGE]}),
.dout({ghr_e4[`RV_BHT_GHR_RANGE]}));
rvdff #(1) e4ghrflushff (.*, .clk(active_clk), .din({exu_flush_final}),
.dout({exu_flush_final_f}));
// RV_NO_SECONDARY_ALU {{
`ifdef RV_NO_SECONDARY_ALU
rvdffe #($bits(predict_pkt_t)) i0_pp_e4_ff (.*, .en(i0_e4_ctl_en), .din(i0_pp_e4_in),.dout(i0_predict_p_e4) );
rvdffe #($bits(predict_pkt_t)) i1_pp_e4_ff (.*, .en(i1_e4_ctl_en), .din(i1_pp_e4_in),.dout(i1_predict_p_e4) );
assign exu_i0_result_e4[31:0] = '0;
assign exu_i0_flush_lower_e4 = '0;
assign exu_i0_flush_path_e4[31:1] = '0;
assign i0_alu_pc_nc[31:1] = '0;
assign i0_pred_correct_lower_e4 = '0;
assign exu_i1_result_e4[31:0] = '0;
assign exu_i1_flush_lower_e4 = '0;
assign exu_i1_flush_path_e4[31:1] = '0;
assign i1_alu_pc_nc[31:1] = '0;
assign i1_pred_correct_lower_e4 = '0;
`else
exu_alu_ctl i0_alu_e4 (.*,
.freeze ( 1'b0 ), // I
.enable ( i0_e4_ctl_en ), // I
.predict_p ( i0_pp_e4_in ), // I
.valid ( dec_i0_sec_decode_e3 ), // I
.flush ( dec_tlu_flush_lower_wb ), // I
.a ( i0_rs1_e3_final[31:0] ), // I
.b ( i0_rs2_e3_final[31:0] ), // I
.pc ( dec_i0_pc_e3[31:1] ), // I
.brimm ( i0_br_immed_e3[12:1] ), // I
.ap ( i0_ap_e4 ), // I
.out ( exu_i0_result_e4[31:0] ), // O
.flush_upper ( exu_i0_flush_lower_e4 ), // O
.flush_path ( exu_i0_flush_path_e4[31:1] ), // O
.predict_p_ff ( i0_predict_p_e4 ), // O
.pc_ff ( i0_alu_pc_nc[31:1] ), // O
.pred_correct ( i0_pred_correct_lower_e4 ) // O
);
exu_alu_ctl i1_alu_e4 (.*,
.freeze ( 1'b0 ), // I
.enable ( i1_e4_ctl_en ), // I
.predict_p ( i1_pp_e4_in ), // I
.valid ( dec_i1_sec_decode_e3 ), // I
.flush ( dec_tlu_flush_lower_wb ), // I
.a ( i1_rs1_e3_final[31:0] ), // I
.b ( i1_rs2_e3_final[31:0] ), // I
.pc ( dec_i1_pc_e3[31:1] ), // I
.brimm ( i1_br_immed_e3[12:1] ), // I
.ap ( i1_ap_e4 ), // I
.out ( exu_i1_result_e4[31:0] ), // O
.flush_upper ( exu_i1_flush_lower_e4 ), // O
.flush_path ( exu_i1_flush_path_e4[31:1] ), // O
.predict_p_ff ( i1_predict_p_e4 ), // O
.pc_ff ( i1_alu_pc_nc[31:1] ), // O
.pred_correct ( i1_pred_correct_lower_e4 ) // O
);
`endif // RV_NO_SECONDARY_ALU }}
assign exu_i0_br_hist_e4[1:0] = i0_predict_p_e4.hist[1:0];
assign exu_i0_br_bank_e4[1:0] = i0_predict_p_e4.bank[1:0];
assign exu_i0_br_error_e4 = i0_predict_p_e4.br_error;
assign exu_i0_br_fghr_e4[`RV_BHT_GHR_RANGE] = i0_predict_p_e4.fghr[`RV_BHT_GHR_RANGE];
assign exu_i0_br_middle_e4 = i0_predict_p_e4.pc4 ^ i0_predict_p_e4.boffset;
assign exu_i0_br_start_error_e4 = i0_predict_p_e4.br_start_error;
assign exu_i0_br_index_e4[`RV_BTB_ADDR_HI:`RV_BTB_ADDR_LO] = i0_predict_p_e4.index[`RV_BTB_ADDR_HI:`RV_BTB_ADDR_LO];
assign exu_i0_br_valid_e4 = i0_predict_p_e4.valid;
assign exu_i0_br_mp_e4 = i0_predict_p_e4.misp; // needed to squash i1 error
assign exu_i0_br_ret_e4 = i0_predict_p_e4.pret;
assign exu_i0_br_call_e4 = i0_predict_p_e4.pcall;
assign exu_i0_br_way_e4 = i0_predict_p_e4.way;
assign exu_i1_br_hist_e4[1:0] = i1_predict_p_e4.hist[1:0];
assign exu_i1_br_bank_e4[1:0] = i1_predict_p_e4.bank[1:0];
assign exu_i1_br_fghr_e4[`RV_BHT_GHR_RANGE] = i1_predict_p_e4.fghr[`RV_BHT_GHR_RANGE];
assign exu_i1_br_middle_e4 = i1_predict_p_e4.pc4 ^ i1_predict_p_e4.boffset;
assign exu_i1_br_error_e4 = i1_predict_p_e4.br_error;
assign exu_i1_br_index_e4[`RV_BTB_ADDR_HI:`RV_BTB_ADDR_LO] = i1_predict_p_e4.index[`RV_BTB_ADDR_HI:`RV_BTB_ADDR_LO];
assign exu_i1_br_start_error_e4 = i1_predict_p_e4.br_start_error;
assign exu_i1_br_valid_e4 = i1_predict_p_e4.valid;
assign exu_i1_br_mp_e4 = i1_predict_p_e4.misp;
assign exu_i1_br_way_e4 = i1_predict_p_e4.way;
assign exu_i1_br_ret_e4 = i1_predict_p_e4.pret;
assign exu_i1_br_call_e4 = i1_predict_p_e4.pcall;
assign exu_rets_e4_pkt.pc0_call = i0_predict_p_e4.pcall & i0_predict_p_e4.valid & ~i0_predict_p_e4.br_error;
assign exu_rets_e4_pkt.pc1_call = i1_predict_p_e4.pcall & i1_predict_p_e4.valid & ~i1_predict_p_e4.br_error;
assign exu_rets_e4_pkt.pc0_ret = i0_predict_p_e4.pret & i0_predict_p_e4.valid & ~i0_predict_p_e4.br_error;
assign exu_rets_e4_pkt.pc1_ret = i1_predict_p_e4.pret & i1_predict_p_e4.valid & ~i1_predict_p_e4.br_error;
assign exu_rets_e4_pkt.pc0_pc4 = i0_predict_p_e4.pc4;
assign exu_rets_e4_pkt.pc1_pc4 = i1_predict_p_e4.pc4;
predict_pkt_t final_predict_mp, final_predict_mp_ff;
logic fp_enable, fp_enable_ff;
assign fp_enable = exu_i0_flush_lower_e4 | exu_i1_flush_lower_e4 |
exu_i0_flush_upper_e1 | exu_i1_flush_upper_e1;
rvdff #(1) final_predict_ff (.*, .clk(active_clk), .din(fp_enable), .dout(fp_enable_ff));
// flush_upper_e1's below take freeze into account
assign final_predict_mp = (exu_i0_flush_lower_e4) ? i0_predict_p_e4 :
(exu_i1_flush_lower_e4) ? i1_predict_p_e4 :
(exu_i0_flush_upper_e1) ? i0_predict_p_e1 :
(exu_i1_flush_upper_e1) ? i1_predict_p_e1 : '0;
rvdffe #($bits(predict_pkt_t)) predict_mp_ff (.*, .en(fp_enable | fp_enable_ff), .din(final_predict_mp), .dout(final_predict_mp_ff));
logic [`RV_BHT_GHR_RANGE] final_eghr, after_flush_eghr;
assign final_eghr[`RV_BHT_GHR_RANGE] = ((exu_i0_flush_upper_e1 | exu_i1_flush_upper_e1) & ~dec_tlu_flush_lower_wb & ~exu_i0_flush_lower_e4 & ~exu_i1_flush_lower_e4 ) ? ghr_e1[`RV_BHT_GHR_RANGE] : ghr_e4[`RV_BHT_GHR_RANGE];
assign after_flush_eghr[`RV_BHT_GHR_RANGE] = ((exu_i0_flush_upper_e2 | exu_i1_flush_upper_e2) & ~dec_tlu_flush_lower_wb) ? ghr_e1[`RV_BHT_GHR_RANGE] : ghr_e4[`RV_BHT_GHR_RANGE];
assign exu_mp_pkt.way = final_predict_mp_ff.way;
assign exu_mp_pkt.misp = final_predict_mp_ff.misp;
assign exu_mp_pkt.pcall = final_predict_mp_ff.pcall;
assign exu_mp_pkt.pja = final_predict_mp_ff.pja;
assign exu_mp_pkt.pret = final_predict_mp_ff.pret;
assign exu_mp_pkt.ataken = final_predict_mp_ff.ataken;
assign exu_mp_pkt.boffset = final_predict_mp_ff.boffset;
assign exu_mp_pkt.pc4 = final_predict_mp_ff.pc4;
assign exu_mp_pkt.hist[1:0] = final_predict_mp_ff.hist[1:0];
assign exu_mp_pkt.toffset[11:0] = final_predict_mp_ff.toffset[11:0];
assign exu_mp_pkt.index[`RV_BTB_ADDR_HI:`RV_BTB_ADDR_LO] = final_predict_mp_ff.index[`RV_BTB_ADDR_HI:`RV_BTB_ADDR_LO];
assign exu_mp_pkt.bank[1:0] = final_predict_mp_ff.bank[1:0];
assign exu_mp_pkt.btag[`RV_BTB_BTAG_SIZE-1:0] = final_predict_mp_ff.btag[`RV_BTB_BTAG_SIZE-1:0];
assign exu_mp_pkt.fghr[`RV_BHT_GHR_RANGE] = after_flush_eghr[`RV_BHT_GHR_RANGE]; // fghr repair value
assign exu_mp_eghr[`RV_BHT_GHR_RANGE] = final_predict_mp_ff.fghr[`RV_BHT_GHR_RANGE]; // mp ghr for bht write
rvdffe #(32) i0_upper_flush_e2_ff (.*,
.en(i0_e2_ctl_en),
.din({
exu_i0_flush_path_e1[31:1],
exu_i0_flush_upper_e1}),
.dout({
i0_flush_path_upper_e2[31:1],
exu_i0_flush_upper_e2})
);
rvdffe #(33) i1_upper_flush_e2_ff (.*,
.en(i1_e2_ctl_en),
.din({dec_i1_valid_e1,
exu_i1_flush_path_e1[31:1],
exu_i1_flush_upper_e1}),
.dout({i1_valid_e2,
i1_flush_path_upper_e2[31:1],
exu_i1_flush_upper_e2})
);
assign exu_flush_path_e2[31:1] = (exu_i0_flush_upper_e2) ? i0_flush_path_upper_e2[31:1] : i1_flush_path_upper_e2[31:1];
assign exu_i0_flush_final = dec_tlu_flush_lower_wb | (exu_i0_flush_upper_e2 & ~freeze);
assign exu_i1_flush_final = dec_tlu_flush_lower_wb | (exu_i1_flush_upper_e2 & ~freeze);
assign exu_flush_upper_e2 = (exu_i0_flush_upper_e2 | exu_i1_flush_upper_e2) & ~freeze;
assign exu_flush_final = dec_tlu_flush_lower_wb | exu_flush_upper_e2;
assign exu_flush_path_final[31:1] = (dec_tlu_flush_lower_wb) ? dec_tlu_flush_path_wb[31:1] : exu_flush_path_e2[31:1];
rvdffe #(63) i0_upper_flush_e3_ff (.*,
.en(i0_e3_ctl_en),
.din({i0_flush_path_upper_e2[31:1],
pred_correct_npc_e2[31:1],
exu_i0_flush_upper_e2}),
.dout({
i0_flush_path_upper_e3[31:1],
pred_correct_npc_e3[31:1],
exu_i0_flush_upper_e3})
);
rvdffe #(32) i1_upper_flush_e3_ff (.*,
.en(i1_e3_ctl_en),
.din({i1_valid_e2,
i1_flush_path_upper_e2[31:1]
}),
.dout({i1_valid_e3,
i1_flush_path_upper_e3[31:1]})
);
rvdffe #(63) i0_upper_flush_e4_ff (.*,
.en(i0_e4_ctl_en),
.din({
i0_flush_path_upper_e3[31:1],
pred_correct_npc_e3[31:1],
exu_i0_flush_upper_e3 & ~freeze}),
.dout({
i0_flush_path_upper_e4[31:1],
pred_correct_npc_e4[31:1],
exu_i0_flush_upper_e4})
);
rvdffe #(32) i1_upper_flush_e4_ff (.*,
.en(i1_e4_ctl_en),
.din({i1_valid_e3 & ~freeze,
i1_flush_path_upper_e3[31:1]}),
.dout({i1_valid_e4,
i1_flush_path_upper_e4[31:1]})
);
// npc logic for commit
rvdffs #(2) pred_correct_upper_e2_ff (.*,
.clk(active_clk),
.en(~freeze),
.din({i1_pred_correct_upper_e1,i0_pred_correct_upper_e1}),
.dout({i1_pred_correct_upper_e2,i0_pred_correct_upper_e2})
);
rvdffs #(2) pred_correct_upper_e3_ff (.*,
.clk(active_clk),
.en(~freeze),
.din({i1_pred_correct_upper_e2,i0_pred_correct_upper_e2}),
.dout({i1_pred_correct_upper_e3,i0_pred_correct_upper_e3})
);
rvdff #(2) pred_correct_upper_e4_ff (.*,
.clk(active_clk),
.din({i1_pred_correct_upper_e3,i0_pred_correct_upper_e3}),
.dout({i1_pred_correct_upper_e4,i0_pred_correct_upper_e4})
);
rvdff #(2) sec_decode_e4_ff (.*,
.clk(active_clk),
.din({dec_i0_sec_decode_e3,dec_i1_sec_decode_e3}),
.dout({i0_sec_decode_e4,i1_sec_decode_e4})
);
assign i1_valid_e4_eff = i1_valid_e4 & ~((i0_sec_decode_e4) ? exu_i0_flush_lower_e4 : exu_i0_flush_upper_e4);
assign i1_pred_correct_e4_eff = (i1_sec_decode_e4) ? i1_pred_correct_lower_e4 : i1_pred_correct_upper_e4;
assign i0_pred_correct_e4_eff = (i0_sec_decode_e4) ? i0_pred_correct_lower_e4 : i0_pred_correct_upper_e4;
assign i1_flush_path_e4_eff[31:1] = (i1_sec_decode_e4) ? exu_i1_flush_path_e4[31:1] : i1_flush_path_upper_e4[31:1];
assign i0_flush_path_e4_eff[31:1] = (i0_sec_decode_e4) ? exu_i0_flush_path_e4[31:1] : i0_flush_path_upper_e4[31:1];
assign npc_e4[31:1] = (i1_valid_e4_eff) ? ((i1_pred_correct_e4_eff) ? pred_correct_npc_e4[31:1] : i1_flush_path_e4_eff[31:1]) :
((i0_pred_correct_e4_eff) ? pred_correct_npc_e4[31:1] : i0_flush_path_e4_eff[31:1]);
assign exu_npc_e4[31:1] = (div_finish_early) ? exu_i0_flush_path_e1[31:1] :
(exu_div_finish) ? div_npc[31:1] :
npc_e4[31:1];
// remember the npc of the divide
rvdffe #(31) npc_any_ff (.*, .en(div_valid_e1), .din(exu_i0_flush_path_e1[31:1]), .dout(div_npc[31:1]));
endmodule // exu

275
design/exu/exu_alu_ctl.sv Normal file
View File

@ -0,0 +1,275 @@
// 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.
module exu_alu_ctl
import swerv_types::*;
(
input logic clk, // Top level clock
input logic active_clk, // Level 1 free clock
input logic rst_l, // Reset
input logic scan_mode, // Scan control
input predict_pkt_t predict_p, // Predicted branch structure
input logic freeze, // Clock enable for valid
input logic [31:0] a, // A operand
input logic [31:0] b, // B operand
input logic [31:1] pc, // for pc=pc+2,4 calculations
input logic valid, // Valid
input logic flush, // Flush pipeline
input logic [12:1] brimm, // Branch offset
input alu_pkt_t ap, // {valid,predecodes}
input logic enable, // Clock enable
output logic [31:0] out, // final result
output logic flush_upper, // Branch flush
output logic [31:1] flush_path, // Branch flush PC
output logic [31:1] pc_ff, // flopped PC
output logic pred_correct, // NPC control
output predict_pkt_t predict_p_ff // Predicted branch structure
);
logic [31:0] aout,bm;
logic cout,ov,neg;
logic [3:1] logic_sel;
logic [31:0] lout;
logic [31:0] sout;
logic sel_logic,sel_shift,sel_adder;
logic slt_one;
logic actual_taken;
logic signed [31:0] a_ff;
logic [31:0] b_ff;
logic [12:1] brimm_ff;
logic [31:1] pcout;
logic valid_ff;
logic [31:0] ashift;
logic cond_mispredict;
logic target_mispredict;
logic eq, ne, lt, ge;
rvdffs #(1) validff (.*, .clk(active_clk), .en(~freeze), .din(valid & ~flush), .dout(valid_ff));
rvdffe #(32) aff (.*, .en(enable & valid), .din(a[31:0]), .dout(a_ff[31:0]));
rvdffe #(32) bff (.*, .en(enable & valid), .din(b[31:0]), .dout(b_ff[31:0]));
// any PC is run through here - doesn't have to be alu
rvdffe #(31) pcff (.*, .en(enable), .din(pc[31:1]), .dout(pc_ff[31:1]));
rvdffe #(12) brimmff (.*, .en(enable), .din(brimm[12:1]), .dout(brimm_ff[12:1]));
predict_pkt_t pp_ff;
rvdffe #($bits(predict_pkt_t)) predictpacketff (.*,
.en(enable),
.din(predict_p),
.dout(pp_ff)
);
// immediates are just muxed into rs2
// add => add=1;
// sub => add=1; sub=1;
// and => lctl=3
// or => lctl=2
// xor => lctl=1
// sll => sctl=3
// srl => sctl=2
// sra => sctl=1
// slt => slt
// lui => lctl=2; or x0, imm20 previously << 12
// auipc => add; add pc, imm20 previously << 12
// beq => bctl=4; add; add x0, pc, sext(offset[12:1])
// bne => bctl=3; add; add x0, pc, sext(offset[12:1])
// blt => bctl=2; add; add x0, pc, sext(offset[12:1])
// bge => bctl=1; add; add x0, pc, sext(offset[12:1])
// jal => rs1=pc {pc[31:1],1'b0}, rs2=sext(offset20:1]); rd=pc+[2,4]
// jalr => rs1=rs1, rs2=sext(offset20:1]); rd=pc+[2,4]
assign bm[31:0] = ( ap.sub ) ? ~b_ff[31:0] : b_ff[31:0];
assign {cout, aout[31:0]} = {1'b0, a_ff[31:0]} + {1'b0, bm[31:0]} + {32'b0, ap.sub};
assign ov = (~a_ff[31] & ~bm[31] & aout[31]) |
( a_ff[31] & bm[31] & ~aout[31] );
assign neg = aout[31];
assign eq = a_ff[31:0] == b_ff[31:0];
assign ne = ~eq;
assign logic_sel[3] = ap.land | ap.lor;
assign logic_sel[2] = ap.lor | ap.lxor;
assign logic_sel[1] = ap.lor | ap.lxor;
assign lout[31:0] = ( a_ff[31:0] & b_ff[31:0] & {32{logic_sel[3]}} ) |
( a_ff[31:0] & ~b_ff[31:0] & {32{logic_sel[2]}} ) |
( ~a_ff[31:0] & b_ff[31:0] & {32{logic_sel[1]}} );
assign ashift[31:0] = a_ff >>> b_ff[4:0];
assign sout[31:0] = ( {32{ap.sll}} & (a_ff[31:0] << b_ff[4:0]) ) |
( {32{ap.srl}} & (a_ff[31:0] >> b_ff[4:0]) ) |
( {32{ap.sra}} & ashift[31:0] );
assign sel_logic = |{ap.land,ap.lor,ap.lxor};
assign sel_shift = |{ap.sll,ap.srl,ap.sra};
assign sel_adder = (ap.add | ap.sub) & ~ap.slt;
assign lt = (~ap.unsign & (neg ^ ov)) |
( ap.unsign & ~cout);
assign ge = ~lt;
assign slt_one = (ap.slt & lt);
assign out[31:0] = ({32{sel_logic}} & lout[31:0]) |
({32{sel_shift}} & sout[31:0]) |
({32{sel_adder}} & aout[31:0]) |
({32{ap.jal | pp_ff.pcall | pp_ff.pja | pp_ff.pret}} & {pcout[31:1],1'b0}) |
({32{ap.csr_write}} & ((ap.csr_imm) ? b_ff[31:0] : a_ff[31:0])) | // csr_write: if csr_imm rs2 else rs1
({31'b0, slt_one});
// branch handling
logic any_jal;
assign any_jal = ap.jal |
pp_ff.pcall |
pp_ff.pja |
pp_ff.pret;
assign actual_taken = (ap.beq & eq) |
(ap.bne & ne) |
(ap.blt & lt) |
(ap.bge & ge) |
(any_jal);
// for a conditional br pcout[] will be the opposite of the branch prediction
// for jal or pcall, it will be the link address pc+2 or pc+4
rvbradder ibradder (
.pc(pc_ff[31:1]),
.offset(brimm_ff[12:1]),
.dout(pcout[31:1])
);
// pred_correct is for the npc logic
// pred_correct indicates not to use the flush_path
// for any_jal pred_correct==0
assign pred_correct = ((ap.predict_nt & ~actual_taken) |
(ap.predict_t & actual_taken)) & ~any_jal;
// for any_jal adder output is the flush path
assign flush_path[31:1] = (any_jal) ? aout[31:1] : pcout[31:1];
// pcall and pret are included here
assign cond_mispredict = (ap.predict_t & ~actual_taken) |
(ap.predict_nt & actual_taken);
// target mispredicts on ret's
assign target_mispredict = pp_ff.pret & (pp_ff.prett[31:1] != aout[31:1]);
assign flush_upper = ( ap.jal | cond_mispredict | target_mispredict) & valid_ff & ~flush & ~freeze;
// .i 3
// .o 2
// .ilb hist[1] hist[0] taken
// .ob newhist[1] newhist[0]
// .type fd
//
// 00 0 01
// 01 0 01
// 10 0 00
// 11 0 10
// 00 1 10
// 01 1 00
// 10 1 11
// 11 1 11
logic [1:0] newhist;
assign newhist[1] = (pp_ff.hist[1]&pp_ff.hist[0]) | (!pp_ff.hist[0]&actual_taken);
assign newhist[0] = (!pp_ff.hist[1]&!actual_taken) | (pp_ff.hist[1]&actual_taken);
always_comb begin
predict_p_ff = pp_ff;
predict_p_ff.misp = (valid_ff) ? (cond_mispredict | target_mispredict) & ~flush : pp_ff.misp;
predict_p_ff.ataken = (valid_ff) ? actual_taken : pp_ff.ataken;
predict_p_ff.hist[1] = (valid_ff) ? newhist[1] : pp_ff.hist[1];
predict_p_ff.hist[0] = (valid_ff) ? newhist[0] : pp_ff.hist[0];
end
endmodule // exu_alu_ctl

315
design/exu/exu_div_ctl.sv Normal file
View File

@ -0,0 +1,315 @@
// 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.
module exu_div_ctl
import swerv_types::*;
(
input logic clk, // Top level clock
input logic active_clk, // Level 1 active clock
input logic rst_l, // Reset
input logic scan_mode, // Scan mode
input logic dec_tlu_fast_div_disable, // Disable small number optimization
input logic [31:0] dividend, // Numerator
input logic [31:0] divisor, // Denominator
input div_pkt_t dp, // valid, sign, rem
input logic flush_lower, // Flush pipeline
output logic valid_ff_e1, // Valid E1 stage
output logic finish_early, // Finish smallnum
output logic finish, // Finish smallnum or normal divide
output logic div_stall, // Divide is running
output logic [31:0] out // Result
);
logic run_in, run_state;
logic [5:0] count_in, count;
logic [32:0] m_ff;
logic qff_enable;
logic aff_enable;
logic [32:0] q_in, q_ff;
logic [32:0] a_in, a_ff;
logic [32:0] m_eff;
logic [32:0] a_shift;
logic dividend_neg_ff, divisor_neg_ff;
logic [31:0] dividend_comp;
logic [31:0] dividend_eff;
logic [31:0] q_ff_comp;
logic [31:0] q_ff_eff;
logic [31:0] a_ff_comp;
logic [31:0] a_ff_eff;
logic sign_ff, sign_eff;
logic rem_ff;
logic add;
logic [32:0] a_eff;
logic [64:0] a_eff_shift;
logic rem_correct;
logic flush_lower_ff;
logic valid_e1;
logic smallnum_case, smallnum_case_ff;
logic [3:0] smallnum, smallnum_ff;
logic m_already_comp;
rvdff #(1) flush_any_ff (.*, .clk(active_clk), .din(flush_lower), .dout(flush_lower_ff));
rvdff #(1) e1val_ff (.*, .clk(active_clk), .din(dp.valid & ~flush_lower_ff), .dout(valid_ff_e1));
rvdff #(1) runff (.*, .clk(active_clk), .din(run_in), .dout(run_state));
rvdff #(6) countff (.*, .clk(active_clk), .din(count_in[5:0]), .dout(count[5:0]));
rvdffs #(4) miscf (.*, .clk(active_clk), .din({dividend[31],divisor[31],sign_eff,dp.rem}), .dout({dividend_neg_ff,divisor_neg_ff,sign_ff,rem_ff}), .en(dp.valid));
rvdff #(5) smallnumff (.*, .clk(active_clk), .din({smallnum_case,smallnum[3:0]}), .dout({smallnum_case_ff,smallnum_ff[3:0]}));
rvdffe #(33) mff (.*, .en(dp.valid), .din({ ~dp.unsign & divisor[31], divisor[31:0]}), .dout(m_ff[32:0]));
rvdffe #(33) qff (.*, .en(qff_enable), .din(q_in[32:0]), .dout(q_ff[32:0]));
rvdffe #(33) aff (.*, .en(aff_enable), .din(a_in[32:0]), .dout(a_ff[32:0]));
rvtwoscomp #(32) dividend_c (.din(q_ff[31:0]), .dout(dividend_comp[31:0]));
rvtwoscomp #(32) q_ff_c (.din(q_ff[31:0]), .dout(q_ff_comp[31:0]));
rvtwoscomp #(32) a_ff_c (.din(a_ff[31:0]), .dout(a_ff_comp[31:0]));
assign valid_e1 = valid_ff_e1 & ~flush_lower_ff;
// START - short circuit logic for small numbers {{
// small number divides - any 4b / 4b is done in 1 cycle (divisor != 0)
// to generate espresso equations:
// 1) smalldiv > smalldiv.e
// 2) espresso -Dso -oeqntott smalldiv.e | addassign > smalldiv
// smallnum case does not cover divide by 0
assign smallnum_case = ((q_ff[31:4] == 28'b0) & (m_ff[31:4] == 28'b0) & (m_ff[31:0] != 32'b0) & ~rem_ff & valid_e1 & ~dec_tlu_fast_div_disable) |
((q_ff[31:0] == 32'b0) & (m_ff[31:0] != 32'b0) & ~rem_ff & valid_e1 & ~dec_tlu_fast_div_disable);
assign smallnum[3] = ( q_ff[3] & ~m_ff[3] & ~m_ff[2] & ~m_ff[1] );
assign smallnum[2] = ( q_ff[3] & ~m_ff[3] & ~m_ff[2] & ~m_ff[0]) |
( q_ff[2] & ~m_ff[3] & ~m_ff[2] & ~m_ff[1] ) |
( q_ff[3] & q_ff[2] & ~m_ff[3] & ~m_ff[2] );
assign smallnum[1] = ( q_ff[2] & ~m_ff[3] & ~m_ff[2] & ~m_ff[0]) |
( q_ff[1] & ~m_ff[3] & ~m_ff[2] & ~m_ff[1] ) |
( q_ff[3] & ~m_ff[3] & ~m_ff[1] & ~m_ff[0]) |
( q_ff[3] & ~q_ff[2] & ~m_ff[3] & ~m_ff[2] & m_ff[1] & m_ff[0]) |
(~q_ff[3] & q_ff[2] & q_ff[1] & ~m_ff[3] & ~m_ff[2] ) |
( q_ff[3] & q_ff[2] & ~m_ff[3] & ~m_ff[0]) |
( q_ff[3] & q_ff[2] & ~m_ff[3] & m_ff[2] & ~m_ff[1] ) |
( q_ff[3] & q_ff[1] & ~m_ff[3] & ~m_ff[1] ) |
( q_ff[3] & q_ff[2] & q_ff[1] & ~m_ff[3] & m_ff[2] );
assign smallnum[0] = ( q_ff[2] & q_ff[1] & q_ff[0] & ~m_ff[3] & ~m_ff[1] ) |
( q_ff[3] & ~q_ff[2] & q_ff[0] & ~m_ff[3] & m_ff[1] & m_ff[0]) |
( q_ff[2] & ~m_ff[3] & ~m_ff[1] & ~m_ff[0]) |
( q_ff[1] & ~m_ff[3] & ~m_ff[2] & ~m_ff[0]) |
( q_ff[0] & ~m_ff[3] & ~m_ff[2] & ~m_ff[1] ) |
(~q_ff[3] & q_ff[2] & ~q_ff[1] & ~m_ff[3] & ~m_ff[2] & m_ff[1] & m_ff[0]) |
(~q_ff[3] & q_ff[2] & q_ff[1] & ~m_ff[3] & ~m_ff[0]) |
( q_ff[3] & ~m_ff[2] & ~m_ff[1] & ~m_ff[0]) |
( q_ff[3] & ~q_ff[2] & ~m_ff[3] & m_ff[2] & m_ff[1] ) |
(~q_ff[3] & q_ff[2] & q_ff[1] & ~m_ff[3] & m_ff[2] & ~m_ff[1] ) |
(~q_ff[3] & q_ff[2] & q_ff[0] & ~m_ff[3] & ~m_ff[1] ) |
( q_ff[3] & ~q_ff[2] & ~q_ff[1] & ~m_ff[3] & m_ff[2] & m_ff[0]) |
( ~q_ff[2] & q_ff[1] & q_ff[0] & ~m_ff[3] & ~m_ff[2] ) |
( q_ff[3] & q_ff[2] & ~m_ff[1] & ~m_ff[0]) |
( q_ff[3] & q_ff[1] & ~m_ff[2] & ~m_ff[0]) |
(~q_ff[3] & q_ff[2] & q_ff[1] & q_ff[0] & ~m_ff[3] & m_ff[2] ) |
( q_ff[3] & q_ff[2] & m_ff[3] & ~m_ff[2] ) |
( q_ff[3] & q_ff[1] & m_ff[3] & ~m_ff[2] & ~m_ff[1] ) |
( q_ff[3] & q_ff[0] & ~m_ff[2] & ~m_ff[1] ) |
( q_ff[3] & ~q_ff[1] & ~m_ff[3] & m_ff[2] & m_ff[1] & m_ff[0]) |
( q_ff[3] & q_ff[2] & q_ff[1] & m_ff[3] & ~m_ff[0]) |
( q_ff[3] & q_ff[2] & q_ff[1] & m_ff[3] & ~m_ff[1] ) |
( q_ff[3] & q_ff[2] & q_ff[0] & m_ff[3] & ~m_ff[1] ) |
( q_ff[3] & ~q_ff[2] & q_ff[1] & ~m_ff[3] & m_ff[1] ) |
( q_ff[3] & q_ff[1] & q_ff[0] & ~m_ff[2] ) |
( q_ff[3] & q_ff[2] & q_ff[1] & q_ff[0] & m_ff[3] );
// END - short circuit logic for small numbers }}
// *** Start Short Q *** {{
logic [4:0] a_cls;
logic [4:0] b_cls;
logic [5:0] shortq;
logic [5:0] shortq_shift;
logic [5:0] shortq_shift_ff;
logic shortq_enable;
logic shortq_enable_ff;
logic [32:0] short_dividend;
assign short_dividend[31:0] = q_ff[31:0];
assign short_dividend[32] = sign_ff & q_ff[31];
// A B
// 210 210 SH
// --- --- --
// 1xx 000 0
// 1xx 001 8
// 1xx 01x 16
// 1xx 1xx 24
// 01x 000 8
// 01x 001 16
// 01x 01x 24
// 01x 1xx 32
// 001 000 16
// 001 001 24
// 001 01x 32
// 001 1xx 32
// 000 000 24
// 000 001 32
// 000 01x 32
// 000 1xx 32
logic [3:0] shortq_raw;
logic [3:0] shortq_shift_xx;
assign a_cls[4:3] = 2'b0;
assign a_cls[2] = (~short_dividend[32] & (short_dividend[31:24] != {8{1'b0}})) | ( short_dividend[32] & (short_dividend[31:23] != {9{1'b1}}));
assign a_cls[1] = (~short_dividend[32] & (short_dividend[23:16] != {8{1'b0}})) | ( short_dividend[32] & (short_dividend[22:15] != {8{1'b1}}));
assign a_cls[0] = (~short_dividend[32] & (short_dividend[15:08] != {8{1'b0}})) | ( short_dividend[32] & (short_dividend[14:07] != {8{1'b1}}));
assign b_cls[4:3] = 2'b0;
assign b_cls[2] = (~m_ff[32] & ( m_ff[31:24] != {8{1'b0}})) | ( m_ff[32] & ( m_ff[31:24] != {8{1'b1}}));
assign b_cls[1] = (~m_ff[32] & ( m_ff[23:16] != {8{1'b0}})) | ( m_ff[32] & ( m_ff[23:16] != {8{1'b1}}));
assign b_cls[0] = (~m_ff[32] & ( m_ff[15:08] != {8{1'b0}})) | ( m_ff[32] & ( m_ff[15:08] != {8{1'b1}}));
assign shortq_raw[3] = ( (a_cls[2:1] == 2'b01 ) & (b_cls[2] == 1'b1 ) ) | // Shift by 32
( (a_cls[2:0] == 3'b001) & (b_cls[2] == 1'b1 ) ) |
( (a_cls[2:0] == 3'b000) & (b_cls[2] == 1'b1 ) ) |
( (a_cls[2:0] == 3'b001) & (b_cls[2:1] == 2'b01 ) ) |
( (a_cls[2:0] == 3'b000) & (b_cls[2:1] == 2'b01 ) ) |
( (a_cls[2:0] == 3'b000) & (b_cls[2:0] == 3'b001) );
assign shortq_raw[2] = ( (a_cls[2] == 1'b1 ) & (b_cls[2] == 1'b1 ) ) | // Shift by 24
( (a_cls[2:1] == 2'b01 ) & (b_cls[2:1] == 2'b01 ) ) |
( (a_cls[2:0] == 3'b001) & (b_cls[2:0] == 3'b001) ) |
( (a_cls[2:0] == 3'b000) & (b_cls[2:0] == 3'b000) );
assign shortq_raw[1] = ( (a_cls[2] == 1'b1 ) & (b_cls[2:1] == 2'b01 ) ) | // Shift by 16
( (a_cls[2:1] == 2'b01 ) & (b_cls[2:0] == 3'b001) ) |
( (a_cls[2:0] == 3'b001) & (b_cls[2:0] == 3'b000) );
assign shortq_raw[0] = ( (a_cls[2] == 1'b1 ) & (b_cls[2:0] == 3'b001) ) | // Shift by 8
( (a_cls[2:1] == 2'b01 ) & (b_cls[2:0] == 3'b000) );
assign shortq_enable = valid_ff_e1 & (m_ff[31:0] != 32'b0) & (shortq_raw[3:0] != 4'b0);
assign shortq_shift[3:0] = ({4{shortq_enable}} & shortq_raw[3:0]);
rvdff #(5) i_shortq_ff (.*, .clk(active_clk), .din({shortq_enable,shortq_shift[3:0]}), .dout({shortq_enable_ff,shortq_shift_xx[3:0]}));
assign shortq_shift_ff[5:0] = ({6{shortq_shift_xx[3]}} & 6'b01_1111) | // 31
({6{shortq_shift_xx[2]}} & 6'b01_1000) | // 24
({6{shortq_shift_xx[1]}} & 6'b01_0000) | // 16
({6{shortq_shift_xx[0]}} & 6'b00_1000); // 8
`ifdef ASSERT_ON
logic div_assert_fail;
assign div_assert_fail = (shortq_shift_xx[3] & shortq_shift_xx[2]) |
(shortq_shift_xx[3] & shortq_shift_xx[1]) |
(shortq_shift_xx[3] & shortq_shift_xx[0]) |
(shortq_shift_xx[2] & shortq_shift_xx[1]) |
(shortq_shift_xx[2] & shortq_shift_xx[0]) |
(shortq_shift_xx[1] & shortq_shift_xx[0]);
assert_exu_div_shortq_shift_error: assert #0 (~div_assert_fail) else $display("ERROR: SHORTQ_SHIFT_XX with multiple shifts ON!");
`endif
// *** End Short Q *** }}
assign div_stall = run_state;
assign run_in = (dp.valid | run_state) & ~finish & ~flush_lower_ff;
assign count_in[5:0] = {6{run_state & ~finish & ~flush_lower_ff & ~shortq_enable}} & (count[5:0] + shortq_shift_ff[5:0] + 6'd1);
assign finish_early = smallnum_case;
assign finish = (smallnum_case | ((~rem_ff) ? (count[5:0] == 6'd32) : (count[5:0] == 6'd33))) & ~flush_lower & ~flush_lower_ff;
assign sign_eff = ~dp.unsign & (divisor[31:0] != 32'b0);
assign q_in[32:0] = ({33{~run_state }} & {1'b0,dividend[31:0]}) |
({33{ run_state & (valid_ff_e1 | shortq_enable_ff)}} & ({dividend_eff[31:0], ~a_in[32]} << shortq_shift_ff[5:0])) |
({33{ run_state & ~(valid_ff_e1 | shortq_enable_ff)}} & {q_ff[31:0], ~a_in[32]});
assign qff_enable = dp.valid | (run_state & ~shortq_enable);
assign dividend_eff[31:0] = (sign_ff & dividend_neg_ff) ? dividend_comp[31:0] : q_ff[31:0];
assign m_eff[32:0] = (add) ? m_ff[32:0] : ~m_ff[32:0];
assign a_eff_shift[64:0] = {33'b0, dividend_eff[31:0]} << shortq_shift_ff[5:0];
assign a_eff[32:0] = ({33{ rem_correct }} & a_ff[32:0] ) |
({33{~rem_correct & ~shortq_enable_ff}} & {a_ff[31:0], q_ff[32]}) |
({33{~rem_correct & shortq_enable_ff}} & a_eff_shift[64:32] );
assign a_shift[32:0] = {33{run_state}} & a_eff[32:0];
assign a_in[32:0] = {33{run_state}} & (a_shift[32:0] + m_eff[32:0] + {32'b0,~add});
assign aff_enable = dp.valid | (run_state & ~shortq_enable & (count[5:0]!=6'd33)) | rem_correct;
assign m_already_comp = (divisor_neg_ff & sign_ff);
// if m already complemented, then invert operation add->sub, sub->add
assign add = (a_ff[32] | rem_correct) ^ m_already_comp;
assign rem_correct = (count[5:0] == 6'd33) & rem_ff & a_ff[32];
assign q_ff_eff[31:0] = (sign_ff & (dividend_neg_ff ^ divisor_neg_ff)) ? q_ff_comp[31:0] : q_ff[31:0];
assign a_ff_eff[31:0] = (sign_ff & dividend_neg_ff) ? a_ff_comp[31:0] : a_ff[31:0];
assign out[31:0] = ({32{ smallnum_case_ff }} & {28'b0, smallnum_ff[3:0]}) |
({32{ rem_ff}} & a_ff_eff[31:0] ) |
({32{~smallnum_case_ff & ~rem_ff}} & q_ff_eff[31:0] );
endmodule // exu_div_ctl

118
design/exu/exu_mul_ctl.sv Normal file
View File

@ -0,0 +1,118 @@
// 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.
module exu_mul_ctl
import swerv_types::*;
(
input logic clk, // Top level clock
input logic active_clk, // Level 1 active clock
input logic clk_override, // Override clock enables
input logic rst_l, // Reset
input logic scan_mode, // Scan mode
input logic [31:0] a, // A operand
input logic [31:0] b, // B operand
input logic [31:0] lsu_result_dc3, // Load result used in E1 bypass
input logic freeze, // Pipeline freeze
input mul_pkt_t mp, // valid, rs1_sign, rs2_sign, low, load_mul_rs1_bypass_e1, load_mul_rs2_bypass_e1
output logic [31:0] out // Result
);
logic valid_e1, valid_e2;
logic mul_c1_e1_clken, mul_c1_e2_clken, mul_c1_e3_clken;
logic exu_mul_c1_e1_clk, exu_mul_c1_e2_clk, exu_mul_c1_e3_clk;
logic [31:0] a_ff_e1, a_e1;
logic [31:0] b_ff_e1, b_e1;
logic load_mul_rs1_bypass_e1, load_mul_rs2_bypass_e1;
logic rs1_sign_e1, rs1_neg_e1;
logic rs2_sign_e1, rs2_neg_e1;
logic signed [32:0] a_ff_e2, b_ff_e2;
logic [63:0] prod_e3;
logic low_e1, low_e2, low_e3;
// --------------------------- Clock gating ----------------------------------
// C1 clock enables
assign mul_c1_e1_clken = (mp.valid | clk_override) & ~freeze;
assign mul_c1_e2_clken = (valid_e1 | clk_override) & ~freeze;
assign mul_c1_e3_clken = (valid_e2 | clk_override) & ~freeze;
// C1 - 1 clock pulse for data
rvclkhdr exu_mul_c1e1_cgc (.*, .en(mul_c1_e1_clken), .l1clk(exu_mul_c1_e1_clk));
rvclkhdr exu_mul_c1e2_cgc (.*, .en(mul_c1_e2_clken), .l1clk(exu_mul_c1_e2_clk));
rvclkhdr exu_mul_c1e3_cgc (.*, .en(mul_c1_e3_clken), .l1clk(exu_mul_c1_e3_clk));
// --------------------------- Input flops ----------------------------------
rvdffs #(1) valid_e1_ff (.*, .din(mp.valid), .dout(valid_e1), .clk(active_clk), .en(~freeze));
rvdff #(1) rs1_sign_e1_ff (.*, .din(mp.rs1_sign), .dout(rs1_sign_e1), .clk(exu_mul_c1_e1_clk));
rvdff #(1) rs2_sign_e1_ff (.*, .din(mp.rs2_sign), .dout(rs2_sign_e1), .clk(exu_mul_c1_e1_clk));
rvdff #(1) low_e1_ff (.*, .din(mp.low), .dout(low_e1), .clk(exu_mul_c1_e1_clk));
rvdff #(1) ld_rs1_byp_e1_ff (.*, .din(mp.load_mul_rs1_bypass_e1), .dout(load_mul_rs1_bypass_e1), .clk(exu_mul_c1_e1_clk));
rvdff #(1) ld_rs2_byp_e1_ff (.*, .din(mp.load_mul_rs2_bypass_e1), .dout(load_mul_rs2_bypass_e1), .clk(exu_mul_c1_e1_clk));
rvdff #(32) a_e1_ff (.*, .din(a[31:0]), .dout(a_ff_e1[31:0]), .clk(exu_mul_c1_e1_clk));
rvdff #(32) b_e1_ff (.*, .din(b[31:0]), .dout(b_ff_e1[31:0]), .clk(exu_mul_c1_e1_clk));
// --------------------------- E1 Logic Stage ----------------------------------
assign a_e1[31:0] = (load_mul_rs1_bypass_e1) ? lsu_result_dc3[31:0] : a_ff_e1[31:0];
assign b_e1[31:0] = (load_mul_rs2_bypass_e1) ? lsu_result_dc3[31:0] : b_ff_e1[31:0];
assign rs1_neg_e1 = rs1_sign_e1 & a_e1[31];
assign rs2_neg_e1 = rs2_sign_e1 & b_e1[31];
rvdffs #(1) valid_e2_ff (.*, .din(valid_e1), .dout(valid_e2), .clk(active_clk), .en(~freeze));
rvdff #(1) low_e2_ff (.*, .din(low_e1), .dout(low_e2), .clk(exu_mul_c1_e2_clk));
rvdff #(33) a_e2_ff (.*, .din({rs1_neg_e1, a_e1[31:0]}), .dout(a_ff_e2[32:0]), .clk(exu_mul_c1_e2_clk));
rvdff #(33) b_e2_ff (.*, .din({rs2_neg_e1, b_e1[31:0]}), .dout(b_ff_e2[32:0]), .clk(exu_mul_c1_e2_clk));
// ---------------------- E2 Logic Stage --------------------------
logic signed [65:0] prod_e2;
assign prod_e2[65:0] = a_ff_e2 * b_ff_e2;
rvdff #(1) low_e3_ff (.*, .din(low_e2), .dout(low_e3), .clk(exu_mul_c1_e3_clk));
rvdff #(64) prod_e3_ff (.*, .din(prod_e2[63:0]), .dout(prod_e3[63:0]), .clk(exu_mul_c1_e3_clk));
// ----------------------- E3 Logic Stage -------------------------
assign out[31:0] = low_e3 ? prod_e3[31:0] : prod_e3[63:32];
endmodule // exu_mul_ctl

52
design/flist.questa Normal file
View File

@ -0,0 +1,52 @@
$RV_ROOT/workspace/work/snapshots/default/common_defines.vh
$RV_ROOT/design/include/def.sv
+incdir+$RV_ROOT/workspace/work/snapshots/default
+incdir+$RV_ROOT/design/lib
+incdir+$RV_ROOT/design/include
+incdir+$RV_ROOT/design/dmi
$RV_ROOT/design/swerv_wrapper.sv
$RV_ROOT/design/mem.sv
$RV_ROOT/design/pic_ctrl.sv
$RV_ROOT/design/swerv.sv
$RV_ROOT/design/dma_ctrl.sv
$RV_ROOT/design/ifu/ifu_aln_ctl.sv
$RV_ROOT/design/ifu/ifu_compress_ctl.sv
$RV_ROOT/design/ifu/ifu_ifc_ctl.sv
$RV_ROOT/design/ifu/ifu_bp_ctl.sv
$RV_ROOT/design/ifu/ifu_ic_mem.sv
$RV_ROOT/design/ifu/ifu_mem_ctl.sv
$RV_ROOT/design/ifu/ifu_iccm_mem.sv
$RV_ROOT/design/ifu/ifu.sv
$RV_ROOT/design/dec/dec_decode_ctl.sv
$RV_ROOT/design/dec/dec_gpr_ctl.sv
$RV_ROOT/design/dec/dec_ib_ctl.sv
$RV_ROOT/design/dec/dec_tlu_ctl.sv
$RV_ROOT/design/dec/dec_trigger.sv
$RV_ROOT/design/dec/dec.sv
$RV_ROOT/design/exu/exu_alu_ctl.sv
$RV_ROOT/design/exu/exu_mul_ctl.sv
$RV_ROOT/design/exu/exu_div_ctl.sv
$RV_ROOT/design/exu/exu.sv
$RV_ROOT/design/lsu/lsu.sv
$RV_ROOT/design/lsu/lsu_clkdomain.sv
$RV_ROOT/design/lsu/lsu_addrcheck.sv
$RV_ROOT/design/lsu/lsu_lsc_ctl.sv
$RV_ROOT/design/lsu/lsu_stbuf.sv
$RV_ROOT/design/lsu/lsu_bus_buffer.sv
$RV_ROOT/design/lsu/lsu_bus_intf.sv
$RV_ROOT/design/lsu/lsu_ecc.sv
$RV_ROOT/design/lsu/lsu_dccm_mem.sv
$RV_ROOT/design/lsu/lsu_dccm_ctl.sv
$RV_ROOT/design/lsu/lsu_trigger.sv
$RV_ROOT/design/dbg/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.sv
$RV_ROOT/design/lib/beh_lib.sv
$RV_ROOT/design/lib/mem_lib.sv
$RV_ROOT/design/lib/svci_to_ahb.sv
$RV_ROOT/design/lib/ahb_to_svci.sv
$RV_ROOT/design/lib/svci_to_axi4.sv
$RV_ROOT/design/lib/axi4_to_svci.sv
$RV_ROOT/design/lib/ahb_to_axi4.sv
$RV_ROOT/design/lib/axi4_to_ahb.sv

406
design/ifu/ifu.sv Normal file
View File

@ -0,0 +1,406 @@
//********************************************************************************
// 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.
//********************************************************************************
//********************************************************************************
// Function: Top level file for Icache, Fetch, Branch prediction & Aligner
// BFF -> F1 -> F2 -> A
//********************************************************************************
module ifu
import swerv_types::*;
(
input logic free_clk,
input logic active_clk,
input logic clk,
input logic clk_override,
input logic rst_l,
input logic dec_ib3_valid_d, dec_ib2_valid_d, // mass balance for decode buffer
input logic dec_ib0_valid_eff_d, // effective valid taking decode into account
input logic dec_ib1_valid_eff_d, // effective valid taking decode into account
input logic exu_i0_br_ret_e4, // i0 branch commit is a ret
input logic exu_i1_br_ret_e4, // i1 branch commit is a ret
input logic exu_i0_br_call_e4, // i0 branch commit is a call
input logic exu_i1_br_call_e4, // i1 branch commit is a call
input logic exu_flush_final, // flush, includes upper and lower
input logic dec_tlu_flush_err_wb , // flush due to parity error.
input logic dec_tlu_flush_noredir_wb, // don't fetch, validated with exu_flush_final
input logic dec_tlu_dbg_halted, // halted, used for leaving IDLE state
input logic dec_tlu_pmu_fw_halted, // Core is halted
input logic [31:1] exu_flush_path_final, // flush fetch address
input logic exu_flush_upper_e2, // flush upper, either i0 or i1
input logic [31:0] dec_tlu_mrac_ff ,// Side_effect , cacheable for each region
input logic dec_tlu_fence_i_wb, // fence.i, invalidate icache, validated with exu_flush_final
input logic dec_tlu_flush_leak_one_wb, // ignore bp for leak one fetches
input logic dec_tlu_bpred_disable, // disable all branch prediction
input logic dec_tlu_core_ecc_disable, // disable ecc checking and flagging
// AXI Write Channels - IFU never writes. So, 0 out mostly
output logic ifu_axi_awvalid,
input logic ifu_axi_awready,
output logic [`RV_IFU_BUS_TAG-1:0] ifu_axi_awid,
output logic [31:0] ifu_axi_awaddr,
output logic [3:0] ifu_axi_awregion,
output logic [7:0] ifu_axi_awlen,
output logic [2:0] ifu_axi_awsize,
output logic [1:0] ifu_axi_awburst,
output logic ifu_axi_awlock,
output logic [3:0] ifu_axi_awcache,
output logic [2:0] ifu_axi_awprot,
output logic [3:0] ifu_axi_awqos,
output logic ifu_axi_wvalid,
input logic ifu_axi_wready,
output logic [63:0] ifu_axi_wdata,
output logic [7:0] ifu_axi_wstrb,
output logic ifu_axi_wlast,
input logic ifu_axi_bvalid,
output logic ifu_axi_bready,
input logic [1:0] ifu_axi_bresp,
input logic [`RV_IFU_BUS_TAG-1:0] ifu_axi_bid,
// AXI Read Channels
output logic ifu_axi_arvalid,
input logic ifu_axi_arready,
output logic [`RV_IFU_BUS_TAG-1:0] ifu_axi_arid,
output logic [31:0] ifu_axi_araddr,
output logic [3:0] ifu_axi_arregion,
output logic [7:0] ifu_axi_arlen,
output logic [2:0] ifu_axi_arsize,
output logic [1:0] ifu_axi_arburst,
output logic ifu_axi_arlock,
output logic [3:0] ifu_axi_arcache,
output logic [2:0] ifu_axi_arprot,
output logic [3:0] ifu_axi_arqos,
input logic ifu_axi_rvalid,
output logic ifu_axi_rready,
input logic [`RV_IFU_BUS_TAG-1:0] ifu_axi_rid,
input logic [63:0] ifu_axi_rdata,
input logic [1:0] ifu_axi_rresp,
input logic ifu_axi_rlast,
//// AHB LITE BUS
//`ifdef RV_BUILD_AHB_LITE
input logic ifu_bus_clk_en,
input logic dma_iccm_req,
input logic dma_iccm_stall_any,
input logic [31:0] dma_mem_addr,
input logic [2:0] dma_mem_sz,
input logic dma_mem_write,
input logic [63:0] dma_mem_wdata,
output logic iccm_dma_ecc_error,
output logic iccm_dma_rvalid,
output logic [63:0] iccm_dma_rdata,
output logic iccm_ready,
//`endif
output logic [1:0] ifu_pmu_instr_aligned,
output logic ifu_pmu_align_stall,
output logic ifu_pmu_fetch_stall,
// I$ & ITAG Ports
output logic [31:3] ic_rw_addr, // Read/Write addresss to the Icache.
output logic [3:0] ic_wr_en, // Icache write enable, when filling the Icache.
output logic ic_rd_en, // Icache read enable.
`ifdef RV_ICACHE_ECC
output logic [83:0] ic_wr_data, // Data to fill to the Icache. With ECC
input logic [167:0] ic_rd_data , // Data read from Icache. 2x64bits + parity bits. F2 stage. With ECC
input logic [24:0] ictag_debug_rd_data,// Debug icache tag.
output logic [41:0] ic_debug_wr_data, // Debug wr cache.
output logic [41:0] ifu_ic_debug_rd_data,
`else
output logic [67:0] ic_wr_data, // Data to fill to the Icache. With Parity
input logic [135:0] ic_rd_data , // Data read from Icache. 2x64bits + parity bits. F2 stage. With Parity
input logic [20:0] ictag_debug_rd_data,// Debug icache tag.
output logic [33:0] ic_debug_wr_data, // Debug wr cache.
output logic [33:0] ifu_ic_debug_rd_data,
`endif
output logic [127:0] ic_premux_data, // Premux data to be muxed with each way of the Icache.
output logic ic_sel_premux_data, // Select the premux data.
output logic [15:2] ic_debug_addr, // Read/Write addresss to the Icache.
output logic ic_debug_rd_en, // Icache debug rd
output logic ic_debug_wr_en, // Icache debug wr
output logic ic_debug_tag_array, // Debug tag array
output logic [3:0] ic_debug_way, // Debug way. Rd or Wr.
output logic [3:0] ic_tag_valid, // Valid bits when accessing the Icache. One valid bit per way. F2 stage
input logic [3:0] ic_rd_hit, // Compare hits from Icache tags. Per way. F2 stage
input logic ic_tag_perr, // Icache Tag parity error
`ifdef RV_ICCM_ENABLE
// ICCM ports
output logic [`RV_ICCM_BITS-1:2] iccm_rw_addr, // ICCM read/write address.
output logic iccm_wren, // ICCM write enable (through the DMA)
output logic iccm_rden, // ICCM read enable.
output logic [77:0] iccm_wr_data, // ICCM write data.
output logic [2:0] iccm_wr_size, // ICCM write location within DW.
input logic [155:0] iccm_rd_data, // Data read from ICCM.
`endif
// Perf counter sigs
output logic ifu_pmu_ic_miss, // ic miss
output logic ifu_pmu_ic_hit, // ic hit
output logic ifu_pmu_bus_error, // iside bus error
output logic ifu_pmu_bus_busy, // iside bus busy
output logic ifu_pmu_bus_trxn, // iside bus transactions
output logic ifu_i0_valid, // Instruction 0 valid. From Aligner to Decode
output logic ifu_i1_valid, // Instruction 1 valid. From Aligner to Decode
output logic ifu_i0_icaf, // Instruction 0 access fault. From Aligner to Decode
output logic ifu_i1_icaf, // Instruction 1 access fault. From Aligner to Decode
output logic ifu_i0_icaf_f1, // Instruction 0 has access fault on second fetch group
output logic ifu_i1_icaf_f1, // Instruction 1 has access fault on second fetch group
output logic ifu_i0_perr, // Instruction 0 parity error. From Aligner to Decode
output logic ifu_i1_perr, // Instruction 1 parity error. From Aligner to Decode
output logic ifu_i0_sbecc, // Instruction 0 has single bit ecc error
output logic ifu_i1_sbecc, // Instruction 1 has single bit ecc error
output logic ifu_i0_dbecc, // Instruction 0 has double bit ecc error
output logic ifu_i1_dbecc, // Instruction 1 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, // Instruction 0 . From Aligner to Decode
output logic[31:0] ifu_i1_instr, // Instruction 1 . From Aligner to Decode
output logic[31:1] ifu_i0_pc, // Instruction 0 pc. From Aligner to Decode
output logic[31:1] ifu_i1_pc, // Instruction 1 pc. From Aligner to Decode
output logic ifu_i0_pc4, // Instruction 0 is 4 byte. From Aligner to Decode
output logic ifu_i1_pc4, // Instruction 1 is 4 byte. From Aligner to Decode
output logic [15:0] ifu_illegal_inst, // Illegal instruction.
output logic ifu_miss_state_idle, // There is no outstanding miss. Cache miss state is idle.
output br_pkt_t i0_brp, // Instruction 0 branch packet. From Aligner to Decode
output br_pkt_t i1_brp, // Instruction 1 branch packet. From Aligner to Decode
input predict_pkt_t exu_mp_pkt, // mispredict packet
input logic [`RV_BHT_GHR_RANGE] exu_mp_eghr, // execute ghr
input br_tlu_pkt_t dec_tlu_br0_wb_pkt, // slot0 update/error pkt
input br_tlu_pkt_t dec_tlu_br1_wb_pkt, // slot1 update/error pkt
input dec_tlu_flush_lower_wb,
input rets_pkt_t exu_rets_e1_pkt, // E1 return stack packet
input rets_pkt_t exu_rets_e4_pkt, // E4 return stack packet
// pc's used to maintain and update the BP RET stacks
`ifdef REAL_COMM_RS
input logic [31:1] exu_i0_pc_e1,
input logic [31:1] exu_i1_pc_e1,
input logic [31:1] dec_tlu_i0_pc_e4,
input logic [31:1] dec_tlu_i1_pc_e4,
`endif
output logic [15:0] ifu_i0_cinst,
output logic [15:0] ifu_i1_cinst,
/// Icache debug
input cache_debug_pkt_t dec_tlu_ic_diag_pkt ,
output logic ifu_ic_debug_rd_data_valid,
input logic scan_mode
);
localparam TAGWIDTH = 2 ;
localparam IDWIDTH = 2 ;
logic ifu_fb_consume1, ifu_fb_consume2;
logic [31:1] ifc_fetch_addr_f2;
logic ifc_fetch_uncacheable_f1;
logic [7:0] ifu_fetch_val; // valids on a 2B boundary, left justified [7] implies valid fetch
logic [31:1] ifu_fetch_pc; // starting pc of fetch
logic [31:1] ifc_fetch_addr_f1;
logic ic_crit_wd_rdy;
logic ic_write_stall;
logic ic_dma_active;
logic ifc_dma_access_ok;
logic ifc_iccm_access_f1;
logic ifc_region_acc_fault_f1;
logic ic_access_fault_f2;
logic ifu_ic_mb_empty;
logic ic_hit_f2;
// fetch control
ifu_ifc_ctl ifc (.*
);
`ifdef RV_BTB_48
logic [7:0][1:0] ifu_bp_way_f2; // way indication; right justified
`else
logic [7:0] ifu_bp_way_f2; // way indication; right justified
`endif
logic ifu_bp_kill_next_f2; // kill next fetch; taken target found
logic [31:1] ifu_bp_btb_target_f2; // predicted target PC
logic [7:1] ifu_bp_inst_mask_f2; // tell ic which valids to kill because of a taken branch; right justified
logic [7:0] ifu_bp_hist1_f2; // history counters for all 4 potential branches; right justified
logic [7:0] ifu_bp_hist0_f2; // history counters for all 4 potential branches; right justified
logic [11:0] ifu_bp_poffset_f2; // predicted target
logic [7:0] ifu_bp_ret_f2; // predicted ret ; right justified
logic [7:0] ifu_bp_pc4_f2; // pc4 indication; right justified
logic [7:0] ifu_bp_valid_f2; // branch valid, right justified
logic [`RV_BHT_GHR_RANGE] ifu_bp_fghr_f2;
// branch predictor
ifu_bp_ctl bp (.*);
logic [7:0] ic_fetch_val_f2;
logic [127:0] ic_data_f2;
logic [127:0] ifu_fetch_data;
logic ifc_fetch_req_f1_raw, ifc_fetch_req_f1, ifc_fetch_req_f2;
logic ic_rd_parity_final_err; // This fetch has a data_cache or tag parity error.
logic iccm_rd_ecc_single_err; // This fetch has an iccm single error.
logic iccm_rd_ecc_double_err; // This fetch has an iccm double error.
icache_err_pkt_t ic_error_f2;
logic ifu_icache_fetch_f2 ;
logic [16:2] ifu_icache_error_index; // Index with parity error
logic ifu_icache_error_val; // Parity error
logic ifu_icache_sb_error_val;
assign ifu_fetch_data[127:0] = ic_data_f2[127:0];
assign ifu_fetch_val[7:0] = ic_fetch_val_f2[7:0];
assign ifu_fetch_pc[31:1] = ifc_fetch_addr_f2[31:1];
// aligner
ifu_aln_ctl aln (.*);
// icache
ifu_mem_ctl mem_ctl
(.*,
.fetch_addr_f1(ifc_fetch_addr_f1),
.ifu_icache_error_index(ifu_icache_error_index[16:6]),
.ic_hit_f2(ic_hit_f2),
.ic_data_f2(ic_data_f2[127:0])
);
// Performance debug info
//
//
`ifdef DUMP_BTB_ON
logic exu_mp_valid; // conditional branch mispredict
logic exu_mp_way; // conditional branch mispredict
logic exu_mp_ataken; // direction is actual taken
logic exu_mp_boffset; // branch offsett
logic exu_mp_pc4; // branch is a 4B inst
logic exu_mp_call; // branch is a call inst
logic exu_mp_ret; // branch is a ret inst
logic exu_mp_ja; // branch is a jump always
logic [1:0] exu_mp_hist; // new history
logic [11:0] exu_mp_tgt; // target offset
logic [`RV_BTB_ADDR_HI:`RV_BTB_ADDR_LO] exu_mp_addr; // BTB/BHT address
logic [1:0] exu_mp_bank; // write bank; based on branch PC[3:2]
logic [`RV_BTB_BTAG_SIZE-1:0] exu_mp_btag; // branch tag
logic [`RV_BHT_GHR_RANGE] exu_mp_fghr; // original fetch ghr (for correcting dir)
assign exu_mp_valid = exu_mp_pkt.misp; // conditional branch mispredict
assign exu_mp_ataken = exu_mp_pkt.ataken; // direction is actual taken
assign exu_mp_boffset = exu_mp_pkt.boffset; // branch offset
assign exu_mp_pc4 = exu_mp_pkt.pc4; // branch is a 4B inst
assign exu_mp_call = exu_mp_pkt.pcall; // branch is a call inst
assign exu_mp_ret = exu_mp_pkt.pret; // branch is a ret inst
assign exu_mp_ja = exu_mp_pkt.pja; // branch is a jump always
assign exu_mp_way = exu_mp_pkt.way; // branch is a jump always
assign exu_mp_hist[1:0] = exu_mp_pkt.hist[1:0]; // new history
assign exu_mp_tgt[11:0] = exu_mp_pkt.toffset[11:0] ; // target offset
assign exu_mp_addr[`RV_BTB_ADDR_HI:`RV_BTB_ADDR_LO] = exu_mp_pkt.index[`RV_BTB_ADDR_HI:`RV_BTB_ADDR_LO] ; // BTB/BHT address
assign exu_mp_bank[1:0] = exu_mp_pkt.bank[1:0] ; // write bank = exu_mp_pkt.; based on branch PC[3:2]
assign exu_mp_btag = exu_mp_pkt.btag[`RV_BTB_BTAG_SIZE-1:0] ; // branch tag
assign exu_mp_fghr[`RV_BHT_GHR_RANGE] = exu_mp_pkt.fghr[`RV_BHT_GHR_RANGE] ; // original fetch ghr (for correcting dir)
logic [`RV_BTB_ADDR_HI:`RV_BTB_ADDR_LO] btb_rd_addr_f2;
`define DEC `CPU_TOP.dec
`define EXU `CPU_TOP.exu
rvbtb_addr_hash f2hash(.pc(ifc_fetch_addr_f2[31:1]), .hash(btb_rd_addr_f2[`RV_BTB_ADDR_HI:`RV_BTB_ADDR_LO]));
logic [31:0] mppc_ns, mppc;
assign mppc_ns[31:1] = `EXU.exu_i0_flush_upper_e1 ? `DEC.decode.i0_pc_e1[31:1] : (`EXU.exu_i1_flush_upper_e1 ? `DEC.decode.i1_pc_e1[31:1] : (`EXU.exu_i0_flush_lower_e4 ? `DEC.decode.i0_pc_e4[31:1] : `DEC.decode.i1_pc_e4[31:1]));
assign mppc_ns[0] = 1'b0;
logic [3:0] ic_rd_hit_f2;
rvdff #(36) mdseal_ff (.*, .din({mppc_ns[31:0], mem_ctl.ic_rd_hit[3:0]}), .dout({mppc[31:0],ic_rd_hit_f2[3:0]}));
logic [2:0] tmp_bnk;
assign tmp_bnk[2:0] = encode8_3(bp.btb_sel_f2[7:0]);
always @(negedge clk) begin
if(`DEC.tlu.mcyclel[31:0] == 32'h0000_0010) begin
$display("BTB_CONFIG: %d",`RV_BTB_ARRAY_DEPTH*4);
`ifndef BP_NOGSHARE
$display("BHT_CONFIG: %d gshare: 1",`RV_BHT_ARRAY_DEPTH*4);
`else
$display("BHT_CONFIG: %d gshare: 0",`RV_BHT_ARRAY_DEPTH*4);
`endif
$display("RS_CONFIG: %d", `RV_RET_STACK_SIZE);
end
if(exu_flush_final & ~(dec_tlu_br0_wb_pkt.br_error | dec_tlu_br0_wb_pkt.br_start_error | dec_tlu_br1_wb_pkt.br_error | dec_tlu_br1_wb_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[`RV_BTB_ADDR_HI:`RV_BTB_ADDR_LO], exu_mp_bank[1:0], exu_mp_call, exu_mp_ret, exu_mp_ataken, exu_mp_hist[1:0], exu_mp_valid, exu_mp_pkt.btag[`RV_BTB_BTAG_SIZE-1:0], {exu_flush_path_final[31:1], 1'b0}, exu_mp_eghr[`RV_BHT_GHR_RANGE], exu_mp_valid, bp.bht_wr_addr0, mppc[31:0], exu_mp_pkt.way);
for(int i = 0; i < 8; i++) begin
if(ifu_bp_valid_f2[i] & ifc_fetch_req_f2)
$display("%7d BTB_HIT : index: %0h bank: %0h call: %b ret: %b taken: %b strength: %b tag: %h targ: %h ghr: %4b ghr_index: %h way: %h", `DEC.tlu.mcyclel[31:0]+32'ha,btb_rd_addr_f2[`RV_BTB_ADDR_HI:`RV_BTB_ADDR_LO],encode8_3(bp.btb_sel_f2[7:0]), bp.btb_rd_call_f2, bp.btb_rd_ret_f2, ifu_bp_hist1_f2[tmp_bnk], ifu_bp_hist0_f2[tmp_bnk], bp.fetch_rd_tag_f2[`RV_BTB_BTAG_SIZE-1:0], {ifu_bp_btb_target_f2[31:1], 1'b0}, bp.fghr[`RV_BHT_GHR_RANGE], bp.bht_rd_addr_f1, ifu_bp_way_f2[tmp_bnk]);
end
`ifdef RV_BTB_48
for(int y = 0; y < 4; y++) begin
for(int z = 0; z < 4; z++) begin
if(bp.lru_bank_sel[y][z])
$display("%7d BTB_LRU: index: %0h bank: %0h newlru %h", `DEC.tlu.mcyclel[31:0]+32'ha, z,y,bp.lru_bank_wr_data[y][z]);
end
end
`endif
if(dec_tlu_br0_wb_pkt.valid & ~(dec_tlu_br0_wb_pkt.br_error | dec_tlu_br0_wb_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[`RV_BHT_ADDR_HI:`RV_BHT_ADDR_LO],{dec_tlu_br0_wb_pkt.bank[1:0],dec_tlu_br0_wb_pkt.middle}, dec_tlu_br0_wb_pkt.hist, dec_tlu_br0_wb_pkt.way);
if(dec_tlu_br1_wb_pkt.valid & ~(dec_tlu_br1_wb_pkt.br_error | dec_tlu_br1_wb_pkt.br_start_error))
$display("%7d BTB_UPD1: ghr_index: %0h bank: %0h hist: %h way: %h", `DEC.tlu.mcyclel[31:0]+32'ha,bp.br1_hashed_wb[`RV_BHT_ADDR_HI:`RV_BHT_ADDR_LO],{dec_tlu_br1_wb_pkt.bank[1:0],dec_tlu_br1_wb_pkt.middle}, dec_tlu_br1_wb_pkt.hist, dec_tlu_br1_wb_pkt.way);
if(dec_tlu_br0_wb_pkt.br_error | dec_tlu_br0_wb_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,dec_tlu_br0_wb_pkt.index[`RV_BTB_ADDR_HI:`RV_BTB_ADDR_LO],dec_tlu_br0_wb_pkt.bank[1:0], dec_tlu_br0_wb_pkt.br_start_error, {exu_flush_path_final[31:1], 1'b0}, dec_tlu_br0_wb_pkt.way);
if(dec_tlu_br1_wb_pkt.br_error | dec_tlu_br1_wb_pkt.br_start_error)
$display("%7d BTB_ERR1: index: %0h bank: %0h start: %b rfpc: %h way: %h", `DEC.tlu.mcyclel[31:0]+32'ha,dec_tlu_br1_wb_pkt.index[`RV_BTB_ADDR_HI:`RV_BTB_ADDR_LO],dec_tlu_br1_wb_pkt.bank[1:0], dec_tlu_br1_wb_pkt.br_start_error, {exu_flush_path_final[31:1], 1'b0}, dec_tlu_br1_wb_pkt.way);
end // always @ (negedge clk)
function [2:0] encode8_3;
input [7:0] in;
encode8_3[2] = |in[7:4];
encode8_3[1] = in[7] | in[6] | in[3] | in[2];
encode8_3[0] = in[7] | in[5] | in[3] | in[1];
endfunction
`endif
endmodule // ifu

1245
design/ifu/ifu_aln_ctl.sv Normal file

File diff suppressed because it is too large Load Diff

1777
design/ifu/ifu_bp_ctl.sv Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,379 @@
//********************************************************************************
// 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.
//********************************************************************************
// purpose of this file is to convert 16b RISCV compressed instruction into 32b equivalent
module ifu_compress_ctl
(
input logic [15:0] din,
output logic [31:0] dout,
output logic legal
);
logic [15:0] i;
logic [31:0] o,l1,l2,l3;
assign i[15:0] = din[15:0];
logic [4:0] rs2d,rdd,rdpd,rs2pd;
logic rdrd;
logic rdrs1;
logic rs2rs2;
logic rdprd;
logic rdprs1;
logic rs2prs2;
logic rs2prd;
logic uimm9_2;
logic ulwimm6_2;
logic ulwspimm7_2;
logic rdeq2;
logic rdeq1;
logic rs1eq2;
logic sbroffset8_1;
logic simm9_4;
logic simm5_0;
logic sjaloffset11_1;
logic sluimm17_12;
logic uimm5_0;
logic uswimm6_2;
logic uswspimm7_2;
// form the opcodes
// formats
//
// c.add rd 11:7 rs2 6:2
// c.and rdp 9:7 rs2p 4:2
//
// add rs2 24:20 rs1 19:15 rd 11:7
assign rs2d[4:0] = i[6:2];
assign rdd[4:0] = i[11:7];
assign rdpd[4:0] = {2'b01, i[9:7]};
assign rs2pd[4:0] = {2'b01, i[4:2]};
// merge in rd, rs1, rs2
// rd
assign l1[6:0] = o[6:0];
assign l1[11:7] = o[11:7] |
({5{rdrd}} & rdd[4:0]) |
({5{rdprd}} & rdpd[4:0]) |
({5{rs2prd}} & rs2pd[4:0]) |
({5{rdeq1}} & 5'd1) |
({5{rdeq2}} & 5'd2);
// rs1
assign l1[14:12] = o[14:12];
assign l1[19:15] = o[19:15] |
({5{rdrs1}} & rdd[4:0]) |
({5{rdprs1}} & rdpd[4:0]) |
({5{rs1eq2}} & 5'd2);
// rs2
assign l1[24:20] = o[24:20] |
({5{rs2rs2}} & rs2d[4:0]) |
({5{rs2prs2}} & rs2pd[4:0]);
assign l1[31:25] = o[31:25];
logic [5:0] simm5d;
logic [9:2] uimm9d;
logic [9:4] simm9d;
logic [6:2] ulwimm6d;
logic [7:2] ulwspimm7d;
logic [5:0] uimm5d;
logic [20:1] sjald;
logic [31:12] sluimmd;
// merge in immediates + jal offset
assign simm5d[5:0] = { i[12], i[6:2] };
assign uimm9d[9:2] = { i[10:7], i[12:11], i[5], i[6] };
assign simm9d[9:4] = { i[12], i[4:3], i[5], i[2], i[6] };
assign ulwimm6d[6:2] = { i[5], i[12:10], i[6] };
assign ulwspimm7d[7:2] = { i[3:2], i[12], i[6:4] };
assign uimm5d[5:0] = { i[12], i[6:2] };
assign sjald[11:1] = { i[12], i[8], i[10:9], i[6], i[7], i[2], i[11], i[5:4], i[3] };
assign sjald[20:12] = {9{i[12]}};
assign sluimmd[31:12] = { {15{i[12]}}, i[6:2] };
assign l2[31:20] = ( l1[31:20] ) |
( {12{simm5_0}} & {{7{simm5d[5]}},simm5d[4:0]} ) |
( {12{uimm9_2}} & {2'b0,uimm9d[9:2],2'b0} ) |
( {12{simm9_4}} & {{3{simm9d[9]}},simm9d[8:4],4'b0} ) |
( {12{ulwimm6_2}} & {5'b0,ulwimm6d[6:2],2'b0} ) |
( {12{ulwspimm7_2}} & {4'b0,ulwspimm7d[7:2],2'b0} ) |
( {12{uimm5_0}} & {6'b0,uimm5d[5:0]} ) |
( {12{sjaloffset11_1}} & {sjald[20],sjald[10:1],sjald[11]} ) |
( {12{sluimm17_12}} & sluimmd[31:20] );
assign l2[19:12] = ( l1[19:12] ) |
( {8{sjaloffset11_1}} & sjald[19:12] ) |
( {8{sluimm17_12}} & sluimmd[19:12] );
assign l2[11:0] = l1[11:0];
// merge in branch offset and store immediates
logic [8:1] sbr8d;
logic [6:2] uswimm6d;
logic [7:2] uswspimm7d;
assign sbr8d[8:1] = { i[12], i[6], i[5], i[2], i[11], i[10], i[4], i[3] };
assign uswimm6d[6:2] = { i[5], i[12:10], i[6] };
assign uswspimm7d[7:2] = { i[8:7], i[12:9] };
assign l3[31:25] = ( l2[31:25] ) |
( {7{sbroffset8_1}} & { {4{sbr8d[8]}},sbr8d[7:5] } ) |
( {7{uswimm6_2}} & { 5'b0, uswimm6d[6:5] } ) |
( {7{uswspimm7_2}} & { 4'b0, uswspimm7d[7:5] } );
assign l3[24:12] = l2[24:12];
assign l3[11:7] = ( l2[11:7] ) |
( {5{sbroffset8_1}} & { sbr8d[4:1], sbr8d[8] } ) |
( {5{uswimm6_2}} & { uswimm6d[4:2], 2'b0 } ) |
( {5{uswspimm7_2}} & { uswspimm7d[4:2], 2'b0 } );
assign l3[6:0] = l2[6:0];
assign dout[31:0] = l3[31:0] & {32{legal}};
// file "cdecode" is human readable file that has all of the compressed instruction decodes defined and is part of git repo
// modify this file as needed
// to generate all the equations below from "cdecode" except legal equation:
// 1) coredecode -in cdecode > cdecode.e
// 2) espresso -Dso -oeqntott cdecode.e | addassign > compress_equations
// to generate the legal (16b compressed instruction is legal) equation below:
// 1) coredecode -in cdecode -legal > clegal.e
// 2) espresso -Dso -oeqntott clegal.e | addassign > clegal_equation
// espresso decodes
assign rdrd = (!i[14]&i[6]&i[1]) | (!i[15]&i[14]&i[11]&i[0]) | (!i[14]&i[5]&i[1]) | (
!i[15]&i[14]&i[10]&i[0]) | (!i[14]&i[4]&i[1]) | (!i[15]&i[14]&i[9]
&i[0]) | (!i[14]&i[3]&i[1]) | (!i[15]&i[14]&!i[8]&i[0]) | (!i[14]
&i[2]&i[1]) | (!i[15]&i[14]&i[7]&i[0]) | (!i[15]&i[1]) | (!i[15]
&!i[13]&i[0]);
assign rdrs1 = (!i[14]&i[12]&i[11]&i[1]) | (!i[14]&i[12]&i[10]&i[1]) | (!i[14]
&i[12]&i[9]&i[1]) | (!i[14]&i[12]&i[8]&i[1]) | (!i[14]&i[12]&i[7]
&i[1]) | (!i[14]&!i[12]&!i[6]&!i[5]&!i[4]&!i[3]&!i[2]&i[1]) | (!i[14]
&i[12]&i[6]&i[1]) | (!i[14]&i[12]&i[5]&i[1]) | (!i[14]&i[12]&i[4]
&i[1]) | (!i[14]&i[12]&i[3]&i[1]) | (!i[14]&i[12]&i[2]&i[1]) | (
!i[15]&!i[14]&!i[13]&i[0]) | (!i[15]&!i[14]&i[1]);
assign rs2rs2 = (i[15]&i[6]&i[1]) | (i[15]&i[5]&i[1]) | (i[15]&i[4]&i[1]) | (
i[15]&i[3]&i[1]) | (i[15]&i[2]&i[1]) | (i[15]&i[14]&i[1]);
assign rdprd = (i[15]&!i[14]&!i[13]&i[0]);
assign rdprs1 = (i[15]&!i[13]&i[0]) | (i[15]&i[14]&i[0]) | (i[14]&!i[1]&!i[0]);
assign rs2prs2 = (i[15]&!i[14]&!i[13]&i[11]&i[10]&i[0]) | (i[15]&!i[1]&!i[0]);
assign rs2prd = (!i[15]&!i[1]&!i[0]);
assign uimm9_2 = (!i[14]&!i[1]&!i[0]);
assign ulwimm6_2 = (!i[15]&i[14]&!i[1]&!i[0]);
assign ulwspimm7_2 = (!i[15]&i[14]&i[1]);
assign rdeq2 = (!i[15]&i[14]&i[13]&!i[11]&!i[10]&!i[9]&i[8]&!i[7]);
assign rdeq1 = (!i[14]&i[12]&i[11]&!i[6]&!i[5]&!i[4]&!i[3]&!i[2]&i[1]) | (!i[14]
&i[12]&i[10]&!i[6]&!i[5]&!i[4]&!i[3]&!i[2]&i[1]) | (!i[14]&i[12]&i[9]
&!i[6]&!i[5]&!i[4]&!i[3]&!i[2]&i[1]) | (!i[14]&i[12]&i[8]&!i[6]&!i[5]
&!i[4]&!i[3]&!i[2]&i[1]) | (!i[14]&i[12]&i[7]&!i[6]&!i[5]&!i[4]&!i[3]
&!i[2]&i[1]) | (!i[15]&!i[14]&i[13]);
assign rs1eq2 = (!i[15]&i[14]&i[13]&!i[11]&!i[10]&!i[9]&i[8]&!i[7]) | (i[14]
&i[1]) | (!i[14]&!i[1]&!i[0]);
assign sbroffset8_1 = (i[15]&i[14]&i[0]);
assign simm9_4 = (!i[15]&i[14]&i[13]&!i[11]&!i[10]&!i[9]&i[8]&!i[7]);
assign simm5_0 = (!i[14]&!i[13]&i[11]&!i[10]&i[0]) | (!i[15]&!i[13]&i[0]);
assign sjaloffset11_1 = (!i[14]&i[13]);
assign sluimm17_12 = (!i[15]&i[14]&i[13]&i[7]) | (!i[15]&i[14]&i[13]&!i[8]) | (
!i[15]&i[14]&i[13]&i[9]) | (!i[15]&i[14]&i[13]&i[10]) | (!i[15]&i[14]
&i[13]&i[11]);
assign uimm5_0 = (i[15]&!i[14]&!i[13]&!i[11]&i[0]) | (!i[15]&!i[14]&i[1]);
assign uswimm6_2 = (i[15]&!i[1]&!i[0]);
assign uswspimm7_2 = (i[15]&i[14]&i[1]);
assign o[31] = 1'b0;
assign o[30] = (i[15]&!i[14]&!i[13]&i[10]&!i[6]&!i[5]&i[0]) | (i[15]&!i[14]
&!i[13]&!i[11]&i[10]&i[0]);
assign o[29] = 1'b0;
assign o[28] = 1'b0;
assign o[27] = 1'b0;
assign o[26] = 1'b0;
assign o[25] = 1'b0;
assign o[24] = 1'b0;
assign o[23] = 1'b0;
assign o[22] = 1'b0;
assign o[21] = 1'b0;
assign o[20] = (!i[14]&i[12]&!i[11]&!i[10]&!i[9]&!i[8]&!i[7]&!i[6]&!i[5]&!i[4]
&!i[3]&!i[2]&i[1]);
assign o[19] = 1'b0;
assign o[18] = 1'b0;
assign o[17] = 1'b0;
assign o[16] = 1'b0;
assign o[15] = 1'b0;
assign o[14] = (i[15]&!i[14]&!i[13]&!i[11]&i[0]) | (i[15]&!i[14]&!i[13]&!i[10]
&i[0]) | (i[15]&!i[14]&!i[13]&i[6]&i[0]) | (i[15]&!i[14]&!i[13]&i[5]
&i[0]);
assign o[13] = (i[15]&!i[14]&!i[13]&i[11]&!i[10]&i[0]) | (i[15]&!i[14]&!i[13]
&i[11]&i[6]&i[0]) | (i[14]&!i[0]);
assign o[12] = (i[15]&!i[14]&!i[13]&i[6]&i[5]&i[0]) | (i[15]&!i[14]&!i[13]&!i[11]
&i[0]) | (i[15]&!i[14]&!i[13]&!i[10]&i[0]) | (!i[15]&!i[14]&i[1]) | (
i[15]&i[14]&i[13]);
assign o[11] = 1'b0;
assign o[10] = 1'b0;
assign o[9] = 1'b0;
assign o[8] = 1'b0;
assign o[7] = 1'b0;
assign o[6] = (i[15]&!i[14]&!i[6]&!i[5]&!i[4]&!i[3]&!i[2]&!i[0]) | (!i[14]&i[13]) | (
i[15]&i[14]&i[0]);
assign o[5] = (i[15]&!i[0]) | (i[15]&i[11]&i[10]) | (i[13]&!i[8]) | (i[13]&i[7]) | (
i[13]&i[9]) | (i[13]&i[10]) | (i[13]&i[11]) | (!i[14]&i[13]) | (
i[15]&i[14]);
assign o[4] = (!i[14]&!i[11]&!i[10]&!i[9]&!i[8]&!i[7]&!i[0]) | (!i[15]&!i[14]
&!i[0]) | (!i[14]&i[6]&!i[0]) | (!i[15]&i[14]&i[0]) | (!i[14]&i[5]
&!i[0]) | (!i[14]&i[4]&!i[0]) | (!i[14]&!i[13]&i[0]) | (!i[14]&i[3]
&!i[0]) | (!i[14]&i[2]&!i[0]);
assign o[3] = (!i[14]&i[13]);
assign o[2] = (!i[14]&i[12]&i[11]&!i[6]&!i[5]&!i[4]&!i[3]&!i[2]&i[1]) | (!i[14]
&i[12]&i[10]&!i[6]&!i[5]&!i[4]&!i[3]&!i[2]&i[1]) | (!i[14]&i[12]&i[9]
&!i[6]&!i[5]&!i[4]&!i[3]&!i[2]&i[1]) | (!i[14]&i[12]&i[8]&!i[6]&!i[5]
&!i[4]&!i[3]&!i[2]&i[1]) | (!i[14]&i[12]&i[7]&!i[6]&!i[5]&!i[4]&!i[3]
&!i[2]&i[1]) | (i[15]&!i[14]&!i[12]&!i[6]&!i[5]&!i[4]&!i[3]&!i[2]
&!i[0]) | (!i[15]&i[13]&!i[8]) | (!i[15]&i[13]&i[7]) | (!i[15]&i[13]
&i[9]) | (!i[15]&i[13]&i[10]) | (!i[15]&i[13]&i[11]) | (!i[14]&i[13]);
// 32b instruction has lower two bits 2'b11
assign o[1] = 1'b1;
assign o[0] = 1'b1;
assign legal = (!i[13]&!i[12]&i[11]&i[1]&!i[0]) | (!i[13]&!i[12]&i[6]&i[1]&!i[0]) | (
!i[15]&!i[13]&i[11]&!i[1]) | (!i[13]&!i[12]&i[5]&i[1]&!i[0]) | (
!i[13]&!i[12]&i[10]&i[1]&!i[0]) | (!i[15]&!i[13]&i[6]&!i[1]) | (
i[15]&!i[12]&!i[1]&i[0]) | (!i[13]&!i[12]&i[9]&i[1]&!i[0]) | (!i[12]
&i[6]&!i[1]&i[0]) | (!i[15]&!i[13]&i[5]&!i[1]) | (!i[13]&!i[12]&i[8]
&i[1]&!i[0]) | (!i[12]&i[5]&!i[1]&i[0]) | (!i[15]&!i[13]&i[10]&!i[1]) | (
!i[13]&!i[12]&i[7]&i[1]&!i[0]) | (i[12]&i[11]&!i[10]&!i[1]&i[0]) | (
!i[15]&!i[13]&i[9]&!i[1]) | (!i[13]&!i[12]&i[4]&i[1]&!i[0]) | (i[13]
&i[12]&!i[1]&i[0]) | (!i[15]&!i[13]&i[8]&!i[1]) | (!i[13]&!i[12]&i[3]
&i[1]&!i[0]) | (i[13]&i[4]&!i[1]&i[0]) | (!i[13]&!i[12]&i[2]&i[1]
&!i[0]) | (!i[15]&!i[13]&i[7]&!i[1]) | (i[13]&i[3]&!i[1]&i[0]) | (
i[13]&i[2]&!i[1]&i[0]) | (i[14]&!i[13]&!i[1]) | (!i[14]&!i[12]&!i[1]
&i[0]) | (i[15]&!i[13]&i[12]&i[1]&!i[0]) | (!i[15]&!i[13]&!i[12]&i[1]
&!i[0]) | (!i[15]&!i[13]&i[12]&!i[1]) | (i[14]&!i[13]&!i[0]);
endmodule

559
design/ifu/ifu_ic_mem.sv Normal file
View File

@ -0,0 +1,559 @@
//********************************************************************************
// SPDX-License-Identifier: Apache-2.0
// Copyright 2019 Western Digital Corporation or it's 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.
//********************************************************************************
////////////////////////////////////////////////////
// ICACHE DATA & TAG MODULE WRAPPER //
/////////////////////////////////////////////////////
module ifu_ic_mem
(
input logic clk,
input logic rst_l,
input logic clk_override,
input logic dec_tlu_core_ecc_disable,
input logic [31:3] ic_rw_addr,
input logic [3:0] ic_wr_en , // Which way to write
input logic ic_rd_en , // Read enable
input logic [15:2] ic_debug_addr, // Read/Write addresss to the Icache.
input logic ic_debug_rd_en, // Icache debug rd
input logic ic_debug_wr_en, // Icache debug wr
input logic ic_debug_tag_array, // Debug tag array
input logic [3:0] ic_debug_way, // Debug way. Rd or Wr.
input logic [127:0] ic_premux_data, // Premux data to be muxed with each way of the Icache.
input logic ic_sel_premux_data, // Select the pre_muxed data
`ifdef RV_ICACHE_ECC
input logic [83:0] ic_wr_data, // Data to fill to the Icache. With ECC
output logic [167:0] ic_rd_data , // Data read from Icache. 2x64bits + parity bits. F2 stage. With ECC
output logic [24:0] ictag_debug_rd_data,// Debug icache tag.
input logic [41:0] ic_debug_wr_data, // Debug wr cache.
`else
input logic [67:0] ic_wr_data, // Data to fill to the Icache. With Parity
output logic [135:0] ic_rd_data , // Data read from Icache. 2x64bits + parity bits. F2 stage. With Parity
output logic [20:0] ictag_debug_rd_data,// Debug icache tag.
input logic [33:0] ic_debug_wr_data, // Debug wr cache.
`endif
input logic [3:0] ic_tag_valid, // Valid from the I$ tag valid outside (in flops).
output logic [3:0] ic_rd_hit, // ic_rd_hit[3:0]
output logic ic_tag_perr, // Tag Parity error
input logic scan_mode
) ;
`include "global.h"
IC_TAG #( .ICACHE_TAG_HIGH(ICACHE_TAG_HIGH) ,
.ICACHE_TAG_LOW(ICACHE_TAG_LOW) ,
.ICACHE_TAG_DEPTH(ICACHE_TAG_DEPTH)
) ic_tag_inst
(
.*,
.ic_wr_en (ic_wr_en[3:0]),
.ic_debug_addr(ic_debug_addr[ICACHE_TAG_HIGH-1:2]),
.ic_rw_addr (ic_rw_addr[31:3])
) ;
IC_DATA #( .ICACHE_TAG_HIGH(ICACHE_TAG_HIGH) ,
.ICACHE_TAG_LOW(ICACHE_TAG_LOW) ,
.ICACHE_IC_DEPTH(ICACHE_IC_DEPTH)
) ic_data_inst
(
.*,
.ic_wr_en (ic_wr_en[3:0]),
.ic_debug_addr(ic_debug_addr[ICACHE_TAG_HIGH-1:2]),
.ic_rw_addr (ic_rw_addr[ICACHE_TAG_HIGH-1:3])
) ;
endmodule
/////////////////////////////////////////////////
////// ICACHE DATA MODULE ////////////////////
/////////////////////////////////////////////////
module IC_DATA #(parameter ICACHE_TAG_HIGH = 16 ,
ICACHE_TAG_LOW=6 ,
ICACHE_IC_DEPTH=1024
)
(
input logic clk,
input logic rst_l,
input logic clk_override,
input logic [ICACHE_TAG_HIGH-1:3] ic_rw_addr,
input logic [3:0] ic_wr_en,
input logic ic_rd_en, // Read enable
`ifdef RV_ICACHE_ECC
input logic [83:0] ic_wr_data, // Data to fill to the Icache. With ECC
output logic [167:0] ic_rd_data , // Data read from Icache. 2x64bits + parity bits. F2 stage. With ECC
input logic [41:0] ic_debug_wr_data, // Debug wr cache.
`else
input logic [67:0] ic_wr_data, // Data to fill to the Icache. With Parity
output logic [135:0] ic_rd_data , // Data read from Icache. 2x64bits + parity bits. F2 stage. With Parity
input logic [33:0] ic_debug_wr_data, // Debug wr cache.
`endif
input logic [ICACHE_TAG_HIGH-1:2] ic_debug_addr, // Read/Write addresss to the Icache.
input logic ic_debug_rd_en, // Icache debug rd
input logic ic_debug_wr_en, // Icache debug wr
input logic ic_debug_tag_array, // Debug tag array
input logic [3:0] ic_debug_way, // Debug way. Rd or Wr.
input logic [127:0] ic_premux_data, // Premux data to be muxed with each way of the Icache.
input logic ic_sel_premux_data, // Select the pre_muxed data
input logic [3:0] ic_rd_hit,
input logic scan_mode
) ;
logic [5:4] ic_rw_addr_ff;
logic [3:0][3:0] ic_b_sb_wren; // way, bank
logic ic_debug_sel_sb0 ;
logic ic_debug_sel_sb1 ;
logic ic_debug_sel_sb2 ;
logic ic_debug_sel_sb3 ;
`ifdef RV_ICACHE_ECC
logic [3:0] [167:0] bank_set_dout;
logic [3:0][167:0] wb_dout ; //
logic [3:0][41:0] ic_sb_wr_data;
`else
logic [3:0] [135:0] bank_set_dout;
logic [3:0] [135:0] wb_dout ; // bank , way , size
logic [3:0] [33:0] ic_sb_wr_data;
`endif
logic [3:0] ic_bank_way_clken; // bank , way
logic [3:0] ic_bank_way_clk ; // bank , way
logic ic_b_rden;
logic [3:0] ic_debug_rd_way_en; // debug wr_way
logic [3:0] ic_debug_rd_way_en_ff; // debug wr_way
logic [3:0] ic_debug_wr_way_en; // debug wr_way
logic [ICACHE_TAG_HIGH-1:4] ic_rw_addr_q;
assign ic_debug_rd_way_en[3:0] = {4{ic_debug_rd_en & ~ic_debug_tag_array}} & ic_debug_way[3:0] ;
assign ic_debug_wr_way_en[3:0] = {4{ic_debug_wr_en & ~ic_debug_tag_array}} & ic_debug_way[3:0] ;
assign ic_b_sb_wren[0][3:0] = (ic_wr_en[3:0] & {4{~ic_rw_addr[3]}} ) |
(ic_debug_wr_way_en[3:0] & {4{ic_debug_addr[3:2] == 2'b00}}) ;
assign ic_b_sb_wren[1][3:0] = (ic_wr_en[3:0] & {4{~ic_rw_addr[3]}} ) |
(ic_debug_wr_way_en[3:0] & {4{ic_debug_addr[3:2] == 2'b01}}) ;
assign ic_b_sb_wren[2][3:0] = (ic_wr_en[3:0] & {4{ic_rw_addr[3]}} ) |
(ic_debug_wr_way_en[3:0] & {4{ic_debug_addr[3:2] == 2'b10}}) ;
assign ic_b_sb_wren[3][3:0] = (ic_wr_en[3:0] & {4{ic_rw_addr[3]}} ) |
(ic_debug_wr_way_en[3:0] & {4{ic_debug_addr[3:2] == 2'b11}}) ;
assign ic_debug_sel_sb0 = (ic_debug_addr[3:2] == 2'b00 ) ;
assign ic_debug_sel_sb1 = (ic_debug_addr[3:2] == 2'b01 ) ;
assign ic_debug_sel_sb2 = (ic_debug_addr[3:2] == 2'b10 ) ;
assign ic_debug_sel_sb3 = (ic_debug_addr[3:2] == 2'b11 ) ;
`ifdef RV_ICACHE_ECC
assign ic_sb_wr_data[0][41:0] = (ic_debug_sel_sb0 & ic_debug_wr_en) ? {ic_debug_wr_data[41:0]} :
ic_wr_data[41:0] ;
assign ic_sb_wr_data[1][41:0] = (ic_debug_sel_sb1 & ic_debug_wr_en) ? {ic_debug_wr_data[41:0]} :
ic_wr_data[83:42] ;
assign ic_sb_wr_data[2][41:0] = (ic_debug_sel_sb2 & ic_debug_wr_en) ? {ic_debug_wr_data[41:0]} :
ic_wr_data[41:0] ;
assign ic_sb_wr_data[3][41:0] = (ic_debug_sel_sb3 & ic_debug_wr_en) ? {ic_debug_wr_data[41:0]} :
ic_wr_data[83:42] ;
`else
assign ic_sb_wr_data[0][33:0] = (ic_debug_sel_sb0 & ic_debug_wr_en) ? ic_debug_wr_data[33:0] :
ic_wr_data[33:0] ;
assign ic_sb_wr_data[1][33:0] = (ic_debug_sel_sb1 & ic_debug_wr_en) ? ic_debug_wr_data[33:0] :
ic_wr_data[67:34] ;
assign ic_sb_wr_data[2][33:0] = (ic_debug_sel_sb2 & ic_debug_wr_en) ? ic_debug_wr_data[33:0] :
ic_wr_data[33:0] ;
assign ic_sb_wr_data[3][33:0] = (ic_debug_sel_sb3 & ic_debug_wr_en) ? ic_debug_wr_data[33:0] :
ic_wr_data[67:34] ;
`endif
// bank read enables
assign ic_b_rden = (ic_rd_en | ic_debug_rd_en );
assign ic_bank_way_clken[3:0] = ({4{ic_b_rden | clk_override }}) |
ic_b_sb_wren[0][3:0] |
ic_b_sb_wren[1][3:0] |
ic_b_sb_wren[2][3:0] |
ic_b_sb_wren[3][3:0] ;
assign ic_rw_addr_q[ICACHE_TAG_HIGH-1:4] = (ic_debug_rd_en | ic_debug_wr_en) ?
ic_debug_addr[ICACHE_TAG_HIGH-1:4] :
ic_rw_addr[ICACHE_TAG_HIGH-1:4] ;
logic ic_debug_rd_en_ff;
rvdff #(2) adr_ff (.*,
.din ({ic_rw_addr_q[5:4]}),
.dout({ic_rw_addr_ff[5:4]}));
rvdff #(5) debug_rd_wy_ff (.*,
.din ({ic_debug_rd_way_en[3:0], ic_debug_rd_en}),
.dout({ic_debug_rd_way_en_ff[3:0], ic_debug_rd_en_ff}));
localparam NUM_WAYS=4 ;
localparam NUM_SUBBANKS=4 ;
for (genvar i=0; i<NUM_WAYS; i++) begin: WAYS
rvclkhdr bank_way_c1_cgc ( .en(ic_bank_way_clken[i]), .l1clk(ic_bank_way_clk[i]), .* );
for (genvar k=0; k<NUM_SUBBANKS; k++) begin: SUBBANKS // 16B subbank
`ifdef RV_ICACHE_ECC
`RV_ICACHE_DATA_CELL ic_bank_sb_way_data (
.CLK(ic_bank_way_clk[i]),
.WE (ic_b_sb_wren[k][i]),
.D (ic_sb_wr_data[k][41:0]),
.ADR(ic_rw_addr_q[ICACHE_TAG_HIGH-1:4]),
.Q (wb_dout[i][(k+1)*42-1:k*42])
);
`else
`RV_ICACHE_DATA_CELL ic_bank_sb_way_data (
.CLK(ic_bank_way_clk[i]),
.WE (ic_b_sb_wren[k][i]),
.D (ic_sb_wr_data[k][33:0]),
.ADR(ic_rw_addr_q[ICACHE_TAG_HIGH-1:4]),
.Q (wb_dout[i][(k+1)*34-1:k*34])
);
`endif
end // block: SUBBANKS
end
logic [3:0] ic_rd_hit_q;
assign ic_rd_hit_q[3:0] = ic_debug_rd_en_ff ? ic_debug_rd_way_en_ff[3:0] : ic_rd_hit[3:0] ;
// set mux
`ifdef RV_ICACHE_ECC
logic [167:0] ic_premux_data_ext;
logic [3:0] [167:0] wb_dout_way;
logic [3:0] [167:0] wb_dout_way_with_premux;
assign ic_premux_data_ext[167:0] = {10'b0,ic_premux_data[127:96],10'b0,ic_premux_data[95:64] ,10'b0,ic_premux_data[63:32],10'b0,ic_premux_data[31:0]};
assign wb_dout_way[0][167:0] = wb_dout[0][167:0];
assign wb_dout_way[1][167:0] = wb_dout[1][167:0];
assign wb_dout_way[2][167:0] = wb_dout[2][167:0];
assign wb_dout_way[3][167:0] = wb_dout[3][167:0];
assign wb_dout_way_with_premux[0][167:0] = ic_sel_premux_data ? ic_premux_data_ext[167:0] : wb_dout_way[0][167:0] ;
assign wb_dout_way_with_premux[1][167:0] = ic_sel_premux_data ? ic_premux_data_ext[167:0] : wb_dout_way[1][167:0] ;
assign wb_dout_way_with_premux[2][167:0] = ic_sel_premux_data ? ic_premux_data_ext[167:0] : wb_dout_way[2][167:0] ;
assign wb_dout_way_with_premux[3][167:0] = ic_sel_premux_data ? ic_premux_data_ext[167:0] : wb_dout_way[3][167:0] ;
assign ic_rd_data[167:0] = ({168{ic_rd_hit_q[0] | ic_sel_premux_data}} & wb_dout_way_with_premux[0][167:0]) |
({168{ic_rd_hit_q[1] | ic_sel_premux_data}} & wb_dout_way_with_premux[1][167:0]) |
({168{ic_rd_hit_q[2] | ic_sel_premux_data}} & wb_dout_way_with_premux[2][167:0]) |
({168{ic_rd_hit_q[3] | ic_sel_premux_data}} & wb_dout_way_with_premux[3][167:0]) ;
`else
logic [135:0] ic_premux_data_ext;
logic [3:0] [135:0] wb_dout_way;
logic [3:0] [135:0] wb_dout_way_with_premux;
assign ic_premux_data_ext[135:0] = {2'b0,ic_premux_data[127:96],2'b0,ic_premux_data[95:64] ,2'b0,ic_premux_data[63:32],2'b0,ic_premux_data[31:0]};
assign wb_dout_way[0][135:0] = wb_dout[0][135:0];
assign wb_dout_way[1][135:0] = wb_dout[1][135:0];
assign wb_dout_way[2][135:0] = wb_dout[2][135:0];
assign wb_dout_way[3][135:0] = wb_dout[3][135:0];
assign wb_dout_way_with_premux[0][135:0] = ic_sel_premux_data ? ic_premux_data_ext[135:0] : wb_dout_way[0][135:0] ;
assign wb_dout_way_with_premux[1][135:0] = ic_sel_premux_data ? ic_premux_data_ext[135:0] : wb_dout_way[1][135:0] ;
assign wb_dout_way_with_premux[2][135:0] = ic_sel_premux_data ? ic_premux_data_ext[135:0] : wb_dout_way[2][135:0] ;
assign wb_dout_way_with_premux[3][135:0] = ic_sel_premux_data ? ic_premux_data_ext[135:0] : wb_dout_way[3][135:0] ;
assign ic_rd_data[135:0] = ({136{ic_rd_hit_q[0] | ic_sel_premux_data}} & wb_dout_way_with_premux[0][135:0]) |
({136{ic_rd_hit_q[1] | ic_sel_premux_data}} & wb_dout_way_with_premux[1][135:0]) |
({136{ic_rd_hit_q[2] | ic_sel_premux_data}} & wb_dout_way_with_premux[2][135:0]) |
({136{ic_rd_hit_q[3] | ic_sel_premux_data}} & wb_dout_way_with_premux[3][135:0]) ;
`endif
endmodule
/////////////////////////////////////////////////
////// ICACHE TAG MODULE ////////////////////
/////////////////////////////////////////////////
module IC_TAG #(parameter ICACHE_TAG_HIGH = 16 ,
ICACHE_TAG_LOW=6 ,
ICACHE_TAG_DEPTH=1024
)
(
input logic clk,
input logic rst_l,
input logic clk_override,
input logic dec_tlu_core_ecc_disable,
input logic [31:3] ic_rw_addr,
input logic [3:0] ic_wr_en, // way
input logic [3:0] ic_tag_valid,
input logic ic_rd_en,
input logic [ICACHE_TAG_HIGH-1:2] ic_debug_addr, // Read/Write addresss to the Icache.
input logic ic_debug_rd_en, // Icache debug rd
input logic ic_debug_wr_en, // Icache debug wr
input logic ic_debug_tag_array, // Debug tag array
input logic [3:0] ic_debug_way, // Debug way. Rd or Wr.
`ifdef RV_ICACHE_ECC
output logic [24:0] ictag_debug_rd_data,
input logic [41:0] ic_debug_wr_data, // Debug wr cache.
`else
output logic [20:0] ictag_debug_rd_data,
input logic [33:0] ic_debug_wr_data, // Debug wr cache.
`endif
output logic [3:0] ic_rd_hit,
output logic ic_tag_perr,
input logic scan_mode
) ;
`ifdef RV_ICACHE_ECC
logic [3:0] [24:0] ic_tag_data_raw;
logic [3:0] [37:ICACHE_TAG_HIGH] w_tout;
logic [24:0] ic_tag_wr_data ;
logic [3:0] [31:0] ic_tag_corrected_data_unc;
logic [3:0] [06:0] ic_tag_corrected_ecc_unc;
logic [3:0] ic_tag_single_ecc_error;
logic [3:0] ic_tag_double_ecc_error;
`else
logic [3:0] [20:0] ic_tag_data_raw;
logic [3:0] [32:ICACHE_TAG_HIGH] w_tout;
logic [20:0] ic_tag_wr_data ;
`endif
logic [3:0] ic_tag_way_perr ;
logic [3:0] ic_debug_rd_way_en ;
logic [3:0] ic_debug_rd_way_en_ff ;
logic [ICACHE_TAG_HIGH-1:6] ic_rw_addr_q;
logic [31:4] ic_rw_addr_ff;
logic [3:0] ic_tag_wren ; // way
logic [3:0] ic_tag_wren_q ; // way
logic [3:0] ic_tag_clk ;
logic [3:0] ic_tag_clken ;
logic [3:0] ic_debug_wr_way_en; // debug wr_way
assign ic_tag_wren [3:0] = ic_wr_en[3:0] & {4{ic_rw_addr[5:3] == 3'b111}} ;
assign ic_tag_clken[3:0] = {4{ic_rd_en | clk_override}} | ic_wr_en[3:0] | ic_debug_wr_way_en[3:0] | ic_debug_rd_way_en[3:0];
rvdff #(32-ICACHE_TAG_HIGH) adr_ff (.*,
.din ({ic_rw_addr[31:ICACHE_TAG_HIGH]}),
.dout({ic_rw_addr_ff[31:ICACHE_TAG_HIGH]}));
localparam TOP_BITS = 21+ICACHE_TAG_HIGH-33 ;
localparam NUM_WAYS=4 ;
// tags
assign ic_debug_rd_way_en[3:0] = {4{ic_debug_rd_en & ic_debug_tag_array}} & ic_debug_way[3:0] ;
assign ic_debug_wr_way_en[3:0] = {4{ic_debug_wr_en & ic_debug_tag_array}} & ic_debug_way[3:0] ;
assign ic_tag_wren_q[3:0] = ic_tag_wren[3:0] |
ic_debug_wr_way_en[3:0] ;
if (ICACHE_TAG_HIGH == 12) begin: SMALLEST
`ifdef RV_ICACHE_ECC
logic [6:0] ic_tag_ecc;
rvecc_encode tag_ecc_encode (
.din ({{ICACHE_TAG_HIGH{1'b0}}, ic_rw_addr[31:ICACHE_TAG_HIGH]}),
.ecc_out({ ic_tag_ecc[6:0]}));
assign ic_tag_wr_data[24:0] = (ic_debug_wr_en & ic_debug_tag_array) ?
{ic_debug_wr_data[36:32], ic_debug_wr_data[31:12]} :
{ic_tag_ecc[4:0], ic_rw_addr[31:ICACHE_TAG_HIGH]} ;
`else
logic ic_tag_parity ;
rveven_paritygen #(32-ICACHE_TAG_HIGH) pargen (.data_in (ic_rw_addr[31:ICACHE_TAG_HIGH]),
.parity_out(ic_tag_parity));
assign ic_tag_wr_data[20:0] = (ic_debug_wr_en & ic_debug_tag_array) ?
{ic_debug_wr_data[32], ic_debug_wr_data[31:12]} :
{ic_tag_parity, ic_rw_addr[31:ICACHE_TAG_HIGH]} ;
`endif
end else begin: OTHERS
`ifdef RV_ICACHE_ECC
logic [6:0] ic_tag_ecc;
rvecc_encode tag_ecc_encode (
.din ({{ICACHE_TAG_HIGH{1'b0}}, ic_rw_addr[31:ICACHE_TAG_HIGH]}),
.ecc_out({ ic_tag_ecc[6:0]}));
assign ic_tag_wr_data[24:0] = (ic_debug_wr_en & ic_debug_tag_array) ?
{ic_debug_wr_data[36:32], ic_debug_wr_data[31:12]} :
{ic_tag_ecc[4:0], {TOP_BITS{1'b0}},ic_rw_addr[31:ICACHE_TAG_HIGH]} ;
`else
logic ic_tag_parity ;
rveven_paritygen #(32-ICACHE_TAG_HIGH) pargen (.data_in (ic_rw_addr[31:ICACHE_TAG_HIGH]),
.parity_out(ic_tag_parity));
assign ic_tag_wr_data[20:0] = (ic_debug_wr_en & ic_debug_tag_array) ?
{ic_debug_wr_data[32], ic_debug_wr_data[31:12]} :
{ic_tag_parity, {TOP_BITS{1'b0}},ic_rw_addr[31:ICACHE_TAG_HIGH]} ;
`endif
end
assign ic_rw_addr_q[ICACHE_TAG_HIGH-1:6] = (ic_debug_rd_en | ic_debug_wr_en) ?
ic_debug_addr[ICACHE_TAG_HIGH-1:6] :
ic_rw_addr[ICACHE_TAG_HIGH-1:6] ;
rvdff #(4) tag_rd_wy_ff (.*,
.din ({ic_debug_rd_way_en[3:0]}),
.dout({ic_debug_rd_way_en_ff[3:0]}));
for (genvar i=0; i<NUM_WAYS; i++) begin: WAYS
rvclkhdr ic_tag_c1_cgc ( .en(ic_tag_clken[i]), .l1clk(ic_tag_clk[i]), .* );
if (ICACHE_TAG_DEPTH == 64 ) begin : ICACHE_SZ_16
`ifdef RV_ICACHE_ECC
ram_64x25 ic_way_tag (
.CLK(ic_tag_clk[i]),
.WE (ic_tag_wren_q[i]),
.D (ic_tag_wr_data[24:0]),
.ADR(ic_rw_addr_q[ICACHE_TAG_HIGH-1:ICACHE_TAG_LOW]),
.Q (ic_tag_data_raw[i][24:0])
);
assign w_tout[i][31:ICACHE_TAG_HIGH] = ic_tag_data_raw[i][31-ICACHE_TAG_HIGH:0] ;
assign w_tout[i][36:32] = ic_tag_data_raw[i][24:20] ;
rvecc_decode ecc_decode (
.en(~dec_tlu_core_ecc_disable),
.sed_ded ( 1'b1 ), // 1 : means only detection
.din({12'b0,ic_tag_data_raw[i][19:0]}),
.ecc_in({2'b0, ic_tag_data_raw[i][24:20]}),
.dout(ic_tag_corrected_data_unc[i][31:0]),
.ecc_out(ic_tag_corrected_ecc_unc[i][6:0]),
.single_ecc_error(ic_tag_single_ecc_error[i]),
.double_ecc_error(ic_tag_double_ecc_error[i]));
assign ic_tag_way_perr[i]= ic_tag_single_ecc_error[i] | ic_tag_double_ecc_error[i] ;
`else
ram_64x21 ic_way_tag (
.CLK(ic_tag_clk[i]),
.WE (ic_tag_wren_q[i]),
.D (ic_tag_wr_data[20:0]),
.ADR(ic_rw_addr_q[ICACHE_TAG_HIGH-1:ICACHE_TAG_LOW]),
.Q (ic_tag_data_raw[i][20:0])
);
assign w_tout[i][31:ICACHE_TAG_HIGH] = ic_tag_data_raw[i][31-ICACHE_TAG_HIGH:0] ;
assign w_tout[i][32] = ic_tag_data_raw[i][20] ;
rveven_paritycheck #(32-ICACHE_TAG_HIGH) parcheck(.data_in (w_tout[i][31:ICACHE_TAG_HIGH]),
.parity_in (w_tout[i][32]),
.parity_err(ic_tag_way_perr[i]));
`endif
end // block: ICACHE_SZ_16
else begin : tag_not_64
`ifdef RV_ICACHE_ECC
`RV_ICACHE_TAG_CELL ic_way_tag (
.CLK(ic_tag_clk[i]),
.WE (ic_tag_wren_q[i]),
.D (ic_tag_wr_data[24:0]),
.ADR(ic_rw_addr_q[ICACHE_TAG_HIGH-1:ICACHE_TAG_LOW]),
.Q (ic_tag_data_raw[i][24:0])
);
assign w_tout[i][31:ICACHE_TAG_HIGH] = ic_tag_data_raw[i][31-ICACHE_TAG_HIGH:0] ;
assign w_tout[i][36:32] = ic_tag_data_raw[i][24:20] ;
rvecc_decode ecc_decode (
.en(~dec_tlu_core_ecc_disable),
.sed_ded ( 1'b1 ), // 1 : if only need detection
.din({12'b0,ic_tag_data_raw[i][19:0]}),
.ecc_in({2'b0, ic_tag_data_raw[i][24:20]}),
.dout(ic_tag_corrected_data_unc[i][31:0]),
.ecc_out(ic_tag_corrected_ecc_unc[i][6:0]),
.single_ecc_error(ic_tag_single_ecc_error[i]),
.double_ecc_error(ic_tag_double_ecc_error[i]));
assign ic_tag_way_perr[i]= ic_tag_single_ecc_error[i] | ic_tag_double_ecc_error[i] ;
`else
`RV_ICACHE_TAG_CELL ic_way_tag (
.CLK(ic_tag_clk[i]),
.WE (ic_tag_wren_q[i]),
.D (ic_tag_wr_data[20:0]),
.ADR(ic_rw_addr_q[ICACHE_TAG_HIGH-1:ICACHE_TAG_LOW]),
.Q ({ic_tag_data_raw[i][20:0]})
);
assign w_tout[i][31:ICACHE_TAG_HIGH] = ic_tag_data_raw[i][31-ICACHE_TAG_HIGH:0] ;
assign w_tout[i][32] = ic_tag_data_raw[i][20] ;
rveven_paritycheck #(32-ICACHE_TAG_HIGH) parcheck(.data_in (w_tout[i][31:ICACHE_TAG_HIGH]),
.parity_in (w_tout[i][32]),
.parity_err(ic_tag_way_perr[i]));
`endif
end // block: tag_not_64
end // block: WAYS
`ifdef RV_ICACHE_ECC
assign ictag_debug_rd_data[24:0] = ({25{ic_debug_rd_way_en_ff[0]}} & ic_tag_data_raw[0] ) |
({25{ic_debug_rd_way_en_ff[1]}} & ic_tag_data_raw[1] ) |
({25{ic_debug_rd_way_en_ff[2]}} & ic_tag_data_raw[2] ) |
({25{ic_debug_rd_way_en_ff[3]}} & ic_tag_data_raw[3] ) ;
`else
assign ictag_debug_rd_data[20:0] = ({21{ic_debug_rd_way_en_ff[0]}} & ic_tag_data_raw[0] ) |
({21{ic_debug_rd_way_en_ff[1]}} & ic_tag_data_raw[1] ) |
({21{ic_debug_rd_way_en_ff[2]}} & ic_tag_data_raw[2] ) |
({21{ic_debug_rd_way_en_ff[3]}} & ic_tag_data_raw[3] ) ;
`endif
assign ic_rd_hit[0] = (w_tout[0][31:ICACHE_TAG_HIGH] == ic_rw_addr_ff[31:ICACHE_TAG_HIGH]) & ic_tag_valid[0];
assign ic_rd_hit[1] = (w_tout[1][31:ICACHE_TAG_HIGH] == ic_rw_addr_ff[31:ICACHE_TAG_HIGH]) & ic_tag_valid[1];
assign ic_rd_hit[2] = (w_tout[2][31:ICACHE_TAG_HIGH] == ic_rw_addr_ff[31:ICACHE_TAG_HIGH]) & ic_tag_valid[2];
assign ic_rd_hit[3] = (w_tout[3][31:ICACHE_TAG_HIGH] == ic_rw_addr_ff[31:ICACHE_TAG_HIGH]) & ic_tag_valid[3];
assign ic_tag_perr = | (ic_tag_way_perr[3:0] & ic_tag_valid[3:0] ) ;
endmodule

143
design/ifu/ifu_iccm_mem.sv Normal file
View File

@ -0,0 +1,143 @@
//********************************************************************************
// 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.
//********************************************************************************
//********************************************************************************
// Icache closely coupled memory --- ICCM
//********************************************************************************
module ifu_iccm_mem
import swerv_types::*;
(
input logic clk,
input logic rst_l,
input logic clk_override,
input logic iccm_wren,
input logic iccm_rden,
input logic [`RV_ICCM_BITS-1:2] iccm_rw_addr,
input logic [2:0] iccm_wr_size,
input logic [77:0] iccm_wr_data,
output logic [155:0] iccm_rd_data,
input logic scan_mode
);
`include "global.h"
logic [ICCM_NUM_BANKS/4-1:0] wren_bank;
logic [ICCM_NUM_BANKS/4-1:0] rden_bank;
logic [ICCM_NUM_BANKS/4-1:0] iccm_hi0_clken;
logic [ICCM_NUM_BANKS/4-1:0] iccm_hi1_clken;
logic [ICCM_NUM_BANKS/4-1:0] iccm_lo0_clken;
logic [ICCM_NUM_BANKS/4-1:0] iccm_lo1_clken;
logic [ICCM_NUM_BANKS/4-1:0] iccm_hi0_clk ;
logic [ICCM_NUM_BANKS/4-1:0] iccm_hi1_clk ;
logic [ICCM_NUM_BANKS/4-1:0] iccm_lo0_clk ;
logic [ICCM_NUM_BANKS/4-1:0] iccm_lo1_clk ;
logic [ICCM_NUM_BANKS/4-1:0] wren_bank_hi0;
logic [ICCM_NUM_BANKS/4-1:0] wren_bank_lo0;
logic [ICCM_NUM_BANKS/4-1:0] wren_bank_hi1;
logic [ICCM_NUM_BANKS/4-1:0] wren_bank_lo1;
logic [ICCM_NUM_BANKS/4-1:0] [ICCM_INDEX_BITS-1:0] addr_bank;
logic [ICCM_NUM_BANKS/4-1:0] [77:0] iccm_bank_dout_hi;
logic [ICCM_NUM_BANKS/4-1:0] [77:0] iccm_bank_dout_lo;
logic [5:4] iccm_rw_addr_q;
// assign CLK = clk ;
for (genvar i=0; i<ICCM_NUM_BANKS/4; i++) begin: mem_bank
assign wren_bank[i] = iccm_wren & ( (iccm_rw_addr[ICCM_BANK_HI:4] == i) | (ICCM_BANK_BITS == 2));
assign rden_bank[i] = iccm_rden & ( (iccm_rw_addr[ICCM_BANK_HI:4] == i) | (ICCM_BANK_BITS == 2));
assign wren_bank_hi0[i] = wren_bank[i] & iccm_rw_addr[3] & (~iccm_rw_addr[2] | (iccm_wr_size[1:0] == 2'b11));
assign wren_bank_hi1[i] = wren_bank[i] & iccm_rw_addr[3] & ( iccm_rw_addr[2] | (iccm_wr_size[1:0] == 2'b11));
assign wren_bank_lo0[i] = wren_bank[i] & ~iccm_rw_addr[3] & (~iccm_rw_addr[2] | (iccm_wr_size[1:0] == 2'b11));
assign wren_bank_lo1[i] = wren_bank[i] & ~iccm_rw_addr[3] & ( iccm_rw_addr[2] | (iccm_wr_size[1:0] == 2'b11));
assign iccm_hi0_clken[i] = wren_bank_hi0[i] | (rden_bank[i] | clk_override); // Do not override the writes
assign iccm_hi1_clken[i] = wren_bank_hi1[i] | (rden_bank[i] | clk_override); // Do not override the writes
assign iccm_lo0_clken[i] = wren_bank_lo0[i] | (rden_bank[i] | clk_override); // Do not override the writes
assign iccm_lo1_clken[i] = wren_bank_lo1[i] | (rden_bank[i] | clk_override); // Do not override the writes
rvclkhdr iccm_hi0_c1_cgc ( .en(iccm_hi0_clken[i]), .l1clk(iccm_hi0_clk[i]), .* );
rvclkhdr iccm_hi1_c1_cgc ( .en(iccm_hi1_clken[i]), .l1clk(iccm_hi1_clk[i]), .* );
rvclkhdr iccm_lo0_c1_cgc ( .en(iccm_lo0_clken[i]), .l1clk(iccm_lo0_clk[i]), .* );
rvclkhdr iccm_lo1_c1_cgc ( .en(iccm_lo1_clken[i]), .l1clk(iccm_lo1_clk[i]), .* );
assign addr_bank[i][ICCM_INDEX_BITS-1:0] = iccm_rw_addr[ICCM_BITS-1:(ICCM_BANK_BITS+2)];
`RV_ICCM_DATA_CELL iccm_bank_hi0 (
// Primary ports
.CLK(iccm_hi0_clk[i]),
.WE(wren_bank_hi0[i]),
.ADR(addr_bank[i]),
.D(iccm_wr_data[38:0]),
.Q(iccm_bank_dout_hi[i][38:0])
);
`RV_ICCM_DATA_CELL iccm_bank_hi1 (
// Primary ports
.CLK(iccm_hi1_clk[i]),
.WE(wren_bank_hi1[i]),
.ADR(addr_bank[i]),
.D(iccm_wr_data[77:39]),
.Q(iccm_bank_dout_hi[i][77:39])
);
`RV_ICCM_DATA_CELL iccm_bank_lo0 (
// Primary ports
.CLK(iccm_lo0_clk[i]),
.WE(wren_bank_lo0[i]),
.ADR(addr_bank[i]),
.D(iccm_wr_data[38:0]),
.Q(iccm_bank_dout_lo[i][38:0])
);
`RV_ICCM_DATA_CELL iccm_bank_lo1 (
// Primary ports
.CLK(iccm_lo1_clk[i]),
.WE(wren_bank_lo1[i]),
.ADR(addr_bank[i]),
.D(iccm_wr_data[77:39]),
.Q(iccm_bank_dout_lo[i][77:39])
);
end : mem_bank
assign iccm_rd_data[155:0] = (ICCM_BANK_BITS == 2) ? {iccm_bank_dout_hi[0][77:0], iccm_bank_dout_lo[0][77:0]} :
{ iccm_bank_dout_hi[iccm_rw_addr_q[ICCM_BANK_HI:4]][77:0], iccm_bank_dout_lo[iccm_rw_addr_q[ICCM_BANK_HI:4]][77:0] };
if (ICCM_BANK_BITS == 2) begin
assign iccm_rw_addr_q[5:4] = '0;
end
// 8 banks, each bank 8B, we index as 4 banks
else begin
rvdff #(2) rd_addr_ff (.*, .din(iccm_rw_addr[5:4]), .dout(iccm_rw_addr_q[5:4]) );
end
endmodule // ifu_iccm_mem

284
design/ifu/ifu_ifc_ctl.sv Normal file
View File

@ -0,0 +1,284 @@
// 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.
//********************************************************************************
// ifu_ifc_ctl.sv
// Function: Fetch pipe control
//
// Comments:
//********************************************************************************
module ifu_ifc_ctl
(
input logic clk,
input logic free_clk,
input logic active_clk,
input logic clk_override, // overrides clock gating
input logic rst_l, // reset enable, from core pin
input logic scan_mode, // scan
input logic ic_hit_f2, // Icache hit
input logic ic_crit_wd_rdy, // Crit word ready to be forwarded
input logic ifu_ic_mb_empty, // Miss buffer empty
input logic ifu_fb_consume1, // Aligner consumed 1 fetch buffer
input logic ifu_fb_consume2, // Aligner consumed 2 fetch buffers
input logic dec_tlu_flush_noredir_wb, // Don't fetch on flush
input logic dec_tlu_dbg_halted, // Core is halted
input logic dec_tlu_pmu_fw_halted, // Core is halted
input logic exu_flush_final, // FLush
input logic [31:1] exu_flush_path_final, // Flush path
input logic ifu_bp_kill_next_f2, // kill next fetch, taken target found
input logic [31:1] ifu_bp_btb_target_f2, // predicted target PC
input logic ic_dma_active, // IC DMA active, stop fetching
input logic ic_write_stall, // IC is writing, stop fetching
input logic dma_iccm_stall_any, // force a stall in the fetch pipe for DMA ICCM access
input logic [31:0] dec_tlu_mrac_ff , // side_effect and cacheable for each region
output logic ifc_fetch_uncacheable_f1, // fetch to uncacheable address as determined by MRAC
output logic [31:1] ifc_fetch_addr_f1, // fetch addr F1
output logic [31:1] ifc_fetch_addr_f2, // fetch addr F2
output logic ifc_fetch_req_f1, // fetch request valid F1
output logic ifc_fetch_req_f1_raw, // for clock-gating in mem_ctl
output logic ifc_fetch_req_f2, // fetch request valid F2
output logic ifu_pmu_fetch_stall, // pmu event measuring fetch stall
output logic ifc_iccm_access_f1, // fetch to ICCM region
output logic ifc_region_acc_fault_f1, // fetch access fault
output logic ifc_dma_access_ok // fetch is not accessing the ICCM, DMA can proceed
);
logic [31:1] fetch_addr_bf, miss_addr, ifc_fetch_addr_f1_raw;
logic [31:1] fetch_addr_next;
logic [31:1] miss_addr_ns;
logic [4:0] cacheable_select;
logic [3:0] fb_write_f1, fb_write_ns;
logic ifc_fetch_req_bf;
logic overflow_nc;
logic fb_full_f1_ns, fb_full_f1;
logic fb_right, fb_right2, fb_right3, fb_left, wfm, fetch_ns, idle;
logic fetch_req_f2_ns;
logic missff_en;
logic fetch_crit_word, ic_crit_wd_rdy_d1, fetch_crit_word_d1, fetch_crit_word_d2;
logic reset_delayed, reset_detect, reset_detected;
logic sel_last_addr_bf, sel_miss_addr_bf, sel_btb_addr_bf, sel_next_addr_bf;
logic miss_f2, miss_a;
logic flush_fb, dma_iccm_stall_any_f;
logic dec_tlu_halted_f;
logic mb_empty_mod, goto_idle, leave_idle;
logic ic_crit_wd_rdy_mod;
logic miss_sel_flush;
logic miss_sel_f2;
logic miss_sel_f1;
logic miss_sel_bf;
logic fetch_bf_en;
logic ifc_fetch_req_f2_raw;
logic ifc_f2_clk;
rvclkhdr ifu_fa2_cgc ( .en(ifc_fetch_req_f1 | clk_override), .l1clk(ifc_f2_clk), .* );
// FSM assignment
typedef enum logic [1:0] { IDLE=2'b00, FETCH=2'b01, STALL=2'b10, WFM=2'b11} state_t;
state_t state, next_state;
logic dma_stall;
assign dma_stall = ic_dma_active | dma_iccm_stall_any_f;
// detect a reset and start fetching the reset vector
rvdff #(2) reset_ff (.*, .clk(free_clk), .din({1'b1, reset_detect}), .dout({reset_detect, reset_detected}));
assign reset_delayed = reset_detect ^ reset_detected;
rvdff #(3) ran_ff (.*, .clk(free_clk), .din({dma_iccm_stall_any, dec_tlu_dbg_halted | dec_tlu_pmu_fw_halted, miss_f2}), .dout({dma_iccm_stall_any_f, dec_tlu_halted_f, miss_a}));
// If crit word fetch is blocked, try again
assign ic_crit_wd_rdy_mod = ic_crit_wd_rdy & ~(fetch_crit_word_d2 & ~ifc_fetch_req_f2);
// For Ifills, we fetch the critical word. Needed for perf and for rom bypass
assign fetch_crit_word = ic_crit_wd_rdy_mod & ~ic_crit_wd_rdy_d1 & ~exu_flush_final & ~ic_write_stall;
assign missff_en = exu_flush_final | (~ic_hit_f2 & ifc_fetch_req_f2) | ifu_bp_kill_next_f2 | fetch_crit_word_d1 | ifu_bp_kill_next_f2 | (ifc_fetch_req_f2 & ~ifc_fetch_req_f1 & ~fetch_crit_word_d2);
assign miss_sel_flush = exu_flush_final & (((wfm | idle) & ~fetch_crit_word_d1) | dma_stall | ic_write_stall);
assign miss_sel_f2 = ~exu_flush_final & ~ic_hit_f2 & ifc_fetch_req_f2;
assign miss_sel_f1 = ~exu_flush_final & ~miss_sel_f2 & ~ifc_fetch_req_f1 & ifc_fetch_req_f2 & ~fetch_crit_word_d2 & ~ifu_bp_kill_next_f2;
assign miss_sel_bf = ~miss_sel_f2 & ~miss_sel_f1 & ~miss_sel_flush;
assign miss_addr_ns[31:1] = ( ({31{miss_sel_flush}} & exu_flush_path_final[31:1]) |
({31{miss_sel_f2}} & ifc_fetch_addr_f2[31:1]) |
({31{miss_sel_f1}} & ifc_fetch_addr_f1[31:1]) |
({31{miss_sel_bf}} & fetch_addr_bf[31:1]));
rvdffe #(31) faddmiss_ff (.*, .en(missff_en), .din(miss_addr_ns[31:1]), .dout(miss_addr[31:1]));
// Fetch address mux
// - flush
// - Miss *or* flush during WFM (icache miss buffer is blocking)
// - Sequential
assign sel_last_addr_bf = ~miss_sel_flush & ~ifc_fetch_req_f1 & ifc_fetch_req_f2 & ~ifu_bp_kill_next_f2;
assign sel_miss_addr_bf = ~miss_sel_flush & ~ifu_bp_kill_next_f2 & ~ifc_fetch_req_f1 & ~ifc_fetch_req_f2;
assign sel_btb_addr_bf = ~miss_sel_flush & ifu_bp_kill_next_f2;
assign sel_next_addr_bf = ~miss_sel_flush & ifc_fetch_req_f1;
assign fetch_addr_bf[31:1] = ( ({31{miss_sel_flush}} & exu_flush_path_final[31:1]) | // FLUSH path
({31{sel_miss_addr_bf}} & miss_addr[31:1]) | // MISS path
({31{sel_btb_addr_bf}} & {ifu_bp_btb_target_f2[31:1]})| // BTB target
({31{sel_last_addr_bf}} & {ifc_fetch_addr_f1[31:1]})| // Last cycle
({31{sel_next_addr_bf}} & {fetch_addr_next[31:1]})); // SEQ path
assign {overflow_nc, fetch_addr_next[31:1]} = {({1'b0, ifc_fetch_addr_f1[31:4]} + 29'b1), 3'b0};
assign ifc_fetch_req_bf = (fetch_ns | fetch_crit_word) ;
assign fetch_bf_en = (fetch_ns | fetch_crit_word);
assign miss_f2 = ifc_fetch_req_f2 & ~ic_hit_f2;
assign mb_empty_mod = (ifu_ic_mb_empty | exu_flush_final) & ~dma_stall & ~miss_f2 & ~miss_a;
// Halt flushes and takes us to IDLE
assign goto_idle = exu_flush_final & dec_tlu_flush_noredir_wb;
// If we're in IDLE, and we get a flush, goto FETCH
assign leave_idle = exu_flush_final & ~dec_tlu_flush_noredir_wb & idle;
//.i 7
//.o 2
//.ilb state[1] state[0] reset_delayed miss_f2 mb_empty_mod goto_idle leave_idle
//.ob next_state[1] next_state[0]
//.type fr
//
//# fetch 01, stall 10, wfm 11, idle 00
//-- 1---- 01
//-- 0--1- 00
//00 0--00 00
//00 0--01 01
//
//01 01-0- 11
//01 00-0- 01
//
//11 0-10- 01
//11 0-00- 11
assign next_state[1] = (~state[1] & state[0] & ~reset_delayed & miss_f2 & ~goto_idle) |
(state[1] & ~reset_delayed & ~mb_empty_mod & ~goto_idle);
assign next_state[0] = (~goto_idle & leave_idle) | (state[0] & ~goto_idle) |
(reset_delayed);
assign flush_fb = exu_flush_final;
// model fb write logic to mass balance the fetch buffers
assign fb_right = (~ifu_fb_consume1 & ~ifu_fb_consume2 & miss_f2) | // F2 cache miss, repair mass balance
( ifu_fb_consume1 & ~ifu_fb_consume2 & ~ifc_fetch_req_f1 & ~miss_f2) | // Consumed and no new fetch
(ifu_fb_consume2 & ifc_fetch_req_f1 & ~miss_f2); // Consumed 2 and new fetch
assign fb_right2 = (ifu_fb_consume1 & ~ifu_fb_consume2 & miss_f2) | // consume 1 and miss 1
(ifu_fb_consume2 & ~ifc_fetch_req_f1); // Consumed 2 and no new fetch
assign fb_right3 = (ifu_fb_consume2 & miss_f2); // consume 2 and miss
assign fb_left = ifc_fetch_req_f1 & ~(ifu_fb_consume1 | ifu_fb_consume2) & ~miss_f2;
assign fb_write_ns[3:0] = ( ({4{(flush_fb & ~ifc_fetch_req_f1)}} & 4'b0001) |
({4{(flush_fb & ifc_fetch_req_f1)}} & 4'b0010) |
({4{~flush_fb & fb_right }} & {1'b0, fb_write_f1[3:1]}) |
({4{~flush_fb & fb_right2}} & {2'b0, fb_write_f1[3:2]}) |
({4{~flush_fb & fb_right3}} & {3'b0, fb_write_f1[3]} ) |
({4{~flush_fb & fb_left }} & {fb_write_f1[2:0], 1'b0}) |
({4{~flush_fb & ~fb_right & ~fb_right2 & ~fb_left & ~fb_right3}} & fb_write_f1[3:0]));
assign fb_full_f1_ns = fb_write_ns[3];
assign idle = state[1:0] == IDLE;
assign wfm = state[1:0] == WFM;
assign fetch_ns = next_state[1:0] == FETCH;
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_f1_ns, fb_write_ns[3:0]}), .dout({fb_full_f1, fb_write_f1[3:0]}));
assign ifu_pmu_fetch_stall = wfm |
(ifc_fetch_req_f1_raw &
( (fb_full_f1 & ~(ifu_fb_consume2 | ifu_fb_consume1 | exu_flush_final)) |
dma_stall));
// BTB hit kills this fetch
assign ifc_fetch_req_f1 = ( ifc_fetch_req_f1_raw &
~ifu_bp_kill_next_f2 &
~(fb_full_f1 & ~(ifu_fb_consume2 | ifu_fb_consume1 | exu_flush_final)) &
~dma_stall &
~ic_write_stall &
~dec_tlu_flush_noredir_wb );
// kill F2 request if we flush or if the prior fetch missed the cache/mem
assign fetch_req_f2_ns = ifc_fetch_req_f1 & ~miss_f2;
rvdff #(2) req_ff (.*, .clk(active_clk), .din({ifc_fetch_req_bf, fetch_req_f2_ns}), .dout({ifc_fetch_req_f1_raw, ifc_fetch_req_f2_raw}));
assign ifc_fetch_req_f2 = ifc_fetch_req_f2_raw & ~exu_flush_final;
rvdffe #(31) faddrf1_ff (.*, .en(fetch_bf_en), .din(fetch_addr_bf[31:1]), .dout(ifc_fetch_addr_f1_raw[31:1]));
rvdff #(31) faddrf2_ff (.*, .clk(ifc_f2_clk), .din(ifc_fetch_addr_f1[31:1]), .dout(ifc_fetch_addr_f2[31:1]));
assign ifc_fetch_addr_f1[31:1] = ( ({31{exu_flush_final}} & exu_flush_path_final[31:1]) |
({31{~exu_flush_final}} & ifc_fetch_addr_f1_raw[31:1]));
rvdff #(3) iccrit_ff (.*, .clk(active_clk), .din({ic_crit_wd_rdy_mod, fetch_crit_word, fetch_crit_word_d1}),
.dout({ic_crit_wd_rdy_d1, fetch_crit_word_d1, fetch_crit_word_d2}));
`ifdef RV_ICCM_ENABLE
logic iccm_acc_in_region_f1;
logic iccm_acc_in_range_f1;
rvrangecheck #( .CCM_SADR (`RV_ICCM_SADR),
.CCM_SIZE (`RV_ICCM_SIZE) ) iccm_rangecheck (
.addr ({ifc_fetch_addr_f1[31:1],1'b0}) ,
.in_range (iccm_acc_in_range_f1) ,
.in_region(iccm_acc_in_region_f1)
);
assign ifc_iccm_access_f1 = iccm_acc_in_range_f1 ;
assign ifc_dma_access_ok = ( (~ifc_iccm_access_f1 |
(fb_full_f1 & ~(ifu_fb_consume2 | ifu_fb_consume1)) |
wfm |
idle ) & ~exu_flush_final) |
dma_iccm_stall_any_f;
assign ifc_region_acc_fault_f1 = ~iccm_acc_in_range_f1 & iccm_acc_in_region_f1 ;
`else
assign ifc_iccm_access_f1 = 1'b0 ;
assign ifc_dma_access_ok = 1'b0 ;
assign ifc_region_acc_fault_f1 = 1'b0 ;
`endif
assign cacheable_select[4:0] = {ifc_fetch_addr_f1[31:28] , 1'b0 } ;
assign ifc_fetch_uncacheable_f1 = ~dec_tlu_mrac_ff[cacheable_select] ; // bit 0 of each region description is the cacheable bit
endmodule // ifu_ifc_ctl

1521
design/ifu/ifu_mem_ctl.sv Normal file

File diff suppressed because it is too large Load Diff

65
design/include/build.h Normal file
View File

@ -0,0 +1,65 @@
// 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.
// BUILD_ICACHE_SIZE = { 32, 64, 128, 256 }
//`define BUILD_ICACHE_SIZE 256
// BUILD_ICACHE_LINE_SIZE = { 16 }
//`define BUILD_ICACHE_LINE_SIZE 64
//// BUILD_BTB_SIZE = {256, 512}
//`define BUILD_BTB_SIZE 512
////`define BUILD_ICCM_SIZE 128
//
////----------------------------------------------------------------------
//// For configurable BTB size
//`define BTB_INDEX1_HI ((`BUILD_BTB_SIZE==256) ? 9 : 10)
//`define BTB_INDEX1_LO 4
//`define BTB_INDEX2_HI ((`BUILD_BTB_SIZE==256) ? 15 : 17)
//`define BTB_INDEX2_LO ((`BUILD_BTB_SIZE==256) ? 10 : 11)
//`define BTB_INDEX3_HI ((`BUILD_BTB_SIZE==256) ? 21 : 24)
//`define BTB_INDEX3_LO ((`BUILD_BTB_SIZE==256) ? 16 : 18)
//`define BTB_ADDR_HI ((`BUILD_BTB_SIZE==256) ? 9 : 10)
//`define BTB_ADDR_LO 4
//// ----------------------------------------------------------------------
// BUILD_DTCM_SADDR
//`define BUILD_DTCM_SADR 32'hf0000000
// BUILD_DTCM_EADDR = {256, 512}
//`define BUILD_DTCM_EADR 32'hf0020000
// BUILD_ITCM_SADDR
//`define BUILD_ITCM_SADR 32'hee000000
// BUILD_ITCM_EADDR = {256, 512}
//`define BUILD_ITCM_EADR 32'hee020000
//----------------------------------------------------------------------
//`define TOTAL_INT 256
//`define INTPEND_BASE_ADDR 32'hcc000400
//`define INTENABLE_BASE_ADDR 32'hcc000800
//`define INTPRIORITY_BASE_ADDR 32'hcc000c00
//`define CLAIMID_ADDR 32'hcc001000
//`define PRITHRESH_ADDR 32'hcc001010
//----------------------------------------------------------------------
// Enable assertions
//`define ASSERT_ON

51
design/include/global.h Normal file
View File

@ -0,0 +1,51 @@
// 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.
localparam TOTAL_INT = `RV_PIC_TOTAL_INT_PLUS1;
localparam DCCM_BITS = `RV_DCCM_BITS;
localparam DCCM_BANK_BITS = `RV_DCCM_BANK_BITS;
localparam DCCM_NUM_BANKS = `RV_DCCM_NUM_BANKS;
localparam DCCM_DATA_WIDTH = `RV_DCCM_DATA_WIDTH;
localparam DCCM_FDATA_WIDTH = `RV_DCCM_FDATA_WIDTH;
localparam DCCM_BYTE_WIDTH = `RV_DCCM_BYTE_WIDTH;
localparam DCCM_ECC_WIDTH = `RV_DCCM_ECC_WIDTH;
localparam LSU_RDBUF_DEPTH = `RV_LSU_NUM_NBLOAD;
localparam DMA_BUF_DEPTH = `RV_DMA_BUF_DEPTH;
localparam LSU_STBUF_DEPTH = `RV_LSU_STBUF_DEPTH;
localparam LSU_SB_BITS = `RV_LSU_SB_BITS;
localparam DEC_INSTBUF_DEPTH = `RV_DEC_INSTBUF_DEPTH;
localparam ICCM_SIZE = `RV_ICCM_SIZE;
localparam ICCM_BITS = `RV_ICCM_BITS;
localparam ICCM_NUM_BANKS = `RV_ICCM_NUM_BANKS;
localparam ICCM_BANK_BITS = `RV_ICCM_BANK_BITS;
localparam ICCM_INDEX_BITS = `RV_ICCM_INDEX_BITS;
localparam ICCM_BANK_HI = 4 + (`RV_ICCM_BANK_BITS/4);
localparam ICACHE_TAG_HIGH = `RV_ICACHE_TAG_HIGH;
localparam ICACHE_TAG_LOW = `RV_ICACHE_TAG_LOW;
localparam ICACHE_IC_DEPTH = `RV_ICACHE_IC_DEPTH;
localparam ICACHE_TAG_DEPTH = `RV_ICACHE_TAG_DEPTH;
localparam LSU_BUS_TAG = `RV_LSU_BUS_TAG;
localparam DMA_BUS_TAG = `RV_DMA_BUS_TAG;
localparam SB_BUS_TAG = `RV_SB_BUS_TAG;
localparam IFU_BUS_TAG = `RV_IFU_BUS_TAG;

View File

@ -0,0 +1,335 @@
// 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.
package swerv_types;
// performance monitor stuff
typedef struct packed {
logic [2:0] trace_rv_i_valid_ip;
logic [95:0] trace_rv_i_insn_ip;
logic [95:0] trace_rv_i_address_ip;
logic [2:0] trace_rv_i_exception_ip;
logic [4:0] trace_rv_i_ecause_ip;
logic [2:0] trace_rv_i_interrupt_ip;
logic [31:0] trace_rv_i_tval_ip;
} trace_pkt_t;
typedef enum logic [3:0] {
NULL = 4'b0000,
MUL = 4'b0001,
LOAD = 4'b0010,
STORE = 4'b0011,
ALU = 4'b0100,
CSRREAD = 4'b0101,
CSRWRITE = 4'b0110,
CSRRW = 4'b0111,
EBREAK = 4'b1000,
ECALL = 4'b1001,
FENCE = 4'b1010,
FENCEI = 4'b1011,
MRET = 4'b1100,
CONDBR = 4'b1101,
JAL = 4'b1110
} inst_t;
typedef struct packed {
`ifdef RV_ICACHE_ECC
logic [39:0] ecc;
`else
logic [7:0] parity;
`endif
} icache_err_pkt_t;
typedef struct packed {
logic valid;
logic wb;
logic [`RV_LSU_NUM_NBLOAD_WIDTH-1:0] tag;
logic [4:0] rd;
} load_cam_pkt_t;
typedef struct packed {
logic pc0_call;
logic pc0_ret;
logic pc0_pc4;
logic pc1_call;
logic pc1_ret;
logic pc1_pc4;
} rets_pkt_t;
typedef struct packed {
logic valid;
logic [11:0] toffset;
logic [1:0] hist;
logic br_error;
logic br_start_error;
logic [`RV_BTB_ADDR_HI:`RV_BTB_ADDR_LO] index;
logic [1:0] bank;
logic [31:1] prett; // predicted ret target
logic [`RV_BHT_GHR_RANGE] fghr;
`ifdef RV_BTB_48
logic [1:0] way;
`else
logic way;
`endif
logic ret;
logic [`RV_BTB_BTAG_SIZE-1:0] btag;
} br_pkt_t;
typedef struct packed {
logic valid;
logic [1:0] hist;
logic br_error;
logic br_start_error;
logic [`RV_BTB_ADDR_HI:`RV_BTB_ADDR_LO] index;
logic [1:0] bank;
logic [`RV_BHT_GHR_RANGE] fghr;
`ifdef RV_BTB_48
logic [1:0] way;
`else
logic way;
`endif
logic middle;
} br_tlu_pkt_t;
typedef struct packed {
logic misp;
logic ataken;
logic boffset;
logic pc4;
logic [1:0] hist;
logic [11:0] toffset;
logic [`RV_BTB_ADDR_HI:`RV_BTB_ADDR_LO] index;
logic [1:0] bank;
logic valid;
logic br_error;
logic br_start_error;
logic [31:1] prett;
logic pcall;
logic pret;
logic pja;
logic [`RV_BTB_BTAG_SIZE-1:0] btag;
logic [`RV_BHT_GHR_RANGE] fghr;
`ifdef RV_BTB_48
logic [1:0] way;
`else
logic way;
`endif
} predict_pkt_t;
typedef struct packed {
logic legal;
logic icaf;
logic icaf_f1;
logic perr;
logic sbecc;
logic fence_i;
logic [3:0] i0trigger;
logic [3:0] i1trigger;
inst_t pmu_i0_itype; // pmu - instruction type
inst_t pmu_i1_itype; // pmu - instruction type
logic pmu_i0_br_unpred; // pmu
logic pmu_i1_br_unpred; // pmu
logic pmu_divide;
logic pmu_lsu_misaligned;
} trap_pkt_t;
typedef struct packed {
logic [4:0] i0rd;
logic i0mul;
logic i0load;
logic i0store;
logic i0div;
logic i0v;
logic i0valid;
logic i0secondary;
logic [1:0] i0rs1bype2;
logic [1:0] i0rs2bype2;
logic [3:0] i0rs1bype3;
logic [3:0] i0rs2bype3;
logic [4:0] i1rd;
logic i1mul;
logic i1load;
logic i1store;
logic i1v;
logic i1valid;
logic csrwen;
logic csrwonly;
logic [11:0] csrwaddr;
logic i1secondary;
logic [1:0] i1rs1bype2;
logic [1:0] i1rs2bype2;
logic [6:0] i1rs1bype3;
logic [6:0] i1rs2bype3;
} dest_pkt_t;
typedef struct packed {
logic mul;
logic load;
logic sec;
logic alu;
} class_pkt_t;
typedef struct packed {
logic [4:0] rs1;
logic [4:0] rs2;
logic [4:0] rd;
} reg_pkt_t;
typedef struct packed {
logic valid;
logic land;
logic lor;
logic lxor;
logic sll;
logic srl;
logic sra;
logic beq;
logic bne;
logic blt;
logic bge;
logic add;
logic sub;
logic slt;
logic unsign;
logic jal;
logic predict_t;
logic predict_nt;
logic csr_write;
logic csr_imm;
} alu_pkt_t;
typedef struct packed {
logic by;
logic half;
logic word;
logic dword; // for dma
logic load;
logic store;
logic unsign;
logic dma; // dma pkt
logic store_data_bypass_c1;
logic load_ldst_bypass_c1;
logic store_data_bypass_c2;
logic store_data_bypass_i0_e2_c2;
logic [1:0] store_data_bypass_e4_c1;
logic [1:0] store_data_bypass_e4_c2;
logic [1:0] store_data_bypass_e4_c3;
logic valid;
} lsu_pkt_t;
typedef struct packed {
logic exc_valid;
logic single_ecc_error;
logic inst_type; //0: Load, 1: Store
logic inst_pipe; //0: i0, 1: i1
logic dma_valid;
logic exc_type; //0: MisAligned, 1: Access Fault
logic [31:0] addr;
} lsu_error_pkt_t;
typedef struct packed {
logic alu;
logic rs1;
logic rs2;
logic imm12;
logic rd;
logic shimm5;
logic imm20;
logic pc;
logic load;
logic store;
logic lsu;
logic add;
logic sub;
logic land;
logic lor;
logic lxor;
logic sll;
logic sra;
logic srl;
logic slt;
logic unsign;
logic condbr;
logic beq;
logic bne;
logic bge;
logic blt;
logic jal;
logic by;
logic half;
logic word;
logic csr_read;
logic csr_clr;
logic csr_set;
logic csr_write;
logic csr_imm;
logic presync;
logic postsync;
logic ebreak;
logic ecall;
logic mret;
logic mul;
logic rs1_sign;
logic rs2_sign;
logic low;
logic div;
logic rem;
logic fence;
logic fence_i;
logic pm_alu;
logic legal;
} dec_pkt_t;
typedef struct packed {
logic valid;
logic rs1_sign;
logic rs2_sign;
logic low;
logic load_mul_rs1_bypass_e1;
logic load_mul_rs2_bypass_e1;
} mul_pkt_t;
typedef struct packed {
logic valid;
logic unsign;
logic rem;
} div_pkt_t;
typedef struct packed {
logic select;
logic match;
logic store;
logic load;
logic execute;
logic m;
logic [31:0] tdata2;
} trigger_pkt_t;
typedef struct packed {
`ifdef RV_ICACHE_ECC
logic [41:0] icache_wrdata; // {dicad0[31:0], dicad1[1:0]}
`else
logic [33:0] icache_wrdata; // {dicad0[31:0], dicad1[1:0]}
`endif
logic [18:2] icache_dicawics;
logic icache_rd_valid;
logic icache_wr_valid;
} cache_debug_pkt_t;
endpackage // swerv_types

281
design/lib/ahb_to_axi4.sv Normal file
View File

@ -0,0 +1,281 @@
// 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.
//********************************************************************************
// $Id$
//
// Owner:
// Function: AHB to AXI4 Bridge
// Comments:
//
//********************************************************************************
module ahb_to_axi4 #(parameter TAG = 1) (
input clk,
input rst_l,
input scan_mode,
input bus_clk_en,
input clk_override,
// AXI signals
// AXI Write Channels
output logic axi_awvalid,
input logic axi_awready,
output logic [TAG-1:0] axi_awid,
output logic [31:0] axi_awaddr,
output logic [2:0] axi_awsize,
output logic [2:0] axi_awprot,
output logic [7:0] axi_awlen,
output logic [1:0] axi_awburst,
output logic axi_wvalid,
input logic axi_wready,
output logic [63:0] axi_wdata,
output logic [7:0] axi_wstrb,
output logic axi_wlast,
input logic axi_bvalid,
output logic axi_bready,
input logic [1:0] axi_bresp,
input logic [TAG-1:0] axi_bid,
// AXI Read Channels
output logic axi_arvalid,
input logic axi_arready,
output logic [TAG-1:0] axi_arid,
output logic [31:0] axi_araddr,
output logic [2:0] axi_arsize,
output logic [2:0] axi_arprot,
output logic [7:0] axi_arlen,
output logic [1:0] axi_arburst,
input logic axi_rvalid,
output logic axi_rready,
input logic [TAG-1:0] axi_rid,
input logic [63:0] axi_rdata,
input logic [1:0] axi_rresp,
// AHB-Lite signals
input logic [31:0] ahb_haddr, // ahb bus address
input logic [2:0] ahb_hburst, // tied to 0
input logic ahb_hmastlock, // tied to 0
input logic [3:0] ahb_hprot, // tied to 4'b0011
input logic [2:0] ahb_hsize, // size of bus transaction (possible values 0,1,2,3)
input logic [1:0] ahb_htrans, // Transaction type (possible values 0,2 only right now)
input logic ahb_hwrite, // ahb bus write
input logic [63:0] ahb_hwdata, // ahb bus write data
input logic ahb_hsel, // this slave was selected
input logic ahb_hreadyin, // previous hready was accepted or not
output logic [63:0] ahb_hrdata, // ahb bus read data
output logic ahb_hreadyout, // slave ready to accept transaction
output logic ahb_hresp // slave response (high indicates erro)
);
logic [7:0] master_wstrb;
typedef enum logic [1:0] { IDLE = 2'b00, // Nothing in the buffer. No commands yet recieved
WR = 2'b01, // Write Command recieved
RD = 2'b10, // Read Command recieved
PEND = 2'b11 // Waiting on Read Data from core
} state_t;
state_t buf_state, buf_nxtstate;
logic buf_state_en;
// Buffer signals (one entry buffer)
logic buf_read_error_in, buf_read_error;
logic [63:0] buf_rdata;
logic ahb_hready;
logic ahb_hready_q;
logic [1:0] ahb_htrans_in, ahb_htrans_q;
logic [2:0] ahb_hsize_q;
logic ahb_hwrite_q;
logic [31:0] ahb_haddr_q;
logic [63:0] ahb_hwdata_q;
logic ahb_hresp_q;
//Miscellaneous signals
logic ahb_addr_in_dccm, ahb_addr_in_iccm, ahb_addr_in_pic;
logic ahb_addr_in_dccm_region_nc, ahb_addr_in_iccm_region_nc, ahb_addr_in_pic_region_nc;
// 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;
// Command buffer is the holding station where we convert to AXI and send to core
logic cmdbuf_wr_en, cmdbuf_rst;
logic cmdbuf_full;
logic cmdbuf_vld, cmdbuf_write;
logic [1:0] cmdbuf_size;
logic [7:0] cmdbuf_wstrb;
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;
buf_state_en = 1'b0;
buf_rdata_en = 1'b0; // signal to load the buffer when the core sends read data back
buf_read_error_in = 1'b0; // signal indicating that an error came back with the read from the core
cmdbuf_wr_en = 1'b0; // all clear from the gasket to load the buffer with the command for reads, command/dat for writes
case (buf_state)
IDLE: begin // No commands recieved
buf_nxtstate = ahb_hwrite ? WR : RD;
buf_state_en = ahb_hready & ahb_htrans[1] & ahb_hsel; // only transition on a valid hrtans
end
WR: begin // Write command recieved last cycle
buf_nxtstate = (ahb_hresp | (ahb_htrans[1:0] == 2'b0) | ~ahb_hsel) ? IDLE : (ahb_hwrite ? WR : RD);
buf_state_en = (~cmdbuf_full | ahb_hresp) ;
cmdbuf_wr_en = ~cmdbuf_full & ~(ahb_hresp | ((ahb_htrans[1:0] == 2'b01) & ahb_hsel)); // Dont send command to the buffer in case of an error or when the master is not ready with the data now.
end
RD: begin // Read command recieved last cycle.
buf_nxtstate = ahb_hresp ? IDLE :PEND; // If error go to idle, else wait for read data
buf_state_en = (~cmdbuf_full | ahb_hresp); // only when command can go, or if its an error
cmdbuf_wr_en = ~ahb_hresp & ~cmdbuf_full; // send command only when no error
end
PEND: begin // Read Command has been sent. Waiting on Data.
buf_nxtstate = IDLE; // go back for next command and present data next cycle
buf_state_en = axi_rvalid & ~cmdbuf_write; // read data is back
buf_rdata_en = buf_state_en; // buffer the read data coming back from core
buf_read_error_in = buf_state_en & |axi_rresp[1:0]; // buffer error flag if return has Error ( ECC )
end
endcase
end // always_comb begin
rvdffs #($bits(state_t)) state_reg (.*, .din(buf_nxtstate), .dout({buf_state}), .en(buf_state_en), .clk(ahb_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])) |
({8{ahb_hsize_q[2:0] == 3'b10}} & (8'b1111 << ahb_haddr_q[2:0])) |
({8{ahb_hsize_q[2:0] == 3'b11}} & 8'b1111_1111);
// AHB signals
assign ahb_hreadyout = ahb_hresp ? (ahb_hresp_q & ~ahb_hready_q) :
((~cmdbuf_full | (buf_state == IDLE)) & ~(buf_state == RD | buf_state == PEND) & ~buf_read_error);
assign ahb_hready = ahb_hreadyout & ahb_hreadyin;
assign ahb_htrans_in[1:0] = {2{ahb_hsel}} & ahb_htrans[1:0];
assign ahb_hrdata[63:0] = buf_rdata[63:0];
assign ahb_hresp = ((ahb_htrans_q[1:0] != 2'b0) & (buf_state != IDLE) &
((~(ahb_addr_in_dccm | ahb_addr_in_iccm)) | // request not for ICCM or DCCM
((ahb_addr_in_iccm | (ahb_addr_in_dccm & ahb_hwrite_q)) & ~((ahb_hsize_q[1:0] == 2'b10) | (ahb_hsize_q[1:0] == 2'b11))) | // ICCM Rd/Wr OR DCCM Wr not the right size
((ahb_hsize_q[2:0] == 3'h1) & ahb_haddr_q[0]) | // HW size but unaligned
((ahb_hsize_q[2:0] == 3'h2) & (|ahb_haddr_q[1:0])) | // W size but unaligned
((ahb_hsize_q[2:0] == 3'h3) & (|ahb_haddr_q[2:0])))) | // DW size but unaligned
buf_read_error | // Read ECC error
(ahb_hresp_q & ~ahb_hready_q); // This is for second cycle of hresp protocol
// 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
// 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), .*);
// Address check dccm
rvrangecheck #(.CCM_SADR(`RV_DCCM_SADR),
.CCM_SIZE(`RV_DCCM_SIZE)) addr_dccm_rangecheck (
.addr(ahb_haddr_q[31:0]),
.in_range(ahb_addr_in_dccm),
.in_region(ahb_addr_in_dccm_region_nc)
);
// Address check iccm
`ifdef RV_ICCM_ENABLE
rvrangecheck #(.CCM_SADR(`RV_ICCM_SADR),
.CCM_SIZE(`RV_ICCM_SIZE)) addr_iccm_rangecheck (
.addr(ahb_haddr_q[31:0]),
.in_range(ahb_addr_in_iccm),
.in_region(ahb_addr_in_iccm_region_nc)
);
`else
assign ahb_addr_in_iccm = '0;
assign ahb_addr_in_iccm_region_nc = '0;
`endif
// PIC memory address check
rvrangecheck #(.CCM_SADR(`RV_PIC_BASE_ADDR),
.CCM_SIZE(`RV_PIC_SIZE)) addr_pic_rangecheck (
.addr(ahb_haddr_q[31:0]),
.in_range(ahb_addr_in_pic),
.in_region(ahb_addr_in_pic_region_nc)
);
// Command Buffer - Holding for the commands to be sent for the AXI. It will be converted to the AXI signals.
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), .*);
// AXI Write Command Channel
assign axi_awvalid = cmdbuf_vld & cmdbuf_write;
assign axi_awid[TAG-1:0] = '0;
assign axi_awaddr[31:0] = cmdbuf_addr[31:0];
assign axi_awsize[2:0] = {1'b0, cmdbuf_size[1:0]};
assign axi_awprot[2:0] = 3'b0;
assign axi_awlen[7:0] = '0;
assign axi_awburst[1:0] = 2'b01;
// AXI Write Data Channel - This is tied to the command channel as we only write the command buffer once we have the data.
assign axi_wvalid = cmdbuf_vld & cmdbuf_write;
assign axi_wdata[63:0] = cmdbuf_wdata[63:0];
assign axi_wstrb[7:0] = cmdbuf_wstrb[7:0];
assign axi_wlast = 1'b1;
// AXI Write Response - Always ready. AHB does not require a write response.
assign axi_bready = 1'b1;
// AXI Read Channels
assign axi_arvalid = cmdbuf_vld & ~cmdbuf_write;
assign axi_arid[TAG-1:0] = '0;
assign axi_araddr[31:0] = cmdbuf_addr[31:0];
assign axi_arsize[2:0] = {1'b0, cmdbuf_size[1:0]};
assign axi_arprot = 3'b0;
assign axi_arlen[7:0] = '0;
assign axi_arburst[1:0] = 2'b01;
// AXI Read Response Channel - Always ready as AHB reads are blocking and the the buffer is available for the read coming back always.
assign axi_rready = 1'b1;
// Clock header logic
rvclkhdr bus_cgc (.en(bus_clk_en), .l1clk(bus_clk), .*);
`ifdef ASSERT_ON
property ahb_error_protocol;
@(posedge ahb_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");
`endif
endmodule // ahb_to_axi4

472
design/lib/axi4_to_ahb.sv Normal file
View File

@ -0,0 +1,472 @@
// 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.
//********************************************************************************
// $Id$
//
// Owner:
// Function: AXI4 -> AHB Bridge
// Comments:
//
//********************************************************************************
module axi4_to_ahb #(parameter TAG = 1) (
input clk,
input rst_l,
input scan_mode,
input bus_clk_en,
input clk_override,
// AXI signals
// AXI Write Channels
input logic axi_awvalid,
output logic axi_awready,
input logic [TAG-1:0] axi_awid,
input logic [31:0] axi_awaddr,
input logic [2:0] axi_awsize,
input logic [2:0] axi_awprot,
input logic axi_wvalid,
output logic axi_wready,
input logic [63:0] axi_wdata,
input logic [7:0] axi_wstrb,
input logic axi_wlast,
output logic axi_bvalid,
input logic axi_bready,
output logic [1:0] axi_bresp,
output logic [TAG-1:0] axi_bid,
// AXI Read Channels
input logic axi_arvalid,
output logic axi_arready,
input logic [TAG-1:0] axi_arid,
input logic [31:0] axi_araddr,
input logic [2:0] axi_arsize,
input logic [2:0] axi_arprot,
output logic axi_rvalid,
input logic axi_rready,
output logic [TAG-1:0] axi_rid,
output logic [63:0] axi_rdata,
output logic [1:0] axi_rresp,
output logic axi_rlast,
// AHB-Lite signals
output logic [31:0] ahb_haddr, // ahb bus address
output logic [2:0] ahb_hburst, // tied to 0
output logic ahb_hmastlock, // tied to 0
output logic [3:0] ahb_hprot, // tied to 4'b0011
output logic [2:0] ahb_hsize, // size of bus transaction (possible values 0,1,2,3)
output logic [1:0] ahb_htrans, // Transaction type (possible values 0,2 only right now)
output logic ahb_hwrite, // ahb bus write
output logic [63:0] ahb_hwdata, // ahb bus write data
input logic [63:0] ahb_hrdata, // ahb bus read data
input logic ahb_hready, // slave ready to accept transaction
input logic ahb_hresp // slave response (high indicates erro)
);
localparam ID = 1;
localparam PRTY = 1;
typedef enum logic [2:0] {IDLE=3'b000, CMD_RD=3'b001, CMD_WR=3'b010, DATA_RD=3'b011, DATA_WR=3'b100, DONE=3'b101, STREAM_RD=3'b110, STREAM_ERR_RD=3'b111} state_t;
state_t buf_state, buf_nxtstate;
logic slave_valid;
logic slave_ready;
logic [TAG-1:0] slave_tag;
logic [63:0] slave_rdata;
logic [3:0] slave_opc;
logic wrbuf_en, wrbuf_data_en;
logic wrbuf_cmd_sent, wrbuf_rst;
logic wrbuf_vld;
logic wrbuf_data_vld;
logic [TAG-1:0] wrbuf_tag;
logic [2:0] wrbuf_size;
logic [31:0] wrbuf_addr;
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;
logic [31:0] master_addr;
logic [63:0] master_wdata;
logic [2:0] master_size;
logic [2:0] master_opc;
// Buffer signals (one entry buffer)
logic [31:0] buf_addr;
logic [1:0] buf_size;
logic buf_write;
logic [7:0] buf_byteen;
logic buf_aligned;
logic [63:0] buf_data;
logic [TAG-1:0] buf_tag;
//Miscellaneous signals
logic buf_rst;
logic [TAG-1:0] buf_tag_in;
logic [31:0] buf_addr_in;
logic [7:0] buf_byteen_in;
logic [63:0] buf_data_in;
logic buf_write_in;
logic buf_aligned_in;
logic [2:0] buf_size_in;
logic buf_state_en;
logic buf_wr_en;
logic buf_data_wr_en;
logic slvbuf_error_en;
logic wr_cmd_vld;
logic cmd_done_rst, cmd_done, cmd_doneQ;
logic trxn_done;
logic [2:0] buf_cmd_byte_ptr, buf_cmd_byte_ptrQ, buf_cmd_nxtbyte_ptr;
logic buf_cmd_byte_ptr_en;
logic found;
logic slave_valid_pre;
logic ahb_hready_q;
logic ahb_hresp_q;
logic [1:0] ahb_htrans_q;
logic ahb_hwrite_q;
logic [63:0] ahb_hrdata_q;
logic slvbuf_write;
logic slvbuf_error;
logic [TAG-1:0] slvbuf_tag;
logic slvbuf_error_in;
logic slvbuf_wr_en;
logic bypass_en;
logic rd_bypass_idle;
logic last_addr_en;
logic [31:0] last_bus_addr;
// Clocks
logic buf_clken, slvbuf_clken;
logic ahbm_addr_clken;
logic ahbm_data_clken;
logic buf_clk, slvbuf_clk;
logic ahbm_clk;
logic ahbm_addr_clk;
logic ahbm_data_clk;
// Function to get the length from byte enable
function automatic logic [1:0] get_write_size;
input logic [7:0] byteen;
logic [1:0] size;
size[1:0] = (2'b11 & {2{(byteen[7:0] == 8'hff)}}) |
(2'b10 & {2{((byteen[7:0] == 8'hf0) | (byteen[7:0] == 8'h0f))}}) |
(2'b01 & {2{((byteen[7:0] == 8'hc0) | (byteen[7:0] == 8'h30) | (byteen[7:0] == 8'h0c) | (byteen[7:0] == 8'h03))}});
return size[1:0];
endfunction // get_write_size
// Function to get the length from byte enable
function automatic logic [2:0] get_write_addr;
input logic [7:0] byteen;
logic [2:0] addr;
addr[2:0] = (3'h0 & {3{((byteen[7:0] == 8'hff) | (byteen[7:0] == 8'h0f) | (byteen[7:0] == 8'h03))}}) |
(3'h2 & {3{(byteen[7:0] == 8'h0c)}}) |
(3'h4 & {3{((byteen[7:0] == 8'hf0) | (byteen[7:0] == 8'h03))}}) |
(3'h6 & {3{(byteen[7:0] == 8'hc0)}});
return addr[2:0];
endfunction // get_write_size
// Function to get the next byte pointer
function automatic logic [2:0] get_nxtbyte_ptr (logic [2:0] current_byte_ptr, logic [7:0] byteen, logic get_next);
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
get_nxtbyte_ptr[2:0] = 3'(j);
found |= (byteen[j] & (3'(j) >= start_ptr[2:0])) ;
end
end
endfunction // get_nextbyte_ptr
// 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 axi_awready = ~(wrbuf_vld & ~wrbuf_cmd_sent) & master_ready;
assign axi_wready = ~(wrbuf_data_vld & ~wrbuf_cmd_sent) & master_ready;
assign axi_arready = ~(wrbuf_vld & wrbuf_data_vld) & master_ready;
assign axi_rlast = 1'b1;
assign wr_cmd_vld = (wrbuf_vld & wrbuf_data_vld);
assign master_valid = wr_cmd_vld | axi_arvalid;
assign master_tag[TAG-1:0] = wr_cmd_vld ? wrbuf_tag[TAG-1:0] : axi_arid[TAG-1:0];
assign master_opc[2:0] = wr_cmd_vld ? 3'b011 : 3'b0;
assign master_addr[31:0] = wr_cmd_vld ? wrbuf_addr[31:0] : axi_araddr[31:0];
assign master_size[2:0] = wr_cmd_vld ? wrbuf_size[2:0] : axi_arsize[2:0];
assign master_wdata[63:0] = wrbuf_data[63:0];
// AXI response channel signals
assign axi_bvalid = slave_valid & slave_ready & slave_opc[3];
assign axi_bresp[1:0] = slave_opc[0] ? 2'b10 : (slave_opc[1] ? 2'b11 : 2'b0);
assign axi_bid[TAG-1:0] = slave_tag[TAG-1:0];
assign axi_rvalid = slave_valid & slave_ready & (slave_opc[3:2] == 2'b0);
assign axi_rresp[1:0] = slave_opc[0] ? 2'b10 : (slave_opc[1] ? 2'b11 : 2'b0);
assign axi_rid[TAG-1:0] = slave_tag[TAG-1:0];
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;
buf_state_en = 1'b0;
buf_wr_en = 1'b0;
buf_data_wr_en = 1'b0;
slvbuf_error_in = 1'b0;
slvbuf_error_en = 1'b0;
buf_write_in = 1'b0;
cmd_done = 1'b0;
trxn_done = 1'b0;
buf_cmd_byte_ptr_en = 1'b0;
buf_cmd_byte_ptr[2:0] = '0;
slave_valid_pre = 1'b0;
master_ready = 1'b0;
ahb_htrans[1:0] = 2'b0;
slvbuf_wr_en = 1'b0;
bypass_en = 1'b0;
rd_bypass_idle = 1'b0;
case (buf_state)
IDLE: begin
master_ready = 1'b1;
buf_write_in = (master_opc[2:1] == 2'b01);
buf_nxtstate = buf_write_in ? CMD_WR : CMD_RD;
buf_state_en = master_valid & master_ready;
buf_wr_en = buf_state_en;
buf_data_wr_en = buf_state_en & (buf_nxtstate == CMD_WR);
buf_cmd_byte_ptr_en = buf_state_en;
buf_cmd_byte_ptr[2:0] = buf_write_in ? get_nxtbyte_ptr(3'b0,buf_byteen_in[7:0],1'b0) : master_addr[2:0];
bypass_en = buf_state_en;
rd_bypass_idle = bypass_en & (buf_nxtstate == CMD_RD);
ahb_htrans[1:0] = {2{bypass_en}} & 2'b10;
end
CMD_RD: begin
buf_nxtstate = (master_valid & (master_opc[2:0] == 3'b000))? STREAM_RD : DATA_RD;
buf_state_en = ahb_hready_q & (ahb_htrans_q[1:0] != 2'b0) & ~ahb_hwrite_q;
cmd_done = buf_state_en & ~master_valid;
slvbuf_wr_en = buf_state_en;
master_ready = buf_state_en & (buf_nxtstate == STREAM_RD);
buf_wr_en = master_ready;
bypass_en = master_ready & master_valid;
buf_cmd_byte_ptr[2:0] = bypass_en ? master_addr[2:0] : buf_addr[2:0];
ahb_htrans[1:0] = 2'b10 & {2{~buf_state_en | bypass_en}};
end
STREAM_RD: begin
master_ready = (ahb_hready_q & ~ahb_hresp_q) & ~(master_valid & master_opc[2:1] == 2'b01);
buf_wr_en = (master_valid & master_ready & (master_opc[2:0] == 3'b000)); // update the fifo if we are streaming the read commands
buf_nxtstate = ahb_hresp_q ? STREAM_ERR_RD : (buf_wr_en ? STREAM_RD : DATA_RD); // assuming that the master accpets the slave response right away.
buf_state_en = (ahb_hready_q | ahb_hresp_q);
buf_data_wr_en = buf_state_en;
slvbuf_error_in = ahb_hresp_q;
slvbuf_error_en = buf_state_en;
slave_valid_pre = buf_state_en & ~ahb_hresp_q; // send a response right away if we are not going through an error response.
cmd_done = buf_state_en & ~master_valid; // last one of the stream should not send a htrans
bypass_en = master_ready & master_valid & (buf_nxtstate == STREAM_RD) & buf_state_en;
buf_cmd_byte_ptr[2:0] = bypass_en ? master_addr[2:0] : buf_addr[2:0];
ahb_htrans[1:0] = 2'b10 & {2{~((buf_nxtstate != STREAM_RD) & buf_state_en)}};
slvbuf_wr_en = buf_wr_en; // shifting the contents from the buf to slv_buf for streaming cases
end // case: STREAM_RD
STREAM_ERR_RD: begin
buf_nxtstate = DATA_RD;
buf_state_en = ahb_hready_q & (ahb_htrans_q[1:0] != 2'b0) & ~ahb_hwrite_q;
slave_valid_pre = buf_state_en;
slvbuf_wr_en = buf_state_en; // Overwrite slvbuf with buffer
buf_cmd_byte_ptr[2:0] = buf_addr[2:0];
ahb_htrans[1:0] = 2'b10 & {2{~buf_state_en}};
end
DATA_RD: begin
buf_nxtstate = DONE;
buf_state_en = (ahb_hready_q | ahb_hresp_q);
buf_data_wr_en = buf_state_en;
slvbuf_error_in= ahb_hresp_q;
slvbuf_error_en= buf_state_en;
slvbuf_wr_en = buf_state_en;
end
CMD_WR: begin
buf_nxtstate = DATA_WR;
trxn_done = ahb_hready_q & ahb_hwrite_q & (ahb_htrans_q[1:0] != 2'b0);
buf_state_en = trxn_done;
buf_cmd_byte_ptr_en = buf_state_en;
slvbuf_wr_en = buf_state_en;
buf_cmd_byte_ptr = trxn_done ? get_nxtbyte_ptr(buf_cmd_byte_ptrQ[2:0],buf_byteen[7:0],1'b1) : buf_cmd_byte_ptrQ;
cmd_done = trxn_done & (buf_aligned | (buf_cmd_byte_ptrQ == 3'b111) |
(buf_byteen[get_nxtbyte_ptr(buf_cmd_byte_ptrQ[2:0],buf_byteen[7:0],1'b1)] == 1'b0));
ahb_htrans[1:0] = {2{~(cmd_done | cmd_doneQ)}} & 2'b10;
end
DATA_WR: begin
buf_state_en = (cmd_doneQ & ahb_hready_q) | ahb_hresp_q;
master_ready = buf_state_en & ~ahb_hresp_q & slave_ready; // Ready to accept new command if current command done and no error
buf_nxtstate = (ahb_hresp_q | ~slave_ready) ? DONE :
((master_valid & master_ready) ? ((master_opc[2:1] == 2'b01) ? CMD_WR : CMD_RD) : IDLE);
slvbuf_error_in = ahb_hresp_q;
slvbuf_error_en = buf_state_en;
buf_write_in = (master_opc[2:1] == 2'b01);
buf_wr_en = buf_state_en & ((buf_nxtstate == CMD_WR) | (buf_nxtstate == CMD_RD));
buf_data_wr_en = buf_wr_en;
cmd_done = (ahb_hresp_q | (ahb_hready_q & (ahb_htrans_q[1:0] != 2'b0) &
((buf_cmd_byte_ptrQ == 3'b111) | (buf_byteen[get_nxtbyte_ptr(buf_cmd_byte_ptrQ[2:0],buf_byteen[7:0],1'b1)] == 1'b0))));
bypass_en = buf_state_en & buf_write_in & (buf_nxtstate == CMD_WR); // Only bypass for writes for the time being
ahb_htrans[1:0] = {2{(~(cmd_done | cmd_doneQ) | bypass_en)}} & 2'b10;
slave_valid_pre = buf_state_en & (buf_nxtstate != DONE);
trxn_done = ahb_hready_q & ahb_hwrite_q & (ahb_htrans_q[1:0] != 2'b0);
buf_cmd_byte_ptr_en = trxn_done | bypass_en;
buf_cmd_byte_ptr = bypass_en ? get_nxtbyte_ptr(3'b0,buf_byteen_in[7:0],1'b0) :
trxn_done ? get_nxtbyte_ptr(buf_cmd_byte_ptrQ[2:0],buf_byteen[7:0],1'b1) : buf_cmd_byte_ptrQ;
end
DONE: begin
buf_nxtstate = IDLE;
buf_state_en = slave_ready;
slvbuf_error_en = 1'b1;
slave_valid_pre = 1'b1;
end
endcase
end
assign buf_rst = 1'b0;
assign cmd_done_rst = slave_valid_pre;
assign buf_addr_in[2:0] = (buf_aligned_in & (master_opc[2:1] == 2'b01)) ? get_write_addr(wrbuf_byteen[7:0]) : master_addr[2:0];
assign buf_addr_in[31:3] = master_addr[31:3];
assign buf_tag_in[TAG-1:0] = master_tag[TAG-1:0];
assign buf_byteen_in[7:0] = wrbuf_byteen[7:0];
assign buf_data_in[63:0] = (buf_state == DATA_RD) ? ahb_hrdata_q[63:0] : master_wdata[63:0];
assign buf_size_in[1:0] = (buf_aligned_in & (master_size[1:0] == 2'b11) & (master_opc[2:1] == 2'b01)) ? get_write_size(wrbuf_byteen[7:0]) : master_size[1:0];
assign buf_aligned_in = (master_opc[2:0] == 3'b0) | // reads are always aligned since they are either DW or sideeffects
(master_size[1:0] == 2'b0) | (master_size[1:0] == 2'b01) | (master_size[1:0] == 2'b10) | // Always aligned for Byte/HW/Word since they can be only for non-idempotent. IFU/SB are always aligned
((master_size[1:0] == 2'b11) &
((wrbuf_byteen[7:0] == 8'h3) | (wrbuf_byteen[7:0] == 8'hc) | (wrbuf_byteen[7:0] == 8'h30) | (wrbuf_byteen[7:0] == 8'hc0) |
(wrbuf_byteen[7:0] == 8'hf) | (wrbuf_byteen[7:0] == 8'hf0) | (wrbuf_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_hsize[2:0] = ((buf_state == CMD_RD) | (buf_state == STREAM_RD) | (buf_state == STREAM_ERR_RD) | rd_bypass_idle) ? 3'b011 :
// 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_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;
assign ahb_hmastlock = 1'b0;
assign ahb_hprot[3:0] = {3'b001,~axi_arprot[2]};
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_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]);
assign slave_tag[TAG-1:0] = slvbuf_tag[TAG-1:0];
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), .*);
rvdffs #(.WIDTH(32)) last_bus_addrff (.din(ahb_haddr[31:0]), .dout(last_bus_addr[31:0]), .en(last_addr_en), .clk(ahbm_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), .*);
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), .*);
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), .*);
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), .*);
// 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);
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), .*);
`ifdef ASSERT_ON
property ahb_trxn_aligned;
@(posedge ahbm_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)));
endproperty
assert_ahb_trxn_aligned: assert property (ahb_trxn_aligned) else
$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));
endproperty
assert_ahb_error_protocol: assert property (ahb_error_protocol) else
$display("Bus Error with hReady isn't preceded with Bus Error without hready");
`endif
endmodule // axi4_to_ahb

452
design/lib/beh_lib.sv Normal file
View File

@ -0,0 +1,452 @@
// 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.
// all flops call the rvdff flop
module rvdff #( parameter WIDTH=1 )
(
input logic [WIDTH-1:0] din,
input logic clk,
input logic rst_l,
output logic [WIDTH-1:0] dout
);
`ifdef 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
`endif
always_ff @(posedge clk or negedge rst_l) begin
if (rst_l == 0)
dout[WIDTH-1:0] <= 0;
else
dout[WIDTH-1:0] <= din[WIDTH-1:0];
end
endmodule
// rvdff with 2:1 input mux to flop din iff sel==1
module rvdffs #( parameter WIDTH=1 )
(
input logic [WIDTH-1:0] din,
input logic en,
input logic clk,
input logic rst_l,
output logic [WIDTH-1:0] dout
);
rvdff #(WIDTH) dffs (.din((en) ? din[WIDTH-1:0] : dout[WIDTH-1:0]), .*);
endmodule
// rvdff with en and clear
module rvdffsc #( parameter WIDTH=1 )
(
input logic [WIDTH-1:0] din,
input logic en,
input logic clear,
input logic clk,
input logic rst_l,
output logic [WIDTH-1:0] dout
);
logic [WIDTH-1:0] din_new;
assign din_new = {WIDTH{~clear}} & (en ? din[WIDTH-1:0] : dout[WIDTH-1:0]);
rvdff #(WIDTH) dffsc (.din(din_new[WIDTH-1:0]), .*);
endmodule
module `TEC_RV_ICG
(
input logic TE, E, CP,
output Q
);
logic en_ff;
logic enable;
assign enable = E | TE;
`ifdef VERILATOR
always @(negedge CP) begin
en_ff <= enable;
end
`else
always @(CP, enable) begin
if(!CP)
en_ff = enable;
end
`endif
assign Q = CP & en_ff;
endmodule
module rvclkhdr
(
input logic en,
input logic clk,
input logic scan_mode,
output logic l1clk
);
logic TE;
assign TE = scan_mode;
`TEC_RV_ICG rvclkhdr ( .*, .E(en), .CP(clk), .Q(l1clk));
endmodule
module rvdffe #( parameter WIDTH=1 )
(
input logic [WIDTH-1:0] din,
input logic en,
input logic clk,
input logic rst_l,
input logic scan_mode,
output logic [WIDTH-1:0] dout
);
logic l1clk;
`ifndef PHYSICAL
if (WIDTH >= 8) begin: genblock
`endif
rvclkhdr clkhdr ( .* );
rvdff #(WIDTH) dff (.*, .clk(l1clk));
`ifndef PHYSICAL
end
else
$error("%m: rvdffe width must be >= 8");
`endif
endmodule // rvdffe
module rvsyncss #(parameter WIDTH = 251)
(
input logic clk,
input logic rst_l,
input logic [WIDTH-1:0] din,
output logic [WIDTH-1:0] dout
);
logic [WIDTH-1:0] din_ff1;
rvdff #(WIDTH) sync_ff1 (.*, .din (din[WIDTH-1:0]), .dout(din_ff1[WIDTH-1:0]));
rvdff #(WIDTH) sync_ff2 (.*, .din (din_ff1[WIDTH-1:0]), .dout(dout[WIDTH-1:0]));
endmodule // rvsyncss
module rvlsadder
(
input logic [31:0] rs1,
input logic [11:0] offset,
output logic [31:0] dout
);
logic cout;
logic sign;
logic [31:12] rs1_inc;
logic [31:12] rs1_dec;
assign {cout,dout[11:0]} = {1'b0,rs1[11:0]} + {1'b0,offset[11:0]};
assign rs1_inc[31:12] = rs1[31:12] + 1;
assign rs1_dec[31:12] = rs1[31:12] - 1;
assign sign = offset[11];
assign dout[31:12] = ({20{ sign ^~ cout}} & rs1[31:12]) |
({20{ ~sign & cout}} & rs1_inc[31:12]) |
({20{ sign & ~cout}} & rs1_dec[31:12]);
endmodule // rvlsadder
// assume we only maintain pc[31:1] in the pipe
module rvbradder
(
input [31:1] pc,
input [12:1] offset,
output [31:1] dout
);
logic cout;
logic sign;
logic [31:13] pc_inc;
logic [31:13] pc_dec;
assign {cout,dout[12:1]} = {1'b0,pc[12:1]} + {1'b0,offset[12:1]};
assign pc_inc[31:13] = pc[31:13] + 1;
assign pc_dec[31:13] = pc[31:13] - 1;
assign sign = offset[12];
assign dout[31:13] = ({19{ sign ^~ cout}} & pc[31:13]) |
({19{ ~sign & cout}} & pc_inc[31:13]) |
({19{ sign & ~cout}} & pc_dec[31:13]);
endmodule // rvbradder
// 2s complement circuit
module rvtwoscomp #( parameter WIDTH=32 )
(
input logic [WIDTH-1:0] din,
output logic [WIDTH-1:0] dout
);
logic [WIDTH-1:1] dout_temp; // holding for all other bits except for the lsb. LSB is always din
genvar i;
for ( i = 1; i < WIDTH; i++ ) begin : flip_after_first_one
assign dout_temp[i] = (|din[i-1:0]) ? ~din[i] : din[i];
end : flip_after_first_one
assign dout[WIDTH-1:0] = { dout_temp[WIDTH-1:1], din[0] };
endmodule // 2'scomp
// find first
module rvfindfirst1 #( parameter WIDTH=32, SHIFT=$clog2(WIDTH) )
(
input logic [WIDTH-1:0] din,
output logic [SHIFT-1:0] dout
);
logic done;
always_comb begin
dout[SHIFT-1:0] = {SHIFT{1'b0}};
done = 1'b0;
for ( int i = WIDTH-1; i > 0; i-- ) begin : find_first_one
done |= din[i];
dout[SHIFT-1:0] += done ? 1'b0 : 1'b1;
end : find_first_one
end
endmodule // rvfindfirst1
module rvfindfirst1hot #( parameter WIDTH=32 )
(
input logic [WIDTH-1:0] din,
output logic [WIDTH-1:0] dout
);
logic done;
always_comb begin
dout[WIDTH-1:0] = {WIDTH{1'b0}};
done = 1'b0;
for ( int i = 0; i < WIDTH; i++ ) begin : find_first_one
dout[i] = ~done & din[i];
done |= din[i];
end : find_first_one
end
endmodule // rvfindfirst1hot
// mask and match function matches bits after finding the first 0 position
// find first starting from LSB. Skip that location and match the rest of the bits
module rvmaskandmatch #( parameter WIDTH=32 )
(
input logic [WIDTH-1:0] mask, // this will have the mask in the lower bit positions
input logic [WIDTH-1:0] data, // this is what needs to be matched on the upper bits with the mask's upper bits
input logic masken, // when 1 : do mask. 0 : full match
output logic match
);
logic [WIDTH-1:0] matchvec;
logic masken_or_fullmask;
assign masken_or_fullmask = masken & ~(&mask[WIDTH-1:0]);
assign matchvec[0] = masken_or_fullmask | (mask[0] == data[0]);
genvar i;
for ( i = 1; i < WIDTH; i++ ) begin : match_after_first_zero
assign matchvec[i] = (&mask[i-1:0] & masken_or_fullmask) ? 1'b1 : (mask[i] == data[i]);
end : match_after_first_zero
assign match = &matchvec[WIDTH-1:0]; // all bits either matched or were masked off
endmodule // rvmaskandmatch
module rvbtb_tag_hash (
input logic [31:1] pc,
output logic [`RV_BTB_BTAG_SIZE-1:0] hash
);
`ifndef RV_BTB_BTAG_FOLD
assign hash = {(pc[`RV_BTB_ADDR_HI+`RV_BTB_BTAG_SIZE+`RV_BTB_BTAG_SIZE+`RV_BTB_BTAG_SIZE:`RV_BTB_ADDR_HI+`RV_BTB_BTAG_SIZE+`RV_BTB_BTAG_SIZE+1] ^
pc[`RV_BTB_ADDR_HI+`RV_BTB_BTAG_SIZE+`RV_BTB_BTAG_SIZE:`RV_BTB_ADDR_HI+`RV_BTB_BTAG_SIZE+1] ^
pc[`RV_BTB_ADDR_HI+`RV_BTB_BTAG_SIZE:`RV_BTB_ADDR_HI+1])};
`else
assign hash = {(
pc[`RV_BTB_ADDR_HI+`RV_BTB_BTAG_SIZE+`RV_BTB_BTAG_SIZE:`RV_BTB_ADDR_HI+`RV_BTB_BTAG_SIZE+1] ^
pc[`RV_BTB_ADDR_HI+`RV_BTB_BTAG_SIZE:`RV_BTB_ADDR_HI+1])};
`endif
// assign hash = {pc[`RV_BTB_ADDR_HI+1],(pc[`RV_BTB_ADDR_HI+13:`RV_BTB_ADDR_HI+10] ^
// pc[`RV_BTB_ADDR_HI+9:`RV_BTB_ADDR_HI+6] ^
// pc[`RV_BTB_ADDR_HI+5:`RV_BTB_ADDR_HI+2])};
endmodule
module rvbtb_addr_hash (
input logic [31:1] pc,
output logic [`RV_BTB_ADDR_HI:`RV_BTB_ADDR_LO] hash
);
assign hash[`RV_BTB_ADDR_HI:`RV_BTB_ADDR_LO] = pc[`RV_BTB_INDEX1_HI:`RV_BTB_INDEX1_LO] ^
`ifndef RV_BTB_FOLD2_INDEX_HASH
pc[`RV_BTB_INDEX2_HI:`RV_BTB_INDEX2_LO] ^
`endif
pc[`RV_BTB_INDEX3_HI:`RV_BTB_INDEX3_LO];
endmodule
module rvbtb_ghr_hash (
input logic [`RV_BTB_ADDR_HI:`RV_BTB_ADDR_LO] hashin,
input logic [`RV_BHT_GHR_RANGE] ghr,
output logic [`RV_BHT_ADDR_HI:`RV_BHT_ADDR_LO] hash
);
// The hash function is too complex to write in verilog for all cases.
// The config script generates the logic string based on the bp config.
assign hash[`RV_BHT_ADDR_HI:`RV_BHT_ADDR_LO] = `RV_BHT_HASH_STRING;
endmodule
// Check if the S_ADDR <= addr < E_ADDR
module rvrangecheck #(CCM_SADR = 32'h0,
CCM_SIZE = 128) (
input logic [31:0] addr, // Address to be checked for range
output logic in_range, // S_ADDR <= start_addr < E_ADDR
output logic in_region
);
localparam REGION_BITS = 4;
localparam MASK_BITS = 10 + $clog2(CCM_SIZE);
logic [31:0] start_addr;
logic [3:0] region;
assign start_addr[31:0] = CCM_SADR;
assign region[REGION_BITS-1:0] = start_addr[31:(32-REGION_BITS)];
assign in_region = (addr[31:(32-REGION_BITS)] == region[REGION_BITS-1:0]);
if (CCM_SIZE == 48)
assign in_range = (addr[31:MASK_BITS] == start_addr[31:MASK_BITS]) & ~(&addr[MASK_BITS-1 : MASK_BITS-2]);
else
assign in_range = (addr[31:MASK_BITS] == start_addr[31:MASK_BITS]);
endmodule // rvrangechecker
// 16 bit even parity generator
module rveven_paritygen #(WIDTH = 16) (
input logic [WIDTH-1:0] data_in, // Data
output logic parity_out // generated even parity
);
assign parity_out = ^(data_in[WIDTH-1:0]) ;
endmodule // rveven_paritygen
module rveven_paritycheck #(WIDTH = 16) (
input logic [WIDTH-1:0] data_in, // Data
input logic parity_in,
output logic parity_err // Parity error
);
assign parity_err = ^(data_in[WIDTH-1:0]) ^ parity_in ;
endmodule // rveven_paritycheck
module rvecc_encode (
input [31:0] din,
output [6:0] ecc_out
);
logic [5:0] ecc_out_temp;
assign ecc_out_temp[0] = din[0]^din[1]^din[3]^din[4]^din[6]^din[8]^din[10]^din[11]^din[13]^din[15]^din[17]^din[19]^din[21]^din[23]^din[25]^din[26]^din[28]^din[30];
assign ecc_out_temp[1] = din[0]^din[2]^din[3]^din[5]^din[6]^din[9]^din[10]^din[12]^din[13]^din[16]^din[17]^din[20]^din[21]^din[24]^din[25]^din[27]^din[28]^din[31];
assign ecc_out_temp[2] = din[1]^din[2]^din[3]^din[7]^din[8]^din[9]^din[10]^din[14]^din[15]^din[16]^din[17]^din[22]^din[23]^din[24]^din[25]^din[29]^din[30]^din[31];
assign ecc_out_temp[3] = din[4]^din[5]^din[6]^din[7]^din[8]^din[9]^din[10]^din[18]^din[19]^din[20]^din[21]^din[22]^din[23]^din[24]^din[25];
assign ecc_out_temp[4] = din[11]^din[12]^din[13]^din[14]^din[15]^din[16]^din[17]^din[18]^din[19]^din[20]^din[21]^din[22]^din[23]^din[24]^din[25];
assign ecc_out_temp[5] = din[26]^din[27]^din[28]^din[29]^din[30]^din[31];
assign ecc_out[6:0] = {(^din[31:0])^(^ecc_out_temp[5:0]),ecc_out_temp[5:0]};
endmodule // rvecc_encode
module rvecc_decode (
input en,
input [31:0] din,
input [6:0] ecc_in,
input sed_ded, // only do detection and no correction. Used for the I$
output [31:0] dout,
output [6:0] ecc_out,
output single_ecc_error,
output double_ecc_error
);
logic [6:0] ecc_check;
logic [38:0] error_mask;
logic [38:0] din_plus_parity, dout_plus_parity;
// Generate the ecc bits
assign ecc_check[0] = ecc_in[0]^din[0]^din[1]^din[3]^din[4]^din[6]^din[8]^din[10]^din[11]^din[13]^din[15]^din[17]^din[19]^din[21]^din[23]^din[25]^din[26]^din[28]^din[30];
assign ecc_check[1] = ecc_in[1]^din[0]^din[2]^din[3]^din[5]^din[6]^din[9]^din[10]^din[12]^din[13]^din[16]^din[17]^din[20]^din[21]^din[24]^din[25]^din[27]^din[28]^din[31];
assign ecc_check[2] = ecc_in[2]^din[1]^din[2]^din[3]^din[7]^din[8]^din[9]^din[10]^din[14]^din[15]^din[16]^din[17]^din[22]^din[23]^din[24]^din[25]^din[29]^din[30]^din[31];
assign ecc_check[3] = ecc_in[3]^din[4]^din[5]^din[6]^din[7]^din[8]^din[9]^din[10]^din[18]^din[19]^din[20]^din[21]^din[22]^din[23]^din[24]^din[25];
assign ecc_check[4] = ecc_in[4]^din[11]^din[12]^din[13]^din[14]^din[15]^din[16]^din[17]^din[18]^din[19]^din[20]^din[21]^din[22]^din[23]^din[24]^din[25];
assign ecc_check[5] = ecc_in[5]^din[26]^din[27]^din[28]^din[29]^din[30]^din[31];
// This is the parity bit
assign ecc_check[6] = ((^din[31:0])^(^ecc_in[6:0])) & ~sed_ded;
assign single_ecc_error = en & (ecc_check[6:0] != 0) & ecc_check[6]; // this will never be on for sed_ded
assign double_ecc_error = en & (ecc_check[6:0] != 0) & ~ecc_check[6]; // all errors in the sed_ded case will be recorded as DE
// Generate the mask for error correctiong
for (genvar i=1; i<40; i++) begin
assign error_mask[i-1] = (ecc_check[5:0] == i);
end
// Generate the corrected data
assign din_plus_parity[38:0] = {ecc_in[6], din[31:26], ecc_in[5], din[25:11], ecc_in[4], din[10:4], ecc_in[3], din[3:1], ecc_in[2], din[0], ecc_in[1:0]};
assign dout_plus_parity[38:0] = single_ecc_error ? (error_mask[38:0] ^ din_plus_parity[38:0]) : din_plus_parity[38:0];
assign dout[31:0] = {dout_plus_parity[37:32], dout_plus_parity[30:16], dout_plus_parity[14:8], dout_plus_parity[6:4], dout_plus_parity[2]};
assign ecc_out[6:0] = {(dout_plus_parity[38] ^ (ecc_check[6:0] == 7'b1000000)), dout_plus_parity[31], dout_plus_parity[15], dout_plus_parity[7], dout_plus_parity[3], dout_plus_parity[1:0]};
endmodule // rvecc_decode

1025
design/lib/mem_lib.sv Normal file

File diff suppressed because it is too large Load Diff

389
design/lsu/lsu.sv Normal file
View File

@ -0,0 +1,389 @@
// 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.
//********************************************************************************
// $Id$
//
//
// Function: Top level file for load store unit
// Comments:
//
//
// DC1 -> DC2 -> DC3 -> DC4 (Commit)
//
//********************************************************************************
module lsu
import swerv_types::*;
(
input logic [31:0] i0_result_e4_eff, // I0 e4 result for e4 -> dc3 store forwarding
input logic [31:0] i1_result_e4_eff, // I1 e4 result for e4 -> dc3 store forwarding
input logic [31:0] i0_result_e2, // I0 e2 result for e2 -> dc2 store forwarding
input logic flush_final_e3, // I0/I1 flush in e3
input logic i0_flush_final_e3, // I0 flush in e3
input logic dec_tlu_flush_lower_wb, // I0/I1 writeback flush. This is used to flush the old packets only
input logic dec_tlu_i0_kill_writeb_wb, // I0 is flushed, don't writeback any results to arch state
input logic dec_tlu_i1_kill_writeb_wb, // I1 is flushed, don't writeback any results to arch state
input logic dec_tlu_cancel_e4, // cancel the bus load in dc4 and reset the freeze
// chicken signals
input logic dec_tlu_non_blocking_disable, // disable the non block
input logic dec_tlu_wb_coalescing_disable, // disable the write buffer coalesce
input logic dec_tlu_ld_miss_byp_wb_disable, // disable the miss bypass in the write buffer
input logic dec_tlu_sideeffect_posted_disable, // disable posted writes to sideeffect addr 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
input lsu_pkt_t lsu_p, // lsu control packet
input logic dec_i0_lsu_decode_d, // lsu is in i0
input logic [31:0] dec_tlu_mrac_ff, // CSR for memory region control
output logic [31:0] lsu_result_dc3, // lsu load data
output logic [31:0] lsu_result_corr_dc4, // This is the ECC corrected data going to RF
output logic lsu_freeze_dc3, // lsu freeze due to load to external
output logic lsu_load_stall_any, // This is for blocking loads in the decode
output logic lsu_store_stall_any, // This is for blocking stores in the decode
output logic lsu_idle_any, // lsu buffers are empty and no instruction in the pipeline
output logic lsu_halt_idle_any, // This is used to enter halt mode. Exclude DMA
output lsu_error_pkt_t lsu_error_pkt_dc3, // lsu exception packet
output logic lsu_freeze_external_ints_dc3, // freeze due to sideeffects loads need to suppress external interrupt
output logic lsu_imprecise_error_load_any, // bus load imprecise error
output logic lsu_imprecise_error_store_any, // bus store imprecise error
output logic [31:0] lsu_imprecise_error_addr_any, // bus store imprecise error address
// Non-blocking loads
input logic dec_nonblock_load_freeze_dc2, //
output logic lsu_nonblock_load_valid_dc3, // there is an external load -> put in the cam
output logic [`RV_LSU_NUM_NBLOAD_WIDTH-1:0] lsu_nonblock_load_tag_dc3, // the tag of the external non block load
output logic lsu_nonblock_load_inv_dc5, // invalidate signal for the cam entry for non block loads
output logic [`RV_LSU_NUM_NBLOAD_WIDTH-1:0] lsu_nonblock_load_inv_tag_dc5, // tag of the enrty which needs to be invalidated
output logic lsu_nonblock_load_data_valid, // the non block is valid - sending information back to the cam
output logic lsu_nonblock_load_data_error, // non block load has an error
output logic [`RV_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_misaligned_dc3, // PMU : misaligned
output logic lsu_pmu_bus_trxn, // PMU : bus transaction
output logic lsu_pmu_bus_misaligned, // PMU : misaligned access going to the bus
output logic lsu_pmu_bus_error, // PMU : bus sending error back
output logic lsu_pmu_bus_busy, // PMU : bus is not ready
// Trigger signals
input trigger_pkt_t [3:0] trigger_pkt_any, // Trigger info from the decode
output logic [3:0] lsu_trigger_match_dc3, // lsu trigger hit (one bit per trigger)
// DCCM ports
output logic dccm_wren, // DCCM write enable
output logic dccm_rden, // DCCM read enable
output logic [`RV_DCCM_BITS-1:0] dccm_wr_addr, // DCCM write address (write can happen to one bank only)
output logic [`RV_DCCM_BITS-1:0] dccm_rd_addr_lo, // DCCM read address low bank
output logic [`RV_DCCM_BITS-1:0] dccm_rd_addr_hi, // DCCM read address hi bank (hi and low same if aligned read)
output logic [`RV_DCCM_FDATA_WIDTH-1:0] dccm_wr_data, // DCCM write data (this is always aligned)
input logic [`RV_DCCM_FDATA_WIDTH-1:0] dccm_rd_data_lo, // DCCM read data low bank
input logic [`RV_DCCM_FDATA_WIDTH-1:0] dccm_rd_data_hi, // DCCM read data hi bank
// PIC ports
output logic picm_wren, // PIC memory write enable
output logic picm_rden, // PIC memory read enable
output logic picm_mken, // Need to read the mask for stores to determine which bits to write/forward
output logic [31:0] picm_addr, // PIC memory address
output logic [31:0] picm_wr_data, // PIC memory write data
input logic [31:0] picm_rd_data, // PIC memory read/mask data
// AXI Write Channels
output logic lsu_axi_awvalid,
input logic lsu_axi_awready,
output logic [`RV_LSU_BUS_TAG-1:0] lsu_axi_awid,
output logic [31:0] lsu_axi_awaddr,
output logic [3:0] lsu_axi_awregion,
output logic [7:0] lsu_axi_awlen,
output logic [2:0] lsu_axi_awsize,
output logic [1:0] lsu_axi_awburst,
output logic lsu_axi_awlock,
output logic [3:0] lsu_axi_awcache,
output logic [2:0] lsu_axi_awprot,
output logic [3:0] lsu_axi_awqos,
output logic lsu_axi_wvalid,
input logic lsu_axi_wready,
output logic [63:0] lsu_axi_wdata,
output logic [7:0] lsu_axi_wstrb,
output logic lsu_axi_wlast,
input logic lsu_axi_bvalid,
output logic lsu_axi_bready,
input logic [1:0] lsu_axi_bresp,
input logic [`RV_LSU_BUS_TAG-1:0] lsu_axi_bid,
// AXI Read Channels
output logic lsu_axi_arvalid,
input logic lsu_axi_arready,
output logic [`RV_LSU_BUS_TAG-1:0] lsu_axi_arid,
output logic [31:0] lsu_axi_araddr,
output logic [3:0] lsu_axi_arregion,
output logic [7:0] lsu_axi_arlen,
output logic [2:0] lsu_axi_arsize,
output logic [1:0] lsu_axi_arburst,
output logic lsu_axi_arlock,
output logic [3:0] lsu_axi_arcache,
output logic [2:0] lsu_axi_arprot,
output logic [3:0] lsu_axi_arqos,
input logic lsu_axi_rvalid,
output logic lsu_axi_rready,
input logic [`RV_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, // external drives a clock_en to control bus ratio
// DMA slave
input logic dma_dccm_req, // DMA read/write to dccm
input logic [31:0] dma_mem_addr, // DMA address
input logic [2:0] dma_mem_sz, // DMA access size
input logic dma_mem_write, // DMA access is a write
input logic [63:0] dma_mem_wdata, // DMA write data
output logic dccm_dma_rvalid, // lsu data valid for DMA dccm read
output logic dccm_dma_ecc_error, // DMA load had ecc error
output logic [63:0] dccm_dma_rdata, // lsu data for DMA dccm read
output logic dccm_ready, // lsu ready for DMA access
input logic clk_override, // Disable clock gating
input logic scan_mode, // scan
input logic clk,
input logic free_clk,
input logic rst_l
);
`include "global.h"
logic lsu_dccm_rden_dc3;
logic [63:0] store_data_dc2;
logic [63:0] store_data_dc3;
logic [31:0] store_data_dc4;
logic [31:0] store_data_dc5;
logic [31:0] store_ecc_datafn_hi_dc3;
logic [31:0] store_ecc_datafn_lo_dc3;
logic single_ecc_error_hi_dc3, single_ecc_error_lo_dc3;
logic lsu_single_ecc_error_dc3, lsu_single_ecc_error_dc4, lsu_single_ecc_error_dc5;
logic lsu_double_ecc_error_dc3;
logic [31:0] dccm_data_hi_dc3;
logic [31:0] dccm_data_lo_dc3;
logic [6:0] dccm_data_ecc_hi_dc3;
logic [6:0] dccm_data_ecc_lo_dc3;
logic [31:0] lsu_ld_data_dc3;
logic [31:0] lsu_ld_data_corr_dc3;
logic [31:0] picm_mask_data_dc3;
logic [31:0] lsu_addr_dc1, lsu_addr_dc2, lsu_addr_dc3, lsu_addr_dc4, lsu_addr_dc5;
logic [31:0] end_addr_dc1, end_addr_dc2, end_addr_dc3, end_addr_dc4, end_addr_dc5;
lsu_pkt_t lsu_pkt_dc1, lsu_pkt_dc2, lsu_pkt_dc3, lsu_pkt_dc4, lsu_pkt_dc5;
logic lsu_i0_valid_dc1, lsu_i0_valid_dc2, lsu_i0_valid_dc3, lsu_i0_valid_dc4, lsu_i0_valid_dc5;
// Store Buffer signals
logic isldst_dc1, dccm_ldst_dc2, dccm_ldst_dc3;
logic store_stbuf_reqvld_dc3;
logic load_stbuf_reqvld_dc3;
logic ldst_stbuf_reqvld_dc3;
logic lsu_commit_dc5;
logic lsu_exc_dc2;
logic addr_in_dccm_dc1, addr_in_dccm_dc2, addr_in_dccm_dc3;
logic addr_in_pic_dc1, addr_in_pic_dc2, addr_in_pic_dc3;
logic addr_external_dc2, addr_external_dc3, addr_external_dc4, addr_external_dc5;
logic stbuf_reqvld_any;
logic stbuf_reqvld_flushed_any;
logic stbuf_addr_in_pic_any;
logic [DCCM_BYTE_WIDTH-1:0] stbuf_byteen_any;
logic [LSU_SB_BITS-1:0] stbuf_addr_any;
logic [DCCM_DATA_WIDTH-1:0] stbuf_data_any;
logic [(DCCM_FDATA_WIDTH-DCCM_DATA_WIDTH-1):0] stbuf_ecc_any;
logic lsu_cmpen_dc2;
logic [DCCM_DATA_WIDTH-1:0] stbuf_fwddata_hi_dc3;
logic [DCCM_DATA_WIDTH-1:0] stbuf_fwddata_lo_dc3;
logic [DCCM_BYTE_WIDTH-1:0] stbuf_fwdbyteen_hi_dc3;
logic [DCCM_BYTE_WIDTH-1:0] stbuf_fwdbyteen_lo_dc3;
logic lsu_stbuf_commit_any;
logic lsu_stbuf_empty_any;
logic lsu_stbuf_nodma_empty_any; // Store Buffer is empty except dma writes
logic lsu_stbuf_full_any;
// Bus signals
logic lsu_busreq_dc5;
logic lsu_bus_buffer_pend_any;
logic lsu_bus_buffer_empty_any;
logic lsu_bus_buffer_full_any;
logic lsu_busreq_dc2;
logic [31:0] bus_read_data_dc3;
logic ld_bus_error_dc3;
logic [31:0] ld_bus_error_addr_dc3;
logic flush_dc2_up, flush_dc3, flush_dc4, flush_dc5, flush_prior_dc5;
logic is_sideeffects_dc2, is_sideeffects_dc3;
logic ldst_nodma_dc1todc3;
// Clocks
logic lsu_c1_dc3_clk, lsu_c1_dc4_clk, lsu_c1_dc5_clk;
logic lsu_c2_dc3_clk, lsu_c2_dc4_clk, lsu_c2_dc5_clk;
logic lsu_freeze_c1_dc1_clk, lsu_freeze_c1_dc2_clk, lsu_freeze_c1_dc3_clk;
logic lsu_store_c1_dc1_clk, lsu_store_c1_dc2_clk, lsu_store_c1_dc3_clk, lsu_store_c1_dc4_clk, lsu_store_c1_dc5_clk;
logic lsu_freeze_c2_dc1_clk, lsu_freeze_c2_dc2_clk, lsu_freeze_c2_dc3_clk, lsu_freeze_c2_dc4_clk;
logic lsu_stbuf_c1_clk;
logic lsu_bus_ibuf_c1_clk, lsu_bus_obuf_c1_clk, lsu_bus_buf_c1_clk;
logic lsu_dccm_c1_dc3_clk, lsu_pic_c1_dc3_clk;
logic lsu_busm_clk;
logic lsu_free_c2_clk;
lsu_lsc_ctl lsu_lsc_ctl(.*);
// block stores in decode - for either bus or stbuf reasons
assign lsu_store_stall_any = lsu_stbuf_full_any | lsu_bus_buffer_full_any;
assign lsu_load_stall_any = lsu_bus_buffer_full_any;
// Ready to accept dma trxns
// There can't be any inpipe forwarding from non-dma packet to dma packet since they can be flushed so we can't have ld/st in dc3-dc5 when dma is in dc2
assign ldst_nodma_dc1todc3 = (lsu_pkt_dc1.valid & ~lsu_pkt_dc1.dma) | (lsu_pkt_dc2.valid & ~lsu_pkt_dc2.dma) | (lsu_pkt_dc3.valid & ~lsu_pkt_dc3.dma);
assign dccm_ready = ~(lsu_p.valid | lsu_stbuf_full_any | lsu_freeze_dc3 | ldst_nodma_dc1todc3);
// Generate per cycle flush signals
assign flush_dc2_up = flush_final_e3 | i0_flush_final_e3 | dec_tlu_flush_lower_wb;
assign flush_dc3 = (flush_final_e3 & i0_flush_final_e3) | dec_tlu_flush_lower_wb;
assign flush_dc4 = dec_tlu_flush_lower_wb;
assign flush_dc5 = (dec_tlu_i0_kill_writeb_wb | (dec_tlu_i1_kill_writeb_wb & ~lsu_i0_valid_dc5));
assign flush_prior_dc5 = dec_tlu_i0_kill_writeb_wb & ~lsu_i0_valid_dc5; // Flush is due to i0 instruction and ld/st is in i1
// lsu idle
assign lsu_idle_any = ~(lsu_pkt_dc1.valid | lsu_pkt_dc2.valid | lsu_pkt_dc3.valid | lsu_pkt_dc4.valid | lsu_pkt_dc5.valid) &
lsu_bus_buffer_empty_any & lsu_stbuf_empty_any;
// lsu halt idle. This is used for entering the halt mode
// Indicates non-idle if there is a instruction valid in dc1-dc5 or read/write buffers are non-empty since they can come with error
// Need to make sure bus trxns are done and there are no non-dma writes in store buffer
assign lsu_halt_idle_any = ~((lsu_pkt_dc1.valid & ~lsu_pkt_dc1.dma) |
(lsu_pkt_dc2.valid & ~lsu_pkt_dc2.dma) |
(lsu_pkt_dc3.valid & ~lsu_pkt_dc3.dma) |
(lsu_pkt_dc4.valid & ~lsu_pkt_dc4.dma) |
(lsu_pkt_dc5.valid & ~lsu_pkt_dc5.dma)) &
lsu_bus_buffer_empty_any & lsu_stbuf_nodma_empty_any;
// Instantiate the store buffer
//assign ldst_stbuf_reqvld_dc3 = store_stbuf_reqvld_dc3 | load_stbuf_reqvld_dc3;
assign store_stbuf_reqvld_dc3 = lsu_pkt_dc3.valid & lsu_pkt_dc3.store & (addr_in_dccm_dc3 | addr_in_pic_dc3) & (~flush_dc3 | lsu_pkt_dc3.dma) & ~lsu_freeze_dc3;
assign load_stbuf_reqvld_dc3 = lsu_pkt_dc3.valid & lsu_pkt_dc3.load & (addr_in_dccm_dc3 | addr_in_pic_dc3) & lsu_single_ecc_error_dc3 & (~flush_dc3 | lsu_pkt_dc3.dma) & ~lsu_freeze_dc3;
// These go to store buffer to detect full
assign isldst_dc1 = lsu_pkt_dc1.valid & (lsu_pkt_dc1.load | lsu_pkt_dc1.store);
assign dccm_ldst_dc2 = lsu_pkt_dc2.valid & (lsu_pkt_dc2.load | lsu_pkt_dc2.store) & (addr_in_dccm_dc2 | addr_in_pic_dc2);
assign dccm_ldst_dc3 = lsu_pkt_dc3.valid & (lsu_pkt_dc3.load | lsu_pkt_dc3.store) & (addr_in_dccm_dc3 | addr_in_pic_dc3);
// Disable Forwarding for now
assign lsu_cmpen_dc2 = lsu_pkt_dc2.valid & (lsu_pkt_dc2.load | lsu_pkt_dc2.store) & (addr_in_dccm_dc2 | addr_in_pic_dc2);
// Bus signals
assign lsu_busreq_dc2 = lsu_pkt_dc2.valid & (lsu_pkt_dc2.load | lsu_pkt_dc2.store) & addr_external_dc2 & ~flush_dc2_up & ~lsu_exc_dc2;
// PMU signals
assign lsu_pmu_misaligned_dc3 = lsu_pkt_dc3.valid & ((lsu_pkt_dc3.half & lsu_addr_dc3[0]) | (lsu_pkt_dc3.word & (|lsu_addr_dc3[1:0])));
lsu_dccm_ctl dccm_ctl (
.lsu_addr_dc1(lsu_addr_dc1[31:0]),
.end_addr_dc1(end_addr_dc1[DCCM_BITS-1:0]),
.lsu_addr_dc3(lsu_addr_dc3[DCCM_BITS-1:0]),
.*
);
lsu_stbuf stbuf(
.lsu_addr_dc1(lsu_addr_dc1[LSU_SB_BITS-1:0]),
.end_addr_dc1(end_addr_dc1[LSU_SB_BITS-1:0]),
.lsu_addr_dc2(lsu_addr_dc2[LSU_SB_BITS-1:0]),
.end_addr_dc2(end_addr_dc2[LSU_SB_BITS-1:0]),
.lsu_addr_dc3(lsu_addr_dc3[LSU_SB_BITS-1:0]),
.end_addr_dc3(end_addr_dc3[LSU_SB_BITS-1:0]),
.*
);
lsu_ecc ecc (
.lsu_addr_dc3(lsu_addr_dc3[DCCM_BITS-1:0]),
.end_addr_dc3(end_addr_dc3[DCCM_BITS-1:0]),
.*
);
lsu_trigger trigger (
.store_data_dc3(store_data_dc3[31:0]),
.*
);
// Clk domain
lsu_clkdomain clkdomain (.*);
// Bus interface
lsu_bus_intf bus_intf (.*);
//Flops
//rvdffs #(1) lsu_i0_valid_dc1ff (.*, .din(dec_i0_lsu_decode_d), .dout(lsu_i0_valid_dc1), .en(~lsu_freeze_dc3));
rvdff #(1) lsu_i0_valid_dc1ff (.*, .din(dec_i0_lsu_decode_d), .dout(lsu_i0_valid_dc1), .clk(lsu_freeze_c2_dc1_clk));
rvdff #(1) lsu_i0_valid_dc2ff (.*, .din(lsu_i0_valid_dc1), .dout(lsu_i0_valid_dc2), .clk(lsu_freeze_c2_dc2_clk));
rvdff #(1) lsu_i0_valid_dc3ff (.*, .din(lsu_i0_valid_dc2), .dout(lsu_i0_valid_dc3), .clk(lsu_freeze_c2_dc3_clk));
rvdff #(1) lsu_i0_valid_dc4ff (.*, .din(lsu_i0_valid_dc3), .dout(lsu_i0_valid_dc4), .clk(lsu_freeze_c2_dc4_clk));
rvdff #(1) lsu_i0_valid_dc5ff (.*, .din(lsu_i0_valid_dc4), .dout(lsu_i0_valid_dc5), .clk(lsu_c2_dc5_clk));
rvdff #(1) lsu_single_ecc_err_dc4(.*, .din(lsu_single_ecc_error_dc3), .dout(lsu_single_ecc_error_dc4), .clk(lsu_c2_dc4_clk));
rvdff #(1) lsu_single_ecc_err_dc5(.*, .din(lsu_single_ecc_error_dc4), .dout(lsu_single_ecc_error_dc5), .clk(lsu_c2_dc5_clk));
`ifdef ASSERT_ON
logic [8:0] store_data_bypass_sel;
assign store_data_bypass_sel[8:0] = {lsu_p.store_data_bypass_c1,
lsu_p.store_data_bypass_c2,
lsu_p.store_data_bypass_i0_e2_c2,
lsu_p.store_data_bypass_e4_c1[1:0],
lsu_p.store_data_bypass_e4_c2[1:0],
lsu_p.store_data_bypass_e4_c3[1:0]};
assert_store_data_bypass_onehot: assert #0 ($onehot0(store_data_bypass_sel[8:0]));
assert_picm_rden_and_wren: assert #0 ($onehot0({(picm_rden | picm_mken),picm_wren}));
assert_picm_rden_and_dccmen: assert #0 ($onehot0({(picm_rden | picm_mken),dccm_rden}));
assert_picm_wren_and_dccmen: assert #0 ($onehot0({picm_wren, dccm_wren}));
//assert_no_exceptions: assert #0 (lsu_exc_pkt_dc3.exc_valid == 1'b0);
property exception_no_lsu_flush;
@(posedge clk) disable iff(~rst_l) lsu_error_pkt_dc3.exc_valid |-> ##[1:2] (flush_dc4 | flush_dc5);
endproperty
assert_exception_no_lsu_flush: assert property (exception_no_lsu_flush) else
$display("No flush within 2 cycles of exception");
`endif
endmodule // lsu

183
design/lsu/lsu_addrcheck.sv Normal file
View File

@ -0,0 +1,183 @@
// 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.
//********************************************************************************
// $Id$
//
//
// Owner:
// Function: Checks the memory map for the address
// Comments:
//
//********************************************************************************
module lsu_addrcheck
import swerv_types::*;
(
input logic lsu_freeze_c2_dc2_clk, // clock
input logic lsu_freeze_c2_dc3_clk,
input logic rst_l, // reset
input logic [31:0] start_addr_dc1, // start address for lsu
input logic [31:0] end_addr_dc1, // end address for lsu
input lsu_pkt_t lsu_pkt_dc1, // packet in dc1
input logic [31:0] dec_tlu_mrac_ff, // CSR read
output logic is_sideeffects_dc2, // is sideffects space
output logic is_sideeffects_dc3,
output logic addr_in_dccm_dc1, // address in dccm
output logic addr_in_pic_dc1, // address in pic
output logic addr_external_dc1, // address in external
output logic access_fault_dc1, // access fault
output logic misaligned_fault_dc1, // misaligned
input logic scan_mode
);
`include "global.h"
localparam DCCM_REGION = `RV_DCCM_REGION;
localparam PIC_REGION = `RV_PIC_REGION;
localparam ICCM_REGION = `RV_ICCM_REGION;
`ifdef RV_ICCM_ENABLE
localparam ICCM_ENABLE = 1'b1;
`else
localparam ICCM_ENABLE = 1'b0;
`endif
`ifdef RV_DCCM_ENABLE
localparam DCCM_ENABLE = 1'b1;
`else
localparam DCCM_ENABLE = 1'b0;
`endif
logic is_sideeffects_dc1, is_aligned_dc1;
logic start_addr_in_dccm_dc1, end_addr_in_dccm_dc1;
logic start_addr_in_dccm_region_dc1, end_addr_in_dccm_region_dc1;
logic start_addr_in_pic_dc1, end_addr_in_pic_dc1;
logic start_addr_in_pic_region_dc1, end_addr_in_pic_region_dc1;
logic [4:0] csr_idx;
logic addr_in_iccm;
logic non_dccm_access_ok;
if (DCCM_ENABLE == 1) begin: Gen_dccm_enable
// Start address check
rvrangecheck #(.CCM_SADR(`RV_DCCM_SADR),
.CCM_SIZE(`RV_DCCM_SIZE)) start_addr_dccm_rangecheck (
.addr(start_addr_dc1[31:0]),
.in_range(start_addr_in_dccm_dc1),
.in_region(start_addr_in_dccm_region_dc1)
);
// End address check
rvrangecheck #(.CCM_SADR(`RV_DCCM_SADR),
.CCM_SIZE(`RV_DCCM_SIZE)) end_addr_dccm_rangecheck (
.addr(end_addr_dc1[31:0]),
.in_range(end_addr_in_dccm_dc1),
.in_region(end_addr_in_dccm_region_dc1)
);
end else begin: Gen_dccm_disable // block: Gen_dccm_enable
assign start_addr_in_dccm_dc1 = '0;
assign start_addr_in_dccm_region_dc1 = '0;
assign end_addr_in_dccm_dc1 = '0;
assign end_addr_in_dccm_region_dc1 = '0;
end
if (ICCM_ENABLE == 1) begin : check_iccm
assign addr_in_iccm = (start_addr_dc1[31:28] == ICCM_REGION);
end
else begin
assign addr_in_iccm = 1'b0;
end
// PIC memory check
// Start address check
rvrangecheck #(.CCM_SADR(`RV_PIC_BASE_ADDR),
.CCM_SIZE(`RV_PIC_SIZE)) start_addr_pic_rangecheck (
.addr(start_addr_dc1[31:0]),
.in_range(start_addr_in_pic_dc1),
.in_region(start_addr_in_pic_region_dc1)
);
// End address check
rvrangecheck #(.CCM_SADR(`RV_PIC_BASE_ADDR),
.CCM_SIZE(`RV_PIC_SIZE)) end_addr_pic_rangecheck (
.addr(end_addr_dc1[31:0]),
.in_range(end_addr_in_pic_dc1),
.in_region(end_addr_in_pic_region_dc1)
);
assign addr_in_dccm_dc1 = (start_addr_in_dccm_dc1 & end_addr_in_dccm_dc1);
assign addr_in_pic_dc1 = (start_addr_in_pic_dc1 & end_addr_in_pic_dc1);
assign addr_external_dc1 = ~(addr_in_dccm_dc1 | addr_in_pic_dc1); //~addr_in_dccm_region_dc1;
assign csr_idx[4:0] = {start_addr_dc1[31:28], 1'b1};
assign is_sideeffects_dc1 = dec_tlu_mrac_ff[csr_idx] & ~(start_addr_in_dccm_region_dc1 | start_addr_in_pic_region_dc1 | addr_in_iccm); //every region has the 2 LSB indicating ( 1: sideeffects/no_side effects, and 0: cacheable ). Ignored in internal regions
assign is_aligned_dc1 = (lsu_pkt_dc1.word & (start_addr_dc1[1:0] == 2'b0)) |
(lsu_pkt_dc1.half & (start_addr_dc1[0] == 1'b0)) |
lsu_pkt_dc1.by;
assign non_dccm_access_ok = (~(|{`RV_DATA_ACCESS_ENABLE0,`RV_DATA_ACCESS_ENABLE1,`RV_DATA_ACCESS_ENABLE2,`RV_DATA_ACCESS_ENABLE3,`RV_DATA_ACCESS_ENABLE4,`RV_DATA_ACCESS_ENABLE5,`RV_DATA_ACCESS_ENABLE6,`RV_DATA_ACCESS_ENABLE7})) |
(((`RV_DATA_ACCESS_ENABLE0 & ((start_addr_dc1[31:0] | `RV_DATA_ACCESS_MASK0)) == (`RV_DATA_ACCESS_ADDR0 | `RV_DATA_ACCESS_MASK0)) |
(`RV_DATA_ACCESS_ENABLE1 & ((start_addr_dc1[31:0] | `RV_DATA_ACCESS_MASK1)) == (`RV_DATA_ACCESS_ADDR1 | `RV_DATA_ACCESS_MASK1)) |
(`RV_DATA_ACCESS_ENABLE2 & ((start_addr_dc1[31:0] | `RV_DATA_ACCESS_MASK2)) == (`RV_DATA_ACCESS_ADDR2 | `RV_DATA_ACCESS_MASK2)) |
(`RV_DATA_ACCESS_ENABLE3 & ((start_addr_dc1[31:0] | `RV_DATA_ACCESS_MASK3)) == (`RV_DATA_ACCESS_ADDR3 | `RV_DATA_ACCESS_MASK3)) |
(`RV_DATA_ACCESS_ENABLE4 & ((start_addr_dc1[31:0] | `RV_DATA_ACCESS_MASK4)) == (`RV_DATA_ACCESS_ADDR4 | `RV_DATA_ACCESS_MASK4)) |
(`RV_DATA_ACCESS_ENABLE5 & ((start_addr_dc1[31:0] | `RV_DATA_ACCESS_MASK5)) == (`RV_DATA_ACCESS_ADDR5 | `RV_DATA_ACCESS_MASK5)) |
(`RV_DATA_ACCESS_ENABLE6 & ((start_addr_dc1[31:0] | `RV_DATA_ACCESS_MASK6)) == (`RV_DATA_ACCESS_ADDR6 | `RV_DATA_ACCESS_MASK6)) |
(`RV_DATA_ACCESS_ENABLE7 & ((start_addr_dc1[31:0] | `RV_DATA_ACCESS_MASK7)) == (`RV_DATA_ACCESS_ADDR7 | `RV_DATA_ACCESS_MASK7))) &
((`RV_DATA_ACCESS_ENABLE0 & ((end_addr_dc1[31:0] | `RV_DATA_ACCESS_MASK0)) == (`RV_DATA_ACCESS_ADDR0 | `RV_DATA_ACCESS_MASK0)) |
(`RV_DATA_ACCESS_ENABLE1 & ((end_addr_dc1[31:0] | `RV_DATA_ACCESS_MASK1)) == (`RV_DATA_ACCESS_ADDR1 | `RV_DATA_ACCESS_MASK1)) |
(`RV_DATA_ACCESS_ENABLE2 & ((end_addr_dc1[31:0] | `RV_DATA_ACCESS_MASK2)) == (`RV_DATA_ACCESS_ADDR2 | `RV_DATA_ACCESS_MASK2)) |
(`RV_DATA_ACCESS_ENABLE3 & ((end_addr_dc1[31:0] | `RV_DATA_ACCESS_MASK3)) == (`RV_DATA_ACCESS_ADDR3 | `RV_DATA_ACCESS_MASK3)) |
(`RV_DATA_ACCESS_ENABLE4 & ((end_addr_dc1[31:0] | `RV_DATA_ACCESS_MASK4)) == (`RV_DATA_ACCESS_ADDR4 | `RV_DATA_ACCESS_MASK4)) |
(`RV_DATA_ACCESS_ENABLE5 & ((end_addr_dc1[31:0] | `RV_DATA_ACCESS_MASK5)) == (`RV_DATA_ACCESS_ADDR5 | `RV_DATA_ACCESS_MASK5)) |
(`RV_DATA_ACCESS_ENABLE6 & ((end_addr_dc1[31:0] | `RV_DATA_ACCESS_MASK6)) == (`RV_DATA_ACCESS_ADDR6 | `RV_DATA_ACCESS_MASK6)) |
(`RV_DATA_ACCESS_ENABLE7 & ((end_addr_dc1[31:0] | `RV_DATA_ACCESS_MASK7)) == (`RV_DATA_ACCESS_ADDR7 | `RV_DATA_ACCESS_MASK7))));
// Access fault logic
// 1. Addr in dccm region but not in dccm offset
// 2. Addr in picm region but not in picm offset
// 3. DCCM -> PIC offset cross when DCCM/PIC in same region (PIC access are always word aligned so no cross possible from PIC->DCCM)
// 4. Ld/St access to picm are not word aligned
// 5. Address not in protected space or dccm/pic region
if (DCCM_REGION == PIC_REGION) begin
assign access_fault_dc1 = ((start_addr_in_dccm_region_dc1 & ~(start_addr_in_dccm_dc1 | start_addr_in_pic_dc1)) |
(end_addr_in_dccm_region_dc1 & ~(end_addr_in_dccm_dc1 | end_addr_in_pic_dc1)) |
((start_addr_dc1[27:18] != end_addr_dc1[27:18]) & start_addr_in_dccm_dc1) |
((addr_in_pic_dc1 & ((start_addr_dc1[1:0] != 2'b0) | ~lsu_pkt_dc1.word))) |
(~start_addr_in_dccm_region_dc1 & ~non_dccm_access_ok)) & lsu_pkt_dc1.valid & ~lsu_pkt_dc1.dma;
end else begin
assign access_fault_dc1 = ((start_addr_in_dccm_region_dc1 & ~start_addr_in_dccm_dc1) |
(end_addr_in_dccm_region_dc1 & ~end_addr_in_dccm_dc1) |
(start_addr_in_pic_region_dc1 & ~start_addr_in_pic_dc1) |
(end_addr_in_pic_region_dc1 & ~end_addr_in_pic_dc1) |
((addr_in_pic_dc1 & ((start_addr_dc1[1:0] != 2'b0) | ~lsu_pkt_dc1.word))) |
(~start_addr_in_pic_region_dc1 & ~start_addr_in_dccm_region_dc1 & ~non_dccm_access_ok)) & lsu_pkt_dc1.valid & ~lsu_pkt_dc1.dma;
end
// Misaligned happens due to 2 reasons
// 1. Region cross
// 2. sideeffects access which are not aligned
assign misaligned_fault_dc1 = ((start_addr_dc1[31:28] != end_addr_dc1[31:28]) |
(is_sideeffects_dc1 & ~is_aligned_dc1)) & addr_external_dc1 & lsu_pkt_dc1.valid & ~lsu_pkt_dc1.dma;
rvdff #(.WIDTH(1)) is_sideeffects_dc2ff (.din(is_sideeffects_dc1), .dout(is_sideeffects_dc2), .clk(lsu_freeze_c2_dc2_clk), .*);
rvdff #(.WIDTH(1)) is_sideeffects_dc3ff (.din(is_sideeffects_dc2), .dout(is_sideeffects_dc3), .clk(lsu_freeze_c2_dc3_clk), .*);
endmodule // lsu_addrcheck

View File

@ -0,0 +1,923 @@
// 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.
//********************************************************************************
// $Id$
//
//
// Owner:
// Function: lsu interface with interface queue
// Comments:
//
//********************************************************************************
// Function to do 8 to 3 bit encoding
function automatic logic [2:0] f_Enc8to3;
input logic [7:0] Dec_value;
logic [2:0] Enc_value;
Enc_value[0] = Dec_value[1] | Dec_value[3] | Dec_value[5] | Dec_value[7];
Enc_value[1] = Dec_value[2] | Dec_value[3] | Dec_value[6] | Dec_value[7];
Enc_value[2] = Dec_value[4] | Dec_value[5] | Dec_value[6] | Dec_value[7];
return Enc_value[2:0];
endfunction // f_Enc8to3
module lsu_bus_buffer
import swerv_types::*;
(
input logic clk,
input logic rst_l,
input logic scan_mode,
input logic dec_tlu_non_blocking_disable, // disable non block
input logic dec_tlu_wb_coalescing_disable, // disable write buffer coalescing
input logic dec_tlu_ld_miss_byp_wb_disable, // disable ld miss bypass of the write buffer
input logic dec_tlu_sideeffect_posted_disable, // disable posted writes to sideeffect addr to the bus
// various clocks needed for the bus reads and writes
input logic lsu_c1_dc3_clk,
input logic lsu_c1_dc4_clk,
input logic lsu_c1_dc5_clk,
input logic lsu_c2_dc3_clk,
input logic lsu_c2_dc4_clk,
input logic lsu_c2_dc5_clk,
input logic lsu_freeze_c1_dc2_clk,
input logic lsu_freeze_c1_dc3_clk,
input logic lsu_freeze_c2_dc2_clk,
input logic lsu_freeze_c2_dc3_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 lsu_busm_clk,
input lsu_pkt_t lsu_pkt_dc1, // lsu packet flowing down the pipe
input lsu_pkt_t lsu_pkt_dc2, // lsu packet flowing down the pipe
input lsu_pkt_t lsu_pkt_dc3, // lsu packet flowing down the pipe
input lsu_pkt_t lsu_pkt_dc4, // lsu packet flowing down the pipe
input lsu_pkt_t lsu_pkt_dc5, // lsu packet flowing down the pipe
input logic [31:0] lsu_addr_dc2, // lsu address flowing down the pipe
input logic [31:0] end_addr_dc2, // lsu address flowing down the pipe
input logic [31:0] lsu_addr_dc5, // lsu address flowing down the pipe
input logic [31:0] end_addr_dc5, // lsu address flowing down the pipe
input logic [31:0] store_data_dc5, // store data flowing down the pipe
input logic no_word_merge_dc5, // dc5 store doesn't need to wait in ibuf since it will not coalesce
input logic no_dword_merge_dc5, // dc5 store doesn't need to wait in ibuf since it will not coalesce
input logic lsu_busreq_dc2, // bus request is in dc2
output logic lsu_busreq_dc3, // bus request is in dc2
output logic lsu_busreq_dc4, // bus request is in dc4
output logic lsu_busreq_dc5, // bus request is in dc5
input logic ld_full_hit_dc2, // load can get all its byte from a write buffer entry
input logic flush_dc2_up, // flush
input logic flush_dc3, // flush
input logic flush_dc4, // flush
input logic flush_dc5, // flush
input logic lsu_freeze_dc3,
input logic dec_tlu_cancel_e4, // cancel the bus load in dc4 and reset the freeze
input logic lsu_commit_dc5, // lsu instruction in dc5 commits
input logic is_sideeffects_dc2, // lsu attribute is side_effects
input logic is_sideeffects_dc5, // lsu attribute is side_effects
input logic ldst_dual_dc1, // load/store is unaligned at 32 bit boundary
input logic ldst_dual_dc2, // load/store is unaligned at 32 bit boundary
input logic ldst_dual_dc3, // load/store is unaligned at 32 bit boundary
input logic ldst_dual_dc4, // load/store is unaligned at 32 bit boundary
input logic ldst_dual_dc5, // load/store is unaligned at 32 bit boundary
input logic [7:0] ldst_byteen_ext_dc2,
output logic ld_freeze_dc3, // load goes to external and asserts freeze
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 ld_bus_error_dc3, // bus error in dc3
output logic [31:0] ld_bus_error_addr_dc3, // address of the bus error
output logic [31:0] ld_bus_data_dc3, // the Dc3 load data from 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
output logic lsu_imprecise_error_load_any, // imprecise load bus error
output logic lsu_imprecise_error_store_any, // imprecise store bus error
output logic [31:0] lsu_imprecise_error_addr_any, // address of the imprecise error
// Non-blocking loads
input logic dec_nonblock_load_freeze_dc2,
output logic lsu_nonblock_load_valid_dc3, // there is an external load -> put in the cam
output logic [`RV_LSU_NUM_NBLOAD_WIDTH-1:0] lsu_nonblock_load_tag_dc3, // the tag of the external non block load
output logic lsu_nonblock_load_inv_dc5, // invalidate signal for the cam entry for non block loads
output logic [`RV_LSU_NUM_NBLOAD_WIDTH-1:0] lsu_nonblock_load_inv_tag_dc5, // tag of the enrty which needs to be invalidated
output logic lsu_nonblock_load_data_valid, // the non block is valid - sending information back to the cam
output logic lsu_nonblock_load_data_error, // non block load has an error
output logic [`RV_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,
output logic lsu_pmu_bus_error,
output logic lsu_pmu_bus_busy,
// AXI Write Channels
output logic lsu_axi_awvalid,
input logic lsu_axi_awready,
output logic [`RV_LSU_BUS_TAG-1:0] lsu_axi_awid,
output logic [31:0] lsu_axi_awaddr,
output logic [3:0] lsu_axi_awregion,
output logic [7:0] lsu_axi_awlen,
output logic [2:0] lsu_axi_awsize,
output logic [1:0] lsu_axi_awburst,
output logic lsu_axi_awlock,
output logic [3:0] lsu_axi_awcache,
output logic [2:0] lsu_axi_awprot,
output logic [3:0] lsu_axi_awqos,
output logic lsu_axi_wvalid,
input logic lsu_axi_wready,
output logic [63:0] lsu_axi_wdata,
output logic [7:0] lsu_axi_wstrb,
output logic lsu_axi_wlast,
input logic lsu_axi_bvalid,
output logic lsu_axi_bready,
input logic [1:0] lsu_axi_bresp,
input logic [`RV_LSU_BUS_TAG-1:0] lsu_axi_bid,
// AXI Read Channels
output logic lsu_axi_arvalid,
input logic lsu_axi_arready,
output logic [`RV_LSU_BUS_TAG-1:0] lsu_axi_arid,
output logic [31:0] lsu_axi_araddr,
output logic [3:0] lsu_axi_arregion,
output logic [7:0] lsu_axi_arlen,
output logic [2:0] lsu_axi_arsize,
output logic [1:0] lsu_axi_arburst,
output logic lsu_axi_arlock,
output logic [3:0] lsu_axi_arcache,
output logic [2:0] lsu_axi_arprot,
output logic [3:0] lsu_axi_arqos,
input logic lsu_axi_rvalid,
output logic lsu_axi_rready,
input logic [`RV_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,
input logic lsu_bus_clk_en_q
);
`include "global.h"
// For Ld: IDLE -> WAIT -> CMD -> RESP -> 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=3'b100} state_t;
localparam DEPTH = `RV_LSU_NUM_NBLOAD;
localparam DEPTH_LOG2 = `RV_LSU_NUM_NBLOAD_WIDTH;
localparam TIMER = 8; // This can be only power of 2
localparam TIMER_LOG2 = (TIMER < 2) ? 1 : $clog2(TIMER);
localparam TIMER_MAX = (TIMER == 0) ? TIMER_LOG2'(0) : TIMER_LOG2'(TIMER - 1); // Maximum value of timer
logic [3:0] ldst_byteen_hi_dc2, ldst_byteen_lo_dc2;
logic [DEPTH-1:0] ld_addr_hitvec_lo, ld_addr_hitvec_hi;
logic [3:0][DEPTH-1:0] ld_byte_hitvec_lo, ld_byte_hitvec_hi;
logic [3:0][DEPTH-1:0] ld_byte_hitvecfn_lo, ld_byte_hitvecfn_hi;
logic ld_addr_ibuf_hit_lo, ld_addr_ibuf_hit_hi;
logic [3:0] ld_byte_ibuf_hit_lo, ld_byte_ibuf_hit_hi;
logic [3:0] ldst_byteen_dc5;
logic [7:0] ldst_byteen_ext_dc5;
logic [3:0] ldst_byteen_hi_dc5, ldst_byteen_lo_dc5;
logic [31:0] store_data_hi_dc5, store_data_lo_dc5;
logic ldst_samedw_dc5;
logic lsu_nonblock_load_valid_dc4,lsu_nonblock_load_valid_dc5;
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_load_data_valid_hi, lsu_nonblock_load_data_valid_lo;
logic lsu_nonblock_load_data_error_hi, lsu_nonblock_load_data_error_lo;
logic lsu_nonblock_unsign, lsu_nonblock_dual;
logic dec_nonblock_load_freeze_dc3;
logic ld_precise_bus_error;
logic [DEPTH_LOG2-1:0] lsu_imprecise_error_load_tag;
logic [31:0] ld_block_bus_data;
logic [DEPTH-1:0] CmdPtr0Dec, CmdPtr1Dec;
logic [DEPTH_LOG2-1:0] CmdPtr0, CmdPtr1;
logic [DEPTH_LOG2-1:0] WrPtr0_dc3, WrPtr0_dc4, WrPtr0_dc5;
logic [DEPTH_LOG2-1:0] WrPtr1_dc3, WrPtr1_dc4, WrPtr1_dc5;
logic found_wrptr0, found_wrptr1, found_cmdptr0, found_cmdptr1;
logic [3:0] buf_numvld_any, buf_numvld_wrcmd_any, buf_numvld_pend_any, buf_numvld_cmd_any;
logic bus_sideeffect_pend;
logic bus_coalescing_disable;
logic ld_freeze_en, ld_freeze_rst;
logic FreezePtrEn;
logic [DEPTH_LOG2-1:0] FreezePtr;
logic bus_addr_match_pending;
logic bus_cmd_sent, bus_cmd_ready;
logic bus_wcmd_sent, bus_wdata_sent;
logic bus_rsp_read, bus_rsp_write;
logic [LSU_BUS_TAG-1:0] bus_rsp_read_tag, bus_rsp_write_tag;
logic bus_rsp_read_error, bus_rsp_write_error;
logic [63:0] bus_rsp_rdata;
// Bus buffer signals
state_t [DEPTH-1:0] buf_state;
logic [DEPTH-1:0][2:0] buf_state_out;
logic [DEPTH-1:0][1:0] buf_sz;
logic [DEPTH-1:0][31:0] buf_addr;
logic [DEPTH-1:0][3:0] buf_byteen;
logic [DEPTH-1:0] buf_sideeffect;
logic [DEPTH-1:0] buf_write;
logic [DEPTH-1:0] buf_unsign;
logic [DEPTH-1:0] buf_dual;
logic [DEPTH-1:0] buf_samedw;
logic [DEPTH-1:0] buf_nomerge;
logic [DEPTH-1:0] buf_dualhi;
logic [DEPTH-1:0][DEPTH_LOG2-1:0] buf_dualtag;
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, buf_age_temp;
state_t [DEPTH-1:0] buf_nxtstate;
logic [DEPTH-1:0] buf_rst;
logic [DEPTH-1:0] buf_state_en;
logic [DEPTH-1:0] buf_cmd_state_bus_en;
logic [DEPTH-1:0] buf_resp_state_bus_en;
logic [DEPTH-1:0] buf_state_bus_en;
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;
logic [DEPTH-1:0] buf_write_in;
logic [DEPTH-1:0] buf_wr_en;
logic [DEPTH-1:0] buf_dualhi_in;
logic [DEPTH-1:0][DEPTH_LOG2-1:0] buf_dualtag_in;
logic [DEPTH-1:0][3:0] buf_byteen_in;
logic [DEPTH-1:0][31:0] buf_addr_in;
logic [DEPTH-1:0][31:0] buf_data_in;
logic [DEPTH-1:0] buf_error_en;
logic [DEPTH-1:0] buf_data_en;
logic [DEPTH-1:0][DEPTH-1:0] buf_age_in;
logic [DEPTH-1:0][DEPTH-1:0] buf_ageQ;
// Input buffer signals
logic ibuf_valid;
logic ibuf_dual;
logic ibuf_samedw;
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;
logic [1:0] ibuf_sz;
logic [3:0] ibuf_byteen;
logic [31:0] ibuf_addr;
logic [31:0] ibuf_data;
logic [TIMER_LOG2-1:0] ibuf_timer;
logic ibuf_byp;
logic ibuf_wr_en;
logic ibuf_rst;
logic ibuf_force_drain;
logic ibuf_drain_vld;
logic [DEPTH-1:0] ibuf_drainvec_vld;
logic [DEPTH_LOG2-1:0] ibuf_tag_in;
logic [DEPTH_LOG2-1:0] ibuf_dualtag_in;
logic [1:0] ibuf_sz_in;
logic [31:0] ibuf_addr_in;
logic [3:0] ibuf_byteen_in;
logic [31:0] ibuf_data_in;
logic [TIMER_LOG2-1:0] ibuf_timer_in;
logic [3:0] ibuf_byteen_out;
logic [31:0] ibuf_data_out;
logic ibuf_merge_en, ibuf_merge_in;
// Output buffer signals
logic obuf_valid;
logic obuf_write;
logic obuf_sideeffect;
logic [31:0] obuf_addr;
logic [63:0] obuf_data;
logic [1:0] obuf_sz;
logic [7:0] obuf_byteen;
logic obuf_merge;
logic obuf_cmd_done, obuf_data_done;
logic [LSU_BUS_TAG-1:0] obuf_tag0;
logic [LSU_BUS_TAG-1:0] obuf_tag1;
logic ibuf_buf_byp;
logic obuf_force_wr_en;
logic obuf_wr_wait;
logic obuf_wr_en, obuf_wr_enQ;
logic obuf_rst;
logic obuf_write_in;
logic obuf_sideeffect_in;
logic [31:0] obuf_addr_in;
logic [63:0] obuf_data_in;
logic [1:0] obuf_sz_in;
logic [7:0] obuf_byteen_in;
logic obuf_merge_in;
logic obuf_cmd_done_in, obuf_data_done_in;
logic [LSU_BUS_TAG-1:0] obuf_tag0_in;
logic [LSU_BUS_TAG-1:0] obuf_tag1_in;
logic obuf_merge_en;
logic [TIMER_LOG2-1:0] obuf_wr_timer, obuf_wr_timer_in;
logic [7:0] obuf_byteen0_in, obuf_byteen1_in;
logic [63:0] obuf_data0_in, obuf_data1_in;
logic lsu_axi_awvalid_q, lsu_axi_awready_q;
logic lsu_axi_wvalid_q, lsu_axi_wready_q;
logic lsu_axi_arvalid_q, lsu_axi_arready_q;
logic lsu_axi_bvalid_q, lsu_axi_bready_q;
logic lsu_axi_rvalid_q, lsu_axi_rready_q;
logic [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 [63:0] lsu_axi_rdata_q;
//------------------------------------------------------------------------------
// Load forwarding logic start
//------------------------------------------------------------------------------
// Buffer hit logic for bus load forwarding
assign ldst_byteen_hi_dc2[3:0] = ldst_byteen_ext_dc2[7:4];
assign ldst_byteen_lo_dc2[3:0] = ldst_byteen_ext_dc2[3:0];
for (genvar i=0; i<DEPTH; i++) begin
// We can't forward from RESP for ahb since multiple writes to the same address can be in RESP and we can't find out their age
assign ld_addr_hitvec_lo[i] = (lsu_addr_dc2[31:2] == buf_addr[i][31:2]) & buf_write[i] & ((buf_state[i] == WAIT) | (buf_state[i] == CMD)) & lsu_busreq_dc2;
assign ld_addr_hitvec_hi[i] = (end_addr_dc2[31:2] == buf_addr[i][31:2]) & buf_write[i] & ((buf_state[i] == WAIT) | (buf_state[i] == CMD)) & lsu_busreq_dc2;
end
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<DEPTH; i++) begin
assign ld_byte_hitvec_lo[j][i] = ld_addr_hitvec_lo[i] & buf_byteen[i][j] & ldst_byteen_lo_dc2[j];
assign ld_byte_hitvec_hi[j][i] = ld_addr_hitvec_hi[i] & buf_byteen[i][j] & ldst_byteen_hi_dc2[j];
assign ld_byte_hitvecfn_lo[j][i] = ld_byte_hitvec_lo[j][i] & ~(|(ld_byte_hitvec_lo[j] & buf_age_younger[i])) & ~ld_byte_ibuf_hit_lo[j]; // Kill the byte enable if younger entry exists or byte exists in ibuf
assign ld_byte_hitvecfn_hi[j][i] = ld_byte_hitvec_hi[j][i] & ~(|(ld_byte_hitvec_hi[j] & buf_age_younger[i])) & ~ld_byte_ibuf_hit_hi[j]; // Kill the byte enable if younger entry exists or byte exists in ibuf
end
end
// Hit in the ibuf
assign ld_addr_ibuf_hit_lo = (lsu_addr_dc2[31:2] == ibuf_addr[31:2]) & ibuf_write & ibuf_valid & lsu_busreq_dc2;
assign ld_addr_ibuf_hit_hi = (end_addr_dc2[31:2] == ibuf_addr[31:2]) & ibuf_write & ibuf_valid & lsu_busreq_dc2;
for (genvar i=0; i<4; i++) begin
assign ld_byte_ibuf_hit_lo[i] = ld_addr_ibuf_hit_lo & ibuf_byteen[i] & ldst_byteen_lo_dc2[i];
assign ld_byte_ibuf_hit_hi[i] = ld_addr_ibuf_hit_hi & ibuf_byteen[i] & ldst_byteen_hi_dc2[i];
end
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<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];
ld_fwddata_buf_lo[31:24] |= {8{ld_byte_hitvecfn_lo[3][i]}} & buf_data[i][31:24];
ld_fwddata_buf_hi[7:0] |= {8{ld_byte_hitvecfn_hi[0][i]}} & buf_data[i][7:0];
ld_fwddata_buf_hi[15:8] |= {8{ld_byte_hitvecfn_hi[1][i]}} & buf_data[i][15:8];
ld_fwddata_buf_hi[23:16] |= {8{ld_byte_hitvecfn_hi[2][i]}} & buf_data[i][23:16];
ld_fwddata_buf_hi[31:24] |= {8{ld_byte_hitvecfn_hi[3][i]}} & buf_data[i][31:24];
end
end
//------------------------------------------------------------------------------
// Load forwarding logic end
//------------------------------------------------------------------------------
`ifdef RV_BUILD_AHB_LITE
assign bus_coalescing_disable = 1'b1; // No coalescing for ahb
`else
assign bus_coalescing_disable = dec_tlu_wb_coalescing_disable;
`endif
// Get the hi/lo byte enable
assign ldst_byteen_dc5[3:0] = ({4{lsu_pkt_dc5.by}} & 4'b0001) |
({4{lsu_pkt_dc5.half}} & 4'b0011) |
({4{lsu_pkt_dc5.word}} & 4'b1111);
assign {ldst_byteen_hi_dc5[3:0], ldst_byteen_lo_dc5[3:0]} = {4'b0,ldst_byteen_dc5[3:0]} << lsu_addr_dc5[1:0];
assign {store_data_hi_dc5[31:0], store_data_lo_dc5[31:0]} = {32'b0,store_data_dc5[31:0]} << {lsu_addr_dc5[1:0],3'b0};
assign ldst_samedw_dc5 = (lsu_addr_dc5[3] == end_addr_dc5[3]);
//------------------------------------------------------------------------------
// Input buffer logic starts here
//------------------------------------------------------------------------------
assign ibuf_byp = lsu_busreq_dc5 & ((lsu_pkt_dc5.load | no_word_merge_dc5) & ~ibuf_valid); // Bypass if ibuf is empty and it's a load or no merge possible
assign ibuf_wr_en = lsu_busreq_dc5 & (lsu_commit_dc5 | lsu_freeze_dc3) & ~ibuf_byp;
assign ibuf_rst = ibuf_drain_vld & ~ibuf_wr_en;
assign ibuf_force_drain = lsu_busreq_dc2 & ~lsu_busreq_dc3 & ~lsu_busreq_dc4 & ~lsu_busreq_dc5 & ibuf_valid & (lsu_pkt_dc2.load | (ibuf_addr[31:2] != lsu_addr_dc2[31:2])); // Move the ibuf to buf if there is a non-colaescable ld/st in dc2 but nothing in dc3/dc4/dc5
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_dc5 ? WrPtr1_dc5 : WrPtr0_dc5);
assign ibuf_dualtag_in[DEPTH_LOG2-1:0] = WrPtr0_dc5;
assign ibuf_sz_in[1:0] = {lsu_pkt_dc5.word, lsu_pkt_dc5.half}; // NOTE: Make sure lsu_pkt_dc3/dc4 are flopped in case of freeze (except the valid)
assign ibuf_addr_in[31:0] = ldst_dual_dc5 ? end_addr_dc5[31:0] : lsu_addr_dc5[31:0];
assign ibuf_byteen_in[3:0] = (ibuf_merge_en & ibuf_merge_in) ? (ibuf_byteen[3:0] | ldst_byteen_lo_dc5[3:0]) : (ldst_dual_dc5 ? ldst_byteen_hi_dc5[3:0] : ldst_byteen_lo_dc5[3:0]);
for (genvar i=0; i<4; i++) begin
assign ibuf_data_in[(8*i)+7:(8*i)] = (ibuf_merge_en & ibuf_merge_in) ? (ldst_byteen_lo_dc5[i] ? store_data_lo_dc5[(8*i)+7:(8*i)] : ibuf_data[(8*i)+7:(8*i)]) :
(ldst_dual_dc5 ? store_data_hi_dc5[(8*i)+7:(8*i)] : store_data_lo_dc5[(8*i)+7:(8*i)]);
end
assign ibuf_timer_in = ibuf_wr_en ? '0 : (ibuf_timer < TIMER_MAX) ? (ibuf_timer + 1'b1) : ibuf_timer;
assign ibuf_merge_en = lsu_busreq_dc5 & lsu_commit_dc5 & lsu_pkt_dc5.store & ibuf_valid & ibuf_write & (lsu_addr_dc5[31:2] == ibuf_addr[31:2]) & ~is_sideeffects_dc5 & ~bus_coalescing_disable;
assign ibuf_merge_in = ~ldst_dual_dc5; // If it's a unaligned store, merge needs to happen on the way out of ibuf
// ibuf signals going to bus buffer after merging
for (genvar i=0; i<4; i++) begin
assign ibuf_byteen_out[i] = (ibuf_merge_en & ~ibuf_merge_in) ? (ibuf_byteen[i] | ldst_byteen_lo_dc5[i]) : ibuf_byteen[i];
assign ibuf_data_out[(8*i)+7:(8*i)] = (ibuf_merge_en & ~ibuf_merge_in) ? (ldst_byteen_lo_dc5[i] ? store_data_lo_dc5[(8*i)+7:(8*i)] : ibuf_data[(8*i)+7:(8*i)]) :
ibuf_data[(8*i)+7:(8*i)];
end
rvdffsc #(.WIDTH(1)) ibuf_valid_ff (.din(1'b1), .dout(ibuf_valid), .en(ibuf_wr_en), .clear(ibuf_rst), .clk(lsu_free_c2_clk), .*);
rvdffs #(.WIDTH(DEPTH_LOG2)) ibuf_tagff (.din(ibuf_tag_in), .dout(ibuf_tag), .en(ibuf_wr_en), .clk(lsu_bus_ibuf_c1_clk), .*);
rvdffs #(.WIDTH(DEPTH_LOG2)) ibuf_dualtagff (.din(ibuf_dualtag_in), .dout(ibuf_dualtag), .en(ibuf_wr_en), .clk(lsu_bus_ibuf_c1_clk), .*);
rvdffs #(.WIDTH(1)) ibuf_dualff (.din(ldst_dual_dc5), .dout(ibuf_dual), .en(ibuf_wr_en), .clk(lsu_bus_ibuf_c1_clk), .*);
rvdffs #(.WIDTH(1)) ibuf_samedwff (.din(ldst_samedw_dc5), .dout(ibuf_samedw), .en(ibuf_wr_en), .clk(lsu_bus_ibuf_c1_clk), .*);
rvdffs #(.WIDTH(1)) ibuf_nomergeff (.din(no_dword_merge_dc5), .dout(ibuf_nomerge), .en(ibuf_wr_en), .clk(lsu_bus_ibuf_c1_clk), .*);
rvdffs #(.WIDTH(1)) ibuf_nbff (.din(lsu_nonblock_load_valid_dc5), .dout(ibuf_nb), .en(ibuf_wr_en), .clk(lsu_bus_ibuf_c1_clk), .*);
rvdffs #(.WIDTH(1)) ibuf_sideeffectff (.din(is_sideeffects_dc5), .dout(ibuf_sideeffect), .en(ibuf_wr_en), .clk(lsu_bus_ibuf_c1_clk), .*);
rvdffs #(.WIDTH(1)) ibuf_unsignff (.din(lsu_pkt_dc5.unsign), .dout(ibuf_unsign), .en(ibuf_wr_en), .clk(lsu_bus_ibuf_c1_clk), .*);
rvdffs #(.WIDTH(1)) ibuf_writeff (.din(lsu_pkt_dc5.store), .dout(ibuf_write), .en(ibuf_wr_en), .clk(lsu_bus_ibuf_c1_clk), .*);
rvdffs #(.WIDTH(2)) ibuf_szff (.din(ibuf_sz_in[1:0]), .dout(ibuf_sz), .en(ibuf_wr_en), .clk(lsu_bus_ibuf_c1_clk), .*);
rvdffe #(.WIDTH(32)) ibuf_addrff (.din(ibuf_addr_in[31:0]), .dout(ibuf_addr), .en(ibuf_wr_en), .*);
rvdffs #(.WIDTH(4)) ibuf_byteenff (.din(ibuf_byteen_in[3:0]), .dout(ibuf_byteen), .en(ibuf_wr_en), .clk(lsu_bus_ibuf_c1_clk), .*);
rvdffe #(.WIDTH(32)) ibuf_dataff (.din(ibuf_data_in[31:0]), .dout(ibuf_data), .en(ibuf_wr_en), .*);
rvdff #(.WIDTH(TIMER_LOG2)) ibuf_timerff (.din(ibuf_timer_in), .dout(ibuf_timer), .clk(lsu_free_c2_clk), .*);
//------------------------------------------------------------------------------
// Input buffer logic ends here
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
// 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_MAX) & ~bus_coalescing_disable & ~buf_nomerge[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_MAX)) ? (obuf_wr_timer + 1'b1) : obuf_wr_timer);
assign obuf_force_wr_en = lsu_busreq_dc2 & ~lsu_busreq_dc3 & ~lsu_busreq_dc4 & ~lsu_busreq_dc5 & ~ibuf_valid & (buf_numvld_cmd_any[3:0] == 4'b1) & (lsu_addr_dc2[31:2] != buf_addr[CmdPtr0][31:2]); // Entry in dc2 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) & ~ldst_dual_dc5 & lsu_pkt_dc5.store;
assign obuf_wr_en = (lsu_bus_clk_en & ((ibuf_buf_byp & lsu_commit_dc5) |
((buf_state[CmdPtr0] == CMD) & found_cmdptr0 & ~buf_cmd_state_bus_en[CmdPtr0] &
(~(buf_dual[CmdPtr0] & buf_samedw[CmdPtr0] & ~buf_write[CmdPtr0]) | found_cmdptr1 | buf_nomerge[CmdPtr0] | obuf_force_wr_en)))) &
(bus_cmd_ready | ~obuf_valid) & ~obuf_wr_wait & ~bus_sideeffect_pend & ~bus_addr_match_pending;
assign obuf_rst = bus_cmd_sent & ~obuf_wr_en;
assign obuf_write_in = ibuf_buf_byp ? lsu_pkt_dc5.store : buf_write[CmdPtr0];
assign obuf_sideeffect_in = ibuf_buf_byp ? is_sideeffects_dc5 : buf_sideeffect[CmdPtr0];
assign obuf_addr_in[31:0] = ibuf_buf_byp ? lsu_addr_dc5[31:0] : buf_addr[CmdPtr0];
assign obuf_sz_in[1:0] = ibuf_buf_byp ? {lsu_pkt_dc5.word, lsu_pkt_dc5.half} : buf_sz[CmdPtr0];
assign obuf_merge_in = obuf_merge_en;
assign obuf_tag0_in[LSU_BUS_TAG-1:0] = ibuf_buf_byp ? LSU_BUS_TAG'(WrPtr0_dc5) : LSU_BUS_TAG'(CmdPtr0);
assign obuf_tag1_in[LSU_BUS_TAG-1:0] = LSU_BUS_TAG'(CmdPtr1);
assign obuf_cmd_done_in = ~(obuf_wr_en | obuf_rst) & (obuf_cmd_done | bus_wcmd_sent);
assign obuf_data_done_in = ~(obuf_wr_en | obuf_rst) & (obuf_data_done | bus_wdata_sent);
assign obuf_byteen0_in[7:0] = ibuf_buf_byp ? (lsu_addr_dc5[2] ? {ldst_byteen_lo_dc5[3:0],4'b0} : {4'b0,ldst_byteen_lo_dc5[3:0]}) :
(buf_addr[CmdPtr0][2] ? {buf_byteen[CmdPtr0],4'b0} : {4'b0,buf_byteen[CmdPtr0]});
assign obuf_byteen1_in[7:0] = 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_dc5[2] ? {store_data_lo_dc5[31:0],32'b0} : {32'b0,store_data_lo_dc5[31:0]}) :
(buf_addr[CmdPtr0][2] ? {buf_data[CmdPtr0],32'b0} : {32'b0,buf_data[CmdPtr0]});
assign obuf_data1_in[63:0] = buf_addr[CmdPtr1][2] ? {buf_data[CmdPtr1],32'b0} : {32'b0,buf_data[CmdPtr1]};
for (genvar i=0 ;i<8; i++) begin
assign obuf_byteen_in[i] = obuf_byteen0_in[i] | (obuf_merge_en & obuf_byteen1_in[i]);
assign obuf_data_in[(8*i)+7:(8*i)] = (obuf_merge_en & obuf_byteen1_in[i]) ? obuf_data1_in[(8*i)+7:(8*i)] : obuf_data0_in[(8*i)+7:(8*i)];
end
// 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_dual[CmdPtr0] & ~buf_dualhi[CmdPtr0] & buf_samedw[CmdPtr0]); // CmdPtr0/CmdPtr1 are for same load which is within a DW
rvdff #(.WIDTH(1)) obuf_wren_ff (.din(obuf_wr_en), .dout(obuf_wr_enQ), .clk(lsu_busm_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), .*);
rvdffsc #(.WIDTH(1)) obuf_valid_ff (.din(1'b1), .dout(obuf_valid), .en(obuf_wr_en), .clear(obuf_rst), .clk(lsu_busm_clk), .*);
rvdffs #(.WIDTH(LSU_BUS_TAG)) obuf_tag0ff (.din(obuf_tag0_in), .dout(obuf_tag0), .en(obuf_wr_en), .clk(lsu_bus_obuf_c1_clk), .*);
rvdffs #(.WIDTH(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), .*);
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), .*);
//------------------------------------------------------------------------------
// Output buffer logic ends here
//------------------------------------------------------------------------------
// Find the entry to allocate and entry to send
always_comb begin
WrPtr0_dc3[DEPTH_LOG2-1:0] = '0;
WrPtr1_dc3[DEPTH_LOG2-1:0] = '0;
found_wrptr0 = '0;
found_wrptr1 = '0;
// Find first write pointer
for (int i=0; i<DEPTH; i++) begin
if (~found_wrptr0) begin
WrPtr0_dc3[DEPTH_LOG2-1:0] = DEPTH_LOG2'(i);
found_wrptr0 = (buf_state[i] == IDLE) & ~((ibuf_valid & (ibuf_tag == DEPTH_LOG2'(i))) |
(lsu_busreq_dc4 & ((WrPtr0_dc4 == DEPTH_LOG2'(i)) | (ldst_dual_dc4 & (WrPtr1_dc4 == DEPTH_LOG2'(i))))) |
(lsu_busreq_dc5 & ((WrPtr0_dc5 == DEPTH_LOG2'(i)) | (ldst_dual_dc5 & (WrPtr1_dc5 == DEPTH_LOG2'(i))))));
//found_wrptr = (buf_state[i] == IDLE);
end
end
// Find second write pointer
for (int i=0; i<DEPTH; i++) begin
if (~found_wrptr1) begin
WrPtr1_dc3[DEPTH_LOG2-1:0] = DEPTH_LOG2'(i);
found_wrptr1 = (buf_state[i] == IDLE) & ~((ibuf_valid & (ibuf_tag == DEPTH_LOG2'(i))) |
(lsu_busreq_dc3 & (WrPtr0_dc3 == DEPTH_LOG2'(i))) |
(lsu_busreq_dc4 & ((WrPtr0_dc4 == DEPTH_LOG2'(i)) | (ldst_dual_dc4 & (WrPtr1_dc4 == DEPTH_LOG2'(i))))) |
(lsu_busreq_dc5 & ((WrPtr0_dc5 == DEPTH_LOG2'(i)) | (ldst_dual_dc5 & (WrPtr1_dc5 == DEPTH_LOG2'(i))))));
//found_wrptr = (buf_state[i] == IDLE);
end
end
end
// Get the command ptr
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];
end
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]));
// Age vector
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_dc5 & (ibuf_byp | ldst_dual_dc5) & (DEPTH_LOG2'(i) == WrPtr0_dc5) & (DEPTH_LOG2'(j) == ibuf_tag)) | // Set case for dual lo
(ibuf_byp & lsu_busreq_dc5 & ldst_dual_dc5 & (DEPTH_LOG2'(i) == WrPtr1_dc5) & (DEPTH_LOG2'(j) == WrPtr0_dc5)))) | // ibuf bypass case
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_younger[i][j] = (i == j) ? 1'b0: (~buf_age[i][j] & (buf_state[j] != IDLE)); // Younger entries
assign buf_age_temp[i][j] = buf_age[i][j] & ~(CmdPtr0 == DEPTH_LOG2'(j)); // Used to determine CmdPtr1
end
end
//------------------------------------------------------------------------------
// Buffer logic
//------------------------------------------------------------------------------
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_dc5 & (i == WrPtr1_dc5)) ? ldst_byteen_hi_dc5[3:0] : ldst_byteen_lo_dc5[3:0]);
assign buf_addr_in[i] = ibuf_drainvec_vld[i] ? ibuf_addr[31:0] : ((ibuf_byp & ldst_dual_dc5 & (i == WrPtr1_dc5)) ? end_addr_dc5[31:0] : lsu_addr_dc5[31:0]);
assign buf_dual_in[i] = ibuf_drainvec_vld[i] ? ibuf_dual : ldst_dual_dc5;
assign buf_samedw_in[i] = ibuf_drainvec_vld[i] ? ibuf_samedw : ldst_samedw_dc5;
assign buf_nomerge_in[i] = ibuf_drainvec_vld[i] ? (ibuf_nomerge | ibuf_force_drain) : no_dword_merge_dc5;
assign buf_dualhi_in[i] = ibuf_drainvec_vld[i] ? ibuf_dual : (ibuf_byp & ldst_dual_dc5 & (i == WrPtr1_dc5)); // 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_dc5 & (i == WrPtr1_dc5)) ? WrPtr0_dc5 : WrPtr1_dc5);
assign buf_nb_in[i] = ibuf_drainvec_vld[i] ? ibuf_nb : lsu_nonblock_load_valid_dc5;
assign buf_sideeffect_in[i] = ibuf_drainvec_vld[i] ? ibuf_sideeffect : is_sideeffects_dc5;
assign buf_unsign_in[i] = ibuf_drainvec_vld[i] ? ibuf_unsign : lsu_pkt_dc5.unsign;
assign buf_sz_in[i] = ibuf_drainvec_vld[i] ? ibuf_sz : {lsu_pkt_dc5.word, lsu_pkt_dc5.half};
assign buf_write_in[i] = ibuf_drainvec_vld[i] ? ibuf_write : lsu_pkt_dc5.store;
// Buffer entry state machine
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;
case (buf_state[i])
IDLE: begin
buf_nxtstate[i] = lsu_bus_clk_en ? CMD : WAIT;
buf_state_en[i] = (lsu_busreq_dc5 & (lsu_commit_dc5 | lsu_freeze_dc3) & (((ibuf_byp | ldst_dual_dc5) & ~ibuf_merge_en & (i == WrPtr0_dc5)) | (ibuf_byp & ldst_dual_dc5 & (i == WrPtr1_dc5)))) |
(ibuf_drain_vld & (i == ibuf_tag));
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_dc5[31:0];
end
WAIT: begin
buf_nxtstate[i] = CMD;
buf_state_en[i] = lsu_bus_clk_en;
end
CMD: begin
buf_nxtstate[i] = RESP;
buf_cmd_state_bus_en[i] = ((obuf_tag0 == i) | (obuf_merge & (obuf_tag1 == i))) & obuf_valid & obuf_wr_enQ; // Just use the recently written obuf_valid
buf_state_bus_en[i] = buf_cmd_state_bus_en[i];
buf_state_en[i] = buf_state_bus_en[i] & lsu_bus_clk_en;
end
RESP: begin
buf_nxtstate[i] = (buf_write[i] & ~bus_rsp_write_error) ? IDLE : DONE; // Need to go to done to handle errors
buf_resp_state_bus_en[i] = (bus_rsp_write & (bus_rsp_write_tag == LSU_BUS_TAG'(i))) |
(bus_rsp_read & ((bus_rsp_read_tag == LSU_BUS_TAG'(i)) | (buf_dual[i] & buf_dualhi[i] & ~buf_write[i] & buf_samedw[i] & (bus_rsp_read_tag == LSU_BUS_TAG'(buf_dualtag[i])))));
buf_state_bus_en[i] = buf_resp_state_bus_en[i];
buf_state_en[i] = buf_state_bus_en[i] & lsu_bus_clk_en;
buf_data_en[i] = buf_state_bus_en[i] & ~buf_write[i] & bus_rsp_read & lsu_bus_clk_en;
// 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 == LSU_BUS_TAG'(i))) |
(bus_rsp_write_error & (bus_rsp_write_tag == 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];
end
DONE: begin
buf_nxtstate[i] = IDLE;
buf_rst[i] = lsu_bus_clk_en_q & (buf_write[i] | ~buf_dual[i] | (buf_state[buf_dualtag[i]] == DONE));
buf_state_en[i] = buf_rst[i];
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;
buf_data_in[i] = '0;
buf_data_en[i] = '0;
buf_error_en[i] = '0;
buf_rst[i] = '0;
end
endcase
end
assign buf_state[i] = state_t'(buf_state_out[i]);
rvdffs #(.WIDTH($bits(state_t))) buf_state_ff (.din(buf_nxtstate[i]), .dout(buf_state_out[i]), .en(buf_state_en[i]), .clk(lsu_bus_buf_c1_clk), .*);
rvdff #(.WIDTH(DEPTH)) buf_ageff (.din(buf_age_in[i]), .dout(buf_ageQ[i]), .clk(lsu_bus_buf_c1_clk), .*);
rvdffs #(.WIDTH(DEPTH_LOG2)) buf_dualtagff (.din(buf_dualtag_in[i]), .dout(buf_dualtag[i]), .en(buf_wr_en[i]), .clk(lsu_bus_buf_c1_clk), .*);
rvdffs #(.WIDTH(1)) buf_dualff (.din(buf_dual_in[i]), .dout(buf_dual[i]), .en(buf_wr_en[i]), .clk(lsu_bus_buf_c1_clk), .*);
rvdffs #(.WIDTH(1)) buf_samedwff (.din(buf_samedw_in[i]), .dout(buf_samedw[i]), .en(buf_wr_en[i]), .clk(lsu_bus_buf_c1_clk), .*);
rvdffs #(.WIDTH(1)) buf_nomergeff (.din(buf_nomerge_in[i]), .dout(buf_nomerge[i]), .en(buf_wr_en[i]), .clk(lsu_bus_buf_c1_clk), .*);
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_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), .*);
rvdffs #(.WIDTH(2)) buf_szff (.din(buf_sz_in[i]), .dout(buf_sz[i]), .en(buf_wr_en[i]), .clk(lsu_bus_buf_c1_clk), .*);
rvdffe #(.WIDTH(32)) buf_addrff (.din(buf_addr_in[i][31:0]), .dout(buf_addr[i]), .en(buf_wr_en[i]), .*);
rvdffs #(.WIDTH(4)) buf_byteenff (.din(buf_byteen_in[i][3:0]), .dout(buf_byteen[i]), .en(buf_wr_en[i]), .clk(lsu_bus_buf_c1_clk), .*);
rvdffe #(.WIDTH(32)) buf_dataff (.din(buf_data_in[i][31:0]), .dout(buf_data[i]), .en(buf_data_en[i]), .*);
rvdffsc #(.WIDTH(1)) buf_errorff (.din(1'b1), .dout(buf_error[i]), .en(buf_error_en[i]), .clear(buf_rst[i]), .clk(lsu_bus_buf_c1_clk), .*);
end
// buffer full logic
always_comb begin
buf_numvld_any[3:0] = ({3'b0,(lsu_pkt_dc1.valid & ~lsu_pkt_dc1.dma)} << (lsu_pkt_dc1.valid & ldst_dual_dc1)) +
({3'b0,lsu_busreq_dc2} << ldst_dual_dc2) +
({3'b0,lsu_busreq_dc3} << ldst_dual_dc3) +
({3'b0,lsu_busreq_dc4} << ldst_dual_dc4) +
({3'b0,lsu_busreq_dc5} << ldst_dual_dc5) +
{3'b0,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;
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])};
buf_numvld_pend_any[3:0] += {3'b0, ((buf_state[i] == WAIT) | ((buf_state[i] == CMD) & ~buf_cmd_state_bus_en[i]))};
end
end
assign lsu_bus_buffer_pend_any = (buf_numvld_pend_any != 0);
assign lsu_bus_buffer_full_any = (buf_numvld_any[3:0] >= (DEPTH-1));
assign lsu_bus_buffer_empty_any = ~(|buf_state[DEPTH-1:0]) & ~ibuf_valid & ~obuf_valid;
// Freeze logic
assign FreezePtrEn = lsu_busreq_dc3 & lsu_pkt_dc3.load & ld_freeze_dc3;
assign ld_freeze_en = (is_sideeffects_dc2 | dec_nonblock_load_freeze_dc2 | dec_tlu_non_blocking_disable) & lsu_busreq_dc2 & lsu_pkt_dc2.load & ~lsu_freeze_dc3 & ~flush_dc2_up & ~ld_full_hit_dc2;
always_comb begin
ld_freeze_rst = flush_dc3 | (dec_tlu_cancel_e4 & ld_freeze_dc3);
for (int i=0; i<DEPTH; i++) begin
ld_freeze_rst |= (buf_rst[i] & (DEPTH_LOG2'(i) == FreezePtr) & ~FreezePtrEn & ld_freeze_dc3);
end
end
// Load signals for freeze
assign ld_block_bus_data[31:0] = 32'(({({32{buf_dual[FreezePtr]}} & buf_data[buf_dualtag[FreezePtr]]), buf_data[FreezePtr][31:0]}) >> (8*buf_addr[FreezePtr][1:0]));
assign ld_precise_bus_error = (buf_error[FreezePtr] | (buf_dual[FreezePtr] & buf_error[buf_dualtag[FreezePtr]])) & ~buf_write[FreezePtr] & buf_rst[FreezePtr] & lsu_freeze_dc3 & ld_freeze_rst & ~flush_dc3; // Don't give bus error for interrupts
assign ld_bus_error_addr_dc3[31:0] = buf_addr[FreezePtr][31:0];
// Non blocking ports
assign lsu_nonblock_load_valid_dc3 = lsu_busreq_dc3 & lsu_pkt_dc3.valid & lsu_pkt_dc3.load & ~flush_dc3 & ~dec_nonblock_load_freeze_dc3 & ~lsu_freeze_dc3 & ~dec_tlu_non_blocking_disable;
assign lsu_nonblock_load_tag_dc3[DEPTH_LOG2-1:0] = WrPtr0_dc3[DEPTH_LOG2-1:0];
assign lsu_nonblock_load_inv_dc5 = lsu_nonblock_load_valid_dc5 & ~lsu_commit_dc5;
assign lsu_nonblock_load_inv_tag_dc5[DEPTH_LOG2-1:0] = WrPtr0_dc5[DEPTH_LOG2-1:0]; // dc5 tag needs to be accurate even if there is no invalidate
always_comb begin
lsu_nonblock_load_data_valid_lo = '0;
lsu_nonblock_load_data_valid_hi = '0;
lsu_nonblock_load_data_error_lo = '0;
lsu_nonblock_load_data_error_hi = '0;
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<DEPTH; i++) begin
// Use buf_rst[i] instead of buf_state_en[i] for timing
lsu_nonblock_load_data_valid_hi |= lsu_bus_clk_en_q & (buf_state[i] == DONE) & buf_rst[i] & ~dec_tlu_non_blocking_disable & buf_nb[i] & ~buf_error[i] & (buf_dual[i] & buf_dualhi[i]);
lsu_nonblock_load_data_valid_lo |= lsu_bus_clk_en_q & (buf_state[i] == DONE) & buf_rst[i] & ~dec_tlu_non_blocking_disable & buf_nb[i] & ~buf_error[i] & (~buf_dual[i] | ~buf_dualhi[i]);
lsu_nonblock_load_data_error_hi |= lsu_bus_clk_en_q & (buf_state[i] == DONE) & buf_rst[i] & ~dec_tlu_non_blocking_disable & buf_error[i] & buf_nb[i] & (buf_dual[i] & buf_dualhi[i]);
lsu_nonblock_load_data_error_lo |= lsu_bus_clk_en_q & (buf_state[i] == DONE) & buf_rst[i] & ~dec_tlu_non_blocking_disable & buf_error[i] & buf_nb[i] & (~buf_dual[i] | ~buf_dualhi[i]);
lsu_nonblock_load_data_tag[DEPTH_LOG2-1:0] |= DEPTH_LOG2'(i) & {DEPTH_LOG2{((buf_state[i] == DONE) & buf_nb[i] & buf_rst[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_nb[i] & buf_rst[i] & (~buf_dual[i] | ~buf_dualhi[i]))}};
lsu_nonblock_load_data_hi[31:0] |= buf_data[i][31:0] & {32{((buf_state[i] == DONE) & buf_nb[i] & buf_rst[i] & (buf_dual[i] & buf_dualhi[i]))}};
end
end
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_valid_lo & (~lsu_nonblock_dual | lsu_nonblock_load_data_valid_hi);
assign lsu_nonblock_load_data_error = lsu_nonblock_load_data_error_lo | (lsu_nonblock_dual & lsu_nonblock_load_data_error_hi);
assign lsu_nonblock_load_data = ({32{ lsu_nonblock_unsign & (lsu_nonblock_sz[1:0] == 2'b00)}} & {24'b0,lsu_nonblock_data_unalgn[7:0]}) |
({32{ lsu_nonblock_unsign & (lsu_nonblock_sz[1:0] == 2'b01)}} & {16'b0,lsu_nonblock_data_unalgn[15:0]}) |
({32{~lsu_nonblock_unsign & (lsu_nonblock_sz[1:0] == 2'b00)}} & {{24{lsu_nonblock_data_unalgn[7]}}, lsu_nonblock_data_unalgn[7:0]}) |
({32{~lsu_nonblock_unsign & (lsu_nonblock_sz[1:0] == 2'b01)}} & {{16{lsu_nonblock_data_unalgn[15]}},lsu_nonblock_data_unalgn[15:0]}) |
({32{(lsu_nonblock_sz[1:0] == 2'b10)}} & lsu_nonblock_data_unalgn[31:0]);
// 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<DEPTH; i++) begin
bus_sideeffect_pend |= ((buf_state[i] == RESP) & buf_sideeffect[i] & dec_tlu_sideeffect_posted_disable);
end
end
// Imprecise bus errors
assign lsu_imprecise_error_load_any = lsu_nonblock_load_data_error; // This is to make sure we send only one imprecise error for loads
// 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<DEPTH; i++) begin
bus_addr_match_pending |= (obuf_valid & (obuf_addr[31:3] == buf_addr[i][31:3]) & (buf_state[i] == RESP) & ~((obuf_tag0 == LSU_BUS_TAG'(i)) | (obuf_merge & (obuf_tag1 == LSU_BUS_TAG'(i)))));
end
end
// Store imprecise error logic
logic [DEPTH_LOG2-1:0] lsu_imprecise_error_store_tag;
always_comb begin
lsu_imprecise_error_store_any = '0;
lsu_imprecise_error_store_tag = '0;
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
end
assign lsu_imprecise_error_addr_any[31:0] = lsu_imprecise_error_load_any ? buf_addr[lsu_nonblock_load_data_tag] : buf_addr[lsu_imprecise_error_store_tag];
// Generic bus signals
assign bus_cmd_ready = obuf_write ? ((obuf_cmd_done | obuf_data_done) ? (obuf_cmd_done ? lsu_axi_wready : lsu_axi_awready) : (lsu_axi_awready & lsu_axi_wready)) : lsu_axi_arready;
assign bus_wcmd_sent = lsu_axi_awvalid & lsu_axi_awready;
assign bus_wdata_sent = lsu_axi_wvalid & lsu_axi_wready;
assign bus_cmd_sent = ((obuf_cmd_done | bus_wcmd_sent) & (obuf_data_done | bus_wdata_sent)) | (lsu_axi_arvalid & lsu_axi_arready);
assign bus_rsp_read = lsu_axi_rvalid_q & lsu_axi_rready_q;
assign bus_rsp_write = lsu_axi_bvalid_q & lsu_axi_bready_q;
assign bus_rsp_read_tag[LSU_BUS_TAG-1:0] = lsu_axi_rid_q[LSU_BUS_TAG-1:0];
assign bus_rsp_write_tag[LSU_BUS_TAG-1:0] = lsu_axi_bid_q[LSU_BUS_TAG-1:0];
assign bus_rsp_write_error = bus_rsp_write & (lsu_axi_bresp_q[1:0] != 2'b0);
assign bus_rsp_read_error = bus_rsp_read & (lsu_axi_rresp_q[1:0] != 2'b0);
assign bus_rsp_rdata[63:0] = lsu_axi_rdata_q[63:0];
// AXI command signals
assign lsu_axi_awvalid = obuf_valid & obuf_write & ~obuf_cmd_done & ~bus_addr_match_pending;
assign lsu_axi_awid[LSU_BUS_TAG-1:0] = 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_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;
assign lsu_axi_awburst[1:0] = 2'b01;
assign lsu_axi_awqos[3:0] = '0;
assign lsu_axi_awlock = '0;
assign lsu_axi_wvalid = obuf_valid & obuf_write & ~obuf_data_done & ~bus_addr_match_pending;
assign lsu_axi_wstrb[7:0] = obuf_byteen[7:0] & {8{obuf_write}};
assign lsu_axi_wdata[63:0] = obuf_data[63:0];
assign lsu_axi_wlast = '1;
assign lsu_axi_arvalid = obuf_valid & ~obuf_write & ~bus_addr_match_pending;
assign lsu_axi_arid[LSU_BUS_TAG-1:0] = 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_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;
assign lsu_axi_arburst[1:0] = 2'b01;
assign lsu_axi_arqos[3:0] = '0;
assign lsu_axi_arlock = '0;
assign lsu_axi_bready = 1;
assign lsu_axi_rready = 1;
// PMU signals
assign lsu_pmu_bus_trxn = (lsu_axi_awvalid_q & lsu_axi_awready_q) | (lsu_axi_wvalid_q & lsu_axi_wready_q) | (lsu_axi_arvalid_q & lsu_axi_arready_q);
assign lsu_pmu_bus_misaligned = lsu_busreq_dc2 & ldst_dual_dc2;
assign lsu_pmu_bus_error = ld_bus_error_dc3 | lsu_imprecise_error_load_any | lsu_imprecise_error_store_any;
assign lsu_pmu_bus_busy = (lsu_axi_awvalid_q & ~lsu_axi_awready_q) | (lsu_axi_wvalid_q & ~lsu_axi_wready_q) | (lsu_axi_arvalid_q & ~lsu_axi_arready_q);
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 #(.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(LSU_BUS_TAG)) lsu_axi_bid_ff (.din(lsu_axi_bid[LSU_BUS_TAG-1:0]), .dout(lsu_axi_bid_q[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 #(.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(LSU_BUS_TAG)) lsu_axi_rid_ff (.din(lsu_axi_rid[LSU_BUS_TAG-1:0]), .dout(lsu_axi_rid_q[LSU_BUS_TAG-1:0]), .clk(lsu_busm_clk), .*);
// General flops
rvdffsc #(.WIDTH(1)) ld_freezeff (.din(1'b1), .dout(ld_freeze_dc3), .en(ld_freeze_en), .clear(ld_freeze_rst), .clk(lsu_free_c2_clk), .*);
rvdffs #(.WIDTH(DEPTH_LOG2)) lsu_FreezePtrff (.din(WrPtr0_dc3), .dout(FreezePtr), .en(FreezePtrEn), .clk(lsu_free_c2_clk), .*);
rvdff #(.WIDTH(1)) ld_bus_errorff (.din(ld_precise_bus_error), .dout(ld_bus_error_dc3), .clk(lsu_free_c2_clk), .*);
rvdff #(.WIDTH(32)) ld_bus_dataff (.din(ld_block_bus_data[31:0]), .dout(ld_bus_data_dc3[31:0]), .clk(lsu_free_c2_clk), .*);
rvdff #(.WIDTH(DEPTH_LOG2)) lsu_WrPtr0_dc4ff (.din(WrPtr0_dc3), .dout(WrPtr0_dc4), .clk(lsu_c2_dc4_clk), .*);
rvdff #(.WIDTH(DEPTH_LOG2)) lsu_WrPtr0_dc5ff (.din(WrPtr0_dc4), .dout(WrPtr0_dc5), .clk(lsu_c2_dc5_clk), .*);
rvdff #(.WIDTH(DEPTH_LOG2)) lsu_WrPtr1_dc4ff (.din(WrPtr1_dc3), .dout(WrPtr1_dc4), .clk(lsu_c2_dc4_clk), .*);
rvdff #(.WIDTH(DEPTH_LOG2)) lsu_WrPtr1_dc5ff (.din(WrPtr1_dc4), .dout(WrPtr1_dc5), .clk(lsu_c2_dc5_clk), .*);
rvdff #(.WIDTH(1)) lsu_busreq_dc3ff (.din(lsu_busreq_dc2 & ~lsu_freeze_dc3 & ~ld_full_hit_dc2), .dout(lsu_busreq_dc3), .clk(lsu_c2_dc3_clk), .*); // Don't want dc2 to dc3 propagation during freeze. Maybe used freeze gated clock
rvdff #(.WIDTH(1)) lsu_busreq_dc4ff (.din(lsu_busreq_dc3 & ~flush_dc4), .dout(lsu_busreq_dc4), .clk(lsu_c2_dc4_clk), .*);
rvdff #(.WIDTH(1)) lsu_busreq_dc5ff (.din(lsu_busreq_dc4 & ~flush_dc5), .dout(lsu_busreq_dc5), .clk(lsu_c2_dc5_clk), .*);
rvdff #(.WIDTH(1)) dec_nonblock_load_freeze_dc3ff (.din(dec_nonblock_load_freeze_dc2), .dout(dec_nonblock_load_freeze_dc3), .clk(lsu_freeze_c2_dc3_clk), .*);
rvdff #(.WIDTH(1)) lsu_nonblock_load_valid_dc4ff (.din(lsu_nonblock_load_valid_dc3), .dout(lsu_nonblock_load_valid_dc4), .clk(lsu_c2_dc4_clk), .*);
rvdff #(.WIDTH(1)) lsu_nonblock_load_valid_dc5ff (.din(lsu_nonblock_load_valid_dc4), .dout(lsu_nonblock_load_valid_dc5), .clk(lsu_c2_dc5_clk), .*);
`ifdef 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]));
`endif
endmodule // lsu_bus_buffer

419
design/lsu/lsu_bus_intf.sv Normal file
View File

@ -0,0 +1,419 @@
// 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.
//********************************************************************************
// $Id$
//
//
// Owner:
// Function: lsu interface with interface queue
// Comments:
//
//********************************************************************************
module lsu_bus_intf
import swerv_types::*;
(
input logic clk,
input logic rst_l,
input logic scan_mode,
input logic dec_tlu_non_blocking_disable, // disable non block
input logic dec_tlu_wb_coalescing_disable, // disable write buffer coalescing
input logic dec_tlu_ld_miss_byp_wb_disable, // disable ld miss bypass of the write buffer
input logic dec_tlu_sideeffect_posted_disable, // disable posted writes to sideeffect addr to the bus
// various clocks needed for the bus reads and writes
input logic lsu_c1_dc3_clk,
input logic lsu_c1_dc4_clk,
input logic lsu_c1_dc5_clk,
input logic lsu_c2_dc3_clk,
input logic lsu_c2_dc4_clk,
input logic lsu_c2_dc5_clk,
input logic lsu_freeze_c1_dc2_clk,
input logic lsu_freeze_c1_dc3_clk,
input logic lsu_freeze_c2_dc2_clk,
input logic lsu_freeze_c2_dc3_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_busreq_dc2, // bus request is in dc2
input lsu_pkt_t lsu_pkt_dc1, // lsu packet flowing down the pipe
input lsu_pkt_t lsu_pkt_dc2, // lsu packet flowing down the pipe
input lsu_pkt_t lsu_pkt_dc3, // lsu packet flowing down the pipe
input lsu_pkt_t lsu_pkt_dc4, // lsu packet flowing down the pipe
input lsu_pkt_t lsu_pkt_dc5, // lsu packet flowing down the pipe
input logic [31:0] lsu_addr_dc1, // lsu address flowing down the pipe
input logic [31:0] lsu_addr_dc2, // lsu address flowing down the pipe
input logic [31:0] lsu_addr_dc3, // lsu address flowing down the pipe
input logic [31:0] lsu_addr_dc4, // lsu address flowing down the pipe
input logic [31:0] lsu_addr_dc5, // lsu address flowing down the pipe
input logic [31:0] end_addr_dc1, // lsu address flowing down the pipe
input logic [31:0] end_addr_dc2, // lsu address flowing down the pipe
input logic [31:0] end_addr_dc3, // lsu address flowing down the pipe
input logic [31:0] end_addr_dc4, // lsu address flowing down the pipe
input logic [31:0] end_addr_dc5, // lsu address flowing down the pipe
input logic addr_external_dc2, // lsu instruction going to external
input logic addr_external_dc3, // lsu instruction going to external
input logic addr_external_dc4, // lsu instruction going to external
input logic addr_external_dc5, // lsu instruction going to external
input logic [63:0] store_data_dc2, // store data flowing down the pipe
input logic [63:0] store_data_dc3, // store data flowing down the pipe
input logic [31:0] store_data_dc4, // store data flowing down the pipe
input logic [31:0] store_data_dc5, // store data flowing down the pipe
input logic lsu_commit_dc5, // lsu instruction in dc5 commits
input logic is_sideeffects_dc2, // lsu attribute is side_effects
input logic is_sideeffects_dc3, // lsu attribute is side_effects
input logic flush_dc2_up, // flush
input logic flush_dc3, // flush
input logic flush_dc4, // flush
input logic flush_dc5, // flush
input logic dec_tlu_cancel_e4, // cancel the bus load in dc4 and reset the freeze
output logic lsu_freeze_dc3, // load goes to external and asserts freeze
output logic lsu_busreq_dc5, // bus request is in dc5
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 [31:0] bus_read_data_dc3, // the bus return data
output logic ld_bus_error_dc3, // bus error in dc3
output logic [31:0] ld_bus_error_addr_dc3, // address of the bus error
output logic lsu_imprecise_error_load_any, // imprecise load bus error
output logic lsu_imprecise_error_store_any, // imprecise store bus error
output logic [31:0] lsu_imprecise_error_addr_any, // address of the imprecise error
// Non-blocking loads
input logic dec_nonblock_load_freeze_dc2,
output logic lsu_nonblock_load_valid_dc3, // there is an external load -> put in the cam
output logic [`RV_LSU_NUM_NBLOAD_WIDTH-1:0] lsu_nonblock_load_tag_dc3, // the tag of the external non block load
output logic lsu_nonblock_load_inv_dc5, // invalidate signal for the cam entry for non block loads
output logic [`RV_LSU_NUM_NBLOAD_WIDTH-1:0] lsu_nonblock_load_inv_tag_dc5, // tag of the enrty which needs to be invalidated
output logic lsu_nonblock_load_data_valid, // the non block is valid - sending information back to the cam
output logic lsu_nonblock_load_data_error, // non block load has an error
output logic [`RV_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,
output logic lsu_pmu_bus_error,
output logic lsu_pmu_bus_busy,
// AXI Write Channels
output logic lsu_axi_awvalid,
input logic lsu_axi_awready,
output logic [`RV_LSU_BUS_TAG-1:0] lsu_axi_awid,
output logic [31:0] lsu_axi_awaddr,
output logic [3:0] lsu_axi_awregion,
output logic [7:0] lsu_axi_awlen,
output logic [2:0] lsu_axi_awsize,
output logic [1:0] lsu_axi_awburst,
output logic lsu_axi_awlock,
output logic [3:0] lsu_axi_awcache,
output logic [2:0] lsu_axi_awprot,
output logic [3:0] lsu_axi_awqos,
output logic lsu_axi_wvalid,
input logic lsu_axi_wready,
output logic [63:0] lsu_axi_wdata,
output logic [7:0] lsu_axi_wstrb,
output logic lsu_axi_wlast,
input logic lsu_axi_bvalid,
output logic lsu_axi_bready,
input logic [1:0] lsu_axi_bresp,
input logic [`RV_LSU_BUS_TAG-1:0] lsu_axi_bid,
// AXI Read Channels
output logic lsu_axi_arvalid,
input logic lsu_axi_arready,
output logic [`RV_LSU_BUS_TAG-1:0] lsu_axi_arid,
output logic [31:0] lsu_axi_araddr,
output logic [3:0] lsu_axi_arregion,
output logic [7:0] lsu_axi_arlen,
output logic [2:0] lsu_axi_arsize,
output logic [1:0] lsu_axi_arburst,
output logic lsu_axi_arlock,
output logic [3:0] lsu_axi_arcache,
output logic [2:0] lsu_axi_arprot,
output logic [3:0] lsu_axi_arqos,
input logic lsu_axi_rvalid,
output logic lsu_axi_rready,
input logic [`RV_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
);
`include "global.h"
logic ld_freeze_dc3;
logic lsu_bus_clk_en_q;
logic ldst_dual_dc1, ldst_dual_dc2, ldst_dual_dc3, ldst_dual_dc4, ldst_dual_dc5;
logic lsu_busreq_dc3, lsu_busreq_dc4;
logic [3:0] ldst_byteen_dc2, ldst_byteen_dc3, ldst_byteen_dc4, ldst_byteen_dc5;
logic [7:0] ldst_byteen_ext_dc2, ldst_byteen_ext_dc3, ldst_byteen_ext_dc4, ldst_byteen_ext_dc5;
logic [3:0] ldst_byteen_hi_dc2, ldst_byteen_hi_dc3, ldst_byteen_hi_dc4, ldst_byteen_hi_dc5;
logic [3:0] ldst_byteen_lo_dc2, ldst_byteen_lo_dc3, ldst_byteen_lo_dc4, ldst_byteen_lo_dc5;
logic is_sideeffects_dc4, is_sideeffects_dc5;
logic [63:0] store_data_ext_dc3, store_data_ext_dc4, store_data_ext_dc5;
logic [31:0] store_data_hi_dc3, store_data_hi_dc4, store_data_hi_dc5;
logic [31:0] store_data_lo_dc3, store_data_lo_dc4, store_data_lo_dc5;
logic addr_match_dw_lo_dc5_dc4, addr_match_dw_lo_dc5_dc3, addr_match_dw_lo_dc5_dc2;
logic addr_match_word_lo_dc5_dc4, addr_match_word_lo_dc5_dc3, addr_match_word_lo_dc5_dc2;
logic no_word_merge_dc5, no_dword_merge_dc5;
logic ld_addr_dc3hit_lo_lo, ld_addr_dc3hit_hi_lo, ld_addr_dc3hit_lo_hi, ld_addr_dc3hit_hi_hi;
logic ld_addr_dc4hit_lo_lo, ld_addr_dc4hit_hi_lo, ld_addr_dc4hit_lo_hi, ld_addr_dc4hit_hi_hi;
logic ld_addr_dc5hit_lo_lo, ld_addr_dc5hit_hi_lo, ld_addr_dc5hit_lo_hi, ld_addr_dc5hit_hi_hi;
logic [3:0] ld_byte_dc3hit_lo_lo, ld_byte_dc3hit_hi_lo, ld_byte_dc3hit_lo_hi, ld_byte_dc3hit_hi_hi;
logic [3:0] ld_byte_dc4hit_lo_lo, ld_byte_dc4hit_hi_lo, ld_byte_dc4hit_lo_hi, ld_byte_dc4hit_hi_hi;
logic [3:0] ld_byte_dc5hit_lo_lo, ld_byte_dc5hit_hi_lo, ld_byte_dc5hit_lo_hi, ld_byte_dc5hit_hi_hi;
logic [3:0] ld_byte_hit_lo, ld_byte_dc3hit_lo, ld_byte_dc4hit_lo, ld_byte_dc5hit_lo;
logic [3:0] ld_byte_hit_hi, ld_byte_dc3hit_hi, ld_byte_dc4hit_hi, ld_byte_dc5hit_hi;
logic [31:0] ld_fwddata_dc3pipe_lo, ld_fwddata_dc4pipe_lo, ld_fwddata_dc5pipe_lo;
logic [31:0] ld_fwddata_dc3pipe_hi, ld_fwddata_dc4pipe_hi, ld_fwddata_dc5pipe_hi;
logic [3:0] ld_byte_hit_buf_lo, ld_byte_hit_buf_hi;
logic [31:0] ld_fwddata_buf_lo, ld_fwddata_buf_hi;
logic ld_hit_rdbuf_hi, ld_hit_rdbuf_lo;
logic [31:0] ld_fwddata_rdbuf_hi, ld_fwddata_rdbuf_lo;
logic [63:0] ld_fwddata_lo, ld_fwddata_hi;
logic [31:0] ld_fwddata_dc2, ld_fwddata_dc3;
logic [31:0] ld_bus_data_dc3;
logic ld_full_hit_hi_dc2, ld_full_hit_lo_dc2;
logic ld_hit_dc2, ld_full_hit_dc2, ld_full_hit_dc3;
logic is_aligned_dc5;
logic [63:32] ld_fwddata_dc2_nc;
logic lsu_write_buffer_empty_any;
assign lsu_write_buffer_empty_any = 1'b1;
assign ldst_byteen_dc2[3:0] = ({4{lsu_pkt_dc2.by}} & 4'b0001) |
({4{lsu_pkt_dc2.half}} & 4'b0011) |
({4{lsu_pkt_dc2.word}} & 4'b1111);
assign ldst_dual_dc1 = (lsu_addr_dc1[2] != end_addr_dc1[2]);
assign lsu_freeze_dc3 = ld_freeze_dc3 & ~(flush_dc4 | flush_dc5);
// Determine if the packet is word aligned
assign is_aligned_dc5 = (lsu_pkt_dc5.word & (lsu_addr_dc5[1:0] == 2'b0)) |
(lsu_pkt_dc5.half & (lsu_addr_dc5[0] == 1'b0));
// Read/Write Buffer
lsu_bus_buffer bus_buffer (
.*
);
// Logic to determine if dc5 store can be coalesced or not with younger stores. Bypass ibuf if cannot colaesced
assign addr_match_dw_lo_dc5_dc4 = (lsu_addr_dc5[31:3] == lsu_addr_dc4[31:3]);
assign addr_match_dw_lo_dc5_dc3 = (lsu_addr_dc5[31:3] == lsu_addr_dc3[31:3]);
assign addr_match_dw_lo_dc5_dc2 = (lsu_addr_dc5[31:3] == lsu_addr_dc2[31:3]);
assign addr_match_word_lo_dc5_dc4 = addr_match_dw_lo_dc5_dc4 & ~(lsu_addr_dc5[2]^lsu_addr_dc4[2]);
assign addr_match_word_lo_dc5_dc3 = addr_match_dw_lo_dc5_dc3 & ~(lsu_addr_dc5[2]^lsu_addr_dc3[2]);
assign addr_match_word_lo_dc5_dc2 = addr_match_dw_lo_dc5_dc2 & ~(lsu_addr_dc5[2]^lsu_addr_dc2[2]);
assign no_word_merge_dc5 = lsu_busreq_dc5 & ~ldst_dual_dc5 &
((lsu_busreq_dc4 & (lsu_pkt_dc4.load | ~addr_match_word_lo_dc5_dc4)) |
(lsu_busreq_dc3 & ~lsu_busreq_dc4 & (lsu_pkt_dc3.load | ~addr_match_word_lo_dc5_dc3)) |
(lsu_busreq_dc2 & ~lsu_busreq_dc3 & ~lsu_busreq_dc4 & (lsu_pkt_dc2.load | ~addr_match_word_lo_dc5_dc2)));
assign no_dword_merge_dc5 = lsu_busreq_dc5 & ~ldst_dual_dc5 &
((lsu_busreq_dc4 & (lsu_pkt_dc4.load | ~addr_match_dw_lo_dc5_dc4)) |
(lsu_busreq_dc3 & ~lsu_busreq_dc4 & (lsu_pkt_dc3.load | ~addr_match_dw_lo_dc5_dc3)) |
(lsu_busreq_dc2 & ~lsu_busreq_dc3 & ~lsu_busreq_dc4 & (lsu_pkt_dc2.load | ~addr_match_dw_lo_dc5_dc2)));
// Create Hi/Lo signals
assign ldst_byteen_ext_dc2[7:0] = {4'b0,ldst_byteen_dc2[3:0]} << lsu_addr_dc2[1:0];
assign ldst_byteen_ext_dc3[7:0] = {4'b0,ldst_byteen_dc3[3:0]} << lsu_addr_dc3[1:0];
assign ldst_byteen_ext_dc4[7:0] = {4'b0,ldst_byteen_dc4[3:0]} << lsu_addr_dc4[1:0];
assign ldst_byteen_ext_dc5[7:0] = {4'b0,ldst_byteen_dc5[3:0]} << lsu_addr_dc5[1:0];
assign store_data_ext_dc3[63:0] = {32'b0,store_data_dc3[31:0]} << {lsu_addr_dc3[1:0],3'b0};
assign store_data_ext_dc4[63:0] = {32'b0,store_data_dc4[31:0]} << {lsu_addr_dc4[1:0],3'b0};
assign store_data_ext_dc5[63:0] = {32'b0,store_data_dc5[31:0]} << {lsu_addr_dc5[1:0],3'b0};
assign ldst_byteen_hi_dc2[3:0] = ldst_byteen_ext_dc2[7:4];
assign ldst_byteen_lo_dc2[3:0] = ldst_byteen_ext_dc2[3:0];
assign ldst_byteen_hi_dc3[3:0] = ldst_byteen_ext_dc3[7:4];
assign ldst_byteen_lo_dc3[3:0] = ldst_byteen_ext_dc3[3:0];
assign ldst_byteen_hi_dc4[3:0] = ldst_byteen_ext_dc4[7:4];
assign ldst_byteen_lo_dc4[3:0] = ldst_byteen_ext_dc4[3:0];
assign ldst_byteen_hi_dc5[3:0] = ldst_byteen_ext_dc5[7:4];
assign ldst_byteen_lo_dc5[3:0] = ldst_byteen_ext_dc5[3:0];
assign store_data_hi_dc3[31:0] = store_data_ext_dc3[63:32];
assign store_data_lo_dc3[31:0] = store_data_ext_dc3[31:0];
assign store_data_hi_dc4[31:0] = store_data_ext_dc4[63:32];
assign store_data_lo_dc4[31:0] = store_data_ext_dc4[31:0];
assign store_data_hi_dc5[31:0] = store_data_ext_dc5[63:32];
assign store_data_lo_dc5[31:0] = store_data_ext_dc5[31:0];
assign ld_addr_dc3hit_lo_lo = (lsu_addr_dc2[31:2] == lsu_addr_dc3[31:2]) & lsu_pkt_dc3.valid & lsu_pkt_dc3.store & lsu_busreq_dc2;
assign ld_addr_dc3hit_lo_hi = (end_addr_dc2[31:2] == lsu_addr_dc3[31:2]) & lsu_pkt_dc3.valid & lsu_pkt_dc3.store & lsu_busreq_dc2;
assign ld_addr_dc3hit_hi_lo = (lsu_addr_dc2[31:2] == end_addr_dc3[31:2]) & lsu_pkt_dc3.valid & lsu_pkt_dc3.store & lsu_busreq_dc2;
assign ld_addr_dc3hit_hi_hi = (end_addr_dc2[31:2] == end_addr_dc3[31:2]) & lsu_pkt_dc3.valid & lsu_pkt_dc3.store & lsu_busreq_dc2;
assign ld_addr_dc4hit_lo_lo = (lsu_addr_dc2[31:2] == lsu_addr_dc4[31:2]) & lsu_pkt_dc4.valid & lsu_pkt_dc4.store & lsu_busreq_dc2;
assign ld_addr_dc4hit_lo_hi = (end_addr_dc2[31:2] == lsu_addr_dc4[31:2]) & lsu_pkt_dc4.valid & lsu_pkt_dc4.store & lsu_busreq_dc2;
assign ld_addr_dc4hit_hi_lo = (lsu_addr_dc2[31:2] == end_addr_dc4[31:2]) & lsu_pkt_dc4.valid & lsu_pkt_dc4.store & lsu_busreq_dc2;
assign ld_addr_dc4hit_hi_hi = (end_addr_dc2[31:2] == end_addr_dc4[31:2]) & lsu_pkt_dc4.valid & lsu_pkt_dc4.store & lsu_busreq_dc2;
assign ld_addr_dc5hit_lo_lo = (lsu_addr_dc2[31:2] == lsu_addr_dc5[31:2]) & lsu_pkt_dc5.valid & lsu_pkt_dc5.store & lsu_busreq_dc2;
assign ld_addr_dc5hit_lo_hi = (end_addr_dc2[31:2] == lsu_addr_dc5[31:2]) & lsu_pkt_dc5.valid & lsu_pkt_dc5.store & lsu_busreq_dc2;
assign ld_addr_dc5hit_hi_lo = (lsu_addr_dc2[31:2] == end_addr_dc5[31:2]) & lsu_pkt_dc5.valid & lsu_pkt_dc5.store & lsu_busreq_dc2;
assign ld_addr_dc5hit_hi_hi = (end_addr_dc2[31:2] == end_addr_dc5[31:2]) & lsu_pkt_dc5.valid & lsu_pkt_dc5.store & lsu_busreq_dc2;
for (genvar i=0; i<4; i++) begin
assign ld_byte_dc3hit_lo_lo[i] = ld_addr_dc3hit_lo_lo & ldst_byteen_lo_dc3[i] & ldst_byteen_lo_dc2[i];
assign ld_byte_dc3hit_lo_hi[i] = ld_addr_dc3hit_lo_hi & ldst_byteen_lo_dc3[i] & ldst_byteen_hi_dc2[i];
assign ld_byte_dc3hit_hi_lo[i] = ld_addr_dc3hit_hi_lo & ldst_byteen_hi_dc3[i] & ldst_byteen_lo_dc2[i];
assign ld_byte_dc3hit_hi_hi[i] = ld_addr_dc3hit_hi_hi & ldst_byteen_hi_dc3[i] & ldst_byteen_hi_dc2[i];
assign ld_byte_dc4hit_lo_lo[i] = ld_addr_dc4hit_lo_lo & ldst_byteen_lo_dc4[i] & ldst_byteen_lo_dc2[i];
assign ld_byte_dc4hit_lo_hi[i] = ld_addr_dc4hit_lo_hi & ldst_byteen_lo_dc4[i] & ldst_byteen_hi_dc2[i];
assign ld_byte_dc4hit_hi_lo[i] = ld_addr_dc4hit_hi_lo & ldst_byteen_hi_dc4[i] & ldst_byteen_lo_dc2[i];
assign ld_byte_dc4hit_hi_hi[i] = ld_addr_dc4hit_hi_hi & ldst_byteen_hi_dc4[i] & ldst_byteen_hi_dc2[i];
assign ld_byte_dc5hit_lo_lo[i] = ld_addr_dc5hit_lo_lo & ldst_byteen_lo_dc5[i] & ldst_byteen_lo_dc2[i];
assign ld_byte_dc5hit_lo_hi[i] = ld_addr_dc5hit_lo_hi & ldst_byteen_lo_dc5[i] & ldst_byteen_hi_dc2[i];
assign ld_byte_dc5hit_hi_lo[i] = ld_addr_dc5hit_hi_lo & ldst_byteen_hi_dc5[i] & ldst_byteen_lo_dc2[i];
assign ld_byte_dc5hit_hi_hi[i] = ld_addr_dc5hit_hi_hi & ldst_byteen_hi_dc5[i] & ldst_byteen_hi_dc2[i];
assign ld_byte_hit_lo[i] = ld_byte_dc3hit_lo_lo[i] | ld_byte_dc3hit_hi_lo[i] |
ld_byte_dc4hit_lo_lo[i] | ld_byte_dc4hit_hi_lo[i] |
ld_byte_dc5hit_lo_lo[i] | ld_byte_dc5hit_hi_lo[i] |
ld_byte_hit_buf_lo[i];
//ld_hit_rdbuf_lo;
assign ld_byte_hit_hi[i] = ld_byte_dc3hit_lo_hi[i] | ld_byte_dc3hit_hi_hi[i] |
ld_byte_dc4hit_lo_hi[i] | ld_byte_dc4hit_hi_hi[i] |
ld_byte_dc5hit_lo_hi[i] | ld_byte_dc5hit_hi_hi[i] |
ld_byte_hit_buf_hi[i];
//ld_hit_rdbuf_hi;
assign ld_byte_dc3hit_lo[i] = ld_byte_dc3hit_lo_lo[i] | ld_byte_dc3hit_hi_lo[i];
assign ld_byte_dc4hit_lo[i] = ld_byte_dc4hit_lo_lo[i] | ld_byte_dc4hit_hi_lo[i];
assign ld_byte_dc5hit_lo[i] = ld_byte_dc5hit_lo_lo[i] | ld_byte_dc5hit_hi_lo[i];
assign ld_byte_dc3hit_hi[i] = ld_byte_dc3hit_lo_hi[i] | ld_byte_dc3hit_hi_hi[i];
assign ld_byte_dc4hit_hi[i] = ld_byte_dc4hit_lo_hi[i] | ld_byte_dc4hit_hi_hi[i];
assign ld_byte_dc5hit_hi[i] = ld_byte_dc5hit_lo_hi[i] | ld_byte_dc5hit_hi_hi[i];
assign ld_fwddata_dc3pipe_lo[(8*i)+7:(8*i)] = ({8{ld_byte_dc3hit_lo_lo[i]}} & store_data_lo_dc3[(8*i)+7:(8*i)]) |
({8{ld_byte_dc3hit_hi_lo[i]}} & store_data_hi_dc3[(8*i)+7:(8*i)]);
assign ld_fwddata_dc4pipe_lo[(8*i)+7:(8*i)] = ({8{ld_byte_dc4hit_lo_lo[i]}} & store_data_lo_dc4[(8*i)+7:(8*i)]) |
({8{ld_byte_dc4hit_hi_lo[i]}} & store_data_hi_dc4[(8*i)+7:(8*i)]);
assign ld_fwddata_dc5pipe_lo[(8*i)+7:(8*i)] = ({8{ld_byte_dc5hit_lo_lo[i]}} & store_data_lo_dc5[(8*i)+7:(8*i)]) |
({8{ld_byte_dc5hit_hi_lo[i]}} & store_data_hi_dc5[(8*i)+7:(8*i)]);
assign ld_fwddata_dc3pipe_hi[(8*i)+7:(8*i)] = ({8{ld_byte_dc3hit_lo_hi[i]}} & store_data_lo_dc3[(8*i)+7:(8*i)]) |
({8{ld_byte_dc3hit_hi_hi[i]}} & store_data_hi_dc3[(8*i)+7:(8*i)]);
assign ld_fwddata_dc4pipe_hi[(8*i)+7:(8*i)] = ({8{ld_byte_dc4hit_lo_hi[i]}} & store_data_lo_dc4[(8*i)+7:(8*i)]) |
({8{ld_byte_dc4hit_hi_hi[i]}} & store_data_hi_dc4[(8*i)+7:(8*i)]);
assign ld_fwddata_dc5pipe_hi[(8*i)+7:(8*i)] = ({8{ld_byte_dc5hit_lo_hi[i]}} & store_data_lo_dc5[(8*i)+7:(8*i)]) |
({8{ld_byte_dc5hit_hi_hi[i]}} & store_data_hi_dc5[(8*i)+7:(8*i)]);
// Final muxing between dc3/dc4/dc5
assign ld_fwddata_lo[(8*i)+7:(8*i)] = ld_byte_dc3hit_lo[i] ? ld_fwddata_dc3pipe_lo[(8*i)+7:(8*i)] :
ld_byte_dc4hit_lo[i] ? ld_fwddata_dc4pipe_lo[(8*i)+7:(8*i)] :
ld_byte_dc5hit_lo[i] ? ld_fwddata_dc5pipe_lo[(8*i)+7:(8*i)] :
ld_fwddata_buf_lo[(8*i)+7:(8*i)];
assign ld_fwddata_hi[(8*i)+7:(8*i)] = ld_byte_dc3hit_hi[i] ? ld_fwddata_dc3pipe_hi[(8*i)+7:(8*i)] :
ld_byte_dc4hit_hi[i] ? ld_fwddata_dc4pipe_hi[(8*i)+7:(8*i)] :
ld_byte_dc5hit_hi[i] ? ld_fwddata_dc5pipe_hi[(8*i)+7:(8*i)] :
ld_fwddata_buf_hi[(8*i)+7:(8*i)];
end
always_comb begin
ld_full_hit_lo_dc2 = 1'b1;
ld_full_hit_hi_dc2 = 1'b1;
for (int i=0; i<4; i++) begin
ld_full_hit_lo_dc2 &= (ld_byte_hit_lo[i] | ~ldst_byteen_lo_dc2[i]);
ld_full_hit_hi_dc2 &= (ld_byte_hit_hi[i] | ~ldst_byteen_hi_dc2[i]);
end
end
// This will be high if atleast one byte hit the stores in pipe/write buffer (dc3/dc4/dc5/wrbuf)
assign ld_hit_dc2 = (|ld_byte_hit_lo[3:0]) | (|ld_byte_hit_hi[3:0]);
// This will be high if all the bytes of load hit the stores in pipe/write buffer (dc3/dc4/dc5/wrbuf)
assign ld_full_hit_dc2 = ld_full_hit_lo_dc2 & ld_full_hit_hi_dc2 & lsu_busreq_dc2 & lsu_pkt_dc2.load & ~is_sideeffects_dc2;
assign {ld_fwddata_dc2_nc[63:32], ld_fwddata_dc2[31:0]} = {ld_fwddata_hi[31:0], ld_fwddata_lo[31:0]} >> (8*lsu_addr_dc2[1:0]);
assign bus_read_data_dc3[31:0] = ld_full_hit_dc3 ? ld_fwddata_dc3[31:0] : ld_bus_data_dc3[31:0];
// Fifo flops
rvdff #(.WIDTH(1)) lsu_full_hit_dc3ff (.din(ld_full_hit_dc2), .dout(ld_full_hit_dc3), .clk(lsu_freeze_c2_dc3_clk), .*);
rvdff #(.WIDTH(32)) lsu_fwddata_dc3ff (.din(ld_fwddata_dc2[31:0]), .dout(ld_fwddata_dc3[31:0]), .clk(lsu_c1_dc3_clk), .*);
rvdff #(.WIDTH(1)) clken_ff (.din(lsu_bus_clk_en), .dout(lsu_bus_clk_en_q), .clk(free_clk), .*);
rvdff #(.WIDTH(1)) ldst_dual_dc2ff (.din(ldst_dual_dc1), .dout(ldst_dual_dc2), .clk(lsu_freeze_c1_dc2_clk), .*);
rvdff #(.WIDTH(1)) ldst_dual_dc3ff (.din(ldst_dual_dc2), .dout(ldst_dual_dc3), .clk(lsu_freeze_c1_dc3_clk), .*);
rvdff #(.WIDTH(1)) ldst_dual_dc4ff (.din(ldst_dual_dc3), .dout(ldst_dual_dc4), .clk(lsu_c1_dc4_clk), .*);
rvdff #(.WIDTH(1)) ldst_dual_dc5ff (.din(ldst_dual_dc4), .dout(ldst_dual_dc5), .clk(lsu_c1_dc5_clk), .*);
rvdff #(.WIDTH(1)) is_sideeffects_dc4ff (.din(is_sideeffects_dc3), .dout(is_sideeffects_dc4), .clk(lsu_c1_dc4_clk), .*);
rvdff #(.WIDTH(1)) is_sideeffects_dc5ff (.din(is_sideeffects_dc4), .dout(is_sideeffects_dc5), .clk(lsu_c1_dc5_clk), .*);
rvdff #(4) lsu_byten_dc3ff (.*, .din(ldst_byteen_dc2[3:0]), .dout(ldst_byteen_dc3[3:0]), .clk(lsu_freeze_c1_dc3_clk));
rvdff #(4) lsu_byten_dc4ff (.*, .din(ldst_byteen_dc3[3:0]), .dout(ldst_byteen_dc4[3:0]), .clk(lsu_c1_dc4_clk));
rvdff #(4) lsu_byten_dc5ff (.*, .din(ldst_byteen_dc4[3:0]), .dout(ldst_byteen_dc5[3:0]), .clk(lsu_c1_dc5_clk));
`ifdef ASSERT_ON
// Assertion to check ld imprecise error comes with right address
// property lsu_ld_imprecise_error_check;
// @(posedge clk) disable iff (~rst_l) lsu_imprecise_error_load_any |-> (lsu_imprecise_error_addr_any[31:0] == ld_imprecise_bus_error_addr[31:0]);
// endproperty
// assert_ld_imprecise_error_check: assert property (lsu_ld_imprecise_error_check) else
// $display("Wrong imprecise error address when lsu_imprecise_error_load_any asserted");
// // Assertion to check st imprecise error comes with right address
// property lsu_st_imprecise_error_check;
// @(posedge clk) disable iff (~rst_l) lsu_imprecise_error_store_any |-> (lsu_imprecise_error_addr_any[31:0] == store_bus_error_addr[31:0]);
// endproperty
// assert_st_imprecise_error_check: assert property (lsu_st_imprecise_error_check) else
// $display("Wrong imprecise error address when lsu_imprecise_error_store_any asserted");
`endif
endmodule // lsu_bus_intf

210
design/lsu/lsu_clkdomain.sv Normal file
View File

@ -0,0 +1,210 @@
// 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.
//********************************************************************************
// $Id$
//
//
// Owner:
// Function: Clock Generation Block
// Comments: All the clocks are generate here
//
// //********************************************************************************
module lsu_clkdomain
import swerv_types::*;
(
input logic clk, // clock
input logic free_clk, // clock
input logic rst_l, // reset
// Inputs
input logic clk_override, // chciken bit to turn off clock gating
input logic lsu_freeze_dc3, // freeze
input logic addr_in_dccm_dc2, // address in dccm
input logic addr_in_pic_dc2, // address is in pic
input logic dma_dccm_req, // dma is active
input logic dma_mem_write, // dma write is active
input logic load_stbuf_reqvld_dc3, // instruction to stbuf
input logic store_stbuf_reqvld_dc3, // instruction to stbuf
input logic stbuf_reqvld_any, // stbuf is draining
input logic stbuf_reqvld_flushed_any, // instruction going to stbuf is flushed
input logic lsu_busreq_dc5, // busreq in dc5
input logic lsu_bus_buffer_pend_any, // bus buffer has a pending bus entry
input logic lsu_bus_buffer_empty_any, // external bus buffer is empty
input logic lsu_stbuf_empty_any, // stbuf is empty
//input logic lsu_load_stall_any, // Need to turn on clocks for this case
input logic lsu_bus_clk_en, // bus clock enable
input lsu_pkt_t lsu_p, // lsu packet in decode
input lsu_pkt_t lsu_pkt_dc1, // lsu packet in dc1
input lsu_pkt_t lsu_pkt_dc2, // lsu packet in dc2
input lsu_pkt_t lsu_pkt_dc3, // lsu packet in dc3
input lsu_pkt_t lsu_pkt_dc4, // lsu packet in dc4
input lsu_pkt_t lsu_pkt_dc5, // lsu packet in dc5
// Outputs
output logic lsu_c1_dc3_clk, // dc3 pipe single pulse clock
output logic lsu_c1_dc4_clk, // dc4 pipe single pulse clock
output logic lsu_c1_dc5_clk, // dc5 pipe single pulse clock
output logic lsu_c2_dc3_clk, // dc3 pipe double pulse clock
output logic lsu_c2_dc4_clk, // dc4 pipe double pulse clock
output logic lsu_c2_dc5_clk, // dc5 pipe double pulse clock
output logic lsu_store_c1_dc1_clk, // store in dc1
output logic lsu_store_c1_dc2_clk, // store in dc2
output logic lsu_store_c1_dc3_clk, // store in dc3
output logic lsu_store_c1_dc4_clk, // store in dc4
output logic lsu_store_c1_dc5_clk, // store in dc5
output logic lsu_freeze_c1_dc1_clk, // freeze
output logic lsu_freeze_c1_dc2_clk, // freeze
output logic lsu_freeze_c1_dc3_clk, // freeze
output logic lsu_freeze_c2_dc1_clk,
output logic lsu_freeze_c2_dc2_clk,
output logic lsu_freeze_c2_dc3_clk,
output logic lsu_freeze_c2_dc4_clk,
output logic lsu_dccm_c1_dc3_clk, // dccm clock
output logic lsu_pic_c1_dc3_clk, // pic clock
output logic lsu_stbuf_c1_clk,
output logic lsu_bus_obuf_c1_clk, // ibuf clock
output logic lsu_bus_ibuf_c1_clk, // ibuf clock
output logic lsu_bus_buf_c1_clk, // ibuf clock
output logic lsu_busm_clk, // bus clock
output logic lsu_free_c2_clk,
input logic scan_mode
);
logic lsu_c1_dc1_clken, lsu_c1_dc2_clken, lsu_c1_dc3_clken, lsu_c1_dc4_clken, lsu_c1_dc5_clken;
logic lsu_c2_dc3_clken, lsu_c2_dc4_clken, lsu_c2_dc5_clken;
logic lsu_c1_dc1_clken_q, lsu_c1_dc2_clken_q, lsu_c1_dc3_clken_q, lsu_c1_dc4_clken_q, lsu_c1_dc5_clken_q;
logic lsu_store_c1_dc1_clken, lsu_store_c1_dc2_clken, lsu_store_c1_dc3_clken, lsu_store_c1_dc4_clken, lsu_store_c1_dc5_clken;
logic lsu_freeze_c1_dc1_clken, lsu_freeze_c1_dc2_clken, lsu_freeze_c1_dc3_clken, lsu_freeze_c1_dc4_clken;
logic lsu_freeze_c2_dc1_clken, lsu_freeze_c2_dc2_clken, lsu_freeze_c2_dc3_clken, lsu_freeze_c2_dc4_clken;
logic lsu_freeze_c1_dc1_clken_q, lsu_freeze_c1_dc2_clken_q, lsu_freeze_c1_dc3_clken_q, lsu_freeze_c1_dc4_clken_q;
logic lsu_stbuf_c1_clken;
logic lsu_bus_ibuf_c1_clken, lsu_bus_obuf_c1_clken, lsu_bus_buf_c1_clken;
logic lsu_dccm_c1_dc3_clken, lsu_pic_c1_dc3_clken;
logic lsu_free_c1_clken, lsu_free_c1_clken_q, lsu_free_c2_clken;
logic lsu_bus_valid_clken;
//-------------------------------------------------------------------------------------------
// Clock Enable logic
//-------------------------------------------------------------------------------------------
// Also use the flopped clock enable. We want to turn on the clocks from dc1->dc5 even if there is a freeze
assign lsu_c1_dc1_clken = lsu_p.valid | dma_dccm_req | clk_override;
assign lsu_c1_dc2_clken = lsu_pkt_dc1.valid | lsu_c1_dc1_clken_q | clk_override;
assign lsu_c1_dc3_clken = lsu_pkt_dc2.valid | lsu_c1_dc2_clken_q | clk_override;
assign lsu_c1_dc4_clken = lsu_pkt_dc3.valid | lsu_c1_dc3_clken_q | clk_override;
assign lsu_c1_dc5_clken = lsu_pkt_dc4.valid | lsu_c1_dc4_clken_q | clk_override;
assign lsu_c2_dc3_clken = lsu_c1_dc3_clken | lsu_c1_dc3_clken_q | clk_override;
assign lsu_c2_dc4_clken = lsu_c1_dc4_clken | lsu_c1_dc4_clken_q | clk_override;
assign lsu_c2_dc5_clken = lsu_c1_dc5_clken | lsu_c1_dc5_clken_q | clk_override;
assign lsu_store_c1_dc1_clken = ((lsu_c1_dc1_clken & (lsu_p.store | dma_mem_write)) | clk_override) & ~lsu_freeze_dc3;
assign lsu_store_c1_dc2_clken = ((lsu_c1_dc2_clken & lsu_pkt_dc1.store) | clk_override) & ~lsu_freeze_dc3;
assign lsu_store_c1_dc3_clken = ((lsu_c1_dc3_clken & lsu_pkt_dc2.store) | clk_override) & ~lsu_freeze_dc3;
assign lsu_store_c1_dc4_clken = (lsu_c1_dc4_clken & lsu_pkt_dc3.store) | clk_override;
assign lsu_store_c1_dc5_clken = (lsu_c1_dc5_clken & lsu_pkt_dc4.store) | clk_override;
assign lsu_freeze_c1_dc1_clken = (lsu_p.valid | dma_dccm_req | clk_override) & ~lsu_freeze_dc3;
assign lsu_freeze_c1_dc2_clken = (lsu_pkt_dc1.valid | clk_override) & ~lsu_freeze_dc3;
assign lsu_freeze_c1_dc3_clken = (lsu_pkt_dc2.valid | clk_override) & ~lsu_freeze_dc3;
assign lsu_freeze_c1_dc4_clken = (lsu_pkt_dc3.valid | clk_override) & ~lsu_freeze_dc3;
assign lsu_freeze_c2_dc1_clken = (lsu_freeze_c1_dc1_clken | lsu_freeze_c1_dc1_clken_q | clk_override) & ~lsu_freeze_dc3;
assign lsu_freeze_c2_dc2_clken = (lsu_freeze_c1_dc2_clken | lsu_freeze_c1_dc2_clken_q | clk_override) & ~lsu_freeze_dc3;
assign lsu_freeze_c2_dc3_clken = (lsu_freeze_c1_dc3_clken | lsu_freeze_c1_dc3_clken_q | clk_override) & ~lsu_freeze_dc3;
assign lsu_freeze_c2_dc4_clken = (lsu_freeze_c1_dc4_clken | lsu_freeze_c1_dc4_clken_q | clk_override) & ~lsu_freeze_dc3;
assign lsu_stbuf_c1_clken = load_stbuf_reqvld_dc3 | store_stbuf_reqvld_dc3 | stbuf_reqvld_any | stbuf_reqvld_flushed_any | clk_override;
assign lsu_bus_ibuf_c1_clken = lsu_busreq_dc5 | clk_override;
assign lsu_bus_obuf_c1_clken = ((lsu_bus_buffer_pend_any | lsu_busreq_dc5) & lsu_bus_clk_en) | clk_override;
assign lsu_bus_buf_c1_clken = ~lsu_bus_buffer_empty_any | lsu_busreq_dc5 | clk_override;
assign lsu_dccm_c1_dc3_clken = ((lsu_c1_dc3_clken & addr_in_dccm_dc2) | clk_override) & ~lsu_freeze_dc3;
assign lsu_pic_c1_dc3_clken = ((lsu_c1_dc3_clken & addr_in_pic_dc2) | clk_override) & ~lsu_freeze_dc3;
assign lsu_free_c1_clken = (lsu_p.valid | lsu_pkt_dc1.valid | lsu_pkt_dc2.valid | lsu_pkt_dc3.valid | lsu_pkt_dc4.valid | lsu_pkt_dc5.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_c1_dc1_clkenff (.din(lsu_c1_dc1_clken), .dout(lsu_c1_dc1_clken_q), .clk(lsu_free_c2_clk), .*);
rvdff #(1) lsu_c1_dc2_clkenff (.din(lsu_c1_dc2_clken), .dout(lsu_c1_dc2_clken_q), .clk(lsu_free_c2_clk), .*);
rvdff #(1) lsu_c1_dc3_clkenff (.din(lsu_c1_dc3_clken), .dout(lsu_c1_dc3_clken_q), .clk(lsu_free_c2_clk), .*);
rvdff #(1) lsu_c1_dc4_clkenff (.din(lsu_c1_dc4_clken), .dout(lsu_c1_dc4_clken_q), .clk(lsu_free_c2_clk), .*);
rvdff #(1) lsu_c1_dc5_clkenff (.din(lsu_c1_dc5_clken), .dout(lsu_c1_dc5_clken_q), .clk(lsu_free_c2_clk), .*);
rvdff #(1) lsu_freeze_c1_dc1_clkenff (.din(lsu_freeze_c1_dc1_clken), .dout(lsu_freeze_c1_dc1_clken_q), .clk(lsu_freeze_c2_dc1_clk), .*);
rvdff #(1) lsu_freeze_c1_dc2_clkenff (.din(lsu_freeze_c1_dc2_clken), .dout(lsu_freeze_c1_dc2_clken_q), .clk(lsu_freeze_c2_dc2_clk), .*);
rvdff #(1) lsu_freeze_c1_dc3_clkenff (.din(lsu_freeze_c1_dc3_clken), .dout(lsu_freeze_c1_dc3_clken_q), .clk(lsu_freeze_c2_dc3_clk), .*);
rvdff #(1) lsu_freeze_c1_dc4_clkenff (.din(lsu_freeze_c1_dc4_clken), .dout(lsu_freeze_c1_dc4_clken_q), .clk(lsu_freeze_c2_dc4_clk), .*);
// Clock Headers
rvclkhdr lsu_c1dc3_cgc ( .en(lsu_c1_dc3_clken), .l1clk(lsu_c1_dc3_clk), .* );
rvclkhdr lsu_c1dc4_cgc ( .en(lsu_c1_dc4_clken), .l1clk(lsu_c1_dc4_clk), .* );
rvclkhdr lsu_c1dc5_cgc ( .en(lsu_c1_dc5_clken), .l1clk(lsu_c1_dc5_clk), .* );
rvclkhdr lsu_c2dc3_cgc ( .en(lsu_c2_dc3_clken), .l1clk(lsu_c2_dc3_clk), .* );
rvclkhdr lsu_c2dc4_cgc ( .en(lsu_c2_dc4_clken), .l1clk(lsu_c2_dc4_clk), .* );
rvclkhdr lsu_c2dc5_cgc ( .en(lsu_c2_dc5_clken), .l1clk(lsu_c2_dc5_clk), .* );
rvclkhdr lsu_store_c1dc1_cgc (.en(lsu_store_c1_dc1_clken), .l1clk(lsu_store_c1_dc1_clk), .*);
rvclkhdr lsu_store_c1dc2_cgc (.en(lsu_store_c1_dc2_clken), .l1clk(lsu_store_c1_dc2_clk), .*);
rvclkhdr lsu_store_c1dc3_cgc (.en(lsu_store_c1_dc3_clken), .l1clk(lsu_store_c1_dc3_clk), .*);
rvclkhdr lsu_store_c1dc4_cgc (.en(lsu_store_c1_dc4_clken), .l1clk(lsu_store_c1_dc4_clk), .*);
rvclkhdr lsu_store_c1dc5_cgc (.en(lsu_store_c1_dc5_clken), .l1clk(lsu_store_c1_dc5_clk), .*);
rvclkhdr lsu_freeze_c1dc1_cgc ( .en(lsu_freeze_c1_dc1_clken), .l1clk(lsu_freeze_c1_dc1_clk), .* );
rvclkhdr lsu_freeze_c1dc2_cgc ( .en(lsu_freeze_c1_dc2_clken), .l1clk(lsu_freeze_c1_dc2_clk), .* );
rvclkhdr lsu_freeze_c1dc3_cgc ( .en(lsu_freeze_c1_dc3_clken), .l1clk(lsu_freeze_c1_dc3_clk), .* );
rvclkhdr lsu_freeze_c2dc1_cgc ( .en(lsu_freeze_c2_dc1_clken), .l1clk(lsu_freeze_c2_dc1_clk), .* );
rvclkhdr lsu_freeze_c2dc2_cgc ( .en(lsu_freeze_c2_dc2_clken), .l1clk(lsu_freeze_c2_dc2_clk), .* );
rvclkhdr lsu_freeze_c2dc3_cgc ( .en(lsu_freeze_c2_dc3_clken), .l1clk(lsu_freeze_c2_dc3_clk), .* );
rvclkhdr lsu_freeze_c2dc4_cgc ( .en(lsu_freeze_c2_dc4_clken), .l1clk(lsu_freeze_c2_dc4_clk), .* );
rvclkhdr lsu_stbuf_c1_cgc ( .en(lsu_stbuf_c1_clken), .l1clk(lsu_stbuf_c1_clk), .* );
rvclkhdr 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), .* );
rvclkhdr 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), .*);
rvclkhdr lsu_dccm_c1dc3_cgc (.en(lsu_dccm_c1_dc3_clken), .l1clk(lsu_dccm_c1_dc3_clk), .*);
rvclkhdr lsu_pic_c1dc3_cgc (.en(lsu_pic_c1_dc3_clken), .l1clk(lsu_pic_c1_dc3_clk), .*);
rvclkhdr lsu_free_cgc (.en(lsu_free_c2_clken), .l1clk(lsu_free_c2_clk), .*);
endmodule

197
design/lsu/lsu_dccm_ctl.sv Normal file
View File

@ -0,0 +1,197 @@
// 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.
//********************************************************************************
// $Id$
//
//
// Owner:
// Function: DCCM for LSU pipe
// Comments: Single ported memory
//
//
// DC1 -> DC2 -> DC3 -> DC4 (Commit)
//
// //********************************************************************************
module lsu_dccm_ctl
import swerv_types::*;
(
input logic lsu_freeze_c2_dc2_clk, // clocks
input logic lsu_freeze_c2_dc3_clk,
input logic lsu_dccm_c1_dc3_clk,
input logic lsu_pic_c1_dc3_clk,
input logic rst_l,
input logic lsu_freeze_dc3, // freze
input lsu_pkt_t lsu_pkt_dc3, // lsu packets
input lsu_pkt_t lsu_pkt_dc1,
input logic addr_in_dccm_dc1, // address maps to dccm
input logic addr_in_pic_dc1, // address maps to pic
input logic addr_in_pic_dc3, // address maps to pic
input logic [31:0] lsu_addr_dc1, // starting byte address for loads
input logic [`RV_DCCM_BITS-1:0] end_addr_dc1, // last address used to calculate unaligned
input logic [`RV_DCCM_BITS-1:0] lsu_addr_dc3, // starting byte address for loads
input logic stbuf_reqvld_any, // write enable
input logic stbuf_addr_in_pic_any, // stbuf is going to pic
input logic [`RV_LSU_SB_BITS-1:0] stbuf_addr_any, // stbuf address (aligned)
input logic [`RV_DCCM_DATA_WIDTH-1:0] stbuf_data_any, // the read out from stbuf
input logic [`RV_DCCM_ECC_WIDTH-1:0] stbuf_ecc_any, // the encoded data with ECC bits
input logic [`RV_DCCM_DATA_WIDTH-1:0] stbuf_fwddata_hi_dc3, // stbuf fowarding to load
input logic [`RV_DCCM_DATA_WIDTH-1:0] stbuf_fwddata_lo_dc3, // stbuf fowarding to load
input logic [`RV_DCCM_BYTE_WIDTH-1:0] stbuf_fwdbyteen_hi_dc3, // stbuf fowarding to load
input logic [`RV_DCCM_BYTE_WIDTH-1:0] stbuf_fwdbyteen_lo_dc3, // stbuf fowarding to load
input logic lsu_double_ecc_error_dc3, // lsu has a DED
input logic [`RV_DCCM_DATA_WIDTH-1:0] store_ecc_datafn_hi_dc3, // store data
input logic [`RV_DCCM_DATA_WIDTH-1:0] store_ecc_datafn_lo_dc3, // store data
output logic [`RV_DCCM_DATA_WIDTH-1:0] dccm_data_hi_dc3, // data from the dccm
output logic [`RV_DCCM_DATA_WIDTH-1:0] dccm_data_lo_dc3, // data from the dccm
output logic [`RV_DCCM_ECC_WIDTH-1:0] dccm_data_ecc_hi_dc3, // data from the dccm + ecc
output logic [`RV_DCCM_ECC_WIDTH-1:0] dccm_data_ecc_lo_dc3,
output logic [`RV_DCCM_DATA_WIDTH-1:0] lsu_ld_data_dc3, // right justified, ie load byte will have data at 7:0
output logic [`RV_DCCM_DATA_WIDTH-1:0] lsu_ld_data_corr_dc3, // right justified, ie load byte will have data at 7:0
output logic [31:0] picm_mask_data_dc3, // pic data to stbuf
output logic lsu_stbuf_commit_any, // stbuf wins the dccm port or is to pic
output logic lsu_dccm_rden_dc3, // dccm read
output logic dccm_dma_rvalid, // dccm serviving the dma load
output logic dccm_dma_ecc_error, // DMA load had ecc error
output logic [63:0] dccm_dma_rdata, // dccm data to dma request
// DCCM ports
output logic dccm_wren, // dccm interface -- write
output logic dccm_rden, // dccm interface -- write
output logic [`RV_DCCM_BITS-1:0] dccm_wr_addr, // dccm interface -- wr addr
output logic [`RV_DCCM_BITS-1:0] dccm_rd_addr_lo, // dccm interface -- read address for lo bank
output logic [`RV_DCCM_BITS-1:0] dccm_rd_addr_hi, // dccm interface -- read address for hi bank
output logic [`RV_DCCM_FDATA_WIDTH-1:0] dccm_wr_data, // dccm write data
input logic [`RV_DCCM_FDATA_WIDTH-1:0] dccm_rd_data_lo, // dccm read data back from the dccm
input logic [`RV_DCCM_FDATA_WIDTH-1:0] dccm_rd_data_hi, // dccm read data back from the dccm
// PIC ports
output logic picm_wren, // write to pic
output logic picm_rden, // read to pick
output logic picm_mken, // write to pic need a mask
output logic [31:0] picm_addr, // address for pic access - shared between reads and write
output logic [31:0] picm_wr_data, // write data
input logic [31:0] picm_rd_data, // read data
input logic scan_mode // scan mode
);
`include "global.h"
`ifdef RV_DCCM_ENABLE
localparam DCCM_ENABLE = 1'b1;
`else
localparam DCCM_ENABLE = 1'b0;
`endif
localparam DCCM_WIDTH_BITS = $clog2(DCCM_BYTE_WIDTH);
localparam PIC_BITS =`RV_PIC_BITS;
logic lsu_dccm_rden_dc1, lsu_dccm_rden_dc2;
logic [DCCM_DATA_WIDTH-1:0] dccm_data_hi_dc2, dccm_data_lo_dc2;
logic [DCCM_ECC_WIDTH-1:0] dccm_data_ecc_hi_dc2, dccm_data_ecc_lo_dc2;
logic [63:0] dccm_dout_dc3, dccm_corr_dout_dc3;
logic [63:0] stbuf_fwddata_dc3;
logic [7:0] stbuf_fwdbyteen_dc3;
logic [63:0] lsu_rdata_dc3, lsu_rdata_corr_dc3;
logic [63:0] picm_rd_data_dc3;
logic [31:0] picm_rd_data_lo_dc3;
logic [63:32] lsu_ld_data_dc3_nc, lsu_ld_data_corr_dc3_nc;
assign dccm_dma_rvalid = lsu_pkt_dc3.valid & lsu_pkt_dc3.load & lsu_pkt_dc3.dma;
assign dccm_dma_ecc_error = lsu_double_ecc_error_dc3;
assign dccm_dma_rdata[63:0] = lsu_rdata_corr_dc3[63:0];
assign {lsu_ld_data_dc3_nc[63:32], lsu_ld_data_dc3[31:0]} = lsu_rdata_dc3[63:0] >> 8*lsu_addr_dc3[1:0];
assign {lsu_ld_data_corr_dc3_nc[63:32], lsu_ld_data_corr_dc3[31:0]} = lsu_rdata_corr_dc3[63:0] >> 8*lsu_addr_dc3[1:0];
assign dccm_dout_dc3[63:0] = {dccm_data_hi_dc3[DCCM_DATA_WIDTH-1:0], dccm_data_lo_dc3[DCCM_DATA_WIDTH-1:0]};
assign dccm_corr_dout_dc3[63:0] = {store_ecc_datafn_hi_dc3[DCCM_DATA_WIDTH-1:0], store_ecc_datafn_lo_dc3[DCCM_DATA_WIDTH-1:0]};
assign stbuf_fwddata_dc3[63:0] = {stbuf_fwddata_hi_dc3[DCCM_DATA_WIDTH-1:0], stbuf_fwddata_lo_dc3[DCCM_DATA_WIDTH-1:0]};
assign stbuf_fwdbyteen_dc3[7:0] = {stbuf_fwdbyteen_hi_dc3[DCCM_BYTE_WIDTH-1:0], stbuf_fwdbyteen_lo_dc3[DCCM_BYTE_WIDTH-1:0]};
for (genvar i=0; i<8; i++) begin: GenLoop
assign lsu_rdata_dc3[(8*i)+7:8*i] = stbuf_fwdbyteen_dc3[i] ? stbuf_fwddata_dc3[(8*i)+7:8*i] :
(addr_in_pic_dc3 ? picm_rd_data_dc3[(8*i)+7:8*i] : dccm_dout_dc3[(8*i)+7:8*i]);
assign lsu_rdata_corr_dc3[(8*i)+7:8*i] = stbuf_fwdbyteen_dc3[i] ? stbuf_fwddata_dc3[(8*i)+7:8*i] :
(addr_in_pic_dc3 ? picm_rd_data_dc3[(8*i)+7:8*i] : dccm_corr_dout_dc3[(8*i)+7:8*i]);
end
assign lsu_stbuf_commit_any = stbuf_reqvld_any & ~lsu_freeze_dc3 & (
(~(lsu_dccm_rden_dc1 | picm_rden | picm_mken)) |
((picm_rden | picm_mken) & ~stbuf_addr_in_pic_any) |
(lsu_dccm_rden_dc1 & (stbuf_addr_in_pic_any | (~((stbuf_addr_any[DCCM_WIDTH_BITS+:DCCM_BANK_BITS] == lsu_addr_dc1[DCCM_WIDTH_BITS+:DCCM_BANK_BITS]) |
(stbuf_addr_any[DCCM_WIDTH_BITS+:DCCM_BANK_BITS] == end_addr_dc1[DCCM_WIDTH_BITS+:DCCM_BANK_BITS]))))));
// No need to read for aligned word/dword stores since ECC will come by new data completely
assign lsu_dccm_rden_dc1 = lsu_pkt_dc1.valid & (lsu_pkt_dc1.load | (lsu_pkt_dc1.store & (~(lsu_pkt_dc1.word | lsu_pkt_dc1.dword) | (lsu_addr_dc1[1:0] != 2'b0)))) & addr_in_dccm_dc1;
// DCCM inputs
assign dccm_wren = lsu_stbuf_commit_any & ~stbuf_addr_in_pic_any;
assign dccm_rden = lsu_dccm_rden_dc1 & addr_in_dccm_dc1;
assign dccm_wr_addr[DCCM_BITS-1:0] = stbuf_addr_any[DCCM_BITS-1:0];
assign dccm_rd_addr_lo[DCCM_BITS-1:0] = lsu_addr_dc1[DCCM_BITS-1:0];
assign dccm_rd_addr_hi[DCCM_BITS-1:0] = end_addr_dc1[DCCM_BITS-1:0];
assign dccm_wr_data[DCCM_FDATA_WIDTH-1:0] = {stbuf_ecc_any[DCCM_ECC_WIDTH-1:0],stbuf_data_any[DCCM_DATA_WIDTH-1:0]};
// DCCM outputs
assign dccm_data_lo_dc2[DCCM_DATA_WIDTH-1:0] = dccm_rd_data_lo[DCCM_DATA_WIDTH-1:0];
assign dccm_data_hi_dc2[DCCM_DATA_WIDTH-1:0] = dccm_rd_data_hi[DCCM_DATA_WIDTH-1:0];
assign dccm_data_ecc_lo_dc2[DCCM_ECC_WIDTH-1:0] = dccm_rd_data_lo[DCCM_FDATA_WIDTH-1:DCCM_DATA_WIDTH];
assign dccm_data_ecc_hi_dc2[DCCM_ECC_WIDTH-1:0] = dccm_rd_data_hi[DCCM_FDATA_WIDTH-1:DCCM_DATA_WIDTH];
// PIC signals. PIC ignores the lower 2 bits of address since PIC memory registers are 32-bits
assign picm_wren = lsu_stbuf_commit_any & stbuf_addr_in_pic_any;
assign picm_rden = lsu_pkt_dc1.valid & lsu_pkt_dc1.load & addr_in_pic_dc1;
assign picm_mken = lsu_pkt_dc1.valid & lsu_pkt_dc1.store & addr_in_pic_dc1; // Get the mask for stores
assign picm_addr[31:0] = (picm_rden | picm_mken) ? (`RV_PIC_BASE_ADDR | {17'b0,lsu_addr_dc1[14:0]}) : (`RV_PIC_BASE_ADDR | {{32-PIC_BITS{1'b0}},stbuf_addr_any[`RV_PIC_BITS-1:0]});
//assign picm_addr[31:0] = (picm_rden | picm_mken) ? {`RV_PIC_REGION,`RV_PIC_OFFSET,3'b0,lsu_addr_dc1[14:0]} : {`RV_PIC_REGION,`RV_PIC_OFFSET,{18-PIC_BITS{1'b0}},stbuf_addr_any[`RV_PIC_BITS-1:0]};
assign picm_wr_data[31:0] = stbuf_data_any[31:0];
// Flops
assign picm_mask_data_dc3[31:0] = picm_rd_data_lo_dc3[31:0];
assign picm_rd_data_dc3[63:0] = {picm_rd_data_lo_dc3[31:0], picm_rd_data_lo_dc3[31:0]} ;
rvdff #(32) picm_data_ff (.*, .din(picm_rd_data[31:0]), .dout(picm_rd_data_lo_dc3[31:0]), .clk(lsu_pic_c1_dc3_clk));
if (DCCM_ENABLE == 1) begin: Gen_dccm_enable
rvdff #(1) dccm_rden_dc2ff (.*, .din(lsu_dccm_rden_dc1), .dout(lsu_dccm_rden_dc2), .clk(lsu_freeze_c2_dc2_clk));
rvdff #(1) dccm_rden_dc3ff (.*, .din(lsu_dccm_rden_dc2), .dout(lsu_dccm_rden_dc3), .clk(lsu_freeze_c2_dc3_clk));
rvdff #(DCCM_DATA_WIDTH) dccm_data_hi_ff (.*, .din(dccm_data_hi_dc2[DCCM_DATA_WIDTH-1:0]), .dout(dccm_data_hi_dc3[DCCM_DATA_WIDTH-1:0]), .clk(lsu_dccm_c1_dc3_clk));
rvdff #(DCCM_DATA_WIDTH) dccm_data_lo_ff (.*, .din(dccm_data_lo_dc2[DCCM_DATA_WIDTH-1:0]), .dout(dccm_data_lo_dc3[DCCM_DATA_WIDTH-1:0]), .clk(lsu_dccm_c1_dc3_clk));
rvdff #(DCCM_ECC_WIDTH) dccm_data_ecc_hi_ff (.*, .din(dccm_data_ecc_hi_dc2[DCCM_ECC_WIDTH-1:0]), .dout(dccm_data_ecc_hi_dc3[DCCM_ECC_WIDTH-1:0]), .clk(lsu_dccm_c1_dc3_clk));
rvdff #(DCCM_ECC_WIDTH) dccm_data_ecc_lo_ff (.*, .din(dccm_data_ecc_lo_dc2[DCCM_ECC_WIDTH-1:0]), .dout(dccm_data_ecc_lo_dc3[DCCM_ECC_WIDTH-1:0]), .clk(lsu_dccm_c1_dc3_clk));
end else begin: Gen_dccm_disable
assign lsu_dccm_rden_dc2 = '0;
assign lsu_dccm_rden_dc3 = '0;
assign dccm_data_hi_dc3[DCCM_DATA_WIDTH-1:0] = '0;
assign dccm_data_lo_dc3[DCCM_DATA_WIDTH-1:0] = '0;
assign dccm_data_ecc_hi_dc3[DCCM_ECC_WIDTH-1:0] = '0;
assign dccm_data_ecc_lo_dc3[DCCM_ECC_WIDTH-1:0] = '0;
end
endmodule

127
design/lsu/lsu_dccm_mem.sv Normal file
View File

@ -0,0 +1,127 @@
// 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.
//********************************************************************************
// $Id$
//
//
// Owner:
// Function: DCCM for LSU pipe
// Comments: Single ported memory
//
//
// DC1 -> DC2 -> DC3 -> DC4 (Commit)
//
// //********************************************************************************
module lsu_dccm_mem
import swerv_types::*;
(
input logic clk, // clock
input logic rst_l,
input logic lsu_freeze_dc3, // freeze
input logic clk_override, // clock override
input logic dccm_wren, // write enable
input logic dccm_rden, // read enable
input logic [`RV_DCCM_BITS-1:0] dccm_wr_addr, // write address
input logic [`RV_DCCM_BITS-1:0] dccm_rd_addr_lo, // read address
input logic [`RV_DCCM_BITS-1:0] dccm_rd_addr_hi, // read address for the upper bank in case of a misaligned access
input logic [`RV_DCCM_FDATA_WIDTH-1:0] dccm_wr_data, // write data
output logic [`RV_DCCM_FDATA_WIDTH-1:0] dccm_rd_data_lo, // read data from the lo bank
output logic [`RV_DCCM_FDATA_WIDTH-1:0] dccm_rd_data_hi, // read data from the hi bank
input logic scan_mode
);
`include "global.h"
localparam DCCM_WIDTH_BITS = $clog2(DCCM_BYTE_WIDTH);
localparam DCCM_INDEX_BITS = (DCCM_BITS - DCCM_BANK_BITS - DCCM_WIDTH_BITS);
logic [DCCM_NUM_BANKS-1:0] wren_bank;
logic [DCCM_NUM_BANKS-1:0] rden_bank;
logic [DCCM_NUM_BANKS-1:0] [DCCM_BITS-1:(DCCM_BANK_BITS+2)] addr_bank;
logic [DCCM_BITS-1:(DCCM_BANK_BITS+DCCM_WIDTH_BITS)] rd_addr_even, rd_addr_odd;
logic rd_unaligned;
logic [DCCM_NUM_BANKS-1:0] [DCCM_FDATA_WIDTH-1:0] dccm_bank_dout;
logic [DCCM_FDATA_WIDTH-1:0] wrdata;
logic [DCCM_NUM_BANKS-1:0] wren_bank_q;
logic [DCCM_NUM_BANKS-1:0] rden_bank_q;
logic [DCCM_NUM_BANKS-1:0][DCCM_BITS-1:(DCCM_BANK_BITS+2)] addr_bank_q;
logic [DCCM_FDATA_WIDTH-1:0] dccm_wr_data_q;
logic [(DCCM_WIDTH_BITS+DCCM_BANK_BITS-1):DCCM_WIDTH_BITS] dccm_rd_addr_lo_q;
logic [(DCCM_WIDTH_BITS+DCCM_BANK_BITS-1):DCCM_WIDTH_BITS] dccm_rd_addr_hi_q;
logic [DCCM_NUM_BANKS-1:0] dccm_clk;
logic [DCCM_NUM_BANKS-1:0] dccm_clken;
assign rd_unaligned = (dccm_rd_addr_lo[DCCM_WIDTH_BITS+:DCCM_BANK_BITS] != dccm_rd_addr_hi[DCCM_WIDTH_BITS+:DCCM_BANK_BITS]);
// Align the read data
assign dccm_rd_data_lo[DCCM_FDATA_WIDTH-1:0] = dccm_bank_dout[dccm_rd_addr_lo_q[DCCM_WIDTH_BITS+:DCCM_BANK_BITS]][DCCM_FDATA_WIDTH-1:0];
assign dccm_rd_data_hi[DCCM_FDATA_WIDTH-1:0] = dccm_bank_dout[dccm_rd_addr_hi_q[DCCM_WIDTH_BITS+:DCCM_BANK_BITS]][DCCM_FDATA_WIDTH-1:0];
// Generate even/odd address
// assign rd_addr_even[(DCCM_BANK_BITS+DCCM_WIDTH_BITS)+:DCCM_INDEX_BITS] = dccm_rd_addr_lo[2] ? dccm_rd_addr_hi[(DCCM_BANK_BITS+DCCM_WIDTH_BITS)+:DCCM_INDEX_BITS] :
// dccm_rd_addr_lo[(DCCM_BANK_BITS+DCCM_WIDTH_BITS)+:DCCM_INDEX_BITS];
// assign rd_addr_odd[(DCCM_BANK_BITS+DCCM_WIDTH_BITS)+:DCCM_INDEX_BITS] = dccm_rd_addr_lo[2] ? dccm_rd_addr_lo[(DCCM_BANK_BITS+DCCM_WIDTH_BITS)+:DCCM_INDEX_BITS] :
// dccm_rd_addr_hi[(DCCM_BANK_BITS+DCCM_WIDTH_BITS)+:DCCM_INDEX_BITS];
// 8 Banks, 16KB each (2048 x 72)
for (genvar i=0; i<DCCM_NUM_BANKS; i++) begin: mem_bank
assign wren_bank[i] = dccm_wren & (dccm_wr_addr[2+:DCCM_BANK_BITS] == i);
assign rden_bank[i] = dccm_rden & ((dccm_rd_addr_hi[2+:DCCM_BANK_BITS] == i) | (dccm_rd_addr_lo[2+:DCCM_BANK_BITS] == i));
assign addr_bank[i][(DCCM_BANK_BITS+DCCM_WIDTH_BITS)+:DCCM_INDEX_BITS] = wren_bank[i] ? dccm_wr_addr[(DCCM_BANK_BITS+DCCM_WIDTH_BITS)+:DCCM_INDEX_BITS] :
(((dccm_rd_addr_hi[2+:DCCM_BANK_BITS] == i) & rd_unaligned) ?
dccm_rd_addr_hi[(DCCM_BANK_BITS+DCCM_WIDTH_BITS)+:DCCM_INDEX_BITS] :
dccm_rd_addr_lo[(DCCM_BANK_BITS+DCCM_WIDTH_BITS)+:DCCM_INDEX_BITS]);
// if (i%2 == 0) begin
// assign addr_bank[i][(DCCM_BANK_BITS+DCCM_WIDTH_BITS)+:DCCM_INDEX_BITS] = wren_bank[i] ? dccm_wr_addr[(DCCM_BANK_BITS+DCCM_WIDTH_BITS)+:DCCM_INDEX_BITS] :
// rd_addr_even[(DCCM_BANK_BITS+DCCM_WIDTH_BITS)+:DCCM_INDEX_BITS];
// end else begin
// assign addr_bank[i][(DCCM_BANK_BITS+DCCM_WIDTH_BITS)+:DCCM_INDEX_BITS] = wren_bank[i] ? dccm_wr_addr[(DCCM_BANK_BITS+DCCM_WIDTH_BITS)+:DCCM_INDEX_BITS] :
// rd_addr_odd[(DCCM_BANK_BITS+DCCM_WIDTH_BITS)+:DCCM_INDEX_BITS];
// end
// clock gating section
assign dccm_clken[i] = (wren_bank[i] | rden_bank[i] | clk_override) & ~lsu_freeze_dc3;
rvclkhdr lsu_dccm_cgc (.en(dccm_clken[i]), .l1clk(dccm_clk[i]), .*);
// end clock gating section
`RV_DCCM_DATA_CELL dccm_bank (
// Primary ports
.CLK(dccm_clk[i]),
.WE(wren_bank[i]),
.ADR(addr_bank[i]),
.D(dccm_wr_data[DCCM_FDATA_WIDTH-1:0]),
.Q(dccm_bank_dout[i][DCCM_FDATA_WIDTH-1:0])
);
end : mem_bank
// Flops
rvdffs #(DCCM_BANK_BITS) rd_addr_lo_ff (.*, .din(dccm_rd_addr_lo[DCCM_WIDTH_BITS+:DCCM_BANK_BITS]), .dout(dccm_rd_addr_lo_q[DCCM_WIDTH_BITS+:DCCM_BANK_BITS]), .en(~lsu_freeze_dc3));
rvdffs #(DCCM_BANK_BITS) rd_addr_hi_ff (.*, .din(dccm_rd_addr_hi[DCCM_WIDTH_BITS+:DCCM_BANK_BITS]), .dout(dccm_rd_addr_hi_q[DCCM_WIDTH_BITS+:DCCM_BANK_BITS]), .en(~lsu_freeze_dc3));
endmodule // lsu_dccm_mem

185
design/lsu/lsu_ecc.sv Normal file
View File

@ -0,0 +1,185 @@
// 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.
//********************************************************************************
// $Id$
//
//
// Owner:
// Function: Top level file for load store unit
// Comments:
//
//
// DC1 -> DC2 -> DC3 -> DC4 (Commit)
//
//********************************************************************************
module lsu_ecc
import swerv_types::*;
(
input logic lsu_c2_dc4_clk, // clocks
input logic lsu_c1_dc4_clk,
input logic lsu_c1_dc5_clk,
input logic clk,
input logic rst_l,
input lsu_pkt_t lsu_pkt_dc3, // packet in dc3
input logic lsu_dccm_rden_dc3, // dccm rden
input logic addr_in_dccm_dc3, // address in dccm
input logic [`RV_DCCM_BITS-1:0] lsu_addr_dc3, // start address
input logic [`RV_DCCM_BITS-1:0] end_addr_dc3, // end address
input logic [63:0] store_data_dc3, // store data
input logic [`RV_DCCM_DATA_WIDTH-1:0] stbuf_data_any,
input logic [`RV_DCCM_DATA_WIDTH-1:0] stbuf_fwddata_hi_dc3, // data forward from the store buffer
input logic [`RV_DCCM_DATA_WIDTH-1:0] stbuf_fwddata_lo_dc3, // data forward from the store buffer
input logic [`RV_DCCM_BYTE_WIDTH-1:0] stbuf_fwdbyteen_hi_dc3,// which bytes from the store buffer are on
input logic [`RV_DCCM_BYTE_WIDTH-1:0] stbuf_fwdbyteen_lo_dc3,// which bytes from the store buffer are on
input logic [`RV_DCCM_DATA_WIDTH-1:0] dccm_data_hi_dc3, // raw data from mem
input logic [`RV_DCCM_DATA_WIDTH-1:0] dccm_data_lo_dc3, // raw data from mem
input logic [`RV_DCCM_ECC_WIDTH-1:0] dccm_data_ecc_hi_dc3, // ecc read out from mem
input logic [`RV_DCCM_ECC_WIDTH-1:0] dccm_data_ecc_lo_dc3, // ecc read out from mem
input logic dec_tlu_core_ecc_disable, // disables the ecc computation and error flagging
output logic [`RV_DCCM_DATA_WIDTH-1:0] store_ecc_datafn_hi_dc3, // final store data either from stbuf or SEC DCCM readout
output logic [`RV_DCCM_DATA_WIDTH-1:0] store_ecc_datafn_lo_dc3,
output logic [`RV_DCCM_ECC_WIDTH-1:0] stbuf_ecc_any,
output logic single_ecc_error_hi_dc3, // sec detected
output logic single_ecc_error_lo_dc3, // sec detected on lower dccm bank
output logic lsu_single_ecc_error_dc3, // or of the 2
output logic lsu_double_ecc_error_dc3, // double error detected
input logic scan_mode
);
`include "global.h"
`ifdef RV_DCCM_ENABLE
localparam DCCM_ENABLE = 1'b1;
`else
localparam DCCM_ENABLE = 1'b0;
`endif
logic [DCCM_DATA_WIDTH-1:0] sec_data_hi_dc3;
logic [DCCM_DATA_WIDTH-1:0] sec_data_lo_dc3;
logic double_ecc_error_hi_dc3, double_ecc_error_lo_dc3;
logic ldst_dual_dc3;
logic is_ldst_dc3;
logic is_ldst_hi_dc3, is_ldst_lo_dc3;
logic [7:0] ldst_byteen_dc3;
logic [7:0] store_byteen_dc3;
logic [7:0] store_byteen_ext_dc3;
logic [DCCM_BYTE_WIDTH-1:0] store_byteen_hi_dc3, store_byteen_lo_dc3;
logic [163:0] store_data_ext_dc3;
logic [DCCM_DATA_WIDTH-1:0] store_data_hi_dc3, store_data_lo_dc3;
logic [6:0] ecc_out_hi_nc, ecc_out_lo_nc;
assign ldst_dual_dc3 = (lsu_addr_dc3[2] != end_addr_dc3[2]);
assign is_ldst_dc3 = lsu_pkt_dc3.valid & (lsu_pkt_dc3.load | lsu_pkt_dc3.store) & addr_in_dccm_dc3 & lsu_dccm_rden_dc3;
assign is_ldst_lo_dc3 = is_ldst_dc3 & ~dec_tlu_core_ecc_disable;
assign is_ldst_hi_dc3 = is_ldst_dc3 & ldst_dual_dc3 & ~dec_tlu_core_ecc_disable;
assign ldst_byteen_dc3[7:0] = ({8{lsu_pkt_dc3.by}} & 8'b0000_0001) |
({8{lsu_pkt_dc3.half}} & 8'b0000_0011) |
({8{lsu_pkt_dc3.word}} & 8'b0000_1111) |
({8{lsu_pkt_dc3.dword}} & 8'b1111_1111);
assign store_byteen_dc3[7:0] = ldst_byteen_dc3[7:0] & {8{lsu_pkt_dc3.store}};
assign store_byteen_ext_dc3[7:0] = store_byteen_dc3[7:0] << lsu_addr_dc3[1:0];
assign store_byteen_hi_dc3[DCCM_BYTE_WIDTH-1:0] = store_byteen_ext_dc3[7:4];
assign store_byteen_lo_dc3[DCCM_BYTE_WIDTH-1:0] = store_byteen_ext_dc3[3:0];
assign store_data_ext_dc3[63:0] = store_data_dc3[63:0] << {lsu_addr_dc3[1:0], 3'b000};
assign store_data_hi_dc3[DCCM_DATA_WIDTH-1:0] = store_data_ext_dc3[63:32];
assign store_data_lo_dc3[DCCM_DATA_WIDTH-1:0] = store_data_ext_dc3[31:0];
// Merge store data and sec data
// This is used for loads as well for ecc error case. store_byteen will be 0 for loads
for (genvar i=0; i<DCCM_BYTE_WIDTH; i++) begin
assign store_ecc_datafn_hi_dc3[(8*i)+7:(8*i)] = store_byteen_hi_dc3[i] ? store_data_hi_dc3[(8*i)+7:(8*i)] :
(stbuf_fwdbyteen_hi_dc3[i] ? stbuf_fwddata_hi_dc3[(8*i)+7:(8*i)] : sec_data_hi_dc3[(8*i)+7:(8*i)]);
assign store_ecc_datafn_lo_dc3[(8*i)+7:(8*i)] = store_byteen_lo_dc3[i] ? store_data_lo_dc3[(8*i)+7:(8*i)] :
(stbuf_fwdbyteen_lo_dc3[i] ? stbuf_fwddata_lo_dc3[(8*i)+7:(8*i)] : sec_data_lo_dc3[(8*i)+7:(8*i)]);
end
if (DCCM_ENABLE == 1) begin: Gen_dccm_enable
//Detect/Repair for Hi/Lo
rvecc_decode lsu_ecc_decode_hi (
// Inputs
.en(is_ldst_hi_dc3),
.sed_ded (1'b0), // 1 : means only detection
.din(dccm_data_hi_dc3[DCCM_DATA_WIDTH-1:0]),
.ecc_in(dccm_data_ecc_hi_dc3[DCCM_ECC_WIDTH-1:0]),
// Outputs
.dout(sec_data_hi_dc3[DCCM_DATA_WIDTH-1:0]),
.ecc_out (ecc_out_hi_nc[6:0]),
.single_ecc_error(single_ecc_error_hi_dc3),
.double_ecc_error(double_ecc_error_hi_dc3),
.*
);
rvecc_decode lsu_ecc_decode_lo (
// Inputs
.en(is_ldst_lo_dc3),
.sed_ded (1'b0), // 1 : means only detection
.din(dccm_data_lo_dc3[DCCM_DATA_WIDTH-1:0] ),
.ecc_in(dccm_data_ecc_lo_dc3[DCCM_ECC_WIDTH-1:0]),
// Outputs
.dout(sec_data_lo_dc3[DCCM_DATA_WIDTH-1:0]),
.ecc_out (ecc_out_lo_nc[6:0]),
.single_ecc_error(single_ecc_error_lo_dc3),
.double_ecc_error(double_ecc_error_lo_dc3),
.*
);
// Generate the ECC bits for store buffer drain
rvecc_encode lsu_ecc_encode (
//Inputs
.din(stbuf_data_any[DCCM_DATA_WIDTH-1:0]),
//Outputs
.ecc_out(stbuf_ecc_any[DCCM_ECC_WIDTH-1:0]),
.*
);
end else begin: Gen_dccm_disable // block: Gen_dccm_enable
assign sec_data_hi_dc3[DCCM_DATA_WIDTH-1:0] = '0;
assign sec_data_lo_dc3[DCCM_DATA_WIDTH-1:0] = '0;
assign single_ecc_error_hi_dc3 = '0;
assign double_ecc_error_hi_dc3 = '0;
assign single_ecc_error_lo_dc3 = '0;
assign double_ecc_error_lo_dc3 = '0;
assign stbuf_ecc_any[DCCM_ECC_WIDTH-1:0] = '0;
end
assign lsu_single_ecc_error_dc3 = single_ecc_error_hi_dc3 | single_ecc_error_lo_dc3;
assign lsu_double_ecc_error_dc3 = double_ecc_error_hi_dc3 | double_ecc_error_lo_dc3;
`ifdef ASSERT_ON
// ecc_check: assert property (@(posedge clk) ~(single_ecc_error_lo_dc3 | single_ecc_error_hi_dc3));
`endif
endmodule // lsu_ecc

329
design/lsu/lsu_lsc_ctl.sv Normal file
View File

@ -0,0 +1,329 @@
// 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.
//********************************************************************************
// $Id$
//
//
// Owner:
// Function: LSU control
// Comments:
//
//
// DC1 -> DC2 -> DC3 -> DC4 (Commit)
//
//********************************************************************************
module lsu_lsc_ctl
import swerv_types::*;
(
input logic rst_l,
// clocks per pipe
input logic lsu_c1_dc4_clk,
input logic lsu_c1_dc5_clk,
input logic lsu_c2_dc4_clk,
input logic lsu_c2_dc5_clk,
// freez clocks per pipe
input logic lsu_freeze_c1_dc1_clk,
input logic lsu_freeze_c1_dc2_clk,
input logic lsu_freeze_c1_dc3_clk,
input logic lsu_freeze_c2_dc1_clk,
input logic lsu_freeze_c2_dc2_clk,
input logic lsu_freeze_c2_dc3_clk,
input logic lsu_store_c1_dc1_clk,
input logic lsu_store_c1_dc2_clk,
input logic lsu_store_c1_dc3_clk,
input logic lsu_store_c1_dc4_clk,
input logic lsu_store_c1_dc5_clk,
input logic [31:0] i0_result_e4_eff,
input logic [31:0] i1_result_e4_eff,
input logic [31:0] i0_result_e2,
input logic ld_bus_error_dc3,
input logic [31:0] ld_bus_error_addr_dc3,
input logic lsu_single_ecc_error_dc3,
input logic lsu_double_ecc_error_dc3,
input logic lsu_freeze_dc3,
input logic lsu_i0_valid_dc3,
input logic flush_dc2_up,
input logic flush_dc3,
input logic flush_dc4,
input logic flush_dc5,
input logic [31:0] exu_lsu_rs1_d, // address
input logic [31:0] exu_lsu_rs2_d, // store data
input lsu_pkt_t lsu_p, // lsu control packet
input logic [11:0] dec_lsu_offset_d,
input logic [31:0] picm_mask_data_dc3,
input logic [31:0] lsu_ld_data_dc3,
input logic [31:0] lsu_ld_data_corr_dc3,
input logic [31:0] bus_read_data_dc3,
output logic [31:0] lsu_result_dc3,
output logic [31:0] lsu_result_corr_dc4, // This is the ECC corrected data going to RF
// lsu address down the pipe
output logic [31:0] lsu_addr_dc1,
output logic [31:0] lsu_addr_dc2,
output logic [31:0] lsu_addr_dc3,
output logic [31:0] lsu_addr_dc4,
output logic [31:0] lsu_addr_dc5,
// lsu address down the pipe - needed to check unaligned
output logic [31:0] end_addr_dc1,
output logic [31:0] end_addr_dc2,
output logic [31:0] end_addr_dc3,
output logic [31:0] end_addr_dc4,
output logic [31:0] end_addr_dc5,
// store data down the pipe
output logic [63:0] store_data_dc2,
output logic [63:0] store_data_dc3,
output logic [31:0] store_data_dc4,
output logic [31:0] store_data_dc5,
input logic [31:0] dec_tlu_mrac_ff,
output logic lsu_exc_dc2,
output lsu_error_pkt_t lsu_error_pkt_dc3,
output logic lsu_freeze_external_ints_dc3,
output logic is_sideeffects_dc2,
output logic is_sideeffects_dc3,
output logic lsu_commit_dc5,
// address in dccm/pic/external per pipe stage
output logic addr_in_dccm_dc1,
output logic addr_in_dccm_dc2,
output logic addr_in_dccm_dc3,
output logic addr_in_pic_dc1,
output logic addr_in_pic_dc2,
output logic addr_in_pic_dc3,
output logic addr_external_dc2,
output logic addr_external_dc3,
output logic addr_external_dc4,
output logic addr_external_dc5,
// DMA slave
input logic dma_dccm_req,
input logic [31:0] dma_mem_addr,
input logic [2:0] dma_mem_sz,
input logic dma_mem_write,
input logic [63:0] dma_mem_wdata,
// Store buffer related signals
output lsu_pkt_t lsu_pkt_dc1,
output lsu_pkt_t lsu_pkt_dc2,
output lsu_pkt_t lsu_pkt_dc3,
output lsu_pkt_t lsu_pkt_dc4,
output lsu_pkt_t lsu_pkt_dc5,
input logic scan_mode
);
`include "global.h"
logic [31:0] full_addr_dc1;
logic [31:0] full_end_addr_dc1;
logic [31:0] lsu_rs1_d;
logic [11:0] lsu_offset_d;
logic [31:0] rs1_dc1;
logic [11:0] offset_dc1;
logic [12:0] end_addr_offset_dc1;
logic [31:0] lsu_ld_datafn_dc3;
logic [31:0] lsu_ld_datafn_corr_dc3;
logic [31:0] lsu_result_corr_dc3;
logic [2:0] addr_offset_dc1;
logic [63:0] dma_mem_wdata_shifted;
logic addr_external_dc1;
logic access_fault_dc1, misaligned_fault_dc1;
logic access_fault_dc2, misaligned_fault_dc2;
logic access_fault_dc3, misaligned_fault_dc3;
logic [63:0] store_data_d;
logic [63:0] store_data_dc1;
logic [63:0] store_data_pre_dc2;
logic [63:0] store_data_pre_dc3;
logic [63:0] store_data_dc2_in;
logic [31:0] rs1_dc1_raw;
lsu_pkt_t dma_pkt_d;
lsu_pkt_t lsu_pkt_dc1_in, lsu_pkt_dc2_in, lsu_pkt_dc3_in, lsu_pkt_dc4_in, lsu_pkt_dc5_in;
// Premux the rs1/offset for dma
assign lsu_rs1_d[31:0] = dma_dccm_req ? dma_mem_addr[31:0] : exu_lsu_rs1_d[31:0];
assign lsu_offset_d[11:0] = dec_lsu_offset_d[11:0] & ~{12{dma_dccm_req}};
rvdff #(32) rs1ff (.*, .din(lsu_rs1_d[31:0]), .dout(rs1_dc1_raw[31:0]), .clk(lsu_freeze_c1_dc1_clk));
rvdff #(12) offsetff (.*, .din(lsu_offset_d[11:0]), .dout(offset_dc1[11:0]), .clk(lsu_freeze_c1_dc1_clk));
assign rs1_dc1[31:0] = (lsu_pkt_dc1.load_ldst_bypass_c1) ? lsu_result_dc3[31:0] : rs1_dc1_raw[31:0];
// generate the ls address
// need to refine this is memory is only 128KB
rvlsadder lsadder (.rs1(rs1_dc1[31:0]),
.offset(offset_dc1[11:0]),
.dout(full_addr_dc1[31:0])
);
// Module to generate the memory map of the address
lsu_addrcheck addrcheck (
.start_addr_dc1(full_addr_dc1[31:0]),
.end_addr_dc1(full_end_addr_dc1[31:0]),
.*
);
// Calculate start/end address for load/store
assign addr_offset_dc1[2:0] = ({3{lsu_pkt_dc1.half}} & 3'b01) | ({3{lsu_pkt_dc1.word}} & 3'b11) | ({3{lsu_pkt_dc1.dword}} & 3'b111);
assign end_addr_offset_dc1[12:0] = {offset_dc1[11],offset_dc1[11:0]} + {9'b0,addr_offset_dc1[2:0]};
assign full_end_addr_dc1[31:0] = rs1_dc1[31:0] + {{19{end_addr_offset_dc1[12]}},end_addr_offset_dc1[12:0]};
assign end_addr_dc1[31:0] = full_end_addr_dc1[31:0];
assign lsu_exc_dc2 = access_fault_dc2 | misaligned_fault_dc2;
assign lsu_freeze_external_ints_dc3 = lsu_freeze_dc3 & is_sideeffects_dc3;
// Generate exception packet
assign lsu_error_pkt_dc3.exc_valid = (access_fault_dc3 | misaligned_fault_dc3 | ld_bus_error_dc3 | lsu_double_ecc_error_dc3) & lsu_pkt_dc3.valid & ~lsu_pkt_dc3.dma & ~flush_dc3;
assign lsu_error_pkt_dc3.single_ecc_error = lsu_single_ecc_error_dc3;
assign lsu_error_pkt_dc3.inst_type = lsu_pkt_dc3.store;
assign lsu_error_pkt_dc3.dma_valid = lsu_pkt_dc3.dma;
assign lsu_error_pkt_dc3.inst_pipe = ~lsu_i0_valid_dc3;
assign lsu_error_pkt_dc3.exc_type = ~misaligned_fault_dc3;
// assign lsu_error_pkt_dc3.addr[31:0] = (access_fault_dc3 | misaligned_fault_dc3) ? lsu_addr_dc3[31:0] : ld_bus_error_addr_dc3[31:0];
assign lsu_error_pkt_dc3.addr[31:0] = lsu_addr_dc3[31:0];
//Create DMA packet
assign dma_pkt_d.valid = dma_dccm_req;
assign dma_pkt_d.dma = 1'b1;
assign dma_pkt_d.unsign = '0;
assign dma_pkt_d.store = dma_mem_write;
assign dma_pkt_d.load = ~dma_mem_write;
assign dma_pkt_d.by = (dma_mem_sz[2:0] == 3'b0);
assign dma_pkt_d.half = (dma_mem_sz[2:0] == 3'b1);
assign dma_pkt_d.word = (dma_mem_sz[2:0] == 3'b10);
assign dma_pkt_d.dword = (dma_mem_sz[2:0] == 3'b11);
assign dma_pkt_d.load_ldst_bypass_c1 = '0;
assign dma_pkt_d.store_data_bypass_c1 = '0;
assign dma_pkt_d.store_data_bypass_c2 = '0;
assign dma_pkt_d.store_data_bypass_i0_e2_c2 = '0;
assign dma_pkt_d.store_data_bypass_e4_c1 = '0;
assign dma_pkt_d.store_data_bypass_e4_c2 = '0;
assign dma_pkt_d.store_data_bypass_e4_c3 = '0;
always_comb begin
lsu_pkt_dc1_in = dma_dccm_req ? dma_pkt_d : lsu_p;
lsu_pkt_dc2_in = lsu_pkt_dc1;
lsu_pkt_dc3_in = lsu_pkt_dc2;
lsu_pkt_dc4_in = lsu_pkt_dc3;
lsu_pkt_dc5_in = lsu_pkt_dc4;
lsu_pkt_dc1_in.valid = (lsu_p.valid & ~flush_dc2_up) | dma_dccm_req;
lsu_pkt_dc2_in.valid = lsu_pkt_dc1.valid & ~(flush_dc2_up & ~lsu_pkt_dc1.dma);
lsu_pkt_dc3_in.valid = lsu_pkt_dc2.valid & ~(flush_dc2_up & ~lsu_pkt_dc2.dma);
lsu_pkt_dc4_in.valid = lsu_pkt_dc3.valid & ~(flush_dc3 & ~lsu_pkt_dc3.dma) & ~lsu_freeze_dc3;
lsu_pkt_dc5_in.valid = lsu_pkt_dc4.valid & ~(flush_dc4 & ~lsu_pkt_dc4.dma);
end
// C2 clock for valid and C1 for other bits of packet
rvdff #(1) lsu_pkt_vlddc1ff (.*, .din(lsu_pkt_dc1_in.valid), .dout(lsu_pkt_dc1.valid), .clk(lsu_freeze_c2_dc1_clk));
rvdff #(1) lsu_pkt_vlddc2ff (.*, .din(lsu_pkt_dc2_in.valid), .dout(lsu_pkt_dc2.valid), .clk(lsu_freeze_c2_dc2_clk));
rvdff #(1) lsu_pkt_vlddc3ff (.*, .din(lsu_pkt_dc3_in.valid), .dout(lsu_pkt_dc3.valid), .clk(lsu_freeze_c2_dc3_clk));
rvdff #(1) lsu_pkt_vlddc4ff (.*, .din(lsu_pkt_dc4_in.valid), .dout(lsu_pkt_dc4.valid), .clk(lsu_c2_dc4_clk));
rvdff #(1) lsu_pkt_vlddc5ff (.*, .din(lsu_pkt_dc5_in.valid), .dout(lsu_pkt_dc5.valid), .clk(lsu_c2_dc5_clk));
rvdff #($bits(lsu_pkt_t)-1) lsu_pkt_dc1ff (.*, .din(lsu_pkt_dc1_in[$bits(lsu_pkt_t)-1:1]), .dout(lsu_pkt_dc1[$bits(lsu_pkt_t)-1:1]), .clk(lsu_freeze_c1_dc1_clk));
rvdff #($bits(lsu_pkt_t)-1) lsu_pkt_dc2ff (.*, .din(lsu_pkt_dc2_in[$bits(lsu_pkt_t)-1:1]), .dout(lsu_pkt_dc2[$bits(lsu_pkt_t)-1:1]), .clk(lsu_freeze_c1_dc2_clk));
rvdff #($bits(lsu_pkt_t)-1) lsu_pkt_dc3ff (.*, .din(lsu_pkt_dc3_in[$bits(lsu_pkt_t)-1:1]), .dout(lsu_pkt_dc3[$bits(lsu_pkt_t)-1:1]), .clk(lsu_freeze_c1_dc3_clk));
rvdff #($bits(lsu_pkt_t)-1) lsu_pkt_dc4ff (.*, .din(lsu_pkt_dc4_in[$bits(lsu_pkt_t)-1:1]), .dout(lsu_pkt_dc4[$bits(lsu_pkt_t)-1:1]), .clk(lsu_c1_dc4_clk));
rvdff #($bits(lsu_pkt_t)-1) lsu_pkt_dc5ff (.*, .din(lsu_pkt_dc5_in[$bits(lsu_pkt_t)-1:1]), .dout(lsu_pkt_dc5[$bits(lsu_pkt_t)-1:1]), .clk(lsu_c1_dc5_clk));
assign lsu_ld_datafn_dc3[31:0] = addr_external_dc3 ? bus_read_data_dc3[31:0] : lsu_ld_data_dc3[31:0];
assign lsu_ld_datafn_corr_dc3[31:0] = addr_external_dc3 ? bus_read_data_dc3[31:0] : lsu_ld_data_corr_dc3[31:0];
// this result must look at prior stores and merge them in
assign lsu_result_dc3[31:0] = ({32{ lsu_pkt_dc3.unsign & lsu_pkt_dc3.by }} & {24'b0,lsu_ld_datafn_dc3[7:0]}) |
({32{ lsu_pkt_dc3.unsign & lsu_pkt_dc3.half}} & {16'b0,lsu_ld_datafn_dc3[15:0]}) |
({32{~lsu_pkt_dc3.unsign & lsu_pkt_dc3.by }} & {{24{ lsu_ld_datafn_dc3[7]}}, lsu_ld_datafn_dc3[7:0]}) |
({32{~lsu_pkt_dc3.unsign & lsu_pkt_dc3.half}} & {{16{ lsu_ld_datafn_dc3[15]}},lsu_ld_datafn_dc3[15:0]}) |
({32{lsu_pkt_dc3.word}} & lsu_ld_datafn_dc3[31:0]);
assign lsu_result_corr_dc3[31:0] = ({32{ lsu_pkt_dc3.unsign & lsu_pkt_dc3.by }} & {24'b0,lsu_ld_datafn_corr_dc3[7:0]}) |
({32{ lsu_pkt_dc3.unsign & lsu_pkt_dc3.half}} & {16'b0,lsu_ld_datafn_corr_dc3[15:0]}) |
({32{~lsu_pkt_dc3.unsign & lsu_pkt_dc3.by }} & {{24{ lsu_ld_datafn_corr_dc3[7]}}, lsu_ld_datafn_corr_dc3[7:0]}) |
({32{~lsu_pkt_dc3.unsign & lsu_pkt_dc3.half}} & {{16{ lsu_ld_datafn_corr_dc3[15]}},lsu_ld_datafn_corr_dc3[15:0]}) |
({32{lsu_pkt_dc3.word}} & lsu_ld_datafn_corr_dc3[31:0]);
// absence load/store all 0's
assign lsu_addr_dc1[31:0] = full_addr_dc1[31:0];
// Interrupt as a flush source allows the WB to occur
assign lsu_commit_dc5 = lsu_pkt_dc5.valid & (lsu_pkt_dc5.store | lsu_pkt_dc5.load) & ~flush_dc5 & ~lsu_pkt_dc5.dma;
assign dma_mem_wdata_shifted[63: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
assign store_data_d[63:0] = dma_dccm_req ? dma_mem_wdata_shifted[63:0] : {32'b0,exu_lsu_rs2_d[31:0]};
assign store_data_dc2_in[63:32] = store_data_dc1[63:32];
assign store_data_dc2_in[31:0] = (lsu_pkt_dc1.store_data_bypass_c1) ? lsu_result_dc3[31:0] :
(lsu_pkt_dc1.store_data_bypass_e4_c1[1]) ? i1_result_e4_eff[31:0] :
(lsu_pkt_dc1.store_data_bypass_e4_c1[0]) ? i0_result_e4_eff[31:0] : store_data_dc1[31:0];
assign store_data_dc2[63:32] = store_data_pre_dc2[63:32];
assign store_data_dc2[31:0] = (lsu_pkt_dc2.store_data_bypass_i0_e2_c2) ? i0_result_e2[31:0] :
(lsu_pkt_dc2.store_data_bypass_c2) ? lsu_result_dc3[31:0] :
(lsu_pkt_dc2.store_data_bypass_e4_c2[1]) ? i1_result_e4_eff[31:0] :
(lsu_pkt_dc2.store_data_bypass_e4_c2[0]) ? i0_result_e4_eff[31:0] : store_data_pre_dc2[31:0];
assign store_data_dc3[63:32] = store_data_pre_dc3[63:32];
assign store_data_dc3[31:0] = (picm_mask_data_dc3[31:0] | {32{~addr_in_pic_dc3}}) &
((lsu_pkt_dc3.store_data_bypass_e4_c3[1]) ? i1_result_e4_eff[31:0] :
(lsu_pkt_dc3.store_data_bypass_e4_c3[0]) ? i0_result_e4_eff[31:0] : store_data_pre_dc3[31:0]);
rvdff #(32) lsu_result_corr_dc4ff (.*, .din(lsu_result_corr_dc3[31:0]), .dout(lsu_result_corr_dc4[31:0]), .clk(lsu_c1_dc4_clk));
rvdff #(64) sddc1ff (.*, .din(store_data_d[63:0]), .dout(store_data_dc1[63:0]), .clk(lsu_store_c1_dc1_clk));
rvdff #(64) sddc2ff (.*, .din(store_data_dc2_in[63:0]), .dout(store_data_pre_dc2[63:0]), .clk(lsu_store_c1_dc2_clk));
rvdffs #(64) sddc3ff (.*, .din(store_data_dc2[63:0]), .dout(store_data_pre_dc3[63:0]), .en(~lsu_freeze_dc3), .clk(lsu_store_c1_dc3_clk));
rvdff #(32) sddc4ff (.*, .din(store_data_dc3[31:0]), .dout(store_data_dc4[31:0]), .clk(lsu_store_c1_dc4_clk));
rvdff #(32) sddc5ff (.*, .din(store_data_dc4[31:0]), .dout(store_data_dc5[31:0]), .clk(lsu_store_c1_dc5_clk));
rvdff #(32) sadc2ff (.*, .din(lsu_addr_dc1[31:0]), .dout(lsu_addr_dc2[31:0]), .clk(lsu_freeze_c1_dc2_clk));
rvdff #(32) sadc3ff (.*, .din(lsu_addr_dc2[31:0]), .dout(lsu_addr_dc3[31:0]), .clk(lsu_freeze_c1_dc3_clk));
rvdff #(32) sadc4ff (.*, .din(lsu_addr_dc3[31:0]), .dout(lsu_addr_dc4[31:0]), .clk(lsu_c1_dc4_clk));
rvdff #(32) sadc5ff (.*, .din(lsu_addr_dc4[31:0]), .dout(lsu_addr_dc5[31:0]), .clk(lsu_c1_dc5_clk));
rvdff #(32) end_addr_dc2ff (.*, .din(end_addr_dc1[31:0]), .dout(end_addr_dc2[31:0]), .clk(lsu_freeze_c1_dc2_clk));
rvdff #(32) end_addr_dc3ff (.*, .din(end_addr_dc2[31:0]), .dout(end_addr_dc3[31:0]), .clk(lsu_freeze_c1_dc3_clk));
rvdff #(32) end_addr_dc4ff (.*, .din(end_addr_dc3[31:0]), .dout(end_addr_dc4[31:0]), .clk(lsu_c1_dc4_clk));
rvdff #(32) end_addr_dc5ff (.*, .din(end_addr_dc4[31:0]), .dout(end_addr_dc5[31:0]), .clk(lsu_c1_dc5_clk));
rvdff #(1) addr_in_dccm_dc2ff(.din(addr_in_dccm_dc1), .dout(addr_in_dccm_dc2), .clk(lsu_freeze_c1_dc2_clk), .*);
rvdff #(1) addr_in_dccm_dc3ff(.din(addr_in_dccm_dc2), .dout(addr_in_dccm_dc3), .clk(lsu_freeze_c1_dc3_clk), .*);
rvdff #(1) addr_in_pic_dc2ff(.din(addr_in_pic_dc1), .dout(addr_in_pic_dc2), .clk(lsu_freeze_c1_dc2_clk), .*);
rvdff #(1) addr_in_pic_dc3ff(.din(addr_in_pic_dc2), .dout(addr_in_pic_dc3), .clk(lsu_freeze_c1_dc3_clk), .*);
rvdff #(1) addr_external_dc2ff(.din(addr_external_dc1), .dout(addr_external_dc2), .clk(lsu_freeze_c1_dc2_clk), .*);
rvdff #(1) addr_external_dc3ff(.din(addr_external_dc2), .dout(addr_external_dc3), .clk(lsu_freeze_c1_dc3_clk), .*);
rvdff #(1) addr_external_dc4ff(.din(addr_external_dc3), .dout(addr_external_dc4), .clk(lsu_c1_dc4_clk), .*);
rvdff #(1) addr_external_dc5ff(.din(addr_external_dc4), .dout(addr_external_dc5), .clk(lsu_c1_dc5_clk), .*);
rvdff #(1) access_fault_dc2ff(.din(access_fault_dc1), .dout(access_fault_dc2), .clk(lsu_freeze_c1_dc2_clk), .*);
rvdff #(1) access_fault_dc3ff(.din(access_fault_dc2), .dout(access_fault_dc3), .clk(lsu_freeze_c1_dc3_clk), .*);
rvdff #(1) misaligned_fault_dc2ff(.din(misaligned_fault_dc1), .dout(misaligned_fault_dc2), .clk(lsu_freeze_c1_dc2_clk), .*);
rvdff #(1) misaligned_fault_dc3ff(.din(misaligned_fault_dc2), .dout(misaligned_fault_dc3), .clk(lsu_freeze_c1_dc3_clk), .*);
endmodule

399
design/lsu/lsu_stbuf.sv Normal file
View File

@ -0,0 +1,399 @@
// 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.
//********************************************************************************
// $Id$
//
//
// Owner:
// Function: Store Buffer
// Comments: Dual writes and single drain
//
//
// DC1 -> DC2 -> DC3 -> DC4 (Commit)
//
// //********************************************************************************
module lsu_stbuf
import swerv_types::*;
(
input logic clk, // core clock
input logic rst_l, // reset
input logic lsu_freeze_c2_dc2_clk, // freeze clock
input logic lsu_freeze_c2_dc3_clk, // freeze clock
input logic lsu_freeze_c1_dc2_clk, // freeze clock
input logic lsu_freeze_c1_dc3_clk, // freeze clock
input logic lsu_c1_dc4_clk, // lsu pipe clock
input logic lsu_c1_dc5_clk, // lsu pipe clock
input logic lsu_c2_dc4_clk, // lsu pipe clock
input logic lsu_c2_dc5_clk, // lsu pipe clock
input logic lsu_stbuf_c1_clk, // stbuf clock
input logic lsu_free_c2_clk, // free clk
// Store Buffer input
input logic load_stbuf_reqvld_dc3, // core instruction goes to stbuf
input logic store_stbuf_reqvld_dc3, // core instruction goes to stbuf
//input logic ldst_stbuf_reqvld_dc3,
input logic addr_in_pic_dc2, // address is in pic
input logic addr_in_pic_dc3, // address is in pic
input logic addr_in_dccm_dc2, // address is in pic
input logic addr_in_dccm_dc3, // address is in pic
input logic [`RV_DCCM_DATA_WIDTH-1:0] store_ecc_datafn_hi_dc3, // data to write
input logic [`RV_DCCM_DATA_WIDTH-1:0] store_ecc_datafn_lo_dc3, // data to write
input logic isldst_dc1, // instruction in dc1 is lsu
input logic dccm_ldst_dc2, // instruction in dc2 is lsu
input logic dccm_ldst_dc3, // instruction in dc3 is lsu
input logic single_ecc_error_hi_dc3, // single ecc error in hi bank
input logic single_ecc_error_lo_dc3, // single ecc error in lo bank
input logic lsu_single_ecc_error_dc5, // single_ecc_error in either bank staged to the dc5 - needed for the load repairs
input logic lsu_commit_dc5, // lsu commits
input logic lsu_freeze_dc3, // lsu freeze
input logic flush_prior_dc5, // Flush is due to i0 and ld/st is in i1
// Store Buffer output
output logic stbuf_reqvld_any, // stbuf is draining
output logic stbuf_reqvld_flushed_any, // Top entry is flushed
output logic stbuf_addr_in_pic_any, // address maps to pic
output logic [`RV_DCCM_BYTE_WIDTH-1:0] stbuf_byteen_any, // which bytes are active
output logic [`RV_LSU_SB_BITS-1:0] stbuf_addr_any, // address
output logic [`RV_DCCM_DATA_WIDTH-1:0] stbuf_data_any, // stbuf data
input logic lsu_stbuf_commit_any, // pop the stbuf as it commite
output logic lsu_stbuf_full_any, // stbuf is full
output logic lsu_stbuf_empty_any, // stbuf is empty
output logic lsu_stbuf_nodma_empty_any, // stbuf is empty except dma
input logic [`RV_LSU_SB_BITS-1:0] lsu_addr_dc1, // lsu address
input logic [`RV_LSU_SB_BITS-1:0] lsu_addr_dc2,
input logic [`RV_LSU_SB_BITS-1:0] lsu_addr_dc3,
input logic [`RV_LSU_SB_BITS-1:0] end_addr_dc1, // lsu end addrress - needed to check unaligned
input logic [`RV_LSU_SB_BITS-1:0] end_addr_dc2,
input logic [`RV_LSU_SB_BITS-1:0] end_addr_dc3,
// Forwarding signals
input logic lsu_cmpen_dc2, // needed for forwarding stbuf - load
input lsu_pkt_t lsu_pkt_dc2,
input lsu_pkt_t lsu_pkt_dc3,
input lsu_pkt_t lsu_pkt_dc5,
output logic [`RV_DCCM_DATA_WIDTH-1:0] stbuf_fwddata_hi_dc3, // stbuf data
output logic [`RV_DCCM_DATA_WIDTH-1:0] stbuf_fwddata_lo_dc3,
output logic [`RV_DCCM_BYTE_WIDTH-1:0] stbuf_fwdbyteen_hi_dc3,
output logic [`RV_DCCM_BYTE_WIDTH-1:0] stbuf_fwdbyteen_lo_dc3,
input logic scan_mode
);
`include "global.h"
localparam DEPTH = LSU_STBUF_DEPTH;
localparam DATA_WIDTH = DCCM_DATA_WIDTH;
localparam BYTE_WIDTH = DCCM_BYTE_WIDTH;
localparam DEPTH_LOG2 = $clog2(DEPTH);
logic [DEPTH-1:0] stbuf_data_vld;
logic [DEPTH-1:0] stbuf_drain_vld;
logic [DEPTH-1:0] stbuf_flush_vld;
logic [DEPTH-1:0] stbuf_addr_in_pic;
logic [DEPTH-1:0] stbuf_dma;
logic [DEPTH-1:0][LSU_SB_BITS-1:0] stbuf_addr;
logic [DEPTH-1:0][BYTE_WIDTH-1:0] stbuf_byteen;
logic [DEPTH-1:0][DATA_WIDTH-1:0] stbuf_data;
logic [DEPTH-1:0] sel_lo;
logic [DEPTH-1:0] stbuf_wr_en;
logic [DEPTH-1:0] stbuf_data_en;
logic [DEPTH-1:0] stbuf_drain_or_flush_en;
logic [DEPTH-1:0] stbuf_flush_en;
logic [DEPTH-1:0] stbuf_drain_en;
logic [DEPTH-1:0] stbuf_reset;
logic [DEPTH-1:0][LSU_SB_BITS-1:0] stbuf_addrin;
logic [DEPTH-1:0][DATA_WIDTH-1:0] stbuf_datain;
logic [DEPTH-1:0][BYTE_WIDTH-1:0] stbuf_byteenin;
logic [7:0] ldst_byteen_dc3;
logic [7:0] store_byteen_ext_dc3;
logic [BYTE_WIDTH-1:0] store_byteen_hi_dc3;
logic [BYTE_WIDTH-1:0] store_byteen_lo_dc3;
logic ldst_stbuf_reqvld_dc3;
logic dual_ecc_error_dc3;
logic dual_stbuf_write_dc3;
logic WrPtrEn, RdPtrEn;
logic [DEPTH_LOG2-1:0] WrPtr, RdPtr;
logic [DEPTH_LOG2-1:0] NxtWrPtr, NxtRdPtr;
logic [DEPTH_LOG2-1:0] WrPtrPlus1, WrPtrPlus1_dc5, WrPtrPlus2, RdPtrPlus1;
logic [DEPTH_LOG2-1:0] WrPtr_dc3, WrPtr_dc4, WrPtr_dc5;
logic ldst_dual_dc1, ldst_dual_dc2, ldst_dual_dc3, ldst_dual_dc4, ldst_dual_dc5;
logic ldst_stbuf_reqvld_dc4, ldst_stbuf_reqvld_dc5;
logic dual_stbuf_write_dc4, dual_stbuf_write_dc5;
logic [3:0] stbuf_numvld_any, stbuf_specvld_any;
logic [1:0] stbuf_specvld_dc1, stbuf_specvld_dc2, stbuf_specvld_dc3;
logic stbuf_oneavl_any, stbuf_twoavl_any;
logic cmpen_hi_dc2, cmpen_lo_dc2, jit_in_same_region;
logic [LSU_SB_BITS-1:$clog2(BYTE_WIDTH)] cmpaddr_hi_dc2, cmpaddr_lo_dc2;
logic stbuf_ldmatch_hi_hi, stbuf_ldmatch_hi_lo;
logic stbuf_ldmatch_lo_hi, stbuf_ldmatch_lo_lo;
logic [BYTE_WIDTH-1:0] stbuf_fwdbyteen_hi_hi, stbuf_fwdbyteen_hi_lo;
logic [BYTE_WIDTH-1:0] stbuf_fwdbyteen_lo_hi, stbuf_fwdbyteen_lo_lo;
logic [DATA_WIDTH-1:0] stbuf_fwddata_hi_hi, stbuf_fwddata_hi_lo;
logic [DATA_WIDTH-1:0] stbuf_fwddata_lo_hi, stbuf_fwddata_lo_lo;
logic [DEPTH-1:0] stbuf_ldmatch_hi, stbuf_ldmatch_lo;
logic [DEPTH-1:0][BYTE_WIDTH-1:0] stbuf_fwdbyteenvec_hi, stbuf_fwdbyteenvec_lo;
logic [DEPTH-1:0][DATA_WIDTH-1:0] stbuf_fwddatavec_hi, stbuf_fwddatavec_lo;
logic [DATA_WIDTH-1:0] stbuf_fwddata_hi_dc2, stbuf_fwddata_lo_dc2;
logic [DATA_WIDTH-1:0] stbuf_fwddata_hi_fn_dc2, stbuf_fwddata_lo_fn_dc2;
logic [BYTE_WIDTH-1:0] stbuf_fwdbyteen_hi_dc2, stbuf_fwdbyteen_lo_dc2;
logic [BYTE_WIDTH-1:0] stbuf_fwdbyteen_hi_fn_dc2, stbuf_fwdbyteen_lo_fn_dc2;
logic stbuf_load_repair_dc5;
//----------------------------------------
// Logic starts here
//----------------------------------------
// Create high/low byte enables
assign ldst_byteen_dc3[7:0] = ({8{lsu_pkt_dc3.by}} & 8'b0000_0001) |
({8{lsu_pkt_dc3.half}} & 8'b0000_0011) |
({8{lsu_pkt_dc3.word}} & 8'b0000_1111) |
({8{lsu_pkt_dc3.dword}} & 8'b1111_1111);
assign store_byteen_ext_dc3[7:0] = ldst_byteen_dc3[7:0] << lsu_addr_dc3[1:0];
assign store_byteen_hi_dc3[BYTE_WIDTH-1:0] = store_byteen_ext_dc3[7:4];
assign store_byteen_lo_dc3[BYTE_WIDTH-1:0] = store_byteen_ext_dc3[3:0];
assign RdPtrPlus1[DEPTH_LOG2-1:0] = RdPtr[DEPTH_LOG2-1:0] + 1'b1;
assign WrPtrPlus1[DEPTH_LOG2-1:0] = WrPtr[DEPTH_LOG2-1:0] + 1'b1;
assign WrPtrPlus2[DEPTH_LOG2-1:0] = WrPtr[DEPTH_LOG2-1:0] + 2'b10;
assign WrPtrPlus1_dc5[DEPTH_LOG2-1:0] = WrPtr_dc5[DEPTH_LOG2-1:0] + 1'b1;
// ecc error on both hi/lo
assign ldst_dual_dc1 = (lsu_addr_dc1[2] != end_addr_dc1[2]);
assign dual_ecc_error_dc3 = (single_ecc_error_hi_dc3 & single_ecc_error_lo_dc3);
assign dual_stbuf_write_dc3 = ldst_dual_dc3 & (store_stbuf_reqvld_dc3 | dual_ecc_error_dc3);
assign ldst_stbuf_reqvld_dc3 = store_stbuf_reqvld_dc3 |
(load_stbuf_reqvld_dc3 & (dual_ecc_error_dc3 ? stbuf_twoavl_any : stbuf_oneavl_any)); // Don't correct ecc if not enough entries. Load will be flushed and come back again
assign stbuf_load_repair_dc5 = lsu_single_ecc_error_dc5 & (lsu_pkt_dc5.valid & lsu_pkt_dc5.load & ~flush_prior_dc5);
// Store Buffer instantiation
for (genvar i=0; i<DEPTH; i++) begin: GenStBuf
assign stbuf_wr_en[i] = ldst_stbuf_reqvld_dc3 & ((i == WrPtr[DEPTH_LOG2-1:0]) |
(i == WrPtrPlus1[DEPTH_LOG2-1:0] & dual_stbuf_write_dc3));
assign stbuf_data_en[i] = stbuf_wr_en[i];
assign stbuf_drain_or_flush_en[i] = ldst_stbuf_reqvld_dc5 & ~lsu_pkt_dc5.dma & ((i == WrPtr_dc5[DEPTH_LOG2-1:0]) |
(i == WrPtrPlus1_dc5[DEPTH_LOG2-1:0] & dual_stbuf_write_dc5));
assign stbuf_drain_en[i] = (stbuf_drain_or_flush_en[i] & (lsu_commit_dc5 | stbuf_load_repair_dc5)) | (stbuf_wr_en[i] & lsu_pkt_dc3.dma);
assign stbuf_flush_en[i] = stbuf_drain_or_flush_en[i] & ~(lsu_commit_dc5 | stbuf_load_repair_dc5);
assign stbuf_reset[i] = (lsu_stbuf_commit_any | stbuf_reqvld_flushed_any) & (i == RdPtr[DEPTH_LOG2-1:0]);
// Mux select for start/end address
assign sel_lo[i] = (~ldst_dual_dc3 | (store_stbuf_reqvld_dc3 | single_ecc_error_lo_dc3)) & (i == WrPtr[DEPTH_LOG2-1:0]);
assign stbuf_addrin[i][LSU_SB_BITS-1:0] = sel_lo[i] ? lsu_addr_dc3[LSU_SB_BITS-1:0] : end_addr_dc3[LSU_SB_BITS-1:0];
assign stbuf_byteenin[i][BYTE_WIDTH-1:0] = sel_lo[i] ? store_byteen_lo_dc3[BYTE_WIDTH-1:0] : store_byteen_hi_dc3[BYTE_WIDTH-1:0];
assign stbuf_datain[i][DATA_WIDTH-1:0] = sel_lo[i] ? store_ecc_datafn_lo_dc3[DATA_WIDTH-1:0] : store_ecc_datafn_hi_dc3[DATA_WIDTH-1:0];
rvdffsc #(.WIDTH(1)) stbuf_data_vldff (.din(1'b1), .dout(stbuf_data_vld[i]), .en(stbuf_wr_en[i]), .clear(stbuf_reset[i]), .clk(lsu_stbuf_c1_clk), .*);
rvdffsc #(.WIDTH(1)) stbuf_drain_vldff (.din(1'b1), .dout(stbuf_drain_vld[i]), .en(stbuf_drain_en[i]), .clear(stbuf_reset[i]), .clk(lsu_free_c2_clk), .*);
rvdffsc #(.WIDTH(1)) stbuf_flush_vldff (.din(1'b1), .dout(stbuf_flush_vld[i]), .en(stbuf_flush_en[i]), .clear(stbuf_reset[i]), .clk(lsu_free_c2_clk), .*);
rvdffs #(.WIDTH(1)) stbuf_dma_picff (.din(lsu_pkt_dc3.dma), .dout(stbuf_dma[i]), .en(stbuf_wr_en[i]), .clk(lsu_stbuf_c1_clk), .*);
rvdffs #(.WIDTH(1)) stbuf_addr_in_picff (.din(addr_in_pic_dc3), .dout(stbuf_addr_in_pic[i]), .en(stbuf_wr_en[i]), .clk(lsu_stbuf_c1_clk), .*);
rvdffe #(.WIDTH(LSU_SB_BITS)) stbuf_addrff (.din(stbuf_addrin[i][LSU_SB_BITS-1:0]), .dout(stbuf_addr[i][LSU_SB_BITS-1:0]), .en(stbuf_wr_en[i]), .*);
rvdffs #(.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]), .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_data_en[i]), .*);
end
// WrPtr flops to dc5
assign WrPtr_dc3[DEPTH_LOG2-1:0] = WrPtr[DEPTH_LOG2-1:0];
rvdff #(.WIDTH(DEPTH_LOG2)) WrPtr_dc4ff (.din(WrPtr_dc3[DEPTH_LOG2-1:0]), .dout(WrPtr_dc4[DEPTH_LOG2-1:0]), .clk(lsu_c1_dc4_clk), .*);
rvdff #(.WIDTH(DEPTH_LOG2)) WrPtr_dc5ff (.din(WrPtr_dc4[DEPTH_LOG2-1:0]), .dout(WrPtr_dc5[DEPTH_LOG2-1:0]), .clk(lsu_c1_dc5_clk), .*);
rvdff #(.WIDTH(1)) ldst_dual_dc2ff (.din(ldst_dual_dc1), .dout(ldst_dual_dc2), .clk(lsu_freeze_c1_dc2_clk), .*);
rvdff #(.WIDTH(1)) ldst_dual_dc3ff (.din(ldst_dual_dc2), .dout(ldst_dual_dc3), .clk(lsu_freeze_c1_dc3_clk), .*);
rvdff #(.WIDTH(1)) ldst_dual_dc4ff (.din(ldst_dual_dc3), .dout(ldst_dual_dc4), .clk(lsu_c1_dc4_clk), .*);
rvdff #(.WIDTH(1)) ldst_dual_dc5ff (.din(ldst_dual_dc4), .dout(ldst_dual_dc5), .clk(lsu_c1_dc5_clk), .*);
rvdff #(.WIDTH(1)) dual_stbuf_write_dc4ff (.din(dual_stbuf_write_dc3), .dout(dual_stbuf_write_dc4), .clk(lsu_c1_dc4_clk), .*);
rvdff #(.WIDTH(1)) dual_stbuf_write_dc5ff (.din(dual_stbuf_write_dc4), .dout(dual_stbuf_write_dc5), .clk(lsu_c1_dc5_clk), .*);
rvdff #(.WIDTH(1)) ldst_reqvld_dc4ff (.din(ldst_stbuf_reqvld_dc3), .dout(ldst_stbuf_reqvld_dc4), .clk(lsu_c2_dc4_clk), .*);
rvdff #(.WIDTH(1)) ldst_reqvld_dc5ff (.din(ldst_stbuf_reqvld_dc4), .dout(ldst_stbuf_reqvld_dc5), .clk(lsu_c2_dc5_clk), .*);
// Store Buffer drain logic
assign stbuf_reqvld_flushed_any = stbuf_flush_vld[RdPtr];
assign stbuf_reqvld_any = stbuf_drain_vld[RdPtr];
assign stbuf_addr_in_pic_any = stbuf_addr_in_pic[RdPtr];
assign stbuf_addr_any[LSU_SB_BITS-1:0] = stbuf_addr[RdPtr][LSU_SB_BITS-1:0];
assign stbuf_byteen_any[BYTE_WIDTH-1:0] = stbuf_byteen[RdPtr][BYTE_WIDTH-1:0]; // Not needed as we always write all the bytes
assign stbuf_data_any[DATA_WIDTH-1:0] = stbuf_data[RdPtr][DATA_WIDTH-1:0];
// Update the RdPtr/WrPtr logic
// Need to revert the WrPtr for flush cases. Also revert the pipe WrPtrs
assign WrPtrEn = ldst_stbuf_reqvld_dc3;
assign NxtWrPtr[DEPTH_LOG2-1:0] = (ldst_stbuf_reqvld_dc3 & dual_stbuf_write_dc3) ? WrPtrPlus2[DEPTH_LOG2-1:0] : WrPtrPlus1[DEPTH_LOG2-1:0];
assign RdPtrEn = lsu_stbuf_commit_any | stbuf_reqvld_flushed_any;
assign NxtRdPtr[DEPTH_LOG2-1:0] = RdPtrPlus1[DEPTH_LOG2-1:0];
always_comb begin
//stbuf_numvld_any[3:0] = {3'b0,isldst_dc3} << ldst_dual_dc3; // Use isldst_dc3 for timing reason
stbuf_numvld_any[3:0] = '0;
for (int i=0; i<DEPTH; i++) begin
stbuf_numvld_any[3:0] += {3'b0, stbuf_data_vld[i]};
end
end
assign stbuf_specvld_dc1[1:0] = {1'b0,isldst_dc1} << (isldst_dc1 & ldst_dual_dc1); // Gate dual with isldst to avoid X propagation
assign stbuf_specvld_dc2[1:0] = {1'b0,dccm_ldst_dc2} << (dccm_ldst_dc2 & ldst_dual_dc2);
assign stbuf_specvld_dc3[1:0] = {1'b0,dccm_ldst_dc3} << (dccm_ldst_dc3 & ldst_dual_dc3);
assign stbuf_specvld_any[3:0] = stbuf_numvld_any[3:0] + {2'b0, stbuf_specvld_dc1[1:0]} + {2'b0, stbuf_specvld_dc2[1:0]} + {2'b0, stbuf_specvld_dc3[1:0]};
assign lsu_stbuf_full_any = (stbuf_specvld_any[3:0] > (DEPTH - 2));
assign lsu_stbuf_empty_any = (stbuf_numvld_any[3:0] == 4'b0);
assign lsu_stbuf_nodma_empty_any = ~(|(stbuf_data_vld[DEPTH-1:0] & ~stbuf_dma[DEPTH-1:0]));
assign stbuf_oneavl_any = (stbuf_numvld_any[3:0] < DEPTH);
assign stbuf_twoavl_any = (stbuf_numvld_any[3:0] < (DEPTH - 1));
// Load forwarding logic
assign cmpen_hi_dc2 = lsu_cmpen_dc2 & ldst_dual_dc2;
assign cmpaddr_hi_dc2[LSU_SB_BITS-1:$clog2(BYTE_WIDTH)] = end_addr_dc2[LSU_SB_BITS-1:$clog2(BYTE_WIDTH)];
assign cmpen_lo_dc2 = lsu_cmpen_dc2;
assign cmpaddr_lo_dc2[LSU_SB_BITS-1:$clog2(BYTE_WIDTH)] = lsu_addr_dc2[LSU_SB_BITS-1:$clog2(BYTE_WIDTH)];
assign jit_in_same_region = (addr_in_pic_dc2 & addr_in_pic_dc3) | (addr_in_dccm_dc2 & addr_in_dccm_dc3);
// JIT forwarding
assign stbuf_ldmatch_hi_hi = (end_addr_dc3[LSU_SB_BITS-1:$clog2(BYTE_WIDTH)] == cmpaddr_hi_dc2[LSU_SB_BITS-1:$clog2(BYTE_WIDTH)]) & ~(cmpen_hi_dc2 & lsu_pkt_dc2.dma & ~lsu_pkt_dc3.dma) & jit_in_same_region;
assign stbuf_ldmatch_hi_lo = (lsu_addr_dc3[LSU_SB_BITS-1:$clog2(BYTE_WIDTH)] == cmpaddr_hi_dc2[LSU_SB_BITS-1:$clog2(BYTE_WIDTH)]) & ~(cmpen_hi_dc2 & lsu_pkt_dc2.dma & ~lsu_pkt_dc3.dma) & jit_in_same_region;
assign stbuf_ldmatch_lo_hi = (end_addr_dc3[LSU_SB_BITS-1:$clog2(BYTE_WIDTH)] == cmpaddr_lo_dc2[LSU_SB_BITS-1:$clog2(BYTE_WIDTH)]) & ~(cmpen_lo_dc2 & lsu_pkt_dc2.dma & ~lsu_pkt_dc3.dma) & jit_in_same_region;
assign stbuf_ldmatch_lo_lo = (lsu_addr_dc3[LSU_SB_BITS-1:$clog2(BYTE_WIDTH)] == cmpaddr_lo_dc2[LSU_SB_BITS-1:$clog2(BYTE_WIDTH)]) & ~(cmpen_lo_dc2 & lsu_pkt_dc2.dma & ~lsu_pkt_dc3.dma) & jit_in_same_region;
for (genvar i=0; i<BYTE_WIDTH; i++) begin
assign stbuf_fwdbyteen_hi_hi[i] = stbuf_ldmatch_hi_hi & store_byteen_hi_dc3[i] & ldst_stbuf_reqvld_dc3 & dual_stbuf_write_dc3;
assign stbuf_fwdbyteen_hi_lo[i] = stbuf_ldmatch_hi_lo & store_byteen_lo_dc3[i] & ldst_stbuf_reqvld_dc3;
assign stbuf_fwdbyteen_lo_hi[i] = stbuf_ldmatch_lo_hi & store_byteen_hi_dc3[i] & ldst_stbuf_reqvld_dc3 & dual_stbuf_write_dc3;
assign stbuf_fwdbyteen_lo_lo[i] = stbuf_ldmatch_lo_lo & store_byteen_lo_dc3[i] & ldst_stbuf_reqvld_dc3;
assign stbuf_fwddata_hi_hi[(8*i)+7:(8*i)] = {8{stbuf_fwdbyteen_hi_hi[i]}} & store_ecc_datafn_hi_dc3[(8*i)+7:(8*i)];
assign stbuf_fwddata_hi_lo[(8*i)+7:(8*i)] = {8{stbuf_fwdbyteen_hi_lo[i]}} & store_ecc_datafn_lo_dc3[(8*i)+7:(8*i)];
assign stbuf_fwddata_lo_hi[(8*i)+7:(8*i)] = {8{stbuf_fwdbyteen_lo_hi[i]}} & store_ecc_datafn_hi_dc3[(8*i)+7:(8*i)];
assign stbuf_fwddata_lo_lo[(8*i)+7:(8*i)] = {8{stbuf_fwdbyteen_lo_lo[i]}} & store_ecc_datafn_lo_dc3[(8*i)+7:(8*i)];
end
always_comb begin: GenLdFwd
stbuf_fwdbyteen_hi_dc2[BYTE_WIDTH-1:0] = '0;
stbuf_fwdbyteen_lo_dc2[BYTE_WIDTH-1:0] = '0;
for (int i=0; i<DEPTH; i++) begin
stbuf_ldmatch_hi[i] = (stbuf_addr[i][LSU_SB_BITS-1:$clog2(BYTE_WIDTH)] == cmpaddr_hi_dc2[LSU_SB_BITS-1:$clog2(BYTE_WIDTH)]) &
(stbuf_drain_vld[i] | ~lsu_pkt_dc2.dma) & ~stbuf_flush_vld[i] & ((stbuf_addr_in_pic[i] & addr_in_pic_dc2) | (~stbuf_addr_in_pic[i] & addr_in_dccm_dc2));
stbuf_ldmatch_lo[i] = (stbuf_addr[i][LSU_SB_BITS-1:$clog2(BYTE_WIDTH)] == cmpaddr_lo_dc2[LSU_SB_BITS-1:$clog2(BYTE_WIDTH)]) &
(stbuf_drain_vld[i] | ~lsu_pkt_dc2.dma) & ~stbuf_flush_vld[i] & ((stbuf_addr_in_pic[i] & addr_in_pic_dc2) | (~stbuf_addr_in_pic[i] & addr_in_dccm_dc2));
for (int j=0; j<BYTE_WIDTH; j++) begin
stbuf_fwdbyteenvec_hi[i][j] = stbuf_ldmatch_hi[i] & stbuf_byteen[i][j] & stbuf_data_vld[i];
stbuf_fwdbyteen_hi_dc2[j] |= stbuf_fwdbyteenvec_hi[i][j];
stbuf_fwdbyteenvec_lo[i][j] = stbuf_ldmatch_lo[i] & stbuf_byteen[i][j] & stbuf_data_vld[i];
stbuf_fwdbyteen_lo_dc2[j] |= stbuf_fwdbyteenvec_lo[i][j];
end
end
end // block: GenLdFwd
for (genvar i=0; i<DEPTH; i++) begin
for (genvar j=0; j<BYTE_WIDTH; j++) begin
assign stbuf_fwddatavec_hi[i][(8*j)+7:(8*j)] = {8{stbuf_fwdbyteenvec_hi[i][j]}} & stbuf_data[i][(8*j)+7:(8*j)];
assign stbuf_fwddatavec_lo[i][(8*j)+7:(8*j)] = {8{stbuf_fwdbyteenvec_lo[i][j]}} & stbuf_data[i][(8*j)+7:(8*j)];
end
end
always_comb begin
stbuf_fwddata_hi_dc2[DATA_WIDTH-1:0] = '0;
stbuf_fwddata_lo_dc2[DATA_WIDTH-1:0] = '0;
for (int i=0; i<DEPTH; i++) begin
// Byte0
if (stbuf_fwdbyteenvec_hi[DEPTH_LOG2'(WrPtr[DEPTH_LOG2-1:0] + DEPTH_LOG2'(i))][0]) begin
stbuf_fwddata_hi_dc2[7:0] = stbuf_fwddatavec_hi[DEPTH_LOG2'(WrPtr[DEPTH_LOG2-1:0] + DEPTH_LOG2'(i))][7:0];
end
if (stbuf_fwdbyteenvec_lo[DEPTH_LOG2'(WrPtr[DEPTH_LOG2-1:0] + DEPTH_LOG2'(i))][0]) begin
stbuf_fwddata_lo_dc2[7:0] = stbuf_fwddatavec_lo[DEPTH_LOG2'(WrPtr[DEPTH_LOG2-1:0] + DEPTH_LOG2'(i))][7:0];
end
// Byte1
if (stbuf_fwdbyteenvec_hi[DEPTH_LOG2'(WrPtr[DEPTH_LOG2-1:0] + DEPTH_LOG2'(i))][1]) begin
stbuf_fwddata_hi_dc2[15:8] = stbuf_fwddatavec_hi[DEPTH_LOG2'(WrPtr[DEPTH_LOG2-1:0] + DEPTH_LOG2'(i))][15:8];
end
if (stbuf_fwdbyteenvec_lo[DEPTH_LOG2'(WrPtr[DEPTH_LOG2-1:0] + DEPTH_LOG2'(i))][1]) begin
stbuf_fwddata_lo_dc2[15:8] = stbuf_fwddatavec_lo[DEPTH_LOG2'(WrPtr[DEPTH_LOG2-1:0] + DEPTH_LOG2'(i))][15:8];
end
// Byte2
if (stbuf_fwdbyteenvec_hi[DEPTH_LOG2'(WrPtr[DEPTH_LOG2-1:0] + DEPTH_LOG2'(i))][2]) begin
stbuf_fwddata_hi_dc2[23:16] = stbuf_fwddatavec_hi[DEPTH_LOG2'(WrPtr[DEPTH_LOG2-1:0] + DEPTH_LOG2'(i))][23:16];
end
if (stbuf_fwdbyteenvec_lo[DEPTH_LOG2'(WrPtr[DEPTH_LOG2-1:0] + DEPTH_LOG2'(i))][2]) begin
stbuf_fwddata_lo_dc2[23:16] = stbuf_fwddatavec_lo[DEPTH_LOG2'(WrPtr[DEPTH_LOG2-1:0] + DEPTH_LOG2'(i))][23:16];
end
// Byte3
if (stbuf_fwdbyteenvec_hi[DEPTH_LOG2'(WrPtr[DEPTH_LOG2-1:0] + DEPTH_LOG2'(i))][3]) begin
stbuf_fwddata_hi_dc2[31:24] = stbuf_fwddatavec_hi[DEPTH_LOG2'(WrPtr[DEPTH_LOG2-1:0] + DEPTH_LOG2'(i))][31:24];
end
if (stbuf_fwdbyteenvec_lo[DEPTH_LOG2'(WrPtr[DEPTH_LOG2-1:0] + DEPTH_LOG2'(i))][3]) begin
stbuf_fwddata_lo_dc2[31:24] = stbuf_fwddatavec_lo[DEPTH_LOG2'(WrPtr[DEPTH_LOG2-1:0] + DEPTH_LOG2'(i))][31:24];
end
end
end
for (genvar i=0; i<BYTE_WIDTH; i++) begin
assign stbuf_fwdbyteen_hi_fn_dc2[i] = stbuf_fwdbyteen_hi_hi[i] | stbuf_fwdbyteen_hi_lo[i] | stbuf_fwdbyteen_hi_dc2[i];
assign stbuf_fwdbyteen_lo_fn_dc2[i] = stbuf_fwdbyteen_lo_hi[i] | stbuf_fwdbyteen_lo_lo[i] | stbuf_fwdbyteen_lo_dc2[i];
assign stbuf_fwddata_hi_fn_dc2[(8*i)+7:(8*i)] = (stbuf_fwdbyteen_hi_hi[i] | stbuf_fwdbyteen_hi_lo[i]) ?
(stbuf_fwddata_hi_hi[(8*i)+7:(8*i)] | stbuf_fwddata_hi_lo[(8*i)+7:(8*i)]) :
stbuf_fwddata_hi_dc2[(8*i)+7:(8*i)];
assign stbuf_fwddata_lo_fn_dc2[(8*i)+7:(8*i)] = (stbuf_fwdbyteen_lo_hi[i] | stbuf_fwdbyteen_lo_lo[i]) ?
(stbuf_fwddata_lo_hi[(8*i)+7:(8*i)] | stbuf_fwddata_lo_lo[(8*i)+7:(8*i)]) :
stbuf_fwddata_lo_dc2[(8*i)+7:(8*i)];
end
// Flops
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), .*);
rvdff #(.WIDTH(BYTE_WIDTH)) stbuf_fwdbyteen_hi_dc3ff (.din(stbuf_fwdbyteen_hi_fn_dc2[BYTE_WIDTH-1:0]), .dout(stbuf_fwdbyteen_hi_dc3[BYTE_WIDTH-1:0]), .clk(lsu_freeze_c1_dc3_clk), .*);
rvdff #(.WIDTH(BYTE_WIDTH)) stbuf_fwdbyteen_lo_dc3ff (.din(stbuf_fwdbyteen_lo_fn_dc2[BYTE_WIDTH-1:0]), .dout(stbuf_fwdbyteen_lo_dc3[BYTE_WIDTH-1:0]), .clk(lsu_freeze_c1_dc3_clk), .*);
rvdff #(.WIDTH(DATA_WIDTH)) stbuf_fwddata_hi_dc3ff (.din(stbuf_fwddata_hi_fn_dc2[DATA_WIDTH-1:0]), .dout(stbuf_fwddata_hi_dc3[DATA_WIDTH-1:0]), .clk(lsu_freeze_c1_dc3_clk), .*);
rvdff #(.WIDTH(DATA_WIDTH)) stbuf_fwddata_lo_dc3ff (.din(stbuf_fwddata_lo_fn_dc2[DATA_WIDTH-1:0]), .dout(stbuf_fwddata_lo_dc3[DATA_WIDTH-1:0]), .clk(lsu_freeze_c1_dc3_clk), .*);
`ifdef ASSERT_ON
assert_drainorflushvld_notvld: assert #0 (~(|((stbuf_drain_vld[DEPTH-1:0] | stbuf_flush_vld[DEPTH-1:0]) & ~stbuf_data_vld[DEPTH-1:0])));
assert_drainAndflushvld: assert #0 (~(|(stbuf_drain_vld[DEPTH-1:0] & stbuf_flush_vld[DEPTH-1:0])));
assert_stbufempty: assert #0 (~lsu_stbuf_empty_any | lsu_stbuf_nodma_empty_any);
`endif
endmodule

61
design/lsu/lsu_trigger.sv Normal file
View File

@ -0,0 +1,61 @@
// 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.
//********************************************************************************
// $Id$
//
//
// Owner:
// Function: LSU Trigger logic
// Comments:
//
//********************************************************************************
module lsu_trigger
import swerv_types::*;
(
input logic clk, // clock
input logic lsu_free_c2_clk, // clock
input logic rst_l, // reset
input trigger_pkt_t [3:0] trigger_pkt_any, // trigger packet from dec
input lsu_pkt_t lsu_pkt_dc3, // lsu packet
input logic [31:0] lsu_addr_dc3, // address
input logic [31:0] lsu_result_dc3, // load data
input logic [31:0] store_data_dc3, // store data
output logic [3:0] lsu_trigger_match_dc3 // match result
);
logic [3:0][31:0] lsu_match_data;
logic [3:0] lsu_trigger_data_match;
logic [31:0] store_data_trigger_dc3;
assign store_data_trigger_dc3[31:0] = { ({16{lsu_pkt_dc3.word}} & store_data_dc3[31:16]) , ({8{(lsu_pkt_dc3.half | lsu_pkt_dc3.word)}} & store_data_dc3[15:8]), store_data_dc3[7:0]};
for (genvar i=0; i<4; i++) begin
assign lsu_match_data[i][31:0] = ({32{~trigger_pkt_any[i].select}} & lsu_addr_dc3[31:0]) |
({32{trigger_pkt_any[i].select & trigger_pkt_any[i].store}} & store_data_trigger_dc3[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_dc3[i] = lsu_pkt_dc3.valid & ~lsu_pkt_dc3.dma &
((trigger_pkt_any[i].store & lsu_pkt_dc3.store) | (trigger_pkt_any[i].load & lsu_pkt_dc3.load & ~trigger_pkt_any[i].select)) &
lsu_trigger_data_match[i];
end
endmodule // lsu_trigger

132
design/mem.sv Normal file
View File

@ -0,0 +1,132 @@
//********************************************************************************
// 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.
//********************************************************************************
module mem
import swerv_types::*;
(
input logic clk,
input logic rst_l,
input logic lsu_freeze_dc3,
input logic dccm_clk_override,
input logic icm_clk_override,
input logic dec_tlu_core_ecc_disable,
//DCCM ports
input logic dccm_wren,
input logic dccm_rden,
input logic [`RV_DCCM_BITS-1:0] dccm_wr_addr,
input logic [`RV_DCCM_BITS-1:0] dccm_rd_addr_lo,
input logic [`RV_DCCM_BITS-1:0] dccm_rd_addr_hi,
input logic [`RV_DCCM_FDATA_WIDTH-1:0] dccm_wr_data,
output logic [`RV_DCCM_FDATA_WIDTH-1:0] dccm_rd_data_lo,
output logic [`RV_DCCM_FDATA_WIDTH-1:0] dccm_rd_data_hi,
`ifdef RV_ICCM_ENABLE
//ICCM ports
input logic [`RV_ICCM_BITS-1:2] iccm_rw_addr,
input logic iccm_wren,
input logic iccm_rden,
input logic [2:0] iccm_wr_size,
input logic [77:0] iccm_wr_data,
output logic [155:0] iccm_rd_data,
`endif
// Icache and Itag Ports
`ifdef RV_ICACHE_ENABLE //temp
input logic [31:3] ic_rw_addr,
input logic [3:0] ic_tag_valid,
input logic [3:0] ic_wr_en,
input logic ic_rd_en,
input logic [127:0] ic_premux_data, // Premux data to be muxed with each way of the Icache.
input logic ic_sel_premux_data, // Premux data sel
`ifdef RV_ICACHE_ECC
input logic [83:0] ic_wr_data, // Data to fill to the Icache. With ECC
input logic [41:0] ic_debug_wr_data, // Debug wr cache.
`else
input logic [67:0] ic_wr_data, // Data to fill to the Icache. With Parity
input logic [33:0] ic_debug_wr_data, // Debug wr cache.
`endif
input logic [15:2] ic_debug_addr, // Read/Write addresss to the Icache.
input logic ic_debug_rd_en, // Icache debug rd
input logic ic_debug_wr_en, // Icache debug wr
input logic ic_debug_tag_array, // Debug tag array
input logic [3:0] ic_debug_way, // Debug way. Rd or Wr.
`endif
`ifdef RV_ICACHE_ECC
output logic [167:0] ic_rd_data , // Data read from Icache. 2x64bits + parity bits. F2 stage. With ECC
output logic [24:0] ictag_debug_rd_data,// Debug icache tag.
`else
output logic [135:0] ic_rd_data , // Data read from Icache. 2x64bits + parity bits. F2 stage. With Parity
output logic [20:0] ictag_debug_rd_data,// Debug icache tag.
`endif
output logic [3:0] ic_rd_hit,
output logic ic_tag_perr, // Icache Tag parity error
input logic scan_mode
);
`include "global.h"
`ifdef RV_DCCM_ENABLE
localparam DCCM_ENABLE = 1'b1;
`else
localparam DCCM_ENABLE = 1'b0;
`endif
// DCCM Instantiation
if (DCCM_ENABLE == 1) begin: Gen_dccm_enable
lsu_dccm_mem dccm (
.clk_override(dccm_clk_override),
.*
);
end else begin: Gen_dccm_disable
assign dccm_rd_data_lo = '0;
assign dccm_rd_data_hi = '0;
end
`ifdef RV_ICACHE_ENABLE
ifu_ic_mem icm (
.clk_override(icm_clk_override),
.*
);
`else
assign ic_rd_hit[3:0] = '0;
assign ic_tag_perr = '0 ;
assign ic_rd_data = '0 ;
assign ictag_debug_rd_data = '0 ;
`endif
`ifdef RV_ICCM_ENABLE
ifu_iccm_mem iccm (.*,
.clk_override(icm_clk_override),
.iccm_rw_addr(iccm_rw_addr[`RV_ICCM_BITS-1:2]),
.iccm_rd_data(iccm_rd_data[155:0])
);
`endif
endmodule

521
design/pic_ctrl.sv Normal file
View File

@ -0,0 +1,521 @@
//********************************************************************************
// 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.
//********************************************************************************
//********************************************************************************
// Function: Programmable Interrupt Controller
// Comments:
//********************************************************************************
module 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 [`RV_PIC_TOTAL_INT_PLUS1-1:0] extintsrc_req, // Interrupt requests
input logic [31:0] picm_addr, // Address of the register
input logic [31:0] picm_wr_data, // Data to be written to the register
input logic picm_wren, // Write enable to the register
input logic picm_rden, // Read enable for the register
input logic picm_mken, // Read the Mask for the register
input logic [3:0] meicurpl, // Current Priority Level
input logic [3:0] meipt, // Current Priority Threshold
output logic mexintpend, // External Inerrupt request to the core
output logic [7:0] claimid, // Claim Id of the requested interrupt
output logic [3:0] pl, // Priority level of the requested interrupt
output logic [31:0] picm_rd_data, // Read data of the register
output logic mhwakeup, // Wake-up interrupt request
input logic scan_mode // scan mode
);
`include "global.h"
localparam NUM_LEVELS = $clog2(TOTAL_INT);
localparam INTPRIORITY_BASE_ADDR = `RV_PIC_BASE_ADDR ;
localparam INTPEND_BASE_ADDR = `RV_PIC_BASE_ADDR + 32'h00001000 ;
localparam INTENABLE_BASE_ADDR = `RV_PIC_BASE_ADDR + 32'h00002000 ;
localparam EXT_INTR_PIC_CONFIG = `RV_PIC_BASE_ADDR + 32'h00003000 ;
localparam EXT_INTR_GW_CONFIG = `RV_PIC_BASE_ADDR + 32'h00004000 ;
localparam EXT_INTR_GW_CLEAR = `RV_PIC_BASE_ADDR + 32'h00005000 ;
localparam INTPEND_SIZE = (TOTAL_INT < 32) ? 32 :
(TOTAL_INT < 64) ? 64 :
(TOTAL_INT < 128) ? 128 :
(TOTAL_INT < 256) ? 256 :
(TOTAL_INT < 512) ? 512 : 1024 ;
localparam INT_GRPS = INTPEND_SIZE / 32 ;
localparam INTPRIORITY_BITS = 4 ;
localparam ID_BITS = 8 ;
localparam int GW_CONFIG[TOTAL_INT-1:0] = '{default:0} ;
logic addr_intpend_base_match;
logic addr_intenable_base_match;
logic addr_intpriority_base_match;
logic addr_config_pic_match ;
logic addr_config_gw_base_match ;
logic addr_clear_gw_base_match ;
logic mexintpend_in;
logic mhwakeup_in ;
logic intpend_reg_read ;
logic [31:0] picm_rd_data_in, intpend_rd_out;
logic intenable_rd_out ;
logic [INTPRIORITY_BITS-1:0] intpriority_rd_out;
logic [1:0] gw_config_rd_out;
logic [TOTAL_INT-1:0] [INTPRIORITY_BITS-1:0] intpriority_reg;
logic [TOTAL_INT-1:0] [INTPRIORITY_BITS-1:0] intpriority_reg_inv;
logic [TOTAL_INT-1:0] intpriority_reg_we;
logic [TOTAL_INT-1:0] intpriority_reg_re;
logic [TOTAL_INT-1:0] [1:0] gw_config_reg;
logic [TOTAL_INT-1:0] intenable_reg;
logic [TOTAL_INT-1:0] intenable_reg_we;
logic [TOTAL_INT-1:0] intenable_reg_re;
logic [TOTAL_INT-1:0] gw_config_reg_we;
logic [TOTAL_INT-1:0] gw_config_reg_re;
logic [TOTAL_INT-1:0] gw_clear_reg_we;
logic [INTPEND_SIZE-1:0] intpend_reg_extended;
logic [TOTAL_INT-1:0] [INTPRIORITY_BITS-1:0] intpend_w_prior_en;
logic [TOTAL_INT-1:0] [ID_BITS-1:0] intpend_id;
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 config_reg;
logic intpriord;
logic config_reg_we ;
logic config_reg_re ;
logic config_reg_in ;
logic prithresh_reg_write , prithresh_reg_read;
logic intpriority_reg_read ;
logic intenable_reg_read ;
logic gw_config_reg_read ;
logic picm_wren_ff , picm_rden_ff ;
logic [31:0] picm_addr_ff;
logic [31:0] picm_wr_data_ff;
logic [3:0] mask;
logic picm_mken_ff;
logic [ID_BITS-1:0] claimid_in ;
logic [INTPRIORITY_BITS-1:0] pl_in ;
logic [INTPRIORITY_BITS-1:0] pl_in_q ;
logic [TOTAL_INT-1:0] extintsrc_req_sync;
logic [TOTAL_INT-1:0] extintsrc_req_gw;
// clkens
logic pic_addr_c1_clken;
logic pic_data_c1_clken;
logic pic_pri_c1_clken;
logic pic_int_c1_clken;
logic gw_config_c1_clken;
// clocks
logic pic_addr_c1_clk;
logic pic_data_c1_clk;
logic pic_pri_c1_clk;
logic pic_int_c1_clk;
logic gw_config_c1_clk;
// ---- Clock gating section ------
// c1 clock enables
assign pic_addr_c1_clken = picm_mken | picm_rden | picm_wren | clk_override;
assign pic_data_c1_clken = picm_wren | clk_override;
assign pic_pri_c1_clken = (addr_intpriority_base_match & (picm_wren_ff | picm_rden_ff)) | clk_override;
assign pic_int_c1_clken = (addr_intenable_base_match & (picm_wren_ff | picm_rden_ff)) | clk_override;
assign gw_config_c1_clken = (addr_config_gw_base_match & (picm_wren_ff | picm_rden_ff)) | clk_override;
// C1 - 1 clock pulse for data
rvclkhdr pic_addr_c1_cgc ( .en(pic_addr_c1_clken), .l1clk(pic_addr_c1_clk), .* );
rvclkhdr pic_data_c1_cgc ( .en(pic_data_c1_clken), .l1clk(pic_data_c1_clk), .* );
rvclkhdr pic_pri_c1_cgc ( .en(pic_pri_c1_clken), .l1clk(pic_pri_c1_clk), .* );
rvclkhdr pic_int_c1_cgc ( .en(pic_int_c1_clken), .l1clk(pic_int_c1_clk), .* );
rvclkhdr gw_config_c1_cgc ( .en(gw_config_c1_clken), .l1clk(gw_config_c1_clk), .* );
// ------ end clock gating section ------------------------
assign addr_intpend_base_match = (picm_addr_ff[31:6] == INTPEND_BASE_ADDR[31:6]) ;
assign addr_intenable_base_match = (picm_addr_ff[31:NUM_LEVELS+2] == INTENABLE_BASE_ADDR[31:NUM_LEVELS+2]) ;
assign addr_intpriority_base_match = (picm_addr_ff[31:NUM_LEVELS+2] == INTPRIORITY_BASE_ADDR[31:NUM_LEVELS+2]) ;
assign addr_config_pic_match = (picm_addr_ff[31:0] == EXT_INTR_PIC_CONFIG[31:0]) ;
assign addr_config_gw_base_match = (picm_addr_ff[31:NUM_LEVELS+2] == EXT_INTR_GW_CONFIG[31:NUM_LEVELS+2]) ;
assign addr_clear_gw_base_match = (picm_addr_ff[31:NUM_LEVELS+2] == EXT_INTR_GW_CLEAR[31:NUM_LEVELS+2]) ;
rvdff #(32) picm_add_flop (.*, .din (picm_addr), .dout(picm_addr_ff), .clk(pic_addr_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 #(32) picm_dat_flop (.*, .din (picm_wr_data[31:0]), .dout(picm_wr_data_ff[31:0]), .clk(pic_data_c1_clk));
rvsyncss #(TOTAL_INT-1) sync_inst
(
.clk (free_clk),
.dout(extintsrc_req_sync[TOTAL_INT-1:1]),
.din (extintsrc_req[TOTAL_INT-1:1]),
.*) ;
assign extintsrc_req_sync[0] = extintsrc_req[0];
genvar i ;
for (i=0; i<TOTAL_INT ; i++) begin : SETREG
if (i > 0 ) begin : NON_ZERO_INT
assign intpriority_reg_we[i] = addr_intpriority_base_match & (picm_addr_ff[NUM_LEVELS+1:2] == i) & picm_wren_ff;
assign intpriority_reg_re[i] = addr_intpriority_base_match & (picm_addr_ff[NUM_LEVELS+1:2] == i) & picm_rden_ff;
assign intenable_reg_we[i] = addr_intenable_base_match & (picm_addr_ff[NUM_LEVELS+1:2] == i) & picm_wren_ff;
assign intenable_reg_re[i] = addr_intenable_base_match & (picm_addr_ff[NUM_LEVELS+1:2] == i) & picm_rden_ff;
assign gw_config_reg_we[i] = addr_config_gw_base_match & (picm_addr_ff[NUM_LEVELS+1:2] == i) & picm_wren_ff;
assign gw_config_reg_re[i] = addr_config_gw_base_match & (picm_addr_ff[NUM_LEVELS+1:2] == i) & picm_rden_ff;
assign gw_clear_reg_we[i] = addr_clear_gw_base_match & (picm_addr_ff[NUM_LEVELS+1:2] == i) & picm_wren_ff ;
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));
// 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));
configurable_gw config_gw_inst(.*, .clk(free_clk),
.extintsrc_req_sync(extintsrc_req_sync[i]) ,
.meigwctrl_polarity(gw_config_reg[i][0]) ,
.meigwctrl_type(gw_config_reg[i][1]) ,
.meigwclr(gw_clear_reg_we[i]) ,
.extintsrc_req_config(extintsrc_req_gw[i])
);
// end else begin
// assign extintsrc_req_gw[i] = extintsrc_req_sync[i] ;
// assign gw_config_reg[i] = '0 ;
// end
end else begin : INT_ZERO
assign intpriority_reg_we[i] = 1'b0 ;
assign intpriority_reg_re[i] = 1'b0 ;
assign intenable_reg_we[i] = 1'b0 ;
assign intenable_reg_re[i] = 1'b0 ;
assign gw_config_reg_we[i] = 1'b0 ;
assign gw_config_reg_re[i] = 1'b0 ;
assign gw_clear_reg_we[i] = 1'b0 ;
assign gw_config_reg[i] = '0 ;
assign intpriority_reg[i] = {INTPRIORITY_BITS{1'b0}} ;
assign intenable_reg[i] = 1'b0 ;
assign extintsrc_req_gw[i] = 1'b0 ;
end
assign intpriority_reg_inv[i] = intpriord ? ~intpriority_reg[i] : intpriority_reg[i] ;
assign intpend_w_prior_en[i] = {INTPRIORITY_BITS{(extintsrc_req_gw[i] & intenable_reg[i])}} & intpriority_reg_inv[i] ;
assign intpend_id[i] = i ;
end
assign pl_in[INTPRIORITY_BITS-1:0] = selected_int_priority[INTPRIORITY_BITS-1:0] ;
`ifdef RV_PIC_2CYCLE
logic [NUM_LEVELS/2:0] [TOTAL_INT+2:0] [INTPRIORITY_BITS-1:0] level_intpend_w_prior_en;
logic [NUM_LEVELS/2:0] [TOTAL_INT+2:0] [ID_BITS-1:0] level_intpend_id;
logic [NUM_LEVELS:NUM_LEVELS/2] [(TOTAL_INT/2**(NUM_LEVELS/2))+1:0] [INTPRIORITY_BITS-1:0] levelx_intpend_w_prior_en;
logic [NUM_LEVELS:NUM_LEVELS/2] [(TOTAL_INT/2**(NUM_LEVELS/2))+1:0] [ID_BITS-1:0] levelx_intpend_id;
assign level_intpend_w_prior_en[0][TOTAL_INT+2:0] = {4'b0,4'b0,4'b0,intpend_w_prior_en[TOTAL_INT-1:0]} ;
assign level_intpend_id[0][TOTAL_INT+2:0] = {8'b0,8'b0,8'b0,intpend_id[TOTAL_INT-1:0]} ;
logic [(TOTAL_INT/2**(NUM_LEVELS/2)):0] [INTPRIORITY_BITS-1:0] l2_intpend_w_prior_en_ff;
logic [(TOTAL_INT/2**(NUM_LEVELS/2)):0] [ID_BITS-1:0] l2_intpend_id_ff;
assign levelx_intpend_w_prior_en[NUM_LEVELS/2][(TOTAL_INT/2**(NUM_LEVELS/2))+1:0] = {{1*INTPRIORITY_BITS{1'b0}},l2_intpend_w_prior_en_ff[(TOTAL_INT/2**(NUM_LEVELS/2)):0]} ;
assign levelx_intpend_id[NUM_LEVELS/2][(TOTAL_INT/2**(NUM_LEVELS/2))+1:0] = {{1*ID_BITS{1'b1}},l2_intpend_id_ff[(TOTAL_INT/2**(NUM_LEVELS/2)):0]} ;
`else
logic [NUM_LEVELS:0] [TOTAL_INT+1:0] [INTPRIORITY_BITS-1:0] level_intpend_w_prior_en;
logic [NUM_LEVELS:0] [TOTAL_INT+1:0] [ID_BITS-1:0] level_intpend_id;
assign level_intpend_w_prior_en[0][TOTAL_INT+1:0] = {{2*INTPRIORITY_BITS{1'b0}},intpend_w_prior_en[TOTAL_INT-1:0]} ;
assign level_intpend_id[0][TOTAL_INT+1:0] = {{2*ID_BITS{1'b1}},intpend_id[TOTAL_INT-1:0]} ;
`endif
genvar l, m , j, k;
// `ifdef VERILATOR
`include "pic_ctrl_verilator_unroll.sv"
// `else
// `ifdef RV_PIC_2CYCLE
// /// Do the prioritization of the interrupts here ////////////
// for (l=0; l<NUM_LEVELS/2 ; l++) begin : TOP_LEVEL
// for (m=0; m<=(TOTAL_INT)/(2**(l+1)) ; m++) begin : COMPARE
// if ( m == (TOTAL_INT)/(2**(l+1))) begin
// assign level_intpend_w_prior_en[l+1][m+1] = '0 ;
// assign level_intpend_id[l+1][m+1] = '0 ;
// end
// cmp_and_mux #(.ID_BITS(ID_BITS),
// .INTPRIORITY_BITS(INTPRIORITY_BITS)) cmp_l1 (
// .a_id(level_intpend_id[l][2*m]),
// .a_priority(level_intpend_w_prior_en[l][2*m]),
// .b_id(level_intpend_id[l][2*m+1]),
// .b_priority(level_intpend_w_prior_en[l][2*m+1]),
// .out_id(level_intpend_id[l+1][m]),
// .out_priority(level_intpend_w_prior_en[l+1][m])) ;
//
// end
// end
//
// for (i=0; i<=TOTAL_INT/2**(NUM_LEVELS/2) ; i++) begin : MIDDLE_FLOPS
// rvdff #(INTPRIORITY_BITS) level2_intpend_prior_reg (.*, .din (level_intpend_w_prior_en[NUM_LEVELS/2][i]), .dout(l2_intpend_w_prior_en_ff[i]), .clk(free_clk));
// rvdff #(ID_BITS) level2_intpend_id_reg (.*, .din (level_intpend_id[NUM_LEVELS/2][i]), .dout(l2_intpend_id_ff[i]), .clk(free_clk));
// end
//
// for (j=NUM_LEVELS/2; j<NUM_LEVELS ; j++) begin : BOT_LEVELS
// for (k=0; k<=(TOTAL_INT)/(2**(j+1)) ; k++) begin : COMPARE
// if ( k == (TOTAL_INT)/(2**(j+1))) begin
// assign levelx_intpend_w_prior_en[j+1][k+1] = '0 ;
// assign levelx_intpend_id[j+1][k+1] = '0 ;
// end
// cmp_and_mux #(.ID_BITS(ID_BITS),
// .INTPRIORITY_BITS(INTPRIORITY_BITS))
// cmp_l1 (
// .a_id(levelx_intpend_id[j][2*k]),
// .a_priority(levelx_intpend_w_prior_en[j][2*k]),
// .b_id(levelx_intpend_id[j][2*k+1]),
// .b_priority(levelx_intpend_w_prior_en[j][2*k+1]),
// .out_id(levelx_intpend_id[j+1][k]),
// .out_priority(levelx_intpend_w_prior_en[j+1][k])) ;
// end
// end
// assign claimid_in[ID_BITS-1:0] = levelx_intpend_id[NUM_LEVELS][0] ; // This is the last level output
// assign selected_int_priority[INTPRIORITY_BITS-1:0] = levelx_intpend_w_prior_en[NUM_LEVELS][0] ;
//
// `else
//
// /// 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<=(TOTAL_INT)/(2**(l+1)) ; m++) begin : COMPARE
// if ( m == (TOTAL_INT)/(2**(l+1))) begin
// assign level_intpend_w_prior_en[l+1][m+1] = '0 ;
// assign level_intpend_id[l+1][m+1] = '0 ;
// end
// cmp_and_mux #(.ID_BITS(ID_BITS),
// .INTPRIORITY_BITS(INTPRIORITY_BITS)) cmp_l1 (
// .a_id(level_intpend_id[l][2*m]),
// .a_priority(level_intpend_w_prior_en[l][2*m]),
// .b_id(level_intpend_id[l][2*m+1]),
// .b_priority(level_intpend_w_prior_en[l][2*m+1]),
// .out_id(level_intpend_id[l+1][m]),
// .out_priority(level_intpend_w_prior_en[l+1][m])) ;
//
// end
// end
// assign claimid_in[ID_BITS-1:0] = level_intpend_id[NUM_LEVELS][0] ; // This is the last level output
// assign selected_int_priority[INTPRIORITY_BITS-1:0] = level_intpend_w_prior_en[NUM_LEVELS][0] ;
//
// `endif
// `endif
///////////////////////////////////////////////////////////////////////
// Config Reg`
///////////////////////////////////////////////////////////////////////
assign config_reg_we = addr_config_pic_match & picm_wren_ff;
assign config_reg_re = addr_config_pic_match & picm_rden_ff;
assign config_reg_in = picm_wr_data_ff[0] ; //
rvdffs #(1) config_reg_ff (.*, .clk(free_clk), .en(config_reg_we), .din (config_reg_in), .dout(config_reg));
assign intpriord = config_reg ;
///////////////////////////////////////////////////////////////////////
// Thresh-hold Reg`
///////////////////////////////////////////////////////////////////////
//assign prithresh_reg_write = addr_prithresh_match & picm_wren_ff;
//assign prithresh_reg_read = addr_prithresh_match & picm_rden_ff;
//
//assign prithresh_reg_in[INTPRIORITY_BITS-1:0] = picm_wr_data_ff[INTPRIORITY_BITS-1:0] ; // Thresh-hold priority.
//rvdffs #(INTPRIORITY_BITS) prithresh_reg_ff (.*, .en(prithresh_reg_write), .din (prithresh_reg_in[INTPRIORITY_BITS-1:0]), .dout(prithresh_reg[INTPRIORITY_BITS-1:0]));
//
//////////////////////////////////////////////////////////////////////////
// Send the interrupt to the core if it is above the thresh-hold
//////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////
/// ClaimId Reg and Corresponding PL
///////////////////////////////////////////////////////////
// logic atleast_one_int_enabled_in,atleast_one_int_enabled ;
// logic mexintpend_unq ;
// logic mhwakeup_unq ;
//
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));
logic [INTPRIORITY_BITS-1:0] meipt_inv , meicurpl_inv ;
assign meipt_inv[INTPRIORITY_BITS-1:0] = intpriord ? ~meipt[INTPRIORITY_BITS-1:0] : meipt[INTPRIORITY_BITS-1:0] ;
assign meicurpl_inv[INTPRIORITY_BITS-1:0] = intpriord ? ~meicurpl[INTPRIORITY_BITS-1:0] : meicurpl[INTPRIORITY_BITS-1:0] ;
assign mexintpend_in = (( selected_int_priority[INTPRIORITY_BITS-1:0] > meipt_inv[INTPRIORITY_BITS-1:0]) &
( selected_int_priority[INTPRIORITY_BITS-1:0] > meicurpl_inv[INTPRIORITY_BITS-1:0]) );
rvdff #(1) mexintpend_ff (.*, .clk(free_clk), .din (mexintpend_in), .dout(mexintpend));
assign maxint[INTPRIORITY_BITS-1:0] = intpriord ? 0 : 15 ;
assign mhwakeup_in = ( pl_in_q[INTPRIORITY_BITS-1:0] == maxint) ;
rvdff #(1) wake_up_ff (.*, .clk(free_clk), .din (mhwakeup_in), .dout(mhwakeup));
// assign atleast_one_int_enabled_in = |intenable_reg[TOTAL_INT-1:0] ;
// rvdff #(1) one_int_en_ff (.*, .din (atleast_one_int_enabled_in), .dout(atleast_one_int_enabled));
//
// assign mexintpend = mexintpend_unq & atleast_one_int_enabled ;
// assign mhwakeup = mhwakeup_unq & atleast_one_int_enabled ;
//////////////////////////////////////////////////////////////////////////
// Reads of register.
// 1- intpending
//////////////////////////////////////////////////////////////////////////
assign intpend_reg_read = addr_intpend_base_match & picm_rden_ff ;
assign intpriority_reg_read = addr_intpriority_base_match & picm_rden_ff;
assign intenable_reg_read = addr_intenable_base_match & picm_rden_ff;
assign gw_config_reg_read = addr_config_gw_base_match & picm_rden_ff;
assign intpend_reg_extended[INTPEND_SIZE-1:0] = {{INTPEND_SIZE-TOTAL_INT{1'b0}},extintsrc_req_gw[TOTAL_INT-1:0]} ;
for (i=0; i<(INT_GRPS); i++) begin
assign intpend_rd_part_out[i] = (({32{intpend_reg_read & picm_addr_ff[5:2] == i}}) & intpend_reg_extended[((32*i)+31):(32*i)]) ;
end
always_comb begin : INTPEND_RD
intpend_rd_out = '0 ;
for (int i=0; i<INT_GRPS; i++) begin
intpend_rd_out |= intpend_rd_part_out[i] ;
end
end
always_comb begin : INTEN_RD
intenable_rd_out = '0 ;
intpriority_rd_out = '0 ;
gw_config_rd_out = '0 ;
for (int i=0; i<TOTAL_INT; i++) begin
if (intenable_reg_re[i]) begin
intenable_rd_out = intenable_reg[i] ;
end
if (intpriority_reg_re[i]) begin
intpriority_rd_out = intpriority_reg[i] ;
end
if (gw_config_reg_re[i]) begin
gw_config_rd_out = gw_config_reg[i] ;
end
end
end
assign picm_rd_data_in[31:0] = ({32{intpend_reg_read }} & intpend_rd_out ) |
({32{intpriority_reg_read }} & {{32-INTPRIORITY_BITS{1'b0}}, intpriority_rd_out } ) |
({32{intenable_reg_read }} & {31'b0 , intenable_rd_out } ) |
({32{gw_config_reg_read }} & {30'b0 , gw_config_rd_out } ) |
({32{config_reg_re }} & {31'b0 , config_reg } ) |
({32{picm_mken_ff & mask[3]}} & {30'b0 , 2'b11 } ) |
({32{picm_mken_ff & mask[2]}} & {31'b0 , 1'b1 } ) |
({32{picm_mken_ff & mask[1]}} & {28'b0 , 4'b1111 } ) |
({32{picm_mken_ff & mask[0]}} & 32'b0 ) ;
assign picm_rd_data[31:0] = picm_rd_data_in[31:0] ;
logic [14:0] address;
assign address[14:0] = picm_addr_ff[14:0];
`include "pic_map_auto.h"
endmodule
module cmp_and_mux #(parameter ID_BITS=8,
INTPRIORITY_BITS = 4)
(
input logic [ID_BITS-1:0] a_id,
input logic [INTPRIORITY_BITS-1:0] a_priority,
input logic [ID_BITS-1:0] b_id,
input logic [INTPRIORITY_BITS-1:0] b_priority,
output logic [ID_BITS-1:0] out_id,
output logic [INTPRIORITY_BITS-1:0] out_priority
);
logic a_is_lt_b ;
assign a_is_lt_b = ( a_priority[INTPRIORITY_BITS-1:0] < b_priority[INTPRIORITY_BITS-1:0] ) ;
// assign a_is_eq_b = ( a_priority[INTPRIORITY_BITS-1:0] == b_priority[INTPRIORITY_BITS-1:0]) ;
assign out_id[ID_BITS-1:0] = a_is_lt_b ? b_id[ID_BITS-1:0] :
a_id[ID_BITS-1:0] ;
assign out_priority[INTPRIORITY_BITS-1:0] = a_is_lt_b ? b_priority[INTPRIORITY_BITS-1:0] :
a_priority[INTPRIORITY_BITS-1:0] ;
endmodule // cmp_and_mux
module configurable_gw (
input logic clk,
input logic rst_l,
input logic extintsrc_req_sync ,
input logic meigwctrl_polarity ,
input logic meigwctrl_type ,
input logic meigwclr ,
output logic extintsrc_req_config
);
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));
assign extintsrc_req_config = meigwctrl_type ? ((extintsrc_req_sync ^ meigwctrl_polarity) | gw_int_pending) : (extintsrc_req_sync ^ meigwctrl_polarity) ;
endmodule // configurable_gw

1351
design/swerv.sv Normal file

File diff suppressed because it is too large Load Diff

409
design/swerv_wrapper.sv Normal file
View File

@ -0,0 +1,409 @@
// 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.
//********************************************************************************
// $Id$
//
// Function: Top wrapper file with swerv/mem instantiated inside
// Comments:
//
//********************************************************************************
`include "build.h"
//`include "def.sv"
module swerv_wrapper
import swerv_types::*;
(
input logic clk,
input logic rst_l,
input logic [31:1] rst_vec,
input logic nmi_int,
input logic [31:1] nmi_vec,
input logic [31:1] jtag_id,
output logic [63:0] trace_rv_i_insn_ip,
output logic [63:0] trace_rv_i_address_ip,
output logic [2:0] trace_rv_i_valid_ip,
output logic [2:0] trace_rv_i_exception_ip,
output logic [4:0] trace_rv_i_ecause_ip,
output logic [2:0] trace_rv_i_interrupt_ip,
output logic [31:0] trace_rv_i_tval_ip,
// Bus signals
`ifdef RV_BUILD_AXI4
//-------------------------- LSU AXI signals--------------------------
// AXI Write Channels
output logic lsu_axi_awvalid,
input logic lsu_axi_awready,
output logic [`RV_LSU_BUS_TAG-1:0] lsu_axi_awid,
output logic [31:0] lsu_axi_awaddr,
output logic [3:0] lsu_axi_awregion,
output logic [7:0] lsu_axi_awlen,
output logic [2:0] lsu_axi_awsize,
output logic [1:0] lsu_axi_awburst,
output logic lsu_axi_awlock,
output logic [3:0] lsu_axi_awcache,
output logic [2:0] lsu_axi_awprot,
output logic [3:0] lsu_axi_awqos,
output logic lsu_axi_wvalid,
input logic lsu_axi_wready,
output logic [63:0] lsu_axi_wdata,
output logic [7:0] lsu_axi_wstrb,
output logic lsu_axi_wlast,
input logic lsu_axi_bvalid,
output logic lsu_axi_bready,
input logic [1:0] lsu_axi_bresp,
input logic [`RV_LSU_BUS_TAG-1:0] lsu_axi_bid,
// AXI Read Channels
output logic lsu_axi_arvalid,
input logic lsu_axi_arready,
output logic [`RV_LSU_BUS_TAG-1:0] lsu_axi_arid,
output logic [31:0] lsu_axi_araddr,
output logic [3:0] lsu_axi_arregion,
output logic [7:0] lsu_axi_arlen,
output logic [2:0] lsu_axi_arsize,
output logic [1:0] lsu_axi_arburst,
output logic lsu_axi_arlock,
output logic [3:0] lsu_axi_arcache,
output logic [2:0] lsu_axi_arprot,
output logic [3:0] lsu_axi_arqos,
input logic lsu_axi_rvalid,
output logic lsu_axi_rready,
input logic [`RV_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,
//-------------------------- IFU AXI signals--------------------------
// AXI Write Channels
output logic ifu_axi_awvalid,
input logic ifu_axi_awready,
output logic [`RV_IFU_BUS_TAG-1:0] ifu_axi_awid,
output logic [31:0] ifu_axi_awaddr,
output logic [3:0] ifu_axi_awregion,
output logic [7:0] ifu_axi_awlen,
output logic [2:0] ifu_axi_awsize,
output logic [1:0] ifu_axi_awburst,
output logic ifu_axi_awlock,
output logic [3:0] ifu_axi_awcache,
output logic [2:0] ifu_axi_awprot,
output logic [3:0] ifu_axi_awqos,
output logic ifu_axi_wvalid,
input logic ifu_axi_wready,
output logic [63:0] ifu_axi_wdata,
output logic [7:0] ifu_axi_wstrb,
output logic ifu_axi_wlast,
input logic ifu_axi_bvalid,
output logic ifu_axi_bready,
input logic [1:0] ifu_axi_bresp,
input logic [`RV_IFU_BUS_TAG-1:0] ifu_axi_bid,
// AXI Read Channels
output logic ifu_axi_arvalid,
input logic ifu_axi_arready,
output logic [`RV_IFU_BUS_TAG-1:0] ifu_axi_arid,
output logic [31:0] ifu_axi_araddr,
output logic [3:0] ifu_axi_arregion,
output logic [7:0] ifu_axi_arlen,
output logic [2:0] ifu_axi_arsize,
output logic [1:0] ifu_axi_arburst,
output logic ifu_axi_arlock,
output logic [3:0] ifu_axi_arcache,
output logic [2:0] ifu_axi_arprot,
output logic [3:0] ifu_axi_arqos,
input logic ifu_axi_rvalid,
output logic ifu_axi_rready,
input logic [`RV_IFU_BUS_TAG-1:0] ifu_axi_rid,
input logic [63:0] ifu_axi_rdata,
input logic [1:0] ifu_axi_rresp,
input logic ifu_axi_rlast,
//-------------------------- SB AXI signals--------------------------
// AXI Write Channels
output logic sb_axi_awvalid,
input logic sb_axi_awready,
output logic [`RV_SB_BUS_TAG-1:0] sb_axi_awid,
output logic [31:0] sb_axi_awaddr,
output logic [3:0] sb_axi_awregion,
output logic [7:0] sb_axi_awlen,
output logic [2:0] sb_axi_awsize,
output logic [1:0] sb_axi_awburst,
output logic sb_axi_awlock,
output logic [3:0] sb_axi_awcache,
output logic [2:0] sb_axi_awprot,
output logic [3:0] sb_axi_awqos,
output logic sb_axi_wvalid,
input logic sb_axi_wready,
output logic [63:0] sb_axi_wdata,
output logic [7:0] sb_axi_wstrb,
output logic sb_axi_wlast,
input logic sb_axi_bvalid,
output logic sb_axi_bready,
input logic [1:0] sb_axi_bresp,
input logic [`RV_SB_BUS_TAG-1:0] sb_axi_bid,
// AXI Read Channels
output logic sb_axi_arvalid,
input logic sb_axi_arready,
output logic [`RV_SB_BUS_TAG-1:0] sb_axi_arid,
output logic [31:0] sb_axi_araddr,
output logic [3:0] sb_axi_arregion,
output logic [7:0] sb_axi_arlen,
output logic [2:0] sb_axi_arsize,
output logic [1:0] sb_axi_arburst,
output logic sb_axi_arlock,
output logic [3:0] sb_axi_arcache,
output logic [2:0] sb_axi_arprot,
output logic [3:0] sb_axi_arqos,
input logic sb_axi_rvalid,
output logic sb_axi_rready,
input logic [`RV_SB_BUS_TAG-1:0] sb_axi_rid,
input logic [63:0] sb_axi_rdata,
input logic [1:0] sb_axi_rresp,
input logic sb_axi_rlast,
//-------------------------- DMA AXI signals--------------------------
// AXI Write Channels
input logic dma_axi_awvalid,
output logic dma_axi_awready,
input logic [`RV_DMA_BUS_TAG-1:0] dma_axi_awid,
input logic [31:0] dma_axi_awaddr,
input logic [2:0] dma_axi_awsize,
input logic [2:0] dma_axi_awprot,
input logic [7:0] dma_axi_awlen,
input logic [1:0] dma_axi_awburst,
input logic dma_axi_wvalid,
output logic dma_axi_wready,
input logic [63:0] dma_axi_wdata,
input logic [7:0] dma_axi_wstrb,
input logic dma_axi_wlast,
output logic dma_axi_bvalid,
input logic dma_axi_bready,
output logic [1:0] dma_axi_bresp,
output logic [`RV_DMA_BUS_TAG-1:0] dma_axi_bid,
// AXI Read Channels
input logic dma_axi_arvalid,
output logic dma_axi_arready,
input logic [`RV_DMA_BUS_TAG-1:0] dma_axi_arid,
input logic [31:0] dma_axi_araddr,
input logic [2:0] dma_axi_arsize,
input logic [2:0] dma_axi_arprot,
input logic [7:0] dma_axi_arlen,
input logic [1:0] dma_axi_arburst,
output logic dma_axi_rvalid,
input logic dma_axi_rready,
output logic [`RV_DMA_BUS_TAG-1:0] dma_axi_rid,
output logic [63:0] dma_axi_rdata,
output logic [1:0] dma_axi_rresp,
output logic dma_axi_rlast,
`endif
`ifdef RV_BUILD_AHB_LITE
//// AHB LITE BUS
output logic [31:0] haddr,
output logic [2:0] hburst,
output logic hmastlock,
output logic [3:0] hprot,
output logic [2:0] hsize,
output logic [1:0] htrans,
output logic hwrite,
input logic [63:0] hrdata,
input logic hready,
input logic hresp,
// LSU AHB Master
output logic [31:0] lsu_haddr,
output logic [2:0] lsu_hburst,
output logic lsu_hmastlock,
output logic [3:0] lsu_hprot,
output logic [2:0] lsu_hsize,
output logic [1:0] lsu_htrans,
output logic lsu_hwrite,
output logic [63:0] lsu_hwdata,
input logic [63:0] lsu_hrdata,
input logic lsu_hready,
input logic lsu_hresp,
// Debug Syster Bus AHB
output logic [31:0] sb_haddr,
output logic [2:0] sb_hburst,
output logic sb_hmastlock,
output logic [3:0] sb_hprot,
output logic [2:0] sb_hsize,
output logic [1:0] sb_htrans,
output logic sb_hwrite,
output logic [63:0] sb_hwdata,
input logic [63:0] sb_hrdata,
input logic sb_hready,
input logic sb_hresp,
// DMA Slave
input logic [31:0] dma_haddr,
input logic [2:0] dma_hburst,
input logic dma_hmastlock,
input logic [3:0] dma_hprot,
input logic [2:0] dma_hsize,
input logic [1:0] dma_htrans,
input logic dma_hwrite,
input logic [63:0] dma_hwdata,
input logic dma_hsel,
input logic dma_hreadyin,
output logic [63:0] dma_hrdata,
output logic dma_hreadyout,
output logic dma_hresp,
`endif
// clk ratio signals
input logic lsu_bus_clk_en, // Clock ratio b/w cpu core clk & AHB master interface
input logic ifu_bus_clk_en, // Clock ratio b/w cpu core clk & AHB master interface
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
// input logic ext_int,
input logic timer_int,
input logic [`RV_PIC_TOTAL_INT:1] extintsrc_req,
output logic [1:0] dec_tlu_perfcnt0, // toggles when perf counter 0 has an event inc
output logic [1:0] dec_tlu_perfcnt1,
output logic [1:0] dec_tlu_perfcnt2,
output logic [1:0] 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
input logic jtag_trst_n, // JTAG Reset
output logic jtag_tdo, // JTAG TDO
// external MPC halt/run interface
input logic mpc_debug_halt_req, // Async halt request
input logic mpc_debug_run_req, // Async run request
input logic mpc_reset_run_req, // Run/halt after reset
output logic mpc_debug_halt_ack, // Halt ack
output logic mpc_debug_run_ack, // Run ack
output logic debug_brkpt_status, // debug breakpoint
input logic i_cpu_halt_req, // Async halt req to CPU
output logic o_cpu_halt_ack, // core response to halt
output logic o_cpu_halt_status, // 1'b1 indicates core is halted
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 i_cpu_run_req, // Async restart req to CPU
output logic o_cpu_run_ack, // Core response to run req
input logic scan_mode, // To enable scan mode
input logic mbist_mode // to enable mbist
);
`include "global.h"
// DCCM ports
logic dccm_wren;
logic dccm_rden;
logic [DCCM_BITS-1:0] dccm_wr_addr;
logic [DCCM_BITS-1:0] dccm_rd_addr_lo;
logic [DCCM_BITS-1:0] dccm_rd_addr_hi;
logic [DCCM_FDATA_WIDTH-1:0] dccm_wr_data;
logic [DCCM_FDATA_WIDTH-1:0] dccm_rd_data_lo;
logic [DCCM_FDATA_WIDTH-1:0] dccm_rd_data_hi;
logic lsu_freeze_dc3;
// PIC ports
// Icache & Itag ports
logic [31:3] ic_rw_addr;
logic [3:0] ic_wr_en ; // Which way to write
logic ic_rd_en ;
logic [3:0] ic_tag_valid; // Valid from the I$ tag valid outside (in flops).
logic [3:0] ic_rd_hit; // ic_rd_hit[3:0]
logic ic_tag_perr; // Ic tag parity error
logic [15:2] ic_debug_addr; // Read/Write addresss to the Icache.
logic ic_debug_rd_en; // Icache debug rd
logic ic_debug_wr_en; // Icache debug wr
logic ic_debug_tag_array; // Debug tag array
logic [3:0] ic_debug_way; // Debug way. Rd or Wr.
`ifdef RV_ICACHE_ECC
logic [24:0] ictag_debug_rd_data;// Debug icache tag.
logic [83:0] ic_wr_data; // ic_wr_data[135:0]
logic [167:0] ic_rd_data; // ic_rd_data[135:0]
logic [41:0] ic_debug_wr_data; // Debug wr cache.
`else
logic [20:0] ictag_debug_rd_data;// Debug icache tag.
logic [67:0] ic_wr_data; // ic_wr_data[135:0]
logic [135:0] ic_rd_data; // ic_rd_data[135:0]
logic [33:0] ic_debug_wr_data; // Debug wr cache.
`endif
logic [127:0] ic_premux_data;
logic ic_sel_premux_data;
`ifdef RV_ICCM_ENABLE
// ICCM ports
logic [`RV_ICCM_BITS-1:2] iccm_rw_addr;
logic iccm_wren;
logic iccm_rden;
logic [2:0] iccm_wr_size;
logic [77:0] iccm_wr_data;
logic [155:0] iccm_rd_data;
`endif
logic core_rst_l; // Core reset including rst_l and dbg_rst_l
logic jtag_tdoEn;
logic dccm_clk_override;
logic icm_clk_override;
logic dec_tlu_core_ecc_disable;
// Instantiate the swerv core
swerv swerv (
.*
);
// Instantiate the mem
mem mem (
.rst_l(core_rst_l),
.*
);
endmodule

166
testbench/ahb_sif.sv Normal file
View File

@ -0,0 +1,166 @@
// 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.
//
module ahb_sif (
input logic [63:0] HWDATA,
input logic HCLK,
input logic HSEL,
input logic [3:0] HPROT,
input logic HWRITE,
input logic [1:0] HTRANS,
input logic [2:0] HSIZE,
input logic HREADY,
input logic HRESETn,
input logic [31:0] HADDR,
input logic [2:0] HBURST,
output logic HREADYOUT,
output logic HRESP,
output logic [63:0] HRDATA
);
localparam MEM_SIZE_DW = 8192;
localparam MAILBOX_ADDR = 32'hD0580000;
logic Last_HSEL;
logic NextLast_HSEL;
logic Last_HWRITE;
logic [1:0] Last_HTRANS;
logic [1:0] NextLast_HTRANS;
logic [31:0] Last_HADDR;
logic [63:0] Next_HRDATA;
logic [63:0] WriteReadData;
logic [63:0] WriteMask;
bit [7:0] mem [0:MEM_SIZE_DW-1];
// Wires
wire [63:0] Next_WriteMask = HSIZE == 3'b000 ? (64'hff << {HADDR[2:0], 3'b000}) : (HSIZE == 3'b001 ? (64'hffff << {HADDR[2], 4'h0}) : (HSIZE == 3'b010 ? (64'hffff_ffff << {HADDR[3],5'h0}) : 64'hffff_ffff_ffff_ffff));
wire [63:0] MaskedWriteData = HWDATA & WriteMask;
wire [63:0] MaskedWriteReadData = WriteReadData & ~WriteMask;
wire [63:0] WriteData = (MaskedWriteData | MaskedWriteReadData );
wire Write = &{Last_HSEL, Last_HWRITE, Last_HTRANS[1]};
wire Read = &{ HSEL, ~HWRITE, HTRANS[1]};
wire mailbox_write = &{Write, Last_HADDR==MAILBOX_ADDR, HRESETn==1};
wire Next_HWRITE = |{HTRANS} ? HWRITE : Last_HWRITE;
wire [63:0] mem_dout = {mem[{Last_HADDR[12:3],3'b0}+7],mem[{Last_HADDR[12:3],3'b0}+6],mem[{Last_HADDR[12:3],3'b0}+5],mem[{Last_HADDR[12:3],3'b0}+4],mem[{Last_HADDR[12:3],3'b0}+3],mem[{Last_HADDR[12:3],3'b0}+2],mem[{Last_HADDR[12:3],3'b0}+1],mem[{Last_HADDR[12:3],3'b0}]};
always @ (posedge HCLK or negedge HRESETn) begin
if (Write && Last_HADDR == 32'h0) begin
mem[{Last_HADDR[12:3],3'b0}+7] <= #1 { WriteData[63:56] };
mem[{Last_HADDR[12:3],3'b0}+6] <= #1 { WriteData[55:48] };
mem[{Last_HADDR[12:3],3'b0}+5] <= #1 { WriteData[47:40] };
mem[{Last_HADDR[12:3],3'b0}+4] <= #1 { WriteData[39:32] };
mem[{Last_HADDR[12:3],3'b0}+3] <= #1 { WriteData[31:24] };
mem[{Last_HADDR[12:3],3'b0}+2] <= #1 { WriteData[23:16] };
mem[{Last_HADDR[12:3],3'b0}+1] <= #1 { WriteData[15:08] };
mem[{Last_HADDR[12:3],3'b0}+0] <= #1 { WriteData[07:00] };
end
end
always @(posedge HCLK or negedge HRESETn) begin
if(~HRESETn) begin
HREADYOUT <= #1 1'b0 ;
HRESP <= #1 1'b0;
end else begin
HREADYOUT <= #1 |HTRANS;
HRESP <= #1 1'b0;
WriteMask <= #1 Next_WriteMask;
end
end
`ifdef VERILATOR
always @(posedge HCLK or negedge HRESETn) begin
`else
always @(negedge HCLK or negedge HRESETn) begin
`endif
if(~HRESETn) begin
Last_HADDR <= #1 32'b0;
end else begin
Last_HADDR <= #1 |{HTRANS} ? {HADDR[31:2], 2'b00} : Last_HADDR;
end
end
always @(posedge HCLK or negedge HRESETn) begin
if(~HRESETn) begin
Last_HWRITE <= #1 1'b0;
end else begin
Last_HWRITE <= #1 Next_HWRITE;
end
end
always @(posedge HCLK or negedge HRESETn) begin
if(~HRESETn) begin
Last_HTRANS <= #1 2'b0;
end else begin
Last_HTRANS <= #1 HTRANS;
end
end
always @(posedge HCLK or negedge HRESETn) begin
if(~HRESETn) begin
Last_HSEL <= #1 1'b0;
end else begin
Last_HSEL <= #1 HSEL;
end
end
`ifndef VERILATOR
always @(posedge HCLK or negedge HRESETn) begin
if(~HRESETn) begin
HRDATA <= #1 Next_HRDATA ;
end else begin
HRDATA <= #1 Next_HRDATA ;
end
end
always @* begin
Next_HRDATA = mem_dout;
end
`else
always @(posedge HCLK) begin
Next_HRDATA <= mem_dout;
end
assign HRDATA = mem_dout;
`endif
always @* begin
if(Last_HSEL) begin
WriteReadData[07:00] = mem[{Last_HADDR[12:3],3'b0}];
WriteReadData[15:08] = mem[{Last_HADDR[12:3],3'b0}+1];
WriteReadData[23:16] = mem[{Last_HADDR[12:3],3'b0}+2];
WriteReadData[31:24] = mem[{Last_HADDR[12:3],3'b0}+3];
WriteReadData[39:32] = mem[{Last_HADDR[12:3],3'b0}+4];
WriteReadData[47:40] = mem[{Last_HADDR[12:3],3'b0}+5];
WriteReadData[55:48] = mem[{Last_HADDR[12:3],3'b0}+6];
WriteReadData[63:56] = mem[{Last_HADDR[12:3],3'b0}+7];
end
end
endmodule

View File

@ -0,0 +1,67 @@
.global _start
_start:
csrrw x2, 0xb02, x3
lui x5, 974848
ori x5, x5, 0
csrrw x2, 0x305, x5
lui x6, 382293
ori x6, x6, 1365
csrrw x1, 0x7c0, x6
lui x5, 0
ori x5, x5, 0
csrrw x2, 0x7f8, x5
lui x5, 0
ori x5, x5, 0
csrrw x2, 0x7f9, x5
addi x0, x0, 0
lui x11, 853376
ori x9, x0, 'H'
sw x9, 0 (x11)
ori x9, x0, 'E'
sw x9, 0 (x11)
ori x9, x0, 'L'
sw x9, 0 (x11)
sw x9, 0 (x11)
ori x9, x0, 'O'
sw x9, 0 (x11)
ori x9, x0, ' '
sw x9, 0 (x11)
addi x9, x0, 'W'
sw x9, 0 (x11)
ori x9, x0, 'O'
sw x9, 0 (x11)
ori x9, x0, 'R'
sw x9, 0 (x11)
ori x9, x0, 'L'
sw x9, 0 (x11)
ori x9, x0, 'D'
sw x9, 0 (x11)
ori x9, x0, '!'
sw x9, 0 (x11)
ori x9, x0, 255
sw x9, 0 (x11)
addi x1,x0,0
finish:
addi x1,x1,1
jal x0, finish;
addi x0,x0,0
addi x0,x0,0
addi x0,x0,0
addi x0,x0,0

View File

@ -0,0 +1,71 @@
// 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"
#define STDOUT 0xd0580000
// Code to execute
.section .text
.global _start
_start:
// Clear minstret
csrw minstret, zero
csrw minstreth, zero
// Set up MTVEC - not expecting to use it though
li x1, RV_ICCM_SADR
csrw mtvec, x1
// Enable Caches in MRAC
li x1, 0x55555555
csrw 0x7c0, x1
// Load string from hw_data
// and write to stdout address
li x3, STDOUT
la x4, hw_data
loop:
lb x5, 0(x4)
sb x5, 0(x3)
addi x4, x4, 1
bnez x5, loop
// Write 0xff to STDOUT for TB to termiate test.
_finish:
li x3, STDOUT
addi x5, x0, 0xff
sb x5, 0(x3)
beq x0, x0, _finish
.rept 100
nop
.endr
.data
hw_data:
.ascii "------------------------------------\n"
.ascii "Hello World from SweRV EH1.1 @WDC !!\n"
.ascii "------------------------------------"
.byte 0

42
testbench/flist.spyglass Normal file
View File

@ -0,0 +1,42 @@
$RV_ROOT/design/swerv_wrapper.sv
$RV_ROOT/design/mem.sv
$RV_ROOT/design/pic_ctrl.sv
$RV_ROOT/design/swerv.sv
$RV_ROOT/design/dma_ctrl.sv
$RV_ROOT/design/ifu/ifu_aln_ctl.sv
$RV_ROOT/design/ifu/ifu_compress_ctl.sv
$RV_ROOT/design/ifu/ifu_ifc_ctl.sv
$RV_ROOT/design/ifu/ifu_bp_ctl.sv
$RV_ROOT/design/ifu/ifu_ic_mem.sv
$RV_ROOT/design/ifu/ifu_mem_ctl.sv
$RV_ROOT/design/ifu/ifu_iccm_mem.sv
$RV_ROOT/design/ifu/ifu.sv
$RV_ROOT/design/dec/dec_decode_ctl.sv
$RV_ROOT/design/dec/dec_gpr_ctl.sv
$RV_ROOT/design/dec/dec_ib_ctl.sv
$RV_ROOT/design/dec/dec_tlu_ctl.sv
$RV_ROOT/design/dec/dec_trigger.sv
$RV_ROOT/design/dec/dec.sv
$RV_ROOT/design/exu/exu_alu_ctl.sv
$RV_ROOT/design/exu/exu_mul_ctl.sv
$RV_ROOT/design/exu/exu_div_ctl.sv
$RV_ROOT/design/exu/exu.sv
$RV_ROOT/design/lsu/lsu.sv
$RV_ROOT/design/lsu/lsu_clkdomain.sv
$RV_ROOT/design/lsu/lsu_addrcheck.sv
$RV_ROOT/design/lsu/lsu_lsc_ctl.sv
$RV_ROOT/design/lsu/lsu_stbuf.sv
$RV_ROOT/design/lsu/lsu_bus_buffer.sv
$RV_ROOT/design/lsu/lsu_bus_intf.sv
$RV_ROOT/design/lsu/lsu_ecc.sv
$RV_ROOT/design/lsu/lsu_dccm_mem.sv
$RV_ROOT/design/lsu/lsu_dccm_ctl.sv
$RV_ROOT/design/lsu/lsu_trigger.sv
$RV_ROOT/design/dbg/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.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

42
testbench/flist.vcs Normal file
View File

@ -0,0 +1,42 @@
$RV_ROOT/design/swerv_wrapper.sv
$RV_ROOT/design/mem.sv
$RV_ROOT/design/pic_ctrl.sv
$RV_ROOT/design/swerv.sv
$RV_ROOT/design/dma_ctrl.sv
$RV_ROOT/design/ifu/ifu_aln_ctl.sv
$RV_ROOT/design/ifu/ifu_compress_ctl.sv
$RV_ROOT/design/ifu/ifu_ifc_ctl.sv
$RV_ROOT/design/ifu/ifu_bp_ctl.sv
$RV_ROOT/design/ifu/ifu_ic_mem.sv
$RV_ROOT/design/ifu/ifu_mem_ctl.sv
$RV_ROOT/design/ifu/ifu_iccm_mem.sv
$RV_ROOT/design/ifu/ifu.sv
$RV_ROOT/design/dec/dec_decode_ctl.sv
$RV_ROOT/design/dec/dec_gpr_ctl.sv
$RV_ROOT/design/dec/dec_ib_ctl.sv
$RV_ROOT/design/dec/dec_tlu_ctl.sv
$RV_ROOT/design/dec/dec_trigger.sv
$RV_ROOT/design/dec/dec.sv
$RV_ROOT/design/exu/exu_alu_ctl.sv
$RV_ROOT/design/exu/exu_mul_ctl.sv
$RV_ROOT/design/exu/exu_div_ctl.sv
$RV_ROOT/design/exu/exu.sv
$RV_ROOT/design/lsu/lsu.sv
$RV_ROOT/design/lsu/lsu_clkdomain.sv
$RV_ROOT/design/lsu/lsu_addrcheck.sv
$RV_ROOT/design/lsu/lsu_lsc_ctl.sv
$RV_ROOT/design/lsu/lsu_stbuf.sv
$RV_ROOT/design/lsu/lsu_bus_buffer.sv
$RV_ROOT/design/lsu/lsu_bus_intf.sv
$RV_ROOT/design/lsu/lsu_ecc.sv
$RV_ROOT/design/lsu/lsu_dccm_mem.sv
$RV_ROOT/design/lsu/lsu_dccm_ctl.sv
$RV_ROOT/design/lsu/lsu_trigger.sv
$RV_ROOT/design/dbg/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.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

42
testbench/flist.verilator Normal file
View File

@ -0,0 +1,42 @@
$RV_ROOT/design/swerv_wrapper.sv
$RV_ROOT/design/mem.sv
$RV_ROOT/design/pic_ctrl.sv
$RV_ROOT/design/swerv.sv
$RV_ROOT/design/dma_ctrl.sv
$RV_ROOT/design/ifu/ifu_aln_ctl.sv
$RV_ROOT/design/ifu/ifu_compress_ctl.sv
$RV_ROOT/design/ifu/ifu_ifc_ctl.sv
$RV_ROOT/design/ifu/ifu_bp_ctl.sv
$RV_ROOT/design/ifu/ifu_ic_mem.sv
$RV_ROOT/design/ifu/ifu_mem_ctl.sv
$RV_ROOT/design/ifu/ifu_iccm_mem.sv
$RV_ROOT/design/ifu/ifu.sv
$RV_ROOT/design/dec/dec_decode_ctl.sv
$RV_ROOT/design/dec/dec_gpr_ctl.sv
$RV_ROOT/design/dec/dec_ib_ctl.sv
$RV_ROOT/design/dec/dec_tlu_ctl.sv
$RV_ROOT/design/dec/dec_trigger.sv
$RV_ROOT/design/dec/dec.sv
$RV_ROOT/design/exu/exu_alu_ctl.sv
$RV_ROOT/design/exu/exu_mul_ctl.sv
$RV_ROOT/design/exu/exu_div_ctl.sv
$RV_ROOT/design/exu/exu.sv
$RV_ROOT/design/lsu/lsu.sv
$RV_ROOT/design/lsu/lsu_clkdomain.sv
$RV_ROOT/design/lsu/lsu_addrcheck.sv
$RV_ROOT/design/lsu/lsu_lsc_ctl.sv
$RV_ROOT/design/lsu/lsu_stbuf.sv
$RV_ROOT/design/lsu/lsu_bus_buffer.sv
$RV_ROOT/design/lsu/lsu_bus_intf.sv
$RV_ROOT/design/lsu/lsu_ecc.sv
$RV_ROOT/design/lsu/lsu_dccm_mem.sv
$RV_ROOT/design/lsu/lsu_dccm_ctl.sv
$RV_ROOT/design/lsu/lsu_trigger.sv
$RV_ROOT/design/dbg/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.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

42
testbench/flist.vlog Normal file
View File

@ -0,0 +1,42 @@
$RV_ROOT/design/swerv_wrapper.sv
$RV_ROOT/design/mem.sv
$RV_ROOT/design/pic_ctrl.sv
$RV_ROOT/design/swerv.sv
$RV_ROOT/design/dma_ctrl.sv
$RV_ROOT/design/ifu/ifu_aln_ctl.sv
$RV_ROOT/design/ifu/ifu_compress_ctl.sv
$RV_ROOT/design/ifu/ifu_ifc_ctl.sv
$RV_ROOT/design/ifu/ifu_bp_ctl.sv
$RV_ROOT/design/ifu/ifu_ic_mem.sv
$RV_ROOT/design/ifu/ifu_mem_ctl.sv
$RV_ROOT/design/ifu/ifu_iccm_mem.sv
$RV_ROOT/design/ifu/ifu.sv
$RV_ROOT/design/dec/dec_decode_ctl.sv
$RV_ROOT/design/dec/dec_gpr_ctl.sv
$RV_ROOT/design/dec/dec_ib_ctl.sv
$RV_ROOT/design/dec/dec_tlu_ctl.sv
$RV_ROOT/design/dec/dec_trigger.sv
$RV_ROOT/design/dec/dec.sv
$RV_ROOT/design/exu/exu_alu_ctl.sv
$RV_ROOT/design/exu/exu_mul_ctl.sv
$RV_ROOT/design/exu/exu_div_ctl.sv
$RV_ROOT/design/exu/exu.sv
$RV_ROOT/design/lsu/lsu.sv
$RV_ROOT/design/lsu/lsu_clkdomain.sv
$RV_ROOT/design/lsu/lsu_addrcheck.sv
$RV_ROOT/design/lsu/lsu_lsc_ctl.sv
$RV_ROOT/design/lsu/lsu_stbuf.sv
$RV_ROOT/design/lsu/lsu_bus_buffer.sv
$RV_ROOT/design/lsu/lsu_bus_intf.sv
$RV_ROOT/design/lsu/lsu_ecc.sv
$RV_ROOT/design/lsu/lsu_dccm_mem.sv
$RV_ROOT/design/lsu/lsu_dccm_ctl.sv
$RV_ROOT/design/lsu/lsu_trigger.sv
$RV_ROOT/design/dbg/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.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

7
testbench/hex/data.hex Executable file
View File

@ -0,0 +1,7 @@
@00001000
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 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 00

View File

@ -0,0 +1,6 @@
@00000000
73 10 20 B0 73 10 20 B8 B7 00 00 EE 73 90 50 30
B7 50 55 55 93 80 50 55 73 90 00 7C B7 01 58 D0
17 12 00 00 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

4
testbench/input.tcl Normal file
View File

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

12
testbench/link.ld Normal file
View File

@ -0,0 +1,12 @@
OUTPUT_ARCH( "riscv" )
ENTRY(_start)
SECTIONS
{
. = 0x1000;
.data . : { *(.*data) *(.rodata*) }
. = 0x0;
.text . : { *(.text) }
_end = .;
}

415
testbench/tb_top.sv Normal file
View File

@ -0,0 +1,415 @@
// 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.
//
`ifndef VERILATOR
module tb_top;
`else
module tb_top ( input logic core_clk, input logic reset_l, output finished);
`endif
`ifndef VERILATOR
logic reset_l;
logic core_clk;
`endif
logic nmi_int;
logic [31:0] reset_vector;
logic [31:0] nmi_vector;
logic [31:1] jtag_id;
logic [31:0] ic_haddr ;
logic [2:0] ic_hburst ;
logic ic_hmastlock ;
logic [3:0] ic_hprot ;
logic [2:0] ic_hsize ;
logic [1:0] ic_htrans ;
logic ic_hwrite ;
logic [63:0] ic_hrdata ;
logic ic_hready ;
logic ic_hresp ;
logic [31:0] lsu_haddr ;
logic [2:0] lsu_hburst ;
logic lsu_hmastlock ;
logic [3:0] lsu_hprot ;
logic [2:0] lsu_hsize ;
logic [1:0] lsu_htrans ;
logic lsu_hwrite ;
logic [63:0] lsu_hrdata ;
logic [63:0] lsu_hwdata ;
logic lsu_hready ;
logic lsu_hresp ;
logic [31:0] sb_haddr ;
logic [2:0] sb_hburst ;
logic sb_hmastlock ;
logic [3:0] sb_hprot ;
logic [2:0] sb_hsize ;
logic [1:0] sb_htrans ;
logic sb_hwrite ;
logic [63:0] sb_hrdata ;
logic [63:0] sb_hwdata ;
logic sb_hready ;
logic sb_hresp ;
logic [63:0] trace_rv_i_insn_ip;
logic [63:0] trace_rv_i_address_ip;
logic [2:0] trace_rv_i_valid_ip;
logic [2:0] trace_rv_i_exception_ip;
logic [4:0] trace_rv_i_ecause_ip;
logic [2:0] trace_rv_i_interrupt_ip;
logic [31:0] trace_rv_i_tval_ip;
logic o_debug_mode_status;
logic [1:0] dec_tlu_perfcnt0;
logic [1:0] dec_tlu_perfcnt1;
logic [1:0] dec_tlu_perfcnt2;
logic [1:0] dec_tlu_perfcnt3;
logic jtag_tdo;
logic o_cpu_halt_ack;
logic o_cpu_halt_status;
logic o_cpu_run_ack;
logic mailbox_write;
logic [63:0] dma_hrdata ;
logic [63:0] dma_hwdata ;
logic dma_hready ;
logic dma_hresp ;
logic mpc_debug_halt_req;
logic mpc_debug_run_req;
logic mpc_reset_run_req;
logic mpc_debug_halt_ack;
logic mpc_debug_run_ack;
logic debug_brkpt_status;
logic [31:0] cycleCnt ;
logic mailbox_data_val;
logic finished;
wire dma_hready_out;
//assign mailbox_write = &{i_ahb_lsu.Write, i_ahb_lsu.Last_HADDR==32'hD0580000, i_ahb_lsu.HRESETn==1};
assign mailbox_write = i_ahb_lsu.mailbox_write;
//assign mailbox_write = i_ahb_lsu.mailbox_write & !core_clk;
assign mailbox_data_val = (i_ahb_lsu.WriteData[7:0] > 8'h5) & (i_ahb_lsu.WriteData[7:0] < 8'h7f);
assign finished = finished | &{i_ahb_lsu.mailbox_write, (i_ahb_lsu.WriteData[7:0] == 8'hff)};
assign jtag_id[31:28] = 4'b1;
assign jtag_id[27:12] = '0;
assign jtag_id[11:1] = 11'h45;
`ifndef VERILATOR
`define FORCE force
`else
`define FORCE
`endif
integer fd;
initial begin
fd = $fopen("console.log","w");
end
integer tp;
always @(posedge core_clk or negedge reset_l) begin
if( reset_l == 0)
cycleCnt <= 0;
else
cycleCnt <= cycleCnt+1;
end
always @(posedge core_clk) begin
//if(cycleCnt == 32'h800)
if(cycleCnt == 32'h800) begin
$display ("Hit max cycle count.. stopping");
$finish;
end
end
`ifdef VERILATOR
always @(negedge mailbox_write)
`else
always @(posedge mailbox_write)
`endif
if( mailbox_data_val ) begin
$fwrite(fd,"%c", i_ahb_lsu.WriteData[7:0]);
$write("%c", i_ahb_lsu.WriteData[7:0]);
end
always @(posedge finished) begin
$display("\n\nFinished : minstret = %0d, mcycle = %0d", rvtop.swerv.dec.tlu.minstretl[31:0],rvtop.swerv.dec.tlu.mcyclel[31:0]);
`ifndef VERILATOR
$finish;
`endif
end
always @(posedge core_clk)
if (rvtop.trace_rv_i_valid_ip !== 0) begin
$fwrite(tp,"%b,%h,%h,%0h,%0h,3,%b,%h,%h,%b\n", rvtop.trace_rv_i_valid_ip, rvtop.trace_rv_i_address_ip[63:32], rvtop.trace_rv_i_address_ip[31:0], rvtop.trace_rv_i_insn_ip[63:32], rvtop.trace_rv_i_insn_ip[31:0],rvtop.trace_rv_i_exception_ip,rvtop.trace_rv_i_ecause_ip,rvtop.trace_rv_i_tval_ip,rvtop.trace_rv_i_interrupt_ip);
end
initial begin
`ifndef VERILATOR
core_clk = 0;
reset_l = 0;
`endif
reset_vector = 32'h80000000;
nmi_vector = 32'hee000000;
nmi_int = 0;
`ifndef VERILATOR
@(posedge core_clk);
reset_l = 0;
`endif
$readmemh("data.hex", i_ahb_lsu.mem);
$readmemh("program.hex", i_ahb_ic.mem);
tp = $fopen("trace_port.csv","w");
`ifndef VERILATOR
repeat (5) @(posedge core_clk);
reset_l = 1;
#100000 $display("");$finish;
`endif
end
`ifndef VERILATOR
initial begin
forever begin
core_clk = #5 ~core_clk;
end
end
`endif
//=========================================================================-
// RTL instance
//=========================================================================-
swerv_wrapper rvtop (
.rst_l ( reset_l ),
.clk ( core_clk ),
.rst_vec ( 31'h40000000 ),
.nmi_int ( nmi_int ),
.nmi_vec ( 31'h77000000 ),
.jtag_id (jtag_id[31:1]),
.haddr ( ic_haddr ),
.hburst ( ic_hburst ),
.hmastlock ( ic_hmastlock ),
.hprot ( ic_hprot ),
.hsize ( ic_hsize ),
.htrans ( ic_htrans ),
.hwrite ( ic_hwrite ),
.hrdata ( ic_hrdata[63:0]),
.hready ( ic_hready ),
.hresp ( ic_hresp ),
//---------------------------------------------------------------
// Debug AHB Master
//---------------------------------------------------------------
.sb_haddr ( sb_haddr ),
.sb_hburst ( sb_hburst ),
.sb_hmastlock ( sb_hmastlock ),
.sb_hprot ( sb_hprot ),
.sb_hsize ( sb_hsize ),
.sb_htrans ( sb_htrans ),
.sb_hwrite ( sb_hwrite ),
.sb_hwdata ( sb_hwdata ),
.sb_hrdata ( sb_hrdata ),
.sb_hready ( sb_hready ),
.sb_hresp ( sb_hresp ),
//---------------------------------------------------------------
// LSU AHB Master
//---------------------------------------------------------------
.lsu_haddr ( lsu_haddr ),
.lsu_hburst ( lsu_hburst ),
.lsu_hmastlock ( lsu_hmastlock ),
.lsu_hprot ( lsu_hprot ),
.lsu_hsize ( lsu_hsize ),
.lsu_htrans ( lsu_htrans ),
.lsu_hwrite ( lsu_hwrite ),
.lsu_hwdata ( lsu_hwdata ),
.lsu_hrdata ( lsu_hrdata[63:0]),
.lsu_hready ( lsu_hready ),
.lsu_hresp ( lsu_hresp ),
//---------------------------------------------------------------
// DMA Slave
//---------------------------------------------------------------
.dma_haddr ( '0 ),
.dma_hburst ( '0 ),
.dma_hmastlock ( '0 ),
.dma_hprot ( '0 ),
.dma_hsize ( '0 ),
.dma_htrans ( '0 ),
.dma_hwrite ( '0 ),
.dma_hwdata ( '0 ),
.dma_hrdata ( dma_hrdata ),
.dma_hresp ( dma_hresp ),
.dma_hsel ( 1'b1 ),
.dma_hreadyin ( dma_hready_out ),
.dma_hreadyout ( dma_hready_out ),
.timer_int ( 1'b0 ),
`ifdef TB_RESTRUCT
.extintsrc_req ( '0 ),
`else
.extintsrc_req ( '0 ),
`endif
`ifdef RV_BUILD_AHB_LITE
.lsu_bus_clk_en ( 1'b1 ),// Clock ratio b/w cpu core clk & AHB master interface
.ifu_bus_clk_en ( 1'b1 ),// Clock ratio b/w cpu core clk & AHB master interface
.dbg_bus_clk_en ( 1'b0 ),// Clock ratio b/w cpu core clk & AHB Debug master interface
.dma_bus_clk_en ( 1'b0 ),// Clock ratio b/w cpu core clk & AHB slave interface
`endif
.trace_rv_i_insn_ip(trace_rv_i_insn_ip),
.trace_rv_i_address_ip(trace_rv_i_address_ip),
.trace_rv_i_valid_ip(trace_rv_i_valid_ip),
.trace_rv_i_exception_ip(trace_rv_i_exception_ip),
.trace_rv_i_ecause_ip(trace_rv_i_ecause_ip),
.trace_rv_i_interrupt_ip(trace_rv_i_interrupt_ip),
.trace_rv_i_tval_ip(trace_rv_i_tval_ip),
.jtag_tck ( 1'b0 ), // JTAG clk
.jtag_tms ( 1'b0 ), // JTAG TMS
.jtag_tdi ( 1'b0 ), // JTAG tdi
.jtag_trst_n ( 1'b0 ), // JTAG Reset
.jtag_tdo ( jtag_tdo ), // JTAG TDO
.mpc_debug_halt_ack ( mpc_debug_halt_ack),
.mpc_debug_halt_req ( 1'b0),
.mpc_debug_run_ack ( mpc_debug_run_ack),
.mpc_debug_run_req ( 1'b1),
.mpc_reset_run_req ( 1'b1), // Start running after reset
.debug_brkpt_status (debug_brkpt_status),
.i_cpu_halt_req ( 1'b0 ), // Async halt req to CPU
.o_cpu_halt_ack ( o_cpu_halt_ack ), // core response to halt
.o_cpu_halt_status ( o_cpu_halt_status ), // 1'b1 indicates core is halted
.i_cpu_run_req ( 1'b0 ), // Async restart req to CPU
.o_debug_mode_status (o_debug_mode_status),
.o_cpu_run_ack ( o_cpu_run_ack ), // Core response to run req
.dec_tlu_perfcnt0(dec_tlu_perfcnt0),
.dec_tlu_perfcnt1(dec_tlu_perfcnt1),
.dec_tlu_perfcnt2(dec_tlu_perfcnt2),
.dec_tlu_perfcnt3(dec_tlu_perfcnt3),
.scan_mode ( 1'b0 ), // To enable scan mode
.mbist_mode ( 1'b0 ) // to enable mbist
);
initial begin
`FORCE rvtop.dccm_rd_data_hi = '0;
`FORCE rvtop.dccm_rd_data_lo = '0;
end
//=========================================================================-
// AHB I$ instance
//=========================================================================-
ahb_sif i_ahb_ic (
// Inputs
.HWDATA(64'h0),
.HCLK(core_clk),
.HSEL(1'b1),
.HPROT(ic_hprot),
.HWRITE(ic_hwrite),
.HTRANS(ic_htrans),
.HSIZE(ic_hsize),
.HREADY(ic_hready),
.HRESETn(reset_l),
.HADDR(ic_haddr),
.HBURST(ic_hburst),
// Outputs
.HREADYOUT(ic_hready),
.HRESP(ic_hresp),
.HRDATA(ic_hrdata[63:0])
);
ahb_sif i_ahb_lsu (
// Inputs
.HWDATA(lsu_hwdata),
.HCLK(core_clk),
.HSEL(1'b1),
.HPROT(lsu_hprot),
.HWRITE(lsu_hwrite),
.HTRANS(lsu_htrans),
.HSIZE(lsu_hsize),
.HREADY(lsu_hready),
.HRESETn(reset_l),
.HADDR(lsu_haddr),
.HBURST(lsu_hburst),
// Outputs
.HREADYOUT(lsu_hready),
.HRESP(lsu_hresp),
.HRDATA(lsu_hrdata[63:0])
);
ahb_sif i_ahb_sb (
// Inputs
.HWDATA(sb_hwdata),
.HCLK(core_clk),
.HSEL(1'b1),
.HPROT(sb_hprot),
.HWRITE(sb_hwrite),
.HTRANS(sb_htrans),
.HSIZE(sb_hsize),
.HREADY(1'b0),
.HRESETn(reset_l),
.HADDR(sb_haddr),
.HBURST(sb_hburst),
// Outputs
.HREADYOUT(sb_hready),
.HRESP(sb_hresp),
.HRDATA(sb_hrdata[63:0])
);
endmodule

83
testbench/test_tb_top.cpp Normal file
View File

@ -0,0 +1,83 @@
// 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.
//
#include <stdlib.h>
#include <iostream>
#include <utility>
#include <string>
#include "Vtb_top.h"
#include "verilated.h"
#include "verilated_vcd_c.h"
// /*
vluint64_t main_time = 0;
double sc_time_stamp () {
return main_time;
}
// */
//int main(int argc, char* argv[]) {
int main(int argc, char** argv) {
std::cout << "\nStart of sim\n" << std::endl;
Verilated::commandArgs(argc, argv);
Vtb_top* tb = new Vtb_top;
uint32_t clkCnt = 0;
// init trace dump
Verilated::traceEverOn(true);
VerilatedVcdC* tfp = new VerilatedVcdC;
tb->trace (tfp, 24);
tfp->open ("sim.vcd");
// Simulate
for(auto i=0; i<200000; ++i){
clkCnt++;
if(i<10) {
tb->reset_l = 0;
} else {
tb->reset_l = 1;
}
for (auto clk=0; clk<2; clk++) {
tfp->dump (2*i+clk);
tb->core_clk = !tb->core_clk;
tb->eval();
}
if (tb->finished) {
tfp->close();
break;
}
}
for(auto i=0; i<100; ++i){
clkCnt++;
for (auto clk=0; clk<2; clk++) {
tfp->dump (2*i+clk);
tb->core_clk = !tb->core_clk;
tb->eval();
}
}
std::cout << "\nEnd of sim" << std::endl;
exit(EXIT_SUCCESS);
}

2267
tools/JSON.pm Normal file

File diff suppressed because it is too large Load Diff

129
tools/Makefile Executable file
View File

@ -0,0 +1,129 @@
# 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.
#
# Check for RV_ROOT
ifeq (,$(wildcard ${RV_ROOT}/configs/swerv.config))
$(error env var RV_ROOT does not point to a valid dir! Exiting!)
endif
# Allow snapshot override
ifeq ($(strip $(snapshot)),)
snapshot = default
endif
# Allow tool override
SWERV_CONFIG = ${RV_ROOT}/configs/swerv.config
IRUN = irun
VCS = vcs
VERILATOR = verilator
GCC_PREFIX = riscv64-unknown-elf
# Define test name
ifeq ($(strip $(ASM_TEST)),)
ASM_TEST = hello_world2
endif
# Define test name
ifeq ($(strip $(ASM_TEST_DIR)),)
ASM_TEST_DIR = ${RV_ROOT}/testbench/asm
endif
defines = ${RV_ROOT}/configs/snapshots/$(snapshot)/common_defines.vh ${RV_ROOT}/design/include/build.h ${RV_ROOT}/design/include/global.h ${RV_ROOT}/design/include/swerv_types.sv
includes = -I${RV_ROOT}/design/include -I${RV_ROOT}/design/lib -I${RV_ROOT}/design/dmi -I${RV_ROOT}/configs/snapshots/$(snapshot)
# CFLAGS for verilator generated Makefiles. Without -std=c++11 it complains for `auto` variables
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=""
# Targets
all: clean verilator
clean:
rm -rf obj_dir *.hex build ${RV_ROOT}/configs/snapshots/$(snapshot)
verilator: ${RV_ROOT}/configs/snapshots/$(snapshot)/common_defines.vh
echo '`undef ASSERT_ON' >> ${RV_ROOT}/configs/snapshots/$(snapshot)/common_defines.vh
$(VERILATOR) '-UASSERT_ON' --cc -CFLAGS ${CFLAGS} $(defines) $(includes) ${RV_ROOT}/configs/snapshots/$(snapshot)/common_defines.vh \
-f ${RV_ROOT}/testbench/flist.verilator --top-module swerv_wrapper
$(MAKE) -C obj_dir/ -f Vswerv_wrapper.mk $(VERILATOR_MAKE_FLAGS)
vcs: ${RV_ROOT}/configs/snapshots/$(snapshot)/common_defines.vh
$(VCS) -full64 -assert svaext -sverilog +define+RV_OPENSOURCE +error+500 +incdir+${RV_ROOT}/design/lib +incdir+${RV_ROOT}/design/include \
${RV_ROOT}/configs/snapshots/$(snapshot)/common_defines.vh \
+incdir+${RV_ROOT}/design/dmi +incdir+${RV_ROOT}/configs/snapshots/$(snapshot) +libext+.v ${RV_ROOT}/configs/snapshots/$(snapshot)/common_defines.vh \
$(defines)-f ${RV_ROOT}/testbench/flist.vcs -l vcs.log
irun: ${RV_ROOT}/configs/snapshots/$(snapshot)/common_defines.vh
$(IRUN) -64bit -elaborate -ida -access +rw -q -sv -sysv -nowarn CUVIHR -nclibdirpath ${PWD} -nclibdirname swerv.build \
-incdir ${RV_ROOT}/design/lib -incdir ${RV_ROOT}/design/include -incdir ${RV_ROOT}/design/dmi -vlog_ext +.vh+.h\
$(defines) -incdir ${RV_ROOT}/configs/snapshots/$(snapshot) -f ${RV_ROOT}/testbench/flist.vcs -elaborate -snapshot default
${RV_ROOT}/configs/snapshots/$(snapshot)/common_defines.vh:
$(SWERV_CONFIG) -snapshot=$(snapshot)
verilator-run: program.hex
snapshot=ahb_lite
$(SWERV_CONFIG) -snapshot=$(snapshot) -ahb_lite
echo '`undef ASSERT_ON' >> ${RV_ROOT}/configs/snapshots/$(snapshot)/common_defines.vh
$(VERILATOR) '-UASSERT_ON' --cc -CFLAGS ${CFLAGS} $(defines) $(includes) ${RV_ROOT}/configs/snapshots/$(snapshot)/common_defines.vh \
${RV_ROOT}/testbench/tb_top.sv -I${RV_ROOT}/testbench \
-f ${RV_ROOT}/testbench/flist.verilator --top-module tb_top -exe test_tb_top.cpp --trace --autoflush
cp ${RV_ROOT}/testbench/test_tb_top.cpp obj_dir/
$(MAKE) -C obj_dir/ -f Vtb_top.mk $(VERILATOR_MAKE_FLAGS)
./obj_dir/Vtb_top
irun-run: program.hex
snapshot=ahb_lite
$(SWERV_CONFIG) -snapshot=$(snapshot) -ahb_lite
$(IRUN) -64bit -ida -access +rw -q -sv -sysv -nowarn CUVIHR -nclibdirpath ${PWD} -nclibdirname swerv.build \
-incdir ${RV_ROOT}/design/lib -incdir ${RV_ROOT}/design/include -incdir ${RV_ROOT}/design/dmi -vlog_ext +.vh+.h\
$(defines) -top tb_top ${RV_ROOT}/testbench/tb_top.sv -I${RV_ROOT}/testbench ${RV_ROOT}/testbench/ahb_sif.sv\
-incdir ${RV_ROOT}/configs/snapshots/$(snapshot) -f ${RV_ROOT}/testbench/flist.vcs -snapshot default
vcs-run: program.hex
snapshot=ahb_lite
$(SWERV_CONFIG) -snapshot=$(snapshot) -ahb_lite
cp ${RV_ROOT}/testbench/hex/*.hex .
$(VCS) -full64 -assert svaext -sverilog +define+RV_OPENSOURCE +error+500 +incdir+${RV_ROOT}/design/lib +incdir+${RV_ROOT}/design/include \
${RV_ROOT}/configs/snapshots/$(snapshot)/common_defines.vh \
+incdir+${RV_ROOT}/design/dmi +incdir+${RV_ROOT}/configs/snapshots/$(snapshot) +libext+.v \
$(defines) -f ${RV_ROOT}/testbench/flist.vcs ${RV_ROOT}/testbench/tb_top.sv -I${RV_ROOT}/testbench ${RV_ROOT}/testbench/ahb_sif.sv -l vcs.log
./simv
program.hex: $(ASM_TEST_DIR)/$(ASM_TEST).s ${RV_ROOT}/configs/snapshots/$(snapshot)/common_defines.vh
@echo Building $(ASM_TEST)
ifeq ($(shell which $(GCC_PREFIX)-as),)
@echo " !!! No $(GCC_PREFIX)-as in path, using canned hex files !!"
cp ${RV_ROOT}/testbench/hex/*.hex .
else
cp $(ASM_TEST_DIR)/$(ASM_TEST).s .
$(GCC_PREFIX)-cpp -I${RV_ROOT}/configs/snapshots/$(snapshot) $(ASM_TEST).s > $(ASM_TEST).cpp.s
$(GCC_PREFIX)-as -march=rv32imc $(ASM_TEST).cpp.s -o $(ASM_TEST).o
$(GCC_PREFIX)-ld -m elf32lriscv --discard-none -T${RV_ROOT}/testbench/link.ld -o $(ASM_TEST).exe $(ASM_TEST).o
$(GCC_PREFIX)-objcopy -O verilog --only-section ".data*" --only-section ".rodata*" $(ASM_TEST).exe data.hex
$(GCC_PREFIX)-objcopy -O verilog --only-section ".text*" --set-start=0x0 $(ASM_TEST).exe program.hex
$(GCC_PREFIX)-objdump -dS $(ASM_TEST).exe > $(ASM_TEST).dis
$(GCC_PREFIX)-nm -f posix -C $(ASM_TEST).exe > $(ASM_TEST).tbl
@echo Completed building $(ASM_TEST)
endif
help:
@echo Make sure the environment variable RV_ROOT is set.
@echo Possible targets: verilator vcs irun help clean all verilator-run irun-run vcs-run program.hex
.PHONY: help clean verilator vcs irun verilator-run irun-run vcs-run

46
tools/addassign Executable file
View File

@ -0,0 +1,46 @@
#!/usr/bin/perl
use Getopt::Long;
$helpusage = "placeholder";
GetOptions ('in=s' => \$in,
'prefix=s' => \$prefix) || die("$helpusage");
@in=`cat $in`;
foreach $line (@in) {
if ($line=~/\#/) { next; }
if ($line=~/([^=]+)=/) {
$sig=$1;
$sig=~s/\s+//g;
printf("logic $sig;\n");
}
}
foreach $line (@in) {
if ($line=~/\#/) { next; }
if ($line=~/([^=]+)=\s*;/) {
printf("assign ${prefix}$1 = 1'b0;\n");
next;
}
if ($line=~/([^=]+)=\s*\(\s*\);/) {
printf("assign ${prefix}$1 = 1'b0;\n");
next;
}
if ($line =~ /=/) { printf("assign ${prefix}$line"); }
else { printf("$line"); }
}
exit;

198
tools/coredecode Executable file
View File

@ -0,0 +1,198 @@
#!/usr/bin/perl
use Getopt::Long;
$helpusage = "placeholder";
GetOptions ('legal' => \$legal,
'in=s' => \$in,
'out=s' => \$out,
'view=s' => \$view ) || die("$helpusage");
if (!defined($in)) { die("must define -in=input"); }
if (!defined($out)) { $out="${in}.out"; }
if ($in eq "decode") { $view="rv32i"; }
elsif ($in eq "cdecode") { $view="rv32c"; }
elsif ($in eq "csrdecode") { $view="csr"; }
if (defined($in)) { printf("in=$in\n"); }
if (defined($out)) { printf("out=$out\n"); }
if (defined($view)) { printf("view=$view\n"); }
@in=`cat $in`;
$gather=0;
$TIMEOUT=50;
foreach $line (@in) {
#printf("$pstate: $line");
if ($line=~/^\s*\#/) { #printf("skip $line");
next; }
if ($gather==1) {
if ($line=~/(\S+)/) {
if ($line=~/}/) { $gather=0; $position=0; next; }
$label=$1;
$label=~s/,//g;
if ($pstate==2) {
if (defined($INPUT{$CVIEW}{$label})) { die("input $label already defined"); }
$INPUT{$CVIEW}{$label}=$position++;
$INPUTLEN{$CVIEW}++;
$INPUTSTR{$CVIEW}.=" $label";
}
elsif ($pstate==3) {
if (defined($OUTPUT{$CVIEW}{$label})) { die("output $label already defined"); }
$OUTPUT{$CVIEW}{$label}=$position++;
$OUTPUTLEN{$CVIEW}++;
$OUTPUTSTR{$CVIEW}.=" $label";
}
else { die("unknown pstate $pstate in gather"); }
}
}
if ($line=~/^.definition/) {
$pstate=1; next;
}
if ($pstate==1) { # definition
if ($line!~/^.output/) {
if ($line=~/(\S+)\s*=\s*(\S+)/) {
$key=$1; $value=$2;
$value=~s/\./-/g;
$value=~s/\[//g;
$value=~s/\]//g;
$DEFINITION{$key}=$value;
}
}
else { $pstate=2; next; }
}
if ($line=~/^.input/) {
$pstate=2; next;
}
if ($pstate==2) { # input
if ($line=~/(\S+)\s*=\s*\{/) {
$CVIEW=$1; $gather=1; next;
}
}
if ($line=~/^.output/) {
$pstate=3; next;
}
if ($pstate==3) { # output
if ($line=~/(\S+)\s*=\s*\{/) {
$CVIEW=$1; $gather=1; next;
}
}
if ($line=~/^.decode/) {
$pstate=4; next;
}
if ($pstate==4) { # decode
if ($line=~/([^\[]+)\[([^\]]+)\]\s+=\s+\{([^\}]+)\}/) {
$dview=$1; $inst=$2; $body=$3;
$dview=~s/\s+//g;
$inst=~s/\s+//g;
#printf("$dview $inst $body\n");
if ($inst=~/([^\{]+)\{([^-]+)-([^\}]+)\}/) {
$base=$1; $lo=$2; $hi=$3;
$hi++;
for ($i=0; $i<$TIMEOUT && $lo ne $hi; $i++) {
#printf("decode $dview $base$lo\n");
$expand=$base.$lo;
if (!defined($DEFINITION{$expand})) { die("could not find instruction definition for inst $expand"); }
$DECODE{$dview}{$expand}=$body;
$lo++;
}
if ($i == $TIMEOUT) { die("timeout in decode expansion"); }
}
else {
if (!defined($DEFINITION{$inst})) { die("could not find instruction definition for inst $inst"); }
$DECODE{$dview}{$inst}=$body;
}
}
}
}
#printf("view $view len %d\n",$OUTPUTLEN{$view});
#printf("$OUTPUTSTR{$view}\n");
# need to switch this somehow based on 16/32
printf(".i %d\n",$INPUTLEN{$view});
if (defined($legal)) {
printf(".o 1\n");
}
else {
printf(".o %d\n",$OUTPUTLEN{$view});
}
printf(".ilb %s\n",$INPUTSTR{$view});
if (defined($legal)) {
printf(".ob legal\n");
}
else {
printf(".ob %s\n",$OUTPUTSTR{$view});
}
if (defined($legal)) {
printf(".type fd\n");
}
else {
printf(".type fr\n");
}
$DEFAULT_TEMPLATE='0'x$OUTPUTLEN{$view};
foreach $inst (sort keys %{ $DECODE{$view} }) {
$body=$DECODE{$view}{$inst};
@sigs=split(' ',$body);
$template=$DEFAULT_TEMPLATE;
foreach $sig (@sigs) {
if (!defined($OUTPUT{$view}{$sig})) { die("could not find output definition for sig $sig in view $view"); }
$position=$OUTPUT{$view}{$sig};
substr($template,$position,1,1);
}
# if (!defined($DEFINITION{$inst})) { die("could not find instruction defintion for inst $inst"); }
printf("# $inst\n");
if (defined($legal)) {
printf("$DEFINITION{$inst} 1\n");
}
else {
printf("$DEFINITION{$inst} $template\n");
}
}
exit;
foreach $inst (sort keys %DEFINITION) {
$value=$DEFINITION{$inst};
printf("%-10s = $value\n",$inst);
}
foreach $sig (sort keys %{ $OUTPUT{$view} }) {
$position=$OUTPUT{$view}{$sig};
printf("$sig $position\n");
}

59
tools/picmap Executable file
View File

@ -0,0 +1,59 @@
#!/usr/bin/perl
use Getopt::Long;
use integer;
$helpusage = "placeholder";
GetOptions ('total_int=s' => \$total_int)|| die("$helpusage");
$LEN=15;
#printf("logic [2:0] mask;\n");
printf("// mask[3:0] = { 4'b1000 - 30b mask,4'b0100 - 31b mask, 4'b0010 - 28b mask, 4'b0001 - 32b mask }\n");
printf("always_comb begin\n");
printf(" case \(address[14:0]\)\n");
printf(" 15'b011000000000000 : mask[3:0] = 4'b0100;\n");
for ($i=1; $i<=$total_int; $i++) {
$j=hex("4000");
printf(" 15'b%s : mask[3:0] = 4'b1000;\n",d2b($j+$i*4));
}
for ($i=1; $i<=$total_int; $i++) {
$j=hex("2000");
printf(" 15'b%s : mask[3:0] = 4'b0100;\n",d2b($j+$i*4));
}
for ($i=1; $i<=$total_int; $i++) {
$j=hex("0");
printf(" 15'b%s : mask[3:0] = 4'b0010;\n",d2b($j+$i*4));
}
printf(" %-17s : mask[3:0] = 4'b0001;\n","default");
printf(" endcase\n");
printf("end\n");
sub b2d {
my ($v) = @_;
$v = oct("0b" . $v);
return($v);
}
sub d2b {
my ($v) = @_;
my $repeat;
$v = sprintf "%b",$v;
if (length($v)<$LEN) {
$repeat=$LEN-length($v);
$v="0"x$repeat.$v;
}
elsif (length($v)>$LEN) {
$v=substr($v,length($v)-$LEN,$LEN);
}
return($v);
}

121
tools/smalldiv Executable file
View File

@ -0,0 +1,121 @@
#!/usr/bin/perl
use Getopt::Long;
use integer;
$helpusage = "placeholder";
GetOptions ('len=s' => \$len,
'num=s' => \$num,
'den=s' => \$den,
'skip' => \$skip) || die("$helpusage");
if (!defined($len)) { $len=8; }
$LEN=$len;
$n=d2b($num); # numerator - quotient
$m=d2b($den); # denominator - divisor
printf(".i 8\n");
printf(".o 4\n");
printf(".ilb q_ff[3] q_ff[2] q_ff[1] q_ff[0] m_ff[3] m_ff[2] m_ff[1] m_ff[0]\n");
printf(".ob smallnum[3] smallnum[2] smallnum[1] smallnum[0]\n");
printf(".type fr\n");
for ($q=0; $q<16; $q++) {
for ($m=0; $m<16; $m++) {
if ($m==0) { next; }
$result=int($q/$m);
printf("%s %s %s\n",d2bl($q,4),d2bl($m,4),d2bl($result,4));
}
}
exit;
#$LEN=length($n);
$a="0"x$LEN;
$q=$n;
#printf("n=%s, m=%s\n",$n,$m);
#printf("a=%s, q=%s\n",$a,$q);
for ($i=1; $i<=$LEN; $i++) {
#printf("iteration $n:\n");
printf("$i: a=%s q=%s\n",$a,$q);
$signa = substr($a,0,1);
$a = substr($a.$q,1,$LEN); # new a with q shifted in
if ($signa==0) { $a=b2d($a)-b2d($m); }
else { $a=b2d($a)+b2d($m); }
$a=d2b($a);
$signa = substr($a,0,1);
if ($signa==0) { $q=substr($q,1,$LEN-1)."1"; }
else { $q=substr($q,1,$LEN-1)."0"; }
}
#printf("a=$a\n");
$signa = substr($a,0,1);
if ($signa==1 && !defined($skip)) {
printf("correction:\n");
$a=b2d($a)+b2d($m);
$a=d2b($a);
}
#printf("a=$a\n");
printf("%d / %d = %d R %d ",b2d($n),b2d($m),b2d($q),b2d($a));
if ($a eq $n) { printf("-> remainder equal numerator\n"); }
else { printf("\n"); }
sub b2d {
my ($v) = @_;
$v = oct("0b" . $v);
return($v);
}
sub d2b {
my ($v) = @_;
my $repeat;
$v = sprintf "%b",$v;
if (length($v)<$LEN) {
$repeat=$LEN-length($v);
$v="0"x$repeat.$v;
}
elsif (length($v)>$LEN) {
$v=substr($v,length($v)-$LEN,$LEN);
}
return($v);
}
sub d2bl {
my ($v,$LEN) = @_;
my $repeat;
$v = sprintf "%b",$v;
if (length($v)<$LEN) {
$repeat=$LEN-length($v);
$v="0"x$repeat.$v;
}
elsif (length($v)>$LEN) {
$v=substr($v,length($v)-$LEN,$LEN);
}
return($v);
}

169
tools/unrollforverilator Executable file
View File

@ -0,0 +1,169 @@
#!/usr/bin/perl
#use strict;
#use warnings;
my $RV_ROOT = $ENV{RV_ROOT};
my $TOTAL_INT=$ARGV[0];
print "// argv=".$ARGV[0]."\n";
my $NUM_LEVELS;
if($TOTAL_INT==2){$NUM_LEVELS=1;}
elsif ($TOTAL_INT==4){$NUM_LEVELS=2;}
elsif ($TOTAL_INT==8){$NUM_LEVELS=3;}
elsif ($TOTAL_INT==16){$NUM_LEVELS=4;}
elsif ($TOTAL_INT==32){$NUM_LEVELS=5;}
elsif ($TOTAL_INT==64){$NUM_LEVELS=6;}
elsif ($TOTAL_INT==128){$NUM_LEVELS=7;}
elsif ($TOTAL_INT==256){$NUM_LEVELS=8;}
elsif ($TOTAL_INT==512){$NUM_LEVELS=9;}
elsif ($TOTAL_INT==1024){$NUM_LEVELS=10;}
else {$NUM_LEVELS=int(log($TOTAL_INT)/log(2))+1;}
print ("// TOTAL_INT=".$TOTAL_INT." NUM_LEVELS=".$NUM_LEVELS."\n");
$next_level = 1;
print ("`ifdef RV_PIC_2CYCLE\n");
if($TOTAL_INT > 2){
print ("// LEVEL0\n");
print ("logic [TOTAL_INT+2:0] [INTPRIORITY_BITS-1:0] level_intpend_w_prior_en_".$next_level.";\n");
print ("logic [TOTAL_INT+2:0] [ID_BITS-1:0] level_intpend_id_".$next_level.";\n");
print (" for (m=0; m<=(TOTAL_INT)/(2**(".$next_level.")) ; m++) begin : COMPARE0\n");
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 (" 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");
print (" .a_priority(level_intpend_w_prior_en[0][2*m]),\n");
print (" .b_id(level_intpend_id[0][2*m+1]),\n");
print (" .b_priority(level_intpend_w_prior_en[0][2*m+1]),\n");
print (" .out_id(level_intpend_id_".$next_level."[m]),\n");
print (" .out_priority(level_intpend_w_prior_en_".$next_level."[m])) ;\n");
print (" \n");
print (" end\n\n");
for (my $l=1; $l<int($NUM_LEVELS/2) ; $l++) {
$next_level = $l+1;
print ("// LEVEL".$l."\n");
print ("logic [TOTAL_INT+2:0] [INTPRIORITY_BITS-1:0] level_intpend_w_prior_en_".$next_level.";\n");
print ("logic [TOTAL_INT+2:0] [ID_BITS-1:0] level_intpend_id_".$next_level.";\n");
print (" for (m=0; m<=(TOTAL_INT)/(2**(".$next_level.")) ; m++) begin : COMPARE$l\n");
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 (" 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");
print (" .a_priority(level_intpend_w_prior_en_".$l."[2*m]),\n");
print (" .b_id(level_intpend_id_".$l."[2*m+1]),\n");
print (" .b_priority(level_intpend_w_prior_en_".$l."[2*m+1]),\n");
print (" .out_id(level_intpend_id_".$next_level."[m]),\n");
print (" .out_priority(level_intpend_w_prior_en_".$next_level."[m])) ;\n");
print (" \n");
print (" end\n\n");
}
### ADD FLOP STAGE
print ("for (i=0; i<=TOTAL_INT/2**(NUM_LEVELS/2) ; i++) begin : MIDDLE_FLOPS\n");
print (" rvdff #(INTPRIORITY_BITS) level2_intpend_prior_reg (.*, .din (level_intpend_w_prior_en_".$next_level."[i]), .dout(l2_intpend_w_prior_en_ff[i]), .clk(active_clk));\n");
print (" rvdff #(ID_BITS) level2_intpend_id_reg (.*, .din (level_intpend_id_".$next_level."[i]), .dout(l2_intpend_id_ff[i]), .clk(active_clk));\n");
print ("end\n");
}else{
print ("for (i=0; i<=TOTAL_INT/2**(NUM_LEVELS/2) ; i++) begin : MIDDLE_FLOPS\n");
print (" rvdff #(INTPRIORITY_BITS) level2_intpend_prior_reg (.*, .din (level_intpend_w_prior_en[0][i]), .dout(l2_intpend_w_prior_en_ff[i]), .clk(active_clk));\n");
print (" rvdff #(ID_BITS) level2_intpend_id_reg (.*, .din (level_intpend_id[0][i]), .dout(l2_intpend_id_ff[i]), .clk(active_clk));\n");
print ("end\n");
}
### END FLOP STAGE
$next_level = int($NUM_LEVELS/2) + 1;
my $tmp = int($NUM_LEVELS/2);
print ("// LEVEL".$tmp."\n");
print ("logic [TOTAL_INT+2:0] [INTPRIORITY_BITS-1:0] levelx_intpend_w_prior_en_".$next_level.";\n");
print ("logic [TOTAL_INT+2:0] [ID_BITS-1:0] levelx_intpend_id_".$next_level.";\n");
print (" for (m=0; m<=(TOTAL_INT)/(2**(".$next_level.")) ; m++) begin : COMPARE$tmp\n");
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 (" 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");
print (" .a_priority(levelx_intpend_w_prior_en[$tmp][2*m]),\n");
print (" .b_id(levelx_intpend_id[$tmp][2*m+1]),\n");
print (" .b_priority(levelx_intpend_w_prior_en[$tmp][2*m+1]),\n");
print (" .out_id(levelx_intpend_id_".$next_level."[m]),\n");
print (" .out_priority(levelx_intpend_w_prior_en_".$next_level."[m])) ;\n");
print (" \n");
print (" end\n\n");
for (my $l=int($NUM_LEVELS/2)+1; $l<$NUM_LEVELS ; $l++) {
$next_level = $l+1;
print ("// LEVEL".$l."\n");
print ("logic [TOTAL_INT+2:0] [INTPRIORITY_BITS-1:0] levelx_intpend_w_prior_en_".$next_level.";\n");
print ("logic [TOTAL_INT+2:0] [ID_BITS-1:0] levelx_intpend_id_".$next_level.";\n");
print (" for (m=0; m<=(TOTAL_INT)/(2**(".$next_level.")) ; m++) begin : COMPARE$l\n");
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 (" 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");
print (" .a_priority(levelx_intpend_w_prior_en_".$l."[2*m]),\n");
print (" .b_id(levelx_intpend_id_".$l."[2*m+1]),\n");
print (" .b_priority(levelx_intpend_w_prior_en_".$l."[2*m+1]),\n");
print (" .out_id(levelx_intpend_id_".$next_level."[m]),\n");
print (" .out_priority(levelx_intpend_w_prior_en_".$next_level."[m])) ;\n");
print (" \n");
print (" end\n\n");
}
print ("assign claimid_in[ID_BITS-1:0] = levelx_intpend_id_".$next_level."[0] ; // This is the last level output\n");
print ("assign selected_int_priority[INTPRIORITY_BITS-1:0] = levelx_intpend_w_prior_en_".$next_level."[0] ;\n");
print ("`else\n");
$next_level = 1;
print ("// LEVEL0\n");
print ("logic [TOTAL_INT+2:0] [INTPRIORITY_BITS-1:0] level_intpend_w_prior_en_".$next_level.";\n");
print ("logic [TOTAL_INT+2:0] [ID_BITS-1:0] level_intpend_id_".$next_level.";\n");
print (" for (m=0; m<=(TOTAL_INT)/(2**(".$next_level.")) ; m++) begin : COMPARE0\n");
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 (" 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");
print (" .a_priority(level_intpend_w_prior_en[0][2*m]),\n");
print (" .b_id(level_intpend_id[0][2*m+1]),\n");
print (" .b_priority(level_intpend_w_prior_en[0][2*m+1]),\n");
print (" .out_id(level_intpend_id_".$next_level."[m]),\n");
print (" .out_priority(level_intpend_w_prior_en_".$next_level."[m])) ;\n");
print (" \n");
print (" end\n\n");
for (my $l=1; $l<$NUM_LEVELS ; $l++) {
$next_level = $l+1;
print ("// LEVEL".$l."\n");
print ("logic [TOTAL_INT+2:0] [INTPRIORITY_BITS-1:0] level_intpend_w_prior_en_".$next_level.";\n");
print ("logic [TOTAL_INT+2:0] [ID_BITS-1:0] level_intpend_id_".$next_level.";\n");
print (" for (m=0; m<=(TOTAL_INT)/(2**(".$next_level.")) ; m++) begin : COMPARE$l\n");
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 (" 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");
print (" .a_priority(level_intpend_w_prior_en_".$l."[2*m]),\n");
print (" .b_id(level_intpend_id_".$l."[2*m+1]),\n");
print (" .b_priority(level_intpend_w_prior_en_".$l."[2*m+1]),\n");
print (" .out_id(level_intpend_id_".$next_level."[m]),\n");
print (" .out_priority(level_intpend_w_prior_en_".$next_level."[m])) ;\n");
print (" \n");
print (" end\n\n");
}
print ("assign claimid_in[ID_BITS-1:0] = level_intpend_id_".$next_level."[0] ; // This is the last level output\n");
print ("assign selected_int_priority[INTPRIORITY_BITS-1:0] = level_intpend_w_prior_en_".$next_level."[0] ;\n");
print ("`endif\n");