【FPGA项目】System Generator算法板级验证-快速搭建外围测试电路

news2024/11/23 6:56:12

🎉欢迎来到FPGA专栏~System Generator算法板级验证-快速搭建外围测试电路


  • ☆* o(≧▽≦)o *☆~我是小夏与酒🍹
  • 博客主页:小夏与酒的博客
  • 🎈该系列文章专栏:FPGA学习之旅
  • 文章作者技术和水平有限,如果文中出现错误,希望大家能指正🙏
  • 📜 欢迎大家关注! ❤️
    FPGQ2

CSDN

🎉 目录-System Generator算法板级验证-快速搭建外围测试电路

  • 一、效果演示
    • 🔸项目介绍
    • 🔸项目演示效果
    • 🔸操作过程演示
  • 二、说明
  • 三、Matlab数据存为bin文件
  • 四、串口收发模块
  • 五、系统各模块详细说明

遇见未来

一、效果演示

🔸项目介绍

使用System Generator搭建算法时,为了快速进行算法正确性的板级验证,只需要将算法的算法时钟端口数据输入端口结果输出端口保留,如下图所示:
sysgen
为了控制算法模块,需要实现数据输入的控制算法启动数据输出的控制等。本篇文章搭建简单的外围电路实现对sysgen算法的控制和执行。

🔸项目演示效果

在本项目中,使用Verilog HDL编写了一个和使用System Generator搭建的算法模块类似的模块,该模块实现的功能是对输入的两个32位的非负整型数据进行相加。该模块有时钟端口复位端口两个数据输入端口一个数据输出端口,如下图所示:
算法模块
使用matlab生成两组1-100随机非负整数,每组数据的个数为100个两组数据以及两组数据对应数据之和的波形绘图如下所示:
matlab
将两组数据存为bin文件并输入到FPGA中执行求和算法,将算法执行结果导出进行数据进制转换并使用matlab画图得到的结果如下所示:
FPGA结果
将FPGA运算得到的结果与matlab运算得到的结果进行对比,算法执行结果一致,如下图所示:
最终结果
本项目的完整系统包括时钟模块、vio控制、串口收发模块、计数器模块、ram控制模块、算法使能模块和算法模块。FPGA系统的RTL视图如下所示:
RTL

🔸操作过程演示

FPGA开发板与电脑连接:
实际连接图
系统串口波特率为115200

项目主要使用到vio控制串口助手收发数据,串口将bin文件数据发送给FPGA并存入到ram1ram2中,运行算法之后的结果存储到ram3中,通过控制从串口将结果数据读出。vio使用4个输出信号控制系统:信号1置为高电平时,存入第一组bin文件数据到ram1中;信号2置为高电平时,存入第二组bin文件数据到ram2中;信号3置为高电平时,执行sysgen算法模块信号4置为高电平时,将ram3中的结果数据通过串口读取出来。操作过程视频如下所示:

【FPGA项目】System Generator算法板级验证

二、说明

本项目基于《【FPGA项目】bin文件ram存取回环测试》来搭建完整的板级验证系统,建议小伙伴们可以先学习该篇文章的知识点。

需要该项目中的串口助手软件或者项目工程文件的小伙伴,直接加入QQ群,在群文件中搜索下载即可QQ群862135231
matlab版本:R2020b
vivado版本:2020.2
开发板型号:AXKU040
接口连接如下所示:
接口
工程文件目录结构如下所示:
目录结构

三、Matlab数据存为bin文件

关于bin文件的介绍和使用bin文件存储数据的原因,在该篇文章中已经做了讲解:《【FPGA项目】bin文件ram存取回环测试》。

通过串口将sysgen算法模块的运行结果导出时,串口助手可以将数据保存为hex格式,需要对数据进行简单的处理,再通过matlab将十六进制的结果数据转换成十进制即可。

本项目中的matlab代码如下,根据需要运行相关代码片段即可:

%% bin文件生成代码:生成两个随机波形数据的bin文件
%----------------------------------------------------
% 首先生成1-100的double类型随机整数;
% 将double类型随机整数转换为32位数据;
% 将转换后的数据保存为bin文件。
%----------------------------------------------------
clear;
clc;
close all;
% 生成1-100的double类型随机整数
random_data1 = randi([1 100], 1, 100);
random_data2 = randi([1 100], 1, 100);

% 将double类型数据转换为uint32类型
random_data1_uint32 = uint32(random_data1);
random_data2_uint32 = uint32(random_data2);

% 画图
figure;
x = 0:1:100-1;
subplot(3,1,1);
plot(x,random_data1_uint32,'b');
title('random data1');
grid on;

subplot(3,1,2);
plot(x,random_data2_uint32,'g');
title('random data2');
grid on;

subplot(3,1,3);
plot(x,random_data1_uint32+random_data2_uint32,'r');
title('random data1 + random data2');
grid on;

% 将数据保存为bin文件
fid = fopen('random_data1.bin', 'wb');
fwrite(fid, random_data1_uint32, 'uint32');
fclose(fid);
fid = fopen('random_data2.bin', 'wb');
fwrite(fid, random_data2_uint32, 'uint32');
fclose(fid);

disp('波形数据已生成并保存为random_data1.bin和random_data2.bin');

%% 读取txt文档中的数据,并转换成十进制
file_path = 'Rec240626210210.txt'; % 替换为实际文件路径
fileId = fopen(file_path, 'r');

hex_values = cell(100, 1);
for i = 1:100
    hex_values{i} = fgetl(fileId);
end

fclose(fileId);
dec_values = hex2dec(hex_values);

figure;
x = 0:1:100-1;
plot(x,dec_values);
title('FPGA');
grid on;

% 画图
figure;
x = 0:1:100-1;
subplot(4,1,1);
plot(x,random_data1_uint32,'b');
title('random data1');
grid on;

subplot(4,1,2);
plot(x,random_data2_uint32,'g');
title('random data2');
grid on;

subplot(4,1,3);
plot(x,random_data1_uint32+random_data2_uint32,'r');
title('random data1 + random data2');
grid on;

subplot(4,1,4);
plot(x,dec_values);
title('FPGA');
grid on;

四、串口收发模块

整个sysgen算法的验证都是通过vio和串口来实现的。

关于串口收发模块的详细讲解,请点击如下两篇文章进行学习:
串口发送模块:【FPGA零基础学习之旅#13】串口发送模块设计与验证;
串口接收模块:【FPGA零基础学习之旅#15】串口接收模块设计与验证(工业环境)。

在此附上模块代码:

串口发送模块:

//
//模块名称:串口发送模块
//
module uart_byte_tx(
	input 		Clk,
	input 		Rst_n,
	input [7:0]	data_byte,
	input 		send_en,
	input [2:0]	baud_set,
	
	output reg uart_tx,
	output reg Tx_Done,
	output reg uart_state
);

	reg bps_clk;//波特率时钟
	
	reg [15:0]div_cnt;//分频计数器
		
	reg [15:0]bps_DR;//分频计数最大值
	
	reg [3:0]bps_cnt;//波特率计数时钟
		
	//定义数据的起始位和停止位
	localparam START_BIT = 1'b0;
	localparam STOP_BIT  = 1'b1;
	
	reg [7:0]r_data_byte;//数据寄存器
	
//--------<uart状态模块>--------	
	always@(posedge Clk or negedge Rst_n)begin
		if(!Rst_n)
			uart_state <= 1'b0;
		else if(send_en)
			uart_state <= 1'b1;
		else if(bps_cnt == 4'd11)//bps_cnt计数达到11次,即发送结束
			uart_state <= 1'b0;
		else
			uart_state <= uart_state;
	end

//--------<使能分频计数模块>-------	
//	assign en_cnt = uart_state;
	
//--------<寄存待发送的数据,使数据保持稳定>--------
	always@(posedge Clk or negedge Rst_n)begin
		if(!Rst_n)
			r_data_byte <= 8'd0;
		else if(send_en)
			r_data_byte <= data_byte;
		else
			r_data_byte <= r_data_byte;
	end
	
//--------<波特率查找表>--------		
	always@(posedge Clk or negedge Rst_n)begin
		if(!Rst_n)
			bps_DR <= 16'd5207;
		else begin
			case(baud_set)
				0:bps_DR <= 16'd5207;
				1:bps_DR <= 16'd2603;
				2:bps_DR <= 16'd1301;
				3:bps_DR <= 16'd867;
				4:bps_DR <= 16'd433;
				default:bps_DR <= 16'd5207;
			endcase
		end	
	end
	
//--------<Div_Cnt模块>--------	
//得到不同计数周期的计数器
	always@(posedge Clk or negedge Rst_n)begin
		if(!Rst_n)
			div_cnt <= 16'd0;
		else if(uart_state)begin	//	assign en_cnt = uart_state;
			if(div_cnt == bps_DR)
				div_cnt <= 16'd0;
			else
				div_cnt <= div_cnt + 1'b1;
		end
		else
			div_cnt <= 16'd0;
	end
//--------<bps_clk信号的产生>--------	
	always@(posedge Clk or negedge Rst_n)begin
		if(!Rst_n)
			bps_clk <= 1'b0;
		else if(div_cnt == 16'd1)
			bps_clk <= 1'b1;
		else
			bps_clk <= 1'b0;
	end
	
//--------<bps_cnt计数模块>--------		
	always@(posedge Clk or negedge Rst_n)begin
		if(!Rst_n)
			bps_cnt <= 4'd0;
		else if(bps_cnt == 4'd11)//clr信号
			bps_cnt <= 4'd0;
		else if(bps_clk)
			bps_cnt <= bps_cnt + 1'b1;
		else
			bps_cnt <= bps_cnt;
	end

//--------<Tx_Done模块>--------	
	always@(posedge Clk or negedge Rst_n)begin
		if(!Rst_n)
			Tx_Done <= 1'b0;
		else if(bps_cnt == 4'd11)
			Tx_Done <= 1'b1;
		else
			Tx_Done <= 1'b0;
	end
	
//--------<数据位输出模块-10选1多路器>--------	
	always@(posedge Clk or negedge Rst_n)begin
		if(!Rst_n)
			uart_tx <= 1'b1;
		else begin
			case(bps_cnt)
				0:uart_tx <= 1'b1;
				1:uart_tx <= START_BIT;
				2:uart_tx <= r_data_byte[0];
				3:uart_tx <= r_data_byte[1];
				4:uart_tx <= r_data_byte[2];
				5:uart_tx <= r_data_byte[3];
				6:uart_tx <= r_data_byte[4];
				7:uart_tx <= r_data_byte[5];
				8:uart_tx <= r_data_byte[6];
				9:uart_tx <= r_data_byte[7];
				10:uart_tx <= STOP_BIT;
				default:uart_tx <= 1'b1;
			endcase
		end
	end
	
endmodule

串口接收模块:

//
//模块名称:串口接收模块(工业环境)
//
module uart_byte_rx(
	input 					Clk,//50M
	input 					Rst_n,
	input 			[2:0]	baud_set,
	input 					data_rx,
	output 	reg 	[7:0]	data_byte,
	output 	reg			Rx_Done
);

	reg s0_Rx,s1_Rx;//同步寄存器
	
	reg tmp0_Rx,tmp1_Rx;//数据寄存器
	
	reg [15:0]bps_DR;//分频计数器计数最大值
	reg [15:0]div_cnt;//分频计数器
	reg bps_clk;//波特率时钟
	reg [7:0]bps_cnt;
	
	reg uart_state;
	
	reg [2:0] r_data_byte [7:0];
	
	reg [2:0]START_BIT;
	reg [2:0]STOP_BIT;
	
	wire nedge;
	
//--------<同步寄存器处理>--------		
//用于消除亚稳态
	always@(posedge Clk or negedge Rst_n)begin
		if(!Rst_n)begin
			s0_Rx <= 1'b0;
			s1_Rx <= 1'b0;
		end
		else begin
			s0_Rx <= data_rx;
			s1_Rx <= s0_Rx;
		end
	end
	
//--------<数据寄存器处理>--------		
	always@(posedge Clk or negedge Rst_n)begin
		if(!Rst_n)begin
			tmp0_Rx <= 1'b0;
			tmp1_Rx <= 1'b0;
		end
		else begin
			tmp0_Rx <= s1_Rx;
			tmp1_Rx <= tmp0_Rx;
		end
	end
	
//--------<下降沿检测>--------	
	assign nedge = !tmp0_Rx & tmp1_Rx;
	
//--------<div_cnt模块>--------	
//得到不同计数周期的计数器
	always@(posedge Clk or negedge Rst_n)begin
		if(!Rst_n)
			div_cnt <= 16'd0;
		else if(uart_state)begin
			if(div_cnt == bps_DR)
				div_cnt <= 16'd0;
			else
				div_cnt <= div_cnt + 1'b1;
		end
		else
			div_cnt <= 16'd0;
	end
//--------<bps_clk信号的产生>--------	
	always@(posedge Clk or negedge Rst_n)begin
		if(!Rst_n)
			bps_clk <= 1'b0;
		else if(div_cnt == 16'd1)
			bps_clk <= 1'b1;
		else
			bps_clk <= 1'b0;
	end
	
//--------<bps_clk计数模块>--------		
	always@(posedge Clk or negedge Rst_n)begin
		if(!Rst_n)
			bps_cnt <= 8'd0;
		else if(bps_cnt == 8'd159 || (bps_cnt == 8'd12 && (START_BIT > 2)))
			bps_cnt <= 8'd0;
		else if(bps_clk)
			bps_cnt <= bps_cnt + 1'b1;
		else
			bps_cnt <= bps_cnt;
	end
	
//--------<Rx_Done模块>--------	
	always@(posedge Clk or negedge Rst_n)begin
		if(!Rst_n)
			Rx_Done <= 1'b0;
		else if(bps_cnt == 8'd159)
			Rx_Done <= 1'b1;
		else
			Rx_Done <= 1'b0;
	end	
	
//--------<波特率查找表>--------		
	always@(posedge Clk or negedge Rst_n)begin
		if(!Rst_n)
			bps_DR <= 16'd324;
		else begin
			case(baud_set)
				0:bps_DR <= 16'd324;
				1:bps_DR <= 16'd162;
				2:bps_DR <= 16'd80;
				3:bps_DR <= 16'd53;
				4:bps_DR <= 16'd26;
				default:bps_DR <= 16'd324;
			endcase
		end	
	end

//--------<采样数据接收模块>--------	
	always@(posedge Clk or negedge Rst_n)begin
		if(!Rst_n)begin
			START_BIT <= 3'd0;
			r_data_byte[0] <= 3'd0; 
			r_data_byte[1] <= 3'd0;
			r_data_byte[2] <= 3'd0; 
			r_data_byte[3] <= 3'd0;
			r_data_byte[4] <= 3'd0; 
			r_data_byte[5] <= 3'd0;
			r_data_byte[6] <= 3'd0; 
			r_data_byte[7] <= 3'd0;
			STOP_BIT <= 3'd0;
		end
		else if(bps_clk)begin
			case(bps_cnt)
				0:begin
					START_BIT <= 3'd0;
					r_data_byte[0] <= 3'd0;
					r_data_byte[1] <= 3'd0;
					r_data_byte[2] <= 3'd0;
					r_data_byte[3] <= 3'd0;
					r_data_byte[4] <= 3'd0;
					r_data_byte[5] <= 3'd0;
					r_data_byte[6] <= 3'd0;
					r_data_byte[7] <= 3'd0;
					STOP_BIT <= 3'd0; 
				end
				6,7,8,9,10,11:START_BIT <= START_BIT + s1_Rx;
				22,23,24,25,26,27:r_data_byte[0] <= r_data_byte[0] + s1_Rx;
				38,39,40,41,42,43:r_data_byte[1] <= r_data_byte[1] + s1_Rx;
				54,55,56,57,58,59:r_data_byte[2] <= r_data_byte[2] + s1_Rx;
				70,71,72,73,74,75:r_data_byte[3] <= r_data_byte[3] + s1_Rx;
				86,87,88,89,90,91:r_data_byte[4] <= r_data_byte[4] + s1_Rx;
				102,103,104,105,106,107:r_data_byte[5] <= r_data_byte[5] + s1_Rx;
				118,119,120,121,122,123:r_data_byte[6] <= r_data_byte[6] + s1_Rx;
				134,135,136,137,138,139:r_data_byte[7] <= r_data_byte[7] + s1_Rx;
				150,151,152,153,154,155:STOP_BIT <= STOP_BIT + s1_Rx;
				default:begin
					START_BIT <= START_BIT;
					r_data_byte[0] <= r_data_byte[0];
					r_data_byte[1] <= r_data_byte[1];
					r_data_byte[2] <= r_data_byte[2];
					r_data_byte[3] <= r_data_byte[3];
					r_data_byte[4] <= r_data_byte[4];
					r_data_byte[5] <= r_data_byte[5];
					r_data_byte[6] <= r_data_byte[6];
					r_data_byte[7] <= r_data_byte[7];
					STOP_BIT <= STOP_BIT;
				end
			endcase
		end
	end

//--------<数据状态判定模块>--------	
	always@(posedge Clk or negedge Rst_n)begin
		if(!Rst_n)
			data_byte <= 8'd0;
		else if(bps_cnt == 8'd159)begin
			data_byte[0] <= r_data_byte[0][2];
			data_byte[1] <= r_data_byte[1][2];
			data_byte[2] <= r_data_byte[2][2];
			data_byte[3] <= r_data_byte[3][2];
			data_byte[4] <= r_data_byte[4][2];
			data_byte[5] <= r_data_byte[5][2];
			data_byte[6] <= r_data_byte[6][2];
			data_byte[7] <= r_data_byte[7][2];
		end
		else
			;
	end

//--------<uart_state模块>--------	
	always@(posedge Clk or negedge Rst_n)begin
		if(!Rst_n)
			uart_state <= 1'b0;
		else if(nedge)
			uart_state <= 1'b1;
		else if(Rx_Done || (bps_cnt == 8'd12 && (START_BIT > 2)))
			uart_state <= 1'b0;
		else
			uart_state <= uart_state;
	end

endmodule

五、系统各模块详细说明

本项目的完整系统包括时钟模块、vio控制、串口收发模块、计数器模块、ram控制模块、算法使能模块和算法模块。FPGA系统的RTL视图如下所示:
RTL
🔸时钟模块:
时钟模块

信号端口功能
rst_n复位
sys_clk_n200MHz差分时钟输入
sys_clk_p200MHz差分时钟输入
clk_50MHz输出50MHz时钟信号
clk_200MHz输出200MHz时钟信号

时钟模块的核心是pll ip核,为了使系统时钟更加稳定,将pll和外围电路封装为一个时钟模块,代码如下:

clk_200MHz_50MHz.v:

`timescale 1ns / 1ps

module clk_200MHz_50MHz(
  input 	sys_clk_p,
  input 	sys_clk_n,
  input	    rst_n,
  output 	clk_200MHz,
  output 	clk_50MHz
);

	wire clk_200MHz_r;
	wire clk_50MHz_r;

	wire locked;

	pll_200MHz_50MHz pll_200MHz_50MHz
   (
        // Clock out ports
        .clk_out1(clk_200MHz_r), //200MHz
        .clk_out2(clk_50MHz_r),  //50MHz
        // Status and control signals
        .resetn(rst_n),
        .locked(locked),
        // Clock in ports
        .clk_in1_p(sys_clk_p),
        .clk_in1_n(sys_clk_n) 
    );

   assign clk_200MHz = (locked)?clk_200MHz_r:1'b0;
   assign clk_50MHz  = (locked)?clk_50MHz_r :1'b0;

endmodule

🔸vio控制:
vio
vio ip核四个输出端口的信号作用如上文中所述:

vio使用4个输出信号控制系统:信号1置为高电平时,存入第一组bin文件数据到ram1中;信号2置为高电平时,存入第二组bin文件数据到ram2中;信号3置为高电平时,执行sysgen算法模块信号4置为高电平时,将ram3中的结果数据通过串口读取出来。

🔸串口收发模块:
串口收发模块在本文的第四节(“四、串口收发模块”)中已提及,收发模块端口如下图所示:
r'x
t'x

🔸计数器模块:
计数器模块

信号端口功能
rst_n复位
clk_200MHz输入200MHz时钟信号
all_cnt_times输入计数器的计数总数
probe_out3计数器使能控制信号(来自vio)
all_cnt输出计数器当前的计数值

计数器模块的作用: 用来控制sysgen算法模块运行的时钟周期数。如输入计数总数为32’d100,则sysgen模块执行100个时钟周期。当计数器计数到输入的计数总数时,计数器的值保持不变,该模块代码如下:

cnt.v:

`timescale 1ns / 1ps

module cnt(
    input                   clk_200MHz,
    input                   rst_n,
    input                   probe_out3,
    input       [32-1:0]    all_cnt_times,
    output reg  [32-1:0]    all_cnt
);

	always@(posedge clk_200MHz or negedge rst_n)begin
        if(!rst_n)
            all_cnt <= 32'd0;
        else if(probe_out3 && all_cnt < all_cnt_times)
            all_cnt <= all_cnt + 1'b1;
        else if(probe_out3 && all_cnt == all_cnt_times)
            all_cnt <= all_cnt_times;
        else
            all_cnt <= all_cnt;
    end

endmodule

🔸ram控制模块:
ram控制模块主要包括两个输入bin文件存储模块一个运算结果保存模块
输入bin文件存储模块——re:
re

ram_re_ctrl.v:

`timescale 1ns / 1ps

module ram_re_ctrl(
    input               clk_50MHz,
    input               clk_200MHz,
    input               rst_n,
    input               probe_out1,
    input   [7:0]       data_byte_rx,
    input               Rx_Done,
    input   [32-1:0]    all_cnt,
    input               probe_out3,
    output  [32-1:0]    doutb_re
);
    
    reg     [17-1:0]    addra_re;
    wire    [8-1:0]     dina_re;

    always@(posedge clk_50MHz or negedge rst_n)begin
        if(!rst_n)
            addra_re <= 17'd0;
        else if(probe_out1 && Rx_Done)
            addra_re <= addra_re + 1'b1;
        else
            addra_re <= addra_re;
    end

	assign dina_re = (probe_out1)?data_byte_rx:8'b0;

    ram_re ram_re
    (
        .clka(clk_50MHz),    // input wire clka
        .ena(probe_out1),      // input wire ena
        .wea(Rx_Done),      // input wire [0 : 0] wea
        .addra(addra_re),  // input wire [16 : 0] addra
        .dina(dina_re),    // input wire [7 : 0] dina
        .clkb(clk_200MHz),    // input wire clkb
        .enb(probe_out3),      // input wire enb
        .addrb(all_cnt),  // input wire [14 : 0] addrb
        .doutb(doutb_re)  // output wire [31 : 0] doutb
    );

endmodule

输入bin文件存储模块——im:
im

ram_im_ctrl.v:

`timescale 1ns / 1ps

module ram_im_ctrl(
    input               clk_50MHz,
    input               clk_200MHz,
    input               rst_n,
    input               probe_out2,
    input   [7:0]       data_byte_rx,
    input               Rx_Done,
    input   [32-1:0]    all_cnt,
    input               probe_out3,
    output  [32-1:0]    doutb_im
);
    
    reg     [17-1:0]    addra_im;
    wire    [8-1:0]     dina_im;

    always@(posedge clk_50MHz or negedge rst_n)begin
        if(!rst_n)
            addra_im <= 17'd0;
        else if(probe_out2 && Rx_Done)
            addra_im <= addra_im + 1'b1;
        else
            addra_im <= addra_im;
    end

	assign dina_im = (probe_out2)?data_byte_rx:8'b0;

    ram_im ram_im
    (
        .clka(clk_50MHz),    // input wire clka
        .ena(probe_out2),      // input wire ena
        .wea(Rx_Done),      // input wire [0 : 0] wea
        .addra(addra_im),  // input wire [16 : 0] addra
        .dina(dina_im),    // input wire [7 : 0] dina
        .clkb(clk_200MHz),    // input wire clkb
        .enb(probe_out3),      // input wire enb
        .addrb(all_cnt),  // input wire [14 : 0] addrb
        .doutb(doutb_im)  // output wire [31 : 0] doutb
    );
    
endmodule

运算结果保存模块:
result
该模块端口中有一个信号端口为:delay_cnt_times,该信号的作用是延迟存储数据。如输入32‘d10给该信号端口,则会在sysgen模块运行10个时钟周期后才存储sysgen模块的运算结果到ram3中。

ram_result_ctrl.v:

`timescale 1ns / 1ps

module ram_result_ctrl(
    input               clk_50MHz,
    input               clk_200MHz,
    input               rst_n,
    input               probe_out3,
    input               probe_out4,
    input   [32-1:0]    delay_cnt_times,
    input   [32-1:0]    all_cnt_times,
    input   [32-1:0]    all_cnt,
    input               Tx_Done,
    input   [32-1:0]    dina_ot,
    output              send_en,
    output  [7:0]       data_byte_tx
);
    
    reg          wea_result;
    reg          rea_result;

    reg [32-1:0] delay_cnt;

    reg [9:0]   addra_ot;
    reg [11:0]  addrb_ot;
    reg [7:0]   doutb_ot;

    always@(posedge clk_200MHz or negedge rst_n)begin
        if(!rst_n)
            delay_cnt <= 32'd0;
        else if(probe_out3 && delay_cnt < delay_cnt_times)
            delay_cnt <= delay_cnt + 1'b1;
        else if(probe_out3 && delay_cnt == delay_cnt_times)
            delay_cnt <= delay_cnt_times;
        else
            delay_cnt <= delay_cnt;
    end

    always@(posedge clk_200MHz or negedge rst_n)begin
        if(!rst_n)
            wea_result <= 1'b0;
        else if(probe_out3 && delay_cnt == delay_cnt_times && all_cnt != all_cnt_times)
            wea_result <= 1'b1;
        else
            wea_result <= 1'b0;
    end

    always@(posedge clk_200MHz or negedge rst_n)begin
        if(!rst_n)
            addra_ot <= 10'd0;
        else if(wea_result)
            addra_ot <= addra_ot + 1'b1;
        else
            addra_ot <= addra_ot;
    end

    ram_result ram_result
    (
        .clka(clk_200MHz),    // input wire clka
        .ena(probe_out3),      // input wire ena
        .wea(wea_result),      // input wire [0 : 0] wea
        .addra(addra_ot),  // input wire [7 : 0] addra
        .dina(dina_ot),    // input wire [31 : 0] dina
        .clkb(clk_50MHz),    // input wire clkb
        .enb(rea_result),      // input wire enb
        .addrb(addrb_ot),  // input wire [9 : 0] addrb
        .doutb(data_byte_tx)  // output wire [7 : 0] doutb
    );

    always@(posedge clk_50MHz or negedge rst_n)begin
        if(!rst_n)
            rea_result <= 1'b0;
        else if(probe_out4 && addrb_ot < 11'd2000)
            rea_result <= 1'b1;
        else if(addrb_ot == 11'd2000)
            rea_result <= 1'b0;
        else
            rea_result <= rea_result;
    end

    assign send_en = rea_result;

    always@(posedge clk_50MHz or negedge rst_n)begin
        if(!rst_n)
            addrb_ot <= 10'd0;
        else if(rea_result && Tx_Done)
            addrb_ot <= addrb_ot + 1'b1;
        else
            addrb_ot <= addrb_ot;
    end
    
endmodule

🔸算法模块:
算法模块

信号端口功能
rst_n复位
sys_clk输入算法模块时钟信号
input_data1输入算法数据1
input_data2输入算法数据2
output_data输出算法执行结果

算法模块只实现简单的32位无符号整型数据相加,代码如下:

sysgen.v:

`timescale 1ns / 1ps

module sysgen(
	input 					sys_clk,//200MHz
	input 					rst_n,
	input 		[32-1:0] 	input_data1,
	input 		[32-1:0] 	input_data2,
	output 	reg [32-1:0] 	output_data
);

	always@(posedge sys_clk or negedge rst_n)begin
		if(!rst_n)
			output_data <= 32'd0;
		else
			output_data <= input_data1 + input_data2;
	end

endmodule

🔸算法使能模块:
算法使能模块

信号端口功能
rst_n复位
sys_clk输入算法模块时钟信号
input_data1输入算法数据1

为了快速对sysgen算法进行板级验证,在搭建sysgen的时候只需保留数据端口时钟端口即可。因此,要控制算法的启动、暂停或停止,只能通过控制sysgen模块的时钟端口来实现,算法使能模块代码如下:

sysgen_clk_en.v:

`timescale 1ns / 1ps

module sysgen_clk_en(
	input 	clk_200MHz,
	input 	probe_out3,
	output 	sysgen_clk
);

	assign sysgen_clk = (probe_out3)?clk_200MHz:1'b0;

endmodule

🔸顶层模块:

uart_io.v:

`timescale 1ns / 1ps

module uart_io(
    input 	sys_clk_p,
	input 	sys_clk_n,
	input 	rst_n,
	input 	uart_rx,
	output 	uart_tx
);

    localparam baud_bps = 3'b100;//115200

    localparam delay_cnt_times = 32'd1;
	localparam all_cnt_times   = 32'd102;

	wire clk_200MHz;
	wire clk_50MHz;

	wire [7:0] data_byte_rx;
	wire [7:0] data_byte_tx;

	wire Tx_Done;
	wire Rx_Done;

    wire probe_out1;
    wire probe_out2;
    wire probe_out3;
    wire probe_out4;

    wire [32-1:0] all_cnt;
    wire [32-1:0] doutb_re;
    wire [32-1:0] doutb_im;
    wire [32-1:0] dina_ot;

    wire send_en;

    //---------------------------------------
    sysgen inst_sysgen
    (
        .sys_clk     (sysgen_clk),
        .rst_n       (rst_n),
        .input_data1 (doutb_re),
        .input_data2 (doutb_im),
        .output_data (dina_ot)
    );
    //---------------------------------------

    sysgen_clk_en inst_sysgen_clk_en
    (
        .clk_200MHz(clk_200MHz), 
        .probe_out3(probe_out3), 
        .sysgen_clk(sysgen_clk)
    );

    clk_200MHz_50MHz inst_clk_200MHz_50MHz
    (
        .sys_clk_p  (sys_clk_p),
        .sys_clk_n  (sys_clk_n),
        .rst_n      (rst_n),
        .clk_200MHz (clk_200MHz),
        .clk_50MHz  (clk_50MHz)
    );

   vio_0 vio
   (
        .clk        (clk_50MHz),                // input wire clk
        .probe_out0 (),  // output wire [0 : 0] probe_out0
        .probe_out1 (probe_out1),  // output wire [0 : 0] probe_out1
        .probe_out2 (probe_out2),  // output wire [0 : 0] probe_out2
        .probe_out3 (probe_out3),  // output wire [0 : 0] probe_out3
        .probe_out4 (probe_out4)  // output wire [0 : 0] probe_out4
    );

    cnt inst_cnt
    (
        .clk_200MHz    (clk_200MHz),
        .rst_n         (rst_n),
        .probe_out3    (probe_out3),
        .all_cnt_times (all_cnt_times),
        .all_cnt       (all_cnt)
    );

    uart_byte_rx inst_uart_byte_rx
    (
        .Clk       (clk_50MHz),
        .Rst_n     (rst_n),
        .baud_set  (baud_bps),
        .data_rx   (uart_rx),
        .data_byte (data_byte_rx),
        .Rx_Done   (Rx_Done)
    );

    ram_re_ctrl inst_ram_re_ctrl
    (
        .clk_50MHz    (clk_50MHz),
        .clk_200MHz   (clk_200MHz),
        .rst_n        (rst_n),
        .probe_out1   (probe_out1),
        .data_byte_rx (data_byte_rx),
        .Rx_Done      (Rx_Done),
        .all_cnt      (all_cnt),
        .probe_out3   (probe_out3),
        .doutb_re     (doutb_re)
    );

    ram_im_ctrl inst_ram_im_ctrl
    (
        .clk_50MHz    (clk_50MHz),
        .clk_200MHz   (clk_200MHz),
        .rst_n        (rst_n),
        .probe_out2   (probe_out2),
        .data_byte_rx (data_byte_rx),
        .Rx_Done      (Rx_Done),
        .all_cnt      (all_cnt),
        .probe_out3   (probe_out3),
        .doutb_im     (doutb_im)
    );

    ram_result_ctrl inst_ram_result_ctrl
    (
        .clk_50MHz       (clk_50MHz),
        .clk_200MHz      (clk_200MHz),
        .rst_n           (rst_n),
        .probe_out3      (probe_out3),
        .probe_out4      (probe_out4),
        .delay_cnt_times (delay_cnt_times),
        .all_cnt_times   (all_cnt_times),
        .all_cnt         (all_cnt),
        .Tx_Done         (Tx_Done),
        .dina_ot         (dina_ot),
        .send_en         (send_en),
        .data_byte_tx    (data_byte_tx)
    );

    uart_byte_tx inst_uart_byte_tx
    (
        .Clk        (clk_50MHz),
        .Rst_n      (rst_n),
        .data_byte  (data_byte_tx),
        .send_en    (send_en),
        .baud_set   (baud_bps),
        .uart_tx    (uart_tx),
        .Tx_Done    (Tx_Done),
        .uart_state ()
    );

endmodule

csdn

🧸结尾


  • ❤️ 感谢您的支持和鼓励! 😊🙏
  • 📜您可能感兴趣的内容:
  • 【FPGA零基础学习之旅#17】搭建串口收发与储存双口RAM系统
  • 【Python】串口通信-与FPGA、蓝牙模块实现串口通信(Python+FPGA)
  • 【Arduino TinyGo】【最新】使用Go语言编写Arduino-环境搭建和点亮LED灯
  • 【全网首发开源教程】【Labview机器人仿真与控制】Labview与Solidworks多路支配关系-四足爬行机器人仿真与控制
    遇见未来

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1880020.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

深入解析MySQL语句的执行步骤

目录 MySQL架构概述语句执行步骤总览连接管理与线程处理语法解析查询缓存语义解析与预处理查询优化执行计划生成存储引擎层执行结果集返回优化查询性能的技巧结论 MySQL架构概述 在深入探讨MySQL语句执行的具体步骤之前&#xff0c;我们先来了解MySQL的整体架构。MySQL架构主…

简单多状态DP问题

这里写目录标题 什么是多状态DP解决多状态DP问题应该怎么做&#xff1f;关于多状态DP问题的几道题1.按摩师2.打家劫舍Ⅱ3.删除并获得点数4.粉刷房子5.买卖股票的最佳时期含手冷冻期 总结 什么是多状态DP 多状态动态规划&#xff08;Multi-State Dynamic Programming, Multi-St…

Chapter8 透明效果——Shader入门精要学习笔记

一、基本概念 在Unity中通常使用两种方法来实现透明效果 透明度测试&#xff08;无法达到真正的半透明效果&#xff09;透明度混合&#xff08;关闭了深度写入&#xff09; 透明度测试 基本原理&#xff1a;设置一个阈值&#xff0c;只要片元的透明度小于阈值&#xff0c;就…

pandas数据分析(2)

列 执行df.columns获取DataFrame列信息&#xff1a; 如果在构造DataFrame时没有提供列名&#xff0c;那么pandas会用 从0开始的数字为列编号。我们也可以为列命名&#xff0c;和为索引命名类似&#xff1a; 同样也可以重命名列名&#xff1a; 使用df.drop删除列&#xff1a; 删…

Apple - Text Layout Programming Guide

本文翻译整理自&#xff1a;Text Layout Programming Guide&#xff08;更新日期&#xff1a;2014-02-11 https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/TextLayout/TextLayout.html#//apple_ref/doc/uid/10000158i 文章目录 一、文本布局编程指…

小米集团25届校招留学生面试经验汇总及入职测评笔试题型分析

一、小米校招24年春招智能驾驶产品管理面试经验分享 ​ - **自我介绍**&#xff1a;准备一个精炼的自我介绍&#xff0c;突出自己的优势和适合岗位的特点。 - **项目经验**&#xff1a;详细回顾你在实习或项目中的具体角色和贡献&#xff0c;准备用成果和数据支撑。 - **行业…

【成都活动邀请函】7月6 | PowerData 数字经济-“成都“开源行!

【成都活动邀请函】7月6 | PowerData 数字经济-"成都"开源行&#xff01; 活动介绍活动信息线上直播扫码报名往期活动回顾专注数据开源&#xff0c;推动大数据发展 活动介绍 九天开出一成都&#xff0c;万户千门入画图。 自古以来&#xff0c;成都便是国家发展的重要…

为什么在重写equals方法后还要再重写hashcode方法(面试题)

接着上篇文章说到&#xff08;上篇文章地址&#xff1a;http://t.csdnimg.cn/udpsThttp://t.csdnimg.cn/udpsT&#xff09;我们在代码中发现重写了equals方法后还需要重写hashcode方法&#xff0c;为什么呢&#xff1f; 对于set这种数据类型&#xff0c;里面的值是不允许有重复…

【游戏引擎之路】登神长阶(五)

5月20日-6月4日&#xff1a;攻克2D物理引擎。 6月4日-6月13日&#xff1a;攻克《3D数学基础》。 6月13日-6月20日&#xff1a;攻克《3D图形教程》。 6月21日-6月22日&#xff1a;攻克《Raycasting游戏教程》。 6月23日-6月30日&#xff1a;攻克《Windows游戏编程大师技巧》。 …

【WPF】Windows系统桌面应用程序编程开发新手入门-打造自己的小工具

电脑Windows系统上的桌面程序通常是用Visual Studio 开发工具编写出来的&#xff0c;有两种开发方式供选择&#xff0c;一种是WindowForm&#xff0c;简称WinForm&#xff0c;另一种是Windows Presentation Foundation&#xff0c;简称WPF&#xff0c;这里将学习WPF项目。 文章…

安全不“放假”!暑期安全老师就用秒报小程序提示学生的安全

随着暑假的到来&#xff0c;孩子们如同出笼的小鸟&#xff0c;迫不及待地投入到广阔天地的怀抱。然而&#xff0c;作为老师&#xff0c;我深知这段时间虽然孩子们得到了放松和游玩的机会&#xff0c;但安全问题却不容忽视。如何让孩子们在享受假期的同时&#xff0c;又能确保他…

SpringBoot(一)创建一个简单的SpringBoot工程

Spring框架常用注解简单介绍 SpringMVC常用注解简单介绍 SpringBoot&#xff08;一&#xff09;创建一个简单的SpringBoot工程 SpringBoot&#xff08;二&#xff09;SpringBoot多环境配置 SpringBoot&#xff08;三&#xff09;SpringBoot整合MyBatis SpringBoot&#xff08;四…

FairGuard游戏加固无缝兼容 Android 15 预览版

2024年6月25日&#xff0c;谷歌发布了 Android 15 Beta 3 &#xff0c;作为Android 15 “平台稳定性”的里程碑版本&#xff0c;谷歌建议所有应用、游戏、SDK、库和游戏引擎开发者都将“平台稳定性”里程碑版本作为规划最终兼容性测试和公开发布的目标。 安卓开发者博客提供的版…

PostgreSQL安装教程及文件介绍

Ubuntu 安装和配置 PostgreSQL 以 Ubuntu Server 20.04&#xff0c;PostgreSQL 12 版本为例。 1. 安装 使用如下命令&#xff0c;安装指定版本的 PostgreSQL sudo apt install postgresql-12在 Ubuntu 20.04 中安装 PostgreSQL 登录您的 Ubuntu 系统并使用以下 apt 命令更新…

[HBM] HBM TSV (Through Silicon Via) 结构与工艺

依公知及经验整理&#xff0c;原创保护&#xff0c;禁止转载。 专栏 《深入理解DDR》 全文 3300 字。 1 概念 1.1 什么是HBM TSV 使用 TSV 堆叠多个DDR DRAM成为一块HBM, 成倍提高了存储器位宽&#xff0c; 一条位宽相当于高速公路的一条车道&#xff0c; 车道越多&#xff…

npm安装依赖报错——npm ERR gyp verb cli的解决方法

1. 问题描述 1.1 npm安装依赖报错——npm ERR! gyp verb cli 登录后复制 npm MARN deprecated axiosQ0.18.1: critical security vuLnerability fixed in v0.21.1. For more information, npm WARN deprecated svg001.3.2: This SVGO version is no Longer supported. upgrade …

汽车电子工程师入门系列——汽车操作系统架构学习研究-AUTOSAR

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 屏蔽力是信息过载时代一个人的特殊竞争力,任何消耗你的人和事,多看一眼都是你的不对。非必要不费力证明自己,无利益不试图说服别人,是精神上的节…

6-14题连接 - 高频 SQL 50 题基础版

目录 1. 相关知识点2. 例子2.6. 使用唯一标识码替换员工ID2.7- 产品销售分析 I2.8 - 进店却未进行过交易的顾客2.9 - 上升的温度2.10 - 每台机器的进程平均运行时间2.11- 员工奖金2.12-学生们参加各科测试的次数2.13-至少有5名直接下属的经理2.14 - 确认率 1. 相关知识点 left …

5 数字滤波器的基本结构

目录 系统框图表示法 系统框图求系统函数 系统框图的其他结构形式 IIR数字滤波器的基本结构 直接型系统框图 级联型系统框图 并联型系统框图 信号流图 信号流图表示法 信号流图代数运算基本规则 系统框图表示法 系统框图求系统函数 系统框图的其他结构形式 IIR数字滤…

30分钟学习如何搭建扩散模型的运行环境【pytorch版】【B站视频教程】【解决环境搭建问题】

30分钟学习如何搭建扩散模型的运行环境【B站视频教程】【解决环境搭建问题】 动手学习扩散模型 点击以下链接即可进入学习&#xff1a; B站视频教程附赠&#xff1a;环境配置安装&#xff08;配套讲解文档&#xff09; 视频 讲解主要内容 一、环境设置 1.本地安装&#xf…