Menu Close

FPGA外部静态总线读写

在实际的工程项目中, 我们往往使用fpga 配合cpu 一起使用。 也有些项目中, 会使用fpga 配合外部芯片比如sram等芯片使用。 在这些情况下,就需要通过外部静态总线fpga 连接其他芯片: cpu + fpga 项目中,往往是 cpu 作为mater, fpga 作为slave; 在fpga + sram等外设时: fpga 作为master; sram 作为slave 模式。

cpu 连接fpga的外部静态总线有很多种模式: 地址和数据总线复用模式(mcs51模式);地址和数据总线分离模式(包括 读写信号通用模式,读写信号分离模式)。

其中:

地址总线和数据总线复用模式:如mcs51模式, 需要增加ALE 控制信号。

地址总线和数据总线分离模式:

读写控制线通用模式:如motorola模式, 读写控制线通用。 高电平代表读操作, 低电平代表写操作。

读写控制线分离模式:读写控制总线分开。 一般情况下 高电平代表无效, 低电平代表有效。

1.cpu (master ) +  fpga (slave) 工程中:(读写控制线分离模式)

%title插图%num图1

verilog 参考代码:

module  static_rw
#(parameter ADDR=8’hff)
(
    input         rd_n,
    input         we_n,
    input         cs_n,
    input  [15:0] addr,
    inout  [15:0] data,
     
    output reg [15:0] fpga_reg0, 
    output reg [15:0] fpga_reg1
)
// cpu read data from fpga
reg [15:0] fpga_data_out;
assign data = cs_n==1’b0 ? fpga_data_out : 16’hzzzz;

always @ (*)
begin
    if((cs_n == 0) & (rd_n == 0))
    begin
        case (addr)
            16'h0000: fpga_data_out = fpga_reg0;
            16'h0001: fpga_data_out = fpga_reg1;
            default:  fpga_data_out = 0;
        endcase
    end
end

 
// cpu write data to fpga
always @ (posedge clk)
if((cs_n == 0) & (we_n == 0) & (addr == 16'h0000) )
    fpga_reg0 <= data;
 
always @ (posedge clk)
if((cs_n == 0) & (we_n == 0) & (addr == 16'h0001) )
    fpga_reg1 <= data; 
endmodule

cpu 读操作:

当cs_n信号为低时,fpga 数据输出; 在cs_n为高时,fpga输出高阻。

当cs_n为低,rd_n为低时,fpga 根据cpu提供的地址,选择数据输出。

cpu 写操作:

当cs_n为低,we_n为低, 地址匹配时:cpu 提供的数据写入到fpga 的寄存器中。

 

CPU(master)+ FPGA (slave)静态总线时序图

图2所示为CPU和FPGA之间总线cpu 读逻辑的时序图。

 

%title插图%num

图2 cpu读时序

fpga 在cs_n == 0期间,在 rd_n 下降沿时,输出fpga_reg 数据,并将fpga_reg的数据发送的data总线上; 在cs_n == 1时,释放总线(在data总线上输出16’hzzzz),地址总线(addr)一般情况下地址线和cs_n 是同步的 。

 

图3所示为CPU和FPGA之间总线cpu 写逻辑的时序图。

%title插图%num

图3 cpu写时序

fpga在cs_n == 0 , we_n == 0, 同时有效的情况下,从data 总线上得到数据提供给fpga 内部使用(fpga_reg),地址总线(addr)一般情况下地址线和cs_n 是同步的 。

2.FPGA (master ) +  SRAM (slave) 工程中:(读写控制线分离模式)图4

%title插图%num

图4

verilog参考代码:

module static_rw
#(
    parameter CS2RD = 1,  
    parameter CS2WE = 1,     
    parameter RD2CS = 2,
    parameter WE2CS = 2,
    parameter DATA_HOLD_TIME = 4
)
(
    output reg rd_n = 1,
    output reg we_n = 1,
    output reg cs_n = 1,
    output reg [15:0] addr,
    inout [15:0] data,

    input op_we_req,
    input op_rd_req,
    input [15:0] op_addr_req,

    output reg        op_ack = 0,
    output reg [15:0] fpga_reg0, 
    output reg [15:0] fpga_reg1
)

reg [7:0] op_cnt = 0;
reg [2:0] op_st = 0;
always @ (posedge clk)
case (op_st)
0:
begin
    op_cnt <= 0;
    we_n <= 1;
    rd_n <= 1;
    op_ack <= 0;
    op_st <= 1;
end
1:
begin
    op_cnt <= 0;
    we_n <= 1;
    rd_n <= 1;
    op_ack <= 0;

    if(op_we_req || op_rd_reg) 
    begin
        cs_n <= 0;
        op_st <= 2;
    end
    else cs_n <= 1;
end
2:
begin
    op_cnt <= op_cnt + 1;

    if((op_cnt == CS2RD) && op_rd_req )
    begin
        rd_n <= 0;
        op_st <= 3;
    end
    else if((op_cnt == CS2WE) && op_we_req )
    begin
        we_n <= 0;
        op_st <= 3;
    end
end
3:
begin
    op_cnt <= op_cnt + 1;
    if(op_cnt == DATA_HOLD_TIME)
    begin
        op_cnt <= 0;
        rd_n <= 1;
        we_n <= 1;
        op_st <= 4;
    end
end
4:
begin
    op_cnt <= op_cnt + 1;
    if((op_cnt == RD2CS) && op_rd_req )
    begin
        op_ack <= 1;
        cs_n <= 1;
        op_st <= 0;
    end
    else if((op_cnt == WE2CS) && op_we_req )
    begin
        op_ack <= 1;
        cs_n <= 1;
        op_st <= 0;
    end
end
default: op_st <= 0;
endcase

// address assignment
always @ (*)
if(cs_n == 0) addr = op_addr_req;


// fpga write data to sram
reg [15:0] fpga_data_out;
assign data = cs_n==1’b0 ? fpga_data_out : 16’hzzzz;
always @ (*)
begin
    if((cs_n == 0) & (we_n == 0))
    begin
        case (addr)
        16'h0000: fpga_data_out = fpga_reg0;
        16'h0001: fpga_data_out = fpga_reg1;
        default: fpga_data_out = 0;
        endcase
    end
end

// fpga read data from sram
always @ (posedge clk)
if((cs_n == 0) & (rd_n == 0) & (addr == 16'h0000) )
    fpga_reg0 <= data;

always @ (posedge clk)
if((cs_n == 0) & (rd_n == 0) & (addr == 16'h0001) )
    fpga_reg1 <= data; 

endmodule

FPGA (master) + SRAM(slave) 读写时序图:

%title插图%num图5

图5 显示fpga 读取sram 上的数据(data)的时序图。

%title插图%num图6

图6显示fpga 发送数据给sram。

Posted in FPGA, Verilog, 教材与教案, 文章, 编程语言

发表评论

相关链接