我们已经完成了初始化模块 自动刷新模块 数据写 数据读模块,其中初始化模块优先级最高。初始化之后才可以进行数据读写,同时为了保持数据就需要间隔进行自动刷新。 多个操作同时请求,或者如果某一操作正在执行,其他操作请求执行,我们需要仲裁模块。
仲裁模块:
原理
优先级: 自动刷新 数据写 数据读。 每一路请求信号只有在仲裁状态才会被响应,保证每一路信号正在响应不会被其他信号所打断。
波形图
初始化结束开始状态跳转 init_end.
sdram_cs_n sdram_cas_n sdram_ras_n sdram_we_n :分别为sdram_cmd[3] sdram_cmd[2] sdram_cmd[1] sdram_cmd[0]
sdram_ba: init_ba
sdram_addr: init_addr
sdram_cmd: init_cmd
wr_req: 写请求信号由fifo控制模块传入
wr_sdram_en: 写使能信号
wr_data:完成数据写入 wr_end信号拉高 由外部传入
仲裁状态下再去判断其他状态的跳转。
程序:
(
input wire sys_clk,
input wire sys_rst_n,
input wire [3:0]init_cmd,
input wire [1:0]init_ba,
input wire [12:0]init_addr,
input wire init_end,
input wire aref_req,
input wire [3:0]aref_cmd,
input wire [1:0]aref_ba,
input wire [12:0]aref_addr,
input wire aref_end,
input wire wr_req,
input wire [3:0] wr_cmd,
input wire [1:0] wr_ba,
input wire [12:0]wr_addr,
input wire wr_end,
input wire wr_sdram_en,
input wire [15:0]wr_data,
input wire rd_req,
input wire [3:0] rd_cmd,
input wire [1:0] rd_ba,
input wire [12:0]rd_addr,
input wire rd_end,
input wire rd_sdram_en,
output reg aref_en,
output reg wr_en,
output reg rd_en,
output wire sdram_cke,
output wire sdram_cs_n,
output wire sdram_cas_n,
output wire sdram_ras_n,
output wire sdram_we_n,
output reg [1:0]sdram_ba,
output reg [12:0]sdram_addr,
output wire [15:0]sdram_dq
);
parameter IDLE = 5'b0_0001,
ARBIT = 5'b0_0010,
AREF = 5'b0_0100,
WRITE = 5'b0_1000,
READ = 5'b1_0000;
//空操作指令
parameter NOP = 4'b0111;
reg [4:0] state;
reg [3:0] sdram_cmd;
//状态参数赋值
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
state <= IDLE;
else
case(state)
IDLE:
if(init_end == 1'b1)
state <= ARBIT;
else
state <= IDLE;
ARBIT:
if(aref_req == 1'b1)
state <= AREF;
else if(wr_req == 1'b1)
state <= WRITE;
else if(rd_req == 1'b1)
state <= READ;
else
state <= AREF;
AREF:
if(aref_end == 1'b1)
state <= ARBIT;
else
state <= AREF;
WRITE:
if(wr_end == 1'b1)
state <= ARBIT;
else
state <= WRITE;
READ:
if(rd_end == 1'b1)
state <= ARBIT;
else
state <= READ;
default:
state <= IDLE;
endcase
//指令赋值 always 组合逻辑赋值 sdram_cmd sdram_ba sdram_addr
always@(*)
case(state)
IDLE:
begin
sdram_cmd <= init_cmd;
sdram_ba <= init_ba;
sdram_addr<= init_addr;
end
AREF:
begin
sdram_cmd <= aref_cmd;
sdram_ba <= aref_ba;
sdram_addr<= aref_addr;
end
WRITE:
begin
sdram_cmd <= wr_cmd;
sdram_ba <= wr_ba;
sdram_addr<= wr_addr;
end
READ:
begin
sdram_cmd <= rd_cmd;
sdram_ba <= rd_ba;
sdram_addr<= rd_addr;
end
default:
begin
sdram_cmd <= NOP;
sdram_ba <= 2'b11;
sdram_addr<= 13'h1fff;
end
endcase
//三路使能信号赋值
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
aref_en <= 1'b0;
else if((state == ARBIT)&& (aref_req == 1'b1))
aref_en<= 1'b1;
else if(aref_end == 1'b1)
aref_en <= 1'b0;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
wr_en <= 1'b0;
else if((state == ARBIT)&& (aref_req == 1'b0)&&(wr_req==1'b1))
wr_en<= 1'b1;
else if(wr_end == 1'b1)
wr_en <= 1'b0;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
rd_en <= 1'b0;
else if((state == ARBIT)&& (aref_req == 1'b0)&&(rd_req == 1'b1)&&(wr_req == 1'b0))
rd_en<= 1'b1;
else if(rd_end == 1'b1)
rd_en <= 1'b0;
// 四路信号构成指令,指令有顺序 思路输出信号
assign{sdram_cs_n,sdram_ras_n,sdram_cas_n,sdram_we_n} = sdram_cmd;
//时钟使能信号 始终保持高电平
assign sdram_cke = 1'b1;
//其他时刻保持高阻态 作为输出端口
assign sdram_dq = (wr_sdram_en == 1'b1) ? wr_data:16'bz;
endmodule