前言:回校了,辦好手續就著手寫測試篇。初步的norflash控制器已經完成,通過硬件測試。目前的norflash完成扇区块擦除、单字节写、单字节读3个功能。博文最后附上源码。
总结:和之前的博文一样,里面的模块没有做时序分析,这一点会在今后的工程里面改进。另外在测试的过程中,发现写完一个字节后只需经过若干个系统时钟周期即可输出正确的写入内容(设置等待写完成的总线方向为输入,可以看到三态口的数据总线显示之前写入的数值,本人源码写入0xcc,可见stp2抓图)。这一点和手册里给的单字节写需要9us的等待时间写操作完成才能进入读不同。但是需要注意的是,手册给的是一个范围,其中9us仅仅是一个典型值,芯片温度、环境因素也将影响整个擦除所用的时间。
如果这时候有人说按照你实际测试值,读和写岂不是差不多相同的数量级?不是这样的,因为我在设计控制器的时候就是讲指令拆解成最小的原子操作,其实真正的写一个字节是包含擦差和写指令2部分,所以算起来用norflash来写东西实在是“慢”。这个过程中没有遇到什么太大的麻烦,norflash就是简单好写!
norflash控制器就先告一段落。
源码1:norflash控制器
`timescale ns / ps
//`define SIM
`define ASIZE
`define DSIZE
`define S29AL032D70TFI04
`define SYS_CLK
//version 0.0
//前级控制模块功能指令集 sys_cmd_i
//000:single byte read(1 cycle)
//001:single byte write(4 cycle)
//010:sect erase
module norflash_ctrl(//common
sys_clk,
sys_rst_n,
sys_cmd_i,
flash_req_i,
flash_ack_o,
//read
sys_rd_addr_i,
sys_data_o,
//write
sys_wr_addr_i,
sys_data_i,
//flash
flash_addr,
flash_data,
flash_ce_n,
flash_oe_n,
flash_we_n,
flash_rst_n
);
`ifdef S29AL032D70TFI04
`define CLAP_WIDTH //器件最小周期70ns,根据系统时钟此模块设置为80ns
`define CLAP
`define SECT_TIME // 單次擦除需要0.7秒時間間隙,主時鐘20ns
`define BYTE_WR_TIME //單字節寫需要9微妙時間間隙,主時鐘20ns
`endif
`ifdef SIM
parameter ST_WIDTH = ;
parameter IDLE = "IDLE.....",
BYTE_RD = "BYTE_RD..",
BYTE_WR1 = "BYTE_WR1.",
BYTE_WR2 = "BYTE_WR2.",
BYTE_WR3 = "BYTE_WR3.",
BYTE_WR4 = "BYTE_WR4.",
SECT_ERA1 = "SECT_ERA1",
SECT_ERA2 = "SECT_ERA2",
SECT_ERA3 = "SECT_ERA3",
SECT_ERA4 = "SECT_ERA4",
SECT_ERA5 = "SECT_ERA5",
SECT_ERA6 = "SECT_ERA6",
SECT_WAIT = "SECT_WAIT",
BYTE_WR_WAIT = "BYTE_WR_W";
`else
parameter ST_WIDTH = ;
`define FSM
parameter IDLE = `FSM'b00_0000_0000_0001,
BYTE_RD = `FSM'b00_0000_0000_0010,
BYTE_WR1 = `FSM'b00_0000_0000_0100,
BYTE_WR2 = `FSM'b00_0000_0000_1000,
BYTE_WR3 = `FSM'b00_0000_0001_0000,
BYTE_WR4 = `FSM'b00_0000_0010_0000,
SECT_ERA1 = `FSM'b00_0000_0100_0000,
SECT_ERA2 = `FSM'b00_0000_1000_0000,
SECT_ERA3 = `FSM'b00_0001_0000_0000,
SECT_ERA4 = `FSM'b00_0010_0000_0000,
SECT_ERA5 = `FSM'b00_0100_0000_0000,
SECT_ERA6 = `FSM'b00_1000_0000_0000,
SECT_WAIT = `FSM'b01_0000_0000_0000,
BYTE_WR_WAIT = `FSM'b10_0000_0000_0000;
`endif
//common
input sys_clk;
input sys_rst_n;
input [:] sys_cmd_i; //前级控制指令变化
input flash_req_i; //前级控制指令请求脉冲,配合指令
output flash_ack_o;
//read
input [`ASIZE-:] sys_rd_addr_i;
output [`DSIZE-:] sys_data_o;
//write
input [`DSIZE-:] sys_data_i;
input [`ASIZE-:] sys_wr_addr_i;
//flash
output [`ASIZE-:] flash_addr;
inout [`DSIZE-:] flash_data; //暂时先设置为读方向
output flash_we_n;
output flash_ce_n;
output flash_oe_n;
output flash_rst_n; //capture the posedge of flash_req_i;
reg flash_req_r = ;
always @ (posedge sys_clk) begin
if(sys_rst_n == 'b0) flash_req_r <= 0;
else flash_req_r <= flash_req_i;
end
wire rqst_edge = flash_req_i & ~flash_req_r;//检测上升沿
//decode cmd 指令译码 并生成 内部控制信号
reg do_byte_rd = ; //单字节读
reg do_sect_era = ; //整片擦出
reg do_byte_wr = ; //单字节写
always @ (posedge sys_clk) begin
if(sys_rst_n == 'b0) begin
do_byte_rd <= ;
do_sect_era <= ;
do_byte_wr <= ;end
else if(flash_ack_o) begin
do_byte_rd <= ;
do_sect_era <= ;
do_byte_wr <= ;end
else if(rqst_edge) begin
case(sys_cmd_i)
'd0:begin
do_byte_rd <= ; //读有效
do_sect_era <= ;
do_byte_wr <= ;end
'd1:begin //写有效
do_byte_wr <= ;
do_byte_rd <= ;
do_sect_era <= ;end
'd2:begin //整片擦除有效
do_sect_era <= ;
do_byte_wr <= ;
do_byte_rd <= ;end
default:begin
do_byte_rd <= ;
do_sect_era <= ;
do_byte_wr <= ;end
endcase
end
else begin
do_byte_rd <= do_byte_rd;
do_sect_era <= do_sect_era;
do_byte_wr <= do_byte_wr;end
end
//combine all does
wire do_process = do_byte_rd|do_sect_era|do_byte_wr;
//GENERATE CLOCK CLAP
reg [`CLAP_WIDTH-:] clk_clap = `CLAP_WIDTH'd0;
always @ (posedge sys_clk) begin
if(sys_rst_n == 'b0) clk_clap <= `CLAP_WIDTH'd0;
else if(flash_ack_o) clk_clap <= `CLAP_WIDTH'd0;
else if(clk_clap == `CLAP) clk_clap <= `CLAP_WIDTH'd1;
else if(do_process) clk_clap <= clk_clap + 'd1;
else clk_clap <= clk_clap;
end
//fsm
reg [ST_WIDTH-:] c_st = IDLE;
reg [ST_WIDTH-:] n_st = IDLE;
reg [:] sect_time_cnt = ; //延遲扇區擦除所需時間
//generate sect_time_cnt
//wire sect_era6 = ((c_st == SECT_ERA6)&&(clk_clap == `CLAP_WIDTH'd`CLAP))?1'b1:1'b0;//擦寫最後一個週期的最後一個脉衝
always @ (posedge sys_clk) begin
if(sys_rst_n == 'b0) sect_time_cnt <= 0;
else if((c_st == SECT_WAIT)&&(sect_time_cnt < `SECT_TIME-)) sect_time_cnt <= sect_time_cnt + 'd1;
else if(sect_time_cnt == `SECT_TIME-) sect_time_cnt <= ;
else sect_time_cnt <= sect_time_cnt;
end
//GENERATE BYTE_WR_TIME_CNT
reg [:] byte_wr_time_cnt = ;
always @ (posedge sys_clk) begin
if(sys_rst_n == 'b0) byte_wr_time_cnt <= 0;
else if((c_st == BYTE_WR_WAIT)&&(byte_wr_time_cnt < `BYTE_WR_TIME-)) byte_wr_time_cnt <= byte_wr_time_cnt + 'd1;
else if(byte_wr_time_cnt == `BYTE_WR_TIME-) byte_wr_time_cnt <= ;
else byte_wr_time_cnt <= byte_wr_time_cnt;
end
//fsm-1
always @ (posedge sys_clk) begin
if(sys_rst_n == 'b0) c_st <= IDLE;
else c_st <= n_st;
end
wire [:] do_type = {do_sect_era,do_byte_rd,do_byte_wr}; //
//fsm-2
always @ (*) begin
case(c_st)
IDLE:begin
case(do_type)
'b001:n_st = BYTE_WR1;
'b010:n_st = BYTE_RD;
'b100:n_st = SECT_ERA1;
default:n_st = IDLE;
endcase
end
BYTE_RD:begin
n_st = (clk_clap == `CLAP_WIDTH'd`CLAP)?IDLE:BYTE_RD;end
BYTE_WR1:begin
n_st = (clk_clap == `CLAP_WIDTH'd`CLAP)?BYTE_WR2:BYTE_WR1;end
BYTE_WR2:begin
n_st = (clk_clap == `CLAP_WIDTH'd`CLAP)?BYTE_WR3:BYTE_WR2;end
BYTE_WR3:begin
n_st = (clk_clap == `CLAP_WIDTH'd`CLAP)?BYTE_WR4:BYTE_WR3;end
BYTE_WR4:begin
n_st = (clk_clap == `CLAP_WIDTH'd`CLAP)?BYTE_WR_WAIT:BYTE_WR4;end
BYTE_WR_WAIT:begin
n_st = ((clk_clap == `CLAP_WIDTH'd`CLAP)&&(byte_wr_time_cnt == `BYTE_WR_TIME-1))?IDLE:BYTE_WR_WAIT;end
SECT_ERA1:begin
n_st = (clk_clap == `CLAP_WIDTH'd`CLAP)?SECT_ERA2:SECT_ERA1;end
SECT_ERA2:begin
n_st = (clk_clap == `CLAP_WIDTH'd`CLAP)?SECT_ERA3:SECT_ERA2;end
SECT_ERA3:begin
n_st = (clk_clap == `CLAP_WIDTH'd`CLAP)?SECT_ERA4:SECT_ERA3;end
SECT_ERA4:begin
n_st = (clk_clap == `CLAP_WIDTH'd`CLAP)?SECT_ERA5:SECT_ERA4;end
SECT_ERA5:begin
n_st = (clk_clap == `CLAP_WIDTH'd`CLAP)?SECT_ERA6:SECT_ERA5;end
SECT_ERA6:begin
n_st = (clk_clap == `CLAP_WIDTH'd`CLAP)?SECT_WAIT:SECT_ERA6;end
SECT_WAIT:begin
n_st = ((clk_clap == `CLAP_WIDTH'd`CLAP)&&(sect_time_cnt == `SECT_TIME-1))?IDLE:SECT_WAIT;end
default:begin
n_st = IDLE;end
endcase
end
//fsm-3
reg [:] cmd_r = ;
reg [`DSIZE-:] sys_data_o = ;
reg [`ASIZE-:] flash_addr = ;
reg [`DSIZE-:] data_buf = ;
reg link = ;
always @ (posedge sys_clk) begin
if('b0 == sys_rst_n) begin
cmd_r <= 'b0011;
flash_addr <= ;
data_buf <= ;
sys_data_o <= ;
link <= ;end
else begin
case(n_st)
IDLE:begin
cmd_r <= 'b0011;
flash_addr <= flash_addr;
data_buf <= data_buf;
sys_data_o <= sys_data_o;
link <= ;end
BYTE_RD:begin
cmd_r <= 'b0011;
flash_addr <= sys_rd_addr_i;
data_buf <= data_buf; //hold
sys_data_o <= (clk_clap == `CLAP_WIDTH'd2)?flash_data:sys_data_o;
link <= ;end
SECT_ERA1:begin
cmd_r <= (clk_clap == `CLAP_WIDTH'd2||clk_clap ==`CLAP_WIDTH'd1)?'b0101:4'b0111;
flash_addr <= `ASIZE'h000aaa;
data_buf <= `DSIZE'haa;
sys_data_o <= sys_data_o;
link <= ;end
SECT_ERA2:begin
cmd_r <= (clk_clap == `CLAP_WIDTH'd2||clk_clap ==`CLAP_WIDTH'd1)?'b0101:4'b0111;
flash_addr <= `ASIZE'h000555;
data_buf <= `DSIZE'h55;
sys_data_o <= sys_data_o;
link <= ;end
SECT_ERA3:begin
cmd_r <= (clk_clap == `CLAP_WIDTH'd2||clk_clap ==`CLAP_WIDTH'd1)?'b0101:4'b0111;
flash_addr <= `ASIZE'h000aaa;
data_buf <= `DSIZE'h80;
sys_data_o <= sys_data_o;
link <= ;end
SECT_ERA4:begin
cmd_r <= (clk_clap == `CLAP_WIDTH'd2||clk_clap ==`CLAP_WIDTH'd1)?'b0101:4'b0111;
flash_addr <= `ASIZE'h000aaa;
data_buf <= `DSIZE'haa;
sys_data_o <= sys_data_o;
link <= ;end
SECT_ERA5:begin
cmd_r <= (clk_clap == `CLAP_WIDTH'd2||clk_clap ==`CLAP_WIDTH'd1)?'b0101:4'b0111;
flash_addr <= `ASIZE'h000555;
data_buf <= `DSIZE'h55;
sys_data_o <= sys_data_o;
link <= ;end
SECT_ERA6:begin
cmd_r <= (clk_clap == `CLAP_WIDTH'd2||clk_clap ==`CLAP_WIDTH'd1)?'b0101:4'b0111;
flash_addr <= sys_wr_addr_i; //sector address
data_buf <= `DSIZE'h30;
sys_data_o <= sys_data_o;
link <= ;end
SECT_WAIT:begin //wait for rphysical sector erase time
cmd_r <= 'b1111;
flash_addr <= flash_addr;
data_buf <= data_buf;
sys_data_o <= sys_data_o;
link <= ;end
BYTE_WR1:begin
cmd_r <= (clk_clap == `CLAP_WIDTH'd2||clk_clap ==`CLAP_WIDTH'd1)?'b0101:4'b0111;
flash_addr <= `ASIZE'h000aaa;
data_buf <= `DSIZE'haa;
sys_data_o <= sys_data_o;
link <= ;end
BYTE_WR2:begin
cmd_r <= (clk_clap == `CLAP_WIDTH'd2||clk_clap ==`CLAP_WIDTH'd1)?'b0101:4'b0111;
flash_addr <= `ASIZE'h000555;
data_buf <= `DSIZE'h55;
link <= ;end
BYTE_WR3:begin
cmd_r <= (clk_clap == `CLAP_WIDTH'd2||clk_clap ==`CLAP_WIDTH'd1)?'b0101:4'b0111;
flash_addr <= `ASIZE'h000aaa;
data_buf <= `DSIZE'ha0;
sys_data_o <= sys_data_o;
link <= ;end
BYTE_WR4:begin
cmd_r <= (clk_clap == `CLAP_WIDTH'd2||clk_clap ==`CLAP_WIDTH'd1)?'b0101:4'b0111;
flash_addr <= sys_wr_addr_i;
data_buf <= sys_data_i;
sys_data_o <= sys_data_o;
link <= ;end
BYTE_WR_WAIT:begin //wait for rphysical sPROGRAM time
cmd_r <= 'b1111;
flash_addr <= flash_addr;
data_buf <= data_buf;
sys_data_o <= sys_data_o;
link <= ;end
default:begin
cmd_r <= 'b0011;
flash_addr <= flash_addr;
data_buf <= data_buf;
link <= link;
sys_data_o <= sys_data_o;end
endcase
end
end
//assign
assign flash_data = (link)?data_buf:`DSIZE'hzz;
wire flash_byte_rd_ack = ((c_st == BYTE_RD)&&(clk_clap == `CLAP_WIDTH'd`CLAP))?1'b1:'b0;
wire flash_byte_wr_ack = ((c_st == BYTE_WR_WAIT)&&(byte_wr_time_cnt == `BYTE_WR_TIME-))?'b1:1'b0;
wire flash_sect_era_ack = ((c_st == SECT_WAIT)&&(sect_time_cnt == `SECT_TIME-))?'b1:1'b0;
wire flash_ack_o = flash_byte_rd_ack | flash_byte_wr_ack | flash_sect_era_ack;
assign {flash_ce_n,flash_oe_n,flash_we_n,flash_rst_n} = cmd_r; endmodule
源码2:norflash驱动
`timescale ns / ps
`define ASIZE
`define DSIZE
module norflash_driver(
sys_clk,
sys_rst_n,
k1_n,
flash_req_o,
sys_cmd_o,
//read
sys_rd_addr_o,
//write
sys_wr_addr_o,
sys_wr_data_o
);
input sys_clk;
input sys_rst_n;
input k1_n;
output flash_req_o;
output [:] sys_cmd_o;
//read
output [`ASIZE-:] sys_rd_addr_o;
//write
output [`ASIZE-:] sys_wr_addr_o;
output [`DSIZE-:] sys_wr_data_o; //capture the negedge of k1_n
reg k1_r = ;
always @ (posedge sys_clk) begin
if(sys_rst_n == 'b0) k1_r <= 1;
else k1_r <= k1_n;
end wire k1_neg = ~k1_n & k1_r; //generate flash_req_o
reg flash_req_o = ;
always @ (posedge sys_clk) begin
if(sys_rst_n == 'b0) flash_req_o <= 0;
else if(k1_neg) flash_req_o <= ;
else flash_req_o <= ;
end //generate sys_cmd_o and sys_rd_addr_o
reg [:] sys_cmd_o = ;
reg [`ASIZE-:] sys_rd_addr_o = ;
reg [`ASIZE-:] sys_wr_addr_o = ;
reg [`DSIZE-:] sys_wr_data_o = ;
reg [:] lut_index = ; //generate lut_index
always @ (posedge sys_clk) begin
if(sys_rst_n == 'b0) begin
lut_index <= ;end
else if(k1_neg) begin
lut_index <= lut_index + 'd1;end
else begin
lut_index <= lut_index;end
end always @ (posedge sys_clk) begin
case(lut_index)
'd3:begin
sys_cmd_o <= 'b000; // off set no meaning
sys_wr_addr_o <= sys_wr_addr_o;
sys_wr_data_o <= sys_wr_data_o;
sys_rd_addr_o <= sys_rd_addr_o;end
'd0:begin
sys_cmd_o <= 'b010; //sector eraser
sys_wr_addr_o[:] <= 'b0_0000_0001;//sector1
sys_wr_addr_o[:] <= 'd0;
sys_wr_data_o <= sys_wr_data_o;
sys_rd_addr_o <= `ASIZE'd0;end
'd1:begin
sys_cmd_o <= 'b001; //write 1 byte
sys_wr_addr_o[:] <= 'b0_0000_0001;//sector1
sys_wr_addr_o[:] <= 'd0;
sys_wr_data_o <= `DSIZE'hCC;//写數據內容
sys_rd_addr_o <= `ASIZE'h00;end
'd2:begin
sys_cmd_o <= 'b000; //read 1 byte
sys_wr_addr_o <= sys_wr_addr_o;
sys_wr_data_o <= sys_wr_data_o;
sys_rd_addr_o[:] <= 'b0_0000_0001;//sector1
sys_rd_addr_o[:] <= 'd0;end
endcase
end endmodule
源码3:顶层文件
`timescale ns / ps
`define ASIZE
`define DSIZE
module norflash(
sys_clk,
sys_rst_n,
k1_n,
//flash
flash_data,
flash_addr,
flash_ce_n,
flash_oe_n,
flash_we_n,
flash_rst_n
);
input sys_clk;
input sys_rst_n;
input k1_n;
//flash
inout [`DSIZE-:] flash_data;
output [`ASIZE-:] flash_addr;
output flash_ce_n;
output flash_oe_n;
output flash_we_n;
output flash_rst_n; wire [:] sys_cmd;
wire flash_req;
wire [`ASIZE-:] sys_rd_addr;
wire [`DSIZE-:] sys_data_o; wire [`ASIZE-:] sys_wr_addr;
wire [`DSIZE-:] sys_wr_data;
norflash_driver inst_driver(
.sys_clk(sys_clk),
.sys_rst_n(sys_rst_n),
.k1_n(k1_n),
.flash_req_o(flash_req),
.sys_cmd_o(sys_cmd),
.sys_rd_addr_o(sys_rd_addr),
//write
.sys_wr_addr_o(sys_wr_addr),
.sys_wr_data_o(sys_wr_data)
); wire flash_ack;
norflash_ctrl inst_ctrl(//common
.sys_clk(sys_clk),
.sys_rst_n(sys_rst_n),
.sys_cmd_i(sys_cmd),
.flash_req_i(flash_req),
.flash_ack_o(flash_ack),
//write
.sys_wr_addr_i(sys_wr_addr),
.sys_data_i(sys_wr_data),
//read
.sys_rd_addr_i(sys_rd_addr),
.sys_data_o(sys_data_o),
//flash
.flash_addr(flash_addr),
.flash_data(flash_data),
.flash_ce_n(flash_ce_n),
.flash_oe_n(flash_oe_n),
.flash_we_n(flash_we_n),
.flash_rst_n(flash_rst_n)
); endmodule