`timescale 1 ns / 1 ps module sdram_ctrl /* verilator tracing_off */ ( //----------------------------- // Clock and reset //----------------------------- input rst, // Global reset input clk, // Master clock (72 MHz) output ram_rdy_n, // SDRAM ready output ram_ref, // SDRAM refresh output [3:0] ram_cyc, // SDRAM cycles output [3:0] ram_ph, // SDRAM phases output [8:0] ram_ph_ctr, // Phase counter //----------------------------- // Access bank #0 //----------------------------- input rden_b0, // Read enable input wren_b0, // Write enable input [22:2] addr_b0, // Address (up to 8 MB) output valid_b0, // Read data valid output fetch_b0, // Write data fetch output [15:0] rdata_b0, // Read data input [15:0] wdata_b0, // Write data input [1:0] bena_b0, // Byte enable //----------------------------- // Access bank #1 //----------------------------- input rden_b1, // Read enable input wren_b1, // Write enable input [22:2] addr_b1, // Address (up to 8 MB) output valid_b1, // Read data valid output fetch_b1, // Write data fetch output [15:0] rdata_b1, // Read data input [15:0] wdata_b1, // Write data input [1:0] bena_b1, // Byte enable //----------------------------- // Access bank #2 //----------------------------- input rden_b2, // Read enable input wren_b2, // Write enable input [22:2] addr_b2, // Address (up to 8 MB) output valid_b2, // Read data valid output fetch_b2, // Write data fetch output [15:0] rdata_b2, // Read data input [15:0] wdata_b2, // Write data input [1:0] bena_b2, // Byte enable //----------------------------- // Access bank #3 //----------------------------- input rden_b3, // Read enable input wren_b3, // Write enable input [22:2] addr_b3, // Address (up to 8 MB) output valid_b3, // Read data valid output fetch_b3, // Write data fetch output [15:0] rdata_b3, // Read data input [15:0] wdata_b3, // Write data input [1:0] bena_b3, // Byte enable //----------------------------- // SDRAM memory signals //----------------------------- output sdram_cs_n, // SDRAM chip select output reg sdram_ras_n, // SDRAM row address strobe output reg sdram_cas_n, // SDRAM column address strobe output reg sdram_we_n, // SDRAM write enable // output reg [1:0] sdram_ba, // SDRAM bank address output reg [12:0] sdram_addr, // SDRAM address // output reg [3:0] sdram_dqm_n, // SDRAM DQ masks output reg sdram_dq_oe, // SDRAM data output enable output reg [31:0] sdram_dq_o, // SDRAM data output input [31:0] sdram_dq_i // SDRAM data input ); // SDRAM memory size (16 or 32 MB) parameter SDRAM_SIZE = 16; // SDRAM memory width (16 or 32 bits) parameter SDRAM_WIDTH = 16; // Clock-to-output delay (for simulation) parameter Tco_dly = 4.5; // SDRAM commands localparam [2:0] CMD_LMR = 3'b000, CMD_REF = 3'b001, CMD_PRE = 3'b010, CMD_ACT = 3'b011, CMD_WR = 3'b100, CMD_RD = 3'b101, CMD_BST = 3'b110, CMD_NOP = 3'b111; // ====================================================== // SDRAM sequencer control // ====================================================== reg [3:0] r_ram_cyc; reg [3:0] r_ram_ph; reg [1:0] r_ba0_ctr; reg [1:0] r_ba1_ctr; reg [8:0] r_ph_ctr; reg [2:0] r_ini_ctr; reg r_ref_ena; wire w_bus_eol; assign w_bus_eol = r_ph_ctr[8] & r_ph_ctr[5] & r_ram_ph[3]; // 288 always@(posedge rst or posedge clk) begin : SEQUENCER_CTRL if (rst) begin r_ram_cyc <= 4'b1000; r_ram_ph <= 4'b1000; r_ba0_ctr <= 2'd0; r_ba1_ctr <= 2'd3; r_ph_ctr <= 9'd3; r_ini_ctr <= 3'd0; r_ref_ena <= 1'b0; end else begin r_ram_cyc <= { r_ram_cyc[2:0], r_ram_cyc[3] }; if (r_ram_cyc[3]) begin r_ram_ph <= { r_ram_ph[2:0], r_ram_ph[3] }; r_ba0_ctr <= r_ba0_ctr + 2'd1; r_ba1_ctr <= r_ba1_ctr + 2'd1; // Phase counter : 3 - 288 if (r_ram_ph[3]) begin r_ph_ctr <= (w_bus_eol) ? 9'd3 : r_ph_ctr + 9'd1; end // Initialization done after 4 scanlines if (w_bus_eol & r_ram_ph[3] & ~r_ini_ctr[2]) r_ini_ctr <= r_ini_ctr + 3'd1; // Refreshes are enabled during phase 284 - 288 //r_ref_ena <= r_ph_ctr[8] & (r_ph_ctr[5] | &r_ph_ctr[4:2]); r_ref_ena <= r_ram_ph[1]; // r_ph_ctr[8] & (r_ph_ctr[5] | &r_ph_ctr[4:2]); end end end assign ram_ref = r_ref_ena; assign ram_cyc = r_ram_cyc; assign ram_ph = r_ram_ph; assign ram_ph_ctr = r_ph_ctr; assign ram_rdy_n = ~r_ini_ctr[2]; // ====================================================== // SDRAM phase generation // ====================================================== reg [3:0] r_rd_act; reg [3:0] r_wr_act; reg r_act_ph; // Activate phase reg r_rd_ph; // Burst read phase reg r_wr_ph; // Burst write phase reg r_ref_ph; // Auto-refresh phase reg [3:0] r_ini_ph; // Initialization phases reg r_pre_ph; // Precharge phase reg r_lmr_ph; // Load mode register phase always@(posedge rst or posedge clk) begin : PHASE_GEN if (rst) begin r_rd_act <= 4'b0000; r_wr_act <= 4'b0000; r_act_ph <= 1'b0; r_rd_ph <= 1'b0; r_wr_ph <= 1'b0; r_ref_ph <= 1'b0; r_ini_ph <= 4'b0000; r_pre_ph <= 1'b0; r_lmr_ph <= 1'b0; end else begin if (r_ram_cyc[0]) begin // Access port #0 read/write if (r_ram_ph[0]) begin r_rd_act[0] <= rden_b0 & ~r_ref_ena; r_wr_act[0] <= wren_b0 & ~r_ref_ena & ~rden_b0; end else if (r_ram_ph[2]) begin r_rd_act[0] <= 1'b0; r_wr_act[0] <= 1'b0; end // Access port #1 read/write if (r_ram_ph[1]) begin r_rd_act[1] <= rden_b1 & ~r_ref_ena; r_wr_act[1] <= wren_b1 & ~r_ref_ena & ~rden_b1; end else if (r_ram_ph[3]) begin r_rd_act[1] <= 1'b0; r_wr_act[1] <= 1'b0; end // Access port #2 read/write if (r_ram_ph[2]) begin r_rd_act[2] <= rden_b2 & ~r_ref_ena; r_wr_act[2] <= wren_b2 & ~r_ref_ena & ~rden_b2; end else if (r_ram_ph[0]) begin r_rd_act[2] <= 1'b0; r_wr_act[2] <= 1'b0; end // Access port #3 read/write if (r_ram_ph[3]) begin r_rd_act[3] <= rden_b3 & ~r_ref_ena; r_wr_act[3] <= wren_b3 & ~r_ref_ena & ~rden_b3; end else if (r_ram_ph[1]) begin r_rd_act[3] <= 1'b0; r_wr_act[3] <= 1'b0; end end if (r_ram_cyc[0] & r_ini_ctr[2]) begin // Activate phase r_act_ph <= (r_ram_ph[0] & (rden_b0 | wren_b0) & ~r_ref_ena) | (r_ram_ph[1] & (rden_b1 | wren_b1) & ~r_ref_ena) | (r_ram_ph[2] & (rden_b2 | wren_b2) & ~r_ref_ena) | (r_ram_ph[3] & (rden_b3 | wren_b3) & ~r_ref_ena); end if (r_ram_cyc[3] & r_ini_ctr[2]) begin // Read phase r_rd_ph <= (r_ram_ph[0] & r_rd_act[0]) | (r_ram_ph[1] & r_rd_act[1]) | (r_ram_ph[2] & r_rd_act[2]) | (r_ram_ph[3] & r_rd_act[3]); // Write phase r_wr_ph <= (r_ram_ph[0] & r_wr_act[0]) | (r_ram_ph[1] & r_wr_act[1]) | (r_ram_ph[2] & r_wr_act[2]) | (r_ram_ph[3] & r_wr_act[3]); end // Initialization phases (0:PRE, 1:REF, 2:REF, 3:LMR) if (r_ram_cyc[3] & r_ram_ph[2]) begin if (r_ref_ena & r_ini_ctr[0] & r_ini_ctr[1]) begin r_ini_ph <= { r_ini_ph[2:0], ~|r_ini_ph }; end else begin r_ini_ph <= 4'b0000; end end // Precharge phase r_pre_ph <= r_ini_ph[0] & r_ram_ph[0]; // Refresh phase //r_ref_ph <= r_ref_ena & r_ini_ctr[2] & (r_ram_ph[0] | r_ram_ph[2]) & r_ph_ctr[8] // Normal // | (r_ini_ph[1] | r_ini_ph[2]) & r_ram_ph[0]; // Init r_ref_ph <= r_ref_ena & r_ini_ctr[2] // Normal | (r_ini_ph[1] | r_ini_ph[2]) & r_ram_ph[0]; // Init // Load mode register phase r_lmr_ph <= r_ini_ph[3] & r_ram_ph[0]; end end // ====================================================== // SDRAM address generation // ====================================================== reg [22:2] r_addr_mux; reg [10:2] r_addr_col; reg [12:0] r_addr_sdr; reg [1:0] r_ba_sdr; always@(posedge rst or posedge clk) begin : ADDRESS_GEN if (rst) begin r_addr_mux <= 21'd0; r_addr_col <= 9'd0; r_addr_sdr <= 13'd0; r_ba_sdr <= 2'b00; end else begin // Port address multiplexer if (r_ram_cyc[0]) begin r_addr_mux <= addr_b0 & {21{r_ram_ph[0] & (rden_b0 | wren_b0) }} | addr_b1 & {21{r_ram_ph[1] & (rden_b1 | wren_b1) }} | addr_b2 & {21{r_ram_ph[2] & (rden_b2 | wren_b2) }} | addr_b3 & {21{r_ram_ph[3] & (rden_b3 | wren_b3) }}; end // Column address (for read/write op.) if (r_ram_cyc[3]) begin r_addr_col <= r_addr_mux[10:2]; end // Memories layouts : // ------------------ // SDRAM 4M x 32b (128 Mb) : 4 banks x 4096 rows x 256 cols x 32 bits // SDRAM 8M x 32b (256 Mb) : 4 banks x 4096 rows x 512 cols x 32 bits // SDRAM 8M x 16b (128 Mb) : 4 banks x 4096 rows x 512 cols x 16 bits // SDRAM 16M x 16b (256 Mb) : 4 banks x 8192 rows x 512 cols x 16 bits // Row / col address if (SDRAM_WIDTH == 32) begin // 32-bit bus if (SDRAM_SIZE == 32) begin // 32 MB r_addr_sdr <= { 4'b0000, r_addr_col[10: 3], 1'b0 } & {13{r_rd_ph & r_ram_cyc[0]}} // 512 cols | { 1'b0, r_addr_mux[22:11] } & {13{r_act_ph & r_ram_cyc[1]}} // 4096 rows | { 4'b0010, r_addr_col[10: 3], 1'b1 } & {13{r_rd_ph & r_ram_cyc[2]}} // 512 cols | { 4'b0010, r_addr_col[10: 2] } & {13{r_wr_ph & r_ram_cyc[3]}} // 512 cols | { 3'b001, 10'b000000000 } & {13{r_ini_ph[0] }} // Init : precharge all | { 3'b000, 10'b1_00_010_0_000 } & {13{r_ini_ph[3] }}; // Init : load mode register (BL=1, CAS=2) end else begin // 16 MB r_addr_sdr <= { 5'b00000, r_addr_col[ 9: 3], 1'b0 } & {13{r_rd_ph & r_ram_cyc[0]}} // 256 cols | { 1'b0, r_addr_mux[21:10] } & {13{r_act_ph & r_ram_cyc[1]}} // 4096 rows | { 5'b00100, r_addr_col[ 9: 3], 1'b1 } & {13{r_rd_ph & r_ram_cyc[2]}} // 256 cols | { 5'b00100, r_addr_col[ 9: 2] } & {13{r_wr_ph & r_ram_cyc[3]}} // 256 cols | { 3'b001, 10'b000000000 } & {13{r_ini_ph[0] }} // Init : precharge all | { 3'b000, 10'b1_00_010_0_000 } & {13{r_ini_ph[3] }}; // Init : load mode register (BL=1, CAS=2) end end else begin // 16-bit bus if (SDRAM_SIZE == 32) begin // 32 MB r_addr_sdr <= { 4'b0000, r_addr_col[9:3], 2'b00 } & {13{r_rd_ph & r_ram_cyc[0]}} // 512 cols | r_addr_mux[22:10] & {13{r_act_ph & r_ram_cyc[1]}} // 8192 rows | { 4'b0010, r_addr_col[9:3], 2'b10 } & {13{r_rd_ph & r_ram_cyc[2]}} // 512 cols | { 4'b0010, r_addr_col[9:2], 1'b0 } & {13{r_wr_ph & r_ram_cyc[3]}} // 512 cols | { 3'b001, 10'b000000000 } & {13{r_ini_ph[0] }} // Init : precharge all | { 3'b000, 10'b1_00_010_0_001 } & {13{r_ini_ph[3] }}; // Init : load mode register (BL=2, CAS=2) end else begin // 16 MB r_addr_sdr <= { 4'b0000, r_addr_col[9:3], 2'b00 } & {13{r_rd_ph & r_ram_cyc[0]}} // 512 cols | { 1'b0, r_addr_mux[21:10] } & {13{r_act_ph & r_ram_cyc[1]}} // 4096 rows | { 4'b0010, r_addr_col[9:3], 2'b10 } & {13{r_rd_ph & r_ram_cyc[2]}} // 512 cols | { 4'b0010, r_addr_col[9:2], 1'b0 } & {13{r_wr_ph & r_ram_cyc[3]}} // 512 cols | { 3'b001, 10'b000000000 } & {13{r_ini_ph[0] }} // Init : precharge all | { 3'b000, 10'b0_00_010_0_001 } & {13{r_ini_ph[3] }}; // Init : load mode register (BL=2, CAS=2) end end // Bank address r_ba_sdr <= r_ba1_ctr & {2{r_rd_ph & r_ram_cyc[0]}} // 32-bit read | r_ba0_ctr & {2{r_act_ph & r_ram_cyc[1]}} // Activate | r_ba1_ctr & {2{r_rd_ph & r_ram_cyc[2]}} // 32-bit read with auto-precharge | r_ba1_ctr & {2{r_wr_ph & r_ram_cyc[3]}}; // 32-bit write with auto-precharge end end // ====================================================== // SDRAM command generation // ====================================================== reg [2:0] r_cmd_sdr; always@(posedge rst or posedge clk) begin : COMMAND_GEN reg [2:0] v_cmd_0; reg [2:0] v_cmd_1; reg [2:0] v_cmd_2; reg [2:0] v_cmd_3; reg [2:0] v_cmd_4; reg [2:0] v_cmd_5; reg [2:0] v_cmd_6; if (rst) begin r_cmd_sdr <= CMD_NOP; end else begin v_cmd_0 = CMD_RD | {3{~r_rd_ph }}; v_cmd_1 = CMD_ACT | {3{~r_act_ph}}; v_cmd_2 = CMD_RD | {3{~r_rd_ph }}; v_cmd_3 = CMD_WR | {3{~r_wr_ph }}; v_cmd_4 = CMD_PRE | {3{~r_pre_ph}}; v_cmd_5 = CMD_REF | {3{~r_ref_ph}}; v_cmd_6 = CMD_LMR | {3{~r_lmr_ph}}; r_cmd_sdr <= (v_cmd_0 | {3{~r_ram_cyc[0]}}) & (v_cmd_1 | {3{~r_ram_cyc[1]}}) & (v_cmd_2 | {3{~r_ram_cyc[2]}}) & (v_cmd_3 | {3{~r_ram_cyc[3]}}) & (v_cmd_4 | {3{~r_ram_cyc[3]}}) & (v_cmd_5 | {3{~r_ram_cyc[3]}}) & (v_cmd_6 | {3{~r_ram_cyc[3]}}); end end assign sdram_cs_n = 1'b0; // Command and address /* verilator lint_off STMTDLY */ always@(*) sdram_ras_n = #Tco_dly r_cmd_sdr[2]; always@(*) sdram_cas_n = #Tco_dly r_cmd_sdr[1]; always@(*) sdram_we_n = #Tco_dly r_cmd_sdr[0]; always@(*) sdram_ba = #Tco_dly r_ba_sdr; always@(*) sdram_addr = #Tco_dly r_addr_sdr; /* verilator lint_on STMTDLY */ // ====================================================== // Data being read // ====================================================== reg [3:0] r_data_vld; reg r_data_sel; reg [15:0] r_lrdata_p0; reg [15:0] r_hrdata_p0; reg [15:0] r_hrdata_p1; wire [15:0] w_rdata_p0; always@(posedge rst or posedge clk) begin : DATA_READ if (rst) begin r_data_vld <= 4'b0000; r_data_sel <= 1'b0; r_lrdata_p0 <= 16'h0000; r_hrdata_p0 <= 16'h0000; r_hrdata_p1 <= 16'h0000; end else begin if (r_ram_cyc[3]) begin r_data_vld[0] <= r_rd_act[0] & r_ram_ph[1]; r_data_vld[1] <= r_rd_act[1] & r_ram_ph[2]; r_data_vld[2] <= r_rd_act[2] & r_ram_ph[3]; r_data_vld[3] <= r_rd_act[3] & r_ram_ph[0]; end r_data_sel <= r_ram_cyc[1] | r_ram_cyc[3]; r_lrdata_p0 <= sdram_dq_i[15:0]; r_hrdata_p0 <= sdram_dq_i[31:16]; r_hrdata_p1 <= r_hrdata_p0; end end // 32-bit to 16-bit multiplexer assign w_rdata_p0 = (r_data_sel) ? r_hrdata_p1 : r_lrdata_p0; // Access Port #0 assign rdata_b0 = (SDRAM_WIDTH == 32) ? w_rdata_p0 : r_lrdata_p0; assign valid_b0 = r_data_vld[0]; // Access Port #1 assign rdata_b1 = (SDRAM_WIDTH == 32) ? w_rdata_p0 : r_lrdata_p0; assign valid_b1 = r_data_vld[1]; // Access Port #2 assign rdata_b2 = (SDRAM_WIDTH == 32) ? w_rdata_p0 : r_lrdata_p0; assign valid_b2 = r_data_vld[2]; // Access Port #3 assign rdata_b3 = (SDRAM_WIDTH == 32) ? w_rdata_p0 : r_lrdata_p0; assign valid_b3 = r_data_vld[3]; // ====================================================== // Data being written // ====================================================== reg [3:0] r_data_fe_p0; reg [3:0] r_data_fe_p1; reg r_data_oe; reg [15:0] r_wdata_p2a; reg [15:0] r_wdata_p2b; reg [31:0] r_wdata_p3; reg [1:0] r_bena_p2a; reg [1:0] r_bena_p2b; reg [3:0] r_bena_p3; always@(posedge rst or posedge clk) begin : DATA_WRITE if (rst) begin r_data_fe_p0 <= 4'b0000; r_data_fe_p1 <= 4'b0000; r_data_oe <= 1'b0; r_wdata_p2a <= 16'h0000; r_wdata_p2b <= 16'h0000; r_wdata_p3 <= 32'h0000_0000; r_bena_p2a <= 2'b00; r_bena_p2b <= 2'b00; r_bena_p3 <= 4'b00_00; end else begin if (r_ram_cyc[3]) begin r_data_fe_p0 <= r_wr_act & r_ram_ph; r_data_oe <= r_wr_ph; end else if (r_ram_cyc[1]) begin r_data_fe_p0 <= 4'b0000; r_data_oe <= 1'b0; end r_data_fe_p1 <= r_data_fe_p0; if (SDRAM_WIDTH == 32) begin // 16-bit -> 32-bit bus if (r_data_sel) begin r_wdata_p2b <= wdata_b0 & {16{r_data_fe_p1[0]}} | wdata_b1 & {16{r_data_fe_p1[1]}} | wdata_b2 & {16{r_data_fe_p1[2]}} | wdata_b3 & {16{r_data_fe_p1[3]}}; r_bena_p2b <= bena_b0 & {2{r_data_fe_p1[0]}} | bena_b1 & {2{r_data_fe_p1[1]}} | bena_b2 & {2{r_data_fe_p1[2]}} | bena_b3 & {2{r_data_fe_p1[3]}} | {2{~|r_data_fe_p1}}; end else begin r_wdata_p2a <= wdata_b0 & {16{r_data_fe_p1[0]}} | wdata_b1 & {16{r_data_fe_p1[1]}} | wdata_b2 & {16{r_data_fe_p1[2]}} | wdata_b3 & {16{r_data_fe_p1[3]}}; r_bena_p2a <= bena_b0 & {2{r_data_fe_p1[0]}} | bena_b1 & {2{r_data_fe_p1[1]}} | bena_b2 & {2{r_data_fe_p1[2]}} | bena_b3 & {2{r_data_fe_p1[3]}} | {2{~|r_data_fe_p1}}; end r_wdata_p3 <= { r_wdata_p2b, r_wdata_p2a }; r_bena_p3 <= { r_bena_p2b, r_bena_p2a }; end else begin // 16-bit bus r_wdata_p2a <= wdata_b0 & {16{r_data_fe_p1[0]}} | wdata_b1 & {16{r_data_fe_p1[1]}} | wdata_b2 & {16{r_data_fe_p1[2]}} | wdata_b3 & {16{r_data_fe_p1[3]}}; r_wdata_p2b <= r_wdata_p2a; r_wdata_p3 <= { 16'h0000, r_wdata_p2b }; r_bena_p2a <= bena_b0 & {2{r_data_fe_p1[0]}} | bena_b1 & {2{r_data_fe_p1[1]}} | bena_b2 & {2{r_data_fe_p1[2]}} | bena_b3 & {2{r_data_fe_p1[3]}} | {2{~|r_data_fe_p1}}; r_bena_p2b <= r_bena_p2a; r_bena_p3 <= { 2'b00, r_bena_p2b }; end end end // Output mask, data & enable /* verilator lint_off STMTDLY */ always@(*) sdram_dqm_n = #Tco_dly ~r_bena_p3; always@(*) sdram_dq_o = #Tco_dly r_wdata_p3; always@(*) sdram_dq_oe = #Tco_dly r_data_oe; /* verilator lint_on STMTDLY */ // Access Port #0 assign fetch_b0 = r_data_fe_p0[0]; // Access Port #1 assign fetch_b1 = r_data_fe_p0[1]; // Access Port #2 assign fetch_b2 = r_data_fe_p0[2]; // Access Port #3 assign fetch_b3 = r_data_fe_p0[3]; endmodule /* verilator tracing_on */