diff --git a/phy/byte_lane.v b/phy/byte_lane.v index 96b3a86e92a6d4eba94b5590e445537ea417a58c..80948edf700721b937ac9133dcb2a4ff8cba7e7f 100644 --- a/phy/byte_lane.v +++ b/phy/byte_lane.v @@ -111,10 +111,12 @@ generate .rst(rst), .dci_disable(dci_disable_dq_r), // disable DCI termination during writes and idle .dly_data(dly_data_r), // delay value (3 LSB - fine delay) - .din(din_r[4*i+3:4*i]) , // parallel data to be sent out + .din({din_r[i+24],din_r[i+16],din_r[i+8],din_r[i]}) , // parallel data to be sent out +// .din(din_r[4*i+3:4*i]) , // parallel data to be sent out // .din(din_r[4*i+3-:4]) , // parallel data to be sent out .tin(tin_dq_r), // tristate for data out (sent out earlier than data!) - .dout(dout[4*i+3:4*i]), // parallel data received from DDR3 memory + .dout({dout[i+24],dout[i+16],dout[i+8],dout[i]}), // parallel data received from DDR3 memory +// .dout(dout[4*i+3:4*i]), // parallel data received from DDR3 memory .set_odelay(set_r), // clk_div synchronous load odelay value from dly_data .ld_odelay(ld_odly[i]), // clk_div synchronous set odealy value from loaded .set_idelay(set_r), // clk_div synchronous load idelay value from dly_data diff --git a/phy/cmd_addr.v b/phy/cmd_addr.v index 7f9dffa1763f2eeb99225e7a95a1c82a5dfb6b11..9c3dc8585f77e5cb2b44e0ce573de9cd210b0498 100644 --- a/phy/cmd_addr.v +++ b/phy/cmd_addr.v @@ -49,7 +49,7 @@ module cmd_addr #( input in_tri, // tristate command/address outputs - same timing, but no odelay input [7:0] dly_data, // delay value (3 LSB - fine delay) input [4:0] dly_addr, // select which delay to program - input ld_delay, // load delay data to selected iodelayl (clk_iv synchronous) + input ld_delay, // load delay data to selected iodelayl (clk_div synchronous) input set // clk_div synchronous set all delays from previously loaded values ); reg [2*ADDRESS_NUMBER-1:0] in_a_r=0; @@ -110,7 +110,7 @@ generate .clk_div(clk_div), // free-running half clk frequency, front aligned to clk (shared for R/W) .rst(rst), .dly_data(dly_data_r[7:0]), // delay value (3 LSB - fine delay) - .din(in_a_r[2*i+1:2*i]), // parallel data to be sent out + .din({in_a_r[ADDRESS_NUMBER+i],in_a_r[i]}), // parallel data to be sent out // .tin(in_tri_r[1:0]), // tristate for data out (sent out earlier than data!) .tin(in_tri_r), // tristate for data out (sent out earlier than data!) .set_delay(set_r), // clk_div synchronous load odelay value from dly_data @@ -132,7 +132,7 @@ endgenerate .clk_div(clk_div), .rst(rst), .dly_data(dly_data_r[7:0]), - .din(in_ba_r[1:0]), + .din({in_ba_r[3],in_ba_r[0]}), // .tin(in_tri_r[1:0]), .tin(in_tri_r), .set_delay(set_r), @@ -150,7 +150,7 @@ endgenerate .clk_div(clk_div), .rst(rst), .dly_data(dly_data_r[7:0]), - .din(in_ba_r[3:2]), + .din({in_ba_r[4],in_ba_r[1]}), // .tin(in_tri_r[1:0]), .tin(in_tri_r), .set_delay(set_r), @@ -168,7 +168,7 @@ endgenerate .clk_div(clk_div), .rst(rst), .dly_data(dly_data_r[7:0]), - .din(in_ba_r[5:4]), + .din({in_ba_r[5],in_ba_r[2]}), // .tin(in_tri_r[1:0]), .tin(in_tri_r), .set_delay(set_r), diff --git a/phy/ddr3c16.v b/phy/ddr3c16.v new file mode 100644 index 0000000000000000000000000000000000000000..71c680089d2d0754ca3bc93819b60956391df8ee --- /dev/null +++ b/phy/ddr3c16.v @@ -0,0 +1,193 @@ +/******************************************************************************* + * Module: ddr3c16 + * Date:2014-05-16 + * Author: Andrey Filippov + * Description: ddr3 controller, 16 channel + * + * Copyright (c) 2014 Elphel, Inc. + * ddr3c16.v is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ddr3c16.v is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + *******************************************************************************/ +`timescale 1ns/1ps + +module ddr3c16 #( + parameter PHASE_WIDTH = 8, + parameter SLEW_DQ = "SLOW", + parameter SLEW_DQS = "SLOW", + parameter SLEW_CMDA = "SLOW", + parameter SLEW_CLK = "SLOW", + parameter IBUF_LOW_PWR = "TRUE", + parameter real REFCLK_FREQUENCY = 300.0, + parameter HIGH_PERFORMANCE_MODE = "FALSE", + parameter CLKIN_PERIOD = 10, //ns >1.25, 60064r) - used for mode set, refresh, write levelling, ... + input cmd0_we, + input [9:0] cmd0_addr, + input [31:0] cmd0_data, +// TODO: add automatic command port1 , filled by the PL, 36w 36r, used for actual page R/W + input cmd1_we, + input [9:0] cmd1_addr, + input [35:0] cmd1_data, +// Controller run interface, posedge mclk + input [10:0] run_addr, // controller sequencer start address (0..11'h1ff - cmd0, 11'h400..11'h7ff - cmd1) + input [3:0] run_chn, // data channel to use + input run_seq, // start controller sequence + output run_done, // controller sequence finished +// inteface to control I/O delays and mmcm + input [7:0] dly_data, // delay value (3 LSB - fine delay) + input [6:0] dly_addr, // select which delay to program + input ld_delay, // load delay data to selected iodelayl (clk_div synchronous) + input set, // clk_div synchronous set all delays from previously loaded values + output locked, + output ps_rdy, + output [PHASE_WIDTH-1:0] ps_out, +// read port 0 + input port0_clk, + input port0_re, + input port0_regen, + input [1:0] port0_page, + input [1:0] port0_int_page, + input [7:0] port0_addr, + output [31:0] port0_data, +// write port 1 + input port1_clk, + input port1_we, + input [1:0] port1_page, + input [1:0] port1_int_page, + input [7:0] port1_addr, + input [31:0] port1_data, + // extras + input cmda_tri, // tristate command and address lines // not likely to be used + input inv_clk_div, + input [7:0] dqs_pattern, // 8'h55 + input [7:0] dqm_pattern // 8'h00 + +); + localparam ADDRESS_NUMBER = 15; + + wire [35:0] phy_cmd; // input[35:0] + wire [6:0] buf_addr; // output[6:0] + wire [63:0] buf_wdata; // output[63:0] + wire [63:0] buf_rdata; // input[63:0] + wire buf_wr; // output + wire buf_rd; // output + + + phy_cmd #( + .ADDRESS_NUMBER (ADDRESS_NUMBER), + .PHASE_WIDTH (PHASE_WIDTH), + .SLEW_DQ (SLEW_DQ), + .SLEW_DQS (SLEW_DQS), + .SLEW_CMDA (SLEW_CMDA), + .SLEW_CLK (SLEW_CLK), + .IBUF_LOW_PWR (IBUF_LOW_PWR), + .REFCLK_FREQUENCY (REFCLK_FREQUENCY), + .HIGH_PERFORMANCE_MODE (HIGH_PERFORMANCE_MODE), + .CLKIN_PERIOD (CLKIN_PERIOD), + .CLKFBOUT_MULT (CLKFBOUT_MULT), + .CLKFBOUT_MULT_REF (CLKFBOUT_MULT_REF), + .CLKFBOUT_DIV_REF (CLKFBOUT_DIV_REF), + .DIVCLK_DIVIDE (DIVCLK_DIVIDE), + .CLKFBOUT_PHASE (CLKFBOUT_PHASE), + .ICLK_PHASE (ICLK_PHASE), + .CLK_PHASE (CLK_PHASE), + .CLK_DIV_PHASE (CLK_DIV_PHASE), + .MCLK_PHASE (MCLK_PHASE), + .REF_JITTER1 (REF_JITTER1), + .SS_EN (SS_EN), + .SS_MODE (SS_MODE), + .SS_MOD_PERIOD (SS_MOD_PERIOD) + ) phy_cmd_i ( + .SDCLK (SDCLK), // output + .SDNCLK (SDNCLK), // output + .SDA (SDA[ADDRESS_NUMBER-1:0]), // output[14:0] + .SDBA (SDBA[2:0]), // output[2:0] + .SDWE (SDWE), // output + .SDRAS (SDRAS), // output + .SDCAS (SDCAS), // output + .SDCKE (SDCKE), // output + .SDODT (SDODT), // output + .SDD (SDD[15:0]), // inout[15:0] + .SDDML (SDDML), // inout + .DQSL (DQSL), // inout + .NDQSL (NDQSL), // inout + .SDDMU (SDDMU), // inout + .DQSU (DQSU), // inout + .NDQSU (NDQSU), // inout + .clk_in (clk_in), // input + .rst_in (rst_in), // input + .mclk (mclk), // output + .dly_data (dly_data[7:0]), // input[7:0] + .dly_addr (dly_addr[6:0]), // input[6:0] + .ld_delay (ld_delay), // input + .set (set), // input + .locked (locked), // output + .ps_rdy (ps_rdy), // output + .ps_out (ps_out[7:0]), // output[7:0] + .phy_cmd (phy_cmd[35:0]), // input[35:0] + .buf_addr (buf_addr[6:0]), // output[6:0] + .buf_wdata (buf_wdata[63:0]), // output[63:0] + .buf_rdata (buf_rdata[63:0]), // input[63:0] + .buf_wr (buf_wr), // output + .buf_rd (buf_rd), // output + .cmda_tri (cmda_tri), // input + .inv_clk_div (inv_clk_div), // input + .dqs_pattern (dqs_pattern), // input[7:0] + .dqm_pattern (dqm_pattern) // input[7:0] + ); + + + +endmodule + diff --git a/phy/phy_cmd.v b/phy/phy_cmd.v new file mode 100644 index 0000000000000000000000000000000000000000..44fb4229d86377643fdd153899f26a712382161a --- /dev/null +++ b/phy/phy_cmd.v @@ -0,0 +1,317 @@ +/******************************************************************************* + * Module: phy_cmd + * Date:2014-05-15 + * Author: Andrey Filippov + * Description: Executes a stream of commands to DDR3 phy at 1/2 ddr3 clock, global + * (also proveides r/w interface to the x64 external buffer) + * + * Copyright (c) 2014 Elphel, Inc. + * phy_cmd.v is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * phy_cmd.v is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + *******************************************************************************/ +`timescale 1ns/1ps + +module phy_cmd#( + parameter ADDRESS_NUMBER = 15, + parameter PHASE_WIDTH = 8, + parameter SLEW_DQ = "SLOW", + parameter SLEW_DQS = "SLOW", + parameter SLEW_CMDA = "SLOW", + parameter SLEW_CLK = "SLOW", + parameter IBUF_LOW_PWR = "TRUE", + parameter real REFCLK_FREQUENCY = 300.0, + parameter HIGH_PERFORMANCE_MODE = "FALSE", + parameter CLKIN_PERIOD = 10, //ns >1.25, 6001 and 1->0) + wire phy_dqs_tri_in; // tristate DQS lines (internal timing sequencer for 0->1 and 1->0) + wire phy_dci_in; // DCI disable, both DQ and DQS lines (internal logic and timing sequencer for 0->1 and 1->0) + wire [ 6:0] phy_buf_addr; // connect to extrenal buffer + wire phy_buf_wr; // connect to extrenal buffer + wire phy_buf_rd; // connect to extrenal buffer + +// wire clk; + wire clk_div; + + reg [7:0] dly_data_r; // delay value (3 LSB - fine delay) + reg [6:0] dly_addr_r; // select which delay to program + reg ld_delay_r; // load delay data to selected iodelayl (clk_div synchronous) + reg set_r; // clk_div synchronous set all delays from previously loaded values + + wire [2*ADDRESS_NUMBER-1:0] phy_addr; // also provides pause length when the command is NOP + wire [ 5:0] phy_bank; + wire [ 5:0] phy_rcw; // {ras,cas,we} + wire [1:0] phy_odt; // may be optimized? + wire [1:0] phy_cke; // may be optimized? + wire [7:0] phy_dq_tri; // tristate DQ lines (internal timing sequencer for 0->1 and 1->0) + wire [7:0] phy_dqs_tri; // tristate DQS lines (internal timing sequencer for 0->1 and 1->0) + wire phy_dci_dis_dq; + wire phy_dci_dis_dqs; + + reg dqs_tri_prev, dq_tri_prev; + wire phy_locked; + wire phy_ps_rdy; + wire [PHASE_WIDTH-1:0] phy_ps_out; + reg locked_r1,locked_r2; + reg ps_rdy_r1,ps_rdy_r2; + reg [PHASE_WIDTH-1:0] ps_out_r1,ps_out_r2; + wire [63:0] phy_rdata; // data read from ddr3 iserdese2 at posedge clk_div + reg [63:0] phy_rdata_r; // registered @ posedge mclk +// output [63:0] buf_wdata, // data to be written to the buffer (from DDR3) + + + assign { + phy_addr_in, + phy_bank_in, + phy_rcw_in, // {ras,cas,we} + phy_odt_in, // may be optimized? + phy_cke_in, // may be optimized? + phy_sel_in, // fitst/second half-cycle, oter will be nop (cke+odt applicable to both) + phy_dq_tri_in, // tristate DQ lines (internal timing sequencer for 0->1 and 1->0) + phy_dqs_tri_in, // tristate DQS lines (internal timing sequencer for 0->1 and 1->0) + phy_dci_in, // DCI disable, both DQ and DQS lines (internal logic and timing sequencer for 0->1 and 1->0) + phy_buf_addr, // connect to extrenal buffer + phy_buf_wr, // connect to extrenal buffer + phy_buf_rd // connect to extrenal buffer + } = phy_cmd; + + assign buf_addr = phy_buf_addr; + assign buf_wr = phy_buf_wr; + assign buf_rd = phy_buf_rd; + + assign phy_addr= {phy_addr_in,phy_addr_in}; // also provides pause length when the command is NOP + assign phy_bank= {phy_bank_in,phy_bank_in}; + assign phy_rcw= {phy_sel_in?phy_rcw_in:3'h0, phy_sel_in?3'h0:phy_rcw_in}; // {ras,cas,we} + assign phy_odt= {phy_odt_in,phy_odt_in}; // may be optimized? + assign phy_cke= {phy_cke_in,phy_cke_in}; // may be optimized? + + // tristate DQ lines (internal timing sequencer for 0->1 and 1->0) + assign phy_dq_tri= (dq_tri_prev==phy_dq_tri_in)?{{8{phy_dq_tri_in}}}: + (dq_tri_prev?{DQTRI_FIRST,DQTRI_FIRST}:{DQTRI_LAST,DQTRI_LAST}); + // tristate DQS lines (internal timing sequencer for 0->1 and 1->0) + assign phy_dqs_tri= (dqs_tri_prev==phy_dqs_tri_in)?{{8{phy_dqs_tri_in}}}: + (dqs_tri_prev?{DQSTRI_FIRST,DQSTRI_FIRST}:{DQSTRI_LAST,DQSTRI_LAST}); + assign phy_dci_dis_dq = phy_dci_in; // DCI disable, both DQ and DQS lines (internal logic and timing sequencer for 0->1 and 1->0) + assign phy_dci_dis_dqs = phy_dci_in; // DCI disable, both DQ and DQS lines (internal logic and timing sequencer for 0->1 and 1->0) + + assign locked = locked_r2; + assign ps_rdy = ps_rdy_r2; + assign ps_out = ps_out_r2; + + assign buf_wdata[63:0] = phy_rdata_r[63:0]; + + always @ (posedge mclk) begin + dqs_tri_prev <= phy_dqs_tri_in; + dq_tri_prev <= phy_dq_tri_in; + end + +// cross clock boundary posedge mclk -> posedge clk_div (mclk is later than clk_div) + always @ (posedge clk_div or posedge rst_in) begin + if (rst_in) begin + dly_data_r <= 0; + dly_addr_r <= 0; + ld_delay_r <= 0; + set_r <= 0; + end else begin + dly_data_r <= dly_data; + dly_addr_r <= dly_addr; + ld_delay_r <= ld_delay; + set_r <= set; + end + end + + +// cross clock boundary posedge posedge clk_div->negedge clk_div -> posedge mclk (mclk is later than clk_div) + always @ (negedge clk_div) begin + locked_r1 <= phy_locked; + ps_rdy_r1 <= phy_ps_rdy; + ps_out_r1 <= phy_ps_out; + end + always @ (posedge mclk) begin + locked_r2 <= locked_r1; + ps_rdy_r2 <= ps_rdy_r1; + ps_out_r2 <= ps_out_r1; + end + + + always @ (negedge mclk) begin + phy_rdata_r[63:0] <= phy_rdata[63:0]; + end + + +/* +phy_rdata + + wire phy_locked; + wire phy_ps_rdy; + wire [PHASE_WIDTH-1:0] phy_ps_out; + + + output locked, + output ps_rdy, + output [PHASE_WIDTH-1:0] ps_out, + +*/ + + + phy_top #( + .IOSTANDARD_DQ ("SSTL15_T_DCI"), + .IOSTANDARD_DQS ("DIFF_SSTL15_T_DCI"), + .IOSTANDARD_CMDA ("SSTL15"), + .IOSTANDARD_CLK ("DIFF_SSTL15"), + .SLEW_DQ (SLEW_DQ), + .SLEW_DQS (SLEW_DQS), + .SLEW_CMDA (SLEW_CMDA), + .SLEW_CLK (SLEW_CLK), + .IBUF_LOW_PWR (IBUF_LOW_PWR), + .IODELAY_GRP ("IODELAY_MEMORY"), + .REFCLK_FREQUENCY (REFCLK_FREQUENCY), + .HIGH_PERFORMANCE_MODE(HIGH_PERFORMANCE_MODE), + .ADDRESS_NUMBER (ADDRESS_NUMBER), + .PHASE_WIDTH (8), + .BANDWIDTH ("OPTIMIZED"), + .CLKIN_PERIOD (CLKIN_PERIOD), + .CLKFBOUT_MULT (CLKFBOUT_MULT), + .CLKFBOUT_MULT_REF(CLKFBOUT_MULT_REF), + .CLKFBOUT_DIV_REF (CLKFBOUT_DIV_REF), + .DIVCLK_DIVIDE (DIVCLK_DIVIDE), + .CLKFBOUT_PHASE (CLKFBOUT_PHASE), + .ICLK_PHASE (ICLK_PHASE), + .CLK_PHASE (CLK_PHASE), + .CLK_DIV_PHASE (CLK_DIV_PHASE), + .MCLK_PHASE (MCLK_PHASE), + .REF_JITTER1 (REF_JITTER1), + .SS_EN (SS_EN), + .SS_MODE (SS_MODE), + .SS_MOD_PERIOD (SS_MOD_PERIOD) + ) phy_top_i ( + .ddr3_clk (SDCLK), // output + .ddr3_nclk (SDNCLK), // output + .ddr3_a (SDA[ADDRESS_NUMBER-1:0]), // output[14:0] + .ddr3_ba (SDBA[2:0]), // output[2:0] + .ddr3_we (SDWE), // output + .ddr3_ras (SDRAS), // output + .ddr3_cas (SDCAS), // output + .ddr3_cke (SDCKE), // output + .ddr3_odt (SDODT), // output + .dq (SDD[15:0]), // inout[15:0] + .dml (SDDML), // inout + .dqsl (DQSL), // inout + .ndqsl (NDQSL), // inout + .dmu (SDDMU), // inout + .dqsu (DQSU), // inout + .ndqsu (NDQSU), // inout + .clk_in (clk_in), // input +// .clk (clk), // output + .clk (), // output + .clk_div (clk_div), // output + .mclk (mclk), // output + .rst_in (rst_in), // input + .in_a (phy_addr[2*ADDRESS_NUMBER-1:0]), // input[29:0] + .in_ba (phy_bank[5:0]), // input[5:0] + .in_we ({phy_rcw[3],phy_rcw[0]}), // input[1:0] + .in_ras ({phy_rcw[5],phy_rcw[2]}), // input[1:0] + .in_cas ({phy_rcw[4],phy_rcw[1]}), // input[1:0] + .in_cke (phy_cke), // input[1:0] + .in_odt (phy_odt), // input[1:0] + .in_tri (cmda_tri), // input + .din (buf_rdata[63:0]), // input[63:0] + .din_dm (dqm_pattern[7:0]), // input[7:0] + .tin_dq (phy_dq_tri[7:0]), // input[7:0] + .din_dqs (dqs_pattern[7:0]), // input[7:0] + .tin_dqs (phy_dqs_tri[7:0]), // input[7:0] + .dout (phy_rdata[63:0]), // output[63:0] @posedge clk_div + .inv_clk_div (inv_clk_div), // input + .dci_disable_dqs (phy_dci_dis_dqs), // input + .dci_disable_dq (phy_dci_dis_dq), // input + .dly_data (dly_data_r), // input[7:0] + .dly_addr (dly_addr_r), // input[6:0] + .ld_delay (ld_delay_r), // input + .set (set_r), // input + .locked (phy_locked), // output + .ps_rdy (phy_ps_rdy), // output + .ps_out (phy_ps_out) // output[7:0] + ); + +endmodule + diff --git a/phy/phy_top.v b/phy/phy_top.v index 9df09e10af587d1a32a65676e0e05b765b0fd074..3a18dd7f0eee19b7501cf070dc97db4c633c3965 100644 --- a/phy/phy_top.v +++ b/phy/phy_top.v @@ -46,7 +46,7 @@ module phy_top #( parameter ICLK_PHASE = 0.000, parameter CLK_PHASE = 0.000, parameter CLK_DIV_PHASE = 0.000, - parameter MCLK_PHASE = 0.000, + parameter MCLK_PHASE = 90.000, parameter REF_JITTER1 = 0.010, parameter SS_EN = "FALSE", parameter SS_MODE = "CENTER_HIGH", @@ -100,7 +100,7 @@ module phy_top #( input [7:0] dly_data, // delay value (3 LSB - fine delay) input [6:0] dly_addr, // select which delay to program - input ld_delay, // load delay data to selected iodelayl (clk_iv synchronous) + input ld_delay, // load delay data to selected iodelayl (clk_div synchronous) input set, // clk_div synchronous set all delays from previously loaded values output locked, output ps_rdy, @@ -148,7 +148,7 @@ module phy_top #( .in_tri (in_tri), // tristate command/address outputs - same timing, but no odelay .dly_data (dly_data[7:0]), // delay value (3 LSB - fine delay) .dly_addr (dly_addr[4:0]), // select which delay to program - .ld_delay (ld_cmda), // load delay data to selected iodelayl (clk_iv synchronous) + .ld_delay (ld_cmda), // load delay data to selected iodelayl (clk_div synchronous) .set (set) // clk_div synchronous set all delays from previously loaded values ); diff --git a/phy/test_phy_top_01.v b/phy/test_phy_top_01.v index c1ddab5f97224c095d2ad47a4574df2125e9182f..d40410b4eba1731ccaed25ae80935d4aebd6a74c 100644 --- a/phy/test_phy_top_01.v +++ b/phy/test_phy_top_01.v @@ -105,7 +105,7 @@ module test_phy_top_01#( reg dci_disable_dq; // disable DCI termination during writes and idle for dq and dm signals reg [7:0] dly_data; // delay value (3 LSB - fine delay) reg [6:0] dly_addr; // select which delay to program - reg ld_delay; // load delay data to selected iodelayl (clk_iv synchronous) + reg ld_delay; // load delay data to selected iodelayl (clk_div synchronous) reg set; // clk_div synchronous set all delays from previously loaded values reg [63:0] dout_r; diff --git a/wrap/ram_1kx32_1kx32.v b/wrap/ram_1kx32_1kx32.v index 6b5c8f9823f5597bd1698073b5fa30d9b6f5a3ae..45121cf1d7eb6048e1e5b96dc01658a0605c47bc 100644 --- a/wrap/ram_1kx32_1kx32.v +++ b/wrap/ram_1kx32_1kx32.v @@ -142,12 +142,12 @@ module ram_1kx32_1kx32 .DIBDI(data_in[31:0]), // Port B data/MSB data[31:0], input .DIPBDIP(4'b0), // Port B parity/MSB parity[3:0], input .ADDRBWRADDR({1'b1,waddr[9:0],5'b11111}), // Port B (write port in SDP) address [15:0]. used from [14] down, unused should be high, input - .CLKBWRCLK(wclk), // Port B (read port in SDP) clock, input - .ENBWREN(we), // Port B (read port in SDP) Enable, input - .REGCEB(1'b0), // Port B (read port in SDP) register enable, input - .RSTRAMB(1'b0), // Port B (read port in SDP) set/reset, input - .RSTREGB(1'b0), // Port B (read port in SDP) register set/reset, input - .WEBWE({4'b0,web[3:0]}), // Port B (read port in SDP) Write Enable[7:0], input + .CLKBWRCLK(wclk), // Port B (write port in SDP) clock, input + .ENBWREN(we), // Port B (write port in SDP) Enable, input + .REGCEB(1'b0), // Port B (write port in SDP) register enable, input + .RSTRAMB(1'b0), // Port B (write port in SDP) set/reset, input + .RSTREGB(1'b0), // Port B (write port in SDP) register set/reset, input + .WEBWE({4'b0,web[3:0]}), // Port B (write port in SDP) Write Enable[7:0], input // Error correction circuitry .SBITERR(), // Single bit error status, output .DBITERR(), // Double bit error status, output diff --git a/wrap/ram_1kx32w_512x64r.v b/wrap/ram_1kx32w_512x64r.v new file mode 100644 index 0000000000000000000000000000000000000000..98a1fccc3277508c0f43372371558c4e62f1044e --- /dev/null +++ b/wrap/ram_1kx32w_512x64r.v @@ -0,0 +1,166 @@ +/******************************************************************************* + * Copyright (c) 2014 Elphel, Inc. + * ram_1kx32w_512x64r.v is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ram_1kx32w_512x64r.v is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + *******************************************************************************/ +/* + Address/data widths + Connect unused data to 1b0, unused addresses - to 1'b1 + + RAMB18E1 in True Dual Port (TDP) Mode - each port individually + +-----------+---------+---------+---------+ + |Data Width | Address | Data | Parity | + +-----------+---------+---------+---------+ + | 1 | A[13:0] | D[0] | --- | + | 2 | A[13:1] | D[1:0] | --- | + | 4 | A[13:2] | D[3:0[ | --- | + | 9 | A[13:3] | D[7:0] | DP[0] | + | 18 | A[13:4] | D[15:0] | DP[1:0] | + +-----------+---------+---------+---------+ + + RAMB18E1 in Simple Dual Port (SDP) Mode + one of the ports (r or w) - 32/36 bits, other - variable + +------------+---------+---------+---------+ + |Data Widths | Address | Data | Parity | + +------------+---------+---------+---------+ + | 32/ 1 | A[13:0] | D[0] | --- | + | 32/ 2 | A[13:1] | D[1:0] | --- | + | 32/ 4 | A[13:2] | D[3:0[ | --- | + | 36/ 9 | A[13:3] | D[7:0] | DP[0] | + | 36/ 18 | A[13:4] | D[15:0] | DP[1:0] | + | 36/ 36 | A[13:5] | D[31:0] | DP[3:0] | + +------------+---------+---------+---------+ + + RAMB36E1 in True Dual Port (TDP) Mode - each port individually + +-----------+---------+---------+---------+ + |Data Width | Address | Data | Parity | + +-----------+---------+---------+---------+ + | 1 | A[14:0] | D[0] | --- | + | 2 | A[14:1] | D[1:0] | --- | + | 4 | A[14:2] | D[3:0[ | --- | + | 9 | A[14:3] | D[7:0] | DP[0] | + | 18 | A[14:4] | D[15:0] | DP[1:0] | + | 36 | A[14:5] | D[31:0] | DP[3:0] | + |1(Cascade) | A[15:0] | D[0] | --- | + +-----------+---------+---------+---------+ + + RAMB36E1 in Simple Dual Port (SDP) Mode + one of the ports (r or w) - 64/72 bits, other - variable + +------------+---------+---------+---------+ + |Data Widths | Address | Data | Parity | + +------------+---------+---------+---------+ + | 64/ 1 | A[14:0] | D[0] | --- | + | 64/ 2 | A[14:1] | D[1:0] | --- | + | 64/ 4 | A[14:2] | D[3:0[ | --- | + | 64/ 9 | A[14:3] | D[7:0] | DP[0] | + | 64/ 18 | A[14:4] | D[15:0] | DP[1:0] | + | 64/ 36 | A[14:5] | D[31:0] | DP[3:0] | + | 64/ 72 | A[14:6] | D[63:0] | DP[7:0] | + +------------+---------+---------+---------+ +*/ +module ram_1kx32w_512x64r +#( + parameter integer registers = 0 // 1 - registered output + ) + ( + input rclk, // clock for read port + input [ 8:0] raddr, // read address + input ren, // read port enable + input regen, // output register enable + output [63:0] data_out, // data out + + input wclk, // clock for read port + input [ 9:0] waddr, // write address + input we, // write port enable + input [ 3:0] web, // write byte enable + input [31:0] data_in // data out + ); + RAMB36E1 + #( + .RSTREG_PRIORITY_A("RSTREG"), // Valid: "RSTREG" or "REGCE" + .RSTREG_PRIORITY_B("RSTREG"), // Valid: "RSTREG" or "REGCE" + .DOA_REG(registers), // Valid: 0 (no output registers) and 1 - one output register (in SDP - to lower 36) + .DOB_REG(registers), // Valid: 0 (no output registers) and 1 - one output register (in SDP - to lower 36) + .RAM_EXTENSION_A("NONE"), // Cascading, valid: "NONE","UPPER", LOWER" + .RAM_EXTENSION_B("NONE"), // Cascading, valid: "NONE","UPPER", LOWER" + .READ_WIDTH_A(72), // Valid: 0,1,2,4,9,18,36 and in SDP mode - 72 (should be 0 if port is not used) + .READ_WIDTH_B(0), // Valid: 0,1,2,4,9,18,36 and in SDP mode - 72 (should be 0 if port is not used) + .WRITE_WIDTH_A(0), // Valid: 0,1,2,4,9,18,36 and in SDP mode - 72 (should be 0 if port is not used) + .WRITE_WIDTH_B(36), // Valid: 0,1,2,4,9,18,36 and in SDP mode - 72 (should be 0 if port is not used) + .RAM_MODE("SDP"), // Valid "TDP" (true dual-port) and "SDP" - simple dual-port + .WRITE_MODE_A("WRITE_FIRST"), // Valid: "WRITE_FIRST", "READ_FIRST", "NO_CHANGE" + .WRITE_MODE_B("WRITE_FIRST"), // Valid: "WRITE_FIRST", "READ_FIRST", "NO_CHANGE" + .RDADDR_COLLISION_HWCONFIG("DELAYED_WRITE"),// Valid: "DELAYED_WRITE","PERFORMANCE" (no access to the same page) + .SIM_COLLISION_CHECK("ALL"), // Valid: "ALL", "GENERATE_X_ONLY", "NONE", and "WARNING_ONLY" + .INIT_FILE("NONE"), // "NONE" or filename with initialization data + .SIM_DEVICE("7SERIES"), // Simulation device family - "VIRTEX6", "VIRTEX5" and "7_SERIES" // "7SERIES" + + .EN_ECC_READ("FALSE"), // Valid:"FALSE","TRUE" (ECC decoder circuitry) + .EN_ECC_WRITE("FALSE") // Valid:"FALSE","TRUE" (ECC decoder circuitry) +// .INIT_A(36'h0), // Output latches initialization data +// .INIT_B(36'h0), // Output latches initialization data +// .SRVAL_A(36'h0), // Output latches initialization data (copied at when RSTRAM/RSTREG activated) +// .SRVAL_B(36'h0) // Output latches initialization data (copied at when RSTRAM/RSTREG activated) +/* + parameter IS_CLKARDCLK_INVERTED = 1'b0; + parameter IS_CLKBWRCLK_INVERTED = 1'b0; + parameter IS_ENARDEN_INVERTED = 1'b0; + parameter IS_ENBWREN_INVERTED = 1'b0; + parameter IS_RSTRAMARSTRAM_INVERTED = 1'b0; + parameter IS_RSTRAMB_INVERTED = 1'b0; + parameter IS_RSTREGARSTREG_INVERTED = 1'b0; + parameter IS_RSTREGB_INVERTED = 1'b0; +*/ + + ) RAMB36E1_i + ( + // Port A (Read port in SDP mode): + .DOADO(data_out[31:0]), // Port A data/LSB data[63:0], output + .DOPADOP(), // Port A parity/LSB parity[7:0], output + .DIADI(32'h0), // Port A data/LSB data[31:0], input + .DIPADIP(4'h0), // Port A parity/LSB parity[3:0], input + .ADDRARDADDR({1'b1,raddr[8:0],6'b111111}), // Port A (read port in SDP) address [15:0]. used from [14] down, unused should be high, input + .CLKARDCLK(rclk), // Port A (read port in SDP) clock, input + .ENARDEN(ren), // Port A (read port in SDP) Enable, input + .REGCEAREGCE(regen), // Port A (read port in SDP) register enable, input + .RSTRAMARSTRAM(1'b0), // Port A (read port in SDP) set/reset, input + .RSTREGARSTREG(1'b0), // Port A (read port in SDP) register set/reset, input + .WEA(4'b0), // Port A (read port in SDP) Write Enable[3:0], input + // Port B + .DOBDO(data_out[63:32]), // Port B data/MSB data[31:0], output + .DOPBDOP(), // Port B parity/MSB parity[3:0], output + .DIBDI(data_in[31:0]), // Port B data/MSB data[31:0], input + .DIPBDIP(4'b0), // Port B parity/MSB parity[3:0], input + .ADDRBWRADDR({1'b1,waddr[9:0],5'b11111}), // Port B (write port in SDP) address [15:0]. used from [14] down, unused should be high, input + .CLKBWRCLK(wclk), // Port B (write port in SDP) clock, input + .ENBWREN(we), // Port B (write port in SDP) Enable, input + .REGCEB(1'b0), // Port B (write port in SDP) register enable, input + .RSTRAMB(1'b0), // Port B (write port in SDP) set/reset, input + .RSTREGB(1'b0), // Port B (write port in SDP) register set/reset, input + .WEBWE({4'b0,web[3:0]}), // Port B (write port in SDP) Write Enable[7:0], input + // Error correction circuitry + .SBITERR(), // Single bit error status, output + .DBITERR(), // Double bit error status, output + .ECCPARITY(), // Genearted error correction parity [7:0], output + .RDADDRECC(), // ECC read address[8:0], output + .INJECTSBITERR(1'b0),// inject a single-bit error, input + .INJECTDBITERR(1'b0),// inject a double-bit error, input + // Cascade signals to create 64Kx1 + .CASCADEOUTA(), // A-port cascade, output + .CASCADEOUTB(), // B-port cascade, output + .CASCADEINA(1'b0), // A-port cascade, input + .CASCADEINB(1'b0) // B-port cascade, input + ); + +endmodule + diff --git a/wrap/ram_512x64w_1kx32r.v b/wrap/ram_512x64w_1kx32r.v new file mode 100644 index 0000000000000000000000000000000000000000..e699909c51ec59bbf6e30e06eae9df951895b4cd --- /dev/null +++ b/wrap/ram_512x64w_1kx32r.v @@ -0,0 +1,166 @@ +/******************************************************************************* + * Copyright (c) 2014 Elphel, Inc. + * ram_512x64w_1kx32r.v is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ram_512x64w_1kx32r.v is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + *******************************************************************************/ +/* + Address/data widths + Connect unused data to 1b0, unused addresses - to 1'b1 + + RAMB18E1 in True Dual Port (TDP) Mode - each port individually + +-----------+---------+---------+---------+ + |Data Width | Address | Data | Parity | + +-----------+---------+---------+---------+ + | 1 | A[13:0] | D[0] | --- | + | 2 | A[13:1] | D[1:0] | --- | + | 4 | A[13:2] | D[3:0[ | --- | + | 9 | A[13:3] | D[7:0] | DP[0] | + | 18 | A[13:4] | D[15:0] | DP[1:0] | + +-----------+---------+---------+---------+ + + RAMB18E1 in Simple Dual Port (SDP) Mode + one of the ports (r or w) - 32/36 bits, other - variable + +------------+---------+---------+---------+ + |Data Widths | Address | Data | Parity | + +------------+---------+---------+---------+ + | 32/ 1 | A[13:0] | D[0] | --- | + | 32/ 2 | A[13:1] | D[1:0] | --- | + | 32/ 4 | A[13:2] | D[3:0[ | --- | + | 36/ 9 | A[13:3] | D[7:0] | DP[0] | + | 36/ 18 | A[13:4] | D[15:0] | DP[1:0] | + | 36/ 36 | A[13:5] | D[31:0] | DP[3:0] | + +------------+---------+---------+---------+ + + RAMB36E1 in True Dual Port (TDP) Mode - each port individually + +-----------+---------+---------+---------+ + |Data Width | Address | Data | Parity | + +-----------+---------+---------+---------+ + | 1 | A[14:0] | D[0] | --- | + | 2 | A[14:1] | D[1:0] | --- | + | 4 | A[14:2] | D[3:0[ | --- | + | 9 | A[14:3] | D[7:0] | DP[0] | + | 18 | A[14:4] | D[15:0] | DP[1:0] | + | 36 | A[14:5] | D[31:0] | DP[3:0] | + |1(Cascade) | A[15:0] | D[0] | --- | + +-----------+---------+---------+---------+ + + RAMB36E1 in Simple Dual Port (SDP) Mode + one of the ports (r or w) - 64/72 bits, other - variable + +------------+---------+---------+---------+ + |Data Widths | Address | Data | Parity | + +------------+---------+---------+---------+ + | 64/ 1 | A[14:0] | D[0] | --- | + | 64/ 2 | A[14:1] | D[1:0] | --- | + | 64/ 4 | A[14:2] | D[3:0[ | --- | + | 64/ 9 | A[14:3] | D[7:0] | DP[0] | + | 64/ 18 | A[14:4] | D[15:0] | DP[1:0] | + | 64/ 36 | A[14:5] | D[31:0] | DP[3:0] | + | 64/ 72 | A[14:6] | D[63:0] | DP[7:0] | + +------------+---------+---------+---------+ +*/ +module ram_512x64w_1kx32r +#( + parameter integer registers = 0 // 1 - registered output + ) + ( + input rclk, // clock for read port + input [ 9:0] raddr, // read address + input ren, // read port enable + input regen, // output register enable + output [31:0] data_out, // data out + + input wclk, // clock for read port + input [ 8:0] waddr, // write address + input we, // write port enable + input [ 7:0] web, // write byte enable + input [63:0] data_in // data out + ); + RAMB36E1 + #( + .RSTREG_PRIORITY_A("RSTREG"), // Valid: "RSTREG" or "REGCE" + .RSTREG_PRIORITY_B("RSTREG"), // Valid: "RSTREG" or "REGCE" + .DOA_REG(registers), // Valid: 0 (no output registers) and 1 - one output register (in SDP - to lower 36) + .DOB_REG(registers), // Valid: 0 (no output registers) and 1 - one output register (in SDP - to lower 36) + .RAM_EXTENSION_A("NONE"), // Cascading, valid: "NONE","UPPER", LOWER" + .RAM_EXTENSION_B("NONE"), // Cascading, valid: "NONE","UPPER", LOWER" + .READ_WIDTH_A(36), // Valid: 0,1,2,4,9,18,36 and in SDP mode - 72 (should be 0 if port is not used) + .READ_WIDTH_B(0), // Valid: 0,1,2,4,9,18,36 and in SDP mode - 72 (should be 0 if port is not used) + .WRITE_WIDTH_A(0), // Valid: 0,1,2,4,9,18,36 and in SDP mode - 72 (should be 0 if port is not used) + .WRITE_WIDTH_B(72), // Valid: 0,1,2,4,9,18,36 and in SDP mode - 72 (should be 0 if port is not used) + .RAM_MODE("SDP"), // Valid "TDP" (true dual-port) and "SDP" - simple dual-port + .WRITE_MODE_A("WRITE_FIRST"), // Valid: "WRITE_FIRST", "READ_FIRST", "NO_CHANGE" + .WRITE_MODE_B("WRITE_FIRST"), // Valid: "WRITE_FIRST", "READ_FIRST", "NO_CHANGE" + .RDADDR_COLLISION_HWCONFIG("DELAYED_WRITE"),// Valid: "DELAYED_WRITE","PERFORMANCE" (no access to the same page) + .SIM_COLLISION_CHECK("ALL"), // Valid: "ALL", "GENERATE_X_ONLY", "NONE", and "WARNING_ONLY" + .INIT_FILE("NONE"), // "NONE" or filename with initialization data + .SIM_DEVICE("7SERIES"), // Simulation device family - "VIRTEX6", "VIRTEX5" and "7_SERIES" // "7SERIES" + + .EN_ECC_READ("FALSE"), // Valid:"FALSE","TRUE" (ECC decoder circuitry) + .EN_ECC_WRITE("FALSE") // Valid:"FALSE","TRUE" (ECC decoder circuitry) +// .INIT_A(36'h0), // Output latches initialization data +// .INIT_B(36'h0), // Output latches initialization data +// .SRVAL_A(36'h0), // Output latches initialization data (copied at when RSTRAM/RSTREG activated) +// .SRVAL_B(36'h0) // Output latches initialization data (copied at when RSTRAM/RSTREG activated) +/* + parameter IS_CLKARDCLK_INVERTED = 1'b0; + parameter IS_CLKBWRCLK_INVERTED = 1'b0; + parameter IS_ENARDEN_INVERTED = 1'b0; + parameter IS_ENBWREN_INVERTED = 1'b0; + parameter IS_RSTRAMARSTRAM_INVERTED = 1'b0; + parameter IS_RSTRAMB_INVERTED = 1'b0; + parameter IS_RSTREGARSTREG_INVERTED = 1'b0; + parameter IS_RSTREGB_INVERTED = 1'b0; +*/ + + ) RAMB36E1_i + ( + // Port A (Read port in SDP mode): + .DOADO(data_out[31:0]), // Port A data/LSB data[31:0], output + .DOPADOP(), // Port A parity/LSB parity[3:0], output + .DIADI(data_in[31:0]), // Port A data/LSB data[31:0], input + .DIPADIP(4'h0), // Port A parity/LSB parity[3:0], input + .ADDRARDADDR({1'b1,raddr[9:0],5'b11111}), // Port A (read port in SDP) address [15:0]. used from [14] down, unused should be high, input + .CLKARDCLK(rclk), // Port A (read port in SDP) clock, input + .ENARDEN(ren), // Port A (read port in SDP) Enable, input + .REGCEAREGCE(regen), // Port A (read port in SDP) register enable, input + .RSTRAMARSTRAM(1'b0), // Port A (read port in SDP) set/reset, input + .RSTREGARSTREG(1'b0), // Port A (read port in SDP) register set/reset, input + .WEA(4'b0), // Port A (read port in SDP) Write Enable[3:0], input + // Port B + .DOBDO(), // Port B data/MSB data[31:0], output + .DOPBDOP(), // Port B parity/MSB parity[3:0], output + .DIBDI(data_in[63:32]), // Port B data/MSB data[31:0], input + .DIPBDIP(4'b0), // Port B parity/MSB parity[3:0], input + .ADDRBWRADDR({1'b1,waddr[8:0],6'b111111}), // Port B (write port in SDP) address [15:0]. used from [14] down, unused should be high, input + .CLKBWRCLK(wclk), // Port B (write port in SDP) clock, input + .ENBWREN(we), // Port B (write port in SDP) Enable, input + .REGCEB(1'b0), // Port B (write port in SDP) register enable, input + .RSTRAMB(1'b0), // Port B (write port in SDP) set/reset, input + .RSTREGB(1'b0), // Port B (write port in SDP) register set/reset, input + .WEBWE(web[7:0]), // Port B (write port in SDP) Write Enable[7:0], input + // Error correction circuitry + .SBITERR(), // Single bit error status, output + .DBITERR(), // Double bit error status, output + .ECCPARITY(), // Genearted error correction parity [7:0], output + .RDADDRECC(), // ECC read address[8:0], output + .INJECTSBITERR(1'b0),// inject a single-bit error, input + .INJECTDBITERR(1'b0),// inject a double-bit error, input + // Cascade signals to create 64Kx1 + .CASCADEOUTA(), // A-port cascade, output + .CASCADEOUTB(), // B-port cascade, output + .CASCADEINA(1'b0), // A-port cascade, input + .CASCADEINB(1'b0) // B-port cascade, input + ); + +endmodule +