应用背景
在FPGA内部,经常需要实现一些寄存器功能,这些寄存器可以通过外部的localbus并行总线或其它串行总线来访问。本文所设计的模块先考虑并行情况,针对串行总线的情况,需要增加另外的串转并模块,请参阅其它博文。
模块所涉及的信号主要是地址、双向数据、片选、读、写,用到的知识就是数字电路里的译码器,地址总线上送来的一组数据满足FPGA内部的地址时,访问寄存器信号有效。然后依据是读有效还是写有些,分别实现不同的功能。
注意事项
- 总线描述的时候,一定要注意位宽是放在变量名称的前面,如果放在后面,则是表示变量的某一位,或者表示某个内存地址。
比如:
[7:0]BMD,表示8位宽度的BMD总线;
BMD[7:0],表示BMD的bit7到bit0;
[7:0]BMD[7:0],表示一个数据,或者叫矩阵,8个位宽是8位矩阵。 - 需要注意地址锁存的条件,写操作时,判断的是nBWE的上升沿;读操作判断nBOE的下降沿。实际应用时需要留意锁存的时序条件是否满足,可以根据实际选择使用上升沿还是下降沿。如果存在锁存失败的情况,需要改为判断Clk上升沿,做成时序逻辑。
always@(posedge Clk )
begin
if (~Rst_n && nBWE)
- 双向端口不能在模块间传递,意思是只能顶层定义双向端口,然后在顶层模块里分别实现读写寄存器,然后往下一层模块传递数据。
- testbench文件请参考下一篇博文。
代码如下:
module regs(
Clk, //时钟
Rst_n, //复位信号,低有效
BMA, //地址信号
BMD, //数据信号
nBOE, //读信号,低有效
nBWE, //写信号,低有效
nBCS1 //片选信号,低有效
);
input Clk;
input Rst_n;
input [7:0]BMA;
inout [7:0]BMD;
input nBOE;
input nBWE;
input nBCS1;
//CPLD Registers
reg [7:0]SFTDog_reg;
reg [7:0]Read_reg_data;
reg [7:0]Test_reg ;
reg [7:0]cpld_ver = 8'b0010_0001; //CPLD major revision
reg system_rst = 1'b0; //CPLD software reset
wire SFTDog_CS;
localparam [7:0]
ADDR_HDDog_Close = 8'h060, // F500_180 ADDR[9:2]
ADDR_Test_reg = 8'h061, // F500_184
ADDR_SFTDog_CS = 8'h071, // F500_01C4
ADDR_SFTDog_Clr = 8'h072; // F500_01C8
assign SFTDog_CS = (!nBCS1 && (BMA[7:0] == ADDR_SFTDog_CS[7:0])) ? 1'b0 : 1'b1;
// write logic
// always@(posedge Clk or negedge Rst_n)
// if (!Rst_n)
// SFTDog_reg <= 8'h38;
// else if (!SFTDog_CS && !nBWE)
// SFTDog_reg <= BMD;
// write logic 写逻辑实现
always@(posedge nBWE or negedge Rst_n )
begin
if (~Rst_n) //Set CPLD registers to default value
begin
SFTDog_reg <= 8'h38;
Test_reg <= 8'b0011_1100;
end
else if (~nBCS1)
begin
case (BMA[7:0])
ADDR_SFTDog_CS: SFTDog_reg <= BMD;
ADDR_Test_reg: Test_reg <= BMD;
// 4: soft_mux_on1[7:0] <= cpld_data[7:0];
// 5: cfg_rcw_src1[7:0] <= cpld_data[7:0];
// 在此处添加更多的寄存器
endcase
end
end
//read registers 读逻辑实现
assign BMD[7:0] = (!nBCS1 && !nBOE) ? Read_reg_data[7:0] : 8'bzzzz_zzzz;
always@(negedge nBOE)
begin
if (~nBCS1)
begin
case (BMA[7:0])
ADDR_SFTDog_CS: Read_reg_data[7:0] <= SFTDog_reg;
ADDR_Test_reg: Read_reg_data[7:0] <= Test_reg ;
//在此处添加更多的寄存器
default: Read_reg_data[7:0]<=8'bzzzz_zzzz;
endcase
end
end
endmodule