龙空技术网

如何实现SDRAM的bank交替(interleaving)访问

xiaomingzi55 98

前言:

此刻看官们对“za无权访问data文件夹”都比较关切,同学们都需要剖析一些“za无权访问data文件夹”的相关内容。那么小编同时在网摘上网罗了一些关于“za无权访问data文件夹””的相关文章,希望同学们能喜欢,兄弟们一起来了解一下吧!

SDRAM的架构

以IS42S16320D为例,整个存储矩阵分为4个bank,每个bank包含8192个row,每个row包含1024个column,每个column包含16bit,bit是最小的存储单元。

sdram的特性是这样的:在读写某个row之前,必须先打开对应的bank/row,然后才能进行读写操作。如果要读写其他的row,就必须先关闭当前访问的row,然后打开其他的row。如果把每个row比作一个盒子,盒子正常状态是关闭着的。要从某个盒子拿放东西,就必须先打开盒子,拿放完东西后还要把盒子关上,否则不能操作其他的盒子。于是操作不同的盒子间就有一段时间是浪费在打开和关闭盒子了。

那有没有办法实现对两个盒子的无缝操作呢?答案是有的,就是bank交替(interleaving)访问功能,在介绍这个功能之前,先介绍几个必不可少的名词。

ACT:激活bank/row的意思,就是上文提到的打开盒子的意思

burst length:突发长度,指示一次命令读写连续column地址的大小,比如为4,则表示一次读或写4个column地址。这里设置为4

PRE:直译过来是预充电的意思,其实就是上文提到关闭盒子的意思

auto precharge命令:对某个row操作完成后,可以手动启动precharge,也可以设置为自动precharge。

rRCD:Active Command To Read / Write Command Delay Time,打开盒子到存取物品之间需要的时间,也可以理解为打开盒子的时间。本文是两个clock的时间

tRP:Command Period (PRE to ACT),关闭盒子到打开下一个盒子的时间,也可以理解为关闭盒子的时间,本文是两个clock的时间

READA:带自动预充电的读命令,在突发长度设置为4的情况下,执行READA命令四个时钟后,对应的bank/row会自动关闭

WRITEA:带自动预充电的读命令,在突发长度设置为4的情况下,执行WRITEA命令四个时钟后,对应的bank/row会自动关闭

如果想要更充分的理解bank交替技术,建议查看IS42S16320D的技术手册。

按照clock数的时间轴,执行从bank0/row0到bank1/row0的交替访问。

T0:执行bank0的ACT命令,BANK[1:0]=2'b00;{RAS_N, CAS_N, WE_N}=3'b011,A[12:0]=row

T1:空闲

T2:执行写WRITEA命令,写bank0的row0。对应的{RAS_N, CAS_N, WE_N}=3'b100,A10=1'b1,A9-A0=column地址,数据总线上写入第1个数据。

T3:数据总线上写入第2个数据。

T4:执行bank1的ACT命令,数据总线上写入第3个数据。BANK[1:0]=2'b01;{RAS_N, CAS_N, WE_N}=3'b011,A[12:0]=row地址

T5:数据总线上写入第4个数据。

T6:执行写WRITEA命令,写bank1的row0。对应的{RAS_N, CAS_N, WE_N}=3‘b100,,A10=1'b1,A9-A0=column地址,数据总线上写入第5个数据。

T7:数据总线上写入第6个数据。

T8:数据总线上写入第7个数据。

T9:数据总线上写入第8个数据。

原理就是利用auto prechage和突发长度不为1,解放出{RAS_N, CAS_N, WE_N},使其有时间去提前打开下一个要访问的bank/row。下面贴上测试通过的源代码,连续读写效率能达到97%左右(仅有refresh的开销)

