eFlash控制器的RTL
gvim 操作
- gg -- 跳到首页
- GG -- 按住shift,跳到尾部
- ctrl+V --> 上下键选择行 --> shift+i -->输入 -->esc退出 -- 实现列操作
- u -- 撤销操作
- . -- 重复上一次操作
- v/flash/d -- 删除有flash的行
- g/flash/d -- 保留有flash的行
- cw -- 删除原来的word进入insert,替换原来的word -- 用点进行重复操作
- shift+v -- 进入visual lines模式 -- >选择行 --> y复制 --> 移动光标 p复制,8p复制8份
flash_ahb_slave_if
// flash_ahb_slave_if
module flash_ahb_slave_if(
//********************************************************
// input signals //
//********************************************************
// ahb signals
hclk,
hresetn,
hsel,
hready_in,
hwrite,
hsize,
htrans,
hburst,
hwdata,
haddr,
// flash_ctrl input signals
flash_rdata,
flash_prog_done,
flash_pe_done,
flash_busy,
// 外部输入的擦写保护信号
eflash_wp_n,
// boot 区间的初始地址,外部输入信号
addr_offset,
// boot 使能信号
boot_en,
// read操作的时候通过hready拉低实现
hready_flag,
//********************************************************
// output signals //
//********************************************************
// *************************输出读写擦使能信号*************************
flash_prog_en,
flash_pe_en,
flash_rd_en,
// *******************读写擦flash中哪部分对应的信号********************
// flash片选信号
// information or main block选择信号
// 读flash0或者flash1
flash0_rd_cs
flash1_rd_cs
// 读flash中的哪部分,代码有冗余
rd_infr0_sel,
rd_infr1_sel,
rd_main0_sel,
rd_main1_sel,
// 写flash中的哪部分
prog_infrarea0_sel,
prog_infrarea1_sel,
prog_mainarea0_sel,
prog_mainarea1_sel,
// 擦除的页数
pe_num,
// 擦除flash中的哪部分
pe_main_infr_sel,
// *******************读写地址和数据********************
flash_addr_out,
flash_wdata,
// ******************时间寄存器配置信号*****************
t_nvstr_setup,
t_nvstr_hold,
t_rcv,
// 写操作寄存器
t_prog_setup,
t_prog_hold,
t_addr_setup,
t_addr_hold,
t_prog_proc,
// 读操作用的寄存器
t_addr_aces,
// 擦除操作
t_page_erase,
// *****************中断信号****************************
flash_ctrl_int
);
input clk;
input hresetn;
input hsel;
input hready_in;
input hwrite;
input [2:0] hsize;
input [2:0] hburst;
input [1:0] htrans;
input [31:0] hwdata;
input [31:0] haddr;
input flash_prog_done;
input flash_pe_done;
input flash_busy;
// 0的时候擦写保护,1的时候不保护
input eflash_wp_n;
input boot_en;
input [4:0] addr_offset;
input hready_flag;
output flash_prog_en;
output flash_pe_en;
output flash_rd_en;
output [11:0] t_nvstr_setup;
output [11:0] t_nvstr_hold;
output [7:0] t_rcv;
output [15:0] t_prog_setup;
output [3:0] t_prog_hold;
output [3:0] t_addr_setup;
output [3:0] t_addr_hold;
output [15:0] t_prog_proc;
output [7:0] t_addr_aces;
output [23:0] t_page_erase;
output flash0_rd_cs
output flash1_rd_cs
output rd_infr0_sel,
output rd_infr1_sel,
output rd_main0_sel,
output rd_main1_sel,
output prog_infrarea0_sel,
output prog_infrarea1_sel,
output prog_mainarea0_sel,
output prog_mainarea1_sel,
output [8:0] pe_num;
output pe_main_infr_sel;
output [14:0] flash_addr_out;
output [31:0] flash_wdata;
//********************************************************
// internal register //
//********************************************************
// register used for temp the ahb input signals
reg hwrite_r;
reg [2:0] hsize_r;
reg [2:] hburst_r;
reg [1:0] htrans_r;
reg [31:0] haddr_r;
// flash operation config registers
// common timing
reg [31:0] nvstr_setup_timing;
reg [31:0] nvstr_hold_timing;
reg [31:0] rcv_timing;
// program timing
reg [31:0] prog_setup_timing;
reg [31:0] prog_hold_timing;
reg [31:0] prog_proc_timing;
reg [31:0] progaddr_sethold_timing;
// read timing
reg [31:0] rd_aces_timing;
// erase timing
reg [31:0] pe_timing;
// Address register and program data register used for flash
// program or page erase operation
reg [31:0] prog_addr_r;
reg [31:0] prog_data_r;
reg [31:0] invalid_data_r;
// flash program/page erase operation control registers and main mem/info mem/info
// selected mark
// wr_en_r[0]:flash prog enable
// pe_en_r[0]:flash pe enable
reg wr_en_r;
reg pe_en_r;
reg pe_main_infr_sel_r;
reg [8:0] pe_num_r;
// int_en_r for enable interrupt and flash operation(prog/pe) status
reg [31:0] int_en_r;
reg [1:0] flash_status_r;
// boot_pe_wr_error_r:boot area page erase or write finish forbidden when boot area protected
reg boot_pe_wr_error_r;
reg boot_pe_done; // This two signals show boot operation
reg boot_wr_done; // finish when in boot area protect
reg [4:0] addr_offset_r; // 16k bytes boot area
reg [31:0] hrdata;
wire ahb_wr_en;
wire ahb_rd_en;
wire trans_en;
wire f_rd_en;
wire wr_status_valid;
wire rd_infr_sel;
wire rd_main_sel;
// flash operation area select
wire reg_sel;
wire rd_infrarea_sel;
wire rd_mainarea_sel;
wire prog_pe_infrarea_sel;
wire prog_pe_mainarea_sel;
wire infrarea_sel;
wire flash_mem_rd;
wire [31:0] flash_addr;
// boot area operation enable signals
wire boot_protect_n;
wire boot_pe_sel;
wire boot_wr_sel;
wire non_boot_addr_correct;
wire flash_addr_correct;
wire wr_en;
wire pe_en;
// AHB Bus transactions
parameter IDLE = 2'b00,
BUSY = 2'b01,
NONSEQ = 2'b10,
SEQ = 2'b11;
// flash 中的 寄存器空间
parameter REG_ADDR = 12'h060; // 60000 - 60fff
parameter INFR_ADDR = 12'h061; // 61000 - 617ff
parameter INFR0_ADDR = 1'b0; // 61000 - 613ff
parameter INFR1_ADDR = 2'h1; // 61400 - 617ff
parameter MAIN_ADDR = 6'h0; // 0000_0000 - 0003_ffff
parameter MAIN0_ADDR = 1'b0; // 0000_0000 - 0001_ffff: haddr[17:16] = 0
parameter MAIN1_ADDR = 1'b1; // 0002_0000 - 0003_ffff: haddr[17;16] = 1
parameter NVSTR_SETUP_ADDR = 8'h00,
NVSTR_HOLD_ADDR = 8'h04,
PROG_SETUP_ADDR = 8'h08,
PROGADDR_SETHOLD_ADDR = 8'h0c,
PROG_PROC_ADDR = 8'h10,
RD_ACES_ADDR = 8'h14,
PE_ADDR = 8'h18,
RCV_ADDR = 8'h1c,
WR_EN_ADDR = 8'h20,
PE_CONFIG_ADDR = 8'h24,
PE_NUM_ADDR = 8'h28,
PE_MAININFR_SEL_ADDR = 8'h2c,
PROG_ADDR_ADDR = 8'h30,
PROG_DATA_ADDR = 8'h34,
INT_EN_ADDR = 8'h38,
FLASH_STATUS_ADDR = 8'h3c,
BOOT_ERROR_ADDR = 8'h40;
//------------------------------------------------------------//
// Generate AHB slave output signals : hready_out & hresp
// flash pe : hready_out = 1
// flash read : if(reg operation) hready_out = 1
// else hready_out = flash_rd_ready
// -----------------------------------------------------------//
assign hready_out = hready_flag;
assign hresp = 2'b0;
//--------------------------------------------//
// Generate ahb wirte and read enable signals //
// ahb_wr_en: htrans_r and hwrite_r
// ahb_rd_en:htrans_r and hwrite_r
assign ahb_wr_en = (htrans == NONSEQ || htrans == SEQ) && hwrite_r && (!flash_busy);
// read的时候不用与上flash_busy,因为hready已经进行了判断
//--------------------------------------------//
// flash input data and address
// flash_addr : haddr_r[17:2] => 64Kbytes row address
// flash_addr_out : haddr_r[17:2] => double word (32bit) align
// flash_wdata:when prog,prog_data_r
// Note: haddr_r willbe xor with addr_offset <=> haddr_r + addr_offset
// why use the xor logic,not use + ?
//--------------------------------------------//
assign flash_addr = (flash_prog_en) ? prog_addr_r:
(boot_en && rd_main_sel) ? {haddr[31:18],haddr[17:13]|addr_offset,haddr[12:0]}:haddr;
// flash_addr是以byte的地址,但是在prog和read的时候是以dw为单位的地址,所以进行转换,去掉低两bit
// xaddr - 10bit
// yaddr - 5bit
// flash_addr_out => 15bit
assign flash_addr_out = flash_addr[16:2];
// ahb写寄存器得到寄存器的值
assign flash_wdata = prog_data_r;
//--------------------------------------------//
// Confige the flash configure registers //
//--------------------------------------------//
// 将寄存器的值连出来
assign t_nvstr_setup = nvstr_setup_timing[11:0];
assign t_nvstr_hold = nvstr_hold_timing[11:0];
assign t_rcv = rcv_timing[7:0];
// program configuration
assign t_prog_setup = prog_setup_timing[15:0];
assign t_prog_hold = progaddr_sethold_timing[3:0];
assign t_addr_setup = progaddr_sethold_timing[7:4];
assign t_addr_hold = progaddr_sethold_timing[11:8];
assign t_prog_proc = prog_proc_timing[15:0]
// read configuration
assign t_addr_aces = rd_aces_timing[7:0];
// page erase configuration
assign t_page_erase = pe_timing[23:0];
//----------------------------------------------------------------------------//
// Generate flash control logic
// flash_prog_en : eflash_wp_n = 1 && wr_en_r[0] = 1;
// flash_pe_en : eflash_wp_n = 1 && wr_en_r[0] = 1;
// ---------------------------------------------------------------------------//
//----------------------------------------------------------------------------//
// Generate flash reg_sel : infr_mem and main_mem sel when flash read operation
// main mem addr: 0x0000 0000 - 0x 0003 ffff (18bit - 256K)
// infr mem addr: 0x0006 1000 - 0x 0006 7fff (15bit - 32K)
// reg config addr 0x0006 0000 - 0x 0006 0fff (12bit - 4k)
//----------------------------------------------------------------------------//
// 寄存器空间4k
// 0x0006 0000 - 0x 0006 0fff
// 只需要判断haddr[23:12]这个范围,就可以判断出访问的是哪个空间
// 060 -- 0000 0110 0000 -- REG_ADDR
assign reg_sel = haddr_r[23:12] == REG_ADDR;
// area select when in flash read operation
// information block 2 page -- 1k -- 10bit(0-9,用第11bit选择哪一个infr)
// 2 information block 2k - 11bit
// 0x0006 1000 - 0x0006 17ff
// 061 -- 0000 0110 0001 -- INFR_ADDR
assign rd_infr_sel = (haddr[23:12] == INFR_ADDR);
assign rd_infr0_sel = rd_infr_sel && (haddr[10] == INFR0_ADDR);
assign rd_infr1_sel = rd_infr_sel && (haddr[11:10] == INFR1_ADDR);
// 低18bit为256Kflash的寻址,23-18bit用于寻址main block
// 128K -- 17bit,可以用18bit选择哪个flash的main block
assign rd_main_sel = (haddr[23:18] == MAIN_ADDR);
assign rd_main0_sel = rd_main_sel && (flash_addr[17] == MAIN0_ADDR);
assign rd_main1_sel = rd_main_sel && (flash_addr[17] == MAIN1_ADDR);
assign flash0_rd_cs = (rd_infr0_sel || rd_main0_sel);
assign flash1_rd_cs = (rd_infr1_sel || rd_main1_sel);
// flash read operation enable
// f_rd_en - 对于flash ctrl的读请求
// flash_rd_en - 对于flash的读请求,只有当选择读取main block的时候才会产生对flash的读请求
// flash_busy - 当前flash正处于读写擦状态,不能进行操作
assign f_rd_en = hsel && (htrans == NONSEQ || htrans == SEQ) && (!hwrite);
assign flash_rd_en = f_rd_en && (!flash_busy) && (flash0_rd_cs || flash1_rd_cs);
// Generate boot protect signal,it actives "high" when boot begin and actives "low" when boot finish
// boot_en为高的时候需要对于boot区间进行保护
assign boot_protect_n = boot_en;
// -------------------------------------------------------------------------//
// Generate boot area operation(write and page erase operation) enable signals
// When boot page erase (addr_offset_r == 5'h11111(8k byte));
// 3e000-->page 496 -->pe_num_r = 5'h11111;
// 16k bytes:
// 3c000-->page 480 -->pe_num_r = 4'h1111;
// When boot write(addr_offset_r == 5'h11111(8 kbytes)):
// 3e000-->prog_addr_r[17:13] = 5'h111111;
// 16k bytes:
// 3c000-->prog_addr_r[17:14] = 4'h1111;
// -------------------------------------------------------------------------//
// boot区间有两种情况
// 8k以3e000为offset
// 16k 以3c000为offset
// 根据addr_offset判断是3c000开始还是3e000开始
// 3c000 - 3ffff -- 16k
// 3e000 - 3ffff -- 8K
// 3e000 -- 0011 1110 0000 0000 0000 - 低13bit表示boot区的粒度,高5bit表示offset地址
// 3c000 -- 0011 1100 0000 0000 0000
// 3ffff -- 0011 1111 1111 1111 1111
// for program
// addr_offset == ox3e000;
// boot area :
// first_addr: 0011 1111 0000 0000 0000
// last_addr: 0011 1111 1111 1111 1111
// addr_offset == ox3c000;
// boot area :
// first_addr: 0011 1110 0000 0000 0000
// last_addr: 0011 1111 1111 1111 1111
// for erase
// page - 512byte -- 9bit表示
// addr_offset == ox3e000;
// boot area :
// first_page: 0011 1111 000
// last_addr: 0011 1111 111
// addr_offset == ox3c000;
// boot area :
// first_page: 0011 1110 000
// last_page: 0011 1111 111
// 判断擦写是不是落在boot区间内
assign boot_wr_sel = (addr_offset_r == 5'b11111) ? (prog_addr_r[17:13] == 5'b11111):
(addr_offset_r == 5'b11110) ? (prog_addr_r[17:14] == 4'b1111) : 1'b0;
assign boot_pe_sel = (addr_offset_r == 5'b11111) ? (page_num_r[8:4] == 5'b11111):
(addr_offset_r == 5'b11110) ? (page_num_r[8:5] == 4'b1111) : 1'b0;
// select the right address when boot protect enable in the flash operation
// except the address of boot area
// non_boot_addr_correct -- 表示当前不是非法操作
assign non_boot_addr_correct = !(boot_wr_sel || boot_pe_sel);
// The address is always right when boot protect turn off in flash operation
// or is part of right when the address is not boot Address when boot protect turn on
assign flash_addr_correct = boot_protect_n ? 1'b1 : non_boot_addr_correct;
// Generate one of condition of flash program and page erase enable
// 擦写寄存器中的值为高并且flash地址选择正确,产生擦写信号
assign wr_en = wr_en_r && flash_addr_correct;
assign pe_en = pe_en_r && flash_addr_correct;
// flash program operation enable
// flash_prog_en - 给到状态机
// eflash_wp_n 为0 ,写保护信号有效,flash_prog_n 永远为0,进行写保护
// eflash_wp_n 为1,撤销写保护,wr_en == 1'b1,产生写使能给状态机
assign flash_prog_en = eflash_wp_n && (wr_en == 1'b1);
// area select when in flash page erase operation
// flash page erase operation enable
assign flash_page_erase = eflash_wp_n && (pe_en == 1'b1);
assign pe_num = pe_num_r;
assign pe_main_infr_sel = pe_main_infr_sel_r;
//area select when in flash program operation
assign prog_infrarea_sel = (prog_addr_r[23:12] == INFR_ADDR);
assign prog_infrarea0_sel = prog_infrarea_sel && (prog_addr_r[10] == INFR0_ADDR);
assign prog_infrarea1_sel = prog_infrarea_sel && (prog_addr_r[11:10] == INFR1_ADDR);
// 低18bit为256Kflash的寻址,23-18bit用于寻址main block
// 128K -- 17bit,可以用18bit选择哪个flash的main block
assign prog_mainarea_sel = (prog_addr_r[23:18] == MAIN_ADDR);
assign prog_mainarea0_sel = prog_mainarea_sel && (prog_addr_r[17] == MAIN0_ADDR);
assign prog_mainarea1_sel = prog_mainarea_sel && (prog_addr_r[17] == MAIN1_ADDR);
//--------------------------------------------------------------//
// Generate interrupt signal.
// When int_en_r[i] enable,flash_ctrl_int[i] output
// enable
//--------------------------------------------------------------//
assign wr_status_valid = ahb_wr_en && reg_sel && (haddr_r[7:0] == FLASH_STATUS_ADDR);
// flash_status_r[0]为高,表示有写操作完成
// int_en_r[0] 为高表示写操作中断使能,可以发出中断
// flash_status_r[1]为高,表示有pe操作完成
// int_en_r[1] 为高表示pe操作中断使能,可以发出中断
assign flash_ctrl_int = ((flash_status_r[0]) && int_en_r[0]) || (flash_status_r[1]) && int_en_r[1];
//--------------------------------------------------------------//
// Temp AHB addr and control signals
//--------------------------------------------------------------//
always @ (posedge hclk or negedge hresetn)
begin
if(!hresetn) begin
hwrite_r <= 1'b0;
hsize_r <= 3'b0;
htrans_r <= 2'b0;
haddr_r <= 32'b0;
hburst_r <= 3'b0;
else if(hsel && hready_in) begin
hwrite_r <= hwrite;
hsize_r <= hsize ;
htrans_r <= htrans;
haddr_r <= haddr ;
hburst_r <= hburst;
end
else begin
hwrite_r <= 1'b0;
hsize_r <= 3'b0;
htrans_r <= 2'b0;
haddr_r <= 32'b0;
hburst_r <= 3'b0;
end
end
end
// ---------------------------------------------------------------//
// ahb read data output
// ahb总线读数据的产生
always @ (*)
begin
if(ahb_rd_en && reg_sel)
begin
case(haddr[7:0])
NVSTR_SETUP_ADDR : hrdata = nvstr_setup_timing;
NVSTR_HOLD_ADDR : hrdata = hvstr_hold_timing;
PROG_SETUP_ADDR : hrdata = prog_setup_timing;
PROGADDR_SETHOLD_ADDR : hrdata = progaddr_sethold_timing;
PROG_PROC_ADDR : hrdata = prog_proc_timing;
RD_ACES_ADDR : hrdata = rd_aces_timing;
RCV_ADDR : hrdata = rcv_timing;
WR_EN_ADDR : hrdata = {31'h0,wr_en_r};
PE_CONFIG_ADDR : hrdata = {31'h0,pe_en_r};
PE_NUM_ADDR : hrdata = {23'h0,pe_num_r};
PE_MAININFR_SEL_ADDR : hrdata = {31'h0,pe_main_infr_sel_r};
PE_ADDR : hrdata = pe_timing;
PROG_ADDR_ADDR : hrdata = prog_addr_r;
PROG_DATA_ADDR : hrdata = prog_data_r;
INT_EN_ADDR : hrdata = int_en_r;
FLASH_STATUS_ADDR : hrdata = {30'h0,flash_status_r};
BOOT_ERROR_ADDR : hrdata = {31'h0,boot_pe_wr_error_r};
default: : hrdata = 32'b0;
endcase
end
else
hrdata = flash_rdata[31:0];
end
//-------------------------------------------------------------------------//
// Temp the value of addr_offset for boot area protect.
//-------------------------------------------------------------------------//
always@(posedge hclk or negedge hresetn) begin
if(!hresetn)
addr_offset_r <= 5'b0;
else if(!boot_en)
addr_offset_r <= addr_offset;
end
//-------------------------------------------------------------------------//
// When boot area protect,the program and page erase operation done
// signal will active high when boot area select and active low in the next clock
//-------------------------------------------------------------------------//
// 擦写使能并且选择boot区间会将boot_wr/pe_done信号拉高
// boot_wr/pe_done -- 信号拉高之后会写状态寄存器
always @(posedge hclk or negedge hresetn)
begin
if(!hresetn) begin
boot_wr_done <= 1'b0;
boot_pe_done <= 1'b0;
end
else if(boot_protect_n) begin // boot_en失效的条件下
boot_wr_done <= 1'b0;
boot_pe_done <= 1'b0;
end
else if(wr_en && boot_wr_sel)
boot_wr_done <= 1'b1;
else if(pe_en && boot_pe_sel)
boot_pe_done <= 1'b1;
else if(boot_wr_done || boot_pe_done) begin
boot_wr_done <= 1'b0;
boot_pe_done <= 1'b0;
end
end
//-------------------------------------------------------------------------//
// AHB write registers
// When ahb_wr_en,hwdata write into reg address.
//-------------------------------------------------------------------------//
// 复位信号来临将默认值写入寄存器
always @(posedge hclk or negedge hresetn) begin
if(!hresetn)
begin
nvstr_setup_timing <= 32'h259;
nvstr_hold_timing <= 32'h259;
rcv_timing <= 32'h79;
prog_setup_timing <= 32'h4b1;
progaddr_sethold_timing <= 32'h333;
prog_proc_timing <= 32'h962;
rd_aces_timing <= 32'h5;
pe_timing <= 32'h24a2c1;
wr_en_r <= 1'b0;
pe_en_r <= 1'b0;
pe_num_r <= 9'h1df;
pe_main_infr_sel_r <= 1'b0;
prog_addr_r <= 32'h0;
prog_data_r <= 32'h0;
int_en_r <= 32'h0;
invalid_data_r <= 32'h0;
end
else if(ahb_wr_en && reg_sel)
begin
case(haddr_r[7:0])
NVSTR_SETUP_ADDR : nvstr_setup_timing <= hwdata;
NVSTR_HOLD_ADDR : nvstr_hold_timing <= hwdata;
PROG_SETUP_ADDR : prog_setup_timing <= hwdata;
PROGADDR_SETHOLD_ADDR : progaddr_sethold_timing <= hwdata;
PROG_PROC_ADDR : prog_proc_timing <= hwdata;
RD_ACES_ADDR : rd_aces_timing <= hwdata;
RCV_ADDR : rcv_timing <= hwdata;
WR_EN_ADDR : wr_en_r <= hwdata[0];
PE_CONFIG_ADDR : pe_en_r <= hwdata[0];
PE_NUM_ADDR : pe_num_r <= hwdata[8:0];
PE_MAININFR_SEL_ADDR : pe_main_infr_sel_r <= hwdata[0];
PE_ADDR : pe_timing <= hwdata;
PROG_ADDR_ADDR : prog_addr_r <= hwdata;
PROG_DATA_ADDR : prog_data_r <= hwdata;
INT_EN_ADDR : int_en_r <= hwdata;
default: : invalid_data_r <= hwdata;
endcase
end
else if(flash_prog_done || boot_wr_done)
begin
// flash_prog_done - 是flash ctrl返回的信号
// boot_wr_done - 是boot使能时,写boot区返回的信号
wr_en_r <= 1'b0;
prog_addr_r <= 32'h3bfff;
end
else if(flash_pe_done || boot_pe_done)
pe_en_r <= 1'b0;
pe_num_r <= 9'h1df;
end
end
//-------------------------------------------------------------------------//
// Flash operation status and boot operation status.
//-------------------------------------------------------------------------//
always @ (posedge hclk or negedge hresetn)
begin
if(!hresetn) begin
// 第一bit表示写状态
flash_status_r[0] <= 1'b0;
end
else if(wr_status_valid && hwdata[0]) begin // 软件清0 - 写1清0
flash_status_r[0] <= 1'b0;
end
else if(flash_prog_done || boot_wr_done) // 硬件置位
flash_status_r[0] <= 1'b1;
end
// flash_status_r 第一bit表示wr状态
// 第二bit表示pe的状态-- 是否完成
always @ (posedge hclk or negedge hresetn)
begin
if(!hresetn) begin
// 第一bit表示写状态
flash_status_r[1] <= 1'b0;
end
else if(wr_status_valid && hwdata[1]) begin // 软件清0 -- 写1清0(寄存器的值不一定为1)
flash_status_r[1] <= 1'b0;
end
else if(flash_pe_done || boot_pe_done) // 硬件置位
flash_status_r[1] <= 1'b1;
end
always @ (posedge hclk or negedge hresetn)
begin
if(!hresetn) begin
// 第一bit表示写状态
boot_pe_wr_error_r <= 1'b0;
end
else if(boot_protect_n) begin
boot_pe_wr_error_r <= 1'b0;
end
else if(wr_status_valid && (hwdata[1]||hwdata[0])) begin
boot_pe_wr_error_r <= 1'b0;
end
else if(boot_pe_sel || boot_wr_sel)
boot_pe_wr_error_r <= 1'b1;
end
endmodule