📄 lp_rx.v
字号:
// ================================================================================
// (c) 2003 Altera Corporation. All rights reserved.
// Altera products are protected under numerous U.S. and foreign patents, maskwork
// rights, copyrights and other intellectual property laws.
//
// This reference design file, and your use thereof, is subject to and governed
// by the terms and conditions of the applicable Altera Reference Design License
// Agreement (either as signed by you, agreed by you upon download or as a
// "click-through" agreement upon installation andor found at www.altera.com).
// By using this reference design file, you indicate your acceptance of such terms
// and conditions between you and Altera Corporation. In the event that you do
// not agree with such terms and conditions, you may not use the reference design
// file and please promptly destroy any copies you have made.
//
// This reference design file is being provided on an "as-is" basis and as an
// accommodation and therefore all warranties, representations or guarantees of
// any kind (whether express, implied or statutory) including, without limitation,
// warranties of merchantability, non-infringement, or fitness for a particular
// purpose, are specifically disclaimed. By making this reference design file
// available, Altera expressly does not recommend, suggest or require that this
// reference design file be used in combination with any other product not
// provided by Altera.
// ================================================================================
module lp_rx (clk,
rst_n,
datain,
inclock,
inclock_en,
acko,
bcmpi_n,
rvere,
rcser,
rdreq,
empty,
rdata
);
input clk; // Local clock
input rst_n;
// Link port
input [3:0] datain;
input inclock;
input inclock_en;
output acko;
input bcmpi_n;
// Local control/status
input rvere; // Receive verification byte enable
output rcser; // Receive checksum error
// Local FIFO interface
input rdreq;
output empty;
output [32:0] rdata;
parameter DEVICE = "Cyclone II";
wire inclock_gated = inclock & inclock_en;
reg [11:0] datain_pos;
reg [11:0] datain_neg;
always @(posedge inclock_gated or negedge rst_n)
if (~rst_n)
datain_pos <= 12'b0;
else
datain_pos <= {datain, datain_pos[11:4]};
always @(negedge inclock_gated or negedge rst_n)
if (~rst_n)
datain_neg <= 12'b0;
else
datain_neg <= {datain, datain_neg[11:4]};
reg [4:0] pos_edges;
reg [4:0] neg_edges;
/* -----\/----- EXCLUDED -----\/-----
always @(posedge inclock_gated or negedge rst_n)
if (~rst_n)
pos_edges <= 5'b0;
else
case (pos_edges)
5'd15:
if (rvere)
pos_edges <= pos_edges + 5'd1;
else
pos_edges <= 5'd0;
5'd17:
pos_edges <= 5'd0;
default:
pos_edges <= pos_edges + 5'b1;
endcase
-----/\----- EXCLUDED -----/\----- */
// Following way of coding improves Fmax for pos_edges
always @(posedge inclock_gated or negedge rst_n)
if (~rst_n)
pos_edges[3:0] <= 4'b0;
else
case (pos_edges[3:0])
4'd1:
if (~pos_edges[4])
pos_edges[3:0] <= pos_edges[3:0] + 4'd1;
else
pos_edges[3:0] <= 4'd0;
4'd15:
if (rvere)
pos_edges[3:0] <= pos_edges[3:0] + 4'd1;
else
pos_edges[3:0] <= 4'd0;
default:
pos_edges[3:0] <= pos_edges[3:0] + 4'b1;
endcase
always @(posedge inclock_gated or negedge rst_n)
if (~rst_n)
pos_edges[4] <= 1'b0;
else
case (pos_edges[3:0])
4'd0:
if (pos_edges[4])
pos_edges[4] <= 1'b1;
else
pos_edges[4] <= 1'b0;
4'd15:
if (rvere)
pos_edges[4] <= 1'b1;
else
pos_edges[4] <= 1'b0;
default:
pos_edges[4] <= 1'b0;
endcase
always @(negedge inclock_gated or negedge rst_n)
if (~rst_n)
neg_edges <= 5'b0;
else
case (neg_edges)
5'd15:
if (rvere)
neg_edges <= neg_edges + 5'd1;
else
neg_edges <= 5'd0;
5'd17:
neg_edges <= 5'd0;
default:
neg_edges <= neg_edges + 5'b1;
endcase
reg freeze_pos;
reg freeze_neg;
always @(posedge inclock_gated)
freeze_pos <= (pos_edges[1:0] == 2'd2);
always @(negedge inclock_gated)
freeze_neg <= (neg_edges[1:0] == 2'd2);
reg [15:0] pos_data;
reg [15:0] neg_data;
always @(posedge inclock_gated)
if (freeze_pos)
pos_data <= {datain, datain_pos};
always @(negedge inclock_gated)
if (freeze_neg)
neg_data <= {datain, datain_neg};
wire [31:0] shift_reg;
assign shift_reg = {neg_data[15:12], pos_data[15:12],
neg_data[11:8], pos_data[11:8],
neg_data[7:4], pos_data[7:4],
neg_data[3:0], pos_data[3:0]};
reg data_ready;
// toggles just before a new quad word is available to give time for
// synchronisation to local clock domain
always @(posedge inclock_gated or negedge rst_n)
if (~rst_n)
data_ready <= 1'b0;
else if (pos_edges[1:0] == 2'd2)
data_ready <= ~data_ready;
reg dr_sync1;
reg dr_sync2;
reg dr_sync3;
reg dr_sync4;
always @(posedge clk or negedge rst_n)
if (~rst_n)
begin
dr_sync1 <= 1'b0;
dr_sync2 <= 1'b0;
dr_sync3 <= 1'b0;
dr_sync4 <= 1'b0;
end
else
begin
dr_sync1 <= data_ready;
dr_sync2 <= dr_sync1;
dr_sync3 <= dr_sync2;
dr_sync4 <= dr_sync3;
end
reg [32:0] fifo_wdata;
reg blk_end;
always @(posedge clk or negedge rst_n)
if (~rst_n)
fifo_wdata <= 33'b0;
else if (dr_sync1 ^ dr_sync2)
fifo_wdata <= {blk_end, shift_reg};
reg fifo_we;
always @(posedge clk or negedge rst_n)
if (~rst_n)
fifo_we <= 1'b0;
else
fifo_we <= dr_sync1 ^ dr_sync2;
wire [32:0] rdata;
wire [6:0] wrused;
dcfifo rx_fifo (
.aclr (~rst_n),
.wrclk (clk),
.data (fifo_wdata),
.wrreq (fifo_we),
.wrfull (),
.wrusedw (wrused),
.rdclk (clk),
.rdreq (rdreq),
.q (rdata),
.rdempty (empty),
.rdusedw ()
);
defparam
rx_fifo.intended_device_family = DEVICE,
rx_fifo.lpm_width = 33,
rx_fifo.lpm_numwords = 128,
rx_fifo.lpm_widthu = 7,
rx_fifo.clocks_are_synchronized = "FALSE",
rx_fifo.lpm_type = "dcfifo",
rx_fifo.lpm_showahead = "OFF",
rx_fifo.overflow_checking = "ON",
rx_fifo.underflow_checking = "ON",
rx_fifo.use_eab = "ON",
rx_fifo.add_ram_output_register = "OFF",
rx_fifo.lpm_hint = "RAM_BLOCK_TYPE=AUTO";
reg acko;
always @(posedge clk or negedge rst_n)
if (~rst_n)
acko <= 1'b1;
else
if (wrused >= 7'h70)
acko <= 1'b0;
else
acko <= 1'b1;
// Checksum checking
reg load_ver_l;
reg load_ver_h;
always @(posedge inclock_gated or negedge rst_n)
if (~rst_n)
load_ver_l <= 1'b0;
else
load_ver_l <= (pos_edges[4] & ~pos_edges[0]);
always @(negedge inclock_gated or negedge rst_n)
if (~rst_n)
load_ver_h <= 1'b0;
else
load_ver_h <= (neg_edges[4] & ~neg_edges[0]);
reg [3:0] ver_h;
reg [3:0] ver_l;
always @(posedge inclock_gated or negedge rst_n)
if (~rst_n)
ver_l <= 4'b0;
else if (load_ver_l)
ver_l <= datain_pos[11:8];
always @(negedge inclock_gated or negedge rst_n)
if (~rst_n)
ver_h <= 4'b0;
else if (load_ver_h)
ver_h <= datain_neg[11:8];
wire [7:0] ver_byte;
assign ver_byte = {ver_h, ver_l};
reg [1:0] words;
always @(posedge clk or negedge rst_n)
if (~rst_n)
words <= 2'h0;
else if (fifo_we)
words <= words + 2'h1;
reg pos_chk_en;
always @(posedge inclock_gated or negedge rst_n)
if (~rst_n)
pos_chk_en <= 1'b0;
else if (pos_edges[4])
pos_chk_en <= 1'b0;
else
pos_chk_en <= 1'b1;
reg neg_chk_en;
always @(negedge inclock_gated or negedge rst_n)
if (~rst_n)
neg_chk_en <= 1'b0;
else if (neg_edges[4])
neg_chk_en <= 1'b0;
else
neg_chk_en <= 1'b1;
/* -----\/----- EXCLUDED -----\/-----
reg [7:0] low_nibble_chk;
always @(posedge inclock_gated or negedge rst_n)
if (~rst_n)
low_nibble_chk <= 8'b0;
else if (pos_chk_en)
low_nibble_chk <= low_nibble_chk + {4'b0, datain_pos[11:8]};
else
low_nibble_chk <= 8'b0;
-----/\----- EXCLUDED -----/\----- */
// split lower nibble into low_nibble and mid_nibble to avoid an
// 8 bit adder that will not run at 500MHz
reg [4:0] low_nibble_chk;
always @(posedge inclock_gated or negedge rst_n)
if (~rst_n)
low_nibble_chk <= 5'b0;
else if (~pos_chk_en)
low_nibble_chk <= 5'b0;
else
low_nibble_chk <= {1'b0, low_nibble_chk[3:0]} + {1'b0, datain_pos[11:8]};
reg [3:0] mid_nibble_chk;
always @(posedge inclock_gated or negedge rst_n)
if (~rst_n)
mid_nibble_chk <= 4'b0;
else if (~pos_chk_en)
mid_nibble_chk <= 4'b0;
else if (low_nibble_chk[4])
mid_nibble_chk <= mid_nibble_chk + 1'b1;
reg [7:0] low_nibble_chk_r;
always @(posedge inclock_gated or negedge rst_n)
if (~rst_n)
low_nibble_chk_r <= 8'b0;
else if (load_ver_l)
low_nibble_chk_r <= {mid_nibble_chk + {3'b0, low_nibble_chk[4]},
low_nibble_chk[3:0]};
reg [3:0] high_nibble_chk;
always @(negedge inclock_gated or negedge rst_n)
if (~rst_n)
high_nibble_chk <= 4'b0;
else if (neg_chk_en)
high_nibble_chk <= high_nibble_chk + datain_neg[11:8];
else
high_nibble_chk <= 4'b0;
reg [3:0] high_nibble_chk_r;
always @(negedge inclock_gated or negedge rst_n)
if (~rst_n)
high_nibble_chk_r <= 4'b0;
else if (load_ver_h)
high_nibble_chk_r <= high_nibble_chk;
wire [7:0] cksum = {high_nibble_chk_r, 4'b0} + low_nibble_chk_r;
reg rcser;
always @(posedge clk or negedge rst_n)
if (~rst_n)
rcser <= 1'b0;
else if (fifo_we & (&words))
rcser <= cksum != ver_byte;
// block complete
reg bcmp;
reg bcmpi_sync_n;
always @(posedge inclock_gated or negedge rst_n)
if (~rst_n)
begin
bcmpi_sync_n <= 1'b1;
bcmp <= 1'b0;
end
else
begin
bcmpi_sync_n <= bcmpi_n;
bcmp <= ~bcmpi_sync_n;
end
reg sample_bcmp;
always @(posedge inclock_gated or negedge rst_n)
if (~rst_n)
sample_bcmp <= 1'b0;
else
sample_bcmp <= (pos_edges[3:2] == 2'b10);
always @(posedge inclock_gated or negedge rst_n)
if (~rst_n)
blk_end <= 1'b0;
else if (freeze_pos & ~sample_bcmp)
blk_end <= 1'b0;
else if (freeze_pos & sample_bcmp & bcmp)
blk_end <= 1'b1;
endmodule
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -