参考链接
FPGA实验课8:ROM(IP核)使用实例_fpga的rom的ip如何调用-CSDN博客
Kimi人工智能
1. FPGA中位宽和深度的概念
- 位宽(Bit Width):
- 想象一下,你有一条高速公路,这条高速公路有多个车道。位宽就是指这些车道的数量。比如,一个32位宽的寄存器就像是有32个车道的高速公路,可以同时让32辆车并排行驶。在FPGA中,位宽越大,意味着可以同时处理更多的数据,从而提高计算速度。
- 深度(Depth):
- 现在,想象你有一座多层的停车场。深度就是指这座停车场有多少层。比如,一个深度为1024的存储器就像是有1024层的停车场,每一层都可以停放一辆车。在FPGA中,深度越大,意味着可以存储更多的数据。
总结一下:
- 位宽:一次操作可以处理的数据量。位宽越大,数据处理能力越强。
- 深度:可以存储的数据总量。深度越大,存储容量越大。
2. ROM IP核的使用方法
2.1 仿真结果
module ROM_IP(
input sys_clk,
input sys_rst_n,
// TLC5620的引脚
output wire da_clk , // 时钟信号
output wire da_data , // 数据信号
output wire da_ldac , // LDAC信号
output wire da_load , // LOAD信号
output wire [7:0] wave
);
// rom地址控制模块
reg [12:0] addr;
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
addr <= 13'd0;
else if(addr == 13'd4095)
addr <= 13'd0;
else
addr <= addr + 1'd1;
end
// 实例化ROM IP核
rom rom_inst (
.address ( addr ),
.clock ( sys_clk ),
.q ( wave )
);
// 实例化tlc5620驱动模块
tlc_5620 tlc_5620_inst
(
.CLOCK_50(sys_clk), // 系统时钟
.RST_N(sys_rst_n), // 复位信号
.da_enable(1'b1), // 使能信号,始终使能
.da_range(1'b0), // 输出范围选择,根据需要设置
.da0_data(wave), // 将dac_data连接到DA0通道
.da1_data(8'b0), // 其他通道暂时不使用,置为0
.da2_data(8'b0), // 其他通道暂时不使用,置为0
.da3_data(8'b0), // 其他通道暂时不使用,置为0
.SCK(da_clk), // 连接到外部引脚
.SDI(da_data), // 连接到外部引脚
.LOAD(da_load) // 连接到外部引脚
);
// TLC5620的LDAC信号通常需要保持低电平以更新输出电压
assign da_ldac = 1'b0;
endmodule
module tlc_5620
(
input CLOCK_50,
input RST_N,
//
input da_enable,
input da_range, // 0, 1倍参考电压; 1, 2倍参考电压
input [7:0] da0_data, // 0~255
input [7:0] da1_data, // 0~255
input [7:0] da2_data, // 0~255
input [7:0] da3_data, // 0~255
//
output reg SCK,
output reg SDI,
output reg LOAD
);
function integer log2(input integer n);
integer i;
for(i=0; 2**i <=n; i=i+1) log2=i+1;
endfunction
/**************************************
* 生成140ns的tick时钟
**************************************/
reg [log2(7):1]cnt_140ns;
always@(posedge CLOCK_50, negedge RST_N)
if(!RST_N) cnt_140ns <= 0;
else begin
if(cnt_140ns < 6)
cnt_140ns <= cnt_140ns + 1'b1;
else cnt_140ns <= 0;
end
wire tick_140ns = (cnt_140ns == 6) ? 1 : 0;
/**************************************
* 根据tick时钟生成da基准计数器
**************************************/
reg [log2(48):1] da_ref_cnt; // [0,47]
always@(posedge CLOCK_50, negedge RST_N)
if(!RST_N) da_ref_cnt <= 0;
else begin
if(!da_enable) da_ref_cnt <= 0;
else begin
if(tick_140ns) begin
if(da_ref_cnt < 47)
da_ref_cnt <= da_ref_cnt + 1'b1;
else da_ref_cnt <= 0;
end
end
end
wire tick_6720ns = (da_ref_cnt == 47) ? 1 : 0;
reg [1:0] da_sel_cnt;
always@(posedge CLOCK_50, negedge RST_N)
if(!RST_N) da_sel_cnt <= 2'b0;
else if (tick_6720ns) begin
if(da_sel_cnt < 3)
da_sel_cnt <= da_sel_cnt + 1'b1;
else da_sel_cnt <= 2'b0;
end
/**************************************
* 根据基准计数器生成串行信号
**************************************/
reg [7:0] da_data;
always@(posedge CLOCK_50, negedge RST_N)
if(!RST_N) da_data <= 8'b0;
else begin
case(da_sel_cnt)
2'b00: da_data <= da0_data;
2'b01: da_data <= da1_data;
2'b10: da_data <= da2_data;
2'b11: da_data <= da3_data;
endcase
end
always@(posedge CLOCK_50, negedge RST_N)
if(!RST_N) begin
SCK <= 0;
SDI <= 0;
LOAD <= 0;
end
else begin
if(tick_140ns) begin
// 生成SCK信号
case(da_ref_cnt)
2,6,10,14,18,22,26,30,34,38,42: SCK <= 1;
4,8,12,16,20,24,28,32,36,40,44: SCK <= 0;
default : ; // 缺省不操作
endcase
// 生成LOAD信号
case(da_ref_cnt)
0: LOAD <= 1;
46: LOAD <= 0;
default : ; // 缺省不操作
endcase
// 送入串型数据
case(da_ref_cnt)
3,4: SDI <= da_sel_cnt[1];
7,8: SDI <= da_sel_cnt[0];
11,12: SDI <= da_range;
15,16: SDI <= da_data[7];
19,20: SDI <= da_data[6];
23,24: SDI <= da_data[5];
27,28: SDI <= da_data[4];
31,32: SDI <= da_data[3];
35,36: SDI <= da_data[2];
39,40: SDI <= da_data[1];
43,44: SDI <= da_data[0];
default : SDI <= 1'b1;
endcase
end
end
endmodule