mirror of
https://github.com/MiSTer-devel/PCFX_MiSTer.git
synced 2026-05-17 03:04:19 +00:00
764 lines
20 KiB
Systemverilog
764 lines
20 KiB
Systemverilog
// HuC6261 (NEW Iron Guanyin)
|
|
//
|
|
// Copyright (c) 2025-2026 David Hunter
|
|
//
|
|
// This program is GPL licensed. See COPYING for the full license.
|
|
|
|
// References:
|
|
// - https://github.com/MiSTer-devel/TurboGrafx16_MiSTer/blob/master/rtl/huc6260.vhd
|
|
// - PC-FXGA Authoring Software / GMAKER Starter Kit (Ver. 1.1) / Device Description: Hu6261
|
|
|
|
|
|
module huc6261
|
|
(
|
|
input CLK,
|
|
input CE,
|
|
input RESn,
|
|
|
|
input CSn,
|
|
input WRn,
|
|
input RDn,
|
|
input A2,
|
|
input [15:0] DI,
|
|
output [15:0] DO,
|
|
|
|
// VDC interface
|
|
output DCK70, // pixel clock enable
|
|
output DCK70_NEGEDGE,
|
|
output reg HSYNC_POSEDGE,
|
|
output reg HSYNC_NEGEDGE,
|
|
output reg VSYNC_POSEDGE,
|
|
output reg VSYNC_NEGEDGE,
|
|
|
|
input [8:0] VDC0_VD,
|
|
input [8:0] VDC1_VD,
|
|
|
|
// MMC (HuC6272 KING) video interface
|
|
output DCKKR, // pixel clock enable
|
|
output DCKKR_NEGEDGE,
|
|
input [23:0] MMC_VD,
|
|
|
|
// NTSC/YUV video output
|
|
output reg [7:0] Y,
|
|
output reg [7:0] U,
|
|
output reg [7:0] V,
|
|
output reg VSn,
|
|
output reg HSn,
|
|
output reg VBL,
|
|
output reg HBL
|
|
);
|
|
|
|
localparam [11:0] LEFT_BL_CLOCKS = 12'd457;
|
|
localparam [11:0] DISP_CLOCKS = 12'd2160;
|
|
localparam [11:0] LINE_CLOCKS = 12'd2730;
|
|
localparam [11:0] HS_CLOCKS = 12'd192;
|
|
localparam [11:0] HS_OFF = 12'd47;
|
|
|
|
localparam [8:0] TOTAL_LINES = 9'd263;
|
|
localparam [8:0] VS_LINES = 9'd3;
|
|
localparam [8:0] TOP_BL_LINES_E = 9'd19;
|
|
localparam [8:0] DISP_LINES_E = 9'd242;
|
|
|
|
localparam [8:0] TOP_BL_LINES = TOP_BL_LINES_E;
|
|
localparam [8:0] DISP_LINES = DISP_LINES_E;
|
|
|
|
typedef struct packed {
|
|
logic [7:0] y, u, v;
|
|
} yuv888_t;
|
|
|
|
typedef struct packed {
|
|
logic bg71;
|
|
logic [3:0] bmg;
|
|
logic sp;
|
|
logic bg;
|
|
logic sp256;
|
|
logic bg256;
|
|
logic [1:0] rsv4;
|
|
logic dc7;
|
|
logic ex;
|
|
logic [1:0] dcc;
|
|
} cr_t;
|
|
|
|
typedef enum bit [1:0] {
|
|
CPE_OFF = 2'b0,
|
|
CPE_ON_1AB,
|
|
CPE_ON_2AB,
|
|
CPE_ON_3AB
|
|
} ble_cpe_t;
|
|
|
|
// Cellophone Surface Setting Register
|
|
typedef struct packed {
|
|
logic fb; // Front/Back
|
|
logic ed; // Enable/Disable
|
|
ble_cpe_t vpu;
|
|
ble_cpe_t mmc_bg3;
|
|
ble_cpe_t mmc_bg2;
|
|
ble_cpe_t mmc_bg1;
|
|
ble_cpe_t mmc_bg0;
|
|
ble_cpe_t vdc_sp;
|
|
ble_cpe_t vdc_bg;
|
|
} ble_t;
|
|
|
|
typedef struct packed {
|
|
logic [3:0] y, u, v;
|
|
} blxx_t;
|
|
|
|
typedef struct packed {
|
|
logic [2:0] pri;
|
|
logic key;
|
|
logic [23:0] vd;
|
|
logic pal;
|
|
ble_cpe_t cpe;
|
|
} layer_t;
|
|
|
|
logic [4:0] ar;
|
|
logic [11:0] h_cnt;
|
|
logic [8:0] v_cnt;
|
|
|
|
cr_t cr, cr_next;
|
|
logic [8:0] cpa;
|
|
logic [15:0] cpdin, cpdout;
|
|
logic cpd_wr, cpd_wr_d;
|
|
logic [7:0] vdc_sp_cpao, vdc_bg_cpao;
|
|
logic [2:0] pri_vdc_bg, pri_vdc_sp, pri_vpu,
|
|
pri_mmc_bg0, pri_mmc_bg1, pri_mmc_bg2, pri_mmc_bg3;
|
|
logic [15:0] ccr, ccr_next;
|
|
ble_t ble, ble_next;
|
|
logic [15:0] spbl, spbl_next;
|
|
blxx_t bl1a, bl1a_next, bl1b, bl1b_next,
|
|
bl2a, bl2a_next, bl2b, bl2b_next,
|
|
bl3a, bl3a_next, bl3b, bl3b_next;
|
|
|
|
layer_t [3:0] layers;
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Register interface
|
|
|
|
logic [15:0] dout;
|
|
|
|
wire cpd_wr_end = ~cpd_wr & cpd_wr_d;
|
|
|
|
always @(posedge CLK) if (CE) begin
|
|
cpd_wr <= '0;
|
|
cpd_wr_d <= cpd_wr;
|
|
|
|
if (~RESn) begin
|
|
cr_next <= '0;
|
|
ar <= '0;
|
|
cpa <= '0;
|
|
vdc_sp_cpao <= '0;
|
|
vdc_bg_cpao <= '0;
|
|
pri_vdc_bg <= '0;
|
|
pri_vdc_sp <= '0;
|
|
pri_vpu <= '0;
|
|
pri_mmc_bg0 <= '0;
|
|
pri_mmc_bg1 <= '0;
|
|
pri_mmc_bg2 <= '0;
|
|
pri_mmc_bg3 <= '0;
|
|
ccr_next <= '0;
|
|
ble_next <= '0;
|
|
spbl_next <= '0;
|
|
bl1a_next <= '0;
|
|
bl1b_next <= '0;
|
|
bl2a_next <= '0;
|
|
bl2b_next <= '0;
|
|
bl3a_next <= '0;
|
|
bl3b_next <= '0;
|
|
end
|
|
else begin
|
|
if (cpd_wr_end)
|
|
cpa <= cpa + 1'd1;
|
|
|
|
if (~CSn & ~WRn) begin
|
|
case (A2)
|
|
1'b0: begin
|
|
ar <= DI[4:0];
|
|
end
|
|
1'b1: begin
|
|
case (ar)
|
|
5'd00:
|
|
cr_next <= DI[14:0];
|
|
5'd01:
|
|
cpa <= DI[8:0];
|
|
5'd02: begin
|
|
cpdin <= DI[15:0];
|
|
cpd_wr <= '1;
|
|
end
|
|
5'd04: begin
|
|
vdc_sp_cpao <= DI[15:8];
|
|
vdc_bg_cpao <= DI[7:0];
|
|
end
|
|
5'h08: begin
|
|
pri_vdc_bg <= DI[0+:3];
|
|
pri_vdc_sp <= DI[4+:3];
|
|
pri_vpu <= DI[8+:3];
|
|
end
|
|
5'h09: begin
|
|
pri_mmc_bg0 <= DI[0+:3];
|
|
pri_mmc_bg1 <= DI[4+:3];
|
|
pri_mmc_bg2 <= DI[8+:3];
|
|
pri_mmc_bg3 <= DI[12+:3];
|
|
end
|
|
5'h0d:
|
|
ccr_next <= DI[15:0];
|
|
5'h0e:
|
|
ble_next <= DI[15:0];
|
|
5'h0f:
|
|
spbl_next <= DI[15:0];
|
|
5'h10:
|
|
bl1a_next <= DI[11:0];
|
|
5'h11:
|
|
bl1b_next <= DI[11:0];
|
|
5'h12:
|
|
bl2a_next <= DI[11:0];
|
|
5'h13:
|
|
bl2b_next <= DI[11:0];
|
|
5'h14:
|
|
bl3a_next <= DI[11:0];
|
|
5'h15:
|
|
bl3b_next <= DI[11:0];
|
|
default: ;
|
|
endcase
|
|
end
|
|
endcase
|
|
end
|
|
end
|
|
end
|
|
|
|
always @* begin
|
|
dout = '0;
|
|
case (A2)
|
|
1'b0: begin
|
|
dout[4:0] = ar;
|
|
dout[13:5] = v_cnt;
|
|
end
|
|
1'b1: begin
|
|
case (ar)
|
|
5'd03:
|
|
dout[15:0] = cpdout;
|
|
5'h08: begin
|
|
dout[0+:3] = pri_vdc_bg;
|
|
dout[4+:3] = pri_vdc_sp;
|
|
dout[8+:3] = pri_vpu;
|
|
end
|
|
5'h09: begin
|
|
dout[0+:3] = pri_mmc_bg0;
|
|
dout[4+:3] = pri_mmc_bg1;
|
|
dout[8+:3] = pri_mmc_bg2;
|
|
dout[12+:3] = pri_mmc_bg3;
|
|
end
|
|
5'h0d:
|
|
dout = ccr_next;
|
|
5'h0e:
|
|
dout = ble_next;
|
|
5'h0f:
|
|
dout = spbl_next;
|
|
5'h10:
|
|
dout[11:0] = bl1a_next;
|
|
5'h11:
|
|
dout[11:0] = bl1b_next;
|
|
5'h12:
|
|
dout[11:0] = bl2a_next;
|
|
5'h13:
|
|
dout[11:0] = bl2b_next;
|
|
5'h14:
|
|
dout[11:0] = bl3a_next;
|
|
5'h15:
|
|
dout[11:0] = bl3b_next;
|
|
default: ;
|
|
endcase
|
|
end
|
|
endcase
|
|
end
|
|
|
|
assign DO = (~CSn & ~RDn) ? dout : '0;
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Video counter
|
|
|
|
logic multires, multires_p;
|
|
|
|
wire h_wrap = h_cnt == (LINE_CLOCKS - 1'd1);
|
|
wire v_wrap = v_cnt == (TOTAL_LINES - 1'd1);
|
|
|
|
always @(posedge CLK) begin
|
|
if (~RESn) begin
|
|
h_cnt <= '0;
|
|
v_cnt <= '0;
|
|
end
|
|
else begin
|
|
if (~h_wrap)
|
|
h_cnt <= h_cnt + 1'd1;
|
|
else begin
|
|
h_cnt <= '0;
|
|
if (~v_wrap)
|
|
v_cnt <= v_cnt + 1'd1;
|
|
else
|
|
v_cnt <= '0;
|
|
end
|
|
end
|
|
end
|
|
|
|
// Some registers update only every line or frame.
|
|
always @(posedge CLK) begin
|
|
if (~RESn) begin
|
|
cr <= '0;
|
|
ccr <= '0;
|
|
ble <= '0;
|
|
spbl <= '0;
|
|
bl1a <= '0;
|
|
bl1b <= '0;
|
|
bl2a <= '0;
|
|
bl2b <= '0;
|
|
bl3a <= '0;
|
|
bl3b <= '0;
|
|
multires_p <= '0;
|
|
multires <= '0;
|
|
end
|
|
else begin
|
|
if (h_wrap) begin
|
|
cr <= cr_next;
|
|
ccr <= ccr_next;
|
|
ble <= ble_next;
|
|
spbl <= spbl_next;
|
|
bl1a <= bl1a_next;
|
|
bl1b <= bl1b_next;
|
|
bl2a <= bl2a_next;
|
|
bl2b <= bl2b_next;
|
|
bl3a <= bl3a_next;
|
|
bl3b <= bl3b_next;
|
|
end
|
|
|
|
if ((v_cnt >= TOP_BL_LINES) & (v_cnt < (TOP_BL_LINES + DISP_LINES)) &
|
|
(cr.dc7 != cr_next.dc7))
|
|
multires_p <= '1;
|
|
|
|
if (v_cnt == TOP_BL_LINES + DISP_LINES) begin
|
|
multires <= multires_p;
|
|
multires_p <= '0;
|
|
end
|
|
end
|
|
end
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// "Fast" (dot processing) clock generator
|
|
//
|
|
// Rate is 4x the 256 pixel clock
|
|
|
|
logic ckenf_cnt;
|
|
logic ckenfp, ckenf;
|
|
|
|
always @(posedge CLK) begin
|
|
ckenfp <= '0;
|
|
|
|
if (~RESn) begin
|
|
ckenf_cnt <= '0;
|
|
end
|
|
else begin
|
|
ckenf_cnt <= ~ckenf_cnt;
|
|
|
|
if ((ckenf_cnt && h_cnt < (LINE_CLOCKS - 12'(2+1))) |
|
|
h_wrap) begin
|
|
ckenf_cnt <= '0;
|
|
ckenfp <= '1;
|
|
end
|
|
end
|
|
|
|
ckenf <= ckenfp;
|
|
end
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// VDC (HuC6270) Pixel clock generator
|
|
//
|
|
// Variable rate for 256 or 320 horizontal pixels
|
|
|
|
logic [2:0] cken70_cnt;
|
|
logic cken70, cken70_ne;
|
|
|
|
always @(posedge CLK) begin
|
|
cken70 <= '0;
|
|
cken70_ne <= '0;
|
|
|
|
if (~RESn) begin
|
|
cken70_cnt <= '0;
|
|
end
|
|
else begin
|
|
cken70_cnt <= cken70_cnt + 1'd1;
|
|
|
|
if ((((multires & (cken70_cnt == 3'd3))
|
|
| (cr.dc7 == 1'b0 & ((cken70_cnt == 3'd7))))
|
|
& (h_cnt < (LINE_CLOCKS - 12'(2+1))))
|
|
| (cr.dc7 == 1'b1 & (cken70_cnt == 3'd5))
|
|
| h_wrap) begin
|
|
cken70_cnt <= '0;
|
|
cken70 <= '1;
|
|
end
|
|
if (((cr.dc7 == 1'b0) & (cken70_cnt == 3'd3))
|
|
| ((cr.dc7 == 1'b1) & (cken70_cnt == 3'd2)))
|
|
cken70_ne <= '1;
|
|
end
|
|
end
|
|
|
|
assign DCK70 = cken70;
|
|
assign DCK70_NEGEDGE = cken70_ne;
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// VPU (HuC6271 RAINBOW) / MMC (HuC6272 KING) Pixel clock generator
|
|
//
|
|
// Fixed rate for 256 horizontal pixels
|
|
|
|
logic [2:0] ckenkr_cnt;
|
|
logic ckenkr, ckenkr_ne;
|
|
|
|
always @(posedge CLK) begin
|
|
ckenkr <= '0;
|
|
ckenkr_ne <= '0;
|
|
|
|
if (~RESn) begin
|
|
ckenkr_cnt <= '0;
|
|
end
|
|
else begin
|
|
ckenkr_cnt <= ckenkr_cnt + 1'd1;
|
|
|
|
if (((ckenkr_cnt == 3'd7)
|
|
& (h_cnt < (LINE_CLOCKS - 12'(2+1))))
|
|
| h_wrap) begin
|
|
ckenkr_cnt <= '0;
|
|
ckenkr <= '1;
|
|
end
|
|
if (ckenkr_cnt == 3'd3)
|
|
ckenkr_ne <= '1;
|
|
end
|
|
end
|
|
|
|
assign DCKKR = ckenkr;
|
|
assign DCKKR_NEGEDGE = ckenkr_ne;
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// VDC MUX
|
|
|
|
logic vdc_en, vdc_key;
|
|
logic [8:0] vdc_vd;
|
|
logic vdc_spbg;
|
|
logic [8:0] vdc_cpa_bg, vdc_cpa_sp;
|
|
logic vdc_cce;
|
|
|
|
wire vdc0_key = VDC0_VD[7:0] != '0;
|
|
wire vdc1_key = VDC1_VD[7:0] != '0;
|
|
|
|
// "Upper" 6270 has priority over "lower".
|
|
assign vdc_vd = ~vdc1_key ? VDC0_VD : VDC1_VD;
|
|
assign vdc_spbg = vdc_vd[8];
|
|
assign vdc_en = vdc_spbg ? cr.sp : cr.bg;
|
|
assign vdc_key = vdc_en & (vdc0_key | vdc1_key);
|
|
|
|
assign vdc_cpa_bg = {vdc_bg_cpao, 1'b0} + {1'b0, vdc_vd[7:0]};
|
|
assign vdc_cpa_sp = {vdc_sp_cpao, 1'b0} + {1'b0, vdc_vd[7:0]};
|
|
assign vdc_cce = spbl[vdc_vd[7:4]];
|
|
|
|
assign layers[0].pri = vdc_spbg ? pri_vdc_sp : pri_vdc_bg;
|
|
assign layers[0].key = vdc_key;
|
|
assign layers[0].vd = 24'(vdc_spbg ? vdc_cpa_sp : vdc_cpa_bg);
|
|
assign layers[0].pal = '1;
|
|
assign layers[0].cpe = ble_cpe_t'(vdc_spbg ? (ble.vdc_sp & {2{vdc_cce}})
|
|
: ble.vdc_bg);
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// MMC (KING) video input
|
|
|
|
logic mmc_en, mmc_key;
|
|
|
|
assign mmc_en = cr.bmg[0];
|
|
assign mmc_key = mmc_en & |MMC_VD[16+:8];
|
|
|
|
// MMC BG0
|
|
assign layers[1].pri = pri_mmc_bg0;
|
|
assign layers[1].key = mmc_key;
|
|
assign layers[1].vd = MMC_VD;
|
|
assign layers[1].pal = '0;
|
|
assign layers[1].cpe = ble.mmc_bg0;
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// [Placeholder] VPU (RAINBOW) video input
|
|
|
|
assign layers[2].pri = pri_vpu;
|
|
assign layers[2].key = '0; // transparent
|
|
assign layers[2].vd = '0;
|
|
assign layers[2].pal = '0;
|
|
assign layers[2].cpe = ble.vpu;
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Layer priority encoder
|
|
|
|
logic [1:0] prio_idx [3];
|
|
logic [1:0] prio_sel;
|
|
logic [1:0] prio_out;
|
|
|
|
// Sort layers from lowest to highest priority
|
|
always @(posedge CLK) begin
|
|
case ({layers[1].pri < layers[0].pri,
|
|
layers[2].pri < layers[1].pri,
|
|
layers[2].pri < layers[0].pri})
|
|
3'b111: begin prio_idx[0] <= 2'd2; prio_idx[1] <= 2'd1; prio_idx[2] <= 2'd0; end
|
|
3'b101: begin prio_idx[0] <= 2'd1; prio_idx[1] <= 2'd2; prio_idx[2] <= 2'd0; end
|
|
3'b011: begin prio_idx[0] <= 2'd2; prio_idx[1] <= 2'd0; prio_idx[2] <= 2'd1; end
|
|
3'b100: begin prio_idx[0] <= 2'd1; prio_idx[1] <= 2'd0; prio_idx[2] <= 2'd2; end
|
|
3'b010: begin prio_idx[0] <= 2'd0; prio_idx[1] <= 2'd2; prio_idx[2] <= 2'd1; end
|
|
3'b000: begin prio_idx[0] <= 2'd0; prio_idx[1] <= 2'd1; prio_idx[2] <= 2'd2; end
|
|
default:begin prio_idx[0] <= 2'dX; prio_idx[1] <= 2'dX; prio_idx[2] <= 2'dX; end
|
|
endcase
|
|
end
|
|
|
|
// Selected priority
|
|
assign prio_out = prio_idx[prio_sel];
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Video layer MUX
|
|
|
|
layer_t vmux;
|
|
logic vmux_low_chroma;
|
|
|
|
always @* begin
|
|
vmux = layers[prio_out];
|
|
if (vmux_low_chroma && prio_sel == 2'd0 && ~vmux.key) begin
|
|
vmux.vd = '0;
|
|
vmux.pal = '1;
|
|
end
|
|
end
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Palette RAM address generator
|
|
|
|
logic [8:0] cpa_out;
|
|
|
|
always @* begin
|
|
cpa_out = '0;
|
|
if (vmux.pal)
|
|
cpa_out = vmux.vd[8:0];
|
|
end
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Color palette RAM
|
|
|
|
logic [15:0] cp_out;
|
|
|
|
dpram #(.addr_width(9), .data_width(16)) cpram
|
|
(
|
|
.clock(CLK),
|
|
.address_a(cpa),
|
|
.data_a(cpdin),
|
|
.enable_a(1'b1),
|
|
.wren_a(cpd_wr),
|
|
.q_a(cpdout),
|
|
.cs_a(1'b1),
|
|
|
|
.address_b(cpa_out),
|
|
.data_b('0),
|
|
.enable_b(1'b1),
|
|
.wren_b('0),
|
|
.q_b(cp_out),
|
|
.cs_b(1'b1)
|
|
);
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Video layer @ YUV
|
|
|
|
logic [23:0] mix_vd;
|
|
yuv888_t mix_out;
|
|
|
|
layer_t mix;
|
|
|
|
always @(posedge CLK) begin
|
|
mix_vd <= vmux.vd;
|
|
end
|
|
|
|
always @* begin
|
|
if (vmux.pal) begin
|
|
mix_out.y = cp_out[8+:8];
|
|
mix_out.u = {cp_out[7:4], cp_out[6:4], cp_out[6]};
|
|
mix_out.v = {cp_out[3:0], cp_out[2:0], cp_out[2]};
|
|
end
|
|
else
|
|
mix_out = yuv888_t'(mix_vd);
|
|
end
|
|
|
|
assign mix.vd = mix_out;
|
|
assign mix.key = vmux.key;
|
|
assign mix.cpe = vmux.cpe;
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Chroma key and Cellophane Dot Processing
|
|
|
|
yuv888_t ccdp_sel1, ccdp_sel2, ccdp_reg1, ccdp_reg2;
|
|
logic ccdp_sel1_ccr;
|
|
logic ccdp_sel2_cc;
|
|
blxx_t ccdp_m, ccdp_n;
|
|
yuv888_t ccdp_ccout;
|
|
logic ccdp_reg1_en;
|
|
logic ccdp_low_chroma;
|
|
|
|
// There are four processing phases per dot clock.
|
|
wire [1:0] ccdp_phase = ckenkr_cnt[2:1];
|
|
|
|
// Cellophane calculation
|
|
function [7:0] ccdp_cc(input [7:0] m, input [7:0] n,
|
|
input [3:0] a, input [3:0] b,
|
|
input uv);
|
|
logic signed [12:0] ma;
|
|
if (uv) begin
|
|
m -= 8'sh80;
|
|
n -= 8'sh80;
|
|
ma = $signed(m) * $signed(a);
|
|
ma += $signed(n) * $signed(b);
|
|
ma += 13'(11'sh80 << 3);
|
|
end
|
|
else begin
|
|
ma = m * a;
|
|
ma += n * b;
|
|
end
|
|
ccdp_cc = ma[10:3];
|
|
if (ma[11])
|
|
ccdp_cc = 8'hff;
|
|
endfunction
|
|
|
|
function blxx_t get_ccdp_m(input ble_cpe_t cpe);
|
|
case (cpe)
|
|
CPE_OFF: get_ccdp_m = '0;
|
|
CPE_ON_1AB: get_ccdp_m = bl1a;
|
|
CPE_ON_2AB: get_ccdp_m = bl2a;
|
|
CPE_ON_3AB: get_ccdp_m = bl3a;
|
|
default: ;
|
|
endcase
|
|
endfunction
|
|
|
|
function blxx_t get_ccdp_n(input ble_cpe_t cpe);
|
|
case (cpe)
|
|
CPE_OFF: get_ccdp_n = '0;
|
|
CPE_ON_1AB: get_ccdp_n = bl1b;
|
|
CPE_ON_2AB: get_ccdp_n = bl2b;
|
|
CPE_ON_3AB: get_ccdp_n = bl3b;
|
|
default: ;
|
|
endcase
|
|
endfunction
|
|
|
|
assign ccdp_m = get_ccdp_m(mix.cpe);
|
|
assign ccdp_n = get_ccdp_n(mix.cpe);
|
|
|
|
always @* begin
|
|
ccdp_ccout.y = ccdp_cc(ccdp_sel1.y, ccdp_reg1.y, ccdp_m.y, ccdp_n.y, 0);
|
|
ccdp_ccout.u = ccdp_cc(ccdp_sel1.u, ccdp_reg1.u, ccdp_m.u, ccdp_n.u, 1);
|
|
ccdp_ccout.v = ccdp_cc(ccdp_sel1.v, ccdp_reg1.v, ccdp_m.v, ccdp_n.v, 1);
|
|
end
|
|
|
|
// Selector 1: Fixed color -or- selected priority layer
|
|
always @* begin
|
|
ccdp_sel1 = yuv888_t'(mix.vd);
|
|
if (ccdp_sel1_ccr) begin
|
|
ccdp_sel1.y = ccr[8+:8];
|
|
ccdp_sel1.u = {ccr[7:4], ccr[6:4], ccr[6]};
|
|
ccdp_sel1.v = {ccr[3:0], ccr[2:0], ccr[2]};
|
|
end
|
|
end
|
|
|
|
// Selector 2: Selector 1 -or- cellophane calculation
|
|
assign ccdp_sel2 = ccdp_sel2_cc ? ccdp_ccout : ccdp_sel1;
|
|
|
|
// Register 1: Latches selector 2 at fast clock rate
|
|
always @(posedge CLK) if (ckenf) begin
|
|
if (ccdp_reg1_en)
|
|
ccdp_reg1 <= ccdp_sel2;
|
|
end
|
|
|
|
// Register 2: Latches register 1 at output dot clock rate
|
|
always @(posedge CLK) if (DCK70) begin
|
|
ccdp_reg2 <= ccdp_reg1;
|
|
end
|
|
|
|
// Logic to glue it all together
|
|
always @* begin
|
|
prio_sel = '0;
|
|
ccdp_sel1_ccr = '0;
|
|
ccdp_sel2_cc = '0;
|
|
ccdp_reg1_en = '0;
|
|
ccdp_low_chroma = '0;
|
|
|
|
if (cr.dc7) begin
|
|
prio_sel = 2'd2;
|
|
ccdp_reg1_en = '1;
|
|
end
|
|
else begin
|
|
if (ccdp_phase < 2'd3) begin
|
|
prio_sel = ccdp_phase;
|
|
ccdp_reg1_en = mix.key;
|
|
ccdp_sel1_ccr = '0;
|
|
ccdp_sel2_cc = mix.cpe != CPE_OFF;
|
|
end
|
|
if (ccdp_phase == 2'd0 && !(ble.ed & ~ble.fb)) begin
|
|
// Special case for lowest priority layer
|
|
ccdp_low_chroma = '1;
|
|
ccdp_reg1_en = '1;
|
|
end
|
|
end
|
|
end
|
|
|
|
assign vmux_low_chroma = ccdp_low_chroma;
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Sync generators
|
|
|
|
logic [11:0] hsync_start_pos, hsync_end_pos;
|
|
logic hbl_ff = '1, vbl_ff = '1;
|
|
|
|
always @* begin
|
|
hsync_start_pos = (cr.dc7 ? (LINE_CLOCKS - 12'd6) : 12'd8) - 1'd1;
|
|
hsync_end_pos = (cr.dc7 ? (12'd468 - 12'd6) : (12'd8 + 12'd464)) - 1'd1;
|
|
end
|
|
|
|
// These syncs are for the VDCs.
|
|
always @(posedge CLK) begin
|
|
HSYNC_NEGEDGE <= (h_cnt == hsync_start_pos);
|
|
HSYNC_POSEDGE <= (h_cnt == hsync_end_pos);
|
|
VSYNC_NEGEDGE <= ((v_cnt == VS_LINES - 1'd1) & h_wrap);
|
|
VSYNC_POSEDGE <= (v_wrap & h_wrap);
|
|
end
|
|
|
|
// These syncs are for the actual video output.
|
|
always @(posedge CLK) begin
|
|
if (h_cnt == HS_OFF)
|
|
HSn <= '0;
|
|
else if (h_cnt == HS_OFF + HS_CLOCKS)
|
|
HSn <= '1;
|
|
|
|
if (v_cnt == 9'd0)
|
|
VSn <= '0;
|
|
else if (v_cnt == VS_LINES)
|
|
VSn <= '1;
|
|
end
|
|
|
|
// Blanking periods
|
|
always @(posedge CLK) begin
|
|
if (h_cnt == LEFT_BL_CLOCKS)
|
|
hbl_ff <= '0;
|
|
else if (h_cnt == LEFT_BL_CLOCKS + DISP_CLOCKS)
|
|
hbl_ff <= '1;
|
|
|
|
if (v_cnt == TOP_BL_LINES)
|
|
vbl_ff <= '0;
|
|
else if (v_cnt == TOP_BL_LINES + DISP_LINES)
|
|
vbl_ff <= '1;
|
|
end
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Final output
|
|
|
|
always @(posedge CLK) if (DCK70) begin
|
|
VBL <= vbl_ff;
|
|
HBL <= hbl_ff;
|
|
|
|
Y <= ccdp_reg2.y;
|
|
U <= ccdp_reg2.u;
|
|
V <= ccdp_reg2.v;
|
|
end
|
|
|
|
endmodule
|