CPU 통신을 위해서 DMA 컨트롤러를 이용하여 통신
BUS를 통해 Slave와 통신할 때는 각 Master와 Slave를 연결해주어야 하는데 연결하는 역할을 BUS에서 진행함. BUS는 MUX의 집합이라고 봐도 된다.
Master에서 Store(Write)할 ADDR, DATA를 전송할 때는 BUS에 있는 MUX를 Arbiter가 제어한다.
Slave에서 Load(Read)할 DATA를 전송할 때는 BUS에 있는 MUX를 Decoder가 제어한다.
AXI Multiplier
Overflow 방지를 위해
A + B = P
A[M] B[N] = MAX[M,N] + 1
Adder에서는 결과 Register는 값 + 1
Multiplier에서는 두 Register bit수를 더함
A x B = P
A[M] B[N] = P[M+N]
- 입력 : two 16-bit unsigned
동작 순서
-
PS에서 UART를 통해 사용자로부터 두 개의 16비트 곱셈 입력을 받음
-
PS는 도합 32-bit 입력을 AXI-Lite Interface를 통해 PL의 Reg0에 씀
-
PL에 구현된 multiplier는 Reg0의 상위 16-bit와 하위 16-bit를 곱한 후 결과값을 Reg1에 씀
-
PS는 AXI-Lite Interface를 통해 PL의 Reg1으로 부터 곱셈 결과를 읽음
-
PS는 UART를 통해 곱셈 결과를 사용자에게 전달함
파형을 보기위해 Verify를 선택합니다.
검증용 IP가 추가되었습니다.
S00_AXI를 시뮬레이션에 올려봅니다.
다시 돌아와서
reg [31:0] multiplier_out;
always @(posedge S_AXI_ACLK)
begin
if (S_AXI_ARESETN==1'b0) multiplier_out <= 0;
else multiplier_out <= slv_reg0[31:16]*slv_reg0[15:0];
end
ip로 저장.
새로운 프로젝트에서
Repository 설정
zynq 보드 추가후 Run
Validate Design하고
Wrapper 생성.
Generate bitstream
Export > Hardware Export > Include Bitstream
Vitis 실행 후 .xsa load하여 Empty Application 생성
src 폴터에 main.c 생성
main.c
#include <stdio.h>
#include "xparameters.h"
#include "xil_io.h"
int main()
{
short operand1, operand2;
int data, quit, operand;
printf("\n\nMultiplier_Test!!\n\r");
while(1) {
printf("Please Enter Operand 1. \n\r");
scanf("%hd", &operand1);
printf("Please Enter Operand 2. \n\r");
scanf("%hd", &operand2);
// 16bit + 16bit라서 operand1을 16칸 옆으로 밀어준다.
operand = (operand1 << 16) | operand2;
//Write multiplier inputs to register ADDRESS 0
Xil_Out32((XPAR_MY_MULTIPLIER_V1_0_0_BASEADDR), (u32)operand);
//Read multiplier outputs from register ADDRESS 4
data = Xil_In32((XPAR_MY_MULTIPLIER_V1_0_0_BASEADDR)+4);
printf("output=%d \n", data);
printf("Do you want to quit? (0: quit, 1: resume)\n");
scanf("%d", &quit);
if (!quit) break;
}
printf("End of Test!!\n\n\r");
return 0;
}
Build
Terminal 생성
Run
Terminal로 곱셈 가능
HLS를 이용한 Adder 생성
adder5.cpp 생성
void adder5 (int A[50], int B[50])
{
int i;
for (i=0; i<50; i++)
{
B[i] = A[i] + 5;
}
}
test_adder.cpp 생성
#include <stdio.h>
void adder5(int A[50], int B[50]);
int main()
{
int i;
int A[50];
int B[50];
int C[50];
printf("HLS Flow with Adder example\n");
//Put data into A
for(i=0; i < 50; i++){
A[i] = i;
}
//Call the hardware function
adder5(A,B);
//Run a software version of the hardware function to validate results
for(i=0; i < 50; i++) {
C[i] = A[i] + 5;
}
//Compare results
for(i=0; i < 50; i++){
if(B[i] != C[i]){
printf("ERROR HW and SW results mismatch\n");
return 1;
}
}
printf("Success HW and SW results match\n");
return 0;
}
C simulation 실행
Top code 설정
C synthesis 실행
생성된 adder5.v
// ==============================================================
// RTL generated by Vitis HLS - High-Level Synthesis from C, C++ and OpenCL v2020.2 (64-bit)
// Version: 2020.2
// Copyright (C) Copyright 1986-2020 Xilinx, Inc. All Rights Reserved.
//
// ===========================================================
`timescale 1 ns / 1 ps
(* CORE_GENERATION_INFO="adder5_adder5,hls_ip_2020_2,{HLS_INPUT_TYPE=cxx,HLS_INPUT_FLOAT=0,HLS_INPUT_FIXED=0,HLS_INPUT_PART=xc7z020-clg400-1,HLS_INPUT_CLOCK=10.000000,HLS_INPUT_ARCH=others,HLS_SYN_CLOCK=9.060000,HLS_SYN_LAT=52,HLS_SYN_TPT=none,HLS_SYN_MEM=0,HLS_SYN_DSP=0,HLS_SYN_FF=18,HLS_SYN_LUT=110,HLS_VERSION=2020_2}" *)
module adder5 (
ap_clk,
ap_rst,
ap_start,
ap_done,
ap_idle,
ap_ready,
A_address0,
A_ce0,
A_q0,
B_address0,
B_ce0,
B_we0,
B_d0
);
parameter ap_ST_fsm_state1 = 3'd1;
parameter ap_ST_fsm_pp0_stage0 = 3'd2;
parameter ap_ST_fsm_state4 = 3'd4;
input ap_clk;
input ap_rst;
input ap_start;
output ap_done;
output ap_idle;
output ap_ready;
output [5:0] A_address0;
output A_ce0;
input [31:0] A_q0;
output [5:0] B_address0;
output B_ce0;
output B_we0;
output [31:0] B_d0;
reg ap_done;
reg ap_idle;
reg ap_ready;
reg A_ce0;
reg B_ce0;
reg B_we0;
(* fsm_encoding = "none" *) reg [2:0] ap_CS_fsm;
wire ap_CS_fsm_state1;
reg [5:0] i_reg_70;
wire [5:0] add_ln4_fu_81_p2;
wire ap_CS_fsm_pp0_stage0;
reg ap_enable_reg_pp0_iter0;
wire ap_block_state2_pp0_stage0_iter0;
wire ap_block_state3_pp0_stage0_iter1;
wire ap_block_pp0_stage0_11001;
wire [0:0] icmp_ln4_fu_87_p2;
reg [0:0] icmp_ln4_reg_110;
wire [63:0] i_cast_fu_93_p1;
reg [63:0] i_cast_reg_114;
wire ap_block_pp0_stage0_subdone;
reg ap_condition_pp0_exit_iter0_state2;
reg ap_enable_reg_pp0_iter1;
wire ap_block_pp0_stage0;
wire ap_CS_fsm_state4;
reg [2:0] ap_NS_fsm;
reg ap_idle_pp0;
wire ap_enable_pp0;
wire ap_ce_reg;
// power-on initialization
initial begin
#0 ap_CS_fsm = 3'd1;
#0 ap_enable_reg_pp0_iter0 = 1'b0;
#0 ap_enable_reg_pp0_iter1 = 1'b0;
end
always @ (posedge ap_clk) begin
if (ap_rst == 1'b1) begin
ap_CS_fsm <= ap_ST_fsm_state1;
end else begin
ap_CS_fsm <= ap_NS_fsm;
end
end
always @ (posedge ap_clk) begin
if (ap_rst == 1'b1) begin
ap_enable_reg_pp0_iter0 <= 1'b0;
end else begin
if (((1'b0 == ap_block_pp0_stage0_subdone) & (1'b1 == ap_condition_pp0_exit_iter0_state2) & (1'b1 == ap_CS_fsm_pp0_stage0))) begin
ap_enable_reg_pp0_iter0 <= 1'b0;
end else if (((ap_start == 1'b1) & (1'b1 == ap_CS_fsm_state1))) begin
ap_enable_reg_pp0_iter0 <= 1'b1;
end
end
end
always @ (posedge ap_clk) begin
if (ap_rst == 1'b1) begin
ap_enable_reg_pp0_iter1 <= 1'b0;
end else begin
if (((1'b0 == ap_block_pp0_stage0_subdone) & (1'b1 == ap_condition_pp0_exit_iter0_state2))) begin
ap_enable_reg_pp0_iter1 <= (1'b1 ^ ap_condition_pp0_exit_iter0_state2);
end else if ((1'b0 == ap_block_pp0_stage0_subdone)) begin
ap_enable_reg_pp0_iter1 <= ap_enable_reg_pp0_iter0;
end else if (((ap_start == 1'b1) & (1'b1 == ap_CS_fsm_state1))) begin
ap_enable_reg_pp0_iter1 <= 1'b0;
end
end
end
always @ (posedge ap_clk) begin
if (((ap_start == 1'b1) & (1'b1 == ap_CS_fsm_state1))) begin
i_reg_70 <= 6'd0;
end else if (((icmp_ln4_fu_87_p2 == 1'd0) & (1'b0 == ap_block_pp0_stage0_11001) & (ap_enable_reg_pp0_iter0 == 1'b1) & (1'b1 == ap_CS_fsm_pp0_stage0))) begin
i_reg_70 <= add_ln4_fu_81_p2;
end
end
always @ (posedge ap_clk) begin
if (((icmp_ln4_fu_87_p2 == 1'd0) & (1'b0 == ap_block_pp0_stage0_11001) & (1'b1 == ap_CS_fsm_pp0_stage0))) begin
i_cast_reg_114[5 : 0] <= i_cast_fu_93_p1[5 : 0];
end
end
always @ (posedge ap_clk) begin
if (((1'b0 == ap_block_pp0_stage0_11001) & (1'b1 == ap_CS_fsm_pp0_stage0))) begin
icmp_ln4_reg_110 <= icmp_ln4_fu_87_p2;
end
end
always @ (*) begin
if (((1'b0 == ap_block_pp0_stage0_11001) & (ap_enable_reg_pp0_iter0 == 1'b1) & (1'b1 == ap_CS_fsm_pp0_stage0))) begin
A_ce0 = 1'b1;
end else begin
A_ce0 = 1'b0;
end
end
always @ (*) begin
if (((ap_enable_reg_pp0_iter1 == 1'b1) & (1'b0 == ap_block_pp0_stage0_11001) & (1'b1 == ap_CS_fsm_pp0_stage0))) begin
B_ce0 = 1'b1;
end else begin
B_ce0 = 1'b0;
end
end
always @ (*) begin
if (((ap_enable_reg_pp0_iter1 == 1'b1) & (icmp_ln4_reg_110 == 1'd0) & (1'b0 == ap_block_pp0_stage0_11001) & (1'b1 == ap_CS_fsm_pp0_stage0))) begin
B_we0 = 1'b1;
end else begin
B_we0 = 1'b0;
end
end
always @ (*) begin
if ((icmp_ln4_fu_87_p2 == 1'd1)) begin
ap_condition_pp0_exit_iter0_state2 = 1'b1;
end else begin
ap_condition_pp0_exit_iter0_state2 = 1'b0;
end
end
always @ (*) begin
if ((1'b1 == ap_CS_fsm_state4)) begin
ap_done = 1'b1;
end else begin
ap_done = 1'b0;
end
end
always @ (*) begin
if (((ap_start == 1'b0) & (1'b1 == ap_CS_fsm_state1))) begin
ap_idle = 1'b1;
end else begin
ap_idle = 1'b0;
end
end
always @ (*) begin
if (((ap_enable_reg_pp0_iter1 == 1'b0) & (ap_enable_reg_pp0_iter0 == 1'b0))) begin
ap_idle_pp0 = 1'b1;
end else begin
ap_idle_pp0 = 1'b0;
end
end
always @ (*) begin
if ((1'b1 == ap_CS_fsm_state4)) begin
ap_ready = 1'b1;
end else begin
ap_ready = 1'b0;
end
end
always @ (*) begin
case (ap_CS_fsm)
ap_ST_fsm_state1 : begin
if (((ap_start == 1'b1) & (1'b1 == ap_CS_fsm_state1))) begin
ap_NS_fsm = ap_ST_fsm_pp0_stage0;
end else begin
ap_NS_fsm = ap_ST_fsm_state1;
end
end
ap_ST_fsm_pp0_stage0 : begin
if (~((icmp_ln4_fu_87_p2 == 1'd1) & (1'b0 == ap_block_pp0_stage0_subdone) & (ap_enable_reg_pp0_iter0 == 1'b1))) begin
ap_NS_fsm = ap_ST_fsm_pp0_stage0;
end else if (((icmp_ln4_fu_87_p2 == 1'd1) & (1'b0 == ap_block_pp0_stage0_subdone) & (ap_enable_reg_pp0_iter0 == 1'b1))) begin
ap_NS_fsm = ap_ST_fsm_state4;
end else begin
ap_NS_fsm = ap_ST_fsm_pp0_stage0;
end
end
ap_ST_fsm_state4 : begin
ap_NS_fsm = ap_ST_fsm_state1;
end
default : begin
ap_NS_fsm = 'bx;
end
endcase
end
assign A_address0 = i_cast_fu_93_p1;
assign B_address0 = i_cast_reg_114;
assign B_d0 = (A_q0 + 32'd5);
assign add_ln4_fu_81_p2 = (i_reg_70 + 6'd1);
assign ap_CS_fsm_pp0_stage0 = ap_CS_fsm[32'd1];
assign ap_CS_fsm_state1 = ap_CS_fsm[32'd0];
assign ap_CS_fsm_state4 = ap_CS_fsm[32'd2];
assign ap_block_pp0_stage0 = ~(1'b1 == 1'b1);
assign ap_block_pp0_stage0_11001 = ~(1'b1 == 1'b1);
assign ap_block_pp0_stage0_subdone = ~(1'b1 == 1'b1);
assign ap_block_state2_pp0_stage0_iter0 = ~(1'b1 == 1'b1);
assign ap_block_state3_pp0_stage0_iter1 = ~(1'b1 == 1'b1);
assign ap_enable_pp0 = (ap_idle_pp0 ^ 1'b1);
assign i_cast_fu_93_p1 = i_reg_70;
assign icmp_ln4_fu_87_p2 = ((i_reg_70 == 6'd50) ? 1'b1 : 1'b0);
always @ (posedge ap_clk) begin
i_cast_reg_114[63:6] <= 58'b0000000000000000000000000000000000000000000000000000000000;
end
endmodule //adder5
AXI를 사용하여 구동하게 설계
Directive(#pragam)
- 컴퓨터나 운영체제별 확장성을 지원
- Vivado HLS에서 C/C++ 코드 내에 직접 삽입하여 합성기에게 특정 동작이나 최적화를 지시하는 역할
생성된 코드 복사하여 B엗 Directive 적용.
C synthesis
axi_adder5.v 파일 생성
// ==============================================================
// RTL generated by Vitis HLS - High-Level Synthesis from C, C++ and OpenCL v2020.2 (64-bit)
// Version: 2020.2
// Copyright (C) Copyright 1986-2020 Xilinx, Inc. All Rights Reserved.
//
// ===========================================================
`timescale 1 ns / 1 ps
(* CORE_GENERATION_INFO="adder5_adder5,hls_ip_2020_2,{HLS_INPUT_TYPE=cxx,HLS_INPUT_FLOAT=0,HLS_INPUT_FIXED=0,HLS_INPUT_PART=xc7z020-clg400-1,HLS_INPUT_CLOCK=10.000000,HLS_INPUT_ARCH=others,HLS_SYN_CLOCK=9.060000,HLS_SYN_LAT=52,HLS_SYN_TPT=none,HLS_SYN_MEM=4,HLS_SYN_DSP=0,HLS_SYN_FF=208,HLS_SYN_LUT=290,HLS_VERSION=2020_2}" *)
module adder5 (
ap_clk,
ap_rst_n,
ap_start,
ap_done,
ap_idle,
ap_ready,
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
);
parameter ap_ST_fsm_state1 = 3'd1;
parameter ap_ST_fsm_pp0_stage0 = 3'd2;
parameter ap_ST_fsm_state4 = 3'd4;
parameter C_S_AXI_CONTROL_DATA_WIDTH = 32;
parameter C_S_AXI_CONTROL_ADDR_WIDTH = 10;
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 ap_clk;
input ap_rst_n;
input ap_start;
output ap_done;
output ap_idle;
output ap_ready;
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;
reg ap_done;
reg ap_idle;
reg ap_ready;
reg ap_rst_n_inv;
(* fsm_encoding = "none" *) reg [2:0] ap_CS_fsm;
wire ap_CS_fsm_state1;
wire [5:0] A_address0;
reg A_ce0;
wire [31:0] A_q0;
wire [5:0] B_address0;
reg B_ce0;
reg B_we0;
wire [31:0] B_d0;
reg [5:0] i_reg_84;
wire [5:0] add_ln7_fu_95_p2;
wire ap_CS_fsm_pp0_stage0;
reg ap_enable_reg_pp0_iter0;
wire ap_block_state2_pp0_stage0_iter0;
wire ap_block_state3_pp0_stage0_iter1;
wire ap_block_pp0_stage0_11001;
wire [0:0] icmp_ln7_fu_101_p2;
reg [0:0] icmp_ln7_reg_124;
wire [63:0] i_cast_fu_107_p1;
reg [63:0] i_cast_reg_128;
wire ap_block_pp0_stage0_subdone;
reg ap_condition_pp0_exit_iter0_state2;
reg ap_enable_reg_pp0_iter1;
wire ap_block_pp0_stage0;
wire ap_CS_fsm_state4;
reg [2:0] ap_NS_fsm;
reg ap_idle_pp0;
wire ap_enable_pp0;
wire ap_ce_reg;
// power-on initialization
initial begin
#0 ap_CS_fsm = 3'd1;
#0 ap_enable_reg_pp0_iter0 = 1'b0;
#0 ap_enable_reg_pp0_iter1 = 1'b0;
end
adder5_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 ))
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),
.A_address0(A_address0),
.A_ce0(A_ce0),
.A_q0(A_q0),
.B_address0(B_address0),
.B_ce0(B_ce0),
.B_we0(B_we0),
.B_d0(B_d0)
);
always @ (posedge ap_clk) begin
if (ap_rst_n_inv == 1'b1) begin
ap_CS_fsm <= ap_ST_fsm_state1;
end else begin
ap_CS_fsm <= ap_NS_fsm;
end
end
always @ (posedge ap_clk) begin
if (ap_rst_n_inv == 1'b1) begin
ap_enable_reg_pp0_iter0 <= 1'b0;
end else begin
if (((1'b0 == ap_block_pp0_stage0_subdone) & (1'b1 == ap_CS_fsm_pp0_stage0) & (1'b1 == ap_condition_pp0_exit_iter0_state2))) begin
ap_enable_reg_pp0_iter0 <= 1'b0;
end else if (((1'b1 == ap_CS_fsm_state1) & (ap_start == 1'b1))) begin
ap_enable_reg_pp0_iter0 <= 1'b1;
end
end
end
always @ (posedge ap_clk) begin
if (ap_rst_n_inv == 1'b1) begin
ap_enable_reg_pp0_iter1 <= 1'b0;
end else begin
if (((1'b0 == ap_block_pp0_stage0_subdone) & (1'b1 == ap_condition_pp0_exit_iter0_state2))) begin
ap_enable_reg_pp0_iter1 <= (1'b1 ^ ap_condition_pp0_exit_iter0_state2);
end else if ((1'b0 == ap_block_pp0_stage0_subdone)) begin
ap_enable_reg_pp0_iter1 <= ap_enable_reg_pp0_iter0;
end else if (((1'b1 == ap_CS_fsm_state1) & (ap_start == 1'b1))) begin
ap_enable_reg_pp0_iter1 <= 1'b0;
end
end
end
always @ (posedge ap_clk) begin
if (((1'b1 == ap_CS_fsm_state1) & (ap_start == 1'b1))) begin
i_reg_84 <= 6'd0;
end else if (((icmp_ln7_fu_101_p2 == 1'd0) & (1'b0 == ap_block_pp0_stage0_11001) & (ap_enable_reg_pp0_iter0 == 1'b1) & (1'b1 == ap_CS_fsm_pp0_stage0))) begin
i_reg_84 <= add_ln7_fu_95_p2;
end
end
always @ (posedge ap_clk) begin
if (((icmp_ln7_fu_101_p2 == 1'd0) & (1'b0 == ap_block_pp0_stage0_11001) & (1'b1 == ap_CS_fsm_pp0_stage0))) begin
i_cast_reg_128[5 : 0] <= i_cast_fu_107_p1[5 : 0];
end
end
always @ (posedge ap_clk) begin
if (((1'b0 == ap_block_pp0_stage0_11001) & (1'b1 == ap_CS_fsm_pp0_stage0))) begin
icmp_ln7_reg_124 <= icmp_ln7_fu_101_p2;
end
end
always @ (*) begin
if (((1'b0 == ap_block_pp0_stage0_11001) & (ap_enable_reg_pp0_iter0 == 1'b1) & (1'b1 == ap_CS_fsm_pp0_stage0))) begin
A_ce0 = 1'b1;
end else begin
A_ce0 = 1'b0;
end
end
always @ (*) begin
if (((1'b0 == ap_block_pp0_stage0_11001) & (1'b1 == ap_CS_fsm_pp0_stage0) & (ap_enable_reg_pp0_iter1 == 1'b1))) begin
B_ce0 = 1'b1;
end else begin
B_ce0 = 1'b0;
end
end
always @ (*) begin
if (((icmp_ln7_reg_124 == 1'd0) & (1'b0 == ap_block_pp0_stage0_11001) & (1'b1 == ap_CS_fsm_pp0_stage0) & (ap_enable_reg_pp0_iter1 == 1'b1))) begin
B_we0 = 1'b1;
end else begin
B_we0 = 1'b0;
end
end
always @ (*) begin
if ((icmp_ln7_fu_101_p2 == 1'd1)) begin
ap_condition_pp0_exit_iter0_state2 = 1'b1;
end else begin
ap_condition_pp0_exit_iter0_state2 = 1'b0;
end
end
always @ (*) begin
if ((1'b1 == ap_CS_fsm_state4)) begin
ap_done = 1'b1;
end else begin
ap_done = 1'b0;
end
end
always @ (*) begin
if (((1'b1 == ap_CS_fsm_state1) & (ap_start == 1'b0))) begin
ap_idle = 1'b1;
end else begin
ap_idle = 1'b0;
end
end
always @ (*) begin
if (((ap_enable_reg_pp0_iter0 == 1'b0) & (ap_enable_reg_pp0_iter1 == 1'b0))) begin
ap_idle_pp0 = 1'b1;
end else begin
ap_idle_pp0 = 1'b0;
end
end
always @ (*) begin
if ((1'b1 == ap_CS_fsm_state4)) begin
ap_ready = 1'b1;
end else begin
ap_ready = 1'b0;
end
end
always @ (*) begin
case (ap_CS_fsm)
ap_ST_fsm_state1 : begin
if (((1'b1 == ap_CS_fsm_state1) & (ap_start == 1'b1))) begin
ap_NS_fsm = ap_ST_fsm_pp0_stage0;
end else begin
ap_NS_fsm = ap_ST_fsm_state1;
end
end
ap_ST_fsm_pp0_stage0 : begin
if (~((icmp_ln7_fu_101_p2 == 1'd1) & (1'b0 == ap_block_pp0_stage0_subdone) & (ap_enable_reg_pp0_iter0 == 1'b1))) begin
ap_NS_fsm = ap_ST_fsm_pp0_stage0;
end else if (((icmp_ln7_fu_101_p2 == 1'd1) & (1'b0 == ap_block_pp0_stage0_subdone) & (ap_enable_reg_pp0_iter0 == 1'b1))) begin
ap_NS_fsm = ap_ST_fsm_state4;
end else begin
ap_NS_fsm = ap_ST_fsm_pp0_stage0;
end
end
ap_ST_fsm_state4 : begin
ap_NS_fsm = ap_ST_fsm_state1;
end
default : begin
ap_NS_fsm = 'bx;
end
endcase
end
assign A_address0 = i_cast_fu_107_p1;
assign B_address0 = i_cast_reg_128;
assign B_d0 = (A_q0 + 32'd5);
assign add_ln7_fu_95_p2 = (i_reg_84 + 6'd1);
assign ap_CS_fsm_pp0_stage0 = ap_CS_fsm[32'd1];
assign ap_CS_fsm_state1 = ap_CS_fsm[32'd0];
assign ap_CS_fsm_state4 = ap_CS_fsm[32'd2];
assign ap_block_pp0_stage0 = ~(1'b1 == 1'b1);
assign ap_block_pp0_stage0_11001 = ~(1'b1 == 1'b1);
assign ap_block_pp0_stage0_subdone = ~(1'b1 == 1'b1);
assign ap_block_state2_pp0_stage0_iter0 = ~(1'b1 == 1'b1);
assign ap_block_state3_pp0_stage0_iter1 = ~(1'b1 == 1'b1);
assign ap_enable_pp0 = (ap_idle_pp0 ^ 1'b1);
always @ (*) begin
ap_rst_n_inv = ~ap_rst_n;
end
assign i_cast_fu_107_p1 = i_reg_84;
assign icmp_ln7_fu_101_p2 = ((i_reg_84 == 6'd50) ? 1'b1 : 1'b0);
always @ (posedge ap_clk) begin
i_cast_reg_128[63:6] <= 58'b0000000000000000000000000000000000000000000000000000000000;
end
endmodule //adder5
Open Wave Viewer
HLS에서
Solution > Export RTL
그 후 zip파일 풀기
Vivado 실행 후 새로운 프로젝트 생성.
Block design에서 zynq 7000 추가
configuration UART1 제외 MIO 다 끄기
repository 경로 추가 후 Adder5 추가
Run Connection Automation
IP module Constant 추가
adder5의 ap_start가 있어야 값이 들어감
Wrapper 생성
Generate Bitstream
Export Hardware
Vitis 실행 후 .xsa파일 로드, Empty Application으로 생성
src폴더에 main.c 파일 생성
#include <stdio.h>
#include "xil_types.h"
#include "xil_printf.h"
#include "xadder5_hw.h"
#include "xadder5.h"
int main()
{
static XAdder5 Adder5Instance_Ptr;
print("Start\n\r");
XAdder5_Initialize(&Adder5Instance_Ptr, XPAR_XADDER5_0_DEVICE_ID);
u32 data_A[50], data_B[50];
for (int i=0; i<50; i++) data_A[i]=i;
XAdder5_Write_A_Words(&Adder5Instance_Ptr, 0, data_A, 50);
XAdder5_Read_B_Words(&Adder5Instance_Ptr, 0, data_B, 50);
for (int i=0; i<50; i++) xil_printf("%d data_A=%d data_B=%d\n\r", i, data_A[i], data_B[i]);
print("End\n\r");
return 0;
}
Build
Terminal
Run
LAB7
top func 설정 후 run synthesis
test_adder.cpp 생성
#include <stdio.h>
void adder5(int A[50], int B[50]);
int main()
{
int i;
int A[50];
int B[50];
int C[50];
printf("HLS Flow with Adder example\n");
//Put data into A
for(i=0; i < 50; i++){
A[i] = i;
}
//Call the hardware function
adder5(A,B);
//Run a software version of the hardware function to validate results
for(i=0; i < 50; i++) {
C[i] = A[i] + 5;
}
//Compare results
for(i=0; i < 50; i++){
if(B[i] != C[i]){
printf("ERROR HW and SW results mismatch\n");
return 1;
}
}
printf("Success HW and SW results match\n");
return 0;
}
co-simulation 실행
Export RTL 실행
후에 zip 파일 압축 풀기
Vivado 열고 새 프로젝트
zynq 7000추가
Scatter Gather Engine 끄기
이건 Cache에서 읽어오는 Data의 주소가 연속적이지 않을 때 필요한 양만큼 연속적으로 가져오도록 함
Run Connection Automation 설정 후
adder5와 연결
Constant추가 후 Valid연결
Validate Design
Wrapper 생성
Generate Bitstream
Export Hareware (include bitstream)
Vitis 실행
main.c 생성
/***************************** Include Files *********************************/
#include "xaxidma.h"
#include "xparameters.h"
#include "xil_exception.h"
#include "xdebug.h"
#include "xscugic.h"
/************************** Constant Definitions *****************************/
/* Device hardware build related constants. */
#define DMA_DEV_ID XPAR_AXIDMA_0_DEVICE_ID
#define RX_INTR_ID XPAR_FABRIC_AXI_DMA_0_S2MM_INTROUT_INTR
#define TX_INTR_ID XPAR_FABRIC_AXI_DMA_0_MM2S_INTROUT_INTR
#define INTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID
#define INTC XScuGic
#define INTC_HANDLER XScuGic_InterruptHandler
/* Timeout loop counter for reset */
#define RESET_TIMEOUT_COUNTER 10000
/* Array length and the number of bytes to transfer */
#define ARRAY_LENGTH 50
#define BYTES_TO_TRANSFER 4*ARRAY_LENGTH
/************************** Function Prototypes ******************************/
#ifndef DEBUG
extern void xil_printf(const char *format, ...);
#endif
static void TxIntrHandler(void *Callback);
static void RxIntrHandler(void *Callback);
static int SetupIntrSystem(INTC * IntcInstancePtr,
XAxiDma * AxiDmaPtr, u16 TxIntrId, u16 RxIntrId);
static void DisableIntrSystem(INTC * IntcInstancePtr,
u16 TxIntrId, u16 RxIntrId);
/************************** Variable Definitions *****************************/
/*
* Device instance definitions
*/
static XAxiDma AxiDma; /* Instance of the XAxiDma */
static INTC Intc; /* Instance of the Interrupt Controller */
/*
* Flags interrupt handlers use to notify the application context the events.
*/
volatile int TxDone;
volatile int RxDone;
volatile int Error;
u32 TxBuffer[ARRAY_LENGTH];
u32 RxBuffer[ARRAY_LENGTH];
/*****************************************************************************/
/**
*
* Main function
*
* This function is the main entry of the interrupt test. It does the following:
* Set up the output terminal if UART16550 is in the hardware build
* Initialize the DMA engine
* Set up Tx and Rx channels
* Set up the interrupt system for the Tx and Rx interrupts
* Submit a transfer
* Wait for the transfer to finish
* Check transfer status
* Disable Tx and Rx interrupts
* Print test status and exit
*
* @param None
*
* @return
* - XST_SUCCESS if example finishes successfully
* - XST_FAILURE if example fails.
*
* @note None.
*
******************************************************************************/
void delay(void)
{
for(int i = 0 ; i < 1000 ; i++)
{}
}
int main(void)
{
int Status;
XAxiDma_Config *Config;
u32 i;
xil_printf("\r\n--- Entering main() --- \r\n");
Config = XAxiDma_LookupConfig(DMA_DEV_ID);
if (!Config) {
xil_printf("No config found for %d\r\n", DMA_DEV_ID);
return XST_FAILURE;
}
/* Initialize DMA engine */
Status = XAxiDma_CfgInitialize(&AxiDma, Config);
if (Status != XST_SUCCESS) {
xil_printf("Initialization failed %d\r\n", Status);
return XST_FAILURE;
}
if(XAxiDma_HasSg(&AxiDma)){
xil_printf("Device configured as SG mode \r\n");
return XST_FAILURE;
}
/* Set up Interrupt system */
Status = SetupIntrSystem(&Intc, &AxiDma, TX_INTR_ID, RX_INTR_ID);
if (Status != XST_SUCCESS) {
xil_printf("Failed intr setup\r\n");
return XST_FAILURE;
}
/* Disable all interrupts before setup */
XAxiDma_IntrDisable(&AxiDma, XAXIDMA_IRQ_ALL_MASK,
XAXIDMA_DMA_TO_DEVICE);
XAxiDma_IntrDisable(&AxiDma, XAXIDMA_IRQ_ALL_MASK,
XAXIDMA_DEVICE_TO_DMA);
/* Enable all interrupts */
XAxiDma_IntrEnable(&AxiDma, XAXIDMA_IRQ_ALL_MASK,
XAXIDMA_DMA_TO_DEVICE);
XAxiDma_IntrEnable(&AxiDma, XAXIDMA_IRQ_ALL_MASK,
XAXIDMA_DEVICE_TO_DMA);
/* Initialize flags before start transfer test */
TxDone = 0;
RxDone = 0;
Error = 0;
for(i = 0; i < ARRAY_LENGTH; i ++) {
TxBuffer[i] = i; // initialize TxBuffer
RxBuffer[i] = 0; // initialize RxBuffer with 0's
}
xil_printf("=========================================================\n");
for(i = 0; i < ARRAY_LENGTH; i++) {
xil_printf("TxBuffer[%d] = %d \r\n", i, TxBuffer[i]);
}
/* Flush the SrcBuffer before the DMA transfer, in case the Data Cache is enabled */
Xil_DCacheFlushRange((u32)TxBuffer, BYTES_TO_TRANSFER);
Status = XAxiDma_SimpleTransfer(&AxiDma,(u32) TxBuffer, BYTES_TO_TRANSFER, XAXIDMA_DMA_TO_DEVICE);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
delay();
Status = XAxiDma_SimpleTransfer(&AxiDma,(u32) RxBuffer, BYTES_TO_TRANSFER, XAXIDMA_DEVICE_TO_DMA);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
/* Wait TX done and RX done */
while (!TxDone && !RxDone && !Error) { /* NOP */ }
if (Error) {
xil_printf("Failed test transmit %s done, receive %s done\r\n", TxDone? "":" not", RxDone? "":" not");
}
/* Invalidate the DestBuffer before checking the data, in case the Data Cache is enabled */
Xil_DCacheInvalidateRange((u32)RxBuffer, BYTES_TO_TRANSFER);
xil_printf("=========================================================\n");
// check received data
for(i = 0; i < ARRAY_LENGTH; i++) {
if(RxBuffer[i] != i+5){
xil_printf("Error : RxBuffer[%d] = %d \r\n", i, RxBuffer[i]);}
else
xil_printf("RxBuffer[%d] = %d \r\n", i, RxBuffer[i]);
}
xil_printf("=========================================================\n");
xil_printf("AXI DMA interrupt example test passed\r\n");
/* Disable TX and RX Ring interrupts and return success */
DisableIntrSystem(&Intc, TX_INTR_ID, RX_INTR_ID);
return XST_SUCCESS;
}
/*****************************************************************************/
/*
*
* This is the DMA TX Interrupt handler function.
*
* It gets the interrupt status from the hardware, acknowledges it, and if any
* error happens, it resets the hardware. Otherwise, if a completion interrupt
* is present, then sets the TxDone.flag
*
* @param Callback is a pointer to TX channel of the DMA engine.
*
* @return None.
*
* @note None.
*
******************************************************************************/
static void TxIntrHandler(void *Callback)
{
u32 IrqStatus;
int TimeOut;
XAxiDma *AxiDmaInst = (XAxiDma *)Callback;
/* Read pending interrupts */
IrqStatus = XAxiDma_IntrGetIrq(AxiDmaInst, XAXIDMA_DMA_TO_DEVICE);
/* Acknowledge pending interrupts */
XAxiDma_IntrAckIrq(AxiDmaInst, IrqStatus, XAXIDMA_DMA_TO_DEVICE);
/*
* If no interrupt is asserted, we do not do anything
*/
if (!(IrqStatus & XAXIDMA_IRQ_ALL_MASK)) {
return;
}
/*
* If error interrupt is asserted, raise error flag, reset the
* hardware to recover from the error, and return with no further
* processing.
*/
if ((IrqStatus & XAXIDMA_IRQ_ERROR_MASK)) {
Error = 1;
/*
* Reset should never fail for transmit channel
*/
XAxiDma_Reset(AxiDmaInst);
TimeOut = RESET_TIMEOUT_COUNTER;
while (TimeOut) {
if (XAxiDma_ResetIsDone(AxiDmaInst)) {
break;
}
TimeOut -= 1;
}
return;
}
/*
* If Completion interrupt is asserted, then set the TxDone flag
*/
if ((IrqStatus & XAXIDMA_IRQ_IOC_MASK)) {
TxDone = 1;
}
}
/*****************************************************************************/
/*
*
* This is the DMA RX interrupt handler function
*
* It gets the interrupt status from the hardware, acknowledges it, and if any
* error happens, it resets the hardware. Otherwise, if a completion interrupt
* is present, then it sets the RxDone flag.
*
* @param Callback is a pointer to RX channel of the DMA engine.
*
* @return None.
*
* @note None.
*
******************************************************************************/
static void RxIntrHandler(void *Callback)
{
u32 IrqStatus;
int TimeOut;
XAxiDma *AxiDmaInst = (XAxiDma *)Callback;
/* Read pending interrupts */
IrqStatus = XAxiDma_IntrGetIrq(AxiDmaInst, XAXIDMA_DEVICE_TO_DMA);
/* Acknowledge pending interrupts */
XAxiDma_IntrAckIrq(AxiDmaInst, IrqStatus, XAXIDMA_DEVICE_TO_DMA);
/*
* If no interrupt is asserted, we do not do anything
*/
if (!(IrqStatus & XAXIDMA_IRQ_ALL_MASK)) {
return;
}
/*
* If error interrupt is asserted, raise error flag, reset the
* hardware to recover from the error, and return with no further
* processing.
*/
if ((IrqStatus & XAXIDMA_IRQ_ERROR_MASK)) {
Error = 1;
/* Reset could fail and hang
* NEED a way to handle this or do not call it??
*/
XAxiDma_Reset(AxiDmaInst);
TimeOut = RESET_TIMEOUT_COUNTER;
while (TimeOut) {
if(XAxiDma_ResetIsDone(AxiDmaInst)) {
break;
}
TimeOut -= 1;
}
return;
}
/*
* If completion interrupt is asserted, then set RxDone flag
*/
if ((IrqStatus & XAXIDMA_IRQ_IOC_MASK)) {
RxDone = 1;
}
}
/*****************************************************************************/
/*
*
* This function setups the interrupt system so interrupts can occur for the
* DMA, it assumes INTC component exists in the hardware system.
*
* @param IntcInstancePtr is a pointer to the instance of the INTC.
* @param AxiDmaPtr is a pointer to the instance of the DMA engine
* @param TxIntrId is the TX channel Interrupt ID.
* @param RxIntrId is the RX channel Interrupt ID.
*
* @return
* - XST_SUCCESS if successful,
* - XST_FAILURE.if not succesful
*
* @note None.
*
******************************************************************************/
static int SetupIntrSystem(INTC * IntcInstancePtr,
XAxiDma * AxiDmaPtr, u16 TxIntrId, u16 RxIntrId)
{
int Status;
#ifdef XPAR_INTC_0_DEVICE_ID
/* Initialize the interrupt controller and connect the ISRs */
Status = XIntc_Initialize(IntcInstancePtr, INTC_DEVICE_ID);
if (Status != XST_SUCCESS) {
xil_printf("Failed init intc\r\n");
return XST_FAILURE;
}
Status = XIntc_Connect(IntcInstancePtr, TxIntrId,
(XInterruptHandler) TxIntrHandler, AxiDmaPtr);
if (Status != XST_SUCCESS) {
xil_printf("Failed tx connect intc\r\n");
return XST_FAILURE;
}
Status = XIntc_Connect(IntcInstancePtr, RxIntrId,
(XInterruptHandler) RxIntrHandler, AxiDmaPtr);
if (Status != XST_SUCCESS) {
xil_printf("Failed rx connect intc\r\n");
return XST_FAILURE;
}
/* Start the interrupt controller */
Status = XIntc_Start(IntcInstancePtr, XIN_REAL_MODE);
if (Status != XST_SUCCESS) {
xil_printf("Failed to start intc\r\n");
return XST_FAILURE;
}
XIntc_Enable(IntcInstancePtr, TxIntrId);
XIntc_Enable(IntcInstancePtr, RxIntrId);
#else
XScuGic_Config *IntcConfig;
/*
* Initialize the interrupt controller driver so that it is ready to
* use.
*/
IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID);
if (NULL == IntcConfig) {
return XST_FAILURE;
}
Status = XScuGic_CfgInitialize(IntcInstancePtr, IntcConfig,
IntcConfig->CpuBaseAddress);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
XScuGic_SetPriorityTriggerType(IntcInstancePtr, TxIntrId, 0xA0, 0x3);
XScuGic_SetPriorityTriggerType(IntcInstancePtr, RxIntrId, 0xA0, 0x3);
/*
* Connect the device driver handler that will be called when an
* interrupt for the device occurs, the handler defined above performs
* the specific interrupt processing for the device.
*/
Status = XScuGic_Connect(IntcInstancePtr, TxIntrId,
(Xil_InterruptHandler)TxIntrHandler,
AxiDmaPtr);
if (Status != XST_SUCCESS) {
return Status;
}
Status = XScuGic_Connect(IntcInstancePtr, RxIntrId,
(Xil_InterruptHandler)RxIntrHandler,
AxiDmaPtr);
if (Status != XST_SUCCESS) {
return Status;
}
XScuGic_Enable(IntcInstancePtr, TxIntrId);
XScuGic_Enable(IntcInstancePtr, RxIntrId);
#endif
/* Enable interrupts from the hardware */
Xil_ExceptionInit();
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
(Xil_ExceptionHandler)INTC_HANDLER,
(void *)IntcInstancePtr);
Xil_ExceptionEnable();
return XST_SUCCESS;
}
/*****************************************************************************/
/**
*
* This function disables the interrupts for DMA engine.
*
* @param IntcInstancePtr is the pointer to the INTC component instance
* @param TxIntrId is interrupt ID associated w/ DMA TX channel
* @param RxIntrId is interrupt ID associated w/ DMA RX channel
*
* @return None.
*
* @note None.
*
******************************************************************************/
static void DisableIntrSystem(INTC * IntcInstancePtr,
u16 TxIntrId, u16 RxIntrId)
{
#ifdef XPAR_INTC_0_DEVICE_ID
/* Disconnect the interrupts for the DMA TX and RX channels */
XIntc_Disconnect(IntcInstancePtr, TxIntrId);
XIntc_Disconnect(IntcInstancePtr, RxIntrId);
#else
XScuGic_Disconnect(IntcInstancePtr, TxIntrId);
XScuGic_Disconnect(IntcInstancePtr, RxIntrId);
#endif
}
Build > Run
'Circuit Design > 🔥HDL' 카테고리의 다른 글
[후기] SEDEX 반도체 대전 2024 (1) | 2024.10.27 |
---|---|
[Verilog] Verilog를 이용한 AI 설계 응용 및 SoC 설계 (2) (0) | 2024.09.29 |
[Verilog] Verilog를 이용한 AI 설계 응용 및 SoC 설계 (1) (0) | 2024.09.25 |
[Verilog] 27. Counter (0) | 2024.08.23 |
[Verilog] 26. SPI - AXI Portfolio (0) | 2024.08.23 |