Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
ycai
simbricks
Commits
738c1fef
Commit
738c1fef
authored
Jun 07, 2020
by
Antoine Kaufmann
Browse files
add corundum and verilator build files
parent
7f925101
Changes
157
Hide whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
9004 additions
and
0 deletions
+9004
-0
corundum/lib/axi/rtl/axi_crossbar_wr.v
corundum/lib/axi/rtl/axi_crossbar_wr.v
+672
-0
corundum/lib/axi/rtl/axi_dma.v
corundum/lib/axi/rtl/axi_dma.v
+353
-0
corundum/lib/axi/rtl/axi_dma_desc_mux.v
corundum/lib/axi/rtl/axi_dma_desc_mux.v
+309
-0
corundum/lib/axi/rtl/axi_dma_rd.v
corundum/lib/axi/rtl/axi_dma_rd.v
+671
-0
corundum/lib/axi/rtl/axi_dma_wr.v
corundum/lib/axi/rtl/axi_dma_wr.v
+899
-0
corundum/lib/axi/rtl/axi_dp_ram.v
corundum/lib/axi/rtl/axi_dp_ram.v
+424
-0
corundum/lib/axi/rtl/axi_fifo.v
corundum/lib/axi/rtl/axi_fifo.v
+312
-0
corundum/lib/axi/rtl/axi_fifo_rd.v
corundum/lib/axi/rtl/axi_fifo_rd.v
+409
-0
corundum/lib/axi/rtl/axi_fifo_wr.v
corundum/lib/axi/rtl/axi_fifo_wr.v
+450
-0
corundum/lib/axi/rtl/axi_interconnect.v
corundum/lib/axi/rtl/axi_interconnect.v
+941
-0
corundum/lib/axi/rtl/axi_ram.v
corundum/lib/axi/rtl/axi_ram.v
+370
-0
corundum/lib/axi/rtl/axi_ram_rd_if.v
corundum/lib/axi/rtl/axi_ram_rd_if.v
+270
-0
corundum/lib/axi/rtl/axi_ram_wr_if.v
corundum/lib/axi/rtl/axi_ram_wr_if.v
+286
-0
corundum/lib/axi/rtl/axi_ram_wr_rd_if.v
corundum/lib/axi/rtl/axi_ram_wr_rd_if.v
+333
-0
corundum/lib/axi/rtl/axi_register.v
corundum/lib/axi/rtl/axi_register.v
+320
-0
corundum/lib/axi/rtl/axi_register_rd.v
corundum/lib/axi/rtl/axi_register_rd.v
+526
-0
corundum/lib/axi/rtl/axi_register_wr.v
corundum/lib/axi/rtl/axi_register_wr.v
+687
-0
corundum/lib/axi/rtl/axil_adapter.v
corundum/lib/axi/rtl/axil_adapter.v
+174
-0
corundum/lib/axi/rtl/axil_adapter_rd.v
corundum/lib/axi/rtl/axil_adapter_rd.v
+268
-0
corundum/lib/axi/rtl/axil_adapter_wr.v
corundum/lib/axi/rtl/axil_adapter_wr.v
+330
-0
No files found.
Too many changes to show.
To preserve performance only
157 of 157+
files are displayed.
Plain diff
Email patch
corundum/lib/axi/rtl/axi_crossbar_wr.v
0 → 100644
View file @
738c1fef
/*
Copyright (c) 2018 Alex Forencich
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.
*/
// Language: Verilog 2001
`timescale
1
ns
/
1
ps
/*
* AXI4 crossbar (write)
*/
module
axi_crossbar_wr
#
(
// Number of AXI inputs (slave interfaces)
parameter
S_COUNT
=
4
,
// Number of AXI outputs (master interfaces)
parameter
M_COUNT
=
4
,
// Width of data bus in bits
parameter
DATA_WIDTH
=
32
,
// Width of address bus in bits
parameter
ADDR_WIDTH
=
32
,
// Width of wstrb (width of data bus in words)
parameter
STRB_WIDTH
=
(
DATA_WIDTH
/
8
),
// Input ID field width (from AXI masters)
parameter
S_ID_WIDTH
=
8
,
// Output ID field width (towards AXI slaves)
// Additional bits required for response routing
parameter
M_ID_WIDTH
=
S_ID_WIDTH
+
$
clog2
(
S_COUNT
),
// Propagate awuser signal
parameter
AWUSER_ENABLE
=
0
,
// Width of awuser signal
parameter
AWUSER_WIDTH
=
1
,
// Propagate wuser signal
parameter
WUSER_ENABLE
=
0
,
// Width of wuser signal
parameter
WUSER_WIDTH
=
1
,
// Propagate buser signal
parameter
BUSER_ENABLE
=
0
,
// Width of buser signal
parameter
BUSER_WIDTH
=
1
,
// Number of concurrent unique IDs for each slave interface
// S_COUNT concatenated fields of 32 bits
parameter
S_THREADS
=
{
S_COUNT
{
32'd2
}}
,
// Number of concurrent operations for each slave interface
// S_COUNT concatenated fields of 32 bits
parameter
S_ACCEPT
=
{
S_COUNT
{
32'd16
}}
,
// Number of regions per master interface
parameter
M_REGIONS
=
1
,
// Master interface base addresses
// M_COUNT concatenated fields of M_REGIONS concatenated fields of ADDR_WIDTH bits
// set to zero for default addressing based on M_ADDR_WIDTH
parameter
M_BASE_ADDR
=
0
,
// Master interface address widths
// M_COUNT concatenated fields of M_REGIONS concatenated fields of 32 bits
parameter
M_ADDR_WIDTH
=
{
M_COUNT
{{
M_REGIONS
{
32'd24
}}}}
,
// Write connections between interfaces
// M_COUNT concatenated fields of S_COUNT bits
parameter
M_CONNECT
=
{
M_COUNT
{{
S_COUNT
{
1'b1
}}}}
,
// Number of concurrent operations for each master interface
// M_COUNT concatenated fields of 32 bits
parameter
M_ISSUE
=
{
M_COUNT
{
32'd4
}}
,
// Secure master (fail operations based on awprot/arprot)
// M_COUNT bits
parameter
M_SECURE
=
{
M_COUNT
{
1'b0
}}
,
// Slave interface AW channel register type (input)
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter
S_AW_REG_TYPE
=
{
S_COUNT
{
2'd0
}}
,
// Slave interface W channel register type (input)
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter
S_W_REG_TYPE
=
{
S_COUNT
{
2'd0
}}
,
// Slave interface B channel register type (output)
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter
S_B_REG_TYPE
=
{
S_COUNT
{
2'd1
}}
,
// Master interface AW channel register type (output)
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter
M_AW_REG_TYPE
=
{
M_COUNT
{
2'd1
}}
,
// Master interface W channel register type (output)
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter
M_W_REG_TYPE
=
{
M_COUNT
{
2'd2
}}
,
// Master interface B channel register type (input)
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter
M_B_REG_TYPE
=
{
M_COUNT
{
2'd0
}}
)
(
input
wire
clk
,
input
wire
rst
,
/*
* AXI slave interfaces
*/
input
wire
[
S_COUNT
*
S_ID_WIDTH
-
1
:
0
]
s_axi_awid
,
input
wire
[
S_COUNT
*
ADDR_WIDTH
-
1
:
0
]
s_axi_awaddr
,
input
wire
[
S_COUNT
*
8
-
1
:
0
]
s_axi_awlen
,
input
wire
[
S_COUNT
*
3
-
1
:
0
]
s_axi_awsize
,
input
wire
[
S_COUNT
*
2
-
1
:
0
]
s_axi_awburst
,
input
wire
[
S_COUNT
-
1
:
0
]
s_axi_awlock
,
input
wire
[
S_COUNT
*
4
-
1
:
0
]
s_axi_awcache
,
input
wire
[
S_COUNT
*
3
-
1
:
0
]
s_axi_awprot
,
input
wire
[
S_COUNT
*
4
-
1
:
0
]
s_axi_awqos
,
input
wire
[
S_COUNT
*
AWUSER_WIDTH
-
1
:
0
]
s_axi_awuser
,
input
wire
[
S_COUNT
-
1
:
0
]
s_axi_awvalid
,
output
wire
[
S_COUNT
-
1
:
0
]
s_axi_awready
,
input
wire
[
S_COUNT
*
DATA_WIDTH
-
1
:
0
]
s_axi_wdata
,
input
wire
[
S_COUNT
*
STRB_WIDTH
-
1
:
0
]
s_axi_wstrb
,
input
wire
[
S_COUNT
-
1
:
0
]
s_axi_wlast
,
input
wire
[
S_COUNT
*
WUSER_WIDTH
-
1
:
0
]
s_axi_wuser
,
input
wire
[
S_COUNT
-
1
:
0
]
s_axi_wvalid
,
output
wire
[
S_COUNT
-
1
:
0
]
s_axi_wready
,
output
wire
[
S_COUNT
*
S_ID_WIDTH
-
1
:
0
]
s_axi_bid
,
output
wire
[
S_COUNT
*
2
-
1
:
0
]
s_axi_bresp
,
output
wire
[
S_COUNT
*
BUSER_WIDTH
-
1
:
0
]
s_axi_buser
,
output
wire
[
S_COUNT
-
1
:
0
]
s_axi_bvalid
,
input
wire
[
S_COUNT
-
1
:
0
]
s_axi_bready
,
/*
* AXI master interfaces
*/
output
wire
[
M_COUNT
*
M_ID_WIDTH
-
1
:
0
]
m_axi_awid
,
output
wire
[
M_COUNT
*
ADDR_WIDTH
-
1
:
0
]
m_axi_awaddr
,
output
wire
[
M_COUNT
*
8
-
1
:
0
]
m_axi_awlen
,
output
wire
[
M_COUNT
*
3
-
1
:
0
]
m_axi_awsize
,
output
wire
[
M_COUNT
*
2
-
1
:
0
]
m_axi_awburst
,
output
wire
[
M_COUNT
-
1
:
0
]
m_axi_awlock
,
output
wire
[
M_COUNT
*
4
-
1
:
0
]
m_axi_awcache
,
output
wire
[
M_COUNT
*
3
-
1
:
0
]
m_axi_awprot
,
output
wire
[
M_COUNT
*
4
-
1
:
0
]
m_axi_awqos
,
output
wire
[
M_COUNT
*
4
-
1
:
0
]
m_axi_awregion
,
output
wire
[
M_COUNT
*
AWUSER_WIDTH
-
1
:
0
]
m_axi_awuser
,
output
wire
[
M_COUNT
-
1
:
0
]
m_axi_awvalid
,
input
wire
[
M_COUNT
-
1
:
0
]
m_axi_awready
,
output
wire
[
M_COUNT
*
DATA_WIDTH
-
1
:
0
]
m_axi_wdata
,
output
wire
[
M_COUNT
*
STRB_WIDTH
-
1
:
0
]
m_axi_wstrb
,
output
wire
[
M_COUNT
-
1
:
0
]
m_axi_wlast
,
output
wire
[
M_COUNT
*
WUSER_WIDTH
-
1
:
0
]
m_axi_wuser
,
output
wire
[
M_COUNT
-
1
:
0
]
m_axi_wvalid
,
input
wire
[
M_COUNT
-
1
:
0
]
m_axi_wready
,
input
wire
[
M_COUNT
*
M_ID_WIDTH
-
1
:
0
]
m_axi_bid
,
input
wire
[
M_COUNT
*
2
-
1
:
0
]
m_axi_bresp
,
input
wire
[
M_COUNT
*
BUSER_WIDTH
-
1
:
0
]
m_axi_buser
,
input
wire
[
M_COUNT
-
1
:
0
]
m_axi_bvalid
,
output
wire
[
M_COUNT
-
1
:
0
]
m_axi_bready
);
parameter
CL_S_COUNT
=
$
clog2
(
S_COUNT
);
parameter
CL_M_COUNT
=
$
clog2
(
M_COUNT
);
parameter
M_COUNT_P1
=
M_COUNT
+
1
;
parameter
CL_M_COUNT_P1
=
$
clog2
(
M_COUNT_P1
);
integer
i
;
// check configuration
initial
begin
if
(
M_ID_WIDTH
<
S_ID_WIDTH
+
$
clog2
(
S_COUNT
))
begin
$
error
(
"Error: M_ID_WIDTH must be at least $clog2(S_COUNT) larger than S_ID_WIDTH (instance %m)"
);
$
finish
;
end
for
(
i
=
0
;
i
<
M_COUNT
*
M_REGIONS
;
i
=
i
+
1
)
begin
if
(
M_ADDR_WIDTH
[
i
*
32
+:
32
]
&&
(
M_ADDR_WIDTH
[
i
*
32
+:
32
]
<
12
||
M_ADDR_WIDTH
[
i
*
32
+:
32
]
>
ADDR_WIDTH
))
begin
$
error
(
"Error: value out of range (instance %m)"
);
$
finish
;
end
end
end
wire
[
S_COUNT
*
S_ID_WIDTH
-
1
:
0
]
int_s_axi_awid
;
wire
[
S_COUNT
*
ADDR_WIDTH
-
1
:
0
]
int_s_axi_awaddr
;
wire
[
S_COUNT
*
8
-
1
:
0
]
int_s_axi_awlen
;
wire
[
S_COUNT
*
3
-
1
:
0
]
int_s_axi_awsize
;
wire
[
S_COUNT
*
2
-
1
:
0
]
int_s_axi_awburst
;
wire
[
S_COUNT
-
1
:
0
]
int_s_axi_awlock
;
wire
[
S_COUNT
*
4
-
1
:
0
]
int_s_axi_awcache
;
wire
[
S_COUNT
*
3
-
1
:
0
]
int_s_axi_awprot
;
wire
[
S_COUNT
*
4
-
1
:
0
]
int_s_axi_awqos
;
wire
[
S_COUNT
*
4
-
1
:
0
]
int_s_axi_awregion
;
wire
[
S_COUNT
*
AWUSER_WIDTH
-
1
:
0
]
int_s_axi_awuser
;
wire
[
S_COUNT
-
1
:
0
]
int_s_axi_awvalid
;
wire
[
S_COUNT
-
1
:
0
]
int_s_axi_awready
;
wire
[
S_COUNT
*
M_COUNT
-
1
:
0
]
int_axi_awvalid
;
wire
[
M_COUNT
*
S_COUNT
-
1
:
0
]
int_axi_awready
;
wire
[
S_COUNT
*
DATA_WIDTH
-
1
:
0
]
int_s_axi_wdata
;
wire
[
S_COUNT
*
STRB_WIDTH
-
1
:
0
]
int_s_axi_wstrb
;
wire
[
S_COUNT
-
1
:
0
]
int_s_axi_wlast
;
wire
[
S_COUNT
*
WUSER_WIDTH
-
1
:
0
]
int_s_axi_wuser
;
wire
[
S_COUNT
-
1
:
0
]
int_s_axi_wvalid
;
wire
[
S_COUNT
-
1
:
0
]
int_s_axi_wready
;
wire
[
S_COUNT
*
M_COUNT
-
1
:
0
]
int_axi_wvalid
;
wire
[
M_COUNT
*
S_COUNT
-
1
:
0
]
int_axi_wready
;
wire
[
M_COUNT
*
M_ID_WIDTH
-
1
:
0
]
int_m_axi_bid
;
wire
[
M_COUNT
*
2
-
1
:
0
]
int_m_axi_bresp
;
wire
[
M_COUNT
*
BUSER_WIDTH
-
1
:
0
]
int_m_axi_buser
;
wire
[
M_COUNT
-
1
:
0
]
int_m_axi_bvalid
;
wire
[
M_COUNT
-
1
:
0
]
int_m_axi_bready
;
wire
[
M_COUNT
*
S_COUNT
-
1
:
0
]
int_axi_bvalid
;
wire
[
S_COUNT
*
M_COUNT
-
1
:
0
]
int_axi_bready
;
generate
genvar
m
,
n
;
for
(
m
=
0
;
m
<
S_COUNT
;
m
=
m
+
1
)
begin
:
s_ifaces
// address decode and admission control
wire
[
CL_M_COUNT
-
1
:
0
]
a_select
;
wire
m_axi_avalid
;
wire
m_axi_aready
;
wire
[
CL_M_COUNT
-
1
:
0
]
m_wc_select
;
wire
m_wc_decerr
;
wire
m_wc_valid
;
wire
m_wc_ready
;
wire
m_rc_decerr
;
wire
m_rc_valid
;
wire
m_rc_ready
;
wire
[
S_ID_WIDTH
-
1
:
0
]
s_cpl_id
;
wire
s_cpl_valid
;
axi_crossbar_addr
#(
.
S
(
m
),
.
S_COUNT
(
S_COUNT
),
.
M_COUNT
(
M_COUNT
),
.
ADDR_WIDTH
(
ADDR_WIDTH
),
.
ID_WIDTH
(
S_ID_WIDTH
),
.
S_THREADS
(
S_THREADS
[
m
*
32
+:
32
]),
.
S_ACCEPT
(
S_ACCEPT
[
m
*
32
+:
32
]),
.
M_REGIONS
(
M_REGIONS
),
.
M_BASE_ADDR
(
M_BASE_ADDR
),
.
M_ADDR_WIDTH
(
M_ADDR_WIDTH
),
.
M_CONNECT
(
M_CONNECT
),
.
M_SECURE
(
M_SECURE
),
.
WC_OUTPUT
(
1
)
)
addr_inst
(
.
clk
(
clk
),
.
rst
(
rst
),
/*
* Address input
*/
.
s_axi_aid
(
int_s_axi_awid
[
m
*
S_ID_WIDTH
+:
S_ID_WIDTH
]),
.
s_axi_aaddr
(
int_s_axi_awaddr
[
m
*
ADDR_WIDTH
+:
ADDR_WIDTH
]),
.
s_axi_aprot
(
int_s_axi_awprot
[
m
*
3
+:
3
]),
.
s_axi_aqos
(
int_s_axi_awqos
[
m
*
4
+:
4
]),
.
s_axi_avalid
(
int_s_axi_awvalid
[
m
]),
.
s_axi_aready
(
int_s_axi_awready
[
m
]),
/*
* Address output
*/
.
m_axi_aregion
(
int_s_axi_awregion
[
m
*
4
+:
4
]),
.
m_select
(
a_select
),
.
m_axi_avalid
(
m_axi_avalid
),
.
m_axi_aready
(
m_axi_aready
),
/*
* Write command output
*/
.
m_wc_select
(
m_wc_select
),
.
m_wc_decerr
(
m_wc_decerr
),
.
m_wc_valid
(
m_wc_valid
),
.
m_wc_ready
(
m_wc_ready
),
/*
* Response command output
*/
.
m_rc_decerr
(
m_rc_decerr
),
.
m_rc_valid
(
m_rc_valid
),
.
m_rc_ready
(
m_rc_ready
),
/*
* Completion input
*/
.
s_cpl_id
(
s_cpl_id
),
.
s_cpl_valid
(
s_cpl_valid
)
);
assign
int_axi_awvalid
[
m
*
M_COUNT
+:
M_COUNT
]
=
m_axi_avalid
<<
a_select
;
assign
m_axi_aready
=
int_axi_awready
[
a_select
*
S_COUNT
+
m
];
// write command handling
reg
[
CL_M_COUNT
-
1
:
0
]
w_select_reg
=
0
,
w_select_next
;
reg
w_drop_reg
=
1'b0
,
w_drop_next
;
reg
w_select_valid_reg
=
1'b0
,
w_select_valid_next
;
assign
m_wc_ready
=
!
w_select_valid_reg
;
always
@*
begin
w_select_next
=
w_select_reg
;
w_drop_next
=
w_drop_reg
&&
!
(
int_s_axi_wvalid
[
m
]
&&
int_s_axi_wready
[
m
]
&&
int_s_axi_wlast
[
m
]);
w_select_valid_next
=
w_select_valid_reg
&&
!
(
int_s_axi_wvalid
[
m
]
&&
int_s_axi_wready
[
m
]
&&
int_s_axi_wlast
[
m
]);
if
(
m_wc_valid
&&
!
w_select_valid_reg
)
begin
w_select_next
=
m_wc_select
;
w_drop_next
=
m_wc_decerr
;
w_select_valid_next
=
m_wc_valid
;
end
end
always
@
(
posedge
clk
)
begin
if
(
rst
)
begin
w_select_valid_reg
<=
1'b0
;
end
else
begin
w_select_valid_reg
<=
w_select_valid_next
;
end
w_select_reg
<=
w_select_next
;
w_drop_reg
<=
w_drop_next
;
end
// write data forwarding
assign
int_axi_wvalid
[
m
*
M_COUNT
+:
M_COUNT
]
=
(
int_s_axi_wvalid
[
m
]
&&
w_select_valid_reg
&&
!
w_drop_reg
)
<<
w_select_reg
;
assign
int_s_axi_wready
[
m
]
=
int_axi_wready
[
w_select_reg
*
S_COUNT
+
m
]
||
w_drop_reg
;
// decode error handling
reg
[
S_ID_WIDTH
-
1
:
0
]
decerr_m_axi_bid_reg
=
{
S_ID_WIDTH
{
1'b0
}}
,
decerr_m_axi_bid_next
;
reg
decerr_m_axi_bvalid_reg
=
1'b0
,
decerr_m_axi_bvalid_next
;
wire
decerr_m_axi_bready
;
assign
m_rc_ready
=
!
decerr_m_axi_bvalid_reg
;
always
@*
begin
decerr_m_axi_bid_next
=
decerr_m_axi_bid_reg
;
decerr_m_axi_bvalid_next
=
decerr_m_axi_bvalid_reg
;
if
(
decerr_m_axi_bvalid_reg
)
begin
if
(
decerr_m_axi_bready
)
begin
decerr_m_axi_bvalid_next
=
1'b0
;
end
end
else
if
(
m_rc_valid
&&
m_rc_ready
)
begin
decerr_m_axi_bid_next
=
int_s_axi_awid
[
m
*
S_ID_WIDTH
+:
S_ID_WIDTH
];
decerr_m_axi_bvalid_next
=
1'b1
;
end
end
always
@
(
posedge
clk
)
begin
if
(
rst
)
begin
decerr_m_axi_bvalid_reg
<=
1'b0
;
end
else
begin
decerr_m_axi_bvalid_reg
<=
decerr_m_axi_bvalid_next
;
end
decerr_m_axi_bid_reg
<=
decerr_m_axi_bid_next
;
end
// write response arbitration
wire
[
M_COUNT_P1
-
1
:
0
]
b_request
;
wire
[
M_COUNT_P1
-
1
:
0
]
b_acknowledge
;
wire
[
M_COUNT_P1
-
1
:
0
]
b_grant
;
wire
b_grant_valid
;
wire
[
CL_M_COUNT_P1
-
1
:
0
]
b_grant_encoded
;
arbiter
#(
.
PORTS
(
M_COUNT_P1
),
.
TYPE
(
"ROUND_ROBIN"
),
.
BLOCK
(
"ACKNOWLEDGE"
),
.
LSB_PRIORITY
(
"HIGH"
)
)
b_arb_inst
(
.
clk
(
clk
),
.
rst
(
rst
),
.
request
(
b_request
),
.
acknowledge
(
b_acknowledge
),
.
grant
(
b_grant
),
.
grant_valid
(
b_grant_valid
),
.
grant_encoded
(
b_grant_encoded
)
);
// write response mux
wire
[
S_ID_WIDTH
-
1
:
0
]
m_axi_bid_mux
=
{
decerr_m_axi_bid_reg
,
int_m_axi_bid
}
>>
b_grant_encoded
*
M_ID_WIDTH
;
wire
[
1
:
0
]
m_axi_bresp_mux
=
{
2'b11
,
int_m_axi_bresp
}
>>
b_grant_encoded
*
2
;
wire
[
BUSER_WIDTH
-
1
:
0
]
m_axi_buser_mux
=
{{
BUSER_WIDTH
{
1'b0
}}
,
int_m_axi_buser
}
>>
b_grant_encoded
*
BUSER_WIDTH
;
wire
m_axi_bvalid_mux
=
(
{
decerr_m_axi_bvalid_reg
,
int_m_axi_bvalid
}
>>
b_grant_encoded
)
&
b_grant_valid
;
wire
m_axi_bready_mux
;
assign
int_axi_bready
[
m
*
M_COUNT
+:
M_COUNT
]
=
(
b_grant_valid
&&
m_axi_bready_mux
)
<<
b_grant_encoded
;
assign
decerr_m_axi_bready
=
(
b_grant_valid
&&
m_axi_bready_mux
)
&&
(
b_grant_encoded
==
M_COUNT_P1
-
1
);
for
(
n
=
0
;
n
<
M_COUNT
;
n
=
n
+
1
)
begin
assign
b_request
[
n
]
=
int_axi_bvalid
[
n
*
S_COUNT
+
m
]
&&
!
b_grant
[
n
];
assign
b_acknowledge
[
n
]
=
b_grant
[
n
]
&&
int_axi_bvalid
[
n
*
S_COUNT
+
m
]
&&
m_axi_bready_mux
;
end
assign
b_request
[
M_COUNT_P1
-
1
]
=
decerr_m_axi_bvalid_reg
&&
!
b_grant
[
M_COUNT_P1
-
1
];
assign
b_acknowledge
[
M_COUNT_P1
-
1
]
=
b_grant
[
M_COUNT_P1
-
1
]
&&
decerr_m_axi_bvalid_reg
&&
m_axi_bready_mux
;
assign
s_cpl_id
=
m_axi_bid_mux
;
assign
s_cpl_valid
=
m_axi_bvalid_mux
&&
m_axi_bready_mux
;
// S side register
axi_register_wr
#(
.
DATA_WIDTH
(
DATA_WIDTH
),
.
ADDR_WIDTH
(
ADDR_WIDTH
),
.
STRB_WIDTH
(
STRB_WIDTH
),
.
ID_WIDTH
(
S_ID_WIDTH
),
.
AWUSER_ENABLE
(
AWUSER_ENABLE
),
.
AWUSER_WIDTH
(
AWUSER_WIDTH
),
.
WUSER_ENABLE
(
WUSER_ENABLE
),
.
WUSER_WIDTH
(
WUSER_WIDTH
),
.
BUSER_ENABLE
(
BUSER_ENABLE
),
.
BUSER_WIDTH
(
BUSER_WIDTH
),
.
AW_REG_TYPE
(
S_AW_REG_TYPE
[
m
*
2
+:
2
]),
.
W_REG_TYPE
(
S_W_REG_TYPE
[
m
*
2
+:
2
]),
.
B_REG_TYPE
(
S_B_REG_TYPE
[
m
*
2
+:
2
])
)
reg_inst
(
.
clk
(
clk
),
.
rst
(
rst
),
.
s_axi_awid
(
s_axi_awid
[
m
*
S_ID_WIDTH
+:
S_ID_WIDTH
]),
.
s_axi_awaddr
(
s_axi_awaddr
[
m
*
ADDR_WIDTH
+:
ADDR_WIDTH
]),
.
s_axi_awlen
(
s_axi_awlen
[
m
*
8
+:
8
]),
.
s_axi_awsize
(
s_axi_awsize
[
m
*
3
+:
3
]),
.
s_axi_awburst
(
s_axi_awburst
[
m
*
2
+:
2
]),
.
s_axi_awlock
(
s_axi_awlock
[
m
]),
.
s_axi_awcache
(
s_axi_awcache
[
m
*
4
+:
4
]),
.
s_axi_awprot
(
s_axi_awprot
[
m
*
3
+:
3
]),
.
s_axi_awqos
(
s_axi_awqos
[
m
*
4
+:
4
]),
.
s_axi_awregion
(
4'd0
),
.
s_axi_awuser
(
s_axi_awuser
[
m
*
AWUSER_WIDTH
+:
AWUSER_WIDTH
]),
.
s_axi_awvalid
(
s_axi_awvalid
[
m
]),
.
s_axi_awready
(
s_axi_awready
[
m
]),
.
s_axi_wdata
(
s_axi_wdata
[
m
*
DATA_WIDTH
+:
DATA_WIDTH
]),
.
s_axi_wstrb
(
s_axi_wstrb
[
m
*
STRB_WIDTH
+:
STRB_WIDTH
]),
.
s_axi_wlast
(
s_axi_wlast
[
m
]),
.
s_axi_wuser
(
s_axi_wuser
[
m
*
WUSER_WIDTH
+:
WUSER_WIDTH
]),
.
s_axi_wvalid
(
s_axi_wvalid
[
m
]),
.
s_axi_wready
(
s_axi_wready
[
m
]),
.
s_axi_bid
(
s_axi_bid
[
m
*
S_ID_WIDTH
+:
S_ID_WIDTH
]),
.
s_axi_bresp
(
s_axi_bresp
[
m
*
2
+:
2
]),
.
s_axi_buser
(
s_axi_buser
[
m
*
BUSER_WIDTH
+:
BUSER_WIDTH
]),
.
s_axi_bvalid
(
s_axi_bvalid
[
m
]),
.
s_axi_bready
(
s_axi_bready
[
m
]),
.
m_axi_awid
(
int_s_axi_awid
[
m
*
S_ID_WIDTH
+:
S_ID_WIDTH
]),
.
m_axi_awaddr
(
int_s_axi_awaddr
[
m
*
ADDR_WIDTH
+:
ADDR_WIDTH
]),
.
m_axi_awlen
(
int_s_axi_awlen
[
m
*
8
+:
8
]),
.
m_axi_awsize
(
int_s_axi_awsize
[
m
*
3
+:
3
]),
.
m_axi_awburst
(
int_s_axi_awburst
[
m
*
2
+:
2
]),
.
m_axi_awlock
(
int_s_axi_awlock
[
m
]),
.
m_axi_awcache
(
int_s_axi_awcache
[
m
*
4
+:
4
]),
.
m_axi_awprot
(
int_s_axi_awprot
[
m
*
3
+:
3
]),
.
m_axi_awqos
(
int_s_axi_awqos
[
m
*
4
+:
4
]),
.
m_axi_awregion
(),
.
m_axi_awuser
(
int_s_axi_awuser
[
m
*
AWUSER_WIDTH
+:
AWUSER_WIDTH
]),
.
m_axi_awvalid
(
int_s_axi_awvalid
[
m
]),
.
m_axi_awready
(
int_s_axi_awready
[
m
]),
.
m_axi_wdata
(
int_s_axi_wdata
[
m
*
DATA_WIDTH
+:
DATA_WIDTH
]),
.
m_axi_wstrb
(
int_s_axi_wstrb
[
m
*
STRB_WIDTH
+:
STRB_WIDTH
]),
.
m_axi_wlast
(
int_s_axi_wlast
[
m
]),
.
m_axi_wuser
(
int_s_axi_wuser
[
m
*
WUSER_WIDTH
+:
WUSER_WIDTH
]),
.
m_axi_wvalid
(
int_s_axi_wvalid
[
m
]),
.
m_axi_wready
(
int_s_axi_wready
[
m
]),
.
m_axi_bid
(
m_axi_bid_mux
),
.
m_axi_bresp
(
m_axi_bresp_mux
),
.
m_axi_buser
(
m_axi_buser_mux
),
.
m_axi_bvalid
(
m_axi_bvalid_mux
),
.
m_axi_bready
(
m_axi_bready_mux
)
);
end
// s_ifaces
for
(
n
=
0
;
n
<
M_COUNT
;
n
=
n
+
1
)
begin
:
m_ifaces
// in-flight transaction count
wire
trans_start
;
wire
trans_complete
;
reg
[$
clog2
(
M_ISSUE
[
n
*
32
+:
32
]
+
1
)
-
1
:
0
]
trans_count_reg
=
0
;
wire
trans_limit
=
trans_count_reg
>=
M_ISSUE
[
n
*
32
+:
32
]
&&
!
trans_complete
;
always
@
(
posedge
clk
)
begin
if
(
rst
)
begin
trans_count_reg
<=
0
;
end
else
begin
if
(
trans_start
&&
!
trans_complete
)
begin
trans_count_reg
<=
trans_count_reg
+
1
;
end
else
if
(
!
trans_start
&&
trans_complete
)
begin
trans_count_reg
<=
trans_count_reg
-
1
;
end
end
end
// address arbitration
reg
[
CL_S_COUNT
-
1
:
0
]
w_select_reg
=
0
,
w_select_next
;
reg
w_select_valid_reg
=
1'b0
,
w_select_valid_next
;
reg
w_select_new_reg
=
1'b0
,
w_select_new_next
;
wire
[
S_COUNT
-
1
:
0
]
a_request
;
wire
[
S_COUNT
-
1
:
0
]
a_acknowledge
;
wire
[
S_COUNT
-
1
:
0
]
a_grant
;
wire
a_grant_valid
;
wire
[
CL_S_COUNT
-
1
:
0
]
a_grant_encoded
;
arbiter
#(
.
PORTS
(
S_COUNT
),
.
TYPE
(
"ROUND_ROBIN"
),
.
BLOCK
(
"ACKNOWLEDGE"
),
.
LSB_PRIORITY
(
"HIGH"
)
)
a_arb_inst
(
.
clk
(
clk
),
.
rst
(
rst
),
.
request
(
a_request
),
.
acknowledge
(
a_acknowledge
),
.
grant
(
a_grant
),
.
grant_valid
(
a_grant_valid
),
.
grant_encoded
(
a_grant_encoded
)
);
// address mux
wire
[
M_ID_WIDTH
-
1
:
0
]
s_axi_awid_mux
=
int_s_axi_awid
[
a_grant_encoded
*
S_ID_WIDTH
+:
S_ID_WIDTH
]
|
(
a_grant_encoded
<<
S_ID_WIDTH
);
wire
[
ADDR_WIDTH
-
1
:
0
]
s_axi_awaddr_mux
=
int_s_axi_awaddr
[
a_grant_encoded
*
ADDR_WIDTH
+:
ADDR_WIDTH
];
wire
[
7
:
0
]
s_axi_awlen_mux
=
int_s_axi_awlen
[
a_grant_encoded
*
8
+:
8
];
wire
[
2
:
0
]
s_axi_awsize_mux
=
int_s_axi_awsize
[
a_grant_encoded
*
3
+:
3
];
wire
[
1
:
0
]
s_axi_awburst_mux
=
int_s_axi_awburst
[
a_grant_encoded
*
2
+:
2
];
wire
s_axi_awlock_mux
=
int_s_axi_awlock
[
a_grant_encoded
];
wire
[
3
:
0
]
s_axi_awcache_mux
=
int_s_axi_awcache
[
a_grant_encoded
*
4
+:
4
];
wire
[
2
:
0
]
s_axi_awprot_mux
=
int_s_axi_awprot
[
a_grant_encoded
*
3
+:
3
];
wire
[
3
:
0
]
s_axi_awqos_mux
=
int_s_axi_awqos
[
a_grant_encoded
*
4
+:
4
];
wire
[
3
:
0
]
s_axi_awregion_mux
=
int_s_axi_awregion
[
a_grant_encoded
*
4
+:
4
];
wire
[
AWUSER_WIDTH
-
1
:
0
]
s_axi_awuser_mux
=
int_s_axi_awuser
[
a_grant_encoded
*
AWUSER_WIDTH
+:
AWUSER_WIDTH
];
wire
s_axi_awvalid_mux
=
int_axi_awvalid
[
a_grant_encoded
*
M_COUNT
+
n
]
&&
a_grant_valid
;
wire
s_axi_awready_mux
;
assign
int_axi_awready
[
n
*
S_COUNT
+:
S_COUNT
]
=
(
a_grant_valid
&&
s_axi_awready_mux
)
<<
a_grant_encoded
;
for
(
m
=
0
;
m
<
S_COUNT
;
m
=
m
+
1
)
begin
assign
a_request
[
m
]
=
int_axi_awvalid
[
m
*
M_COUNT
+
n
]
&&
!
a_grant
[
m
]
&&
!
trans_limit
&&
!
w_select_valid_next
;
assign
a_acknowledge
[
m
]
=
a_grant
[
m
]
&&
int_axi_awvalid
[
m
*
M_COUNT
+
n
]
&&
s_axi_awready_mux
;
end
assign
trans_start
=
s_axi_awvalid_mux
&&
s_axi_awready_mux
&&
a_grant_valid
;
// write data mux
wire
[
DATA_WIDTH
-
1
:
0
]
s_axi_wdata_mux
=
int_s_axi_wdata
[
w_select_reg
*
DATA_WIDTH
+:
DATA_WIDTH
];
wire
[
STRB_WIDTH
-
1
:
0
]
s_axi_wstrb_mux
=
int_s_axi_wstrb
[
w_select_reg
*
STRB_WIDTH
+:
STRB_WIDTH
];
wire
s_axi_wlast_mux
=
int_s_axi_wlast
[
w_select_reg
];
wire
[
WUSER_WIDTH
-
1
:
0
]
s_axi_wuser_mux
=
int_s_axi_wuser
[
w_select_reg
*
WUSER_WIDTH
+:
WUSER_WIDTH
];
wire
s_axi_wvalid_mux
=
int_axi_wvalid
[
w_select_reg
*
M_COUNT
+
n
]
&&
w_select_valid_reg
;
wire
s_axi_wready_mux
;
assign
int_axi_wready
[
n
*
S_COUNT
+:
S_COUNT
]
=
(
w_select_valid_reg
&&
s_axi_wready_mux
)
<<
w_select_reg
;
// write data routing
always
@*
begin
w_select_next
=
w_select_reg
;
w_select_valid_next
=
w_select_valid_reg
&&
!
(
s_axi_wvalid_mux
&&
s_axi_wready_mux
&&
s_axi_wlast_mux
);
w_select_new_next
=
w_select_new_reg
||
!
a_grant_valid
||
a_acknowledge
;
if
(
a_grant_valid
&&
!
w_select_valid_reg
&&
w_select_new_reg
)
begin
w_select_next
=
a_grant_encoded
;
w_select_valid_next
=
a_grant_valid
;
w_select_new_next
=
1'b0
;
end
end
always
@
(
posedge
clk
)
begin
if
(
rst
)
begin
w_select_valid_reg
<=
1'b0
;
w_select_new_reg
<=
1'b1
;
end
else
begin
w_select_valid_reg
<=
w_select_valid_next
;
w_select_new_reg
<=
w_select_new_next
;
end
w_select_reg
<=
w_select_next
;
end
// write response forwarding
wire
[
CL_S_COUNT
-
1
:
0
]
b_select
=
m_axi_bid
[
n
*
M_ID_WIDTH
+:
M_ID_WIDTH
]
>>
S_ID_WIDTH
;
assign
int_axi_bvalid
[
n
*
S_COUNT
+:
S_COUNT
]
=
int_m_axi_bvalid
[
n
]
<<
b_select
;
assign
int_m_axi_bready
[
n
]
=
int_axi_bready
[
b_select
*
M_COUNT
+
n
];
assign
trans_complete
=
int_m_axi_bvalid
[
n
]
&&
int_m_axi_bready
[
n
];
// M side register
axi_register_wr
#(
.
DATA_WIDTH
(
DATA_WIDTH
),
.
ADDR_WIDTH
(
ADDR_WIDTH
),
.
STRB_WIDTH
(
STRB_WIDTH
),
.
ID_WIDTH
(
M_ID_WIDTH
),
.
AWUSER_ENABLE
(
AWUSER_ENABLE
),
.
AWUSER_WIDTH
(
AWUSER_WIDTH
),
.
WUSER_ENABLE
(
WUSER_ENABLE
),
.
WUSER_WIDTH
(
WUSER_WIDTH
),
.
BUSER_ENABLE
(
BUSER_ENABLE
),
.
BUSER_WIDTH
(
BUSER_WIDTH
),
.
AW_REG_TYPE
(
M_AW_REG_TYPE
[
n
*
2
+:
2
]),
.
W_REG_TYPE
(
M_W_REG_TYPE
[
n
*
2
+:
2
]),
.
B_REG_TYPE
(
M_B_REG_TYPE
[
n
*
2
+:
2
])
)
reg_inst
(
.
clk
(
clk
),
.
rst
(
rst
),
.
s_axi_awid
(
s_axi_awid_mux
),
.
s_axi_awaddr
(
s_axi_awaddr_mux
),
.
s_axi_awlen
(
s_axi_awlen_mux
),
.
s_axi_awsize
(
s_axi_awsize_mux
),
.
s_axi_awburst
(
s_axi_awburst_mux
),
.
s_axi_awlock
(
s_axi_awlock_mux
),
.
s_axi_awcache
(
s_axi_awcache_mux
),
.
s_axi_awprot
(
s_axi_awprot_mux
),
.
s_axi_awqos
(
s_axi_awqos_mux
),
.
s_axi_awregion
(
s_axi_awregion_mux
),
.
s_axi_awuser
(
s_axi_awuser_mux
),
.
s_axi_awvalid
(
s_axi_awvalid_mux
),
.
s_axi_awready
(
s_axi_awready_mux
),
.
s_axi_wdata
(
s_axi_wdata_mux
),
.
s_axi_wstrb
(
s_axi_wstrb_mux
),
.
s_axi_wlast
(
s_axi_wlast_mux
),
.
s_axi_wuser
(
s_axi_wuser_mux
),
.
s_axi_wvalid
(
s_axi_wvalid_mux
),
.
s_axi_wready
(
s_axi_wready_mux
),
.
s_axi_bid
(
int_m_axi_bid
[
n
*
M_ID_WIDTH
+:
M_ID_WIDTH
]),
.
s_axi_bresp
(
int_m_axi_bresp
[
n
*
2
+:
2
]),
.
s_axi_buser
(
int_m_axi_buser
[
n
*
BUSER_WIDTH
+:
BUSER_WIDTH
]),
.
s_axi_bvalid
(
int_m_axi_bvalid
[
n
]),
.
s_axi_bready
(
int_m_axi_bready
[
n
]),
.
m_axi_awid
(
m_axi_awid
[
n
*
M_ID_WIDTH
+:
M_ID_WIDTH
]),
.
m_axi_awaddr
(
m_axi_awaddr
[
n
*
ADDR_WIDTH
+:
ADDR_WIDTH
]),
.
m_axi_awlen
(
m_axi_awlen
[
n
*
8
+:
8
]),
.
m_axi_awsize
(
m_axi_awsize
[
n
*
3
+:
3
]),
.
m_axi_awburst
(
m_axi_awburst
[
n
*
2
+:
2
]),
.
m_axi_awlock
(
m_axi_awlock
[
n
]),
.
m_axi_awcache
(
m_axi_awcache
[
n
*
4
+:
4
]),
.
m_axi_awprot
(
m_axi_awprot
[
n
*
3
+:
3
]),
.
m_axi_awqos
(
m_axi_awqos
[
n
*
4
+:
4
]),
.
m_axi_awregion
(
m_axi_awregion
[
n
*
4
+:
4
]),
.
m_axi_awuser
(
m_axi_awuser
[
n
*
AWUSER_WIDTH
+:
AWUSER_WIDTH
]),
.
m_axi_awvalid
(
m_axi_awvalid
[
n
]),
.
m_axi_awready
(
m_axi_awready
[
n
]),
.
m_axi_wdata
(
m_axi_wdata
[
n
*
DATA_WIDTH
+:
DATA_WIDTH
]),
.
m_axi_wstrb
(
m_axi_wstrb
[
n
*
STRB_WIDTH
+:
STRB_WIDTH
]),
.
m_axi_wlast
(
m_axi_wlast
[
n
]),
.
m_axi_wuser
(
m_axi_wuser
[
n
*
WUSER_WIDTH
+:
WUSER_WIDTH
]),
.
m_axi_wvalid
(
m_axi_wvalid
[
n
]),
.
m_axi_wready
(
m_axi_wready
[
n
]),
.
m_axi_bid
(
m_axi_bid
[
n
*
M_ID_WIDTH
+:
M_ID_WIDTH
]),
.
m_axi_bresp
(
m_axi_bresp
[
n
*
2
+:
2
]),
.
m_axi_buser
(
m_axi_buser
[
n
*
BUSER_WIDTH
+:
BUSER_WIDTH
]),
.
m_axi_bvalid
(
m_axi_bvalid
[
n
]),
.
m_axi_bready
(
m_axi_bready
[
n
])
);
end
// m_ifaces
endgenerate
endmodule
corundum/lib/axi/rtl/axi_dma.v
0 → 100644
View file @
738c1fef
/*
Copyright (c) 2018 Alex Forencich
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.
*/
// Language: Verilog 2001
`timescale
1
ns
/
1
ps
/*
* AXI4 DMA
*/
module
axi_dma
#
(
// Width of AXI data bus in bits
parameter
AXI_DATA_WIDTH
=
32
,
// Width of AXI address bus in bits
parameter
AXI_ADDR_WIDTH
=
16
,
// Width of AXI wstrb (width of data bus in words)
parameter
AXI_STRB_WIDTH
=
(
AXI_DATA_WIDTH
/
8
),
// Width of AXI ID signal
parameter
AXI_ID_WIDTH
=
8
,
// Maximum AXI burst length to generate
parameter
AXI_MAX_BURST_LEN
=
16
,
// Width of AXI stream interfaces in bits
parameter
AXIS_DATA_WIDTH
=
AXI_DATA_WIDTH
,
// Use AXI stream tkeep signal
parameter
AXIS_KEEP_ENABLE
=
(
AXIS_DATA_WIDTH
>
8
),
// AXI stream tkeep signal width (words per cycle)
parameter
AXIS_KEEP_WIDTH
=
(
AXIS_DATA_WIDTH
/
8
),
// Use AXI stream tlast signal
parameter
AXIS_LAST_ENABLE
=
1
,
// Propagate AXI stream tid signal
parameter
AXIS_ID_ENABLE
=
0
,
// AXI stream tid signal width
parameter
AXIS_ID_WIDTH
=
8
,
// Propagate AXI stream tdest signal
parameter
AXIS_DEST_ENABLE
=
0
,
// AXI stream tdest signal width
parameter
AXIS_DEST_WIDTH
=
8
,
// Propagate AXI stream tuser signal
parameter
AXIS_USER_ENABLE
=
1
,
// AXI stream tuser signal width
parameter
AXIS_USER_WIDTH
=
1
,
// Width of length field
parameter
LEN_WIDTH
=
20
,
// Width of tag field
parameter
TAG_WIDTH
=
8
,
// Enable support for scatter/gather DMA
// (multiple descriptors per AXI stream frame)
parameter
ENABLE_SG
=
0
,
// Enable support for unaligned transfers
parameter
ENABLE_UNALIGNED
=
0
)
(
input
wire
clk
,
input
wire
rst
,
/*
* AXI read descriptor input
*/
input
wire
[
AXI_ADDR_WIDTH
-
1
:
0
]
s_axis_read_desc_addr
,
input
wire
[
LEN_WIDTH
-
1
:
0
]
s_axis_read_desc_len
,
input
wire
[
TAG_WIDTH
-
1
:
0
]
s_axis_read_desc_tag
,
input
wire
[
AXIS_ID_WIDTH
-
1
:
0
]
s_axis_read_desc_id
,
input
wire
[
AXIS_DEST_WIDTH
-
1
:
0
]
s_axis_read_desc_dest
,
input
wire
[
AXIS_USER_WIDTH
-
1
:
0
]
s_axis_read_desc_user
,
input
wire
s_axis_read_desc_valid
,
output
wire
s_axis_read_desc_ready
,
/*
* AXI read descriptor status output
*/
output
wire
[
TAG_WIDTH
-
1
:
0
]
m_axis_read_desc_status_tag
,
output
wire
m_axis_read_desc_status_valid
,
/*
* AXI stream read data output
*/
output
wire
[
AXIS_DATA_WIDTH
-
1
:
0
]
m_axis_read_data_tdata
,
output
wire
[
AXIS_KEEP_WIDTH
-
1
:
0
]
m_axis_read_data_tkeep
,
output
wire
m_axis_read_data_tvalid
,
input
wire
m_axis_read_data_tready
,
output
wire
m_axis_read_data_tlast
,
output
wire
[
AXIS_ID_WIDTH
-
1
:
0
]
m_axis_read_data_tid
,
output
wire
[
AXIS_DEST_WIDTH
-
1
:
0
]
m_axis_read_data_tdest
,
output
wire
[
AXIS_USER_WIDTH
-
1
:
0
]
m_axis_read_data_tuser
,
/*
* AXI write descriptor input
*/
input
wire
[
AXI_ADDR_WIDTH
-
1
:
0
]
s_axis_write_desc_addr
,
input
wire
[
LEN_WIDTH
-
1
:
0
]
s_axis_write_desc_len
,
input
wire
[
TAG_WIDTH
-
1
:
0
]
s_axis_write_desc_tag
,
input
wire
s_axis_write_desc_valid
,
output
wire
s_axis_write_desc_ready
,
/*
* AXI write descriptor status output
*/
output
wire
[
LEN_WIDTH
-
1
:
0
]
m_axis_write_desc_status_len
,
output
wire
[
TAG_WIDTH
-
1
:
0
]
m_axis_write_desc_status_tag
,
output
wire
[
AXIS_ID_WIDTH
-
1
:
0
]
m_axis_write_desc_status_id
,
output
wire
[
AXIS_DEST_WIDTH
-
1
:
0
]
m_axis_write_desc_status_dest
,
output
wire
[
AXIS_USER_WIDTH
-
1
:
0
]
m_axis_write_desc_status_user
,
output
wire
m_axis_write_desc_status_valid
,
/*
* AXI stream write data input
*/
input
wire
[
AXIS_DATA_WIDTH
-
1
:
0
]
s_axis_write_data_tdata
,
input
wire
[
AXIS_KEEP_WIDTH
-
1
:
0
]
s_axis_write_data_tkeep
,
input
wire
s_axis_write_data_tvalid
,
output
wire
s_axis_write_data_tready
,
input
wire
s_axis_write_data_tlast
,
input
wire
[
AXIS_ID_WIDTH
-
1
:
0
]
s_axis_write_data_tid
,
input
wire
[
AXIS_DEST_WIDTH
-
1
:
0
]
s_axis_write_data_tdest
,
input
wire
[
AXIS_USER_WIDTH
-
1
:
0
]
s_axis_write_data_tuser
,
/*
* AXI master interface
*/
output
wire
[
AXI_ID_WIDTH
-
1
:
0
]
m_axi_awid
,
output
wire
[
AXI_ADDR_WIDTH
-
1
:
0
]
m_axi_awaddr
,
output
wire
[
7
:
0
]
m_axi_awlen
,
output
wire
[
2
:
0
]
m_axi_awsize
,
output
wire
[
1
:
0
]
m_axi_awburst
,
output
wire
m_axi_awlock
,
output
wire
[
3
:
0
]
m_axi_awcache
,
output
wire
[
2
:
0
]
m_axi_awprot
,
output
wire
m_axi_awvalid
,
input
wire
m_axi_awready
,
output
wire
[
AXI_DATA_WIDTH
-
1
:
0
]
m_axi_wdata
,
output
wire
[
AXI_STRB_WIDTH
-
1
:
0
]
m_axi_wstrb
,
output
wire
m_axi_wlast
,
output
wire
m_axi_wvalid
,
input
wire
m_axi_wready
,
input
wire
[
AXI_ID_WIDTH
-
1
:
0
]
m_axi_bid
,
input
wire
[
1
:
0
]
m_axi_bresp
,
input
wire
m_axi_bvalid
,
output
wire
m_axi_bready
,
output
wire
[
AXI_ID_WIDTH
-
1
:
0
]
m_axi_arid
,
output
wire
[
AXI_ADDR_WIDTH
-
1
:
0
]
m_axi_araddr
,
output
wire
[
7
:
0
]
m_axi_arlen
,
output
wire
[
2
:
0
]
m_axi_arsize
,
output
wire
[
1
:
0
]
m_axi_arburst
,
output
wire
m_axi_arlock
,
output
wire
[
3
:
0
]
m_axi_arcache
,
output
wire
[
2
:
0
]
m_axi_arprot
,
output
wire
m_axi_arvalid
,
input
wire
m_axi_arready
,
input
wire
[
AXI_ID_WIDTH
-
1
:
0
]
m_axi_rid
,
input
wire
[
AXI_DATA_WIDTH
-
1
:
0
]
m_axi_rdata
,
input
wire
[
1
:
0
]
m_axi_rresp
,
input
wire
m_axi_rlast
,
input
wire
m_axi_rvalid
,
output
wire
m_axi_rready
,
/*
* Configuration
*/
input
wire
read_enable
,
input
wire
write_enable
,
input
wire
write_abort
);
axi_dma_rd
#(
.
AXI_DATA_WIDTH
(
AXI_DATA_WIDTH
),
.
AXI_ADDR_WIDTH
(
AXI_ADDR_WIDTH
),
.
AXI_STRB_WIDTH
(
AXI_STRB_WIDTH
),
.
AXI_ID_WIDTH
(
AXI_ID_WIDTH
),
.
AXI_MAX_BURST_LEN
(
AXI_MAX_BURST_LEN
),
.
AXIS_DATA_WIDTH
(
AXIS_DATA_WIDTH
),
.
AXIS_KEEP_ENABLE
(
AXIS_KEEP_ENABLE
),
.
AXIS_KEEP_WIDTH
(
AXIS_KEEP_WIDTH
),
.
AXIS_LAST_ENABLE
(
AXIS_LAST_ENABLE
),
.
AXIS_ID_ENABLE
(
AXIS_ID_ENABLE
),
.
AXIS_ID_WIDTH
(
AXIS_ID_WIDTH
),
.
AXIS_DEST_ENABLE
(
AXIS_DEST_ENABLE
),
.
AXIS_DEST_WIDTH
(
AXIS_DEST_WIDTH
),
.
AXIS_USER_ENABLE
(
AXIS_USER_ENABLE
),
.
AXIS_USER_WIDTH
(
AXIS_USER_WIDTH
),
.
LEN_WIDTH
(
LEN_WIDTH
),
.
TAG_WIDTH
(
TAG_WIDTH
),
.
ENABLE_SG
(
ENABLE_SG
),
.
ENABLE_UNALIGNED
(
ENABLE_UNALIGNED
)
)
axi_dma_rd_inst
(
.
clk
(
clk
),
.
rst
(
rst
),
/*
* AXI read descriptor input
*/
.
s_axis_read_desc_addr
(
s_axis_read_desc_addr
),
.
s_axis_read_desc_len
(
s_axis_read_desc_len
),
.
s_axis_read_desc_tag
(
s_axis_read_desc_tag
),
.
s_axis_read_desc_id
(
s_axis_read_desc_id
),
.
s_axis_read_desc_dest
(
s_axis_read_desc_dest
),
.
s_axis_read_desc_user
(
s_axis_read_desc_user
),
.
s_axis_read_desc_valid
(
s_axis_read_desc_valid
),
.
s_axis_read_desc_ready
(
s_axis_read_desc_ready
),
/*
* AXI read descriptor status output
*/
.
m_axis_read_desc_status_tag
(
m_axis_read_desc_status_tag
),
.
m_axis_read_desc_status_valid
(
m_axis_read_desc_status_valid
),
/*
* AXI stream read data output
*/
.
m_axis_read_data_tdata
(
m_axis_read_data_tdata
),
.
m_axis_read_data_tkeep
(
m_axis_read_data_tkeep
),
.
m_axis_read_data_tvalid
(
m_axis_read_data_tvalid
),
.
m_axis_read_data_tready
(
m_axis_read_data_tready
),
.
m_axis_read_data_tlast
(
m_axis_read_data_tlast
),
.
m_axis_read_data_tid
(
m_axis_read_data_tid
),
.
m_axis_read_data_tdest
(
m_axis_read_data_tdest
),
.
m_axis_read_data_tuser
(
m_axis_read_data_tuser
),
/*
* AXI master interface
*/
.
m_axi_arid
(
m_axi_arid
),
.
m_axi_araddr
(
m_axi_araddr
),
.
m_axi_arlen
(
m_axi_arlen
),
.
m_axi_arsize
(
m_axi_arsize
),
.
m_axi_arburst
(
m_axi_arburst
),
.
m_axi_arlock
(
m_axi_arlock
),
.
m_axi_arcache
(
m_axi_arcache
),
.
m_axi_arprot
(
m_axi_arprot
),
.
m_axi_arvalid
(
m_axi_arvalid
),
.
m_axi_arready
(
m_axi_arready
),
.
m_axi_rid
(
m_axi_rid
),
.
m_axi_rdata
(
m_axi_rdata
),
.
m_axi_rresp
(
m_axi_rresp
),
.
m_axi_rlast
(
m_axi_rlast
),
.
m_axi_rvalid
(
m_axi_rvalid
),
.
m_axi_rready
(
m_axi_rready
),
/*
* Configuration
*/
.
enable
(
read_enable
)
);
axi_dma_wr
#(
.
AXI_DATA_WIDTH
(
AXI_DATA_WIDTH
),
.
AXI_ADDR_WIDTH
(
AXI_ADDR_WIDTH
),
.
AXI_STRB_WIDTH
(
AXI_STRB_WIDTH
),
.
AXI_ID_WIDTH
(
AXI_ID_WIDTH
),
.
AXI_MAX_BURST_LEN
(
AXI_MAX_BURST_LEN
),
.
AXIS_DATA_WIDTH
(
AXIS_DATA_WIDTH
),
.
AXIS_KEEP_ENABLE
(
AXIS_KEEP_ENABLE
),
.
AXIS_KEEP_WIDTH
(
AXIS_KEEP_WIDTH
),
.
AXIS_LAST_ENABLE
(
AXIS_LAST_ENABLE
),
.
AXIS_ID_ENABLE
(
AXIS_ID_ENABLE
),
.
AXIS_ID_WIDTH
(
AXIS_ID_WIDTH
),
.
AXIS_DEST_ENABLE
(
AXIS_DEST_ENABLE
),
.
AXIS_DEST_WIDTH
(
AXIS_DEST_WIDTH
),
.
AXIS_USER_ENABLE
(
AXIS_USER_ENABLE
),
.
AXIS_USER_WIDTH
(
AXIS_USER_WIDTH
),
.
LEN_WIDTH
(
LEN_WIDTH
),
.
TAG_WIDTH
(
TAG_WIDTH
),
.
ENABLE_SG
(
ENABLE_SG
),
.
ENABLE_UNALIGNED
(
ENABLE_UNALIGNED
)
)
axi_dma_wr_inst
(
.
clk
(
clk
),
.
rst
(
rst
),
/*
* AXI write descriptor input
*/
.
s_axis_write_desc_addr
(
s_axis_write_desc_addr
),
.
s_axis_write_desc_len
(
s_axis_write_desc_len
),
.
s_axis_write_desc_tag
(
s_axis_write_desc_tag
),
.
s_axis_write_desc_valid
(
s_axis_write_desc_valid
),
.
s_axis_write_desc_ready
(
s_axis_write_desc_ready
),
/*
* AXI write descriptor status output
*/
.
m_axis_write_desc_status_len
(
m_axis_write_desc_status_len
),
.
m_axis_write_desc_status_tag
(
m_axis_write_desc_status_tag
),
.
m_axis_write_desc_status_id
(
m_axis_write_desc_status_id
),
.
m_axis_write_desc_status_dest
(
m_axis_write_desc_status_dest
),
.
m_axis_write_desc_status_user
(
m_axis_write_desc_status_user
),
.
m_axis_write_desc_status_valid
(
m_axis_write_desc_status_valid
),
/*
* AXI stream write data input
*/
.
s_axis_write_data_tdata
(
s_axis_write_data_tdata
),
.
s_axis_write_data_tkeep
(
s_axis_write_data_tkeep
),
.
s_axis_write_data_tvalid
(
s_axis_write_data_tvalid
),
.
s_axis_write_data_tready
(
s_axis_write_data_tready
),
.
s_axis_write_data_tlast
(
s_axis_write_data_tlast
),
.
s_axis_write_data_tid
(
s_axis_write_data_tid
),
.
s_axis_write_data_tdest
(
s_axis_write_data_tdest
),
.
s_axis_write_data_tuser
(
s_axis_write_data_tuser
),
/*
* AXI master interface
*/
.
m_axi_awid
(
m_axi_awid
),
.
m_axi_awaddr
(
m_axi_awaddr
),
.
m_axi_awlen
(
m_axi_awlen
),
.
m_axi_awsize
(
m_axi_awsize
),
.
m_axi_awburst
(
m_axi_awburst
),
.
m_axi_awlock
(
m_axi_awlock
),
.
m_axi_awcache
(
m_axi_awcache
),
.
m_axi_awprot
(
m_axi_awprot
),
.
m_axi_awvalid
(
m_axi_awvalid
),
.
m_axi_awready
(
m_axi_awready
),
.
m_axi_wdata
(
m_axi_wdata
),
.
m_axi_wstrb
(
m_axi_wstrb
),
.
m_axi_wlast
(
m_axi_wlast
),
.
m_axi_wvalid
(
m_axi_wvalid
),
.
m_axi_wready
(
m_axi_wready
),
.
m_axi_bid
(
m_axi_bid
),
.
m_axi_bresp
(
m_axi_bresp
),
.
m_axi_bvalid
(
m_axi_bvalid
),
.
m_axi_bready
(
m_axi_bready
),
/*
* Configuration
*/
.
enable
(
write_enable
),
.
abort
(
write_abort
)
);
endmodule
corundum/lib/axi/rtl/axi_dma_desc_mux.v
0 → 100644
View file @
738c1fef
/*
Copyright (c) 2019 Alex Forencich
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.
*/
// Language: Verilog 2001
`timescale
1
ns
/
1
ps
/*
* AXI DMA descriptor mux
*/
module
axi_dma_desc_mux
#
(
// Number of ports
parameter
PORTS
=
2
,
// AXI address width
parameter
AXI_ADDR_WIDTH
=
16
,
// Propagate AXI stream tid signal
parameter
AXIS_ID_ENABLE
=
0
,
// AXI stream tid signal width
parameter
AXIS_ID_WIDTH
=
8
,
// Propagate AXI stream tdest signal
parameter
AXIS_DEST_ENABLE
=
0
,
// AXI stream tdest signal width
parameter
AXIS_DEST_WIDTH
=
8
,
// Propagate AXI stream tuser signal
parameter
AXIS_USER_ENABLE
=
1
,
// AXI stream tuser signal width
parameter
AXIS_USER_WIDTH
=
1
,
// Length field width
parameter
LEN_WIDTH
=
20
,
// Input tag field width
parameter
S_TAG_WIDTH
=
8
,
// Output tag field width (towards CDMA module)
// Additional bits required for response routing
parameter
M_TAG_WIDTH
=
S_TAG_WIDTH
+
$
clog2
(
PORTS
),
// arbitration type: "PRIORITY" or "ROUND_ROBIN"
parameter
ARB_TYPE
=
"PRIORITY"
,
// LSB priority: "LOW", "HIGH"
parameter
LSB_PRIORITY
=
"HIGH"
)
(
input
wire
clk
,
input
wire
rst
,
/*
* Descriptor output (to AXI DMA core)
*/
output
wire
[
AXI_ADDR_WIDTH
-
1
:
0
]
m_axis_desc_addr
,
output
wire
[
LEN_WIDTH
-
1
:
0
]
m_axis_desc_len
,
output
wire
[
M_TAG_WIDTH
-
1
:
0
]
m_axis_desc_tag
,
output
wire
[
AXIS_ID_WIDTH
-
1
:
0
]
m_axis_desc_id
,
output
wire
[
AXIS_DEST_WIDTH
-
1
:
0
]
m_axis_desc_dest
,
output
wire
[
AXIS_USER_WIDTH
-
1
:
0
]
m_axis_desc_user
,
output
wire
m_axis_desc_valid
,
input
wire
m_axis_desc_ready
,
/*
* Descriptor status input (from AXI DMA core)
*/
input
wire
[
LEN_WIDTH
-
1
:
0
]
s_axis_desc_status_len
,
input
wire
[
M_TAG_WIDTH
-
1
:
0
]
s_axis_desc_status_tag
,
input
wire
[
AXIS_ID_WIDTH
-
1
:
0
]
s_axis_desc_status_id
,
input
wire
[
AXIS_DEST_WIDTH
-
1
:
0
]
s_axis_desc_status_dest
,
input
wire
[
AXIS_USER_WIDTH
-
1
:
0
]
s_axis_desc_status_user
,
input
wire
s_axis_desc_status_valid
,
/*
* Descriptor input
*/
input
wire
[
PORTS
*
AXI_ADDR_WIDTH
-
1
:
0
]
s_axis_desc_addr
,
input
wire
[
PORTS
*
LEN_WIDTH
-
1
:
0
]
s_axis_desc_len
,
input
wire
[
PORTS
*
S_TAG_WIDTH
-
1
:
0
]
s_axis_desc_tag
,
input
wire
[
PORTS
*
AXIS_ID_WIDTH
-
1
:
0
]
s_axis_desc_id
,
input
wire
[
PORTS
*
AXIS_DEST_WIDTH
-
1
:
0
]
s_axis_desc_dest
,
input
wire
[
PORTS
*
AXIS_USER_WIDTH
-
1
:
0
]
s_axis_desc_user
,
input
wire
[
PORTS
-
1
:
0
]
s_axis_desc_valid
,
output
wire
[
PORTS
-
1
:
0
]
s_axis_desc_ready
,
/*
* Descriptor status output
*/
output
wire
[
PORTS
*
LEN_WIDTH
-
1
:
0
]
m_axis_desc_status_len
,
output
wire
[
PORTS
*
S_TAG_WIDTH
-
1
:
0
]
m_axis_desc_status_tag
,
output
wire
[
PORTS
*
AXIS_ID_WIDTH
-
1
:
0
]
m_axis_desc_status_id
,
output
wire
[
PORTS
*
AXIS_DEST_WIDTH
-
1
:
0
]
m_axis_desc_status_dest
,
output
wire
[
PORTS
*
AXIS_USER_WIDTH
-
1
:
0
]
m_axis_desc_status_user
,
output
wire
[
PORTS
-
1
:
0
]
m_axis_desc_status_valid
);
parameter
CL_PORTS
=
$
clog2
(
PORTS
);
// check configuration
initial
begin
if
(
M_TAG_WIDTH
<
S_TAG_WIDTH
+
$
clog2
(
PORTS
))
begin
$
error
(
"Error: M_TAG_WIDTH must be at least $clog2(PORTS) larger than S_TAG_WIDTH (instance %m)"
);
$
finish
;
end
end
// descriptor mux
wire
[
PORTS
-
1
:
0
]
request
;
wire
[
PORTS
-
1
:
0
]
acknowledge
;
wire
[
PORTS
-
1
:
0
]
grant
;
wire
grant_valid
;
wire
[
CL_PORTS
-
1
:
0
]
grant_encoded
;
// internal datapath
reg
[
AXI_ADDR_WIDTH
-
1
:
0
]
m_axis_desc_addr_int
;
reg
[
LEN_WIDTH
-
1
:
0
]
m_axis_desc_len_int
;
reg
[
M_TAG_WIDTH
-
1
:
0
]
m_axis_desc_tag_int
;
reg
[
AXIS_ID_WIDTH
-
1
:
0
]
m_axis_desc_id_int
;
reg
[
AXIS_DEST_WIDTH
-
1
:
0
]
m_axis_desc_dest_int
;
reg
[
AXIS_USER_WIDTH
-
1
:
0
]
m_axis_desc_user_int
;
reg
m_axis_desc_valid_int
;
reg
m_axis_desc_ready_int_reg
=
1'b0
;
wire
m_axis_desc_ready_int_early
;
assign
s_axis_desc_ready
=
(
m_axis_desc_ready_int_reg
&&
grant_valid
)
<<
grant_encoded
;
// mux for incoming packet
wire
[
AXI_ADDR_WIDTH
-
1
:
0
]
current_s_desc_addr
=
s_axis_desc_addr
[
grant_encoded
*
AXI_ADDR_WIDTH
+:
AXI_ADDR_WIDTH
];
wire
[
LEN_WIDTH
-
1
:
0
]
current_s_desc_len
=
s_axis_desc_len
[
grant_encoded
*
LEN_WIDTH
+:
LEN_WIDTH
];
wire
[
S_TAG_WIDTH
-
1
:
0
]
current_s_desc_tag
=
s_axis_desc_tag
[
grant_encoded
*
S_TAG_WIDTH
+:
S_TAG_WIDTH
];
wire
[
AXIS_ID_WIDTH
-
1
:
0
]
current_s_desc_id
=
s_axis_desc_id
[
grant_encoded
*
AXIS_ID_WIDTH
+:
AXIS_ID_WIDTH
];
wire
[
AXIS_DEST_WIDTH
-
1
:
0
]
current_s_desc_dest
=
s_axis_desc_dest
[
grant_encoded
*
AXIS_DEST_WIDTH
+:
AXIS_DEST_WIDTH
];
wire
[
AXIS_USER_WIDTH
-
1
:
0
]
current_s_desc_user
=
s_axis_desc_user
[
grant_encoded
*
AXIS_USER_WIDTH
+:
AXIS_USER_WIDTH
];
wire
current_s_desc_valid
=
s_axis_desc_valid
[
grant_encoded
];
wire
current_s_desc_ready
=
s_axis_desc_ready
[
grant_encoded
];
// arbiter instance
arbiter
#(
.
PORTS
(
PORTS
),
.
TYPE
(
ARB_TYPE
),
.
BLOCK
(
"ACKNOWLEDGE"
),
.
LSB_PRIORITY
(
LSB_PRIORITY
)
)
arb_inst
(
.
clk
(
clk
),
.
rst
(
rst
),
.
request
(
request
),
.
acknowledge
(
acknowledge
),
.
grant
(
grant
),
.
grant_valid
(
grant_valid
),
.
grant_encoded
(
grant_encoded
)
);
assign
request
=
s_axis_desc_valid
&
~
grant
;
assign
acknowledge
=
grant
&
s_axis_desc_valid
&
s_axis_desc_ready
;
always
@*
begin
m_axis_desc_addr_int
=
current_s_desc_addr
;
m_axis_desc_len_int
=
current_s_desc_len
;
m_axis_desc_tag_int
=
{
grant_encoded
,
current_s_desc_tag
}
;
m_axis_desc_id_int
=
current_s_desc_id
;
m_axis_desc_dest_int
=
current_s_desc_dest
;
m_axis_desc_user_int
=
current_s_desc_user
;
m_axis_desc_valid_int
=
current_s_desc_valid
&&
m_axis_desc_ready_int_reg
&&
grant_valid
;
end
// output datapath logic
reg
[
AXI_ADDR_WIDTH
-
1
:
0
]
m_axis_desc_addr_reg
=
{
AXI_ADDR_WIDTH
{
1'b0
}}
;
reg
[
LEN_WIDTH
-
1
:
0
]
m_axis_desc_len_reg
=
{
LEN_WIDTH
{
1'b0
}}
;
reg
[
M_TAG_WIDTH
-
1
:
0
]
m_axis_desc_tag_reg
=
{
M_TAG_WIDTH
{
1'b0
}}
;
reg
[
AXIS_ID_WIDTH
-
1
:
0
]
m_axis_desc_id_reg
=
{
AXIS_ID_WIDTH
{
1'b0
}}
;
reg
[
AXIS_DEST_WIDTH
-
1
:
0
]
m_axis_desc_dest_reg
=
{
AXIS_DEST_WIDTH
{
1'b0
}}
;
reg
[
AXIS_USER_WIDTH
-
1
:
0
]
m_axis_desc_user_reg
=
{
AXIS_USER_WIDTH
{
1'b0
}}
;
reg
m_axis_desc_valid_reg
=
1'b0
,
m_axis_desc_valid_next
;
reg
[
AXI_ADDR_WIDTH
-
1
:
0
]
temp_m_axis_desc_addr_reg
=
{
AXI_ADDR_WIDTH
{
1'b0
}}
;
reg
[
LEN_WIDTH
-
1
:
0
]
temp_m_axis_desc_len_reg
=
{
LEN_WIDTH
{
1'b0
}}
;
reg
[
M_TAG_WIDTH
-
1
:
0
]
temp_m_axis_desc_tag_reg
=
{
M_TAG_WIDTH
{
1'b0
}}
;
reg
[
AXIS_ID_WIDTH
-
1
:
0
]
temp_m_axis_desc_id_reg
=
{
AXIS_ID_WIDTH
{
1'b0
}}
;
reg
[
AXIS_DEST_WIDTH
-
1
:
0
]
temp_m_axis_desc_dest_reg
=
{
AXIS_DEST_WIDTH
{
1'b0
}}
;
reg
[
AXIS_USER_WIDTH
-
1
:
0
]
temp_m_axis_desc_user_reg
=
{
AXIS_USER_WIDTH
{
1'b0
}}
;
reg
temp_m_axis_desc_valid_reg
=
1'b0
,
temp_m_axis_desc_valid_next
;
// datapath control
reg
store_axis_int_to_output
;
reg
store_axis_int_to_temp
;
reg
store_axis_temp_to_output
;
assign
m_axis_desc_addr
=
m_axis_desc_addr_reg
;
assign
m_axis_desc_len
=
m_axis_desc_len_reg
;
assign
m_axis_desc_tag
=
m_axis_desc_tag_reg
;
assign
m_axis_desc_id
=
AXIS_ID_ENABLE
?
m_axis_desc_id_reg
:
{
AXIS_ID_WIDTH
{
1'b0
}}
;
assign
m_axis_desc_dest
=
AXIS_DEST_ENABLE
?
m_axis_desc_dest_reg
:
{
AXIS_DEST_WIDTH
{
1'b0
}}
;
assign
m_axis_desc_user
=
AXIS_USER_ENABLE
?
m_axis_desc_user_reg
:
{
AXIS_USER_WIDTH
{
1'b0
}}
;
assign
m_axis_desc_valid
=
m_axis_desc_valid_reg
;
// enable ready input next cycle if output is ready or the temp reg will not be filled on the next cycle (output reg empty or no input)
assign
m_axis_desc_ready_int_early
=
m_axis_desc_ready
||
(
!
temp_m_axis_desc_valid_reg
&&
(
!
m_axis_desc_valid_reg
||
!
m_axis_desc_valid_int
));
always
@*
begin
// transfer sink ready state to source
m_axis_desc_valid_next
=
m_axis_desc_valid_reg
;
temp_m_axis_desc_valid_next
=
temp_m_axis_desc_valid_reg
;
store_axis_int_to_output
=
1'b0
;
store_axis_int_to_temp
=
1'b0
;
store_axis_temp_to_output
=
1'b0
;
if
(
m_axis_desc_ready_int_reg
)
begin
// input is ready
if
(
m_axis_desc_ready
||
!
m_axis_desc_valid_reg
)
begin
// output is ready or currently not valid, transfer data to output
m_axis_desc_valid_next
=
m_axis_desc_valid_int
;
store_axis_int_to_output
=
1'b1
;
end
else
begin
// output is not ready, store input in temp
temp_m_axis_desc_valid_next
=
m_axis_desc_valid_int
;
store_axis_int_to_temp
=
1'b1
;
end
end
else
if
(
m_axis_desc_ready
)
begin
// input is not ready, but output is ready
m_axis_desc_valid_next
=
temp_m_axis_desc_valid_reg
;
temp_m_axis_desc_valid_next
=
1'b0
;
store_axis_temp_to_output
=
1'b1
;
end
end
always
@
(
posedge
clk
)
begin
if
(
rst
)
begin
m_axis_desc_valid_reg
<=
1'b0
;
m_axis_desc_ready_int_reg
<=
1'b0
;
temp_m_axis_desc_valid_reg
<=
1'b0
;
end
else
begin
m_axis_desc_valid_reg
<=
m_axis_desc_valid_next
;
m_axis_desc_ready_int_reg
<=
m_axis_desc_ready_int_early
;
temp_m_axis_desc_valid_reg
<=
temp_m_axis_desc_valid_next
;
end
// datapath
if
(
store_axis_int_to_output
)
begin
m_axis_desc_addr_reg
<=
m_axis_desc_addr_int
;
m_axis_desc_len_reg
<=
m_axis_desc_len_int
;
m_axis_desc_tag_reg
<=
m_axis_desc_tag_int
;
m_axis_desc_id_reg
<=
m_axis_desc_id_int
;
m_axis_desc_dest_reg
<=
m_axis_desc_dest_int
;
m_axis_desc_user_reg
<=
m_axis_desc_user_int
;
end
else
if
(
store_axis_temp_to_output
)
begin
m_axis_desc_addr_reg
<=
temp_m_axis_desc_addr_reg
;
m_axis_desc_len_reg
<=
temp_m_axis_desc_len_reg
;
m_axis_desc_tag_reg
<=
temp_m_axis_desc_tag_reg
;
m_axis_desc_id_reg
<=
temp_m_axis_desc_id_reg
;
m_axis_desc_dest_reg
<=
temp_m_axis_desc_dest_reg
;
m_axis_desc_user_reg
<=
temp_m_axis_desc_user_reg
;
end
if
(
store_axis_int_to_temp
)
begin
temp_m_axis_desc_addr_reg
<=
m_axis_desc_addr_int
;
temp_m_axis_desc_len_reg
<=
m_axis_desc_len_int
;
temp_m_axis_desc_tag_reg
<=
m_axis_desc_tag_int
;
temp_m_axis_desc_id_reg
<=
m_axis_desc_id_int
;
temp_m_axis_desc_dest_reg
<=
m_axis_desc_dest_int
;
temp_m_axis_desc_user_reg
<=
m_axis_desc_user_int
;
end
end
// descriptor status demux
reg
[
LEN_WIDTH
-
1
:
0
]
m_axis_desc_status_len_reg
=
{
LEN_WIDTH
{
1'b0
}}
;
reg
[
S_TAG_WIDTH
-
1
:
0
]
m_axis_desc_status_tag_reg
=
{
S_TAG_WIDTH
{
1'b0
}}
;
reg
[
AXIS_ID_WIDTH
-
1
:
0
]
m_axis_desc_status_id_reg
=
{
AXIS_ID_WIDTH
{
1'b0
}}
;
reg
[
AXIS_DEST_WIDTH
-
1
:
0
]
m_axis_desc_status_dest_reg
=
{
AXIS_DEST_WIDTH
{
1'b0
}}
;
reg
[
AXIS_USER_WIDTH
-
1
:
0
]
m_axis_desc_status_user_reg
=
{
AXIS_USER_WIDTH
{
1'b0
}}
;
reg
[
PORTS
-
1
:
0
]
m_axis_desc_status_valid_reg
=
{
PORTS
{
1'b0
}}
;
assign
m_axis_desc_status_len
=
{
PORTS
{
m_axis_desc_status_len_reg
}}
;
assign
m_axis_desc_status_tag
=
{
PORTS
{
m_axis_desc_status_tag_reg
}}
;
assign
m_axis_desc_status_id
=
AXIS_ID_ENABLE
?
{
PORTS
{
m_axis_desc_status_id_reg
}}
:
{
AXIS_ID_WIDTH
*
PORTS
{
1'b0
}}
;
assign
m_axis_desc_status_dest
=
AXIS_DEST_ENABLE
?
{
PORTS
{
m_axis_desc_status_dest_reg
}}
:
{
AXIS_DEST_WIDTH
*
PORTS
{
1'b0
}}
;
assign
m_axis_desc_status_user
=
AXIS_USER_ENABLE
?
{
PORTS
{
m_axis_desc_status_user_reg
}}
:
{
AXIS_USER_WIDTH
*
PORTS
{
1'b0
}}
;
assign
m_axis_desc_status_valid
=
m_axis_desc_status_valid_reg
;
always
@
(
posedge
clk
)
begin
if
(
rst
)
begin
m_axis_desc_status_valid_reg
<=
{
PORTS
{
1'b0
}}
;
end
else
begin
m_axis_desc_status_valid_reg
<=
s_axis_desc_status_valid
<<
(
PORTS
>
1
?
s_axis_desc_status_tag
[
S_TAG_WIDTH
+
CL_PORTS
-
1
:
S_TAG_WIDTH
]
:
0
);
end
m_axis_desc_status_len_reg
<=
s_axis_desc_status_len
;
m_axis_desc_status_tag_reg
<=
s_axis_desc_status_tag
;
m_axis_desc_status_id_reg
<=
s_axis_desc_status_id
;
m_axis_desc_status_dest_reg
<=
s_axis_desc_status_dest
;
m_axis_desc_status_user_reg
<=
s_axis_desc_status_user
;
end
endmodule
corundum/lib/axi/rtl/axi_dma_rd.v
0 → 100644
View file @
738c1fef
/*
Copyright (c) 2018 Alex Forencich
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.
*/
// Language: Verilog 2001
`timescale
1
ns
/
1
ps
/*
* AXI4 DMA
*/
module
axi_dma_rd
#
(
// Width of AXI data bus in bits
parameter
AXI_DATA_WIDTH
=
32
,
// Width of AXI address bus in bits
parameter
AXI_ADDR_WIDTH
=
16
,
// Width of AXI wstrb (width of data bus in words)
parameter
AXI_STRB_WIDTH
=
(
AXI_DATA_WIDTH
/
8
),
// Width of AXI ID signal
parameter
AXI_ID_WIDTH
=
8
,
// Maximum AXI burst length to generate
parameter
AXI_MAX_BURST_LEN
=
16
,
// Width of AXI stream interfaces in bits
parameter
AXIS_DATA_WIDTH
=
AXI_DATA_WIDTH
,
// Use AXI stream tkeep signal
parameter
AXIS_KEEP_ENABLE
=
(
AXIS_DATA_WIDTH
>
8
),
// AXI stream tkeep signal width (words per cycle)
parameter
AXIS_KEEP_WIDTH
=
(
AXIS_DATA_WIDTH
/
8
),
// Use AXI stream tlast signal
parameter
AXIS_LAST_ENABLE
=
1
,
// Propagate AXI stream tid signal
parameter
AXIS_ID_ENABLE
=
0
,
// AXI stream tid signal width
parameter
AXIS_ID_WIDTH
=
8
,
// Propagate AXI stream tdest signal
parameter
AXIS_DEST_ENABLE
=
0
,
// AXI stream tdest signal width
parameter
AXIS_DEST_WIDTH
=
8
,
// Propagate AXI stream tuser signal
parameter
AXIS_USER_ENABLE
=
1
,
// AXI stream tuser signal width
parameter
AXIS_USER_WIDTH
=
1
,
// Width of length field
parameter
LEN_WIDTH
=
20
,
// Width of tag field
parameter
TAG_WIDTH
=
8
,
// Enable support for scatter/gather DMA
// (multiple descriptors per AXI stream frame)
parameter
ENABLE_SG
=
0
,
// Enable support for unaligned transfers
parameter
ENABLE_UNALIGNED
=
0
)
(
input
wire
clk
,
input
wire
rst
,
/*
* AXI read descriptor input
*/
input
wire
[
AXI_ADDR_WIDTH
-
1
:
0
]
s_axis_read_desc_addr
,
input
wire
[
LEN_WIDTH
-
1
:
0
]
s_axis_read_desc_len
,
input
wire
[
TAG_WIDTH
-
1
:
0
]
s_axis_read_desc_tag
,
input
wire
[
AXIS_ID_WIDTH
-
1
:
0
]
s_axis_read_desc_id
,
input
wire
[
AXIS_DEST_WIDTH
-
1
:
0
]
s_axis_read_desc_dest
,
input
wire
[
AXIS_USER_WIDTH
-
1
:
0
]
s_axis_read_desc_user
,
input
wire
s_axis_read_desc_valid
,
output
wire
s_axis_read_desc_ready
,
/*
* AXI read descriptor status output
*/
output
wire
[
TAG_WIDTH
-
1
:
0
]
m_axis_read_desc_status_tag
,
output
wire
m_axis_read_desc_status_valid
,
/*
* AXI stream read data output
*/
output
wire
[
AXIS_DATA_WIDTH
-
1
:
0
]
m_axis_read_data_tdata
,
output
wire
[
AXIS_KEEP_WIDTH
-
1
:
0
]
m_axis_read_data_tkeep
,
output
wire
m_axis_read_data_tvalid
,
input
wire
m_axis_read_data_tready
,
output
wire
m_axis_read_data_tlast
,
output
wire
[
AXIS_ID_WIDTH
-
1
:
0
]
m_axis_read_data_tid
,
output
wire
[
AXIS_DEST_WIDTH
-
1
:
0
]
m_axis_read_data_tdest
,
output
wire
[
AXIS_USER_WIDTH
-
1
:
0
]
m_axis_read_data_tuser
,
/*
* AXI master interface
*/
output
wire
[
AXI_ID_WIDTH
-
1
:
0
]
m_axi_arid
,
output
wire
[
AXI_ADDR_WIDTH
-
1
:
0
]
m_axi_araddr
,
output
wire
[
7
:
0
]
m_axi_arlen
,
output
wire
[
2
:
0
]
m_axi_arsize
,
output
wire
[
1
:
0
]
m_axi_arburst
,
output
wire
m_axi_arlock
,
output
wire
[
3
:
0
]
m_axi_arcache
,
output
wire
[
2
:
0
]
m_axi_arprot
,
output
wire
m_axi_arvalid
,
input
wire
m_axi_arready
,
input
wire
[
AXI_ID_WIDTH
-
1
:
0
]
m_axi_rid
,
input
wire
[
AXI_DATA_WIDTH
-
1
:
0
]
m_axi_rdata
,
input
wire
[
1
:
0
]
m_axi_rresp
,
input
wire
m_axi_rlast
,
input
wire
m_axi_rvalid
,
output
wire
m_axi_rready
,
/*
* Configuration
*/
input
wire
enable
);
parameter
AXI_WORD_WIDTH
=
AXI_STRB_WIDTH
;
parameter
AXI_WORD_SIZE
=
AXI_DATA_WIDTH
/
AXI_WORD_WIDTH
;
parameter
AXI_BURST_SIZE
=
$
clog2
(
AXI_STRB_WIDTH
);
parameter
AXI_MAX_BURST_SIZE
=
AXI_MAX_BURST_LEN
<<
AXI_BURST_SIZE
;
parameter
AXIS_KEEP_WIDTH_INT
=
AXIS_KEEP_ENABLE
?
AXIS_KEEP_WIDTH
:
1
;
parameter
AXIS_WORD_WIDTH
=
AXIS_KEEP_WIDTH_INT
;
parameter
AXIS_WORD_SIZE
=
AXIS_DATA_WIDTH
/
AXIS_WORD_WIDTH
;
parameter
OFFSET_WIDTH
=
AXI_STRB_WIDTH
>
1
?
$
clog2
(
AXI_STRB_WIDTH
)
:
1
;
parameter
OFFSET_MASK
=
AXI_STRB_WIDTH
>
1
?
{
OFFSET_WIDTH
{
1'b1
}}
:
0
;
parameter
ADDR_MASK
=
{
AXI_ADDR_WIDTH
{
1'b1
}}
<<
$
clog2
(
AXI_STRB_WIDTH
);
parameter
CYCLE_COUNT_WIDTH
=
LEN_WIDTH
-
AXI_BURST_SIZE
+
1
;
// bus width assertions
initial
begin
if
(
AXI_WORD_SIZE
*
AXI_STRB_WIDTH
!=
AXI_DATA_WIDTH
)
begin
$
error
(
"Error: AXI data width not evenly divisble (instance %m)"
);
$
finish
;
end
if
(
AXIS_WORD_SIZE
*
AXIS_KEEP_WIDTH_INT
!=
AXIS_DATA_WIDTH
)
begin
$
error
(
"Error: AXI stream data width not evenly divisble (instance %m)"
);
$
finish
;
end
if
(
AXI_WORD_SIZE
!=
AXIS_WORD_SIZE
)
begin
$
error
(
"Error: word size mismatch (instance %m)"
);
$
finish
;
end
if
(
2
**
$
clog2
(
AXI_WORD_WIDTH
)
!=
AXI_WORD_WIDTH
)
begin
$
error
(
"Error: AXI word width must be even power of two (instance %m)"
);
$
finish
;
end
if
(
AXI_DATA_WIDTH
!=
AXIS_DATA_WIDTH
)
begin
$
error
(
"Error: AXI interface width must match AXI stream interface width (instance %m)"
);
$
finish
;
end
if
(
AXI_MAX_BURST_LEN
<
1
||
AXI_MAX_BURST_LEN
>
256
)
begin
$
error
(
"Error: AXI_MAX_BURST_LEN must be between 1 and 256 (instance %m)"
);
$
finish
;
end
if
(
ENABLE_SG
)
begin
$
error
(
"Error: scatter/gather is not yet implemented (instance %m)"
);
$
finish
;
end
end
localparam
[
0
:
0
]
AXI_STATE_IDLE
=
1'd0
,
AXI_STATE_START
=
1'd1
;
reg
[
0
:
0
]
axi_state_reg
=
AXI_STATE_IDLE
,
axi_state_next
;
localparam
[
0
:
0
]
AXIS_STATE_IDLE
=
1'd0
,
AXIS_STATE_READ
=
1'd1
;
reg
[
0
:
0
]
axis_state_reg
=
AXIS_STATE_IDLE
,
axis_state_next
;
// datapath control signals
reg
transfer_in_save
;
reg
axis_cmd_ready
;
reg
[
AXI_ADDR_WIDTH
-
1
:
0
]
addr_reg
=
{
AXI_ADDR_WIDTH
{
1'b0
}}
,
addr_next
;
reg
[
LEN_WIDTH
-
1
:
0
]
op_word_count_reg
=
{
LEN_WIDTH
{
1'b0
}}
,
op_word_count_next
;
reg
[
LEN_WIDTH
-
1
:
0
]
tr_word_count_reg
=
{
LEN_WIDTH
{
1'b0
}}
,
tr_word_count_next
;
reg
[
OFFSET_WIDTH
-
1
:
0
]
axis_cmd_offset_reg
=
{
OFFSET_WIDTH
{
1'b0
}}
,
axis_cmd_offset_next
;
reg
[
OFFSET_WIDTH
-
1
:
0
]
axis_cmd_last_cycle_offset_reg
=
{
OFFSET_WIDTH
{
1'b0
}}
,
axis_cmd_last_cycle_offset_next
;
reg
[
CYCLE_COUNT_WIDTH
-
1
:
0
]
axis_cmd_input_cycle_count_reg
=
{
CYCLE_COUNT_WIDTH
{
1'b0
}}
,
axis_cmd_input_cycle_count_next
;
reg
[
CYCLE_COUNT_WIDTH
-
1
:
0
]
axis_cmd_output_cycle_count_reg
=
{
CYCLE_COUNT_WIDTH
{
1'b0
}}
,
axis_cmd_output_cycle_count_next
;
reg
axis_cmd_bubble_cycle_reg
=
1'b0
,
axis_cmd_bubble_cycle_next
;
reg
[
TAG_WIDTH
-
1
:
0
]
axis_cmd_tag_reg
=
{
TAG_WIDTH
{
1'b0
}}
,
axis_cmd_tag_next
;
reg
[
AXIS_ID_WIDTH
-
1
:
0
]
axis_cmd_axis_id_reg
=
{
AXIS_ID_WIDTH
{
1'b0
}}
,
axis_cmd_axis_id_next
;
reg
[
AXIS_DEST_WIDTH
-
1
:
0
]
axis_cmd_axis_dest_reg
=
{
AXIS_DEST_WIDTH
{
1'b0
}}
,
axis_cmd_axis_dest_next
;
reg
[
AXIS_USER_WIDTH
-
1
:
0
]
axis_cmd_axis_user_reg
=
{
AXIS_USER_WIDTH
{
1'b0
}}
,
axis_cmd_axis_user_next
;
reg
axis_cmd_valid_reg
=
1'b0
,
axis_cmd_valid_next
;
reg
[
OFFSET_WIDTH
-
1
:
0
]
offset_reg
=
{
OFFSET_WIDTH
{
1'b0
}}
,
offset_next
;
reg
[
OFFSET_WIDTH
-
1
:
0
]
last_cycle_offset_reg
=
{
OFFSET_WIDTH
{
1'b0
}}
,
last_cycle_offset_next
;
reg
[
CYCLE_COUNT_WIDTH
-
1
:
0
]
input_cycle_count_reg
=
{
CYCLE_COUNT_WIDTH
{
1'b0
}}
,
input_cycle_count_next
;
reg
[
CYCLE_COUNT_WIDTH
-
1
:
0
]
output_cycle_count_reg
=
{
CYCLE_COUNT_WIDTH
{
1'b0
}}
,
output_cycle_count_next
;
reg
input_active_reg
=
1'b0
,
input_active_next
;
reg
output_active_reg
=
1'b0
,
output_active_next
;
reg
bubble_cycle_reg
=
1'b0
,
bubble_cycle_next
;
reg
first_cycle_reg
=
1'b0
,
first_cycle_next
;
reg
output_last_cycle_reg
=
1'b0
,
output_last_cycle_next
;
reg
[
TAG_WIDTH
-
1
:
0
]
tag_reg
=
{
TAG_WIDTH
{
1'b0
}}
,
tag_next
;
reg
[
AXIS_ID_WIDTH
-
1
:
0
]
axis_id_reg
=
{
AXIS_ID_WIDTH
{
1'b0
}}
,
axis_id_next
;
reg
[
AXIS_DEST_WIDTH
-
1
:
0
]
axis_dest_reg
=
{
AXIS_DEST_WIDTH
{
1'b0
}}
,
axis_dest_next
;
reg
[
AXIS_USER_WIDTH
-
1
:
0
]
axis_user_reg
=
{
AXIS_USER_WIDTH
{
1'b0
}}
,
axis_user_next
;
reg
s_axis_read_desc_ready_reg
=
1'b0
,
s_axis_read_desc_ready_next
;
reg
[
TAG_WIDTH
-
1
:
0
]
m_axis_read_desc_status_tag_reg
=
{
TAG_WIDTH
{
1'b0
}}
,
m_axis_read_desc_status_tag_next
;
reg
m_axis_read_desc_status_valid_reg
=
1'b0
,
m_axis_read_desc_status_valid_next
;
reg
[
AXI_ADDR_WIDTH
-
1
:
0
]
m_axi_araddr_reg
=
{
AXI_ADDR_WIDTH
{
1'b0
}}
,
m_axi_araddr_next
;
reg
[
7
:
0
]
m_axi_arlen_reg
=
8'd0
,
m_axi_arlen_next
;
reg
m_axi_arvalid_reg
=
1'b0
,
m_axi_arvalid_next
;
reg
m_axi_rready_reg
=
1'b0
,
m_axi_rready_next
;
reg
[
AXI_DATA_WIDTH
-
1
:
0
]
save_axi_rdata_reg
=
{
AXI_DATA_WIDTH
{
1'b0
}}
;
wire
[
AXI_DATA_WIDTH
-
1
:
0
]
shift_axi_rdata
=
{
m_axi_rdata
,
save_axi_rdata_reg
}
>>
((
AXI_STRB_WIDTH
-
offset_reg
)
*
AXI_WORD_SIZE
);
// internal datapath
reg
[
AXIS_DATA_WIDTH
-
1
:
0
]
m_axis_read_data_tdata_int
;
reg
[
AXIS_KEEP_WIDTH
-
1
:
0
]
m_axis_read_data_tkeep_int
;
reg
m_axis_read_data_tvalid_int
;
reg
m_axis_read_data_tready_int_reg
=
1'b0
;
reg
m_axis_read_data_tlast_int
;
reg
[
AXIS_ID_WIDTH
-
1
:
0
]
m_axis_read_data_tid_int
;
reg
[
AXIS_DEST_WIDTH
-
1
:
0
]
m_axis_read_data_tdest_int
;
reg
[
AXIS_USER_WIDTH
-
1
:
0
]
m_axis_read_data_tuser_int
;
wire
m_axis_read_data_tready_int_early
;
assign
s_axis_read_desc_ready
=
s_axis_read_desc_ready_reg
;
assign
m_axis_read_desc_status_tag
=
m_axis_read_desc_status_tag_reg
;
assign
m_axis_read_desc_status_valid
=
m_axis_read_desc_status_valid_reg
;
assign
m_axi_arid
=
{
AXI_ID_WIDTH
{
1'b0
}}
;
assign
m_axi_araddr
=
m_axi_araddr_reg
;
assign
m_axi_arlen
=
m_axi_arlen_reg
;
assign
m_axi_arsize
=
AXI_BURST_SIZE
;
assign
m_axi_arburst
=
2'b01
;
assign
m_axi_arlock
=
1'b0
;
assign
m_axi_arcache
=
4'b0011
;
assign
m_axi_arprot
=
3'b010
;
assign
m_axi_arvalid
=
m_axi_arvalid_reg
;
assign
m_axi_rready
=
m_axi_rready_reg
;
wire
[
AXI_ADDR_WIDTH
-
1
:
0
]
addr_plus_max_burst
=
addr_reg
+
AXI_MAX_BURST_SIZE
;
wire
[
AXI_ADDR_WIDTH
-
1
:
0
]
addr_plus_count
=
addr_reg
+
op_word_count_reg
;
always
@*
begin
axi_state_next
=
AXI_STATE_IDLE
;
s_axis_read_desc_ready_next
=
1'b0
;
m_axi_araddr_next
=
m_axi_araddr_reg
;
m_axi_arlen_next
=
m_axi_arlen_reg
;
m_axi_arvalid_next
=
m_axi_arvalid_reg
&&
!
m_axi_arready
;
addr_next
=
addr_reg
;
op_word_count_next
=
op_word_count_reg
;
tr_word_count_next
=
tr_word_count_reg
;
axis_cmd_offset_next
=
axis_cmd_offset_reg
;
axis_cmd_last_cycle_offset_next
=
axis_cmd_last_cycle_offset_reg
;
axis_cmd_input_cycle_count_next
=
axis_cmd_input_cycle_count_reg
;
axis_cmd_output_cycle_count_next
=
axis_cmd_output_cycle_count_reg
;
axis_cmd_bubble_cycle_next
=
axis_cmd_bubble_cycle_reg
;
axis_cmd_tag_next
=
axis_cmd_tag_reg
;
axis_cmd_axis_id_next
=
axis_cmd_axis_id_reg
;
axis_cmd_axis_dest_next
=
axis_cmd_axis_dest_reg
;
axis_cmd_axis_user_next
=
axis_cmd_axis_user_reg
;
axis_cmd_valid_next
=
axis_cmd_valid_reg
&&
!
axis_cmd_ready
;
case
(
axi_state_reg
)
AXI_STATE_IDLE:
begin
// idle state - load new descriptor to start operation
s_axis_read_desc_ready_next
=
!
axis_cmd_valid_reg
&&
enable
;
if
(
s_axis_read_desc_ready
&&
s_axis_read_desc_valid
)
begin
if
(
ENABLE_UNALIGNED
)
begin
addr_next
=
s_axis_read_desc_addr
;
axis_cmd_offset_next
=
AXI_STRB_WIDTH
>
1
?
AXI_STRB_WIDTH
-
(
s_axis_read_desc_addr
&
OFFSET_MASK
)
:
0
;
axis_cmd_bubble_cycle_next
=
axis_cmd_offset_next
>
0
;
axis_cmd_last_cycle_offset_next
=
s_axis_read_desc_len
&
OFFSET_MASK
;
end
else
begin
addr_next
=
s_axis_read_desc_addr
&
ADDR_MASK
;
axis_cmd_offset_next
=
0
;
axis_cmd_bubble_cycle_next
=
1'b0
;
axis_cmd_last_cycle_offset_next
=
s_axis_read_desc_len
&
OFFSET_MASK
;
end
axis_cmd_tag_next
=
s_axis_read_desc_tag
;
op_word_count_next
=
s_axis_read_desc_len
;
axis_cmd_axis_id_next
=
s_axis_read_desc_id
;
axis_cmd_axis_dest_next
=
s_axis_read_desc_dest
;
axis_cmd_axis_user_next
=
s_axis_read_desc_user
;
if
(
ENABLE_UNALIGNED
)
begin
axis_cmd_input_cycle_count_next
=
(
op_word_count_next
+
(
s_axis_read_desc_addr
&
OFFSET_MASK
)
-
1
)
>>
AXI_BURST_SIZE
;
end
else
begin
axis_cmd_input_cycle_count_next
=
(
op_word_count_next
-
1
)
>>
AXI_BURST_SIZE
;
end
axis_cmd_output_cycle_count_next
=
(
op_word_count_next
-
1
)
>>
AXI_BURST_SIZE
;
axis_cmd_valid_next
=
1'b1
;
s_axis_read_desc_ready_next
=
1'b0
;
axi_state_next
=
AXI_STATE_START
;
end
else
begin
axi_state_next
=
AXI_STATE_IDLE
;
end
end
AXI_STATE_START:
begin
// start state - initiate new AXI transfer
if
(
!
m_axi_arvalid
)
begin
if
(
op_word_count_reg
<=
AXI_MAX_BURST_SIZE
-
(
addr_reg
&
OFFSET_MASK
)
||
AXI_MAX_BURST_SIZE
>=
4096
)
begin
// packet smaller than max burst size
if
(
addr_reg
[
12
]
!=
addr_plus_count
[
12
])
begin
// crosses 4k boundary
tr_word_count_next
=
13'h1000
-
addr_reg
[
11
:
0
];
end
else
begin
// does not cross 4k boundary
tr_word_count_next
=
op_word_count_reg
;
end
end
else
begin
// packet larger than max burst size
if
(
addr_reg
[
12
]
!=
addr_plus_max_burst
[
12
])
begin
// crosses 4k boundary
tr_word_count_next
=
13'h1000
-
addr_reg
[
11
:
0
];
end
else
begin
// does not cross 4k boundary
tr_word_count_next
=
AXI_MAX_BURST_SIZE
-
(
addr_reg
&
OFFSET_MASK
);
end
end
m_axi_araddr_next
=
addr_reg
;
if
(
ENABLE_UNALIGNED
)
begin
m_axi_arlen_next
=
(
tr_word_count_next
+
(
addr_reg
&
OFFSET_MASK
)
-
1
)
>>
AXI_BURST_SIZE
;
end
else
begin
m_axi_arlen_next
=
(
tr_word_count_next
-
1
)
>>
AXI_BURST_SIZE
;
end
m_axi_arvalid_next
=
1'b1
;
addr_next
=
addr_reg
+
tr_word_count_next
;
op_word_count_next
=
op_word_count_reg
-
tr_word_count_next
;
if
(
op_word_count_next
>
0
)
begin
axi_state_next
=
AXI_STATE_START
;
end
else
begin
s_axis_read_desc_ready_next
=
!
axis_cmd_valid_reg
&&
enable
;
axi_state_next
=
AXI_STATE_IDLE
;
end
end
else
begin
axi_state_next
=
AXI_STATE_START
;
end
end
endcase
end
always
@*
begin
axis_state_next
=
AXIS_STATE_IDLE
;
m_axis_read_desc_status_tag_next
=
m_axis_read_desc_status_tag_reg
;
m_axis_read_desc_status_valid_next
=
1'b0
;
m_axis_read_data_tdata_int
=
shift_axi_rdata
;
m_axis_read_data_tkeep_int
=
{
AXIS_KEEP_WIDTH
{
1'b1
}}
;
m_axis_read_data_tlast_int
=
1'b0
;
m_axis_read_data_tvalid_int
=
1'b0
;
m_axis_read_data_tid_int
=
axis_id_reg
;
m_axis_read_data_tdest_int
=
axis_dest_reg
;
m_axis_read_data_tuser_int
=
axis_user_reg
;
m_axi_rready_next
=
1'b0
;
transfer_in_save
=
1'b0
;
axis_cmd_ready
=
1'b0
;
offset_next
=
offset_reg
;
last_cycle_offset_next
=
last_cycle_offset_reg
;
input_cycle_count_next
=
input_cycle_count_reg
;
output_cycle_count_next
=
output_cycle_count_reg
;
input_active_next
=
input_active_reg
;
output_active_next
=
output_active_reg
;
bubble_cycle_next
=
bubble_cycle_reg
;
first_cycle_next
=
first_cycle_reg
;
output_last_cycle_next
=
output_last_cycle_reg
;
tag_next
=
tag_reg
;
axis_id_next
=
axis_id_reg
;
axis_dest_next
=
axis_dest_reg
;
axis_user_next
=
axis_user_reg
;
case
(
axis_state_reg
)
AXIS_STATE_IDLE:
begin
// idle state - load new descriptor to start operation
m_axi_rready_next
=
1'b0
;
// store transfer parameters
if
(
ENABLE_UNALIGNED
)
begin
offset_next
=
axis_cmd_offset_reg
;
end
else
begin
offset_next
=
0
;
end
last_cycle_offset_next
=
axis_cmd_last_cycle_offset_reg
;
input_cycle_count_next
=
axis_cmd_input_cycle_count_reg
;
output_cycle_count_next
=
axis_cmd_output_cycle_count_reg
;
bubble_cycle_next
=
axis_cmd_bubble_cycle_reg
;
tag_next
=
axis_cmd_tag_reg
;
axis_id_next
=
axis_cmd_axis_id_reg
;
axis_dest_next
=
axis_cmd_axis_dest_reg
;
axis_user_next
=
axis_cmd_axis_user_reg
;
output_last_cycle_next
=
output_cycle_count_next
==
0
;
input_active_next
=
1'b1
;
output_active_next
=
1'b1
;
first_cycle_next
=
1'b1
;
if
(
axis_cmd_valid_reg
)
begin
axis_cmd_ready
=
1'b1
;
m_axi_rready_next
=
m_axis_read_data_tready_int_early
;
axis_state_next
=
AXIS_STATE_READ
;
end
end
AXIS_STATE_READ:
begin
// handle AXI read data
m_axi_rready_next
=
m_axis_read_data_tready_int_early
&&
input_active_reg
;
if
(
m_axis_read_data_tready_int_reg
&&
((
m_axi_rready
&&
m_axi_rvalid
)
||
!
input_active_reg
))
begin
// transfer in AXI read data
transfer_in_save
=
m_axi_rready
&&
m_axi_rvalid
;
if
(
ENABLE_UNALIGNED
&&
first_cycle_reg
&&
bubble_cycle_reg
)
begin
if
(
input_active_reg
)
begin
input_cycle_count_next
=
input_cycle_count_reg
-
1
;
input_active_next
=
input_cycle_count_reg
>
0
;
end
bubble_cycle_next
=
1'b0
;
first_cycle_next
=
1'b0
;
m_axi_rready_next
=
m_axis_read_data_tready_int_early
&&
input_active_next
;
axis_state_next
=
AXIS_STATE_READ
;
end
else
begin
// update counters
if
(
input_active_reg
)
begin
input_cycle_count_next
=
input_cycle_count_reg
-
1
;
input_active_next
=
input_cycle_count_reg
>
0
;
end
if
(
output_active_reg
)
begin
output_cycle_count_next
=
output_cycle_count_reg
-
1
;
output_active_next
=
output_cycle_count_reg
>
0
;
end
output_last_cycle_next
=
output_cycle_count_next
==
0
;
bubble_cycle_next
=
1'b0
;
first_cycle_next
=
1'b0
;
// pass through read data
m_axis_read_data_tdata_int
=
shift_axi_rdata
;
m_axis_read_data_tkeep_int
=
{
AXIS_KEEP_WIDTH_INT
{
1'b1
}}
;
m_axis_read_data_tvalid_int
=
1'b1
;
if
(
output_last_cycle_reg
)
begin
// no more data to transfer, finish operation
if
(
last_cycle_offset_reg
>
0
)
begin
m_axis_read_data_tkeep_int
=
{
AXIS_KEEP_WIDTH_INT
{
1'b1
}}
>>
(
AXIS_KEEP_WIDTH_INT
-
last_cycle_offset_reg
);
end
m_axis_read_data_tlast_int
=
1'b1
;
m_axis_read_desc_status_tag_next
=
tag_reg
;
m_axis_read_desc_status_valid_next
=
1'b1
;
m_axi_rready_next
=
1'b0
;
axis_state_next
=
AXIS_STATE_IDLE
;
end
else
begin
// more cycles in AXI transfer
m_axi_rready_next
=
m_axis_read_data_tready_int_early
&&
input_active_next
;
axis_state_next
=
AXIS_STATE_READ
;
end
end
end
else
begin
axis_state_next
=
AXIS_STATE_READ
;
end
end
endcase
end
always
@
(
posedge
clk
)
begin
if
(
rst
)
begin
axi_state_reg
<=
AXI_STATE_IDLE
;
axis_state_reg
<=
AXIS_STATE_IDLE
;
axis_cmd_valid_reg
<=
1'b0
;
s_axis_read_desc_ready_reg
<=
1'b0
;
m_axis_read_desc_status_valid_reg
<=
1'b0
;
m_axi_arvalid_reg
<=
1'b0
;
m_axi_rready_reg
<=
1'b0
;
end
else
begin
axi_state_reg
<=
axi_state_next
;
axis_state_reg
<=
axis_state_next
;
axis_cmd_valid_reg
<=
axis_cmd_valid_next
;
s_axis_read_desc_ready_reg
<=
s_axis_read_desc_ready_next
;
m_axis_read_desc_status_valid_reg
<=
m_axis_read_desc_status_valid_next
;
m_axi_arvalid_reg
<=
m_axi_arvalid_next
;
m_axi_rready_reg
<=
m_axi_rready_next
;
end
m_axis_read_desc_status_tag_reg
<=
m_axis_read_desc_status_tag_next
;
m_axi_araddr_reg
<=
m_axi_araddr_next
;
m_axi_arlen_reg
<=
m_axi_arlen_next
;
addr_reg
<=
addr_next
;
op_word_count_reg
<=
op_word_count_next
;
tr_word_count_reg
<=
tr_word_count_next
;
axis_cmd_offset_reg
<=
axis_cmd_offset_next
;
axis_cmd_last_cycle_offset_reg
<=
axis_cmd_last_cycle_offset_next
;
axis_cmd_input_cycle_count_reg
<=
axis_cmd_input_cycle_count_next
;
axis_cmd_output_cycle_count_reg
<=
axis_cmd_output_cycle_count_next
;
axis_cmd_bubble_cycle_reg
<=
axis_cmd_bubble_cycle_next
;
axis_cmd_tag_reg
<=
axis_cmd_tag_next
;
axis_cmd_axis_id_reg
<=
axis_cmd_axis_id_next
;
axis_cmd_axis_dest_reg
<=
axis_cmd_axis_dest_next
;
axis_cmd_axis_user_reg
<=
axis_cmd_axis_user_next
;
axis_cmd_valid_reg
<=
axis_cmd_valid_next
;
offset_reg
<=
offset_next
;
last_cycle_offset_reg
<=
last_cycle_offset_next
;
input_cycle_count_reg
<=
input_cycle_count_next
;
output_cycle_count_reg
<=
output_cycle_count_next
;
input_active_reg
<=
input_active_next
;
output_active_reg
<=
output_active_next
;
bubble_cycle_reg
<=
bubble_cycle_next
;
first_cycle_reg
<=
first_cycle_next
;
output_last_cycle_reg
<=
output_last_cycle_next
;
tag_reg
<=
tag_next
;
axis_id_reg
<=
axis_id_next
;
axis_dest_reg
<=
axis_dest_next
;
axis_user_reg
<=
axis_user_next
;
if
(
transfer_in_save
)
begin
save_axi_rdata_reg
<=
m_axi_rdata
;
end
end
// output datapath logic
reg
[
AXIS_DATA_WIDTH
-
1
:
0
]
m_axis_read_data_tdata_reg
=
{
AXIS_DATA_WIDTH
{
1'b0
}}
;
reg
[
AXIS_KEEP_WIDTH
-
1
:
0
]
m_axis_read_data_tkeep_reg
=
{
AXIS_KEEP_WIDTH
{
1'b0
}}
;
reg
m_axis_read_data_tvalid_reg
=
1'b0
,
m_axis_read_data_tvalid_next
;
reg
m_axis_read_data_tlast_reg
=
1'b0
;
reg
[
AXIS_ID_WIDTH
-
1
:
0
]
m_axis_read_data_tid_reg
=
{
AXIS_ID_WIDTH
{
1'b0
}}
;
reg
[
AXIS_DEST_WIDTH
-
1
:
0
]
m_axis_read_data_tdest_reg
=
{
AXIS_DEST_WIDTH
{
1'b0
}}
;
reg
[
AXIS_USER_WIDTH
-
1
:
0
]
m_axis_read_data_tuser_reg
=
{
AXIS_USER_WIDTH
{
1'b0
}}
;
reg
[
AXIS_DATA_WIDTH
-
1
:
0
]
temp_m_axis_read_data_tdata_reg
=
{
AXIS_DATA_WIDTH
{
1'b0
}}
;
reg
[
AXIS_KEEP_WIDTH
-
1
:
0
]
temp_m_axis_read_data_tkeep_reg
=
{
AXIS_KEEP_WIDTH
{
1'b0
}}
;
reg
temp_m_axis_read_data_tvalid_reg
=
1'b0
,
temp_m_axis_read_data_tvalid_next
;
reg
temp_m_axis_read_data_tlast_reg
=
1'b0
;
reg
[
AXIS_ID_WIDTH
-
1
:
0
]
temp_m_axis_read_data_tid_reg
=
{
AXIS_ID_WIDTH
{
1'b0
}}
;
reg
[
AXIS_DEST_WIDTH
-
1
:
0
]
temp_m_axis_read_data_tdest_reg
=
{
AXIS_DEST_WIDTH
{
1'b0
}}
;
reg
[
AXIS_USER_WIDTH
-
1
:
0
]
temp_m_axis_read_data_tuser_reg
=
{
AXIS_USER_WIDTH
{
1'b0
}}
;
// datapath control
reg
store_axis_int_to_output
;
reg
store_axis_int_to_temp
;
reg
store_axis_temp_to_output
;
assign
m_axis_read_data_tdata
=
m_axis_read_data_tdata_reg
;
assign
m_axis_read_data_tkeep
=
AXIS_KEEP_ENABLE
?
m_axis_read_data_tkeep_reg
:
{
AXIS_KEEP_WIDTH
{
1'b1
}}
;
assign
m_axis_read_data_tvalid
=
m_axis_read_data_tvalid_reg
;
assign
m_axis_read_data_tlast
=
AXIS_LAST_ENABLE
?
m_axis_read_data_tlast_reg
:
1'b1
;
assign
m_axis_read_data_tid
=
AXIS_ID_ENABLE
?
m_axis_read_data_tid_reg
:
{
AXIS_ID_WIDTH
{
1'b0
}}
;
assign
m_axis_read_data_tdest
=
AXIS_DEST_ENABLE
?
m_axis_read_data_tdest_reg
:
{
AXIS_DEST_WIDTH
{
1'b0
}}
;
assign
m_axis_read_data_tuser
=
AXIS_USER_ENABLE
?
m_axis_read_data_tuser_reg
:
{
AXIS_USER_WIDTH
{
1'b0
}}
;
// enable ready input next cycle if output is ready or the temp reg will not be filled on the next cycle (output reg empty or no input)
assign
m_axis_read_data_tready_int_early
=
m_axis_read_data_tready
||
(
!
temp_m_axis_read_data_tvalid_reg
&&
(
!
m_axis_read_data_tvalid_reg
||
!
m_axis_read_data_tvalid_int
));
always
@*
begin
// transfer sink ready state to source
m_axis_read_data_tvalid_next
=
m_axis_read_data_tvalid_reg
;
temp_m_axis_read_data_tvalid_next
=
temp_m_axis_read_data_tvalid_reg
;
store_axis_int_to_output
=
1'b0
;
store_axis_int_to_temp
=
1'b0
;
store_axis_temp_to_output
=
1'b0
;
if
(
m_axis_read_data_tready_int_reg
)
begin
// input is ready
if
(
m_axis_read_data_tready
||
!
m_axis_read_data_tvalid_reg
)
begin
// output is ready or currently not valid, transfer data to output
m_axis_read_data_tvalid_next
=
m_axis_read_data_tvalid_int
;
store_axis_int_to_output
=
1'b1
;
end
else
begin
// output is not ready, store input in temp
temp_m_axis_read_data_tvalid_next
=
m_axis_read_data_tvalid_int
;
store_axis_int_to_temp
=
1'b1
;
end
end
else
if
(
m_axis_read_data_tready
)
begin
// input is not ready, but output is ready
m_axis_read_data_tvalid_next
=
temp_m_axis_read_data_tvalid_reg
;
temp_m_axis_read_data_tvalid_next
=
1'b0
;
store_axis_temp_to_output
=
1'b1
;
end
end
always
@
(
posedge
clk
)
begin
if
(
rst
)
begin
m_axis_read_data_tvalid_reg
<=
1'b0
;
m_axis_read_data_tready_int_reg
<=
1'b0
;
temp_m_axis_read_data_tvalid_reg
<=
1'b0
;
end
else
begin
m_axis_read_data_tvalid_reg
<=
m_axis_read_data_tvalid_next
;
m_axis_read_data_tready_int_reg
<=
m_axis_read_data_tready_int_early
;
temp_m_axis_read_data_tvalid_reg
<=
temp_m_axis_read_data_tvalid_next
;
end
// datapath
if
(
store_axis_int_to_output
)
begin
m_axis_read_data_tdata_reg
<=
m_axis_read_data_tdata_int
;
m_axis_read_data_tkeep_reg
<=
m_axis_read_data_tkeep_int
;
m_axis_read_data_tlast_reg
<=
m_axis_read_data_tlast_int
;
m_axis_read_data_tid_reg
<=
m_axis_read_data_tid_int
;
m_axis_read_data_tdest_reg
<=
m_axis_read_data_tdest_int
;
m_axis_read_data_tuser_reg
<=
m_axis_read_data_tuser_int
;
end
else
if
(
store_axis_temp_to_output
)
begin
m_axis_read_data_tdata_reg
<=
temp_m_axis_read_data_tdata_reg
;
m_axis_read_data_tkeep_reg
<=
temp_m_axis_read_data_tkeep_reg
;
m_axis_read_data_tlast_reg
<=
temp_m_axis_read_data_tlast_reg
;
m_axis_read_data_tid_reg
<=
temp_m_axis_read_data_tid_reg
;
m_axis_read_data_tdest_reg
<=
temp_m_axis_read_data_tdest_reg
;
m_axis_read_data_tuser_reg
<=
temp_m_axis_read_data_tuser_reg
;
end
if
(
store_axis_int_to_temp
)
begin
temp_m_axis_read_data_tdata_reg
<=
m_axis_read_data_tdata_int
;
temp_m_axis_read_data_tkeep_reg
<=
m_axis_read_data_tkeep_int
;
temp_m_axis_read_data_tlast_reg
<=
m_axis_read_data_tlast_int
;
temp_m_axis_read_data_tid_reg
<=
m_axis_read_data_tid_int
;
temp_m_axis_read_data_tdest_reg
<=
m_axis_read_data_tdest_int
;
temp_m_axis_read_data_tuser_reg
<=
m_axis_read_data_tuser_int
;
end
end
endmodule
corundum/lib/axi/rtl/axi_dma_wr.v
0 → 100644
View file @
738c1fef
/*
Copyright (c) 2018 Alex Forencich
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.
*/
// Language: Verilog 2001
`timescale
1
ns
/
1
ps
/*
* AXI4 DMA
*/
module
axi_dma_wr
#
(
// Width of AXI data bus in bits
parameter
AXI_DATA_WIDTH
=
32
,
// Width of AXI address bus in bits
parameter
AXI_ADDR_WIDTH
=
16
,
// Width of AXI wstrb (width of data bus in words)
parameter
AXI_STRB_WIDTH
=
(
AXI_DATA_WIDTH
/
8
),
// Width of AXI ID signal
parameter
AXI_ID_WIDTH
=
8
,
// Maximum AXI burst length to generate
parameter
AXI_MAX_BURST_LEN
=
16
,
// Width of AXI stream interfaces in bits
parameter
AXIS_DATA_WIDTH
=
AXI_DATA_WIDTH
,
// Use AXI stream tkeep signal
parameter
AXIS_KEEP_ENABLE
=
(
AXIS_DATA_WIDTH
>
8
),
// AXI stream tkeep signal width (words per cycle)
parameter
AXIS_KEEP_WIDTH
=
(
AXIS_DATA_WIDTH
/
8
),
// Use AXI stream tlast signal
parameter
AXIS_LAST_ENABLE
=
1
,
// Propagate AXI stream tid signal
parameter
AXIS_ID_ENABLE
=
0
,
// AXI stream tid signal width
parameter
AXIS_ID_WIDTH
=
8
,
// Propagate AXI stream tdest signal
parameter
AXIS_DEST_ENABLE
=
0
,
// AXI stream tdest signal width
parameter
AXIS_DEST_WIDTH
=
8
,
// Propagate AXI stream tuser signal
parameter
AXIS_USER_ENABLE
=
1
,
// AXI stream tuser signal width
parameter
AXIS_USER_WIDTH
=
1
,
// Width of length field
parameter
LEN_WIDTH
=
20
,
// Width of tag field
parameter
TAG_WIDTH
=
8
,
// Enable support for scatter/gather DMA
// (multiple descriptors per AXI stream frame)
parameter
ENABLE_SG
=
0
,
// Enable support for unaligned transfers
parameter
ENABLE_UNALIGNED
=
0
)
(
input
wire
clk
,
input
wire
rst
,
/*
* AXI write descriptor input
*/
input
wire
[
AXI_ADDR_WIDTH
-
1
:
0
]
s_axis_write_desc_addr
,
input
wire
[
LEN_WIDTH
-
1
:
0
]
s_axis_write_desc_len
,
input
wire
[
TAG_WIDTH
-
1
:
0
]
s_axis_write_desc_tag
,
input
wire
s_axis_write_desc_valid
,
output
wire
s_axis_write_desc_ready
,
/*
* AXI write descriptor status output
*/
output
wire
[
LEN_WIDTH
-
1
:
0
]
m_axis_write_desc_status_len
,
output
wire
[
TAG_WIDTH
-
1
:
0
]
m_axis_write_desc_status_tag
,
output
wire
[
AXIS_ID_WIDTH
-
1
:
0
]
m_axis_write_desc_status_id
,
output
wire
[
AXIS_DEST_WIDTH
-
1
:
0
]
m_axis_write_desc_status_dest
,
output
wire
[
AXIS_USER_WIDTH
-
1
:
0
]
m_axis_write_desc_status_user
,
output
wire
m_axis_write_desc_status_valid
,
/*
* AXI stream write data input
*/
input
wire
[
AXIS_DATA_WIDTH
-
1
:
0
]
s_axis_write_data_tdata
,
input
wire
[
AXIS_KEEP_WIDTH
-
1
:
0
]
s_axis_write_data_tkeep
,
input
wire
s_axis_write_data_tvalid
,
output
wire
s_axis_write_data_tready
,
input
wire
s_axis_write_data_tlast
,
input
wire
[
AXIS_ID_WIDTH
-
1
:
0
]
s_axis_write_data_tid
,
input
wire
[
AXIS_DEST_WIDTH
-
1
:
0
]
s_axis_write_data_tdest
,
input
wire
[
AXIS_USER_WIDTH
-
1
:
0
]
s_axis_write_data_tuser
,
/*
* AXI master interface
*/
output
wire
[
AXI_ID_WIDTH
-
1
:
0
]
m_axi_awid
,
output
wire
[
AXI_ADDR_WIDTH
-
1
:
0
]
m_axi_awaddr
,
output
wire
[
7
:
0
]
m_axi_awlen
,
output
wire
[
2
:
0
]
m_axi_awsize
,
output
wire
[
1
:
0
]
m_axi_awburst
,
output
wire
m_axi_awlock
,
output
wire
[
3
:
0
]
m_axi_awcache
,
output
wire
[
2
:
0
]
m_axi_awprot
,
output
wire
m_axi_awvalid
,
input
wire
m_axi_awready
,
output
wire
[
AXI_DATA_WIDTH
-
1
:
0
]
m_axi_wdata
,
output
wire
[
AXI_STRB_WIDTH
-
1
:
0
]
m_axi_wstrb
,
output
wire
m_axi_wlast
,
output
wire
m_axi_wvalid
,
input
wire
m_axi_wready
,
input
wire
[
AXI_ID_WIDTH
-
1
:
0
]
m_axi_bid
,
input
wire
[
1
:
0
]
m_axi_bresp
,
input
wire
m_axi_bvalid
,
output
wire
m_axi_bready
,
/*
* Configuration
*/
input
wire
enable
,
input
wire
abort
);
parameter
AXI_WORD_WIDTH
=
AXI_STRB_WIDTH
;
parameter
AXI_WORD_SIZE
=
AXI_DATA_WIDTH
/
AXI_WORD_WIDTH
;
parameter
AXI_BURST_SIZE
=
$
clog2
(
AXI_STRB_WIDTH
);
parameter
AXI_MAX_BURST_SIZE
=
AXI_MAX_BURST_LEN
<<
AXI_BURST_SIZE
;
parameter
AXIS_KEEP_WIDTH_INT
=
AXIS_KEEP_ENABLE
?
AXIS_KEEP_WIDTH
:
1
;
parameter
AXIS_WORD_WIDTH
=
AXIS_KEEP_WIDTH_INT
;
parameter
AXIS_WORD_SIZE
=
AXIS_DATA_WIDTH
/
AXIS_WORD_WIDTH
;
parameter
OFFSET_WIDTH
=
AXI_STRB_WIDTH
>
1
?
$
clog2
(
AXI_STRB_WIDTH
)
:
1
;
parameter
OFFSET_MASK
=
AXI_STRB_WIDTH
>
1
?
{
OFFSET_WIDTH
{
1'b1
}}
:
0
;
parameter
ADDR_MASK
=
{
AXI_ADDR_WIDTH
{
1'b1
}}
<<
$
clog2
(
AXI_STRB_WIDTH
);
parameter
CYCLE_COUNT_WIDTH
=
LEN_WIDTH
-
AXI_BURST_SIZE
+
1
;
parameter
STATUS_FIFO_ADDR_WIDTH
=
5
;
// bus width assertions
initial
begin
if
(
AXI_WORD_SIZE
*
AXI_STRB_WIDTH
!=
AXI_DATA_WIDTH
)
begin
$
error
(
"Error: AXI data width not evenly divisble (instance %m)"
);
$
finish
;
end
if
(
AXIS_WORD_SIZE
*
AXIS_KEEP_WIDTH_INT
!=
AXIS_DATA_WIDTH
)
begin
$
error
(
"Error: AXI stream data width not evenly divisble (instance %m)"
);
$
finish
;
end
if
(
AXI_WORD_SIZE
!=
AXIS_WORD_SIZE
)
begin
$
error
(
"Error: word size mismatch (instance %m)"
);
$
finish
;
end
if
(
2
**
$
clog2
(
AXI_WORD_WIDTH
)
!=
AXI_WORD_WIDTH
)
begin
$
error
(
"Error: AXI word width must be even power of two (instance %m)"
);
$
finish
;
end
if
(
AXI_DATA_WIDTH
!=
AXIS_DATA_WIDTH
)
begin
$
error
(
"Error: AXI interface width must match AXI stream interface width (instance %m)"
);
$
finish
;
end
if
(
AXI_MAX_BURST_LEN
<
1
||
AXI_MAX_BURST_LEN
>
256
)
begin
$
error
(
"Error: AXI_MAX_BURST_LEN must be between 1 and 256 (instance %m)"
);
$
finish
;
end
if
(
ENABLE_SG
)
begin
$
error
(
"Error: scatter/gather is not yet implemented (instance %m)"
);
$
finish
;
end
end
localparam
[
2
:
0
]
STATE_IDLE
=
3'd0
,
STATE_START
=
3'd1
,
STATE_WRITE
=
3'd2
,
STATE_FINISH_BURST
=
3'd3
,
STATE_DROP_DATA
=
3'd4
;
reg
[
2
:
0
]
state_reg
=
STATE_IDLE
,
state_next
;
// datapath control signals
reg
transfer_in_save
;
reg
flush_save
;
reg
status_fifo_we
;
integer
i
;
reg
[
OFFSET_WIDTH
:
0
]
cycle_size
;
reg
[
AXI_ADDR_WIDTH
-
1
:
0
]
addr_reg
=
{
AXI_ADDR_WIDTH
{
1'b0
}}
,
addr_next
;
reg
[
LEN_WIDTH
-
1
:
0
]
op_word_count_reg
=
{
LEN_WIDTH
{
1'b0
}}
,
op_word_count_next
;
reg
[
LEN_WIDTH
-
1
:
0
]
tr_word_count_reg
=
{
LEN_WIDTH
{
1'b0
}}
,
tr_word_count_next
;
reg
[
OFFSET_WIDTH
-
1
:
0
]
offset_reg
=
{
OFFSET_WIDTH
{
1'b0
}}
,
offset_next
;
reg
[
AXI_STRB_WIDTH
-
1
:
0
]
strb_offset_mask_reg
=
{
AXI_STRB_WIDTH
{
1'b1
}}
,
strb_offset_mask_next
;
reg
zero_offset_reg
=
1'b1
,
zero_offset_next
;
reg
[
OFFSET_WIDTH
-
1
:
0
]
last_cycle_offset_reg
=
{
OFFSET_WIDTH
{
1'b0
}}
,
last_cycle_offset_next
;
reg
[
LEN_WIDTH
-
1
:
0
]
length_reg
=
{
LEN_WIDTH
{
1'b0
}}
,
length_next
;
reg
[
CYCLE_COUNT_WIDTH
-
1
:
0
]
input_cycle_count_reg
=
{
CYCLE_COUNT_WIDTH
{
1'b0
}}
,
input_cycle_count_next
;
reg
[
CYCLE_COUNT_WIDTH
-
1
:
0
]
output_cycle_count_reg
=
{
CYCLE_COUNT_WIDTH
{
1'b0
}}
,
output_cycle_count_next
;
reg
input_active_reg
=
1'b0
,
input_active_next
;
reg
first_cycle_reg
=
1'b0
,
first_cycle_next
;
reg
input_last_cycle_reg
=
1'b0
,
input_last_cycle_next
;
reg
output_last_cycle_reg
=
1'b0
,
output_last_cycle_next
;
reg
last_transfer_reg
=
1'b0
,
last_transfer_next
;
reg
[
TAG_WIDTH
-
1
:
0
]
tag_reg
=
{
TAG_WIDTH
{
1'b0
}}
,
tag_next
;
reg
[
AXIS_ID_WIDTH
-
1
:
0
]
axis_id_reg
=
{
AXIS_ID_WIDTH
{
1'b0
}}
,
axis_id_next
;
reg
[
AXIS_DEST_WIDTH
-
1
:
0
]
axis_dest_reg
=
{
AXIS_DEST_WIDTH
{
1'b0
}}
,
axis_dest_next
;
reg
[
AXIS_USER_WIDTH
-
1
:
0
]
axis_user_reg
=
{
AXIS_USER_WIDTH
{
1'b0
}}
,
axis_user_next
;
reg
[
STATUS_FIFO_ADDR_WIDTH
+
1
-
1
:
0
]
status_fifo_wr_ptr_reg
=
0
,
status_fifo_wr_ptr_next
;
reg
[
STATUS_FIFO_ADDR_WIDTH
+
1
-
1
:
0
]
status_fifo_rd_ptr_reg
=
0
,
status_fifo_rd_ptr_next
;
reg
[
LEN_WIDTH
-
1
:
0
]
status_fifo_len
[(
2
**
STATUS_FIFO_ADDR_WIDTH
)
-
1
:
0
];
reg
[
TAG_WIDTH
-
1
:
0
]
status_fifo_tag
[(
2
**
STATUS_FIFO_ADDR_WIDTH
)
-
1
:
0
];
reg
[
AXIS_ID_WIDTH
-
1
:
0
]
status_fifo_id
[(
2
**
STATUS_FIFO_ADDR_WIDTH
)
-
1
:
0
];
reg
[
AXIS_DEST_WIDTH
-
1
:
0
]
status_fifo_dest
[(
2
**
STATUS_FIFO_ADDR_WIDTH
)
-
1
:
0
];
reg
[
AXIS_USER_WIDTH
-
1
:
0
]
status_fifo_user
[(
2
**
STATUS_FIFO_ADDR_WIDTH
)
-
1
:
0
];
reg
status_fifo_last
[(
2
**
STATUS_FIFO_ADDR_WIDTH
)
-
1
:
0
];
reg
[
LEN_WIDTH
-
1
:
0
]
status_fifo_wr_len
;
reg
[
TAG_WIDTH
-
1
:
0
]
status_fifo_wr_tag
;
reg
[
AXIS_ID_WIDTH
-
1
:
0
]
status_fifo_wr_id
;
reg
[
AXIS_DEST_WIDTH
-
1
:
0
]
status_fifo_wr_dest
;
reg
[
AXIS_USER_WIDTH
-
1
:
0
]
status_fifo_wr_user
;
reg
status_fifo_wr_last
;
reg
s_axis_write_desc_ready_reg
=
1'b0
,
s_axis_write_desc_ready_next
;
reg
[
LEN_WIDTH
-
1
:
0
]
m_axis_write_desc_status_len_reg
=
{
LEN_WIDTH
{
1'b0
}}
,
m_axis_write_desc_status_len_next
;
reg
[
TAG_WIDTH
-
1
:
0
]
m_axis_write_desc_status_tag_reg
=
{
TAG_WIDTH
{
1'b0
}}
,
m_axis_write_desc_status_tag_next
;
reg
[
AXIS_ID_WIDTH
-
1
:
0
]
m_axis_write_desc_status_id_reg
=
{
AXIS_ID_WIDTH
{
1'b0
}}
,
m_axis_write_desc_status_id_next
;
reg
[
AXIS_DEST_WIDTH
-
1
:
0
]
m_axis_write_desc_status_dest_reg
=
{
AXIS_DEST_WIDTH
{
1'b0
}}
,
m_axis_write_desc_status_dest_next
;
reg
[
AXIS_USER_WIDTH
-
1
:
0
]
m_axis_write_desc_status_user_reg
=
{
AXIS_USER_WIDTH
{
1'b0
}}
,
m_axis_write_desc_status_user_next
;
reg
m_axis_write_desc_status_valid_reg
=
1'b0
,
m_axis_write_desc_status_valid_next
;
reg
[
AXI_ADDR_WIDTH
-
1
:
0
]
m_axi_awaddr_reg
=
{
AXI_ADDR_WIDTH
{
1'b0
}}
,
m_axi_awaddr_next
;
reg
[
7
:
0
]
m_axi_awlen_reg
=
8'd0
,
m_axi_awlen_next
;
reg
m_axi_awvalid_reg
=
1'b0
,
m_axi_awvalid_next
;
reg
m_axi_bready_reg
=
1'b0
,
m_axi_bready_next
;
reg
s_axis_write_data_tready_reg
=
1'b0
,
s_axis_write_data_tready_next
;
reg
[
AXIS_DATA_WIDTH
-
1
:
0
]
save_axis_tdata_reg
=
{
AXIS_DATA_WIDTH
{
1'b0
}}
;
reg
[
AXIS_KEEP_WIDTH_INT
-
1
:
0
]
save_axis_tkeep_reg
=
{
AXIS_KEEP_WIDTH_INT
{
1'b0
}}
;
reg
save_axis_tlast_reg
=
1'b0
;
reg
[
AXIS_DATA_WIDTH
-
1
:
0
]
shift_axis_tdata
;
reg
[
AXIS_KEEP_WIDTH_INT
-
1
:
0
]
shift_axis_tkeep
;
reg
shift_axis_tvalid
;
reg
shift_axis_tlast
;
reg
shift_axis_input_tready
;
reg
shift_axis_extra_cycle_reg
=
1'b0
;
// internal datapath
reg
[
AXI_DATA_WIDTH
-
1
:
0
]
m_axi_wdata_int
;
reg
[
AXI_STRB_WIDTH
-
1
:
0
]
m_axi_wstrb_int
;
reg
m_axi_wlast_int
;
reg
m_axi_wvalid_int
;
reg
m_axi_wready_int_reg
=
1'b0
;
wire
m_axi_wready_int_early
;
assign
s_axis_write_desc_ready
=
s_axis_write_desc_ready_reg
;
assign
m_axis_write_desc_status_len
=
m_axis_write_desc_status_len_reg
;
assign
m_axis_write_desc_status_tag
=
m_axis_write_desc_status_tag_reg
;
assign
m_axis_write_desc_status_id
=
m_axis_write_desc_status_id_reg
;
assign
m_axis_write_desc_status_dest
=
m_axis_write_desc_status_dest_reg
;
assign
m_axis_write_desc_status_user
=
m_axis_write_desc_status_user_reg
;
assign
m_axis_write_desc_status_valid
=
m_axis_write_desc_status_valid_reg
;
assign
s_axis_write_data_tready
=
s_axis_write_data_tready_reg
;
assign
m_axi_awid
=
{
AXI_ID_WIDTH
{
1'b0
}}
;
assign
m_axi_awaddr
=
m_axi_awaddr_reg
;
assign
m_axi_awlen
=
m_axi_awlen_reg
;
assign
m_axi_awsize
=
AXI_BURST_SIZE
;
assign
m_axi_awburst
=
2'b01
;
assign
m_axi_awlock
=
1'b0
;
assign
m_axi_awcache
=
4'b0011
;
assign
m_axi_awprot
=
3'b010
;
assign
m_axi_awvalid
=
m_axi_awvalid_reg
;
assign
m_axi_bready
=
m_axi_bready_reg
;
wire
[
AXI_ADDR_WIDTH
-
1
:
0
]
addr_plus_max_burst
=
addr_reg
+
AXI_MAX_BURST_SIZE
;
wire
[
AXI_ADDR_WIDTH
-
1
:
0
]
addr_plus_count
=
addr_reg
+
op_word_count_reg
;
always
@*
begin
if
(
!
ENABLE_UNALIGNED
||
zero_offset_reg
)
begin
// passthrough if no overlap
shift_axis_tdata
=
s_axis_write_data_tdata
;
shift_axis_tkeep
=
s_axis_write_data_tkeep
;
shift_axis_tvalid
=
s_axis_write_data_tvalid
;
shift_axis_tlast
=
AXIS_LAST_ENABLE
&&
s_axis_write_data_tlast
;
shift_axis_input_tready
=
1'b1
;
end
else
if
(
!
AXIS_LAST_ENABLE
)
begin
shift_axis_tdata
=
{
s_axis_write_data_tdata
,
save_axis_tdata_reg
}
>>
((
AXIS_KEEP_WIDTH_INT
-
offset_reg
)
*
AXIS_WORD_SIZE
);
shift_axis_tkeep
=
{
s_axis_write_data_tkeep
,
save_axis_tkeep_reg
}
>>
(
AXIS_KEEP_WIDTH_INT
-
offset_reg
);
shift_axis_tvalid
=
s_axis_write_data_tvalid
;
shift_axis_tlast
=
1'b0
;
shift_axis_input_tready
=
1'b1
;
end
else
if
(
shift_axis_extra_cycle_reg
)
begin
shift_axis_tdata
=
{
s_axis_write_data_tdata
,
save_axis_tdata_reg
}
>>
((
AXIS_KEEP_WIDTH_INT
-
offset_reg
)
*
AXIS_WORD_SIZE
);
shift_axis_tkeep
=
{{
AXIS_KEEP_WIDTH_INT
{
1'b0
}}
,
save_axis_tkeep_reg
}
>>
(
AXIS_KEEP_WIDTH_INT
-
offset_reg
);
shift_axis_tvalid
=
1'b1
;
shift_axis_tlast
=
save_axis_tlast_reg
;
shift_axis_input_tready
=
flush_save
;
end
else
begin
shift_axis_tdata
=
{
s_axis_write_data_tdata
,
save_axis_tdata_reg
}
>>
((
AXIS_KEEP_WIDTH_INT
-
offset_reg
)
*
AXIS_WORD_SIZE
);
shift_axis_tkeep
=
{
s_axis_write_data_tkeep
,
save_axis_tkeep_reg
}
>>
(
AXIS_KEEP_WIDTH_INT
-
offset_reg
);
shift_axis_tvalid
=
s_axis_write_data_tvalid
;
shift_axis_tlast
=
(
s_axis_write_data_tlast
&&
((
s_axis_write_data_tkeep
&
(
{
AXIS_KEEP_WIDTH_INT
{
1'b1
}}
<<
(
AXIS_KEEP_WIDTH_INT
-
offset_reg
)))
==
0
));
shift_axis_input_tready
=
1'b1
;
end
end
always
@*
begin
state_next
=
STATE_IDLE
;
s_axis_write_desc_ready_next
=
1'b0
;
m_axis_write_desc_status_len_next
=
m_axis_write_desc_status_len_reg
;
m_axis_write_desc_status_tag_next
=
m_axis_write_desc_status_tag_reg
;
m_axis_write_desc_status_id_next
=
m_axis_write_desc_status_id_reg
;
m_axis_write_desc_status_dest_next
=
m_axis_write_desc_status_dest_reg
;
m_axis_write_desc_status_user_next
=
m_axis_write_desc_status_user_reg
;
m_axis_write_desc_status_valid_next
=
1'b0
;
s_axis_write_data_tready_next
=
1'b0
;
m_axi_awaddr_next
=
m_axi_awaddr_reg
;
m_axi_awlen_next
=
m_axi_awlen_reg
;
m_axi_awvalid_next
=
m_axi_awvalid_reg
&&
!
m_axi_awready
;
m_axi_wdata_int
=
shift_axis_tdata
;
m_axi_wstrb_int
=
shift_axis_tkeep
;
m_axi_wlast_int
=
1'b0
;
m_axi_wvalid_int
=
1'b0
;
m_axi_bready_next
=
1'b0
;
transfer_in_save
=
1'b0
;
flush_save
=
1'b0
;
status_fifo_we
=
1'b0
;
cycle_size
=
AXIS_KEEP_WIDTH_INT
;
addr_next
=
addr_reg
;
offset_next
=
offset_reg
;
strb_offset_mask_next
=
strb_offset_mask_reg
;
zero_offset_next
=
zero_offset_reg
;
last_cycle_offset_next
=
last_cycle_offset_reg
;
length_next
=
length_reg
;
op_word_count_next
=
op_word_count_reg
;
tr_word_count_next
=
tr_word_count_reg
;
input_cycle_count_next
=
input_cycle_count_reg
;
output_cycle_count_next
=
output_cycle_count_reg
;
input_active_next
=
input_active_reg
;
first_cycle_next
=
first_cycle_reg
;
input_last_cycle_next
=
input_last_cycle_reg
;
output_last_cycle_next
=
output_last_cycle_reg
;
last_transfer_next
=
last_transfer_reg
;
status_fifo_rd_ptr_next
=
status_fifo_rd_ptr_reg
;
tag_next
=
tag_reg
;
axis_id_next
=
axis_id_reg
;
axis_dest_next
=
axis_dest_reg
;
axis_user_next
=
axis_user_reg
;
status_fifo_wr_len
=
length_reg
;
status_fifo_wr_tag
=
tag_reg
;
status_fifo_wr_id
=
axis_id_reg
;
status_fifo_wr_dest
=
axis_dest_reg
;
status_fifo_wr_user
=
axis_user_reg
;
status_fifo_wr_last
=
1'b0
;
case
(
state_reg
)
STATE_IDLE:
begin
// idle state - load new descriptor to start operation
flush_save
=
1'b1
;
s_axis_write_desc_ready_next
=
enable
;
if
(
ENABLE_UNALIGNED
)
begin
addr_next
=
s_axis_write_desc_addr
;
offset_next
=
s_axis_write_desc_addr
&
OFFSET_MASK
;
strb_offset_mask_next
=
{
AXI_STRB_WIDTH
{
1'b1
}}
<<
(
s_axis_write_desc_addr
&
OFFSET_MASK
);
zero_offset_next
=
(
s_axis_write_desc_addr
&
OFFSET_MASK
)
==
0
;
last_cycle_offset_next
=
offset_next
+
(
s_axis_write_desc_len
&
OFFSET_MASK
);
end
else
begin
addr_next
=
s_axis_write_desc_addr
&
ADDR_MASK
;
offset_next
=
0
;
strb_offset_mask_next
=
{
AXI_STRB_WIDTH
{
1'b1
}}
;
zero_offset_next
=
1'b1
;
last_cycle_offset_next
=
offset_next
+
(
s_axis_write_desc_len
&
OFFSET_MASK
);
end
tag_next
=
s_axis_write_desc_tag
;
op_word_count_next
=
s_axis_write_desc_len
;
first_cycle_next
=
1'b1
;
length_next
=
0
;
if
(
s_axis_write_desc_ready
&&
s_axis_write_desc_valid
)
begin
s_axis_write_desc_ready_next
=
1'b0
;
state_next
=
STATE_START
;
end
else
begin
state_next
=
STATE_IDLE
;
end
end
STATE_START:
begin
// start state - initiate new AXI transfer
if
(
op_word_count_reg
<=
AXI_MAX_BURST_SIZE
-
(
addr_reg
&
OFFSET_MASK
)
||
AXI_MAX_BURST_SIZE
>=
4096
)
begin
// packet smaller than max burst size
if
(
addr_reg
[
12
]
!=
addr_plus_count
[
12
])
begin
// crosses 4k boundary
tr_word_count_next
=
13'h1000
-
addr_reg
[
11
:
0
];
end
else
begin
// does not cross 4k boundary
tr_word_count_next
=
op_word_count_reg
;
end
end
else
begin
// packet larger than max burst size
if
(
addr_reg
[
12
]
!=
addr_plus_max_burst
[
12
])
begin
// crosses 4k boundary
tr_word_count_next
=
13'h1000
-
addr_reg
[
11
:
0
];
end
else
begin
// does not cross 4k boundary
tr_word_count_next
=
AXI_MAX_BURST_SIZE
-
(
addr_reg
&
OFFSET_MASK
);
end
end
input_cycle_count_next
=
(
tr_word_count_next
-
1
)
>>
$
clog2
(
AXIS_KEEP_WIDTH_INT
);
input_last_cycle_next
=
input_cycle_count_next
==
0
;
if
(
ENABLE_UNALIGNED
)
begin
output_cycle_count_next
=
(
tr_word_count_next
+
(
addr_reg
&
OFFSET_MASK
)
-
1
)
>>
AXI_BURST_SIZE
;
end
else
begin
output_cycle_count_next
=
(
tr_word_count_next
-
1
)
>>
AXI_BURST_SIZE
;
end
output_last_cycle_next
=
output_cycle_count_next
==
0
;
last_transfer_next
=
tr_word_count_next
==
op_word_count_reg
;
input_active_next
=
1'b1
;
if
(
ENABLE_UNALIGNED
)
begin
if
(
!
first_cycle_reg
&&
last_transfer_next
)
begin
if
(
offset_reg
>=
last_cycle_offset_reg
&&
last_cycle_offset_reg
>
0
)
begin
// last cycle will be served by stored partial cycle
input_active_next
=
input_cycle_count_next
>
0
;
input_cycle_count_next
=
input_cycle_count_next
-
1
;
end
end
end
if
(
!
m_axi_awvalid_reg
)
begin
m_axi_awaddr_next
=
addr_reg
;
m_axi_awlen_next
=
output_cycle_count_next
;
m_axi_awvalid_next
=
s_axis_write_data_tvalid
||
!
first_cycle_reg
;
if
(
m_axi_awvalid_next
)
begin
addr_next
=
addr_reg
+
tr_word_count_next
;
op_word_count_next
=
op_word_count_reg
-
tr_word_count_next
;
s_axis_write_data_tready_next
=
m_axi_wready_int_early
&&
input_active_next
;
state_next
=
STATE_WRITE
;
end
else
begin
state_next
=
STATE_START
;
end
end
else
begin
state_next
=
STATE_START
;
end
end
STATE_WRITE:
begin
s_axis_write_data_tready_next
=
m_axi_wready_int_early
&&
(
last_transfer_reg
||
input_active_reg
)
&&
shift_axis_input_tready
;
if
(
m_axi_wready_int_reg
&&
((
s_axis_write_data_tready
&&
shift_axis_tvalid
)
||
(
!
input_active_reg
&&
!
last_transfer_reg
)
||
!
shift_axis_input_tready
))
begin
if
(
s_axis_write_data_tready
&&
s_axis_write_data_tvalid
)
begin
transfer_in_save
=
1'b1
;
axis_id_next
=
s_axis_write_data_tid
;
axis_dest_next
=
s_axis_write_data_tdest
;
axis_user_next
=
s_axis_write_data_tuser
;
end
// update counters
if
(
first_cycle_reg
)
begin
length_next
=
length_reg
+
(
AXIS_KEEP_WIDTH_INT
-
offset_reg
);
end
else
begin
length_next
=
length_reg
+
AXIS_KEEP_WIDTH_INT
;
end
if
(
input_active_reg
)
begin
input_cycle_count_next
=
input_cycle_count_reg
-
1
;
input_active_next
=
input_cycle_count_reg
>
0
;
end
input_last_cycle_next
=
input_cycle_count_next
==
0
;
output_cycle_count_next
=
output_cycle_count_reg
-
1
;
output_last_cycle_next
=
output_cycle_count_next
==
0
;
first_cycle_next
=
1'b0
;
strb_offset_mask_next
=
{
AXI_STRB_WIDTH
{
1'b1
}}
;
m_axi_wdata_int
=
shift_axis_tdata
;
m_axi_wstrb_int
=
strb_offset_mask_reg
;
m_axi_wvalid_int
=
1'b1
;
if
(
AXIS_LAST_ENABLE
&&
s_axis_write_data_tlast
)
begin
// end of input frame
input_active_next
=
1'b0
;
s_axis_write_data_tready_next
=
1'b0
;
end
if
(
AXIS_LAST_ENABLE
&&
shift_axis_tlast
)
begin
// end of data packet
if
(
AXIS_KEEP_ENABLE
)
begin
cycle_size
=
AXIS_KEEP_WIDTH_INT
;
for
(
i
=
AXIS_KEEP_WIDTH_INT
-
1
;
i
>=
0
;
i
=
i
-
1
)
begin
if
(
~
shift_axis_tkeep
&
strb_offset_mask_reg
&
(
1
<<
i
))
begin
cycle_size
=
i
;
end
end
end
else
begin
cycle_size
=
AXIS_KEEP_WIDTH_INT
;
end
if
(
output_last_cycle_reg
)
begin
m_axi_wlast_int
=
1'b1
;
// no more data to transfer, finish operation
if
(
last_transfer_reg
&&
last_cycle_offset_reg
>
0
)
begin
if
(
AXIS_KEEP_ENABLE
&&
!
(
shift_axis_tkeep
&
~
(
{
AXI_STRB_WIDTH
{
1'b1
}}
>>
(
AXI_STRB_WIDTH
-
last_cycle_offset_reg
))))
begin
m_axi_wstrb_int
=
strb_offset_mask_reg
&
shift_axis_tkeep
;
if
(
first_cycle_reg
)
begin
length_next
=
length_reg
+
(
cycle_size
-
offset_reg
);
end
else
begin
length_next
=
length_reg
+
cycle_size
;
end
end
else
begin
m_axi_wstrb_int
=
strb_offset_mask_reg
&
{
AXI_STRB_WIDTH
{
1'b1
}}
>>
(
AXI_STRB_WIDTH
-
last_cycle_offset_reg
);
if
(
first_cycle_reg
)
begin
length_next
=
length_reg
+
(
last_cycle_offset_reg
-
offset_reg
);
end
else
begin
length_next
=
length_reg
+
last_cycle_offset_reg
;
end
end
end
else
begin
if
(
AXIS_KEEP_ENABLE
)
begin
m_axi_wstrb_int
=
strb_offset_mask_reg
&
shift_axis_tkeep
;
if
(
first_cycle_reg
)
begin
length_next
=
length_reg
+
(
cycle_size
-
offset_reg
);
end
else
begin
length_next
=
length_reg
+
cycle_size
;
end
end
end
// enqueue status FIFO entry for write completion
status_fifo_we
=
1'b1
;
status_fifo_wr_len
=
length_next
;
status_fifo_wr_tag
=
tag_reg
;
status_fifo_wr_id
=
axis_id_next
;
status_fifo_wr_dest
=
axis_dest_next
;
status_fifo_wr_user
=
axis_user_next
;
status_fifo_wr_last
=
1'b1
;
s_axis_write_data_tready_next
=
1'b0
;
s_axis_write_desc_ready_next
=
enable
;
state_next
=
STATE_IDLE
;
end
else
begin
// more cycles left in burst, finish burst
if
(
AXIS_KEEP_ENABLE
)
begin
m_axi_wstrb_int
=
strb_offset_mask_reg
&
shift_axis_tkeep
;
if
(
first_cycle_reg
)
begin
length_next
=
length_reg
+
(
cycle_size
-
offset_reg
);
end
else
begin
length_next
=
length_reg
+
cycle_size
;
end
end
// enqueue status FIFO entry for write completion
status_fifo_we
=
1'b1
;
status_fifo_wr_len
=
length_next
;
status_fifo_wr_tag
=
tag_reg
;
status_fifo_wr_id
=
axis_id_next
;
status_fifo_wr_dest
=
axis_dest_next
;
status_fifo_wr_user
=
axis_user_next
;
status_fifo_wr_last
=
1'b1
;
s_axis_write_data_tready_next
=
1'b0
;
state_next
=
STATE_FINISH_BURST
;
end
end
else
if
(
output_last_cycle_reg
)
begin
m_axi_wlast_int
=
1'b1
;
if
(
op_word_count_reg
>
0
)
begin
// current AXI transfer complete, but there is more data to transfer
// enqueue status FIFO entry for write completion
status_fifo_we
=
1'b1
;
status_fifo_wr_len
=
length_next
;
status_fifo_wr_tag
=
tag_reg
;
status_fifo_wr_id
=
axis_id_next
;
status_fifo_wr_dest
=
axis_dest_next
;
status_fifo_wr_user
=
axis_user_next
;
status_fifo_wr_last
=
1'b0
;
s_axis_write_data_tready_next
=
1'b0
;
state_next
=
STATE_START
;
end
else
begin
// no more data to transfer, finish operation
if
(
last_cycle_offset_reg
>
0
)
begin
m_axi_wstrb_int
=
strb_offset_mask_reg
&
{
AXI_STRB_WIDTH
{
1'b1
}}
>>
(
AXI_STRB_WIDTH
-
last_cycle_offset_reg
);
if
(
first_cycle_reg
)
begin
length_next
=
length_reg
+
(
last_cycle_offset_reg
-
offset_reg
);
end
else
begin
length_next
=
length_reg
+
last_cycle_offset_reg
;
end
end
// enqueue status FIFO entry for write completion
status_fifo_we
=
1'b1
;
status_fifo_wr_len
=
length_next
;
status_fifo_wr_tag
=
tag_reg
;
status_fifo_wr_id
=
axis_id_next
;
status_fifo_wr_dest
=
axis_dest_next
;
status_fifo_wr_user
=
axis_user_next
;
status_fifo_wr_last
=
1'b1
;
if
(
AXIS_LAST_ENABLE
)
begin
// not at the end of packet; drop remainder
s_axis_write_data_tready_next
=
shift_axis_input_tready
;
state_next
=
STATE_DROP_DATA
;
end
else
begin
// no framing; return to idle
s_axis_write_data_tready_next
=
1'b0
;
s_axis_write_desc_ready_next
=
enable
;
state_next
=
STATE_IDLE
;
end
end
end
else
begin
s_axis_write_data_tready_next
=
m_axi_wready_int_early
&&
(
last_transfer_reg
||
input_active_next
)
&&
shift_axis_input_tready
;
state_next
=
STATE_WRITE
;
end
end
else
begin
state_next
=
STATE_WRITE
;
end
end
STATE_FINISH_BURST:
begin
// finish current AXI burst
if
(
m_axi_wready_int_reg
)
begin
// update counters
if
(
input_active_reg
)
begin
input_cycle_count_next
=
input_cycle_count_reg
-
1
;
input_active_next
=
input_cycle_count_reg
>
0
;
end
input_last_cycle_next
=
input_cycle_count_next
==
0
;
output_cycle_count_next
=
output_cycle_count_reg
-
1
;
output_last_cycle_next
=
output_cycle_count_next
==
0
;
m_axi_wdata_int
=
{
AXI_DATA_WIDTH
{
1'b0
}}
;
m_axi_wstrb_int
=
{
AXI_STRB_WIDTH
{
1'b0
}}
;
m_axi_wvalid_int
=
1'b1
;
if
(
output_last_cycle_reg
)
begin
// no more data to transfer, finish operation
m_axi_wlast_int
=
1'b1
;
s_axis_write_data_tready_next
=
1'b0
;
s_axis_write_desc_ready_next
=
enable
;
state_next
=
STATE_IDLE
;
end
else
begin
// more cycles in AXI transfer
state_next
=
STATE_FINISH_BURST
;
end
end
else
begin
state_next
=
STATE_FINISH_BURST
;
end
end
STATE_DROP_DATA:
begin
// drop excess AXI stream data
s_axis_write_data_tready_next
=
shift_axis_input_tready
;
if
(
shift_axis_tvalid
)
begin
if
(
s_axis_write_data_tready
&&
s_axis_write_data_tvalid
)
begin
transfer_in_save
=
1'b1
;
end
if
(
shift_axis_tlast
)
begin
s_axis_write_data_tready_next
=
1'b0
;
s_axis_write_desc_ready_next
=
enable
;
state_next
=
STATE_IDLE
;
end
else
begin
state_next
=
STATE_DROP_DATA
;
end
end
else
begin
state_next
=
STATE_DROP_DATA
;
end
end
endcase
if
(
status_fifo_rd_ptr_reg
!=
status_fifo_wr_ptr_reg
)
begin
// status FIFO not empty
if
(
m_axi_bready
&&
m_axi_bvalid
)
begin
// got write completion, pop and return status
m_axis_write_desc_status_len_next
=
status_fifo_len
[
status_fifo_rd_ptr_reg
[
STATUS_FIFO_ADDR_WIDTH
-
1
:
0
]];
m_axis_write_desc_status_tag_next
=
status_fifo_tag
[
status_fifo_rd_ptr_reg
[
STATUS_FIFO_ADDR_WIDTH
-
1
:
0
]];
m_axis_write_desc_status_id_next
=
status_fifo_id
[
status_fifo_rd_ptr_reg
[
STATUS_FIFO_ADDR_WIDTH
-
1
:
0
]];
m_axis_write_desc_status_dest_next
=
status_fifo_dest
[
status_fifo_rd_ptr_reg
[
STATUS_FIFO_ADDR_WIDTH
-
1
:
0
]];
m_axis_write_desc_status_user_next
=
status_fifo_user
[
status_fifo_rd_ptr_reg
[
STATUS_FIFO_ADDR_WIDTH
-
1
:
0
]];
m_axis_write_desc_status_valid_next
=
status_fifo_last
[
status_fifo_rd_ptr_reg
[
STATUS_FIFO_ADDR_WIDTH
-
1
:
0
]];
status_fifo_rd_ptr_next
=
status_fifo_rd_ptr_reg
+
1
;
m_axi_bready_next
=
1'b0
;
end
else
begin
// wait for write completion
m_axi_bready_next
=
1'b1
;
end
end
end
always
@
(
posedge
clk
)
begin
if
(
rst
)
begin
state_reg
<=
STATE_IDLE
;
s_axis_write_desc_ready_reg
<=
1'b0
;
m_axis_write_desc_status_valid_reg
<=
1'b0
;
s_axis_write_data_tready_reg
<=
1'b0
;
m_axi_awvalid_reg
<=
1'b0
;
m_axi_bready_reg
<=
1'b0
;
save_axis_tlast_reg
<=
1'b0
;
shift_axis_extra_cycle_reg
<=
1'b0
;
status_fifo_wr_ptr_reg
<=
0
;
status_fifo_rd_ptr_reg
<=
0
;
end
else
begin
state_reg
<=
state_next
;
s_axis_write_desc_ready_reg
<=
s_axis_write_desc_ready_next
;
m_axis_write_desc_status_valid_reg
<=
m_axis_write_desc_status_valid_next
;
s_axis_write_data_tready_reg
<=
s_axis_write_data_tready_next
;
m_axi_awvalid_reg
<=
m_axi_awvalid_next
;
m_axi_bready_reg
<=
m_axi_bready_next
;
// datapath
if
(
flush_save
)
begin
save_axis_tlast_reg
<=
1'b0
;
shift_axis_extra_cycle_reg
<=
1'b0
;
end
else
if
(
transfer_in_save
)
begin
save_axis_tlast_reg
<=
s_axis_write_data_tlast
;
shift_axis_extra_cycle_reg
<=
s_axis_write_data_tlast
&
((
s_axis_write_data_tkeep
>>
(
AXIS_KEEP_WIDTH_INT
-
offset_reg
))
!=
0
);
end
if
(
status_fifo_we
)
begin
status_fifo_wr_ptr_reg
<=
status_fifo_wr_ptr_reg
+
1
;
end
status_fifo_rd_ptr_reg
<=
status_fifo_rd_ptr_next
;
end
m_axis_write_desc_status_len_reg
<=
m_axis_write_desc_status_len_next
;
m_axis_write_desc_status_tag_reg
<=
m_axis_write_desc_status_tag_next
;
m_axis_write_desc_status_id_reg
<=
m_axis_write_desc_status_id_next
;
m_axis_write_desc_status_dest_reg
<=
m_axis_write_desc_status_dest_next
;
m_axis_write_desc_status_user_reg
<=
m_axis_write_desc_status_user_next
;
m_axi_awaddr_reg
<=
m_axi_awaddr_next
;
m_axi_awlen_reg
<=
m_axi_awlen_next
;
addr_reg
<=
addr_next
;
offset_reg
<=
offset_next
;
strb_offset_mask_reg
<=
strb_offset_mask_next
;
zero_offset_reg
<=
zero_offset_next
;
last_cycle_offset_reg
<=
last_cycle_offset_next
;
length_reg
<=
length_next
;
op_word_count_reg
<=
op_word_count_next
;
tr_word_count_reg
<=
tr_word_count_next
;
input_cycle_count_reg
<=
input_cycle_count_next
;
output_cycle_count_reg
<=
output_cycle_count_next
;
input_active_reg
<=
input_active_next
;
first_cycle_reg
<=
first_cycle_next
;
input_last_cycle_reg
<=
input_last_cycle_next
;
output_last_cycle_reg
<=
output_last_cycle_next
;
last_transfer_reg
<=
last_transfer_next
;
tag_reg
<=
tag_next
;
axis_id_reg
<=
axis_id_next
;
axis_dest_reg
<=
axis_dest_next
;
axis_user_reg
<=
axis_user_next
;
if
(
flush_save
)
begin
save_axis_tkeep_reg
<=
{
AXIS_KEEP_WIDTH_INT
{
1'b0
}}
;
end
else
if
(
transfer_in_save
)
begin
save_axis_tdata_reg
<=
s_axis_write_data_tdata
;
save_axis_tkeep_reg
<=
AXIS_KEEP_ENABLE
?
s_axis_write_data_tkeep
:
{
AXIS_KEEP_WIDTH_INT
{
1'b1
}}
;
end
if
(
status_fifo_we
)
begin
status_fifo_len
[
status_fifo_wr_ptr_reg
[
STATUS_FIFO_ADDR_WIDTH
-
1
:
0
]]
<=
status_fifo_wr_len
;
status_fifo_tag
[
status_fifo_wr_ptr_reg
[
STATUS_FIFO_ADDR_WIDTH
-
1
:
0
]]
<=
status_fifo_wr_tag
;
status_fifo_id
[
status_fifo_wr_ptr_reg
[
STATUS_FIFO_ADDR_WIDTH
-
1
:
0
]]
<=
status_fifo_wr_id
;
status_fifo_dest
[
status_fifo_wr_ptr_reg
[
STATUS_FIFO_ADDR_WIDTH
-
1
:
0
]]
<=
status_fifo_wr_dest
;
status_fifo_user
[
status_fifo_wr_ptr_reg
[
STATUS_FIFO_ADDR_WIDTH
-
1
:
0
]]
<=
status_fifo_wr_user
;
status_fifo_last
[
status_fifo_wr_ptr_reg
[
STATUS_FIFO_ADDR_WIDTH
-
1
:
0
]]
<=
status_fifo_wr_last
;
status_fifo_wr_ptr_reg
<=
status_fifo_wr_ptr_reg
+
1
;
end
end
// output datapath logic
reg
[
AXI_DATA_WIDTH
-
1
:
0
]
m_axi_wdata_reg
=
{
AXI_DATA_WIDTH
{
1'b0
}}
;
reg
[
AXI_STRB_WIDTH
-
1
:
0
]
m_axi_wstrb_reg
=
{
AXI_STRB_WIDTH
{
1'b0
}}
;
reg
m_axi_wlast_reg
=
1'b0
;
reg
m_axi_wvalid_reg
=
1'b0
,
m_axi_wvalid_next
;
reg
[
AXI_DATA_WIDTH
-
1
:
0
]
temp_m_axi_wdata_reg
=
{
AXI_DATA_WIDTH
{
1'b0
}}
;
reg
[
AXI_STRB_WIDTH
-
1
:
0
]
temp_m_axi_wstrb_reg
=
{
AXI_STRB_WIDTH
{
1'b0
}}
;
reg
temp_m_axi_wlast_reg
=
1'b0
;
reg
temp_m_axi_wvalid_reg
=
1'b0
,
temp_m_axi_wvalid_next
;
// datapath control
reg
store_axi_w_int_to_output
;
reg
store_axi_w_int_to_temp
;
reg
store_axi_w_temp_to_output
;
assign
m_axi_wdata
=
m_axi_wdata_reg
;
assign
m_axi_wstrb
=
m_axi_wstrb_reg
;
assign
m_axi_wvalid
=
m_axi_wvalid_reg
;
assign
m_axi_wlast
=
m_axi_wlast_reg
;
// enable ready input next cycle if output is ready or the temp reg will not be filled on the next cycle (output reg empty or no input)
assign
m_axi_wready_int_early
=
m_axi_wready
||
(
!
temp_m_axi_wvalid_reg
&&
(
!
m_axi_wvalid_reg
||
!
m_axi_wvalid_int
));
always
@*
begin
// transfer sink ready state to source
m_axi_wvalid_next
=
m_axi_wvalid_reg
;
temp_m_axi_wvalid_next
=
temp_m_axi_wvalid_reg
;
store_axi_w_int_to_output
=
1'b0
;
store_axi_w_int_to_temp
=
1'b0
;
store_axi_w_temp_to_output
=
1'b0
;
if
(
m_axi_wready_int_reg
)
begin
// input is ready
if
(
m_axi_wready
||
!
m_axi_wvalid_reg
)
begin
// output is ready or currently not valid, transfer data to output
m_axi_wvalid_next
=
m_axi_wvalid_int
;
store_axi_w_int_to_output
=
1'b1
;
end
else
begin
// output is not ready, store input in temp
temp_m_axi_wvalid_next
=
m_axi_wvalid_int
;
store_axi_w_int_to_temp
=
1'b1
;
end
end
else
if
(
m_axi_wready
)
begin
// input is not ready, but output is ready
m_axi_wvalid_next
=
temp_m_axi_wvalid_reg
;
temp_m_axi_wvalid_next
=
1'b0
;
store_axi_w_temp_to_output
=
1'b1
;
end
end
always
@
(
posedge
clk
)
begin
if
(
rst
)
begin
m_axi_wvalid_reg
<=
1'b0
;
m_axi_wready_int_reg
<=
1'b0
;
temp_m_axi_wvalid_reg
<=
1'b0
;
end
else
begin
m_axi_wvalid_reg
<=
m_axi_wvalid_next
;
m_axi_wready_int_reg
<=
m_axi_wready_int_early
;
temp_m_axi_wvalid_reg
<=
temp_m_axi_wvalid_next
;
end
// datapath
if
(
store_axi_w_int_to_output
)
begin
m_axi_wdata_reg
<=
m_axi_wdata_int
;
m_axi_wstrb_reg
<=
m_axi_wstrb_int
;
m_axi_wlast_reg
<=
m_axi_wlast_int
;
end
else
if
(
store_axi_w_temp_to_output
)
begin
m_axi_wdata_reg
<=
temp_m_axi_wdata_reg
;
m_axi_wstrb_reg
<=
temp_m_axi_wstrb_reg
;
m_axi_wlast_reg
<=
temp_m_axi_wlast_reg
;
end
if
(
store_axi_w_int_to_temp
)
begin
temp_m_axi_wdata_reg
<=
m_axi_wdata_int
;
temp_m_axi_wstrb_reg
<=
m_axi_wstrb_int
;
temp_m_axi_wlast_reg
<=
m_axi_wlast_int
;
end
end
endmodule
corundum/lib/axi/rtl/axi_dp_ram.v
0 → 100644
View file @
738c1fef
/*
Copyright (c) 2019 Alex Forencich
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.
*/
// Language: Verilog 2001
`timescale
1
ns
/
1
ps
/*
* AXI4 dual port RAM
*/
module
axi_dp_ram
#
(
// Width of data bus in bits
parameter
DATA_WIDTH
=
32
,
// Width of address bus in bits
parameter
ADDR_WIDTH
=
16
,
// Width of wstrb (width of data bus in words)
parameter
STRB_WIDTH
=
(
DATA_WIDTH
/
8
),
// Width of ID signal
parameter
ID_WIDTH
=
8
,
// Extra pipeline register on output port A
parameter
A_PIPELINE_OUTPUT
=
0
,
// Extra pipeline register on output port B
parameter
B_PIPELINE_OUTPUT
=
0
,
// Interleave read and write burst cycles on port A
parameter
A_INTERLEAVE
=
0
,
// Interleave read and write burst cycles on port B
parameter
B_INTERLEAVE
=
0
)
(
input
wire
a_clk
,
input
wire
a_rst
,
input
wire
b_clk
,
input
wire
b_rst
,
input
wire
[
ID_WIDTH
-
1
:
0
]
s_axi_a_awid
,
input
wire
[
ADDR_WIDTH
-
1
:
0
]
s_axi_a_awaddr
,
input
wire
[
7
:
0
]
s_axi_a_awlen
,
input
wire
[
2
:
0
]
s_axi_a_awsize
,
input
wire
[
1
:
0
]
s_axi_a_awburst
,
input
wire
s_axi_a_awlock
,
input
wire
[
3
:
0
]
s_axi_a_awcache
,
input
wire
[
2
:
0
]
s_axi_a_awprot
,
input
wire
s_axi_a_awvalid
,
output
wire
s_axi_a_awready
,
input
wire
[
DATA_WIDTH
-
1
:
0
]
s_axi_a_wdata
,
input
wire
[
STRB_WIDTH
-
1
:
0
]
s_axi_a_wstrb
,
input
wire
s_axi_a_wlast
,
input
wire
s_axi_a_wvalid
,
output
wire
s_axi_a_wready
,
output
wire
[
ID_WIDTH
-
1
:
0
]
s_axi_a_bid
,
output
wire
[
1
:
0
]
s_axi_a_bresp
,
output
wire
s_axi_a_bvalid
,
input
wire
s_axi_a_bready
,
input
wire
[
ID_WIDTH
-
1
:
0
]
s_axi_a_arid
,
input
wire
[
ADDR_WIDTH
-
1
:
0
]
s_axi_a_araddr
,
input
wire
[
7
:
0
]
s_axi_a_arlen
,
input
wire
[
2
:
0
]
s_axi_a_arsize
,
input
wire
[
1
:
0
]
s_axi_a_arburst
,
input
wire
s_axi_a_arlock
,
input
wire
[
3
:
0
]
s_axi_a_arcache
,
input
wire
[
2
:
0
]
s_axi_a_arprot
,
input
wire
s_axi_a_arvalid
,
output
wire
s_axi_a_arready
,
output
wire
[
ID_WIDTH
-
1
:
0
]
s_axi_a_rid
,
output
wire
[
DATA_WIDTH
-
1
:
0
]
s_axi_a_rdata
,
output
wire
[
1
:
0
]
s_axi_a_rresp
,
output
wire
s_axi_a_rlast
,
output
wire
s_axi_a_rvalid
,
input
wire
s_axi_a_rready
,
input
wire
[
ID_WIDTH
-
1
:
0
]
s_axi_b_awid
,
input
wire
[
ADDR_WIDTH
-
1
:
0
]
s_axi_b_awaddr
,
input
wire
[
7
:
0
]
s_axi_b_awlen
,
input
wire
[
2
:
0
]
s_axi_b_awsize
,
input
wire
[
1
:
0
]
s_axi_b_awburst
,
input
wire
s_axi_b_awlock
,
input
wire
[
3
:
0
]
s_axi_b_awcache
,
input
wire
[
2
:
0
]
s_axi_b_awprot
,
input
wire
s_axi_b_awvalid
,
output
wire
s_axi_b_awready
,
input
wire
[
DATA_WIDTH
-
1
:
0
]
s_axi_b_wdata
,
input
wire
[
STRB_WIDTH
-
1
:
0
]
s_axi_b_wstrb
,
input
wire
s_axi_b_wlast
,
input
wire
s_axi_b_wvalid
,
output
wire
s_axi_b_wready
,
output
wire
[
ID_WIDTH
-
1
:
0
]
s_axi_b_bid
,
output
wire
[
1
:
0
]
s_axi_b_bresp
,
output
wire
s_axi_b_bvalid
,
input
wire
s_axi_b_bready
,
input
wire
[
ID_WIDTH
-
1
:
0
]
s_axi_b_arid
,
input
wire
[
ADDR_WIDTH
-
1
:
0
]
s_axi_b_araddr
,
input
wire
[
7
:
0
]
s_axi_b_arlen
,
input
wire
[
2
:
0
]
s_axi_b_arsize
,
input
wire
[
1
:
0
]
s_axi_b_arburst
,
input
wire
s_axi_b_arlock
,
input
wire
[
3
:
0
]
s_axi_b_arcache
,
input
wire
[
2
:
0
]
s_axi_b_arprot
,
input
wire
s_axi_b_arvalid
,
output
wire
s_axi_b_arready
,
output
wire
[
ID_WIDTH
-
1
:
0
]
s_axi_b_rid
,
output
wire
[
DATA_WIDTH
-
1
:
0
]
s_axi_b_rdata
,
output
wire
[
1
:
0
]
s_axi_b_rresp
,
output
wire
s_axi_b_rlast
,
output
wire
s_axi_b_rvalid
,
input
wire
s_axi_b_rready
);
parameter
VALID_ADDR_WIDTH
=
ADDR_WIDTH
-
$
clog2
(
STRB_WIDTH
);
parameter
WORD_WIDTH
=
STRB_WIDTH
;
parameter
WORD_SIZE
=
DATA_WIDTH
/
WORD_WIDTH
;
// bus width assertions
initial
begin
if
(
WORD_SIZE
*
STRB_WIDTH
!=
DATA_WIDTH
)
begin
$
error
(
"Error: AXI data width not evenly divisble (instance %m)"
);
$
finish
;
end
if
(
2
**
$
clog2
(
WORD_WIDTH
)
!=
WORD_WIDTH
)
begin
$
error
(
"Error: AXI word width must be even power of two (instance %m)"
);
$
finish
;
end
end
wire
[
ID_WIDTH
-
1
:
0
]
ram_a_cmd_id
;
wire
[
ADDR_WIDTH
-
1
:
0
]
ram_a_cmd_addr
;
wire
[
DATA_WIDTH
-
1
:
0
]
ram_a_cmd_wr_data
;
wire
[
STRB_WIDTH
-
1
:
0
]
ram_a_cmd_wr_strb
;
wire
ram_a_cmd_wr_en
;
wire
ram_a_cmd_rd_en
;
wire
ram_a_cmd_last
;
reg
ram_a_cmd_ready_reg
=
1'b1
;
reg
[
ID_WIDTH
-
1
:
0
]
ram_a_rd_resp_id_reg
=
{
ID_WIDTH
{
1'b0
}}
;
reg
[
DATA_WIDTH
-
1
:
0
]
ram_a_rd_resp_data_reg
=
{
DATA_WIDTH
{
1'b0
}}
;
reg
ram_a_rd_resp_last_reg
=
1'b0
;
reg
ram_a_rd_resp_valid_reg
=
1'b0
;
wire
ram_a_rd_resp_ready
;
wire
[
ID_WIDTH
-
1
:
0
]
ram_b_cmd_id
;
wire
[
ADDR_WIDTH
-
1
:
0
]
ram_b_cmd_addr
;
wire
[
DATA_WIDTH
-
1
:
0
]
ram_b_cmd_wr_data
;
wire
[
STRB_WIDTH
-
1
:
0
]
ram_b_cmd_wr_strb
;
wire
ram_b_cmd_wr_en
;
wire
ram_b_cmd_rd_en
;
wire
ram_b_cmd_last
;
reg
ram_b_cmd_ready_reg
=
1'b1
;
reg
[
ID_WIDTH
-
1
:
0
]
ram_b_rd_resp_id_reg
=
{
ID_WIDTH
{
1'b0
}}
;
reg
[
DATA_WIDTH
-
1
:
0
]
ram_b_rd_resp_data_reg
=
{
DATA_WIDTH
{
1'b0
}}
;
reg
ram_b_rd_resp_last_reg
=
1'b0
;
reg
ram_b_rd_resp_valid_reg
=
1'b0
;
wire
ram_b_rd_resp_ready
;
axi_ram_wr_rd_if
#(
.
DATA_WIDTH
(
DATA_WIDTH
),
.
ADDR_WIDTH
(
ADDR_WIDTH
),
.
STRB_WIDTH
(
STRB_WIDTH
),
.
ID_WIDTH
(
ID_WIDTH
),
.
AWUSER_ENABLE
(
0
),
.
WUSER_ENABLE
(
0
),
.
BUSER_ENABLE
(
0
),
.
ARUSER_ENABLE
(
0
),
.
RUSER_ENABLE
(
0
),
.
PIPELINE_OUTPUT
(
A_PIPELINE_OUTPUT
),
.
INTERLEAVE
(
A_INTERLEAVE
)
)
a_if
(
.
clk
(
a_clk
),
.
rst
(
a_rst
),
/*
* AXI slave interface
*/
.
s_axi_awid
(
s_axi_a_awid
),
.
s_axi_awaddr
(
s_axi_a_awaddr
),
.
s_axi_awlen
(
s_axi_a_awlen
),
.
s_axi_awsize
(
s_axi_a_awsize
),
.
s_axi_awburst
(
s_axi_a_awburst
),
.
s_axi_awlock
(
s_axi_a_awlock
),
.
s_axi_awcache
(
s_axi_a_awcache
),
.
s_axi_awprot
(
s_axi_a_awprot
),
.
s_axi_awqos
(
4'd0
),
.
s_axi_awregion
(
4'd0
),
.
s_axi_awuser
(
0
),
.
s_axi_awvalid
(
s_axi_a_awvalid
),
.
s_axi_awready
(
s_axi_a_awready
),
.
s_axi_wdata
(
s_axi_a_wdata
),
.
s_axi_wstrb
(
s_axi_a_wstrb
),
.
s_axi_wlast
(
s_axi_a_wlast
),
.
s_axi_wuser
(
0
),
.
s_axi_wvalid
(
s_axi_a_wvalid
),
.
s_axi_wready
(
s_axi_a_wready
),
.
s_axi_bid
(
s_axi_a_bid
),
.
s_axi_bresp
(
s_axi_a_bresp
),
.
s_axi_buser
(),
.
s_axi_bvalid
(
s_axi_a_bvalid
),
.
s_axi_bready
(
s_axi_a_bready
),
.
s_axi_arid
(
s_axi_a_arid
),
.
s_axi_araddr
(
s_axi_a_araddr
),
.
s_axi_arlen
(
s_axi_a_arlen
),
.
s_axi_arsize
(
s_axi_a_arsize
),
.
s_axi_arburst
(
s_axi_a_arburst
),
.
s_axi_arlock
(
s_axi_a_arlock
),
.
s_axi_arcache
(
s_axi_a_arcache
),
.
s_axi_arprot
(
s_axi_a_arprot
),
.
s_axi_arqos
(
4'd0
),
.
s_axi_arregion
(
4'd0
),
.
s_axi_aruser
(
0
),
.
s_axi_arvalid
(
s_axi_a_arvalid
),
.
s_axi_arready
(
s_axi_a_arready
),
.
s_axi_rid
(
s_axi_a_rid
),
.
s_axi_rdata
(
s_axi_a_rdata
),
.
s_axi_rresp
(
s_axi_a_rresp
),
.
s_axi_rlast
(
s_axi_a_rlast
),
.
s_axi_ruser
(),
.
s_axi_rvalid
(
s_axi_a_rvalid
),
.
s_axi_rready
(
s_axi_a_rready
),
/*
* RAM interface
*/
.
ram_cmd_id
(
ram_a_cmd_id
),
.
ram_cmd_addr
(
ram_a_cmd_addr
),
.
ram_cmd_lock
(),
.
ram_cmd_cache
(),
.
ram_cmd_prot
(),
.
ram_cmd_qos
(),
.
ram_cmd_region
(),
.
ram_cmd_auser
(),
.
ram_cmd_wr_data
(
ram_a_cmd_wr_data
),
.
ram_cmd_wr_strb
(
ram_a_cmd_wr_strb
),
.
ram_cmd_wr_user
(),
.
ram_cmd_wr_en
(
ram_a_cmd_wr_en
),
.
ram_cmd_rd_en
(
ram_a_cmd_rd_en
),
.
ram_cmd_last
(
ram_a_cmd_last
),
.
ram_cmd_ready
(
ram_a_cmd_ready_reg
),
.
ram_rd_resp_id
(
ram_a_rd_resp_id_reg
),
.
ram_rd_resp_data
(
ram_a_rd_resp_data_reg
),
.
ram_rd_resp_last
(
ram_a_rd_resp_last_reg
),
.
ram_rd_resp_user
(
0
),
.
ram_rd_resp_valid
(
ram_a_rd_resp_valid_reg
),
.
ram_rd_resp_ready
(
ram_a_rd_resp_ready
)
);
axi_ram_wr_rd_if
#(
.
DATA_WIDTH
(
DATA_WIDTH
),
.
ADDR_WIDTH
(
ADDR_WIDTH
),
.
STRB_WIDTH
(
STRB_WIDTH
),
.
ID_WIDTH
(
ID_WIDTH
),
.
AWUSER_ENABLE
(
0
),
.
WUSER_ENABLE
(
0
),
.
BUSER_ENABLE
(
0
),
.
ARUSER_ENABLE
(
0
),
.
RUSER_ENABLE
(
0
),
.
PIPELINE_OUTPUT
(
B_PIPELINE_OUTPUT
),
.
INTERLEAVE
(
B_INTERLEAVE
)
)
b_if
(
.
clk
(
b_clk
),
.
rst
(
b_rst
),
/*
* AXI slave interface
*/
.
s_axi_awid
(
s_axi_b_awid
),
.
s_axi_awaddr
(
s_axi_b_awaddr
),
.
s_axi_awlen
(
s_axi_b_awlen
),
.
s_axi_awsize
(
s_axi_b_awsize
),
.
s_axi_awburst
(
s_axi_b_awburst
),
.
s_axi_awlock
(
s_axi_b_awlock
),
.
s_axi_awcache
(
s_axi_b_awcache
),
.
s_axi_awprot
(
s_axi_b_awprot
),
.
s_axi_awqos
(
4'd0
),
.
s_axi_awregion
(
4'd0
),
.
s_axi_awuser
(
0
),
.
s_axi_awvalid
(
s_axi_b_awvalid
),
.
s_axi_awready
(
s_axi_b_awready
),
.
s_axi_wdata
(
s_axi_b_wdata
),
.
s_axi_wstrb
(
s_axi_b_wstrb
),
.
s_axi_wlast
(
s_axi_b_wlast
),
.
s_axi_wuser
(
0
),
.
s_axi_wvalid
(
s_axi_b_wvalid
),
.
s_axi_wready
(
s_axi_b_wready
),
.
s_axi_bid
(
s_axi_b_bid
),
.
s_axi_bresp
(
s_axi_b_bresp
),
.
s_axi_buser
(),
.
s_axi_bvalid
(
s_axi_b_bvalid
),
.
s_axi_bready
(
s_axi_b_bready
),
.
s_axi_arid
(
s_axi_b_arid
),
.
s_axi_araddr
(
s_axi_b_araddr
),
.
s_axi_arlen
(
s_axi_b_arlen
),
.
s_axi_arsize
(
s_axi_b_arsize
),
.
s_axi_arburst
(
s_axi_b_arburst
),
.
s_axi_arlock
(
s_axi_b_arlock
),
.
s_axi_arcache
(
s_axi_b_arcache
),
.
s_axi_arprot
(
s_axi_b_arprot
),
.
s_axi_arqos
(
4'd0
),
.
s_axi_arregion
(
4'd0
),
.
s_axi_aruser
(
0
),
.
s_axi_arvalid
(
s_axi_b_arvalid
),
.
s_axi_arready
(
s_axi_b_arready
),
.
s_axi_rid
(
s_axi_b_rid
),
.
s_axi_rdata
(
s_axi_b_rdata
),
.
s_axi_rresp
(
s_axi_b_rresp
),
.
s_axi_rlast
(
s_axi_b_rlast
),
.
s_axi_ruser
(),
.
s_axi_rvalid
(
s_axi_b_rvalid
),
.
s_axi_rready
(
s_axi_b_rready
),
/*
* RAM interface
*/
.
ram_cmd_id
(
ram_b_cmd_id
),
.
ram_cmd_addr
(
ram_b_cmd_addr
),
.
ram_cmd_lock
(),
.
ram_cmd_cache
(),
.
ram_cmd_prot
(),
.
ram_cmd_qos
(),
.
ram_cmd_region
(),
.
ram_cmd_auser
(),
.
ram_cmd_wr_data
(
ram_b_cmd_wr_data
),
.
ram_cmd_wr_strb
(
ram_b_cmd_wr_strb
),
.
ram_cmd_wr_user
(),
.
ram_cmd_wr_en
(
ram_b_cmd_wr_en
),
.
ram_cmd_rd_en
(
ram_b_cmd_rd_en
),
.
ram_cmd_last
(
ram_b_cmd_last
),
.
ram_cmd_ready
(
ram_b_cmd_ready_reg
),
.
ram_rd_resp_id
(
ram_b_rd_resp_id_reg
),
.
ram_rd_resp_data
(
ram_b_rd_resp_data_reg
),
.
ram_rd_resp_last
(
ram_b_rd_resp_last_reg
),
.
ram_rd_resp_user
(
0
),
.
ram_rd_resp_valid
(
ram_b_rd_resp_valid_reg
),
.
ram_rd_resp_ready
(
ram_b_rd_resp_ready
)
);
// (* RAM_STYLE="BLOCK" *)
reg
[
DATA_WIDTH
-
1
:
0
]
mem
[(
2
**
VALID_ADDR_WIDTH
)
-
1
:
0
];
wire
[
VALID_ADDR_WIDTH
-
1
:
0
]
addr_a_valid
=
ram_a_cmd_addr
>>
(
ADDR_WIDTH
-
VALID_ADDR_WIDTH
);
wire
[
VALID_ADDR_WIDTH
-
1
:
0
]
addr_b_valid
=
ram_b_cmd_addr
>>
(
ADDR_WIDTH
-
VALID_ADDR_WIDTH
);
integer
i
,
j
;
initial
begin
// two nested loops for smaller number of iterations per loop
// workaround for synthesizer complaints about large loop counts
for
(
i
=
0
;
i
<
2
**
ADDR_WIDTH
;
i
=
i
+
2
**
(
ADDR_WIDTH
/
2
))
begin
for
(
j
=
i
;
j
<
i
+
2
**
(
ADDR_WIDTH
/
2
);
j
=
j
+
1
)
begin
mem
[
j
]
=
0
;
end
end
end
always
@
(
posedge
a_clk
)
begin
ram_a_rd_resp_valid_reg
<=
ram_a_rd_resp_valid_reg
&&
!
ram_a_rd_resp_ready
;
ram_a_cmd_ready_reg
<=
!
ram_a_rd_resp_valid_reg
||
ram_a_rd_resp_ready
;
if
(
ram_a_cmd_ready_reg
&&
ram_a_cmd_rd_en
)
begin
ram_a_rd_resp_id_reg
<=
ram_a_cmd_id
;
ram_a_rd_resp_data_reg
<=
mem
[
addr_a_valid
];
ram_a_rd_resp_last_reg
<=
ram_a_cmd_last
;
ram_a_rd_resp_valid_reg
<=
1'b1
;
ram_a_cmd_ready_reg
<=
ram_a_rd_resp_ready
;
end
else
if
(
ram_a_cmd_ready_reg
&&
ram_a_cmd_wr_en
)
begin
for
(
i
=
0
;
i
<
WORD_WIDTH
;
i
=
i
+
1
)
begin
if
(
ram_a_cmd_wr_strb
[
i
])
begin
mem
[
addr_a_valid
][
WORD_SIZE
*
i
+:
WORD_SIZE
]
<=
ram_a_cmd_wr_data
[
WORD_SIZE
*
i
+:
WORD_SIZE
];
end
end
end
if
(
a_rst
)
begin
ram_a_cmd_ready_reg
<=
1'b1
;
ram_a_rd_resp_valid_reg
<=
1'b0
;
end
end
always
@
(
posedge
b_clk
)
begin
ram_b_rd_resp_valid_reg
<=
ram_b_rd_resp_valid_reg
&&
!
ram_b_rd_resp_ready
;
ram_b_cmd_ready_reg
<=
!
ram_b_rd_resp_valid_reg
||
ram_b_rd_resp_ready
;
if
(
ram_b_cmd_ready_reg
&&
ram_b_cmd_rd_en
)
begin
ram_b_rd_resp_id_reg
<=
ram_b_cmd_id
;
ram_b_rd_resp_data_reg
<=
mem
[
addr_b_valid
];
ram_b_rd_resp_last_reg
<=
ram_b_cmd_last
;
ram_b_rd_resp_valid_reg
<=
1'b1
;
ram_b_cmd_ready_reg
<=
ram_b_rd_resp_ready
;
end
else
if
(
ram_b_cmd_ready_reg
&&
ram_b_cmd_wr_en
)
begin
for
(
i
=
0
;
i
<
WORD_WIDTH
;
i
=
i
+
1
)
begin
if
(
ram_b_cmd_wr_strb
[
i
])
begin
mem
[
addr_b_valid
][
WORD_SIZE
*
i
+:
WORD_SIZE
]
<=
ram_b_cmd_wr_data
[
WORD_SIZE
*
i
+:
WORD_SIZE
];
end
end
end
if
(
b_rst
)
begin
ram_a_cmd_ready_reg
<=
1'b1
;
ram_b_rd_resp_valid_reg
<=
1'b0
;
end
end
endmodule
corundum/lib/axi/rtl/axi_fifo.v
0 → 100644
View file @
738c1fef
/*
Copyright (c) 2018 Alex Forencich
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.
*/
// Language: Verilog 2001
`timescale
1
ns
/
1
ps
/*
* AXI4 FIFO
*/
module
axi_fifo
#
(
// Width of data bus in bits
parameter
DATA_WIDTH
=
32
,
// Width of address bus in bits
parameter
ADDR_WIDTH
=
32
,
// Width of wstrb (width of data bus in words)
parameter
STRB_WIDTH
=
(
DATA_WIDTH
/
8
),
// Width of ID signal
parameter
ID_WIDTH
=
8
,
// Propagate awuser signal
parameter
AWUSER_ENABLE
=
0
,
// Width of awuser signal
parameter
AWUSER_WIDTH
=
1
,
// Propagate wuser signal
parameter
WUSER_ENABLE
=
0
,
// Width of wuser signal
parameter
WUSER_WIDTH
=
1
,
// Propagate buser signal
parameter
BUSER_ENABLE
=
0
,
// Width of buser signal
parameter
BUSER_WIDTH
=
1
,
// Propagate aruser signal
parameter
ARUSER_ENABLE
=
0
,
// Width of aruser signal
parameter
ARUSER_WIDTH
=
1
,
// Propagate ruser signal
parameter
RUSER_ENABLE
=
0
,
// Width of ruser signal
parameter
RUSER_WIDTH
=
1
,
// Write data FIFO depth (cycles)
parameter
WRITE_FIFO_DEPTH
=
32
,
// Read data FIFO depth (cycles)
parameter
READ_FIFO_DEPTH
=
32
,
// Hold write address until write data in FIFO, if possible
parameter
WRITE_FIFO_DELAY
=
0
,
// Hold read address until space available in FIFO for data, if possible
parameter
READ_FIFO_DELAY
=
0
)
(
input
wire
clk
,
input
wire
rst
,
/*
* AXI slave interface
*/
input
wire
[
ID_WIDTH
-
1
:
0
]
s_axi_awid
,
input
wire
[
ADDR_WIDTH
-
1
:
0
]
s_axi_awaddr
,
input
wire
[
7
:
0
]
s_axi_awlen
,
input
wire
[
2
:
0
]
s_axi_awsize
,
input
wire
[
1
:
0
]
s_axi_awburst
,
input
wire
s_axi_awlock
,
input
wire
[
3
:
0
]
s_axi_awcache
,
input
wire
[
2
:
0
]
s_axi_awprot
,
input
wire
[
3
:
0
]
s_axi_awqos
,
input
wire
[
3
:
0
]
s_axi_awregion
,
input
wire
[
AWUSER_WIDTH
-
1
:
0
]
s_axi_awuser
,
input
wire
s_axi_awvalid
,
output
wire
s_axi_awready
,
input
wire
[
DATA_WIDTH
-
1
:
0
]
s_axi_wdata
,
input
wire
[
STRB_WIDTH
-
1
:
0
]
s_axi_wstrb
,
input
wire
s_axi_wlast
,
input
wire
[
WUSER_WIDTH
-
1
:
0
]
s_axi_wuser
,
input
wire
s_axi_wvalid
,
output
wire
s_axi_wready
,
output
wire
[
ID_WIDTH
-
1
:
0
]
s_axi_bid
,
output
wire
[
1
:
0
]
s_axi_bresp
,
output
wire
[
BUSER_WIDTH
-
1
:
0
]
s_axi_buser
,
output
wire
s_axi_bvalid
,
input
wire
s_axi_bready
,
input
wire
[
ID_WIDTH
-
1
:
0
]
s_axi_arid
,
input
wire
[
ADDR_WIDTH
-
1
:
0
]
s_axi_araddr
,
input
wire
[
7
:
0
]
s_axi_arlen
,
input
wire
[
2
:
0
]
s_axi_arsize
,
input
wire
[
1
:
0
]
s_axi_arburst
,
input
wire
s_axi_arlock
,
input
wire
[
3
:
0
]
s_axi_arcache
,
input
wire
[
2
:
0
]
s_axi_arprot
,
input
wire
[
3
:
0
]
s_axi_arqos
,
input
wire
[
3
:
0
]
s_axi_arregion
,
input
wire
[
ARUSER_WIDTH
-
1
:
0
]
s_axi_aruser
,
input
wire
s_axi_arvalid
,
output
wire
s_axi_arready
,
output
wire
[
ID_WIDTH
-
1
:
0
]
s_axi_rid
,
output
wire
[
DATA_WIDTH
-
1
:
0
]
s_axi_rdata
,
output
wire
[
1
:
0
]
s_axi_rresp
,
output
wire
s_axi_rlast
,
output
wire
[
RUSER_WIDTH
-
1
:
0
]
s_axi_ruser
,
output
wire
s_axi_rvalid
,
input
wire
s_axi_rready
,
/*
* AXI master interface
*/
output
wire
[
ID_WIDTH
-
1
:
0
]
m_axi_awid
,
output
wire
[
ADDR_WIDTH
-
1
:
0
]
m_axi_awaddr
,
output
wire
[
7
:
0
]
m_axi_awlen
,
output
wire
[
2
:
0
]
m_axi_awsize
,
output
wire
[
1
:
0
]
m_axi_awburst
,
output
wire
m_axi_awlock
,
output
wire
[
3
:
0
]
m_axi_awcache
,
output
wire
[
2
:
0
]
m_axi_awprot
,
output
wire
[
3
:
0
]
m_axi_awqos
,
output
wire
[
3
:
0
]
m_axi_awregion
,
output
wire
[
AWUSER_WIDTH
-
1
:
0
]
m_axi_awuser
,
output
wire
m_axi_awvalid
,
input
wire
m_axi_awready
,
output
wire
[
DATA_WIDTH
-
1
:
0
]
m_axi_wdata
,
output
wire
[
STRB_WIDTH
-
1
:
0
]
m_axi_wstrb
,
output
wire
m_axi_wlast
,
output
wire
[
WUSER_WIDTH
-
1
:
0
]
m_axi_wuser
,
output
wire
m_axi_wvalid
,
input
wire
m_axi_wready
,
input
wire
[
ID_WIDTH
-
1
:
0
]
m_axi_bid
,
input
wire
[
1
:
0
]
m_axi_bresp
,
input
wire
[
BUSER_WIDTH
-
1
:
0
]
m_axi_buser
,
input
wire
m_axi_bvalid
,
output
wire
m_axi_bready
,
output
wire
[
ID_WIDTH
-
1
:
0
]
m_axi_arid
,
output
wire
[
ADDR_WIDTH
-
1
:
0
]
m_axi_araddr
,
output
wire
[
7
:
0
]
m_axi_arlen
,
output
wire
[
2
:
0
]
m_axi_arsize
,
output
wire
[
1
:
0
]
m_axi_arburst
,
output
wire
m_axi_arlock
,
output
wire
[
3
:
0
]
m_axi_arcache
,
output
wire
[
2
:
0
]
m_axi_arprot
,
output
wire
[
3
:
0
]
m_axi_arqos
,
output
wire
[
3
:
0
]
m_axi_arregion
,
output
wire
[
ARUSER_WIDTH
-
1
:
0
]
m_axi_aruser
,
output
wire
m_axi_arvalid
,
input
wire
m_axi_arready
,
input
wire
[
ID_WIDTH
-
1
:
0
]
m_axi_rid
,
input
wire
[
DATA_WIDTH
-
1
:
0
]
m_axi_rdata
,
input
wire
[
1
:
0
]
m_axi_rresp
,
input
wire
m_axi_rlast
,
input
wire
[
RUSER_WIDTH
-
1
:
0
]
m_axi_ruser
,
input
wire
m_axi_rvalid
,
output
wire
m_axi_rready
);
axi_fifo_wr
#(
.
DATA_WIDTH
(
DATA_WIDTH
),
.
ADDR_WIDTH
(
ADDR_WIDTH
),
.
STRB_WIDTH
(
STRB_WIDTH
),
.
ID_WIDTH
(
ID_WIDTH
),
.
AWUSER_ENABLE
(
AWUSER_ENABLE
),
.
AWUSER_WIDTH
(
AWUSER_WIDTH
),
.
WUSER_ENABLE
(
WUSER_ENABLE
),
.
WUSER_WIDTH
(
WUSER_WIDTH
),
.
BUSER_ENABLE
(
BUSER_ENABLE
),
.
BUSER_WIDTH
(
BUSER_WIDTH
),
.
FIFO_DEPTH
(
WRITE_FIFO_DEPTH
),
.
FIFO_DELAY
(
WRITE_FIFO_DELAY
)
)
axi_fifo_wr_inst
(
.
clk
(
clk
),
.
rst
(
rst
),
/*
* AXI slave interface
*/
.
s_axi_awid
(
s_axi_awid
),
.
s_axi_awaddr
(
s_axi_awaddr
),
.
s_axi_awlen
(
s_axi_awlen
),
.
s_axi_awsize
(
s_axi_awsize
),
.
s_axi_awburst
(
s_axi_awburst
),
.
s_axi_awlock
(
s_axi_awlock
),
.
s_axi_awcache
(
s_axi_awcache
),
.
s_axi_awprot
(
s_axi_awprot
),
.
s_axi_awqos
(
s_axi_awqos
),
.
s_axi_awregion
(
s_axi_awregion
),
.
s_axi_awuser
(
s_axi_awuser
),
.
s_axi_awvalid
(
s_axi_awvalid
),
.
s_axi_awready
(
s_axi_awready
),
.
s_axi_wdata
(
s_axi_wdata
),
.
s_axi_wstrb
(
s_axi_wstrb
),
.
s_axi_wlast
(
s_axi_wlast
),
.
s_axi_wuser
(
s_axi_wuser
),
.
s_axi_wvalid
(
s_axi_wvalid
),
.
s_axi_wready
(
s_axi_wready
),
.
s_axi_bid
(
s_axi_bid
),
.
s_axi_bresp
(
s_axi_bresp
),
.
s_axi_buser
(
s_axi_buser
),
.
s_axi_bvalid
(
s_axi_bvalid
),
.
s_axi_bready
(
s_axi_bready
),
/*
* AXI master interface
*/
.
m_axi_awid
(
m_axi_awid
),
.
m_axi_awaddr
(
m_axi_awaddr
),
.
m_axi_awlen
(
m_axi_awlen
),
.
m_axi_awsize
(
m_axi_awsize
),
.
m_axi_awburst
(
m_axi_awburst
),
.
m_axi_awlock
(
m_axi_awlock
),
.
m_axi_awcache
(
m_axi_awcache
),
.
m_axi_awprot
(
m_axi_awprot
),
.
m_axi_awqos
(
m_axi_awqos
),
.
m_axi_awregion
(
m_axi_awregion
),
.
m_axi_awuser
(
m_axi_awuser
),
.
m_axi_awvalid
(
m_axi_awvalid
),
.
m_axi_awready
(
m_axi_awready
),
.
m_axi_wdata
(
m_axi_wdata
),
.
m_axi_wstrb
(
m_axi_wstrb
),
.
m_axi_wlast
(
m_axi_wlast
),
.
m_axi_wuser
(
m_axi_wuser
),
.
m_axi_wvalid
(
m_axi_wvalid
),
.
m_axi_wready
(
m_axi_wready
),
.
m_axi_bid
(
m_axi_bid
),
.
m_axi_bresp
(
m_axi_bresp
),
.
m_axi_buser
(
m_axi_buser
),
.
m_axi_bvalid
(
m_axi_bvalid
),
.
m_axi_bready
(
m_axi_bready
)
);
axi_fifo_rd
#(
.
DATA_WIDTH
(
DATA_WIDTH
),
.
ADDR_WIDTH
(
ADDR_WIDTH
),
.
STRB_WIDTH
(
STRB_WIDTH
),
.
ID_WIDTH
(
ID_WIDTH
),
.
ARUSER_ENABLE
(
ARUSER_ENABLE
),
.
ARUSER_WIDTH
(
ARUSER_WIDTH
),
.
RUSER_ENABLE
(
RUSER_ENABLE
),
.
RUSER_WIDTH
(
RUSER_WIDTH
),
.
FIFO_DEPTH
(
READ_FIFO_DEPTH
),
.
FIFO_DELAY
(
READ_FIFO_DELAY
)
)
axi_fifo_rd_inst
(
.
clk
(
clk
),
.
rst
(
rst
),
/*
* AXI slave interface
*/
.
s_axi_arid
(
s_axi_arid
),
.
s_axi_araddr
(
s_axi_araddr
),
.
s_axi_arlen
(
s_axi_arlen
),
.
s_axi_arsize
(
s_axi_arsize
),
.
s_axi_arburst
(
s_axi_arburst
),
.
s_axi_arlock
(
s_axi_arlock
),
.
s_axi_arcache
(
s_axi_arcache
),
.
s_axi_arprot
(
s_axi_arprot
),
.
s_axi_arqos
(
s_axi_arqos
),
.
s_axi_arregion
(
s_axi_arregion
),
.
s_axi_aruser
(
s_axi_aruser
),
.
s_axi_arvalid
(
s_axi_arvalid
),
.
s_axi_arready
(
s_axi_arready
),
.
s_axi_rid
(
s_axi_rid
),
.
s_axi_rdata
(
s_axi_rdata
),
.
s_axi_rresp
(
s_axi_rresp
),
.
s_axi_rlast
(
s_axi_rlast
),
.
s_axi_ruser
(
s_axi_ruser
),
.
s_axi_rvalid
(
s_axi_rvalid
),
.
s_axi_rready
(
s_axi_rready
),
/*
* AXI master interface
*/
.
m_axi_arid
(
m_axi_arid
),
.
m_axi_araddr
(
m_axi_araddr
),
.
m_axi_arlen
(
m_axi_arlen
),
.
m_axi_arsize
(
m_axi_arsize
),
.
m_axi_arburst
(
m_axi_arburst
),
.
m_axi_arlock
(
m_axi_arlock
),
.
m_axi_arcache
(
m_axi_arcache
),
.
m_axi_arprot
(
m_axi_arprot
),
.
m_axi_arqos
(
m_axi_arqos
),
.
m_axi_arregion
(
m_axi_arregion
),
.
m_axi_aruser
(
m_axi_aruser
),
.
m_axi_arvalid
(
m_axi_arvalid
),
.
m_axi_arready
(
m_axi_arready
),
.
m_axi_rid
(
m_axi_rid
),
.
m_axi_rdata
(
m_axi_rdata
),
.
m_axi_rresp
(
m_axi_rresp
),
.
m_axi_rlast
(
m_axi_rlast
),
.
m_axi_ruser
(
m_axi_ruser
),
.
m_axi_rvalid
(
m_axi_rvalid
),
.
m_axi_rready
(
m_axi_rready
)
);
endmodule
corundum/lib/axi/rtl/axi_fifo_rd.v
0 → 100644
View file @
738c1fef
/*
Copyright (c) 2018 Alex Forencich
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.
*/
// Language: Verilog 2001
`timescale
1
ns
/
1
ps
/*
* AXI4 FIFO (read)
*/
module
axi_fifo_rd
#
(
// Width of data bus in bits
parameter
DATA_WIDTH
=
32
,
// Width of address bus in bits
parameter
ADDR_WIDTH
=
32
,
// Width of wstrb (width of data bus in words)
parameter
STRB_WIDTH
=
(
DATA_WIDTH
/
8
),
// Width of ID signal
parameter
ID_WIDTH
=
8
,
// Propagate aruser signal
parameter
ARUSER_ENABLE
=
0
,
// Width of aruser signal
parameter
ARUSER_WIDTH
=
1
,
// Propagate ruser signal
parameter
RUSER_ENABLE
=
0
,
// Width of ruser signal
parameter
RUSER_WIDTH
=
1
,
// Read data FIFO depth (cycles)
parameter
FIFO_DEPTH
=
32
,
// Hold read address until space available in FIFO for data, if possible
parameter
FIFO_DELAY
=
0
)
(
input
wire
clk
,
input
wire
rst
,
/*
* AXI slave interface
*/
input
wire
[
ID_WIDTH
-
1
:
0
]
s_axi_arid
,
input
wire
[
ADDR_WIDTH
-
1
:
0
]
s_axi_araddr
,
input
wire
[
7
:
0
]
s_axi_arlen
,
input
wire
[
2
:
0
]
s_axi_arsize
,
input
wire
[
1
:
0
]
s_axi_arburst
,
input
wire
s_axi_arlock
,
input
wire
[
3
:
0
]
s_axi_arcache
,
input
wire
[
2
:
0
]
s_axi_arprot
,
input
wire
[
3
:
0
]
s_axi_arqos
,
input
wire
[
3
:
0
]
s_axi_arregion
,
input
wire
[
ARUSER_WIDTH
-
1
:
0
]
s_axi_aruser
,
input
wire
s_axi_arvalid
,
output
wire
s_axi_arready
,
output
wire
[
ID_WIDTH
-
1
:
0
]
s_axi_rid
,
output
wire
[
DATA_WIDTH
-
1
:
0
]
s_axi_rdata
,
output
wire
[
1
:
0
]
s_axi_rresp
,
output
wire
s_axi_rlast
,
output
wire
[
RUSER_WIDTH
-
1
:
0
]
s_axi_ruser
,
output
wire
s_axi_rvalid
,
input
wire
s_axi_rready
,
/*
* AXI master interface
*/
output
wire
[
ID_WIDTH
-
1
:
0
]
m_axi_arid
,
output
wire
[
ADDR_WIDTH
-
1
:
0
]
m_axi_araddr
,
output
wire
[
7
:
0
]
m_axi_arlen
,
output
wire
[
2
:
0
]
m_axi_arsize
,
output
wire
[
1
:
0
]
m_axi_arburst
,
output
wire
m_axi_arlock
,
output
wire
[
3
:
0
]
m_axi_arcache
,
output
wire
[
2
:
0
]
m_axi_arprot
,
output
wire
[
3
:
0
]
m_axi_arqos
,
output
wire
[
3
:
0
]
m_axi_arregion
,
output
wire
[
ARUSER_WIDTH
-
1
:
0
]
m_axi_aruser
,
output
wire
m_axi_arvalid
,
input
wire
m_axi_arready
,
input
wire
[
ID_WIDTH
-
1
:
0
]
m_axi_rid
,
input
wire
[
DATA_WIDTH
-
1
:
0
]
m_axi_rdata
,
input
wire
[
1
:
0
]
m_axi_rresp
,
input
wire
m_axi_rlast
,
input
wire
[
RUSER_WIDTH
-
1
:
0
]
m_axi_ruser
,
input
wire
m_axi_rvalid
,
output
wire
m_axi_rready
);
parameter
LAST_OFFSET
=
DATA_WIDTH
;
parameter
ID_OFFSET
=
LAST_OFFSET
+
1
;
parameter
RESP_OFFSET
=
ID_OFFSET
+
ID_WIDTH
;
parameter
RUSER_OFFSET
=
RESP_OFFSET
+
2
;
parameter
RWIDTH
=
RUSER_OFFSET
+
(
RUSER_ENABLE
?
RUSER_WIDTH
:
0
);
parameter
FIFO_ADDR_WIDTH
=
$
clog2
(
FIFO_DEPTH
);
reg
[
FIFO_ADDR_WIDTH
:
0
]
wr_ptr_reg
=
{
FIFO_ADDR_WIDTH
+
1
{
1'b0
}}
,
wr_ptr_next
;
reg
[
FIFO_ADDR_WIDTH
:
0
]
wr_addr_reg
=
{
FIFO_ADDR_WIDTH
+
1
{
1'b0
}}
;
reg
[
FIFO_ADDR_WIDTH
:
0
]
rd_ptr_reg
=
{
FIFO_ADDR_WIDTH
+
1
{
1'b0
}}
,
rd_ptr_next
;
reg
[
FIFO_ADDR_WIDTH
:
0
]
rd_addr_reg
=
{
FIFO_ADDR_WIDTH
+
1
{
1'b0
}}
;
reg
[
RWIDTH
-
1
:
0
]
mem
[(
2
**
FIFO_ADDR_WIDTH
)
-
1
:
0
];
reg
[
RWIDTH
-
1
:
0
]
mem_read_data_reg
;
reg
mem_read_data_valid_reg
=
1'b0
,
mem_read_data_valid_next
;
wire
[
RWIDTH
-
1
:
0
]
m_axi_r
;
reg
[
RWIDTH
-
1
:
0
]
s_axi_r_reg
;
reg
s_axi_rvalid_reg
=
1'b0
,
s_axi_rvalid_next
;
// full when first MSB different but rest same
wire
full
=
((
wr_ptr_reg
[
FIFO_ADDR_WIDTH
]
!=
rd_ptr_reg
[
FIFO_ADDR_WIDTH
])
&&
(
wr_ptr_reg
[
FIFO_ADDR_WIDTH
-
1
:
0
]
==
rd_ptr_reg
[
FIFO_ADDR_WIDTH
-
1
:
0
]));
// empty when pointers match exactly
wire
empty
=
wr_ptr_reg
==
rd_ptr_reg
;
// control signals
reg
write
;
reg
read
;
reg
store_output
;
assign
m_axi_rready
=
!
full
;
generate
assign
m_axi_r
[
DATA_WIDTH
-
1
:
0
]
=
m_axi_rdata
;
assign
m_axi_r
[
LAST_OFFSET
]
=
m_axi_rlast
;
assign
m_axi_r
[
ID_OFFSET
+:
ID_WIDTH
]
=
m_axi_rid
;
assign
m_axi_r
[
RESP_OFFSET
+:
2
]
=
m_axi_rresp
;
if
(
RUSER_ENABLE
)
assign
m_axi_r
[
RUSER_OFFSET
+:
RUSER_WIDTH
]
=
m_axi_ruser
;
endgenerate
generate
if
(
FIFO_DELAY
)
begin
// store AR channel value until there is enough space to store R channel burst in FIFO or FIFO is empty
localparam
COUNT_WIDTH
=
(
FIFO_ADDR_WIDTH
>
8
?
FIFO_ADDR_WIDTH
:
8
)
+
1
;
localparam
[
1
:
0
]
STATE_IDLE
=
1'd0
,
STATE_WAIT
=
1'd1
;
reg
[
1
:
0
]
state_reg
=
STATE_IDLE
,
state_next
;
reg
[
COUNT_WIDTH
-
1
:
0
]
count_reg
=
0
,
count_next
;
reg
[
ID_WIDTH
-
1
:
0
]
m_axi_arid_reg
=
{
ID_WIDTH
{
1'b0
}}
,
m_axi_arid_next
;
reg
[
ADDR_WIDTH
-
1
:
0
]
m_axi_araddr_reg
=
{
ADDR_WIDTH
{
1'b0
}}
,
m_axi_araddr_next
;
reg
[
7
:
0
]
m_axi_arlen_reg
=
8'd0
,
m_axi_arlen_next
;
reg
[
2
:
0
]
m_axi_arsize_reg
=
3'd0
,
m_axi_arsize_next
;
reg
[
1
:
0
]
m_axi_arburst_reg
=
2'd0
,
m_axi_arburst_next
;
reg
m_axi_arlock_reg
=
1'b0
,
m_axi_arlock_next
;
reg
[
3
:
0
]
m_axi_arcache_reg
=
4'd0
,
m_axi_arcache_next
;
reg
[
2
:
0
]
m_axi_arprot_reg
=
3'd0
,
m_axi_arprot_next
;
reg
[
3
:
0
]
m_axi_arqos_reg
=
4'd0
,
m_axi_arqos_next
;
reg
[
3
:
0
]
m_axi_arregion_reg
=
4'd0
,
m_axi_arregion_next
;
reg
[
ARUSER_WIDTH
-
1
:
0
]
m_axi_aruser_reg
=
{
ARUSER_WIDTH
{
1'b0
}}
,
m_axi_aruser_next
;
reg
m_axi_arvalid_reg
=
1'b0
,
m_axi_arvalid_next
;
reg
s_axi_arready_reg
=
1'b0
,
s_axi_arready_next
;
assign
m_axi_arid
=
m_axi_arid_reg
;
assign
m_axi_araddr
=
m_axi_araddr_reg
;
assign
m_axi_arlen
=
m_axi_arlen_reg
;
assign
m_axi_arsize
=
m_axi_arsize_reg
;
assign
m_axi_arburst
=
m_axi_arburst_reg
;
assign
m_axi_arlock
=
m_axi_arlock_reg
;
assign
m_axi_arcache
=
m_axi_arcache_reg
;
assign
m_axi_arprot
=
m_axi_arprot_reg
;
assign
m_axi_arqos
=
m_axi_arqos_reg
;
assign
m_axi_arregion
=
m_axi_arregion_reg
;
assign
m_axi_aruser
=
ARUSER_ENABLE
?
m_axi_aruser_reg
:
{
ARUSER_WIDTH
{
1'b0
}}
;
assign
m_axi_arvalid
=
m_axi_arvalid_reg
;
assign
s_axi_arready
=
s_axi_arready_reg
;
always
@*
begin
state_next
=
STATE_IDLE
;
count_next
=
count_reg
;
m_axi_arid_next
=
m_axi_arid_reg
;
m_axi_araddr_next
=
m_axi_araddr_reg
;
m_axi_arlen_next
=
m_axi_arlen_reg
;
m_axi_arsize_next
=
m_axi_arsize_reg
;
m_axi_arburst_next
=
m_axi_arburst_reg
;
m_axi_arlock_next
=
m_axi_arlock_reg
;
m_axi_arcache_next
=
m_axi_arcache_reg
;
m_axi_arprot_next
=
m_axi_arprot_reg
;
m_axi_arqos_next
=
m_axi_arqos_reg
;
m_axi_arregion_next
=
m_axi_arregion_reg
;
m_axi_aruser_next
=
m_axi_aruser_reg
;
m_axi_arvalid_next
=
m_axi_arvalid_reg
&&
!
m_axi_arready
;
s_axi_arready_next
=
s_axi_arready_reg
;
case
(
state_reg
)
STATE_IDLE:
begin
s_axi_arready_next
=
!
m_axi_arvalid
;
if
(
s_axi_arready
&
s_axi_arvalid
)
begin
s_axi_arready_next
=
1'b0
;
m_axi_arid_next
=
s_axi_arid
;
m_axi_araddr_next
=
s_axi_araddr
;
m_axi_arlen_next
=
s_axi_arlen
;
m_axi_arsize_next
=
s_axi_arsize
;
m_axi_arburst_next
=
s_axi_arburst
;
m_axi_arlock_next
=
s_axi_arlock
;
m_axi_arcache_next
=
s_axi_arcache
;
m_axi_arprot_next
=
s_axi_arprot
;
m_axi_arqos_next
=
s_axi_arqos
;
m_axi_arregion_next
=
s_axi_arregion
;
m_axi_aruser_next
=
s_axi_aruser
;
if
(
count_reg
==
0
||
count_reg
+
m_axi_arlen_next
+
1
<=
2
**
FIFO_ADDR_WIDTH
)
begin
count_next
=
count_reg
+
m_axi_arlen_next
+
1
;
m_axi_arvalid_next
=
1'b1
;
s_axi_arready_next
=
1'b0
;
state_next
=
STATE_IDLE
;
end
else
begin
s_axi_arready_next
=
1'b0
;
state_next
=
STATE_WAIT
;
end
end
else
begin
state_next
=
STATE_IDLE
;
end
end
STATE_WAIT:
begin
s_axi_arready_next
=
1'b0
;
if
(
count_reg
==
0
||
count_reg
+
m_axi_arlen_reg
+
1
<=
2
**
FIFO_ADDR_WIDTH
)
begin
count_next
=
count_reg
+
m_axi_arlen_reg
+
1
;
m_axi_arvalid_next
=
1'b1
;
state_next
=
STATE_IDLE
;
end
else
begin
state_next
=
STATE_WAIT
;
end
end
endcase
if
(
s_axi_rready
&&
s_axi_rvalid
)
begin
count_next
=
count_next
-
1
;
end
end
always
@
(
posedge
clk
)
begin
if
(
rst
)
begin
state_reg
<=
STATE_IDLE
;
m_axi_arvalid_reg
<=
1'b0
;
s_axi_arready_reg
<=
1'b0
;
end
else
begin
state_reg
<=
state_next
;
m_axi_arvalid_reg
<=
m_axi_arvalid_next
;
s_axi_arready_reg
<=
s_axi_arready_next
;
end
count_reg
<=
count_next
;
m_axi_arid_reg
<=
m_axi_arid_next
;
m_axi_araddr_reg
<=
m_axi_araddr_next
;
m_axi_arlen_reg
<=
m_axi_arlen_next
;
m_axi_arsize_reg
<=
m_axi_arsize_next
;
m_axi_arburst_reg
<=
m_axi_arburst_next
;
m_axi_arlock_reg
<=
m_axi_arlock_next
;
m_axi_arcache_reg
<=
m_axi_arcache_next
;
m_axi_arprot_reg
<=
m_axi_arprot_next
;
m_axi_arqos_reg
<=
m_axi_arqos_next
;
m_axi_arregion_reg
<=
m_axi_arregion_next
;
m_axi_aruser_reg
<=
m_axi_aruser_next
;
end
end
else
begin
// bypass AR channel
assign
m_axi_arid
=
s_axi_arid
;
assign
m_axi_araddr
=
s_axi_araddr
;
assign
m_axi_arlen
=
s_axi_arlen
;
assign
m_axi_arsize
=
s_axi_arsize
;
assign
m_axi_arburst
=
s_axi_arburst
;
assign
m_axi_arlock
=
s_axi_arlock
;
assign
m_axi_arcache
=
s_axi_arcache
;
assign
m_axi_arprot
=
s_axi_arprot
;
assign
m_axi_arqos
=
s_axi_arqos
;
assign
m_axi_arregion
=
s_axi_arregion
;
assign
m_axi_aruser
=
ARUSER_ENABLE
?
s_axi_aruser
:
{
ARUSER_WIDTH
{
1'b0
}}
;
assign
m_axi_arvalid
=
s_axi_arvalid
;
assign
s_axi_arready
=
m_axi_arready
;
end
endgenerate
assign
s_axi_rvalid
=
s_axi_rvalid_reg
;
assign
s_axi_rdata
=
s_axi_r_reg
[
DATA_WIDTH
-
1
:
0
];
assign
s_axi_rlast
=
s_axi_r_reg
[
LAST_OFFSET
];
assign
s_axi_rid
=
s_axi_r_reg
[
ID_OFFSET
+:
ID_WIDTH
];
assign
s_axi_rresp
=
s_axi_r_reg
[
RESP_OFFSET
+:
2
];
assign
s_axi_ruser
=
RUSER_ENABLE
?
s_axi_r_reg
[
RUSER_OFFSET
+:
RUSER_WIDTH
]
:
{
RUSER_WIDTH
{
1'b0
}}
;
// Write logic
always
@*
begin
write
=
1'b0
;
wr_ptr_next
=
wr_ptr_reg
;
if
(
m_axi_rvalid
)
begin
// input data valid
if
(
!
full
)
begin
// not full, perform write
write
=
1'b1
;
wr_ptr_next
=
wr_ptr_reg
+
1
;
end
end
end
always
@
(
posedge
clk
)
begin
if
(
rst
)
begin
wr_ptr_reg
<=
{
FIFO_ADDR_WIDTH
+
1
{
1'b0
}}
;
end
else
begin
wr_ptr_reg
<=
wr_ptr_next
;
end
wr_addr_reg
<=
wr_ptr_next
;
if
(
write
)
begin
mem
[
wr_addr_reg
[
FIFO_ADDR_WIDTH
-
1
:
0
]]
<=
m_axi_r
;
end
end
// Read logic
always
@*
begin
read
=
1'b0
;
rd_ptr_next
=
rd_ptr_reg
;
mem_read_data_valid_next
=
mem_read_data_valid_reg
;
if
(
store_output
||
!
mem_read_data_valid_reg
)
begin
// output data not valid OR currently being transferred
if
(
!
empty
)
begin
// not empty, perform read
read
=
1'b1
;
mem_read_data_valid_next
=
1'b1
;
rd_ptr_next
=
rd_ptr_reg
+
1
;
end
else
begin
// empty, invalidate
mem_read_data_valid_next
=
1'b0
;
end
end
end
always
@
(
posedge
clk
)
begin
if
(
rst
)
begin
rd_ptr_reg
<=
{
FIFO_ADDR_WIDTH
+
1
{
1'b0
}}
;
mem_read_data_valid_reg
<=
1'b0
;
end
else
begin
rd_ptr_reg
<=
rd_ptr_next
;
mem_read_data_valid_reg
<=
mem_read_data_valid_next
;
end
rd_addr_reg
<=
rd_ptr_next
;
if
(
read
)
begin
mem_read_data_reg
<=
mem
[
rd_addr_reg
[
FIFO_ADDR_WIDTH
-
1
:
0
]];
end
end
// Output register
always
@*
begin
store_output
=
1'b0
;
s_axi_rvalid_next
=
s_axi_rvalid_reg
;
if
(
s_axi_rready
||
!
s_axi_rvalid
)
begin
store_output
=
1'b1
;
s_axi_rvalid_next
=
mem_read_data_valid_reg
;
end
end
always
@
(
posedge
clk
)
begin
if
(
rst
)
begin
s_axi_rvalid_reg
<=
1'b0
;
end
else
begin
s_axi_rvalid_reg
<=
s_axi_rvalid_next
;
end
if
(
store_output
)
begin
s_axi_r_reg
<=
mem_read_data_reg
;
end
end
endmodule
corundum/lib/axi/rtl/axi_fifo_wr.v
0 → 100644
View file @
738c1fef
/*
Copyright (c) 2018 Alex Forencich
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.
*/
// Language: Verilog 2001
`timescale
1
ns
/
1
ps
/*
* AXI4 FIFO (write)
*/
module
axi_fifo_wr
#
(
// Width of data bus in bits
parameter
DATA_WIDTH
=
32
,
// Width of address bus in bits
parameter
ADDR_WIDTH
=
32
,
// Width of wstrb (width of data bus in words)
parameter
STRB_WIDTH
=
(
DATA_WIDTH
/
8
),
// Width of ID signal
parameter
ID_WIDTH
=
8
,
// Propagate awuser signal
parameter
AWUSER_ENABLE
=
0
,
// Width of awuser signal
parameter
AWUSER_WIDTH
=
1
,
// Propagate wuser signal
parameter
WUSER_ENABLE
=
0
,
// Width of wuser signal
parameter
WUSER_WIDTH
=
1
,
// Propagate buser signal
parameter
BUSER_ENABLE
=
0
,
// Width of buser signal
parameter
BUSER_WIDTH
=
1
,
// Write data FIFO depth (cycles)
parameter
FIFO_DEPTH
=
32
,
// Hold write address until write data in FIFO, if possible
parameter
FIFO_DELAY
=
0
)
(
input
wire
clk
,
input
wire
rst
,
/*
* AXI slave interface
*/
input
wire
[
ID_WIDTH
-
1
:
0
]
s_axi_awid
,
input
wire
[
ADDR_WIDTH
-
1
:
0
]
s_axi_awaddr
,
input
wire
[
7
:
0
]
s_axi_awlen
,
input
wire
[
2
:
0
]
s_axi_awsize
,
input
wire
[
1
:
0
]
s_axi_awburst
,
input
wire
s_axi_awlock
,
input
wire
[
3
:
0
]
s_axi_awcache
,
input
wire
[
2
:
0
]
s_axi_awprot
,
input
wire
[
3
:
0
]
s_axi_awqos
,
input
wire
[
3
:
0
]
s_axi_awregion
,
input
wire
[
AWUSER_WIDTH
-
1
:
0
]
s_axi_awuser
,
input
wire
s_axi_awvalid
,
output
wire
s_axi_awready
,
input
wire
[
DATA_WIDTH
-
1
:
0
]
s_axi_wdata
,
input
wire
[
STRB_WIDTH
-
1
:
0
]
s_axi_wstrb
,
input
wire
s_axi_wlast
,
input
wire
[
WUSER_WIDTH
-
1
:
0
]
s_axi_wuser
,
input
wire
s_axi_wvalid
,
output
wire
s_axi_wready
,
output
wire
[
ID_WIDTH
-
1
:
0
]
s_axi_bid
,
output
wire
[
1
:
0
]
s_axi_bresp
,
output
wire
[
BUSER_WIDTH
-
1
:
0
]
s_axi_buser
,
output
wire
s_axi_bvalid
,
input
wire
s_axi_bready
,
/*
* AXI master interface
*/
output
wire
[
ID_WIDTH
-
1
:
0
]
m_axi_awid
,
output
wire
[
ADDR_WIDTH
-
1
:
0
]
m_axi_awaddr
,
output
wire
[
7
:
0
]
m_axi_awlen
,
output
wire
[
2
:
0
]
m_axi_awsize
,
output
wire
[
1
:
0
]
m_axi_awburst
,
output
wire
m_axi_awlock
,
output
wire
[
3
:
0
]
m_axi_awcache
,
output
wire
[
2
:
0
]
m_axi_awprot
,
output
wire
[
3
:
0
]
m_axi_awqos
,
output
wire
[
3
:
0
]
m_axi_awregion
,
output
wire
[
AWUSER_WIDTH
-
1
:
0
]
m_axi_awuser
,
output
wire
m_axi_awvalid
,
input
wire
m_axi_awready
,
output
wire
[
DATA_WIDTH
-
1
:
0
]
m_axi_wdata
,
output
wire
[
STRB_WIDTH
-
1
:
0
]
m_axi_wstrb
,
output
wire
m_axi_wlast
,
output
wire
[
WUSER_WIDTH
-
1
:
0
]
m_axi_wuser
,
output
wire
m_axi_wvalid
,
input
wire
m_axi_wready
,
input
wire
[
ID_WIDTH
-
1
:
0
]
m_axi_bid
,
input
wire
[
1
:
0
]
m_axi_bresp
,
input
wire
[
BUSER_WIDTH
-
1
:
0
]
m_axi_buser
,
input
wire
m_axi_bvalid
,
output
wire
m_axi_bready
);
parameter
STRB_OFFSET
=
DATA_WIDTH
;
parameter
LAST_OFFSET
=
STRB_OFFSET
+
STRB_WIDTH
;
parameter
WUSER_OFFSET
=
LAST_OFFSET
+
1
;
parameter
WWIDTH
=
WUSER_OFFSET
+
(
WUSER_ENABLE
?
WUSER_WIDTH
:
0
);
parameter
FIFO_ADDR_WIDTH
=
$
clog2
(
FIFO_DEPTH
);
reg
[
FIFO_ADDR_WIDTH
:
0
]
wr_ptr_reg
=
{
FIFO_ADDR_WIDTH
+
1
{
1'b0
}}
,
wr_ptr_next
;
reg
[
FIFO_ADDR_WIDTH
:
0
]
wr_addr_reg
=
{
FIFO_ADDR_WIDTH
+
1
{
1'b0
}}
;
reg
[
FIFO_ADDR_WIDTH
:
0
]
rd_ptr_reg
=
{
FIFO_ADDR_WIDTH
+
1
{
1'b0
}}
,
rd_ptr_next
;
reg
[
FIFO_ADDR_WIDTH
:
0
]
rd_addr_reg
=
{
FIFO_ADDR_WIDTH
+
1
{
1'b0
}}
;
reg
[
WWIDTH
-
1
:
0
]
mem
[(
2
**
FIFO_ADDR_WIDTH
)
-
1
:
0
];
reg
[
WWIDTH
-
1
:
0
]
mem_read_data_reg
;
reg
mem_read_data_valid_reg
=
1'b0
,
mem_read_data_valid_next
;
wire
[
WWIDTH
-
1
:
0
]
s_axi_w
;
reg
[
WWIDTH
-
1
:
0
]
m_axi_w_reg
;
reg
m_axi_wvalid_reg
=
1'b0
,
m_axi_wvalid_next
;
// full when first MSB different but rest same
wire
full
=
((
wr_ptr_reg
[
FIFO_ADDR_WIDTH
]
!=
rd_ptr_reg
[
FIFO_ADDR_WIDTH
])
&&
(
wr_ptr_reg
[
FIFO_ADDR_WIDTH
-
1
:
0
]
==
rd_ptr_reg
[
FIFO_ADDR_WIDTH
-
1
:
0
]));
// empty when pointers match exactly
wire
empty
=
wr_ptr_reg
==
rd_ptr_reg
;
wire
hold
;
// control signals
reg
write
;
reg
read
;
reg
store_output
;
assign
s_axi_wready
=
!
full
&&
!
hold
;
generate
assign
s_axi_w
[
DATA_WIDTH
-
1
:
0
]
=
s_axi_wdata
;
assign
s_axi_w
[
STRB_OFFSET
+:
STRB_WIDTH
]
=
s_axi_wstrb
;
assign
s_axi_w
[
LAST_OFFSET
]
=
s_axi_wlast
;
if
(
WUSER_ENABLE
)
assign
s_axi_w
[
WUSER_OFFSET
+:
WUSER_WIDTH
]
=
s_axi_wuser
;
endgenerate
generate
if
(
FIFO_DELAY
)
begin
// store AW channel value until W channel burst is stored in FIFO or FIFO is full
localparam
[
1
:
0
]
STATE_IDLE
=
2'd0
,
STATE_TRANSFER_IN
=
2'd1
,
STATE_TRANSFER_OUT
=
2'd2
;
reg
[
1
:
0
]
state_reg
=
STATE_IDLE
,
state_next
;
reg
hold_reg
=
1'b1
,
hold_next
;
reg
[
8
:
0
]
count_reg
=
9'd0
,
count_next
;
reg
[
ID_WIDTH
-
1
:
0
]
m_axi_awid_reg
=
{
ID_WIDTH
{
1'b0
}}
,
m_axi_awid_next
;
reg
[
ADDR_WIDTH
-
1
:
0
]
m_axi_awaddr_reg
=
{
ADDR_WIDTH
{
1'b0
}}
,
m_axi_awaddr_next
;
reg
[
7
:
0
]
m_axi_awlen_reg
=
8'd0
,
m_axi_awlen_next
;
reg
[
2
:
0
]
m_axi_awsize_reg
=
3'd0
,
m_axi_awsize_next
;
reg
[
1
:
0
]
m_axi_awburst_reg
=
2'd0
,
m_axi_awburst_next
;
reg
m_axi_awlock_reg
=
1'b0
,
m_axi_awlock_next
;
reg
[
3
:
0
]
m_axi_awcache_reg
=
4'd0
,
m_axi_awcache_next
;
reg
[
2
:
0
]
m_axi_awprot_reg
=
3'd0
,
m_axi_awprot_next
;
reg
[
3
:
0
]
m_axi_awqos_reg
=
4'd0
,
m_axi_awqos_next
;
reg
[
3
:
0
]
m_axi_awregion_reg
=
4'd0
,
m_axi_awregion_next
;
reg
[
AWUSER_WIDTH
-
1
:
0
]
m_axi_awuser_reg
=
{
AWUSER_WIDTH
{
1'b0
}}
,
m_axi_awuser_next
;
reg
m_axi_awvalid_reg
=
1'b0
,
m_axi_awvalid_next
;
reg
s_axi_awready_reg
=
1'b0
,
s_axi_awready_next
;
assign
m_axi_awid
=
m_axi_awid_reg
;
assign
m_axi_awaddr
=
m_axi_awaddr_reg
;
assign
m_axi_awlen
=
m_axi_awlen_reg
;
assign
m_axi_awsize
=
m_axi_awsize_reg
;
assign
m_axi_awburst
=
m_axi_awburst_reg
;
assign
m_axi_awlock
=
m_axi_awlock_reg
;
assign
m_axi_awcache
=
m_axi_awcache_reg
;
assign
m_axi_awprot
=
m_axi_awprot_reg
;
assign
m_axi_awqos
=
m_axi_awqos_reg
;
assign
m_axi_awregion
=
m_axi_awregion_reg
;
assign
m_axi_awuser
=
AWUSER_ENABLE
?
m_axi_awuser_reg
:
{
AWUSER_WIDTH
{
1'b0
}}
;
assign
m_axi_awvalid
=
m_axi_awvalid_reg
;
assign
s_axi_awready
=
s_axi_awready_reg
;
assign
hold
=
hold_reg
;
always
@*
begin
state_next
=
STATE_IDLE
;
hold_next
=
hold_reg
;
count_next
=
count_reg
;
m_axi_awid_next
=
m_axi_awid_reg
;
m_axi_awaddr_next
=
m_axi_awaddr_reg
;
m_axi_awlen_next
=
m_axi_awlen_reg
;
m_axi_awsize_next
=
m_axi_awsize_reg
;
m_axi_awburst_next
=
m_axi_awburst_reg
;
m_axi_awlock_next
=
m_axi_awlock_reg
;
m_axi_awcache_next
=
m_axi_awcache_reg
;
m_axi_awprot_next
=
m_axi_awprot_reg
;
m_axi_awqos_next
=
m_axi_awqos_reg
;
m_axi_awregion_next
=
m_axi_awregion_reg
;
m_axi_awuser_next
=
m_axi_awuser_reg
;
m_axi_awvalid_next
=
m_axi_awvalid_reg
&&
!
m_axi_awready
;
s_axi_awready_next
=
s_axi_awready_reg
;
case
(
state_reg
)
STATE_IDLE:
begin
s_axi_awready_next
=
!
m_axi_awvalid
;
hold_next
=
1'b1
;
if
(
s_axi_awready
&
s_axi_awvalid
)
begin
s_axi_awready_next
=
1'b0
;
m_axi_awid_next
=
s_axi_awid
;
m_axi_awaddr_next
=
s_axi_awaddr
;
m_axi_awlen_next
=
s_axi_awlen
;
m_axi_awsize_next
=
s_axi_awsize
;
m_axi_awburst_next
=
s_axi_awburst
;
m_axi_awlock_next
=
s_axi_awlock
;
m_axi_awcache_next
=
s_axi_awcache
;
m_axi_awprot_next
=
s_axi_awprot
;
m_axi_awqos_next
=
s_axi_awqos
;
m_axi_awregion_next
=
s_axi_awregion
;
m_axi_awuser_next
=
s_axi_awuser
;
hold_next
=
1'b0
;
count_next
=
0
;
state_next
=
STATE_TRANSFER_IN
;
end
else
begin
state_next
=
STATE_IDLE
;
end
end
STATE_TRANSFER_IN:
begin
s_axi_awready_next
=
1'b0
;
hold_next
=
1'b0
;
if
(
s_axi_wready
&
s_axi_wvalid
)
begin
count_next
=
count_reg
+
1
;
if
(
count_next
==
2
**
FIFO_ADDR_WIDTH
)
begin
m_axi_awvalid_next
=
1'b1
;
state_next
=
STATE_TRANSFER_OUT
;
end
else
if
(
count_reg
==
m_axi_awlen
)
begin
m_axi_awvalid_next
=
1'b1
;
hold_next
=
1'b1
;
state_next
=
STATE_IDLE
;
end
else
begin
state_next
=
STATE_TRANSFER_IN
;
end
end
else
begin
state_next
=
STATE_TRANSFER_IN
;
end
end
STATE_TRANSFER_OUT:
begin
s_axi_awready_next
=
1'b0
;
hold_next
=
1'b0
;
if
(
s_axi_wready
&
s_axi_wvalid
)
begin
count_next
=
count_reg
+
1
;
if
(
count_reg
==
m_axi_awlen
)
begin
hold_next
=
1'b1
;
state_next
=
STATE_IDLE
;
end
else
begin
state_next
=
STATE_TRANSFER_OUT
;
end
end
else
begin
state_next
=
STATE_TRANSFER_OUT
;
end
end
endcase
end
always
@
(
posedge
clk
)
begin
if
(
rst
)
begin
state_reg
<=
STATE_IDLE
;
hold_reg
<=
1'b1
;
m_axi_awvalid_reg
<=
1'b0
;
s_axi_awready_reg
<=
1'b0
;
end
else
begin
state_reg
<=
state_next
;
hold_reg
<=
hold_next
;
m_axi_awvalid_reg
<=
m_axi_awvalid_next
;
s_axi_awready_reg
<=
s_axi_awready_next
;
end
count_reg
<=
count_next
;
m_axi_awid_reg
<=
m_axi_awid_next
;
m_axi_awaddr_reg
<=
m_axi_awaddr_next
;
m_axi_awlen_reg
<=
m_axi_awlen_next
;
m_axi_awsize_reg
<=
m_axi_awsize_next
;
m_axi_awburst_reg
<=
m_axi_awburst_next
;
m_axi_awlock_reg
<=
m_axi_awlock_next
;
m_axi_awcache_reg
<=
m_axi_awcache_next
;
m_axi_awprot_reg
<=
m_axi_awprot_next
;
m_axi_awqos_reg
<=
m_axi_awqos_next
;
m_axi_awregion_reg
<=
m_axi_awregion_next
;
m_axi_awuser_reg
<=
m_axi_awuser_next
;
end
end
else
begin
// bypass AW channel
assign
m_axi_awid
=
s_axi_awid
;
assign
m_axi_awaddr
=
s_axi_awaddr
;
assign
m_axi_awlen
=
s_axi_awlen
;
assign
m_axi_awsize
=
s_axi_awsize
;
assign
m_axi_awburst
=
s_axi_awburst
;
assign
m_axi_awlock
=
s_axi_awlock
;
assign
m_axi_awcache
=
s_axi_awcache
;
assign
m_axi_awprot
=
s_axi_awprot
;
assign
m_axi_awqos
=
s_axi_awqos
;
assign
m_axi_awregion
=
s_axi_awregion
;
assign
m_axi_awuser
=
AWUSER_ENABLE
?
s_axi_awuser
:
{
AWUSER_WIDTH
{
1'b0
}}
;
assign
m_axi_awvalid
=
s_axi_awvalid
;
assign
s_axi_awready
=
m_axi_awready
;
assign
hold
=
1'b0
;
end
endgenerate
// bypass B channel
assign
s_axi_bid
=
m_axi_bid
;
assign
s_axi_bresp
=
m_axi_bresp
;
assign
s_axi_buser
=
BUSER_ENABLE
?
m_axi_buser
:
{
BUSER_WIDTH
{
1'b0
}}
;
assign
s_axi_bvalid
=
m_axi_bvalid
;
assign
m_axi_bready
=
s_axi_bready
;
assign
m_axi_wvalid
=
m_axi_wvalid_reg
;
assign
m_axi_wdata
=
m_axi_w_reg
[
DATA_WIDTH
-
1
:
0
];
assign
m_axi_wstrb
=
m_axi_w_reg
[
STRB_OFFSET
+:
STRB_WIDTH
];
assign
m_axi_wlast
=
m_axi_w_reg
[
LAST_OFFSET
];
assign
m_axi_wuser
=
WUSER_ENABLE
?
m_axi_w_reg
[
WUSER_OFFSET
+:
WUSER_WIDTH
]
:
{
WUSER_WIDTH
{
1'b0
}}
;
// Write logic
always
@*
begin
write
=
1'b0
;
wr_ptr_next
=
wr_ptr_reg
;
if
(
s_axi_wvalid
)
begin
// input data valid
if
(
!
full
&&
!
hold
)
begin
// not full, perform write
write
=
1'b1
;
wr_ptr_next
=
wr_ptr_reg
+
1
;
end
end
end
always
@
(
posedge
clk
)
begin
if
(
rst
)
begin
wr_ptr_reg
<=
{
FIFO_ADDR_WIDTH
+
1
{
1'b0
}}
;
end
else
begin
wr_ptr_reg
<=
wr_ptr_next
;
end
wr_addr_reg
<=
wr_ptr_next
;
if
(
write
)
begin
mem
[
wr_addr_reg
[
FIFO_ADDR_WIDTH
-
1
:
0
]]
<=
s_axi_w
;
end
end
// Read logic
always
@*
begin
read
=
1'b0
;
rd_ptr_next
=
rd_ptr_reg
;
mem_read_data_valid_next
=
mem_read_data_valid_reg
;
if
(
store_output
||
!
mem_read_data_valid_reg
)
begin
// output data not valid OR currently being transferred
if
(
!
empty
)
begin
// not empty, perform read
read
=
1'b1
;
mem_read_data_valid_next
=
1'b1
;
rd_ptr_next
=
rd_ptr_reg
+
1
;
end
else
begin
// empty, invalidate
mem_read_data_valid_next
=
1'b0
;
end
end
end
always
@
(
posedge
clk
)
begin
if
(
rst
)
begin
rd_ptr_reg
<=
{
FIFO_ADDR_WIDTH
+
1
{
1'b0
}}
;
mem_read_data_valid_reg
<=
1'b0
;
end
else
begin
rd_ptr_reg
<=
rd_ptr_next
;
mem_read_data_valid_reg
<=
mem_read_data_valid_next
;
end
rd_addr_reg
<=
rd_ptr_next
;
if
(
read
)
begin
mem_read_data_reg
<=
mem
[
rd_addr_reg
[
FIFO_ADDR_WIDTH
-
1
:
0
]];
end
end
// Output register
always
@*
begin
store_output
=
1'b0
;
m_axi_wvalid_next
=
m_axi_wvalid_reg
;
if
(
m_axi_wready
||
!
m_axi_wvalid
)
begin
store_output
=
1'b1
;
m_axi_wvalid_next
=
mem_read_data_valid_reg
;
end
end
always
@
(
posedge
clk
)
begin
if
(
rst
)
begin
m_axi_wvalid_reg
<=
1'b0
;
end
else
begin
m_axi_wvalid_reg
<=
m_axi_wvalid_next
;
end
if
(
store_output
)
begin
m_axi_w_reg
<=
mem_read_data_reg
;
end
end
endmodule
corundum/lib/axi/rtl/axi_interconnect.v
0 → 100644
View file @
738c1fef
/*
Copyright (c) 2018 Alex Forencich
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.
*/
// Language: Verilog 2001
`timescale
1
ns
/
1
ps
/*
* AXI4 interconnect
*/
module
axi_interconnect
#
(
// Number of AXI inputs (slave interfaces)
parameter
S_COUNT
=
4
,
// Number of AXI outputs (master interfaces)
parameter
M_COUNT
=
4
,
// Width of data bus in bits
parameter
DATA_WIDTH
=
32
,
// Width of address bus in bits
parameter
ADDR_WIDTH
=
32
,
// Width of wstrb (width of data bus in words)
parameter
STRB_WIDTH
=
(
DATA_WIDTH
/
8
),
// Width of ID signal
parameter
ID_WIDTH
=
8
,
// Propagate awuser signal
parameter
AWUSER_ENABLE
=
0
,
// Width of awuser signal
parameter
AWUSER_WIDTH
=
1
,
// Propagate wuser signal
parameter
WUSER_ENABLE
=
0
,
// Width of wuser signal
parameter
WUSER_WIDTH
=
1
,
// Propagate buser signal
parameter
BUSER_ENABLE
=
0
,
// Width of buser signal
parameter
BUSER_WIDTH
=
1
,
// Propagate aruser signal
parameter
ARUSER_ENABLE
=
0
,
// Width of aruser signal
parameter
ARUSER_WIDTH
=
1
,
// Propagate ruser signal
parameter
RUSER_ENABLE
=
0
,
// Width of ruser signal
parameter
RUSER_WIDTH
=
1
,
// Propagate ID field
parameter
FORWARD_ID
=
0
,
// Number of regions per master interface
parameter
M_REGIONS
=
1
,
// Master interface base addresses
// M_COUNT concatenated fields of M_REGIONS concatenated fields of ADDR_WIDTH bits
// set to zero for default addressing based on M_ADDR_WIDTH
parameter
M_BASE_ADDR
=
0
,
// Master interface address widths
// M_COUNT concatenated fields of M_REGIONS concatenated fields of 32 bits
parameter
M_ADDR_WIDTH
=
{
M_COUNT
{{
M_REGIONS
{
32'd24
}}}}
,
// Read connections between interfaces
// M_COUNT concatenated fields of S_COUNT bits
parameter
M_CONNECT_READ
=
{
M_COUNT
{{
S_COUNT
{
1'b1
}}}}
,
// Write connections between interfaces
// M_COUNT concatenated fields of S_COUNT bits
parameter
M_CONNECT_WRITE
=
{
M_COUNT
{{
S_COUNT
{
1'b1
}}}}
,
// Secure master (fail operations based on awprot/arprot)
// M_COUNT bits
parameter
M_SECURE
=
{
M_COUNT
{
1'b0
}}
)
(
input
wire
clk
,
input
wire
rst
,
/*
* AXI slave interfaces
*/
input
wire
[
S_COUNT
*
ID_WIDTH
-
1
:
0
]
s_axi_awid
,
input
wire
[
S_COUNT
*
ADDR_WIDTH
-
1
:
0
]
s_axi_awaddr
,
input
wire
[
S_COUNT
*
8
-
1
:
0
]
s_axi_awlen
,
input
wire
[
S_COUNT
*
3
-
1
:
0
]
s_axi_awsize
,
input
wire
[
S_COUNT
*
2
-
1
:
0
]
s_axi_awburst
,
input
wire
[
S_COUNT
-
1
:
0
]
s_axi_awlock
,
input
wire
[
S_COUNT
*
4
-
1
:
0
]
s_axi_awcache
,
input
wire
[
S_COUNT
*
3
-
1
:
0
]
s_axi_awprot
,
input
wire
[
S_COUNT
*
4
-
1
:
0
]
s_axi_awqos
,
input
wire
[
S_COUNT
*
AWUSER_WIDTH
-
1
:
0
]
s_axi_awuser
,
input
wire
[
S_COUNT
-
1
:
0
]
s_axi_awvalid
,
output
wire
[
S_COUNT
-
1
:
0
]
s_axi_awready
,
input
wire
[
S_COUNT
*
DATA_WIDTH
-
1
:
0
]
s_axi_wdata
,
input
wire
[
S_COUNT
*
STRB_WIDTH
-
1
:
0
]
s_axi_wstrb
,
input
wire
[
S_COUNT
-
1
:
0
]
s_axi_wlast
,
input
wire
[
S_COUNT
*
WUSER_WIDTH
-
1
:
0
]
s_axi_wuser
,
input
wire
[
S_COUNT
-
1
:
0
]
s_axi_wvalid
,
output
wire
[
S_COUNT
-
1
:
0
]
s_axi_wready
,
output
wire
[
S_COUNT
*
ID_WIDTH
-
1
:
0
]
s_axi_bid
,
output
wire
[
S_COUNT
*
2
-
1
:
0
]
s_axi_bresp
,
output
wire
[
S_COUNT
*
BUSER_WIDTH
-
1
:
0
]
s_axi_buser
,
output
wire
[
S_COUNT
-
1
:
0
]
s_axi_bvalid
,
input
wire
[
S_COUNT
-
1
:
0
]
s_axi_bready
,
input
wire
[
S_COUNT
*
ID_WIDTH
-
1
:
0
]
s_axi_arid
,
input
wire
[
S_COUNT
*
ADDR_WIDTH
-
1
:
0
]
s_axi_araddr
,
input
wire
[
S_COUNT
*
8
-
1
:
0
]
s_axi_arlen
,
input
wire
[
S_COUNT
*
3
-
1
:
0
]
s_axi_arsize
,
input
wire
[
S_COUNT
*
2
-
1
:
0
]
s_axi_arburst
,
input
wire
[
S_COUNT
-
1
:
0
]
s_axi_arlock
,
input
wire
[
S_COUNT
*
4
-
1
:
0
]
s_axi_arcache
,
input
wire
[
S_COUNT
*
3
-
1
:
0
]
s_axi_arprot
,
input
wire
[
S_COUNT
*
4
-
1
:
0
]
s_axi_arqos
,
input
wire
[
S_COUNT
*
ARUSER_WIDTH
-
1
:
0
]
s_axi_aruser
,
input
wire
[
S_COUNT
-
1
:
0
]
s_axi_arvalid
,
output
wire
[
S_COUNT
-
1
:
0
]
s_axi_arready
,
output
wire
[
S_COUNT
*
ID_WIDTH
-
1
:
0
]
s_axi_rid
,
output
wire
[
S_COUNT
*
DATA_WIDTH
-
1
:
0
]
s_axi_rdata
,
output
wire
[
S_COUNT
*
2
-
1
:
0
]
s_axi_rresp
,
output
wire
[
S_COUNT
-
1
:
0
]
s_axi_rlast
,
output
wire
[
S_COUNT
*
RUSER_WIDTH
-
1
:
0
]
s_axi_ruser
,
output
wire
[
S_COUNT
-
1
:
0
]
s_axi_rvalid
,
input
wire
[
S_COUNT
-
1
:
0
]
s_axi_rready
,
/*
* AXI master interfaces
*/
output
wire
[
M_COUNT
*
ID_WIDTH
-
1
:
0
]
m_axi_awid
,
output
wire
[
M_COUNT
*
ADDR_WIDTH
-
1
:
0
]
m_axi_awaddr
,
output
wire
[
M_COUNT
*
8
-
1
:
0
]
m_axi_awlen
,
output
wire
[
M_COUNT
*
3
-
1
:
0
]
m_axi_awsize
,
output
wire
[
M_COUNT
*
2
-
1
:
0
]
m_axi_awburst
,
output
wire
[
M_COUNT
-
1
:
0
]
m_axi_awlock
,
output
wire
[
M_COUNT
*
4
-
1
:
0
]
m_axi_awcache
,
output
wire
[
M_COUNT
*
3
-
1
:
0
]
m_axi_awprot
,
output
wire
[
M_COUNT
*
4
-
1
:
0
]
m_axi_awqos
,
output
wire
[
M_COUNT
*
4
-
1
:
0
]
m_axi_awregion
,
output
wire
[
M_COUNT
*
AWUSER_WIDTH
-
1
:
0
]
m_axi_awuser
,
output
wire
[
M_COUNT
-
1
:
0
]
m_axi_awvalid
,
input
wire
[
M_COUNT
-
1
:
0
]
m_axi_awready
,
output
wire
[
M_COUNT
*
DATA_WIDTH
-
1
:
0
]
m_axi_wdata
,
output
wire
[
M_COUNT
*
STRB_WIDTH
-
1
:
0
]
m_axi_wstrb
,
output
wire
[
M_COUNT
-
1
:
0
]
m_axi_wlast
,
output
wire
[
M_COUNT
*
WUSER_WIDTH
-
1
:
0
]
m_axi_wuser
,
output
wire
[
M_COUNT
-
1
:
0
]
m_axi_wvalid
,
input
wire
[
M_COUNT
-
1
:
0
]
m_axi_wready
,
input
wire
[
M_COUNT
*
ID_WIDTH
-
1
:
0
]
m_axi_bid
,
input
wire
[
M_COUNT
*
2
-
1
:
0
]
m_axi_bresp
,
input
wire
[
M_COUNT
*
BUSER_WIDTH
-
1
:
0
]
m_axi_buser
,
input
wire
[
M_COUNT
-
1
:
0
]
m_axi_bvalid
,
output
wire
[
M_COUNT
-
1
:
0
]
m_axi_bready
,
output
wire
[
M_COUNT
*
ID_WIDTH
-
1
:
0
]
m_axi_arid
,
output
wire
[
M_COUNT
*
ADDR_WIDTH
-
1
:
0
]
m_axi_araddr
,
output
wire
[
M_COUNT
*
8
-
1
:
0
]
m_axi_arlen
,
output
wire
[
M_COUNT
*
3
-
1
:
0
]
m_axi_arsize
,
output
wire
[
M_COUNT
*
2
-
1
:
0
]
m_axi_arburst
,
output
wire
[
M_COUNT
-
1
:
0
]
m_axi_arlock
,
output
wire
[
M_COUNT
*
4
-
1
:
0
]
m_axi_arcache
,
output
wire
[
M_COUNT
*
3
-
1
:
0
]
m_axi_arprot
,
output
wire
[
M_COUNT
*
4
-
1
:
0
]
m_axi_arqos
,
output
wire
[
M_COUNT
*
4
-
1
:
0
]
m_axi_arregion
,
output
wire
[
M_COUNT
*
ARUSER_WIDTH
-
1
:
0
]
m_axi_aruser
,
output
wire
[
M_COUNT
-
1
:
0
]
m_axi_arvalid
,
input
wire
[
M_COUNT
-
1
:
0
]
m_axi_arready
,
input
wire
[
M_COUNT
*
ID_WIDTH
-
1
:
0
]
m_axi_rid
,
input
wire
[
M_COUNT
*
DATA_WIDTH
-
1
:
0
]
m_axi_rdata
,
input
wire
[
M_COUNT
*
2
-
1
:
0
]
m_axi_rresp
,
input
wire
[
M_COUNT
-
1
:
0
]
m_axi_rlast
,
input
wire
[
M_COUNT
*
RUSER_WIDTH
-
1
:
0
]
m_axi_ruser
,
input
wire
[
M_COUNT
-
1
:
0
]
m_axi_rvalid
,
output
wire
[
M_COUNT
-
1
:
0
]
m_axi_rready
);
parameter
CL_S_COUNT
=
$
clog2
(
S_COUNT
);
parameter
CL_M_COUNT
=
$
clog2
(
M_COUNT
);
parameter
AUSER_WIDTH
=
AWUSER_WIDTH
>
ARUSER_WIDTH
?
AWUSER_WIDTH
:
ARUSER_WIDTH
;
// default address computation
function
[
M_COUNT
*
M_REGIONS
*
ADDR_WIDTH
-
1
:
0
]
calcBaseAddrs
(
input
[
31
:
0
]
dummy
);
integer
i
;
reg
[
ADDR_WIDTH
-
1
:
0
]
base
;
begin
calcBaseAddrs
=
{
M_COUNT
*
M_REGIONS
*
ADDR_WIDTH
{
1'b0
}}
;
base
=
0
;
for
(
i
=
1
;
i
<
M_COUNT
*
M_REGIONS
;
i
=
i
+
1
)
begin
if
(
M_ADDR_WIDTH
[
i
*
32
+:
32
])
begin
base
=
base
+
2
**
M_ADDR_WIDTH
[(
i
-
1
)
*
32
+:
32
];
// increment
base
=
base
-
(
base
%
2
**
M_ADDR_WIDTH
[
i
*
32
+:
32
]);
// align
calcBaseAddrs
[
i
*
ADDR_WIDTH
+:
ADDR_WIDTH
]
=
base
;
end
end
end
endfunction
parameter
M_BASE_ADDR_INT
=
M_BASE_ADDR
?
M_BASE_ADDR
:
calcBaseAddrs
(
0
);
integer
i
,
j
;
// check configuration
initial
begin
if
(
M_REGIONS
<
1
||
M_REGIONS
>
16
)
begin
$
error
(
"Error: M_REGIONS must be between 1 and 16 (instance %m)"
);
$
finish
;
end
for
(
i
=
0
;
i
<
M_COUNT
*
M_REGIONS
;
i
=
i
+
1
)
begin
if
(
M_ADDR_WIDTH
[
i
*
32
+:
32
]
&&
(
M_ADDR_WIDTH
[
i
*
32
+:
32
]
<
12
||
M_ADDR_WIDTH
[
i
*
32
+:
32
]
>
ADDR_WIDTH
))
begin
$
error
(
"Error: address width out of range (instance %m)"
);
$
finish
;
end
end
$
display
(
"Addressing configuration for axi_interconnect instance %m"
);
for
(
i
=
0
;
i
<
M_COUNT
*
M_REGIONS
;
i
=
i
+
1
)
begin
if
(
M_ADDR_WIDTH
[
i
*
32
+:
32
])
begin
$
display
(
"%2d (%2d): %x / %2d -- %x-%x"
,
i
/
M_REGIONS
,
i
%
M_REGIONS
,
M_BASE_ADDR_INT
[
i
*
ADDR_WIDTH
+:
ADDR_WIDTH
],
M_ADDR_WIDTH
[
i
*
32
+:
32
],
M_BASE_ADDR_INT
[
i
*
ADDR_WIDTH
+:
ADDR_WIDTH
]
&
(
{
ADDR_WIDTH
{
1'b1
}}
<<
M_ADDR_WIDTH
[
i
*
32
+:
32
]),
M_BASE_ADDR_INT
[
i
*
ADDR_WIDTH
+:
ADDR_WIDTH
]
|
(
{
ADDR_WIDTH
{
1'b1
}}
>>
(
ADDR_WIDTH
-
M_ADDR_WIDTH
[
i
*
32
+:
32
])));
end
end
for
(
i
=
0
;
i
<
M_COUNT
*
M_REGIONS
;
i
=
i
+
1
)
begin
for
(
j
=
i
+
1
;
j
<
M_COUNT
*
M_REGIONS
;
j
=
j
+
1
)
begin
if
(
M_ADDR_WIDTH
[
i
*
32
+:
32
]
&&
M_ADDR_WIDTH
[
j
*
32
+:
32
])
begin
if
(((
M_BASE_ADDR_INT
[
i
*
ADDR_WIDTH
+:
ADDR_WIDTH
]
&
(
{
ADDR_WIDTH
{
1'b1
}}
<<
M_ADDR_WIDTH
[
i
*
32
+:
32
]))
<=
(
M_BASE_ADDR_INT
[
j
*
ADDR_WIDTH
+:
ADDR_WIDTH
]
|
(
{
ADDR_WIDTH
{
1'b1
}}
>>
(
ADDR_WIDTH
-
M_ADDR_WIDTH
[
j
*
32
+:
32
]))))
&&
((
M_BASE_ADDR_INT
[
j
*
ADDR_WIDTH
+:
ADDR_WIDTH
]
&
(
{
ADDR_WIDTH
{
1'b1
}}
<<
M_ADDR_WIDTH
[
j
*
32
+:
32
]))
<=
(
M_BASE_ADDR_INT
[
i
*
ADDR_WIDTH
+:
ADDR_WIDTH
]
|
(
{
ADDR_WIDTH
{
1'b1
}}
>>
(
ADDR_WIDTH
-
M_ADDR_WIDTH
[
i
*
32
+:
32
])))))
begin
$
display
(
"Overlapping regions:"
);
$
display
(
"%2d (%2d): %x / %2d -- %x-%x"
,
i
/
M_REGIONS
,
i
%
M_REGIONS
,
M_BASE_ADDR_INT
[
i
*
ADDR_WIDTH
+:
ADDR_WIDTH
],
M_ADDR_WIDTH
[
i
*
32
+:
32
],
M_BASE_ADDR_INT
[
i
*
ADDR_WIDTH
+:
ADDR_WIDTH
]
&
(
{
ADDR_WIDTH
{
1'b1
}}
<<
M_ADDR_WIDTH
[
i
*
32
+:
32
]),
M_BASE_ADDR_INT
[
i
*
ADDR_WIDTH
+:
ADDR_WIDTH
]
|
(
{
ADDR_WIDTH
{
1'b1
}}
>>
(
ADDR_WIDTH
-
M_ADDR_WIDTH
[
i
*
32
+:
32
])));
$
display
(
"%2d (%2d): %x / %2d -- %x-%x"
,
j
/
M_REGIONS
,
j
%
M_REGIONS
,
M_BASE_ADDR_INT
[
j
*
ADDR_WIDTH
+:
ADDR_WIDTH
],
M_ADDR_WIDTH
[
j
*
32
+:
32
],
M_BASE_ADDR_INT
[
j
*
ADDR_WIDTH
+:
ADDR_WIDTH
]
&
(
{
ADDR_WIDTH
{
1'b1
}}
<<
M_ADDR_WIDTH
[
j
*
32
+:
32
]),
M_BASE_ADDR_INT
[
j
*
ADDR_WIDTH
+:
ADDR_WIDTH
]
|
(
{
ADDR_WIDTH
{
1'b1
}}
>>
(
ADDR_WIDTH
-
M_ADDR_WIDTH
[
j
*
32
+:
32
])));
$
error
(
"Error: address ranges overlap (instance %m)"
);
$
finish
;
end
end
end
end
end
localparam
[
2
:
0
]
STATE_IDLE
=
3'd0
,
STATE_DECODE
=
3'd1
,
STATE_WRITE
=
3'd2
,
STATE_WRITE_RESP
=
3'd3
,
STATE_WRITE_DROP
=
3'd4
,
STATE_READ
=
3'd5
,
STATE_READ_DROP
=
3'd6
,
STATE_WAIT_IDLE
=
3'd7
;
reg
[
2
:
0
]
state_reg
=
STATE_IDLE
,
state_next
;
reg
match
;
reg
[
CL_M_COUNT
-
1
:
0
]
m_select_reg
=
2'd0
,
m_select_next
;
reg
[
ID_WIDTH
-
1
:
0
]
axi_id_reg
=
{
ID_WIDTH
{
1'b0
}}
,
axi_id_next
;
reg
[
ADDR_WIDTH
-
1
:
0
]
axi_addr_reg
=
{
ADDR_WIDTH
{
1'b0
}}
,
axi_addr_next
;
reg
axi_addr_valid_reg
=
1'b0
,
axi_addr_valid_next
;
reg
[
7
:
0
]
axi_len_reg
=
8'd0
,
axi_len_next
;
reg
[
2
:
0
]
axi_size_reg
=
3'd0
,
axi_size_next
;
reg
[
1
:
0
]
axi_burst_reg
=
2'd0
,
axi_burst_next
;
reg
axi_lock_reg
=
1'b0
,
axi_lock_next
;
reg
[
3
:
0
]
axi_cache_reg
=
4'd0
,
axi_cache_next
;
reg
[
2
:
0
]
axi_prot_reg
=
3'b000
,
axi_prot_next
;
reg
[
3
:
0
]
axi_qos_reg
=
4'd0
,
axi_qos_next
;
reg
[
3
:
0
]
axi_region_reg
=
4'd0
,
axi_region_next
;
reg
[
AUSER_WIDTH
-
1
:
0
]
axi_auser_reg
=
{
AUSER_WIDTH
{
1'b0
}}
,
axi_auser_next
;
reg
[
1
:
0
]
axi_bresp_reg
=
2'b00
,
axi_bresp_next
;
reg
[
BUSER_WIDTH
-
1
:
0
]
axi_buser_reg
=
{
BUSER_WIDTH
{
1'b0
}}
,
axi_buser_next
;
reg
[
S_COUNT
-
1
:
0
]
s_axi_awready_reg
=
0
,
s_axi_awready_next
;
reg
[
S_COUNT
-
1
:
0
]
s_axi_wready_reg
=
0
,
s_axi_wready_next
;
reg
[
S_COUNT
-
1
:
0
]
s_axi_bvalid_reg
=
0
,
s_axi_bvalid_next
;
reg
[
S_COUNT
-
1
:
0
]
s_axi_arready_reg
=
0
,
s_axi_arready_next
;
reg
[
M_COUNT
-
1
:
0
]
m_axi_awvalid_reg
=
0
,
m_axi_awvalid_next
;
reg
[
M_COUNT
-
1
:
0
]
m_axi_bready_reg
=
0
,
m_axi_bready_next
;
reg
[
M_COUNT
-
1
:
0
]
m_axi_arvalid_reg
=
0
,
m_axi_arvalid_next
;
reg
[
M_COUNT
-
1
:
0
]
m_axi_rready_reg
=
0
,
m_axi_rready_next
;
// internal datapath
reg
[
ID_WIDTH
-
1
:
0
]
s_axi_rid_int
;
reg
[
DATA_WIDTH
-
1
:
0
]
s_axi_rdata_int
;
reg
[
1
:
0
]
s_axi_rresp_int
;
reg
s_axi_rlast_int
;
reg
[
RUSER_WIDTH
-
1
:
0
]
s_axi_ruser_int
;
reg
s_axi_rvalid_int
;
reg
s_axi_rready_int_reg
=
1'b0
;
wire
s_axi_rready_int_early
;
reg
[
DATA_WIDTH
-
1
:
0
]
m_axi_wdata_int
;
reg
[
STRB_WIDTH
-
1
:
0
]
m_axi_wstrb_int
;
reg
m_axi_wlast_int
;
reg
[
WUSER_WIDTH
-
1
:
0
]
m_axi_wuser_int
;
reg
m_axi_wvalid_int
;
reg
m_axi_wready_int_reg
=
1'b0
;
wire
m_axi_wready_int_early
;
assign
s_axi_awready
=
s_axi_awready_reg
;
assign
s_axi_wready
=
s_axi_wready_reg
;
assign
s_axi_bid
=
{
S_COUNT
{
axi_id_reg
}}
;
assign
s_axi_bresp
=
{
S_COUNT
{
axi_bresp_reg
}}
;
assign
s_axi_buser
=
{
S_COUNT
{
BUSER_ENABLE
?
axi_buser_reg
:
{
BUSER_WIDTH
{
1'b0
}}}}
;
assign
s_axi_bvalid
=
s_axi_bvalid_reg
;
assign
s_axi_arready
=
s_axi_arready_reg
;
assign
m_axi_awid
=
{
M_COUNT
{
FORWARD_ID
?
axi_id_reg
:
{
ID_WIDTH
{
1'b0
}}}}
;
assign
m_axi_awaddr
=
{
M_COUNT
{
axi_addr_reg
}}
;
assign
m_axi_awlen
=
{
M_COUNT
{
axi_len_reg
}}
;
assign
m_axi_awsize
=
{
M_COUNT
{
axi_size_reg
}}
;
assign
m_axi_awburst
=
{
M_COUNT
{
axi_burst_reg
}}
;
assign
m_axi_awlock
=
{
M_COUNT
{
axi_lock_reg
}}
;
assign
m_axi_awcache
=
{
M_COUNT
{
axi_cache_reg
}}
;
assign
m_axi_awprot
=
{
M_COUNT
{
axi_prot_reg
}}
;
assign
m_axi_awqos
=
{
M_COUNT
{
axi_qos_reg
}}
;
assign
m_axi_awregion
=
{
M_COUNT
{
axi_region_reg
}}
;
assign
m_axi_awuser
=
{
M_COUNT
{
AWUSER_ENABLE
?
axi_auser_reg
[
AWUSER_WIDTH
-
1
:
0
]
:
{
AWUSER_WIDTH
{
1'b0
}}}}
;
assign
m_axi_awvalid
=
m_axi_awvalid_reg
;
assign
m_axi_bready
=
m_axi_bready_reg
;
assign
m_axi_arid
=
{
M_COUNT
{
FORWARD_ID
?
axi_id_reg
:
{
ID_WIDTH
{
1'b0
}}}}
;
assign
m_axi_araddr
=
{
M_COUNT
{
axi_addr_reg
}}
;
assign
m_axi_arlen
=
{
M_COUNT
{
axi_len_reg
}}
;
assign
m_axi_arsize
=
{
M_COUNT
{
axi_size_reg
}}
;
assign
m_axi_arburst
=
{
M_COUNT
{
axi_burst_reg
}}
;
assign
m_axi_arlock
=
{
M_COUNT
{
axi_lock_reg
}}
;
assign
m_axi_arcache
=
{
M_COUNT
{
axi_cache_reg
}}
;
assign
m_axi_arprot
=
{
M_COUNT
{
axi_prot_reg
}}
;
assign
m_axi_arqos
=
{
M_COUNT
{
axi_qos_reg
}}
;
assign
m_axi_arregion
=
{
M_COUNT
{
axi_region_reg
}}
;
assign
m_axi_aruser
=
{
M_COUNT
{
ARUSER_ENABLE
?
axi_auser_reg
[
ARUSER_WIDTH
-
1
:
0
]
:
{
ARUSER_WIDTH
{
1'b0
}}}}
;
assign
m_axi_arvalid
=
m_axi_arvalid_reg
;
assign
m_axi_rready
=
m_axi_rready_reg
;
// slave side mux
wire
[(
CL_S_COUNT
>
0
?
CL_S_COUNT
-
1
:
0
)
:
0
]
s_select
;
wire
[
ID_WIDTH
-
1
:
0
]
current_s_axi_awid
=
s_axi_awid
[
s_select
*
ID_WIDTH
+:
ID_WIDTH
];
wire
[
ADDR_WIDTH
-
1
:
0
]
current_s_axi_awaddr
=
s_axi_awaddr
[
s_select
*
ADDR_WIDTH
+:
ADDR_WIDTH
];
wire
[
7
:
0
]
current_s_axi_awlen
=
s_axi_awlen
[
s_select
*
8
+:
8
];
wire
[
2
:
0
]
current_s_axi_awsize
=
s_axi_awsize
[
s_select
*
3
+:
3
];
wire
[
1
:
0
]
current_s_axi_awburst
=
s_axi_awburst
[
s_select
*
2
+:
2
];
wire
current_s_axi_awlock
=
s_axi_awlock
[
s_select
];
wire
[
3
:
0
]
current_s_axi_awcache
=
s_axi_awcache
[
s_select
*
4
+:
4
];
wire
[
2
:
0
]
current_s_axi_awprot
=
s_axi_awprot
[
s_select
*
3
+:
3
];
wire
[
3
:
0
]
current_s_axi_awqos
=
s_axi_awqos
[
s_select
*
4
+:
4
];
wire
[
AWUSER_WIDTH
-
1
:
0
]
current_s_axi_awuser
=
s_axi_awuser
[
s_select
*
AWUSER_WIDTH
+:
AWUSER_WIDTH
];
wire
current_s_axi_awvalid
=
s_axi_awvalid
[
s_select
];
wire
current_s_axi_awready
=
s_axi_awready
[
s_select
];
wire
[
DATA_WIDTH
-
1
:
0
]
current_s_axi_wdata
=
s_axi_wdata
[
s_select
*
DATA_WIDTH
+:
DATA_WIDTH
];
wire
[
STRB_WIDTH
-
1
:
0
]
current_s_axi_wstrb
=
s_axi_wstrb
[
s_select
*
STRB_WIDTH
+:
STRB_WIDTH
];
wire
current_s_axi_wlast
=
s_axi_wlast
[
s_select
];
wire
[
WUSER_WIDTH
-
1
:
0
]
current_s_axi_wuser
=
s_axi_wuser
[
s_select
*
WUSER_WIDTH
+:
WUSER_WIDTH
];
wire
current_s_axi_wvalid
=
s_axi_wvalid
[
s_select
];
wire
current_s_axi_wready
=
s_axi_wready
[
s_select
];
wire
[
ID_WIDTH
-
1
:
0
]
current_s_axi_bid
=
s_axi_bid
[
s_select
*
ID_WIDTH
+:
ID_WIDTH
];
wire
[
1
:
0
]
current_s_axi_bresp
=
s_axi_bresp
[
s_select
*
2
+:
2
];
wire
[
BUSER_WIDTH
-
1
:
0
]
current_s_axi_buser
=
s_axi_buser
[
s_select
*
BUSER_WIDTH
+:
BUSER_WIDTH
];
wire
current_s_axi_bvalid
=
s_axi_bvalid
[
s_select
];
wire
current_s_axi_bready
=
s_axi_bready
[
s_select
];
wire
[
ID_WIDTH
-
1
:
0
]
current_s_axi_arid
=
s_axi_arid
[
s_select
*
ID_WIDTH
+:
ID_WIDTH
];
wire
[
ADDR_WIDTH
-
1
:
0
]
current_s_axi_araddr
=
s_axi_araddr
[
s_select
*
ADDR_WIDTH
+:
ADDR_WIDTH
];
wire
[
7
:
0
]
current_s_axi_arlen
=
s_axi_arlen
[
s_select
*
8
+:
8
];
wire
[
2
:
0
]
current_s_axi_arsize
=
s_axi_arsize
[
s_select
*
3
+:
3
];
wire
[
1
:
0
]
current_s_axi_arburst
=
s_axi_arburst
[
s_select
*
2
+:
2
];
wire
current_s_axi_arlock
=
s_axi_arlock
[
s_select
];
wire
[
3
:
0
]
current_s_axi_arcache
=
s_axi_arcache
[
s_select
*
4
+:
4
];
wire
[
2
:
0
]
current_s_axi_arprot
=
s_axi_arprot
[
s_select
*
3
+:
3
];
wire
[
3
:
0
]
current_s_axi_arqos
=
s_axi_arqos
[
s_select
*
4
+:
4
];
wire
[
ARUSER_WIDTH
-
1
:
0
]
current_s_axi_aruser
=
s_axi_aruser
[
s_select
*
ARUSER_WIDTH
+:
ARUSER_WIDTH
];
wire
current_s_axi_arvalid
=
s_axi_arvalid
[
s_select
];
wire
current_s_axi_arready
=
s_axi_arready
[
s_select
];
wire
[
ID_WIDTH
-
1
:
0
]
current_s_axi_rid
=
s_axi_rid
[
s_select
*
ID_WIDTH
+:
ID_WIDTH
];
wire
[
DATA_WIDTH
-
1
:
0
]
current_s_axi_rdata
=
s_axi_rdata
[
s_select
*
DATA_WIDTH
+:
DATA_WIDTH
];
wire
[
1
:
0
]
current_s_axi_rresp
=
s_axi_rresp
[
s_select
*
2
+:
2
];
wire
current_s_axi_rlast
=
s_axi_rlast
[
s_select
];
wire
[
RUSER_WIDTH
-
1
:
0
]
current_s_axi_ruser
=
s_axi_ruser
[
s_select
*
RUSER_WIDTH
+:
RUSER_WIDTH
];
wire
current_s_axi_rvalid
=
s_axi_rvalid
[
s_select
];
wire
current_s_axi_rready
=
s_axi_rready
[
s_select
];
// master side mux
wire
[
ID_WIDTH
-
1
:
0
]
current_m_axi_awid
=
m_axi_awid
[
m_select_reg
*
ID_WIDTH
+:
ID_WIDTH
];
wire
[
ADDR_WIDTH
-
1
:
0
]
current_m_axi_awaddr
=
m_axi_awaddr
[
m_select_reg
*
ADDR_WIDTH
+:
ADDR_WIDTH
];
wire
[
7
:
0
]
current_m_axi_awlen
=
m_axi_awlen
[
m_select_reg
*
8
+:
8
];
wire
[
2
:
0
]
current_m_axi_awsize
=
m_axi_awsize
[
m_select_reg
*
3
+:
3
];
wire
[
1
:
0
]
current_m_axi_awburst
=
m_axi_awburst
[
m_select_reg
*
2
+:
2
];
wire
current_m_axi_awlock
=
m_axi_awlock
[
m_select_reg
];
wire
[
3
:
0
]
current_m_axi_awcache
=
m_axi_awcache
[
m_select_reg
*
4
+:
4
];
wire
[
2
:
0
]
current_m_axi_awprot
=
m_axi_awprot
[
m_select_reg
*
3
+:
3
];
wire
[
3
:
0
]
current_m_axi_awqos
=
m_axi_awqos
[
m_select_reg
*
4
+:
4
];
wire
[
3
:
0
]
current_m_axi_awregion
=
m_axi_awregion
[
m_select_reg
*
4
+:
4
];
wire
[
AWUSER_WIDTH
-
1
:
0
]
current_m_axi_awuser
=
m_axi_awuser
[
m_select_reg
*
AWUSER_WIDTH
+:
AWUSER_WIDTH
];
wire
current_m_axi_awvalid
=
m_axi_awvalid
[
m_select_reg
];
wire
current_m_axi_awready
=
m_axi_awready
[
m_select_reg
];
wire
[
DATA_WIDTH
-
1
:
0
]
current_m_axi_wdata
=
m_axi_wdata
[
m_select_reg
*
DATA_WIDTH
+:
DATA_WIDTH
];
wire
[
STRB_WIDTH
-
1
:
0
]
current_m_axi_wstrb
=
m_axi_wstrb
[
m_select_reg
*
STRB_WIDTH
+:
STRB_WIDTH
];
wire
current_m_axi_wlast
=
m_axi_wlast
[
m_select_reg
];
wire
[
WUSER_WIDTH
-
1
:
0
]
current_m_axi_wuser
=
m_axi_wuser
[
m_select_reg
*
WUSER_WIDTH
+:
WUSER_WIDTH
];
wire
current_m_axi_wvalid
=
m_axi_wvalid
[
m_select_reg
];
wire
current_m_axi_wready
=
m_axi_wready
[
m_select_reg
];
wire
[
ID_WIDTH
-
1
:
0
]
current_m_axi_bid
=
m_axi_bid
[
m_select_reg
*
ID_WIDTH
+:
ID_WIDTH
];
wire
[
1
:
0
]
current_m_axi_bresp
=
m_axi_bresp
[
m_select_reg
*
2
+:
2
];
wire
[
BUSER_WIDTH
-
1
:
0
]
current_m_axi_buser
=
m_axi_buser
[
m_select_reg
*
BUSER_WIDTH
+:
BUSER_WIDTH
];
wire
current_m_axi_bvalid
=
m_axi_bvalid
[
m_select_reg
];
wire
current_m_axi_bready
=
m_axi_bready
[
m_select_reg
];
wire
[
ID_WIDTH
-
1
:
0
]
current_m_axi_arid
=
m_axi_arid
[
m_select_reg
*
ID_WIDTH
+:
ID_WIDTH
];
wire
[
ADDR_WIDTH
-
1
:
0
]
current_m_axi_araddr
=
m_axi_araddr
[
m_select_reg
*
ADDR_WIDTH
+:
ADDR_WIDTH
];
wire
[
7
:
0
]
current_m_axi_arlen
=
m_axi_arlen
[
m_select_reg
*
8
+:
8
];
wire
[
2
:
0
]
current_m_axi_arsize
=
m_axi_arsize
[
m_select_reg
*
3
+:
3
];
wire
[
1
:
0
]
current_m_axi_arburst
=
m_axi_arburst
[
m_select_reg
*
2
+:
2
];
wire
current_m_axi_arlock
=
m_axi_arlock
[
m_select_reg
];
wire
[
3
:
0
]
current_m_axi_arcache
=
m_axi_arcache
[
m_select_reg
*
4
+:
4
];
wire
[
2
:
0
]
current_m_axi_arprot
=
m_axi_arprot
[
m_select_reg
*
3
+:
3
];
wire
[
3
:
0
]
current_m_axi_arqos
=
m_axi_arqos
[
m_select_reg
*
4
+:
4
];
wire
[
3
:
0
]
current_m_axi_arregion
=
m_axi_arregion
[
m_select_reg
*
4
+:
4
];
wire
[
ARUSER_WIDTH
-
1
:
0
]
current_m_axi_aruser
=
m_axi_aruser
[
m_select_reg
*
ARUSER_WIDTH
+:
ARUSER_WIDTH
];
wire
current_m_axi_arvalid
=
m_axi_arvalid
[
m_select_reg
];
wire
current_m_axi_arready
=
m_axi_arready
[
m_select_reg
];
wire
[
ID_WIDTH
-
1
:
0
]
current_m_axi_rid
=
m_axi_rid
[
m_select_reg
*
ID_WIDTH
+:
ID_WIDTH
];
wire
[
DATA_WIDTH
-
1
:
0
]
current_m_axi_rdata
=
m_axi_rdata
[
m_select_reg
*
DATA_WIDTH
+:
DATA_WIDTH
];
wire
[
1
:
0
]
current_m_axi_rresp
=
m_axi_rresp
[
m_select_reg
*
2
+:
2
];
wire
current_m_axi_rlast
=
m_axi_rlast
[
m_select_reg
];
wire
[
RUSER_WIDTH
-
1
:
0
]
current_m_axi_ruser
=
m_axi_ruser
[
m_select_reg
*
RUSER_WIDTH
+:
RUSER_WIDTH
];
wire
current_m_axi_rvalid
=
m_axi_rvalid
[
m_select_reg
];
wire
current_m_axi_rready
=
m_axi_rready
[
m_select_reg
];
// arbiter instance
wire
[
S_COUNT
*
2
-
1
:
0
]
request
;
wire
[
S_COUNT
*
2
-
1
:
0
]
acknowledge
;
wire
[
S_COUNT
*
2
-
1
:
0
]
grant
;
wire
grant_valid
;
wire
[
CL_S_COUNT
:
0
]
grant_encoded
;
wire
read
=
grant_encoded
[
0
];
assign
s_select
=
grant_encoded
>>
1
;
arbiter
#(
.
PORTS
(
S_COUNT
*
2
),
.
TYPE
(
"ROUND_ROBIN"
),
.
BLOCK
(
"ACKNOWLEDGE"
),
.
LSB_PRIORITY
(
"HIGH"
)
)
arb_inst
(
.
clk
(
clk
),
.
rst
(
rst
),
.
request
(
request
),
.
acknowledge
(
acknowledge
),
.
grant
(
grant
),
.
grant_valid
(
grant_valid
),
.
grant_encoded
(
grant_encoded
)
);
genvar
n
;
// request generation
generate
for
(
n
=
0
;
n
<
S_COUNT
;
n
=
n
+
1
)
begin
assign
request
[
2
*
n
]
=
s_axi_awvalid
[
n
];
assign
request
[
2
*
n
+
1
]
=
s_axi_arvalid
[
n
];
end
endgenerate
// acknowledge generation
generate
for
(
n
=
0
;
n
<
S_COUNT
;
n
=
n
+
1
)
begin
assign
acknowledge
[
2
*
n
]
=
grant
[
2
*
n
]
&&
s_axi_bvalid
[
n
]
&&
s_axi_bready
[
n
];
assign
acknowledge
[
2
*
n
+
1
]
=
grant
[
2
*
n
+
1
]
&&
s_axi_rvalid
[
n
]
&&
s_axi_rready
[
n
]
&&
s_axi_rlast
[
n
];
end
endgenerate
always
@*
begin
state_next
=
STATE_IDLE
;
match
=
1'b0
;
m_select_next
=
m_select_reg
;
axi_id_next
=
axi_id_reg
;
axi_addr_next
=
axi_addr_reg
;
axi_addr_valid_next
=
axi_addr_valid_reg
;
axi_len_next
=
axi_len_reg
;
axi_size_next
=
axi_size_reg
;
axi_burst_next
=
axi_burst_reg
;
axi_lock_next
=
axi_lock_reg
;
axi_cache_next
=
axi_cache_reg
;
axi_prot_next
=
axi_prot_reg
;
axi_qos_next
=
axi_qos_reg
;
axi_region_next
=
axi_region_reg
;
axi_auser_next
=
axi_auser_reg
;
axi_bresp_next
=
axi_bresp_reg
;
axi_buser_next
=
axi_buser_reg
;
s_axi_awready_next
=
0
;
s_axi_wready_next
=
0
;
s_axi_bvalid_next
=
s_axi_bvalid_reg
&
~
s_axi_bready
;
s_axi_arready_next
=
0
;
m_axi_awvalid_next
=
m_axi_awvalid_reg
&
~
m_axi_awready
;
m_axi_bready_next
=
0
;
m_axi_arvalid_next
=
m_axi_arvalid_reg
&
~
m_axi_arready
;
m_axi_rready_next
=
0
;
s_axi_rid_int
=
axi_id_reg
;
s_axi_rdata_int
=
current_m_axi_rdata
;
s_axi_rresp_int
=
current_m_axi_rresp
;
s_axi_rlast_int
=
current_m_axi_rlast
;
s_axi_ruser_int
=
current_m_axi_ruser
;
s_axi_rvalid_int
=
1'b0
;
m_axi_wdata_int
=
current_s_axi_wdata
;
m_axi_wstrb_int
=
current_s_axi_wstrb
;
m_axi_wlast_int
=
current_s_axi_wlast
;
m_axi_wuser_int
=
current_s_axi_wuser
;
m_axi_wvalid_int
=
1'b0
;
case
(
state_reg
)
STATE_IDLE:
begin
// idle state; wait for arbitration
if
(
grant_valid
)
begin
axi_addr_valid_next
=
1'b1
;
if
(
read
)
begin
// reading
axi_addr_next
=
current_s_axi_araddr
;
axi_prot_next
=
current_s_axi_arprot
;
axi_id_next
=
current_s_axi_arid
;
axi_addr_next
=
current_s_axi_araddr
;
axi_len_next
=
current_s_axi_arlen
;
axi_size_next
=
current_s_axi_arsize
;
axi_burst_next
=
current_s_axi_arburst
;
axi_lock_next
=
current_s_axi_arlock
;
axi_cache_next
=
current_s_axi_arcache
;
axi_prot_next
=
current_s_axi_arprot
;
axi_qos_next
=
current_s_axi_arqos
;
axi_auser_next
=
current_s_axi_aruser
;
s_axi_arready_next
[
s_select
]
=
1'b1
;
end
else
begin
// writing
axi_addr_next
=
current_s_axi_awaddr
;
axi_prot_next
=
current_s_axi_awprot
;
axi_id_next
=
current_s_axi_awid
;
axi_addr_next
=
current_s_axi_awaddr
;
axi_len_next
=
current_s_axi_awlen
;
axi_size_next
=
current_s_axi_awsize
;
axi_burst_next
=
current_s_axi_awburst
;
axi_lock_next
=
current_s_axi_awlock
;
axi_cache_next
=
current_s_axi_awcache
;
axi_prot_next
=
current_s_axi_awprot
;
axi_qos_next
=
current_s_axi_awqos
;
axi_auser_next
=
current_s_axi_awuser
;
s_axi_awready_next
[
s_select
]
=
1'b1
;
end
state_next
=
STATE_DECODE
;
end
else
begin
state_next
=
STATE_IDLE
;
end
end
STATE_DECODE:
begin
// decode state; determine master interface
match
=
1'b0
;
for
(
i
=
0
;
i
<
M_COUNT
;
i
=
i
+
1
)
begin
for
(
j
=
0
;
j
<
M_REGIONS
;
j
=
j
+
1
)
begin
if
(
M_ADDR_WIDTH
[(
i
*
M_REGIONS
+
j
)
*
32
+:
32
]
&&
(
!
M_SECURE
[
i
]
||
!
axi_prot_reg
[
1
])
&&
((
read
?
M_CONNECT_READ
:
M_CONNECT_WRITE
)
&
(
1
<<
(
s_select
+
i
*
S_COUNT
)))
&&
(
axi_addr_reg
>>
M_ADDR_WIDTH
[(
i
*
M_REGIONS
+
j
)
*
32
+:
32
])
==
(
M_BASE_ADDR_INT
[(
i
*
M_REGIONS
+
j
)
*
ADDR_WIDTH
+:
ADDR_WIDTH
]
>>
M_ADDR_WIDTH
[(
i
*
M_REGIONS
+
j
)
*
32
+:
32
]))
begin
m_select_next
=
i
;
axi_region_next
=
j
;
match
=
1'b1
;
end
end
end
if
(
match
)
begin
if
(
read
)
begin
// reading
m_axi_rready_next
[
m_select_reg
]
=
s_axi_rready_int_early
;
state_next
=
STATE_READ
;
end
else
begin
// writing
s_axi_wready_next
[
s_select
]
=
m_axi_wready_int_early
;
state_next
=
STATE_WRITE
;
end
end
else
begin
// no match; return decode error
if
(
read
)
begin
// reading
state_next
=
STATE_READ_DROP
;
end
else
begin
// writing
axi_bresp_next
=
2'b11
;
s_axi_wready_next
[
s_select
]
=
1'b1
;
state_next
=
STATE_WRITE_DROP
;
end
end
end
STATE_WRITE:
begin
// write state; store and forward write data
s_axi_wready_next
[
s_select
]
=
m_axi_wready_int_early
;
if
(
axi_addr_valid_reg
)
begin
m_axi_awvalid_next
[
m_select_reg
]
=
1'b1
;
end
axi_addr_valid_next
=
1'b0
;
if
(
current_s_axi_wready
&&
current_s_axi_wvalid
)
begin
m_axi_wdata_int
=
current_s_axi_wdata
;
m_axi_wstrb_int
=
current_s_axi_wstrb
;
m_axi_wlast_int
=
current_s_axi_wlast
;
m_axi_wuser_int
=
current_s_axi_wuser
;
m_axi_wvalid_int
=
1'b1
;
if
(
current_s_axi_wlast
)
begin
s_axi_wready_next
[
s_select
]
=
1'b0
;
m_axi_bready_next
[
m_select_reg
]
=
1'b1
;
state_next
=
STATE_WRITE_RESP
;
end
else
begin
state_next
=
STATE_WRITE
;
end
end
else
begin
state_next
=
STATE_WRITE
;
end
end
STATE_WRITE_RESP:
begin
// write response state; store and forward write response
m_axi_bready_next
[
m_select_reg
]
=
1'b1
;
if
(
current_m_axi_bready
&&
current_m_axi_bvalid
)
begin
m_axi_bready_next
[
m_select_reg
]
=
1'b0
;
axi_bresp_next
=
current_m_axi_bresp
;
s_axi_bvalid_next
[
s_select
]
=
1'b1
;
state_next
=
STATE_WAIT_IDLE
;
end
else
begin
state_next
=
STATE_WRITE_RESP
;
end
end
STATE_WRITE_DROP:
begin
// write drop state; drop write data
s_axi_wready_next
[
s_select
]
=
1'b1
;
axi_addr_valid_next
=
1'b0
;
if
(
current_s_axi_wready
&&
current_s_axi_wvalid
)
begin
s_axi_wready_next
[
s_select
]
=
1'b0
;
s_axi_bvalid_next
[
s_select
]
=
1'b1
;
state_next
=
STATE_WAIT_IDLE
;
end
else
begin
state_next
=
STATE_WRITE_DROP
;
end
end
STATE_READ:
begin
// read state; store and forward read response
m_axi_rready_next
[
m_select_reg
]
=
s_axi_rready_int_early
;
if
(
axi_addr_valid_reg
)
begin
m_axi_arvalid_next
[
m_select_reg
]
=
1'b1
;
end
axi_addr_valid_next
=
1'b0
;
if
(
current_m_axi_rready
&&
current_m_axi_rvalid
)
begin
s_axi_rid_int
=
axi_id_reg
;
s_axi_rdata_int
=
current_m_axi_rdata
;
s_axi_rresp_int
=
current_m_axi_rresp
;
s_axi_rlast_int
=
current_m_axi_rlast
;
s_axi_ruser_int
=
current_m_axi_ruser
;
s_axi_rvalid_int
=
1'b1
;
if
(
current_m_axi_rlast
)
begin
m_axi_rready_next
[
m_select_reg
]
=
1'b0
;
state_next
=
STATE_WAIT_IDLE
;
end
else
begin
state_next
=
STATE_READ
;
end
end
else
begin
state_next
=
STATE_READ
;
end
end
STATE_READ_DROP:
begin
// read drop state; generate decode error read response
s_axi_rid_int
=
axi_id_reg
;
s_axi_rdata_int
=
{
DATA_WIDTH
{
1'b0
}}
;
s_axi_rresp_int
=
2'b11
;
s_axi_rlast_int
=
axi_len_reg
==
0
;
s_axi_ruser_int
=
{
RUSER_WIDTH
{
1'b0
}}
;
s_axi_rvalid_int
=
1'b1
;
if
(
s_axi_rready_int_reg
)
begin
axi_len_next
=
axi_len_reg
-
1
;
if
(
axi_len_reg
==
0
)
begin
state_next
=
STATE_WAIT_IDLE
;
end
else
begin
state_next
=
STATE_READ_DROP
;
end
end
else
begin
state_next
=
STATE_READ_DROP
;
end
end
STATE_WAIT_IDLE:
begin
// wait for idle state; wait untl grant valid is deasserted
if
(
!
grant_valid
||
acknowledge
)
begin
state_next
=
STATE_IDLE
;
end
else
begin
state_next
=
STATE_WAIT_IDLE
;
end
end
endcase
end
always
@
(
posedge
clk
)
begin
if
(
rst
)
begin
state_reg
<=
STATE_IDLE
;
s_axi_awready_reg
<=
0
;
s_axi_wready_reg
<=
0
;
s_axi_bvalid_reg
<=
0
;
s_axi_arready_reg
<=
0
;
m_axi_awvalid_reg
<=
0
;
m_axi_bready_reg
<=
0
;
m_axi_arvalid_reg
<=
0
;
m_axi_rready_reg
<=
0
;
end
else
begin
state_reg
<=
state_next
;
s_axi_awready_reg
<=
s_axi_awready_next
;
s_axi_wready_reg
<=
s_axi_wready_next
;
s_axi_bvalid_reg
<=
s_axi_bvalid_next
;
s_axi_arready_reg
<=
s_axi_arready_next
;
m_axi_awvalid_reg
<=
m_axi_awvalid_next
;
m_axi_bready_reg
<=
m_axi_bready_next
;
m_axi_arvalid_reg
<=
m_axi_arvalid_next
;
m_axi_rready_reg
<=
m_axi_rready_next
;
end
m_select_reg
<=
m_select_next
;
axi_id_reg
<=
axi_id_next
;
axi_addr_reg
<=
axi_addr_next
;
axi_addr_valid_reg
<=
axi_addr_valid_next
;
axi_len_reg
<=
axi_len_next
;
axi_size_reg
<=
axi_size_next
;
axi_burst_reg
<=
axi_burst_next
;
axi_lock_reg
<=
axi_lock_next
;
axi_cache_reg
<=
axi_cache_next
;
axi_prot_reg
<=
axi_prot_next
;
axi_qos_reg
<=
axi_qos_next
;
axi_region_reg
<=
axi_region_next
;
axi_auser_reg
<=
axi_auser_next
;
axi_bresp_reg
<=
axi_bresp_next
;
axi_buser_reg
<=
axi_buser_next
;
end
// output datapath logic (R channel)
reg
[
ID_WIDTH
-
1
:
0
]
s_axi_rid_reg
=
{
ID_WIDTH
{
1'b0
}}
;
reg
[
DATA_WIDTH
-
1
:
0
]
s_axi_rdata_reg
=
{
DATA_WIDTH
{
1'b0
}}
;
reg
[
1
:
0
]
s_axi_rresp_reg
=
2'd0
;
reg
s_axi_rlast_reg
=
1'b0
;
reg
[
RUSER_WIDTH
-
1
:
0
]
s_axi_ruser_reg
=
1'b0
;
reg
[
S_COUNT
-
1
:
0
]
s_axi_rvalid_reg
=
1'b0
,
s_axi_rvalid_next
;
reg
[
ID_WIDTH
-
1
:
0
]
temp_s_axi_rid_reg
=
{
ID_WIDTH
{
1'b0
}}
;
reg
[
DATA_WIDTH
-
1
:
0
]
temp_s_axi_rdata_reg
=
{
DATA_WIDTH
{
1'b0
}}
;
reg
[
1
:
0
]
temp_s_axi_rresp_reg
=
2'd0
;
reg
temp_s_axi_rlast_reg
=
1'b0
;
reg
[
RUSER_WIDTH
-
1
:
0
]
temp_s_axi_ruser_reg
=
1'b0
;
reg
temp_s_axi_rvalid_reg
=
1'b0
,
temp_s_axi_rvalid_next
;
// datapath control
reg
store_axi_r_int_to_output
;
reg
store_axi_r_int_to_temp
;
reg
store_axi_r_temp_to_output
;
assign
s_axi_rid
=
{
S_COUNT
{
s_axi_rid_reg
}}
;
assign
s_axi_rdata
=
{
S_COUNT
{
s_axi_rdata_reg
}}
;
assign
s_axi_rresp
=
{
S_COUNT
{
s_axi_rresp_reg
}}
;
assign
s_axi_rlast
=
{
S_COUNT
{
s_axi_rlast_reg
}}
;
assign
s_axi_ruser
=
{
S_COUNT
{
RUSER_ENABLE
?
s_axi_ruser_reg
:
{
RUSER_WIDTH
{
1'b0
}}}}
;
assign
s_axi_rvalid
=
s_axi_rvalid_reg
;
// enable ready input next cycle if output is ready or the temp reg will not be filled on the next cycle (output reg empty or no input)
assign
s_axi_rready_int_early
=
current_s_axi_rready
|
(
~
temp_s_axi_rvalid_reg
&
(
~
current_s_axi_rvalid
|
~
s_axi_rvalid_int
));
always
@*
begin
// transfer sink ready state to source
s_axi_rvalid_next
=
s_axi_rvalid_reg
;
temp_s_axi_rvalid_next
=
temp_s_axi_rvalid_reg
;
store_axi_r_int_to_output
=
1'b0
;
store_axi_r_int_to_temp
=
1'b0
;
store_axi_r_temp_to_output
=
1'b0
;
if
(
s_axi_rready_int_reg
)
begin
// input is ready
if
(
current_s_axi_rready
|
~
current_s_axi_rvalid
)
begin
// output is ready or currently not valid, transfer data to output
s_axi_rvalid_next
[
s_select
]
=
s_axi_rvalid_int
;
store_axi_r_int_to_output
=
1'b1
;
end
else
begin
// output is not ready, store input in temp
temp_s_axi_rvalid_next
=
s_axi_rvalid_int
;
store_axi_r_int_to_temp
=
1'b1
;
end
end
else
if
(
current_s_axi_rready
)
begin
// input is not ready, but output is ready
s_axi_rvalid_next
[
s_select
]
=
temp_s_axi_rvalid_reg
;
temp_s_axi_rvalid_next
=
1'b0
;
store_axi_r_temp_to_output
=
1'b1
;
end
end
always
@
(
posedge
clk
)
begin
if
(
rst
)
begin
s_axi_rvalid_reg
<=
1'b0
;
s_axi_rready_int_reg
<=
1'b0
;
temp_s_axi_rvalid_reg
<=
1'b0
;
end
else
begin
s_axi_rvalid_reg
<=
s_axi_rvalid_next
;
s_axi_rready_int_reg
<=
s_axi_rready_int_early
;
temp_s_axi_rvalid_reg
<=
temp_s_axi_rvalid_next
;
end
// datapath
if
(
store_axi_r_int_to_output
)
begin
s_axi_rid_reg
<=
s_axi_rid_int
;
s_axi_rdata_reg
<=
s_axi_rdata_int
;
s_axi_rresp_reg
<=
s_axi_rresp_int
;
s_axi_rlast_reg
<=
s_axi_rlast_int
;
s_axi_ruser_reg
<=
s_axi_ruser_int
;
end
else
if
(
store_axi_r_temp_to_output
)
begin
s_axi_rid_reg
<=
temp_s_axi_rid_reg
;
s_axi_rdata_reg
<=
temp_s_axi_rdata_reg
;
s_axi_rresp_reg
<=
temp_s_axi_rresp_reg
;
s_axi_rlast_reg
<=
temp_s_axi_rlast_reg
;
s_axi_ruser_reg
<=
temp_s_axi_ruser_reg
;
end
if
(
store_axi_r_int_to_temp
)
begin
temp_s_axi_rid_reg
<=
s_axi_rid_int
;
temp_s_axi_rdata_reg
<=
s_axi_rdata_int
;
temp_s_axi_rresp_reg
<=
s_axi_rresp_int
;
temp_s_axi_rlast_reg
<=
s_axi_rlast_int
;
temp_s_axi_ruser_reg
<=
s_axi_ruser_int
;
end
end
// output datapath logic (W channel)
reg
[
DATA_WIDTH
-
1
:
0
]
m_axi_wdata_reg
=
{
DATA_WIDTH
{
1'b0
}}
;
reg
[
STRB_WIDTH
-
1
:
0
]
m_axi_wstrb_reg
=
{
STRB_WIDTH
{
1'b0
}}
;
reg
m_axi_wlast_reg
=
1'b0
;
reg
[
WUSER_WIDTH
-
1
:
0
]
m_axi_wuser_reg
=
1'b0
;
reg
[
M_COUNT
-
1
:
0
]
m_axi_wvalid_reg
=
1'b0
,
m_axi_wvalid_next
;
reg
[
DATA_WIDTH
-
1
:
0
]
temp_m_axi_wdata_reg
=
{
DATA_WIDTH
{
1'b0
}}
;
reg
[
STRB_WIDTH
-
1
:
0
]
temp_m_axi_wstrb_reg
=
{
STRB_WIDTH
{
1'b0
}}
;
reg
temp_m_axi_wlast_reg
=
1'b0
;
reg
[
WUSER_WIDTH
-
1
:
0
]
temp_m_axi_wuser_reg
=
1'b0
;
reg
temp_m_axi_wvalid_reg
=
1'b0
,
temp_m_axi_wvalid_next
;
// datapath control
reg
store_axi_w_int_to_output
;
reg
store_axi_w_int_to_temp
;
reg
store_axi_w_temp_to_output
;
assign
m_axi_wdata
=
{
M_COUNT
{
m_axi_wdata_reg
}}
;
assign
m_axi_wstrb
=
{
M_COUNT
{
m_axi_wstrb_reg
}}
;
assign
m_axi_wlast
=
{
M_COUNT
{
m_axi_wlast_reg
}}
;
assign
m_axi_wuser
=
{
M_COUNT
{
WUSER_ENABLE
?
m_axi_wuser_reg
:
{
WUSER_WIDTH
{
1'b0
}}}}
;
assign
m_axi_wvalid
=
m_axi_wvalid_reg
;
// enable ready input next cycle if output is ready or the temp reg will not be filled on the next cycle (output reg empty or no input)
assign
m_axi_wready_int_early
=
current_m_axi_wready
|
(
~
temp_m_axi_wvalid_reg
&
(
~
current_m_axi_wvalid
|
~
m_axi_wvalid_int
));
always
@*
begin
// transfer sink ready state to source
m_axi_wvalid_next
=
m_axi_wvalid_reg
;
temp_m_axi_wvalid_next
=
temp_m_axi_wvalid_reg
;
store_axi_w_int_to_output
=
1'b0
;
store_axi_w_int_to_temp
=
1'b0
;
store_axi_w_temp_to_output
=
1'b0
;
if
(
m_axi_wready_int_reg
)
begin
// input is ready
if
(
current_m_axi_wready
|
~
current_m_axi_wvalid
)
begin
// output is ready or currently not valid, transfer data to output
m_axi_wvalid_next
[
m_select_reg
]
=
m_axi_wvalid_int
;
store_axi_w_int_to_output
=
1'b1
;
end
else
begin
// output is not ready, store input in temp
temp_m_axi_wvalid_next
=
m_axi_wvalid_int
;
store_axi_w_int_to_temp
=
1'b1
;
end
end
else
if
(
current_m_axi_wready
)
begin
// input is not ready, but output is ready
m_axi_wvalid_next
[
m_select_reg
]
=
temp_m_axi_wvalid_reg
;
temp_m_axi_wvalid_next
=
1'b0
;
store_axi_w_temp_to_output
=
1'b1
;
end
end
always
@
(
posedge
clk
)
begin
if
(
rst
)
begin
m_axi_wvalid_reg
<=
1'b0
;
m_axi_wready_int_reg
<=
1'b0
;
temp_m_axi_wvalid_reg
<=
1'b0
;
end
else
begin
m_axi_wvalid_reg
<=
m_axi_wvalid_next
;
m_axi_wready_int_reg
<=
m_axi_wready_int_early
;
temp_m_axi_wvalid_reg
<=
temp_m_axi_wvalid_next
;
end
// datapath
if
(
store_axi_w_int_to_output
)
begin
m_axi_wdata_reg
<=
m_axi_wdata_int
;
m_axi_wstrb_reg
<=
m_axi_wstrb_int
;
m_axi_wlast_reg
<=
m_axi_wlast_int
;
m_axi_wuser_reg
<=
m_axi_wuser_int
;
end
else
if
(
store_axi_w_temp_to_output
)
begin
m_axi_wdata_reg
<=
temp_m_axi_wdata_reg
;
m_axi_wstrb_reg
<=
temp_m_axi_wstrb_reg
;
m_axi_wlast_reg
<=
temp_m_axi_wlast_reg
;
m_axi_wuser_reg
<=
temp_m_axi_wuser_reg
;
end
if
(
store_axi_w_int_to_temp
)
begin
temp_m_axi_wdata_reg
<=
m_axi_wdata_int
;
temp_m_axi_wstrb_reg
<=
m_axi_wstrb_int
;
temp_m_axi_wlast_reg
<=
m_axi_wlast_int
;
temp_m_axi_wuser_reg
<=
m_axi_wuser_int
;
end
end
endmodule
corundum/lib/axi/rtl/axi_ram.v
0 → 100644
View file @
738c1fef
/*
Copyright (c) 2018 Alex Forencich
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.
*/
// Language: Verilog 2001
`timescale
1
ns
/
1
ps
/*
* AXI4 RAM
*/
module
axi_ram
#
(
// Width of data bus in bits
parameter
DATA_WIDTH
=
32
,
// Width of address bus in bits
parameter
ADDR_WIDTH
=
16
,
// Width of wstrb (width of data bus in words)
parameter
STRB_WIDTH
=
(
DATA_WIDTH
/
8
),
// Width of ID signal
parameter
ID_WIDTH
=
8
,
// Extra pipeline register on output
parameter
PIPELINE_OUTPUT
=
0
)
(
input
wire
clk
,
input
wire
rst
,
input
wire
[
ID_WIDTH
-
1
:
0
]
s_axi_awid
,
input
wire
[
ADDR_WIDTH
-
1
:
0
]
s_axi_awaddr
,
input
wire
[
7
:
0
]
s_axi_awlen
,
input
wire
[
2
:
0
]
s_axi_awsize
,
input
wire
[
1
:
0
]
s_axi_awburst
,
input
wire
s_axi_awlock
,
input
wire
[
3
:
0
]
s_axi_awcache
,
input
wire
[
2
:
0
]
s_axi_awprot
,
input
wire
s_axi_awvalid
,
output
wire
s_axi_awready
,
input
wire
[
DATA_WIDTH
-
1
:
0
]
s_axi_wdata
,
input
wire
[
STRB_WIDTH
-
1
:
0
]
s_axi_wstrb
,
input
wire
s_axi_wlast
,
input
wire
s_axi_wvalid
,
output
wire
s_axi_wready
,
output
wire
[
ID_WIDTH
-
1
:
0
]
s_axi_bid
,
output
wire
[
1
:
0
]
s_axi_bresp
,
output
wire
s_axi_bvalid
,
input
wire
s_axi_bready
,
input
wire
[
ID_WIDTH
-
1
:
0
]
s_axi_arid
,
input
wire
[
ADDR_WIDTH
-
1
:
0
]
s_axi_araddr
,
input
wire
[
7
:
0
]
s_axi_arlen
,
input
wire
[
2
:
0
]
s_axi_arsize
,
input
wire
[
1
:
0
]
s_axi_arburst
,
input
wire
s_axi_arlock
,
input
wire
[
3
:
0
]
s_axi_arcache
,
input
wire
[
2
:
0
]
s_axi_arprot
,
input
wire
s_axi_arvalid
,
output
wire
s_axi_arready
,
output
wire
[
ID_WIDTH
-
1
:
0
]
s_axi_rid
,
output
wire
[
DATA_WIDTH
-
1
:
0
]
s_axi_rdata
,
output
wire
[
1
:
0
]
s_axi_rresp
,
output
wire
s_axi_rlast
,
output
wire
s_axi_rvalid
,
input
wire
s_axi_rready
);
parameter
VALID_ADDR_WIDTH
=
ADDR_WIDTH
-
$
clog2
(
STRB_WIDTH
);
parameter
WORD_WIDTH
=
STRB_WIDTH
;
parameter
WORD_SIZE
=
DATA_WIDTH
/
WORD_WIDTH
;
// bus width assertions
initial
begin
if
(
WORD_SIZE
*
STRB_WIDTH
!=
DATA_WIDTH
)
begin
$
error
(
"Error: AXI data width not evenly divisble (instance %m)"
);
$
finish
;
end
if
(
2
**
$
clog2
(
WORD_WIDTH
)
!=
WORD_WIDTH
)
begin
$
error
(
"Error: AXI word width must be even power of two (instance %m)"
);
$
finish
;
end
end
localparam
[
0
:
0
]
READ_STATE_IDLE
=
1'd0
,
READ_STATE_BURST
=
1'd1
;
reg
[
0
:
0
]
read_state_reg
=
READ_STATE_IDLE
,
read_state_next
;
localparam
[
1
:
0
]
WRITE_STATE_IDLE
=
2'd0
,
WRITE_STATE_BURST
=
2'd1
,
WRITE_STATE_RESP
=
2'd2
;
reg
[
1
:
0
]
write_state_reg
=
WRITE_STATE_IDLE
,
write_state_next
;
reg
mem_wr_en
;
reg
mem_rd_en
;
reg
[
ID_WIDTH
-
1
:
0
]
read_id_reg
=
{
ID_WIDTH
{
1'b0
}}
,
read_id_next
;
reg
[
ADDR_WIDTH
-
1
:
0
]
read_addr_reg
=
{
ADDR_WIDTH
{
1'b0
}}
,
read_addr_next
;
reg
[
7
:
0
]
read_count_reg
=
8'd0
,
read_count_next
;
reg
[
2
:
0
]
read_size_reg
=
3'd0
,
read_size_next
;
reg
[
1
:
0
]
read_burst_reg
=
2'd0
,
read_burst_next
;
reg
[
ID_WIDTH
-
1
:
0
]
write_id_reg
=
{
ID_WIDTH
{
1'b0
}}
,
write_id_next
;
reg
[
ADDR_WIDTH
-
1
:
0
]
write_addr_reg
=
{
ADDR_WIDTH
{
1'b0
}}
,
write_addr_next
;
reg
[
7
:
0
]
write_count_reg
=
8'd0
,
write_count_next
;
reg
[
2
:
0
]
write_size_reg
=
3'd0
,
write_size_next
;
reg
[
1
:
0
]
write_burst_reg
=
2'd0
,
write_burst_next
;
reg
s_axi_awready_reg
=
1'b0
,
s_axi_awready_next
;
reg
s_axi_wready_reg
=
1'b0
,
s_axi_wready_next
;
reg
[
ID_WIDTH
-
1
:
0
]
s_axi_bid_reg
=
{
ID_WIDTH
{
1'b0
}}
,
s_axi_bid_next
;
reg
s_axi_bvalid_reg
=
1'b0
,
s_axi_bvalid_next
;
reg
s_axi_arready_reg
=
1'b0
,
s_axi_arready_next
;
reg
[
ID_WIDTH
-
1
:
0
]
s_axi_rid_reg
=
{
ID_WIDTH
{
1'b0
}}
,
s_axi_rid_next
;
reg
[
DATA_WIDTH
-
1
:
0
]
s_axi_rdata_reg
=
{
DATA_WIDTH
{
1'b0
}}
,
s_axi_rdata_next
;
reg
s_axi_rlast_reg
=
1'b0
,
s_axi_rlast_next
;
reg
s_axi_rvalid_reg
=
1'b0
,
s_axi_rvalid_next
;
reg
[
ID_WIDTH
-
1
:
0
]
s_axi_rid_pipe_reg
=
{
ID_WIDTH
{
1'b0
}}
;
reg
[
DATA_WIDTH
-
1
:
0
]
s_axi_rdata_pipe_reg
=
{
DATA_WIDTH
{
1'b0
}}
;
reg
s_axi_rlast_pipe_reg
=
1'b0
;
reg
s_axi_rvalid_pipe_reg
=
1'b0
;
// (* RAM_STYLE="BLOCK" *)
reg
[
DATA_WIDTH
-
1
:
0
]
mem
[(
2
**
VALID_ADDR_WIDTH
)
-
1
:
0
];
wire
[
VALID_ADDR_WIDTH
-
1
:
0
]
s_axi_awaddr_valid
=
s_axi_awaddr
>>
(
ADDR_WIDTH
-
VALID_ADDR_WIDTH
);
wire
[
VALID_ADDR_WIDTH
-
1
:
0
]
s_axi_araddr_valid
=
s_axi_araddr
>>
(
ADDR_WIDTH
-
VALID_ADDR_WIDTH
);
wire
[
VALID_ADDR_WIDTH
-
1
:
0
]
read_addr_valid
=
read_addr_reg
>>
(
ADDR_WIDTH
-
VALID_ADDR_WIDTH
);
wire
[
VALID_ADDR_WIDTH
-
1
:
0
]
write_addr_valid
=
write_addr_reg
>>
(
ADDR_WIDTH
-
VALID_ADDR_WIDTH
);
assign
s_axi_awready
=
s_axi_awready_reg
;
assign
s_axi_wready
=
s_axi_wready_reg
;
assign
s_axi_bid
=
s_axi_bid_reg
;
assign
s_axi_bresp
=
2'b00
;
assign
s_axi_bvalid
=
s_axi_bvalid_reg
;
assign
s_axi_arready
=
s_axi_arready_reg
;
assign
s_axi_rid
=
PIPELINE_OUTPUT
?
s_axi_rid_pipe_reg
:
s_axi_rid_reg
;
assign
s_axi_rdata
=
PIPELINE_OUTPUT
?
s_axi_rdata_pipe_reg
:
s_axi_rdata_reg
;
assign
s_axi_rresp
=
2'b00
;
assign
s_axi_rlast
=
PIPELINE_OUTPUT
?
s_axi_rlast_pipe_reg
:
s_axi_rlast_reg
;
assign
s_axi_rvalid
=
PIPELINE_OUTPUT
?
s_axi_rvalid_pipe_reg
:
s_axi_rvalid_reg
;
integer
i
,
j
;
initial
begin
// two nested loops for smaller number of iterations per loop
// workaround for synthesizer complaints about large loop counts
for
(
i
=
0
;
i
<
2
**
ADDR_WIDTH
;
i
=
i
+
2
**
(
ADDR_WIDTH
/
2
))
begin
for
(
j
=
i
;
j
<
i
+
2
**
(
ADDR_WIDTH
/
2
);
j
=
j
+
1
)
begin
mem
[
j
]
=
0
;
end
end
end
always
@*
begin
write_state_next
=
WRITE_STATE_IDLE
;
mem_wr_en
=
1'b0
;
write_id_next
=
write_id_reg
;
write_addr_next
=
write_addr_reg
;
write_count_next
=
write_count_reg
;
write_size_next
=
write_size_reg
;
write_burst_next
=
write_burst_reg
;
s_axi_awready_next
=
1'b0
;
s_axi_wready_next
=
1'b0
;
s_axi_bid_next
=
s_axi_bid_reg
;
s_axi_bvalid_next
=
s_axi_bvalid_reg
&&
!
s_axi_bready
;
case
(
write_state_reg
)
WRITE_STATE_IDLE:
begin
s_axi_awready_next
=
1'b1
;
if
(
s_axi_awready
&&
s_axi_awvalid
)
begin
write_id_next
=
s_axi_awid
;
write_addr_next
=
s_axi_awaddr
;
write_count_next
=
s_axi_awlen
;
write_size_next
=
s_axi_awsize
<
$
clog2
(
STRB_WIDTH
)
?
s_axi_awsize
:
$
clog2
(
STRB_WIDTH
);
write_burst_next
=
s_axi_awburst
;
s_axi_awready_next
=
1'b0
;
s_axi_wready_next
=
1'b1
;
write_state_next
=
WRITE_STATE_BURST
;
end
else
begin
write_state_next
=
WRITE_STATE_IDLE
;
end
end
WRITE_STATE_BURST:
begin
s_axi_wready_next
=
1'b1
;
if
(
s_axi_wready
&&
s_axi_wvalid
)
begin
mem_wr_en
=
1'b1
;
if
(
write_burst_reg
!=
2'b00
)
begin
write_addr_next
=
write_addr_reg
+
(
1
<<
write_size_reg
);
end
write_count_next
=
write_count_reg
-
1
;
if
(
write_count_reg
>
0
)
begin
write_state_next
=
WRITE_STATE_BURST
;
end
else
begin
s_axi_wready_next
=
1'b0
;
if
(
s_axi_bready
||
!
s_axi_bvalid
)
begin
s_axi_bid_next
=
write_id_reg
;
s_axi_bvalid_next
=
1'b1
;
s_axi_awready_next
=
1'b1
;
write_state_next
=
WRITE_STATE_IDLE
;
end
else
begin
write_state_next
=
WRITE_STATE_RESP
;
end
end
end
else
begin
write_state_next
=
WRITE_STATE_BURST
;
end
end
WRITE_STATE_RESP:
begin
if
(
s_axi_bready
||
!
s_axi_bvalid
)
begin
s_axi_bid_next
=
write_id_reg
;
s_axi_bvalid_next
=
1'b1
;
s_axi_awready_next
=
1'b1
;
write_state_next
=
WRITE_STATE_IDLE
;
end
else
begin
write_state_next
=
WRITE_STATE_RESP
;
end
end
endcase
end
always
@
(
posedge
clk
)
begin
if
(
rst
)
begin
write_state_reg
<=
WRITE_STATE_IDLE
;
s_axi_awready_reg
<=
1'b0
;
s_axi_wready_reg
<=
1'b0
;
s_axi_bvalid_reg
<=
1'b0
;
end
else
begin
write_state_reg
<=
write_state_next
;
s_axi_awready_reg
<=
s_axi_awready_next
;
s_axi_wready_reg
<=
s_axi_wready_next
;
s_axi_bvalid_reg
<=
s_axi_bvalid_next
;
end
write_id_reg
<=
write_id_next
;
write_addr_reg
<=
write_addr_next
;
write_count_reg
<=
write_count_next
;
write_size_reg
<=
write_size_next
;
write_burst_reg
<=
write_burst_next
;
s_axi_bid_reg
<=
s_axi_bid_next
;
for
(
i
=
0
;
i
<
WORD_WIDTH
;
i
=
i
+
1
)
begin
if
(
mem_wr_en
&
s_axi_wstrb
[
i
])
begin
mem
[
write_addr_valid
][
WORD_SIZE
*
i
+:
WORD_SIZE
]
<=
s_axi_wdata
[
WORD_SIZE
*
i
+:
WORD_SIZE
];
end
end
end
always
@*
begin
read_state_next
=
READ_STATE_IDLE
;
mem_rd_en
=
1'b0
;
s_axi_rid_next
=
s_axi_rid_reg
;
s_axi_rlast_next
=
s_axi_rlast_reg
;
s_axi_rvalid_next
=
s_axi_rvalid_reg
&&
!
(
s_axi_rready
||
(
PIPELINE_OUTPUT
&&
!
s_axi_rvalid_pipe_reg
));
read_id_next
=
read_id_reg
;
read_addr_next
=
read_addr_reg
;
read_count_next
=
read_count_reg
;
read_size_next
=
read_size_reg
;
read_burst_next
=
read_burst_reg
;
s_axi_arready_next
=
1'b0
;
case
(
read_state_reg
)
READ_STATE_IDLE:
begin
s_axi_arready_next
=
1'b1
;
if
(
s_axi_arready
&&
s_axi_arvalid
)
begin
read_id_next
=
s_axi_arid
;
read_addr_next
=
s_axi_araddr
;
read_count_next
=
s_axi_arlen
;
read_size_next
=
s_axi_arsize
<
$
clog2
(
STRB_WIDTH
)
?
s_axi_arsize
:
$
clog2
(
STRB_WIDTH
);
read_burst_next
=
s_axi_arburst
;
s_axi_arready_next
=
1'b0
;
read_state_next
=
READ_STATE_BURST
;
end
else
begin
read_state_next
=
READ_STATE_IDLE
;
end
end
READ_STATE_BURST:
begin
if
(
s_axi_rready
||
(
PIPELINE_OUTPUT
&&
!
s_axi_rvalid_pipe_reg
)
||
!
s_axi_rvalid_reg
)
begin
mem_rd_en
=
1'b1
;
s_axi_rvalid_next
=
1'b1
;
s_axi_rid_next
=
read_id_reg
;
s_axi_rlast_next
=
read_count_reg
==
0
;
if
(
read_burst_reg
!=
2'b00
)
begin
read_addr_next
=
read_addr_reg
+
(
1
<<
read_size_reg
);
end
read_count_next
=
read_count_reg
-
1
;
if
(
read_count_reg
>
0
)
begin
read_state_next
=
READ_STATE_BURST
;
end
else
begin
s_axi_arready_next
=
1'b1
;
read_state_next
=
READ_STATE_IDLE
;
end
end
else
begin
read_state_next
=
READ_STATE_BURST
;
end
end
endcase
end
always
@
(
posedge
clk
)
begin
if
(
rst
)
begin
read_state_reg
<=
READ_STATE_IDLE
;
s_axi_arready_reg
<=
1'b0
;
s_axi_rvalid_reg
<=
1'b0
;
s_axi_rvalid_pipe_reg
<=
1'b0
;
end
else
begin
read_state_reg
<=
read_state_next
;
s_axi_arready_reg
<=
s_axi_arready_next
;
s_axi_rvalid_reg
<=
s_axi_rvalid_next
;
if
(
!
s_axi_rvalid_pipe_reg
||
s_axi_rready
)
begin
s_axi_rvalid_pipe_reg
<=
s_axi_rvalid_reg
;
end
end
read_id_reg
<=
read_id_next
;
read_addr_reg
<=
read_addr_next
;
read_count_reg
<=
read_count_next
;
read_size_reg
<=
read_size_next
;
read_burst_reg
<=
read_burst_next
;
s_axi_rid_reg
<=
s_axi_rid_next
;
s_axi_rlast_reg
<=
s_axi_rlast_next
;
if
(
mem_rd_en
)
begin
s_axi_rdata_reg
<=
mem
[
read_addr_valid
];
end
if
(
!
s_axi_rvalid_pipe_reg
||
s_axi_rready
)
begin
s_axi_rid_pipe_reg
<=
s_axi_rid_reg
;
s_axi_rdata_pipe_reg
<=
s_axi_rdata_reg
;
s_axi_rlast_pipe_reg
<=
s_axi_rlast_reg
;
end
end
endmodule
corundum/lib/axi/rtl/axi_ram_rd_if.v
0 → 100644
View file @
738c1fef
/*
Copyright (c) 2019 Alex Forencich
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.
*/
// Language: Verilog 2001
`timescale
1
ns
/
1
ps
/*
* AXI4 RAM read interface
*/
module
axi_ram_rd_if
#
(
// Width of data bus in bits
parameter
DATA_WIDTH
=
32
,
// Width of address bus in bits
parameter
ADDR_WIDTH
=
16
,
// Width of wstrb (width of data bus in words)
parameter
STRB_WIDTH
=
(
DATA_WIDTH
/
8
),
// Width of ID signal
parameter
ID_WIDTH
=
8
,
// Propagate aruser signal
parameter
ARUSER_ENABLE
=
0
,
// Width of aruser signal
parameter
ARUSER_WIDTH
=
1
,
// Propagate ruser signal
parameter
RUSER_ENABLE
=
0
,
// Width of ruser signal
parameter
RUSER_WIDTH
=
1
,
// Extra pipeline register on output
parameter
PIPELINE_OUTPUT
=
0
)
(
input
wire
clk
,
input
wire
rst
,
/*
* AXI slave interface
*/
input
wire
[
ID_WIDTH
-
1
:
0
]
s_axi_arid
,
input
wire
[
ADDR_WIDTH
-
1
:
0
]
s_axi_araddr
,
input
wire
[
7
:
0
]
s_axi_arlen
,
input
wire
[
2
:
0
]
s_axi_arsize
,
input
wire
[
1
:
0
]
s_axi_arburst
,
input
wire
s_axi_arlock
,
input
wire
[
3
:
0
]
s_axi_arcache
,
input
wire
[
2
:
0
]
s_axi_arprot
,
input
wire
[
3
:
0
]
s_axi_arqos
,
input
wire
[
3
:
0
]
s_axi_arregion
,
input
wire
[
ARUSER_WIDTH
-
1
:
0
]
s_axi_aruser
,
input
wire
s_axi_arvalid
,
output
wire
s_axi_arready
,
output
wire
[
ID_WIDTH
-
1
:
0
]
s_axi_rid
,
output
wire
[
DATA_WIDTH
-
1
:
0
]
s_axi_rdata
,
output
wire
[
1
:
0
]
s_axi_rresp
,
output
wire
s_axi_rlast
,
output
wire
[
RUSER_WIDTH
-
1
:
0
]
s_axi_ruser
,
output
wire
s_axi_rvalid
,
input
wire
s_axi_rready
,
/*
* RAM interface
*/
output
wire
[
ID_WIDTH
-
1
:
0
]
ram_rd_cmd_id
,
output
wire
[
ADDR_WIDTH
-
1
:
0
]
ram_rd_cmd_addr
,
output
wire
ram_rd_cmd_lock
,
output
wire
[
3
:
0
]
ram_rd_cmd_cache
,
output
wire
[
2
:
0
]
ram_rd_cmd_prot
,
output
wire
[
3
:
0
]
ram_rd_cmd_qos
,
output
wire
[
3
:
0
]
ram_rd_cmd_region
,
output
wire
[
ARUSER_WIDTH
-
1
:
0
]
ram_rd_cmd_auser
,
output
wire
ram_rd_cmd_en
,
output
wire
ram_rd_cmd_last
,
input
wire
ram_rd_cmd_ready
,
input
wire
[
ID_WIDTH
-
1
:
0
]
ram_rd_resp_id
,
input
wire
[
DATA_WIDTH
-
1
:
0
]
ram_rd_resp_data
,
input
wire
ram_rd_resp_last
,
input
wire
[
RUSER_WIDTH
-
1
:
0
]
ram_rd_resp_user
,
input
wire
ram_rd_resp_valid
,
output
wire
ram_rd_resp_ready
);
parameter
VALID_ADDR_WIDTH
=
ADDR_WIDTH
-
$
clog2
(
STRB_WIDTH
);
parameter
WORD_WIDTH
=
STRB_WIDTH
;
parameter
WORD_SIZE
=
DATA_WIDTH
/
WORD_WIDTH
;
// bus width assertions
initial
begin
if
(
WORD_SIZE
*
STRB_WIDTH
!=
DATA_WIDTH
)
begin
$
error
(
"Error: AXI data width not evenly divisble (instance %m)"
);
$
finish
;
end
if
(
2
**
$
clog2
(
WORD_WIDTH
)
!=
WORD_WIDTH
)
begin
$
error
(
"Error: AXI word width must be even power of two (instance %m)"
);
$
finish
;
end
end
localparam
[
0
:
0
]
STATE_IDLE
=
1'd0
,
STATE_BURST
=
1'd1
;
reg
[
0
:
0
]
state_reg
=
STATE_IDLE
,
state_next
;
reg
[
ID_WIDTH
-
1
:
0
]
read_id_reg
=
{
ID_WIDTH
{
1'b0
}}
,
read_id_next
;
reg
[
ADDR_WIDTH
-
1
:
0
]
read_addr_reg
=
{
ADDR_WIDTH
{
1'b0
}}
,
read_addr_next
;
reg
read_lock_reg
=
1'b0
,
read_lock_next
;
reg
[
3
:
0
]
read_cache_reg
=
4'd0
,
read_cache_next
;
reg
[
2
:
0
]
read_prot_reg
=
3'd0
,
read_prot_next
;
reg
[
3
:
0
]
read_qos_reg
=
4'd0
,
read_qos_next
;
reg
[
3
:
0
]
read_region_reg
=
4'd0
,
read_region_next
;
reg
[
ARUSER_WIDTH
-
1
:
0
]
read_aruser_reg
=
{
ARUSER_WIDTH
{
1'b0
}}
,
read_aruser_next
;
reg
read_addr_valid_reg
=
1'b0
,
read_addr_valid_next
;
reg
read_last_reg
=
1'b0
,
read_last_next
;
reg
[
7
:
0
]
read_count_reg
=
8'd0
,
read_count_next
;
reg
[
2
:
0
]
read_size_reg
=
3'd0
,
read_size_next
;
reg
[
1
:
0
]
read_burst_reg
=
2'd0
,
read_burst_next
;
reg
s_axi_arready_reg
=
1'b0
,
s_axi_arready_next
;
reg
[
ID_WIDTH
-
1
:
0
]
s_axi_rid_pipe_reg
=
{
ID_WIDTH
{
1'b0
}}
;
reg
[
DATA_WIDTH
-
1
:
0
]
s_axi_rdata_pipe_reg
=
{
DATA_WIDTH
{
1'b0
}}
;
reg
s_axi_rlast_pipe_reg
=
1'b0
;
reg
[
RUSER_WIDTH
-
1
:
0
]
s_axi_ruser_pipe_reg
=
{
RUSER_WIDTH
{
1'b0
}}
;
reg
s_axi_rvalid_pipe_reg
=
1'b0
;
assign
s_axi_arready
=
s_axi_arready_reg
;
assign
s_axi_rid
=
PIPELINE_OUTPUT
?
s_axi_rid_pipe_reg
:
ram_rd_resp_id
;
assign
s_axi_rdata
=
PIPELINE_OUTPUT
?
s_axi_rdata_pipe_reg
:
ram_rd_resp_data
;
assign
s_axi_rresp
=
2'b00
;
assign
s_axi_rlast
=
PIPELINE_OUTPUT
?
s_axi_rlast_pipe_reg
:
ram_rd_resp_last
;
assign
s_axi_ruser
=
PIPELINE_OUTPUT
?
s_axi_ruser_pipe_reg
:
ram_rd_resp_user
;
assign
s_axi_rvalid
=
PIPELINE_OUTPUT
?
s_axi_rvalid_pipe_reg
:
ram_rd_resp_valid
;
assign
ram_rd_cmd_id
=
read_id_reg
;
assign
ram_rd_cmd_addr
=
read_addr_reg
;
assign
ram_rd_cmd_lock
=
read_lock_reg
;
assign
ram_rd_cmd_cache
=
read_cache_reg
;
assign
ram_rd_cmd_prot
=
read_prot_reg
;
assign
ram_rd_cmd_qos
=
read_qos_reg
;
assign
ram_rd_cmd_region
=
read_region_reg
;
assign
ram_rd_cmd_auser
=
ARUSER_ENABLE
?
read_aruser_reg
:
{
ARUSER_WIDTH
{
1'b0
}}
;
assign
ram_rd_cmd_en
=
read_addr_valid_reg
;
assign
ram_rd_cmd_last
=
read_last_reg
;
assign
ram_rd_resp_ready
=
s_axi_rready
||
(
PIPELINE_OUTPUT
&&
!
s_axi_rvalid_pipe_reg
);
always
@*
begin
state_next
=
STATE_IDLE
;
read_id_next
=
read_id_reg
;
read_addr_next
=
read_addr_reg
;
read_lock_next
=
read_lock_reg
;
read_cache_next
=
read_cache_reg
;
read_prot_next
=
read_prot_reg
;
read_qos_next
=
read_qos_reg
;
read_region_next
=
read_region_reg
;
read_aruser_next
=
read_aruser_reg
;
read_addr_valid_next
=
read_addr_valid_reg
&&
!
ram_rd_cmd_ready
;
read_last_next
=
read_last_reg
;
read_count_next
=
read_count_reg
;
read_size_next
=
read_size_reg
;
read_burst_next
=
read_burst_reg
;
s_axi_arready_next
=
1'b0
;
case
(
state_reg
)
STATE_IDLE:
begin
s_axi_arready_next
=
1'b1
;
if
(
s_axi_arready
&&
s_axi_arvalid
)
begin
read_id_next
=
s_axi_arid
;
read_addr_next
=
s_axi_araddr
;
read_lock_next
=
s_axi_arlock
;
read_cache_next
=
s_axi_arcache
;
read_prot_next
=
s_axi_arprot
;
read_qos_next
=
s_axi_arqos
;
read_region_next
=
s_axi_arregion
;
read_aruser_next
=
s_axi_aruser
;
read_count_next
=
s_axi_arlen
;
read_size_next
=
s_axi_arsize
<
$
clog2
(
STRB_WIDTH
)
?
s_axi_arsize
:
$
clog2
(
STRB_WIDTH
);
read_burst_next
=
s_axi_arburst
;
s_axi_arready_next
=
1'b0
;
read_last_next
=
read_count_next
==
0
;
read_addr_valid_next
=
1'b1
;
state_next
=
STATE_BURST
;
end
else
begin
state_next
=
STATE_IDLE
;
end
end
STATE_BURST:
begin
if
(
ram_rd_cmd_ready
&&
ram_rd_cmd_en
)
begin
if
(
read_burst_reg
!=
2'b00
)
begin
read_addr_next
=
read_addr_reg
+
(
1
<<
read_size_reg
);
end
read_count_next
=
read_count_reg
-
1
;
read_last_next
=
read_count_next
==
0
;
if
(
read_count_reg
>
0
)
begin
read_addr_valid_next
=
1'b1
;
state_next
=
STATE_BURST
;
end
else
begin
s_axi_arready_next
=
1'b1
;
state_next
=
STATE_IDLE
;
end
end
else
begin
state_next
=
STATE_BURST
;
end
end
endcase
end
always
@
(
posedge
clk
)
begin
if
(
rst
)
begin
state_reg
<=
STATE_IDLE
;
read_addr_valid_reg
<=
1'b0
;
s_axi_arready_reg
<=
1'b0
;
s_axi_rvalid_pipe_reg
<=
1'b0
;
end
else
begin
state_reg
<=
state_next
;
read_addr_valid_reg
<=
read_addr_valid_next
;
s_axi_arready_reg
<=
s_axi_arready_next
;
if
(
!
s_axi_rvalid_pipe_reg
||
s_axi_rready
)
begin
s_axi_rvalid_pipe_reg
<=
ram_rd_resp_valid
;
end
end
read_id_reg
<=
read_id_next
;
read_addr_reg
<=
read_addr_next
;
read_lock_reg
<=
read_lock_next
;
read_cache_reg
<=
read_cache_next
;
read_prot_reg
<=
read_prot_next
;
read_qos_reg
<=
read_qos_next
;
read_region_reg
<=
read_region_next
;
read_aruser_reg
<=
read_aruser_next
;
read_last_reg
<=
read_last_next
;
read_count_reg
<=
read_count_next
;
read_size_reg
<=
read_size_next
;
read_burst_reg
<=
read_burst_next
;
if
(
!
s_axi_rvalid_pipe_reg
||
s_axi_rready
)
begin
s_axi_rid_pipe_reg
<=
ram_rd_resp_id
;
s_axi_rdata_pipe_reg
<=
ram_rd_resp_data
;
s_axi_rlast_pipe_reg
<=
ram_rd_resp_last
;
s_axi_ruser_pipe_reg
<=
ram_rd_resp_user
;
end
end
endmodule
corundum/lib/axi/rtl/axi_ram_wr_if.v
0 → 100644
View file @
738c1fef
/*
Copyright (c) 2019 Alex Forencich
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.
*/
// Language: Verilog 2001
`timescale
1
ns
/
1
ps
/*
* AXI4 RAM write interface
*/
module
axi_ram_wr_if
#
(
// Width of data bus in bits
parameter
DATA_WIDTH
=
32
,
// Width of address bus in bits
parameter
ADDR_WIDTH
=
16
,
// Width of wstrb (width of data bus in words)
parameter
STRB_WIDTH
=
(
DATA_WIDTH
/
8
),
// Width of ID signal
parameter
ID_WIDTH
=
8
,
// Propagate awuser signal
parameter
AWUSER_ENABLE
=
0
,
// Width of awuser signal
parameter
AWUSER_WIDTH
=
1
,
// Propagate wuser signal
parameter
WUSER_ENABLE
=
0
,
// Width of wuser signal
parameter
WUSER_WIDTH
=
1
,
// Propagate buser signal
parameter
BUSER_ENABLE
=
0
,
// Width of buser signal
parameter
BUSER_WIDTH
=
1
)
(
input
wire
clk
,
input
wire
rst
,
/*
* AXI slave interface
*/
input
wire
[
ID_WIDTH
-
1
:
0
]
s_axi_awid
,
input
wire
[
ADDR_WIDTH
-
1
:
0
]
s_axi_awaddr
,
input
wire
[
7
:
0
]
s_axi_awlen
,
input
wire
[
2
:
0
]
s_axi_awsize
,
input
wire
[
1
:
0
]
s_axi_awburst
,
input
wire
s_axi_awlock
,
input
wire
[
3
:
0
]
s_axi_awcache
,
input
wire
[
2
:
0
]
s_axi_awprot
,
input
wire
[
3
:
0
]
s_axi_awqos
,
input
wire
[
3
:
0
]
s_axi_awregion
,
input
wire
[
AWUSER_WIDTH
-
1
:
0
]
s_axi_awuser
,
input
wire
s_axi_awvalid
,
output
wire
s_axi_awready
,
input
wire
[
DATA_WIDTH
-
1
:
0
]
s_axi_wdata
,
input
wire
[
STRB_WIDTH
-
1
:
0
]
s_axi_wstrb
,
input
wire
s_axi_wlast
,
input
wire
[
WUSER_WIDTH
-
1
:
0
]
s_axi_wuser
,
input
wire
s_axi_wvalid
,
output
wire
s_axi_wready
,
output
wire
[
ID_WIDTH
-
1
:
0
]
s_axi_bid
,
output
wire
[
1
:
0
]
s_axi_bresp
,
output
wire
[
BUSER_WIDTH
-
1
:
0
]
s_axi_buser
,
output
wire
s_axi_bvalid
,
input
wire
s_axi_bready
,
/*
* RAM interface
*/
output
wire
[
ID_WIDTH
-
1
:
0
]
ram_wr_cmd_id
,
output
wire
[
ADDR_WIDTH
-
1
:
0
]
ram_wr_cmd_addr
,
output
wire
ram_wr_cmd_lock
,
output
wire
[
3
:
0
]
ram_wr_cmd_cache
,
output
wire
[
2
:
0
]
ram_wr_cmd_prot
,
output
wire
[
3
:
0
]
ram_wr_cmd_qos
,
output
wire
[
3
:
0
]
ram_wr_cmd_region
,
output
wire
[
AWUSER_WIDTH
-
1
:
0
]
ram_wr_cmd_auser
,
output
wire
[
DATA_WIDTH
-
1
:
0
]
ram_wr_cmd_data
,
output
wire
[
STRB_WIDTH
-
1
:
0
]
ram_wr_cmd_strb
,
output
wire
[
WUSER_WIDTH
-
1
:
0
]
ram_wr_cmd_user
,
output
wire
ram_wr_cmd_en
,
output
wire
ram_wr_cmd_last
,
input
wire
ram_wr_cmd_ready
);
parameter
VALID_ADDR_WIDTH
=
ADDR_WIDTH
-
$
clog2
(
STRB_WIDTH
);
parameter
WORD_WIDTH
=
STRB_WIDTH
;
parameter
WORD_SIZE
=
DATA_WIDTH
/
WORD_WIDTH
;
// bus width assertions
initial
begin
if
(
WORD_SIZE
*
STRB_WIDTH
!=
DATA_WIDTH
)
begin
$
error
(
"Error: AXI data width not evenly divisble (instance %m)"
);
$
finish
;
end
if
(
2
**
$
clog2
(
WORD_WIDTH
)
!=
WORD_WIDTH
)
begin
$
error
(
"Error: AXI word width must be even power of two (instance %m)"
);
$
finish
;
end
end
localparam
[
1
:
0
]
STATE_IDLE
=
2'd0
,
STATE_BURST
=
2'd1
,
STATE_RESP
=
2'd2
;
reg
[
1
:
0
]
state_reg
=
STATE_IDLE
,
state_next
;
reg
[
ID_WIDTH
-
1
:
0
]
write_id_reg
=
{
ID_WIDTH
{
1'b0
}}
,
write_id_next
;
reg
[
ADDR_WIDTH
-
1
:
0
]
write_addr_reg
=
{
ADDR_WIDTH
{
1'b0
}}
,
write_addr_next
;
reg
write_lock_reg
=
1'b0
,
write_lock_next
;
reg
[
3
:
0
]
write_cache_reg
=
4'd0
,
write_cache_next
;
reg
[
2
:
0
]
write_prot_reg
=
3'd0
,
write_prot_next
;
reg
[
3
:
0
]
write_qos_reg
=
4'd0
,
write_qos_next
;
reg
[
3
:
0
]
write_region_reg
=
4'd0
,
write_region_next
;
reg
[
AWUSER_WIDTH
-
1
:
0
]
write_awuser_reg
=
{
AWUSER_WIDTH
{
1'b0
}}
,
write_awuser_next
;
reg
write_addr_valid_reg
=
1'b0
,
write_addr_valid_next
;
reg
write_last_reg
=
1'b0
,
write_last_next
;
reg
[
7
:
0
]
write_count_reg
=
8'd0
,
write_count_next
;
reg
[
2
:
0
]
write_size_reg
=
3'd0
,
write_size_next
;
reg
[
1
:
0
]
write_burst_reg
=
2'd0
,
write_burst_next
;
reg
s_axi_awready_reg
=
1'b0
,
s_axi_awready_next
;
reg
[
ID_WIDTH
-
1
:
0
]
s_axi_bid_reg
=
{
ID_WIDTH
{
1'b0
}}
,
s_axi_bid_next
;
reg
s_axi_bvalid_reg
=
1'b0
,
s_axi_bvalid_next
;
assign
s_axi_awready
=
s_axi_awready_reg
;
assign
s_axi_wready
=
write_addr_valid_reg
&&
ram_wr_cmd_ready
;
assign
s_axi_bid
=
s_axi_bid_reg
;
assign
s_axi_bresp
=
2'b00
;
assign
s_axi_buser
=
{
BUSER_WIDTH
{
1'b0
}}
;
assign
s_axi_bvalid
=
s_axi_bvalid_reg
;
assign
ram_wr_cmd_id
=
write_id_reg
;
assign
ram_wr_cmd_addr
=
write_addr_reg
;
assign
ram_wr_cmd_lock
=
write_lock_reg
;
assign
ram_wr_cmd_cache
=
write_cache_reg
;
assign
ram_wr_cmd_prot
=
write_prot_reg
;
assign
ram_wr_cmd_qos
=
write_qos_reg
;
assign
ram_wr_cmd_region
=
write_region_reg
;
assign
ram_wr_cmd_auser
=
AWUSER_ENABLE
?
write_awuser_reg
:
{
AWUSER_WIDTH
{
1'b0
}}
;
assign
ram_wr_cmd_data
=
s_axi_wdata
;
assign
ram_wr_cmd_strb
=
s_axi_wstrb
;
assign
ram_wr_cmd_user
=
WUSER_ENABLE
?
s_axi_wuser
:
{
WUSER_WIDTH
{
1'b0
}}
;
assign
ram_wr_cmd_en
=
write_addr_valid_reg
&&
s_axi_wvalid
;
assign
ram_wr_cmd_last
=
write_last_reg
;
always
@*
begin
state_next
=
STATE_IDLE
;
write_id_next
=
write_id_reg
;
write_addr_next
=
write_addr_reg
;
write_lock_next
=
write_lock_reg
;
write_cache_next
=
write_cache_reg
;
write_prot_next
=
write_prot_reg
;
write_qos_next
=
write_qos_reg
;
write_region_next
=
write_region_reg
;
write_awuser_next
=
write_awuser_reg
;
write_addr_valid_next
=
write_addr_valid_reg
;
write_last_next
=
write_last_reg
;
write_count_next
=
write_count_reg
;
write_size_next
=
write_size_reg
;
write_burst_next
=
write_burst_reg
;
s_axi_awready_next
=
1'b0
;
s_axi_bid_next
=
s_axi_bid_reg
;
s_axi_bvalid_next
=
s_axi_bvalid_reg
&&
!
s_axi_bready
;
case
(
state_reg
)
STATE_IDLE:
begin
s_axi_awready_next
=
1'b1
;
if
(
s_axi_awready
&&
s_axi_awvalid
)
begin
write_id_next
=
s_axi_awid
;
write_addr_next
=
s_axi_awaddr
;
write_lock_next
=
s_axi_awlock
;
write_cache_next
=
s_axi_awcache
;
write_prot_next
=
s_axi_awprot
;
write_qos_next
=
s_axi_awqos
;
write_region_next
=
s_axi_awregion
;
write_awuser_next
=
s_axi_awuser
;
write_count_next
=
s_axi_awlen
;
write_size_next
=
s_axi_awsize
<
$
clog2
(
STRB_WIDTH
)
?
s_axi_awsize
:
$
clog2
(
STRB_WIDTH
);
write_burst_next
=
s_axi_awburst
;
write_addr_valid_next
=
1'b1
;
s_axi_awready_next
=
1'b0
;
if
(
s_axi_awlen
>
0
)
begin
write_last_next
=
1'b0
;
end
else
begin
write_last_next
=
1'b1
;
end
state_next
=
STATE_BURST
;
end
else
begin
state_next
=
STATE_IDLE
;
end
end
STATE_BURST:
begin
if
(
s_axi_wready
&&
s_axi_wvalid
)
begin
if
(
write_burst_reg
!=
2'b00
)
begin
write_addr_next
=
write_addr_reg
+
(
1
<<
write_size_reg
);
end
write_count_next
=
write_count_reg
-
1
;
write_last_next
=
write_count_next
==
0
;
if
(
write_count_reg
>
0
)
begin
write_addr_valid_next
=
1'b1
;
state_next
=
STATE_BURST
;
end
else
begin
write_addr_valid_next
=
1'b0
;
if
(
s_axi_bready
||
!
s_axi_bvalid
)
begin
s_axi_bid_next
=
write_id_reg
;
s_axi_bvalid_next
=
1'b1
;
s_axi_awready_next
=
1'b1
;
state_next
=
STATE_IDLE
;
end
else
begin
state_next
=
STATE_RESP
;
end
end
end
else
begin
state_next
=
STATE_BURST
;
end
end
STATE_RESP:
begin
if
(
s_axi_bready
||
!
s_axi_bvalid
)
begin
s_axi_bid_next
=
write_id_reg
;
s_axi_bvalid_next
=
1'b1
;
s_axi_awready_next
=
1'b1
;
state_next
=
STATE_IDLE
;
end
else
begin
state_next
=
STATE_RESP
;
end
end
endcase
end
always
@
(
posedge
clk
)
begin
if
(
rst
)
begin
state_reg
<=
STATE_IDLE
;
write_addr_valid_reg
<=
1'b0
;
s_axi_awready_reg
<=
1'b0
;
s_axi_bvalid_reg
<=
1'b0
;
end
else
begin
state_reg
<=
state_next
;
write_addr_valid_reg
<=
write_addr_valid_next
;
s_axi_awready_reg
<=
s_axi_awready_next
;
s_axi_bvalid_reg
<=
s_axi_bvalid_next
;
end
write_id_reg
<=
write_id_next
;
write_addr_reg
<=
write_addr_next
;
write_lock_reg
<=
write_lock_next
;
write_cache_reg
<=
write_cache_next
;
write_prot_reg
<=
write_prot_next
;
write_qos_reg
<=
write_qos_next
;
write_region_reg
<=
write_region_next
;
write_awuser_reg
<=
write_awuser_next
;
write_last_reg
<=
write_last_next
;
write_count_reg
<=
write_count_next
;
write_size_reg
<=
write_size_next
;
write_burst_reg
<=
write_burst_next
;
s_axi_bid_reg
<=
s_axi_bid_next
;
end
endmodule
corundum/lib/axi/rtl/axi_ram_wr_rd_if.v
0 → 100644
View file @
738c1fef
/*
Copyright (c) 2019 Alex Forencich
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.
*/
// Language: Verilog 2001
`timescale
1
ns
/
1
ps
/*
* AXI4 RAM read/write interface
*/
module
axi_ram_wr_rd_if
#
(
// Width of data bus in bits
parameter
DATA_WIDTH
=
32
,
// Width of address bus in bits
parameter
ADDR_WIDTH
=
16
,
// Width of wstrb (width of data bus in words)
parameter
STRB_WIDTH
=
(
DATA_WIDTH
/
8
),
// Width of ID signal
parameter
ID_WIDTH
=
8
,
// Propagate awuser signal
parameter
AWUSER_ENABLE
=
0
,
// Width of awuser signal
parameter
AWUSER_WIDTH
=
1
,
// Propagate wuser signal
parameter
WUSER_ENABLE
=
0
,
// Width of wuser signal
parameter
WUSER_WIDTH
=
1
,
// Propagate buser signal
parameter
BUSER_ENABLE
=
0
,
// Width of buser signal
parameter
BUSER_WIDTH
=
1
,
// Propagate aruser signal
parameter
ARUSER_ENABLE
=
0
,
// Width of aruser signal
parameter
ARUSER_WIDTH
=
1
,
// Propagate ruser signal
parameter
RUSER_ENABLE
=
0
,
// Width of ruser signal
parameter
RUSER_WIDTH
=
1
,
// Width of auser output
parameter
AUSER_WIDTH
=
(
ARUSER_ENABLE
&&
(
!
AWUSER_ENABLE
||
ARUSER_WIDTH
>
AWUSER_WIDTH
))
?
ARUSER_WIDTH
:
AWUSER_WIDTH
,
// Extra pipeline register on output
parameter
PIPELINE_OUTPUT
=
0
,
// Interleave read and write burst cycles
parameter
INTERLEAVE
=
0
)
(
input
wire
clk
,
input
wire
rst
,
/*
* AXI slave interface
*/
input
wire
[
ID_WIDTH
-
1
:
0
]
s_axi_awid
,
input
wire
[
ADDR_WIDTH
-
1
:
0
]
s_axi_awaddr
,
input
wire
[
7
:
0
]
s_axi_awlen
,
input
wire
[
2
:
0
]
s_axi_awsize
,
input
wire
[
1
:
0
]
s_axi_awburst
,
input
wire
s_axi_awlock
,
input
wire
[
3
:
0
]
s_axi_awcache
,
input
wire
[
2
:
0
]
s_axi_awprot
,
input
wire
[
3
:
0
]
s_axi_awqos
,
input
wire
[
3
:
0
]
s_axi_awregion
,
input
wire
[
AWUSER_WIDTH
-
1
:
0
]
s_axi_awuser
,
input
wire
s_axi_awvalid
,
output
wire
s_axi_awready
,
input
wire
[
DATA_WIDTH
-
1
:
0
]
s_axi_wdata
,
input
wire
[
STRB_WIDTH
-
1
:
0
]
s_axi_wstrb
,
input
wire
s_axi_wlast
,
input
wire
[
WUSER_WIDTH
-
1
:
0
]
s_axi_wuser
,
input
wire
s_axi_wvalid
,
output
wire
s_axi_wready
,
output
wire
[
ID_WIDTH
-
1
:
0
]
s_axi_bid
,
output
wire
[
1
:
0
]
s_axi_bresp
,
output
wire
[
BUSER_WIDTH
-
1
:
0
]
s_axi_buser
,
output
wire
s_axi_bvalid
,
input
wire
s_axi_bready
,
input
wire
[
ID_WIDTH
-
1
:
0
]
s_axi_arid
,
input
wire
[
ADDR_WIDTH
-
1
:
0
]
s_axi_araddr
,
input
wire
[
7
:
0
]
s_axi_arlen
,
input
wire
[
2
:
0
]
s_axi_arsize
,
input
wire
[
1
:
0
]
s_axi_arburst
,
input
wire
s_axi_arlock
,
input
wire
[
3
:
0
]
s_axi_arcache
,
input
wire
[
2
:
0
]
s_axi_arprot
,
input
wire
[
3
:
0
]
s_axi_arqos
,
input
wire
[
3
:
0
]
s_axi_arregion
,
input
wire
[
ARUSER_WIDTH
-
1
:
0
]
s_axi_aruser
,
input
wire
s_axi_arvalid
,
output
wire
s_axi_arready
,
output
wire
[
ID_WIDTH
-
1
:
0
]
s_axi_rid
,
output
wire
[
DATA_WIDTH
-
1
:
0
]
s_axi_rdata
,
output
wire
[
1
:
0
]
s_axi_rresp
,
output
wire
s_axi_rlast
,
output
wire
[
RUSER_WIDTH
-
1
:
0
]
s_axi_ruser
,
output
wire
s_axi_rvalid
,
input
wire
s_axi_rready
,
/*
* RAM interface
*/
output
wire
[
ID_WIDTH
-
1
:
0
]
ram_cmd_id
,
output
wire
[
ADDR_WIDTH
-
1
:
0
]
ram_cmd_addr
,
output
wire
ram_cmd_lock
,
output
wire
[
3
:
0
]
ram_cmd_cache
,
output
wire
[
2
:
0
]
ram_cmd_prot
,
output
wire
[
3
:
0
]
ram_cmd_qos
,
output
wire
[
3
:
0
]
ram_cmd_region
,
output
wire
[
AUSER_WIDTH
-
1
:
0
]
ram_cmd_auser
,
output
wire
[
DATA_WIDTH
-
1
:
0
]
ram_cmd_wr_data
,
output
wire
[
STRB_WIDTH
-
1
:
0
]
ram_cmd_wr_strb
,
output
wire
[
WUSER_WIDTH
-
1
:
0
]
ram_cmd_wr_user
,
output
wire
ram_cmd_wr_en
,
output
wire
ram_cmd_rd_en
,
output
wire
ram_cmd_last
,
input
wire
ram_cmd_ready
,
input
wire
[
ID_WIDTH
-
1
:
0
]
ram_rd_resp_id
,
input
wire
[
DATA_WIDTH
-
1
:
0
]
ram_rd_resp_data
,
input
wire
ram_rd_resp_last
,
input
wire
[
RUSER_WIDTH
-
1
:
0
]
ram_rd_resp_user
,
input
wire
ram_rd_resp_valid
,
output
wire
ram_rd_resp_ready
);
wire
[
ID_WIDTH
-
1
:
0
]
ram_wr_cmd_id
;
wire
[
ADDR_WIDTH
-
1
:
0
]
ram_wr_cmd_addr
;
wire
ram_wr_cmd_lock
;
wire
[
3
:
0
]
ram_wr_cmd_cache
;
wire
[
2
:
0
]
ram_wr_cmd_prot
;
wire
[
3
:
0
]
ram_wr_cmd_qos
;
wire
[
3
:
0
]
ram_wr_cmd_region
;
wire
[
AWUSER_WIDTH
-
1
:
0
]
ram_wr_cmd_auser
;
wire
[
ID_WIDTH
-
1
:
0
]
ram_rd_cmd_id
;
wire
[
ADDR_WIDTH
-
1
:
0
]
ram_rd_cmd_addr
;
wire
ram_rd_cmd_lock
;
wire
[
3
:
0
]
ram_rd_cmd_cache
;
wire
[
2
:
0
]
ram_rd_cmd_prot
;
wire
[
3
:
0
]
ram_rd_cmd_qos
;
wire
[
3
:
0
]
ram_rd_cmd_region
;
wire
[
AWUSER_WIDTH
-
1
:
0
]
ram_rd_cmd_auser
;
axi_ram_wr_if
#(
.
DATA_WIDTH
(
DATA_WIDTH
),
.
ADDR_WIDTH
(
ADDR_WIDTH
),
.
STRB_WIDTH
(
STRB_WIDTH
),
.
ID_WIDTH
(
ID_WIDTH
),
.
AWUSER_ENABLE
(
AWUSER_ENABLE
),
.
AWUSER_WIDTH
(
AWUSER_WIDTH
),
.
WUSER_ENABLE
(
WUSER_ENABLE
),
.
WUSER_WIDTH
(
WUSER_WIDTH
),
.
BUSER_ENABLE
(
BUSER_ENABLE
),
.
BUSER_WIDTH
(
BUSER_WIDTH
)
)
axi_ram_wr_if_inst
(
.
clk
(
clk
),
.
rst
(
rst
),
.
s_axi_awid
(
s_axi_awid
),
.
s_axi_awaddr
(
s_axi_awaddr
),
.
s_axi_awlen
(
s_axi_awlen
),
.
s_axi_awsize
(
s_axi_awsize
),
.
s_axi_awburst
(
s_axi_awburst
),
.
s_axi_awlock
(
s_axi_awlock
),
.
s_axi_awcache
(
s_axi_awcache
),
.
s_axi_awprot
(
s_axi_awprot
),
.
s_axi_awqos
(
s_axi_awqos
),
.
s_axi_awregion
(
s_axi_awregion
),
.
s_axi_awuser
(
s_axi_awuser
),
.
s_axi_awvalid
(
s_axi_awvalid
),
.
s_axi_awready
(
s_axi_awready
),
.
s_axi_wdata
(
s_axi_wdata
),
.
s_axi_wstrb
(
s_axi_wstrb
),
.
s_axi_wlast
(
s_axi_wlast
),
.
s_axi_wuser
(
s_axi_wuser
),
.
s_axi_wvalid
(
s_axi_wvalid
),
.
s_axi_wready
(
s_axi_wready
),
.
s_axi_bid
(
s_axi_bid
),
.
s_axi_bresp
(
s_axi_bresp
),
.
s_axi_buser
(
s_axi_buser
),
.
s_axi_bvalid
(
s_axi_bvalid
),
.
s_axi_bready
(
s_axi_bready
),
.
ram_wr_cmd_id
(
ram_wr_cmd_id
),
.
ram_wr_cmd_addr
(
ram_wr_cmd_addr
),
.
ram_wr_cmd_lock
(
ram_wr_cmd_lock
),
.
ram_wr_cmd_cache
(
ram_wr_cmd_cache
),
.
ram_wr_cmd_prot
(
ram_wr_cmd_prot
),
.
ram_wr_cmd_qos
(
ram_wr_cmd_qos
),
.
ram_wr_cmd_region
(
ram_wr_cmd_region
),
.
ram_wr_cmd_auser
(
ram_wr_cmd_auser
),
.
ram_wr_cmd_data
(
ram_cmd_wr_data
),
.
ram_wr_cmd_strb
(
ram_cmd_wr_strb
),
.
ram_wr_cmd_user
(
ram_cmd_wr_user
),
.
ram_wr_cmd_en
(
ram_wr_cmd_en
),
.
ram_wr_cmd_last
(
ram_wr_cmd_last
),
.
ram_wr_cmd_ready
(
ram_wr_cmd_ready
)
);
axi_ram_rd_if
#(
.
DATA_WIDTH
(
DATA_WIDTH
),
.
ADDR_WIDTH
(
ADDR_WIDTH
),
.
STRB_WIDTH
(
STRB_WIDTH
),
.
ID_WIDTH
(
ID_WIDTH
),
.
ARUSER_ENABLE
(
ARUSER_ENABLE
),
.
ARUSER_WIDTH
(
ARUSER_WIDTH
),
.
RUSER_ENABLE
(
RUSER_ENABLE
),
.
RUSER_WIDTH
(
RUSER_WIDTH
),
.
PIPELINE_OUTPUT
(
PIPELINE_OUTPUT
)
)
axi_ram_rd_if_inst
(
.
clk
(
clk
),
.
rst
(
rst
),
.
s_axi_arid
(
s_axi_arid
),
.
s_axi_araddr
(
s_axi_araddr
),
.
s_axi_arlen
(
s_axi_arlen
),
.
s_axi_arsize
(
s_axi_arsize
),
.
s_axi_arburst
(
s_axi_arburst
),
.
s_axi_arlock
(
s_axi_arlock
),
.
s_axi_arcache
(
s_axi_arcache
),
.
s_axi_arprot
(
s_axi_arprot
),
.
s_axi_arqos
(
s_axi_arqos
),
.
s_axi_arregion
(
s_axi_arregion
),
.
s_axi_aruser
(
s_axi_aruser
),
.
s_axi_arvalid
(
s_axi_arvalid
),
.
s_axi_arready
(
s_axi_arready
),
.
s_axi_rid
(
s_axi_rid
),
.
s_axi_rdata
(
s_axi_rdata
),
.
s_axi_rresp
(
s_axi_rresp
),
.
s_axi_rlast
(
s_axi_rlast
),
.
s_axi_ruser
(
s_axi_ruser
),
.
s_axi_rvalid
(
s_axi_rvalid
),
.
s_axi_rready
(
s_axi_rready
),
.
ram_rd_cmd_id
(
ram_rd_cmd_id
),
.
ram_rd_cmd_addr
(
ram_rd_cmd_addr
),
.
ram_rd_cmd_lock
(
ram_rd_cmd_lock
),
.
ram_rd_cmd_cache
(
ram_rd_cmd_cache
),
.
ram_rd_cmd_prot
(
ram_rd_cmd_prot
),
.
ram_rd_cmd_qos
(
ram_rd_cmd_qos
),
.
ram_rd_cmd_region
(
ram_rd_cmd_region
),
.
ram_rd_cmd_auser
(
ram_rd_cmd_auser
),
.
ram_rd_cmd_en
(
ram_rd_cmd_en
),
.
ram_rd_cmd_last
(
ram_rd_cmd_last
),
.
ram_rd_cmd_ready
(
ram_rd_cmd_ready
),
.
ram_rd_resp_id
(
ram_rd_resp_id
),
.
ram_rd_resp_data
(
ram_rd_resp_data
),
.
ram_rd_resp_last
(
ram_rd_resp_last
),
.
ram_rd_resp_user
(
ram_rd_resp_user
),
.
ram_rd_resp_valid
(
ram_rd_resp_valid
),
.
ram_rd_resp_ready
(
ram_rd_resp_ready
)
);
// arbitration
reg
read_eligible
;
reg
write_eligible
;
reg
write_en
;
reg
read_en
;
reg
last_read_reg
=
1'b0
,
last_read_next
;
reg
transaction_reg
=
1'b0
,
transaction_next
;
assign
ram_cmd_wr_en
=
write_en
;
assign
ram_cmd_rd_en
=
read_en
;
assign
ram_cmd_id
=
ram_cmd_rd_en
?
ram_rd_cmd_id
:
ram_wr_cmd_id
;
assign
ram_cmd_addr
=
ram_cmd_rd_en
?
ram_rd_cmd_addr
:
ram_wr_cmd_addr
;
assign
ram_cmd_lock
=
ram_cmd_rd_en
?
ram_rd_cmd_lock
:
ram_wr_cmd_lock
;
assign
ram_cmd_cache
=
ram_cmd_rd_en
?
ram_rd_cmd_cache
:
ram_wr_cmd_cache
;
assign
ram_cmd_prot
=
ram_cmd_rd_en
?
ram_rd_cmd_prot
:
ram_wr_cmd_prot
;
assign
ram_cmd_qos
=
ram_cmd_rd_en
?
ram_rd_cmd_qos
:
ram_wr_cmd_qos
;
assign
ram_cmd_region
=
ram_cmd_rd_en
?
ram_rd_cmd_region
:
ram_wr_cmd_region
;
assign
ram_cmd_auser
=
ram_cmd_rd_en
?
ram_rd_cmd_auser
:
ram_wr_cmd_auser
;
assign
ram_cmd_last
=
ram_cmd_rd_en
?
ram_rd_cmd_last
:
ram_wr_cmd_last
;
assign
ram_wr_cmd_ready
=
ram_cmd_ready
&&
write_en
;
assign
ram_rd_cmd_ready
=
ram_cmd_ready
&&
read_en
;
always
@*
begin
write_en
=
1'b0
;
read_en
=
1'b0
;
last_read_next
=
last_read_reg
;
transaction_next
=
transaction_reg
;
write_eligible
=
ram_wr_cmd_en
&&
ram_cmd_ready
;
read_eligible
=
ram_rd_cmd_en
&&
ram_cmd_ready
;
if
(
write_eligible
&&
(
!
read_eligible
||
last_read_reg
||
(
!
INTERLEAVE
&&
transaction_reg
))
&&
(
INTERLEAVE
||
!
transaction_reg
||
!
last_read_reg
))
begin
last_read_next
=
1'b0
;
transaction_next
=
!
ram_wr_cmd_last
;
write_en
=
1'b1
;
end
else
if
(
read_eligible
&&
(
INTERLEAVE
||
!
transaction_reg
||
last_read_reg
))
begin
last_read_next
=
1'b1
;
transaction_next
=
!
ram_rd_cmd_last
;
read_en
=
1'b1
;
end
end
always
@
(
posedge
clk
)
begin
if
(
rst
)
begin
last_read_reg
<=
1'b0
;
transaction_reg
<=
1'b0
;
end
else
begin
last_read_reg
<=
last_read_next
;
transaction_reg
<=
transaction_next
;
end
end
endmodule
corundum/lib/axi/rtl/axi_register.v
0 → 100644
View file @
738c1fef
/*
Copyright (c) 2018 Alex Forencich
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.
*/
// Language: Verilog 2001
`timescale
1
ns
/
1
ps
/*
* AXI4 register
*/
module
axi_register
#
(
// Width of data bus in bits
parameter
DATA_WIDTH
=
32
,
// Width of address bus in bits
parameter
ADDR_WIDTH
=
32
,
// Width of wstrb (width of data bus in words)
parameter
STRB_WIDTH
=
(
DATA_WIDTH
/
8
),
// Width of ID signal
parameter
ID_WIDTH
=
8
,
// Propagate awuser signal
parameter
AWUSER_ENABLE
=
0
,
// Width of awuser signal
parameter
AWUSER_WIDTH
=
1
,
// Propagate wuser signal
parameter
WUSER_ENABLE
=
0
,
// Width of wuser signal
parameter
WUSER_WIDTH
=
1
,
// Propagate buser signal
parameter
BUSER_ENABLE
=
0
,
// Width of buser signal
parameter
BUSER_WIDTH
=
1
,
// Propagate aruser signal
parameter
ARUSER_ENABLE
=
0
,
// Width of aruser signal
parameter
ARUSER_WIDTH
=
1
,
// Propagate ruser signal
parameter
RUSER_ENABLE
=
0
,
// Width of ruser signal
parameter
RUSER_WIDTH
=
1
,
// AW channel register type
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter
AW_REG_TYPE
=
1
,
// W channel register type
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter
W_REG_TYPE
=
2
,
// B channel register type
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter
B_REG_TYPE
=
1
,
// AR channel register type
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter
AR_REG_TYPE
=
1
,
// R channel register type
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter
R_REG_TYPE
=
2
)
(
input
wire
clk
,
input
wire
rst
,
/*
* AXI slave interface
*/
input
wire
[
ID_WIDTH
-
1
:
0
]
s_axi_awid
,
input
wire
[
ADDR_WIDTH
-
1
:
0
]
s_axi_awaddr
,
input
wire
[
7
:
0
]
s_axi_awlen
,
input
wire
[
2
:
0
]
s_axi_awsize
,
input
wire
[
1
:
0
]
s_axi_awburst
,
input
wire
s_axi_awlock
,
input
wire
[
3
:
0
]
s_axi_awcache
,
input
wire
[
2
:
0
]
s_axi_awprot
,
input
wire
[
3
:
0
]
s_axi_awqos
,
input
wire
[
3
:
0
]
s_axi_awregion
,
input
wire
[
AWUSER_WIDTH
-
1
:
0
]
s_axi_awuser
,
input
wire
s_axi_awvalid
,
output
wire
s_axi_awready
,
input
wire
[
DATA_WIDTH
-
1
:
0
]
s_axi_wdata
,
input
wire
[
STRB_WIDTH
-
1
:
0
]
s_axi_wstrb
,
input
wire
s_axi_wlast
,
input
wire
[
WUSER_WIDTH
-
1
:
0
]
s_axi_wuser
,
input
wire
s_axi_wvalid
,
output
wire
s_axi_wready
,
output
wire
[
ID_WIDTH
-
1
:
0
]
s_axi_bid
,
output
wire
[
1
:
0
]
s_axi_bresp
,
output
wire
[
BUSER_WIDTH
-
1
:
0
]
s_axi_buser
,
output
wire
s_axi_bvalid
,
input
wire
s_axi_bready
,
input
wire
[
ID_WIDTH
-
1
:
0
]
s_axi_arid
,
input
wire
[
ADDR_WIDTH
-
1
:
0
]
s_axi_araddr
,
input
wire
[
7
:
0
]
s_axi_arlen
,
input
wire
[
2
:
0
]
s_axi_arsize
,
input
wire
[
1
:
0
]
s_axi_arburst
,
input
wire
s_axi_arlock
,
input
wire
[
3
:
0
]
s_axi_arcache
,
input
wire
[
2
:
0
]
s_axi_arprot
,
input
wire
[
3
:
0
]
s_axi_arqos
,
input
wire
[
3
:
0
]
s_axi_arregion
,
input
wire
[
ARUSER_WIDTH
-
1
:
0
]
s_axi_aruser
,
input
wire
s_axi_arvalid
,
output
wire
s_axi_arready
,
output
wire
[
ID_WIDTH
-
1
:
0
]
s_axi_rid
,
output
wire
[
DATA_WIDTH
-
1
:
0
]
s_axi_rdata
,
output
wire
[
1
:
0
]
s_axi_rresp
,
output
wire
s_axi_rlast
,
output
wire
[
RUSER_WIDTH
-
1
:
0
]
s_axi_ruser
,
output
wire
s_axi_rvalid
,
input
wire
s_axi_rready
,
/*
* AXI master interface
*/
output
wire
[
ID_WIDTH
-
1
:
0
]
m_axi_awid
,
output
wire
[
ADDR_WIDTH
-
1
:
0
]
m_axi_awaddr
,
output
wire
[
7
:
0
]
m_axi_awlen
,
output
wire
[
2
:
0
]
m_axi_awsize
,
output
wire
[
1
:
0
]
m_axi_awburst
,
output
wire
m_axi_awlock
,
output
wire
[
3
:
0
]
m_axi_awcache
,
output
wire
[
2
:
0
]
m_axi_awprot
,
output
wire
[
3
:
0
]
m_axi_awqos
,
output
wire
[
3
:
0
]
m_axi_awregion
,
output
wire
[
AWUSER_WIDTH
-
1
:
0
]
m_axi_awuser
,
output
wire
m_axi_awvalid
,
input
wire
m_axi_awready
,
output
wire
[
DATA_WIDTH
-
1
:
0
]
m_axi_wdata
,
output
wire
[
STRB_WIDTH
-
1
:
0
]
m_axi_wstrb
,
output
wire
m_axi_wlast
,
output
wire
[
WUSER_WIDTH
-
1
:
0
]
m_axi_wuser
,
output
wire
m_axi_wvalid
,
input
wire
m_axi_wready
,
input
wire
[
ID_WIDTH
-
1
:
0
]
m_axi_bid
,
input
wire
[
1
:
0
]
m_axi_bresp
,
input
wire
[
BUSER_WIDTH
-
1
:
0
]
m_axi_buser
,
input
wire
m_axi_bvalid
,
output
wire
m_axi_bready
,
output
wire
[
ID_WIDTH
-
1
:
0
]
m_axi_arid
,
output
wire
[
ADDR_WIDTH
-
1
:
0
]
m_axi_araddr
,
output
wire
[
7
:
0
]
m_axi_arlen
,
output
wire
[
2
:
0
]
m_axi_arsize
,
output
wire
[
1
:
0
]
m_axi_arburst
,
output
wire
m_axi_arlock
,
output
wire
[
3
:
0
]
m_axi_arcache
,
output
wire
[
2
:
0
]
m_axi_arprot
,
output
wire
[
3
:
0
]
m_axi_arqos
,
output
wire
[
3
:
0
]
m_axi_arregion
,
output
wire
[
ARUSER_WIDTH
-
1
:
0
]
m_axi_aruser
,
output
wire
m_axi_arvalid
,
input
wire
m_axi_arready
,
input
wire
[
ID_WIDTH
-
1
:
0
]
m_axi_rid
,
input
wire
[
DATA_WIDTH
-
1
:
0
]
m_axi_rdata
,
input
wire
[
1
:
0
]
m_axi_rresp
,
input
wire
m_axi_rlast
,
input
wire
[
RUSER_WIDTH
-
1
:
0
]
m_axi_ruser
,
input
wire
m_axi_rvalid
,
output
wire
m_axi_rready
);
axi_register_wr
#(
.
DATA_WIDTH
(
DATA_WIDTH
),
.
ADDR_WIDTH
(
ADDR_WIDTH
),
.
STRB_WIDTH
(
STRB_WIDTH
),
.
ID_WIDTH
(
ID_WIDTH
),
.
AWUSER_ENABLE
(
AWUSER_ENABLE
),
.
AWUSER_WIDTH
(
AWUSER_WIDTH
),
.
WUSER_ENABLE
(
WUSER_ENABLE
),
.
WUSER_WIDTH
(
WUSER_WIDTH
),
.
BUSER_ENABLE
(
BUSER_ENABLE
),
.
BUSER_WIDTH
(
BUSER_WIDTH
),
.
AW_REG_TYPE
(
AW_REG_TYPE
),
.
W_REG_TYPE
(
W_REG_TYPE
),
.
B_REG_TYPE
(
B_REG_TYPE
)
)
axi_register_wr_inst
(
.
clk
(
clk
),
.
rst
(
rst
),
/*
* AXI slave interface
*/
.
s_axi_awid
(
s_axi_awid
),
.
s_axi_awaddr
(
s_axi_awaddr
),
.
s_axi_awlen
(
s_axi_awlen
),
.
s_axi_awsize
(
s_axi_awsize
),
.
s_axi_awburst
(
s_axi_awburst
),
.
s_axi_awlock
(
s_axi_awlock
),
.
s_axi_awcache
(
s_axi_awcache
),
.
s_axi_awprot
(
s_axi_awprot
),
.
s_axi_awqos
(
s_axi_awqos
),
.
s_axi_awregion
(
s_axi_awregion
),
.
s_axi_awuser
(
s_axi_awuser
),
.
s_axi_awvalid
(
s_axi_awvalid
),
.
s_axi_awready
(
s_axi_awready
),
.
s_axi_wdata
(
s_axi_wdata
),
.
s_axi_wstrb
(
s_axi_wstrb
),
.
s_axi_wlast
(
s_axi_wlast
),
.
s_axi_wuser
(
s_axi_wuser
),
.
s_axi_wvalid
(
s_axi_wvalid
),
.
s_axi_wready
(
s_axi_wready
),
.
s_axi_bid
(
s_axi_bid
),
.
s_axi_bresp
(
s_axi_bresp
),
.
s_axi_buser
(
s_axi_buser
),
.
s_axi_bvalid
(
s_axi_bvalid
),
.
s_axi_bready
(
s_axi_bready
),
/*
* AXI master interface
*/
.
m_axi_awid
(
m_axi_awid
),
.
m_axi_awaddr
(
m_axi_awaddr
),
.
m_axi_awlen
(
m_axi_awlen
),
.
m_axi_awsize
(
m_axi_awsize
),
.
m_axi_awburst
(
m_axi_awburst
),
.
m_axi_awlock
(
m_axi_awlock
),
.
m_axi_awcache
(
m_axi_awcache
),
.
m_axi_awprot
(
m_axi_awprot
),
.
m_axi_awqos
(
m_axi_awqos
),
.
m_axi_awregion
(
m_axi_awregion
),
.
m_axi_awuser
(
m_axi_awuser
),
.
m_axi_awvalid
(
m_axi_awvalid
),
.
m_axi_awready
(
m_axi_awready
),
.
m_axi_wdata
(
m_axi_wdata
),
.
m_axi_wstrb
(
m_axi_wstrb
),
.
m_axi_wlast
(
m_axi_wlast
),
.
m_axi_wuser
(
m_axi_wuser
),
.
m_axi_wvalid
(
m_axi_wvalid
),
.
m_axi_wready
(
m_axi_wready
),
.
m_axi_bid
(
m_axi_bid
),
.
m_axi_bresp
(
m_axi_bresp
),
.
m_axi_buser
(
m_axi_buser
),
.
m_axi_bvalid
(
m_axi_bvalid
),
.
m_axi_bready
(
m_axi_bready
)
);
axi_register_rd
#(
.
DATA_WIDTH
(
DATA_WIDTH
),
.
ADDR_WIDTH
(
ADDR_WIDTH
),
.
STRB_WIDTH
(
STRB_WIDTH
),
.
ID_WIDTH
(
ID_WIDTH
),
.
ARUSER_ENABLE
(
ARUSER_ENABLE
),
.
ARUSER_WIDTH
(
ARUSER_WIDTH
),
.
RUSER_ENABLE
(
RUSER_ENABLE
),
.
RUSER_WIDTH
(
RUSER_WIDTH
),
.
AR_REG_TYPE
(
AR_REG_TYPE
),
.
R_REG_TYPE
(
R_REG_TYPE
)
)
axi_register_rd_inst
(
.
clk
(
clk
),
.
rst
(
rst
),
/*
* AXI slave interface
*/
.
s_axi_arid
(
s_axi_arid
),
.
s_axi_araddr
(
s_axi_araddr
),
.
s_axi_arlen
(
s_axi_arlen
),
.
s_axi_arsize
(
s_axi_arsize
),
.
s_axi_arburst
(
s_axi_arburst
),
.
s_axi_arlock
(
s_axi_arlock
),
.
s_axi_arcache
(
s_axi_arcache
),
.
s_axi_arprot
(
s_axi_arprot
),
.
s_axi_arqos
(
s_axi_arqos
),
.
s_axi_arregion
(
s_axi_arregion
),
.
s_axi_aruser
(
s_axi_aruser
),
.
s_axi_arvalid
(
s_axi_arvalid
),
.
s_axi_arready
(
s_axi_arready
),
.
s_axi_rid
(
s_axi_rid
),
.
s_axi_rdata
(
s_axi_rdata
),
.
s_axi_rresp
(
s_axi_rresp
),
.
s_axi_rlast
(
s_axi_rlast
),
.
s_axi_ruser
(
s_axi_ruser
),
.
s_axi_rvalid
(
s_axi_rvalid
),
.
s_axi_rready
(
s_axi_rready
),
/*
* AXI master interface
*/
.
m_axi_arid
(
m_axi_arid
),
.
m_axi_araddr
(
m_axi_araddr
),
.
m_axi_arlen
(
m_axi_arlen
),
.
m_axi_arsize
(
m_axi_arsize
),
.
m_axi_arburst
(
m_axi_arburst
),
.
m_axi_arlock
(
m_axi_arlock
),
.
m_axi_arcache
(
m_axi_arcache
),
.
m_axi_arprot
(
m_axi_arprot
),
.
m_axi_arqos
(
m_axi_arqos
),
.
m_axi_arregion
(
m_axi_arregion
),
.
m_axi_aruser
(
m_axi_aruser
),
.
m_axi_arvalid
(
m_axi_arvalid
),
.
m_axi_arready
(
m_axi_arready
),
.
m_axi_rid
(
m_axi_rid
),
.
m_axi_rdata
(
m_axi_rdata
),
.
m_axi_rresp
(
m_axi_rresp
),
.
m_axi_rlast
(
m_axi_rlast
),
.
m_axi_ruser
(
m_axi_ruser
),
.
m_axi_rvalid
(
m_axi_rvalid
),
.
m_axi_rready
(
m_axi_rready
)
);
endmodule
corundum/lib/axi/rtl/axi_register_rd.v
0 → 100644
View file @
738c1fef
/*
Copyright (c) 2018 Alex Forencich
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.
*/
// Language: Verilog 2001
`timescale
1
ns
/
1
ps
/*
* AXI4 register (read)
*/
module
axi_register_rd
#
(
// Width of data bus in bits
parameter
DATA_WIDTH
=
32
,
// Width of address bus in bits
parameter
ADDR_WIDTH
=
32
,
// Width of wstrb (width of data bus in words)
parameter
STRB_WIDTH
=
(
DATA_WIDTH
/
8
),
// Width of ID signal
parameter
ID_WIDTH
=
8
,
// Propagate aruser signal
parameter
ARUSER_ENABLE
=
0
,
// Width of aruser signal
parameter
ARUSER_WIDTH
=
1
,
// Propagate ruser signal
parameter
RUSER_ENABLE
=
0
,
// Width of ruser signal
parameter
RUSER_WIDTH
=
1
,
// AR channel register type
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter
AR_REG_TYPE
=
1
,
// R channel register type
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter
R_REG_TYPE
=
2
)
(
input
wire
clk
,
input
wire
rst
,
/*
* AXI slave interface
*/
input
wire
[
ID_WIDTH
-
1
:
0
]
s_axi_arid
,
input
wire
[
ADDR_WIDTH
-
1
:
0
]
s_axi_araddr
,
input
wire
[
7
:
0
]
s_axi_arlen
,
input
wire
[
2
:
0
]
s_axi_arsize
,
input
wire
[
1
:
0
]
s_axi_arburst
,
input
wire
s_axi_arlock
,
input
wire
[
3
:
0
]
s_axi_arcache
,
input
wire
[
2
:
0
]
s_axi_arprot
,
input
wire
[
3
:
0
]
s_axi_arqos
,
input
wire
[
3
:
0
]
s_axi_arregion
,
input
wire
[
ARUSER_WIDTH
-
1
:
0
]
s_axi_aruser
,
input
wire
s_axi_arvalid
,
output
wire
s_axi_arready
,
output
wire
[
ID_WIDTH
-
1
:
0
]
s_axi_rid
,
output
wire
[
DATA_WIDTH
-
1
:
0
]
s_axi_rdata
,
output
wire
[
1
:
0
]
s_axi_rresp
,
output
wire
s_axi_rlast
,
output
wire
[
RUSER_WIDTH
-
1
:
0
]
s_axi_ruser
,
output
wire
s_axi_rvalid
,
input
wire
s_axi_rready
,
/*
* AXI master interface
*/
output
wire
[
ID_WIDTH
-
1
:
0
]
m_axi_arid
,
output
wire
[
ADDR_WIDTH
-
1
:
0
]
m_axi_araddr
,
output
wire
[
7
:
0
]
m_axi_arlen
,
output
wire
[
2
:
0
]
m_axi_arsize
,
output
wire
[
1
:
0
]
m_axi_arburst
,
output
wire
m_axi_arlock
,
output
wire
[
3
:
0
]
m_axi_arcache
,
output
wire
[
2
:
0
]
m_axi_arprot
,
output
wire
[
3
:
0
]
m_axi_arqos
,
output
wire
[
3
:
0
]
m_axi_arregion
,
output
wire
[
ARUSER_WIDTH
-
1
:
0
]
m_axi_aruser
,
output
wire
m_axi_arvalid
,
input
wire
m_axi_arready
,
input
wire
[
ID_WIDTH
-
1
:
0
]
m_axi_rid
,
input
wire
[
DATA_WIDTH
-
1
:
0
]
m_axi_rdata
,
input
wire
[
1
:
0
]
m_axi_rresp
,
input
wire
m_axi_rlast
,
input
wire
[
RUSER_WIDTH
-
1
:
0
]
m_axi_ruser
,
input
wire
m_axi_rvalid
,
output
wire
m_axi_rready
);
generate
// AR channel
if
(
AR_REG_TYPE
>
1
)
begin
// skid buffer, no bubble cycles
// datapath registers
reg
s_axi_arready_reg
=
1'b0
;
reg
[
ID_WIDTH
-
1
:
0
]
m_axi_arid_reg
=
{
ID_WIDTH
{
1'b0
}}
;
reg
[
ADDR_WIDTH
-
1
:
0
]
m_axi_araddr_reg
=
{
ADDR_WIDTH
{
1'b0
}}
;
reg
[
7
:
0
]
m_axi_arlen_reg
=
8'd0
;
reg
[
2
:
0
]
m_axi_arsize_reg
=
3'd0
;
reg
[
1
:
0
]
m_axi_arburst_reg
=
2'd0
;
reg
m_axi_arlock_reg
=
1'b0
;
reg
[
3
:
0
]
m_axi_arcache_reg
=
4'd0
;
reg
[
2
:
0
]
m_axi_arprot_reg
=
3'd0
;
reg
[
3
:
0
]
m_axi_arqos_reg
=
4'd0
;
reg
[
3
:
0
]
m_axi_arregion_reg
=
4'd0
;
reg
[
ARUSER_WIDTH
-
1
:
0
]
m_axi_aruser_reg
=
{
ARUSER_WIDTH
{
1'b0
}}
;
reg
m_axi_arvalid_reg
=
1'b0
,
m_axi_arvalid_next
;
reg
[
ID_WIDTH
-
1
:
0
]
temp_m_axi_arid_reg
=
{
ID_WIDTH
{
1'b0
}}
;
reg
[
ADDR_WIDTH
-
1
:
0
]
temp_m_axi_araddr_reg
=
{
ADDR_WIDTH
{
1'b0
}}
;
reg
[
7
:
0
]
temp_m_axi_arlen_reg
=
8'd0
;
reg
[
2
:
0
]
temp_m_axi_arsize_reg
=
3'd0
;
reg
[
1
:
0
]
temp_m_axi_arburst_reg
=
2'd0
;
reg
temp_m_axi_arlock_reg
=
1'b0
;
reg
[
3
:
0
]
temp_m_axi_arcache_reg
=
4'd0
;
reg
[
2
:
0
]
temp_m_axi_arprot_reg
=
3'd0
;
reg
[
3
:
0
]
temp_m_axi_arqos_reg
=
4'd0
;
reg
[
3
:
0
]
temp_m_axi_arregion_reg
=
4'd0
;
reg
[
ARUSER_WIDTH
-
1
:
0
]
temp_m_axi_aruser_reg
=
{
ARUSER_WIDTH
{
1'b0
}}
;
reg
temp_m_axi_arvalid_reg
=
1'b0
,
temp_m_axi_arvalid_next
;
// datapath control
reg
store_axi_ar_input_to_output
;
reg
store_axi_ar_input_to_temp
;
reg
store_axi_ar_temp_to_output
;
assign
s_axi_arready
=
s_axi_arready_reg
;
assign
m_axi_arid
=
m_axi_arid_reg
;
assign
m_axi_araddr
=
m_axi_araddr_reg
;
assign
m_axi_arlen
=
m_axi_arlen_reg
;
assign
m_axi_arsize
=
m_axi_arsize_reg
;
assign
m_axi_arburst
=
m_axi_arburst_reg
;
assign
m_axi_arlock
=
m_axi_arlock_reg
;
assign
m_axi_arcache
=
m_axi_arcache_reg
;
assign
m_axi_arprot
=
m_axi_arprot_reg
;
assign
m_axi_arqos
=
m_axi_arqos_reg
;
assign
m_axi_arregion
=
m_axi_arregion_reg
;
assign
m_axi_aruser
=
ARUSER_ENABLE
?
m_axi_aruser_reg
:
{
ARUSER_WIDTH
{
1'b0
}}
;
assign
m_axi_arvalid
=
m_axi_arvalid_reg
;
// enable ready input next cycle if output is ready or the temp reg will not be filled on the next cycle (output reg empty or no input)
wire
s_axi_arready_early
=
m_axi_arready
|
(
~
temp_m_axi_arvalid_reg
&
(
~
m_axi_arvalid_reg
|
~
s_axi_arvalid
));
always
@*
begin
// transfer sink ready state to source
m_axi_arvalid_next
=
m_axi_arvalid_reg
;
temp_m_axi_arvalid_next
=
temp_m_axi_arvalid_reg
;
store_axi_ar_input_to_output
=
1'b0
;
store_axi_ar_input_to_temp
=
1'b0
;
store_axi_ar_temp_to_output
=
1'b0
;
if
(
s_axi_arready_reg
)
begin
// input is ready
if
(
m_axi_arready
|
~
m_axi_arvalid_reg
)
begin
// output is ready or currently not valid, transfer data to output
m_axi_arvalid_next
=
s_axi_arvalid
;
store_axi_ar_input_to_output
=
1'b1
;
end
else
begin
// output is not ready, store input in temp
temp_m_axi_arvalid_next
=
s_axi_arvalid
;
store_axi_ar_input_to_temp
=
1'b1
;
end
end
else
if
(
m_axi_arready
)
begin
// input is not ready, but output is ready
m_axi_arvalid_next
=
temp_m_axi_arvalid_reg
;
temp_m_axi_arvalid_next
=
1'b0
;
store_axi_ar_temp_to_output
=
1'b1
;
end
end
always
@
(
posedge
clk
)
begin
if
(
rst
)
begin
s_axi_arready_reg
<=
1'b0
;
m_axi_arvalid_reg
<=
1'b0
;
temp_m_axi_arvalid_reg
<=
1'b0
;
end
else
begin
s_axi_arready_reg
<=
s_axi_arready_early
;
m_axi_arvalid_reg
<=
m_axi_arvalid_next
;
temp_m_axi_arvalid_reg
<=
temp_m_axi_arvalid_next
;
end
// datapath
if
(
store_axi_ar_input_to_output
)
begin
m_axi_arid_reg
<=
s_axi_arid
;
m_axi_araddr_reg
<=
s_axi_araddr
;
m_axi_arlen_reg
<=
s_axi_arlen
;
m_axi_arsize_reg
<=
s_axi_arsize
;
m_axi_arburst_reg
<=
s_axi_arburst
;
m_axi_arlock_reg
<=
s_axi_arlock
;
m_axi_arcache_reg
<=
s_axi_arcache
;
m_axi_arprot_reg
<=
s_axi_arprot
;
m_axi_arqos_reg
<=
s_axi_arqos
;
m_axi_arregion_reg
<=
s_axi_arregion
;
m_axi_aruser_reg
<=
s_axi_aruser
;
end
else
if
(
store_axi_ar_temp_to_output
)
begin
m_axi_arid_reg
<=
temp_m_axi_arid_reg
;
m_axi_araddr_reg
<=
temp_m_axi_araddr_reg
;
m_axi_arlen_reg
<=
temp_m_axi_arlen_reg
;
m_axi_arsize_reg
<=
temp_m_axi_arsize_reg
;
m_axi_arburst_reg
<=
temp_m_axi_arburst_reg
;
m_axi_arlock_reg
<=
temp_m_axi_arlock_reg
;
m_axi_arcache_reg
<=
temp_m_axi_arcache_reg
;
m_axi_arprot_reg
<=
temp_m_axi_arprot_reg
;
m_axi_arqos_reg
<=
temp_m_axi_arqos_reg
;
m_axi_arregion_reg
<=
temp_m_axi_arregion_reg
;
m_axi_aruser_reg
<=
temp_m_axi_aruser_reg
;
end
if
(
store_axi_ar_input_to_temp
)
begin
temp_m_axi_arid_reg
<=
s_axi_arid
;
temp_m_axi_araddr_reg
<=
s_axi_araddr
;
temp_m_axi_arlen_reg
<=
s_axi_arlen
;
temp_m_axi_arsize_reg
<=
s_axi_arsize
;
temp_m_axi_arburst_reg
<=
s_axi_arburst
;
temp_m_axi_arlock_reg
<=
s_axi_arlock
;
temp_m_axi_arcache_reg
<=
s_axi_arcache
;
temp_m_axi_arprot_reg
<=
s_axi_arprot
;
temp_m_axi_arqos_reg
<=
s_axi_arqos
;
temp_m_axi_arregion_reg
<=
s_axi_arregion
;
temp_m_axi_aruser_reg
<=
s_axi_aruser
;
end
end
end
else
if
(
AR_REG_TYPE
==
1
)
begin
// simple register, inserts bubble cycles
// datapath registers
reg
s_axi_arready_reg
=
1'b0
;
reg
[
ID_WIDTH
-
1
:
0
]
m_axi_arid_reg
=
{
ID_WIDTH
{
1'b0
}}
;
reg
[
ADDR_WIDTH
-
1
:
0
]
m_axi_araddr_reg
=
{
ADDR_WIDTH
{
1'b0
}}
;
reg
[
7
:
0
]
m_axi_arlen_reg
=
8'd0
;
reg
[
2
:
0
]
m_axi_arsize_reg
=
3'd0
;
reg
[
1
:
0
]
m_axi_arburst_reg
=
2'd0
;
reg
m_axi_arlock_reg
=
1'b0
;
reg
[
3
:
0
]
m_axi_arcache_reg
=
4'd0
;
reg
[
2
:
0
]
m_axi_arprot_reg
=
3'd0
;
reg
[
3
:
0
]
m_axi_arqos_reg
=
4'd0
;
reg
[
3
:
0
]
m_axi_arregion_reg
=
4'd0
;
reg
[
ARUSER_WIDTH
-
1
:
0
]
m_axi_aruser_reg
=
{
ARUSER_WIDTH
{
1'b0
}}
;
reg
m_axi_arvalid_reg
=
1'b0
,
m_axi_arvalid_next
;
// datapath control
reg
store_axi_ar_input_to_output
;
assign
s_axi_arready
=
s_axi_arready_reg
;
assign
m_axi_arid
=
m_axi_arid_reg
;
assign
m_axi_araddr
=
m_axi_araddr_reg
;
assign
m_axi_arlen
=
m_axi_arlen_reg
;
assign
m_axi_arsize
=
m_axi_arsize_reg
;
assign
m_axi_arburst
=
m_axi_arburst_reg
;
assign
m_axi_arlock
=
m_axi_arlock_reg
;
assign
m_axi_arcache
=
m_axi_arcache_reg
;
assign
m_axi_arprot
=
m_axi_arprot_reg
;
assign
m_axi_arqos
=
m_axi_arqos_reg
;
assign
m_axi_arregion
=
m_axi_arregion_reg
;
assign
m_axi_aruser
=
ARUSER_ENABLE
?
m_axi_aruser_reg
:
{
ARUSER_WIDTH
{
1'b0
}}
;
assign
m_axi_arvalid
=
m_axi_arvalid_reg
;
// enable ready input next cycle if output buffer will be empty
wire
s_axi_arready_early
=
!
m_axi_arvalid_next
;
always
@*
begin
// transfer sink ready state to source
m_axi_arvalid_next
=
m_axi_arvalid_reg
;
store_axi_ar_input_to_output
=
1'b0
;
if
(
s_axi_arready_reg
)
begin
m_axi_arvalid_next
=
s_axi_arvalid
;
store_axi_ar_input_to_output
=
1'b1
;
end
else
if
(
m_axi_arready
)
begin
m_axi_arvalid_next
=
1'b0
;
end
end
always
@
(
posedge
clk
)
begin
if
(
rst
)
begin
s_axi_arready_reg
<=
1'b0
;
m_axi_arvalid_reg
<=
1'b0
;
end
else
begin
s_axi_arready_reg
<=
s_axi_arready_early
;
m_axi_arvalid_reg
<=
m_axi_arvalid_next
;
end
// datapath
if
(
store_axi_ar_input_to_output
)
begin
m_axi_arid_reg
<=
s_axi_arid
;
m_axi_araddr_reg
<=
s_axi_araddr
;
m_axi_arlen_reg
<=
s_axi_arlen
;
m_axi_arsize_reg
<=
s_axi_arsize
;
m_axi_arburst_reg
<=
s_axi_arburst
;
m_axi_arlock_reg
<=
s_axi_arlock
;
m_axi_arcache_reg
<=
s_axi_arcache
;
m_axi_arprot_reg
<=
s_axi_arprot
;
m_axi_arqos_reg
<=
s_axi_arqos
;
m_axi_arregion_reg
<=
s_axi_arregion
;
m_axi_aruser_reg
<=
s_axi_aruser
;
end
end
end
else
begin
// bypass AR channel
assign
m_axi_arid
=
s_axi_arid
;
assign
m_axi_araddr
=
s_axi_araddr
;
assign
m_axi_arlen
=
s_axi_arlen
;
assign
m_axi_arsize
=
s_axi_arsize
;
assign
m_axi_arburst
=
s_axi_arburst
;
assign
m_axi_arlock
=
s_axi_arlock
;
assign
m_axi_arcache
=
s_axi_arcache
;
assign
m_axi_arprot
=
s_axi_arprot
;
assign
m_axi_arqos
=
s_axi_arqos
;
assign
m_axi_arregion
=
s_axi_arregion
;
assign
m_axi_aruser
=
ARUSER_ENABLE
?
s_axi_aruser
:
{
ARUSER_WIDTH
{
1'b0
}}
;
assign
m_axi_arvalid
=
s_axi_arvalid
;
assign
s_axi_arready
=
m_axi_arready
;
end
// R channel
if
(
R_REG_TYPE
>
1
)
begin
// skid buffer, no bubble cycles
// datapath registers
reg
m_axi_rready_reg
=
1'b0
;
reg
[
ID_WIDTH
-
1
:
0
]
s_axi_rid_reg
=
{
ID_WIDTH
{
1'b0
}}
;
reg
[
DATA_WIDTH
-
1
:
0
]
s_axi_rdata_reg
=
{
DATA_WIDTH
{
1'b0
}}
;
reg
[
1
:
0
]
s_axi_rresp_reg
=
2'b0
;
reg
s_axi_rlast_reg
=
1'b0
;
reg
[
RUSER_WIDTH
-
1
:
0
]
s_axi_ruser_reg
=
{
RUSER_WIDTH
{
1'b0
}}
;
reg
s_axi_rvalid_reg
=
1'b0
,
s_axi_rvalid_next
;
reg
[
ID_WIDTH
-
1
:
0
]
temp_s_axi_rid_reg
=
{
ID_WIDTH
{
1'b0
}}
;
reg
[
DATA_WIDTH
-
1
:
0
]
temp_s_axi_rdata_reg
=
{
DATA_WIDTH
{
1'b0
}}
;
reg
[
1
:
0
]
temp_s_axi_rresp_reg
=
2'b0
;
reg
temp_s_axi_rlast_reg
=
1'b0
;
reg
[
RUSER_WIDTH
-
1
:
0
]
temp_s_axi_ruser_reg
=
{
RUSER_WIDTH
{
1'b0
}}
;
reg
temp_s_axi_rvalid_reg
=
1'b0
,
temp_s_axi_rvalid_next
;
// datapath control
reg
store_axi_r_input_to_output
;
reg
store_axi_r_input_to_temp
;
reg
store_axi_r_temp_to_output
;
assign
m_axi_rready
=
m_axi_rready_reg
;
assign
s_axi_rid
=
s_axi_rid_reg
;
assign
s_axi_rdata
=
s_axi_rdata_reg
;
assign
s_axi_rresp
=
s_axi_rresp_reg
;
assign
s_axi_rlast
=
s_axi_rlast_reg
;
assign
s_axi_ruser
=
RUSER_ENABLE
?
s_axi_ruser_reg
:
{
RUSER_WIDTH
{
1'b0
}}
;
assign
s_axi_rvalid
=
s_axi_rvalid_reg
;
// enable ready input next cycle if output is ready or the temp reg will not be filled on the next cycle (output reg empty or no input)
wire
m_axi_rready_early
=
s_axi_rready
|
(
~
temp_s_axi_rvalid_reg
&
(
~
s_axi_rvalid_reg
|
~
m_axi_rvalid
));
always
@*
begin
// transfer sink ready state to source
s_axi_rvalid_next
=
s_axi_rvalid_reg
;
temp_s_axi_rvalid_next
=
temp_s_axi_rvalid_reg
;
store_axi_r_input_to_output
=
1'b0
;
store_axi_r_input_to_temp
=
1'b0
;
store_axi_r_temp_to_output
=
1'b0
;
if
(
m_axi_rready_reg
)
begin
// input is ready
if
(
s_axi_rready
|
~
s_axi_rvalid_reg
)
begin
// output is ready or currently not valid, transfer data to output
s_axi_rvalid_next
=
m_axi_rvalid
;
store_axi_r_input_to_output
=
1'b1
;
end
else
begin
// output is not ready, store input in temp
temp_s_axi_rvalid_next
=
m_axi_rvalid
;
store_axi_r_input_to_temp
=
1'b1
;
end
end
else
if
(
s_axi_rready
)
begin
// input is not ready, but output is ready
s_axi_rvalid_next
=
temp_s_axi_rvalid_reg
;
temp_s_axi_rvalid_next
=
1'b0
;
store_axi_r_temp_to_output
=
1'b1
;
end
end
always
@
(
posedge
clk
)
begin
if
(
rst
)
begin
m_axi_rready_reg
<=
1'b0
;
s_axi_rvalid_reg
<=
1'b0
;
temp_s_axi_rvalid_reg
<=
1'b0
;
end
else
begin
m_axi_rready_reg
<=
m_axi_rready_early
;
s_axi_rvalid_reg
<=
s_axi_rvalid_next
;
temp_s_axi_rvalid_reg
<=
temp_s_axi_rvalid_next
;
end
// datapath
if
(
store_axi_r_input_to_output
)
begin
s_axi_rid_reg
<=
m_axi_rid
;
s_axi_rdata_reg
<=
m_axi_rdata
;
s_axi_rresp_reg
<=
m_axi_rresp
;
s_axi_rlast_reg
<=
m_axi_rlast
;
s_axi_ruser_reg
<=
m_axi_ruser
;
end
else
if
(
store_axi_r_temp_to_output
)
begin
s_axi_rid_reg
<=
temp_s_axi_rid_reg
;
s_axi_rdata_reg
<=
temp_s_axi_rdata_reg
;
s_axi_rresp_reg
<=
temp_s_axi_rresp_reg
;
s_axi_rlast_reg
<=
temp_s_axi_rlast_reg
;
s_axi_ruser_reg
<=
temp_s_axi_ruser_reg
;
end
if
(
store_axi_r_input_to_temp
)
begin
temp_s_axi_rid_reg
<=
m_axi_rid
;
temp_s_axi_rdata_reg
<=
m_axi_rdata
;
temp_s_axi_rresp_reg
<=
m_axi_rresp
;
temp_s_axi_rlast_reg
<=
m_axi_rlast
;
temp_s_axi_ruser_reg
<=
m_axi_ruser
;
end
end
end
else
if
(
R_REG_TYPE
==
1
)
begin
// simple register, inserts bubble cycles
// datapath registers
reg
m_axi_rready_reg
=
1'b0
;
reg
[
ID_WIDTH
-
1
:
0
]
s_axi_rid_reg
=
{
ID_WIDTH
{
1'b0
}}
;
reg
[
DATA_WIDTH
-
1
:
0
]
s_axi_rdata_reg
=
{
DATA_WIDTH
{
1'b0
}}
;
reg
[
1
:
0
]
s_axi_rresp_reg
=
2'b0
;
reg
s_axi_rlast_reg
=
1'b0
;
reg
[
RUSER_WIDTH
-
1
:
0
]
s_axi_ruser_reg
=
{
RUSER_WIDTH
{
1'b0
}}
;
reg
s_axi_rvalid_reg
=
1'b0
,
s_axi_rvalid_next
;
// datapath control
reg
store_axi_r_input_to_output
;
assign
m_axi_rready
=
m_axi_rready_reg
;
assign
s_axi_rid
=
s_axi_rid_reg
;
assign
s_axi_rdata
=
s_axi_rdata_reg
;
assign
s_axi_rresp
=
s_axi_rresp_reg
;
assign
s_axi_rlast
=
s_axi_rlast_reg
;
assign
s_axi_ruser
=
RUSER_ENABLE
?
s_axi_ruser_reg
:
{
RUSER_WIDTH
{
1'b0
}}
;
assign
s_axi_rvalid
=
s_axi_rvalid_reg
;
// enable ready input next cycle if output buffer will be empty
wire
m_axi_rready_early
=
!
s_axi_rvalid_next
;
always
@*
begin
// transfer sink ready state to source
s_axi_rvalid_next
=
s_axi_rvalid_reg
;
store_axi_r_input_to_output
=
1'b0
;
if
(
m_axi_rready_reg
)
begin
s_axi_rvalid_next
=
m_axi_rvalid
;
store_axi_r_input_to_output
=
1'b1
;
end
else
if
(
s_axi_rready
)
begin
s_axi_rvalid_next
=
1'b0
;
end
end
always
@
(
posedge
clk
)
begin
if
(
rst
)
begin
m_axi_rready_reg
<=
1'b0
;
s_axi_rvalid_reg
<=
1'b0
;
end
else
begin
m_axi_rready_reg
<=
m_axi_rready_early
;
s_axi_rvalid_reg
<=
s_axi_rvalid_next
;
end
// datapath
if
(
store_axi_r_input_to_output
)
begin
s_axi_rid_reg
<=
m_axi_rid
;
s_axi_rdata_reg
<=
m_axi_rdata
;
s_axi_rresp_reg
<=
m_axi_rresp
;
s_axi_rlast_reg
<=
m_axi_rlast
;
s_axi_ruser_reg
<=
m_axi_ruser
;
end
end
end
else
begin
// bypass R channel
assign
s_axi_rid
=
m_axi_rid
;
assign
s_axi_rdata
=
m_axi_rdata
;
assign
s_axi_rresp
=
m_axi_rresp
;
assign
s_axi_rlast
=
m_axi_rlast
;
assign
s_axi_ruser
=
RUSER_ENABLE
?
m_axi_ruser
:
{
RUSER_WIDTH
{
1'b0
}}
;
assign
s_axi_rvalid
=
m_axi_rvalid
;
assign
m_axi_rready
=
s_axi_rready
;
end
endgenerate
endmodule
corundum/lib/axi/rtl/axi_register_wr.v
0 → 100644
View file @
738c1fef
/*
Copyright (c) 2018 Alex Forencich
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.
*/
// Language: Verilog 2001
`timescale
1
ns
/
1
ps
/*
* AXI4 register (write)
*/
module
axi_register_wr
#
(
// Width of data bus in bits
parameter
DATA_WIDTH
=
32
,
// Width of address bus in bits
parameter
ADDR_WIDTH
=
32
,
// Width of wstrb (width of data bus in words)
parameter
STRB_WIDTH
=
(
DATA_WIDTH
/
8
),
// Width of ID signal
parameter
ID_WIDTH
=
8
,
// Propagate awuser signal
parameter
AWUSER_ENABLE
=
0
,
// Width of awuser signal
parameter
AWUSER_WIDTH
=
1
,
// Propagate wuser signal
parameter
WUSER_ENABLE
=
0
,
// Width of wuser signal
parameter
WUSER_WIDTH
=
1
,
// Propagate buser signal
parameter
BUSER_ENABLE
=
0
,
// Width of buser signal
parameter
BUSER_WIDTH
=
1
,
// AW channel register type
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter
AW_REG_TYPE
=
1
,
// W channel register type
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter
W_REG_TYPE
=
2
,
// B channel register type
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter
B_REG_TYPE
=
1
)
(
input
wire
clk
,
input
wire
rst
,
/*
* AXI slave interface
*/
input
wire
[
ID_WIDTH
-
1
:
0
]
s_axi_awid
,
input
wire
[
ADDR_WIDTH
-
1
:
0
]
s_axi_awaddr
,
input
wire
[
7
:
0
]
s_axi_awlen
,
input
wire
[
2
:
0
]
s_axi_awsize
,
input
wire
[
1
:
0
]
s_axi_awburst
,
input
wire
s_axi_awlock
,
input
wire
[
3
:
0
]
s_axi_awcache
,
input
wire
[
2
:
0
]
s_axi_awprot
,
input
wire
[
3
:
0
]
s_axi_awqos
,
input
wire
[
3
:
0
]
s_axi_awregion
,
input
wire
[
AWUSER_WIDTH
-
1
:
0
]
s_axi_awuser
,
input
wire
s_axi_awvalid
,
output
wire
s_axi_awready
,
input
wire
[
DATA_WIDTH
-
1
:
0
]
s_axi_wdata
,
input
wire
[
STRB_WIDTH
-
1
:
0
]
s_axi_wstrb
,
input
wire
s_axi_wlast
,
input
wire
[
WUSER_WIDTH
-
1
:
0
]
s_axi_wuser
,
input
wire
s_axi_wvalid
,
output
wire
s_axi_wready
,
output
wire
[
ID_WIDTH
-
1
:
0
]
s_axi_bid
,
output
wire
[
1
:
0
]
s_axi_bresp
,
output
wire
[
BUSER_WIDTH
-
1
:
0
]
s_axi_buser
,
output
wire
s_axi_bvalid
,
input
wire
s_axi_bready
,
/*
* AXI master interface
*/
output
wire
[
ID_WIDTH
-
1
:
0
]
m_axi_awid
,
output
wire
[
ADDR_WIDTH
-
1
:
0
]
m_axi_awaddr
,
output
wire
[
7
:
0
]
m_axi_awlen
,
output
wire
[
2
:
0
]
m_axi_awsize
,
output
wire
[
1
:
0
]
m_axi_awburst
,
output
wire
m_axi_awlock
,
output
wire
[
3
:
0
]
m_axi_awcache
,
output
wire
[
2
:
0
]
m_axi_awprot
,
output
wire
[
3
:
0
]
m_axi_awqos
,
output
wire
[
3
:
0
]
m_axi_awregion
,
output
wire
[
AWUSER_WIDTH
-
1
:
0
]
m_axi_awuser
,
output
wire
m_axi_awvalid
,
input
wire
m_axi_awready
,
output
wire
[
DATA_WIDTH
-
1
:
0
]
m_axi_wdata
,
output
wire
[
STRB_WIDTH
-
1
:
0
]
m_axi_wstrb
,
output
wire
m_axi_wlast
,
output
wire
[
WUSER_WIDTH
-
1
:
0
]
m_axi_wuser
,
output
wire
m_axi_wvalid
,
input
wire
m_axi_wready
,
input
wire
[
ID_WIDTH
-
1
:
0
]
m_axi_bid
,
input
wire
[
1
:
0
]
m_axi_bresp
,
input
wire
[
BUSER_WIDTH
-
1
:
0
]
m_axi_buser
,
input
wire
m_axi_bvalid
,
output
wire
m_axi_bready
);
generate
// AW channel
if
(
AW_REG_TYPE
>
1
)
begin
// skid buffer, no bubble cycles
// datapath registers
reg
s_axi_awready_reg
=
1'b0
;
reg
[
ID_WIDTH
-
1
:
0
]
m_axi_awid_reg
=
{
ID_WIDTH
{
1'b0
}}
;
reg
[
ADDR_WIDTH
-
1
:
0
]
m_axi_awaddr_reg
=
{
ADDR_WIDTH
{
1'b0
}}
;
reg
[
7
:
0
]
m_axi_awlen_reg
=
8'd0
;
reg
[
2
:
0
]
m_axi_awsize_reg
=
3'd0
;
reg
[
1
:
0
]
m_axi_awburst_reg
=
2'd0
;
reg
m_axi_awlock_reg
=
1'b0
;
reg
[
3
:
0
]
m_axi_awcache_reg
=
4'd0
;
reg
[
2
:
0
]
m_axi_awprot_reg
=
3'd0
;
reg
[
3
:
0
]
m_axi_awqos_reg
=
4'd0
;
reg
[
3
:
0
]
m_axi_awregion_reg
=
4'd0
;
reg
[
AWUSER_WIDTH
-
1
:
0
]
m_axi_awuser_reg
=
{
AWUSER_WIDTH
{
1'b0
}}
;
reg
m_axi_awvalid_reg
=
1'b0
,
m_axi_awvalid_next
;
reg
[
ID_WIDTH
-
1
:
0
]
temp_m_axi_awid_reg
=
{
ID_WIDTH
{
1'b0
}}
;
reg
[
ADDR_WIDTH
-
1
:
0
]
temp_m_axi_awaddr_reg
=
{
ADDR_WIDTH
{
1'b0
}}
;
reg
[
7
:
0
]
temp_m_axi_awlen_reg
=
8'd0
;
reg
[
2
:
0
]
temp_m_axi_awsize_reg
=
3'd0
;
reg
[
1
:
0
]
temp_m_axi_awburst_reg
=
2'd0
;
reg
temp_m_axi_awlock_reg
=
1'b0
;
reg
[
3
:
0
]
temp_m_axi_awcache_reg
=
4'd0
;
reg
[
2
:
0
]
temp_m_axi_awprot_reg
=
3'd0
;
reg
[
3
:
0
]
temp_m_axi_awqos_reg
=
4'd0
;
reg
[
3
:
0
]
temp_m_axi_awregion_reg
=
4'd0
;
reg
[
AWUSER_WIDTH
-
1
:
0
]
temp_m_axi_awuser_reg
=
{
AWUSER_WIDTH
{
1'b0
}}
;
reg
temp_m_axi_awvalid_reg
=
1'b0
,
temp_m_axi_awvalid_next
;
// datapath control
reg
store_axi_aw_input_to_output
;
reg
store_axi_aw_input_to_temp
;
reg
store_axi_aw_temp_to_output
;
assign
s_axi_awready
=
s_axi_awready_reg
;
assign
m_axi_awid
=
m_axi_awid_reg
;
assign
m_axi_awaddr
=
m_axi_awaddr_reg
;
assign
m_axi_awlen
=
m_axi_awlen_reg
;
assign
m_axi_awsize
=
m_axi_awsize_reg
;
assign
m_axi_awburst
=
m_axi_awburst_reg
;
assign
m_axi_awlock
=
m_axi_awlock_reg
;
assign
m_axi_awcache
=
m_axi_awcache_reg
;
assign
m_axi_awprot
=
m_axi_awprot_reg
;
assign
m_axi_awqos
=
m_axi_awqos_reg
;
assign
m_axi_awregion
=
m_axi_awregion_reg
;
assign
m_axi_awuser
=
AWUSER_ENABLE
?
m_axi_awuser_reg
:
{
AWUSER_WIDTH
{
1'b0
}}
;
assign
m_axi_awvalid
=
m_axi_awvalid_reg
;
// enable ready input next cycle if output is ready or the temp reg will not be filled on the next cycle (output reg empty or no input)
wire
s_axi_awready_early
=
m_axi_awready
|
(
~
temp_m_axi_awvalid_reg
&
(
~
m_axi_awvalid_reg
|
~
s_axi_awvalid
));
always
@*
begin
// transfer sink ready state to source
m_axi_awvalid_next
=
m_axi_awvalid_reg
;
temp_m_axi_awvalid_next
=
temp_m_axi_awvalid_reg
;
store_axi_aw_input_to_output
=
1'b0
;
store_axi_aw_input_to_temp
=
1'b0
;
store_axi_aw_temp_to_output
=
1'b0
;
if
(
s_axi_awready_reg
)
begin
// input is ready
if
(
m_axi_awready
|
~
m_axi_awvalid_reg
)
begin
// output is ready or currently not valid, transfer data to output
m_axi_awvalid_next
=
s_axi_awvalid
;
store_axi_aw_input_to_output
=
1'b1
;
end
else
begin
// output is not ready, store input in temp
temp_m_axi_awvalid_next
=
s_axi_awvalid
;
store_axi_aw_input_to_temp
=
1'b1
;
end
end
else
if
(
m_axi_awready
)
begin
// input is not ready, but output is ready
m_axi_awvalid_next
=
temp_m_axi_awvalid_reg
;
temp_m_axi_awvalid_next
=
1'b0
;
store_axi_aw_temp_to_output
=
1'b1
;
end
end
always
@
(
posedge
clk
)
begin
if
(
rst
)
begin
s_axi_awready_reg
<=
1'b0
;
m_axi_awvalid_reg
<=
1'b0
;
temp_m_axi_awvalid_reg
<=
1'b0
;
end
else
begin
s_axi_awready_reg
<=
s_axi_awready_early
;
m_axi_awvalid_reg
<=
m_axi_awvalid_next
;
temp_m_axi_awvalid_reg
<=
temp_m_axi_awvalid_next
;
end
// datapath
if
(
store_axi_aw_input_to_output
)
begin
m_axi_awid_reg
<=
s_axi_awid
;
m_axi_awaddr_reg
<=
s_axi_awaddr
;
m_axi_awlen_reg
<=
s_axi_awlen
;
m_axi_awsize_reg
<=
s_axi_awsize
;
m_axi_awburst_reg
<=
s_axi_awburst
;
m_axi_awlock_reg
<=
s_axi_awlock
;
m_axi_awcache_reg
<=
s_axi_awcache
;
m_axi_awprot_reg
<=
s_axi_awprot
;
m_axi_awqos_reg
<=
s_axi_awqos
;
m_axi_awregion_reg
<=
s_axi_awregion
;
m_axi_awuser_reg
<=
s_axi_awuser
;
end
else
if
(
store_axi_aw_temp_to_output
)
begin
m_axi_awid_reg
<=
temp_m_axi_awid_reg
;
m_axi_awaddr_reg
<=
temp_m_axi_awaddr_reg
;
m_axi_awlen_reg
<=
temp_m_axi_awlen_reg
;
m_axi_awsize_reg
<=
temp_m_axi_awsize_reg
;
m_axi_awburst_reg
<=
temp_m_axi_awburst_reg
;
m_axi_awlock_reg
<=
temp_m_axi_awlock_reg
;
m_axi_awcache_reg
<=
temp_m_axi_awcache_reg
;
m_axi_awprot_reg
<=
temp_m_axi_awprot_reg
;
m_axi_awqos_reg
<=
temp_m_axi_awqos_reg
;
m_axi_awregion_reg
<=
temp_m_axi_awregion_reg
;
m_axi_awuser_reg
<=
temp_m_axi_awuser_reg
;
end
if
(
store_axi_aw_input_to_temp
)
begin
temp_m_axi_awid_reg
<=
s_axi_awid
;
temp_m_axi_awaddr_reg
<=
s_axi_awaddr
;
temp_m_axi_awlen_reg
<=
s_axi_awlen
;
temp_m_axi_awsize_reg
<=
s_axi_awsize
;
temp_m_axi_awburst_reg
<=
s_axi_awburst
;
temp_m_axi_awlock_reg
<=
s_axi_awlock
;
temp_m_axi_awcache_reg
<=
s_axi_awcache
;
temp_m_axi_awprot_reg
<=
s_axi_awprot
;
temp_m_axi_awqos_reg
<=
s_axi_awqos
;
temp_m_axi_awregion_reg
<=
s_axi_awregion
;
temp_m_axi_awuser_reg
<=
s_axi_awuser
;
end
end
end
else
if
(
AW_REG_TYPE
==
1
)
begin
// simple register, inserts bubble cycles
// datapath registers
reg
s_axi_awready_reg
=
1'b0
;
reg
[
ID_WIDTH
-
1
:
0
]
m_axi_awid_reg
=
{
ID_WIDTH
{
1'b0
}}
;
reg
[
ADDR_WIDTH
-
1
:
0
]
m_axi_awaddr_reg
=
{
ADDR_WIDTH
{
1'b0
}}
;
reg
[
7
:
0
]
m_axi_awlen_reg
=
8'd0
;
reg
[
2
:
0
]
m_axi_awsize_reg
=
3'd0
;
reg
[
1
:
0
]
m_axi_awburst_reg
=
2'd0
;
reg
m_axi_awlock_reg
=
1'b0
;
reg
[
3
:
0
]
m_axi_awcache_reg
=
4'd0
;
reg
[
2
:
0
]
m_axi_awprot_reg
=
3'd0
;
reg
[
3
:
0
]
m_axi_awqos_reg
=
4'd0
;
reg
[
3
:
0
]
m_axi_awregion_reg
=
4'd0
;
reg
[
AWUSER_WIDTH
-
1
:
0
]
m_axi_awuser_reg
=
{
AWUSER_WIDTH
{
1'b0
}}
;
reg
m_axi_awvalid_reg
=
1'b0
,
m_axi_awvalid_next
;
// datapath control
reg
store_axi_aw_input_to_output
;
assign
s_axi_awready
=
s_axi_awready_reg
;
assign
m_axi_awid
=
m_axi_awid_reg
;
assign
m_axi_awaddr
=
m_axi_awaddr_reg
;
assign
m_axi_awlen
=
m_axi_awlen_reg
;
assign
m_axi_awsize
=
m_axi_awsize_reg
;
assign
m_axi_awburst
=
m_axi_awburst_reg
;
assign
m_axi_awlock
=
m_axi_awlock_reg
;
assign
m_axi_awcache
=
m_axi_awcache_reg
;
assign
m_axi_awprot
=
m_axi_awprot_reg
;
assign
m_axi_awqos
=
m_axi_awqos_reg
;
assign
m_axi_awregion
=
m_axi_awregion_reg
;
assign
m_axi_awuser
=
AWUSER_ENABLE
?
m_axi_awuser_reg
:
{
AWUSER_WIDTH
{
1'b0
}}
;
assign
m_axi_awvalid
=
m_axi_awvalid_reg
;
// enable ready input next cycle if output buffer will be empty
wire
s_axi_awready_eawly
=
!
m_axi_awvalid_next
;
always
@*
begin
// transfer sink ready state to source
m_axi_awvalid_next
=
m_axi_awvalid_reg
;
store_axi_aw_input_to_output
=
1'b0
;
if
(
s_axi_awready_reg
)
begin
m_axi_awvalid_next
=
s_axi_awvalid
;
store_axi_aw_input_to_output
=
1'b1
;
end
else
if
(
m_axi_awready
)
begin
m_axi_awvalid_next
=
1'b0
;
end
end
always
@
(
posedge
clk
)
begin
if
(
rst
)
begin
s_axi_awready_reg
<=
1'b0
;
m_axi_awvalid_reg
<=
1'b0
;
end
else
begin
s_axi_awready_reg
<=
s_axi_awready_eawly
;
m_axi_awvalid_reg
<=
m_axi_awvalid_next
;
end
// datapath
if
(
store_axi_aw_input_to_output
)
begin
m_axi_awid_reg
<=
s_axi_awid
;
m_axi_awaddr_reg
<=
s_axi_awaddr
;
m_axi_awlen_reg
<=
s_axi_awlen
;
m_axi_awsize_reg
<=
s_axi_awsize
;
m_axi_awburst_reg
<=
s_axi_awburst
;
m_axi_awlock_reg
<=
s_axi_awlock
;
m_axi_awcache_reg
<=
s_axi_awcache
;
m_axi_awprot_reg
<=
s_axi_awprot
;
m_axi_awqos_reg
<=
s_axi_awqos
;
m_axi_awregion_reg
<=
s_axi_awregion
;
m_axi_awuser_reg
<=
s_axi_awuser
;
end
end
end
else
begin
// bypass AW channel
assign
m_axi_awid
=
s_axi_awid
;
assign
m_axi_awaddr
=
s_axi_awaddr
;
assign
m_axi_awlen
=
s_axi_awlen
;
assign
m_axi_awsize
=
s_axi_awsize
;
assign
m_axi_awburst
=
s_axi_awburst
;
assign
m_axi_awlock
=
s_axi_awlock
;
assign
m_axi_awcache
=
s_axi_awcache
;
assign
m_axi_awprot
=
s_axi_awprot
;
assign
m_axi_awqos
=
s_axi_awqos
;
assign
m_axi_awregion
=
s_axi_awregion
;
assign
m_axi_awuser
=
AWUSER_ENABLE
?
s_axi_awuser
:
{
AWUSER_WIDTH
{
1'b0
}}
;
assign
m_axi_awvalid
=
s_axi_awvalid
;
assign
s_axi_awready
=
m_axi_awready
;
end
// W channel
if
(
W_REG_TYPE
>
1
)
begin
// skid buffer, no bubble cycles
// datapath registers
reg
s_axi_wready_reg
=
1'b0
;
reg
[
DATA_WIDTH
-
1
:
0
]
m_axi_wdata_reg
=
{
DATA_WIDTH
{
1'b0
}}
;
reg
[
STRB_WIDTH
-
1
:
0
]
m_axi_wstrb_reg
=
{
STRB_WIDTH
{
1'b0
}}
;
reg
m_axi_wlast_reg
=
1'b0
;
reg
[
WUSER_WIDTH
-
1
:
0
]
m_axi_wuser_reg
=
{
WUSER_WIDTH
{
1'b0
}}
;
reg
m_axi_wvalid_reg
=
1'b0
,
m_axi_wvalid_next
;
reg
[
DATA_WIDTH
-
1
:
0
]
temp_m_axi_wdata_reg
=
{
DATA_WIDTH
{
1'b0
}}
;
reg
[
STRB_WIDTH
-
1
:
0
]
temp_m_axi_wstrb_reg
=
{
STRB_WIDTH
{
1'b0
}}
;
reg
temp_m_axi_wlast_reg
=
1'b0
;
reg
[
WUSER_WIDTH
-
1
:
0
]
temp_m_axi_wuser_reg
=
{
WUSER_WIDTH
{
1'b0
}}
;
reg
temp_m_axi_wvalid_reg
=
1'b0
,
temp_m_axi_wvalid_next
;
// datapath control
reg
store_axi_w_input_to_output
;
reg
store_axi_w_input_to_temp
;
reg
store_axi_w_temp_to_output
;
assign
s_axi_wready
=
s_axi_wready_reg
;
assign
m_axi_wdata
=
m_axi_wdata_reg
;
assign
m_axi_wstrb
=
m_axi_wstrb_reg
;
assign
m_axi_wlast
=
m_axi_wlast_reg
;
assign
m_axi_wuser
=
WUSER_ENABLE
?
m_axi_wuser_reg
:
{
WUSER_WIDTH
{
1'b0
}}
;
assign
m_axi_wvalid
=
m_axi_wvalid_reg
;
// enable ready input next cycle if output is ready or the temp reg will not be filled on the next cycle (output reg empty or no input)
wire
s_axi_wready_early
=
m_axi_wready
|
(
~
temp_m_axi_wvalid_reg
&
(
~
m_axi_wvalid_reg
|
~
s_axi_wvalid
));
always
@*
begin
// transfer sink ready state to source
m_axi_wvalid_next
=
m_axi_wvalid_reg
;
temp_m_axi_wvalid_next
=
temp_m_axi_wvalid_reg
;
store_axi_w_input_to_output
=
1'b0
;
store_axi_w_input_to_temp
=
1'b0
;
store_axi_w_temp_to_output
=
1'b0
;
if
(
s_axi_wready_reg
)
begin
// input is ready
if
(
m_axi_wready
|
~
m_axi_wvalid_reg
)
begin
// output is ready or currently not valid, transfer data to output
m_axi_wvalid_next
=
s_axi_wvalid
;
store_axi_w_input_to_output
=
1'b1
;
end
else
begin
// output is not ready, store input in temp
temp_m_axi_wvalid_next
=
s_axi_wvalid
;
store_axi_w_input_to_temp
=
1'b1
;
end
end
else
if
(
m_axi_wready
)
begin
// input is not ready, but output is ready
m_axi_wvalid_next
=
temp_m_axi_wvalid_reg
;
temp_m_axi_wvalid_next
=
1'b0
;
store_axi_w_temp_to_output
=
1'b1
;
end
end
always
@
(
posedge
clk
)
begin
if
(
rst
)
begin
s_axi_wready_reg
<=
1'b0
;
m_axi_wvalid_reg
<=
1'b0
;
temp_m_axi_wvalid_reg
<=
1'b0
;
end
else
begin
s_axi_wready_reg
<=
s_axi_wready_early
;
m_axi_wvalid_reg
<=
m_axi_wvalid_next
;
temp_m_axi_wvalid_reg
<=
temp_m_axi_wvalid_next
;
end
// datapath
if
(
store_axi_w_input_to_output
)
begin
m_axi_wdata_reg
<=
s_axi_wdata
;
m_axi_wstrb_reg
<=
s_axi_wstrb
;
m_axi_wlast_reg
<=
s_axi_wlast
;
m_axi_wuser_reg
<=
s_axi_wuser
;
end
else
if
(
store_axi_w_temp_to_output
)
begin
m_axi_wdata_reg
<=
temp_m_axi_wdata_reg
;
m_axi_wstrb_reg
<=
temp_m_axi_wstrb_reg
;
m_axi_wlast_reg
<=
temp_m_axi_wlast_reg
;
m_axi_wuser_reg
<=
temp_m_axi_wuser_reg
;
end
if
(
store_axi_w_input_to_temp
)
begin
temp_m_axi_wdata_reg
<=
s_axi_wdata
;
temp_m_axi_wstrb_reg
<=
s_axi_wstrb
;
temp_m_axi_wlast_reg
<=
s_axi_wlast
;
temp_m_axi_wuser_reg
<=
s_axi_wuser
;
end
end
end
else
if
(
W_REG_TYPE
==
1
)
begin
// simple register, inserts bubble cycles
// datapath registers
reg
s_axi_wready_reg
=
1'b0
;
reg
[
DATA_WIDTH
-
1
:
0
]
m_axi_wdata_reg
=
{
DATA_WIDTH
{
1'b0
}}
;
reg
[
STRB_WIDTH
-
1
:
0
]
m_axi_wstrb_reg
=
{
STRB_WIDTH
{
1'b0
}}
;
reg
m_axi_wlast_reg
=
1'b0
;
reg
[
WUSER_WIDTH
-
1
:
0
]
m_axi_wuser_reg
=
{
WUSER_WIDTH
{
1'b0
}}
;
reg
m_axi_wvalid_reg
=
1'b0
,
m_axi_wvalid_next
;
// datapath control
reg
store_axi_w_input_to_output
;
assign
s_axi_wready
=
s_axi_wready_reg
;
assign
m_axi_wdata
=
m_axi_wdata_reg
;
assign
m_axi_wstrb
=
m_axi_wstrb_reg
;
assign
m_axi_wlast
=
m_axi_wlast_reg
;
assign
m_axi_wuser
=
WUSER_ENABLE
?
m_axi_wuser_reg
:
{
WUSER_WIDTH
{
1'b0
}}
;
assign
m_axi_wvalid
=
m_axi_wvalid_reg
;
// enable ready input next cycle if output buffer will be empty
wire
s_axi_wready_ewly
=
!
m_axi_wvalid_next
;
always
@*
begin
// transfer sink ready state to source
m_axi_wvalid_next
=
m_axi_wvalid_reg
;
store_axi_w_input_to_output
=
1'b0
;
if
(
s_axi_wready_reg
)
begin
m_axi_wvalid_next
=
s_axi_wvalid
;
store_axi_w_input_to_output
=
1'b1
;
end
else
if
(
m_axi_wready
)
begin
m_axi_wvalid_next
=
1'b0
;
end
end
always
@
(
posedge
clk
)
begin
if
(
rst
)
begin
s_axi_wready_reg
<=
1'b0
;
m_axi_wvalid_reg
<=
1'b0
;
end
else
begin
s_axi_wready_reg
<=
s_axi_wready_ewly
;
m_axi_wvalid_reg
<=
m_axi_wvalid_next
;
end
// datapath
if
(
store_axi_w_input_to_output
)
begin
m_axi_wdata_reg
<=
s_axi_wdata
;
m_axi_wstrb_reg
<=
s_axi_wstrb
;
m_axi_wlast_reg
<=
s_axi_wlast
;
m_axi_wuser_reg
<=
s_axi_wuser
;
end
end
end
else
begin
// bypass W channel
assign
m_axi_wdata
=
s_axi_wdata
;
assign
m_axi_wstrb
=
s_axi_wstrb
;
assign
m_axi_wlast
=
s_axi_wlast
;
assign
m_axi_wuser
=
WUSER_ENABLE
?
s_axi_wuser
:
{
WUSER_WIDTH
{
1'b0
}}
;
assign
m_axi_wvalid
=
s_axi_wvalid
;
assign
s_axi_wready
=
m_axi_wready
;
end
// B channel
if
(
B_REG_TYPE
>
1
)
begin
// skid buffer, no bubble cycles
// datapath registers
reg
m_axi_bready_reg
=
1'b0
;
reg
[
ID_WIDTH
-
1
:
0
]
s_axi_bid_reg
=
{
ID_WIDTH
{
1'b0
}}
;
reg
[
1
:
0
]
s_axi_bresp_reg
=
2'b0
;
reg
[
BUSER_WIDTH
-
1
:
0
]
s_axi_buser_reg
=
{
BUSER_WIDTH
{
1'b0
}}
;
reg
s_axi_bvalid_reg
=
1'b0
,
s_axi_bvalid_next
;
reg
[
ID_WIDTH
-
1
:
0
]
temp_s_axi_bid_reg
=
{
ID_WIDTH
{
1'b0
}}
;
reg
[
1
:
0
]
temp_s_axi_bresp_reg
=
2'b0
;
reg
[
BUSER_WIDTH
-
1
:
0
]
temp_s_axi_buser_reg
=
{
BUSER_WIDTH
{
1'b0
}}
;
reg
temp_s_axi_bvalid_reg
=
1'b0
,
temp_s_axi_bvalid_next
;
// datapath control
reg
store_axi_b_input_to_output
;
reg
store_axi_b_input_to_temp
;
reg
store_axi_b_temp_to_output
;
assign
m_axi_bready
=
m_axi_bready_reg
;
assign
s_axi_bid
=
s_axi_bid_reg
;
assign
s_axi_bresp
=
s_axi_bresp_reg
;
assign
s_axi_buser
=
BUSER_ENABLE
?
s_axi_buser_reg
:
{
BUSER_WIDTH
{
1'b0
}}
;
assign
s_axi_bvalid
=
s_axi_bvalid_reg
;
// enable ready input next cycle if output is ready or the temp reg will not be filled on the next cycle (output reg empty or no input)
wire
m_axi_bready_early
=
s_axi_bready
|
(
~
temp_s_axi_bvalid_reg
&
(
~
s_axi_bvalid_reg
|
~
m_axi_bvalid
));
always
@*
begin
// transfer sink ready state to source
s_axi_bvalid_next
=
s_axi_bvalid_reg
;
temp_s_axi_bvalid_next
=
temp_s_axi_bvalid_reg
;
store_axi_b_input_to_output
=
1'b0
;
store_axi_b_input_to_temp
=
1'b0
;
store_axi_b_temp_to_output
=
1'b0
;
if
(
m_axi_bready_reg
)
begin
// input is ready
if
(
s_axi_bready
|
~
s_axi_bvalid_reg
)
begin
// output is ready or currently not valid, transfer data to output
s_axi_bvalid_next
=
m_axi_bvalid
;
store_axi_b_input_to_output
=
1'b1
;
end
else
begin
// output is not ready, store input in temp
temp_s_axi_bvalid_next
=
m_axi_bvalid
;
store_axi_b_input_to_temp
=
1'b1
;
end
end
else
if
(
s_axi_bready
)
begin
// input is not ready, but output is ready
s_axi_bvalid_next
=
temp_s_axi_bvalid_reg
;
temp_s_axi_bvalid_next
=
1'b0
;
store_axi_b_temp_to_output
=
1'b1
;
end
end
always
@
(
posedge
clk
)
begin
if
(
rst
)
begin
m_axi_bready_reg
<=
1'b0
;
s_axi_bvalid_reg
<=
1'b0
;
temp_s_axi_bvalid_reg
<=
1'b0
;
end
else
begin
m_axi_bready_reg
<=
m_axi_bready_early
;
s_axi_bvalid_reg
<=
s_axi_bvalid_next
;
temp_s_axi_bvalid_reg
<=
temp_s_axi_bvalid_next
;
end
// datapath
if
(
store_axi_b_input_to_output
)
begin
s_axi_bid_reg
<=
m_axi_bid
;
s_axi_bresp_reg
<=
m_axi_bresp
;
s_axi_buser_reg
<=
m_axi_buser
;
end
else
if
(
store_axi_b_temp_to_output
)
begin
s_axi_bid_reg
<=
temp_s_axi_bid_reg
;
s_axi_bresp_reg
<=
temp_s_axi_bresp_reg
;
s_axi_buser_reg
<=
temp_s_axi_buser_reg
;
end
if
(
store_axi_b_input_to_temp
)
begin
temp_s_axi_bid_reg
<=
m_axi_bid
;
temp_s_axi_bresp_reg
<=
m_axi_bresp
;
temp_s_axi_buser_reg
<=
m_axi_buser
;
end
end
end
else
if
(
B_REG_TYPE
==
1
)
begin
// simple register, inserts bubble cycles
// datapath registers
reg
m_axi_bready_reg
=
1'b0
;
reg
[
ID_WIDTH
-
1
:
0
]
s_axi_bid_reg
=
{
ID_WIDTH
{
1'b0
}}
;
reg
[
1
:
0
]
s_axi_bresp_reg
=
2'b0
;
reg
[
BUSER_WIDTH
-
1
:
0
]
s_axi_buser_reg
=
{
BUSER_WIDTH
{
1'b0
}}
;
reg
s_axi_bvalid_reg
=
1'b0
,
s_axi_bvalid_next
;
// datapath control
reg
store_axi_b_input_to_output
;
assign
m_axi_bready
=
m_axi_bready_reg
;
assign
s_axi_bid
=
s_axi_bid_reg
;
assign
s_axi_bresp
=
s_axi_bresp_reg
;
assign
s_axi_buser
=
BUSER_ENABLE
?
s_axi_buser_reg
:
{
BUSER_WIDTH
{
1'b0
}}
;
assign
s_axi_bvalid
=
s_axi_bvalid_reg
;
// enable ready input next cycle if output buffer will be empty
wire
m_axi_bready_early
=
!
s_axi_bvalid_next
;
always
@*
begin
// transfer sink ready state to source
s_axi_bvalid_next
=
s_axi_bvalid_reg
;
store_axi_b_input_to_output
=
1'b0
;
if
(
m_axi_bready_reg
)
begin
s_axi_bvalid_next
=
m_axi_bvalid
;
store_axi_b_input_to_output
=
1'b1
;
end
else
if
(
s_axi_bready
)
begin
s_axi_bvalid_next
=
1'b0
;
end
end
always
@
(
posedge
clk
)
begin
if
(
rst
)
begin
m_axi_bready_reg
<=
1'b0
;
s_axi_bvalid_reg
<=
1'b0
;
end
else
begin
m_axi_bready_reg
<=
m_axi_bready_early
;
s_axi_bvalid_reg
<=
s_axi_bvalid_next
;
end
// datapath
if
(
store_axi_b_input_to_output
)
begin
s_axi_bid_reg
<=
m_axi_bid
;
s_axi_bresp_reg
<=
m_axi_bresp
;
s_axi_buser_reg
<=
m_axi_buser
;
end
end
end
else
begin
// bypass B channel
assign
s_axi_bid
=
m_axi_bid
;
assign
s_axi_bresp
=
m_axi_bresp
;
assign
s_axi_buser
=
BUSER_ENABLE
?
m_axi_buser
:
{
BUSER_WIDTH
{
1'b0
}}
;
assign
s_axi_bvalid
=
m_axi_bvalid
;
assign
m_axi_bready
=
s_axi_bready
;
end
endgenerate
endmodule
corundum/lib/axi/rtl/axil_adapter.v
0 → 100644
View file @
738c1fef
/*
Copyright (c) 2018 Alex Forencich
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.
*/
// Language: Verilog 2001
`timescale
1
ns
/
1
ps
/*
* AXI4 lite width adapter
*/
module
axil_adapter
#
(
// Width of address bus in bits
parameter
ADDR_WIDTH
=
32
,
// Width of input (slave) interface data bus in bits
parameter
S_DATA_WIDTH
=
32
,
// Width of input (slave) interface wstrb (width of data bus in words)
parameter
S_STRB_WIDTH
=
(
S_DATA_WIDTH
/
8
),
// Width of output (master) interface data bus in bits
parameter
M_DATA_WIDTH
=
32
,
// Width of output (master) interface wstrb (width of data bus in words)
parameter
M_STRB_WIDTH
=
(
M_DATA_WIDTH
/
8
)
)
(
input
wire
clk
,
input
wire
rst
,
/*
* AXI lite slave interface
*/
input
wire
[
ADDR_WIDTH
-
1
:
0
]
s_axil_awaddr
,
input
wire
[
2
:
0
]
s_axil_awprot
,
input
wire
s_axil_awvalid
,
output
wire
s_axil_awready
,
input
wire
[
S_DATA_WIDTH
-
1
:
0
]
s_axil_wdata
,
input
wire
[
S_STRB_WIDTH
-
1
:
0
]
s_axil_wstrb
,
input
wire
s_axil_wvalid
,
output
wire
s_axil_wready
,
output
wire
[
1
:
0
]
s_axil_bresp
,
output
wire
s_axil_bvalid
,
input
wire
s_axil_bready
,
input
wire
[
ADDR_WIDTH
-
1
:
0
]
s_axil_araddr
,
input
wire
[
2
:
0
]
s_axil_arprot
,
input
wire
s_axil_arvalid
,
output
wire
s_axil_arready
,
output
wire
[
S_DATA_WIDTH
-
1
:
0
]
s_axil_rdata
,
output
wire
[
1
:
0
]
s_axil_rresp
,
output
wire
s_axil_rvalid
,
input
wire
s_axil_rready
,
/*
* AXI lite master interface
*/
output
wire
[
ADDR_WIDTH
-
1
:
0
]
m_axil_awaddr
,
output
wire
[
2
:
0
]
m_axil_awprot
,
output
wire
m_axil_awvalid
,
input
wire
m_axil_awready
,
output
wire
[
M_DATA_WIDTH
-
1
:
0
]
m_axil_wdata
,
output
wire
[
M_STRB_WIDTH
-
1
:
0
]
m_axil_wstrb
,
output
wire
m_axil_wvalid
,
input
wire
m_axil_wready
,
input
wire
[
1
:
0
]
m_axil_bresp
,
input
wire
m_axil_bvalid
,
output
wire
m_axil_bready
,
output
wire
[
ADDR_WIDTH
-
1
:
0
]
m_axil_araddr
,
output
wire
[
2
:
0
]
m_axil_arprot
,
output
wire
m_axil_arvalid
,
input
wire
m_axil_arready
,
input
wire
[
M_DATA_WIDTH
-
1
:
0
]
m_axil_rdata
,
input
wire
[
1
:
0
]
m_axil_rresp
,
input
wire
m_axil_rvalid
,
output
wire
m_axil_rready
);
axil_adapter_wr
#(
.
ADDR_WIDTH
(
ADDR_WIDTH
),
.
S_DATA_WIDTH
(
S_DATA_WIDTH
),
.
S_STRB_WIDTH
(
S_STRB_WIDTH
),
.
M_DATA_WIDTH
(
M_DATA_WIDTH
),
.
M_STRB_WIDTH
(
M_STRB_WIDTH
)
)
axil_adapter_wr_inst
(
.
clk
(
clk
),
.
rst
(
rst
),
/*
* AXI lite slave interface
*/
.
s_axil_awaddr
(
s_axil_awaddr
),
.
s_axil_awprot
(
s_axil_awprot
),
.
s_axil_awvalid
(
s_axil_awvalid
),
.
s_axil_awready
(
s_axil_awready
),
.
s_axil_wdata
(
s_axil_wdata
),
.
s_axil_wstrb
(
s_axil_wstrb
),
.
s_axil_wvalid
(
s_axil_wvalid
),
.
s_axil_wready
(
s_axil_wready
),
.
s_axil_bresp
(
s_axil_bresp
),
.
s_axil_bvalid
(
s_axil_bvalid
),
.
s_axil_bready
(
s_axil_bready
),
/*
* AXI lite master interface
*/
.
m_axil_awaddr
(
m_axil_awaddr
),
.
m_axil_awprot
(
m_axil_awprot
),
.
m_axil_awvalid
(
m_axil_awvalid
),
.
m_axil_awready
(
m_axil_awready
),
.
m_axil_wdata
(
m_axil_wdata
),
.
m_axil_wstrb
(
m_axil_wstrb
),
.
m_axil_wvalid
(
m_axil_wvalid
),
.
m_axil_wready
(
m_axil_wready
),
.
m_axil_bresp
(
m_axil_bresp
),
.
m_axil_bvalid
(
m_axil_bvalid
),
.
m_axil_bready
(
m_axil_bready
)
);
axil_adapter_rd
#(
.
ADDR_WIDTH
(
ADDR_WIDTH
),
.
S_DATA_WIDTH
(
S_DATA_WIDTH
),
.
S_STRB_WIDTH
(
S_STRB_WIDTH
),
.
M_DATA_WIDTH
(
M_DATA_WIDTH
),
.
M_STRB_WIDTH
(
M_STRB_WIDTH
)
)
axil_adapter_rd_inst
(
.
clk
(
clk
),
.
rst
(
rst
),
/*
* AXI lite slave interface
*/
.
s_axil_araddr
(
s_axil_araddr
),
.
s_axil_arprot
(
s_axil_arprot
),
.
s_axil_arvalid
(
s_axil_arvalid
),
.
s_axil_arready
(
s_axil_arready
),
.
s_axil_rdata
(
s_axil_rdata
),
.
s_axil_rresp
(
s_axil_rresp
),
.
s_axil_rvalid
(
s_axil_rvalid
),
.
s_axil_rready
(
s_axil_rready
),
/*
* AXI lite master interface
*/
.
m_axil_araddr
(
m_axil_araddr
),
.
m_axil_arprot
(
m_axil_arprot
),
.
m_axil_arvalid
(
m_axil_arvalid
),
.
m_axil_arready
(
m_axil_arready
),
.
m_axil_rdata
(
m_axil_rdata
),
.
m_axil_rresp
(
m_axil_rresp
),
.
m_axil_rvalid
(
m_axil_rvalid
),
.
m_axil_rready
(
m_axil_rready
)
);
endmodule
corundum/lib/axi/rtl/axil_adapter_rd.v
0 → 100644
View file @
738c1fef
/*
Copyright (c) 2018 Alex Forencich
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.
*/
// Language: Verilog 2001
`timescale
1
ns
/
1
ps
/*
* AXI4 lite width adapter (read)
*/
module
axil_adapter_rd
#
(
// Width of address bus in bits
parameter
ADDR_WIDTH
=
32
,
// Width of input (slave) interface data bus in bits
parameter
S_DATA_WIDTH
=
32
,
// Width of input (slave) interface wstrb (width of data bus in words)
parameter
S_STRB_WIDTH
=
(
S_DATA_WIDTH
/
8
),
// Width of output (master) interface data bus in bits
parameter
M_DATA_WIDTH
=
32
,
// Width of output (master) interface wstrb (width of data bus in words)
parameter
M_STRB_WIDTH
=
(
M_DATA_WIDTH
/
8
)
)
(
input
wire
clk
,
input
wire
rst
,
/*
* AXI lite slave interface
*/
input
wire
[
ADDR_WIDTH
-
1
:
0
]
s_axil_araddr
,
input
wire
[
2
:
0
]
s_axil_arprot
,
input
wire
s_axil_arvalid
,
output
wire
s_axil_arready
,
output
wire
[
S_DATA_WIDTH
-
1
:
0
]
s_axil_rdata
,
output
wire
[
1
:
0
]
s_axil_rresp
,
output
wire
s_axil_rvalid
,
input
wire
s_axil_rready
,
/*
* AXI lite master interface
*/
output
wire
[
ADDR_WIDTH
-
1
:
0
]
m_axil_araddr
,
output
wire
[
2
:
0
]
m_axil_arprot
,
output
wire
m_axil_arvalid
,
input
wire
m_axil_arready
,
input
wire
[
M_DATA_WIDTH
-
1
:
0
]
m_axil_rdata
,
input
wire
[
1
:
0
]
m_axil_rresp
,
input
wire
m_axil_rvalid
,
output
wire
m_axil_rready
);
parameter
S_ADDR_BIT_OFFSET
=
$
clog2
(
S_STRB_WIDTH
);
parameter
M_ADDR_BIT_OFFSET
=
$
clog2
(
M_STRB_WIDTH
);
parameter
S_WORD_WIDTH
=
S_STRB_WIDTH
;
parameter
M_WORD_WIDTH
=
M_STRB_WIDTH
;
parameter
S_WORD_SIZE
=
S_DATA_WIDTH
/
S_WORD_WIDTH
;
parameter
M_WORD_SIZE
=
M_DATA_WIDTH
/
M_WORD_WIDTH
;
// output bus is wider
parameter
EXPAND
=
M_STRB_WIDTH
>
S_STRB_WIDTH
;
parameter
DATA_WIDTH
=
EXPAND
?
M_DATA_WIDTH
:
S_DATA_WIDTH
;
parameter
STRB_WIDTH
=
EXPAND
?
M_STRB_WIDTH
:
S_STRB_WIDTH
;
// required number of segments in wider bus
parameter
SEGMENT_COUNT
=
EXPAND
?
(
M_STRB_WIDTH
/
S_STRB_WIDTH
)
:
(
S_STRB_WIDTH
/
M_STRB_WIDTH
);
parameter
SEGMENT_COUNT_WIDTH
=
SEGMENT_COUNT
==
1
?
1
:
$
clog2
(
SEGMENT_COUNT
);
// data width and keep width per segment
parameter
SEGMENT_DATA_WIDTH
=
DATA_WIDTH
/
SEGMENT_COUNT
;
parameter
SEGMENT_STRB_WIDTH
=
STRB_WIDTH
/
SEGMENT_COUNT
;
// bus width assertions
initial
begin
if
(
S_WORD_SIZE
*
S_STRB_WIDTH
!=
S_DATA_WIDTH
)
begin
$
error
(
"Error: AXI slave interface data width not evenly divisble (instance %m)"
);
$
finish
;
end
if
(
M_WORD_SIZE
*
M_STRB_WIDTH
!=
M_DATA_WIDTH
)
begin
$
error
(
"Error: AXI master interface data width not evenly divisble (instance %m)"
);
$
finish
;
end
if
(
S_WORD_SIZE
!=
M_WORD_SIZE
)
begin
$
error
(
"Error: word size mismatch (instance %m)"
);
$
finish
;
end
if
(
2
**
$
clog2
(
S_WORD_WIDTH
)
!=
S_WORD_WIDTH
)
begin
$
error
(
"Error: AXI slave interface word width must be even power of two (instance %m)"
);
$
finish
;
end
if
(
2
**
$
clog2
(
M_WORD_WIDTH
)
!=
M_WORD_WIDTH
)
begin
$
error
(
"Error: AXI master interface word width must be even power of two (instance %m)"
);
$
finish
;
end
end
localparam
[
0
:
0
]
STATE_IDLE
=
1'd0
,
STATE_DATA
=
1'd1
;
reg
[
0
:
0
]
state_reg
=
STATE_IDLE
,
state_next
;
reg
[
SEGMENT_COUNT_WIDTH
-
1
:
0
]
current_segment_reg
=
0
,
current_segment_next
;
reg
s_axil_arready_reg
=
1'b0
,
s_axil_arready_next
;
reg
[
S_DATA_WIDTH
-
1
:
0
]
s_axil_rdata_reg
=
{
S_DATA_WIDTH
{
1'b0
}}
,
s_axil_rdata_next
;
reg
[
1
:
0
]
s_axil_rresp_reg
=
2'd0
,
s_axil_rresp_next
;
reg
s_axil_rvalid_reg
=
1'b0
,
s_axil_rvalid_next
;
reg
[
ADDR_WIDTH
-
1
:
0
]
m_axil_araddr_reg
=
{
ADDR_WIDTH
{
1'b0
}}
,
m_axil_araddr_next
;
reg
[
2
:
0
]
m_axil_arprot_reg
=
3'd0
,
m_axil_arprot_next
;
reg
m_axil_arvalid_reg
=
1'b0
,
m_axil_arvalid_next
;
reg
m_axil_rready_reg
=
1'b0
,
m_axil_rready_next
;
assign
s_axil_arready
=
s_axil_arready_reg
;
assign
s_axil_rdata
=
s_axil_rdata_reg
;
assign
s_axil_rresp
=
s_axil_rresp_reg
;
assign
s_axil_rvalid
=
s_axil_rvalid_reg
;
assign
m_axil_araddr
=
m_axil_araddr_reg
;
assign
m_axil_arprot
=
m_axil_arprot_reg
;
assign
m_axil_arvalid
=
m_axil_arvalid_reg
;
assign
m_axil_rready
=
m_axil_rready_reg
;
always
@*
begin
state_next
=
STATE_IDLE
;
current_segment_next
=
current_segment_reg
;
s_axil_arready_next
=
1'b0
;
s_axil_rdata_next
=
s_axil_rdata_reg
;
s_axil_rresp_next
=
s_axil_rresp_reg
;
s_axil_rvalid_next
=
s_axil_rvalid_reg
&&
!
s_axil_rready
;
m_axil_araddr_next
=
m_axil_araddr_reg
;
m_axil_arprot_next
=
m_axil_arprot_reg
;
m_axil_arvalid_next
=
m_axil_arvalid_reg
&&
!
m_axil_arready
;
m_axil_rready_next
=
1'b0
;
if
(
SEGMENT_COUNT
==
1
||
EXPAND
)
begin
// master output is same width or wider; single cycle direct transfer
case
(
state_reg
)
STATE_IDLE:
begin
s_axil_arready_next
=
!
m_axil_arvalid
;
if
(
s_axil_arready
&&
s_axil_arvalid
)
begin
s_axil_arready_next
=
1'b0
;
m_axil_araddr_next
=
s_axil_araddr
;
m_axil_arprot_next
=
s_axil_arprot
;
m_axil_arvalid_next
=
1'b1
;
m_axil_rready_next
=
!
m_axil_rvalid
;
state_next
=
STATE_DATA
;
end
else
begin
state_next
=
STATE_IDLE
;
end
end
STATE_DATA:
begin
m_axil_rready_next
=
!
s_axil_rvalid
;
if
(
m_axil_rready
&&
m_axil_rvalid
)
begin
m_axil_rready_next
=
1'b0
;
if
(
M_WORD_WIDTH
==
S_WORD_WIDTH
)
begin
s_axil_rdata_next
=
m_axil_rdata
;
end
else
begin
s_axil_rdata_next
=
m_axil_rdata
>>
(
m_axil_araddr_reg
[
M_ADDR_BIT_OFFSET
-
1
:
S_ADDR_BIT_OFFSET
]
*
S_DATA_WIDTH
);
end
s_axil_rresp_next
=
m_axil_rresp
;
s_axil_rvalid_next
=
1'b1
;
s_axil_arready_next
=
!
m_axil_arvalid
;
state_next
=
STATE_IDLE
;
end
else
begin
state_next
=
STATE_DATA
;
end
end
endcase
end
else
begin
// master output is narrower; may need several cycles
case
(
state_reg
)
STATE_IDLE:
begin
s_axil_arready_next
=
!
m_axil_arvalid
;
current_segment_next
=
0
;
s_axil_rresp_next
=
2'd0
;
if
(
s_axil_arready
&&
s_axil_arvalid
)
begin
s_axil_arready_next
=
1'b0
;
m_axil_araddr_next
=
s_axil_araddr
&
(
{
ADDR_WIDTH
{
1'b1
}}
<<
S_ADDR_BIT_OFFSET
);
m_axil_arprot_next
=
s_axil_arprot
;
m_axil_arvalid_next
=
1'b1
;
m_axil_rready_next
=
!
m_axil_rvalid
;
state_next
=
STATE_DATA
;
end
else
begin
state_next
=
STATE_IDLE
;
end
end
STATE_DATA:
begin
m_axil_rready_next
=
!
s_axil_rvalid
;
if
(
m_axil_rready
&&
m_axil_rvalid
)
begin
m_axil_rready_next
=
1'b0
;
s_axil_rdata_next
[
current_segment_reg
*
SEGMENT_DATA_WIDTH
+:
SEGMENT_DATA_WIDTH
]
=
m_axil_rdata
;
if
(
m_axil_rresp
)
begin
s_axil_rresp_next
=
m_axil_rresp
;
end
if
(
current_segment_reg
==
SEGMENT_COUNT
-
1
)
begin
s_axil_rvalid_next
=
1'b1
;
s_axil_arready_next
=
!
m_axil_arvalid
;
state_next
=
STATE_IDLE
;
end
else
begin
current_segment_next
=
current_segment_reg
+
1
;
m_axil_araddr_next
=
m_axil_araddr_reg
+
SEGMENT_STRB_WIDTH
;
m_axil_arvalid_next
=
1'b1
;
state_next
=
STATE_DATA
;
end
end
else
begin
state_next
=
STATE_DATA
;
end
end
endcase
end
end
always
@
(
posedge
clk
)
begin
if
(
rst
)
begin
state_reg
<=
STATE_IDLE
;
s_axil_arready_reg
<=
1'b0
;
s_axil_rvalid_reg
<=
1'b0
;
m_axil_arvalid_reg
<=
1'b0
;
m_axil_rready_reg
<=
1'b0
;
end
else
begin
state_reg
<=
state_next
;
s_axil_arready_reg
<=
s_axil_arready_next
;
s_axil_rvalid_reg
<=
s_axil_rvalid_next
;
m_axil_arvalid_reg
<=
m_axil_arvalid_next
;
m_axil_rready_reg
<=
m_axil_rready_next
;
end
current_segment_reg
<=
current_segment_next
;
s_axil_rdata_reg
<=
s_axil_rdata_next
;
s_axil_rresp_reg
<=
s_axil_rresp_next
;
m_axil_araddr_reg
<=
m_axil_araddr_next
;
m_axil_arprot_reg
<=
m_axil_arprot_next
;
end
endmodule
corundum/lib/axi/rtl/axil_adapter_wr.v
0 → 100644
View file @
738c1fef
/*
Copyright (c) 2018 Alex Forencich
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.
*/
// Language: Verilog 2001
`timescale
1
ns
/
1
ps
/*
* AXI4 lite width adapter (write)
*/
module
axil_adapter_wr
#
(
// Width of address bus in bits
parameter
ADDR_WIDTH
=
32
,
// Width of input (slave) interface data bus in bits
parameter
S_DATA_WIDTH
=
32
,
// Width of input (slave) interface wstrb (width of data bus in words)
parameter
S_STRB_WIDTH
=
(
S_DATA_WIDTH
/
8
),
// Width of output (master) interface data bus in bits
parameter
M_DATA_WIDTH
=
32
,
// Width of output (master) interface wstrb (width of data bus in words)
parameter
M_STRB_WIDTH
=
(
M_DATA_WIDTH
/
8
)
)
(
input
wire
clk
,
input
wire
rst
,
/*
* AXI lite slave interface
*/
input
wire
[
ADDR_WIDTH
-
1
:
0
]
s_axil_awaddr
,
input
wire
[
2
:
0
]
s_axil_awprot
,
input
wire
s_axil_awvalid
,
output
wire
s_axil_awready
,
input
wire
[
S_DATA_WIDTH
-
1
:
0
]
s_axil_wdata
,
input
wire
[
S_STRB_WIDTH
-
1
:
0
]
s_axil_wstrb
,
input
wire
s_axil_wvalid
,
output
wire
s_axil_wready
,
output
wire
[
1
:
0
]
s_axil_bresp
,
output
wire
s_axil_bvalid
,
input
wire
s_axil_bready
,
/*
* AXI lite master interface
*/
output
wire
[
ADDR_WIDTH
-
1
:
0
]
m_axil_awaddr
,
output
wire
[
2
:
0
]
m_axil_awprot
,
output
wire
m_axil_awvalid
,
input
wire
m_axil_awready
,
output
wire
[
M_DATA_WIDTH
-
1
:
0
]
m_axil_wdata
,
output
wire
[
M_STRB_WIDTH
-
1
:
0
]
m_axil_wstrb
,
output
wire
m_axil_wvalid
,
input
wire
m_axil_wready
,
input
wire
[
1
:
0
]
m_axil_bresp
,
input
wire
m_axil_bvalid
,
output
wire
m_axil_bready
);
parameter
S_ADDR_BIT_OFFSET
=
$
clog2
(
S_STRB_WIDTH
);
parameter
M_ADDR_BIT_OFFSET
=
$
clog2
(
M_STRB_WIDTH
);
parameter
S_WORD_WIDTH
=
S_STRB_WIDTH
;
parameter
M_WORD_WIDTH
=
M_STRB_WIDTH
;
parameter
S_WORD_SIZE
=
S_DATA_WIDTH
/
S_WORD_WIDTH
;
parameter
M_WORD_SIZE
=
M_DATA_WIDTH
/
M_WORD_WIDTH
;
// output bus is wider
parameter
EXPAND
=
M_STRB_WIDTH
>
S_STRB_WIDTH
;
parameter
DATA_WIDTH
=
EXPAND
?
M_DATA_WIDTH
:
S_DATA_WIDTH
;
parameter
STRB_WIDTH
=
EXPAND
?
M_STRB_WIDTH
:
S_STRB_WIDTH
;
// required number of segments in wider bus
parameter
SEGMENT_COUNT
=
EXPAND
?
(
M_STRB_WIDTH
/
S_STRB_WIDTH
)
:
(
S_STRB_WIDTH
/
M_STRB_WIDTH
);
parameter
SEGMENT_COUNT_WIDTH
=
SEGMENT_COUNT
==
1
?
1
:
$
clog2
(
SEGMENT_COUNT
);
// data width and keep width per segment
parameter
SEGMENT_DATA_WIDTH
=
DATA_WIDTH
/
SEGMENT_COUNT
;
parameter
SEGMENT_STRB_WIDTH
=
STRB_WIDTH
/
SEGMENT_COUNT
;
// bus width assertions
initial
begin
if
(
S_WORD_SIZE
*
S_STRB_WIDTH
!=
S_DATA_WIDTH
)
begin
$
error
(
"Error: AXI slave interface data width not evenly divisble (instance %m)"
);
$
finish
;
end
if
(
M_WORD_SIZE
*
M_STRB_WIDTH
!=
M_DATA_WIDTH
)
begin
$
error
(
"Error: AXI master interface data width not evenly divisble (instance %m)"
);
$
finish
;
end
if
(
S_WORD_SIZE
!=
M_WORD_SIZE
)
begin
$
error
(
"Error: word size mismatch (instance %m)"
);
$
finish
;
end
if
(
2
**
$
clog2
(
S_WORD_WIDTH
)
!=
S_WORD_WIDTH
)
begin
$
error
(
"Error: AXI slave interface word width must be even power of two (instance %m)"
);
$
finish
;
end
if
(
2
**
$
clog2
(
M_WORD_WIDTH
)
!=
M_WORD_WIDTH
)
begin
$
error
(
"Error: AXI master interface word width must be even power of two (instance %m)"
);
$
finish
;
end
end
localparam
[
1
:
0
]
STATE_IDLE
=
2'd0
,
STATE_DATA
=
2'd1
,
STATE_RESP
=
2'd3
;
reg
[
1
:
0
]
state_reg
=
STATE_IDLE
,
state_next
;
reg
[
DATA_WIDTH
-
1
:
0
]
data_reg
=
{
DATA_WIDTH
{
1'b0
}}
,
data_next
;
reg
[
STRB_WIDTH
-
1
:
0
]
strb_reg
=
{
STRB_WIDTH
{
1'b0
}}
,
strb_next
;
reg
[
SEGMENT_COUNT_WIDTH
-
1
:
0
]
current_segment_reg
=
0
,
current_segment_next
;
reg
s_axil_awready_reg
=
1'b0
,
s_axil_awready_next
;
reg
s_axil_wready_reg
=
1'b0
,
s_axil_wready_next
;
reg
[
1
:
0
]
s_axil_bresp_reg
=
2'd0
,
s_axil_bresp_next
;
reg
s_axil_bvalid_reg
=
1'b0
,
s_axil_bvalid_next
;
reg
[
ADDR_WIDTH
-
1
:
0
]
m_axil_awaddr_reg
=
{
ADDR_WIDTH
{
1'b0
}}
,
m_axil_awaddr_next
;
reg
[
2
:
0
]
m_axil_awprot_reg
=
3'd0
,
m_axil_awprot_next
;
reg
m_axil_awvalid_reg
=
1'b0
,
m_axil_awvalid_next
;
reg
[
M_DATA_WIDTH
-
1
:
0
]
m_axil_wdata_reg
=
{
M_DATA_WIDTH
{
1'b0
}}
,
m_axil_wdata_next
;
reg
[
M_STRB_WIDTH
-
1
:
0
]
m_axil_wstrb_reg
=
{
M_STRB_WIDTH
{
1'b0
}}
,
m_axil_wstrb_next
;
reg
m_axil_wvalid_reg
=
1'b0
,
m_axil_wvalid_next
;
reg
m_axil_bready_reg
=
1'b0
,
m_axil_bready_next
;
assign
s_axil_awready
=
s_axil_awready_reg
;
assign
s_axil_wready
=
s_axil_wready_reg
;
assign
s_axil_bresp
=
s_axil_bresp_reg
;
assign
s_axil_bvalid
=
s_axil_bvalid_reg
;
assign
m_axil_awaddr
=
m_axil_awaddr_reg
;
assign
m_axil_awprot
=
m_axil_awprot_reg
;
assign
m_axil_awvalid
=
m_axil_awvalid_reg
;
assign
m_axil_wdata
=
m_axil_wdata_reg
;
assign
m_axil_wstrb
=
m_axil_wstrb_reg
;
assign
m_axil_wvalid
=
m_axil_wvalid_reg
;
assign
m_axil_bready
=
m_axil_bready_reg
;
always
@*
begin
state_next
=
STATE_IDLE
;
data_next
=
data_reg
;
strb_next
=
strb_reg
;
current_segment_next
=
current_segment_reg
;
s_axil_awready_next
=
1'b0
;
s_axil_wready_next
=
1'b0
;
s_axil_bresp_next
=
s_axil_bresp_reg
;
s_axil_bvalid_next
=
s_axil_bvalid_reg
&&
!
s_axil_bready
;
m_axil_awaddr_next
=
m_axil_awaddr_reg
;
m_axil_awprot_next
=
m_axil_awprot_reg
;
m_axil_awvalid_next
=
m_axil_awvalid_reg
&&
!
m_axil_awready
;
m_axil_wdata_next
=
m_axil_wdata_reg
;
m_axil_wstrb_next
=
m_axil_wstrb_reg
;
m_axil_wvalid_next
=
m_axil_wvalid_reg
&&
!
m_axil_wready
;
m_axil_bready_next
=
1'b0
;
if
(
SEGMENT_COUNT
==
1
||
EXPAND
)
begin
// master output is same width or wider; single cycle direct transfer
case
(
state_reg
)
STATE_IDLE:
begin
s_axil_awready_next
=
!
m_axil_awvalid
;
if
(
s_axil_awready
&&
s_axil_awvalid
)
begin
s_axil_awready_next
=
1'b0
;
m_axil_awaddr_next
=
s_axil_awaddr
;
m_axil_awprot_next
=
s_axil_awprot
;
m_axil_awvalid_next
=
1'b1
;
s_axil_wready_next
=
!
m_axil_wvalid
;
state_next
=
STATE_DATA
;
end
else
begin
state_next
=
STATE_IDLE
;
end
end
STATE_DATA:
begin
s_axil_wready_next
=
!
m_axil_wvalid
;
if
(
s_axil_wready
&&
s_axil_wvalid
)
begin
s_axil_wready_next
=
1'b0
;
if
(
M_WORD_WIDTH
==
S_WORD_WIDTH
)
begin
m_axil_wdata_next
=
s_axil_wdata
;
m_axil_wstrb_next
=
s_axil_wstrb
;
end
else
begin
m_axil_wdata_next
=
{
(
M_WORD_WIDTH
/
S_WORD_WIDTH
)
{
s_axil_wdata
}}
;
m_axil_wstrb_next
=
s_axil_wstrb
<<
(
m_axil_awaddr_reg
[
M_ADDR_BIT_OFFSET
-
1
:
S_ADDR_BIT_OFFSET
]
*
S_STRB_WIDTH
);
end
m_axil_wvalid_next
=
1'b1
;
m_axil_bready_next
=
!
s_axil_bvalid
;
state_next
=
STATE_RESP
;
end
else
begin
state_next
=
STATE_DATA
;
end
end
STATE_RESP:
begin
m_axil_bready_next
=
!
s_axil_bvalid
;
if
(
m_axil_bready
&&
m_axil_bvalid
)
begin
m_axil_bready_next
=
1'b0
;
s_axil_bresp_next
=
m_axil_bresp
;
s_axil_bvalid_next
=
1'b1
;
s_axil_awready_next
=
!
m_axil_awvalid
;
state_next
=
STATE_IDLE
;
end
else
begin
state_next
=
STATE_RESP
;
end
end
endcase
end
else
begin
// master output is narrower; may need several cycles
case
(
state_reg
)
STATE_IDLE:
begin
s_axil_awready_next
=
!
m_axil_awvalid
;
current_segment_next
=
0
;
s_axil_bresp_next
=
2'd0
;
if
(
s_axil_awready
&&
s_axil_awvalid
)
begin
s_axil_awready_next
=
1'b0
;
m_axil_awaddr_next
=
s_axil_awaddr
&
(
{
ADDR_WIDTH
{
1'b1
}}
<<
S_ADDR_BIT_OFFSET
);
m_axil_awprot_next
=
s_axil_awprot
;
m_axil_awvalid_next
=
1'b1
;
s_axil_wready_next
=
!
m_axil_wvalid
;
state_next
=
STATE_DATA
;
end
else
begin
state_next
=
STATE_IDLE
;
end
end
STATE_DATA:
begin
s_axil_wready_next
=
!
m_axil_wvalid
;
if
(
s_axil_wready
&&
s_axil_wvalid
)
begin
s_axil_wready_next
=
1'b0
;
data_next
=
s_axil_wdata
;
strb_next
=
s_axil_wstrb
;
m_axil_wdata_next
=
s_axil_wdata
;
m_axil_wstrb_next
=
s_axil_wstrb
;
m_axil_wvalid_next
=
1'b1
;
m_axil_bready_next
=
!
s_axil_bvalid
;
state_next
=
STATE_RESP
;
end
else
begin
state_next
=
STATE_DATA
;
end
end
STATE_RESP:
begin
m_axil_bready_next
=
!
s_axil_bvalid
;
if
(
m_axil_bready
&&
m_axil_bvalid
)
begin
m_axil_bready_next
=
1'b0
;
if
(
m_axil_bresp
!=
0
)
begin
s_axil_bresp_next
=
m_axil_bresp
;
end
if
(
current_segment_reg
==
SEGMENT_COUNT
-
1
)
begin
s_axil_bvalid_next
=
1'b1
;
s_axil_awready_next
=
!
m_axil_awvalid
;
state_next
=
STATE_IDLE
;
end
else
begin
current_segment_next
=
current_segment_reg
+
1
;
m_axil_awaddr_next
=
m_axil_awaddr_reg
+
SEGMENT_STRB_WIDTH
;
m_axil_awvalid_next
=
1'b1
;
m_axil_wdata_next
=
data_reg
>>
(
current_segment_reg
+
1
)
*
SEGMENT_DATA_WIDTH
;
m_axil_wstrb_next
=
strb_reg
>>
(
current_segment_reg
+
1
)
*
SEGMENT_STRB_WIDTH
;
m_axil_wvalid_next
=
1'b1
;
state_next
=
STATE_RESP
;
end
end
else
begin
state_next
=
STATE_RESP
;
end
end
endcase
end
end
always
@
(
posedge
clk
)
begin
if
(
rst
)
begin
state_reg
<=
STATE_IDLE
;
s_axil_awready_reg
<=
1'b0
;
s_axil_wready_reg
<=
1'b0
;
s_axil_bvalid_reg
<=
1'b0
;
m_axil_awvalid_reg
<=
1'b0
;
m_axil_wvalid_reg
<=
1'b0
;
m_axil_bready_reg
<=
1'b0
;
end
else
begin
state_reg
<=
state_next
;
s_axil_awready_reg
<=
s_axil_awready_next
;
s_axil_wready_reg
<=
s_axil_wready_next
;
s_axil_bvalid_reg
<=
s_axil_bvalid_next
;
m_axil_awvalid_reg
<=
m_axil_awvalid_next
;
m_axil_wvalid_reg
<=
m_axil_wvalid_next
;
m_axil_bready_reg
<=
m_axil_bready_next
;
end
data_reg
<=
data_next
;
strb_reg
<=
strb_next
;
current_segment_reg
<=
current_segment_next
;
s_axil_bresp_reg
<=
s_axil_bresp_next
;
m_axil_awaddr_reg
<=
m_axil_awaddr_next
;
m_axil_awprot_reg
<=
m_axil_awprot_next
;
m_axil_wdata_reg
<=
m_axil_wdata_next
;
m_axil_wstrb_reg
<=
m_axil_wstrb_next
;
end
endmodule
Prev
1
2
3
4
5
6
…
8
Next
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment