diff --git a/src/finn/qnn-data/verilog/myadd/myadd_myadd.v b/src/finn/qnn-data/verilog/myadd/myadd_myadd.v new file mode 100644 index 0000000000000000000000000000000000000000..0b18b5c300c4dc62d2f0105a896d19980a4f7dca --- /dev/null +++ b/src/finn/qnn-data/verilog/myadd/myadd_myadd.v @@ -0,0 +1,118 @@ +// ============================================================== +// RTL generated by Vivado(TM) HLS - High-Level Synthesis from C, C++ and SystemC +// Version: 2019.1 +// Copyright (C) 1986-2019 Xilinx, Inc. All Rights Reserved. +// +// =========================================================== + +`timescale 1 ns / 1 ps + +(* CORE_GENERATION_INFO="myadd_myadd,hls_ip_2019_1,{HLS_INPUT_TYPE=cxx,HLS_INPUT_FLOAT=0,HLS_INPUT_FIXED=1,HLS_INPUT_PART=xc7z020-clg400-1,HLS_INPUT_CLOCK=5.000000,HLS_INPUT_ARCH=others,HLS_SYN_CLOCK=3.552000,HLS_SYN_LAT=0,HLS_SYN_TPT=none,HLS_SYN_MEM=0,HLS_SYN_DSP=0,HLS_SYN_FF=144,HLS_SYN_LUT=271,HLS_VERSION=2019_1}" *) + +module myadd_myadd ( + s_axi_control_AWVALID, + s_axi_control_AWREADY, + s_axi_control_AWADDR, + s_axi_control_WVALID, + s_axi_control_WREADY, + s_axi_control_WDATA, + s_axi_control_WSTRB, + s_axi_control_ARVALID, + s_axi_control_ARREADY, + s_axi_control_ARADDR, + s_axi_control_RVALID, + s_axi_control_RREADY, + s_axi_control_RDATA, + s_axi_control_RRESP, + s_axi_control_BVALID, + s_axi_control_BREADY, + s_axi_control_BRESP, + ap_clk, + ap_rst_n, + interrupt +); + +parameter C_S_AXI_CONTROL_DATA_WIDTH = 32; +parameter C_S_AXI_CONTROL_ADDR_WIDTH = 6; +parameter C_S_AXI_DATA_WIDTH = 32; + +parameter C_S_AXI_CONTROL_WSTRB_WIDTH = (32 / 8); +parameter C_S_AXI_WSTRB_WIDTH = (32 / 8); + +input s_axi_control_AWVALID; +output s_axi_control_AWREADY; +input [C_S_AXI_CONTROL_ADDR_WIDTH - 1:0] s_axi_control_AWADDR; +input s_axi_control_WVALID; +output s_axi_control_WREADY; +input [C_S_AXI_CONTROL_DATA_WIDTH - 1:0] s_axi_control_WDATA; +input [C_S_AXI_CONTROL_WSTRB_WIDTH - 1:0] s_axi_control_WSTRB; +input s_axi_control_ARVALID; +output s_axi_control_ARREADY; +input [C_S_AXI_CONTROL_ADDR_WIDTH - 1:0] s_axi_control_ARADDR; +output s_axi_control_RVALID; +input s_axi_control_RREADY; +output [C_S_AXI_CONTROL_DATA_WIDTH - 1:0] s_axi_control_RDATA; +output [1:0] s_axi_control_RRESP; +output s_axi_control_BVALID; +input s_axi_control_BREADY; +output [1:0] s_axi_control_BRESP; +input ap_clk; +input ap_rst_n; +output interrupt; + +wire ap_start; +wire ap_done; +wire ap_idle; +wire ap_ready; +wire [31:0] a_V; +wire [31:0] b_V; +wire [31:0] ap_return; + reg ap_rst_n_inv; + +myadd_myadd_control_s_axi #( + .C_S_AXI_ADDR_WIDTH( C_S_AXI_CONTROL_ADDR_WIDTH ), + .C_S_AXI_DATA_WIDTH( C_S_AXI_CONTROL_DATA_WIDTH )) +myadd_control_s_axi_U( + .AWVALID(s_axi_control_AWVALID), + .AWREADY(s_axi_control_AWREADY), + .AWADDR(s_axi_control_AWADDR), + .WVALID(s_axi_control_WVALID), + .WREADY(s_axi_control_WREADY), + .WDATA(s_axi_control_WDATA), + .WSTRB(s_axi_control_WSTRB), + .ARVALID(s_axi_control_ARVALID), + .ARREADY(s_axi_control_ARREADY), + .ARADDR(s_axi_control_ARADDR), + .RVALID(s_axi_control_RVALID), + .RREADY(s_axi_control_RREADY), + .RDATA(s_axi_control_RDATA), + .RRESP(s_axi_control_RRESP), + .BVALID(s_axi_control_BVALID), + .BREADY(s_axi_control_BREADY), + .BRESP(s_axi_control_BRESP), + .ACLK(ap_clk), + .ARESET(ap_rst_n_inv), + .ACLK_EN(1'b1), + .ap_start(ap_start), + .interrupt(interrupt), + .ap_ready(ap_ready), + .ap_done(ap_done), + .ap_idle(ap_idle), + .ap_return(ap_return), + .a_V(a_V), + .b_V(b_V) +); + +assign ap_done = ap_start; + +assign ap_idle = 1'b1; + +assign ap_ready = ap_start; + +assign ap_return = (b_V + a_V); + +always @ (*) begin + ap_rst_n_inv = ~ap_rst_n; +end + +endmodule //myadd_myadd diff --git a/src/finn/qnn-data/verilog/myadd/myadd_myadd_control_s_axi.v b/src/finn/qnn-data/verilog/myadd/myadd_myadd_control_s_axi.v new file mode 100644 index 0000000000000000000000000000000000000000..40260ca930b5dc251f9d095420ae9ad0b77d4c93 --- /dev/null +++ b/src/finn/qnn-data/verilog/myadd/myadd_myadd_control_s_axi.v @@ -0,0 +1,357 @@ +// ============================================================== +// Vivado(TM) HLS - High-Level Synthesis from C, C++ and SystemC v2019.1 (64-bit) +// Copyright 1986-2019 Xilinx, Inc. All Rights Reserved. +// ============================================================== +`timescale 1ns/1ps +module myadd_myadd_control_s_axi +#(parameter + C_S_AXI_ADDR_WIDTH = 6, + C_S_AXI_DATA_WIDTH = 32 +)( + input wire ACLK, + input wire ARESET, + input wire ACLK_EN, + input wire [C_S_AXI_ADDR_WIDTH-1:0] AWADDR, + input wire AWVALID, + output wire AWREADY, + input wire [C_S_AXI_DATA_WIDTH-1:0] WDATA, + input wire [C_S_AXI_DATA_WIDTH/8-1:0] WSTRB, + input wire WVALID, + output wire WREADY, + output wire [1:0] BRESP, + output wire BVALID, + input wire BREADY, + input wire [C_S_AXI_ADDR_WIDTH-1:0] ARADDR, + input wire ARVALID, + output wire ARREADY, + output wire [C_S_AXI_DATA_WIDTH-1:0] RDATA, + output wire [1:0] RRESP, + output wire RVALID, + input wire RREADY, + output wire interrupt, + output wire ap_start, + input wire ap_done, + input wire ap_ready, + input wire ap_idle, + input wire [31:0] ap_return, + output wire [31:0] a_V, + output wire [31:0] b_V +); +//------------------------Address Info------------------- +// 0x00 : Control signals +// bit 0 - ap_start (Read/Write/SC) +// bit 1 - ap_done (Read/COR) +// bit 2 - ap_idle (Read) +// bit 3 - ap_ready (Read) +// bit 7 - auto_restart (Read/Write) +// others - reserved +// 0x04 : Global Interrupt Enable Register +// bit 0 - Global Interrupt Enable (Read/Write) +// others - reserved +// 0x08 : IP Interrupt Enable Register (Read/Write) +// bit 0 - Channel 0 (ap_done) +// others - reserved +// 0x0c : IP Interrupt Status Register (Read/TOW) +// bit 0 - Channel 0 (ap_done) +// others - reserved +// 0x10 : Data signal of ap_return +// bit 31~0 - ap_return[31:0] (Read) +// 0x18 : Data signal of a_V +// bit 31~0 - a_V[31:0] (Read/Write) +// 0x1c : reserved +// 0x20 : Data signal of b_V +// bit 31~0 - b_V[31:0] (Read/Write) +// 0x24 : reserved +// (SC = Self Clear, COR = Clear on Read, TOW = Toggle on Write, COH = Clear on Handshake) + +//------------------------Parameter---------------------- +localparam + ADDR_AP_CTRL = 6'h00, + ADDR_GIE = 6'h04, + ADDR_IER = 6'h08, + ADDR_ISR = 6'h0c, + ADDR_AP_RETURN_0 = 6'h10, + ADDR_A_V_DATA_0 = 6'h18, + ADDR_A_V_CTRL = 6'h1c, + ADDR_B_V_DATA_0 = 6'h20, + ADDR_B_V_CTRL = 6'h24, + WRIDLE = 2'd0, + WRDATA = 2'd1, + WRRESP = 2'd2, + WRRESET = 2'd3, + RDIDLE = 2'd0, + RDDATA = 2'd1, + RDRESET = 2'd2, + ADDR_BITS = 6; + +//------------------------Local signal------------------- + reg [1:0] wstate = WRRESET; + reg [1:0] wnext; + reg [ADDR_BITS-1:0] waddr; + wire [31:0] wmask; + wire aw_hs; + wire w_hs; + reg [1:0] rstate = RDRESET; + reg [1:0] rnext; + reg [31:0] rdata; + wire ar_hs; + wire [ADDR_BITS-1:0] raddr; + // internal registers + reg int_ap_idle; + reg int_ap_ready; + reg int_ap_done = 1'b0; + reg int_ap_start = 1'b0; + reg int_auto_restart = 1'b0; + reg int_gie = 1'b0; + reg int_ier = 1'b0; + reg int_isr = 1'b0; + reg [31:0] int_ap_return; + reg [31:0] int_a_V = 'b0; + reg [31:0] int_b_V = 'b0; + +//------------------------Instantiation------------------ + +//------------------------AXI write fsm------------------ +assign AWREADY = (wstate == WRIDLE); +assign WREADY = (wstate == WRDATA); +assign BRESP = 2'b00; // OKAY +assign BVALID = (wstate == WRRESP); +assign wmask = { {8{WSTRB[3]}}, {8{WSTRB[2]}}, {8{WSTRB[1]}}, {8{WSTRB[0]}} }; +assign aw_hs = AWVALID & AWREADY; +assign w_hs = WVALID & WREADY; + +// wstate +always @(posedge ACLK) begin + if (ARESET) + wstate <= WRRESET; + else if (ACLK_EN) + wstate <= wnext; +end + +// wnext +always @(*) begin + case (wstate) + WRIDLE: + if (AWVALID) + wnext = WRDATA; + else + wnext = WRIDLE; + WRDATA: + if (WVALID) + wnext = WRRESP; + else + wnext = WRDATA; + WRRESP: + if (BREADY) + wnext = WRIDLE; + else + wnext = WRRESP; + default: + wnext = WRIDLE; + endcase +end + +// waddr +always @(posedge ACLK) begin + if (ACLK_EN) begin + if (aw_hs) + waddr <= AWADDR[ADDR_BITS-1:0]; + end +end + +//------------------------AXI read fsm------------------- +assign ARREADY = (rstate == RDIDLE); +assign RDATA = rdata; +assign RRESP = 2'b00; // OKAY +assign RVALID = (rstate == RDDATA); +assign ar_hs = ARVALID & ARREADY; +assign raddr = ARADDR[ADDR_BITS-1:0]; + +// rstate +always @(posedge ACLK) begin + if (ARESET) + rstate <= RDRESET; + else if (ACLK_EN) + rstate <= rnext; +end + +// rnext +always @(*) begin + case (rstate) + RDIDLE: + if (ARVALID) + rnext = RDDATA; + else + rnext = RDIDLE; + RDDATA: + if (RREADY & RVALID) + rnext = RDIDLE; + else + rnext = RDDATA; + default: + rnext = RDIDLE; + endcase +end + +// rdata +always @(posedge ACLK) begin + if (ACLK_EN) begin + if (ar_hs) begin + rdata <= 1'b0; + case (raddr) + ADDR_AP_CTRL: begin + rdata[0] <= int_ap_start; + rdata[1] <= int_ap_done; + rdata[2] <= int_ap_idle; + rdata[3] <= int_ap_ready; + rdata[7] <= int_auto_restart; + end + ADDR_GIE: begin + rdata <= int_gie; + end + ADDR_IER: begin + rdata <= int_ier; + end + ADDR_ISR: begin + rdata <= int_isr; + end + ADDR_AP_RETURN_0: begin + rdata <= int_ap_return[31:0]; + end + ADDR_A_V_DATA_0: begin + rdata <= int_a_V[31:0]; + end + ADDR_B_V_DATA_0: begin + rdata <= int_b_V[31:0]; + end + endcase + end + end +end + + +//------------------------Register logic----------------- +assign interrupt = int_gie & (|int_isr); +assign ap_start = int_ap_start; +assign a_V = int_a_V; +assign b_V = int_b_V; +// int_ap_start +always @(posedge ACLK) begin + if (ARESET) + int_ap_start <= 1'b0; + else if (ACLK_EN) begin + if (w_hs && waddr == ADDR_AP_CTRL && WSTRB[0] && WDATA[0]) + int_ap_start <= 1'b1; + else if (ap_done & int_auto_restart) + int_ap_start <= 1'b1; // auto restart + else + int_ap_start <= 1'b0; // self clear + end +end + +// int_ap_done +always @(posedge ACLK) begin + if (ARESET) + int_ap_done <= 1'b0; + else if (ACLK_EN) begin + if (ap_done) + int_ap_done <= 1'b1; + else if (ar_hs && raddr == ADDR_AP_CTRL) + int_ap_done <= 1'b0; // clear on read + end +end + +// int_ap_idle +always @(posedge ACLK) begin + if (ARESET) + int_ap_idle <= 1'b0; + else if (ACLK_EN) begin + int_ap_idle <= ap_idle; + end +end + +// int_ap_ready +always @(posedge ACLK) begin + if (ARESET) + int_ap_ready <= 1'b0; + else if (ACLK_EN) begin + int_ap_ready <= ap_ready; + end +end + +// int_auto_restart +always @(posedge ACLK) begin + if (ARESET) + int_auto_restart <= 1'b0; + else if (ACLK_EN) begin + if (w_hs && waddr == ADDR_AP_CTRL && WSTRB[0]) + int_auto_restart <= WDATA[7]; + end +end + +// int_gie +always @(posedge ACLK) begin + if (ARESET) + int_gie <= 1'b0; + else if (ACLK_EN) begin + if (w_hs && waddr == ADDR_GIE && WSTRB[0]) + int_gie <= WDATA[0]; + end +end + +// int_ier +always @(posedge ACLK) begin + if (ARESET) + int_ier <= 1'b0; + else if (ACLK_EN) begin + if (w_hs && waddr == ADDR_IER && WSTRB[0]) + int_ier <= WDATA[0]; + end +end + +// int_isr +always @(posedge ACLK) begin + if (ARESET) + int_isr <= 1'b0; + else if (ACLK_EN) begin + if (int_ier & ap_done) + int_isr <= 1'b1; + else if (w_hs && waddr == ADDR_ISR && WSTRB[0]) + int_isr <= int_isr ^ WDATA[0]; // toggle on write + end +end + +// int_ap_return +always @(posedge ACLK) begin + if (ARESET) + int_ap_return <= 0; + else if (ACLK_EN) begin + if (ap_done) + int_ap_return <= ap_return; + end +end + +// int_a_V[31:0] +always @(posedge ACLK) begin + if (ARESET) + int_a_V[31:0] <= 0; + else if (ACLK_EN) begin + if (w_hs && waddr == ADDR_A_V_DATA_0) + int_a_V[31:0] <= (WDATA[31:0] & wmask) | (int_a_V[31:0] & ~wmask); + end +end + +// int_b_V[31:0] +always @(posedge ACLK) begin + if (ARESET) + int_b_V[31:0] <= 0; + else if (ACLK_EN) begin + if (w_hs && waddr == ADDR_B_V_DATA_0) + int_b_V[31:0] <= (WDATA[31:0] & wmask) | (int_b_V[31:0] & ~wmask); + end +end + + +//------------------------Memory logic------------------- + +endmodule diff --git a/src/finn/transformation/fpgadataflow/set_fifo_depths.py b/src/finn/transformation/fpgadataflow/set_fifo_depths.py index 713148d7fcdfea4411554b6d3b817a14b33a53c6..30fa8b089ae6bdfc3249b2a725e1b97c2ba9c1f0 100644 --- a/src/finn/transformation/fpgadataflow/set_fifo_depths.py +++ b/src/finn/transformation/fpgadataflow/set_fifo_depths.py @@ -39,11 +39,8 @@ from finn.transformation.fpgadataflow.create_stitched_ip import CreateStitchedIP from finn.transformation.fpgadataflow.insert_dwc import InsertDWC from finn.transformation.fpgadataflow.insert_fifo import InsertFIFO from finn.transformation.general import GiveUniqueNodeNames, GiveReadableTensorNames -from finn.core.rtlsim_exec import ( - _reset_rtlsim, - _toggle_clk, -) from finn.util.fpgadataflow import pyverilate_stitched_ip, is_fpgadataflow_node +from finn.util.pyverilator import reset_rtlsim, toggle_clk def reset_implementation(node): @@ -298,8 +295,8 @@ class InsertAndSetFIFODepths(Transformation): # prepare pyverilator model sim = pyverilate_stitched_ip(model) - _reset_rtlsim(sim) - _toggle_clk(sim) + reset_rtlsim(sim) + toggle_clk(sim) # set all input valids to 0 and output readies to 1 # set input data to some constant @@ -309,7 +306,7 @@ class InsertAndSetFIFODepths(Transformation): output_detected = False while ncycles > 0: - _toggle_clk(sim) + toggle_clk(sim) # set/unset valids if ncycles % ncycles_per_input == 0: set_signal(sim, "tvalid", 1) diff --git a/src/finn/util/pyverilator.py b/src/finn/util/pyverilator.py new file mode 100644 index 0000000000000000000000000000000000000000..41b72db9504ebeb8d10c5d838977da93b27f94ed --- /dev/null +++ b/src/finn/util/pyverilator.py @@ -0,0 +1,124 @@ +# Copyright (c) 2020, Xilinx +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * 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. +# +# * Neither the name of FINN 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. + + +def reset_rtlsim(sim, rst_name="ap_rst_n", active_low=True): + """Sets reset input in pyverilator to zero, toggles the clock and set it + back to one""" + sim.io[rst_name] = 0 if active_low else 1 + toggle_clk(sim) + toggle_clk(sim) + sim.io[rst_name] = 1 if active_low else 0 + toggle_clk(sim) + toggle_clk(sim) + + +def toggle_clk(sim, clk_name="ap_clk"): + """Toggles the clock input in pyverilator once.""" + sim.io[clk_name] = 0 + sim.eval() + sim.io[clk_name] = 1 + sim.eval() + + +def wait_for_handshake(sim, ifname, basename="s_axi_control_", dataname="DATA"): + """Wait for handshake (READY and VALID high at the same time) on given + interface on PyVerilator sim object. + + Arguments: + - sim : PyVerilator sim object + - ifname : name for decoupled interface to wait for handshake on + - basename : prefix for decoupled interface name + - dataname : interface data sig name, will be return value if it exists + + Returns: value of interface data signal during handshake (if given by dataname), + None otherwise (e.g. if there is no data signal associated with interface) + """ + ret = None + while 1: + hs = ( + sim.io[basename + ifname + "READY"] == 1 + and sim.io[basename + ifname + "VALID"] == 1 + ) + if basename + ifname + dataname in sim.io: + ret = sim.io[basename + ifname + dataname] + toggle_clk(sim) + if hs: + break + return ret + + +def axilite_write(sim, addr, val, basename="s_axi_control_", wstrb=0xF): + """Write val to addr on AXI lite interface given by basename. + + Arguments: + - sim : PyVerilator sim object + - addr : address for write + - val : value to be written at addr + - basename : prefix for AXI lite interface name + - wstrb : write strobe value to do partial writes, see AXI protocol reference + """ + sim.io[basename + "WSTRB"] = wstrb + sim.io[basename + "AWADDR"] = addr + sim.io[basename + "AWVALID"] = 1 + wait_for_handshake(sim, "AW", basename=basename) + # write request done + sim.io[basename + "AWVALID"] = 0 + # write data + sim.io[basename + "WDATA"] = val + sim.io[basename + "WVALID"] = 1 + wait_for_handshake(sim, "W", basename=basename) + # write data OK + sim.io[basename + "WVALID"] = 0 + # wait for write response + sim.io[basename + "BREADY"] = 1 + wait_for_handshake(sim, "B", basename=basename) + # write response OK + sim.io[basename + "BREADY"] = 0 + + +def axilite_read(sim, addr, basename="s_axi_control_"): + """Read val from addr on AXI lite interface given by basename. + + Arguments: + - sim : PyVerilator sim object + - addr : address for read + - basename : prefix for AXI lite interface name + + Returns: read value from AXI lite interface at given addr + """ + sim.io[basename + "ARADDR"] = addr + sim.io[basename + "ARVALID"] = 1 + wait_for_handshake(sim, "AR", basename=basename) + # read request OK + sim.io[basename + "ARVALID"] = 0 + # wait for read response + sim.io[basename + "RREADY"] = 1 + ret_data = wait_for_handshake(sim, "R", basename=basename) + sim.io[basename + "RREADY"] = 0 + return ret_data diff --git a/tests/util/test_pyverilator.py b/tests/util/test_pyverilator.py new file mode 100644 index 0000000000000000000000000000000000000000..5d837a924d92ca9a834557c21756d5f490146908 --- /dev/null +++ b/tests/util/test_pyverilator.py @@ -0,0 +1,96 @@ +# Copyright (c) 2020, Xilinx +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * 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. +# +# * Neither the name of FINN 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. + +import pkg_resources as pk +from pyverilator import PyVerilator +from finn.util.pyverilator import axilite_read, axilite_write, reset_rtlsim + + +def test_pyverilator_axilite(): + example_root = pk.resource_filename("finn.qnn-data", "verilog/myadd") + # load example verilog: takes two 32-bit integers as AXI lite mem mapped + # registers, adds them together and return result + sim = PyVerilator.build( + "myadd_myadd.v", verilog_path=[example_root], top_module_name="myadd_myadd", + ) + ifname = "s_axi_control_" + expected_signals = [ + "AWVALID", + "AWREADY", + "AWADDR", + "WVALID", + "WREADY", + "WDATA", + "WSTRB", + "ARVALID", + "ARREADY", + "ARADDR", + "RVALID", + "RREADY", + "RDATA", + "RRESP", + "BVALID", + "BREADY", + "BRESP", + ] + for signal_name in expected_signals: + assert ifname + signal_name in sim.io + reset_rtlsim(sim) + # initial values + sim.io[ifname + "WVALID"] = 0 + sim.io[ifname + "AWVALID"] = 0 + sim.io[ifname + "ARVALID"] = 0 + sim.io[ifname + "BREADY"] = 0 + sim.io[ifname + "RREADY"] = 0 + # write + verify first parameter in AXI lite memory mapped regs + val_a = 3 + addr_a = 0x18 + axilite_write(sim, addr_a, val_a) + ret_data = axilite_read(sim, addr_a) + assert ret_data == val_a + # write + verify second parameter in AXI lite memory mapped regs + val_b = 5 + addr_b = 0x20 + axilite_write(sim, addr_b, val_b) + ret_data = axilite_read(sim, addr_b) + assert ret_data == val_b + # launch accelerator and wait for completion + addr_ctrl_status = 0x00 + # check for ap_idle + assert axilite_read(sim, addr_ctrl_status) and (1 << 2) != 0 + # set ap_start + axilite_write(sim, addr_ctrl_status, 1) + # wait until ap_done + while 1: + ap_done = axilite_read(sim, addr_ctrl_status) and (1 << 1) + if ap_done != 0: + break + # read out and verify result + addr_return = 0x10 + val_ret = axilite_read(sim, addr_return) + assert val_ret == val_a + val_b