xilinx在线升级+flash操作+N25Q128
因为使用xdc升级跳转方式,实际测试升级过程中无法回退版本,开始了使用ICAP方式来进行跳转
Flash操作:
说明:
擦除操作:收到擦除start命令--->读ID号匹配手册上的ID--->如果读ID成功--->开始进行擦除操作--->擦除一个块--->读状态寄存器不忙--->循环进行擦除操作
--->直到60个块擦完后--->IDLE
写操作:收到写start命令--->读ID号匹配手册上的ID--->如果读ID成功--->开始进行写操作--->1页写完后--->读状态寄存器不忙--->读出当前写入页数据--->循环写入读出(可验证数据是否写入)
--->直到4页完且读完--->IDLE
有的flash第一次擦不成功,所以得加一下读ID成功操作,
实际板子上使用:
module flash_top( // input wire sys_clk_p, //system clock positive// input wire sys_clk_n, //system clock negative input clk , input wire rst_n , //reset ,low active input erase_start,input write_start,input fl_data_en ,input [7:0] fl_data ,output erase_completed, //仿真output four_pp_completed,//仿真input cmd_reply_clear_finish,input miso ,// output sck ,output mosi ,output cs_n );// wire erase_completed;//调试// wire four_pp_completed;//调试wire sck;STARTUPE2 #(.PROG_USR("FALSE"), // Activate program event security feature. Requires encrypted bitstreams..SIM_CCLK_FREQ(0.0) // Set the Configuration Clock Frequency(ns) for simulation. )STARTUPE2_spi (.CFGCLK(), // 1-bit output: Configuration main clock output.CFGMCLK( ), // 1-bit output: Configuration internal oscillator clock output.EOS(), // 1-bit output: Active high output signal indicating the End Of Startup..PREQ(), // 1-bit output: PROGRAM request to fabric output.CLK(1'b0), // 1-bit input: User start-up clock input.GSR(1'b0), // 1-bit input: Global Set/Reset input (GSR cannot be used for the port name).GTS(1'b0), // 1-bit input: Global 3-state input (GTS cannot be used for the port name).KEYCLEARB(1'b1), // 1-bit input: Clear AES Decrypter Key input from Battery-Backed RAM (BBRAM).PACK(1'b1), // 1-bit input: PROGRAM acknowledge input.USRCCLKO(sck), // 1-bit input: User CCLK input.USRCCLKTS(1'b0), // 1-bit input: User CCLK 3-state enable input.USRDONEO(1'b1), // 1-bit input: User DONE pin output control.USRDONETS(1'b1) // 1-bit input: User DONE 3-state enable output );// reg [5:0] cnt_clk=0; // wire add_cnt_clk; // wire end_cnt_clk; // always@(posedge sys_clk or negedge rst_n)begin// if(rst_n==1'b0)begin// cnt_clk<=0;// end// else if(add_cnt_clk)begin// if(end_cnt_clk)// cnt_clk<=0;// else// cnt_clk<=cnt_clk+1;// end // end // assign add_cnt_clk = 1; // assign end_cnt_clk = add_cnt_clk && cnt_clk == 2-1;// reg clk;//100MHz // always@(posedge sys_clk)begin// if(cnt_clk<1)begin// clk<=1'b1;// end// else begin// clk<=1'b0;// end // end // wire clk; // assign clk=sys_clk;// wire clk_out1; // wire clk_out2;// clk_wiz_0 clk_wiz_0_uut// (// .clk_out1(clk_out1), // output clk_out1// .clk_out2(clk_out2), // output clk_out2// .reset(~rst_n), // input reset// .locked(locked), // output locked// .clk_in1(sys_clk)); // input clk_in1// wire clk; // assign clk=clk_out2 & locked;//===========================vio========================================= // wire earse_start_vio; // wire write_start_vio; // wire read_start_vio; // vio_0 uut_vio_0 (// .clk(clk), // .probe_out0(earse_start_vio), // .probe_out1(write_start_vio),// .probe_out2(read_start_vio) // ); // reg earse_start_r1; // always@(posedge clk)begin // earse_start_r1<=earse_start_vio; // end// wire earse_edge; // assign earse_edge= earse_start_r1 & ~earse_start_vio;// reg write_start_r1; // always@(posedge clk)begin // write_start_r1<=write_start_vio; // end// wire write_edge; // assign write_edge= write_start_r1 & ~write_start_vio;// reg read_start_r1; // always@(posedge clk)begin // read_start_r1<=read_start_vio; // end// wire read_edge; // assign read_edge= read_start_r1 & ~read_start_vio; //===========================test========================================= // reg I_fl_data_en ; // wire end_cnt0;// always @(posedge clk or negedge rst_n)begin // if(!rst_n)begin// I_fl_data_en <= 0;// end// else if(write_start) begin //仿真// else if(write_edge)begin //实际// I_fl_data_en <= 1;// end // else if(end_cnt0) begin// I_fl_data_en <= 0;// end // end // reg [15:0] cnt0; // wire add_cnt0;// always@(posedge clk or negedge rst_n)begin// if(rst_n==1'b0)begin// cnt0<='d0;// end// else if(add_cnt0)begin// if(end_cnt0)// cnt0<=0;// else// cnt0<=cnt0+1;// end // end // assign add_cnt0 = I_fl_data_en; // assign end_cnt0 = add_cnt0 && cnt0 == 1024-1;//256-1;// (*mark_debug="true", dont_touch="true"*)wire [7:0] wr_rd_state_spi_out ;(*mark_debug="true", dont_touch="true"*)wire [7:0] dout ;//读取数据(*mark_debug="true", dont_touch="true"*)wire dout_vld ;//数据有效(*mark_debug="true", dont_touch="true"*)wire spi_vld ;(*mark_debug="true", dont_touch="true"*)wire en ;(*mark_debug="true", dont_touch="true"*)wire [7:0] spi_dout ;//读取数据进入fifo (*mark_debug="true", dont_touch="true"*)wire spi_one_byte_done ; wr_control u_wr_control( /*input */.clk (clk ),/*input */.rst_n (rst_n ),// `ifdef simulation// `elsif.erase_start (erase_start),// erase_start 仿真.write_start (write_start),//write_start// .erase_start (earse_edge ),//erase_start 调试// .write_start (write_edge ),//write_start .erase_completed(erase_completed),.four_pp_completed(four_pp_completed),.cmd_reply_clear_finish(cmd_reply_clear_finish),.read_start(read_edge),// `endif /*input */.spi_one_byte_done (spi_one_byte_done ),/*input */.din_vld ( fl_data_en ),// (I_fl_data_en),//(rx_byte_vld ),// /*input [7:0] */.din ( fl_data),// (cnt0[7:0] ),//(rx_byte ),// /*input [7:0] */.read_data (spi_dout ),/*output reg [7:0] */.wr_rd_state_spi_out (wr_rd_state_spi_out ),/*output [7:0] */.read_flash_data_fifo_out (dout ),/*output */.read_flash_data_fifo_out_vld (dout_vld ),/*output */.en (en ),/*output */.spi_vld (spi_vld ) );spi_master u_spi_master( /*input */.clk (clk ),/*input */.rst_n (rst_n ),/*input */.en (en ),/*input [1:0] */.spi_mode (2'b00 ),/*input */.spi_vld (spi_vld ),/*input [7:0] */.spi_din (wr_rd_state_spi_out),//写入数据/*input */.miso (miso ),/*output reg */.sck (sck ),/*output reg */.cs_n (cs_n ),/*output */.mosi (mosi ),/*output reg [7:0] */.spi_dout (spi_dout ),//读取数据/*output reg */.busy ( ),/*output */.spi_one_byte_done (spi_one_byte_done ) ); endmodule
`include "param.v" module wr_control( input clk ,input rst_n ,input erase_start, (*mark_debug="true", dont_touch="true"*)output erase_completed,input write_start, (*mark_debug="true", dont_touch="true"*)output reg four_pp_completed,input cmd_reply_clear_finish,input read_start,input spi_one_byte_done ,input [7:0] din ,input din_vld ,input [7:0] read_data ,output reg [7:0] wr_rd_state_spi_out ,output [7:0] read_flash_data_fifo_out ,output read_flash_data_fifo_out_vld ,output en ,output reg spi_vld ); //参数定义 parameter DATA_WIDTH = 8'd12;//8'd15;parameter DATA_LENGTH = 1024;//'d10240; //中间信号定义 reg flag ;reg flag0 ;reg en_r ;wire en_dge_n ;reg read_data_vld ;//例化中间信号wire read_id ;wire read_rdsr ;wire read_data_flag;wire read_only_data_flag;wire busy_read;wire data_req ;wire [7:0] write_state_spi_out ;wire [7:0] read_state_spi_out ;wire [1:0] en_ ;wire read_spi_one_byte_vld ;wire write_done ;wire read_done ;wire rxf_rdreq ;wire rxf_wrreq ;wire rxf_empty ;wire rxf_full ;wire [7:0] rxf_dout ;// wire [11:0] rxf_usedw ; wire [DATA_WIDTH-1:0] rxf_usedw ; wire txf_rdreq ;wire txf_wrreq ; (*mark_debug="true", dont_touch="true"*) wire txf_empty ;wire txf_full ; // (*mark_debug="true", dont_touch="true"*) wire [11:0] txf_usedw ; wire [DATA_WIDTH-1:0] txf_usedw ; reg [7:0] din_fifo; reg din_fifo_vld; //标志信号//flag 1: uart 发送数据 0:停止发送数据always @(posedge clk or negedge rst_n)begin if(!rst_n)beginflag <= 0;end else if(txf_usedw >= DATA_LENGTH-1)begin // else if(txf_usedw >='d1023)begin flag <= 1;end else if(txf_empty)begin flag <= 0;end end//flag0 0:fish读模块输出数据(命令、地址)1:fish写模块发送数据(命令、地址、写入数据)always @(posedge clk or negedge rst_n)begin if(!rst_n)beginflag0 <= 0;end else if(en_[0])begin flag0 <= 1;end else if(en_[1])begin flag0 <= 0;end end//en_r 打拍 检测en信号边沿always @(posedge clk or negedge rst_n)begin if(!rst_n)beginen_r <= 0;end else begin en_r <= en;end endassign en_dge_n = !en & en_r;//read_data_vldalways @(posedge clk or negedge rst_n)begin if(!rst_n)beginread_data_vld <= 0;end else begin read_data_vld <= read_spi_one_byte_vld;//读出数据有效end end//输出//wr_rd_state_spi_out 数据输出给spi_master模块always @(*)begin if(flag0)beginwr_rd_state_spi_out = write_state_spi_out;end else if(flag0 == 0)begin wr_rd_state_spi_out = read_state_spi_out; end else begin wr_rd_state_spi_out = wr_rd_state_spi_out;end end//enassign en = en_[0] | en_[1];//spi_vldalways @(posedge clk or negedge rst_n)begin if(!rst_n)beginspi_vld <= 0;end else if(en_dge_n)begin spi_vld <= 1;end else if(write_done | read_done)begin spi_vld <= 0; end else beginspi_vld <= spi_vld; endendflash_write u_flash_write ( /*input */.clk (clk ),/*input */.rst_n (rst_n ),/*input */.erase_start (erase_start),.erase_completed(erase_completed),.cmd_reply_clear_finish(cmd_reply_clear_finish),/*input */.write_start (write_start),.read_id (read_id ),.read_rdsr (read_rdsr ),.read_data_flag(read_data_flag),/*input */.read_data (read_data),/*input */.read_data_vld(read_data_vld),/*input */.read_done (read_done),.busy_read(busy_read),/*input */.spi_one_byte_done (spi_one_byte_done ),//spi一个字节数据传输完成/*input [7:0] */.din (rxf_dout ),/*output */.data_req (data_req ), //写入flash数据请求/*output */.en (en_[0] ), /*output */.write_done (write_done ),/*output reg [7:0] */.write_state_spi_out (write_state_spi_out ) //给spi配置 );flash_read u_flash_read ( /*input */.clk (clk ),/*input */.rst_n (rst_n ),.read_id (read_id ),.read_rdsr (read_rdsr ), .read_data_flag(read_data_flag | read_start),.read_only_data_flag(read_only_data_flag),.busy_read(busy_read),/*input */.spi_one_byte_done (spi_one_byte_done ),/*output */.en (en_[1] ),/*output */.read_done (read_done ),/*output */.read_spi_one_byte_vld (read_spi_one_byte_vld ),/*output reg [7:0] */.read_state_spi_out (read_state_spi_out )//给spi配置 ); //fifo例化 // rx_fifo rx_fifo_inst (// .aclr ( !rst_n ),// .clock ( clk ),// .data ( din ), //uart输入数据// .rdreq ( rxf_rdreq ),// .wrreq ( rxf_wrreq ),// .empty ( rxf_empty ),// .full ( rxf_full ),// .q ( rxf_dout ),// .usedw ( rxf_usedw )// ); flash_fifo rx_fifo (.clk(clk), // input wire clk.srst(!rst_n), // input wire srst// .din(din), // input wire [7 : 0] din .din(din_fifo),.wr_en(rxf_wrreq), // input wire wr_en.rd_en(rxf_rdreq), // input wire rd_en.dout(rxf_dout), // output wire [7 : 0] dout.full(rxf_full), // output wire full.empty(rxf_empty), // output wire empty.data_count(rxf_usedw) // output wire [8 : 0] data_count );// assign rxf_wrreq = !rxf_full && din_vld;assign rxf_wrreq = !rxf_full && din_fifo_vld;assign rxf_rdreq = !rxf_empty && data_req;// fifo_tx fifo_tx_inst (// .aclr ( !rst_n ),// .clock ( clk ),// .data ( read_data ),//din_m从flash中读取数据// .rdreq ( txf_rdreq ),// .wrreq ( txf_wrreq ),// .empty ( txf_empty ),// .full ( txf_full ),// .q ( read_flash_data_fifo_out ), //uart输出数据// .usedw ( txf_usedw )// ); flash_fifo fifo_tx (.clk(clk), // input wire clk.srst(!rst_n), // input wire srst.din (read_data ), // input wire [7 : 0] din.wr_en(txf_wrreq), // input wire wr_en.rd_en(txf_rdreq), // input wire rd_en.dout(read_flash_data_fifo_out), // output wire [7 : 0] dout.full(txf_full), // output wire full.empty(txf_empty), // output wire empty.data_count(txf_usedw) // output wire [11 : 0] data_count );assign txf_wrreq = !txf_full && read_data_vld && read_only_data_flag;//从flash中读取数据 data_vld数据有效assign txf_rdreq = flag && (!txf_empty) ;//&& (!busy_t);assign read_flash_data_fifo_out_vld = txf_rdreq; //uart数据输出有效 (*mark_debug="true", dont_touch="true"*)reg [8:0] cnt_fifo; wire add_cnt_fifo; wire end_cnt_fifo; always @(posedge clk or negedge rst_n)begin if(!rst_n)begincnt_fifo<=0;endelse if(add_cnt_fifo)beginif(end_cnt_fifo)cnt_fifo<=0;elsecnt_fifo<=cnt_fifo+1;end end assign add_cnt_fifo = txf_wrreq; assign end_cnt_fifo = add_cnt_fifo && cnt_fifo == 256-1;//一页写字节//--------------------比较----------------------- (*mark_debug="true", dont_touch="true"*)wire [7 : 0] original_dout; wire compare_fifo_full; (*mark_debug="true", dont_touch="true"*)wire compare_fifo_empty; // (*mark_debug="true", dont_touch="true"*)wire [11 : 0] compare_fifo_usedw; (*mark_debug="true", dont_touch="true"*)wire [DATA_WIDTH-1:0] compare_fifo_usedw; flash_fifo compare_fifo (.clk(clk), // input wire clk.srst(!rst_n), // input wire srst// .din(din), // input wire [7 : 0] din .din(din_fifo), .wr_en(rxf_wrreq), // input wire wr_en.rd_en(txf_rdreq), // input wire rd_en.dout(original_dout), // output wire [7 : 0] dout.full(compare_fifo_full), // output wire full.empty(compare_fifo_empty), // output wire empty.data_count(compare_fifo_usedw) // output wire [11 : 0] data_count );// (*mark_debug="true", dont_touch="true"*)reg [11:0] cnt_compare; (*mark_debug="true", dont_touch="true"*)reg [DATA_WIDTH-1:0] cnt_compare; wire add_cnt_compare; wire end_cnt_compare; always @(posedge clk or negedge rst_n)begin if(!rst_n)begincnt_compare<=0;endelse if(add_cnt_compare)beginif(end_cnt_compare)cnt_compare<=0;elsecnt_compare<=cnt_compare+1;end end assign add_cnt_compare = txf_rdreq&original_dout==read_flash_data_fifo_out/* &(~compare_fifo_empty) */; assign end_cnt_compare = add_cnt_compare && cnt_compare == DATA_LENGTH-1;//10240-1;//回读比较字节 // assign end_cnt_compare = add_cnt_compare && cnt_compare == 1024-1;// (*mark_debug="true", dont_touch="true"*)wire four_pp_completed; // assign four_pp_completed=end_cnt_compare;always @(posedge clk or negedge rst_n)begin if(!rst_n)beginfour_pp_completed <=1'b0;end else if(end_cnt_compare)begin four_pp_completed <= 1'b1;end else if(cmd_reply_clear_finish)begin four_pp_completed <= 1'b0; end end//不够1024字节后面都写ff reg din_vld_r; always @(posedge clk or negedge rst_n)begin if(!rst_n)begindin_vld_r<=0;endelse begindin_vld_r<=din_vld;end endwire din_vld_pos; assign din_vld_pos = din_vld & ~din_vld_r;always @(posedge clk or negedge rst_n)begin if(!rst_n)begindin_fifo<='hff;endelse if(din_vld)begindin_fifo<=din;end else begindin_fifo<='hff; end end// reg din_fifo_vld;wire end_cnt_din; always @(posedge clk or negedge rst_n)begin if(!rst_n)begindin_fifo_vld<=1'b0;endelse if(din_vld_pos)begindin_fifo_vld<=1'b1;end else if(end_cnt_din)begindin_fifo_vld<=0; end endreg [15:0] cnt_din; wire add_cnt_din;// wire end_cnt_din; always@(posedge clk or negedge rst_n)beginif(rst_n==1'b0)begincnt_din<='d0;endelse if(add_cnt_din)beginif(end_cnt_din)cnt_din<=0;elsecnt_din<=cnt_din+1;end end assign add_cnt_din = din_fifo_vld; assign end_cnt_din = add_cnt_din && cnt_din == 1024-1;//256-1;//一页输入字节//收包统计个数 (*mark_debug="true", dont_touch="true"*)reg [15:0] cnt_udp; always @(posedge clk or negedge rst_n)begin if(!rst_n)begincnt_udp<=0;endelse if(din_vld_pos)begincnt_udp<=cnt_udp+1'b1;end else begincnt_udp<=cnt_udp; end endendmodule
`include "param.v" module flash_write( input clk ,input rst_n ,input erase_start,output reg erase_completed,input cmd_reply_clear_finish,input write_start,output reg read_id,(*mark_debug="true", dont_touch="true"*) output reg read_rdsr,(*mark_debug="true", dont_touch="true"*) output reg read_data_flag,(*mark_debug="true", dont_touch="true"*) input [7:0] read_data,(*mark_debug="true", dont_touch="true"*) input read_data_vld,(*mark_debug="true", dont_touch="true"*) input read_done,input busy_read,input spi_one_byte_done ,input [7:0] din ,output data_req , //写入flash数据请求output en , output write_done , output reg [7:0] write_state_spi_out ); //参数定义 parameter M_IDLE =8'b0000_0001,M_RDID =8'b0000_0010,M_WREN =8'b0000_0100,M_SE =8'b0000_1000, M_RDSR =8'b0001_0000,M_WAIT =8'b0010_0000,M_RDDA =8'b0100_0000,M_PP =8'b1000_0000; parameter S_IDLE = 5'b00001, S_CMD = 5'b00010, S_ADDR = 5'b00100, S_DATA = 5'b01000, S_DELAY = 5'b10000; parameter INIT_ADDR = 24'h80_0000; //中间信号定义 reg [7:0] m_state_c ;reg [7:0] m_state_n ;(*mark_debug="true", dont_touch="true"*) reg [4:0] s_state_c ;reg [4:0] s_state_n ;reg [7:0] cnt_100ns ;wire add_cnt_100ns ;wire end_cnt_100ns ;reg [18:0] cnt_pp ;wire add_cnt_pp ;wire end_cnt_pp ;reg end_cnt_pp_r ;reg [10:0] cnt_se ;wire add_cnt_se ;wire end_cnt_se ;reg end_cnt_se_r ; reg [8:0] cnt_byte ;wire add_cnt_byte ;wire end_cnt_byte ;reg [8:0] byte_num ;(*mark_debug="true", dont_touch="true"*) reg [23:0] addr_wr ; (*mark_debug="true", dont_touch="true"*) reg [1:0] flag ;//主wire m_idle2m_rdid ;wire m_rdid2m_wren ;wire m_rdid2m_idle ;wire m_wren2m_se ;wire m_wren2m_pp ;wire m_se2m_rdsr ;wire m_rdsr2m_rdda ;wire m_rdsr2m_idle ;wire m_rdsr2m_wren ;wire m_rdsr2m_wait ;wire m_wait2m_rdsr ;wire m_rdda2m_wren ;wire m_rdda2m_idle ;wire m_pp2m_rdsr ;//从wire s_idle2s_cmd ;wire s_cmd2s_addr ;wire s_cmd2s_data ;wire s_cmd2s_delay ;wire s_addr2s_data ;wire s_addr2s_delay ;wire s_data2s_idle ;wire s_data2s_delay ;wire s_delay2s_idle ;reg [2:0] read_id_cnt;reg [7:0] first_id ;reg [7:0] second_id;reg [7:0] third_id ;reg read_done_r1;reg read_done_r2;reg read_done_r3;reg [1:0] read_id_flag;reg [11:0] erase_cnt;reg rdsr_sta_reg_vld ;reg [23:0] wait_time_cnt;reg [11:0] pp_cnt;reg second_erase_start;//状态机//主状态机always @(posedge clk or negedge rst_n)begin if(!rst_n)beginm_state_c <= M_IDLE;end else begin m_state_c <= m_state_n;end endalways @(*)begin case (m_state_c)M_IDLE: begin if(m_idle2m_rdid)beginm_state_n = M_RDID;endelse beginm_state_n = m_state_c;endend M_RDID: begin if(m_rdid2m_wren)beginm_state_n = M_WREN;end else if(m_rdid2m_idle)beginm_state_n = M_IDLE;end else beginm_state_n = m_state_c;end endM_WREN: begin if(m_wren2m_se)beginm_state_n = M_SE;end else if(m_wren2m_pp)beginm_state_n = M_PP;endelse beginm_state_n = m_state_c;endendM_SE: begin if(m_se2m_rdsr)beginm_state_n = M_RDSR;endelse beginm_state_n = m_state_c;end endM_RDSR: begin if(m_rdsr2m_rdda)beginm_state_n = M_RDDA;endelse if (m_rdsr2m_idle) beginm_state_n = M_IDLE;end else if (m_rdsr2m_wren) beginm_state_n = M_WREN;endelse if (m_rdsr2m_wait) beginm_state_n = M_WAIT;end else beginm_state_n = m_state_c;end endM_WAIT:begin if(m_wait2m_rdsr)beginm_state_n = M_RDSR;end else beginm_state_n = m_state_c;end end M_RDDA:begin if(m_rdda2m_wren)beginm_state_n = M_WREN;end else if(m_rdda2m_idle)beginm_state_n = M_IDLE;end else beginm_state_n = m_state_c;end end M_PP: begin if (m_pp2m_rdsr) beginm_state_n = M_RDSR;end else beginm_state_n = m_state_c;end enddefault: m_state_n = m_state_c;endcaseend//从状态机always @(posedge clk or negedge rst_n)begin if(!rst_n)begins_state_c <= S_IDLE;end else begin s_state_c <= s_state_n;end endalways @(*)begin case (s_state_c)S_IDLE : begin if (s_idle2s_cmd) begins_state_n = S_CMD;endelse begins_state_n = s_state_c; end endS_CMD : begin if (s_cmd2s_addr) begins_state_n = S_ADDR;end// else if (s_cmd2s_data) begin// s_state_n = S_DATA;// endelse if (s_cmd2s_delay) begins_state_n = S_DELAY;endelse begins_state_n = s_state_c;end endS_ADDR : begin if (s_addr2s_data) begins_state_n = S_DATA;endelse if(s_addr2s_delay) begins_state_n = S_DELAY;endelse begins_state_n = s_state_c;end endS_DATA : begin // if (s_data2s_idle) begin// s_state_n = S_IDLE;// end// else if(s_data2s_delay)begins_state_n = S_DELAY;endelse begins_state_n = s_state_c;end endS_DELAY : begin if(s_delay2s_idle)begins_state_n = S_IDLE;endelse begins_state_n = s_state_c;end enddefault: s_state_n = s_state_c;endcaseend//主状态机转换条件assign m_idle2m_rdid = m_state_c == M_IDLE && (erase_start || write_start ||second_erase_start);assign m_rdid2m_wren = m_state_c == M_RDID && read_id_flag==2'b11;assign m_rdid2m_idle = m_state_c == M_RDID && read_id_flag==2'b10;assign m_wren2m_se = m_state_c == M_WREN && s_delay2s_idle && flag == 2'b01; assign m_wren2m_pp = m_state_c == M_WREN && s_delay2s_idle && flag == 2'b10; assign m_se2m_rdsr = m_state_c == M_SE && s_delay2s_idle;assign m_rdsr2m_rdda = m_state_c == M_RDSR && /* s_data2s_idle && */ rdsr_sta_reg_vld && flag == 2'b10;assign m_rdsr2m_idle = m_state_c == M_RDSR && /* s_data2s_idle && */ rdsr_sta_reg_vld && erase_cnt==12'd60 &&flag == 2'b01;assign m_rdsr2m_wren = m_state_c == M_RDSR && /* s_data2s_idle && */ rdsr_sta_reg_vld && erase_cnt <12'd60 &&flag == 2'b01;assign m_rdsr2m_wait = m_state_c == M_RDSR && /* s_data2s_idle */ read_done_r1 && read_data_vld && read_data[1:0] == 2'b11;assign m_wait2m_rdsr = m_state_c == M_WAIT && ((flag == 2'b01 && wait_time_cnt== 24'd250_0000)|(flag == 2'b10 && wait_time_cnt== 24'd150_000 ));assign m_rdda2m_wren = m_state_c == M_RDDA && /* read_done */ (~read_data_flag)&&read_done_r3 &&flag == 2'b10 && pp_cnt< 12'd4;assign m_rdda2m_idle = m_state_c == M_RDDA && /* read_done */ (~read_data_flag)&&read_done_r3 &&flag == 2'b10 && pp_cnt==12'd4;//1024字节4页assign m_pp2m_rdsr = m_state_c == M_PP && s_delay2s_idle;//从状态机转换条件assign s_idle2s_cmd = s_state_c == S_IDLE && (!(m_state_c == M_IDLE)) && (!(m_state_c == M_RDSR)) && (!(m_state_c == M_RDID)) && (!(m_state_c == M_RDDA)) ;assign s_cmd2s_addr = s_state_c == S_CMD && end_cnt_byte && (m_state_c == M_SE | m_state_c == M_PP);assign s_cmd2s_data = s_state_c == S_CMD && end_cnt_byte && (m_state_c == M_RDSR | m_state_c == M_RDID);assign s_addr2s_data = s_state_c == S_ADDR && end_cnt_byte && m_state_c == M_PP;assign s_addr2s_delay = s_state_c == S_ADDR && end_cnt_byte && m_state_c == M_SE;assign s_data2s_idle = s_state_c == S_DATA && read_done_r3 && (m_state_c == M_RDSR|| m_state_c == M_RDID);assign s_data2s_delay = s_state_c == S_DATA && end_cnt_byte && (m_state_c == M_PP);assign s_cmd2s_delay = s_state_c == S_CMD && end_cnt_byte && m_state_c == M_WREN;assign s_delay2s_idle = s_state_c == S_DELAY && ((( (m_state_c == M_SE)?end_cnt_se_r : end_cnt_pp_r)&& (m_state_c == M_SE || m_state_c == M_PP)) || (end_cnt_100ns && m_state_c == M_WREN));//计数器always @(posedge clk or negedge rst_n)begin if(!rst_n)begincnt_100ns <= 0;end else if(add_cnt_100ns)begin if(end_cnt_100ns)begin cnt_100ns <= 0;endelse begin cnt_100ns <= cnt_100ns + 1;end endelse begincnt_100ns <= cnt_100ns;endend assign add_cnt_100ns = s_state_c == S_DELAY && m_state_c == M_WREN;assign end_cnt_100ns = add_cnt_100ns && cnt_100ns == 30;always @(posedge clk or negedge rst_n)begin if(!rst_n)begincnt_byte <= 0;end else if(add_cnt_byte)begin if(end_cnt_byte)begin cnt_byte <= 0;endelse begin cnt_byte <= cnt_byte + 1;end endelse begincnt_byte <= cnt_byte;endend assign add_cnt_byte = spi_one_byte_done && (s_state_c == S_CMD | s_state_c == S_ADDR | s_state_c == S_DATA ) && ~busy_read;assign end_cnt_byte = add_cnt_byte && cnt_byte == byte_num-1; always @(posedge clk or negedge rst_n)begin if(!rst_n)begincnt_pp <= 0;end else if(add_cnt_pp)begin if(end_cnt_pp | s_delay2s_idle)begin cnt_pp <= 0;endelse begin cnt_pp <= cnt_pp + 1;end endelse begincnt_pp <= cnt_pp;endend assign add_cnt_pp = s_state_c == S_DELAY && (m_state_c == M_PP || m_state_c == M_SE);assign end_cnt_pp = add_cnt_pp && cnt_pp == `DELAY_5MS-1;always @(posedge clk or negedge rst_n)begin if(!rst_n)begincnt_se <= 0;end else if(add_cnt_se)begin if(end_cnt_se)begin cnt_se <= 0;endelse begin cnt_se <= cnt_se + 1;end endelse begincnt_se <= cnt_se;endend assign add_cnt_se= s_state_c == S_DELAY && end_cnt_pp && m_state_c == M_SE;assign end_cnt_se = add_cnt_se && cnt_se == 2-1;//flagalways @(posedge clk or negedge rst_n)begin if(!rst_n)beginflag <=2'b00;end else if(erase_start)beginflag <=2'b01;end else if(write_start)beginflag <=2'b10;end endalways @(posedge clk or negedge rst_n)begin if(!rst_n)beginend_cnt_pp_r <= 0;end_cnt_se_r <= 0;end else begin end_cnt_pp_r <= end_cnt_pp;end_cnt_se_r <= end_cnt_se;end end//byte_numalways @(posedge clk or negedge rst_n)begin if(!rst_n)beginbyte_num <= 0;end else if(s_state_c == S_CMD)begin byte_num <= `CMD_BYTE;end else if(s_state_c == S_ADDR)begin byte_num <= `ADDR_BYTE;end else if(s_state_c == S_DATA)beginbyte_num <= `DATA_BYTE;endelse beginbyte_num <= byte_num;endendreg [23:0] addr_erase;always @(posedge clk or negedge rst_n)begin if(!rst_n | m_state_c == M_IDLE)beginaddr_erase <= INIT_ADDR;//24'h40_0000;end else if(m_rdsr2m_wren & flag == 2'b01)begin addr_erase <= addr_erase +24'h01_0000;end else begin addr_erase <= addr_erase;end endreg [23:0] addr_pp;always @(posedge clk or negedge rst_n)begin if(!rst_n /* | m_state_c == M_IDLE */)beginaddr_pp <=INIT_ADDR;end// else if(addr_pp ==24'h7a_607b)begin // addr_pp <=INIT_ADDR;// end else if(m_pp2m_rdsr & flag == 2'b10)begin addr_pp <= addr_pp +24'h00_0100;end else begin addr_pp <= addr_pp;end end //addr_wralways @(posedge clk or negedge rst_n)begin if(!rst_n)beginaddr_wr <= INIT_ADDR;end else if(flag==2'b01)begin addr_wr <= addr_erase;end else if(flag==2'b10 )begin addr_wr <= addr_pp;end else begin addr_wr <= addr_wr;end end//输出//write_state_spi_outalways @(posedge clk or negedge rst_n)begin if(!rst_n)beginwrite_state_spi_out <= 0;end else if(s_state_c == S_CMD)begin if(m_state_c == M_WREN)beginwrite_state_spi_out <= `CMD_WREN;endelse if(m_state_c == M_SE ) beginwrite_state_spi_out <= `CMD_SE;endelse if (m_state_c == M_PP ) beginwrite_state_spi_out <= `CMD_PP;endelse beginwrite_state_spi_out <= write_state_spi_out;endend else if(s_state_c == S_ADDR)begin write_state_spi_out <=addr_wr[23-cnt_byte*8-:8];end else if (s_state_c == S_DATA && m_state_c == M_PP) beginwrite_state_spi_out <=din;endend//data_req en write_done read_data_vld busy// wire en_temp;assign data_req = m_state_c == M_PP && spi_one_byte_done && s_state_c == S_DATA; assign /* en_temp */ en = m_rdid2m_wren |m_rdsr2m_wren |m_wren2m_se |m_wren2m_pp |m_rdda2m_wren;assign write_done = s_data2s_delay | s_addr2s_delay | s_cmd2s_delay;// reg [7:0] en_r;// always @(posedge clk or negedge rst_n)begin // if(!rst_n)begin// en_r[7:0] <= 8'h0;// end // else begin// en_r[7:0] <= {en_r[6:0],en_temp};// end // end // assign en=en_r[7];always @(posedge clk or negedge rst_n)begin if(!rst_n)beginread_id <= 1'b0;end else if(erase_start|write_start|second_erase_start)begin read_id <= 1'b1;endelse beginread_id <= 1'b0;end end always @(posedge clk or negedge rst_n)begin if(!rst_n | m_state_c == M_IDLE)beginread_id_cnt <= 'd0;end else if(m_state_c == M_RDID && read_data_vld)begin read_id_cnt <= read_id_cnt + 1'b1;endelse beginread_id_cnt <= read_id_cnt;end end always @(posedge clk or negedge rst_n)begin if(!rst_n | m_state_c == M_IDLE)beginfirst_id <= 'd0;second_id <= 'd0;third_id <= 'd0;end else if(m_state_c == M_RDID && read_data_vld &&read_id_cnt==0)begin first_id <= read_data;endelse if(m_state_c == M_RDID && read_data_vld &&read_id_cnt==1)begin second_id <= read_data;end else if(m_state_c == M_RDID && read_data_vld &&read_id_cnt==2)begin third_id <= read_data;endelse beginfirst_id <= first_id ;second_id <= second_id;third_id <= third_id ; end end always @(posedge clk or negedge rst_n)begin if(!rst_n )beginread_done_r1<=1'b0;read_done_r2<=1'b0;read_done_r3<=1'b0;end else begin read_done_r1<=read_done;read_done_r2<=read_done_r1;read_done_r3<=read_done_r2;endendalways @(posedge clk or negedge rst_n)begin if(!rst_n | m_state_c == M_IDLE)beginread_id_flag <= 2'b00;end else if(read_done_r3 && first_id==`MF_ID && second_id == `ID1 && third_id == `ID2)begin read_id_flag <= 2'b11;endelse if(read_done_r3 && (first_id != `MF_ID || second_id != `ID1 || third_id != `ID2))begin read_id_flag <= 2'b10;//实际// read_id_flag <= 2'b11;//仿真endelse if(m_state_c != M_RDID)beginread_id_flag <= 2'b00; end else beginread_id_flag <= read_id_flag;end end always @(posedge clk or negedge rst_n)begin if(!rst_n | m_state_c == M_IDLE)beginerase_cnt <= 'd0;end else if(m_se2m_rdsr)begin erase_cnt <= erase_cnt + 1'b1;endelse beginerase_cnt <= erase_cnt;end endalways @(posedge clk or negedge rst_n)begin if(!rst_n | m_state_c == M_IDLE)beginrdsr_sta_reg_vld <= 1'b0;end else if(m_state_c == M_RDSR && read_data_vld && read_data[1:0] == 2'b00)begin rdsr_sta_reg_vld <= 1'b1;endelse if(m_state_c != M_RDSR)beginrdsr_sta_reg_vld <= 1'b0;end else beginrdsr_sta_reg_vld <= rdsr_sta_reg_vld ; end end always @(posedge clk or negedge rst_n)begin if(!rst_n)beginread_rdsr <= 1'b0;end else if(m_se2m_rdsr|m_wait2m_rdsr|m_pp2m_rdsr)begin read_rdsr <= 1'b1;endelse beginread_rdsr <= 1'b0;end endalways @(posedge clk or negedge rst_n)begin if(!rst_n)beginwait_time_cnt <= 24'd0;end else if(m_state_c == M_WAIT)begin wait_time_cnt <= wait_time_cnt+1'b1;endelse if(m_state_c != M_WAIT)beginwait_time_cnt <= 24'd0; end else beginwait_time_cnt <= wait_time_cnt;end end always @(posedge clk or negedge rst_n)begin if(!rst_n | m_state_c == M_IDLE)beginpp_cnt <= 'd0;end else if(m_pp2m_rdsr)begin pp_cnt <= pp_cnt + 1'b1;endelse beginpp_cnt <= pp_cnt;end end always @(posedge clk or negedge rst_n)begin if(!rst_n)beginread_data_flag <= 1'b0;end else if(m_rdsr2m_rdda)begin read_data_flag <= 1'b1;endelse beginread_data_flag <= 1'b0;end end// reg erase_completed;always @(posedge clk or negedge rst_n)begin if(!rst_n)beginerase_completed <= 1'b0;end else if(m_rdsr2m_idle)begin erase_completed <= 1'b1;endelse if(cmd_reply_clear_finish)beginerase_completed <= 1'b0;end end//// reg second_erase_start;always @(posedge clk or negedge rst_n)begin if(!rst_n)beginsecond_erase_start <= 1'b0;end else if(m_rdid2m_idle)begin second_erase_start <= 1'b1;endelse if(m_idle2m_rdid)beginsecond_erase_start <= 1'b0;end endendmodule
`include "param.v" module flash_read( input clk ,input rst_n ,input read_id,input read_rdsr,input read_data_flag,(*mark_debug="true", dont_touch="true"*) output reg read_only_data_flag,output wire busy_read,input spi_one_byte_done ,output en ,output read_done ,output read_spi_one_byte_vld ,output reg [7:0] read_state_spi_out ); //参数定义 parameter IDLE =9'b00000_0001,RDID_CMD =9'b00000_0010, RDID_DATA =9'b00000_0100,RDSR_CMD =9'b00000_1000,RDSR_DATA =9'b00001_0000,RDAD_CMD =9'b00010_0000, RDAD_ADDR =9'b00100_0000, RDAD_DATA =9'b01000_0000, RD_DONE =9'b10000_0000;parameter INIT_ADDR = 24'h80_0000;//中间信号定义 (*mark_debug="true", dont_touch="true"*) reg [8:0] state_c ;reg [8:0] state_n ;reg [8:0] cnt_byte ;wire add_cnt_byte ;wire end_cnt_byte ;reg [8:0] byte_num ;(*mark_debug="true", dont_touch="true"*) reg [23:0] addr_rd ;wire idle2rdid_cmd ;wire idle2rdsr_cmd ;wire idle2rdad_cmd ;wire rdid_cmd2rdid_data ;wire rdsr_cmd2rdsr_data ;wire rdad_cmd2rdad_addr ;wire rdad_addr2rdad_data ;wire rdid_data2rd_done ;wire rdsr_data2rd_done ;wire rdad_data2rd_done ;wire rd_done2idle ;//状态机always @(posedge clk or negedge rst_n)begin if(!rst_n)beginstate_c <= IDLE;end else begin state_c <= state_n;end endalways @(*)begin case (state_c)IDLE : begin if (idle2rdid_cmd) beginstate_n <= RDID_CMD;endelse if(idle2rdsr_cmd) beginstate_n <= RDSR_CMD;end else if(idle2rdad_cmd) beginstate_n <= RDAD_CMD;endelse beginstate_n <= state_c;end endRDID_CMD : begin if(rdid_cmd2rdid_data)beginstate_n <= RDID_DATA;endelse beginstate_n <= state_c;end endRDID_DATA : begin if (rdid_data2rd_done) beginstate_n <= RD_DONE;endelse beginstate_n <= state_c;endend RDSR_CMD : begin if(rdsr_cmd2rdsr_data)beginstate_n <= RDSR_DATA;endelse beginstate_n <= state_c;end end RDSR_DATA : begin if (rdsr_data2rd_done) beginstate_n <= RD_DONE;endelse beginstate_n <= state_c;end endRDAD_CMD : begin if (rdad_cmd2rdad_addr) beginstate_n <= RDAD_ADDR;endelse beginstate_n <= state_c;endendRDAD_ADDR : begin if (rdad_addr2rdad_data ) beginstate_n <= RDAD_DATA;endelse beginstate_n <= state_c;end endRDAD_DATA : begin if(rdad_data2rd_done)beginstate_n <= RD_DONE;endelse beginstate_n <= state_c;endendRD_DONE : begin if(rd_done2idle)beginstate_n <= IDLE;endelse beginstate_n <= state_c;endenddefault: state_n <= state_c;endcaseendassign idle2rdid_cmd = state_c == IDLE && read_id ; assign idle2rdsr_cmd = state_c == IDLE && read_rdsr ; assign idle2rdad_cmd = state_c == IDLE && read_data_flag ; assign rdid_cmd2rdid_data = state_c == RDID_CMD && end_cnt_byte; assign rdsr_cmd2rdsr_data = state_c == RDSR_CMD && end_cnt_byte; assign rdad_cmd2rdad_addr = state_c == RDAD_CMD && end_cnt_byte; assign rdad_addr2rdad_data = state_c == RDAD_ADDR && end_cnt_byte; assign rdid_data2rd_done = state_c == RDID_DATA && end_cnt_byte; assign rdsr_data2rd_done = state_c == RDSR_DATA && end_cnt_byte;assign rdad_data2rd_done = state_c == RDAD_DATA && end_cnt_byte; assign rd_done2idle = state_c == RD_DONE && 1'b1;//计数器always @(posedge clk or negedge rst_n)begin if(!rst_n)begincnt_byte <= 0;end else if(add_cnt_byte)begin if(end_cnt_byte)begin cnt_byte <= 0;endelse begin cnt_byte <= cnt_byte + 1;end endelse begincnt_byte <= cnt_byte;endend assign add_cnt_byte = (state_c == RDID_CMD | state_c == RDID_DATA |state_c == RDSR_CMD | state_c == RDSR_DATA | state_c == RDAD_CMD | state_c == RDAD_ADDR |state_c == RDAD_DATA) && spi_one_byte_done;assign end_cnt_byte = add_cnt_byte && cnt_byte == byte_num-1;always @(posedge clk or negedge rst_n)begin if(!rst_n)beginbyte_num <= 0;end else if(state_c == RDID_CMD |state_c == RDSR_CMD | state_c == RDAD_CMD )begin byte_num <= `CMD_BYTE; end else if(state_c == RDID_DATA)begin byte_num <= `ID_BYTE; end else if(state_c == RDSR_DATA)begin byte_num <= `RDSR_BYTE; end else if (state_c == RDAD_ADDR) beginbyte_num <= `ADDR_BYTE;endelse if(state_c == RDAD_DATA)beginbyte_num <= `DATA_BYTE;endend//addr_rdalways @(posedge clk or negedge rst_n)begin if(!rst_n /* | addr_rd==24'h00_0400 */)beginaddr_rd <= INIT_ADDR;end else if(rdad_data2rd_done)begin addr_rd <= addr_rd + 24'h00_0100;end else begin addr_rd <= addr_rd;end end//输出 //read_state_spi_outalways @(posedge clk or negedge rst_n)begin if(!rst_n)beginread_state_spi_out <= 0;end else if(state_c == RDID_CMD)begin read_state_spi_out <= `CMD_RDID;end else if(state_c == RDSR_CMD)begin read_state_spi_out <= `CMD_RDSR;end else if(state_c == RDAD_CMD)begin read_state_spi_out <= `CMD_READ;endelse if(state_c == RDAD_ADDR)beginif(cnt_byte == 0)beginread_state_spi_out <= addr_rd[23:16];endelse if(cnt_byte == 1)beginread_state_spi_out <= addr_rd[15:8];endelse if(cnt_byte == 2)beginread_state_spi_out <= addr_rd[7:0];endendelse beginread_state_spi_out <= read_state_spi_out;end end//en read_done dtat_m_vldassign en =(read_id |read_rdsr| read_data_flag) & state_c == IDLE;assign read_done = rdid_data2rd_done | rdsr_data2rd_done| rdad_data2rd_done;assign read_spi_one_byte_vld = spi_one_byte_done && (state_c == RDID_DATA | state_c == RDSR_DATA | state_c == RDAD_DATA);// assign read_only_data_flag=state_c == RDAD_DATA;always @(posedge clk or negedge rst_n)begin if(!rst_n)beginread_only_data_flag<=1'b0;end else if(state_c == RDAD_DATA)beginread_only_data_flag<=1'b1;endelse beginread_only_data_flag<=1'b0;end end assign busy_read= !(state_c==IDLE);endmodule
`include "param.v"module spi_master( input clk ,input rst_n ,input en ,input [1:0] spi_mode,input spi_vld ,input [7:0] spi_din ,input miso ,output reg sck ,output reg cs_n ,output mosi ,output reg [7:0] spi_dout ,output reg busy ,output spi_one_byte_done ); //中间信号定义 reg [4:0] cnt_bit ;wire add_cnt_bit ;wire end_cnt_bit ;reg [8:0] cnt_sck ;wire add_cnt_sck ;wire end_cnt_sck ;reg end_cnt_sck_r ;//计数器 //cnt_sckalways @(posedge clk or negedge rst_n)begin if(!rst_n)begincnt_sck <= 0;end else if(add_cnt_sck)begin if(end_cnt_sck | en)begin cnt_sck <= 0;endelse begin cnt_sck <= cnt_sck + 1;end endelse begincnt_sck <= cnt_sck;endend assign add_cnt_sck = spi_vld;assign end_cnt_sck = add_cnt_sck && cnt_sck == `SCK_PERIOD-1;//cnt_bitalways @(posedge clk or negedge rst_n)begin if(!rst_n)begincnt_bit <= 0;end else if(add_cnt_bit )begin if(end_cnt_bit | en)begin cnt_bit <= 0;endelse begin cnt_bit <= cnt_bit + 1;end endelse begincnt_bit <= cnt_bit;endend assign add_cnt_bit = (cs_n == 0)&& end_cnt_sck;assign end_cnt_bit = add_cnt_bit && cnt_bit == 8-1;//sckalways @(*)begincase (spi_mode)0 : begin if(spi_vld && (cnt_sck <= `SCK_HALF-1))beginsck <= 0;endelse if(cnt_sck > `SCK_HALF-1)beginsck <= 1;end else beginsck <= 0; end end1 : begin if(spi_vld && (cnt_sck <= `SCK_HALF-1))beginsck <= 1;endelse if(cnt_sck > `SCK_HALF-1)beginsck <= 0;end else beginsck <= 0; end end2 : begin if(spi_vld && (cnt_sck <= `SCK_HALF-1 ))beginsck <= 1;endelse if(cnt_sck > `SCK_HALF-1 )beginsck <= 0;end else beginsck <= 1;endend3 : begin if(spi_vld && (cnt_sck <= `SCK_HALF-1))beginsck <= 0;endelse if(cnt_sck > `SCK_HALF-1 )beginsck <= 1;end else beginsck <= 1;endend default: sck <= sck;endcaseend//end_cnt_sck_ralways @(posedge clk or negedge rst_n)begin if(!rst_n)beginend_cnt_sck_r <= 0;end else begin end_cnt_sck_r <= end_cnt_sck;end end//输出//cs_nalways @(posedge clk or negedge rst_n)begin if(!rst_n)begincs_n <= 1;end else if(en)begin cs_n <= 0; end else if(cs_n == 0 && (!spi_vld) && end_cnt_sck_r)begin cs_n <= 1;end end//mosiassign mosi = spi_din[7-cnt_bit]; //spi_dout always @(posedge clk or negedge rst_n)begin if(!rst_n)beginspi_dout <= 0;end else if(cs_n == 0 && cnt_sck == `SCK_PERIOD-1)begin spi_dout[7-cnt_bit] <= miso;end else begin spi_dout <= spi_dout; end end//spi_one_byte_doneassign spi_one_byte_done = end_cnt_bit;//busyalways @(posedge clk or negedge rst_n)begin if(!rst_n)beginbusy <= 0;end else if(add_cnt_bit && end_cnt_bit == 0)begin busy <= 1;end else if(end_cnt_bit)begin busy <= 0;end endendmodule
//参数定义//spi时钟参数`define SCK_PERIOD 20`define SCK_HALF 10//spi command`define CMD_WREN 8'h06 // `define CMD_WRDI 8'h04 // `define CMD_RDID 8'h9f // `define CMD_RDSR 8'h05 // `define CMD_WRSR 8'h01 // `define CMD_READ 8'h03 // `define CMD_FAST_READ 8'h0b // `define CMD_PP 8'h02 // `define CMD_SE 8'hd8 // `define CMD_BE 8'hc7 // `define CMD_DP 8'hb9 // `define CMD_RES 8'hab // //spi byte`define CMD_BYTE 1 // 命令1字节数 `define ADDR_BYTE 3 // 地址3字节数 `define ID_BYTE 3 // 读取id字节数 `define DATA_BYTE 256 // 读取数据字节数 `define RDSR_BYTE 1 // 读状态寄存器字节数// `define DELAY_5MS 250_000 // 5ms 数据写入后需要等待5ms才能读出`define DELAY_5MS 50 // 5ms 数据写入后需要等待5ms才能读出 //波特率`define BAUD_9600 5208`define BAUD_19200 2604`define BAUD_38400 1302`define BAUD_115200 434`define STOP_BIT 1'b1 //数据停止位`define START_BIT 1'b0 //数据开始位 `define MF_ID 8'h20 `define ID1 8'hBA `define ID2 8'h18
仿真相关:
module top( input wire sys_clk_p, //system clock positiveinput wire sys_clk_n, //system clock negative input wire rst_n , //reset ,low active input erase_start,input write_start,// output erase_completed, //仿真// output four_pp_completed,//仿真input miso ,// output sck ,output mosi ,output cs_n );wire erase_completed;//调试wire four_pp_completed;//调试wire sck;IBUFGDS sys_clk_ibufgds ( .O (sys_clk ),//200MHz .I (sys_clk_p ), .IB (sys_clk_n ) );STARTUPE2 #(.PROG_USR("FALSE"), // Activate program event security feature. Requires encrypted bitstreams..SIM_CCLK_FREQ(0.0) // Set the Configuration Clock Frequency(ns) for simulation. )STARTUPE2_spi (.CFGCLK(), // 1-bit output: Configuration main clock output.CFGMCLK( ), // 1-bit output: Configuration internal oscillator clock output.EOS(), // 1-bit output: Active high output signal indicating the End Of Startup..PREQ(), // 1-bit output: PROGRAM request to fabric output.CLK(1'b0), // 1-bit input: User start-up clock input.GSR(1'b0), // 1-bit input: Global Set/Reset input (GSR cannot be used for the port name).GTS(1'b0), // 1-bit input: Global 3-state input (GTS cannot be used for the port name).KEYCLEARB(1'b1), // 1-bit input: Clear AES Decrypter Key input from Battery-Backed RAM (BBRAM).PACK(1'b1), // 1-bit input: PROGRAM acknowledge input.USRCCLKO(sck), // 1-bit input: User CCLK input.USRCCLKTS(1'b0), // 1-bit input: User CCLK 3-state enable input.USRDONEO(1'b1), // 1-bit input: User DONE pin output control.USRDONETS(1'b1) // 1-bit input: User DONE 3-state enable output );reg [5:0] cnt_clk=0; wire add_cnt_clk; wire end_cnt_clk; always@(posedge sys_clk or negedge rst_n)beginif(rst_n==1'b0)begincnt_clk<=0;endelse if(add_cnt_clk)beginif(end_cnt_clk)cnt_clk<=0;elsecnt_clk<=cnt_clk+1;end end assign add_cnt_clk = 1; assign end_cnt_clk = add_cnt_clk && cnt_clk == 2-1;// reg clk;//100MHz // always@(posedge sys_clk)begin// if(cnt_clk<1)begin// clk<=1'b1;// end// else begin// clk<=1'b0;// end // end wire clk; assign clk=sys_clk;// wire clk_out1; // wire clk_out2;// clk_wiz_0 clk_wiz_0_uut// (// .clk_out1(clk_out1), // output clk_out1// .clk_out2(clk_out2), // output clk_out2// .reset(~rst_n), // input reset// .locked(locked), // output locked// .clk_in1(sys_clk)); // input clk_in1// wire clk; // assign clk=clk_out2 & locked;//===========================vio========================================= wire earse_start_vio; wire write_start_vio; wire read_start_vio; vio_0 uut_vio_0 (.clk(clk), .probe_out0(earse_start_vio), .probe_out1(write_start_vio),.probe_out2(read_start_vio) ); reg earse_start_r1; always@(posedge clk)begin earse_start_r1<=earse_start_vio; endwire earse_edge; assign earse_edge= earse_start_r1 & ~earse_start_vio;reg write_start_r1; always@(posedge clk)begin write_start_r1<=write_start_vio; endwire write_edge; assign write_edge= write_start_r1 & ~write_start_vio;reg read_start_r1; always@(posedge clk)begin read_start_r1<=read_start_vio; endwire read_edge; assign read_edge= read_start_r1 & ~read_start_vio; //===========================test========================================= reg I_fl_data_en ; wire end_cnt0;always @(posedge clk or negedge rst_n)begin if(!rst_n)beginI_fl_data_en <= 0;end// else if(write_start) begin //仿真else if(write_edge)begin //实际I_fl_data_en <= 1;end else if(end_cnt0) beginI_fl_data_en <= 0;end end reg [15:0] cnt0; wire add_cnt0; // wire end_cnt0; always@(posedge clk or negedge rst_n)beginif(rst_n==1'b0)begincnt0<='d0;endelse if(add_cnt0)beginif(end_cnt0)cnt0<=0;elsecnt0<=cnt0+1;end end assign add_cnt0 = I_fl_data_en; assign end_cnt0 = add_cnt0 && cnt0 == 1024-1;//256-1;// (*mark_debug="true", dont_touch="true"*)wire [7:0] wr_rd_state_spi_out ;(*mark_debug="true", dont_touch="true"*)wire [7:0] dout ;//读取数据(*mark_debug="true", dont_touch="true"*)wire dout_vld ;//数据有效(*mark_debug="true", dont_touch="true"*)wire spi_vld ;(*mark_debug="true", dont_touch="true"*)wire en ;(*mark_debug="true", dont_touch="true"*)wire [7:0] spi_dout ;//读取数据进入fifo (*mark_debug="true", dont_touch="true"*)wire spi_one_byte_done ; // (*mark_debug="true", dont_touch="true"*) wire [1:0] key_out;// key_filter_fsm # (.KEY_W(2),.TIME_20MS(1_000_000))u_key_filter_fsm// (// /*input */.clk (clk ),// /*input */.rst_n (rst_n ),// /*input [KEY_W - 1:0] */.key_in ({write_start,erase_start} ),// /*output [KEY_W - 1:0] */.key_out (key_out )// ); wr_control u_wr_control( /*input */.clk (clk ),/*input */.rst_n (rst_n ),// `ifdef simulation// `elsif// .erase_start (erase_start),// erase_start 仿真// .write_start (write_start),//write_start .erase_start (earse_edge ),//erase_start 调试.write_start (write_edge ),//write_start .erase_completed(erase_completed),.four_pp_completed(four_pp_completed),.read_start(read_edge),// `endif /*input */.spi_one_byte_done (spi_one_byte_done ),/*input [7:0] */.din (cnt0[7:0]),//(rx_byte ),// /*input */.din_vld (I_fl_data_en),//(rx_byte_vld ),// /*input [7:0] */.read_data (spi_dout ),/*output reg [7:0] */.wr_rd_state_spi_out (wr_rd_state_spi_out ),/*output [7:0] */.read_flash_data_fifo_out (dout ),/*output */.read_flash_data_fifo_out_vld (dout_vld ),/*output */.en (en ),/*output */.spi_vld (spi_vld ) );spi_master u_spi_master( /*input */.clk (clk ),/*input */.rst_n (rst_n ),/*input */.en (en ),/*input [1:0] */.spi_mode (2'b00 ),/*input */.spi_vld (spi_vld ),/*input [7:0] */.spi_din (wr_rd_state_spi_out),//写入数据/*input */.miso (miso ),/*output reg */.sck (sck ),/*output reg */.cs_n (cs_n ),/*output */.mosi (mosi ),/*output reg [7:0] */.spi_dout (spi_dout ),//读取数据/*output reg */.busy ( ),/*output */.spi_one_byte_done (spi_one_byte_done ) ); endmodule
`timescale 1ns / 1ps // `define simulation module top_tb();//时钟与复位 reg sys_clk_p; reg rst_n;//uut的输入信号 reg erase_start ; reg write_start ; reg miso; //时钟周期,单位为ns, parameter CYCLE = 5; //复位时间,此时表示复位3个时钟周期的时间 parameter RST_TIME = 3;//待测试的模块例化 top uut( .sys_clk_p(sys_clk_p), .sys_clk_n(~sys_clk_p), .rst_n (rst_n),.erase_start (erase_start ), .write_start (write_start ),.miso (miso), .mosi (mosi), .cs_n (cs_n) );//生成本地时钟200M initial beginsys_clk_p =0;forever#(CYCLE/2)sys_clk_p =~sys_clk_p; end //产生复位信号 initial beginrst_n =1;#2;rst_n =0; #(CYCLE*RST_TIME)rst_n =1; end initial begin write_start=0;erase_start =0;#1000erase_start =1; #100erase_start =0; #35_0000 //擦除4块 write_start=1; #100 write_start=0;#180_0000 write_start=1; #100 write_start=0; // #10_0000 //擦除4块 // write_start=1; // #100 // write_start=0;// #180_0000 // write_start=1; // #100 // write_start=0;end initial beginmiso =0;end endmodule
xilinx在线升级相关:
这里icap控制跳转的代码,测试可用,以下是原文连接:
https://blog.csdn.net/qq_43557686/article/details/134750377?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522028715b643b80c588730a73e4c1310ae%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=028715b643b80c588730a73e4c1310ae&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_ecpm_v1~rank_v31_ecpm-1-134750377-null-null.nonecase&utm_term=icap&spm=1018.2226.3001.4450
/* * file : multiboot_ctrl.v* author : 今朝无言* Lab : WHU-EIS-LMSWE* date : 2023-11-30* version : v1.0* description : ICAP 原语实现程控 multiboot(多重启动),K7需要使用 ICAPE2 原语* Copyright © 2023 WHU-EIS-LMSWE, All Rights Reserved.*/module multiboot_ctrl( input wire clk, input wire rst_n,input wire multiboot_start, //触发Multiboot, 上升沿有效 input wire [31:0] multiboot_addr, //要启动的Muliboot Image的起始地址output reg busy );//-------------------ICAPE2原语----------------------------- wire ICAPE2_CLK; wire [31:0] ICAPE2_O; reg ICAPE2_CSIB; wire [31:0] ICAPE2_I; reg ICAPE2_RDWRB;assign ICAPE2_CLK = clk;ICAPE2 #(.DEVICE_ID (32'h3631093), // Specifies the pre-programmed Device ID value to be used for simulation purposes. K7-100T的为32'h3631093.ICAP_WIDTH ("X32"), // Specifies the input and output data width..SIM_CFG_FILE_NAME ("NONE") // Specifies the Raw Bitstream (RBT) file to be parsed by the simulation model. ) ICAPE2_inst(.O (ICAPE2_O), // 32-bit output: Configuration data output bus.CLK (ICAPE2_CLK), // 1-bit input: Clock Input.CSIB (ICAPE2_CSIB), // 1-bit input: Active-Low ICAP Enable.I (ICAPE2_I), // 32-bit input: Configuration data input bus.RDWRB (ICAPE2_RDWRB) // 1-bit input: Read/Write Select input 1对应rd,0对应wr );wire [31:0] Dummy = 32'hFFFFFFFF; wire [31:0] Sync_Word = 32'hAA995566; wire [31:0] NOOP = 32'h20000000; wire [31:0] WR_WBSTAR = 32'h30020001;/*When using ICAPE2 to set the WBSTAR address, the 24 most significant address bits should be writtento WBSTAR[23:0]. For SPI 32-bit addressing mode, WBSTAR[23:0] are sent as address bits [31:8]. Thelower 8 bits of the address are undefined and the value could be as high as 0xFF. Any bitstreamat the WBSTAR address should contain 256 dummy bytes before the start of the bitstream.*/ wire [31:0] WBSTAR = {3'b000, 5'h0, multiboot_addr[31:8]};wire [31:0] WR_CMD = 32'h30008001; wire [31:0] IPROG = 32'h0000000F;//ICAPE2位翻转 reg [31:0] wrdat; assign ICAPE2_I = {wrdat[24], wrdat[25], wrdat[26], wrdat[27], wrdat[28], wrdat[29], wrdat[30], wrdat[31], wrdat[16], wrdat[17], wrdat[18], wrdat[19], wrdat[20], wrdat[21], wrdat[22], wrdat[23], wrdat[8], wrdat[9], wrdat[10], wrdat[11], wrdat[12], wrdat[13], wrdat[14], wrdat[15], wrdat[0], wrdat[1], wrdat[2], wrdat[3], wrdat[4], wrdat[5], wrdat[6], wrdat[7]};//------------------------FSM---------------------------------- localparam S_IDLE = 16'h0001; localparam S_DUMMY = 16'h0002; localparam S_SYN_WORD = 16'h0004; localparam S_NOOP1 = 16'h0008; localparam S_WR_WBSTAR = 16'h0010; localparam S_WBSTAR = 16'h0020; localparam S_WR_CMD = 16'h0040; localparam S_IPROG = 16'h0080; localparam S_NOOP2 = 16'h0100; localparam S_STOP = 16'h0200; (*mark_debug="true", dont_touch="true"*)wire multiboot_start_pe; reg multiboot_start_d0; reg multiboot_start_d1;assign multiboot_start_pe = multiboot_start_d0 & (~multiboot_start_d1);always @(posedge clk) beginmultiboot_start_d0 <= multiboot_start;multiboot_start_d1 <= multiboot_start_d0; end(*mark_debug="true", dont_touch="true"*) reg [15:0] state = S_IDLE; reg [15:0] next_state;always @(posedge clk) beginif(~rst_n) beginstate <= S_IDLE;endelse beginstate <= next_state;end endalways @(*) begincase(state)S_IDLE: beginif(multiboot_start_pe) beginnext_state <= S_DUMMY;endelse beginnext_state <= S_IDLE;endendS_DUMMY: next_state <= S_SYN_WORD;S_SYN_WORD: next_state <= S_NOOP1;S_NOOP1: next_state <= S_WR_WBSTAR;S_WR_WBSTAR: next_state <= S_WBSTAR;S_WBSTAR: next_state <= S_WR_CMD;S_WR_CMD: next_state <= S_IPROG;S_IPROG: next_state <= S_NOOP2;S_NOOP2: next_state <= S_STOP;S_STOP: next_state <= S_IDLE;default: next_state <= S_IDLE;endcase endalways @(posedge clk) begincase(state)S_IDLE: beginwrdat <= 32'd0;ICAPE2_CSIB <= 1'b1;ICAPE2_RDWRB <= 1'b1;endS_DUMMY: beginwrdat <= Dummy;ICAPE2_CSIB <= 1'b0;ICAPE2_RDWRB <= 1'b0;endS_SYN_WORD: beginwrdat <= Sync_Word;ICAPE2_CSIB <= 1'b0;ICAPE2_RDWRB <= 1'b0;endS_NOOP1: beginwrdat <= NOOP;ICAPE2_CSIB <= 1'b0;ICAPE2_RDWRB <= 1'b0;endS_WR_WBSTAR: beginwrdat <= WR_WBSTAR;ICAPE2_CSIB <= 1'b0;ICAPE2_RDWRB <= 1'b0;endS_WBSTAR: beginwrdat <= WBSTAR;ICAPE2_CSIB <= 1'b0;ICAPE2_RDWRB <= 1'b0;endS_WR_CMD: beginwrdat <= WR_CMD;ICAPE2_CSIB <= 1'b0;ICAPE2_RDWRB <= 1'b0;endS_IPROG: beginwrdat <= IPROG;ICAPE2_CSIB <= 1'b0;ICAPE2_RDWRB <= 1'b0;endS_NOOP2: beginwrdat <= NOOP;ICAPE2_CSIB <= 1'b0;ICAPE2_RDWRB <= 1'b0;endS_STOP: beginwrdat <= 32'd0;ICAPE2_CSIB <= 1'b1;ICAPE2_RDWRB <= 1'b1;enddefault: beginwrdat <= 32'd0;ICAPE2_CSIB <= 1'b1;ICAPE2_RDWRB <= 1'b1;endendcase endalways@(*)beginif(state==S_IDLE)busy <= 1'b0;else busy <= 1'b1; endendmodule
//上电初始化信号 // parameter STA_EN_DLY = 32'd399_999_999; parameter STA_EN_DLY = 32'd7_999_999_999;//64s (*mark_debug="true", dont_touch="true"*)reg [32:0] power_ini_cnt; always @(posedge clk or negedge rst_n)beginif(rst_n==1'b0)beginpower_ini_cnt<='d0;endelse if(power_ini_cnt < STA_EN_DLY)beginpower_ini_cnt<=power_ini_cnt+1'b1;endelse beginpower_ini_cnt<=power_ini_cnt;end end reg power_en; always @(posedge clk or negedge rst_n)beginif(rst_n==1'b0)beginpower_en<= 1'b0;end else if(power_ini_cnt == STA_EN_DLY) beginpower_en<= 1'b1;end else beginpower_en<= 1'd0;end endreg power_en_r1; reg power_en_r2; always @(posedge clk or negedge rst_n)beginif(rst_n==1'b0)beginpower_en_r1 <= 1'b0;power_en_r2 <= 1'b0;end else beginpower_en_r1 <= power_en;power_en_r2 <= power_en_r1;end end// (*mark_debug="true", dont_touch="true"*)wire power_ini_pos; assign power_ini_pos = power_en_r1 & ~power_en_r2; // (*mark_debug="true", dont_touch="true"*)reg erase_write_start_reg; always @(posedge clk or negedge rst_n)beginif(rst_n==1'b0)beginerase_write_start_reg<= 1'b0;end else if(erase_start|write_start) beginerase_write_start_reg<= 1'b1;end else beginerase_write_start_reg<= erase_write_start_reg;end end // (*mark_debug="true", dont_touch="true"*)reg multiboot_start; always @(posedge clk or negedge rst_n)beginif(rst_n==1'b0)beginmultiboot_start<= 1'b0;end else if(power_ini_pos&(~erase_write_start_reg)) beginmultiboot_start<= 1'b1;end else if(update_end)beginmultiboot_start<= 1'b0;//1'b0不跳//1'b1跳end else beginmultiboot_start<= 1'b0;end end// multiboot_ctrl multiboot_ctrl_inst(.clk (clk),//(sys_clk), .rst_n (rst_n),.multiboot_start (multiboot_start),//(~key_in[0]),//key_in[0]---key1 key_in[1]---key2 .multiboot_addr (32'h80000000), //实际是(32'h00800000),模块内部移动了8位 //加载0x01000000处的Multiboot Image .busy () );
multiboot_addr的地址这里写的是0x8000_0000,实际上在multiboot_ctrl内部做了8位偏移,而我使用的FLASH型号的S25FL128,采用的是24位地址。实际上跳转地址是0x0080_0000,经过仿真输出的是0x0080_0000;
XDC相关:
############## NET - IOSTANDARD ###################### set_property CFGBVS VCCO [current_design] set_property CONFIG_VOLTAGE 3.3 [current_design] #############SPI Configurate Setting################## #set_property BITSTREAM.CONFIG.CONFIGRATE 50 [current_design]set_property BITSTREAM.CONFIG.UNUSEDPIN Pullnone [current_design] set_property BITSTREAM.CONFIG.CONFIGRATE 50 [current_design] set_property BITSTREAM.CONFIG.TIMER_CFG 32'h0007A120 [current_design] ##for golden image set_property BITSTREAM.CONFIG.CONFIGFALLBACK ENABLE [current_design] #set_property BITSTREAM.CONFIG.NEXT_CONFIG_ADDR 32'h00800000 [current_design] set_property BITSTREAM.GENERAL.COMPRESS TRUE [current_design] set_property BITSTREAM.CONFIG.SPI_BUSWIDTH 1 [current_design]
############## NET - IOSTANDARD ###################### set_property CFGBVS VCCO [current_design] set_property CONFIG_VOLTAGE 3.3 [current_design] #############SPI Configurate Setting################## #set_property BITSTREAM.CONFIG.CONFIGRATE 50 [current_design]set_property BITSTREAM.CONFIG.UNUSEDPIN Pullnone [current_design] set_property BITSTREAM.CONFIG.CONFIGRATE 50 [current_design] set_property BITSTREAM.CONFIG.TIMER_CFG 32'h0007A120 [current_design] #for multiboot image set_property BITSTREAM.CONFIG.CONFIGFALLBACK ENABLE [current_design] set_property BITSTREAM.GENERAL.COMPRESS TRUE [current_design] set_property BITSTREAM.CONFIG.SPI_BUSWIDTH 1 [current_design]
使用icap跳转升级流程:
1.升级指令顺序:
第一步,首先发送第六条升级启动指令,该指令将update区跳转到golden区,(如果已再golden区则可不用)
第二步,获取golden版本号,如果获取到golden版本号说明跳转成功
第三步,golden区版本号获取成功,开始进行擦除操作,
第四步,收到擦除完成信号,可以发送写升级包数据命令;发一包(1024字节写4页)后,收到应答后再下发一包,直到所有包发完,
第五步,掉电,拔掉jtag下载线,重启
2.注意事项:
每次重启后,先进入golden版本,一分钟内如果未收到擦除写flash命令,一分钟后,自动跳转到update版本;如果update版本破坏,则回退至golden版本,
如果需要升级,则需要跳转到golden区,update版本不具有擦写flash权,防止升级掉电版本不回退;
这里有一个问题:当update区没有数据或者数据破坏时,可以退回golden区,如果没有升级操作,两个区会一直来回跳,如果此时想使用golden区,那么这里的方法是,当进入golden区,一分钟内,发送擦除指令,这样就会一直停留在golden区,
使用工具:
软件:vivado2019.1
使用的FPGA型号为XC7A100T-2FGG4841,属于Xilinx 公司 Artix-7 系列的产品,速度等级为 2,温度等级为工业级。此型号为 FGG484封装,484 个引脚。
使用了一片 容量16M的 QSPI FLASH 芯片,型号为 N25Q128,它使用 3.3V CMOS 电压标准。由于它的非易失特性,在使用中,QSPIFLASH 可以作为 FPGA 系统的启动镜像。
vivado可选Mt25ql128-spi-x1_x2_x4









合成mcs,


参考连接:
K7系列FPGA多重启动(Multiboot)(今朝无言)
https://blog.csdn.net/qq_43557686/article/details/134750377?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522028715b643b80c588730a73e4c1310ae%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=028715b643b80c588730a73e4c1310ae&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_ecpm_v1~rank_v31_ecpm-1-134750377-null-null.nonecase&utm_term=icap&spm=1018.2226.3001.4450
FPGA在线升级 -- Multiboot(热爱学习地派大星)
https://blog.csdn.net/weixin_51418325/article/details/144370219?utm_medium=distribute.pc_relevant.none-task-blog-2~default~baidujs_baidulandingword~default-5-144370219-blog-136070049.235^v43^pc_blog_bottom_relevance_base8&spm=1001.2101.3001.4242.4&utm_relevant_index=7
感谢各位前辈的指路,记录一下,
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/972180.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!