当前位置: 首页 > news >正文

FPGA学习笔记——简单的乒乓缓存(RAM)

一、任务

按键按下,将ROM里面存储的数据进行乒乓缓存(我这里的数据是方波的数据),然后以串口的形式发送出去(串口可以看看我之前写的),以50MHz的速率输入,以50MHz的速率输出(这里没有涉及到速度---面积的换算)。


二、分析

首先,先要一个ROM IP核,将.mif文件.hex文件放进去,让它形成一个数据发送源,其次,还需要两个双端口的RAM将接收到的数据来进行乒乓缓存,这里就要用状态机来写(状态机写法更简单,逻辑清晰),

双端口RAM的状态可以有:

IDLE

RAM1

W2R1

W1R2

首先,RAM里面是没有数据的,当按键按下,ROM将不间断的发送数据,RAM1就开始写入数据,当RAM1的数据写满(地址达到最大),就跳入下一个状态,RAM1的读取RAM2的写入,当RAM1中的数据读完或者RAM2中的数据写满(地址达到最大),就跳回W2R1的状态,形成一个循环


三、需要用到的IP 核

单端口ROM配置

双端口RAM配置


四、Visio图


五、代码

key.v

module key(
input   wire    clk     ,
input   wire    rst_n   ,
input   wire    key     ,
output  reg     key_out
);
//消抖后的按键
parameter delay = 100_0000;//20ms
reg [20:0] cnt;always@(posedge clk)//延时消抖的过程
if(!rst_n)cnt<=0;
else if(key == 0)begin//1.按键按下 2.抖动过程 3.中间稳定if(cnt == delay - 1) cnt <= cnt;//300mselsecnt <= cnt + 1;//0--1--2  
end
else //1.抖动 2.没有按键cnt<=0;always@(posedge clk)//产生消抖信号:1clk的持续时间
if(!rst_n)key_out<=0;
else if(cnt == delay - 2)key_out<=1;
elsekey_out<=0;endmodule

rom_ctrl.v

module rom_ctrl (
input       wire                clk         ,
input       wire                rst_n       ,
input       wire                key_out     ,
output      wire      [7:0]     data_rom    ,
output      reg                 rom_wren            
);reg     [7:0]   address;
wire     [7:0]   q      ;reg     en;always @(posedge clk) beginif(!rst_n)en <= 0;else if (key_out)en <= ~en;elseen <= en;
endalways @(posedge clk) beginif(!rst_n)address <= 0;else if(en == 1)address <= address + 1;elseaddress <= address;
endalways @(posedge clk) beginif(!rst_n)rom_wren <= 0;else if ( key_out )rom_wren <= ~rom_wren;
endassign data_rom = q;rom	rom_inst (.aclr ( !rst_n ),.address ( address ),.clock ( clk ),.q ( q ));endmodule

ctrl.v

