1
0
mirror of https://github.com/marqs85/ossc.git synced 2024-06-11 07:29:32 +00:00
ossc/rtl/scanconverter.v
2023-02-28 19:39:59 +02:00

463 lines
18 KiB
Verilog

//
// Copyright (C) 2019-2022 Markus Hiienkari <mhiienka@niksula.hut.fi>
//
// This file is part of Open Source Scan Converter project.
//
// This program 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.
//
// This program 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/>.
//
module scanconverter (
input PCLK_CAP_i,
input PCLK_OUT_i,
input reset_n,
input [7:0] R_i,
input [7:0] G_i,
input [7:0] B_i,
input HSYNC_i,
input VSYNC_i,
input DE_i,
input FID_i,
input datavalid_i,
input interlaced_in_i,
input frame_change_i,
input [10:0] xpos_i,
input [10:0] ypos_i,
input [11:0] h_in_active,
input [31:0] hv_out_config,
input [31:0] hv_out_config2,
input [31:0] hv_out_config3,
input [31:0] xy_out_config,
input [31:0] xy_out_config2,
input [31:0] misc_config,
input [31:0] sl_config,
input [31:0] sl_config2,
input [31:0] sl_config3,
input testpattern_enable,
input lb_enable,
input ext_sync_mode,
input ext_frame_change_i,
input [7:0] ext_R_i,
input [7:0] ext_G_i,
input [7:0] ext_B_i,
output PCLK_o,
output [7:0] R_o,
output [7:0] G_o,
output [7:0] B_o,
output HSYNC_o,
output VSYNC_o,
output DE_o,
output [11:0] xpos_o,
output [10:0] ypos_o,
output reg resync_strobe,
input emif_br_clk,
input emif_br_reset,
output [27:0] emif_rd_addr,
output emif_rd_read,
input [255:0] emif_rd_rdata,
input emif_rd_waitrequest,
input emif_rd_readdatavalid,
output [5:0] emif_rd_burstcount,
output [27:0] emif_wr_addr,
output emif_wr_write,
output [255:0] emif_wr_wdata,
input emif_wr_waitrequest,
output [5:0] emif_wr_burstcount
);
parameter EMIF_ENABLE = 0;
parameter NUM_LINE_BUFFERS = 32;
localparam FID_EVEN = 1'b0;
localparam FID_ODD = 1'b1;
localparam PP_PL_START = 1;
localparam PP_LINEBUF_START = PP_PL_START + 1;
localparam PP_LINEBUF_LENGTH = 1;
localparam PP_LINEBUF_END = PP_LINEBUF_START + PP_LINEBUF_LENGTH;
localparam PP_SRCSEL_START = PP_LINEBUF_END;
localparam PP_SRCSEL_LENGTH = 1;
localparam PP_SRCSEL_END = PP_SRCSEL_START + PP_SRCSEL_LENGTH;
localparam PP_SLGEN_START = PP_SRCSEL_START;
localparam PP_SLGEN_LENGTH = 3;
localparam PP_SLGEN_END = PP_SLGEN_START + PP_SLGEN_LENGTH;
localparam PP_TP_START = PP_SLGEN_END;
localparam PP_TP_LENGTH = 1;
localparam PP_TP_END = PP_TP_START + PP_TP_LENGTH;
localparam PP_PL_END = PP_TP_END;
wire [11:0] H_TOTAL = hv_out_config[11:0];
wire [11:0] H_ACTIVE = hv_out_config[23:12];
wire [7:0] H_SYNCLEN = hv_out_config[31:24];
wire [8:0] H_BACKPORCH = hv_out_config2[8:0];
wire V_INTERLACED = hv_out_config2[31];
wire [10:0] V_TOTAL = hv_out_config2[19:9] >> V_INTERLACED;
wire [10:0] V_ACTIVE = hv_out_config2[30:20];
wire [3:0] V_SYNCLEN = hv_out_config3[3:0];
wire [8:0] V_BACKPORCH = hv_out_config3[12:4];
wire [10:0] V_STARTLINE = hv_out_config3[23:13];
wire [10:0] V_STARTLINE_PREV = (V_STARTLINE == 0) ? (V_TOTAL-1) : (V_STARTLINE-1);
wire [11:0] X_SIZE = xy_out_config[11:0];
wire [10:0] Y_SIZE = xy_out_config[22:12];
wire signed [9:0] X_OFFSET = xy_out_config2[9:0];
wire signed [8:0] Y_OFFSET = xy_out_config[31:23];
wire [7:0] X_START_LB = xy_out_config2[17:10];
wire signed [5:0] Y_START_LB = xy_out_config2[23:18];
wire signed [3:0] X_RPT = xy_out_config2[27:24];
wire signed [3:0] Y_RPT = xy_out_config2[31:28];
wire Y_SKIP = (Y_RPT == 4'(-1));
wire [1:0] Y_STEP = Y_SKIP+1'b1;
wire [3:0] SL_L_STR[5:0] = '{sl_config[23:20], sl_config[19:16], sl_config[15:12], sl_config[11:8], sl_config[7:4], sl_config[3:0]};
wire [3:0] SL_C_STR[9:0] = '{sl_config3[7:4], sl_config3[3:0], sl_config2[31:28], sl_config2[27:24], sl_config2[23:20], sl_config2[19:16], sl_config2[15:12], sl_config2[11:8], sl_config2[7:4], sl_config2[3:0]};
wire [5:0] SL_L_OVERLAY = sl_config[29:24];
wire SL_METHOD_PRE = sl_config[30];
wire SL_BOB_ALTERN = sl_config[31];
wire [9:0] SL_C_OVERLAY = sl_config3[17:8];
wire [2:0] SL_IV_Y = sl_config3[20:18];
wire [3:0] SL_IV_X = sl_config3[24:21];
wire [3:0] MISC_MASK_BR = misc_config[3:0];
wire [2:0] MISC_MASK_COLOR = misc_config[6:4];
wire [5:0] MISC_REV_LPF_STR = (misc_config[11:7] + 6'd16);
wire MISC_REV_LPF_ENABLE = (misc_config[11:7] != 5'h0);
wire MISC_LM_DEINT_MODE = misc_config[12];
wire MISC_NIR_EVEN_OFFSET = misc_config[13];
wire [3:0] MISC_BFI_STR = misc_config[19:16];
wire MISC_BFI_ENABLE = misc_config[20];
wire [7:0] MASK_R = MISC_MASK_COLOR[2] ? {2{MISC_MASK_BR}} : 8'h00;
wire [7:0] MASK_G = MISC_MASK_COLOR[1] ? {2{MISC_MASK_BR}} : 8'h00;
wire [7:0] MASK_B = MISC_MASK_COLOR[0] ? {2{MISC_MASK_BR}} : 8'h00;
reg frame_change_sync1_reg, frame_change_sync2_reg, frame_change_prev, frame_change_resync;
wire frame_change = frame_change_sync2_reg;
reg [11:0] h_cnt;
reg [10:0] v_cnt;
reg h_avidstart, v_avidstart;
reg src_fid, dst_fid;
reg [10:0] xpos_lb;
wire [10:0] xpos_lb_start = (X_OFFSET < 10'sd0) ? 11'd0 : {1'b0, X_OFFSET};
reg [10:0] ypos_lb, ypos_lb_next;
reg [3:0] x_ctr;
reg [3:0] y_ctr;
reg line_id;
reg ypos_pp_init;
reg [7:0] sl_str;
reg sl_method;
wire bfi_frame;
wire [7:0] R_sl_mult, G_sl_mult, B_sl_mult;
wire [7:0] R_linebuf, G_linebuf, B_linebuf;
// Pipeline registers
reg [7:0] R_pp[PP_LINEBUF_END:PP_PL_END] /* synthesis ramstyle = "logic" */;
reg [7:0] G_pp[PP_LINEBUF_END:PP_PL_END] /* synthesis ramstyle = "logic" */;
reg [7:0] B_pp[PP_LINEBUF_END:PP_PL_END] /* synthesis ramstyle = "logic" */;
reg HSYNC_pp[PP_PL_START:PP_PL_END] /* synthesis ramstyle = "logic" */;
reg VSYNC_pp[PP_PL_START:PP_PL_END] /* synthesis ramstyle = "logic" */;
reg DE_pp[PP_PL_START:PP_PL_END] /* synthesis ramstyle = "logic" */;
reg [11:0] xpos_pp[PP_PL_START:PP_PL_END] /* synthesis ramstyle = "logic" */;
reg [10:0] ypos_pp[PP_PL_START:PP_PL_END] /* synthesis ramstyle = "logic" */;
reg mask_enable_pp[PP_LINEBUF_START:PP_TP_START] /* synthesis ramstyle = "logic" */;
reg draw_sl_pp[(PP_SLGEN_START+1):(PP_SLGEN_END-1)] /* synthesis ramstyle = "logic" */;
reg [3:0] x_ctr_sl_pp[PP_PL_START:PP_SLGEN_START] /* synthesis ramstyle = "logic" */;
reg [2:0] y_ctr_sl_pp[PP_PL_START:PP_SLGEN_START] /* synthesis ramstyle = "logic" */;
assign PCLK_o = PCLK_OUT_i;
lpm_mult_4_sl R_sl_mult_u
(
.clock(PCLK_OUT_i),
.dataa(R_pp[PP_SLGEN_START+1]),
.datab(~sl_str),
.result(R_sl_mult)
);
lpm_mult_4_sl G_sl_mult_u
(
.clock(PCLK_OUT_i),
.dataa(G_pp[PP_SLGEN_START+1]),
.datab(~sl_str),
.result(G_sl_mult)
);
lpm_mult_4_sl B_sl_mult_u
(
.clock(PCLK_OUT_i),
.dataa(B_pp[PP_SLGEN_START+1]),
.datab(~sl_str),
.result(B_sl_mult)
);
linebuf_top #(
.EMIF_ENABLE(EMIF_ENABLE),
.NUM_LINE_BUFFERS(NUM_LINE_BUFFERS)
) linebuf_top_inst (
.PCLK_CAP_i(PCLK_CAP_i),
.PCLK_OUT_i(PCLK_OUT_i),
.R_i(R_i),
.G_i(G_i),
.B_i(B_i),
.DE_i(DE_i),
.datavalid_i(datavalid_i),
.h_in_active(h_in_active),
.xpos_i(xpos_i),
.ypos_i(ypos_i),
.xpos_lb(xpos_lb),
.ypos_lb(ypos_lb),
.ypos_lb_next(ypos_lb_next),
.line_id(line_id),
.lb_enable(lb_enable),
.R_linebuf(R_linebuf),
.G_linebuf(G_linebuf),
.B_linebuf(B_linebuf),
.emif_br_clk(emif_br_clk),
.emif_br_reset(emif_br_reset),
.emif_rd_addr(emif_rd_addr),
.emif_rd_read(emif_rd_read),
.emif_rd_rdata(emif_rd_rdata),
.emif_rd_waitrequest(emif_rd_waitrequest),
.emif_rd_readdatavalid(emif_rd_readdatavalid),
.emif_rd_burstcount(emif_rd_burstcount),
.emif_wr_addr(emif_wr_addr),
.emif_wr_write(emif_wr_write),
.emif_wr_wdata(emif_wr_wdata),
.emif_wr_waitrequest(emif_wr_waitrequest),
.emif_wr_burstcount(emif_wr_burstcount)
);
// Frame change strobe synchronization
always @(posedge PCLK_OUT_i) begin
frame_change_sync1_reg <= frame_change_i;
frame_change_sync2_reg <= frame_change_sync1_reg;
frame_change_prev <= frame_change_sync2_reg;
frame_change_resync <= ~frame_change_prev & frame_change & ((v_cnt != V_STARTLINE_PREV) & (v_cnt != V_STARTLINE));
end
// H/V counters
always @(posedge PCLK_OUT_i) begin
if (ext_sync_mode & ext_frame_change_i) begin
h_cnt <= PP_SRCSEL_START; // compensate pipeline delays
v_cnt <= 0;
bfi_frame <= bfi_frame ^ 1'b1;
end else if (~ext_sync_mode & frame_change_resync) begin
h_cnt <= 0;
v_cnt <= V_STARTLINE;
bfi_frame <= 0;
src_fid <= (~interlaced_in_i | (V_STARTLINE < (V_TOTAL/2))) ? FID_ODD : FID_EVEN;
dst_fid <= (~V_INTERLACED | (V_STARTLINE < (V_TOTAL/2))) ? FID_ODD : FID_EVEN;
resync_strobe <= 1'b1;
end else begin
if (h_cnt == H_TOTAL-1) begin
if ((~V_INTERLACED & (v_cnt == V_TOTAL-1)) |
(V_INTERLACED & (dst_fid == FID_ODD) & (v_cnt == V_TOTAL)) |
(V_INTERLACED & (dst_fid == FID_EVEN) & (v_cnt == V_TOTAL-1)))
begin
v_cnt <= 0;
v_avidstart <= (V_SYNCLEN+V_BACKPORCH-1'b1 == 0);
src_fid <= interlaced_in_i ? (src_fid ^ 1'b1) : FID_ODD;
dst_fid <= V_INTERLACED ? (dst_fid ^ 1'b1) : FID_ODD;
resync_strobe <= 1'b0;
end else begin
v_cnt <= v_cnt + 1'b1;
v_avidstart <= (v_cnt == V_SYNCLEN+V_BACKPORCH-2'h2);
end
h_cnt <= 0;
h_avidstart <= 1'b0;
end else begin
h_cnt <= h_cnt + 1'b1;
h_avidstart <= (h_cnt == H_SYNCLEN+H_BACKPORCH-1'b1);
end
end
end
// Postprocess pipeline structure
// 1 2 3 4 5 6 7
// |----------|----------|---------|---------|---------|---------|--------|
// | SYNC/DE | | | | | | |
// | X/Y POS | | | | | | |
// | | MASK | | | | | |
// | | LB_SETUP | LINEBUF | | | | |
// | | | | SRCSEL | | | |
// | | | | SLGEN | SLGEN | SLGEN | |
// | | | | | | | TP |
// Pipeline stage 1
always @(posedge PCLK_OUT_i) begin
HSYNC_pp[1] <= (h_cnt < H_SYNCLEN) ? 1'b0 : 1'b1;
if (dst_fid == FID_ODD)
VSYNC_pp[1] <= ((v_cnt < V_SYNCLEN) | ((v_cnt == V_TOTAL) & (h_cnt >= (H_TOTAL/2)))) ? 1'b0 : 1'b1;
else
VSYNC_pp[1] <= ((v_cnt < V_SYNCLEN-1) | ((v_cnt == V_SYNCLEN-1) & (h_cnt < (H_TOTAL/2)))) ? 1'b0 : 1'b1;
DE_pp[1] <= (h_cnt >= H_SYNCLEN+H_BACKPORCH) & (h_cnt < H_SYNCLEN+H_BACKPORCH+H_ACTIVE) & (v_cnt >= V_SYNCLEN+V_BACKPORCH) & (v_cnt < V_SYNCLEN+V_BACKPORCH+V_ACTIVE);
if (h_avidstart) begin
// Start 1 line before active so that linebuffer can be filled from DRAM in time
if (v_avidstart) begin
ypos_pp[1] <= 11'(-1);
ypos_pp_init <= 1'b1;
// Bob deinterlace adjusts linebuf start position and y_ctr for even source fields if
// output is progressive mode. Noninterlace restore as raw output mode is an exception
// which ignores LM deinterlace mode setting.
if (~ext_sync_mode & ~MISC_LM_DEINT_MODE & (Y_RPT > 0) & ~V_INTERLACED & (src_fid == FID_EVEN)) begin
ypos_lb_next <= 11'(Y_START_LB) - 1'b1;
y_ctr <= ((Y_RPT+1'b1) >> 1);
y_ctr_sl_pp[1] <= SL_BOB_ALTERN ? ((Y_RPT+1'b1) >> 1) : 0;
end else begin
if (Y_SKIP & (dst_fid == FID_EVEN)) begin
// Linedrop mode and output interlaced
ypos_lb_next <= 11'(Y_START_LB) + 1'b1;
end else if ((((Y_RPT == 0) & ~V_INTERLACED) | ((Y_RPT > 0) & MISC_LM_DEINT_MODE)) & (src_fid == FID_EVEN)) begin
// Adjust even field Y-offset for noninterlace restore
ypos_lb_next <= 11'(Y_START_LB) - MISC_NIR_EVEN_OFFSET;
end else begin
ypos_lb_next <= 11'(Y_START_LB);
end
y_ctr <= 0;
y_ctr_sl_pp[1] <= 0;
end
line_id <= ~line_id;
end else begin
if (ypos_pp[1] != V_ACTIVE) begin
ypos_pp[1] <= ypos_pp[1] + 1'b1;
if (ypos_pp_init | (y_ctr == Y_RPT) | Y_SKIP) begin
if ((ypos_lb_next >= NUM_LINE_BUFFERS-Y_STEP) & (ypos_lb_next < NUM_LINE_BUFFERS))
ypos_lb_next <= ypos_lb_next + Y_STEP - NUM_LINE_BUFFERS;
else
ypos_lb_next <= ypos_lb_next + Y_STEP;
ypos_lb <= ypos_lb_next;
line_id <= ~line_id;
ypos_pp_init <= 1'b0;
if (!ypos_pp_init)
y_ctr <= 0;
end else begin
y_ctr <= y_ctr + 1'b1;
end
if (!ypos_pp_init)
y_ctr_sl_pp[1] <= (y_ctr_sl_pp[1] == SL_IV_Y) ? 0 : y_ctr_sl_pp[1] + 1'b1;
end
end
xpos_pp[1] <= 0;
xpos_lb <= X_START_LB;
x_ctr <= 0;
x_ctr_sl_pp[1] <= 0;
end else begin
if (xpos_pp[1] != H_ACTIVE) begin
xpos_pp[1] <= xpos_pp[1] + 1'b1;
end
if (xpos_pp[1] >= xpos_lb_start) begin
if (x_ctr == X_RPT) begin
xpos_lb <= xpos_lb + 1'b1;
x_ctr <= 0;
end else begin
x_ctr <= x_ctr + 1'b1;
end
x_ctr_sl_pp[1] <= (x_ctr_sl_pp[1] == SL_IV_X) ? 0 : x_ctr_sl_pp[1] + 1'b1;
end
end
end
// Pipeline stages 2-
integer pp_idx;
always @(posedge PCLK_OUT_i) begin
for(pp_idx = PP_LINEBUF_START; pp_idx <= PP_PL_END; pp_idx = pp_idx+1) begin
HSYNC_pp[pp_idx] <= HSYNC_pp[pp_idx-1];
VSYNC_pp[pp_idx] <= VSYNC_pp[pp_idx-1];
DE_pp[pp_idx] <= DE_pp[pp_idx-1];
xpos_pp[pp_idx] <= xpos_pp[pp_idx-1];
ypos_pp[pp_idx] <= ypos_pp[pp_idx-1];
end
for(pp_idx = PP_LINEBUF_START; pp_idx <= PP_SLGEN_START; pp_idx = pp_idx+1) begin
x_ctr_sl_pp[pp_idx] <= x_ctr_sl_pp[pp_idx-1];
y_ctr_sl_pp[pp_idx] <= y_ctr_sl_pp[pp_idx-1];
end
if (($signed({1'b0, xpos_pp[PP_LINEBUF_START-1]}) >= X_OFFSET) &
($signed({1'b0, xpos_pp[PP_LINEBUF_START-1]}) < X_OFFSET+X_SIZE) &
($signed({1'b0, ypos_pp[PP_LINEBUF_START-1]}) >= Y_OFFSET) &
($signed({1'b0, ypos_pp[PP_LINEBUF_START-1]}) < Y_OFFSET+Y_SIZE))
begin
mask_enable_pp[PP_LINEBUF_START] <= 1'b0;
end else begin
mask_enable_pp[PP_LINEBUF_START] <= 1'b1;
end
for(pp_idx = PP_LINEBUF_START+1; pp_idx <= PP_TP_START; pp_idx = pp_idx+1) begin
mask_enable_pp[pp_idx] <= mask_enable_pp[pp_idx-1];
end
R_pp[PP_SRCSEL_END] <= ext_sync_mode ? ext_R_i : R_linebuf;
G_pp[PP_SRCSEL_END] <= ext_sync_mode ? ext_G_i : G_linebuf;
B_pp[PP_SRCSEL_END] <= ext_sync_mode ? ext_B_i : B_linebuf;
// Scanlines (3 cycles)
if (MISC_BFI_ENABLE & bfi_frame) begin
sl_str <= ((MISC_BFI_STR+8'h01)<<4)-1'b1;
sl_method <= 1'b1;
draw_sl_pp[PP_SLGEN_START+1] <= 1'b1;
end else if (|(SL_L_OVERLAY & (6'h1<<y_ctr_sl_pp[PP_SLGEN_START]))) begin
sl_str <= ((SL_L_STR[y_ctr_sl_pp[PP_SLGEN_START]]+8'h01)<<4)-1'b1;
sl_method <= ~SL_METHOD_PRE;
draw_sl_pp[PP_SLGEN_START+1] <= 1'b1;
end else if (|(SL_C_OVERLAY & (10'h1<<x_ctr_sl_pp[PP_SLGEN_START]))) begin
sl_str <= ((SL_C_STR[x_ctr_sl_pp[PP_SLGEN_START]]+8'h01)<<4)-1'b1;
sl_method <= ~SL_METHOD_PRE;
draw_sl_pp[PP_SLGEN_START+1] <= 1'b1;
end else begin
draw_sl_pp[PP_SLGEN_START+1] <= 1'b0;
end
for (pp_idx = PP_SLGEN_START+2; pp_idx <= PP_SLGEN_END-1; pp_idx = pp_idx+1) begin
draw_sl_pp[pp_idx] <= draw_sl_pp[pp_idx-1];
end
R_pp[PP_SLGEN_START+2] <= draw_sl_pp[PP_SLGEN_START+1] ? ((R_pp[PP_SLGEN_START+1] > sl_str) ? (R_pp[PP_SLGEN_START+1] - sl_str) : 8'h00) : R_pp[PP_SLGEN_START+1];
G_pp[PP_SLGEN_START+2] <= draw_sl_pp[PP_SLGEN_START+1] ? ((G_pp[PP_SLGEN_START+1] > sl_str) ? (G_pp[PP_SLGEN_START+1] - sl_str) : 8'h00) : G_pp[PP_SLGEN_START+1];
B_pp[PP_SLGEN_START+2] <= draw_sl_pp[PP_SLGEN_START+1] ? ((B_pp[PP_SLGEN_START+1] > sl_str) ? (B_pp[PP_SLGEN_START+1] - sl_str) : 8'h00) : B_pp[PP_SLGEN_START+1];
R_pp[PP_SLGEN_END] <= (draw_sl_pp[PP_SLGEN_START+2] & sl_method) ? R_sl_mult : R_pp[PP_SLGEN_START+2];
G_pp[PP_SLGEN_END] <= (draw_sl_pp[PP_SLGEN_START+2] & sl_method) ? G_sl_mult : G_pp[PP_SLGEN_START+2];
B_pp[PP_SLGEN_END] <= (draw_sl_pp[PP_SLGEN_START+2] & sl_method) ? B_sl_mult : B_pp[PP_SLGEN_START+2];
R_pp[PP_TP_END] <= testpattern_enable ? (xpos_pp[PP_TP_START] ^ ypos_pp[PP_TP_START]) : (mask_enable_pp[PP_TP_START] ? MASK_R : R_pp[PP_TP_START]);
G_pp[PP_TP_END] <= testpattern_enable ? (xpos_pp[PP_TP_START] ^ ypos_pp[PP_TP_START]) : (mask_enable_pp[PP_TP_START] ? MASK_G : G_pp[PP_TP_START]);
B_pp[PP_TP_END] <= testpattern_enable ? (xpos_pp[PP_TP_START] ^ ypos_pp[PP_TP_START]) : (mask_enable_pp[PP_TP_START] ? MASK_B : B_pp[PP_TP_START]);
end
// Output
assign R_o = R_pp[PP_PL_END];
assign G_o = G_pp[PP_PL_END];
assign B_o = B_pp[PP_PL_END];
assign HSYNC_o = HSYNC_pp[PP_PL_END];
assign VSYNC_o = VSYNC_pp[PP_PL_END];
assign DE_o = DE_pp[PP_PL_END];
assign xpos_o = xpos_pp[PP_PL_END];
assign ypos_o = ypos_pp[PP_PL_END];
endmodule