Skip to content
Snippets Groups Projects
Commit ee2748a2 authored by Thomas B. Preußer's avatar Thomas B. Preußer Committed by Yaman Umuroglu
Browse files

Added AXI-Light adapter to dynamically-sized feature map padding.

parent cba8536a
No related branches found
No related tags found
No related merge requests found
/******************************************************************************
* Copyright (C) 2022, Advanced Micro Devices, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION). HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* @brief AXI-Light adapter for trivial write enable interface.
* @author Thomas B. Preußer <tpreusse@amd.com>
*****************************************************************************/
module axi2we #(
int unsigned ADDR_BITS
)(
//- Global Control ------------------
input logic ap_clk,
input logic ap_rst_n,
//- AXI Lite ------------------------
// Writing
input s_axilite_AWVALID,
output s_axilite_AWREADY,
input [ADDR_BITS-1:0] s_axilite_AWADDR,
input s_axilite_WVALID,
output s_axilite_WREADY,
input [31:0] s_axilite_WDATA,
input [ 3:0] s_axilite_WSTRB,
output s_axilite_BVALID,
input s_axilite_BREADY,
output [1:0] s_axilite_BRESP,
// Reading tied to all-ones
input s_axilite_ARVALID,
output s_axilite_ARREADY,
input [3:0] s_axilite_ARADDR,
output s_axilite_RVALID,
input s_axilite_RREADY,
output [31:0] s_axilite_RDATA,
output [ 1:0] s_axilite_RRESP,
// Write Enable Interface
output logic we,
output logic [ADDR_BITS-1:0] wa,
output logic [ 31:0] wd
);
uwire clk = ap_clk;
uwire rst = !ap_rst_n;
logic WABusy = 0;
logic WDBusy = 0;
logic [ADDR_BITS-1:0] Addr = 'x;
logic [ 31:0] Data = 'x;
assign we = WABusy && WDBusy && s_axilite_BREADY;
assign wa = Addr;
assign wd = Data;
uwire clr_wr = rst || we;
always_ff @(posedge clk) begin
if(clr_wr) begin
WABusy <= 0;
Addr <= 'x;
WDBusy <= 0;
Data <= 'x;
end
else begin
if(!WABusy) begin
WABusy <= s_axilite_AWVALID;
Addr <= s_axilite_AWADDR;
end
if(!WDBusy) begin
WDBusy <= s_axilite_WVALID;
Data <= s_axilite_WDATA;
end
end
end
assign s_axilite_AWREADY = !WABusy;
assign s_axilite_WREADY = !WDBusy;
assign s_axilite_BVALID = WABusy && WDBusy;
assign s_axilite_BRESP = '0; // OK
// Answer all reads with '1
logic RValid = 0;
uwire clr_rd = rst || (RValid && s_axilite_RREADY);
always_ff @(posedge clk) begin
if(clr_rd) RValid <= 0;
else if(!RValid) RValid <= s_axilite_ARVALID;
end
assign s_axilite_ARREADY = !RValid;
assign s_axilite_RVALID = RValid;
assign s_axilite_RDATA = '1;
assign s_axilite_RRESP = '0; // OK
endmodule : axi2we
/******************************************************************************
* Copyright (C) 2022, Advanced Micro Devices, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION). HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* @brief Feature map padding.
* @author Thomas B. Preußer <tpreusse@amd.com>
*****************************************************************************/
module fmpadding #(
int unsigned XCOUNTER_BITS,
int unsigned YCOUNTER_BITS,
int unsigned NUM_CHANNELS,
int unsigned SIMD,
int unsigned ELEM_BITS,
localparam int unsigned STREAM_BITS = 8*(1 + (SIMD*ELEM_BITS-1)/8)
)(
//- Global Control ------------------
input logic ap_clk,
input logic ap_rst_n,
// Parameter Configuration ----------
input logic we,
input logic [ 2:0] wa,
input logic [31:0] wd,
//- AXI Stream - Input --------------
output logic s_axis_tready,
input logic s_axis_tvalid,
input logic [STREAM_BITS-1:0] s_axis_tdata,
//- AXI Stream - Output -------------
input logic m_axis_tready,
output logic m_axis_tvalid,
output logic [STREAM_BITS-1:0] m_axis_tdata
);
uwire clk = ap_clk;
uwire rst = !ap_rst_n;
//-----------------------------------------------------------------------
// Dynamically configurable state
typedef logic [XCOUNTER_BITS-1:0] xcount_t;
xcount_t XEnd = 0;
xcount_t XOn = 0;
xcount_t XOff = 0;
typedef logic [YCOUNTER_BITS-1:0] ycount_t;
ycount_t YEnd = 0;
ycount_t YOn = 0;
ycount_t YOff = 0;
always_ff @(posedge clk) begin
if(we) begin
unique case(wa)
0: XOn <= wd;
1: XOff <= wd;
2: XEnd <= wd;
4: YOn <= wd;
5: YOff <= wd;
6: YEnd <= wd;
default: assert(0) else begin
$error("Illegal write address.");
$stop;
end
endcase
end
end
//-----------------------------------------------------------------------
// Cascaded enables for the nested counters: SCount, XCount, YCount
uwire sen;
uwire xen;
uwire yen;
//- S-Counter: SIMD fold ------------
initial begin
if((NUM_CHANNELS < 1) || (NUM_CHANNELS % SIMD != 0)) begin
$error("Channel count must be SIMD multiple.");
$finish;
end
end
// Count SF-2, SF-3, ..., 1, 0, -1
localparam int unsigned SF = NUM_CHANNELS/SIMD;
typedef logic [$clog2(SF-1):0] scount_t;
scount_t SCount = SF-2;
assign xen = sen && SCount[$left(SCount)];
uwire sclr = rst || xen;
always_ff @(posedge clk) begin
if(sclr) SCount <= SF-2;
else if(sen) SCount <= SCount - 1;
end
//- X-Counter: image width ----------
xcount_t XCount = 0;
assign yen = xen && (XCount == XEnd);
uwire xclr = rst || yen;
always_ff @(posedge clk) begin
if(xclr) XCount <= 0;
else if(xen) XCount <= XCount + 1;
end
uwire xfwd = (XOn <= XCount) && (XCount < XOff);
//- Y-Counter: image height ---------
ycount_t YCount = 0;
uwire yclr = rst || (yen && (YCount == YEnd));
always_ff @(posedge clk) begin
if(yclr) YCount <= 0;
else if(yen) YCount <= YCount + 1;
end
uwire yfwd = (YOn <= YCount) && (YCount < YOff);
//-----------------------------------------------------------------------
// Input forwarding and edge padding
typedef struct {
logic vld;
logic [STREAM_BITS-1:0] dat;
} buf_t;
buf_t A = '{ vld: 0, dat: 'x };
buf_t B = '{ vld: 0, dat: 'x };
uwire fwd = xfwd && yfwd;
assign sen = (m_axis_tready || !B.vld) && (s_axis_tvalid || A.vld || !fwd);
assign s_axis_tready = !A.vld;
assign m_axis_tvalid = B.vld;
assign m_axis_tdata = B.dat;
always_ff @(posedge clk) begin
if(rst) begin
B <= '{ vld: 0, dat: 'x };
end
else if(m_axis_tready || !B.vld) begin
B.vld <= s_axis_tvalid || A.vld || !fwd;
B.dat <= !fwd? '0 : A.vld? A.dat : s_axis_tdata;
end
end
always_ff @(posedge clk) begin
if(rst) begin
A <= '{ vld: 0, dat: 'x };
end
else begin
A.vld <= (A.vld || s_axis_tvalid) && ((B.vld && !m_axis_tready) || !fwd);
if(!A.vld) A.dat <= s_axis_tdata;
end
end
endmodule : fmpadding
......@@ -44,7 +44,6 @@ module fmpadding_axi #(
input logic ap_clk,
input logic ap_rst_n,
/*
//- AXI Lite ------------------------
// Writing
input s_axilite_AWVALID,
......@@ -69,11 +68,6 @@ module fmpadding_axi #(
input s_axilite_RREADY,
output [31:0] s_axilite_RDATA,
output [ 1:0] s_axilite_RRESP,
*/
input logic we,
input logic [ 2:0] wa,
input logic [31:0] wd,
//- AXI Stream - Input --------------
output logic s_axis_tready,
......@@ -86,118 +80,35 @@ module fmpadding_axi #(
output logic [STREAM_BITS-1:0] m_axis_tdata
);
uwire clk = ap_clk;
uwire rst = !ap_rst_n;
//-----------------------------------------------------------------------
// Dynamically configurable state
typedef logic [XCOUNTER_BITS-1:0] xcount_t;
xcount_t XEnd = 0;
xcount_t XOn = 0;
xcount_t XOff = 0;
typedef logic [YCOUNTER_BITS-1:0] ycount_t;
ycount_t YEnd = 0;
ycount_t YOn = 0;
ycount_t YOff = 0;
always_ff @(posedge clk) begin
if(we) begin
unique case(wa)
0: XOn <= wd;
1: XOff <= wd;
2: XEnd <= wd;
4: YOn <= wd;
5: YOff <= wd;
6: YEnd <= wd;
default: assert(0) else begin
$error("Illegal write address.");
$stop;
end
endcase
end
end
//-----------------------------------------------------------------------
// Cascaded enables for the nested counters: SCount, XCount, YCount
uwire sen;
uwire xen;
uwire yen;
//- S-Counter: SIMD fold ------------
initial begin
if((NUM_CHANNELS < 1) || (NUM_CHANNELS % SIMD != 0)) begin
$error("Channel count must be SIMD multiple.");
$finish;
end
end
// Count SF-2, SF-3, ..., 1, 0, -1
localparam int unsigned SF = NUM_CHANNELS/SIMD;
typedef logic [$clog2(SF-1):0] scount_t;
scount_t SCount = SF-2;
assign xen = sen && SCount[$left(SCount)];
uwire sclr = rst || xen;
always_ff @(posedge clk) begin
if(sclr) SCount <= SF-2;
else if(sen) SCount <= SCount - 1;
end
//- X-Counter: image width ----------
xcount_t XCount = 0;
assign yen = xen && (XCount == XEnd);
uwire xclr = rst || yen;
always_ff @(posedge clk) begin
if(xclr) XCount <= 0;
else if(xen) XCount <= XCount + 1;
end
uwire xfwd = (XOn <= XCount) && (XCount < XOff);
//- Y-Counter: image height ---------
ycount_t YCount = 0;
uwire yclr = rst || (yen && (YCount == YEnd));
always_ff @(posedge clk) begin
if(yclr) YCount <= 0;
else if(yen) YCount <= YCount + 1;
end
uwire yfwd = (YOn <= YCount) && (YCount < YOff);
//-----------------------------------------------------------------------
// Input forwarding and edge padding
typedef struct {
logic vld;
logic [STREAM_BITS-1:0] dat;
} buf_t;
buf_t A = '{ vld: 0, dat: 'x };
buf_t B = '{ vld: 0, dat: 'x };
uwire fwd = xfwd && yfwd;
assign sen = (m_axis_tready || !B.vld) && (s_axis_tvalid || A.vld || !fwd);
assign s_axis_tready = !A.vld;
assign m_axis_tvalid = B.vld;
assign m_axis_tdata = B.dat;
always_ff @(posedge clk) begin
if(rst) begin
B <= '{ vld: 0, dat: 'x };
end
else if(m_axis_tready || !B.vld) begin
B.vld <= s_axis_tvalid || A.vld || !fwd;
B.dat <= !fwd? '0 : A.vld? A.dat : s_axis_tdata;
end
end
always_ff @(posedge clk) begin
if(rst) begin
A <= '{ vld: 0, dat: 'x };
end
else begin
A.vld <= (A.vld || s_axis_tvalid) && ((B.vld && !m_axis_tready) || !fwd);
if(!A.vld) A.dat <= s_axis_tdata;
end
end
// AXI-Lite Adapter
uwire we;
uwire [ 2:0] wa;
uwire [31:0] wd;
axi2we #(.ADDR_BITS(3)) axilight_adapter (
.ap_clk, .ap_rst_n,
.s_axilite_AWVALID, .s_axilite_AWREADY, .s_axilite_AWADDR,
.s_axilite_WVALID, .s_axilite_WREADY, .s_axilite_WDATA, .s_axilite_WSTRB,
.s_axilite_BVALID, .s_axilite_BREADY, .s_axilite_BRESP,
.s_axilite_ARVALID, .s_axilite_ARREADY, .s_axilite_ARADDR,
.s_axilite_RVALID, .s_axilite_RREADY, .s_axilite_RDATA, .s_axilite_RRESP,
.we, .wa, .wd
);
// Actual Padding
fmpadding #(
.XCOUNTER_BITS(XCOUNTER_BITS), .YCOUNTER_BITS(YCOUNTER_BITS),
.NUM_CHANNELS(NUM_CHANNELS), .SIMD(SIMD),
.ELEM_BITS(ELEM_BITS)
) padding (
.ap_clk, .ap_rst_n,
.we, .wa, .wd,
.s_axis_tready, .s_axis_tvalid, .s_axis_tdata,
.m_axis_tready, .m_axis_tvalid, .m_axis_tdata
);
endmodule : fmpadding_axi
......@@ -13,10 +13,14 @@ module fmpadding_axi_tb #(
always #5ns clk = !clk;
logic rst;
// Parameter Configuration ----------
logic we;
logic [ 2:0] wa;
logic [31:0] wd;
// AXI-Light for Parameter Configuration
logic s_axilite_AWVALID;
uwire s_axilite_AWREADY;
logic [2:0] s_axilite_AWADDR;
logic s_axilite_WVALID;
uwire s_axilite_WREADY;
logic [31:0] s_axilite_WDATA;
//- AXI Stream - Input --------------
uwire s_axis_tready;
......@@ -38,7 +42,13 @@ module fmpadding_axi_tb #(
.ELEM_BITS(ELEM_BITS)
) dut (
.ap_clk(clk), .ap_rst_n(!rst),
.we, .wa, .wd,
.s_axilite_AWVALID, .s_axilite_AWREADY, .s_axilite_AWADDR,
.s_axilite_WVALID, .s_axilite_WREADY, .s_axilite_WDATA, .s_axilite_WSTRB('1),
.s_axilite_BVALID(), .s_axilite_BREADY('1), .s_axilite_BRESP(),
.s_axilite_ARVALID('0), .s_axilite_ARREADY(), .s_axilite_ARADDR('x),
.s_axilite_RVALID(), .s_axilite_RREADY('0), .s_axilite_RDATA(), .s_axilite_RRESP(),
.s_axis_tready, .s_axis_tvalid, .s_axis_tdata,
.m_axis_tready, .m_axis_tvalid, .m_axis_tdata
);
......@@ -51,29 +61,45 @@ module fmpadding_axi_tb #(
localparam int unsigned PAD_RIGHT = 3;
localparam int unsigned PAD_TOP = 1;
localparam int unsigned PAD_BOTTOM = 2;
task axi_write(input logic [2:0] wa, input logic [31:0] wd);
s_axilite_AWVALID <= 1;
s_axilite_AWADDR <= wa;
@(posedge clk iff s_axilite_AWREADY);
s_axilite_AWVALID <= 0;
s_axilite_AWADDR <= 'x;
s_axilite_WVALID <= 1;
s_axilite_WDATA <= wd;
@(posedge clk iff s_axilite_WREADY);
s_axilite_WVALID <= 0;
s_axilite_WDATA <= 'x;
endtask : axi_write
initial begin
we = 0;
wa = 'x;
wd = 'x;
s_axilite_AWVALID = 0;
s_axilite_AWADDR = 'x;
s_axilite_WVALID = 0;
s_axilite_WDATA = 'x;
s_axis_tvalid = 0;
s_axis_tdata = 'x;
// Configure Parameters
rst = 1;
rst = 0;
@(posedge clk);
we <= 1;
/* XOn */ wa <= 0; wd <= PAD_LEFT; @(posedge clk);
/* XOff */ wa <= 1; wd <= XSIZE - PAD_RIGHT; @(posedge clk);
/* XEnd */ wa <= 2; wd <= XSIZE - 1; @(posedge clk);
/* YOn */ wa <= 4; wd <= PAD_TOP; @(posedge clk);
/* YOff */ wa <= 5; wd <= YSIZE - PAD_BOTTOM; @(posedge clk);
/* YEnd */ wa <= 6; wd <= YSIZE - 1; @(posedge clk);
we <= 0;
wa <= 'x;
wd <= 'x;
/* XOn */ axi_write(0, PAD_LEFT);
/* XOff */ axi_write(1, XSIZE - PAD_RIGHT);
/* XEnd */ axi_write(2, XSIZE - 1);
/* YOn */ axi_write(4, PAD_TOP);
/* YOff */ axi_write(5, YSIZE - PAD_BOTTOM);
/* YEnd */ axi_write(6, YSIZE - 1);
@(posedge clk);
rst <= 1;
@(posedge clk);
rst <= 0;
@(posedge clk);
// Feed data input
s_axis_tvalid <= 1;
......@@ -91,7 +117,7 @@ module fmpadding_axi_tb #(
s_axis_tdata <= 'x;
end
// Ouput Throttler
// Output Throttler
initial begin
m_axis_tready = 0;
@(posedge clk iff !rst);
......@@ -105,6 +131,7 @@ module fmpadding_axi_tb #(
// Output logger
initial begin
@(negedge rst);
repeat(IMAGES) begin
for(int unsigned y = 0; y < YSIZE; y++) begin
for(int unsigned x = 0; x < XSIZE; x++) begin
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment