mirror of
https://github.com/Silicon1602/srdl2sv.git
synced 2024-12-22 06:58:41 +00:00
Add hierarchical interrupts under examples
The SystemRDL that was added comes from Section 17.2 "Understanding hierarchical interrupts in SystemRDL" of the SystemRDL 2.0 LRM. The present code succesfully compiles.
This commit is contained in:
parent
eb3f1dd57e
commit
b8e9adb1f0
8
examples/interrupt_hierarchy/README.md
Normal file
8
examples/interrupt_hierarchy/README.md
Normal file
@ -0,0 +1,8 @@
|
||||
The RDL in `interrupt_hierarchy.rdl` is copied from Section 17.2 of the SystemRDL 2.0 LRM and is meant to show how this "Advanced topic in SystemRDL" looks in compiled form. The former figure below below shows the hierarchy that this RDL will achieve. The latter image shows the block interrupt register.
|
||||
|
||||
**Note that both pictures are copied from the [SystemRDL 2.0 LRM](https://www.accellera.org/images/downloads/standards/systemrdl/SystemRDL_2.0_Jan2018.pdf).**
|
||||
|
||||
![hierarchical_interrupt_structure](images/hierarchical_interrupt_structure.jpg)
|
||||
|
||||
![block_interrupt_example](images/block_interrupt_example.jpg)
|
||||
|
BIN
examples/interrupt_hierarchy/images/block_interrupt_example.jpg
Normal file
BIN
examples/interrupt_hierarchy/images/block_interrupt_example.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 96 KiB |
Binary file not shown.
After Width: | Height: | Size: 86 KiB |
377
examples/interrupt_hierarchy/interrupt_hierarchy.rdl
Normal file
377
examples/interrupt_hierarchy/interrupt_hierarchy.rdl
Normal file
@ -0,0 +1,377 @@
|
||||
//------------------------------------------------------------
|
||||
// Block Level Interrupt Register
|
||||
//------------------------------------------------------------
|
||||
|
||||
reg block_int_r {
|
||||
name = "Example Block Interrupt Register";
|
||||
desc = "This is an example of an IP Block with 3 int events. 2 of these
|
||||
are non-fatal and the third event multi_bit_ecc_error is fatal";
|
||||
|
||||
default hw=w; // HW can Set int only
|
||||
default sw=rw; // SW can clear
|
||||
default woclr; // Clear is via writing a 1
|
||||
|
||||
field {
|
||||
desc = "A Packet with a CRC Error has been received";
|
||||
level intr;
|
||||
} crc_error = 0x0;
|
||||
|
||||
field {
|
||||
desc = "A Packet with an invalid length has been received";
|
||||
level intr;
|
||||
} len_error = 0x0;
|
||||
|
||||
field {
|
||||
desc="An uncorrectable multi-bit ECC error has been received";
|
||||
level intr;
|
||||
} multi_bit_ecc_error = 0 ;
|
||||
|
||||
field {
|
||||
desc="Master who was active when ECC Error Occurred";
|
||||
sticky;
|
||||
} active_ecc_master[7:4] = 0; // Example of multi-bit sticky field
|
||||
// This field is not an intr
|
||||
}; // End of Reg: block_int_r
|
||||
|
||||
reg block_int_en_r {
|
||||
name = "Example Block Interrupt Enable Register";
|
||||
desc = "This is an example of an IP Block with 3 int events";
|
||||
|
||||
default hw=na; // HW can't access the enables
|
||||
default sw=rw; // SW can control them
|
||||
|
||||
field {
|
||||
desc = "Enable: A Packet with a CRC Error has been received";
|
||||
} crc_error = 0x1;
|
||||
|
||||
field {
|
||||
desc = "Enable: A Packet with an invalid length has been received";
|
||||
} len_error = 0x1;
|
||||
|
||||
field {
|
||||
desc = "Enable: A multi-bit error has been detected";
|
||||
} multi_bit_ecc_error = 0x0;
|
||||
}; // End of Reg: block_int_en_r
|
||||
|
||||
reg block_halt_en_r {
|
||||
name = "Example Block Halt Enable Register";
|
||||
desc = "This is an example of an IP Block with 3 int events";
|
||||
|
||||
default hw=na; // HW can't access the enables
|
||||
default sw=rw; // SW can control them
|
||||
|
||||
field {
|
||||
desc = "Enable: A Packet with a CRC Error has been received";
|
||||
} crc_error = 0x0; // not a fatal error do not halt
|
||||
|
||||
field {
|
||||
desc = "Enable: A Packet with an invalid length has been received";
|
||||
} len_error = 0x0; // not a fatal error do not halt
|
||||
|
||||
field {
|
||||
desc = "Enable: A Packet with an invalid length has been received";
|
||||
} multi_bit_ecc_error = 0x1; // fatal error that will
|
||||
// cause device to halt
|
||||
}; // End of Reg: block_halt_en_r
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Master Interrupt Status Register
|
||||
//------------------------------------------------------------
|
||||
|
||||
reg master_int_r {
|
||||
name = "Master Interrupt Status Register";
|
||||
desc = "This register contains the status of the 4 lower Module interrupts.
|
||||
Also an interrupt signal (myMasterInt) is generated which is the 'OR'
|
||||
of the four Module interrupts. A Halt signal is also generated which
|
||||
represents the bitwise or the masked/enabled halt bits";
|
||||
|
||||
default nonsticky intr; // Unless we want to have to clear this separately
|
||||
// from the leaf intr this should be non sticky
|
||||
|
||||
default hw=w; // HW normally won't want to access this but it could
|
||||
default sw=r; // Software can just read this. It clears the leaf intr's
|
||||
// to clear this
|
||||
field {
|
||||
desc = "An interrupt has occurred with ModuleD.
|
||||
Software must read the ModuleD Master Interrupt Register
|
||||
in order to determine the source of the interrupt.";
|
||||
} module_d_int[3:3] = 0x0;
|
||||
|
||||
field {
|
||||
desc = "An interrupt has occurred with ModuleC.
|
||||
Software must read the ModuleC Master Interrupt Register
|
||||
in order to determine the source of the interrupt.";
|
||||
} module_c_int[2:2] = 0x0;
|
||||
|
||||
field {
|
||||
desc = "An interrupt has occurred with ModuleB.
|
||||
Software must read the ModuleB Interrupt Register
|
||||
in order to determine the source of the interrupt.";
|
||||
} module_b_int[1:1] = 0x0;
|
||||
|
||||
field {
|
||||
desc = "An interrupt has occurred with ModuleA.
|
||||
Software must read the ModuleA Master Interrupt Register
|
||||
in order to determine the source of the interrupt.";
|
||||
} module_a_int[0:0] = 0x0;
|
||||
};
|
||||
|
||||
//
|
||||
// The following is the accompanying enable register. Since the combinatorial
|
||||
// logic for processing the interrupt is internal to the generated verilog,
|
||||
// there's no need for an external port - which is realized by assigning "na"
|
||||
// to the hw attribute of the specific field. This could have been defined as
|
||||
// a mask register just as easily...
|
||||
//
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Interrupt Enable Register
|
||||
//------------------------------------------------------------
|
||||
|
||||
reg master_int_en_r {
|
||||
name = "Master Interrupt Enable Register";
|
||||
desc = "Configurable register used in order to enable the corresponding
|
||||
interrupts found in myMasterInt register.";
|
||||
|
||||
default hw = na;
|
||||
default sw = rw;
|
||||
|
||||
field {
|
||||
desc = "Interrupt enable for ModuleD Interrupts. 1 = enable, 0 = disable";
|
||||
} module_d_int_en[3:3] = 0x0;
|
||||
|
||||
field {
|
||||
desc = "Interrupt enable for ModuleC Interrupts. 1 = enable, 0 = disable";
|
||||
} module_c_int_en[2:2] = 0x0;
|
||||
|
||||
field {
|
||||
desc = "Interrupt enable for ModuleB Interrupts. 1 = enable, 0 = disable";
|
||||
} module_b_int_en[1:1] = 0x0;
|
||||
|
||||
field {
|
||||
desc = "Interrupt enable for ModuleA Interrupts. 1 = enable, 0 = disable";
|
||||
} module_a_int_en[0:0] = 0x0;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Halt Enable Register
|
||||
//------------------------------------------------------------
|
||||
|
||||
// The halt en is another enable or mask that could be used to generate an
|
||||
// alternate signal like a halt that represents a fatal error in the system or
|
||||
// some other event NOTE: It does not have to mean fatal as the name implies
|
||||
// its just another priority level for interrupts...
|
||||
|
||||
reg master_halt_en_r {
|
||||
name = "Master Halt Enable Register";
|
||||
desc = "Configurable register used in order to enable the corresponding
|
||||
interrupts found in myMasterInt register.";
|
||||
|
||||
default hw = na;
|
||||
default sw = rw;
|
||||
|
||||
field {
|
||||
desc = "Halt enable for ModuleD Interrupts. 1 = enable, 0 = disable";
|
||||
} module_d_halt_en[3:3] = 0x0;
|
||||
|
||||
field {
|
||||
desc = "Halt enable for ModuleC Interrupts. 1 = enable, 0 = disable";
|
||||
} module_c_halt_en[2:2] = 0x0;
|
||||
|
||||
field {
|
||||
desc = "Halt enable for ModuleB Interrupts. 1 = enable, 0 = disable";
|
||||
} module_b_halt_en[1:1] = 0x0;
|
||||
|
||||
field {
|
||||
desc = "Halt enable for ModuelA Interrupts. 1 = enable, 0 = disable";
|
||||
} module_a_halt_en[0:0] = 0x0;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Global Interrupt Status Register
|
||||
//------------------------------------------------------------
|
||||
|
||||
// This takes the block int which feeds the master int and then distills it
|
||||
// down one more level so we end up with a single bit intr and single bit halt...
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Global Interrupt/Halt Enable Register
|
||||
//------------------------------------------------------------
|
||||
reg final_en_r {
|
||||
name = "My Final Enable Register";
|
||||
desc = "This enable allows all interrupts/halts to be suppressed
|
||||
with a single bit";
|
||||
|
||||
default hw = na;
|
||||
default sw = rw;
|
||||
|
||||
field {
|
||||
desc = "Global Interrupt Enable. 1 = enable, 0 = disable";
|
||||
} global_int_en = 0x0;
|
||||
|
||||
field {
|
||||
desc = "Global Halt Enable. 1 = enable, 0 = disable";
|
||||
} global_halt_en = 0x0;
|
||||
};
|
||||
|
||||
reg final_int_r {
|
||||
name = "My Final Int/Halt Register";
|
||||
desc = "This distills a lower level interrupts into a final bit than can be
|
||||
masked";
|
||||
|
||||
default sw = r; // sw does not need to clear global_int
|
||||
// (global_int is of type final_int_r)
|
||||
// instead it clears itself when all master_int intr
|
||||
// bits get serviced
|
||||
|
||||
default nonsticky intr;
|
||||
default hw = w; // w needed since dyn assign below implies interconnect to hw
|
||||
// global_int.global_int->next = master_int->intr;
|
||||
|
||||
field {
|
||||
desc = "Global Interrupt";
|
||||
} global_int = 0x0;
|
||||
|
||||
field {
|
||||
desc = "Global Halt";
|
||||
} global_halt = 0x0;
|
||||
};
|
||||
|
||||
addrmap interrupt_hierarchy {
|
||||
signal { activelow; async; field_reset;} field_reset_n;
|
||||
|
||||
name = "Sample ASIC Interrupt Registers";
|
||||
desc = "This register map is designed how one can use interrupt concepts
|
||||
effectively in SystemRDL";
|
||||
|
||||
// Leaf Interrupts
|
||||
|
||||
// Block A Registers
|
||||
|
||||
block_int_r block_a_int; // Instance the Leaf Int Register
|
||||
block_int_en_r block_a_int_en; // Instance the corresponding Int Enable
|
||||
// Register
|
||||
block_halt_en_r block_a_halt_en; // Instance the corresponding halt enable
|
||||
// register
|
||||
|
||||
// This block connects the int bits to their corresponding
|
||||
// int enables and halt enables
|
||||
//
|
||||
block_a_int.crc_error->enable = block_a_int_en.crc_error;
|
||||
block_a_int.len_error->enable = block_a_int_en.len_error;
|
||||
block_a_int.multi_bit_ecc_error->enable = block_a_int_en.multi_bit_ecc_error;
|
||||
block_a_int.crc_error->haltenable = block_a_halt_en.crc_error;
|
||||
block_a_int.len_error->haltenable = block_a_halt_en.len_error;
|
||||
block_a_int.multi_bit_ecc_error->haltenable = block_a_halt_en.multi_bit_ecc_error;
|
||||
|
||||
// Block B Registers
|
||||
block_int_r block_b_int @0x100;
|
||||
block_int_en_r block_b_int_en;
|
||||
block_halt_en_r block_b_halt_en;
|
||||
|
||||
block_b_int.crc_error->enable = block_b_int_en.crc_error;
|
||||
block_b_int.len_error->enable = block_b_int_en.len_error;
|
||||
block_b_int.multi_bit_ecc_error->enable = block_b_int_en.multi_bit_ecc_error;
|
||||
block_b_int.crc_error->haltenable = block_b_halt_en.crc_error;
|
||||
block_b_int.len_error->haltenable = block_b_halt_en.len_error;
|
||||
block_b_int.multi_bit_ecc_error->haltenable = block_b_halt_en.multi_bit_ecc_error;
|
||||
|
||||
// Block C Registers
|
||||
block_int_r block_c_int @0x200;
|
||||
block_int_en_r block_c_int_en;
|
||||
block_halt_en_r block_c_halt_en;
|
||||
|
||||
block_c_int.crc_error->enable = block_c_int_en.crc_error;
|
||||
block_c_int.len_error->enable = block_c_int_en.len_error;
|
||||
block_c_int.multi_bit_ecc_error->enable = block_c_int_en.multi_bit_ecc_error;
|
||||
block_c_int.crc_error->haltenable = block_c_halt_en.crc_error;
|
||||
block_c_int.len_error->haltenable = block_c_halt_en.len_error;
|
||||
block_c_int.multi_bit_ecc_error->haltenable = block_c_halt_en.multi_bit_ecc_error;
|
||||
|
||||
// Block D Registers
|
||||
block_int_r block_d_int @0x300;
|
||||
block_int_en_r block_d_int_en;
|
||||
block_halt_en_r block_d_halt_en;
|
||||
|
||||
block_d_int.crc_error->enable = block_d_int_en.crc_error;
|
||||
block_d_int.len_error->enable = block_d_int_en.len_error;
|
||||
block_d_int.multi_bit_ecc_error->enable = block_d_int_en.multi_bit_ecc_error;
|
||||
block_d_int.crc_error->haltenable = block_d_halt_en.crc_error;
|
||||
block_d_int.len_error->haltenable = block_d_halt_en.len_error;
|
||||
block_d_int.multi_bit_ecc_error->haltenable = block_d_halt_en.multi_bit_ecc_error;
|
||||
|
||||
//
|
||||
// Master Interrupts
|
||||
//
|
||||
|
||||
master_int_r master_int @0x01000;
|
||||
master_int_r master_halt;
|
||||
master_int_en_r master_int_en;
|
||||
master_halt_en_r master_halt_en;
|
||||
|
||||
// Associate the INT’s with the EN’s
|
||||
master_int.module_d_int->enable = master_int_en.module_d_int_en;
|
||||
master_int.module_c_int->enable = master_int_en.module_c_int_en;
|
||||
master_int.module_b_int->enable = master_int_en.module_b_int_en;
|
||||
master_int.module_a_int->enable = master_int_en.module_a_int_en;
|
||||
|
||||
// Associate the HALT’s with the EN’s
|
||||
master_halt.module_d_int->haltenable = master_halt_en.module_d_halt_en;
|
||||
master_halt.module_c_int->haltenable = master_halt_en.module_c_halt_en;
|
||||
master_halt.module_b_int->haltenable = master_halt_en.module_b_halt_en;
|
||||
master_halt.module_a_int->haltenable = master_halt_en.module_a_halt_en;
|
||||
|
||||
// Now hook the lower level leaf interrupts to the higher level interrupts
|
||||
|
||||
// This connects the Implicit Or from Block A's INT reg after
|
||||
// masking/enable to the next level up (master)
|
||||
master_int.module_a_int->next = block_a_int->intr;
|
||||
|
||||
// This connects the Implicit Or from Block B's INT reg after
|
||||
// masking/enable to the next level up (master)
|
||||
master_int.module_b_int->next = block_b_int->intr;
|
||||
|
||||
// This connects the Implicit Or from Block C's INT reg after
|
||||
// masking/enable to the next level up (master)
|
||||
master_int.module_c_int->next = block_c_int->intr;
|
||||
|
||||
// This connects the Implicit Or from Block D's INT reg after
|
||||
// masking/enable to the next level up (master)
|
||||
master_int.module_d_int->next = block_d_int->intr;
|
||||
|
||||
// This connects the Implicit Or from Block A's HALT reg after
|
||||
// masking/enable to the next level up (master)
|
||||
master_halt.module_a_int->next = block_a_int->halt;
|
||||
|
||||
// This connects the Implicit Or from Block B's HALT reg after
|
||||
// masking/enable to the next level up (master)
|
||||
master_halt.module_b_int->next = block_b_int->halt;
|
||||
|
||||
// This connects the Implicit Or from Block C's HALT reg after
|
||||
// masking/enable to the next level up (master)
|
||||
master_halt.module_c_int->next = block_c_int->halt;
|
||||
|
||||
// This connects the Implicit Or from Block D's HALT reg after
|
||||
// masking/enable to the next level up (master)
|
||||
master_halt.module_d_int->next = block_d_int->halt;
|
||||
|
||||
final_int_r global_int @0x1010;
|
||||
// Inst the global int/halt register
|
||||
|
||||
final_en_r global_int_en @0x1014;
|
||||
// Inst the global int/halt enable register
|
||||
|
||||
global_int.global_int->enable = global_int_en.global_int_en;
|
||||
// Associate the INT with the EN
|
||||
|
||||
global_int.global_halt->haltenable = global_int_en.global_halt_en;
|
||||
// Associate the HALT with the EN
|
||||
|
||||
global_int.global_int->next = master_int->intr;
|
||||
// Take the or of the 4 blocks in the master
|
||||
// Int and create one final interrupt
|
||||
|
||||
global_int.global_halt->next = master_halt->halt;
|
||||
// Take the or of the 4 blocks in the master
|
||||
// Int and create one final halt
|
||||
};
|
2743
examples/interrupt_hierarchy/srdl2sv_out/interrupt_hierarchy.sv
Normal file
2743
examples/interrupt_hierarchy/srdl2sv_out/interrupt_hierarchy.sv
Normal file
File diff suppressed because it is too large
Load Diff
314
examples/interrupt_hierarchy/srdl2sv_out/srdl2sv_amba3ahblite.sv
Normal file
314
examples/interrupt_hierarchy/srdl2sv_out/srdl2sv_amba3ahblite.sv
Normal file
@ -0,0 +1,314 @@
|
||||
/*
|
||||
* Copyright 2021 Dennis Potter <dennis@dennispotter.eu>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following
|
||||
* conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
module srdl2sv_amba3ahblite
|
||||
import srdl2sv_if_pkg::*;
|
||||
#(
|
||||
parameter bit FLOP_REGISTER_IF = 0,
|
||||
parameter BUS_BITS = 32,
|
||||
parameter NO_BYTE_ENABLE = 0
|
||||
)
|
||||
(
|
||||
// Outputs to internal logic
|
||||
output b2r_t b2r,
|
||||
|
||||
// Inputs from internal logic
|
||||
input r2b_t r2b,
|
||||
|
||||
// Bus protocol
|
||||
input HCLK,
|
||||
input HRESETn,
|
||||
input HSEL,
|
||||
input [31:0] HADDR,
|
||||
input HWRITE,
|
||||
input [ 2:0] HSIZE,
|
||||
input [ 3:0] HPROT, // Might be used in the future together with an RDL UDP
|
||||
input [ 1:0] HTRANS,
|
||||
input [BUS_BITS-1:0] HWDATA,
|
||||
|
||||
output logic HREADYOUT,
|
||||
output logic HRESP,
|
||||
output logic [BUS_BITS-1:0] HRDATA
|
||||
);
|
||||
|
||||
localparam BUS_BYTES = BUS_BITS/8;
|
||||
localparam BUS_BYTES_W = $clog2(BUS_BYTES);
|
||||
|
||||
/***********************
|
||||
* Define enums
|
||||
***********************/
|
||||
typedef enum logic [2:0] {
|
||||
SINGLE = 3'b000,
|
||||
INCR = 3'b001,
|
||||
WRAP4 = 3'b010,
|
||||
INCR4 = 3'b011,
|
||||
WRAP8 = 3'b100,
|
||||
INCR8 = 3'b101,
|
||||
WRAP16 = 3'b110,
|
||||
INCR16 = 3'b111
|
||||
} HBURST_t;
|
||||
|
||||
typedef enum logic [1:0] {
|
||||
IDLE = 2'b00,
|
||||
BUSY = 2'b01,
|
||||
NONSEQ = 2'b10,
|
||||
SEQ = 2'b11
|
||||
} HTRANS_t;
|
||||
|
||||
typedef enum logic {
|
||||
OKAY = 1'b0,
|
||||
ERROR = 1'b1
|
||||
} HRESP_t;
|
||||
|
||||
typedef enum logic {
|
||||
READ = 1'b0,
|
||||
WRITE = 1'b1
|
||||
} OP_t;
|
||||
|
||||
typedef enum logic [1:0] {
|
||||
FSM_IDLE = 2'b00,
|
||||
FSM_TRANS = 2'b01,
|
||||
FSM_ERR_0 = 2'b10,
|
||||
FSM_ERR_1 = 2'b11
|
||||
} fsm_t;
|
||||
|
||||
/****************************
|
||||
* Determine current address
|
||||
****************************/
|
||||
logic [31:0] HADDR_q;
|
||||
logic [2:0] HSIZE_q;
|
||||
OP_t operation_q;
|
||||
|
||||
wire addr_err = HADDR % (32'b1 << HSIZE) != 32'b0;
|
||||
|
||||
always_ff @ (posedge HCLK)
|
||||
begin
|
||||
case (HTRANS)
|
||||
IDLE: ;// Do nothing
|
||||
BUSY: ;// Do nothing
|
||||
NONSEQ:
|
||||
begin
|
||||
// When a transfer is extended it has the side-effecxt
|
||||
// of extending the address phase of the next transfer
|
||||
if (HREADYOUT)
|
||||
begin
|
||||
HADDR_q <= HADDR;
|
||||
HSIZE_q <= HSIZE;
|
||||
operation_q <= HWRITE ? WRITE : READ;
|
||||
end
|
||||
end
|
||||
SEQ:
|
||||
begin
|
||||
if (HREADYOUT)
|
||||
begin
|
||||
HADDR_q <= HADDR;
|
||||
HSIZE_q <= HSIZE;
|
||||
end
|
||||
end
|
||||
endcase
|
||||
end
|
||||
|
||||
/****************************
|
||||
* Statemachine
|
||||
****************************/
|
||||
logic [BUS_BITS-1:0] HRDATA_temp;
|
||||
fsm_t fsm_next, fsm_q;
|
||||
|
||||
always_comb
|
||||
begin
|
||||
// Defaults
|
||||
HREADYOUT = 1'b1;
|
||||
HRESP = 1'b0;
|
||||
|
||||
// When reading back, the data of the bit that was accessed over the bus
|
||||
// should be at byte 0 of the HRDATA bus and bits that were not accessed
|
||||
// should be masked with 0s.
|
||||
HRDATA_temp = r2b.data >> (8*HADDR_q[BUS_BYTES_W-1:0]);
|
||||
|
||||
for (int i = 0; i < BUS_BYTES; i++)
|
||||
if (i < (1 << HSIZE_q))
|
||||
HRDATA[8*(i+1)-1 -: 8] = HRDATA_temp[8*(i+1)-1 -: 8];
|
||||
else
|
||||
HRDATA[8*(i+1)-1 -: 8] = 8'b0;
|
||||
|
||||
b2r_w_vld_next = 0;
|
||||
b2r_r_vld_next = 0;
|
||||
fsm_next = fsm_q;
|
||||
|
||||
case (fsm_q)
|
||||
default: // FSM_IDLE
|
||||
begin
|
||||
if (HSEL && HTRANS > BUSY)
|
||||
begin
|
||||
if (addr_err)
|
||||
// In case the address is illegal, switch to an error state
|
||||
fsm_next = FSM_ERR_0;
|
||||
else if (HTRANS == NONSEQ)
|
||||
// If NONSEQ, go to NONSEQ state
|
||||
fsm_next = FSM_TRANS;
|
||||
else if (HTRANS == SEQ)
|
||||
// If a SEQ is provided, something is wrong
|
||||
fsm_next = FSM_ERR_0;
|
||||
end
|
||||
end
|
||||
FSM_TRANS:
|
||||
begin
|
||||
HREADYOUT = r2b.rdy;
|
||||
b2r_w_vld_next = operation_q == WRITE;
|
||||
b2r_r_vld_next = operation_q == READ;
|
||||
|
||||
if (r2b.err && r2b.rdy)
|
||||
begin
|
||||
fsm_next = FSM_ERR_0;
|
||||
end
|
||||
else if (HTRANS == BUSY)
|
||||
begin
|
||||
// Wait
|
||||
fsm_next = FSM_TRANS;
|
||||
end
|
||||
else if (HTRANS == NONSEQ)
|
||||
begin
|
||||
// Another unrelated access is coming
|
||||
fsm_next = FSM_TRANS;
|
||||
end
|
||||
else if (HTRANS == SEQ)
|
||||
begin
|
||||
// Another part of the burst is coming
|
||||
fsm_next = FSM_TRANS;
|
||||
end
|
||||
else if (HTRANS == IDLE)
|
||||
begin
|
||||
// All done, wrapping things up!
|
||||
fsm_next = r2b.rdy ? FSM_IDLE : FSM_TRANS;
|
||||
end
|
||||
end
|
||||
FSM_ERR_0:
|
||||
begin
|
||||
HREADYOUT = 0;
|
||||
|
||||
if (HTRANS == BUSY)
|
||||
begin
|
||||
// Slaves must always provide a zero wait state OKAY response
|
||||
// to BUSY transfers and the transfer must be ignored by the slave.
|
||||
HRESP = OKAY;
|
||||
fsm_next = FSM_ERR_0;
|
||||
end
|
||||
else
|
||||
begin
|
||||
HRESP = ERROR;
|
||||
fsm_next = FSM_ERR_1;
|
||||
end
|
||||
end
|
||||
FSM_ERR_1:
|
||||
begin
|
||||
if (HTRANS == BUSY)
|
||||
begin
|
||||
// Slaves must always provide a zero wait state OKAY response
|
||||
// to BUSY transfers and the transfer must be ignored by the slave.
|
||||
HREADYOUT = 0;
|
||||
HRESP = OKAY;
|
||||
fsm_next = FSM_ERR_0;
|
||||
end
|
||||
else
|
||||
begin
|
||||
HREADYOUT = 1;
|
||||
HRESP = ERROR;
|
||||
|
||||
fsm_next = FSM_IDLE;
|
||||
end
|
||||
end
|
||||
endcase
|
||||
end
|
||||
|
||||
|
||||
always_ff @ (posedge HCLK or negedge HRESETn)
|
||||
if (!HRESETn)
|
||||
fsm_q <= FSM_IDLE;
|
||||
else
|
||||
fsm_q <= fsm_next;
|
||||
|
||||
/***
|
||||
* Determine the number of active bytes
|
||||
***/
|
||||
logic [BUS_BYTES-1:0] HSIZE_bitfielded;
|
||||
logic [BUS_BYTES-1:0] b2r_byte_en_next;
|
||||
logic b2r_w_vld_next;
|
||||
logic b2r_r_vld_next;
|
||||
|
||||
generate
|
||||
if (NO_BYTE_ENABLE)
|
||||
begin
|
||||
assign b2r_byte_en_next = {BUS_BYTES{1'b1}};
|
||||
end
|
||||
else
|
||||
begin
|
||||
always_comb
|
||||
begin
|
||||
for (int i = 0; i < BUS_BYTES; i++)
|
||||
HSIZE_bitfielded[i] = i < (1 << HSIZE_q);
|
||||
|
||||
// Shift if not the full bus is accessed
|
||||
b2r_byte_en_next = HSIZE_bitfielded << (HADDR_q % BUS_BYTES);
|
||||
end
|
||||
end
|
||||
endgenerate
|
||||
|
||||
/***
|
||||
* Drive interface to registers
|
||||
***/
|
||||
generate
|
||||
if (FLOP_REGISTER_IF)
|
||||
begin
|
||||
always_ff @ (posedge HCLK or negedge HRESETn)
|
||||
if (!HRESETn)
|
||||
begin
|
||||
b2r.w_vld <= 1'b0;
|
||||
b2r.r_vld <= 1'b0;
|
||||
end
|
||||
else
|
||||
begin
|
||||
b2r.w_vld <= b2r_w_vld_next;
|
||||
b2r.r_vld <= b2r_r_vld_next;
|
||||
end
|
||||
|
||||
always_ff @ (posedge HCLK)
|
||||
begin
|
||||
b2r.addr <= {HADDR_q[31:BUS_BYTES_W], {BUS_BYTES_W{1'b0}}};
|
||||
b2r.data <= HWDATA << (8*HADDR_q[BUS_BYTES_W-1:0]);
|
||||
b2r.byte_en <= b2r_byte_en_next;
|
||||
end
|
||||
end
|
||||
else
|
||||
begin
|
||||
assign b2r.w_vld = b2r_w_vld_next;
|
||||
assign b2r.r_vld = b2r_r_vld_next;
|
||||
assign b2r.addr = {HADDR_q[31:BUS_BYTES_W], {BUS_BYTES_W{1'b0}}};
|
||||
assign b2r.data = HWDATA << (8*HADDR_q[BUS_BYTES_W-1:0]);
|
||||
assign b2r.byte_en = b2r_byte_en_next;
|
||||
end
|
||||
endgenerate
|
||||
|
||||
endmodule
|
||||
|
18
examples/interrupt_hierarchy/srdl2sv_out/srdl2sv_if_pkg.sv
Normal file
18
examples/interrupt_hierarchy/srdl2sv_out/srdl2sv_if_pkg.sv
Normal file
@ -0,0 +1,18 @@
|
||||
package srdl2sv_if_pkg;
|
||||
|
||||
typedef struct packed { // .Verilator does not support unpacked structs in packages
|
||||
logic [31:0] addr;
|
||||
logic [31:0] data;
|
||||
logic w_vld;
|
||||
logic r_vld;
|
||||
logic [ 3:0] byte_en;
|
||||
} b2r_t;
|
||||
|
||||
typedef struct packed { // .Verilator does not support unpacked structs in packages
|
||||
logic [31:0] data;
|
||||
logic rdy;
|
||||
logic err;
|
||||
} r2b_t;
|
||||
|
||||
endpackage
|
||||
|
Loading…
Reference in New Issue
Block a user