|
| 1 | +`default_nettype none |
| 2 | +`timescale 1 ns / 1 ps |
| 3 | + |
| 4 | +// Example usage of sdram_gw2ar. |
| 5 | +// |
| 6 | +// After initialization completes the module writes the 32-bit word 0xDEADBEEF |
| 7 | +// to SDRAM address 0, then reads it back. Two LEDs report the outcome: |
| 8 | +// o_led_ok – pulses high when the readback value matches the written word |
| 9 | +// o_led_err – pulses high when the readback value does not match |
| 10 | +// |
| 11 | +// Wiring for Tang Nano 20K (27 MHz oscillator, GW2AR-18 embedded SDRAM): |
| 12 | +// i_clk <- 27 MHz system clock (same clock fed to SDRAM) |
| 13 | +// i_rst_n <- active-low reset (e.g. button_n) |
| 14 | +// o_sdram_* <- connect directly to the GW2AR embedded SDRAM pins |
| 15 | +// io_sdram_dq<- bidirectional data bus |
| 16 | + |
| 17 | +module sdram_gw2ar_example ( |
| 18 | + input wire i_clk, |
| 19 | + input wire i_rst_n, |
| 20 | + |
| 21 | + // Status LEDs (active-high) |
| 22 | + output reg o_led_ok, |
| 23 | + output reg o_led_err, |
| 24 | + |
| 25 | + // SDRAM physical interface (pass through from sdram_gw2ar) |
| 26 | + output wire o_sdram_clk, |
| 27 | + output wire o_sdram_cke, |
| 28 | + output wire o_sdram_cs_n, |
| 29 | + output wire o_sdram_cas_n, |
| 30 | + output wire o_sdram_ras_n, |
| 31 | + output wire o_sdram_wen_n, |
| 32 | + output wire [ 3:0] o_sdram_dqm, |
| 33 | + output wire [10:0] o_sdram_addr, |
| 34 | + output wire [ 1:0] o_sdram_ba, |
| 35 | + inout wire [31:0] io_sdram_dq |
| 36 | +); |
| 37 | + |
| 38 | + // ── Controller user-side wires ───────────────────────────────────────────── |
| 39 | + reg sdrc_wr_n; |
| 40 | + reg sdrc_rd_n; |
| 41 | + reg [20:0] sdrc_addr; |
| 42 | + reg [31:0] sdrc_data_in; |
| 43 | + wire [31:0] sdrc_data_out; |
| 44 | + wire sdrc_init_done; |
| 45 | + wire sdrc_busy_n; |
| 46 | + wire sdrc_rd_valid; |
| 47 | + wire sdrc_wrd_ack; |
| 48 | + |
| 49 | + // ── sdram_gw2ar instance ─────────────────────────────────────────────────── |
| 50 | + // Tang Nano 20K: 27 MHz, GW2AR-18 embedded SDRAM (64 Mbit, 32-bit wide). |
| 51 | + // Timing parameters follow the JEDEC SDR SDRAM spec for -6 speed grade. |
| 52 | + sdram_gw2ar #( |
| 53 | + .DATA_WIDTH (32), |
| 54 | + .BANK_WIDTH (2), |
| 55 | + .ROW_WIDTH (11), |
| 56 | + .COLUMN_WIDTH (8), |
| 57 | + .CLOCK_FREQ_MHZ (27), |
| 58 | + .REFRESH_PERIOD_NS (64_000_000), |
| 59 | + .REFRESH_TIMES (4096), |
| 60 | + .INITIALIZATION_WAIT_PERIOD_NS(200_000), |
| 61 | + .T_CL_PERIOD (3), |
| 62 | + .T_RP_PERIOD (3), |
| 63 | + .T_MRD_PERIOD (3), |
| 64 | + .T_WR_PERIOD (3), |
| 65 | + .T_RFC_PERIOD (9), |
| 66 | + .T_RCD_PERIOD (3) |
| 67 | + ) u_sdram ( |
| 68 | + .i_sdrc_rst_n (i_rst_n), |
| 69 | + .i_sdrc_clk (i_clk), |
| 70 | + .i_sdram_clk (i_clk), |
| 71 | + .i_sdrc_self_refresh(1'b0), |
| 72 | + .i_sdrc_power_down (1'b0), |
| 73 | + .i_sdrc_wr_n (sdrc_wr_n), |
| 74 | + .i_sdrc_rd_n (sdrc_rd_n), |
| 75 | + .i_sdrc_addr (sdrc_addr), |
| 76 | + .i_sdrc_dqm (4'b0000), |
| 77 | + .i_sdrc_data_len (8'd0), |
| 78 | + .i_sdrc_data (sdrc_data_in), |
| 79 | + .o_sdrc_data (sdrc_data_out), |
| 80 | + .o_sdrc_init_done (sdrc_init_done), |
| 81 | + .o_sdrc_busy_n (sdrc_busy_n), |
| 82 | + .o_sdrc_rd_valid (sdrc_rd_valid), |
| 83 | + .o_sdrc_wrd_ack (sdrc_wrd_ack), |
| 84 | + |
| 85 | + .o_sdram_clk (o_sdram_clk), |
| 86 | + .o_sdram_cke (o_sdram_cke), |
| 87 | + .o_sdram_cs_n (o_sdram_cs_n), |
| 88 | + .o_sdram_cas_n(o_sdram_cas_n), |
| 89 | + .o_sdram_ras_n(o_sdram_ras_n), |
| 90 | + .o_sdram_wen_n(o_sdram_wen_n), |
| 91 | + .o_sdram_dqm (o_sdram_dqm), |
| 92 | + .o_sdram_addr (o_sdram_addr), |
| 93 | + .o_sdram_ba (o_sdram_ba), |
| 94 | + .io_sdram_dq (io_sdram_dq) |
| 95 | + ); |
| 96 | + |
| 97 | + // ── Simple write-then-read-back FSM ─────────────────────────────────────── |
| 98 | + localparam [2:0] |
| 99 | + S_WAIT_INIT = 3'd0, // wait for controller initialisation to finish |
| 100 | + S_WRITE = 3'd1, // issue a single-word write |
| 101 | + S_WAIT_ACK = 3'd2, // wait for write acknowledgement |
| 102 | + S_READ = 3'd3, // issue a single-word read |
| 103 | + S_WAIT_DATA = 3'd4, // wait for read data to be valid |
| 104 | + S_DONE = 3'd5; // latch result, stay here |
| 105 | + |
| 106 | + localparam [31:0] TEST_WORD = 32'hDEAD_BEEF; |
| 107 | + localparam [20:0] TEST_ADDRESS = 21'd0; |
| 108 | + |
| 109 | + reg [2:0] state; |
| 110 | + |
| 111 | + always @(posedge i_clk) begin |
| 112 | + if (!i_rst_n) begin |
| 113 | + state <= S_WAIT_INIT; |
| 114 | + sdrc_wr_n <= 1'b1; |
| 115 | + sdrc_rd_n <= 1'b1; |
| 116 | + sdrc_addr <= 21'd0; |
| 117 | + sdrc_data_in <= 32'd0; |
| 118 | + o_led_ok <= 1'b0; |
| 119 | + o_led_err <= 1'b0; |
| 120 | + end else begin |
| 121 | + // Default: deassert strobes every cycle so they are single-cycle pulses. |
| 122 | + sdrc_wr_n <= 1'b1; |
| 123 | + sdrc_rd_n <= 1'b1; |
| 124 | + |
| 125 | + case (state) |
| 126 | + |
| 127 | + S_WAIT_INIT: begin |
| 128 | + if (sdrc_init_done && sdrc_busy_n) |
| 129 | + state <= S_WRITE; |
| 130 | + end |
| 131 | + |
| 132 | + S_WRITE: begin |
| 133 | + sdrc_wr_n <= 1'b0; |
| 134 | + sdrc_addr <= TEST_ADDRESS; |
| 135 | + sdrc_data_in <= TEST_WORD; |
| 136 | + state <= S_WAIT_ACK; |
| 137 | + end |
| 138 | + |
| 139 | + S_WAIT_ACK: begin |
| 140 | + if (sdrc_wrd_ack) |
| 141 | + state <= S_READ; |
| 142 | + end |
| 143 | + |
| 144 | + S_READ: begin |
| 145 | + if (sdrc_busy_n) begin |
| 146 | + sdrc_rd_n <= 1'b0; |
| 147 | + sdrc_addr <= TEST_ADDRESS; |
| 148 | + state <= S_WAIT_DATA; |
| 149 | + end |
| 150 | + end |
| 151 | + |
| 152 | + S_WAIT_DATA: begin |
| 153 | + if (sdrc_rd_valid) begin |
| 154 | + o_led_ok <= (sdrc_data_out == TEST_WORD); |
| 155 | + o_led_err <= (sdrc_data_out != TEST_WORD); |
| 156 | + state <= S_DONE; |
| 157 | + end |
| 158 | + end |
| 159 | + |
| 160 | + S_DONE: begin |
| 161 | + // Result latched in LEDs; stay idle. |
| 162 | + end |
| 163 | + |
| 164 | + default: state <= S_WAIT_INIT; |
| 165 | + endcase |
| 166 | + end |
| 167 | + end |
| 168 | + |
| 169 | +endmodule // sdram_gw2ar_example |
0 commit comments