├── LICENSE ├── README.md └── src ├── LED_mux.v ├── bin2bcd.v ├── comprehensive_tb.ucf ├── comprehensive_tb.v ├── debounce_explicit.v └── sdram_controller.v /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Angelo Jacobo 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Created by: Angelo Jacobo 2 | Date: August 12,2021 3 | 4 | # Inside the src folder are: 5 | * sdram_controller.v -> Controller for Synchronous Dynamic RAM. Specs are given below. 6 | * comprehensive_tb.v -> Tests the sdram controller by writing to all 2^24 addresses of SDRAM then 7 |            reading it all back. 8 |            - key[0] writes deterministic data to all 2^24 addresses 9 |            - key[1] reads data from all addresses and checks if the data follows the 10 |              predetermined pattern 11 |            - key[2] injects 10240 errors when pressed along with key[0] 12 |            - number of errors read will be displayed on the seven-segment LEDs 13 | * bin2bcd.v -> binary to bcd converter to display the value of error_q to seven-segment LEDs 14 | * LED_mux.v -> LED multiplexing module for seven-segment LEDs 15 | * comprehensive_tb.ucf -> Constraint file for comprehensive_tb.v 16 | 17 | # UML Chart [SDRAM Controller Sequence]: 18 | ![SDRAM](https://user-images.githubusercontent.com/87559347/129528537-fcd08e70-c3e5-4879-a331-bf02b3d201fb.jpg) 19 | 20 | 21 | # UML Chart [Test Sequence]: 22 | ![SDRAM_TEST](https://user-images.githubusercontent.com/87559347/129528806-16a8d61e-f88c-4729-81a6-bb7e25a5429a.jpg) 23 | 24 | 25 | # About: 26 | This project implemented a controller for the SDRAM mounted on AX309 FPGA development board (i.e. Winbond W9825G6KH SDRAM) 27 | Specs of the controller are: 28 | 29 | * Memory bandwidth is 316MB/s **(can be checked by looking at the value of index_q register on Chipscope)** 30 | * Burst mode is "Full page" **(i.e. burst of 512 words every read and write)** 31 | * Clock input must be 165MHz 32 | * Auto-precharged is disabled **(illegal for 165MHz clk)** 33 | * Clock latency of 3 **(CL=2 is illegal for 165MHz clk)** 34 | * All banks are closed every refresh **(in short no interleaving)** 35 | * Parameters can be configured on sdram_controller.v to suit any kind/brand of sdram device 36 | 37 | # Donate 38 | Support these open-source projects by donating 39 | 40 | [![paypal](https://www.paypalobjects.com/en_US/i/btn/btn_donateCC_LG.gif)](https://www.paypal.com/donate?hosted_button_id=GBJQGJNCJZVRU) 41 | 42 | 43 | # Inquiries 44 | Connect with me at my linkedin: https://www.linkedin.com/in/angelo-jacobo/ 45 | -------------------------------------------------------------------------------- /src/LED_mux.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | module LED_mux 4 | #(parameter N=19) //last 3 bits will be used as output. Frequency=50MHz/(2^(N-3)). So N=19 will have 763Hz 5 | ( 6 | input clk,rst, 7 | input[5:0] in0,in1,in2,in3,in4,in5, //format: {dp,char[4:0]} , dp is active high 8 | output reg[7:0] seg_out, 9 | output reg[5:0] sel_out 10 | ); 11 | /* 12 | LED_mux m1 13 | ( 14 | .clk(clk), 15 | .rst(rst_n), 16 | .in0(in0), 17 | .in1(in1), 18 | .in2(in2), 19 | .in3(in3), 20 | .in4(in4), 21 | .in5(in5), //format: {dp,char[4:0]} , dp is active high 22 | .seg_out(seg_out), 23 | .sel_out(sel_out) 24 | ); 25 | */ 26 | reg[N-1:0] r_reg=0; 27 | reg[5:0] hex_out=0; 28 | wire[N-1:0] r_nxt; 29 | wire[2:0] out_counter; //last 3 bits to be used as output signal 30 | 31 | 32 | //N-bit counter 33 | always @(posedge clk,negedge rst) 34 | if(!rst) r_reg<=0; 35 | else r_reg<=r_nxt; 36 | 37 | assign r_nxt=(r_reg=={3'd5,{(N-3){1'b1}}})?19'd0:r_reg+1'b1; //last 3 bits counts from 0 to 5(6 turns) then wraps around 38 | assign out_counter=r_reg[N-1:N-3]; 39 | 40 | 41 | //sel_out output logic 42 | always @(out_counter) begin 43 | sel_out=6'b111_111; //active low 44 | sel_out[out_counter]=1'b0; 45 | end 46 | 47 | //hex_out output logic 48 | always @* begin 49 | hex_out=0; 50 | casez(out_counter) 51 | 3'b000: hex_out=in0; 52 | 3'b001: hex_out=in1; 53 | 3'b010: hex_out=in2; 54 | 3'b011: hex_out=in3; 55 | 3'b100: hex_out=in4; 56 | 3'b101: hex_out=in5; 57 | endcase 58 | end 59 | 60 | //hex-to-seg decoder 61 | always @* begin 62 | seg_out=0; 63 | case(hex_out[4:0]) 64 | 5'd0: seg_out[6:0]=7'b0000_001; 65 | 5'd1: seg_out[6:0]=7'b1001_111; 66 | 5'd2: seg_out[6:0]=7'b0010_010; 67 | 5'd3: seg_out[6:0]=7'b0000_110; 68 | 5'd4: seg_out[6:0]=7'b1001_100; 69 | 5'd5: seg_out[6:0]=7'b0100_100; 70 | 5'd6: seg_out[6:0]=7'b0100_000; 71 | 5'd7: seg_out[6:0]=7'b0001_111; 72 | 5'd8: seg_out[6:0]=7'b0000_000; 73 | 5'd9: seg_out[6:0]=7'b0001_100; 74 | /*A*/5'd10: seg_out[6:0]=7'b0001_000; 75 | /*b*/5'd11: seg_out[6:0]=7'b1100_000; 76 | /*C*/5'd12: seg_out[6:0]=7'b0110_001; 77 | /*d*/5'd13: seg_out[6:0]=7'b1000_010; 78 | /*E*/5'd14: seg_out[6:0]=7'b0110_000; 79 | /*F*/5'd15: seg_out[6:0]=7'b0111_000; 80 | /*G*/5'd16: seg_out[6:0]=7'b0100_000; 81 | /*H*/5'd17: seg_out[6:0]=7'b1001_000; 82 | /*I*/5'd18: seg_out[6:0]=7'b1111_001; 83 | /*J*/5'd19: seg_out[6:0]=7'b1000_011; 84 | /*L*/5'd20: seg_out[6:0]=7'b1110_001; 85 | /*O*/5'd21: seg_out[6:0]=7'b0000_001; 86 | /*P*/5'd22: seg_out[6:0]=7'b0011_000; 87 | /*R*/5'd23: seg_out[6:0]=7'b0001_000; 88 | /*S*/5'd24: seg_out[6:0]=7'b0100_100; 89 | /*U*/5'd25: seg_out[6:0]=7'b1000_001; 90 | /*y*/5'd26: seg_out[6:0]=7'b1000_100; 91 | /*Z*/5'd27: seg_out[6:0]=7'b0010_010; 92 | /*OFF*/5'd28: seg_out[6:0]=7'b1111_111; //decimal 29 to 31 will be alloted for future use 93 | endcase 94 | seg_out[7]=!hex_out[5]; //active high decimal 95 | end 96 | 97 | endmodule 98 | -------------------------------------------------------------------------------- /src/bin2bcd.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | module bin2bcd( 4 | input clk,rst_n, 5 | input start, 6 | input[36:0] bin,//11 digit max of {11{9}} 7 | output reg ready,done_tick, 8 | output reg[3:0] dig0,dig1,dig2,dig3,dig4,dig5,dig6,dig7,dig8,dig9,dig10 //not all output will be used(this module is a general-purpose bin2bcd) 9 | ); 10 | //FSM declarations 11 | localparam[1:0] idle=2'd0, 12 | op=2'd1, 13 | done=2'd2; 14 | localparam N=37; //width of binary 15 | 16 | reg[1:0] state_reg,state_nxt; 17 | reg[36:0] bin_reg,bin_nxt; 18 | reg[3:0] dig0_reg,dig1_reg,dig2_reg,dig3_reg,dig4_reg,dig5_reg,dig6_reg,dig7_reg,dig8_reg,dig9_reg,dig10_reg; 19 | reg[3:0] dig0_nxt,dig1_nxt,dig2_nxt,dig3_nxt,dig4_nxt,dig5_nxt,dig6_nxt,dig7_nxt,dig8_nxt,dig9_nxt,dig10_nxt; 20 | reg[5:0] n_reg,n_nxt; //will store value of "N" 21 | 22 | //FSM reguster operations 23 | always @(posedge clk,negedge rst_n) begin 24 | if(!rst_n) begin 25 | state_reg<=idle; 26 | bin_reg<=0; 27 | dig0_reg<=0; 28 | dig1_reg<=0; 29 | dig2_reg<=0; 30 | dig3_reg<=0; 31 | dig4_reg<=0; 32 | dig5_reg<=0; 33 | dig6_reg<=0; 34 | dig7_reg<=0; 35 | dig8_reg<=0; 36 | dig9_reg<=0; 37 | dig10_reg<=0; 38 | n_reg<=0; 39 | end 40 | else begin 41 | state_reg<=state_nxt; 42 | bin_reg<=bin_nxt; 43 | dig0_reg<=dig0_nxt; 44 | dig1_reg<=dig1_nxt; 45 | dig2_reg<=dig2_nxt; 46 | dig3_reg<=dig3_nxt; 47 | dig4_reg<=dig4_nxt; 48 | dig5_reg<=dig5_nxt; 49 | dig6_reg<=dig6_nxt; 50 | dig7_reg<=dig7_nxt; 51 | dig8_reg<=dig8_nxt; 52 | dig9_reg<=dig9_nxt; 53 | dig10_reg<=dig10_nxt; 54 | n_reg<=n_nxt; 55 | 56 | if(done_tick) begin 57 | dig0=dig0_reg; 58 | dig1=dig1_reg; 59 | dig2=dig2_reg; 60 | dig3=dig3_reg; 61 | dig4=dig4_reg; 62 | dig5=dig5_reg; 63 | dig6=dig6_reg; 64 | dig7=dig7_reg; 65 | dig8=dig8_reg; 66 | dig9=dig9_reg; 67 | dig10=dig10_reg; 68 | end 69 | else begin //retain previous value 70 | dig0=dig0; 71 | dig1=dig1; 72 | dig2=dig2; 73 | dig3=dig3; 74 | dig4=dig4; 75 | dig5=dig5; 76 | dig6=dig6; 77 | dig7=dig7; 78 | dig8=dig8; 79 | dig9=dig9; 80 | dig10=dig10; 81 | end 82 | end 83 | end 84 | //FSM next-state logics 85 | always @* begin 86 | state_nxt=state_reg; 87 | bin_nxt=bin_reg; 88 | dig0_nxt=dig0_reg; 89 | dig1_nxt=dig1_reg; 90 | dig2_nxt=dig2_reg; 91 | dig3_nxt=dig3_reg; 92 | dig4_nxt=dig4_reg; 93 | dig5_nxt=dig5_reg; 94 | dig6_nxt=dig6_reg; 95 | dig7_nxt=dig7_reg; 96 | dig8_nxt=dig8_reg; 97 | dig9_nxt=dig9_reg; 98 | dig10_nxt=dig10_reg; 99 | n_nxt=n_reg; 100 | done_tick=0; 101 | ready=0; 102 | case(state_reg) 103 | idle: begin 104 | ready=1; 105 | if(start) begin 106 | bin_nxt=bin; 107 | dig0_nxt=0; 108 | dig1_nxt=0; 109 | dig2_nxt=0; 110 | dig3_nxt=0; 111 | dig4_nxt=0; 112 | dig5_nxt=0; 113 | dig6_nxt=0; 114 | dig7_nxt=0; 115 | dig8_nxt=0; 116 | dig9_nxt=0; 117 | dig10_nxt=0; 118 | n_nxt=N; 119 | state_nxt=op; 120 | end 121 | end 122 | op: begin 123 | dig0_nxt=(dig0_reg<=4)?dig0_reg:dig0_reg+4'd3; 124 | dig1_nxt=(dig1_reg<=4)?dig1_reg:dig1_reg+4'd3; 125 | dig2_nxt=(dig2_reg<=4)?dig2_reg:dig2_reg+4'd3; 126 | dig3_nxt=(dig3_reg<=4)?dig3_reg:dig3_reg+4'd3; 127 | dig4_nxt=(dig4_reg<=4)?dig4_reg:dig4_reg+4'd3; 128 | dig5_nxt=(dig5_reg<=4)?dig5_reg:dig5_reg+4'd3; 129 | dig6_nxt=(dig6_reg<=4)?dig6_reg:dig6_reg+4'd3; 130 | dig7_nxt=(dig7_reg<=4)?dig7_reg:dig7_reg+4'd3; 131 | dig8_nxt=(dig8_reg<=4)?dig8_reg:dig8_reg+4'd3; 132 | dig9_nxt=(dig9_reg<=4)?dig9_reg:dig9_reg+4'd3; 133 | dig10_nxt=(dig10_reg<=4)?dig10_reg:dig10_reg+4'd3; 134 | 135 | {dig10_nxt,dig9_nxt,dig8_nxt,dig7_nxt,dig6_nxt,dig5_nxt,dig4_nxt,dig3_nxt,dig2_nxt,dig1_nxt,dig0_nxt,bin_nxt} 136 | ={dig10_nxt,dig9_nxt,dig8_nxt,dig7_nxt,dig6_nxt,dig5_nxt,dig4_nxt,dig3_nxt,dig2_nxt,dig1_nxt,dig0_nxt,bin_nxt}<<1; //shift left by 1(just copy the left side to right side) 137 | n_nxt=n_reg-1; 138 | if(n_nxt==0) state_nxt=done; 139 | end 140 | done: begin 141 | done_tick=1; 142 | state_nxt=idle; 143 | end 144 | default: state_nxt=idle; 145 | endcase 146 | end 147 | 148 | 149 | 150 | 151 | endmodule 152 | -------------------------------------------------------------------------------- /src/comprehensive_tb.ucf: -------------------------------------------------------------------------------- 1 | NET "clk" LOC = T8 | TNM_NET = sys_clk_pin; 2 | TIMESPEC TS_sys_clk_pin = PERIOD sys_clk_pin 50000 kHz; 3 | 4 | NET rst_n LOC = L3 | IOSTANDARD = "LVCMOS33"; ## reset pushbutton 5 | 6 | NET key<0> LOC = C3 | IOSTANDARD = "LVCMOS33"; ## KEY1 7 | NET key<1> LOC = D3 | IOSTANDARD = "LVCMOS33"; ## KEY2 8 | NET key<2> LOC = E4 | IOSTANDARD = "LVCMOS33"; ## KEY3 9 | 10 | NET seg_out<6> LOC = C7 | IOSTANDARD = "LVCMOS33" | SLEW=FAST; 11 | NET seg_out<5> LOC = E6 | IOSTANDARD = "LVCMOS33" | SLEW=FAST; 12 | NET seg_out<4> LOC = C5 | IOSTANDARD = "LVCMOS33" | SLEW=FAST; 13 | NET seg_out<3> LOC = F7 | IOSTANDARD = "LVCMOS33" | SLEW=FAST; 14 | NET seg_out<2> LOC = D6 | IOSTANDARD = "LVCMOS33" | SLEW=FAST; 15 | NET seg_out<1> LOC = E7 | IOSTANDARD = "LVCMOS33" | SLEW=FAST; 16 | NET seg_out<0> LOC = D5 | IOSTANDARD = "LVCMOS33" | SLEW=FAST; 17 | NET seg_out<7> LOC = C6 | IOSTANDARD = "LVCMOS33" | SLEW=FAST; 18 | NET sel_out<5> LOC = D9 | IOSTANDARD = "LVCMOS33" | SLEW=FAST; 19 | NET sel_out<4> LOC = E10 | IOSTANDARD = "LVCMOS33" | SLEW=FAST; 20 | NET sel_out<3> LOC = F10 | IOSTANDARD = "LVCMOS33" | SLEW=FAST; 21 | NET sel_out<2> LOC = F9 | IOSTANDARD = "LVCMOS33" | SLEW=FAST; 22 | NET sel_out<1> LOC = E8 | IOSTANDARD = "LVCMOS33" | SLEW=FAST; 23 | NET sel_out<0> LOC = D8 | IOSTANDARD = "LVCMOS33" | SLEW=FAST; 24 | 25 | 26 | NET led<0> LOC = P4 | IOSTANDARD = "LVCMOS33"; ## LED1 27 | NET led<1> LOC = N5 | IOSTANDARD = "LVCMOS33"; ## LED2 28 | NET led<2> LOC = P5 | IOSTANDARD = "LVCMOS33"; ## LED3 29 | NET led<3> LOC = M6 | IOSTANDARD = "LVCMOS33"; ## LED4 30 | 31 | NET sdram_clk LOC = H4 | IOSTANDARD = "LVCMOS33" | SLEW=FAST; ## SDRAM CLOCK 32 | NET sdram_cke LOC = H2 | IOSTANDARD = "LVCMOS33" | SLEW=FAST; ## SDRAM CKE 33 | NET sdram_cs_n LOC = G1 | IOSTANDARD = "LVCMOS33" | SLEW=FAST; ## SDRAM CS 34 | NET sdram_we_n LOC = E1 | IOSTANDARD = "LVCMOS33" | SLEW=FAST; ## SDRAM NWE 35 | NET sdram_cas_n LOC = F2 | IOSTANDARD = "LVCMOS33" | SLEW=FAST; ## SDRAM CAS 36 | NET sdram_ras_n LOC = F1 | IOSTANDARD = "LVCMOS33" | SLEW=FAST; ## SDRAM RAS 37 | NET sdram_dqm<0> LOC = E2 | IOSTANDARD = "LVCMOS33" | SLEW=FAST; ## SDRAM DQM0 38 | NET sdram_dqm<1> LOC = H1 | IOSTANDARD = "LVCMOS33" | SLEW=FAST; ## SDRAM DQM1 39 | NET sdram_ba<0> LOC = G6 | IOSTANDARD = "LVCMOS33" | SLEW=FAST; ## SDRAM BA0 40 | NET sdram_ba<1> LOC = J6 | IOSTANDARD = "LVCMOS33" | SLEW=FAST; ## SDRAM BA1 41 | NET sdram_addr<0> LOC = J3 | IOSTANDARD = "LVCMOS33" | SLEW=FAST; ## SDRAM ADDR0 42 | NET sdram_addr<1> LOC = J4 | IOSTANDARD = "LVCMOS33" | SLEW=FAST; ## SDRAM ADDR1 43 | NET sdram_addr<2> LOC = K3 | IOSTANDARD = "LVCMOS33" | SLEW=FAST; ## SDRAM ADDR2 44 | NET sdram_addr<3> LOC = K5 | IOSTANDARD = "LVCMOS33" | SLEW=FAST; ## SDRAM ADDR3 45 | NET sdram_addr<4> LOC = P1 | IOSTANDARD = "LVCMOS33" | SLEW=FAST; ## SDRAM ADDR4 46 | NET sdram_addr<5> LOC = N1 | IOSTANDARD = "LVCMOS33" | SLEW=FAST; ## SDRAM ADDR5 47 | NET sdram_addr<6> LOC = M2 | IOSTANDARD = "LVCMOS33" | SLEW=FAST; ## SDRAM ADDR6 48 | NET sdram_addr<7> LOC = M1 | IOSTANDARD = "LVCMOS33" | SLEW=FAST; ## SDRAM ADDR7 49 | NET sdram_addr<8> LOC = L1 | IOSTANDARD = "LVCMOS33" | SLEW=FAST; ## SDRAM ADDR8 50 | NET sdram_addr<9> LOC = K2 | IOSTANDARD = "LVCMOS33" | SLEW=FAST; ## SDRAM ADDR9 51 | NET sdram_addr<10> LOC = K6 | IOSTANDARD = "LVCMOS33" | SLEW=FAST; ## SDRAM ADDR10 52 | NET sdram_addr<11> LOC = K1 | IOSTANDARD = "LVCMOS33" | SLEW=FAST; ## SDRAM ADDR11 53 | NET sdram_addr<12> LOC = J1 | IOSTANDARD = "LVCMOS33" | SLEW=FAST; ## SDRAM ADDR12 54 | NET sdram_dq<0> LOC = A3 | IOSTANDARD = "LVCMOS33" | SLEW=FAST; ## SDRAM DATA0 55 | NET sdram_dq<1> LOC = B3 | IOSTANDARD = "LVCMOS33" | SLEW=FAST; ## SDRAM DATA1 56 | NET sdram_dq<2> LOC = A2 | IOSTANDARD = "LVCMOS33" | SLEW=FAST; ## SDRAM DATA2 57 | NET sdram_dq<3> LOC = B2 | IOSTANDARD = "LVCMOS33" | SLEW=FAST; ## SDRAM DATA3 58 | NET sdram_dq<4> LOC = B1 | IOSTANDARD = "LVCMOS33" | SLEW=FAST; ## SDRAM DATA4 59 | NET sdram_dq<5> LOC = C2 | IOSTANDARD = "LVCMOS33" | SLEW=FAST; ## SDRAM DATA5 60 | NET sdram_dq<6> LOC = C1 | IOSTANDARD = "LVCMOS33" | SLEW=FAST; ## SDRAM DATA6 61 | NET sdram_dq<7> LOC = D1 | IOSTANDARD = "LVCMOS33" | SLEW=FAST; ## SDRAM DATA7 62 | NET sdram_dq<8> LOC = H5 | IOSTANDARD = "LVCMOS33" | SLEW=FAST; ## SDRAM DATA8 63 | NET sdram_dq<9> LOC = G5 | IOSTANDARD = "LVCMOS33" | SLEW=FAST; ## SDRAM DATA9 64 | NET sdram_dq<10> LOC = H3 | IOSTANDARD = "LVCMOS33" | SLEW=FAST; ## SDRAM DATA10 65 | NET sdram_dq<11> LOC = F6 | IOSTANDARD = "LVCMOS33" | SLEW=FAST; ## SDRAM DATA11 66 | NET sdram_dq<12> LOC = G3 | IOSTANDARD = "LVCMOS33" | SLEW=FAST; ## SDRAM DATA12 67 | NET sdram_dq<13> LOC = F5 | IOSTANDARD = "LVCMOS33" | SLEW=FAST; ## SDRAM DATA13 68 | NET sdram_dq<14> LOC = F3 | IOSTANDARD = "LVCMOS33" | SLEW=FAST; ## SDRAM DATA14 69 | NET sdram_dq<15> LOC = F4 | IOSTANDARD = "LVCMOS33" | SLEW=FAST; ## SDRAM DATA15 70 | -------------------------------------------------------------------------------- /src/comprehensive_tb.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | module comprehensive_tb( 4 | input clk,rst_n, 5 | input[2:0] key, //key[0] for burst writing, key[1] for burst reading , press key[2] along with key[0] to inject 10240 errors to be displayed on the seven-segment LEDs 6 | output[3:0] led, //led[1:0] will light up if burst writing is successfull, led[3:0] will light up if burst reading is successful 7 | output [7:0] seg_out, 8 | output [5:0] sel_out, 9 | //FPGA to SDRAM 10 | output sdram_clk, 11 | output sdram_cke, 12 | output sdram_cs_n, sdram_ras_n, sdram_cas_n, sdram_we_n, 13 | output[12:0] sdram_addr, 14 | output[1:0] sdram_ba, 15 | output[1:0] sdram_dqm, 16 | inout[15:0] sdram_dq 17 | ); 18 | 19 | //FSM state declarationss 20 | localparam idle=0, 21 | //write test-data to all addresses 22 | new_write=1, 23 | write_burst=2, 24 | //read test-data written to all addresses 25 | new_read=3, 26 | read_burst=4; 27 | 28 | reg[2:0] state_q=idle,state_d; 29 | reg[14:0] f_addr_q=0,f_addr_d; 30 | reg[9:0] burst_index_q=0,burst_index_d; 31 | reg[3:0] led_q=0,led_d; 32 | reg[19:0] error_q=0,error_d; 33 | 34 | reg rw,rw_en; 35 | reg[15:0] f2s_data; 36 | wire ready,s2f_data_valid,f2s_data_valid; 37 | wire[15:0] s2f_data; 38 | wire key0_tick,key1_tick; 39 | wire[5:0] in0,in1,in2,in3,in4,in5; //format: {dp,char[4:0]} , dp is active high 40 | 41 | (*KEEP="TRUE"*)reg[36:0] counter_q,index_q,index_d; //counter_q increments until 1 second(165_000_000 clk cycles). Index_q holds the number of words read/written(check the value at chipscope) 42 | //Memory Bandwidth: index_q*2 = X bytes/seconds 43 | // RESULT: 190MB/s (100MHz with t_CL=2) 44 | // RESULT: 316MB/s (165MHz clk with t_CL=3) 45 | 46 | //register operations 47 | always @(posedge CLK_OUT,negedge rst_n) begin 48 | if(!rst_n) begin 49 | state_q<=0; 50 | f_addr_q<=0; 51 | burst_index_q<=0; 52 | led_q<=0; 53 | error_q<=0; 54 | counter_q<=0; 55 | index_q<=0; 56 | end 57 | else begin 58 | state_q<=state_d; 59 | f_addr_q<=f_addr_d; 60 | burst_index_q<=burst_index_d; 61 | led_q<=led_d; 62 | error_q<=error_d; 63 | counter_q<=(state_q==idle) ?0:counter_q+1'b1; 64 | index_q<=index_d; 65 | end 66 | end 67 | 68 | //FSM next-state logic 69 | always @* begin 70 | state_d=state_q; 71 | f_addr_d=f_addr_q; 72 | burst_index_d=burst_index_q; 73 | led_d=led_q; 74 | error_d=error_q; 75 | rw=0; 76 | rw_en=0; 77 | f2s_data=0; 78 | index_d=index_q; 79 | 80 | case(state_q) 81 | idle: begin //wait until either button is toggled 82 | f_addr_d=0; 83 | burst_index_d=0; 84 | if(key0_tick) begin 85 | state_d=new_write; 86 | index_d=0; 87 | end 88 | if(key1_tick) begin 89 | state_d=new_read; 90 | error_d=0; 91 | index_d=0; 92 | end 93 | end 94 | new_write: if(ready) begin //write a deterministic data to all possible addresses of sdram 95 | led_d[1]=1'b1; 96 | rw_en=1; 97 | rw=0; 98 | state_d=write_burst; 99 | burst_index_d=0; 100 | end 101 | write_burst: begin 102 | f2s_data=f_addr_q+burst_index_q; 103 | if(!key[2] && (f_addr_q==13000 || f_addr_q==100)) f2s_data=9999; //Inject errors when key[2] is pressed. The output error must be 512*2*10=10240 104 | if(f2s_data_valid) begin 105 | burst_index_d=burst_index_q+1; //track the number of already bursted data 106 | index_d=index_q+1'b1; //holds the total number of words written to sdram 107 | end 108 | else if(burst_index_q==512) begin //last data must be 512th(for full page mode), since index starts at zero, the 512th is expected to have deasserted f2s_data_valid 109 | if(counter_q>=165_000_000) begin //1 second had passed 110 | led_d[1:0]=2'b11; 111 | state_d=idle; 112 | end 113 | else begin 114 | f_addr_d=f_addr_q+1; 115 | state_d=new_write; 116 | end 117 | end 118 | end 119 | new_read: if(ready) begin //read each data from all addresses and test if it matches the deterministic data we assigned earlier 120 | led_d[2]=1'b1; 121 | rw_en=1; 122 | rw=1; 123 | state_d=read_burst; 124 | burst_index_d=0; 125 | end 126 | read_burst: begin 127 | if(s2f_data_valid) begin 128 | if(s2f_data!=f_addr_q+burst_index_q) error_d=error_q+1'b1; //count the errors in which the read output does not match the expected assigned data 129 | burst_index_d=burst_index_q+1; 130 | index_d=index_q+1'b1; //holds the total number of words read from sdram 131 | end 132 | else if(burst_index_q==512) begin 133 | if(counter_q>=165_000_000) begin //1 second had passed 134 | led_d[3:0]=4'b1111; //all leds on after successfull write 135 | state_d=idle; 136 | end 137 | else begin 138 | f_addr_d=f_addr_q+1; 139 | state_d=new_read; 140 | end 141 | end 142 | end 143 | default: state_d=idle; 144 | endcase 145 | end 146 | 147 | assign led=led_q; 148 | 149 | //module instantiations 150 | sdram_controller m0 151 | ( 152 | //fpga to controller 153 | .clk(CLK_OUT), //clk=100MHz 154 | .rst_n(rst_n), 155 | .rw(rw), // 1:read , 0:write 156 | .rw_en(rw_en), //must be asserted before read/write 157 | .f_addr(f_addr_q), //23:11=row , 10:9=bank , no need for column address since full page mode will always start from zero and end with 511 words 158 | .f2s_data(f2s_data), //fpga-to-sdram data 159 | .s2f_data(s2f_data), //sdram to fpga data 160 | .s2f_data_valid(s2f_data_valid), //asserts while burst-reading(data is available at output UNTIL the next rising edge) 161 | .f2s_data_valid(f2s_data_valid), //asserts while burst-writing(data must be available at input BEFORE the next rising edge) 162 | .ready(ready), //"1" if sdram is available for nxt read/write operation 163 | //controller to sdram 164 | .s_clk(sdram_clk), 165 | .s_cke(sdram_cke), 166 | .s_cs_n(sdram_cs_n), 167 | .s_ras_n(sdram_ras_n ), 168 | .s_cas_n(sdram_cas_n), 169 | .s_we_n(sdram_we_n), 170 | .s_addr(sdram_addr), 171 | .s_ba(sdram_ba), 172 | .LDQM(sdram_dqm[0]), 173 | .HDQM(sdram_dqm[1]), 174 | .s_dq(sdram_dq) 175 | ); 176 | 177 | debounce_explicit m1 178 | ( 179 | .clk(CLK_OUT), 180 | .rst_n(rst_n), 181 | .sw({!{key[0]}}), 182 | .db_level(), 183 | .db_tick(key0_tick) 184 | ); 185 | 186 | debounce_explicit m2 187 | ( 188 | .clk(CLK_OUT), 189 | .rst_n(rst_n), 190 | .sw({!{key[1]}}), 191 | .db_level(), 192 | .db_tick(key1_tick) 193 | ); 194 | 195 | LED_mux m3 196 | ( 197 | .clk(CLK_OUT), 198 | .rst(rst_n), 199 | .in0(in0), 200 | .in1(in1), 201 | .in2(in2), 202 | .in3(in3), 203 | .in4(in4), 204 | .in5(in5), //format: {dp,char[4:0]} , dp is active high 205 | .seg_out(seg_out), 206 | .sel_out(sel_out) 207 | ); 208 | 209 | bin2bcd m4 210 | ( 211 | .clk(CLK_OUT), 212 | .rst_n(rst_n), 213 | .start(1), 214 | .bin(error_q),//11 digit max of {11{9}} 215 | .ready(), 216 | .done_tick(), 217 | .dig0(in0), 218 | .dig1(in1), 219 | .dig2(in2), 220 | .dig3(in3), 221 | .dig4(in4), 222 | .dig5(in5), 223 | .dig6(), 224 | .dig7(), 225 | .dig8(), 226 | .dig9(), 227 | .dig10() //not all output will be used(this module is a general-purpose bin2bcd) 228 | ); 229 | 230 | //100MHz clock 231 | dcm_165MHz m5 232 | ( 233 | .clk(clk), // IN 234 | // Clock out ports 235 | .CLK_OUT(CLK_OUT), // OUT 236 | // Status and control signals 237 | .RESET(RESET),// IN 238 | .LOCKED(LOCKED) 239 | ); // OUT 240 | 241 | endmodule 242 | -------------------------------------------------------------------------------- /src/debounce_explicit.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | module debounce_explicit( 4 | input clk,rst_n, 5 | input sw, 6 | output reg db_level,db_tick 7 | ); 8 | /* 9 | 10 | debounce_explicit 11 | ( 12 | .clk(clk), 13 | .rst_n(rst_n), 14 | .sw(sw), 15 | .db_level(), 16 | .db_tick(key_tick) 17 | ); 18 | 19 | */ 20 | 21 | //FSM symbolic declaration 22 | localparam[1:0] idle=2'b00, 23 | delay0=2'b01, 24 | one=2'b10, 25 | delay1=2'b11; 26 | localparam N=21; //21 bits is 42ms -> 2^N/50MHz=42ms 27 | reg[1:0] state_reg,state_nxt; 28 | reg[N-1:0] timer_reg,timer_nxt; 29 | reg timer_zero,timer_inc,timer_tick; //control and status signal 30 | 31 | //FSM and timer register 32 | always @(posedge clk,negedge rst_n) begin 33 | if(!rst_n) begin 34 | state_reg<=idle; 35 | timer_reg<=0; 36 | end 37 | else begin 38 | state_reg<=state_nxt; 39 | timer_reg<=timer_nxt; 40 | end 41 | end 42 | 43 | //FSM control path next-state logic 44 | always @* begin 45 | state_nxt=state_reg; 46 | timer_zero=0; 47 | timer_inc=0; 48 | db_tick=0; 49 | db_level=0; 50 | 51 | case(state_reg) 52 | idle: if(sw==1) begin 53 | timer_zero=1; //load the timer with value of zero 54 | state_nxt=delay0; 55 | end 56 | delay0: if(sw==1) begin 57 | timer_inc=1;//increment timer by 1 58 | if(timer_tick) begin //if timer reaches the max(nxt edge will wrap the timer to zero again) 59 | state_nxt=one; 60 | db_tick=1; 61 | end 62 | end 63 | else state_nxt=idle; 64 | one: begin 65 | db_level=1; 66 | if(sw==0) begin 67 | timer_zero=1; //load the timer with value of zero 68 | state_nxt=delay1; 69 | end 70 | end 71 | delay1: begin 72 | db_level=1; 73 | if(sw==0) begin 74 | timer_inc=1; 75 | if(timer_tick) //if timer reaches the max(wherein the nxt edge will wrap the timer to zero again) 76 | state_nxt=idle; 77 | end 78 | else state_nxt=one; 79 | end 80 | default: state_nxt=idle; 81 | endcase 82 | end 83 | 84 | //Datapath(timer) logic and operation 85 | always @* begin 86 | timer_nxt=timer_reg; 87 | if(timer_zero) timer_nxt=0; //load zero 88 | else if(timer_inc) timer_nxt=timer_reg+1; //increment by one 89 | timer_tick=(timer_reg=={N{1'b1}})?1:0; //notify if timer is already at max 90 | end 91 | 92 | 93 | endmodule 94 | -------------------------------------------------------------------------------- /src/sdram_controller.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | module sdram_controller( 4 | //fpga to controller 5 | input clk,rst_n, //clk=165MHz 6 | input rw, // 1:read , 0:write 7 | input rw_en, //must be asserted before read/write 8 | input[14:0] f_addr, //14:2=row(13) , 1:0=bank(2) , no need for column address since full page mode will always start from zero and end with 512 words 9 | input [15:0] f2s_data, //fpga-to-sdram data , write data burst will start at assertion of f2s_data_valid 10 | output[15:0] s2f_data, //sdram to fpga data 11 | output s2f_data_valid, //asserts while burst-reading(data is available at output UNTIL the next rising edge) 12 | output reg f2s_data_valid, //asserts while burst-writing(data must be available at input BEFORE the next rising edge) 13 | output reg ready, //"1" if sdram is available for nxt read/write operation 14 | 15 | //controller to sdram 16 | output s_clk, 17 | output s_cke, //always high for almost all operations(except for self-refresh w/c I did not use here) 18 | output s_cs_n, s_ras_n, s_cas_n, s_we_n, //commands 19 | output[12:0] s_addr, //row/colum address bus 20 | output[1:0] s_ba, //bank address bus 21 | output LDQM , HDQM, //low-byte and high-byte mask (always zero:disabled) 22 | inout[15:0] s_dq //sdram inout/output data 23 | ); 24 | 25 | /* 26 | sdram_controller m1( 27 | //fpga to controller 28 | .clk(CLK_OUT), //clk=165MHz 29 | .rst_n(rst_n), 30 | .rw(rw), // 1:read , 0:write 31 | .rw_en(rw_en), //must be asserted before read/write 32 | .f_addr(f_addr_q), //14:2=row(13) , 1:0=bank(2) , no need for column address since full page mode will always start from zero and end with 512 words 33 | .f2s_data(f2s_data_q), //fpga-to-sdram data , write data burst will start at assertion of f2s_data_valid 34 | .s2f_data(s2f_data), //sdram to fpga data 35 | .s2f_data_valid(s2f_data_valid), //asserts while burst-reading(data is available at output UNTIL the next rising edge) 36 | .f2s_data_valid(f2s_data_valid), //asserts while burst-writing(data must be available at input BEFORE the next rising edge) 37 | .ready(ready), //"1" if sdram is available for nxt read/write operation 38 | //controller to sdram 39 | .s_clk(sdram_clk), 40 | .s_cke(sdram_cke), 41 | .s_cs_n(sdram_cs_n), 42 | .s_ras_n(sdram_ras_n ), 43 | .s_cas_n(sdram_cas_n), 44 | .s_we_n(sdram_we_n), 45 | .s_addr(sdram_addr), 46 | .s_ba(sdram_ba), 47 | .LDQM(sdram_dqm[0]), 48 | .HDQM(sdram_dqm[1]), 49 | .s_dq(sdram_dq) 50 | ); 51 | */ 52 | 53 | //s_clock(clk input to sdram) is 180 degrees lagging from main clock to solve the hold-setup time requirements of sdram 54 | ODDR2#(.DDR_ALIGNMENT("NONE"), .INIT(1'b0),.SRTYPE("SYNC")) oddr2_primitive 55 | ( 56 | .D0(1'b0), //1'b0 57 | .D1(1'b1 ), //1'b1 58 | .C0(clk), 59 | .C1(~clk), 60 | .CE(1'b1), 61 | .R(1'b0), 62 | .S(1'b0), 63 | .Q(s_clk) 64 | ); 65 | //FSM states //initialize 66 | localparam[3:0] start=0, 67 | precharge_init=1, 68 | refresh_1=2, 69 | refresh_2=3, 70 | load_mode_reg=4, 71 | //normal operation 72 | idle=5, 73 | read=6, 74 | read_data=7, 75 | write=8, 76 | write_burst=9, 77 | //refresh every 7.81us 78 | refresh=10, 79 | 80 | delay=11; //waiting state for any amount of delay needed 81 | 82 | //minimum time specs needed(in clks for 165MHz(6ns)) 83 | localparam[3:0] t_RP=3, //15ns(precharge) 84 | t_RC=10, //60ns(active to active,ref to ref) 85 | t_MRD=2, //2 clk,(mode register) /2/ 86 | t_RCD=3, //15ns (active to read/write) 87 | t_WR=2, //2clk delay after writing before manual/auto precharge can start 88 | t_CL=3; //CAS latency(delay of data_out after read command) 89 | 90 | //commands {cs_n,ras_n,cas_n,we_n} REFER TO THE DATASHEET: winbond W9825G6KH 91 | localparam[3:0] cmd_precharge=4'b0010, 92 | cmd_NOP=4'b1111, 93 | cmd_activate=4'b0011, 94 | cmd_write=4'b0100, 95 | cmd_read=4'b0101, 96 | cmd_setmode=4'b0000, 97 | cmd_refresh=4'b0001; 98 | 99 | reg[3:0] state_q,state_d; //_q is registered output, _d is input to DFF 100 | reg[3:0] nxt_q,nxt_d; //state after next state 101 | reg[3:0] cmd_q,cmd_d; //{cs_n,ras_n,cas_n,we_n} 102 | reg[15:0] delay_ctr_q,delay_ctr_d; //stores delay needed(max is 200us for the initialization sequence) 103 | reg[10:0] refresh_ctr_q=0,refresh_ctr_d; 104 | reg refresh_flag_q,refresh_flag_d; 105 | reg[9:0] burst_index_q=0,burst_index_d; //stores the data left to be burst(512 for full page burst) 106 | reg rw_d,rw_q,rw_en_q,rw_en_d; 107 | 108 | //buffer for output for a glitch-free signal 109 | reg[12:0] s_addr_q,s_addr_d; 110 | reg[1:0] s_ba_q,s_ba_d; 111 | reg[15:0] s_dq_q,s_dq_d; 112 | reg tri_q,tri_d; 113 | 114 | //buffer for input 115 | reg[14:0] f_addr_q,f_addr_d; 116 | reg[15:0] f2s_data_q,f2s_data_d; 117 | reg[15:0] s2f_data_q,s2f_data_d; 118 | reg s2f_data_valid_q,s2f_data_valid_d; 119 | 120 | 121 | 122 | 123 | //register operation 124 | always @(posedge clk,negedge rst_n) begin 125 | if(!rst_n) begin 126 | state_q<=start; 127 | nxt_q<=start; 128 | cmd_q<=cmd_NOP; 129 | delay_ctr_q<=0; 130 | refresh_ctr_q<=0; 131 | s_addr_q<=0; 132 | tri_q<=0; 133 | rw_q<=0; 134 | rw_en_q<=0; 135 | 136 | s_ba_q<=0; 137 | s_dq_q<=0; 138 | f_addr_q<=0; 139 | rw_q<=0; 140 | f2s_data_q<=0; 141 | s2f_data_q<=0; 142 | s2f_data_valid_q<=0; 143 | rw_q<=0; 144 | refresh_flag_q<=0; 145 | burst_index_q<=0; 146 | end 147 | else begin 148 | state_q<=state_d; 149 | nxt_q<=nxt_d; 150 | cmd_q<=cmd_d; 151 | delay_ctr_q<=delay_ctr_d; 152 | refresh_ctr_q<=refresh_ctr_d; 153 | s_addr_q<=s_addr_d; 154 | tri_q<=tri_d; 155 | refresh_flag_q<=refresh_flag_d; 156 | burst_index_q<=burst_index_d; 157 | 158 | s_ba_q<=s_ba_d; 159 | s_dq_q<=s_dq_d; 160 | f_addr_q<=f_addr_d; 161 | rw_q<=rw_d; 162 | f2s_data_q<=f2s_data_d; 163 | s2f_data_q<=s2f_data_d; 164 | s2f_data_valid_q<=s2f_data_valid_d; 165 | rw_q<=rw_d; 166 | rw_en_q<=rw_en_d; 167 | end 168 | end 169 | 170 | 171 | //next-state logics 172 | always @* begin 173 | state_d=state_q; 174 | nxt_d=nxt_q; 175 | cmd_d=cmd_NOP; //always default to No Operation 176 | delay_ctr_d=delay_ctr_q; 177 | ready=0; 178 | s_addr_d=s_addr_q; 179 | s_ba_d=s_ba_q; 180 | s_dq_d=s_dq_q; 181 | f_addr_d=f_addr_q; 182 | rw_d=rw_q; 183 | f2s_data_d=f2s_data_q; 184 | s2f_data_d=s2f_data_q; 185 | tri_d=0; 186 | s2f_data_valid_d=1'b0; 187 | f2s_data_valid=1'b0; 188 | burst_index_d=burst_index_q; 189 | rw_d=rw_q; 190 | rw_en_d=rw_en_q; 191 | 192 | //refresh every 7.8us or else data will be lost. 193 | refresh_flag_d=refresh_flag_q; 194 | refresh_ctr_d=refresh_ctr_q+1'b1; 195 | if(refresh_ctr_q==1270) begin //7.7 us 196 | refresh_ctr_d=0; 197 | refresh_flag_d=1; 198 | end 199 | 200 | 201 | 202 | case(state_q) 203 | ////////////////BEGIN:INITIALIZE//////////////// 204 | delay: begin //wait here for a delay specified by delay_ctr_q(parameter in time specs) 205 | delay_ctr_d=delay_ctr_q-1'b1; 206 | if(delay_ctr_d==0) state_d=nxt_q; 207 | if(nxt_q==write) tri_d=1; 208 | end 209 | start: begin //initiliaze after power-up 210 | state_d=delay; 211 | nxt_d=precharge_init; 212 | delay_ctr_d=16'd33_000; //wait for 200us 213 | s_addr_d=0; 214 | s_ba_d=0; 215 | end 216 | precharge_init: begin //precharge ALL banks (A10 must be high) 217 | state_d=delay; 218 | nxt_d=refresh_1; 219 | delay_ctr_d=t_RP-1; 220 | cmd_d=cmd_precharge; 221 | s_addr_d[10]=1'b1; 222 | end 223 | refresh_1: begin 224 | state_d=delay; 225 | nxt_d=refresh_2; 226 | delay_ctr_d=t_RC-1; 227 | cmd_d=cmd_refresh; 228 | end 229 | refresh_2: begin 230 | state_d=delay; 231 | nxt_d=load_mode_reg; 232 | delay_ctr_d=t_RC-1; 233 | cmd_d=cmd_refresh; 234 | end 235 | load_mode_reg: begin 236 | state_d=delay; 237 | nxt_d=idle; 238 | delay_ctr_d=t_MRD-1; 239 | cmd_d=cmd_setmode; 240 | s_addr_d=13'b 000_0_00_011_0_111; //{reserved,writemode,reserved,CL,AddressingMode,BurstLength} 241 | s_ba_d=2'b00; //reserved 242 | end 243 | ////////////////END:INITIALIZE//////////////// 244 | 245 | ////////////////BEGIN:NORMAL OPERATION//////////////// 246 | idle: begin 247 | ready=rw_en_q? 0:1; 248 | if(rw_en_q) begin //permission granted for r/w operation 249 | state_d=delay; 250 | cmd_d=cmd_activate; 251 | delay_ctr_d=t_RCD-1; 252 | nxt_d=rw_q?read:write; 253 | burst_index_d=0; 254 | rw_en_d=1'b0; 255 | {s_addr_d,s_ba_d}=f_addr_q;//row + bank addr 256 | end 257 | else if(refresh_flag_q || rw_en) begin //refresh every 7.7us and BEFORE start of burst read/write operations 258 | state_d=delay; 259 | nxt_d=refresh; 260 | delay_ctr_d=t_RP-1; 261 | cmd_d=cmd_precharge; //precharge all banks first before auto-refresh 262 | s_addr_d[10]=1'b1; 263 | refresh_flag_d=0; 264 | if(rw_en) begin 265 | rw_en_d=rw_en; 266 | f_addr_d=f_addr; 267 | rw_d=rw; 268 | end 269 | end 270 | 271 | end 272 | refresh: begin 273 | state_d=delay; 274 | nxt_d=idle; 275 | delay_ctr_d=t_RC-1; 276 | cmd_d=cmd_refresh; 277 | end 278 | read: begin 279 | state_d=delay; 280 | delay_ctr_d=t_CL; //not subtracted by one since the sdram is "late" by half a cycle so register is one clk after the expected clock latency delay 281 | cmd_d=cmd_read; 282 | s_addr_d=0;//what column to activate(in full page mode, column starts at LEFTMOST which is zero) 283 | s_ba_d=f_addr_q[1:0]; //what bank to activate 284 | s_addr_d[10]=1'b0; //no auto-precharge for full page burst 285 | nxt_d=read_data; 286 | end 287 | read_data: begin //read data after CAS latency of 3 clk 288 | s2f_data_d=s_dq; 289 | s2f_data_valid_d=1'b1; 290 | burst_index_d=burst_index_q+1; 291 | if(burst_index_q==512) begin //if all 512 burst data is already finished, precharge then go back to idle 292 | s2f_data_valid_d=1'b0; 293 | state_d=delay; 294 | nxt_d=idle; 295 | delay_ctr_d=t_RP-1; 296 | cmd_d=cmd_precharge; 297 | end 298 | end 299 | write: begin 300 | f2s_data_d=f2s_data; //write data 301 | f2s_data_valid=1'b1; 302 | s_addr_d=0; //what column to activate(in full page mode, column starts at LEFTMOST which is zero) 303 | s_ba_d=f_addr_q[1:0]; 304 | s_addr_d[10]=1'b0; //no auto-precharge for full page burst 305 | tri_d=1'b1; //tristate buffer on since we output/write signals 306 | cmd_d=cmd_write; 307 | state_d=write_burst; 308 | burst_index_d=burst_index_q+1; 309 | end 310 | write_burst: begin //write data burst will start at assertion of f2s_data_valid 311 | f2s_data_d=f2s_data; //write data 312 | f2s_data_valid=1'b1; 313 | tri_d=1'b1; //tristate buffer on since we output/write signals 314 | burst_index_d=burst_index_q+1; 315 | 316 | if(burst_index_q==512) begin //if all 512 burst data is already finished, precharge then go back to idle 317 | tri_d=0; 318 | state_d=delay; 319 | f2s_data_valid=1'b0; 320 | nxt_d=idle; 321 | delay_ctr_d=t_RP+t_WR-1; 322 | cmd_d=cmd_precharge; 323 | end 324 | end 325 | ////////////////END:NORMAL OPERATION//////////////// 326 | 327 | default: state_d=start; 328 | endcase 329 | 330 | 331 | 332 | 333 | end 334 | 335 | //assign the outputs to corresponding buffers 336 | assign s_cs_n=cmd_q[3], 337 | s_ras_n=cmd_q[2], 338 | s_cas_n=cmd_q[1], 339 | s_we_n=cmd_q[0]; 340 | assign s_cke=1'b1; 341 | assign LDQM=1'b0, 342 | HDQM=1'b0; 343 | assign s_addr=s_addr_q; 344 | assign s_ba=s_ba_q; 345 | assign s_dq=tri_q? f2s_data_q:16'hzzzz; //tri-state output,tri=1 for write , tri=0 for read(hi-Z) 346 | assign s2f_data=s2f_data_q; 347 | assign s2f_data_valid=s2f_data_valid_q; 348 | 349 | 350 | endmodule 351 | --------------------------------------------------------------------------------