module ctrl (
input   wire            clk          ,
input   wire            rst_n        ,
input   wire    [7:0]   data_rom     ,//并行数据 ,其它模块用
input   wire            done_tx      ,    //字节传输完成
input   wire            rom_wren     ,
output  reg     [7:0]   data_tx      ,//并行输入 --- 变化
output  reg             start         //数据有效信号
);//ram1
reg 	[7:0]    data1      ;
reg     [7:0]    rdaddress1 ;
reg              rden1      ;
reg  	[7:0]    wraddress1 ;
reg 	         wren1      ;
wire	[7:0]    q1         ;//ram2
reg 	[7:0]    data2      ;
reg     [7:0]    rdaddress2 ;
reg              rden2      ;
reg  	[7:0]    wraddress2 ;
reg 	         wren2      ;
wire	[7:0]    q2         ;reg flag1;
reg flag2;parameter   NUM = 256;localparam  IDLE = 4'b0001,RAM1 = 4'b0010,W2R1 = 4'b0100,W1R2 = 4'b1000;reg [3:0] cur_state , next_state;//描述状态转移:现态
always @(posedge clk) beginif(!rst_n)cur_state <= IDLE;else cur_state <= next_state;
endalways @(*) beginif(!rst_n)next_state = IDLE;elsecase (cur_state)IDLE: beginnext_state = RAM1;endRAM1:beginif(wraddress1 == NUM - 1 )next_state = W2R1;elsenext_state = cur_state;endW2R1:beginif(wraddress2 == NUM - 1 && flag1 )next_state = W1R2;elsenext_state = cur_state;endW1R2: beginif(wraddress1 == NUM - 1 && flag2 )next_state = W2R1;elsenext_state = cur_state;enddefault: next_state = IDLE;endcase
end//ram1
always @(posedge clk) beginif(!rst_n) begindata1      <= 0;rdaddress1 <= 0;rden1      <= 0;wraddress1 <= 0;wren1      <= 0;flag1      <= 0;endelsecase (cur_state)IDLE:begin data1      <= 0;rdaddress1 <= 0;rden1      <= 0;wraddress1 <= 0;wren1      <= 0;flag1      <= 0;endRAM1:beginif(rom_wren) beginwraddress1 <= wraddress1 + 1;data1      <= data_rom;endwren1      <= rom_wren;flag1      <= 0;endW2R1:begindata1      <= 0;wren1      <= 0;wraddress1 <= 0;if(done_tx) beginrden1 <= 1;if(rdaddress1 == NUM - 1) beginrdaddress1 <= 0;flag1      <= 1;endelse beginrdaddress1 <= rdaddress1 + 1;flag1      <= 0;endendelserden1 <= 0;endW1R2: beginif(rom_wren) beginwraddress1 <= wraddress1 + 1;data1      <= data_rom;endwren1      <= rom_wren;flag1      <= 0;enddefault: begin data1      <= 0;rdaddress1 <= 0;rden1      <= 0;wraddress1 <= 0;wren1      <= 0;flag1      <= 0;endendcase
end//ram2
always @(posedge clk) beginif(!rst_n) begindata2      <= 0;rdaddress2 <= 0;rden2      <= 0;wraddress2 <= 0;wren2      <= 0;flag2      <=0;endelsecase (cur_state)IDLE:begindata2      <= 0;rdaddress2 <= 0;rden2      <= 0;wraddress2 <= 0;wren2      <= 0;flag2      <=0;endRAM1: ;W2R1: begindata2      <= data_rom;rdaddress2 <= 0;rden2      <= 0;wraddress2 <= wraddress2 + 1;wren2      <= rom_wren;flag2      <=0;endW1R2: begindata2      <= 0;wren2      <= 0;wraddress2 <= 0;if(done_tx) beginrden2      <= 1;if(rdaddress2 == NUM - 1) beginrdaddress2 <= 0;flag2      <= 1;endelse beginrdaddress2 <= rdaddress2 + 1;flag2      <= 0;endendelse rden2      <= 0;enddefault: begindata2      <= 0;rdaddress2 <= 0;rden2      <= 0;wraddress2 <= 0;wren2      <= 0;flag2      <=0;endendcase
end//start
always @(posedge clk) beginif(!rst_n) begindata_tx <= 0;start   <= 0;endelsecase (cur_state)IDLE:begindata_tx <= 0;start   <= 0;endRAM1:begindata_tx <= 0;if(wraddress1 == NUM - 1)start   <= 1;elsestart   <= 0;endW2R1:begindata_tx <= q1;if(rden1)start   <= 1;elsestart   <= 0;endW1R2: begindata_tx <= q2;if(rden2)start   <= 1;elsestart   <= 0;enddefault: begindata_tx <= 0;start   <= 0;endendcase
endram	ram_inst1 (.aclr ( !rst_n ),.clock ( clk ),.data ( data1 ),.rdaddress ( rdaddress1 ),.rden ( rden1 ),.wraddress ( wraddress1 ),.wren ( wren1 ),.q ( q1 ));ram	ram_inst2 (.aclr ( !rst_n ),.clock ( clk ),.data ( data2 ),.rdaddress ( rdaddress2 ),.rden ( rden2 ),.wraddress ( wraddress2 ),.wren ( wren2 ),.q ( q2 ));endmodule

