Commit 5034058e authored by Andrey Filippov's avatar Andrey Filippov

added modules to test ddrc phy over axi read/write

parent 03bce211
......@@ -89,7 +89,7 @@ module axibram_write #(
reg [ 1:0] wburst; // registered burst type
reg [ 3:0] wlen; // registered awlen type (for wrapped over transfers)
wire [ADDRESS_BITS-1:0] next_wr_address_w; // next transfer address;
wire bram_we_w; // write BRAM memory
wire bram_we_w; //,bram_we_nonmasked; // write BRAM memory non-masked - should be combined with
wire start_write_burst_w;
wire write_in_progress_w;
reg dev_ready_r; // device, selected at start burst
......@@ -98,7 +98,8 @@ module axibram_write #(
(wburst[0]? {ADDRESS_BITS{1'b0}}:((write_address[ADDRESS_BITS-1:0]+1) & {{(ADDRESS_BITS-4){1'b1}}, ~wlen[3:0]})):
(wburst[0]? (write_address[ADDRESS_BITS-1:0]+1):(write_address[ADDRESS_BITS-1:0]));
assign bram_we_w= w_nempty && write_in_progress && dev_ready_r;
assign bram_we_w= w_nempty && write_in_progress && dev_ready_r;
// assign bram_we_nonmasked= w_nempty && write_in_progress;
assign start_write_burst_w=aw_nempty && (!write_in_progress || (w_nempty && (write_left[3:0]==4'b0)));
assign write_in_progress_w=aw_nempty || (write_in_progress && !(w_nempty && (write_left[3:0]==4'b0)));
......
/*******************************************************************************
* Module: ddrc_control
* Date:2014-05-19
* Author: Andrey Filippov
* Description: Temporary module with DDRC control / command registers
*
* Copyright (c) 2014 Elphel, Inc.
* ddrc_control.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.
*
* ddrc_control.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 <http://www.gnu.org/licenses/> .
*******************************************************************************/
`timescale 1ns/1ps
module ddrc_control #(
parameter AXI_WR_ADDR_BITS= 12,
parameter SELECT_ADDR = 'h800, // address to select this module
parameter SELECT_ADDR_MASK = 'h800, // address mask to select this module
parameter BUSY_ADDR = 'hc00, // address to generate busy
parameter BUSY_ADDR_MASK = 'hc00 // address mask to generate busy
)(
input clk,
input mclk,
input rst,
input [AXI_WR_ADDR_BITS-1:0] pre_waddr, // AXI write address, before actual writes (to generate busy), valid@start_burst
input start_wburst, // burst start - should generate ~ready (should be AND-ed with !busy internally)
input [AXI_WR_ADDR_BITS-1:0] waddr, // write address, valid with wr_en
input wr_en, // write enable
input [31:0] wdata, // write data, valid with waddr and wr_en
output busy, // interface busy (combinatorial delay from start_wburst and pre_addr
// control signals
// control: sequencer run
output [10:0] run_addr, // Start address of the physical sequencer (MSB = 0 - "manual", 1 -"auto")
output [ 3:0] run_chn, // channel number to use for I/O buffers
output run_seq, // single mclk pulse to start sequencer
// input run_done; // output - will go through other channel - sequencer done (add busy?)
// control: delays and mmcm setup
output [ 7:0] dly_data, // 8-bit IDELAY/ODELAY (fine) and MMCM phase shift
output [ 6:0] dly_addr, // address to select delay register
output ld_delay, // write dly_data to dly_address, one mclk active pulse
output set, // transfer (activate) all delays simultaneosly, 1 mclk pulse
// control: additional signals
output cmda_tri, // tri-state all command and address lines to DDR chip
output inv_clk_div, // invert clk_div to ISERDES
output [ 7:0] dqs_pattern, // DQS pattern during write (normally 8'h55)
output [ 7:0] dqm_pattern, // DQM pattern (just for testing, should be 8'h0)
// control: buffers pages
output [ 1:0] port0_page, // port 0 buffer read page (to be controlled by arbiter later, set to 2'b0)
output [ 1:0] port0_int_page, // port 0 PHY-side write to buffer page (to be controlled by arbiter later, set to 2'b0)
output [ 1:0] port1_page, // port 1 buffer write page (to be controlled by arbiter later, set to 2'b0)
output [ 1:0] port1_int_page // port 1 PHY-side buffer read page (to be controlled by arbiter later, set to 2'b0)
);
reg busy_r=0;
reg selected_r=0;
// assign busy=busy_r && start_wburst?(((pre_addr ^ SELECT_ADDR) & SELECT_ADDR_MASK)==0): selected_r;
assign busy=busy_r && start_wburst?(((pre_waddr ^ BUSY_ADDR) & BUSY_ADDR_MASK)==0): selected_r;
endmodule
/*******************************************************************************
* Module: ddrc_status
* Date:2014-05-19
* Author: Andrey Filippov
* Description: Read status/radback information from the DDR controller
*
* Copyright (c) 2014 Elphel, Inc.
* ddrc_status.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.
*
* ddrc_status.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 <http://www.gnu.org/licenses/> .
*******************************************************************************/
`timescale 1ns/1ps
module ddrc_status#(
parameter AXI_RD_ADDR_BITS= 12,
parameter SELECT_ADDR = 'h800, // address to select this module
parameter SELECT_ADDR_MASK = 'h800, // address mask to select this module
parameter BUSY_ADDR = 'hc00, // address to generate busy
parameter BUSY_ADDR_MASK = 'hc00 // address mask to generate busy
)(
input clk,
input mclk,
input rst,
input [AXI_RD_ADDR_BITS-1:0] pre_raddr, // AXI reade address, before actual reads (to generate busy), valid@start_burst
input start_rburst, // burst start - should generate ~ready (should be AND-ed with !busy internally)
input [AXI_RD_ADDR_BITS-1:0] raddr, // read address, valid with rd_en
input rd_en, // read enable
output [31:0] rdata, // read data, should valid with raddr and rd_en
output busy, // interface busy (combinatorial delay from start_wburst and pre_addr
// status/readback signals
input run_done, // sequencer done (add busy?)
input run_busy, // sequencer busy
input locked, // MMCM and PLL locked
input ps_rdy, // MMCM phase shift control ready
input [ 7:0] ps_out // MMCM phase shift value (in 1/56 of the Fvco period)
);
endmodule
......@@ -46,7 +46,16 @@ module ddrc_test01 #(
parameter CMD_PAUSE_BITS= 6,
parameter CMD_DONE_BIT= 6,
parameter AXI_WR_ADDR_BITS = 12,
parameter AXI_RD_ADDR_BITS = 12
parameter AXI_RD_ADDR_BITS = 12,
parameter SELECT_WR_ADDR = 'h800, // AXI write address to select this module
parameter SELECT_WR_ADDR_MASK = 'h800, // AXI write address mask to select this module
parameter BUSY_WR_ADDR = 'hc00, // AXI write address to generate busy
parameter BUSY_WR_ADDR_MASK = 'hc00, // AXI write address mask to generate busy
parameter SELECT_RD_ADDR = 'h800, // AXI read address to select this module
parameter SELECT_RD_ADDR_MASK = 'h800, // AXI read address mask to select this module
parameter BUSY_RD_ADDR = 'hc00, // AXI read address to generate busy
parameter BUSY_RD_ADDR_MASK = 'hc00 // AXI read address mask to generate busy
)(
// DDR3 interface
output SDCLK, // DDR3 clock differential output, positive
......@@ -68,6 +77,7 @@ module ddrc_test01 #(
inout NDQSU // ~UDQS I/O pad
// AXI write (ps -> pl)
);
localparam ADDRESS_NUMBER=15;
// Source for reset and clock
wire [3:0] fclk; // PL Clocks [3:0], output
wire [3:0] frst; // PL Clocks [3:0], output
......@@ -109,7 +119,8 @@ module ddrc_test01 #(
wire axiwr_dev_ready; // extrernal combinatorial ready signal, multiplexed from different sources according to pre_awaddr@start_burst
wire axiwr_bram_wclk;
wire [AXI_WR_ADDR_BITS-1:0] axiwr_bram_waddr;
wire axiwr_bram_wen; // external memory wreite enable, (internally combined with registered dev_ready
wire axiwr_bram_wen; // external memory write enable, (internally combined with registered dev_ready
// SuppressWarnings VEditor unused (yet?)
wire [3:0] axiwr_bram_wstb;
wire [31:0] axiwr_bram_wdata;
......@@ -138,6 +149,7 @@ module ddrc_test01 #(
wire axird_start_burst; // start of read burst, valid pre_araddr, save externally to control ext. dev_ready multiplexer
wire axird_dev_ready; // extrernal combinatorial ready signal, multiplexed from different sources according to pre_araddr@start_burst
// External memory interface
// SuppressWarnings VEditor unused (yet?) - use mclk
wire axird_bram_rclk; // .rclk(aclk), // clock for read port
wire [AXI_RD_ADDR_BITS-1:0] axird_bram_raddr; // .raddr(read_in_progress?read_address[9:0]:10'h3ff), // read address
wire axird_bram_ren; // .ren(bram_reg_re_w) , // read port enable
......@@ -214,6 +226,7 @@ wire [10:0] run_addr; // input[10:0]
wire [ 3:0] run_chn; // input[3:0]
wire run_seq; // input
wire run_done; // output
wire run_busy; // TODO: add to ddrc_sequencer
wire [ 7:0] dly_data; // input[7:0]
wire [ 6:0] dly_addr; // input[6:0]
wire ld_delay; // input
......@@ -223,9 +236,87 @@ wire locked; // output
wire ps_rdy; // output
wire [ 7:0] ps_out; // output[7:0]
wire en_port0_rd;
wire en_port0_regen;
wire en_port1_wr;
wire [ 1:0] port0_page; // input[1:0]
wire [ 1:0] port0_int_page; // input[1:0]
wire [ 1:0] port1_page; // input[1:0]
wire [ 1:0] port1_int_page;// input[1:0]
// additional control signals
wire cmda_tri; // input
wire inv_clk_div; // input
wire [ 7:0] dqs_pattern; // input[7:0] 8'h55
wire [ 7:0] dqm_pattern; // input[7:0] 8'h00
assign en_cmd0_wr= axiwr_bram_wen && (axiwr_bram_waddr[11:10]==3);
assign en_cmd0_wr= axiwr_bram_wen && (axiwr_bram_waddr[11:10]==2'h1);
assign en_port0_rd= axird_bram_ren && (axird_bram_raddr[11:10]==2'h0);
assign en_port0_regen= axird_bram_regen && (axird_bram_raddr[11:10]==2'h0);
assign en_port1_wr= axiwr_bram_wen && (axiwr_bram_waddr[11:10]==2'h0);
wire axiwr_dev_busy;
assign axiwr_dev_ready = ~axiwr_dev_busy; //may combine (AND) multiple sources if needed
wire axird_dev_busy;
assign axird_dev_ready = ~axird_dev_busy; //may combine (AND) multiple sources if needed
ddrc_control #(
.AXI_WR_ADDR_BITS (AXI_WR_ADDR_BITS),
.SELECT_ADDR (SELECT_WR_ADDR),
.SELECT_ADDR_MASK (SELECT_WR_ADDR_MASK),
.BUSY_ADDR (BUSY_WR_ADDR),
.BUSY_ADDR_MASK (BUSY_WR_ADDR_MASK)
) ddrc_control_i (
.clk (axi_aclk), // input
.mclk (axiwr_bram_wclk), // input
.rst (axi_rst), // input
.pre_waddr (axiwr_pre_awaddr[AXI_WR_ADDR_BITS-1:0]), // input[11:0]
.start_wburst (axiwr_start_burst), // input
.waddr (axiwr_bram_waddr[AXI_WR_ADDR_BITS-1:0]), // input[11:0]
.wr_en (axiwr_bram_wen), // input
.wdata (axiwr_bram_wdata[31:0]), // input[31:0] (no input for wstb here)
.busy (axiwr_dev_busy), // output
.run_addr (run_addr[10:0]), // output[10:0]
.run_chn (run_chn[3:0]), // output[3:0]
.run_seq (run_seq), // output
.dly_data (dly_data[7:0]), // output[7:0]
.dly_addr (dly_addr[6:0]), // output[6:0]
.ld_delay (ld_delay), // output
.set (set), // output
.cmda_tri (cmda_tri), // output
.inv_clk_div (inv_clk_div), // output
.dqs_pattern (dqs_pattern[7:0]), // output[7:0]
.dqm_pattern (dqm_pattern[7:0]), // output[7:0]
.port0_page (port0_page[1:0]), // output[1:0]
.port0_int_page (port0_int_page[1:0]), // output[1:0]
.port1_page (port1_page[1:0]), // output[1:0]
.port1_int_page (port1_int_page[1:0]) // output[1:0]
);
ddrc_status #(
.AXI_RD_ADDR_BITS (AXI_RD_ADDR_BITS),
.SELECT_ADDR (SELECT_RD_ADDR),
.SELECT_ADDR_MASK (SELECT_RD_ADDR_MASK),
.BUSY_ADDR (BUSY_RD_ADDR),
.BUSY_ADDR_MASK (BUSY_RD_ADDR_MASK)
) ddrc_status_i (
.clk (axi_aclk), // input
.mclk (mclk), // input
.rst (axi_rst), // input
.pre_raddr (axird_pre_araddr[AXI_RD_ADDR_BITS-1:0]), // input[11:0]
.start_rburst (axird_start_burst), // input
.raddr (axird_bram_raddr[AXI_RD_ADDR_BITS-1:0]), // input[11:0]
.rd_en (axird_bram_regen), // input
.rdata (axird_bram_rdata[31:0]), // output[31:0]
.busy (axird_dev_busy), // output
.run_done (run_done), // input
.run_busy (run_busy), // input
.locked (locked), // input
.ps_rdy (ps_rdy), // input
.ps_out (ps_out[7:0]) // input[7:0]
);
ddrc_sequencer #(
......@@ -254,63 +345,65 @@ assign en_cmd0_wr= axiwr_bram_wen && (axiwr_bram_waddr[11:10]==3);
.CMD_PAUSE_BITS (CMD_PAUSE_BITS),
.CMD_DONE_BIT (CMD_DONE_BIT)
) ddrc_sequencer_i (
.SDCLK (SDCLK), // output
.SDNCLK (SDNCLK), // output
.SDA (SDA), // output[14:0]
.SDBA (SDBA), // output[2:0]
.SDWE (SDWE), // output
.SDRAS (SDRAS), // output
.SDCAS (SDCAS), // output
.SDCKE (SDCKE), // output
.SDODT (SDODT), // output
.SDD (SDD), // inout[15:0]
.SDDML (SDDML), // inout
.DQSL (DQSL), // inout
.NDQSL (NDQSL), // inout
.SDDMU (SDDMU), // inout
.DQSU (DQSU), // inout
.NDQSU (NDQSU), // inout
.clk_in (axi_aclk), // input
.rst_in (axi_rst), // input
.mclk (mclk), // output
.cmd0_clk (axi_aclk), // input
.cmd0_we (en_cmd0_wr), // input
.cmd0_addr (axiwr_bram_waddr[9:0]), // input[9:0]
.cmd0_data (axiwr_bram_wdata[31:0]), // input[31:0]
.cmd1_clk (mclk), // input
.cmd1_we (1'b0), // input
.cmd1_addr (10'b0), // input[9:0]
.cmd1_data (32'b0), // input[31:0]
.SDCLK (SDCLK), // output
.SDNCLK (SDNCLK), // output
.SDA (SDA[14:0]), // output[14:0] // BUG with localparam - fixed
.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 (axi_aclk), // input
.rst_in (axi_rst), // input
.mclk (mclk), // output
.cmd0_clk (axi_aclk), // input
.cmd0_we (en_cmd0_wr), // input
.cmd0_addr (axiwr_bram_waddr[9:0]), // input[9:0]
.cmd0_data (axiwr_bram_wdata[31:0]), // input[31:0]
.cmd1_clk (mclk), // input
// TODO: add - from PL generation of the command sequences
.cmd1_we (1'b0), // input
.cmd1_addr (10'b0), // input[9:0]
.cmd1_data (32'b0), // input[31:0]
.run_addr (run_addr[10:0]), // input[10:0]
.run_chn (run_chn[3:0]), // input[3:0]
.run_seq (run_seq), // input
.run_done (run_done), // 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]
.run_addr (run_addr[10:0]), // input[10:0]
.run_chn (run_chn[3:0]), // input[3:0]
.run_seq (run_seq), // input
.run_done (run_done), // output
.run_busy (run_busy), // 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]
.port0_clk(), // input
.port0_re(), // input
.port0_regen(), // input
.port0_page(), // input[1:0]
.port0_int_page(), // input[1:0]
.port0_addr(), // input[7:0]
.port0_data(), // output[31:0]
.port1_clk(), // input
.port1_we(), // input
.port1_page(), // input[1:0]
.port1_int_page(), // input[1:0]
.port1_addr(), // input[7:0]
.port1_data(), // input[31:0]
.cmda_tri(), // input
.inv_clk_div(), // input
.dqs_pattern(), // input[7:0]
.dqm_pattern() // input[7:0]
.port0_clk (axi_aclk), // input
.port0_re (en_port0_rd), // input
.port0_regen (en_port0_regen), // input
.port0_page (port0_page[1:0]), // input[1:0]
.port0_int_page (port0_int_page[1:0]), // input[1:0]
.port0_addr (axird_bram_raddr[7:0]), // input[7:0]
.port0_data (axird_bram_rdata[31:0]), // output[31:0]
.port1_clk (axi_aclk), // input
.port1_we (en_port1_wr), // input
.port1_page (port1_page[1:0]), // input[1:0]
.port1_int_page (port1_int_page[1:0]), // input[1:0]
.port1_addr (axiwr_bram_waddr[7:0]), // input[7:0]
.port1_data (axiwr_bram_wdata[31:0]), // input[31:0]
.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]
);
......
......@@ -82,7 +82,8 @@ module ddrc_sequencer #(
input [10:0] run_addr, // controller sequencer start address (0..11'h3ff - 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
output run_done, // controller sequence finished
output run_busy, // controller sequence in progress
// 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
......@@ -150,7 +151,7 @@ module ddrc_sequencer #(
reg run_seq_d;
assign run_done=sequence_done;
assign run_busy=cmd_busy[0]; //earliest
assign pause=cmd_fetch? (phy_cmd_nop && (pause_len != 0)): (cmd_busy[2] && (pause_cntr[CMD_PAUSE_BITS-1:1]!=0));
assign phy_cmd_word = phy_cmd_word?phy_cmd1_word:phy_cmd0_word;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment