【黑金原创教程】【FPGA那些事儿-驱动篇I 】实验十九:SDRAM模块② — 多字读写

简介: 实验十九:SDRAM模块② — 多字读写 表示19.1 Mode Register的内容。 Mode Register A12 A11 A10 A9 A8 A7 A6 A5 A4 A3...

实验十九:SDRAM模块② — 多字读写

表示19.1 Mode Register的内容。

Mode Register

A12

A11

A10

A9

A8

A7

A6

A5

A4

A3

A2

A1

A0

0

0

OP Code

0

0

CAS Latency

BT

Burst Length

A3

Burst Type

0

Sequential

1

Interleave

 

Burst Length

A2

A1

A0

A3 = 0

A3 = 1

0

0

0

1

1

0

0

1

2

2

0

1

0

4

4

0

1

1

8

8

1

1

1

Full Page

Reserved

A9

Write Mode

0

Burst Read and Burst Write

1

Burst Read and Single Write

A6

A5

A4

CAS Latency

0

1

0

2

0

1

1

3

实验十八我们实现单字读写,实验十九则要实现多字读写。表19.1告诉我们,A2~A0控制Burst Length的长度,为了实现长度为4的字读写,A2~A0的内容设置为3’b010。

7: // Send LMR Cmd. Burst Read & Write, 3'b011 mean CAS latecy = 3, Sequentia 4 burst length

begin rCMD <= _LMR; rBA <= 2'b11; rA <= { 3'd0, 1'b0, 2'd0, 3'b011, 1'b0, 3'b010 }; i <= i + 1'b1; end

代码19.2

如代码基本上,初始化的大致过程与实验十八没有什么两样,仅有更改 Mode Register 的内容,结果如代码19.2所示。对此,写操作还有读操作因为读写字节改变,所以时序也稍微改变了一下。

多字写操作:

clip_image002

图19.1 多字写操作的理想时序图。

图19.1是多字写操作的理想时序图。T1~T3基本上没有什么改变,反之接续的T4~T6会依据Burst Length设置的长度而有所改变。由于 Burst Length 设置为 4,结果T3写第一字数据,T4写第二字数据,T5写第三字数据,T6则写第四字,然而大致的过程如下所示:

l T1,发送ACT命令,BANK地址与行地址;

l T1半周期,SDRAM读取;

l T2,满足TRCD;

l T3,发送WR命令,BANK地址与列地址,还有写第一字数据;

l T3半周期,SDRAM读取;

l T4,写第二字数据;

l T4半周期,SDRAM读取;

l T5,写第三字数据;

l T5半周期,SDRAM读取;

l T6,写第四字数据;

l T6半周期,SDRAM读取;

l T7,满足TWR;

l T8,满足TRP。

Verilog则可以这样描述,结果如代码19.2所示:

1.          1: // Send Active Command with Bank and Row address
2.          begin rCMD <= _ACT; rBA <= iAddr[23:22]; rA <= iAddr[21:9]; i <= i + 1'b1; end
3.                         
4.         2: // wait TRCD 20ns
5.         if( C1 == TRCD -1 ) begin C1 <= 14'd0; i <= i + 1'b1; end
6.          else begin rCMD <= _NOP; C1 <= C1 + 1'b1; end             
7.                   
8.          3: // Send Write command with row address, pull up A10 to PR
9.           begin rCMD <= _WR; rBA <= iAddr[23:22]; rA <= {4'b0010,iAddr[8:0]}; D1 <= iData[63:48]; i <= i + 1'b1; end
10.                         
11.          4:  
12.         begin rCMD <= _NOP; D1 <= iData[47:32]; i <= i + 1'b1; end
13.                         
14.         5:
15.          begin rCMD <= _NOP; D1 <= iData[31:16]; i <= i + 1'b1; end
16.                         
17.         6:
18.         begin rCMD <= _NOP; D1 <= iData[15:0]; i <= i + 1'b1; end
19.                                          
20.         7: // wait TWR 2 clock
21.         if( C1 == TWR -1 ) begin C1 <= 14'd0; i <= i + 1'b1; end
22.          else begin rCMD <= _NOP; C1 <= C1 + 1'b1; end  
23.                         
24.          8: // wait TRP 20ns
25.         if( C1 == TRP -1 ) begin C1 <= 14'd0; i <= i + 1'b1; end
26.          else begin rCMD <= _NOP; C1 <= C1 + 1'b1; end  

代码19.2

假设多字读写由高至低,那么步骤3写入iData[63:48],步骤4写入 iData[47:32],步骤5写入 iData[31:16],步骤6写 iData[15:0]。

多字读操作:

clip_image004

图19.2 多字读操作的理想时序图。

图19.2是多字读操作的理想时序图,大致过程如下:

l T1,发送ACT命令,BANK地址与行地址;

l T1半周期,SDRAM读取;

l T2,满足TRCD;

l T3,发送RD命令,BANK地址与列地址;

l T3半周期,SDRAM读取命令;

l T4,满足 CAS Latency;

l T5,读取第一字数据;

l T6,读取第二字数据;

l T7,读取第三字数据;

l T8,读取第四字数据。

多字读操作相较单字读操作稍微有一些不同,不同的地方除了读取数据的字变长以外,还有 TRP满足在最后两字之中。至于Verilog则可以这样描述,结果如代码19.3所示:

1.         1: // Send Active command with Bank and Row address
2.         begin rCMD <= _ACT; rBA <= iAddr[23:22]; rA <= iAddr[21:9]; i <= i + 1'b1; end
3.                         
4.         2: // wait TRCD 20ns
5.         if( C1 == TRCD -1 ) begin C1 <= 14'd0; i <= i + 1'b1; end
6.         else begin rCMD <= _NOP; C1 <= C1 + 1'b1; end 
7.                    
8.         3: // Send Read command and column address, pull up A10 to PR
9.         begin rCMD <= _RD; rBA <= iAddr[23:22]; rA <= { 4'b0010, iAddr[8:0]}; i <= i + 1'b1; end
10.    
11.         4: // wait CL 3 clock
12.         if( C1 == CL -1 ) begin C1 <= 14'd0; i <= i + 1'b1; end
13.         else begin rCMD <= _NOP; C1 <= C1 + 1'b1; end 
14.                                       
15.         5: // Read Data
16.         begin T[63:48] <= S_DQ; i <= i + 1'b1; end
17.                    
18.         6: // Read Data
19.         begin T[47:32] <= S_DQ; i <= i + 1'b1; end
20.                         
21.         7: // Read Data
22.         begin T[31:16] <= S_DQ; i <= i + 1'b1; end
23.                         
24.         8: // Read Data
25.         begin T[15:0] <= S_DQ; i <= i + 1'b1; end 

代码19.3

代码19.3也没有什么好解释的,基本上完全根据图19.2描述。理解完毕以后,我们就可以开始建模了。

clip_image006

图19.3 SDRAM基础模块的建模图。

图19.3是SDRAM基础模块的建模图,这家伙比较实验十八,最大的区别就是iData与oData的位宽增大而已。

sdram_funcmod.v

clip_image008

图19.4 SDRAM功能模块的建模图。

图19.4是SDRAM功能模块的建模图,具体内容我们还是来看代码吧。

1.    module sdram_funcmod
2.    (
3.         input CLOCK,
4.         input RESET,
5.         
6.         output S_CKE, S_NCS, S_NRAS, S_NCAS, S_NWE,
7.         output [1:0]S_BA,  //2
8.         output [12:0]S_A,  //12, CA0~CA8, RA0~RA12, BA0~BA1, 9+13+2 = 24;
9.         output [1:0]S_DQM,
10.         inout [15:0]S_DQ,
11.         
12.         input [3:0]iCall,
13.         output oDone,
14.         input [23:0]iAddr,  // [23:22]BA,[21:9]Row,[8:0]Column
15.         input [63:0]iData,
16.         output [63:0]oData
17.    );

以上内容为相关的出入端声明,注意第15~16行的位宽增大至64位。

18.        parameter T100US = 14'd13300;
19.        // tRP 20ns, tRRC 63ns, tRCD 20ns, tMRD 2CLK, tWR/tDPL 2CLK, CAS Latency 3CLK
20.        parameter TRP = 14'd3, TRRC = 14'd9, TMRD = 14'd2, TRCD = 14'd3, TWR = 14'd2, CL = 14'd3;
21.        parameter  _INIT = 5'b01111, _NOP = 5'b10111, _ACT = 5'b10011, _RD = 5'b10101, _WR = 5'b10100,
22.                  _BSTP = 5'b10110, _PR = 5'b10010, _AR = 5'b10001, _LMR = 5'b10000;
23.        

以上内容为相关的常量声明。

24.        reg [4:0]i;
25.        reg [13:0]C1;
26.        reg [15:0]D1;
27.        reg [63:0]T;
28.        reg [4:0]rCMD;
29.        reg [1:0]rBA;
30.        reg [12:0]rA;
31.        reg [1:0]rDQM;
32.        reg isOut;
33.        reg isDone;
34.    
35.        always @ ( posedge CLOCK or negedge RESET )
36.            if( !RESET )
37.                begin
38.                    i <= 4'd0;
39.                  C1 <= 14'd0;
40.                  D1 <= 16'd0;
41.                  T <= 64'd0;
42.                    rCMD <= _NOP;
43.                    rBA <= 2'b11;
44.                  rA <= 13'h1fff;
45.                    rDQM <= 2'b00;
46.                    isOut <= 1'b1;
47.                  isDone <= 1'b0;
48.                end

以上内容为相关的寄存器声明与复位操作,注意寄存器T是用来暂存读取数据。

49.              else if( iCall[3] )
50.                case( i )
51.                    
52.                    0: // Set IO to output State
53.                    begin isOut <= 1'b1; i <= i + 1'b1; end
54.                       
55.                    1: // Send Active Command with Bank and Row address
56.                    begin rCMD <= _ACT; rBA <= iAddr[23:22]; rA <= iAddr[21:9]; i <= i + 1'b1; end
57.                         
58.                  2: // wait TRCD 20ns
59.                  if( C1 == TRCD -1 ) begin C1 <= 14'd0; i <= i + 1'b1; end
60.                    else begin rCMD <= _NOP; C1 <= C1 + 1'b1; end             
61.                    
62.                    /*********************************************/
63.                    
64.                   3: // Send Write command with row address, pull up A10 to PR
65.                 begin rCMD <= _WR; rBA <= iAddr[23:22]; rA <= { 4'b0010, iAddr[8:0] }; D1 <= iData[63:48]; i <= i + 1'b1; end
66.                         
67.                    4:  
68.                  begin rCMD <= _NOP; D1 <= iData[47:32]; i <= i + 1'b1; end
69.                         
70.                  5:
71.                  begin rCMD <= _NOP; D1 <= iData[31:16]; i <= i + 1'b1; end
72.                         
73.                  6:
74.                  begin rCMD <= _NOP; D1 <= iData[15:0]; i <= i + 1'b1; end
75.                     
76.                    /**********************************************/
77.                         
78.                  7: // wait TWR 2 clock
79.                  if( C1 == TWR -1 ) begin C1 <= 14'd0; i <= i + 1'b1; end
80.                    else begin rCMD <= _NOP; C1 <= C1 + 1'b1; end  
81.                         
82.                  8: // wait TRP 20ns
83.                  if( C1 == TRP -1 ) begin C1 <= 14'd0; i <= i + 1'b1; end
84.                    else begin rCMD <= _NOP; C1 <= C1 + 1'b1; end        
85.                         
86.                    /*******************/
87.                         
88.                    9: // Generate done signal
89.                    begin isDone <= 1'b1; i <= i + 1'b1; end
90.                        
91.                  10:
92.                  begin isDone <= 1'b0; i <= 4'd0; end
93.    
94.                endcase

以上内容为部分核心操作。注意步骤3~6,D1用来驱动SD_Q,而iData赋值D1,次序由高至低。

95.            else if( iCall[2] )
96.                case( i )
97.                    
98.                  0:
99.                  begin isOut <= 1'b0; D1 <= 16'd0; i <= i + 1'b1; end
100.    
101.                    1: // Send Active command with Bank and Row address
102.                    begin rCMD <= _ACT; rBA <= iAddr[23:22]; rA <= iAddr[21:9]; i <= i + 1'b1; end
103.                         
104.                  2: // wait TRCD 20ns
105.                  if( C1 == TRCD -1 ) begin C1 <= 14'd0; i <= i + 1'b1; end
106.                    else begin rCMD <= _NOP; C1 <= C1 + 1'b1; end 
107.                
108.                    /********************/
109.                    
110.                    3: // Send Read command and column address, pull up A10 to PR
111.                    begin rCMD <= _RD; rBA <= iAddr[23:22]; rA <= { 4'b0010, iAddr[8:0]}; i <= i + 1'b1; end
112.    
113.                    4: // wait CL 3 clock
114.                    if( C1 == CL -1 ) begin C1 <= 14'd0; i <= i + 1'b1; end
115.                    else begin rCMD <= _NOP; C1 <= C1 + 1'b1; end 
116.                                       
117.                    /********************/ 
118.                    
119.                    5: // Read Data
120.                    begin T[63:48] <= S_DQ; i <= i + 1'b1; end
121.                    
122.                  6: // Read Data
123.                    begin T[47:32] <= S_DQ; i <= i + 1'b1; end
124.                         
125.                  7: // Read Data
126.                    begin T[31:16] <= S_DQ; i <= i + 1'b1; end
127.                         
128.                  8: // Read Data
129.                    begin T[15:0] <= S_DQ; i <= i + 1'b1; end
130.                         
131.                    /********************/
132.                
133.                    9: // Generate done signal
134.                    begin rCMD <= _NOP; isDone <= 1'b1; i <= i + 1'b1; end
135.                        
136.                  10:
137.                  begin isDone <= 1'b0; i <= 4'd0; end
138.    
139.                endcase

以上内容为部分核心操作。注意步骤5~8,寄存器T用来暂存读数据,次序由高至低。

140.              else if( iCall[1] )
141.                case( i )
142.                    
143.                  0: // Send Precharge Command
144.                  begin rCMD <= _PR; i <= i + 1'b1; end
145.                         
146.                  1: // wait TRP 20ns
147.                  if( C1 == TRP -1 ) begin C1 <= 14'd0; i <= i + 1'b1; end
148.                    else begin rCMD <= _NOP; C1 <= C1 + 1'b1; end
149.                         
150.                    2: // Send Auto Refresh Command
151.                    begin rCMD <= _AR; i <= i + 1'b1; end
152.                   
153.                    3: // wait TRRC 63ns
154.                  if( C1 == TRRC -1 ) begin C1 <= 14'd0; i <= i + 1'b1; end
155.                    else begin rCMD <= _NOP; C1 <= C1 + 1'b1; end
156.                         
157.                  4: // Send Auto Refresh Command
158.                    begin rCMD <= _AR; i <= i + 1'b1; end
159.                   
160.                    5: // wait TRRC 63ns
161.                  if( C1 == TRRC -1 ) begin C1 <= 14'd0; i <= i + 1'b1; end
162.                    else begin rCMD <= _NOP; C1 <= C1 + 1'b1; end
163.                    
164.                    /********************/
165.                    
166.                    6: // Generate done signal
167.                    begin isDone <= 1'b1; i <= i + 1'b1; end
168.                        
169.                  7:
170.                  begin isDone <= 1'b0; i <= 4'd0; end
171.    
172.                endcase

以上内容为部分核心操作。刷新操作,基本上没有什么改变。

173.              else if( iCall[0] )
174.               case( i )
175.                    
176.                   0:  // delay 100us
177.                   if( C1 == T100US -1 ) begin C1 <= 14'd0; i <= i + 1'b1; end
178.                   else begin C1 <= C1 + 1'b1; end 
179.                   
180.                   /********************/
181.                   
182.                   1: // Send Precharge Command
183.                   begin rCMD <= _PR; { rBA, rA } <= 15'h3fff; i <= i + 1'b1; end
184.                        
185.                   2: // wait TRP 20ns
186.                 if( C1 == TRP -1 ) begin C1 <= 14'd0; i <= i + 1'b1; end
187.                   else begin rCMD <= _NOP; C1 <= C1 + 1'b1; end
188.                   
189.                   3: // Send Auto Refresh Command
190.                   begin rCMD <= _AR; i <= i + 1'b1; end
191.                   
192.                   4: // wait TRRC 63ns
193.                 if( C1 == TRRC -1 ) begin C1 <= 14'd0; i <= i + 1'b1; end
194.                   else begin rCMD <= _NOP; C1 <= C1 + 1'b1; end
195.                        
196.                   5: // Send Auto Refresh Command
197.                   begin rCMD <= _AR; i <= i + 1'b1; end
198.                   
199.                   6: // wait TRRC 63ns
200.                 if( C1 == TRRC -1 ) begin C1 <= 14'd0; i <= i + 1'b1; end
201.                   else begin rCMD <= _NOP; C1 <= C1 + 1'b1; end
202.                
203.                   /********************/
204.                   
205.                   7: // Send LMR Cmd. Burst Read & Write,  3'b011 mean CAS latecy = 3, Sequentia 4 burst length
206.                   begin rCMD <= _LMR; rBA <= 2'b11; rA <= { 3'd0, 1'b0, 2'd0, 3'b011, 1'b0, 3'b010 }; i <= i + 1'b1; end
207.                        
208.                 8: // Send 2 nop CLK for tMRD
209.                 if( C1 == TMRD -1 ) begin C1 <= 14'd0; i <= i + 1'b1; end
210.                   else begin rCMD <= _NOP; C1 <= C1 + 1'b1; end
211.                   
212.                   /********************/
213.                   
214.                   9: // Generate done signal
215.                   begin isDone <= 1'b1; i <= i + 1'b1; end
216.                        
217.                 10:
218.                 begin isDone <= 1'b0; i <= 4'd0; end
219.                   
220.                endcase
221.      

以上内容为部分核心操作。初始化操作,注意步骤7,Burst Length 设置为 3’b010。

222.          assign { S_CKE, S_NCS, S_NRAS, S_NCAS, S_NWE } = rCMD;
223.         assign { S_BA, S_A } = { rBA, rA };
224.         assign S_DQM = rDQM;
225.         assign S_DQ  = isOut ? D1 : 16'hzzzz;
226.         assign oDone = isDone;
227.         assign oData = T;
228.    
229.    endmodule

以上内容为相关的输出驱动,D1驱动S_DQ,T驱动oData。

sdram_ctrlmod.v

该控制模块的内容基本上与实验十八一模一样,笔者就不重复粘贴了。

sdram_demo.v

clip_image010

图19.5 实验十九的建模图。

图19.5是实验十九的建模图,虽然外观上改变不大,最多只是Data的位宽改为64位而已 ... 话虽如此,核心操作则有点不同,具体的内容让我们来看代码吧。

1.    module sdram_demo
2.    (
3.        input CLOCK,
4.        input RESET,
5.        output S_CLK,
6.        output S_CKE, S_NCS, S_NRAS, S_NCAS, S_NWE,
7.        output [12:0]S_A, 
8.        output [1:0]S_BA,
9.        output [1:0]S_DQM,
10.        inout [15:0]S_DQ,
11.        output TXD
12.    ); 

以上内容为相关的出入端声明。

13.         wire CLOCK1,CLOCK2;
14.         
15.         pll_module U1
16.         (
17.                 .inclk0 ( CLOCK ), // 50Mhz
18.                .c0 ( CLOCK1 ),  // 133Mhz -210 degree phase
19.                .c1 ( CLOCK2 )   // 133Mhz 
20.         );
21.             

以上内容为PLL模块的实例化。

22.         wire [1:0]DoneU2;
23.         wire [63:0]DataU2;
24.         
25.         sdram_basemod U2
26.         (
27.              .CLOCK( CLOCK1 ),
28.              .RESET( RESET ),
29.              .S_CKE( S_CKE ),
30.              .S_NCS( S_NCS ),
31.              .S_NRAS( S_NRAS ),
32.              .S_NCAS( S_NCAS ),
33.              .S_NWE( S_NWE ),
34.              .S_A( S_A ),
35.              .S_BA( S_BA ),
36.              .S_DQM( S_DQM ),
37.              .S_DQ( S_DQ ),
38.              .iCall( isCall ),
39.              .oDone( DoneU2 ),
40.              .iAddr( {D1,2’b00} ),
41.               .iData( D2 ),
42.              .oData( DataU2 )
43.         );
44.         

以上内容为sdram基础模块的实例化。

45.         parameter B115K2 = 11'd1157, TXFUNC = 6'd16;
46.         
47.         reg [5:0]i,Go;
48.         reg [10:0]C1;
49.         reg [21:0]D1;
50.         reg [63:0]D2,D3;
51.         reg [10:0]T;
52.         reg [1:0]isCall;
53.         reg rTXD;
54.         
55.         always @ ( posedge CLOCK1 or negedge RESET )
56.             if( !RESET )
57.                 begin
58.                           i <= 6'd0;
59.                          Go <= 6'd0;
60.                          C1 <= 11'd0;
61.                           D1 <= 22'd0;
62.                          D2 <= 64'd0;
63.                          D3 <= 64'd0;
64.                          T <= 11'd0;
65.                          isCall <= 2'b00;
66.                          rTXD <= 1'b1;
67.                 end

以上内容为相关的寄存器声明还有复位操作。第45行是波特率为115200的常量声明还有伪函数入口。

68.             else 
69.                 case( i )
70.                        
71.                         0:
72.                         if( DoneU2[1] ) begin isCall[1] <= 1'b0; i <= i + 1'b1; end
73.                         else begin isCall[1] <= 1'b1; D1 <= 22'd0; D2 <= 64'hAABBCCDDEEFF8899; end
74.                         
75.                         1:
76.                         if( DoneU2[0] ) begin D3 <= DataU2; isCall[0] <= 1'b0; i <= i + 1'b1; end
77.                         else begin isCall[0] <= 1'b1; D1 <= 22'd0; end
78.                         
79.                         2:
80.                         begin T <= { 2'b11, D3[63:56], 1'b0 }; i <= TXFUNC; Go <= i + 1'b1; end
81.                         
82.                         3:
83.                         begin T <= { 2'b11, D3[55:48], 1'b0 }; i <= TXFUNC; Go <= i + 1'b1; end
84.                         
85.                         4:
86.                         begin T <= { 2'b11, D3[47:40], 1'b0 }; i <= TXFUNC; Go <= i + 1'b1; end
87.                         
88.                         5:
89.                         begin T <= { 2'b11, D3[39:32], 1'b0 }; i <= TXFUNC; Go <= i + 1'b1; end
90.                         
91.                         6:
92.                         begin T <= { 2'b11, D3[31:24], 1'b0 }; i <= TXFUNC; Go <= i + 1'b1; end
93.                         
94.                         7:
95.                         begin T <= { 2'b11, D3[23:16], 1'b0 }; i <= TXFUNC; Go <= i + 1'b1; end
96.                                              
97.                         8:
98.                         begin T <= { 2'b11, D3[15:8], 1'b0 }; i <= TXFUNC; Go <= i + 1'b1; end
99.                         
100.                         9:
101.                         begin T <= { 2'b11, D3[7:0], 1'b0 }; i <= TXFUNC; Go <= i + 1'b1; end
102.                         
103.                          10:
104.                         i <= i;
105.                         
106.                        /******************************/
107.                     

以上内容为部分核心操作。步骤0将64位的数据写入地址0,步骤1则将数据从地址0读取。步骤2~9则是轮番将数据送出去。

108.                          16,17,18,19,20,21,22,23,24,25,26:
109.                         if( C1 == B115K2 -1 ) begin C1 <= 11'd0; i <= i + 1'b1; end
110.                         else begin rTXD <= T[i - 16]; C1 <= C1 + 1'b1; end
111.                         
112.                         27:
113.                         i <= Go;
114.                         
115.                endcase
116.    
117.          assign S_CLK = CLOCK2;
118.          assign TXD = rTXD;
119.    
120.    endmodule

以上内容为部分核心操作。步骤16~27是发送一帧数据的伪函数。第117~118行则是相关的输出驱动。综合完毕并且下载程序,如果串口调试程序出现数据 AABBCCDDEEFF8899,结果表示实验成功。

细节一:完整的个体模块

本实验的SDRAM基础模块已经准备就绪。

细节二:读写地址的驱动方式

1.    sdram_basemod
2.    (   
3.        ... 
4.        iAddr( {D1,2’b00} ),
5.        ...
6.    );
7.    reg [21:0]D1;
8.    ...
9.    always @ ( posedge CLOCK1 )
10.         ...
11.         case( i )
12.             0:
13.             if( ... ) ...
14.             else D1 <= 22'd0; ...

代码19.4

代码19.4是sdram_demo的部分内容,其中iAddr由22位宽的D1与2’b00联合驱动,好奇的朋友一定会觉得疑惑“为什么”?其实这是经过深思以后的写法。实验十九是多字读写操作,其中长度为4,或者说地址的偏移量为4,所以iAddr[1:0] 所指定的范围基本作废。为了正式这点问题,代码19.4需要这样表达。

1.    sdram_basemod
2.    (   
3.        ... 
4.        iAddr( D1 ),
5.        ...
6.    );
7.    reg [23:0]D1;
8.    ...
9.    always @ ( posedge CLOCK1 )
10.         ...
11.         case( i )
12.             0:
13.             if( ... ) ...
14.             else D1 <= 24'd1; ...

代码19.5

如代码19.5所示,假设我们无视这个问题,直接使用24位宽的D1驱动iAddr,然后将数据写入地址24’d1。根据SDRAM的内部操作,数据会依序写入地址为1234,而不是 0123 或者 4567 之类 ... 如此一来,我们会不小心破坏地址的偏移量。

目录
相关文章
|
3天前
|
算法 数据安全/隐私保护 异构计算
基于FPGA的16QAM调制+软解调系统,包含testbench,高斯信道模块,误码率统计模块,可以设置不同SNR
本项目基于FPGA实现了16QAM基带通信系统,包括调制、信道仿真、解调及误码率统计模块。通过Vivado2019.2仿真,设置不同SNR(如8dB、12dB),验证了软解调相较于传统16QAM系统的优越性,误码率显著降低。系统采用Verilog语言编写,详细介绍了16QAM软解调的原理及实现步骤,适用于高性能数据传输场景。
101 69
|
8天前
|
移动开发 算法 数据安全/隐私保护
基于FPGA的QPSK调制+软解调系统,包含testbench,高斯信道模块,误码率统计模块,可以设置不同SNR
本文介绍了基于FPGA的QPSK调制解调系统,通过Vivado 2019.2进行仿真,展示了在不同信噪比(SNR=1dB, 5dB, 10dB)下的仿真效果。与普通QPSK系统相比,该系统的软解调技术显著降低了误码率。文章还详细阐述了QPSK调制的基本原理、信号采样、判决、解调及软解调的实现过程,并提供了Verilog核心程序代码。
45 26
|
14天前
|
算法 异构计算
基于FPGA的4ASK调制解调系统,包含testbench,高斯信道模块,误码率统计模块,可以设置不同SNR
本文介绍了基于FPGA的4-ASK调制解调系统的算法仿真效果、理论基础及Verilog核心程序。仿真在Vivado2019.2环境下进行,分别测试了SNR为20dB、15dB、10dB时的性能。理论部分概述了4-ASK的工作原理,包括调制、解调过程及其数学模型。Verilog代码实现了4-ASK调制器、加性高斯白噪声(AWGN)信道模拟、解调器及误码率计算模块。
38 8
|
21天前
|
算法 物联网 异构计算
基于FPGA的4FSK调制解调系统,包含testbench,高斯信道模块,误码率统计模块,可以设置不同SNR
本文介绍了基于FPGA的4FSK调制解调系统的Verilog实现,包括高斯信道模块和误码率统计模块,支持不同SNR设置。系统在Vivado 2019.2上开发,展示了在不同SNR条件下的仿真结果。4FSK调制通过将输入数据转换为四个不同频率的信号来提高频带利用率和抗干扰能力,适用于无线通信和数据传输领域。文中还提供了核心Verilog代码,详细描述了调制、加噪声、解调及误码率计算的过程。
46 11
|
1月前
|
算法 数据安全/隐私保护 异构计算
基于FPGA的1024QAM基带通信系统,包含testbench,高斯信道模块,误码率统计模块,可以设置不同SNR
本文介绍了基于FPGA的1024QAM调制解调系统的仿真与实现。通过Vivado 2019.2进行仿真,分别在SNR=40dB和35dB下验证了算法效果,并将数据导入Matlab生成星座图。1024QAM调制将10比特映射到复数平面上的1024个星座点之一,适用于高数据传输速率的应用。系统包含数据接口、串并转换、星座映射、调制器、解调器等模块。Verilog核心程序实现了调制、加噪声信道和解调过程,并统计误码率。
42 1
|
2月前
|
算法 数据安全/隐私保护 异构计算
基于FPGA的64QAM基带通信系统,包含testbench,高斯信道模块,误码率统计模块,可以设置不同SNR
本文介绍了基于FPGA的64QAM调制解调通信系统的设计与实现,包括信号生成、调制、解调和误码率测试。系统在Vivado 2019.2中进行了仿真,通过设置不同SNR值(15、20、25)验证了系统的性能,并展示了相应的星座图。核心程序使用Verilog语言编写,加入了信道噪声模块和误码率统计功能,提升了仿真效率。
52 4
|
2月前
|
存储 算法 数据处理
基于FPGA的8PSK调制解调系统,包含testbench,高斯信道模块,误码率统计模块,可以设置不同SNR
本系统在原有的8PSK调制解调基础上,新增了高斯信道与误码率统计模块,验证了不同SNR条件下的8PSK性能。VIVADO2019.2仿真结果显示,在SNR分别为30dB、15dB和10dB时,系统表现出不同的误码率和星座图分布。8PSK作为一种高效的相位调制技术,广泛应用于无线通信中。FPGA凭借其高度灵活性和并行处理能力,成为实现此类复杂算法的理想平台。系统RTL结构展示了各模块间的连接与协同工作。
54 16
|
2月前
|
算法 数据安全/隐私保护 异构计算
基于FPGA的16QAM基带通信系统,包含testbench,高斯信道模块,误码率统计模块,可以设置不同SNR
本项目基于FPGA实现16QAM调制解调通信系统,使用Verilog语言编写,包括信道模块、误码率统计模块。通过设置不同SNR值(如8dB、12dB、16dB),仿真测试系统的误码性能。项目提供了完整的RTL结构图及操作视频,便于理解和操作。核心程序实现了信号的生成、调制、信道传输、解调及误码统计等功能。
49 3
|
1月前
|
算法 数据安全/隐私保护 异构计算
基于FPGA的256QAM基带通信系统,包含testbench,高斯信道模块,误码率统计模块,可以设置不同SNR
本文介绍了256QAM调制解调算法的仿真效果及理论基础。使用Vivado 2019.2进行仿真,分别在SNR为40dB、32dB和24dB下生成星座图,并导入Matlab进行分析。256QAM通过将8比特数据映射到复平面上的256个点,实现高效的数据传输。Verilog核心程序包括调制、信道噪声添加和解调模块,最终统计误码率。
34 0
|
2月前
|
算法 数据安全/隐私保护 异构计算
基于FPGA的16PSK调制解调系统,包含testbench,高斯信道模块,误码率统计模块,可以设置不同SNR
### 简介 本项目采用VIVADO 2019.2进行了十六进制相位移键控(16PSK)算法仿真,结果显示,在SNR=30dB时效果为Tttttttttttttt12,在SNR=20dB时效果为Tttttttttttttt34。系统RTL结构如Tttttttttttttt555555所示。16PSK是一种高效的相位调制技术,能在每个符号时间内传输4比特信息,适用于高速数据传输。其工作原理包括将比特流映射到16个相位状态之一(Tttttttttttttt777777),并通过匹配滤波和决策进行解调。具体Verilog核心程序见完整代码。
39 1

热门文章

最新文章