module flash_ahb_slave_if (
//input signals
hclk,
hresetn,
hsel,
hready_in,
hwrite,
hsize,
htrans,
hburst,
hwdata,
haddr,
flash_rdata,
flash_prog_done,
flash_pe_done,
flash_busy,
eflash_wp_n,
addr_offset,//used for boot area
boot_en,
hready_flag,
//output signals
hready_out,
hresp,
hrdata,
flash_prog_en, //program enable
flash_pe_en, //page erase enable
flash_rd_en, //read enable
rd_inf0_sel,
rd_inf1_sel,
rd_main0_sel,
rd_main1_sel,
flash0_rd_cs,
flash1_rd_cs,
prog_infrarea0_sel,
prog_infrarea1_sel,
prog_mainarea0_sel,
prog_mainarea1_sel,
pe_num,
pe_main_infr_sel,
flash_addr_out,
flash_wdata,
flash_ctrl_int, //use for interupt controller
//flash operation configuration for timing
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
);
input hclk;
input hsel;
//总线上其它slave是否全部IDLE(全IDLE才可以工作),
//其它slave有hready为低,则总线在满,这个hready_in也为低
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;
//从flash读出的地址,传输到AHB Bus
//(如果不在配置寄存器则直接赋值给hrdata输出到总线)
input [31:0] flash_rdata;
input flash_prog_done;
input flash_pe_done;
input flash_busy;
input eflash_wp_n;
input boot_en;
input [4:0] addr_offset;
input hready_flag;
//output signals
output hready_out;
output [1:0] hresp;
//------------------------------------------------------//
//AHB read data output.
//hrdata = if(status_sel) flash_status_r
// else (flash_cs) flash_rdata
//读配置寄存器,或者flash
//------------------------------------------------------//
output [31:0] hrdata;
output flash_prog_en;
output flash_pe_en;
output flash_rd_en;
output rd_inf0_sel;
output rd_inf1_sel;
output rd_main0_sel;
output rd_main1_sel;
output flash0_rd_cs;
output flash1_rd_cs;
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;
//给Flash的地址一共15bit
output [14:0] flash_addr_out;
output [31:0] flash_wdata;
output flash_ctrl_int; //use for interrupt controller
//flash operation configuration for timing
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;
//----------------------------------------------//
// register used for temp the ahb input signas
reg hwrite_r ;
reg [2:0] hsize_r ;
reg [1:0] htrans_r ;
reg [2:0] hburst_r ;
reg [31:0] haddr_r ;
//flash operation config register
//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] progaddr_sethold_timing;
reg [31:0] prog_proc_timing;
//read timing
reg [31:0] rd_aces_timing;
//page erase timing
reg [31:0] pe_timing;
//Address register and progam 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] prog_data1_r;
reg [31:0] prog_data2_r;
reg [31:0] prog_data3_r;
reg [31:0] invalid_data_r;
//falsh program/page erase operation control registers
//and main/info mem selected mark
//wr_en_r[0]:flash prog enable
//pe_en_r[0]:flash page erase enable
reg wr_en_r;
reg pe_en_r;
reg main_infr_sel;
//AHN Bus transactions
parameter IDLE = 2'b00;
parameter BUSY = 2'b01;
parameter NONSEQ = 2'b10;
parameter SEQ = 2'b11;
//Soc总线地址分配使用到 0x0028_1FFF ,所以识别控制寄存器地址
//以及MAIN INFR 地址判断到24位[23:0]
// REG : 0x0006_0000~0x0006_0fff :haddr[23:12] = 12'h060
// INFR : 0x0006_1000~0x0006_7fff :
// INFR : 0x0006_1000~0x0006_13ff 0110_0001_0000_0000
// INFR : 0x0006_1400~0x0006_17ff 0110_0100_0000_0000
parameter REG_ADDR = 12'h060;
parameter INFR_ADDR = 12'h061;
parameter INFR0_ADDR = 1'h0;
parameter INFR1_ADDR = 2'h1;
// MAIN : 0000_0000 ~ 0003_ffff :haddr[23:15] = 6'h00
// MIAN0: 0000_0000 ~ 0001_ffff :haddr[17:16] = 0-
// MIAN1: 0002_0000 ~ 0003_ffff: haddr[17:16] = 1-
parameter MAIN_ADDR = 6'h0;
parameter MAIN0_ADDR = 1'b0;
parameter MAIN1_ADDR = 1'b1;
//时序控制寄存器的地址偏移,在在控制寄存器初始地址
//加上偏移地址就是相应控制寄存器的地址
//timing configuration register address
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_MIANINFR_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,
PROG_DATA1_ADDR = 8'h44,
PROG_DATA2_ADDR = 8'h48,
PROG_DATA3_ADDR = 8'h50,
PROG_NUM_ADDR = 8'h54;
//-----------------------------------------------------//
//Generate AHB slave output signals:hready_out & hresp //
//flash prog : hready_out = 1; //
//flash pe : hready_out = 1; //
//flash read : if(reg_operation) hready_out = 1; //
// else hready_out =flash_rd_ready //
//-----------------------------------------------------//
//hready_flag 是控制器那边给的接口模块的,然后AHB总线判断
//ready了,就可以进行读取数据了
//hresp这里直接赋值00,表示response只有OK这种状态,其它不考虑
assign hready_out = hready_flag;
assign hresp = 2'b00;
//---------------------------------------------//
//Generate AHB write and read enable signals //
//ahb_wr_en : htrasn_r and hwrite_r //
//ahb_rd_en : htrasn_r and hwrite_r //
//---------------------------------------------//
//ahb_wr_en 当写信号有效、flash不处在busy状态、
//并且htrans不为IDLE或者BUSY,则有效
//ahb_wr_en 不用判断flash_busy 因为在读的时候有hready信号判断
assign ahb_wr_en = ((htrans == NONSEQ)||(htrans == SEQ)) && hwrite_r && (!flash_busy);
assign ahb_rd_en = ((htrans == NONSEQ)||(htrans == SEQ)) && (!hwrite_r);
//---------------------------------------------//
//flash input data and address.
//flash_addr : haddr_r[17:0] => 64KBytes row address
//flash_addr_out : haddr_r[17:2] => double word (32bits) align
//flash_wdata : when prog,prog_data_r
//
// NOTE:haddr_r will be XOR with addr_offser, <=> haddr_r+addr_offset
// why use the xor logic,not use the + ?
//----------------------------------------------------//
//flash_addr 是一个byte的地址(AHB那边),要给FLash一个32bit地址(4byte),flash_addr_out要去掉地址低2位
//???这里flash_addr 有问题
//??不确定:prog_addr_r寄存器18bit有效?每一片是15bit,最高bit片选;一个byte的地址,最低2位没用。高16位有用,最高位选哪一个flash,中间15位位XYADR
// 如果是写FLash那么地址等于prog_addr,这个地址被配置在PROG_ADDR 寄存器中;
// 如果
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;
assign flash_addr_out = flash_addr[16:2];
//flash_wdata 通过AHB写寄存器得到
assign flash_wdata = prog_data_r;
//------------------------------------------//
//config the flash configure register
//timing 都是通过hwdata写进来的
//-------------------------------------------//
//common configuration except for read operation
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 = progaddr_sethold_timing[15:0];
//read configuration
assign t_addr_aces = rd_aces_timing[7:0];
//page erase timing
assign t_page_erase = pe_timing[23:0];
//---------------------------------------------------//
//Generate flash reg_sel;infr_mem and main_mem sel when
//flash read operation
//main mem addr :0x0000_0000~0x0003_ffff
//infr mem addr :0x0006_1000~0x0006_7fff
//reg confige addr :0x0006_0000~0x0006_0fff
//Soc总线地址分配使用到 0x0028_1FFF ,所以识别控制寄存器地址
//以及MAIN INFR 地址判断到24位[23:0]
// REG : 0x0006_0000~0x0006_0fff :haddr[23:12] = 12'h060
// INFR : 0x0006_1000~0x0006_7fff :
// INFR : 0x0006_1000~0x0006_13ff 0110_0001_0000_0000
// INFR : 0x0006_1400~0x0006_17ff 0110_0100_0000_0000
//parameter REG_ADDR = 12'h060;
//parameter INFR_ADDR = 12'h061; ❓
//用地址的 haddr[11]判断INFR0,INFR1
//parameter INFR0_ADDR = 1'h0;
//parameter INFR1_ADDR = 2'h1;
// MAIN : 0000_0000 ~ 0003_ffff :haddr[23:15] = 6'h00
// MIAN0: 0000_0000 ~ 0001_ffff :haddr[17:16] = 0-
// MIAN1: 0002_0000 ~ 0003_ffff :haddr[17:16] = 1-
//parameter MAIN_ADDR = 6'h0;
//用地址的 haddr[17]判断main0,main1
//parameter MAIN0_ADDR = 1'b0;
//parameter MAIN0_ADDR = 1'b1;
//---------------------------------------------------//
assign reg_sel = (haddr_r[23:12] == REG_ADDR);
//area selected when in flash operation
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);
assign rd_main_sel = (haddr[23:18] == MAIN_ADDR);
assign rd_main0_sel = rd_mian_sel && (flash_addr[17] == MAIN0_ADDR);
assign rd_main1_sel = rd_mian_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_en作区分;
//读中断寄存器还是读存储器有区分,读存储器要等ready
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
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 bytes));
// 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(8K bytes));
// 3e000--> prog_addr_r[17:13] = 5'h11111;
// 16K bytes:
// 3c000--> prog_addr_r[17:14] = 4'h1111;
//-------------------------------------------------------------//
//一页4行,1行128byte,一页512byte;3c000-->page 480;3e000-->page 496
//写/页擦的地址刚好是boot区地址的话,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) ? (pe_num_r[8:4] == 5'b11111 ):
(addr_offset_r == 5'b11110) ? (pe_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
//boot区没写,没页擦,boot区地址没有选中
assign non_boot_addr_correct = !(boot_wr_sel || boot_pe_sel);
//the adress is always right when boot protect turn off in flash
//operation or is part of right when address is not boot adress
//when boot prot turn on
//判断地址是否正确:启用了boot保护的话,non_boot_addr_correct要为1才正确
//即没有boot wr和pe;没启用boot保护,那么地址正确
assign flash_addr_correct = boot_protect_n ? 1'b1 : non_boot_addr_correct;
//generate one of conditions of flash program and page erase enable
//若地址不正确则不能进行写和页擦
assign wr_en = wr_en_r && flash_addr_correct;
assign pe_en = pe_en_r && flash_addr_correct;
//--------------------------------------------------//
//Generate flash control logic
//flash_prog_en :flash_wp_n = 1 && wr_en_r[0] = 1;
//flash_pe_en :flash_wp_n = 1 && pe_en_r[0] = 1;
//--------------------------------------------------//
//flash program operation enable
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_pe_en = eflash_wp_n && (pe_en == 1'b1);
//pe_num_r和pe_main_infr_sel_r :配置寄存器,写入配置
assign pe_num = pe_num_r;
assign pe_main_infr_sel = pe_main_infr_sel_r;
//写状态寄存器有效:ahb写使能,配置寄存器选中,地址为状态寄存器地址
assign wr_status_valid = ahb_wr_en && reg_sel && (haddr_r[7:0] == FLASH_STATUS_ADDR);
//--------------------------------------------------------------//
//Generate interupt signal.
//when int_en_r[1] enable,flash_ctrl_int[i] output enable
//-------------------------------------------------------------//
assign flash_ctrl_int = (flash_status_r[0] && int_en_r[0] ||(flash_status_r[1]&&int_en_r[1])
//------------------------------------------------------//
//AHB read data output. ✔
//hrdata = if(status_sel) flash_status_r
// else (flash_cs) flash_rdata
//------------------------------------------------------//
//AHB读数据,当配置寄存器选中,读配置寄存器中内容,否则读flash读出的数据;
always@(*) begin
if(ahb_rd_en && reg_sel)
begin
case(haddr_r[7:0])
NVSTR_SETUP_ADDR : hrdata = nvstr_setup_timing ;
NVSTR_HOLD_ADDR : hrdata = nvstr_hold_timing ;
RCV_ADDR : hrdata = rcv_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 ;
PE_ADDR : hrdata = pe_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_MIANINFR_SEL_ADDR : hrdata = {31'h0,pe_main_infr_sel_r};
PROG_ADDR_ADDR : hrdata = prog_addr_r ;
PROG_DATA_ADDR : hrdata = prog_data_r ;
PROG_DATA1_ADDR : hrdata = prog_data1_r ;
PROG_DATA2_ADDR : hrdata = prog_data2_r ;
PROG_DATA3_ADDR : hrdata = prog_data3_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 AHB addr and control signals ✔
//--------------------------------------------------//
always@(posedge hclk or negedge hresetn) begin
if(!hresetn)
begin
hsize_r <= 1'b0 ;
htrans_r <= 3'b0 ;
hburst_r <= 3'b0 ;
hwdata_r <= 2'b0 ;
haddr_r <= 32'b0;
end
else if (hsel && hready_in)
begin
hsize_r <= hsize ;
htrans_r <= htrans ;
hburst_r <= hburst ;
hwdata_r <= hwdata ;
haddr_r <= haddr ;
end
else
begin
hsize_r <= 1'b0 ;
htrans_r <= 3'b0 ;
hburst_r <= 3'b0 ;
hwdata_r <= 2'b0 ;
haddr_r <= 32'b0;
end
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 ✔
//用于硬件清零,done 信号只保持一个周期
//----------------------------------------------------------//
always@(posedge hclk or negedge hresetn)
begin
if (!hresetn)
begin
boot_pe_done <= 1'b0;
boot_wr_done <= 1'b0;
end
else if(boot_protect_n)
begin
boot_pe_done <= 1'b0;
boot_wr_done <= 1'b0;
end
else
begin
if (wr_en_r && boot_wr_sel)
boot_wr_done <= 1'b1;
else if (pe_en_r && boot_pe_sel)
boot_pe_done <= 1'b1;
else if (boot_wr_done || boot_pe_done)
begin
boot_pe_done <= 1'b0;
boot_wr_done <= 1'b0;
end
end
end
//-------------------------------------------------///
//AHB write registers.
//when ahb_wr_en,hdata 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 <= 2'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;
RCV_ADDR : rcv_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;
PE_ADDR : pe_timing <= hwdata;
WR_EN_ADDR : wr_en_r <= hwdata[0]; //software set
PE_CONFIG_ADDR : pe_en_r <= hwdata[0];
//最高位判断是flash0,还是flash1
PE_NUM_ADDR : pe_num_r <= hwdata[8:0];
PE_MIANINFR_SEL_ADDR : pe_main_infr_sel_r <= hwdata[0];
PROG_ADDR_ADDR : prog_addr_r <= hwdata;
PROG_DATA_ADDR : prog_data_r <= hwdata;
PROG_DATA1_ADDR : prog_data1_r <= hwdata;
PROG_DATA2_ADDR : prog_data2_r <= hwdata;
PROG_DATA3_ADDR : prog_data3_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
wr_en_r <= 1'b0; //hardware reset,
prog_addr_r <= 32'h3bfff;
end
else if (flash_pe_done || boot_pe_done)
begin
pe_en_r <= 1'b0;
pe_num_r <= 9'h1df;
end
end
//----------------------------------------------------------------//
//Flash operation status and boot operation status
//flash_status_r:页擦写操作完成信号 ✔
//----------------------------------------------------------------//
always@(posedge hclk or negedge hresetn)
begin
if (!hresetn)
flash_status_r[0] <= 1'b0;
else if (wr_status_valid && hwdata[0]) //software :wite operation to reset;write 1 to reset
flash_status_r[0] <= 1'b0;
else if (flash_prog_done || boot_wr_done)
flash_status_r[0] <= 1'b1; //hardware set,when to reset? -->status
end
always@(posedge hclk or negedge hresetn)
begin
if (!hresetn)
flash_status_r[1] <= 1'b0;
else if (wr_status_valid && hwdata[1]) //software :wite operation to reset;write 1 to reset
flash_status_r[1] <= 1'b0;
else if (flash_pe_done || boot_pe_done)
flash_status_r[1] <= 1'b1; //hardware set,when to reset? -->status
end
//----------------------------------------------------------------//
//Flash operation status and boot operation status
//boot_pe_wr_error_r:boot区非法操作
//启动了boot区保护boot_pe_sel/boot_wr_sel确有效 ✔
always@(posedge hclk or negedge hresetn)
begin
if (!hresetn)
boot_pe_wr_error_r <= 1'b0;
else if (boot_protect_n)
boot_pe_wr_error_r <= 1'b0;
else if (wr_status_valid && (hwdata[0]||hwdata[1]))
boot_pe_wr_error_r <= 1'b0;
else if (boot_pe_sel || boot_wr_sel)
boot_pe_wr_error_r <= 1'b1;
end
endmodule
PROJECT 2
于 2022-07-31 17:46:27 首次发布