2071 lines
49 KiB
Verilog
2071 lines
49 KiB
Verilog
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Filename: axisvoverlay.v
|
|
// {{{
|
|
// Project: 10Gb Ethernet switch
|
|
//
|
|
// Purpose: Overlay a second video stream on top of a first one, producing
|
|
// an outgoing video stream.
|
|
//
|
|
// Inputs:
|
|
// Primary video:
|
|
// Can be from a camera or a memory/frame buffer driving a display.
|
|
// The assumption is made that the speed can be controlled by
|
|
// the downstream/output video port. (i.e., hold READY high if
|
|
// this is coming from a camera, or toggle it if/when the outgoing
|
|
// display is/isn't ready.)
|
|
// Secondary (overlay) video
|
|
// May or may not be present. Must be able to handle stalls, so
|
|
// must be driven from memory. The primary video and associated
|
|
// output interface drives drive the speed of the interface.
|
|
// The design will report an error if the secondary video ever
|
|
// gets out of sync.
|
|
//
|
|
// Outputs:
|
|
// Outgoing AXI Stream video stream
|
|
// To be produced at all costs.
|
|
//
|
|
// Creator: Dan Gisselquist, Ph.D.
|
|
// Gisselquist Technology, LLC
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// }}}
|
|
// Copyright (C) 2023, Gisselquist Technology, LLC
|
|
// {{{
|
|
// This file is part of the ETH10G project.
|
|
//
|
|
// The ETH10G project contains free software and gateware, licensed under the
|
|
// Apache License, Version 2.0 (the "License"). You may not use this project,
|
|
// or this file, except in compliance with the License. You may obtain a copy
|
|
// of the License at
|
|
// }}}
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
// {{{
|
|
// Unless required by applicable law or agreed to in writing, files
|
|
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
// License for the specific language governing permissions and limitations
|
|
// under the License.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
`default_nettype none
|
|
// }}}
|
|
module axisvoverlay #(
|
|
// {{{
|
|
// LGFRAME: Control the number of bits required in the two
|
|
// {{{
|
|
// position counters. If there will never be more than 2047
|
|
// horizontal positions, then this number never need be more
|
|
// than 11.
|
|
parameter LGFRAME = 11,
|
|
// }}}
|
|
// ALPHA_BITS: Number of alpha bits in the overlay channel
|
|
// {{{
|
|
// If zero, the overlay will always replace the primary when
|
|
// present. If one, then the overlay will only replace the
|
|
// primary when the alpha bit is 1. If greater than 1, then
|
|
// the alpha bits are used to scale both primary, by 1-alpha,
|
|
// and overlay, by alpha, before summing the two together.
|
|
// This allows the generation of a gradient effect if desired.
|
|
parameter ALPHA_BITS = 1,
|
|
// }}}
|
|
// COLORS: Number of color components to apply alpha mixing to
|
|
// {{{
|
|
// While you might think of this as nominally 3, REG+GRN+BLU,
|
|
// it could be set to 6 (RGB, RGB), or even 9 (RGB, RGB, RGB),
|
|
// if you want to share alpha across multiple pixels.
|
|
parameter COLORS = 3,
|
|
// }}}
|
|
// BITS_PER_PIXEL: Bits per color component
|
|
// {{{
|
|
parameter BITS_PER_PIXEL = 8,
|
|
localparam BPP = BITS_PER_PIXEL,
|
|
parameter DATA_WIDTH = COLORS * BITS_PER_PIXEL,
|
|
localparam DW = DATA_WIDTH,
|
|
// }}}
|
|
// OPT_TUSER_IS_SOF: This is the normal video mode, as defined
|
|
// {{{
|
|
// by Xilinx's documentation. TUSER = the start of frame
|
|
// signal. This makes TUSER true for the one pixel when
|
|
// X = Y == 0. TLAST is then used to reference the last item
|
|
// in a line. Set this to 1 for best compatibility with other
|
|
// video cores for this reason. Unfortunately, this makes
|
|
// our processing below more challenging. Therefore, I offer
|
|
// another option: TLAST == the last pixel in the frame, when
|
|
// X == WIDTH -1 && Y == HEIGHT-1. This is easier to work with
|
|
// internally, and requires less logic. Both are tested.
|
|
parameter [0:0] OPT_TUSER_IS_SOF = 1'b1,
|
|
// }}}
|
|
// OPT_LINE_BREAK: If set, then we force READY to be low for
|
|
// {{{
|
|
// one clock cycle following every line break (HLAST). This
|
|
// allows our pointers to recover and the in_overlay flag to
|
|
// be calculated with seven fewer logic operations on the
|
|
// critical path between clock ticks. This should help the
|
|
// design pass timing in a high speed environment.
|
|
parameter [0:0] OPT_LINE_BREAK = 1'b0
|
|
// }}}
|
|
// }}}
|
|
) (
|
|
// {{{
|
|
input wire ACLK, ARESETN,
|
|
// Config inputs
|
|
// {{{
|
|
// i_enable: if true, apply the overlay to the primary channel
|
|
// {{{
|
|
input wire i_enable,
|
|
// }}}
|
|
// i_hpos, i_vpos: Describe the location of the top-left corner
|
|
// {{{
|
|
// of the overlay. This will allow the overlay position to be
|
|
// adjusted as necessary. The design (currently) does not
|
|
// allow the overlay to be positioned partially off screen to
|
|
// either top or left, although running off screen to right or
|
|
// bottom should be okay as long as there's enough bandwidth
|
|
// to allow it.
|
|
input wire [LGFRAME-1:0] i_hpos, i_vpos,
|
|
// }}}
|
|
output wire o_err,
|
|
// }}}
|
|
// Primary video input
|
|
// {{{
|
|
input wire S_PRI_TVALID,
|
|
output wire S_PRI_TREADY,
|
|
input wire [DW-1:0] S_PRI_TDATA,
|
|
input wire S_PRI_TLAST, // HLAST
|
|
input wire S_PRI_TUSER, // SOF
|
|
// }}}
|
|
// Secondary (overlap) video input
|
|
// {{{
|
|
input wire S_OVW_TVALID,
|
|
output wire S_OVW_TREADY,
|
|
input wire [DW+ALPHA_BITS-1:0] S_OVW_TDATA,
|
|
input wire S_OVW_TLAST, // HLAST
|
|
input wire S_OVW_TUSER, // SOF
|
|
// }}}
|
|
// Video output
|
|
// {{{
|
|
output reg M_VID_TVALID,
|
|
input wire M_VID_TREADY,
|
|
output reg [DW-1:0] M_VID_TDATA,
|
|
output reg M_VID_TLAST, // HLAST
|
|
output reg M_VID_TUSER // SOF
|
|
// }}}
|
|
// }}}
|
|
);
|
|
|
|
// Local declarations
|
|
// {{{
|
|
localparam [ALPHA_BITS:0] // OPAQUE = (1<<ALPHA_BITS),
|
|
TRANSPARENT = 0;
|
|
|
|
wire pskd_tuser, pskd_tlast, pskd_ready, pskd_valid,
|
|
pskd_vlast, pskd_hlast, pskd_sof;
|
|
wire [DW-1:0] pskd_data;
|
|
|
|
wire ovskd_tuser, ovskd_tlast, ovskd_ready,
|
|
ovskd_vlast, ovskd_hlast, ovskd_sof,
|
|
ovskd_valid;
|
|
wire [ALPHA_BITS+DW-1:0] ovskd_data;
|
|
reg pix_line_pause, ov_line_pause;
|
|
|
|
reg [LGFRAME-1:0] prhpos, prvpos;
|
|
reg [LGFRAME-1:0] ovhpos, ovvpos;
|
|
wire [LGFRAME-1:0] lines_per_frame;
|
|
|
|
reg in_overlay, in_frame, frame_err, ovw_eof, ovw_eol;
|
|
|
|
wire pix_loaded;
|
|
wire pix_ready;
|
|
|
|
wire mpy_loaded, mpy_ready;
|
|
wire mix_valid, mix_ready, mix_hlast, mix_vlast, mix_sof;
|
|
|
|
wire [DW-1:0] mix_pixel;
|
|
`ifdef FORMAL
|
|
(* anyconst *) reg [LGFRAME-1:0] f_vid_width, f_vid_height;
|
|
(* anyconst *) reg [LGFRAME-1:0] f_ovw_width, f_ovw_height;
|
|
reg [LGFRAME-1:0] f_pri_hpos, f_pri_vpos;
|
|
reg [LGFRAME-1:0] f_ovw_hpos, f_ovw_vpos;
|
|
reg [LGFRAME-1:0] f_vid_hpos, f_vid_vpos;
|
|
reg [LGFRAME-1:0] f_pskd_hpos, f_pskd_vpos;
|
|
reg [LGFRAME-1:0] f_mix_hpos, f_mix_vpos;
|
|
wire f_pri_known, f_ovw_known;
|
|
wire [LGFRAME-1:0] f_ovw_lines_per_frame;
|
|
wire f_mix_err;
|
|
`endif
|
|
// }}}
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Pixel skid buffers
|
|
// {{{
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
//
|
|
|
|
skidbuffer #(
|
|
.DW(DW+2), .OPT_OUTREG(0)
|
|
`ifdef FORMAL
|
|
, .OPT_PASSTHROUGH(1)
|
|
`endif
|
|
) primary_skid (
|
|
// {{{
|
|
.i_clk(ACLK), .i_reset(!ARESETN),
|
|
.i_valid(S_PRI_TVALID), .o_ready(S_PRI_TREADY),
|
|
.i_data({ S_PRI_TDATA, S_PRI_TLAST, S_PRI_TUSER }),
|
|
.o_valid(pskd_valid), .i_ready(pskd_ready),
|
|
.o_data({ pskd_data, pskd_tlast, pskd_tuser })
|
|
// }}}
|
|
);
|
|
|
|
skidbuffer #(
|
|
.DW(DW+ALPHA_BITS+2), .OPT_OUTREG(0)
|
|
`ifdef FORMAL
|
|
, .OPT_PASSTHROUGH(1)
|
|
`endif
|
|
) overlay_skid (
|
|
// {{{
|
|
.i_clk(ACLK), .i_reset(!ARESETN),
|
|
.i_valid(S_OVW_TVALID), .o_ready(S_OVW_TREADY),
|
|
.i_data({ S_OVW_TDATA, S_OVW_TLAST, S_OVW_TUSER }),
|
|
.o_valid(ovskd_valid), .i_ready(ovskd_ready),
|
|
.o_data({ ovskd_data, ovskd_tlast, ovskd_tuser })
|
|
// }}}
|
|
);
|
|
|
|
// }}}
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Incoming frame counters, VLAST/SOF insertion
|
|
// {{{
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
//
|
|
|
|
// VLAST, HLAST, SOF
|
|
// {{{
|
|
generate if (OPT_TUSER_IS_SOF)
|
|
begin : GEN_VLAST
|
|
// {{{
|
|
reg p_vlast, ov_vlast;
|
|
reg [LGFRAME-1:0] ovw_lines, vcount, ovcount, r_lines;
|
|
|
|
assign pskd_sof = pskd_tuser;
|
|
assign pskd_hlast = pskd_tlast;
|
|
assign pskd_vlast = p_vlast && pskd_hlast;
|
|
assign lines_per_frame = r_lines;
|
|
|
|
// vcount, lines_per_frame, p_vlast
|
|
// {{{
|
|
always @(posedge ACLK)
|
|
if (!ARESETN)
|
|
begin
|
|
p_vlast <= 0;
|
|
vcount <= 0;
|
|
r_lines <= 0;
|
|
end else if (pskd_valid && pskd_ready)
|
|
begin
|
|
if (pskd_sof)
|
|
begin
|
|
r_lines <= vcount;
|
|
vcount <= 0;
|
|
end
|
|
|
|
if (pskd_hlast)
|
|
begin
|
|
vcount <= vcount + 1;
|
|
p_vlast <= (vcount == lines_per_frame - 2);
|
|
if (lines_per_frame == 0)
|
|
p_vlast <= 0;
|
|
end
|
|
end
|
|
// }}}
|
|
|
|
assign ovskd_sof = ovskd_tuser;
|
|
assign ovskd_hlast = ovskd_tlast;
|
|
assign ovskd_vlast = ov_vlast && ovskd_hlast;
|
|
|
|
// ovcount, ovw_lines, ovskd_vlast
|
|
// {{{
|
|
always @(posedge ACLK)
|
|
if (!ARESETN)
|
|
begin
|
|
ov_vlast <= 0;
|
|
ovcount <= 0;
|
|
ovw_lines <= 0;
|
|
end else if (ovskd_valid && ovskd_ready)
|
|
begin
|
|
if (ovskd_sof)
|
|
begin
|
|
ovw_lines <= ovcount;
|
|
ovcount <= 0;
|
|
end
|
|
|
|
if (ovskd_hlast)
|
|
begin
|
|
ovcount <= ovcount + 1;
|
|
ov_vlast <= (ovcount + 2 == ovw_lines);
|
|
end
|
|
end
|
|
// }}}
|
|
`ifdef FORMAL
|
|
// {{{
|
|
assign f_ovw_lines_per_frame = ovw_lines;
|
|
always @(*)
|
|
if (ARESETN)
|
|
begin
|
|
assert((r_lines == 0) || (r_lines == f_vid_height));
|
|
|
|
if (f_pri_sof && (vcount != 0 || r_lines != 0))
|
|
begin
|
|
assert(vcount == f_vid_height);
|
|
end
|
|
|
|
// Primary tracking
|
|
if (r_lines == 0)
|
|
begin
|
|
assert(!p_vlast);
|
|
assert(!f_pri_known
|
|
|| (f_pri_sof && (vcount == f_vid_height)));
|
|
end else begin
|
|
assert(f_pri_known);
|
|
assert(r_lines == f_vid_height);
|
|
assert(p_vlast == (f_pri_vpos == f_vid_height-1));
|
|
end
|
|
|
|
if (vcount < f_vid_height)
|
|
begin
|
|
assert(f_pri_vpos == vcount);
|
|
assert(prvpos == f_pri_vpos
|
|
|| (f_pri_sof && prvpos == f_vid_height));
|
|
end else begin
|
|
assert(vcount == f_vid_height);
|
|
assert(!p_vlast);
|
|
assert(f_pri_sof);
|
|
assert(f_pri_known);
|
|
end
|
|
end
|
|
|
|
always @(*)
|
|
if (ARESETN)
|
|
begin
|
|
if (ovw_lines != 0)
|
|
assert(ovw_lines == f_ovw_height);
|
|
assert((ovw_lines == 0) || (ovw_lines == f_ovw_height));
|
|
if (f_ovw_known)
|
|
begin
|
|
assert(ov_vlast == (f_ovw_vpos == f_ovw_height-1));
|
|
if (!f_ovw_sof)
|
|
assert(ovw_lines== f_ovw_height);
|
|
else begin
|
|
assert(ovcount == f_ovw_height);
|
|
assert(ovw_lines == 0
|
|
|| ovw_lines == f_ovw_height);
|
|
end
|
|
end else
|
|
assert(!ov_vlast);
|
|
|
|
if (f_ovw_known && f_ovw_sof)
|
|
assert(ovcount == f_ovw_height);
|
|
if (f_ovw_vpos != ovcount)
|
|
assert(ovcount == f_ovw_height && f_ovw_sof
|
|
&& f_ovw_known);
|
|
|
|
if (ovw_lines == 0)
|
|
begin
|
|
assert(!f_ovw_known
|
|
||(f_ovw_sof && ovcount == f_ovw_height));
|
|
assert(!ov_vlast);
|
|
end else begin
|
|
assert(f_ovw_known);
|
|
assert(ovw_lines == f_ovw_height);
|
|
assert(ov_vlast == (f_ovw_vpos == f_ovw_height-1));
|
|
end
|
|
|
|
if (f_ovw_known && ovw_lines == f_ovw_height)
|
|
begin
|
|
assert(ovvpos == f_ovw_vpos);
|
|
assert(ovw_eof == f_ovw_sof);
|
|
end else
|
|
assert(ovw_lines == 0);
|
|
end
|
|
// }}}
|
|
`endif
|
|
// }}}
|
|
end else begin : GEN_SOF
|
|
// {{{
|
|
reg p_sof, ov_sof;
|
|
|
|
assign pskd_vlast = pskd_tlast && pskd_tuser;
|
|
assign pskd_hlast = pskd_tuser;
|
|
assign pskd_sof = p_sof;
|
|
assign lines_per_frame = 0; // A dummy value
|
|
|
|
// p_sof
|
|
// {{{
|
|
always @(posedge ACLK)
|
|
if (!ARESETN)
|
|
p_sof <= 1;
|
|
else if (pskd_valid && pskd_ready)
|
|
p_sof <= pskd_tlast && pskd_tuser;
|
|
// }}}
|
|
|
|
assign ovskd_vlast = ovskd_tlast && ovskd_tuser;
|
|
assign ovskd_hlast = ovskd_tuser;
|
|
assign ovskd_sof = ov_sof;
|
|
|
|
// ov_sof
|
|
// {{{
|
|
always @(posedge ACLK)
|
|
if (!ARESETN)
|
|
ov_sof <= 1;
|
|
else if (ovskd_valid && ovskd_ready)
|
|
ov_sof <= ovskd_tlast && ovskd_tuser;
|
|
// }}}
|
|
`ifdef FORMAL
|
|
assign f_ovw_lines_per_frame = f_ovw_height;
|
|
always @(*)
|
|
if (ARESETN)
|
|
begin
|
|
assert(pskd_sof == ((f_pri_hpos == 0) && (f_pri_vpos == 0)));
|
|
assert(ovskd_sof == ((f_ovw_hpos == 0) && (f_ovw_vpos == 0)));
|
|
assert(prvpos == f_pskd_vpos);
|
|
assert(ovw_eof == f_ovw_sof);
|
|
assert(ovvpos == f_ovw_vpos);
|
|
end
|
|
`endif
|
|
// }}}
|
|
end endgenerate
|
|
// }}}
|
|
|
|
// prhpos, prvpos
|
|
// {{{
|
|
always @(posedge ACLK)
|
|
if (!ARESETN)
|
|
begin
|
|
prhpos <= 0;
|
|
prvpos <= 0;
|
|
end else if (pskd_valid && pskd_ready)
|
|
begin
|
|
if (pskd_hlast)
|
|
begin
|
|
prhpos <= 0;
|
|
prvpos <= prvpos + 1;
|
|
if (pskd_vlast)
|
|
prvpos <= 0;
|
|
end else
|
|
prhpos <= prhpos + 1;
|
|
|
|
if (pskd_vlast || pskd_sof)
|
|
prvpos <= 0;
|
|
end
|
|
`ifdef FORMAL
|
|
always @(*)
|
|
if (ARESETN)
|
|
begin
|
|
assert(prhpos == f_pskd_hpos);
|
|
if (!f_pskd_sof)
|
|
assert(f_pskd_vpos == prvpos);
|
|
else if (f_pskd_known)
|
|
begin
|
|
if (lines_per_frame == 0)
|
|
begin
|
|
assert(!OPT_TUSER_IS_SOF
|
|
|| prvpos == f_vid_height);
|
|
end else
|
|
assert(prvpos == 0);
|
|
end
|
|
|
|
if (prvpos < f_vid_height)
|
|
begin
|
|
assert(prvpos == f_pskd_vpos);
|
|
end else if (prvpos != f_pskd_vpos)
|
|
begin
|
|
assert(!f_pri_known
|
|
|| (f_pri_sof && prvpos == f_vid_height));
|
|
assert(prvpos == f_vid_height);
|
|
assert(f_pskd_vpos == 0);
|
|
assert(prhpos == 0);
|
|
end
|
|
end
|
|
`endif
|
|
// }}}
|
|
|
|
// ovhpos, ovvpos
|
|
// {{{
|
|
always @(posedge ACLK)
|
|
if (!ARESETN)
|
|
begin
|
|
ovhpos <= 0;
|
|
ovvpos <= 0;
|
|
end else if (ovskd_valid && ovskd_ready)
|
|
begin
|
|
if (ovskd_sof)
|
|
ovvpos <= 0;
|
|
if (ovskd_hlast)
|
|
begin
|
|
ovhpos <= 0;
|
|
ovvpos <= ovvpos + 1;
|
|
if (ovskd_vlast)
|
|
ovvpos <= 0;
|
|
end else
|
|
ovhpos <= ovhpos + 1;
|
|
end
|
|
`ifdef FORMAL
|
|
// {{{
|
|
always @(*)
|
|
if (ARESETN)
|
|
begin
|
|
assert(ovhpos == f_ovw_hpos);
|
|
assert(ovvpos == f_ovw_vpos
|
|
|| (ovvpos == f_ovw_height && f_ovw_sof && f_ovw_known));
|
|
if (ovskd_valid)
|
|
assert(ovskd_hlast == (f_ovw_hpos == f_ovw_width-1));
|
|
end
|
|
// }}}
|
|
`endif
|
|
// }}}
|
|
// }}}
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// (Optional) line breaks
|
|
// {{{
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
//
|
|
|
|
always @(posedge ACLK)
|
|
if (!ARESETN || !OPT_LINE_BREAK)
|
|
pix_line_pause <= 1'b0;
|
|
else
|
|
pix_line_pause <= pskd_valid && pskd_ready && pskd_hlast;
|
|
|
|
always @(posedge ACLK)
|
|
if (!ARESETN || !OPT_LINE_BREAK)
|
|
ov_line_pause <= 1'b0;
|
|
else
|
|
ov_line_pause <= ovskd_valid && ovskd_ready && ovskd_hlast;
|
|
|
|
`ifdef FORMAL
|
|
always @(*)
|
|
if (ARESETN)
|
|
begin
|
|
if (!OPT_LINE_BREAK || f_pskd_hpos != 0)
|
|
assert(!pix_line_pause);
|
|
if (!OPT_LINE_BREAK || f_ovw_hpos != 0)
|
|
assert(!ov_line_pause);
|
|
end
|
|
`endif
|
|
// }}}
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Overlay flags: in_overlay, o_err, frame_err, ovw_eof, ovw_eol
|
|
// {{{
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
//
|
|
|
|
// ovw_eof, ovw_eol
|
|
// {{{
|
|
always @(posedge ACLK)
|
|
if (!ARESETN)
|
|
begin
|
|
ovw_eof <= !OPT_TUSER_IS_SOF;
|
|
ovw_eol <= 1;
|
|
end else if (ovskd_valid && ovskd_ready)
|
|
begin
|
|
ovw_eol <= ovskd_hlast;
|
|
ovw_eof <= ovskd_hlast && ovskd_vlast;
|
|
end
|
|
`ifdef FORMAL
|
|
always @(*)
|
|
if (ARESETN)
|
|
begin
|
|
assert(ovw_eol == (f_ovw_hpos == 0));
|
|
if (ovw_eof)
|
|
assert(ovw_eol);
|
|
//
|
|
// ovw_eof is checked in the big generate block above
|
|
// if (f_ovw_known)
|
|
// assert(ovw_eof == f_ovw_sof);
|
|
end
|
|
`endif
|
|
// }}}
|
|
|
|
// in_frame -- y-handling
|
|
// {{{
|
|
always @(posedge ACLK)
|
|
if (!ARESETN)
|
|
in_frame <= 0;
|
|
else begin
|
|
if (in_frame && ovskd_valid && ovskd_ready && ovskd_vlast
|
|
&& ((prvpos > i_vpos)
|
|
||(prvpos == i_vpos && prhpos > i_hpos)))
|
|
in_frame <= 0;
|
|
|
|
if (pskd_valid && pskd_ready)
|
|
begin
|
|
if (pskd_vlast)
|
|
in_frame <= (i_vpos == 0);
|
|
else if (pskd_hlast && !in_frame)
|
|
in_frame <= (i_vpos == prvpos + 1);
|
|
end
|
|
end
|
|
`ifdef FORMAL
|
|
// {{{
|
|
always @(posedge ACLK)
|
|
if (ARESETN && !frame_err)
|
|
begin
|
|
if (ovw_eof && f_pri_vpos != i_vpos)
|
|
assert(!in_frame || (i_hpos >= f_vid_width));
|
|
end
|
|
|
|
always @(posedge ACLK)
|
|
if (ARESETN && !frame_err // && !w_frame_err
|
|
&& (f_pri_known && $past(f_pri_known))
|
|
&& (f_ovw_known && $past(f_ovw_known)
|
|
&& !f_ovw_sof && !$past(f_ovw_sof)
|
|
&& (lines_per_frame != 0)
|
|
&& $stable(lines_per_frame))
|
|
)
|
|
begin
|
|
if (in_overlay)
|
|
assert(in_frame);
|
|
|
|
if (f_pri_vpos < i_vpos)
|
|
begin
|
|
assert(!in_frame);
|
|
end else if (f_pri_vpos
|
|
>= { 1'b0, i_vpos } + { 1'b0, f_ovw_height })
|
|
begin
|
|
// Was ... if (f_sum_ypos != prvpos)
|
|
assert(!in_frame
|
|
// It is possible that we passed the end of the
|
|
// primary line, but not (yet) the end of the
|
|
// overlay line. In this case, we'd be on the
|
|
// last overline of the overlay frame, and we
|
|
// wouldn't have come across the EOL yet.
|
|
|| ((f_pri_vpos == { 1'b0, i_vpos }
|
|
+ { 1'b0, f_ovw_height })
|
|
&& !ovw_eol));
|
|
end else if ({ 1'b0, f_pri_vpos } + 1
|
|
== { 1'b0, i_vpos }+{ 1'b0, f_ovw_height })
|
|
begin
|
|
assert(in_frame != ovw_eof);
|
|
end else begin
|
|
assert(in_frame);
|
|
end
|
|
end
|
|
// }}}
|
|
`endif
|
|
// }}}
|
|
|
|
// in_overlay
|
|
// {{{
|
|
always @(posedge ACLK)
|
|
if (!ARESETN)
|
|
in_overlay <= 0;
|
|
else if (pskd_valid && pskd_ready)
|
|
begin
|
|
if (pskd_vlast)
|
|
in_overlay <= (i_hpos == 0) && (i_vpos == 0);
|
|
else if (pskd_hlast)
|
|
begin
|
|
in_overlay <= 0;
|
|
if (in_frame && !ovw_eof)
|
|
in_overlay <= !ovskd_vlast;
|
|
if (i_vpos == prvpos + 1)
|
|
in_overlay <= 1'b1;
|
|
|
|
if (i_hpos != 0)
|
|
in_overlay <= 0;
|
|
end else if (ovskd_hlast && in_overlay)
|
|
in_overlay <= 0;
|
|
else if (prhpos + 1 == i_hpos)
|
|
in_overlay <= in_frame;
|
|
end
|
|
|
|
`ifdef FORMAL
|
|
// {{{
|
|
(* keep *) reg [LGFRAME:0] f_sum_xpos, f_sum_ypos;
|
|
always @(*)
|
|
begin
|
|
f_sum_xpos = { 1'b0, i_hpos } + { 1'b0, f_ovw_hpos };
|
|
f_sum_ypos = { 1'b0, i_vpos } + { 1'b0, f_ovw_vpos };
|
|
end
|
|
|
|
always @(posedge ACLK)
|
|
if (ARESETN && !frame_err)
|
|
begin
|
|
if (f_pri_hpos != i_hpos && ovw_eol)
|
|
assert(!in_overlay);
|
|
|
|
if (in_overlay && (f_pri_hpos != i_hpos || !w_frame_err))
|
|
assert(f_pri_hpos == f_sum_xpos);
|
|
|
|
if ((f_pri_hpos < i_hpos)
|
|
|| f_pri_hpos >= { 1'b0, i_hpos }
|
|
+ { 1'b0, f_ovw_width })
|
|
begin
|
|
assert(!in_overlay);
|
|
end else if (!in_frame && f_pri_vpos > i_vpos)
|
|
begin
|
|
assert(!in_overlay);
|
|
end else if (f_pri_vpos < i_vpos)
|
|
begin
|
|
assert(!in_overlay);
|
|
end
|
|
|
|
if (ovw_eof && (f_pri_vpos == i_vpos)
|
|
&& (f_pri_hpos > { 1'b0, i_hpos }))
|
|
assert(!in_frame);
|
|
end
|
|
|
|
always @(posedge ACLK)
|
|
if (ARESETN && !frame_err && !w_frame_err)
|
|
begin
|
|
if (f_pri_hpos != i_hpos && ovw_eol)
|
|
assert(!in_overlay);
|
|
|
|
if ((f_pri_hpos < i_hpos)
|
|
|| f_pri_hpos >= { 1'b0, i_hpos }
|
|
+ { 1'b0, f_ovw_width })
|
|
begin
|
|
// Was ... if (f_sum_xpos != { 1'b0, f_pri_hpos })
|
|
assert(!in_overlay);
|
|
end else if (!in_frame && f_pri_vpos > i_vpos)
|
|
begin
|
|
assert(!in_overlay);
|
|
end else if (f_pri_vpos < i_vpos)
|
|
begin
|
|
assert(!in_overlay);
|
|
end else if (in_frame)
|
|
begin
|
|
assert(in_overlay);
|
|
end
|
|
end
|
|
// }}}
|
|
`endif
|
|
// }}}
|
|
|
|
// o_err, frame_err
|
|
// {{{
|
|
reg w_frame_err;
|
|
|
|
always @(*)
|
|
begin
|
|
w_frame_err = 1'b0;
|
|
if (in_overlay)
|
|
w_frame_err = (!ovskd_valid || !ovskd_ready);
|
|
else begin
|
|
// if (prhpos >= i_hpos && !ovw_eol)
|
|
// w_frame_err = 1;
|
|
// if (prvpos >= i_vpos && !ovw_eof)
|
|
// w_frame_err = 1;
|
|
end
|
|
|
|
if (prhpos == i_hpos)
|
|
begin
|
|
if (!ovw_eol)
|
|
w_frame_err = 1;
|
|
if (prvpos == i_vpos && !ovw_eof)
|
|
w_frame_err = 1;
|
|
end
|
|
end
|
|
|
|
initial frame_err = OPT_TUSER_IS_SOF;
|
|
always @(posedge ACLK)
|
|
if (!ARESETN)
|
|
begin
|
|
frame_err <= OPT_TUSER_IS_SOF;
|
|
end else if (!frame_err && pskd_valid && pskd_ready)
|
|
begin
|
|
frame_err <= w_frame_err;
|
|
end else if ((ovw_eof || ovskd_valid && ovskd_ready && ovskd_vlast)
|
|
&& ((pskd_valid && pskd_ready && pskd_vlast)
|
|
|| (prvpos < i_vpos)))
|
|
begin
|
|
frame_err <= 0;
|
|
end
|
|
|
|
assign o_err = frame_err && i_enable;
|
|
`ifdef FORMAL
|
|
reg f_ovw_recovering,
|
|
f_ovw_final_line,
|
|
f_offscreen;
|
|
(* keep *) reg [3:0] f_region;
|
|
|
|
always @(*)
|
|
begin
|
|
f_ovw_final_line = 0;
|
|
if (((f_sum_ypos + 1 == f_vid_height)
|
|
|| (f_ovw_vpos + 1 == f_ovw_height))
|
|
&& (f_sum_xpos >= f_vid_width))
|
|
f_ovw_final_line = 1;
|
|
|
|
f_ovw_recovering = f_ovw_final_line;
|
|
if (f_ovw_vpos + i_vpos >= f_vid_height)
|
|
f_ovw_recovering = 1;
|
|
|
|
f_offscreen = (i_hpos >= f_vid_width);
|
|
end
|
|
|
|
always @(posedge ACLK)
|
|
if (ARESETN && $past(ARESETN))
|
|
begin
|
|
if (f_pri_hpos < i_hpos)
|
|
begin
|
|
// Left column
|
|
// {{{
|
|
assert(!in_overlay);
|
|
|
|
if (f_pri_vpos < i_vpos)
|
|
begin // #0: Top left corner
|
|
// {{{
|
|
f_region <= 0;
|
|
assert(!in_frame);
|
|
assert(frame_err|| ovw_eof || f_ovw_recovering);
|
|
// }}}
|
|
end else if (f_pri_vpos < { 1'b0, i_vpos } + {1'b0, f_ovw_height})
|
|
begin // #4: Left of overlay area
|
|
// {{{
|
|
f_region <= 4;
|
|
if (f_pri_vpos == i_vpos)
|
|
assert(frame_err || in_frame);
|
|
|
|
if (in_frame && !frame_err)
|
|
begin
|
|
if (f_pri_vpos == i_vpos)
|
|
begin
|
|
assert(ovw_eof // !!!
|
|
|| f_ovw_recovering);
|
|
end else if (ovw_eol)
|
|
begin
|
|
assert(f_pri_vpos== f_sum_ypos
|
|
|| f_offscreen);
|
|
end else if (ovw_eof)
|
|
begin
|
|
assert(f_pri_vpos == i_vpos);
|
|
end else if (f_pri_vpos == i_vpos)
|
|
begin
|
|
assert(f_ovw_recovering);
|
|
end else if (f_pri_vpos > i_vpos)
|
|
begin
|
|
assert(f_sum_ypos + 1
|
|
== f_pri_vpos);
|
|
end
|
|
end
|
|
// }}}
|
|
end else begin // #8: Below the overlay area
|
|
// {{{
|
|
f_region <= 8;
|
|
assert(frame_err || !in_frame
|
|
|| i_hpos >= f_vid_width
|
|
|| f_ovw_final_line); // !!!
|
|
if (!frame_err)
|
|
begin
|
|
assert(ovw_eof || f_offscreen
|
|
|| (!ovw_eol && f_ovw_final_line));
|
|
end
|
|
// }}}
|
|
end
|
|
// }}}
|
|
end else if (f_pri_hpos < { 1'b0, i_hpos }+{ 1'b0, f_ovw_width})
|
|
begin
|
|
// Center column
|
|
// {{{
|
|
if (f_pri_vpos < i_vpos)
|
|
begin
|
|
assert(!in_frame);
|
|
|
|
// #1: Top middle section
|
|
f_region <= 1;
|
|
assert(frame_err|| ovw_eof || f_ovw_recovering);
|
|
end else if (f_pri_vpos < { 1'b0, i_vpos } + {1'b0, f_ovw_height})
|
|
begin // #5: Valid middle section
|
|
// {{{
|
|
f_region <= 5;
|
|
if (!frame_err)
|
|
begin
|
|
assert(in_frame);
|
|
assert(in_overlay);
|
|
if (ovw_eof)
|
|
begin
|
|
assert(f_pri_vpos == i_vpos
|
|
&&f_pri_hpos == i_hpos);
|
|
end
|
|
|
|
if (ovw_eol)
|
|
begin
|
|
assert(f_pri_hpos == i_hpos);
|
|
end
|
|
|
|
if (f_sum_xpos != f_pri_hpos)
|
|
begin
|
|
assert(w_frame_err);
|
|
assert(f_pri_hpos == i_hpos
|
|
&& !ovw_eol);
|
|
end
|
|
|
|
if (f_sum_ypos != f_pri_vpos)
|
|
begin
|
|
assert(w_frame_err);
|
|
assert(!ovw_eol
|
|
|| (f_pri_vpos == i_vpos
|
|
&& f_ovw_recovering));
|
|
end
|
|
end
|
|
// }}}
|
|
end else begin
|
|
// #9: Bottom center section
|
|
f_region <= 9;
|
|
assert(frame_err || !in_frame
|
|
|| (!ovw_eol && f_ovw_final_line));
|
|
assert(frame_err || ovw_eof || f_offscreen
|
|
|| (!ovw_eol && f_ovw_final_line));
|
|
end
|
|
// }}}
|
|
end else begin
|
|
// Right column
|
|
// {{{
|
|
assert(frame_err || !in_overlay);
|
|
|
|
if (f_pri_vpos < i_vpos)
|
|
begin // #2: Top right corner
|
|
// {{{
|
|
f_region <= 2;
|
|
assert(frame_err|| ovw_eof || f_ovw_recovering);
|
|
// }}}
|
|
end else if (f_pri_vpos < { 1'b0, i_vpos } + {1'b0, f_ovw_height})
|
|
begin // #6: Right of overlay area
|
|
// {{{
|
|
f_region <= 6;
|
|
assert(frame_err || ovw_eol);
|
|
assert(frame_err || in_frame
|
|
|| (f_pri_vpos + 1 == { 1'b0, i_vpos } + { 1'b0, f_ovw_height }));
|
|
// }}}
|
|
end else begin // #10: Bottom right corner
|
|
// {{{
|
|
f_region <= 10;
|
|
assert(frame_err || ovw_eof || f_offscreen
|
|
|| (!ovw_eol && f_ovw_vpos + 1 == f_ovw_height
|
|
&& f_ovw_hpos + i_hpos >= f_vid_width));
|
|
assert(frame_err || !in_frame);
|
|
// }}}
|
|
end
|
|
// }}}
|
|
end
|
|
end else
|
|
f_region <= 12;
|
|
|
|
always @(posedge ACLK)
|
|
if (ARESETN && $past(ARESETN) && !ovw_eof)
|
|
begin
|
|
if (f_pri_vpos >= i_vpos
|
|
&& f_pri_vpos != f_sum_ypos)
|
|
begin
|
|
if (f_pri_hpos >= i_hpos
|
|
&& f_pri_hpos != f_sum_xpos)
|
|
begin
|
|
assert(ovw_eol || frame_err || w_frame_err);
|
|
end
|
|
end
|
|
|
|
/*
|
|
if (f_pri_vpos > i_vpos // && !ovw_eof
|
|
&& ((ovw_eol && f_pri_hpos <= i_hpos
|
|
&& f_pri_vpos != f_sum_ypos)
|
|
|| (!ovw_eol && f_pri_hpos <= i_hpos
|
|
&& f_pri_vpos != f_sum_ypos + 1)
|
|
|| (!ovw_eol && f_pri_hpos > i_hpos
|
|
&& f_pri_vpos != f_sum_ypos)
|
|
))
|
|
assert(frame_err || w_frame_err);
|
|
*/
|
|
end
|
|
|
|
always @(posedge ACLK)
|
|
if (ARESETN && OPT_TUSER_IS_SOF)
|
|
begin
|
|
if (!f_pri_known || lines_per_frame == 0)
|
|
assert(frame_err);
|
|
if (!f_ovw_known || f_ovw_lines_per_frame == 0)
|
|
assert(frame_err);
|
|
if (ovw_eof)
|
|
assert(f_ovw_lines_per_frame != 0);
|
|
end
|
|
`endif
|
|
// }}}
|
|
|
|
// }}}
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Mix the two channels together
|
|
// {{{
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
//
|
|
|
|
// mix_pixel
|
|
// {{{
|
|
generate if (ALPHA_BITS == 0)
|
|
begin : NO_ALPHA
|
|
// {{{
|
|
reg [DW-1:0] r_mix_pixel;
|
|
|
|
always @(posedge ACLK)
|
|
if (pskd_valid && pskd_ready)
|
|
begin
|
|
r_mix_pixel <= pskd_data;
|
|
if (in_overlay && ovskd_valid && !frame_err
|
|
&& i_enable)
|
|
r_mix_pixel <= ovskd_data;
|
|
end
|
|
|
|
assign mix_pixel = r_mix_pixel;
|
|
// }}}
|
|
end else if (ALPHA_BITS == 1)
|
|
begin: ALPHA_MASK
|
|
// {{{
|
|
reg [DW-1:0] r_mix_pixel;
|
|
|
|
always @(posedge ACLK)
|
|
if (pskd_valid && pskd_ready)
|
|
begin
|
|
r_mix_pixel <= pskd_data;
|
|
if (in_overlay && ovskd_valid && i_enable
|
|
&& !frame_err && ovskd_data[DW])
|
|
r_mix_pixel <= ovskd_data[DW-1:0];
|
|
end
|
|
|
|
assign mix_pixel = r_mix_pixel;
|
|
// }}}
|
|
end else begin : ALPHA_MIXING
|
|
// {{{
|
|
genvar clr;
|
|
reg [ALPHA_BITS:0] alpha, negalpha;
|
|
reg [DW-1:0] pri_pixel, ovw_pixel;
|
|
|
|
// pri_pixel, ovw_pixel
|
|
// {{{
|
|
always @(posedge ACLK)
|
|
if (!ARESETN)
|
|
begin
|
|
pri_pixel <= 0;
|
|
ovw_pixel <= 0;
|
|
alpha <= TRANSPARENT;
|
|
end else if (pskd_valid && pskd_ready)
|
|
begin
|
|
pri_pixel <= pskd_data;
|
|
ovw_pixel <= ovskd_data[DW-1:0];
|
|
// Verilator lint_off WIDTH
|
|
alpha <= ovskd_data[ALPHA_BITS + DW-1 : DW]
|
|
+ ovskd_data[ALPHA_BITS + DW-1];
|
|
negalpha <= (1<<ALPHA_BITS)
|
|
- ovskd_data[ALPHA_BITS + DW-1 : DW]
|
|
- ovskd_data[ALPHA_BITS + DW-1];
|
|
// Verilator lint_on WIDTH
|
|
if (!ovskd_valid || frame_err || !in_overlay
|
|
|| !i_enable)
|
|
begin
|
|
ovw_pixel <= 0;
|
|
alpha <= TRANSPARENT;
|
|
end
|
|
end
|
|
// }}}
|
|
|
|
// mix_pixel
|
|
// {{{
|
|
for(clr=0; clr<COLORS; clr=clr+1)
|
|
begin : MIXCLR
|
|
// Verilator lint_off UNUSED
|
|
reg [BPP + ALPHA_BITS:0] pclr, oclr, sclr;
|
|
wire [BPP-1:0] pri_clr, ovw_clr;
|
|
|
|
assign pri_clr = pri_pixel[clr * BPP +: BPP];
|
|
assign ovw_clr = ovw_pixel[clr * BPP +: BPP];
|
|
// Verilator lint_on UNUSED
|
|
|
|
always @(posedge ACLK)
|
|
if (pix_loaded && pix_ready)
|
|
pclr <= pri_clr * alpha;
|
|
|
|
always @(posedge ACLK)
|
|
if (pix_loaded && pix_ready)
|
|
oclr <= ovw_clr * negalpha;
|
|
|
|
always @(posedge ACLK)
|
|
if (mpy_loaded && mpy_ready)
|
|
sclr <= pclr + oclr;
|
|
|
|
assign mix_pixel[clr * BPP +: BPP] = sclr[ALPHA_BITS +: BPP];
|
|
end
|
|
// }}}
|
|
// }}}
|
|
end endgenerate
|
|
// }}}
|
|
|
|
// mix_valid, mix_hlast, mix_vlast, mix_sof
|
|
// {{{
|
|
generate if (ALPHA_BITS <= 1)
|
|
begin : NO_ALPHA_PIPELINE
|
|
assign pskd_ready = !pix_line_pause
|
|
&&(!mix_valid || mix_ready);
|
|
// {{{
|
|
reg r_mix_sof, r_mix_valid, r_mix_hlast, r_mix_vlast;
|
|
|
|
// r_mix_valid
|
|
// {{{
|
|
initial r_mix_valid = 0;
|
|
always @(posedge ACLK)
|
|
if (!ARESETN)
|
|
r_mix_valid <= 1'b0;
|
|
else if (pskd_valid && pskd_ready)
|
|
r_mix_valid <= 1'b1;
|
|
else if (mix_ready)
|
|
r_mix_valid <= 1'b0;
|
|
// }}}
|
|
|
|
// r_mix_[vh]last, r_mix_sof
|
|
// {{{
|
|
always @(posedge ACLK)
|
|
if (pskd_valid && pskd_ready)
|
|
begin
|
|
r_mix_hlast <= pskd_hlast;
|
|
r_mix_vlast <= pskd_vlast;
|
|
r_mix_sof <= pskd_sof;
|
|
end
|
|
// }}}
|
|
|
|
// mix_*
|
|
// {{{
|
|
assign mix_valid = r_mix_valid;
|
|
assign mix_hlast = r_mix_hlast;
|
|
assign mix_vlast = r_mix_vlast;
|
|
assign mix_sof = r_mix_sof;
|
|
// }}}
|
|
|
|
// Keep Verilator happy
|
|
// {{{
|
|
wire unused_no_alpha;
|
|
assign pix_ready = 1'b0;
|
|
assign { pix_loaded, mpy_loaded, mpy_ready } = 0;
|
|
assign unused_no_alpha = &{ 1'b0, pix_loaded, mpy_loaded,
|
|
pix_ready, mix_valid, mpy_ready };
|
|
// }}}
|
|
`ifdef FORMAL
|
|
// {{{
|
|
reg r_mix_err;
|
|
|
|
always @(posedge ACLK)
|
|
if (pskd_valid && pskd_ready)
|
|
r_mix_err <= frame_err;
|
|
|
|
assign f_mix_err = r_mix_err;
|
|
|
|
always @(*)
|
|
if (ARESETN)
|
|
begin
|
|
if (!mix_valid)
|
|
begin
|
|
assert(f_pskd_hpos == f_mix_hpos);
|
|
assert(f_pskd_vpos == f_mix_vpos);
|
|
end else if (f_mix_hpos < f_vid_width-1)
|
|
begin
|
|
assert(f_pskd_hpos == f_mix_hpos + 1);
|
|
assert(f_pskd_vpos == f_mix_vpos);
|
|
end else if (f_mix_vpos < f_vid_height-1)
|
|
begin
|
|
assert(f_pskd_hpos == 0);
|
|
assert(f_pskd_vpos == f_mix_vpos + 1);
|
|
end else // if (f_mix_vpos == f_mix_height-1)
|
|
begin
|
|
assert(f_pskd_hpos == 0);
|
|
assert(f_pskd_vpos == 0);
|
|
end
|
|
end
|
|
// }}}
|
|
`endif
|
|
// }}}
|
|
end else begin : MATCH_ALPHA_PIPELINE
|
|
assign pskd_ready = !pix_line_pause
|
|
&& (!pix_loaded || pix_ready);
|
|
// {{{
|
|
reg pix_hlast, pix_vlast, pix_sof, r_pix_loaded;
|
|
reg r_mpy_loaded, mpy_hlast, mpy_vlast, mpy_sof;
|
|
reg mix_loaded, r_mix_hlast, r_mix_vlast, r_mix_sof;
|
|
|
|
assign pix_ready = !mpy_loaded || mpy_ready;
|
|
assign mpy_ready = !mix_valid || mix_ready;
|
|
|
|
always @(posedge ACLK)
|
|
if (!ARESETN)
|
|
r_pix_loaded <= 0;
|
|
else if (pskd_valid && pskd_ready)
|
|
r_pix_loaded <= 1;
|
|
else if (pix_ready)
|
|
r_pix_loaded <= 0;
|
|
|
|
always @(posedge ACLK)
|
|
if (pskd_valid && pskd_ready)
|
|
begin
|
|
pix_hlast <= pskd_hlast;
|
|
pix_vlast <= pskd_vlast;
|
|
pix_sof <= pskd_sof;
|
|
end
|
|
|
|
always @(posedge ACLK)
|
|
if (!ARESETN)
|
|
r_mpy_loaded <= 0;
|
|
else if (pix_loaded && pix_ready)
|
|
r_mpy_loaded<= 1;
|
|
else if (mpy_ready)
|
|
r_mpy_loaded <= 0;
|
|
|
|
assign mpy_loaded = r_mpy_loaded;
|
|
|
|
always @(posedge ACLK)
|
|
if (pix_loaded && pix_ready)
|
|
begin
|
|
mpy_hlast <= pix_hlast;
|
|
mpy_vlast <= pix_vlast;
|
|
mpy_sof <= pix_sof;
|
|
end
|
|
|
|
always @(posedge ACLK)
|
|
if (!ARESETN)
|
|
mix_loaded <= 0;
|
|
else if (mpy_loaded && mpy_ready)
|
|
mix_loaded <= 1;
|
|
else if (mix_ready)
|
|
mix_loaded <= 0;
|
|
|
|
always @(posedge ACLK)
|
|
if (mpy_loaded && mpy_ready)
|
|
begin
|
|
r_mix_hlast <= mpy_hlast;
|
|
r_mix_vlast <= mpy_vlast;
|
|
r_mix_sof <= mpy_sof;
|
|
end
|
|
|
|
|
|
assign pix_loaded= r_pix_loaded;
|
|
assign mix_hlast = r_mix_hlast;
|
|
assign mix_vlast = r_mix_vlast;
|
|
assign mix_sof = r_mix_sof;
|
|
|
|
assign mix_valid = mix_loaded;
|
|
// }}}
|
|
end endgenerate
|
|
// }}}
|
|
// }}}
|
|
|
|
assign ovskd_ready = (frame_err && !ovw_eof)
|
|
|| !ov_line_pause && ((!in_overlay && !ovw_eol)
|
|
|| (in_overlay && pskd_valid && pskd_ready));
|
|
|
|
// M_VID_TVALID
|
|
// {{{
|
|
assign mix_ready = !M_VID_TVALID || M_VID_TREADY;
|
|
|
|
initial M_VID_TVALID = 0;
|
|
always @(posedge ACLK)
|
|
if (!ARESETN)
|
|
M_VID_TVALID <= 0;
|
|
else if (!M_VID_TVALID || M_VID_TREADY)
|
|
M_VID_TVALID <= mix_valid;
|
|
// }}}
|
|
|
|
// M_VID_TDATA, M_VID_TLAST, M_VID_TUSER
|
|
// {{{
|
|
always @(posedge ACLK)
|
|
if (!M_VID_TVALID || M_VID_TREADY)
|
|
begin
|
|
M_VID_TDATA <= mix_pixel;
|
|
if (OPT_TUSER_IS_SOF)
|
|
begin
|
|
M_VID_TLAST <= mix_hlast;
|
|
M_VID_TUSER <= mix_sof;
|
|
end else begin
|
|
M_VID_TLAST <= mix_vlast;
|
|
M_VID_TUSER <= mix_hlast;
|
|
end
|
|
end
|
|
// }}}
|
|
|
|
// Keep Verilator happy
|
|
// {{{
|
|
// Verilator lint_off UNUSED
|
|
wire unused;
|
|
assign unused = &{ 1'b0, lines_per_frame };
|
|
// Verilator lint_on UNUSED
|
|
// }}}
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Formal properties
|
|
// {{{
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
`ifdef FORMAL
|
|
// Declarations
|
|
// {{{
|
|
wire f_pri_hlast, f_pri_vlast, f_pri_sof;
|
|
wire f_ovw_hlast, f_ovw_vlast, f_ovw_sof;
|
|
wire f_pskd_hlast, f_pskd_vlast, f_pskd_sof, f_pskd_known;
|
|
wire f_mix_hlast, f_mix_vlast, f_mix_sof, f_mix_known;
|
|
wire f_vid_hlast, f_vid_vlast, f_vid_sof, f_vid_known;
|
|
(* keep *) reg f_past_valid, f_mix_frame_valid, f_ovw_frame_valid,
|
|
f_m_frame_valid;
|
|
|
|
initial f_past_valid = 0;
|
|
always @(posedge ACLK)
|
|
f_past_valid <= 1;
|
|
|
|
always @(*)
|
|
if (!f_past_valid)
|
|
assume(!ARESETN);
|
|
|
|
always @(posedge ACLK)
|
|
if (!ARESETN)
|
|
f_ovw_frame_valid <= 0;
|
|
else if (f_ovw_lines_per_frame == f_ovw_height)
|
|
f_ovw_frame_valid <= 1;
|
|
|
|
always @(posedge ACLK)
|
|
if (!ARESETN)
|
|
f_mix_frame_valid <= 0;
|
|
else if (pskd_valid && pskd_ready && lines_per_frame == f_vid_height)
|
|
f_mix_frame_valid <= 1;
|
|
|
|
always @(posedge ACLK)
|
|
if (!ARESETN)
|
|
f_m_frame_valid <= 0;
|
|
else if ((!M_VID_TVALID || M_VID_TREADY) && f_mix_frame_valid)
|
|
f_m_frame_valid <= 1;
|
|
|
|
// }}}
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Input properties
|
|
// {{{
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
//
|
|
always @(posedge ACLK)
|
|
begin
|
|
assume($stable(i_enable));
|
|
assume($stable(i_hpos));
|
|
assume($stable(i_vpos));
|
|
end
|
|
// }}}
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// AXI stream properties
|
|
// {{{
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
//
|
|
|
|
// Priority video slave input
|
|
// {{{
|
|
always @(posedge ACLK)
|
|
if (!f_past_valid || $past(!ARESETN))
|
|
assume(!S_PRI_TVALID);
|
|
else if ($past(S_PRI_TVALID && !S_PRI_TREADY))
|
|
begin
|
|
assume(S_PRI_TVALID);
|
|
assume($stable(S_PRI_TDATA));
|
|
assume($stable(S_PRI_TLAST));
|
|
assume($stable(S_PRI_TUSER));
|
|
end
|
|
// }}}
|
|
|
|
// Overlay slave input
|
|
// {{{
|
|
always @(posedge ACLK)
|
|
if (!f_past_valid || $past(!ARESETN))
|
|
assume(!S_OVW_TVALID);
|
|
else if ($past(S_OVW_TVALID && !S_OVW_TREADY))
|
|
begin
|
|
assume(S_OVW_TVALID);
|
|
assume($stable(S_OVW_TDATA));
|
|
assume($stable(S_OVW_TLAST));
|
|
assume($stable(S_OVW_TUSER));
|
|
end
|
|
// }}}
|
|
|
|
// Video output (master)
|
|
// {{{
|
|
always @(posedge ACLK)
|
|
if (!f_past_valid || $past(!ARESETN))
|
|
assert(!M_VID_TVALID);
|
|
else if ($past(M_VID_TVALID && !M_VID_TREADY))
|
|
begin
|
|
assert(M_VID_TVALID);
|
|
assert($stable(M_VID_TDATA));
|
|
assert($stable(M_VID_TLAST));
|
|
assert($stable(M_VID_TUSER));
|
|
end
|
|
// }}}
|
|
// }}}
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Video properties
|
|
// {{{
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
//
|
|
|
|
always @(*)
|
|
begin
|
|
assume(f_vid_width >= 4);
|
|
assume(f_vid_height>= 4);
|
|
|
|
assume(f_ovw_width >= 2);
|
|
assume(f_ovw_height>= 2);
|
|
end
|
|
|
|
// f_pri_?pos
|
|
// {{{
|
|
faxivideo #(
|
|
// {{{
|
|
.PW(DW), .LGDIM(LGFRAME),
|
|
.OPT_TUSER_IS_SOF(OPT_TUSER_IS_SOF)
|
|
// }}}
|
|
) fpri (
|
|
// {{{
|
|
.i_clk(ACLK), .i_reset_n(ARESETN),
|
|
.S_VID_TVALID(S_PRI_TVALID),
|
|
.S_VID_TREADY(S_PRI_TREADY),
|
|
.S_VID_TDATA( S_PRI_TDATA),
|
|
.S_VID_TLAST( S_PRI_TLAST),
|
|
.S_VID_TUSER( S_PRI_TUSER),
|
|
//
|
|
.i_width(f_vid_width), .i_height(f_vid_height),
|
|
.o_xpos(f_pri_hpos), .o_ypos(f_pri_vpos),
|
|
.f_known_height(f_pri_known),
|
|
.o_hlast(f_pri_hlast), .o_vlast(f_pri_vlast),
|
|
.o_sof(f_pri_sof),
|
|
// }}}
|
|
);
|
|
|
|
always @(*)
|
|
if (ARESETN && S_PRI_TVALID)
|
|
begin
|
|
if (OPT_TUSER_IS_SOF)
|
|
begin
|
|
assume(S_PRI_TLAST == f_pri_hlast);
|
|
assume(S_PRI_TUSER == f_pri_sof);
|
|
end else begin
|
|
assume(S_PRI_TLAST == (f_pri_vlast && f_pri_hlast));
|
|
assume(S_PRI_TUSER == f_pri_hlast);
|
|
end
|
|
end
|
|
// }}}
|
|
|
|
// f_ovw_?pos
|
|
// {{{
|
|
faxivideo #(
|
|
// {{{
|
|
.PW(DW), .LGDIM(LGFRAME),
|
|
.OPT_TUSER_IS_SOF(OPT_TUSER_IS_SOF)
|
|
// }}}
|
|
) fovw (
|
|
// {{{
|
|
.i_clk(ACLK), .i_reset_n(ARESETN),
|
|
.S_VID_TVALID(S_OVW_TVALID),
|
|
.S_VID_TREADY(S_OVW_TREADY),
|
|
.S_VID_TDATA( S_OVW_TDATA),
|
|
.S_VID_TLAST( S_OVW_TLAST),
|
|
.S_VID_TUSER( S_OVW_TUSER),
|
|
//
|
|
.i_width(f_ovw_width), .i_height(f_ovw_height),
|
|
.o_xpos(f_ovw_hpos), .o_ypos(f_ovw_vpos),
|
|
.f_known_height(f_ovw_known),
|
|
.o_hlast(f_ovw_hlast), .o_vlast(f_ovw_vlast),
|
|
.o_sof(f_ovw_sof),
|
|
// }}}
|
|
);
|
|
|
|
always @(*)
|
|
if (ARESETN && S_OVW_TVALID)
|
|
begin
|
|
if (OPT_TUSER_IS_SOF)
|
|
begin
|
|
assume(S_OVW_TLAST == f_ovw_hlast);
|
|
assume(S_OVW_TUSER == f_ovw_sof);
|
|
end else begin
|
|
assume(S_OVW_TLAST == (f_ovw_vlast && f_ovw_hlast));
|
|
assume(S_OVW_TUSER == f_ovw_hlast);
|
|
end
|
|
end
|
|
// }}}
|
|
|
|
// S_PRI_TLAST, S_PRI_TUSER
|
|
// {{{
|
|
generate if (OPT_TUSER_IS_SOF)
|
|
begin : ASSUME_SOF
|
|
always @(*)
|
|
if (S_PRI_TVALID)
|
|
begin
|
|
assume(S_PRI_TLAST == (f_pri_hpos == f_vid_width-1));
|
|
assume(S_PRI_TUSER == (f_pri_hpos == 0 && f_pri_vpos == 0));
|
|
end
|
|
end else begin : ASSUME_VLAST
|
|
always @(*)
|
|
if (S_PRI_TVALID)
|
|
begin
|
|
assume(S_PRI_TUSER == (f_pri_hpos == f_vid_width-1));
|
|
if (f_pri_vpos < f_vid_height-1)
|
|
assume(!S_PRI_TLAST);
|
|
else if (S_PRI_TUSER)
|
|
assume(S_PRI_TLAST == (f_pri_vpos == f_vid_height-1));
|
|
end
|
|
end endgenerate
|
|
// }}}
|
|
|
|
// S_OVW_TLAST, S_OVW_TUSER
|
|
// {{{
|
|
generate if (OPT_TUSER_IS_SOF)
|
|
begin
|
|
always @(*)
|
|
if (S_OVW_TVALID)
|
|
begin
|
|
assume(S_OVW_TLAST == (f_ovw_hpos == f_ovw_width-1));
|
|
assume(S_OVW_TUSER == (f_ovw_hpos == 0 && f_ovw_vpos == 0));
|
|
end
|
|
end else begin
|
|
always @(*)
|
|
if (S_OVW_TVALID)
|
|
begin
|
|
assume(S_OVW_TUSER == (f_ovw_hpos == f_ovw_width-1));
|
|
if (f_ovw_vpos < f_ovw_height-1)
|
|
assume(!S_OVW_TLAST);
|
|
else if (S_OVW_TUSER)
|
|
assume(S_OVW_TLAST == (f_ovw_vpos == f_ovw_height-1));
|
|
end
|
|
end endgenerate
|
|
// }}}
|
|
|
|
// f_vid_?pos
|
|
// {{{
|
|
faxivideo #(
|
|
// {{{
|
|
.PW(DW), .LGDIM(LGFRAME),
|
|
.OPT_TUSER_IS_SOF(OPT_TUSER_IS_SOF)
|
|
// }}}
|
|
) fvid (
|
|
// {{{
|
|
.i_clk(ACLK), .i_reset_n(ARESETN),
|
|
.S_VID_TVALID(M_VID_TVALID),
|
|
.S_VID_TREADY(M_VID_TREADY),
|
|
.S_VID_TDATA( M_VID_TDATA),
|
|
.S_VID_TLAST( M_VID_TLAST),
|
|
.S_VID_TUSER( M_VID_TUSER),
|
|
//
|
|
.i_width(f_vid_width), .i_height(f_vid_height),
|
|
.o_xpos(f_vid_hpos), .o_ypos(f_vid_vpos),
|
|
.f_known_height(f_vid_known),
|
|
.o_hlast(f_vid_hlast), .o_vlast(f_vid_vlast),
|
|
.o_sof(f_vid_sof),
|
|
// }}}
|
|
);
|
|
// }}}
|
|
|
|
// f_mix_?pos
|
|
// {{{
|
|
faxivideo #(
|
|
// {{{
|
|
.PW(DW), .LGDIM(LGFRAME),
|
|
.OPT_TUSER_IS_SOF(OPT_TUSER_IS_SOF)
|
|
// }}}
|
|
) fmix (
|
|
// {{{
|
|
.i_clk(ACLK), .i_reset_n(ARESETN),
|
|
.S_VID_TVALID(mix_valid),
|
|
.S_VID_TREADY(mix_ready),
|
|
.S_VID_TDATA( mix_pixel),
|
|
.S_VID_TLAST( (OPT_TUSER_IS_SOF) ? mix_hlast : mix_vlast),
|
|
.S_VID_TUSER( (OPT_TUSER_IS_SOF) ? mix_sof : mix_hlast),
|
|
//
|
|
.i_width(f_vid_width), .i_height(f_vid_height),
|
|
.o_xpos(f_mix_hpos), .o_ypos(f_mix_vpos),
|
|
.f_known_height(f_mix_known),
|
|
.o_hlast(f_mix_hlast), .o_vlast(f_mix_vlast),
|
|
.o_sof(f_mix_sof),
|
|
// }}}
|
|
);
|
|
// }}}
|
|
|
|
// f_mix_hlast, f_mix_sof, f_mix_vlast
|
|
// {{{
|
|
always @(*)
|
|
if (ARESETN && mix_valid)
|
|
begin
|
|
assert(mix_hlast == (f_mix_hpos == f_vid_width-1));
|
|
assert(mix_sof == (f_mix_vpos == 0 && f_mix_hpos == 0));
|
|
if (mix_vlast || f_mix_known || f_pri_known)
|
|
assert(f_pri_sof || (mix_vlast == (mix_hlast && f_mix_vpos == f_vid_height-1)));
|
|
end
|
|
// }}}
|
|
|
|
always @(*)
|
|
if (ARESETN)
|
|
begin
|
|
if (!M_VID_TVALID)
|
|
begin
|
|
assert(f_mix_hpos == f_vid_hpos);
|
|
assert(f_mix_vpos == f_vid_vpos);
|
|
end else if (f_vid_hpos < f_vid_width-1)
|
|
begin
|
|
assert(f_mix_hpos == f_vid_hpos + 1);
|
|
assert(f_mix_vpos == f_vid_vpos);
|
|
end else // if (f_vid_hpos == f_vid_width-1)
|
|
begin
|
|
assert(f_mix_hpos == 0);
|
|
if (f_vid_vpos == f_vid_height-1)
|
|
assert(f_mix_vpos == 0);
|
|
else
|
|
assert(f_mix_vpos == f_vid_vpos + 1);
|
|
end
|
|
end
|
|
|
|
generate if (OPT_TUSER_IS_SOF)
|
|
begin : CHECK_VLAST
|
|
|
|
always @(*)
|
|
if (ARESETN && lines_per_frame > 0)
|
|
begin
|
|
assert(lines_per_frame == f_vid_height);
|
|
if (pskd_valid)
|
|
assert(pskd_vlast == (pskd_hlast && f_pskd_vpos == f_vid_height-1));
|
|
end else if (ARESETN)
|
|
begin
|
|
if (pskd_valid)
|
|
assert(!pskd_vlast);
|
|
if (mix_valid)
|
|
assert(!mix_vlast);
|
|
end
|
|
|
|
end endgenerate
|
|
|
|
// f_pskd_?pos
|
|
// {{{
|
|
faxivideo #(
|
|
// {{{
|
|
.PW(DW), .LGDIM(LGFRAME),
|
|
.OPT_TUSER_IS_SOF(OPT_TUSER_IS_SOF)
|
|
// }}}
|
|
) fpskd (
|
|
// {{{
|
|
.i_clk(ACLK), .i_reset_n(ARESETN),
|
|
.S_VID_TVALID(pskd_valid),
|
|
.S_VID_TREADY(pskd_ready),
|
|
.S_VID_TDATA( pskd_data),
|
|
.S_VID_TLAST( (OPT_TUSER_IS_SOF) ? pskd_hlast : pskd_vlast),
|
|
.S_VID_TUSER( (OPT_TUSER_IS_SOF) ? pskd_sof : pskd_hlast),
|
|
//
|
|
.i_width(f_vid_width), .i_height(f_vid_height),
|
|
.o_xpos(f_pskd_hpos), .o_ypos(f_pskd_vpos),
|
|
.f_known_height(f_pskd_known),
|
|
.o_hlast(f_pskd_hlast), .o_vlast(f_pskd_vlast),
|
|
.o_sof(f_pskd_sof),
|
|
// }}}
|
|
);
|
|
|
|
always @(*)
|
|
begin
|
|
assert(f_pskd_sof == f_pri_sof);
|
|
assert(f_pskd_hpos == f_pri_hpos);
|
|
assert(f_pskd_vpos == f_pri_vpos);
|
|
assert(f_pskd_known == f_pri_known);
|
|
end
|
|
// }}}
|
|
|
|
// Relate f_pskd to f_pri (they are the same)
|
|
// {{{
|
|
always @(*)
|
|
if (ARESETN)
|
|
begin
|
|
if (1 || S_PRI_TREADY)
|
|
begin
|
|
assert(f_pskd_hpos == f_pri_hpos);
|
|
assert(f_pskd_vpos == f_pri_vpos);
|
|
end else if (f_vid_hpos > 0)
|
|
begin
|
|
assert(f_pskd_hpos + 1 == f_pri_hpos);
|
|
assert(f_pskd_vpos <= f_pri_vpos);
|
|
end else if (f_vid_vpos > 0)
|
|
begin
|
|
assert(f_pskd_hpos == f_vid_width -1);
|
|
assert(f_pskd_vpos + 1 == f_pri_vpos);
|
|
end else begin
|
|
assert(f_pskd_hpos == f_vid_width -1);
|
|
assert(f_pskd_vpos == f_vid_height - 1);
|
|
end
|
|
end
|
|
// }}}
|
|
|
|
// pskd_hlast, pskd_sof
|
|
// {{{
|
|
generate if (OPT_TUSER_IS_SOF)
|
|
begin : CHECK_LINES_PER_FRAME
|
|
always @(posedge ACLK)
|
|
if (f_past_valid && $past(ARESETN))
|
|
begin
|
|
if ($past(lines_per_frame == f_vid_height))
|
|
assert(lines_per_frame == f_vid_height);
|
|
if (lines_per_frame != 0)
|
|
assert(f_pri_known);
|
|
end
|
|
end endgenerate
|
|
|
|
always @(*)
|
|
if (ARESETN)
|
|
begin
|
|
if (!f_pri_known)
|
|
begin
|
|
assert(lines_per_frame == 0);
|
|
end else begin
|
|
assert(lines_per_frame == f_vid_height
|
|
|| lines_per_frame == 0);
|
|
end
|
|
end
|
|
|
|
always @(*)
|
|
if (pskd_valid)
|
|
begin
|
|
assert(pskd_hlast == f_pskd_hlast);
|
|
assert(pskd_sof == f_pskd_sof);
|
|
if (lines_per_frame == f_vid_height)
|
|
begin
|
|
assert(f_pskd_known);
|
|
assert(pskd_vlast == (pskd_hlast && f_pskd_vlast));
|
|
end
|
|
end
|
|
// }}}
|
|
|
|
// }}}
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Contract properties
|
|
// {{{
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
//
|
|
(* anyconst *) reg fc_check;
|
|
(* anyconst *) reg [LGFRAME-1:0] fc_pri_hpos, fc_pri_vpos;
|
|
(* anyconst *) reg [LGFRAME-1:0] fc_ovw_hpos, fc_ovw_vpos;
|
|
(* anyconst *) reg [LGFRAME-1:0] fc_off_hpos, fc_off_vpos;
|
|
(* anyconst *) reg [DW-1:0] fc_pri_pixel;
|
|
(* anyconst *) reg [DW+ALPHA_BITS-1:0] fc_ovw_pixel;
|
|
reg f_vid_err;
|
|
|
|
always @(*)
|
|
begin
|
|
assume(fc_pri_hpos < f_vid_width);
|
|
assume(fc_pri_vpos < f_vid_height);
|
|
|
|
assume(fc_off_hpos < f_vid_width);
|
|
assume(fc_off_vpos < f_vid_height);
|
|
|
|
assume(fc_ovw_hpos < f_ovw_width);
|
|
assume(fc_ovw_vpos < f_ovw_height);
|
|
|
|
end
|
|
|
|
always @(posedge ACLK)
|
|
if (!ARESETN)
|
|
f_vid_err <= 0;
|
|
else if (!M_VID_TVALID || M_VID_TREADY)
|
|
f_vid_err <= f_mix_err;
|
|
|
|
always @(*)
|
|
if (fc_check && ARESETN)
|
|
begin
|
|
if (S_PRI_TVALID && f_pri_hpos == fc_pri_hpos
|
|
&& f_pri_vpos == fc_pri_vpos)
|
|
assume(S_PRI_TDATA == fc_pri_pixel);
|
|
if (S_OVW_TVALID && f_ovw_hpos == fc_ovw_hpos
|
|
&& f_ovw_vpos == fc_ovw_vpos)
|
|
assume(S_OVW_TDATA == fc_ovw_pixel);
|
|
|
|
assume(fc_off_hpos == i_hpos);
|
|
assume(fc_off_vpos == i_vpos);
|
|
|
|
assume({ 1'b0, fc_pri_hpos } == { 1'b0, i_hpos } + { 1'b0, fc_ovw_hpos });
|
|
assume({ 1'b0, fc_pri_vpos } == { 1'b0, i_vpos } + { 1'b0, fc_ovw_vpos });
|
|
end
|
|
|
|
always @(posedge ACLK)
|
|
if (ARESETN && fc_check)
|
|
assume(!$rose(frame_err));
|
|
|
|
always @(posedge ACLK)
|
|
if (ARESETN && fc_check && !frame_err)
|
|
begin
|
|
if (f_pri_known && $stable(f_pri_known)
|
|
&& f_ovw_known && $stable(f_ovw_known)
|
|
&& f_ovw_lines_per_frame == f_ovw_height
|
|
&& (lines_per_frame > 0)
|
|
&& $stable(lines_per_frame))
|
|
begin
|
|
if (f_pri_hpos >= i_hpos && f_pri_vpos >= i_vpos
|
|
&& f_pri_hpos < { 1'b0, i_hpos } + { 1'b0, f_ovw_width }
|
|
&& f_pri_vpos < { 1'b0, i_vpos } + { 1'b0, f_ovw_height })
|
|
begin
|
|
assert(in_overlay);
|
|
// {{{
|
|
// assert({ 1'b0, f_pri_hpos } == { 1'b0, f_ovw_hpos } + { 1'b0, i_hpos });
|
|
// assert({ 1'b0, f_pri_vpos } == { 1'b0, f_ovw_vpos } + { 1'b0, i_vpos });
|
|
// }}}
|
|
end else begin
|
|
assert(!in_overlay);
|
|
// {{{
|
|
if (ovw_eof)
|
|
begin
|
|
// {{{
|
|
assert(
|
|
// Before/waiting 4 the frame
|
|
(f_pri_vpos < i_vpos
|
|
|| (f_pri_vpos == i_vpos && f_pri_hpos < i_hpos))
|
|
// or afterwards on the same line
|
|
||(f_pri_hpos >= { 1'b0, i_hpos } + { 1'b0, f_ovw_width }
|
|
&& { 1'b0, f_pri_vpos } == { 1'b0, i_vpos } + { 1'b0, f_ovw_height } - 1)
|
|
// or on following lines
|
|
||({ 1'b0, f_pri_vpos } >= { 1'b0, i_vpos } + { 1'b0, f_ovw_height }));
|
|
// }}}
|
|
end else if (ovw_eol
|
|
&& f_pri_vpos >= i_vpos
|
|
&& f_pri_vpos < { 1'b0, i_vpos } + { 1'b0, f_ovw_height })
|
|
begin
|
|
if (f_pri_hpos < i_hpos)
|
|
begin
|
|
assert({ 1'b0, f_pri_vpos } == { 1'b0, f_ovw_vpos } + { 1'b0, i_vpos });
|
|
end else
|
|
assert({ 1'b0, f_pri_vpos } == { 1'b0, f_ovw_vpos } + { 1'b0, i_vpos } - 1);
|
|
end else if (f_pri_vpos >= i_vpos
|
|
&& f_pri_vpos < { 1'b0, i_vpos } + { 1'b0, f_ovw_height })
|
|
begin
|
|
if (f_pri_hpos <= i_hpos)
|
|
begin
|
|
assert({ 1'b0, f_pri_vpos }
|
|
== { 1'b0, f_ovw_vpos }
|
|
+ { 1'b0, i_vpos } + 1);
|
|
end else
|
|
assert({ 1'b0, f_pri_vpos }
|
|
== { 1'b0, f_ovw_vpos }
|
|
+ { 1'b0, i_vpos });
|
|
end // else assert(ovw_eof);
|
|
// }}}
|
|
end
|
|
end
|
|
end
|
|
|
|
generate if (ALPHA_BITS == 0)
|
|
begin : GEN_CONTRACT_A0
|
|
// {{{
|
|
always @(posedge ACLK)
|
|
if (ARESETN && fc_check && mix_valid
|
|
&& (f_mix_hpos == fc_pri_hpos
|
|
&& f_mix_vpos == fc_pri_vpos))
|
|
begin
|
|
if (i_enable && !f_mix_err)
|
|
begin
|
|
assert(mix_pixel == fc_ovw_pixel);
|
|
end else begin
|
|
assert(mix_pixel == fc_pri_pixel);
|
|
end
|
|
end
|
|
|
|
always @(posedge ACLK)
|
|
if (ARESETN && fc_check && M_VID_TVALID)
|
|
begin
|
|
if (f_vid_hpos == fc_pri_hpos
|
|
&& f_vid_vpos == fc_pri_vpos)
|
|
begin
|
|
if (i_enable && !f_vid_err)
|
|
begin
|
|
assert(M_VID_TDATA == fc_ovw_pixel);
|
|
end else begin
|
|
assert(M_VID_TDATA == fc_pri_pixel);
|
|
end
|
|
end
|
|
end
|
|
// }}}
|
|
end else if (ALPHA_BITS == 1)
|
|
begin : GEN_CONTRACT_A1
|
|
// {{{
|
|
always @(posedge ACLK)
|
|
if (ARESETN && fc_check && mix_valid
|
|
&& (f_mix_hpos == fc_pri_hpos
|
|
&& f_mix_vpos == fc_pri_vpos))
|
|
begin
|
|
if (fc_ovw_pixel[DW] && i_enable && !f_mix_err)
|
|
begin
|
|
assert(mix_pixel == fc_ovw_pixel[DW-1:0]);
|
|
end else begin
|
|
assert(mix_pixel == fc_pri_pixel[DW-1:0]);
|
|
end
|
|
end
|
|
|
|
always @(posedge ACLK)
|
|
if (ARESETN && fc_check && M_VID_TVALID)
|
|
begin
|
|
if (f_vid_hpos == fc_pri_hpos
|
|
&& f_vid_vpos == fc_pri_vpos)
|
|
begin
|
|
if (fc_ovw_pixel[DW] && i_enable && !f_vid_err)
|
|
begin
|
|
assert(M_VID_TDATA == fc_ovw_pixel[DW-1:0]);
|
|
end else begin
|
|
assert(M_VID_TDATA == fc_pri_pixel[DW-1:0]);
|
|
end
|
|
end
|
|
end
|
|
// }}}
|
|
end endgenerate
|
|
|
|
// }}}
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Overlay tracking
|
|
// {{{
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
//
|
|
|
|
always @(posedge ACLK)
|
|
if (ARESETN && (!OPT_LINE_BREAK || !pix_line_pause))
|
|
begin
|
|
if (f_pskd_hpos < i_hpos)
|
|
begin
|
|
assert(!in_overlay);
|
|
end else if (f_pskd_vpos < i_vpos
|
|
&& f_pskd_vpos == prvpos
|
|
&& f_ovw_vpos == ovvpos
|
|
&& f_pskd_hpos != 1)
|
|
assert(!in_overlay);
|
|
|
|
if (!frame_err && !ovw_eof && in_frame && lines_per_frame > 0)
|
|
begin
|
|
if (ovw_eol && f_pri_hpos > i_hpos)
|
|
begin
|
|
assert(f_sum_ypos == f_pskd_vpos + 1);
|
|
/*
|
|
end else if (ovw_eol && f_pri_hpos <= i_hpos)
|
|
begin
|
|
assert(f_sum_ypos == f_pskd_vpos
|
|
|| (f_ovw_vpos == 0
|
|
&& f_ovw_hpos == 0
|
|
&& f_ovw_lines_per_frame == 0
|
|
&& (f_sum_ypos == { 1'b0, i_vpos } + { 1'b0, f_ovw_height })
|
|
&& OPT_TUSER_IS_SOF));
|
|
end
|
|
else if (f_pri_hpos <= i_hpos)
|
|
begin
|
|
assert(f_sum_ypos + 1 == f_pskd_vpos);
|
|
end else begin // if (!ovw_eol && f_pri_hpos > i_hpos)
|
|
assert(f_sum_ypos == f_pskd_vpos
|
|
|| f_sum_ypos >= f_vid_height);
|
|
*/
|
|
end
|
|
end
|
|
|
|
if (!frame_err && !ovw_eof && in_overlay
|
|
&& lines_per_frame > 0)
|
|
begin
|
|
assert(w_frame_err || (i_hpos + f_ovw_hpos == f_pskd_hpos));
|
|
end
|
|
end
|
|
// }}}
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Cover properties
|
|
// {{{
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
//
|
|
|
|
reg [2:0] cvr_pframes, cvr_oframes;
|
|
|
|
initial cvr_pframes = 0;
|
|
always @(posedge ACLK)
|
|
if (!ARESETN)
|
|
cvr_pframes <= 0;
|
|
else if (pskd_valid && pskd_ready && pskd_vlast && !cvr_pframes[2])
|
|
cvr_pframes <= cvr_pframes + 1;
|
|
|
|
initial cvr_oframes = 0;
|
|
always @(posedge ACLK)
|
|
if (!ARESETN)
|
|
cvr_oframes <= 0;
|
|
else if (ovskd_valid && ovskd_ready && ovskd_vlast && !cvr_oframes[2])
|
|
cvr_oframes <= cvr_oframes + 1;
|
|
|
|
always @(posedge ACLK)
|
|
if (ARESETN)
|
|
begin
|
|
cover(cvr_pframes == 1);
|
|
cover(cvr_oframes == 1);
|
|
|
|
cover(cvr_pframes == 2);
|
|
cover(cvr_oframes == 2);
|
|
end
|
|
|
|
// }}}
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// "Careless" assumptions
|
|
// {{{
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
//
|
|
|
|
always @(posedge ACLK)
|
|
if ((1||fc_check) && ARESETN && $past(ARESETN && !S_PRI_TVALID)
|
|
&& $past(ARESETN && !S_PRI_TVALID, 2)
|
|
&& $past(ARESETN && !S_PRI_TVALID, 3))
|
|
begin
|
|
assume(S_PRI_TVALID);
|
|
end
|
|
|
|
always @(*)
|
|
if (fc_check)
|
|
assume(M_VID_TREADY);
|
|
|
|
always @(posedge ACLK)
|
|
if ((1||fc_check) && ARESETN && $past(ARESETN && !M_VID_TREADY)
|
|
&& $past(ARESETN && !M_VID_TREADY, 2)
|
|
&& $past(ARESETN && !M_VID_TREADY, 3))
|
|
begin
|
|
assume(M_VID_TREADY);
|
|
end
|
|
|
|
|
|
always @(*)
|
|
assume(i_vpos == 0);
|
|
|
|
always @(*)
|
|
if (!S_PRI_TVALID)
|
|
begin
|
|
assume(!S_PRI_TUSER);
|
|
assume(!S_PRI_TLAST);
|
|
end
|
|
|
|
always @(*)
|
|
if (!S_OVW_TVALID)
|
|
begin
|
|
assume(!S_OVW_TUSER);
|
|
assume(!S_OVW_TLAST);
|
|
end
|
|
|
|
// }}}
|
|
`endif
|
|
// }}}
|
|
endmodule
|