tx.v

 module tx (input   wire            clk       ,input   wire            rst_n     ,input   wire    [7:0]   data_tx   ,//并行输入 --- 变化input   wire            start     ,//数据有效信号output  wire            tx        ,  //串行输出output  wire            done_tx     //字节传输完成);parameter   sysclk = 50_000_000  ,//系统时钟下:1sbps    = 115200      , //波特率delay  = sysclk / bps;//1bit工作周期reg  [7:0]   data_reg;reg  [12:0]  cnt;//周期计数reg  [3:0]   cnt_bit;//bit计数reg en_tx ;reg tx_reg;//发送数据寄存器//寄存数据always @(posedge clk) beginif(!rst_n)data_reg <= 0;else if(start)data_reg <= data_tx;elsedata_reg <= data_reg;end//产生使能信号always @(posedge clk) beginif(!rst_n)en_tx <= 0;else if (start)en_tx <= 1;else if ( cnt_bit == 9  && cnt == delay - 1)en_tx <= 0;elseen_tx <= en_tx;end//周期计数always @(posedge clk) beginif(!rst_n)cnt <= 0;else if (  en_tx ) beginif (cnt == delay - 1)cnt <= 0;else cnt <= cnt + 1;endelsecnt <= 0;end//bit 计数always @(posedge clk) beginif(!rst_n)cnt_bit <= 0;else if (en_tx == 1) begin //使能打开if( cnt == delay - 1 ) begin // 周期计数最大值if(cnt_bit == 9) // bit最大值cnt_bit <= 0;else cnt_bit <= cnt_bit + 1;end else cnt_bit <= cnt_bit;endelse //使能关闭cnt_bit <= 0;end//发送数据always @(posedge clk) beginif(!rst_n)tx_reg <= 1; //空闲else if( en_tx )beginif ( cnt_bit == 0 )tx_reg <= 0; //起始位 else if( cnt_bit > 0 && cnt_bit < 9 ) //数据位tx_reg <= data_reg[cnt_bit - 1]; //起始位 elsetx_reg <= 1; //停止位endelsetx_reg <= 1; //空闲endassign tx      = tx_reg;assign done_tx = (cnt_bit == 9 && cnt == delay - 1) ? 1 : 0;//长 or 短endmodule

top.v

module top (
input   wire    clk     ,
input   wire    rst_n   ,
input   wire    key     ,
output  wire    tx          
);
//rom
wire      [7:0]     data_rom;
wire                rom_wren;
//key
wire    key_out;
//ctrl//tx
wire    [7:0]   data_tx;
wire            start  ;
wire            done_tx;ctrl ctrl_u(
.     clk        (clk     )  ,
.     rst_n      (rst_n   )  ,
.     data_rom   (data_rom)  ,//并行数据 ,其它模块用
.     done_tx    (done_tx )  ,    //字节传输完成
.     rom_wren   (rom_wren)  ,
.     data_tx    (data_tx )  ,//并行输入 --- 变化
.     start      (start   )   //数据有效信号
);rom_ctrl rom_ctrl_u(
.     clk       (clk     )  ,
.     rst_n     (rst_n   )  ,
.     key_out   (key_out )  ,
.     data_rom  (data_rom)  ,
.     rom_wren  (rom_wren)          
);tx tx_u(
.   clk      (clk    ) ,
.   rst_n    (rst_n  ) ,
.   data_tx  (data_tx) ,//并行输入 --- 变化
.   start    (start  ) ,//数据有效信号
.   tx       (tx     ) ,  //串行输出
.   done_tx  (done_tx)   //字节传输完成
);key key_u(
.   clk    (clk    ) ,
.   rst_n  (rst_n  ) ,
.   key    (key    ) ,
.   key_out(key_out)
);endmodule


六、现象


以上就是用RAM来实现乒乓缓存。

http://www.lryc.cn/news/610172.html

相关文章:

  • 飞算JavaAI需求转SpringBoot项目沉浸式体验
  • android内存作假通杀补丁(4GB作假8GB)
  • labview连接PLC的三种方式
  • 设计模式(一)——抽象工厂模式
  • ES集群规划与调优
  • 进程间通信:管道与共享内存
  • 移动前后端全栈项目
  • 读写分离有那些坑?
  • 16.8 华为昇腾CANN架构深度实战:3大核心引擎解析与性能优化216%秘籍
  • 手搓TCP服务器实现基础IO
  • falsk windows 服务器部署-解决服务器外无法访问
  • javacc学习笔记 02、JavaCC 语法描述文件的格式解析
  • Sklearn 机器学习 数据聚类 肘部法则选择聚类数目
  • 昇思学习营-模型推理和性能优化学习心得
  • MS-DOS 常用指令集
  • 【清除pip缓存】Windows上AppData\Local\pip\cache内容
  • 我的世界进阶模组开发教程——附魔(2)
  • (二)软件工程
  • 论文阅读笔记:《Dataset Distillation by Matching Training Trajectories》
  • 在CentOS 7上安装配置MySQL 8.0完整指南
  • PyTorch :三角函数与特殊运算
  • MFC-Ribbbon-图标-PS
  • 【秋招笔试】2025.08.03虾皮秋招笔试-第二题
  • 蜜汁整体二分——区间 kth
  • Next.js 中的文件路由:工作原理
  • 秋招笔记-8.4
  • 软件需求关闭前的质量评估标准是什么
  • Java项目:基于SSM框架实现的商铺租赁管理系统【ssm+B/S架构+源码+数据库+毕业论文+开题报告+任务书+远程部署】
  • 优化 Unity ConstantForce2D 性能的简单方法【资料】
  • 2025年08月04日Github流行趋势