module qsys_sdram_input_efifo_module (// inputs:clk,rd,reset_n,wr,wr_data,// outputs:empty,full,rd_data);output empty;output full;output [ 95: 0] rd_data;input clk;input rd;input reset_n;input wr;input [ 95: 0] wr_data;wire empty;reg [ 1: 0] entries;reg [ 95: 0] entry_0;reg [ 95: 0] entry_1;wire full;reg rd_address;reg [ 95: 0] rd_data;wire [ 1: 0] rdwr;reg wr_address;assign rdwr = {rd, wr};assign full = entries == 2;assign empty = entries == 0;always @(entry_0 or entry_1 or rd_address)begincase (rd_address) // synthesis parallel_case full_case1'd0: beginrd_data = entry_0;end // 1'd01'd1: beginrd_data = entry_1;end // 1'd1default: beginend // defaultendcase // rd_addressendalways @(posedge clk or negedge reset_n)beginif (reset_n == 0)beginwr_address <= 0;rd_address <= 0;entries <= 0;endelsecase (rdwr) // synthesis parallel_case full_case2'd1: begin// Write dataif (!full)beginentries <= entries + 1;wr_address <= (wr_address == 1) ? 0 : (wr_address + 1);endend // 2'd12'd2: begin// Read dataif (!empty)beginentries <= entries - 1;rd_address <= (rd_address == 1) ? 0 : (rd_address + 1);endend // 2'd22'd3: beginwr_address <= (wr_address == 1) ? 0 : (wr_address + 1);rd_address <= (rd_address == 1) ? 0 : (rd_address + 1);end // 2'd3default: beginend // defaultendcase // rdwrendalways @(posedge clk)begin//Write dataif (wr & !full)case (wr_address) // synthesis parallel_case full_case1'd0: beginentry_0 <= wr_data;end // 1'd01'd1: beginentry_1 <= wr_data;end // 1'd1default: beginend // defaultendcase // wr_addressendendmodule
module qsys_sdram (// inputs:az_addr,az_be_n,az_cs,az_data,az_rd_n,az_wr_n,clk,reset_n,// outputs:za_data,za_valid,za_waitrequest,zs_addr,zs_ba,zs_cas_n,zs_cke,zs_cs_n,zs_dq,zs_dqm,zs_ras_n,zs_we_n,m_next,m_state);input clk;input reset_n;output [ 63: 0] za_data;output za_valid;output za_waitrequest;input [ 22: 0] az_addr;input [ 7: 0] az_be_n;input az_cs;input [ 63: 0] az_data;input az_rd_n;input az_wr_n;output [ 12: 0] zs_addr;output [ 1: 0] zs_ba;output zs_cas_n;output zs_cke;output zs_cs_n;inout [ 15: 0] zs_dq;output [ 1: 0] zs_dqm;output zs_ras_n;output zs_we_n;output [ 3: 0] m_next;output [ 3: 0] m_state;reg ack_refresh_request;reg [ 24: 0] active_addr;wire [ 1: 0] active_bank;reg active_cs_n;reg [ 63: 0] active_data;reg [ 7: 0] active_dqm;reg active_rnw;wire bank_match;wire [ 9: 0] cas_addr;wire clk_en;wire cs_n;wire csn_decode;wire csn_match;wire [ 24: 0] f_addr;wire [ 1: 0] f_bank;wire f_cs_n;wire [ 63: 0] f_data;wire [ 7: 0] f_dqm;wire f_empty;reg f_pop;wire f_rnw;wire f_select;wire [ 95: 0] fifo_read_data;reg [ 12: 0] i_addr;reg [ 3: 0] i_cmd;reg [ 3: 0] i_count;reg [ 2: 0] i_next;reg [ 2: 0] i_refs;reg [ 2: 0] i_state;reg init_done;reg [ 12: 0] m_addr /* synthesis ALTERA_ATTRIBUTE = "FAST_OUTPUT_REGISTER=ON" */;reg [ 1: 0] m_bank /* synthesis ALTERA_ATTRIBUTE = "FAST_OUTPUT_REGISTER=ON" */;reg [ 3: 0] m_cmd /* synthesis ALTERA_ATTRIBUTE = "FAST_OUTPUT_REGISTER=ON" */;reg [ 3: 0] m_count;reg [ 63: 0] m_data /* synthesis ALTERA_ATTRIBUTE = "FAST_OUTPUT_REGISTER=ON ; FAST_OUTPUT_ENABLE_REGISTER=ON" */;reg [ 7: 0] m_dqm /* synthesis ALTERA_ATTRIBUTE = "FAST_OUTPUT_REGISTER=ON" */;reg [ 3: 0] m_next;reg [ 3: 0] m_state;reg oe /* synthesis ALTERA_ATTRIBUTE = "FAST_OUTPUT_ENABLE_REGISTER=ON" */;wire pending;wire bank_alter;wire rd_strobe;reg [ 5: 0] rd_valid;reg [ 14: 0] refresh_counter;reg refresh_request;wire rnw_match;wire row_match;reg [ 63: 0] za_data /* synthesis ALTERA_ATTRIBUTE = "FAST_INPUT_REGISTER=ON" */;reg za_valid;wire za_waitrequest;wire [ 12: 0] zs_addr;wire [ 1: 0] zs_ba;wire zs_cas_n;wire zs_cke;wire zs_cs_n;wire [ 15: 0] zs_dq;wire [ 1: 0] zs_dqm;wire zs_ras_n;wire zs_we_n;// Refresh/init counter.always @(posedge clk or negedge reset_n)beginif (reset_n == 0)refresh_counter <= 26667;else if (refresh_counter == 0)refresh_counter <= 1066;elserefresh_counter <= refresh_counter - 1'b1;end// Refresh request signal.always @(posedge clk or negedge reset_n)beginif (reset_n == 0)refresh_request <= 0;else if (1)refresh_request <= ((refresh_counter == 0) | refresh_request) & ~ack_refresh_request & init_done;end// Initialization-done flag.always @(posedge clk or negedge reset_n)beginif (reset_n == 0)init_done <= 0;else if (1)init_done <= init_done | (i_state == 3'b101);end// **** Init FSM ****always @(posedge clk or negedge reset_n)beginif (reset_n == 0)begini_state <= 3'b000;i_next <= 3'b000;i_cmd <= 4'b1111;i_addr <= {13{1'b1}};i_count <= {4{1'b0}};endelsebegini_addr <= {13{1'b1}};case (i_state) // synthesis parallel_case full_case3'b000: begini_cmd <= 4'b1111;i_refs <= 3'b0;//Wait for refresh count-down after resetif (refresh_counter == 0)i_state <= 3'b001;end // 3'b0003'b001: begini_state <= 3'b011;i_cmd <= {{1{1'b0}},3'h2};i_count <= 2;i_next <= 3'b010;end // 3'b0013'b010: begini_cmd <= {{1{1'b0}},3'h1};i_refs <= i_refs + 1'b1;i_state <= 3'b011;i_count <= 9;// Count up init_refresh_commandsif (i_refs == 3'h7)i_next <= 3'b111;elsei_next <= 3'b010;end // 3'b0103'b011: begini_cmd <= {{1{1'b0}},3'h7};//WAIT til safe to Proceed...if (i_count > 1)i_count <= i_count - 1'b1;elsei_state <= i_next;end // 3'b0113'b101: begini_state <= 3'b101;end // 3'b1013'b111: begini_state <= 3'b011;i_cmd <= {{1{1'b0}},3'h0};i_addr <= {{3{1'b0}},1'b0,2'b00,3'h3,4'h2};i_count <= 3;i_next <= 3'b101;end // 3'b111default: begini_state <= 3'b000;end // defaultendcase // i_stateendendqsys_sdram_input_efifo_module the_qsys_sdram_input_efifo_module(.clk (clk),.empty (f_empty),.full (za_waitrequest),.rd (f_select),.rd_data (fifo_read_data),.reset_n (reset_n),.wr ((~az_wr_n | ~az_rd_n) & !za_waitrequest),.wr_data ({az_wr_n, az_wr_n ? 2'b0 : az_be_n, az_data,az_addr}));assign clk_en = 1;//s1, which is an e_avalon_slaveassign {zs_cs_n, zs_ras_n, zs_cas_n, zs_we_n} = m_cmd;assign zs_addr = m_addr;assign zs_cke = clk_en;assign zs_dq = oe?m_data[15:0]:{16{1'bz}};assign zs_dqm = m_dqm[1:0];assign zs_ba = m_bank;assign f_select = f_pop & pending;assign f_cs_n = 1'b0;assign cs_n = f_select ? f_cs_n : active_cs_n;assign csn_decode = cs_n;assign {f_rnw,f_dqm,f_data,f_addr} = {fifo_read_data,2'd0};assign f_bank = {f_addr[11],f_addr[10]};assign active_bank = {active_addr[11],active_addr[10]};assign csn_match = active_cs_n == f_cs_n;assign rnw_match = active_rnw == f_rnw;assign bank_match = active_bank == f_bank;assign row_match = {active_addr[24 : 12]} == {f_addr[24 : 12]};assign pending = csn_match && bank_match && rnw_match && row_match && !f_empty;assign bank_alter = csn_match && !bank_match && !f_empty;assign cas_addr = f_select ? f_addr[9 : 0] : active_addr[9 : 0];reg last_rnw;//0=read;1=writereg [1:0] burst;// **** Main FSM ****always @(posedge clk or negedge reset_n)beginif (reset_n == 0)beginm_state <= 0;m_next <= 0;m_cmd <= 4'b1111;m_bank <= 2'b00;m_addr <= 13'b0000000000000;m_data <= 64'b0000000000000000;m_dqm <= 8'b00;m_count <= 4'b0000;ack_refresh_request <= 1'b0;f_pop <= 1'b0;oe <= 1'b0;endelsebeginf_pop <= 1'b0;oe <= 1'b0;case (m_state) // synthesis parallel_case full_case0: begin//Wait for init-fsm to be done...if (init_done)begin//Hold bus if another cycle ended to arf.if (refresh_request)m_cmd <= {{1{1'b0}},3'h7};elsem_cmd <= 4'b1111;ack_refresh_request <= 1'b0;//Wait for a read/write request.if (refresh_request)beginm_state <= 6;m_next <= 7;m_count <= 2;active_cs_n <= 1'b1;endelse if (!f_empty)beginf_pop <= 1'b1;active_cs_n <= f_cs_n;active_rnw <= f_rnw;active_addr <= f_addr;active_data <= f_data;active_dqm <= f_dqm;m_state <= 1;endendelsebeginm_addr <= i_addr;m_state <= 0;m_next <= 0;m_cmd <= i_cmd;endend // 0//active1: beginm_state <= 2;m_cmd <= {csn_decode,3'h3};m_bank <= active_bank;m_addr <= active_addr[24 : 12];m_data <= active_data;m_dqm <= active_dqm;m_count <= 3;m_next <= active_rnw ? 3 : 4;end // 12: begin// precharge all if arf, else precharge csn_decodeif (m_next == 7)m_cmd <= {{1{1'b0}},3'h7};elsem_cmd <= {csn_decode,3'h7};//Count down til safe to Proceed...if (m_count > 1)m_count <= m_count - 1'b1;elsem_state <= m_next;end // 23: begin //readlast_rnw<=0;burst<=burst+1;case(burst)0:beginm_cmd <= {cs_n,3'h5};m_bank <= f_select ? f_bank : active_bank;m_dqm <= f_select ? f_dqm : active_dqm;m_addr<={2'b00,bank_alter,cas_addr};//auto precharge for bank ALTERNATINGend1:m_cmd <= {cs_n,3'h7};2:beginif(bank_alter) beginm_cmd <= {cs_n,3'h3};m_bank <= f_bank;m_dqm <= f_dqm;m_addr<= f_addr[24 : 12];endend3:beginm_cmd <= {cs_n,3'h7};//Do we have a transaction pending?if (pending || (bank_alter&rnw_match)) begin//if we need to ARF, bail, else spinif (refresh_request) beginm_state <= 2;m_next <= 0;m_count <= 2;endelse beginf_pop <= 1'b1;active_cs_n <= f_cs_n;active_rnw <= f_rnw;active_addr <= f_addr;active_data <= f_data;active_dqm <= f_dqm;endendelse if(bank_alter) beginm_state <= 8;active_cs_n <= f_cs_n;//active_rnw <= f_rnw;active_addr <= f_addr;active_data <= f_data;active_dqm <= f_dqm;endelse begin//correctly end RD spin cycle if fifo mtm_state <= 8;if (~pending & ~bank_alter & f_pop)m_cmd <= {cs_n,3'h7};endendendcaseend4: begin//writeoe <= 1'b1;last_rnw<=1;burst<=burst+1;case(burst)0:beginm_cmd <= {csn_decode,3'h4};m_data <= f_select ? f_data : active_data;m_dqm <= f_select ? f_dqm : active_dqm;m_bank <= f_select ? f_bank : active_bank;m_addr<={2'b00,bank_alter,cas_addr};//auto precharge for bank ALTERNATINGend1:begin m_cmd <= {cs_n,3'h7};m_data<=m_data>>16;m_dqm<=m_dqm>>2;end2:beginm_data<=m_data>>16;m_dqm<=m_dqm>>2;if(bank_alter) beginm_cmd <= {cs_n,3'h3};m_bank <= f_bank;m_dqm <= f_dqm;m_addr<= f_addr[24 : 12];endend3:begin//Do we have a transaction pending?m_cmd <= {cs_n,3'h7};m_data<=m_data>>16;m_dqm<=m_dqm>>2;if (pending || (bank_alter&rnw_match)) begin//if we need to ARF, bail, else spinif (refresh_request) beginm_state <= 2;m_next <= 0;m_count <= 2;endelse beginf_pop <= 1'b1;active_cs_n <= f_cs_n;active_rnw <= f_rnw;active_addr <= f_addr;active_data <= f_data;active_dqm <= f_dqm;endendelse if(bank_alter) beginm_state <= 8;active_cs_n <= f_cs_n;//active_rnw <= f_rnw;active_addr <= f_addr;active_data <= f_data;active_dqm <= f_dqm;endelse begin//correctly end WR spin cycle if fifo emptym_state <= 8;if (~pending & ~bank_alter & f_pop) beginm_cmd <= {csn_decode,3'h7};oe <= 1'b0;endendendendcaseend // 45: beginm_cmd <= {csn_decode,3'h7};//Count down til safe to Proceed...if (m_count > 1)m_count <= m_count - 1'b1;elsebeginm_state <= 6;m_count <= 2;endend // 56: beginm_state <= 2;m_addr <= {13{1'b1}};// precharge all if arf, else precharge csn_decodeif (refresh_request)m_cmd <= {{1{1'b0}},3'h2};elsem_cmd <= {csn_decode,3'h2};end // 67: beginack_refresh_request <= 1'b1;m_state <= 2;m_cmd <= {{1{1'b0}},3'h1};m_count <= 9;m_next <= 0;end // 78: beginm_cmd <= {csn_decode,3'h7};//if we need to ARF, bail, else spinif (refresh_request)beginm_state <= 2;m_next <= 0;m_count <= 1;endelse //wait for fifo to have contentsif (!f_empty)//Are we 'pending' yet?if (csn_match && (rnw_match|last_rnw) && bank_match && row_match) //read to read,write to write,write to readbeginm_state <= f_rnw ? 3 : 4;f_pop <= 1'b1;active_cs_n <= f_cs_n;active_rnw <= f_rnw;active_addr <= f_addr;active_data <= f_data;active_dqm <= f_dqm;endelse if(csn_match && bank_match && row_match)//read to writebeginm_state <= 2;m_next <= 4;m_count <= 3;f_pop <= 1'b1;active_cs_n <= f_cs_n;active_rnw <= f_rnw;active_addr <= f_addr;active_data <= f_data;active_dqm <= f_dqm;endelsebeginm_state <= 5;m_next <= 0;m_count <= 1;endend // 8// synthesis translate_offdefault: beginm_state <= m_state;m_cmd <= 4'b1111;f_pop <= 1'b0;oe <= 1'b0;end // default// synthesis translate_onendcase // m_stateendendassign rd_strobe = m_cmd[2 : 0] == 3'h5;//Track RD Req's based on cas_latency w/shift regalways @(posedge clk or negedge reset_n)beginif (reset_n == 0)rd_valid <= {6{1'b0}};elserd_valid <= {rd_valid[4:0], rd_strobe};end// Register dq data.always @(posedge clk)za_data <= {zs_dq,za_data[63:16]};// Delay za_valid to match registered data.always @(posedge clk or negedge reset_n)beginif (reset_n == 0)za_valid <= 0;else if (1)za_valid <= rd_valid[5];end// Register dq data.(*noprune*) reg [15:0] za_data_stp;always @(posedge clk)za_data_stp <= zs_dq;(*noprune*) reg za_valid_stp;always @(posedge clk)za_valid_stp <= |rd_valid[5:2];endmodule

标签: #za无权访问data文件夹