Commit 8b1599eb authored by Andrey Filippov's avatar Andrey Filippov

Working on compressors interaction with external memory buffer

parent 72dc592d
......@@ -49,7 +49,7 @@ module membridge#(
// mcntrl_linear_rw.v interface
output frame_start_chn, // input
output next_page_chn, // input
input cmd_wrmem, //
input cmd_wrmem, // @mclk - writing to DDR3 mode (0 - reading from DDR3)
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)
......
/*******************************************************************************
* Module: cmprs_macroblock_buf_iface
* Date:2015-06-11
* Author: andrey
* Description: Communicates with compressor memory buffer, generates pixel
* stream matching selected color mode, accommodates for the buffer latency,
* acts as a pacemaker for the whole compressor (next stages are able to keep up).
*
* Copyright (c) 2015 <set up in Preferences-Verilog/VHDL Editor-Templates> .
* cmprs_macroblock_buf_iface.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.
*
* cmprs_macroblock_buf_iface.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 cmprs_macroblock_buf_iface #(
)(
input rst,
input xclk, // global clock input, compressor single clock rate
input mclk, // global clock for commands (posedge) and write side of the memory buffer (negedge)
// buffer interface, DDR3 memory read
input xfer_reset_page_rd, // @ negedge mclk - reset ddr3 memory buffer. Use it to reset the read buffer too
input page_ready_chn, // single mclk (posedge)
output next_page_chn, // single mclk (posedge): Done with the page in the buffer, memory controller may read more data
input frame_en, // if 0 - will reset logic immediately (but not page number)
input frame_go, // start frame: if idle, will start reading data (if available),
// if running - will not restart a new frame if 0.
input [ 4:0] left_marg, // left margin (for not-yet-implemented) mono JPEG (8 lines tile row) can need 7 bits (mod 32 - tile)
input [12:0] n_blocks_in_row_m1, // number of macroblocks in a macroblock row minus 1
input [12:0] n_block_rows_m1, // number of macroblock rows in a frame minus 1
input [ 5:0] mb_w_m1, // macroblock width minus 1 // 3 LSB not used
input [ 4:0] mb_hper, // macroblock horizontal period (8/16) // 3 LSB not used
input [ 1:0] tile_width, // memory tile width (can be 128 for monochrome JPEG) Can be 32/64/128: 0 - 16, 1 - 32, 2 - 64, 3 - 128
input mb_pre_end_in, // from cmprs_pixel_buf_iface - just in time to start a new macroblock w/o gaps
input mb_release_buf, // send required "next_page" pulses to buffer. Having rather long minimal latency in the memory
// controller this can just be the same as mb_pre_end_in
output mb_pre_start_out, // 1 clock cycle before stream of addresses to the buffer
output [ 1:0] start_page, // page to read next tile from (or first of several pages)
output [ 6:0] macroblock_x // macroblock left pixel x relative to a tile (page) Maximal page - 128 bytes wide
);
wire reset_page_rd;
wire page_ready;
wire frame_en_w;
reg frame_en_r;
reg [12:0] mb_cols_left; // number of a macroblocks left in a row (after this)
reg [12:0] mb_rows_left; // number of a rows left in a row (after this)
wire [ 6:0] mbl_x; // macroblock left pixel x relative to a tile (page) Maximal page - 128 bytes wide
reg [ 6:3] mbl_x_r; // macroblock left pixel x relative to a tile (page) (3 low don't change)
reg [ 6:3] mbl_x_next_r; // macroblock left pixel x relative to a tile (page), not valid for first column (3 low don't change)
reg [ 7:3] mbl_x_inc_r; // intermediate register for calculating mbl_x_next_r and add_invalid
reg [ 7:3] mbl_x_last_r; // intermediate register for calculating needed_page
reg [1:0] pre_advance_tiles; // advance tiles by this for same row of macroblocks
wire mb_pre_start_w; // start sequence for a macroblock
wire frame_pre_start_w; // start sequence for a new frame
reg frame_pre_start_r;
reg [ 8:0] mb_pre_start; // 1-hot macroblock pre start calcualtions - TODO: adjust width
wire [ 2:0] buf_diff; // difference between page needed and next valid - should be negative to have it ready
wire buf_ready_w; // External memory buffer has all the pages needed
reg mb_first_in_row;
reg mb_last_in_row;
reg mb_last_row;
wire mb_last;
reg [ 2:0] next_valid; // number of next valid page (only 2 LSB are actual page number)
reg [ 2:0] next_invalid; // oldest valid page
reg [ 1:0] add_invalid; // advance next_invalid pointer by this value, send next_page pulses
reg [ 2:0] used_pages; // number of pages simultaneously used for the last macroblock
reg [ 2:0] needed_page; // calculate at MB start
wire starting;
reg frame_pre_run;
assign frame_en_w = frame_en && frame_go;
assign mbl_x={mbl_x_r[6:3], left_marg[2:0]};
assign buf_diff = needed_page - next_valid;
assign buf_ready_w = buf_diff[2];
assign mb_pre_start_out=mb_pre_start[5]; // first after wait?
assign macroblock_x = mbl_x;
assign mb_last = mb_last_row && mb_last_in_row;
assign starting = |mb_pre_start;
assign mb_pre_start_w = (mb_pre_end_in && (!mb_last || frame_en_w)) || (!frame_pre_run && frame_en_w && !frame_en_r && !starting);
assign frame_pre_start_w = frame_en_w && ((mb_pre_end_in && mb_last) || (!frame_pre_run && !frame_en_r && !starting));
assign start_page = next_invalid[1:0]; // oldest page needed for this macroblock
always @ (posedge xclk) begin
if (!frame_en) frame_en_r <= 0;
else frame_en_r <= frame_en_w;
frame_pre_start_r <= frame_pre_start_w; // same time as mb_pre_start
if (!frame_en) mb_first_in_row <= 0;
else if (frame_pre_start_r) mb_first_in_row <= 1;
else if (mb_pre_start[0]) mb_first_in_row <= mb_last_in_row;
if (!frame_en) frame_pre_run <= 0;
else if (mb_pre_start_w) frame_pre_run <= 1;
else if (mb_pre_end_in && mb_last) frame_pre_run <= 0;
if (frame_pre_start_r) mb_rows_left <= n_block_rows_m1;
else if (mb_pre_start[0] && mb_last_in_row) mb_rows_left <= mb_rows_left - 1;
if (frame_pre_start_r || (mb_pre_start[0] && mb_last_in_row)) mb_cols_left <= n_blocks_in_row_m1;
else if (mb_pre_start[0]) mb_cols_left <= mb_cols_left - 1;
if (mb_pre_start[1]) mb_last_row <= (mb_rows_left == 0);
if (mb_pre_start[1]) mb_last_in_row <= (mb_cols_left == 0);
// pages read from the external memory, previous one is the last in the buffer
if (reset_page_rd) next_valid <= 0;
else if (page_ready) next_valid <= next_valid + 1;
// calculate before starting each macroblock (will wait if buffer is not ready) (TODO: align mb_pre_start[0] to mb_pre_end[2] - same)
//mb_pre_start_w
if (mb_pre_start_w) mb_pre_start <= 1;
else if (!mb_pre_start[4] || buf_ready_w) mb_pre_start <= mb_pre_start << 1;
if (mb_pre_start[1]) mbl_x_r[6:3] <= mb_first_in_row? {2'b0,left_marg[4:3]} : mbl_x_next_r[6:3];
if (mb_pre_start[2]) mbl_x_last_r[7:3] <= {1'b0,mbl_x_r[6:3]} + {2'b0,mb_w_m1[5:3]};
if (mb_pre_start[3]) begin
case (tile_width)
2'b00: needed_page[2:0] <= next_invalid[2:0]+{1'b0, mbl_x_last_r[5:4]};
2'b01: needed_page[2:0] <= next_invalid[2:0]+{1'b0, mbl_x_last_r[6:5]};
2'b10: needed_page[2:0] <= next_invalid[2:0]+{1'b0, mbl_x_last_r[7:6]};
2'b11: needed_page[2:0] <= next_invalid[2:0]+{2'b0, mbl_x_last_r[7]};
endcase
end
// at the end of each macroblock - calculate start page increment (and after delay - advance invalidate_next)
// changed to after started:
// calculate next start X in page (regardless of emd of macroblock row - selection will be at macroblock start)
if (mb_pre_start[5]) mbl_x_inc_r[7:3] <= {1'b0,mbl_x_r[6:3]} + {3'b0,mb_hper[4:3]};
if (mb_pre_start[6]) begin
case (tile_width)
2'b00: begin
mbl_x_next_r[6:3] <= {3'b0,mbl_x_inc_r[3]};
pre_advance_tiles[1:0] <= mbl_x_inc_r[5:4];
end
2'b01: begin
mbl_x_next_r[6:3] <= {2'b0,mbl_x_inc_r[4:3]};
pre_advance_tiles[1:0] <= mbl_x_inc_r[6:5];
end
2'b10: begin
mbl_x_next_r[6:3] <= {1'b0,mbl_x_inc_r[5:3]};
pre_advance_tiles[1:0] <= mbl_x_inc_r[7:6];
end
2'b11: begin
mbl_x_next_r[6:3] <= { mbl_x_inc_r[6:3]};
pre_advance_tiles[1:0] <= {1'b0, mbl_x_inc_r[7]};
end
endcase
used_pages <= needed_page - next_invalid +1;
end
if (mb_pre_start[7]) begin // TODO: apply after delay, regardless last or not
if (mb_last_in_row) add_invalid <= used_pages[1:0];
else add_invalid <= pre_advance_tiles;
end
// pages already processed by compressor - they can be reused for reading new tiles
if (reset_page_rd) next_invalid <= 0;
else if (mb_pre_start[8]) next_invalid <= next_invalid + {1'b0, add_invalid}; // TODO: Send next_page after delay
// "next_page_ pulses will be sent near the end of the macroblock
end
// synchronization between mclk and xclk clock domains
// negedge mclk -> xclk (verify clock inversion is absorbed)
pulse_cross_clock reset_page_rd_i (.rst(rst), .src_clk(~mclk),.dst_clk(xclk), .in_pulse(xfer_reset_page_rd), .out_pulse(reset_page_rd),.busy());
// mclk -> xclk
pulse_cross_clock page_ready_i (.rst(rst), .src_clk(mclk), .dst_clk(xclk), .in_pulse(page_ready_chn), .out_pulse(page_ready),.busy());
multipulse_cross_clock #(
.WIDTH(3),
.EXTRA_DLY(0)
) multipulse_cross_clock_i (
.rst (rst), // input
.src_clk (xclk), // input
.dst_clk (mclk), // input
.num_pulses ({1'b0,add_invalid}), // input[0:0]
.we (mb_release_buf), // input
.out_pulse (next_page_chn), // output
.busy () // output
);
endmodule
/*******************************************************************************
* Module: cmprs_pixel_buf_iface
* Date:2015-06-11
* Author: andrey
* Description: Communicates with compressor memory buffer, generates pixel
* stream matching selected color mode, accommodates for the buffer latency,
* acts as a pacemaker for the whole compressor (next stages are able to keep up).
*
* Copyright (c) 2015 <set up in Preferences-Verilog/VHDL Editor-Templates> .
* cmprs_pixel_buf_iface.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.
*
* cmprs_pixel_buf_iface.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 cmprs_pixel_buf_iface #(
parameter CMPRS_BUF_EXTRA_LATENCY = 0 // extra register layers insered between the buffer and this module
)(
input rst,
input xclk, // global clock input, compressor single clock rate
input mclk, // global clock for commands (posedge) and write side of the memory buffer (negedge)
// buffer interface, DDR3 memory read
input xfer_reset_page_rd, // @ negedge mclk - reset ddr3 memory buffer. Use it to reset the read buffer too
input page_ready_chn, // single mclk (posedge)
output next_page_chn, // single mclk (posedge): Done with the page in the buffer, memory controller may read more data
input [ 7:0] buf_di, // data from the buffer
output [11:0] buf_ra, // buffer read address (1 MSB - page number)
output [ 1:0] buf_rd, // buf {regen, re}
input frame_en, // if 0 - will reset logic immediately (but not page number)
input frame_go, // start frame: if idle, will start reading data (if available),
// if running - will not restart a new frame if 0.
input [ 6:0] mode, // TODO: adjust width. Color mode that determins address mapping
input [ 4:0] left_marg, // left margin (for not-yet-implemented) mono JPEG (8 lines tile row) can need 7 bits (mod 32 - tile)
input [12:0] n_blocks_in_row_m1, // number of macroblocks in a macroblock row minus 1
input [12:0] n_block_rows_m1, // number of macroblock rows in a frame minus 1
output [ 7:0] data_out, //
output pre_first_out, // For each macroblock in a frame
output data_valid //
);
localparam CMPRS_MB_DLY=5;
wire buf_re_w;
reg [CMPRS_BUF_EXTRA_LATENCY+2:0] buf_re;
reg [ 7:0] do_r;
wire reset_page_rd;
wire page_ready;
// wire next_page; // @ posedge xclk - source
// wire busy_next_page; // do not send next_page -previous is crossing clock boundaries
wire frame_end_w; // calculated
wire frame_en_w;
reg frame_en_r;
wire pre_frame_start;
wire frame_start;
wire en;
reg pre_en;
reg [11:0] mb_start; // full adderss of the next macroblock start;
reg [11:0] mbr_start; // start address of the next macroblock row
reg [11:0] buf_ra_r; // buffer read address
reg [ 5:0] mb_w_m1; // macroblock width minus 1
reg [ 5:0] mb_h_m1; // macroblock height minus 1
// reg [ 4:0] left_marg; // left margin of the leftmost macroblock column relative to read tiles (aligned to 32 bytes)
reg [ 4:3] mb_hper; // macroblock horizontal period (8/16)
reg [ 1:0] tile_width; // memory tile width (can be 128 for monochrome JPEG) Can be 32/64/128: 0 - 16, 1 - 32, 2 - 64, 3 - 128
reg [12:0] mb_col; // number of a macroblock in a row
reg [12:0] mb_row; // number of a macroblock row
wire [ 6:0] mbl_x; // macroblock left pixel x relative to a tile (page) Maximal page - 128 bytes wide
reg [ 6:3] mbl_x_r; // macroblock left pixel x relative to a tile (page) (3 low don't change)
reg [ 6:3] mbl_x_next_r; // macroblock left pixel x relative to a tile (page), not valid for first column (3 low don't change)
reg [ 7:3] mbl_x_inc_r; // intermediate register for calculating mbl_x_next_r and add_invalid
reg [ 7:3] mbl_x_last_r; // intermediate register for calculating needed_page
wire mb_pre_end_w; // start mb_pre_end sequence
reg [ 3:0] mb_pre_end; // 1-hot macroblock pre end calcualtions
// wire mb_pre_end_done = mb_pre_end[2]; // overlap
reg [1:0] pre_advance_tiles; // advance tiles by this for same row of macroblocks
wire mb_pre_start_w; // same timing as mb_pre_end[1]
reg [ 4:0] mb_pre_start; // 1-hot macroblock pre start calcualtions - TODO: adjust width
wire [ 2:0] buf_diff; // difference between page needed and next valid - should be negative to have it ready
wire buf_ready_w; // External memory buffer has all the pages needed
reg mb_first_in_row;
reg mb_last_in_row;
reg [ 2:0] next_valid; // number of next valid page (only 2 LSB are actual page number)
reg [ 2:0] next_invalid; // oldest valid page
reg [ 1:0] add_invalid; // advance next_invalid pointer by this value, send next_page pulses
reg we_invalid; // advance next_invalid pointer, send next_page pulses
reg [ 2:0] used_pages; // number of pages simultaneously used for the last macroblock
reg [ 2:0] needed_page; // calculate at MB start
// reg [ 1:0] need_pages_m1; // number of tiles needed for macroblock being started minus 1 (0 - just a single macroblock)
assign buf_rd = buf_re[1:0];
assign data_out = do_r;
assign frame_en_w = frame_en && frame_go;
assign pre_frame_start=frame_en_w && (en?frame_end_w:(!frame_en_r));
assign mbl_x={mbl_x_r[6:3], left_marg[2:0]};
assign buf_diff = needed_page - next_valid;
assign buf_ready_w = buf_diff[2];
always @ (posedge xclk) begin
if (!frame_en) frame_en_r <= 0;
else frame_en_r <= frame_en_w;
if (!frame_en) pre_en <= 0;
else if ( frame_end_w || !pre_en) pre_en <= frame_go;
if (!en) buf_re <= 0;
else buf_re <= {buf_re[CMPRS_BUF_EXTRA_LATENCY+1:0],buf_re_w};
if (buf_re[CMPRS_BUF_EXTRA_LATENCY+2]) do_r <= buf_di;
// pages read from the external memory, previous one is the last in the buffer
if (reset_page_rd) next_valid <= 0;
else if (page_ready) next_valid <= next_valid + 1;
// at the end of each macroblock - calculate start page increment (and after delay - advance invalidate_next)
// calculate next start X in page (regardless of emd of macroblock row - selection will be at macroblock start)
if (mb_pre_end_w) mb_pre_end <= 1;
else mb_pre_end <= mb_pre_end << 1;
if (mb_pre_end[0]) mbl_x_inc_r[7:3] <= {1'b0,mbl_x_r[6:3]} + {3'b0,mb_hper[4:3]};
if (mb_pre_end[1]) begin
case (tile_width)
2'b00: begin
mbl_x_next_r[6:3] <= {3'b0,mbl_x_inc_r[3]};
pre_advance_tiles[1:0] <= mbl_x_inc_r[5:4];
end
2'b01: begin
mbl_x_next_r[6:3] <= {2'b0,mbl_x_inc_r[4:3]};
pre_advance_tiles[1:0] <= mbl_x_inc_r[6:5];
end
2'b10: begin
mbl_x_next_r[6:3] <= {1'b0,mbl_x_inc_r[5:3]};
pre_advance_tiles[1:0] <= mbl_x_inc_r[7:6];
end
2'b11: begin
mbl_x_next_r[6:3] <= { mbl_x_inc_r[6:3]};
pre_advance_tiles[1:0] <= {1'b0, mbl_x_inc_r[7]};
end
endcase
used_pages <= needed_page - next_invalid +1;
end
if (mb_pre_end[2]) begin // TODO: apply after delay, regardless last or not
if (mb_last_in_row) add_invalid <= used_pages[1:0];
else add_invalid <= pre_advance_tiles;
end
// pages already processed by compressor - they can be reused for reading new tiles
if (reset_page_rd) next_invalid <= 0;
else if (mb_pre_end[3]) next_invalid <= next_invalid + {1'b0, add_invalid}; // TODO: Send next_page after delay
// calculate before starting each macroblock (will wait if buffer is not ready) (TODO: align mb_pre_start[0] to mb_pre_end[2] - same)
//mb_pre_start_w
if (mb_pre_start_w) mb_pre_start <= 1;
else if (!mb_pre_start[3] || buf_ready_w) mb_pre_start <= mb_pre_start << 1;
if (mb_pre_start[0]) mbl_x_r[6:3] <= mb_first_in_row? {2'b0,left_marg[4:3]} : mbl_x_next_r[6:3];
if (mb_pre_start[1]) mbl_x_last_r[7:3] <= {1'b0,mbl_x_r[6:3]} + {2'b0,mb_w_m1[5:3]};
if (mb_pre_start[2]) begin
case (tile_width)
2'b00: needed_page[2:0] <= next_invalid[2:0]+{1'b0, mbl_x_last_r[5:4]};
2'b01: needed_page[2:0] <= next_invalid[2:0]+{1'b0, mbl_x_last_r[6:5]};
2'b10: needed_page[2:0] <= next_invalid[2:0]+{1'b0, mbl_x_last_r[7:6]};
2'b11: needed_page[2:0] <= next_invalid[2:0]+{2'b0, mbl_x_last_r[7]};
endcase
end
//need_pages_m1[1:0] <= ;
/*
if (mb_pre_end_w) mb_pre_end <= 1;
else mb_pre_end <= mb_pre_end << 1;
reg [ 3:0] mb_pre_start; // 1-hot macroblock pre start calcualtions - TODO: adjust width
wire buf_ready_w; // External memory buffer has all the pages needed
reg mb_first_in_row;
reg [ 2:0] next_valid; // number of next valid page (only 2 LSB are actual page number)
reg [ 2:0] next_invalid; // oldest valid page
reg [ 2:0] needed_page; // calculate at MB start
reg [ 7:3] mbl_x_last_r; // intermediate register for calculating needed_page
reg [ 5:0] mb_w_m1; // macroblock width minus 1
wire [ 6:0] mbl_x; // macroblock left pixel x relative to a tile (page) Maximal page - 128 bytes wide
reg [ 6:3] mbl_x_r; // macroblock left pixel x relative to a tile (page) (3 low don't change)
reg [ 6:3] mbl_x_next_r; // macroblock left pixel x relative to a tile (page), not valid for first column (3 low don't change)
reg [ 1:0] add_invalid; // advance next_invalid pointer by this value, send next_page pulses
reg we_invalid; // advance next_invalid pointer, send next_page pulses
reg [ 4:3] mb_hper; // macroblock horizontal period (8/16)
reg [ 4:0] mb_pre_end; // 1-hot macroblock pre end calcualtions - TODO: adjust width
wire [ 6:0] mbl_x; // macroblock left pixel x relative to a tile (page) Maximal page - 128 bytes wide
reg [ 6:3] mbl_x_r; // macroblock left pixel x relative to a tile (page) (3 low don't change)
reg [ 6:3] mbl_x_next_r; // macroblock left pixel x relative to a tile (page), not valid for first column (3 low don't change)
reg [ 7:3] mbl_x_inc_r; // intermediate register for calculatingm bl_x_next_r and add_invalid
reg [ 4:0] mb_hper; // macroblock horizontal period (8/16)
reg [ 1:0] tile_width; // memory tile width (can be 128 for monochrome JPEG) Can be 32/64/128: 0 - 16, 1 - 32, 2 - 64, 3 - 128
reg mb_first_in_row;
reg mb_last_in_row;
reg [ 1:0] add_invalid; // advance next_invalid pointer by this value, send next_page pulses
reg we_invalid; // advance next_invalid pointer, send next_page pulses
*/
end
// synchronization between mclk and xclk clock domains
// negedge mclk -> xclk (verify clock inversion is absorbed)
pulse_cross_clock reset_page_rd_i (.rst(rst), .src_clk(~mclk),.dst_clk(xclk), .in_pulse(xfer_reset_page_rd), .out_pulse(reset_page_rd),.busy());
// mclk -> xclk
pulse_cross_clock page_ready_i (.rst(rst), .src_clk(mclk), .dst_clk(xclk), .in_pulse(page_ready_chn), .out_pulse(page_ready),.busy());
// xclk -> mclk
// pulse_cross_clock next_page_i (.rst(rst), .src_clk(xclk), .dst_clk(mclk), .in_pulse(next_page), .out_pulse(next_page_chn),.busy(busy_next_page));
dly_16 #(.WIDTH(1)) dly_16_i (.clk(xclk),.rst(rst), .dly(CMPRS_MB_DLY), .din(pre_frame_start), .dout(frame_start));
dly_16 #(.WIDTH(1)) dly_16_i (.clk(xclk),.rst(!frame_en),.dly(CMPRS_MB_DLY), .din(pre_en), .dout(en));
multipulse_cross_clock #(
.WIDTH(3),
.EXTRA_DLY(0)
) multipulse_cross_clock_i (
.rst (rst), // input
.src_clk (xclk), // input
.dst_clk (mclk), // input
.num_pulses ({1'b0,add_invalid}), // input[0:0]
.we (we_invalid), // input
.out_pulse (next_page_chn), // output
.busy () // output
);
endmodule
......@@ -27,7 +27,13 @@ module color_proc393 (
input en, // Enable (0 will reset states)
input en_sdc, // enable subtracting of DC component
input go, // pulse to star/restart (needed for each frame, repeat generated by the caller)
// TODO: Remove
input [25:0] nblocks, // ***** was [17:0] number of 16x16 blocks to read (valid @ "go" pulse)
// NEW: Now number of SDRAM blobks (tiles) is not equal to number of macroblocks
input [12:0] n_blocks_in_row, // number of macroblocks in a macroblock row
input [12:0] n_block_rows, // number of macroblock rows in a frame
// input reset_sdram_page, // SDRAM buffer page may be reset (normally just increments for each new tile
// end of NEW
output eot, // single-cycle end of transfer pulse
input [ 9:0] m_cb, // [9:0] scale for CB - default 0.564 (10'h90)
input [ 9:0] m_cr, // [9:0] scale for CB - default 0.713 (10'hb6)
......@@ -114,7 +120,7 @@ module color_proc393 (
reg [2:0] sdrama_line_inc; // increment amount when proceeding to next tile line
reg [1:0] inc_sdrama_r;
reg last_from_sdram; // reading last_r byte from SDRAM
reg first_pixel; // reading first_r pixel to color converter (di will be evailable next cycle)
reg first_pixel; // reading first_r pixel to color converter (di will be available next cycle)
reg tim2next;
reg [8:0] y_in, c_in;
reg [7:0] yaddrw, caddrw;
......@@ -471,7 +477,7 @@ module color_proc393 (
wire limit_diff=1'b1;
csconvert18 i_csconvert18 (
csconvert18a i_csconvert18 (
.RST (!en_converters[0]),
.CLK (clk),
.mono (ignore_color_r),
......@@ -536,39 +542,39 @@ assign conv20_pre_first_out= conv18_pre_first_out;
// currently only 8 bits are used in the memories
ramp_var_w_var_r #(
ram18p_var_w_var_r #(
.REGISTERS (1), // will need to delay output strobe(s) by 1
.LOG2WIDTH_WR (3),
.LOG2WIDTH_RD (3),
.DUMMY (0)
) i_y_buff (
.rclk (clk), // input
.raddr ({2'b0,rpage[1:0],raddr[7:0]}), // input[11:0]
.raddr ({1'b0,rpage[1:0],raddr[7:0]}), // input[11:0]
.ren (!raddr[8]), // input
.regen (!raddr8_d), // input
.data_out (y_out[8:0]), // output[8:0]
.wclk (clk), // input
.waddr ({2'b0,wpage[1:0],yaddrw[7:0]}), // input[11:0]
.waddr ({1'b0,wpage[1:0],yaddrw[7:0]}), // input[11:0]
.we (ywe), // input
.web (8'hf), // input[7:0]
.web (4'hf), // input[7:0]
.data_in (y_in[8:0]) // input[9:0]
);
ramp_var_w_var_r #(
ram18p_var_w_var_r #(
.REGISTERS (1), // will need to delay output strobe(s) by 1
.LOG2WIDTH_WR (3),
.LOG2WIDTH_RD (3),
.DUMMY (0)
) i_CrCb_buff (
.rclk (clk), // input
.raddr ({2'b0,rpage[1:0],raddr[7:0]}), // input[11:0]
.raddr ({1'b0,rpage[1:0],raddr[7:0]}), // input[11:0]
.ren (raddr[8]), // input
.regen (raddr8_d), // input
.data_out (c_out[8:0]), // output[8:0]
.wclk (clk), // input
.waddr ({2'b0,wpage[1:0],yaddrw[7:0]}), // input[11:0]
.waddr ({1'b0,wpage[1:0],yaddrw[7:0]}), // input[11:0]
.we (ywe), // input
.web (8'hf), // input[7:0]
.web (4'hf), // input[7:0]
.data_in (y_in[8:0]) // input[71:0]
);
......
/*******************************************************************************
* Module: multipulse_cross_clock
* Date:2015-04-27
* Author: andrey
* Description: Generate a train of pulses through clock domains boundary
* Maximal duty cycle (with EXTRA_DLY=0 and Fdst << Fsrc) = 50%
* same frequencies - ~1/3 (with EXTRA_DLY=0) and 1/5 (with EXTRA_DLY=1)
* Lowering Fsrc reduces duty cycle proportianally as counter is in src_clk
* domain.
*
* Copyright (c) 2015 <set up in Preferences-Verilog/VHDL Editor-Templates> .
* multipulse_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.
*
* multipulse_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 multipulse_cross_clock#(
parameter WIDTH=1, // width of the pulse counter (assign MSB of input to 0 to
// have more pending that possible input)
parameter EXTRA_DLY=0)( // 0 or 1 - output duty cycle control
input rst,
input src_clk,
input dst_clk,
input [WIDTH-1:0] num_pulses, // single-cycle positive pulse
input we,
output out_pulse,
output busy
);
reg [WIDTH-1:0] pend_cntr=0;
wire busy_single;
wire single_rq_w;
reg single_rq_r=0;
assign busy = busy_single && (|pend_cntr);
assign single_rq_w = busy_single && (|pend_cntr);
always @(posedge src_clk) begin
single_rq_r <= single_rq_w;
pend_cntr <= pend_cntr + (we ? num_pulses : {WIDTH{1'b0}}) + (single_rq_r ? {WIDTH{1'b1}}:{WIDTH{1'b0}});
end
pulse_cross_clock #(
.EXTRA_DLY(EXTRA_DLY)
) pulse_cross_clock_i (
.rst (rst), // input
.src_clk (src_clk), // input
.dst_clk (dst_clk), // input
.in_pulse (single_rq_w), // input
.out_pulse (out_pulse), // output
.busy (busy_single) // output
);
endmodule
......@@ -3,6 +3,8 @@
* Date:2015-04-27
* Author: andrey
* Description: Propagate a single pulse through clock domain boundary
* For same frequencies input pulses can have 1:3 duty cycle EXTRA_DLY=0
* and 1:5 for EXTRA_DLY=1
*
* 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
......@@ -20,7 +22,9 @@
*******************************************************************************/
`timescale 1ns/1ps
module pulse_cross_clock(
module pulse_cross_clock#(
parameter EXTRA_DLY=0 // for
)(
input rst,
input src_clk,
input dst_clk,
......@@ -28,13 +32,17 @@ module pulse_cross_clock(
output out_pulse,
output busy
);
reg in_reg;
reg [2:0] out_reg;
localparam EXTRA_DLY_SAFE=EXTRA_DLY ? 1 : 0;
reg in_reg = 0;
reg [2:0] out_reg = 0;
reg busy_r = 0;
assign out_pulse=out_reg[2];
assign busy=in_reg;
assign busy=busy_r; // 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]);
else in_reg <= in_pulse || (in_reg && !out_reg[EXTRA_DLY_SAFE]);
if (rst) busy_r <= 0;
else busy_r <= in_pulse || in_reg || (busy_r && out_reg[EXTRA_DLY_SAFE]);
end
always @(posedge dst_clk or posedge rst) begin
if (rst) out_reg <= 0;
......
/*******************************************************************************
* Copyright (c) 2015 Elphel, Inc.
* Dual port memory wrapper, with variable width write and variable width read
* using "SDP" or "TDP" mode of RAMB18E1 (half of RAMB18E1)
* Uses parity bits to extend total data width (minimal width should be >=8).
* ram18p_var_w_var_r.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.
*
* ram18p_var_w_var_r.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/>.
*******************************************************************************/
/*
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 ram18p_var_w_var_r
#(
parameter integer REGISTERS = 0, // 1 - registered output
parameter integer LOG2WIDTH_WR = 5, // WIDTH= 9 << (LOG2WIDTH - 3)
parameter integer LOG2WIDTH_RD = 5, // WIDTH= 9 << (LOG2WIDTH - 3)
parameter DUMMY = 0
)
(
input rclk, // clock for read port
// input [ 9:0] raddr, // read address
input [13-LOG2WIDTH_RD:0] raddr, // read address
input ren, // read port enable
input regen, // output register enable
output [(9 << (LOG2WIDTH_RD-3))-1:0] data_out, // data out
input wclk, // clock for read port
input [13-LOG2WIDTH_WR:0] waddr, // write address
input we, // write port enable
input [ 3:0] web, // write byte enable
input [(9 << (LOG2WIDTH_WR-3))-1:0] data_in // data out
);
generate
if (DUMMY)
ram18p_dummy #(
.LOG2WIDTH_RD(LOG2WIDTH_RD)
) ram18p_dummy_i (
.data_out(data_out)
);
else if ((LOG2WIDTH_WR == 5) && (LOG2WIDTH_RD == 5))
ramp_32w_32r #(
.REGISTERS (REGISTERS)
) ram_i (
.rclk (rclk), // input
.raddr (raddr), // input[8:0]
.ren (ren), // input
.regen (regen), // input
.data_out (data_out), // output[35:0]
.wclk (wclk), // input
.waddr (waddr), // input[8:0]
.we (we), // input
.web (web), // input[3:0]
.data_in (data_in) // input[35:0]
);
else if ((LOG2WIDTH_WR == 5) && (LOG2WIDTH_RD < 5))
ram18p_32w_lt32r #(
.REGISTERS (REGISTERS),
.LOG2WIDTH_RD (LOG2WIDTH_RD)
) ram_i (
.rclk (rclk), // input
.raddr (raddr), // input[(>8):0]
.ren (ren), // input
.regen (regen), // input
.data_out (data_out), // output[(<35):0]
.wclk (wclk), // input
.waddr (waddr), // input[8:0]
.we (we), // input
.web (web), // input[3:0]
.data_in (data_in) // input[35:0]
);
else if ((LOG2WIDTH_WR < 5) && (LOG2WIDTH_RD == 5))
ramp_lt32w_32r #(
.REGISTERS (REGISTERS),
.LOG2WIDTH_WR (LOG2WIDTH_WR)
) ram_i (
.rclk (rclk), // input
.raddr (raddr), // input[8:0]
.ren (ren), // input
.regen (regen), // input
.data_out (data_out), // output[35:0]
.wclk (wclk), // input
.waddr (waddr), // input[(>8):0]
.we (we), // input
.web (web), // input[3:0]
.data_in (data_in) // input[(<35):0]
);
else if ((LOG2WIDTH_WR < 5) && (LOG2WIDTH_RD < 5))
ramp_lt32w_lt32r #(
.REGISTERS (REGISTERS),
.LOG2WIDTH_WR (LOG2WIDTH_WR),
.LOG2WIDTH_RD (LOG2WIDTH_RD)
) ram_i (
.rclk (rclk), // input
.raddr (raddr), // input[(>8):0]
.ren (ren), // input
.regen (regen), // input
.data_out (data_out), // output[(<35):0]
.wclk (wclk), // input
.waddr (waddr), // input[(>8):0]
.we (we), // input
.web (web), // input[7:0]
.data_in (data_in) // input[(<35):0]
);
endgenerate
endmodule
// Both ports with 32 bit widths
module ramp_32w_32r
#(
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 [35:0] data_out, // data out
input wclk, // clock for read port
input [ 8:0] waddr, // write address
input we, // write port enable
input [ 3:0] web, // write byte enable
input [35:0] data_in // data out
);
localparam PWIDTH_WR=72;
localparam PWIDTH_RD=72;
RAMB18E1
#(
.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 18)
.DOB_REG (REGISTERS), // Valid: 0 (no output registers) and 1 - one output register (in SDP - to lower 18)
.READ_WIDTH_A (PWIDTH_RD), // Valid: 0,1,2,4,9,18 and in SDP mode - 36 (should be 0 if port is not used)
.READ_WIDTH_B (0), // Valid: 0,1,2,4,9,18 and in SDP mode - 36 (should be 0 if port is not used)
.WRITE_WIDTH_A (0), // Valid: 0,1,2,4,9,18 and in SDP mode - 36 (should be 0 if port is not used)
.WRITE_WIDTH_B (PWIDTH_WR), // Valid: 0,1,2,4,9,18 and in SDP mode - 36 (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"
) RAMB36E1_i
(
// Port A (Read port in SDP mode):
.DOADO (data_out[15:0]), // Port A data/LSB data[15:0], output
.DOPADOP (data_out[17:16]),// Port A parity/LSB parity[2:0], output
.DIADI (data_in[15:0]), // Port A data/LSB data[15:0], input
.DIPADIP (data_in[17:16]), // Port A parity/LSB parity[2:0], input
.ADDRARDADDR ({raddr[8:0],5'b11111}), // Port A (read port in SDP) address [13:0], 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 (2'b0), // Port A (read port in SDP) Write Enable[2:0], input
// Port B
.DOBDO (data_out[33:18]),// Port B data/MSB data[15:0], output
.DOPBDOP (data_out[35:34]),// Port B parity/MSB parity[2:0], output
.DIBDI (data_in[33:18]), // Port B data/MSB data[31:0], input
.DIPBDIP (data_in[35:34]), // Port B parity/MSB parity[1:0], input
.ADDRBWRADDR ({waddr[8:0],5'b11111}), // Port B (write port in SDP) address [13:0], 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) // Port B (write port in SDP) Write Enable[7:0], input
);
endmodule
// Both ports with less than 32 bit widths
module ramp_lt32w_lt32r
#(
parameter integer REGISTERS = 0, // 1 - registered output
parameter integer LOG2WIDTH_WR = 4, // WIDTH= 1 << LOG2WIDTH
parameter integer LOG2WIDTH_RD = 4 // WIDTH= 1 << LOG2WIDTH
)
(
input rclk, // clock for read port
input [13-LOG2WIDTH_RD:0] raddr, // read address
input ren, // read port enable
input regen, // output register enable
output [(9 << (LOG2WIDTH_RD-3))-1:0] data_out, // data out
input wclk, // clock for read port
input [13-LOG2WIDTH_WR:0] waddr, // write address
input we, // write port enable
input [ 3:0] web, // write byte enable
input [(9 << (LOG2WIDTH_WR-3))-1:0] data_in // data out
);
localparam PWIDTH_WR = (LOG2WIDTH_WR > 2)? (9 << (LOG2WIDTH_WR - 3)): (1 << LOG2WIDTH_WR);
localparam PWIDTH_RD = (LOG2WIDTH_RD > 2)? (9 << (LOG2WIDTH_RD - 3)): (1 << LOG2WIDTH_RD);
localparam WIDTH_WR = 1 << LOG2WIDTH_WR;
localparam WIDTH_WRP = 1 << (LOG2WIDTH_WR-3);
localparam WIDTH_RD = 1 << LOG2WIDTH_RD;
localparam WIDTH_RDP = 1 << (LOG2WIDTH_RD-3);
wire [15:0] data_out16;
wire [ 1:0] datap_out2;
assign data_out={datap_out2[WIDTH_RDP-1:0], data_out16[WIDTH_RD-1:0]};
wire [WIDTH_WR+15:0] data_in_ext = {16'b0,data_in[WIDTH_WR-1:0]};
wire [15:0] data_in16=data_in_ext[15:0];
wire [WIDTH_WRP+1:0] datap_in_ext = {2'b0,data_in[WIDTH_WR+:WIDTH_WRP]};
wire [1:0] datap_in2= datap_in_ext[1:0];
RAMB18E1
#(
.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 18)
.DOB_REG (REGISTERS), // Valid: 0 (no output registers) and 1 - one output register (in SDP - to lower 18)
.READ_WIDTH_A (PWIDTH_RD), // Valid: 0,1,2,4,9,18 and in SDP mode - 36 (should be 0 if port is not used)
.READ_WIDTH_B (0), // Valid: 0,1,2,4,9,18 and in SDP mode - 36 (should be 0 if port is not used)
.WRITE_WIDTH_A (0), // Valid: 0,1,2,4,9,18 and in SDP mode - 36 (should be 0 if port is not used)
.WRITE_WIDTH_B (PWIDTH_WR), // Valid: 0,1,2,4,9,18 and in SDP mode - 36 (should be 0 if port is not used)
.RAM_MODE ("TDP"), // 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"
) RAMB36E1_i
(
// Port A (Read port in SDP mode):
.DOADO (data_out16), // Port A data/LSB data[15:0], output
.DOPADOP (datap_out2), // Port A parity/LSB parity[1:0], output
.DIADI (16'h0), // Port A data/LSB data[15:0], input
.DIPADIP (2'h0), // Port A parity/LSB parity[1:0], input
.ADDRARDADDR ({raddr,{LOG2WIDTH_RD{1'b1}}}), // Port A (read port in SDP) address [13:0], 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 (2'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_in16), // Port B data/MSB data[31:0], input
.DIPBDIP (datap_in2), // Port B parity/MSB parity[3:0], input
.ADDRBWRADDR ({waddr,{LOG2WIDTH_WR{1'b1}}}), // Port B (write port in SDP) address [13:0], 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[3:0]) // Port B (write port in SDP) Write Enable[3:0], input
);
endmodule
// Write port less than 32bits, read port 32 bit widths
module ramp_lt32w_32r
#(
parameter integer REGISTERS = 0, // 1 - registered output
parameter integer LOG2WIDTH_WR = 4 // WIDTH= 1 << LOG2WIDTH
)
(
input rclk, // clock for read port
input [8:0] raddr, // read address
input ren, // read port enable
input regen, // output register enable
output [35:0] data_out, // data out
input wclk, // clock for read port
input [13-LOG2WIDTH_WR:0] waddr, // write address
input we, // write port enable
input [ 3:0] web, // write byte enable
input [(9 << (LOG2WIDTH_WR-3))-1:0] data_in // data out
);
localparam PWIDTH_WR = (LOG2WIDTH_WR > 2)? (9 << (LOG2WIDTH_WR - 3)): (1 << LOG2WIDTH_WR);
localparam PWIDTH_RD = 36;
localparam WIDTH_WR = 1 << LOG2WIDTH_WR;
localparam WIDTH_WRP = 1 << (LOG2WIDTH_WR-3);
wire [WIDTH_WR+15:0] data_in_ext = {16'b0,data_in[WIDTH_WR-1:0]};
wire [15:0] data_in16=data_in_ext[15:0];
wire [WIDTH_WRP+1:0] datap_in_ext = {2'b0,data_in[WIDTH_WR+:WIDTH_WRP]};
wire [1:0] datap_in2= datap_in_ext[1:0];
RAMB18E1
#(
.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 18)
.DOB_REG (REGISTERS), // Valid: 0 (no output registers) and 1 - one output register (in SDP - to lower 18)
.READ_WIDTH_A (PWIDTH_RD), // Valid: 0,1,2,4,9,18 and in SDP mode - 36 (should be 0 if port is not used)
.READ_WIDTH_B (0), // Valid: 0,1,2,4,9,18 and in SDP mode - 36 (should be 0 if port is not used)
.WRITE_WIDTH_A (0), // Valid: 0,1,2,4,9,18 and in SDP mode - 36 (should be 0 if port is not used)
.WRITE_WIDTH_B (PWIDTH_WR), // Valid: 0,1,2,4,9,18 and in SDP mode - 36 (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"
) RAMB36E1_i
(
// Port A (Read port in SDP mode):
.DOADO (data_out[15:0]), // Port A data/LSB data[15:0], output
.DOPADOP (data_out[17:16]),// Port A parity/LSB parity[3:0], output
.DIADI (16'h0), // Port A data/LSB data[31:0], input
.DIPADIP (2'h0), // Port A parity/LSB parity[3:0], input
.ADDRARDADDR ({raddr[8: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 (2'b0), // Port A (read port in SDP) Write Enable[3:0], input
// Port B
.DOBDO (data_out[33:18]),// Port B data/MSB data[31:0], output
.DOPBDOP (data_out[35:34]),// Port B parity/MSB parity[3:0], output
.DIBDI (data_in16), // Port B data/MSB data[31:0], input
.DIPBDIP (datap_in2), // Port B parity/MSB parity[3:0], input
.ADDRBWRADDR ({waddr,{LOG2WIDTH_WR{1'b1}}}), // 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[3:0]) // Port B (write port in SDP) Write Enable[7:0], input
);
endmodule
// Write port 64 bita, read port - less than 64 bits
module ram18p_32w_lt32r
#(
parameter integer REGISTERS = 0, // 1 - registered output
// parameter integer LOG2WIDTH_WR = 4, // WIDTH= 1 << LOG2WIDTH
parameter integer LOG2WIDTH_RD = 4 // WIDTH= 1 << LOG2WIDTH
)
(
input rclk, // clock for read port
input [13-LOG2WIDTH_RD:0] raddr, // read address
input ren, // read port enable
input regen, // output register enable
output [(9 << (LOG2WIDTH_RD-3))-1:0] data_out, // data out
input wclk, // clock for read port
input [8:0] waddr, // write address
input we, // write port enable
input [ 3:0] web, // write byte enable
input [35:0] data_in // data out
);
localparam PWIDTH_WR = 72;
localparam PWIDTH_RD = (LOG2WIDTH_RD > 2)? (9 << (LOG2WIDTH_RD - 3)): (1 << LOG2WIDTH_RD);
localparam WIDTH_RD = 1 << LOG2WIDTH_RD;
localparam WIDTH_RDP = 1 << (LOG2WIDTH_RD-3);
wire [15:0] data_out16;
wire [ 1:0] datap_out2;
assign data_out={datap_out2[WIDTH_RDP-1:0], data_out16[WIDTH_RD-1:0]};
RAMB18E1
#(
.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 18)
.DOB_REG (REGISTERS), // Valid: 0 (no output registers) and 1 - one output register (in SDP - to lower 18)
.READ_WIDTH_A (PWIDTH_RD), // Valid: 0,1,2,4,9,18 and in SDP mode - 36 (should be 0 if port is not used)
.READ_WIDTH_B (0), // Valid: 0,1,2,4,9,18 and in SDP mode - 36 (should be 0 if port is not used)
.WRITE_WIDTH_A (0), // Valid: 0,1,2,4,9,18 and in SDP mode - 36 (should be 0 if port is not used)
.WRITE_WIDTH_B (PWIDTH_WR), // Valid: 0,1,2,4,9,18 and in SDP mode - 36 (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"
) RAMB36E1_i
(
// Port A (Read port in SDP mode):
.DOADO (data_out16), // Port A data/LSB data[15:0], output
.DOPADOP (datap_out2), // Port A parity/LSB parity[1:0], output
.DIADI (data_in[15:0]), // Port A data/LSB data[15:0], input
.DIPADIP (data_in[17:16]), // Port A parity/LSB parity[1:0], input
.ADDRARDADDR ({raddr,{LOG2WIDTH_RD{1'b1}}}), // Port A (read port in SDP) address [13:0], 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 (2'b0), // Port A (read port in SDP) Write Enable[1:0], input
// Port B
.DOBDO (), // Port B data/MSB data[15:0], output
.DOPBDOP (), // Port B parity/MSB parity[1:0], output
.DIBDI (data_in[33:18]), // Port B data/MSB data[15:0], input
.DIPBDIP (data_in[35:34]), // Port B parity/MSB parity[1:0], input
.ADDRBWRADDR({waddr[8:0],5'b11111}), // Port B (write port in SDP) address [13:0], 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[3:0]) // Port B (write port in SDP) Write Enable[7:0], input
);
endmodule
module ram18p_dummy
#(
parameter integer LOG2WIDTH_RD = 4 // WIDTH= 1 << LOG2WIDTH
)
(
output [(9 << (LOG2WIDTH_RD-3))-1:0] data_out // data out
);
assign data_out=0;
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