Commit 7a0fa46b authored by Andrey Filippov's avatar Andrey Filippov

Working on membridge.v - module to read/write ddr3 in scanline mode over ahi_hp

parent caf85bde
......@@ -62,77 +62,77 @@
<link>
<name>vivado_logs/VivadoBitstream.log</name>
<type>1</type>
<location>/home/andrey/git/x393/vivado_logs/VivadoBitstream-20150422150006515.log</location>
<location>/home/andrey/git/x393/vivado_logs/VivadoBitstream-20150426202414513.log</location>
</link>
<link>
<name>vivado_logs/VivadoOpt.log</name>
<type>1</type>
<location>/home/andrey/git/x393/vivado_logs/VivadoOpt-20150422150006515.log</location>
<location>/home/andrey/git/x393/vivado_logs/VivadoOpt-20150426202414513.log</location>
</link>
<link>
<name>vivado_logs/VivadoOptPhys.log</name>
<type>1</type>
<location>/home/andrey/git/x393/vivado_logs/VivadoOptPhys-20150422150006515.log</location>
<location>/home/andrey/git/x393/vivado_logs/VivadoOptPhys-20150426202414513.log</location>
</link>
<link>
<name>vivado_logs/VivadoOptPower.log</name>
<type>1</type>
<location>/home/andrey/git/x393/vivado_logs/VivadoOptPower-20150422150006515.log</location>
<location>/home/andrey/git/x393/vivado_logs/VivadoOptPower-20150426202414513.log</location>
</link>
<link>
<name>vivado_logs/VivadoPlace.log</name>
<type>1</type>
<location>/home/andrey/git/x393/vivado_logs/VivadoPlace-20150422150006515.log</location>
<location>/home/andrey/git/x393/vivado_logs/VivadoPlace-20150426202414513.log</location>
</link>
<link>
<name>vivado_logs/VivadoRoute.log</name>
<type>1</type>
<location>/home/andrey/git/x393/vivado_logs/VivadoRoute-20150422150006515.log</location>
<location>/home/andrey/git/x393/vivado_logs/VivadoRoute-20150426202414513.log</location>
</link>
<link>
<name>vivado_logs/VivadoSynthesis.log</name>
<type>1</type>
<location>/home/andrey/git/x393/vivado_logs/VivadoSynthesis-20150422145717867.log</location>
<location>/home/andrey/git/x393/vivado_logs/VivadoSynthesis-20150426202222327.log</location>
</link>
<link>
<name>vivado_logs/VivadoTimimgSummaryReportImplemented.log</name>
<type>1</type>
<location>/home/andrey/git/x393/vivado_logs/VivadoTimimgSummaryReportImplemented-20150422150006515.log</location>
<location>/home/andrey/git/x393/vivado_logs/VivadoTimimgSummaryReportImplemented-20150426202414513.log</location>
</link>
<link>
<name>vivado_logs/VivadoTimimgSummaryReportSynthesis.log</name>
<type>1</type>
<location>/home/andrey/git/x393/vivado_logs/VivadoTimimgSummaryReportSynthesis-20150422145717867.log</location>
<location>/home/andrey/git/x393/vivado_logs/VivadoTimimgSummaryReportSynthesis-20150426202222327.log</location>
</link>
<link>
<name>vivado_logs/VivadoTimingReportImplemented.log</name>
<type>1</type>
<location>/home/andrey/git/x393/vivado_logs/VivadoTimingReportImplemented-20150422150006515.log</location>
<location>/home/andrey/git/x393/vivado_logs/VivadoTimingReportImplemented-20150426202414513.log</location>
</link>
<link>
<name>vivado_logs/VivadoTimingReportSynthesis.log</name>
<type>1</type>
<location>/home/andrey/git/x393/vivado_logs/VivadoTimingReportSynthesis-20150422145717867.log</location>
<location>/home/andrey/git/x393/vivado_logs/VivadoTimingReportSynthesis-20150426202222327.log</location>
</link>
<link>
<name>vivado_state/x393-opt-phys.dcp</name>
<type>1</type>
<location>/home/andrey/git/x393/vivado_state/x393-opt-phys-20150422150006515.dcp</location>
<location>/home/andrey/git/x393/vivado_state/x393-opt-phys-20150426202414513.dcp</location>
</link>
<link>
<name>vivado_state/x393-place.dcp</name>
<type>1</type>
<location>/home/andrey/git/x393/vivado_state/x393-place-20150422150006515.dcp</location>
<location>/home/andrey/git/x393/vivado_state/x393-place-20150426202414513.dcp</location>
</link>
<link>
<name>vivado_state/x393-route.dcp</name>
<type>1</type>
<location>/home/andrey/git/x393/vivado_state/x393-route-20150422150006515.dcp</location>
<location>/home/andrey/git/x393/vivado_state/x393-route-20150426202414513.dcp</location>
</link>
<link>
<name>vivado_state/x393-synth.dcp</name>
<type>1</type>
<location>/home/andrey/git/x393/vivado_state/x393-synth-20150422145717867.dcp</location>
<location>/home/andrey/git/x393/vivado_state/x393-synth-20150426202222327.dcp</location>
</link>
</linkedResources>
</projectDescription>
/*******************************************************************************
* Module: membridge
* Date:2015-04-26
* Author: andrey
* Description: bi-directional bridge between system and video memory over axi_hp
*
* Copyright (c) 2015 <set up in Preferences-Verilog/VHDL Editor-Templates> .
* membridge.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.
*
* membridge.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 membridge#(
parameter MEMBRIDGE_ADDR= 'h200,
parameter MEMBRIDGE_MASK= 'h3f0,
parameter MEMBRIDGE_CTRL= 'h0, // bit 0 - enable, bits[2:1]: 01 - start, 11 - start and reset address
parameter MEMBRIDGE_STATUS_CNTRL= 'h1,
parameter MEMBRIDGE_LO_ADDR64= 'h2, // low address of the system memory, in 64-bit words (<<3 to get byte address)
parameter MEMBRIDGE_SIZE64= 'h3, // size of the system memory range (access will roll over to lo_addr
parameter MEMBRIDGE_START64= 'h4, // start address relative to lo_addr
parameter MEMBRIDGE_LEN64= 'h5, // full length of transfer in 64-bit words
parameter MEMBRIDGE_WIDTH64= 'h6, // frame width in 64-bit words (partial last page in each line)
parameter MEMBRIDGE_STATUS_REG= 'h3b,
parameter FRAME_HEIGHT_BITS= 16, // Maximal frame height bits
parameter FRAME_WIDTH_BITS= 13
// ,parameter MCNTRL_SCANLINE_FRAME_PAGE_RESET= 1'b0 // reset internal page number to zero at the frame start (false - only when hard/soft reset)
)(
input rst,
input mclk, // for command/status
input hclk, // global clock to run axi_hp @ 150MHz
// programming interface
input [7:0] cmd_ad, // byte-serial command address/data (up to 6 bytes: AL-AH-D0-D1-D2-D3
input cmd_stb, // strobe (with first byte) for the command a/d
output [7:0] status_ad, // status address/data - up to 5 bytes: A - {seq,status[1:0]} - status[2:9] - status[10:17] - status[18:25]
output status_rq, // input request to send status downstream
input status_start, // Acknowledge of the first status packet byte (address)
// mcntrl_linear_rw.v interface
output frame_start_chn, // input
output next_page_chn, // input
input cmd_wrmem, //
input page_ready_chn, // output single mclk
input frame_done_chn, // output single mclk
input [FRAME_HEIGHT_BITS-1:0] line_unfinished_chn1, // output[15:0] @SuppressThisWarning VEditor unused (yet)
output suspend_chn1, // input @SuppressThisWarning VEditor unused (yet)
// buffer interface, DDR3 memory read
input xfer_reset_page_rd, // input
input buf_wpage_nxt, // input
input buf_wr, // input
input [63:0] buf_wdata,
// buffer interface, DDR3 memory write
input xfer_reset_page_wr, // input @ posedge mclk
input buf_rpage_nxt,
input buf_rd,
output [63:0] buf_rdata,
// axi_hp signals write channel
// write address
output [31:0] afi_awaddr,
output afi_awvalid,
input afi_awready, // @SuppressThisWarning VEditor unused - used FIF0 level
output [ 5:0] afi_awid,
output [ 1:0] afi_awlock,
output [ 3:0] afi_awcache,
output [ 2:0] afi_awprot,
output [ 3:0] afi_awlen,
output [ 2:0] afi_awsize,
output [ 1:0] afi_awburst,
output [ 3:0] afi_awqos,
// write data
output [63:0] afi_wdata,
output afi_wvalid,
input afi_wready, // @SuppressThisWarning VEditor unused - used FIF0 level
output [ 5:0] afi_wid,
output afi_wlast,
output [ 7:0] afi_wstrb,
// write response
input afi_bvalid,
output afi_bready,
input [ 5:0] afi_bid, // @SuppressThisWarning VEditor unused
input [ 1:0] afi_bresp, // @SuppressThisWarning VEditor unused
// PL extra (non-AXI) signals
input [ 7:0] afi_wcount,
input [ 5:0] afi_wacount,
output afi_wrissuecap1en,
// AXI_HP signals - read channel
// read address
output [31:0] afi_araddr,
output afi_arvalid,
input afi_arready, // @SuppressThisWarning VEditor unused - used FIF0 level
output [ 5:0] afi_arid,
output [ 1:0] afi_arlock,
output [ 3:0] afi_arcache,
output [ 2:0] afi_arprot,
output [ 3:0] afi_arlen,
output [ 2:0] afi_arsize,
output [ 1:0] afi_arburst,
output [ 3:0] afi_arqos,
// read data
input [63:0] afi_rdata,
input afi_rvalid,
output afi_rready,
input [ 5:0] afi_rid, // @SuppressThisWarning VEditor unused
input afi_rlast, // @SuppressThisWarning VEditor unused
input [ 2:0] afi_rresp, // @SuppressThisWarning VEditor unused
// PL extra (non-AXI) signals
input [ 7:0] afi_rcount,
input [ 2:0] afi_racount,
output afi_rdissuecap1en
);
// Some constant signals:
assign afi_awlock = 2'h0;
assign afi_awcache = 4'h3;
assign afi_awprot = 3'h0;
assign afi_awsize = 3'h3;
assign afi_awburst = 2'h1;
assign afi_awqos = 4'h0;
assign afi_wstrb = 8'hff;
assign afi_wrissuecap1en = 1'b0;
assign afi_arlock = 2'h0;
assign afi_arcache = 4'h3;
assign afi_arprot = 3'h0;
assign afi_arsize = 3'h3;
assign afi_arburst = 2'h1;
assign afi_arqos = 4'h0;
assign afi_rdissuecap1en = 1'b0;
assign frame_start_chn=start_mclk;
wire [ 3:0] cmd_a; // control register address
wire [31:0] cmd_data; // register data
wire cmd_we; // register write
wire set_ctrl_w;
wire set_status_w;
wire set_lo_addr64_w;
wire set_size64_w;
wire set_start64_w;
wire set_len64_w;
wire set_width64_w;
assign set_ctrl_w = cmd_we && (cmd_a== MEMBRIDGE_CTRL);
assign set_lo_addr64_w = cmd_we && (cmd_a== MEMBRIDGE_LO_ADDR64);
assign set_size64_w = cmd_we && (cmd_a== MEMBRIDGE_SIZE64);
assign set_start64_w = cmd_we && (cmd_a== MEMBRIDGE_START64);
assign set_len64_w = cmd_we && (cmd_a== MEMBRIDGE_LEN64);
assign set_width64_w = cmd_we && (cmd_a== MEMBRIDGE_WIDTH64);
assign set_status_w = cmd_we && (cmd_a== MEMBRIDGE_STATUS_CNTRL);
reg [28:0] lo_addr64_mclk;
reg [28:0] size64_mclk;
reg [28:0] start64_mclk;
reg [28:0] len64_mclk;
reg [FRAME_WIDTH_BITS+1:0] width64_mclk; // FRAME_WIDTH_BITS in 128 bit bursts
reg rdwr_en_mclk;
reg rdwr_reset_addr_mclk; // resets system memory address
reg start_mclk;
//cmd_wrmem
always @ (posedge mclk) begin
if (set_lo_addr64_w) lo_addr64_mclk <= {cmd_data[28:4],4'b0}; // align to 16-bursts
if (set_size64_w) size64_mclk <= {cmd_data[28:4],4'b0}; // align to 16-bursts
if (set_lo_addr64_w) start64_mclk <= 0;
else if (set_start64_w) start64_mclk <= {cmd_data[28:4],4'b0}; // align to 16-bursts
if (set_len64_w) len64_mclk <= cmd_data[28:0]; // OK not to be aligned
if (set_width64_w) width64_mclk <= {~(|cmd_data[FRAME_WIDTH_BITS:0]),cmd_data[FRAME_WIDTH_BITS:0]}; // OK not to be aligned
if (set_ctrl_w) rdwr_reset_addr_mclk <= cmd_data[1] && !cmd_data[2];
end
always @ (posedge mclk or posedge rst) begin
if (rst) rdwr_en_mclk <= 0;
else if (set_ctrl_w) rdwr_en_mclk <= cmd_data[0];
if (rst) start_mclk <= 0;
else start_mclk <= set_ctrl_w & cmd_data[1];
end
// syncronize mclk ->hclk
reg [28:0] lo_addr64;
reg [28:0] size64;
reg [28:0] start64;
reg [28:0] len64;
reg [FRAME_WIDTH_BITS:0] last_in_line64;
reg [24:0] last_addr1k; // last adress before rollover w/o 4 LSB
reg rdwr_en; // TODO: Use it?
reg rdwr_reset_addr; // resets system memory address
wire start_hclk;
reg rd_start;
reg wr_start;
reg [2:0] rdwr_start;
reg wr_mode;
wire page_ready; // @ posedge hclk
wire frame_done; // @ posedge hclk
//next_page_chn
wire reset_page_wr; // @ posedge hclk (from @ posedge mclk)
wire reset_page_rd; // @ posedge hclk (from @ negedge mclk)
reg page_ready_rd;
reg page_ready_wr;
reg next_page_rd;
reg next_page_wr;
wire next_page; // @ posedge hclk - source
wire busy_next_page; // do not send next_page -previous is crossing clock boundaries
assign next_page= next_page_wr | next_page_rd;
// incrementing IDs for read (MSB==0) and write (MSB==1)
reg [4:0] rd_id;
reg [4:0] wr_id;
assign afi_arid={1'b1,rd_id};
assign afi_awid={1'b1,wr_id};
assign afi_wid= {1'b1,wr_id};
always @ (posedge hclk) begin
lo_addr64 <= lo_addr64_mclk;
size64 <= size64_mclk;
start64 <= start64_mclk;
len64 <= len64_mclk;
// width64 <= width64_mclk;
last_in_line64 <= width64_mclk[FRAME_WIDTH_BITS:0]-1;
wr_mode <= cmd_wrmem;
rdwr_reset_addr <= rdwr_reset_addr_mclk;
last_addr1k <= size64[28:4] - 1;
end
always @ (posedge hclk or posedge rst) begin
if (rst) rdwr_en <= 0;
else rdwr_en <= rdwr_en_mclk;
if (rst) rdwr_start <= 0;
else rdwr_start <= {rdwr_start[1:0],start_hclk};
if (rst) rd_start <= 0;
else rd_start <= rdwr_start[2] && !wr_mode; // later to enable adders+ to propagate
if (rst) wr_start <= 0;
else wr_start <= rdwr_start[2] && wr_mode;
page_ready_rd <= page_ready && !wr_mode;
if (rst) rd_id <= 0;
else if (rd_start) rd_id <= rd_id +1;
if (rst) wr_id <= 0;
else if (wr_start) wr_id <= wr_id +1;
end
// mclk -> hclk
pulse_cross_clock start_i (.rst(rst), .src_clk(mclk), .dst_clk(hclk), .in_pulse(start_mclk), .out_pulse(start_hclk),.busy());
pulse_cross_clock page_ready_i (.rst(rst), .src_clk(mclk), .dst_clk(hclk), .in_pulse(page_ready_chn), .out_pulse(page_ready),.busy());
pulse_cross_clock frame_done_i (.rst(rst), .src_clk(mclk), .dst_clk(hclk), .in_pulse(frame_done_chn), .out_pulse(frame_done),.busy());
pulse_cross_clock reset_page_wr_i (.rst(rst), .src_clk(mclk), .dst_clk(hclk), .in_pulse(xfer_reset_page_wr), .out_pulse(reset_page_wr),.busy());
// negedge mclk -> hclk (verify clock inversion is absorbed)
pulse_cross_clock reset_page_rd_i (.rst(rst), .src_clk(~mclk),.dst_clk(hclk), .in_pulse(xfer_reset_page_rd), .out_pulse(reset_page_rd),.busy());
// hclk -> mclk
pulse_cross_clock next_page_i (.rst(rst), .src_clk(hclk), .dst_clk(mclk), .in_pulse(next_page), .out_pulse(next_page_chn),.busy(busy_next_page));
// Common to both directions
localparam DELAY_ADVANCE_ADDR=4;
reg [28:0] rel_addr64; // realtive (to lo_addr) address
wire advance_rel_addr_w;
wire advance_rel_addr_wr;
wire advance_rel_addr_rd;
reg advance_rel_addr;
reg [DELAY_ADVANCE_ADDR-1:0] advance_rel_addr_d;
reg [28:0] left64;
reg last_burst;
reg rollover;
reg [ 3:0] afi_len;
reg [ 4:0] afi_len_plus1;
reg low4_zero;
reg [28:0] buf_left64; // number of 64-bit words yet to be read from the DDR3 (or written to it)
reg [FRAME_WIDTH_BITS:0] buf_in_line64; // number of last 64-bit words in line
//last_addr1k
assign afi_awlen = afi_len;
assign afi_arlen = afi_len;
reg [28:0] axi_addr64;
wire left_zero;
assign afi_awaddr={axi_addr64,3'b0};
assign afi_araddr={axi_addr64,3'b0};
assign left_zero = low4_zero && last_burst;
always @ (posedge hclk or posedge rst) begin
if (rst) advance_rel_addr_d <= 0;
else if (advance_rel_addr_w) advance_rel_addr_d <= {DELAY_ADVANCE_ADDR{1'b1}};
else advance_rel_addr_d <= advance_rel_addr_d << 1;
end
reg read_started;
reg write_busy;
wire rw_in_progress;
reg busy;
reg done;
assign rw_in_progress = read_started || write_busy;
always @ (posedge hclk) begin
advance_rel_addr <= advance_rel_addr_w && !advance_rel_addr_d[DELAY_ADVANCE_ADDR-1]; // make sure advance_rel_addr_w is recalculated after address change
last_burst <= ! (|left64[28:4]);
rollover <= rel_addr64[28:4] == last_addr1k;
low4_zero <= ! (|left64[3:0]);
if (rdwr_start[0] && rdwr_reset_addr) rel_addr64 <= start64;
else if (advance_rel_addr) rel_addr64 <= last_burst?(rel_addr64 + left64[3:0]) : (rollover?29'h0:(rel_addr64 + 4'h10));
axi_addr64 <= lo_addr64 + rel_addr64;
if (rdwr_start) left64 <= len64;
else if (advance_rel_addr) left64 <= last_burst? 0: (left64 - 4'h10);
afi_len <= (|left64[28:4])?4'hf : (left64[3:0]-1);
afi_len_plus1 <= (|left64[28:4]) ? 5'h10 : {1'b0,left64[3:0]};
page_ready_rd <= page_ready && !wr_mode;
page_ready_wr <= page_ready && wr_mode;
if (!rw_in_progress) buf_left64 <= len64;
else if (buf_rdwr) buf_left64 <= buf_left64 - 1;
if (!rw_in_progress) buf_in_line64 <= 0;
else if (buf_rdwr) buf_in_line64 <= is_last_in_line? {(FRAME_WIDTH_BITS+1){1'b0}} : (buf_in_line64 +1);
next_page_rd <= next_page_rd_w;
next_page_wr <= next_page_wr_w;
end
// DDR3 read - AFI write
//rdwr_en
reg [7:0] wresp_pending; // count not-yet-confirmed afi writes
reg read_busy;
reg read_over;
reg afi_bvalid_r;
reg [1:0] read_page;
// reg [6:0] read_addr;
reg [2:0] read_pages_ready;
assign afi_bready = 1'b1; // always ready to receive confirmation
reg afi_wd_safe_not_full;
reg afi_wa_safe_not_full;
assign advance_rel_addr_w = advance_rel_addr_wr || advance_rel_addr_rd;
assign advance_rel_addr_wr = read_started && afi_wa_safe_not_full && (|left64); // left 64 is decremented by 16, except possibly the last (partial)
assign afi_awvalid=advance_rel_addr && read_started;
always @ (posedge hclk or posedge rst) begin
if (rst) read_busy <= 0;
else if (rd_start) read_busy <= 1;
else if (read_over) read_busy <= 0;
if (rst) read_started <= 0;
else if (!read_busy) read_started <= 0;
else if (page_ready) read_started <= 1; // first page is in the buffer - use it to mask page number comparison
if (rst) wresp_pending <= 0;
else if (!read_busy) wresp_pending <= 0;
else if ( afi_wvalid && !afi_bvalid_r) wresp_pending <= wresp_pending +1;
else if (!afi_wvalid && afi_bvalid_r) wresp_pending <= wresp_pending -1;
read_over <= left_zero && (wresp_pending == 0);
if (rst) read_page <= 0;
else if (reset_page_rd) read_page <= 0;
else if (next_page_rd_w) read_page <= read_page + 1;
if (rst) read_pages_ready <= 0;
else if (!read_busy) read_pages_ready <= 0;
else if ( page_ready_rd && !next_page_rd_w) read_pages_ready <= read_pages_ready +1;
else if (!page_ready_rd && next_page_rd_w) read_pages_ready <= read_pages_ready -1;
if (rst) afi_wd_safe_not_full <= 0;
else afi_wd_safe_not_full <= rdwr_en && (!afi_wcount[7] && !(&afi_wcount[6:3]));
if (rst) afi_wa_safe_not_full <= 0;
else afi_wa_safe_not_full <= rdwr_en && (!afi_wacount[5] && !(&afi_wacount[4:2]));
if (rst) busy <= 0;
else busy <= read_busy || write_busy;
if (rst) done <= 0;
else if (!rdwr_en) done <= 0; // disabling when idle will reset done
else if ((write_busy && frame_done) || (read_busy && read_over)) done <= 1;
end
always @ (posedge hclk) begin
afi_bvalid_r <=afi_bvalid;
end
// handle interaction with the buffer, advance addresses, keep track of partial (last) pages in each line
wire bufrd_rd_w;
wire bufwr_we_w; // TODO: assign
reg [2:0] bufrd_rd;
reg [1:0] bufwr_we;
reg buf_rdwr; // equiv to bufrd_rd[0] || bufwr_we)
wire is_last_in_line;
wire is_last_in_page;
wire next_page_rd_w;
wire next_page_wr_w;
assign next_page_rd_w = read_started && !busy_next_page && is_last_in_page && bufrd_rd[0];
assign is_last_in_line = buf_in_line64 == last_in_line64;
assign is_last_in_page = is_last_in_line || (&buf_in_line64[6:0]);
assign bufrd_rd_w = afi_wd_safe_not_full && (|read_pages_ready[2:1] || (read_pages_ready[0] && !is_last_in_page));
//last_in_line64 - last word number in scan line
reg left_was_1; // was 1 or 0 (0 does not matter)
reg [3:0] src_wcntr;
reg [1:0] wlast_in_burst;
assign afi_wlast = wlast_in_burst[1];
always @ (posedge hclk) begin
if (!rw_in_progress) left_was_1 <= 0;
else if (buf_rdwr) left_was_1 <= !(|buf_left64[28:1]);
if (!read_started) src_wcntr <= 0;
else if (bufrd_rd[0]) src_wcntr <= src_wcntr+1;
if (!read_started) wlast_in_burst <= 0;
else if (bufrd_rd[0]) wlast_in_burst <= {wlast_in_burst[0],left_was_1 | (&src_wcntr)};
bufrd_rd <= {bufrd_rd[1:0], bufrd_rd_w };
buf_rdwr <= bufrd_rd_w || bufwr_we_w;
bufwr_we <= {bufwr_we[0],bufwr_we_w};
end
assign afi_wvalid=bufrd_rd[2];
// write to ddr3 from afi
wire [7:0] axi_rd_pending;
reg [7:0] axi_rd_requested;
reg [7:0] axi_rd_received;
// wire axi_rd_data; // assign
assign axi_rd_pending= axi_rd_requested - axi_rd_received;
// wire some_read_ready;
reg afi_rd_safe_not_empty;
reg afi_ra_safe_not_full;
reg afi_safe_rd_pending;
// assign advance_rel_addr_wr = read_started && afi_wa_safe_not_full && (|left64); // left 64 is decremented by 16, except possibly the last (partial)
assign advance_rel_addr_rd = write_busy && afi_ra_safe_not_full && afi_safe_rd_pending && (|left64);
assign afi_arvalid=advance_rel_addr && write_busy;
assign next_page_wr_w = write_busy && !busy_next_page && is_last_in_page && bufwr_we[0];
assign bufwr_we_w= afi_rd_safe_not_empty && !write_pages_ready[2] && (!(&write_pages_ready[1:0]) || !is_last_in_page);
//afi_len_plus1
// handle buffer address, page
reg [1:0] write_page; // current number of buffer page
reg [2:0] write_pages_ready; // number of pages in the buffer
reg [1:0] write_page_r; // 1-cycle delayed page address
reg [6:0] buf_in_line64_r; // 1-cycle delayed buffer address
assign afi_rready = bufwr_we[0];
always @ (posedge hclk or posedge rst) begin
if (rst) write_busy <= 0;
else if (wr_start) write_busy <= 1;
else if (frame_done) write_busy <= 0;
if (rst) axi_rd_requested <= 0;
else if (!write_busy) axi_rd_requested <= 0;
else if (advance_rel_addr) axi_rd_requested <= axi_rd_requested + afi_len_plus1;
if (rst) axi_rd_received <= 0;
else if (!write_busy) axi_rd_received <= 0;
else if (bufwr_we[0]) axi_rd_received <= axi_rd_received + 1;
if (rst) afi_rd_safe_not_empty <= 0;
// allow 1 cycle latency, no continuous reads when FIFO is low (like in the very end of the transfer)
// Adjust '2' in afi_rcount[6:2] ?
else afi_rd_safe_not_empty <= rdwr_en && ( afi_rcount[7] || (|afi_rcount[6:2]) || (!(|bufwr_we) && afi_rvalid));
if (rst) afi_ra_safe_not_full <= 0;
else afi_ra_safe_not_full <= rdwr_en && ( !afi_racount[2] && !(&afi_racount[1:0]));
if (rst) afi_safe_rd_pending <= 0;
else afi_safe_rd_pending <= rdwr_en && ( !axi_rd_pending[7] && !(&axi_rd_pending[6:4]));
// handle buffer address, page
if (rst) write_page <= 0;
else if (reset_page_wr) write_page <= 0;
else if (next_page_wr_w) write_page <= write_page + 1;
if (rst) write_pages_ready <= 0;
else if (!read_busy) write_pages_ready <= 0;
else if ( page_ready_wr && !next_page_wr_w) write_pages_ready <= write_pages_ready -1; //+1;
else if (!page_ready_wr && next_page_wr_w) write_pages_ready <= write_pages_ready +1; //-1;
end
always @ (posedge hclk) begin
write_page_r <= write_page;
buf_in_line64_r <= buf_in_line64[6:0];
end
//{write_page, buf_in_line64[6:0]}
//bufwr_we
cmd_deser #(
.ADDR (MEMBRIDGE_ADDR),
.ADDR_MASK (MEMBRIDGE_MASK),
.NUM_CYCLES (6),
.ADDR_WIDTH (4),
.DATA_WIDTH (32)
) cmd_deser_32bit_i (
.rst (rst), // input
.clk (mclk), // input
.ad (cmd_ad), // input[7:0]
.stb (cmd_stb), // input
.addr (cmd_a), // output[3:0]
.data (cmd_data), // output[31:0]
.we (cmd_we) // output
);
status_generate #(
.STATUS_REG_ADDR (MEMBRIDGE_STATUS_REG),
.PAYLOAD_BITS (2) // ???
) status_generate_i (
.rst (rst), // input
.clk (mclk), // input
.we (set_status_w), // input
.wd (cmd_data[7:0]), // input[7:0]
.status ({busy,done}), // input[25:0]
.ad (status_ad), // output[7:0]
.rq (status_rq), // output
.start (status_start) // input
);
// Port 1rd (read DDR to AFI) buffer, linear
mcntrl_buf_rd #(
.LOG2WIDTH_RD(6) // 64 bit external interface
) chn1rd_buf_i (
.ext_clk (hclk), // input
.ext_raddr ({read_page,buf_in_line64[6:0]}), // input[8:0]
.ext_rd (bufrd_rd[0]), // input
.ext_regen (bufrd_rd[1]), // input
.ext_data_out (afi_wdata), // output[63:0]
.wclk (!mclk), // input
.wpage_in (2'b0), // input[1:0]
.wpage_set (xfer_reset_page_rd), // input TODO: Generate @ negedge mclk on frame start
.page_next (buf_wpage_nxt), // input
.page (), // output[1:0]
.we (buf_wr), // input
.data_in (buf_wdata) // input[63:0]
);
// Port 1wr (write DDR from AFI) buffer, linear
mcntrl_buf_wr #(
.LOG2WIDTH_WR(6) // 64 bit external interface
) chn1wr_buf_i (
.ext_clk (hclk), // input
.ext_waddr ({write_page_r, buf_in_line64_r[6:0]}), // input[8:0]
.ext_we (bufwr_we[1]), // input
.ext_data_in (afi_rdata), // input[63:0] buf_wdata - from AXI
.rclk (mclk), // input
.rpage_in (2'b0), // input[1:0]
.rpage_set (xfer_reset_page_wr), // input @ posedge mclk
.page_next (buf_rpage_nxt), // input
.page (), // output[1:0]
.rd (buf_rd), // input
.data_out (buf_rdata) // output[63:0]
);
endmodule
/*******************************************************************************
* Module: axi_hp_clk
* Date:2015-04-27
* Author: andrey
* Description: Generate global clock for axi_hp
*
* Copyright (c) 2015 <set up in Preferences-Verilog/VHDL Editor-Templates> .
* axi_hp_clk.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.
*
* axi_hp_clk.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 axi_hp_clk#(
parameter CLKIN_PERIOD = 20, //ns >1.25, 600<Fvco<1200
parameter CLKFBOUT_MULT_AXIHP = 18, // Fvco=Fclkin*CLKFBOUT_MULT_F/DIVCLK_DIVIDE, Fout=Fvco/CLKOUT#_DIVIDE
parameter CLKFBOUT_DIV_AXIHP = 6 // To get 150MHz for the reference clock
)(
input rst,
input clk_in,
output clk_axihp,
output locked_axihp
);
wire clkfb_axihp, clk_axihp_pre;
BUFG clk_axihp_i (.O(clk_axihp), .I(clk_axihp_pre));
pll_base #(
.CLKIN_PERIOD(CLKIN_PERIOD), // 20
.BANDWIDTH("OPTIMIZED"),
.CLKFBOUT_MULT(CLKFBOUT_MULT_AXIHP), // 18, // Fvco=Fclkin*CLKFBOUT_MULT_F/DIVCLK_DIVIDE, Fout=Fvco/CLKOUT#_DIVIDE
.CLKOUT0_DIVIDE(CLKFBOUT_DIV_AXIHP), // 6, // To get 300MHz for the reference clock
.REF_JITTER1(0.010),
.STARTUP_WAIT("FALSE")
) pll_base_i (
.clkin(clk_in), // input
.clkfbin(clkfb_axihp), // input
// .rst(rst), // input
.rst(rst), // input
.pwrdwn(1'b0), // input
.clkout0(clk_axihp_pre), // output
.clkout1(), // output
.clkout2(), // output
.clkout3(), // output
.clkout4(), // output
.clkout5(), // output
.clkfbout(clkfb_axihp), // output
.locked(locked_axihp) // output
);
endmodule
......@@ -163,7 +163,7 @@
parameter NUM_CYCLES_05 = 6, // 6-cycle 140.017f
parameter NUM_CYCLES_06 = 4, // 4-cycle 180.01bf
parameter NUM_CYCLES_07 = 4, // 4-cycle 1c0.01ff
parameter NUM_CYCLES_08 = 6, //
parameter NUM_CYCLES_08 = 6, // 6-cycle 200.023f
parameter NUM_CYCLES_09 = 6, //
parameter NUM_CYCLES_10 = 6, //
parameter NUM_CYCLES_11 = 6, //
......@@ -245,6 +245,20 @@
parameter MCNTRL_TEST01_STATUS_REG_CHN2_ADDR= 'h3d, // status/readback register for channel 3
parameter MCNTRL_TEST01_STATUS_REG_CHN3_ADDR= 'h3e, // status/readback register for channel 4
parameter MCNTRL_TEST01_STATUS_REG_CHN4_ADDR= 'h3f, // status/readback register for channel 4
// membridge module parameters
parameter MEMBRIDGE_ADDR= 'h200,
parameter MEMBRIDGE_MASK= 'h3f0,
parameter MEMBRIDGE_CTRL= 'h0,
parameter MEMBRIDGE_STATUS_CNTRL= 'h1,
parameter MEMBRIDGE_RD_LOADDR64= 'h2,
parameter MEMBRIDGE_RD_RUNADDR64= 'h3,
parameter MEMBRIDGE_RD_LEN64= 'h5,
parameter MEMBRIDGE_WR_LOADDR64= 'h2,
parameter MEMBRIDGE_WR_RUNADDR64= 'h3,
parameter MEMBRIDGE_WR_LEN64= 'h5,
parameter MEMBRIDGE_STATUS_REG= 'h3b,
parameter RSEL= 1'b1, // late/early READ commands (to adjust timing by 1 SDCLK period)
parameter WSEL= 1'b0 // late/early WRITE commands (to adjust timing by 1 SDCLK period)
\ No newline at end of file
......@@ -962,7 +962,8 @@ module mcntrl393 #(
.xfer_partial (lin_rw_chn1_partial), // output
.xfer_done (seq_done1), // input : sequence over
.xfer_page_rst_wr (xfer_reset_page1_wr), // output
.xfer_page_rst_rd (xfer_reset_page1_rd) // output
.xfer_page_rst_rd (xfer_reset_page1_rd), // output
.cmd_wrmem () // output
);
mcntrl_linear_rw #(
......@@ -1009,7 +1010,8 @@ module mcntrl393 #(
.xfer_partial (lin_rw_chn3_partial), // output
.xfer_done (seq_done3), // input : sequence over
.xfer_page_rst_wr (xfer_reset_page3_wr), // output
.xfer_page_rst_rd (xfer_reset_page3_rd) // output
.xfer_page_rst_rd (xfer_reset_page3_rd), // output
.cmd_wrmem () // output
);
mcntrl_tiled_rw #(
......
......@@ -77,7 +77,8 @@ module mcntrl_linear_rw #(
output xfer_partial, // partial tile (first of 2) , sequencer will not generate page_next at the end of block
input xfer_done, // transfer to/from the buffer finished
output xfer_page_rst_wr, // reset buffer internal page - at each frame start or when specifically reset (write to memory channel), @posedge
output xfer_page_rst_rd // reset buffer internal page - at each frame start or when specifically reset (read memory channel), @negedge
output xfer_page_rst_rd, // reset buffer internal page - at each frame start or when specifically reset (read memory channel), @negedge
output cmd_wrmem
);
localparam NUM_RC_BURST_BITS=ADDRESS_NUMBER+COLADDR_NUMBER-3; //to spcify row and col8 == 22
localparam MPY_WIDTH= NUM_RC_BURST_BITS; // 22
......@@ -129,7 +130,7 @@ module mcntrl_linear_rw #(
reg [2:0] page_cntr;
wire cmd_wrmem; //=MCNTRL_SCANLINE_WRITE_MODE; // 0: read from memory, 1:write to memory
// wire cmd_wrmem; //=MCNTRL_SCANLINE_WRITE_MODE; // 0: read from memory, 1:write to memory
wire [1:0] cmd_extra_pages; // external module needs more than 1 page
reg busy_r;
reg want_r;
......@@ -247,7 +248,7 @@ module mcntrl_linear_rw #(
assign xfer_row= row_col_r[NUM_RC_BURST_BITS-1:COLADDR_NUMBER-3] ; // memory row
assign xfer_col= row_col_r[COLADDR_NUMBER-4:0]; // start memory column in 8-bursts
assign line_unfinished=line_unfinished_r[1];
assign chn_en = &mode_reg[1:0]; // enable requests by channle (continue ones in progress)
assign chn_en = &mode_reg[1:0]; // enable requests by channel (continue ones in progress)
assign chn_rst = ~mode_reg[0]; // resets command, including fifo;
assign cmd_wrmem = mode_reg[2];// 0: read from memory, 1:write to memory
assign cmd_extra_pages = mode_reg[4:3]; // external module needs more than 1 page
......
/*******************************************************************************
* Module: pulse_cross_clock
* Date:2015-04-27
* Author: andrey
* Description: Propagate a single pulse through clock domain boundary
*
* Copyright (c) 2015 <set up in Preferences-Verilog/VHDL Editor-Templates> .
* pulse_cross_clock.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.
*
* pulse_cross_clock.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 pulse_cross_clock(
input rst,
input src_clk,
input dst_clk,
input in_pulse, // single-cycle positive pulse
output out_pulse,
output busy
);
reg in_reg;
reg [2:0] out_reg;
assign out_pulse=out_reg[2];
assign busy=in_reg;
always @(posedge src_clk or posedge rst) begin
if (rst) in_reg <= 0;
else in_reg <= in_pulse || (in_reg && !out_reg[1]);
end
always @(posedge dst_clk or posedge rst) begin
if (rst) out_reg <= 0;
else out_reg <= {out_reg[0] & ~out_reg[1],out_reg[0],in_reg};
end
endmodule
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