Update sys. HV-Integer scale.

This commit is contained in:
sorgelig 2021-03-03 17:35:46 +08:00
parent 6e539eba92
commit 7d22fc77e8
16 changed files with 1069 additions and 263 deletions

View File

@ -39,8 +39,9 @@ module emu
output CE_PIXEL,
//Video aspect ratio for HDMI. Most retro systems have ratio 4:3.
output [11:0] VIDEO_ARX,
output [11:0] VIDEO_ARY,
//if VIDEO_ARX[12] or VIDEO_ARY[12] is set then [11:0] contains scaled size instead of aspect ratio.
output [12:0] VIDEO_ARX,
output [12:0] VIDEO_ARY,
output [7:0] VGA_R,
output [7:0] VGA_G,
@ -52,6 +53,9 @@ module emu
output [1:0] VGA_SL,
output VGA_SCALER, // Force VGA scaler
input [11:0] HDMI_WIDTH,
input [11:0] HDMI_HEIGHT,
`ifdef USE_FB
// Use framebuffer in DDRAM (USE_FB=1 in qsf)
// FB_FORMAT:
@ -182,9 +186,18 @@ assign BUTTONS = 0;
assign VGA_SCALER= 0;
wire [1:0] ar = status[8:7];
video_freak video_freak
(
.*,
.VGA_DE_IN(VGA_DE),
.VGA_DE(),
assign VIDEO_ARX = (!ar) ? 12'd4 : (ar - 1'd1);
assign VIDEO_ARY = (!ar) ? 12'd3 : 12'd0;
.ARX((!ar) ? 12'd4 : (ar - 1'd1)),
.ARY((!ar) ? 12'd3 : 12'd0),
.CROP_SIZE(0),
.CROP_OFF(0),
.SCALE(status[12:11])
);
`include "build_id.v"
localparam CONF_STR = {
@ -196,6 +209,8 @@ localparam CONF_STR = {
"S0,VHD,Mount HDD;",
"-;",
"O78,Aspect ratio,Original,Full Screen,[ARC1],[ARC2];",
"OBC,Scale,Normal,V-Integer,Narrower HV-Integer,Wider HV-Integer;",
"-;",
"O9A,Memory,512KB,1MB,4MB;",
"O5,Speed,Normal,Turbo;",
"-;",

View File

@ -112,9 +112,9 @@ wire scandoubler = fx || forced_scandoubler;
video_mixer #(.LINE_LENGTH(WIDTH+4), .HALF_DEPTH(DW!=24), .GAMMA(GAMMA)) video_mixer
(
.clk_vid(CLK_VIDEO),
.CLK_VIDEO(CLK_VIDEO),
.ce_pix(CE),
.ce_pix_out(CE_PIXEL),
.CE_PIXEL(CE_PIXEL),
.scandoubler(scandoubler),
.hq2x(fx==1),

View File

@ -429,7 +429,7 @@ ARCHITECTURE rtl OF ascal IS
SIGNAL o_readdataack,o_readdataack_sync,o_readdataack_sync2 : std_logic;
SIGNAL o_copyv : unsigned(0 TO 8);
SIGNAL o_adrs : unsigned(31 DOWNTO 0); -- Avalon address
SIGNAL o_adrs_pre : natural RANGE 0 TO 2**23-1;
SIGNAL o_adrs_pre : natural RANGE 0 TO 2**24-1;
SIGNAL o_stride : unsigned(13 DOWNTO 0);
SIGNAL o_adrsa,o_adrsb,o_rline : std_logic;
SIGNAL o_ad,o_ad1,o_ad2,o_ad3 : natural RANGE 0 TO 2*BLEN-1;
@ -1519,7 +1519,7 @@ BEGIN
avl_read_sync<=o_read; -- <ASYNC>
avl_read_sync2<=avl_read_sync;
avl_read_pulse<=avl_read_sync XOR avl_read_sync2;
avl_radrs <=o_adrs AND (RAMSIZE - 1); -- <ASYNC>
avl_radrs <=o_adrs; -- <ASYNC>
avl_rline <=o_rline; -- <ASYNC>
--------------------------------------------

View File

@ -0,0 +1,250 @@
// ============================================================================
//
// f2sdram_safe_terminator for MiSTer platform
//
// ============================================================================
// Copyright (c) 2021 bellwood420
//
// Background:
//
// Terminating a transaction of burst writing(/reading) in its midstream
// seems to cause an illegal state to f2sdram interface.
//
// Forced reset request that occurs when loading other core is inevitable.
//
// So if it happens exactly within the transaction period,
// unexpected issues with accessing to f2sdram interface will be caused
// in next loaded core.
//
// It seems that only way to reset broken f2sdram interface is to reset
// whole SDRAM Controller Subsystem from HPS via permodrst register
// in Reset Manager.
// But it cannot be done safely while Linux is running.
// It is usually done when cold or warm reset is issued in HPS.
//
// Main_MiSTer is issuing reset for FPGA <> HPS bridges
// via brgmodrst register in Reset Manager when loading rbf.
// But it has no effect on f2sdram interface.
// f2sdram interface seems to belong to SDRAM Controller Subsystem
// rather than FPGA-to-HPS bridge.
//
// Main_MiSTer is also trying to issuing reset for f2sdram ports
// via fpgaportrst register in SDRAM Controller Subsystem when loading rbf.
// But according to the Intel's document, fpgaportrst register can be
// used to stretch the port reset.
// It seems that it cannot be used to assert the port reset.
//
// According to the Intel's document, there seems to be a reset port on
// Avalon-MM slave interface, but it cannot be found in Qsys generated HDL.
//
// To conclude, the only thing FPGA can do is not to break the transaction.
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
//
// Purpose:
// To prevent the issue, this module completes ongoing transaction
// on behalf of user logic, when reset is asserted.
//
// Usage:
// Insert this module into the bus line between
// f2sdram (Avalon-MM slave) and user logic (Avalon-MM master).
//
// Notice:
// Asynchronous reset request is not supported.
// Please feed reset request synchronized to clock.
//
module f2sdram_safe_terminator #(
parameter DATA_WIDTH = 64,
parameter BURSTCOUNT_WIDTH = 8
) (
// clk should be the same as one provided to f2sdram port
// clk should not be stop when reset is asserted
input clk,
// rst_req_sync should be synchronized to clk
// Asynchronous reset request is not supported
input rst_req_sync,
// Master port: connecting to Alavon-MM slave(f2sdram)
input waitrequest_master,
output [BURSTCOUNT_WIDTH-1:0] burstcount_master,
output [ADDRESS_WITDH-1:0] address_master,
input [DATA_WIDTH-1:0] readdata_master,
input readdatavalid_master,
output read_master,
output [DATA_WIDTH-1:0] writedata_master,
output [BYTEENABLE_WIDTH-1:0] byteenable_master,
output write_master,
// Slave port: connecting to Alavon-MM master(user logic)
output waitrequest_slave,
input [BURSTCOUNT_WIDTH-1:0] burstcount_slave,
input [ADDRESS_WITDH-1:0] address_slave,
output [DATA_WIDTH-1:0] readdata_slave,
output readdatavalid_slave,
input read_slave,
input [DATA_WIDTH-1:0] writedata_slave,
input [BYTEENABLE_WIDTH-1:0] byteenable_slave,
input write_slave
);
localparam BYTEENABLE_WIDTH = DATA_WIDTH/8;
localparam ADDRESS_WITDH = 32-$clog2(BYTEENABLE_WIDTH);
/*
* Capture init reset deaseert
*/
reg init_reset_deasserted = 1'b0;
always_ff @(posedge clk) begin
if (!rst_req_sync) begin
init_reset_deasserted <= 1'b1;
end
end
/*
* Lock stage
*/
reg lock_stage = 1'b0;
always_ff @(posedge clk) begin
if (rst_req_sync) begin
// Reset assert
if (init_reset_deasserted) begin
lock_stage <= 1'b1;
end
end
else begin
// Reset deassert
lock_stage <= 1'b0;
end
end
/*
* Write burst transaction observer
*/
reg state_write = 1'b0;
wire next_state_write;
wire burst_write_start = !state_write && next_state_write;
wire valid_write_data = state_write && !waitrequest_master;
wire burst_write_end = state_write && (write_burstcounter == write_burstcount_latch - 1'd1);
wire valid_non_burst_write = !state_write && write_slave && (burstcount_slave == 1) && !waitrequest_master;
reg [BURSTCOUNT_WIDTH-1:0] write_burstcounter = 0;
reg [BURSTCOUNT_WIDTH-1:0] write_burstcount_latch = 0;
reg [ADDRESS_WITDH-1:0] write_address_latch = 0;
always_ff @(posedge clk) begin
state_write <= next_state_write;
if (burst_write_start) begin
write_burstcounter <= waitrequest_master ? 1'd0 : 1'd1;
write_burstcount_latch <= burstcount_slave;
write_address_latch <= address_slave;
end
else if (valid_write_data) begin
write_burstcounter <= write_burstcounter + 1'd1;
end
end
always_comb begin
if (!state_write) begin
if (valid_non_burst_write)
next_state_write = 1'b0;
else if (write_slave)
next_state_write = 1'b1;
else
next_state_write = 1'b0;
end
else begin
if (burst_write_end)
next_state_write = 1'b0;
else
next_state_write = 1'b1;
end
end
reg [BURSTCOUNT_WIDTH-1:0] write_terminate_counter = 0;
reg [BURSTCOUNT_WIDTH-1:0] burstcount_latch = 0;
reg [ADDRESS_WITDH-1:0] address_latch = 0;
reg terminating = 0;
reg read_terminating = 0;
reg write_terminating = 0;
wire on_write_transaction = state_write && next_state_write;
wire on_start_write_transaction = !state_write && next_state_write;
always_ff @(posedge clk) begin
if (rst_req_sync) begin
// Reset assert
if (init_reset_deasserted) begin
if (!lock_stage) begin
// Even not knowing reading is in progress or not,
// if it is in progress, it will finish at some point, and no need to do anything.
// Assume that reading is in progress when we are not on write transaction.
burstcount_latch <= burstcount_slave;
address_latch <= address_slave;
terminating <= 1;
if (on_write_transaction) begin
write_terminating <= 1;
burstcount_latch <= write_burstcount_latch;
address_latch <= write_address_latch;
write_terminate_counter <= waitrequest_master ? write_burstcounter : write_burstcounter + 1'd1;
end
else if (on_start_write_transaction) begin
if (!valid_non_burst_write) begin
write_terminating <= 1;
write_terminate_counter <= waitrequest_master ? 1'd0 : 1'd1;
end
end
else if (read_slave && waitrequest_master) begin
// Need to keep read signal, burstcount and address until waitrequest_master deasserted
read_terminating <= 1;
end
end
else if (!waitrequest_master) begin
read_terminating <= 0;
end
end
end
else begin
// Reset deassert
if (!write_terminating) terminating <= 0;
read_terminating <= 0;
end
if (write_terminating) begin
// Continue write transaction until the end
if (!waitrequest_master) write_terminate_counter <= write_terminate_counter + 1'd1;
if (write_terminate_counter == burstcount_latch - 1'd1) write_terminating <= 0;
end
end
/*
* Bus mux depending on the stage.
*/
always_comb begin
if (terminating) begin
burstcount_master = burstcount_latch;
address_master = address_latch;
read_master = read_terminating;
write_master = write_terminating;
byteenable_master = 0;
end
else begin
burstcount_master = burstcount_slave;
address_master = address_slave;
read_master = read_slave;
byteenable_master = byteenable_slave;
write_master = write_slave;
end
end
// Just passing master <-> slave
assign writedata_master = writedata_slave;
assign readdata_slave = readdata_master;
assign readdatavalid_slave = readdatavalid_master;
assign waitrequest_slave = waitrequest_master;
endmodule

View File

@ -37,13 +37,23 @@ always @(posedge CLK) begin
end
end
assign I2C_SCL = SCLK | I2C_CLOCK;
assign I2C_SCL = (SCLK | I2C_CLOCK) ? 1'bZ : 1'b0;
assign I2C_SDA = SDO[3] ? 1'bz : 1'b0;
reg SCLK = 1;
reg [3:0] SDO = 4'b1111;
reg SCLK;
reg [3:0] SDO;
reg [0:7] rdata;
reg [5:0] SD_COUNTER;
reg [0:31] SD;
initial begin
SD_COUNTER = 'b111111;
SD = 'hFFFF;
SCLK = 1;
SDO = 4'b1111;
end
assign I2C_RDATA = rdata;
always @(posedge CLK) begin
@ -51,9 +61,6 @@ always @(posedge CLK) begin
reg old_st;
reg rd,len;
reg [5:0] SD_COUNTER = 'b111111;
reg [0:31] SD;
old_clk <= I2C_CLOCK;
old_st <= START;

109
sys/math.sv Normal file
View File

@ -0,0 +1,109 @@
// result = num/div
module sys_udiv
#(
parameter NB_NUM,
parameter NB_DIV
)
(
input clk,
input start,
output busy,
input [NB_NUM-1:0] num,
input [NB_DIV-1:0] div,
output reg [NB_NUM-1:0] result,
output reg [NB_DIV-1:0] remainder
);
reg run;
assign busy = run;
always @(posedge clk) begin
reg [5:0] cpt;
reg [NB_NUM+NB_DIV+1:0] rem;
if (start) begin
cpt <= 0;
run <= 1;
rem <= num;
end
else if (run) begin
cpt <= cpt + 1'd1;
run <= (cpt != NB_NUM + 1'd1);
remainder <= rem[NB_NUM+NB_DIV:NB_NUM+1];
if (!rem[NB_DIV + NB_NUM + 1'd1])
rem <= {rem[NB_DIV+NB_NUM:0] - (div << NB_NUM),1'b0};
else
rem <= {rem[NB_DIV+NB_NUM:0] + (div << NB_NUM),1'b0};
result <= {result[NB_NUM-2:0], !rem[NB_DIV + NB_NUM + 1'd1]};
end
end
endmodule
// result = mul1*mul2
module sys_umul
#(
parameter NB_MUL1,
parameter NB_MUL2
)
(
input clk,
input start,
output busy,
input [NB_MUL1-1:0] mul1,
input [NB_MUL2-1:0] mul2,
output reg [NB_MUL1+NB_MUL2-1:0] result
);
reg run;
assign busy = run;
always @(posedge clk) begin
reg [NB_MUL1+NB_MUL2-1:0] add;
reg [NB_MUL2-1:0] map;
if (start) begin
run <= 1;
result <= 0;
add <= mul1;
map <= mul2;
end
else if (run) begin
if(!map) run <= 0;
if(map[0]) result <= result + add;
add <= add << 1;
map <= map >> 1;
end
end
endmodule
// result = (mul1*mul2)/div
module sys_umuldiv
#(
parameter NB_MUL1,
parameter NB_MUL2,
parameter NB_DIV
)
(
input clk,
input start,
output busy,
input [NB_MUL1-1:0] mul1,
input [NB_MUL2-1:0] mul2,
input [NB_DIV-1:0] div,
output [NB_MUL1+NB_MUL2-1:0] result,
output [NB_DIV-1:0] remainder
);
wire mul_run;
wire [NB_MUL1+NB_MUL2-1:0] mul_res;
sys_umul #(NB_MUL1,NB_MUL2) umul(clk,start,mul_run,mul1,mul2,mul_res);
sys_udiv #(NB_MUL1+NB_MUL2,NB_DIV) udiv(clk,start|mul_run,busy,mul_res,div,result,remainder);
endmodule

View File

@ -2,7 +2,7 @@
// scandoubler.v
//
// Copyright (c) 2015 Till Harbaum <till@harbaum.org>
// Copyright (c) 2017-2019 Sorgelig
// Copyright (c) 2017-2021 Alexey Melnikov
//
// This source file is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published
@ -23,23 +23,20 @@ module scandoubler #(parameter LENGTH, parameter HALF_DEPTH)
(
// system interface
input clk_vid,
input ce_pix,
output ce_pix_out,
input hq2x,
// shifter video interface
input ce_pix,
input hs_in,
input vs_in,
input hb_in,
input vb_in,
input [DWIDTH:0] r_in,
input [DWIDTH:0] g_in,
input [DWIDTH:0] b_in,
input mono,
// output interface
output ce_pix_out,
output reg hs_out,
output vs_out,
output hb_out,
@ -109,7 +106,6 @@ Hq2x #(.LENGTH(LENGTH), .HALF_DEPTH(HALF_DEPTH)) Hq2x
.ce_in(ce_x4i),
.inputpixel({b_d,g_d,r_d}),
.mono(mono),
.disable_hq2x(~hq2x),
.reset_frame(vb_in),
.reset_line(req_line_reset),

View File

@ -67,7 +67,7 @@ reg spdif_out_q;
reg [5:0] parity_count_q;
reg channel_status_bit;
reg channel_status_bit_q;
//-----------------------------------------------------------------
// Subframe Counter
@ -144,19 +144,20 @@ assign subframe_w[28] = 1'b0; // Valid
assign subframe_w[29] = 1'b0;
// Timeslots 30 = Channel status bit
assign subframe_w[30] = channel_status_bit ; //was constant 1'b0 enabling copy-bit;
assign subframe_w[30] = channel_status_bit_q ; //was constant 1'b0 enabling copy-bit;
// Timeslots 31 = Even Parity bit (31:4)
assign subframe_w[31] = 1'b0;
//-----------------------------------------------------------------
// Preamble
// Preamble and Channel status bit
//-----------------------------------------------------------------
localparam PREAMBLE_Z = 8'b00010111; // "B" channel A data at start of block
localparam PREAMBLE_Y = 8'b00100111; // "W" channel B data
localparam PREAMBLE_X = 8'b01000111; // "M" channel A data not at start of block
reg [7:0] preamble_r;
reg channel_status_bit_r;
always @ *
begin
@ -172,20 +173,28 @@ begin
preamble_r = PREAMBLE_X; // X(M)
if (subframe_count_q[8:1] == 8'd2) // frame 2 => subframes 4 and 5 => 0 = copy inhibited, 1 = copy permitted
channel_status_bit = 1'b1;
channel_status_bit_r = 1'b1;
else if (subframe_count_q[8:1] == 8'd15) // frame 15 => 0 = no indication, 1 = original media
channel_status_bit = 1'b1;
channel_status_bit_r = 1'b1;
else if (subframe_count_q[8:1] == 8'd25) // frame 24 to 27 => sample frequency, 0100 = 48kHz, 0000 = 44kHz (l2r)
channel_status_bit = 1'b1;
channel_status_bit_r = 1'b1;
else
channel_status_bit = 1'b0; // everything else defaults to 0
channel_status_bit_r = 1'b0; // everything else defaults to 0
end
always @ (posedge rst_i or posedge clk_i )
if (rst_i == 1'b1)
begin
if (rst_i == 1'b1)
begin
preamble_q <= 8'h00;
else if (load_subframe_q)
channel_status_bit_q <= 1'b0;
end
else if (load_subframe_q)
begin
preamble_q <= preamble_r;
channel_status_bit_q <= channel_status_bit_r;
end
end
//-----------------------------------------------------------------
// Parity Counter

View File

@ -3,12 +3,14 @@ set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) s
set_global_assignment -name SDC_FILE [file join $::quartus(qip_path) sys_top.sdc ]
set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) ascal.vhd ]
set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) pll_hdmi_adj.vhd ]
set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) math.sv ]
set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) hq2x.sv ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) scandoubler.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) scanlines.v ]
set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) video_cleaner.sv ]
set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) gamma_corr.sv ]
set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) video_mixer.sv ]
set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) video_freak.sv ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) arcade_video.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) osd.v ]
set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) vga_out.sv ]
@ -23,6 +25,7 @@ set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) s
set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) mt32pi.sv ]
set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) hdmi_config.sv ]
set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) mcp23009.sv ]
set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) f2sdram_safe_terminator.sv ]
set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) ddr_svc.sv ]
set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) sysmem.sv ]
set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) sd_card.sv ]

View File

@ -218,6 +218,7 @@ set_location_assignment PIN_W20 -to SW[3]
set_instance_assignment -name HPS_LOCATION HPSINTERFACEPERIPHERALSPIMASTER_X52_Y72_N111 -entity sys_top -to spi
set_instance_assignment -name HPS_LOCATION HPSINTERFACEPERIPHERALUART_X52_Y67_N111 -entity sys_top -to uart
set_instance_assignment -name HPS_LOCATION HPSINTERFACEPERIPHERALI2C_X52_Y60_N111 -entity sys_top -to hdmi_i2c
set_global_assignment -name PRE_FLOW_SCRIPT_FILE "quartus_sh:sys/build_id.tcl"

View File

@ -4,6 +4,7 @@ create_clock -period "50.0 MHz" [get_ports FPGA_CLK2_50]
create_clock -period "50.0 MHz" [get_ports FPGA_CLK3_50]
create_clock -period "100.0 MHz" [get_pins -compatibility_mode *|h2f_user0_clk]
create_clock -period "100.0 MHz" [get_pins -compatibility_mode spi|sclk_out] -name spi_sck
create_clock -period "10.0 MHz" [get_pins -compatibility_mode hdmi_i2c|out_clk] -name hdmi_sck
derive_pll_clocks
derive_clock_uncertainty
@ -14,6 +15,7 @@ set_clock_groups -exclusive \
-group [get_clocks { pll_hdmi|pll_hdmi_inst|altera_pll_i|*[0].*|divclk}] \
-group [get_clocks { pll_audio|pll_audio_inst|altera_pll_i|*[0].*|divclk}] \
-group [get_clocks { spi_sck}] \
-group [get_clocks { hdmi_sck}] \
-group [get_clocks { *|h2f_user0_clk}] \
-group [get_clocks { FPGA_CLK1_50 }] \
-group [get_clocks { FPGA_CLK2_50 }] \
@ -30,7 +32,7 @@ set_false_path -to {cfg[*]}
set_false_path -from {cfg[*]}
set_false_path -from {VSET[*]}
set_false_path -to {wcalc[*] hcalc[*]}
set_false_path -to {width[*] height[*]}
set_false_path -to {hdmi_width[*] hdmi_height[*]}
set_multicycle_path -to {*_osd|osd_vcnt*} -setup 2
set_multicycle_path -to {*_osd|osd_vcnt*} -hold 1
@ -60,3 +62,8 @@ set_false_path -from {ascal|o_ivsize*}
set_false_path -from {ascal|o_format*}
set_false_path -from {ascal|o_hdown}
set_false_path -from {ascal|o_vdown}
set_false_path -from {ascal|o_hmin* ascal|o_hmax* ascal|o_vmin* ascal|o_vmax*}
set_false_path -from {ascal|o_hdisp* ascal|o_vdisp*}
set_false_path -from {ascal|o_htotal* ascal|o_vtotal*}
set_false_path -from {ascal|o_hsstart* ascal|o_vsstart* ascal|o_hsend* ascal|o_vsend*}
set_false_path -from {ascal|o_hsize* ascal|o_vsize*}

View File

@ -316,7 +316,7 @@ reg [6:0] coef_addr;
reg [8:0] coef_data;
reg coef_wr = 0;
wire[11:0] ARX, ARY;
wire[12:0] ARX, ARY;
reg [11:0] VSET = 0, HSET = 0;
reg FREESCALE = 0;
reg [2:0] scaler_flt;
@ -337,10 +337,10 @@ reg [23:0] acy0 = -24'd6216759;
reg [23:0] acy1 = 24'd6143386;
reg [23:0] acy2 = -24'd2023767;
reg areset = 0;
reg [11:0] arc1x = 0;
reg [11:0] arc1y = 0;
reg [11:0] arc2x = 0;
reg [11:0] arc2y = 0;
reg [12:0] arc1x = 0;
reg [12:0] arc1y = 0;
reg [12:0] arc2x = 0;
reg [12:0] arc2y = 0;
always@(posedge clk_sys) begin
reg [7:0] cmd;
@ -430,6 +430,7 @@ always@(posedge clk_sys) begin
6: LFB_HMAX <= io_din[11:0];
7: LFB_VMIN <= io_din[11:0];
8: LFB_VMAX <= io_din[11:0];
9: LFB_STRIDE <= io_din[13:0];
endcase
end
if(cmd == 'h25) {led_overtake, led_state} <= io_din;
@ -462,10 +463,10 @@ always@(posedge clk_sys) begin
if(cmd == 'h3A) begin
cnt <= cnt + 1'd1;
case(cnt[3:0])
0: arc1x <= io_din[11:0];
1: arc1y <= io_din[11:0];
2: arc2x <= io_din[11:0];
3: arc2y <= io_din[11:0];
0: arc1x <= io_din[12:0];
1: arc1y <= io_din[12:0];
2: arc2x <= io_din[12:0];
3: arc2y <= io_din[12:0];
endcase
end
end
@ -747,6 +748,7 @@ reg [11:0] LFB_HMAX = 0;
reg [11:0] LFB_VMIN = 0;
reg [11:0] LFB_VMAX = 0;
reg [31:0] LFB_BASE = 0;
reg [13:0] LFB_STRIDE = 0;
reg FB_EN = 0;
reg [5:0] FB_FMT = 0;
@ -762,7 +764,7 @@ always @(posedge clk_sys) begin
FB_WIDTH <= LFB_WIDTH;
FB_HEIGHT <= LFB_HEIGHT;
FB_BASE <= LFB_BASE;
FB_STRIDE <= 0;
FB_STRIDE <= LFB_STRIDE;
end
else begin
FB_FMT <= fb_fmt;
@ -778,74 +780,123 @@ reg fb_vbl;
always @(posedge clk_vid) fb_vbl <= hdmi_vbl;
`endif
reg ar_md_start;
wire ar_md_busy;
reg [11:0] ar_md_mul1, ar_md_mul2, ar_md_div;
wire [11:0] ar_md_res;
sys_umuldiv #(12,12,12) ar_muldiv
(
.clk(clk_vid),
.start(ar_md_start),
.busy(ar_md_busy),
.mul1(ar_md_mul1),
.mul2(ar_md_mul2),
.div(ar_md_div),
.result(ar_md_res)
);
reg [11:0] hmin;
reg [11:0] hmax;
reg [11:0] vmin;
reg [11:0] vmax;
reg [11:0] hdmi_height;
reg [11:0] hdmi_width;
always @(posedge clk_vid) begin
reg [31:0] wcalc;
reg [31:0] hcalc;
reg [11:0] hmini,hmaxi,vmini,vmaxi;
reg [11:0] wcalc,videow,arx;
reg [11:0] hcalc,videoh,ary;
reg [2:0] state;
reg [11:0] videow;
reg [11:0] videoh;
reg [11:0] height;
reg [11:0] width;
reg [11:0] arx;
reg [11:0] ary;
reg xy;
height <= (VSET && (VSET < HEIGHT)) ? VSET : HEIGHT;
width <= (HSET && (HSET < WIDTH)) ? HSET : WIDTH;
hdmi_height <= (VSET && (VSET < HEIGHT)) ? VSET : HEIGHT;
hdmi_width <= (HSET && (HSET < WIDTH)) ? HSET : WIDTH;
if(!ARY) begin
if(ARX == 1) begin
arx <= arc1x;
ary <= arc1y;
arx <= arc1x[11:0];
ary <= arc1y[11:0];
xy <= arc1x[12] | arc1y[12];
end
else if(ARX == 2) begin
arx <= arc2x;
ary <= arc2y;
arx <= arc2x[11:0];
ary <= arc2y[11:0];
xy <= arc2x[12] | arc2y[12];
end
else begin
arx <= 0;
ary <= 0;
xy <= 0;
end
end
else begin
arx <= ARX;
ary <= ARY;
arx <= ARX[11:0];
ary <= ARY[11:0];
xy <= ARX[12] | ARY[12];
end
ar_md_start <= 0;
state <= state + 1'd1;
case(state)
0: if(LFB_EN) begin
hmin <= LFB_HMIN;
vmin <= LFB_VMIN;
hmax <= LFB_HMAX;
vmax <= LFB_VMAX;
state<= 0;
hmini <= LFB_HMIN;
vmini <= LFB_VMIN;
hmaxi <= LFB_HMAX;
vmaxi <= LFB_VMAX;
state <= 0;
end
else if(FREESCALE || !arx || !ary) begin
wcalc <= width;
hcalc <= height;
wcalc <= hdmi_width;
hcalc <= hdmi_height;
state <= 6;
end
else begin
wcalc <= (height*arx)/ary;
hcalc <= (width*ary)/arx;
else if(xy) begin
wcalc <= arx;
hcalc <= ary;
state <= 6;
end
1: begin
ar_md_mul1 <= hdmi_height;
ar_md_mul2 <= arx;
ar_md_div <= ary;
ar_md_start<= 1;
end
2: begin
wcalc <= ar_md_res;
if(ar_md_start | ar_md_busy) state <= 2;
end
3: begin
ar_md_mul1 <= hdmi_width;
ar_md_mul2 <= ary;
ar_md_div <= arx;
ar_md_start<= 1;
end
4: begin
hcalc <= ar_md_res;
if(ar_md_start | ar_md_busy) state <= 4;
end
6: begin
videow <= (wcalc > width) ? width : wcalc[11:0];
videoh <= (hcalc > height) ? height : hcalc[11:0];
videow <= (wcalc > hdmi_width) ? hdmi_width : wcalc[11:0];
videoh <= (hcalc > hdmi_height) ? hdmi_height : hcalc[11:0];
end
7: begin
hmin <= ((WIDTH - videow)>>1);
hmax <= ((WIDTH - videow)>>1) + videow - 1'd1;
vmin <= ((HEIGHT - videoh)>>1);
vmax <= ((HEIGHT - videoh)>>1) + videoh - 1'd1;
hmini <= ((WIDTH - videow)>>1);
hmaxi <= ((WIDTH - videow)>>1) + videow - 1'd1;
vmini <= ((HEIGHT - videoh)>>1);
vmaxi <= ((HEIGHT - videoh)>>1) + videoh - 1'd1;
end
endcase
hmin <= hmini;
hmax <= hmaxi;
vmin <= vmini;
vmax <= vmaxi;
end
`ifndef DEBUG_NOHDMI
@ -1000,6 +1051,18 @@ hdmi_config hdmi_config
.ypbpr(ypbpr_en & direct_video)
);
assign HDMI_I2C_SCL = hdmi_scl_en ? 1'b0 : 1'bZ;
assign HDMI_I2C_SDA = hdmi_sda_en ? 1'b0 : 1'bZ;
wire hdmi_scl_en, hdmi_sda_en;
cyclonev_hps_interface_peripheral_i2c hdmi_i2c
(
.out_clk(hdmi_scl_en),
.scl(HDMI_I2C_SCL),
.out_data(hdmi_sda_en),
.sda(HDMI_I2C_SDA)
);
`ifndef DEBUG_NOHDMI
wire [23:0] hdmi_data_sl;
wire hdmi_de_sl, hdmi_vs_sl, hdmi_hs_sl;
@ -1210,32 +1273,45 @@ wire vga_cs_osd;
csync csync_vga(clk_vid, vga_hs_osd, vga_vs_osd, vga_cs_osd);
`ifndef DUAL_SDRAM
wire vs1 = (vga_fb | vga_scaler) ? hdmi_vs_osd : vga_vs_osd;
wire hs1 = (vga_fb | vga_scaler) ? hdmi_hs_osd : vga_hs_osd;
wire cs1 = (vga_fb | vga_scaler) ? hdmi_cs_osd : vga_cs_osd;
wire [23:0] vgas_o;
wire vgas_hs, vgas_vs, vgas_cs;
vga_out vga_scaler_out
(
.clk(clk_hdmi),
.ypbpr_en(ypbpr_en),
.hsync(hdmi_hs_osd),
.vsync(hdmi_vs_osd),
.csync(hdmi_cs_osd),
.dout(vgas_o),
.din({24{hdmi_de_osd}} & hdmi_data_osd),
.hsync_o(vgas_hs),
.vsync_o(vgas_vs),
.csync_o(vgas_cs)
);
wire [23:0] vga_o;
wire vga_hs, vga_vs, vga_cs;
vga_out vga_out
(
.clk(clk_vid),
.ypbpr_full(0),
.ypbpr_en(ypbpr_en),
.hsync(hs1),
.vsync(vs1),
.csync(cs1),
.hsync(vga_hs_osd),
.vsync(vga_vs_osd),
.csync(vga_cs_osd),
.dout(vga_o),
.din((vga_fb | vga_scaler) ? {24{hdmi_de_osd}} & hdmi_data_osd : vga_data_osd),
.din(vga_data_osd),
.hsync_o(vga_hs),
.vsync_o(vga_vs),
.csync_o(vga_cs)
);
assign VGA_VS = (VGA_EN | SW[3]) ? 1'bZ : csync_en ? 1'b1 : ~vga_vs;
assign VGA_HS = (VGA_EN | SW[3]) ? 1'bZ : csync_en ? ~vga_cs : ~vga_hs;
assign VGA_R = (VGA_EN | SW[3]) ? 6'bZZZZZZ : vga_o[23:18];
assign VGA_G = (VGA_EN | SW[3]) ? 6'bZZZZZZ : vga_o[15:10];
assign VGA_B = (VGA_EN | SW[3]) ? 6'bZZZZZZ : vga_o[7:2];
wire cs1 = (vga_fb | vga_scaler) ? vgas_cs : vga_cs;
assign VGA_VS = (VGA_EN | SW[3]) ? 1'bZ : ((vga_fb | vga_scaler) ? ~vgas_vs : ~vga_vs) | csync_en;
assign VGA_HS = (VGA_EN | SW[3]) ? 1'bZ : (vga_fb | vga_scaler) ? (csync_en ? ~vgas_cs : ~vgas_hs) : (csync_en ? ~vga_cs : ~vga_hs);
assign VGA_R = (VGA_EN | SW[3]) ? 6'bZZZZZZ : (vga_fb | vga_scaler) ? vgas_o[23:18] : vga_o[23:18];
assign VGA_G = (VGA_EN | SW[3]) ? 6'bZZZZZZ : (vga_fb | vga_scaler) ? vgas_o[15:10] : vga_o[15:10];
assign VGA_B = (VGA_EN | SW[3]) ? 6'bZZZZZZ : (vga_fb | vga_scaler) ? vgas_o[7:2] : vga_o[7:2] ;
`endif
reg video_sync = 0;
@ -1458,7 +1534,10 @@ emu emu
(
.CLK_50M(FPGA_CLK2_50),
.RESET(reset),
.HPS_BUS({f1, HDMI_TX_VS, clk_100m, clk_ihdmi, ce_hpix, hde_emu, hhs_fix, hvs_fix, io_wait, clk_sys, io_fpga, io_uio, io_strobe, io_wide, io_din, io_dout}),
.HPS_BUS({f1, HDMI_TX_VS,
clk_100m, clk_ihdmi,
ce_hpix, hde_emu, hhs_fix, hvs_fix,
io_wait, clk_sys, io_fpga, io_uio, io_strobe, io_wide, io_din, io_dout}),
.VGA_R(r_out),
.VGA_G(g_out),
@ -1469,6 +1548,9 @@ emu emu
.VGA_F1(f1),
.VGA_SCALER(vga_force_scaler),
.HDMI_WIDTH(direct_video ? 12'd0 : hdmi_width),
.HDMI_HEIGHT(direct_video ? 12'd0 : hdmi_height),
.CLK_VIDEO(clk_vid),
.CE_PIXEL(ce_pix),
.VGA_SL(scanlines),

View File

@ -44,41 +44,182 @@ module sysmem_lite
assign reset_out = ~init_reset_n | ~hps_h2f_reset_n | reset_core_req;
////////////////////////////////////////////////////////
//// f2sdram_safe_terminator_ram1 ////
////////////////////////////////////////////////////////
wire [28:0] f2h_ram1_address;
wire [7:0] f2h_ram1_burstcount;
wire f2h_ram1_waitrequest;
wire [63:0] f2h_ram1_readdata;
wire f2h_ram1_readdatavalid;
wire f2h_ram1_read;
wire [63:0] f2h_ram1_writedata;
wire [7:0] f2h_ram1_byteenable;
wire f2h_ram1_write;
(* altera_attribute = {"-name SYNCHRONIZER_IDENTIFICATION FORCED_IF_ASYNCHRONOUS"} *) reg ram1_reset_0 = 1'b1;
(* altera_attribute = {"-name SYNCHRONIZER_IDENTIFICATION FORCED_IF_ASYNCHRONOUS"} *) reg ram1_reset_1 = 1'b1;
always @(posedge ram1_clk) begin
ram1_reset_0 <= reset_out;
ram1_reset_1 <= ram1_reset_0;
end
f2sdram_safe_terminator #(64, 8) f2sdram_safe_terminator_ram1
(
.clk (ram1_clk),
.rst_req_sync (ram1_reset_1),
.waitrequest_slave (ram1_waitrequest),
.burstcount_slave (ram1_burstcount),
.address_slave (ram1_address),
.readdata_slave (ram1_readdata),
.readdatavalid_slave (ram1_readdatavalid),
.read_slave (ram1_read),
.writedata_slave (ram1_writedata),
.byteenable_slave (ram1_byteenable),
.write_slave (ram1_write),
.waitrequest_master (f2h_ram1_waitrequest),
.burstcount_master (f2h_ram1_burstcount),
.address_master (f2h_ram1_address),
.readdata_master (f2h_ram1_readdata),
.readdatavalid_master (f2h_ram1_readdatavalid),
.read_master (f2h_ram1_read),
.writedata_master (f2h_ram1_writedata),
.byteenable_master (f2h_ram1_byteenable),
.write_master (f2h_ram1_write)
);
////////////////////////////////////////////////////////
//// f2sdram_safe_terminator_ram2 ////
////////////////////////////////////////////////////////
wire [28:0] f2h_ram2_address;
wire [7:0] f2h_ram2_burstcount;
wire f2h_ram2_waitrequest;
wire [63:0] f2h_ram2_readdata;
wire f2h_ram2_readdatavalid;
wire f2h_ram2_read;
wire [63:0] f2h_ram2_writedata;
wire [7:0] f2h_ram2_byteenable;
wire f2h_ram2_write;
(* altera_attribute = {"-name SYNCHRONIZER_IDENTIFICATION FORCED_IF_ASYNCHRONOUS"} *) reg ram2_reset_0 = 1'b1;
(* altera_attribute = {"-name SYNCHRONIZER_IDENTIFICATION FORCED_IF_ASYNCHRONOUS"} *) reg ram2_reset_1 = 1'b1;
always @(posedge ram2_clk) begin
ram2_reset_0 <= reset_out;
ram2_reset_1 <= ram2_reset_0;
end
f2sdram_safe_terminator #(64, 8) f2sdram_safe_terminator_ram2
(
.clk (ram2_clk),
.rst_req_sync (ram2_reset_1),
.waitrequest_slave (ram2_waitrequest),
.burstcount_slave (ram2_burstcount),
.address_slave (ram2_address),
.readdata_slave (ram2_readdata),
.readdatavalid_slave (ram2_readdatavalid),
.read_slave (ram2_read),
.writedata_slave (ram2_writedata),
.byteenable_slave (ram2_byteenable),
.write_slave (ram2_write),
.waitrequest_master (f2h_ram2_waitrequest),
.burstcount_master (f2h_ram2_burstcount),
.address_master (f2h_ram2_address),
.readdata_master (f2h_ram2_readdata),
.readdatavalid_master (f2h_ram2_readdatavalid),
.read_master (f2h_ram2_read),
.writedata_master (f2h_ram2_writedata),
.byteenable_master (f2h_ram2_byteenable),
.write_master (f2h_ram2_write)
);
////////////////////////////////////////////////////////
//// f2sdram_safe_terminator_vbuf ////
////////////////////////////////////////////////////////
wire [27:0] f2h_vbuf_address;
wire [7:0] f2h_vbuf_burstcount;
wire f2h_vbuf_waitrequest;
wire [127:0] f2h_vbuf_readdata;
wire f2h_vbuf_readdatavalid;
wire f2h_vbuf_read;
wire [127:0] f2h_vbuf_writedata;
wire [15:0] f2h_vbuf_byteenable;
wire f2h_vbuf_write;
(* altera_attribute = {"-name SYNCHRONIZER_IDENTIFICATION FORCED_IF_ASYNCHRONOUS"} *) reg vbuf_reset_0 = 1'b1;
(* altera_attribute = {"-name SYNCHRONIZER_IDENTIFICATION FORCED_IF_ASYNCHRONOUS"} *) reg vbuf_reset_1 = 1'b1;
always @(posedge vbuf_clk) begin
vbuf_reset_0 <= reset_out;
vbuf_reset_1 <= vbuf_reset_0;
end
f2sdram_safe_terminator #(128, 8) f2sdram_safe_terminator_vbuf
(
.clk (vbuf_clk),
.rst_req_sync (vbuf_reset_1),
.waitrequest_slave (vbuf_waitrequest),
.burstcount_slave (vbuf_burstcount),
.address_slave (vbuf_address),
.readdata_slave (vbuf_readdata),
.readdatavalid_slave (vbuf_readdatavalid),
.read_slave (vbuf_read),
.writedata_slave (vbuf_writedata),
.byteenable_slave (vbuf_byteenable),
.write_slave (vbuf_write),
.waitrequest_master (f2h_vbuf_waitrequest),
.burstcount_master (f2h_vbuf_burstcount),
.address_master (f2h_vbuf_address),
.readdata_master (f2h_vbuf_readdata),
.readdatavalid_master (f2h_vbuf_readdatavalid),
.read_master (f2h_vbuf_read),
.writedata_master (f2h_vbuf_writedata),
.byteenable_master (f2h_vbuf_byteenable),
.write_master (f2h_vbuf_write)
);
////////////////////////////////////////////////////////
//// HPS <> FPGA interfaces ////
////////////////////////////////////////////////////////
sysmem_HPS_fpga_interfaces fpga_interfaces (
.f2h_cold_rst_req_n (~reset_hps_cold_req),
.f2h_warm_rst_req_n (~reset_hps_warm_req),
.h2f_user0_clk (clock),
.h2f_rst_n (hps_h2f_reset_n),
.f2h_sdram0_clk (vbuf_clk),
.f2h_sdram0_ADDRESS (vbuf_address),
.f2h_sdram0_BURSTCOUNT (vbuf_burstcount),
.f2h_sdram0_WAITREQUEST (vbuf_waitrequest),
.f2h_sdram0_READDATA (vbuf_readdata),
.f2h_sdram0_READDATAVALID (vbuf_readdatavalid),
.f2h_sdram0_READ (vbuf_read),
.f2h_sdram0_WRITEDATA (vbuf_writedata),
.f2h_sdram0_BYTEENABLE (vbuf_byteenable),
.f2h_sdram0_WRITE (vbuf_write),
.f2h_sdram0_ADDRESS (f2h_vbuf_address),
.f2h_sdram0_BURSTCOUNT (f2h_vbuf_burstcount),
.f2h_sdram0_WAITREQUEST (f2h_vbuf_waitrequest),
.f2h_sdram0_READDATA (f2h_vbuf_readdata),
.f2h_sdram0_READDATAVALID (f2h_vbuf_readdatavalid),
.f2h_sdram0_READ (f2h_vbuf_read),
.f2h_sdram0_WRITEDATA (f2h_vbuf_writedata),
.f2h_sdram0_BYTEENABLE (f2h_vbuf_byteenable),
.f2h_sdram0_WRITE (f2h_vbuf_write),
.f2h_sdram1_clk (ram1_clk),
.f2h_sdram1_ADDRESS (ram1_address),
.f2h_sdram1_BURSTCOUNT (ram1_burstcount),
.f2h_sdram1_WAITREQUEST (ram1_waitrequest),
.f2h_sdram1_READDATA (ram1_readdata),
.f2h_sdram1_READDATAVALID (ram1_readdatavalid),
.f2h_sdram1_READ (ram1_read),
.f2h_sdram1_WRITEDATA (ram1_writedata),
.f2h_sdram1_BYTEENABLE (ram1_byteenable),
.f2h_sdram1_WRITE (ram1_write),
.f2h_sdram1_ADDRESS (f2h_ram1_address),
.f2h_sdram1_BURSTCOUNT (f2h_ram1_burstcount),
.f2h_sdram1_WAITREQUEST (f2h_ram1_waitrequest),
.f2h_sdram1_READDATA (f2h_ram1_readdata),
.f2h_sdram1_READDATAVALID (f2h_ram1_readdatavalid),
.f2h_sdram1_READ (f2h_ram1_read),
.f2h_sdram1_WRITEDATA (f2h_ram1_writedata),
.f2h_sdram1_BYTEENABLE (f2h_ram1_byteenable),
.f2h_sdram1_WRITE (f2h_ram1_write),
.f2h_sdram2_clk (ram2_clk),
.f2h_sdram2_ADDRESS (ram2_address),
.f2h_sdram2_BURSTCOUNT (ram2_burstcount),
.f2h_sdram2_WAITREQUEST (ram2_waitrequest),
.f2h_sdram2_READDATA (ram2_readdata),
.f2h_sdram2_READDATAVALID (ram2_readdatavalid),
.f2h_sdram2_READ (ram2_read),
.f2h_sdram2_WRITEDATA (ram2_writedata),
.f2h_sdram2_BYTEENABLE (ram2_byteenable),
.f2h_sdram2_WRITE (ram2_write)
.f2h_sdram2_ADDRESS (f2h_ram2_address),
.f2h_sdram2_BURSTCOUNT (f2h_ram2_burstcount),
.f2h_sdram2_WAITREQUEST (f2h_ram2_waitrequest),
.f2h_sdram2_READDATA (f2h_ram2_readdata),
.f2h_sdram2_READDATAVALID (f2h_ram2_readdatavalid),
.f2h_sdram2_READ (f2h_ram2_read),
.f2h_sdram2_WRITEDATA (f2h_ram2_writedata),
.f2h_sdram2_BYTEENABLE (f2h_ram2_byteenable),
.f2h_sdram2_WRITE (f2h_ram2_write)
);
wire hps_h2f_reset_n;

View File

@ -2,7 +2,6 @@
module vga_out
(
input clk,
input ypbpr_full,
input ypbpr_en,
input hsync,
@ -17,38 +16,6 @@ module vga_out
output reg csync_o
);
wire [5:0] yuv_full[225] = '{
6'd0, 6'd0, 6'd0, 6'd0, 6'd1, 6'd1, 6'd1, 6'd1,
6'd2, 6'd2, 6'd2, 6'd3, 6'd3, 6'd3, 6'd3, 6'd4,
6'd4, 6'd4, 6'd5, 6'd5, 6'd5, 6'd5, 6'd6, 6'd6,
6'd6, 6'd7, 6'd7, 6'd7, 6'd7, 6'd8, 6'd8, 6'd8,
6'd9, 6'd9, 6'd9, 6'd9, 6'd10, 6'd10, 6'd10, 6'd11,
6'd11, 6'd11, 6'd11, 6'd12, 6'd12, 6'd12, 6'd13, 6'd13,
6'd13, 6'd13, 6'd14, 6'd14, 6'd14, 6'd15, 6'd15, 6'd15,
6'd15, 6'd16, 6'd16, 6'd16, 6'd17, 6'd17, 6'd17, 6'd17,
6'd18, 6'd18, 6'd18, 6'd19, 6'd19, 6'd19, 6'd19, 6'd20,
6'd20, 6'd20, 6'd21, 6'd21, 6'd21, 6'd21, 6'd22, 6'd22,
6'd22, 6'd23, 6'd23, 6'd23, 6'd23, 6'd24, 6'd24, 6'd24,
6'd25, 6'd25, 6'd25, 6'd25, 6'd26, 6'd26, 6'd26, 6'd27,
6'd27, 6'd27, 6'd27, 6'd28, 6'd28, 6'd28, 6'd29, 6'd29,
6'd29, 6'd29, 6'd30, 6'd30, 6'd30, 6'd31, 6'd31, 6'd31,
6'd31, 6'd32, 6'd32, 6'd32, 6'd33, 6'd33, 6'd33, 6'd33,
6'd34, 6'd34, 6'd34, 6'd35, 6'd35, 6'd35, 6'd35, 6'd36,
6'd36, 6'd36, 6'd36, 6'd37, 6'd37, 6'd37, 6'd38, 6'd38,
6'd38, 6'd38, 6'd39, 6'd39, 6'd39, 6'd40, 6'd40, 6'd40,
6'd40, 6'd41, 6'd41, 6'd41, 6'd42, 6'd42, 6'd42, 6'd42,
6'd43, 6'd43, 6'd43, 6'd44, 6'd44, 6'd44, 6'd44, 6'd45,
6'd45, 6'd45, 6'd46, 6'd46, 6'd46, 6'd46, 6'd47, 6'd47,
6'd47, 6'd48, 6'd48, 6'd48, 6'd48, 6'd49, 6'd49, 6'd49,
6'd50, 6'd50, 6'd50, 6'd50, 6'd51, 6'd51, 6'd51, 6'd52,
6'd52, 6'd52, 6'd52, 6'd53, 6'd53, 6'd53, 6'd54, 6'd54,
6'd54, 6'd54, 6'd55, 6'd55, 6'd55, 6'd56, 6'd56, 6'd56,
6'd56, 6'd57, 6'd57, 6'd57, 6'd58, 6'd58, 6'd58, 6'd58,
6'd59, 6'd59, 6'd59, 6'd60, 6'd60, 6'd60, 6'd60, 6'd61,
6'd61, 6'd61, 6'd62, 6'd62, 6'd62, 6'd62, 6'd63, 6'd63,
6'd63
};
wire [5:0] red = din[23:18];
wire [5:0] green = din[15:10];
wire [5:0] blue = din[7:2];
@ -59,12 +26,7 @@ wire [5:0] blue = din[7:2];
// Pr = 128 + 0.439*R - 0.368*G - 0.071*B (Pr = 0.500*R - 0.419*G - 0.081*B)
reg [18:0] y_2, pb_2, pr_2;
wire [7:0] y = ( y_2[17:8] < 16) ? 8'd16 : ( y_2[17:8] > 235) ? 8'd235 : y_2[15:8];
wire [7:0] pb = (pb_2[17:8] < 16) ? 8'd16 : (pb_2[17:8] > 240) ? 8'd240 : pb_2[15:8];
wire [7:0] pr = (pr_2[17:8] < 16) ? 8'd16 : (pr_2[17:8] > 240) ? 8'd240 : pr_2[15:8];
reg [7:0] y_3, pb_3, pr_3;
reg [7:0] y, pb, pr;
reg [23:0] din2, din3;
reg hsync2, vsync2, csync2;
always @(posedge clk) begin
@ -72,9 +34,9 @@ always @(posedge clk) begin
pb_2 <= 19'd32768 - ({red, 7'd0} + {red, 4'd0} + {red, 3'd0}) - ({green, 8'd0} + {green, 5'd0} + {green, 3'd0}) + ({blue, 8'd0} + {blue, 7'd0} + {blue, 6'd0});
pr_2 <= 19'd32768 + ({red, 8'd0} + {red, 7'd0} + {red, 6'd0}) - ({green, 8'd0} + {green, 6'd0} + {green, 5'd0} + {green, 4'd0} + {green, 3'd0}) - ({blue, 6'd0} + {blue , 3'd0});
y_3 <= {(ypbpr_full ? yuv_full[y -8'd16] : y[7:2]), 2'b00};
pb_3 <= {(ypbpr_full ? yuv_full[pb-8'd16] : pb[7:2]), 2'b00};
pr_3 <= {(ypbpr_full ? yuv_full[pr-8'd16] : pr[7:2]), 2'b00};
y <= ( y_2[18] || !y_2[17:12]) ? 8'd16 : (y_2[17:8] > 235) ? 8'd235 : y_2[15:8];
pb <= (pb_2[18] || !pb_2[17:12]) ? 8'd16 : (&pb_2[17:12]) ? 8'd240 : pb_2[15:8];
pr <= (pr_2[18] || !pr_2[17:12]) ? 8'd16 : (&pr_2[17:12]) ? 8'd240 : pr_2[15:8];
hsync_o <= hsync2; hsync2 <= hsync;
vsync_o <= vsync2; vsync2 <= vsync;
@ -84,6 +46,6 @@ always @(posedge clk) begin
din3 <= din2;
end
assign dout = ypbpr_en ? {pr_3, y_3, pb_3} : din3;
assign dout = ypbpr_en ? {pr, y, pb} : din3;
endmodule

270
sys/video_freak.sv Normal file
View File

@ -0,0 +1,270 @@
//
//
// Video crop
// Copyright (c) 2020 Grabulosaure, (c) 2021 Alexey Melnikov
//
// Integer scaling
// Copyright (c) 2021 Alexey Melnikov
//
// This program is GPL Licensed. See COPYING for the full license.
//
//
////////////////////////////////////////////////////////////////////////////////////////////////////////
`timescale 1ns / 1ps
module video_freak
(
input CLK_VIDEO,
input CE_PIXEL,
input VGA_VS,
input [11:0] HDMI_WIDTH,
input [11:0] HDMI_HEIGHT,
output VGA_DE,
output reg [12:0] VIDEO_ARX,
output reg [12:0] VIDEO_ARY,
input VGA_DE_IN,
input [11:0] ARX,
input [11:0] ARY,
input [11:0] CROP_SIZE,
input [4:0] CROP_OFF, // -16...+15
input [2:0] SCALE //0 - normal, 1 - V-integer, 2 - HV-Integer-, 3 - HV-Integer+, 4 - HV-Integer
);
reg mul_start;
wire mul_run;
reg [11:0] mul_arg1, mul_arg2;
wire [23:0] mul_res;
sys_umul #(12,12) mul(CLK_VIDEO,mul_start,mul_run, mul_arg1,mul_arg2,mul_res);
reg vde;
reg [11:0] arxo,aryo;
reg [11:0] vsize;
reg [11:0] hsize;
always @(posedge CLK_VIDEO) begin
reg old_de, old_vs,ovde;
reg [11:0] vtot,vcpt,vcrop,voff;
reg [11:0] hcpt;
reg [11:0] vadj;
reg [23:0] ARXG,ARYG;
reg [11:0] arx,ary;
reg [1:0] vcalc;
if (CE_PIXEL) begin
old_de <= VGA_DE_IN;
old_vs <= VGA_VS;
if (VGA_VS & ~old_vs) begin
vcpt <= 0;
vtot <= vcpt;
vcalc <= 1;
vcrop <= (CROP_SIZE >= vcpt) ? 12'd0 : CROP_SIZE;
end
if (VGA_DE_IN) hcpt <= hcpt + 1'd1;
if (~VGA_DE_IN & old_de) begin
vcpt <= vcpt + 1'd1;
if(!vcpt) hsize <= hcpt;
hcpt <= 0;
end
end
arx <= ARX;
ary <= ARY;
vsize <= vcrop;
mul_start <= 0;
if(!vcrop || !ary || !arx) begin
arxo <= arx;
aryo <= ary;
vsize <= vtot;
end
else if (vcalc) begin
if(~mul_start & ~mul_run) begin
vcalc <= vcalc + 1'd1;
case(vcalc)
1: begin
mul_arg1 <= arx;
mul_arg2 <= vtot;
mul_start <= 1;
end
2: begin
ARXG <= mul_res;
mul_arg1 <= ary;
mul_arg2 <= vcrop;
mul_start <= 1;
end
3: begin
ARYG <= mul_res;
end
endcase
end
end
else if (ARXG[23] | ARYG[23]) begin
arxo <= ARXG[23:12];
aryo <= ARYG[23:12];
end
else begin
ARXG <= ARXG << 1;
ARYG <= ARYG << 1;
end
vadj <= (vtot-vcrop) + {{6{CROP_OFF[4]}},CROP_OFF,1'b0};
voff <= vadj[11] ? 12'd0 : ((vadj[11:1] + vcrop) > vtot) ? vtot-vcrop : vadj[11:1];
ovde <= ((vcpt >= voff) && (vcpt < (vcrop + voff))) || !vcrop;
vde <= ovde;
end
assign VGA_DE = vde & VGA_DE_IN;
video_scale_int scale
(
.CLK_VIDEO(CLK_VIDEO),
.HDMI_WIDTH(HDMI_WIDTH),
.HDMI_HEIGHT(HDMI_HEIGHT),
.SCALE(SCALE),
.hsize(hsize),
.vsize(vsize),
.arx_i(arxo),
.ary_i(aryo),
.arx_o(VIDEO_ARX),
.ary_o(VIDEO_ARY)
);
endmodule
module video_scale_int
(
input CLK_VIDEO,
input [11:0] HDMI_WIDTH,
input [11:0] HDMI_HEIGHT,
input [2:0] SCALE,
input [11:0] hsize,
input [11:0] vsize,
input [11:0] arx_i,
input [11:0] ary_i,
output reg [12:0] arx_o,
output reg [12:0] ary_o
);
reg div_start;
wire div_run;
reg [23:0] div_num;
reg [11:0] div_den;
wire [23:0] div_res;
sys_udiv #(24,12) div(CLK_VIDEO,div_start,div_run, div_num,div_den,div_res);
reg mul_start;
wire mul_run;
reg [11:0] mul_arg1, mul_arg2;
wire [23:0] mul_res;
sys_umul #(12,12) mul(CLK_VIDEO,mul_start,mul_run, mul_arg1,mul_arg2,mul_res);
wire [11:0] wideres = mul_res[11:0] + hsize;
always @(posedge CLK_VIDEO) begin
reg [11:0] oheight,wres;
reg [12:0] arxf,aryf;
reg [3:0] cnt;
reg narrow;
div_start <= 0;
mul_start <= 0;
if (!SCALE || !ary_i || !arx_i) begin
arxf <= arx_i;
aryf <= ary_i;
end
else if(~div_start & ~div_run & ~mul_start & ~mul_run) begin
cnt <= cnt + 1'd1;
case(cnt)
0: begin
div_num <= HDMI_HEIGHT;
div_den <= vsize;
div_start <= 1;
end
1: if(!div_res[11:0]) begin
// screen resolution is lower than video resolution.
// Integer scaling is impossible.
arxf <= arx_i;
aryf <= ary_i;
cnt <= 0;
end
else begin
mul_arg1 <= vsize;
mul_arg2 <= div_res[11:0];
mul_start <= 1;
end
2: begin
oheight <= mul_res[11:0];
mul_arg1 <= mul_res[11:0];
mul_arg2 <= arx_i;
mul_start <= 1;
end
3: begin
div_num <= mul_res;
div_den <= ary_i;
div_start <= 1;
end
4: begin
div_num <= div_res;
div_den <= hsize;
div_start <= 1;
end
5: begin
mul_arg1 <= hsize;
mul_arg2 <= div_res[11:0] ? div_res[11:0] : 12'd1;
mul_start <= 1;
end
6: if(mul_res <= HDMI_WIDTH) cnt <= 8;
else begin
div_num <= HDMI_WIDTH;
div_den <= hsize;
div_start <= 1;
end
7: begin
mul_arg1 <= hsize;
mul_arg2 <= div_res[11:0] ? div_res[11:0] : 12'd1;
mul_start <= 1;
end
8: begin
narrow <= ((div_num[11:0] - mul_res[11:0]) <= (wideres - div_num[11:0])) || (wideres > HDMI_WIDTH);
wres <= wideres;
end
9: begin
case(SCALE)
2: arxf <= {1'b1, mul_res[11:0]};
3: arxf <= {1'b1, (wres > HDMI_WIDTH) ? mul_res[11:0] : wres};
4: arxf <= {1'b1, narrow ? mul_res[11:0] : wres};
default: arxf <= {1'b1, div_num[11:0]};
endcase
aryf <= {1'b1, oheight};
end
endcase
end
arx_o <= arxf;
ary_o <= aryf;
end
endmodule

View File

@ -1,6 +1,6 @@
//
//
// Copyright (c) 2017 Sorgelig
// Copyright (c) 2017,2021 Alexey Melnikov
//
// This program is GPL Licensed. See COPYING for the full license.
//
@ -15,8 +15,6 @@
// May be less if line_start is used.
//
// HALF_DEPTH: If =1 then color dept is 4 bits per component
// For half depth 8 bits monochrome is available with
// mono signal enabled and color = {G, R}
//
// altera message_off 10720
// altera message_off 12161
@ -28,32 +26,21 @@ module video_mixer
parameter GAMMA = 0
)
(
// video clock
// it should be multiple by (ce_pix*4).
input clk_vid,
input CLK_VIDEO, // should be multiple by (ce_pix*4)
output reg CE_PIXEL, // output pixel clock enable
// Pixel clock or clock_enable (both are accepted).
input ce_pix,
output ce_pix_out,
input ce_pix, // input pixel clock or clock_enable
input scandoubler,
input hq2x, // high quality 2x scaling
// scanlines (00-none 01-25% 10-50% 11-75%)
input [1:0] scanlines,
// High quality 2x scaling
input hq2x,
inout [21:0] gamma_bus,
// color
input [DWIDTH:0] R,
input [DWIDTH:0] G,
input [DWIDTH:0] B,
// Monochrome mode (for HALF_DEPTH only)
input mono,
inout [21:0] gamma_bus,
// Positive pulses.
input HSync,
input VSync,
@ -75,9 +62,9 @@ localparam HALF_DEPTH_SD = GAMMA ? 0 : HALF_DEPTH;
generate
if(GAMMA && HALF_DEPTH) begin
wire [7:0] R_in = mono ? {G,R} : {R,R};
wire [7:0] G_in = mono ? {G,R} : {G,G};
wire [7:0] B_in = mono ? {G,R} : {B,B};
wire [7:0] R_in = {R,R};
wire [7:0] G_in = {G,G};
wire [7:0] B_in = {B,B};
end else begin
wire [DWIDTH:0] R_in = R;
wire [DWIDTH:0] G_in = G;
@ -95,7 +82,7 @@ generate
assign gamma_bus[21] = 1;
gamma_corr gamma(
.clk_sys(gamma_bus[20]),
.clk_vid(clk_vid),
.clk_vid(CLK_VIDEO),
.ce_pix(ce_pix),
.gamma_en(gamma_bus[19]),
@ -122,7 +109,6 @@ generate
end
endgenerate
wire [DWIDTH_SD:0] R_sd;
wire [DWIDTH_SD:0] G_sd;
wire [DWIDTH_SD:0] B_sd;
@ -130,7 +116,10 @@ wire hs_sd, vs_sd, hb_sd, vb_sd, ce_pix_sd;
scandoubler #(.LENGTH(LINE_LENGTH), .HALF_DEPTH(HALF_DEPTH_SD)) sd
(
.*,
.clk_vid(CLK_VIDEO),
.hq2x(hq2x),
.ce_pix(ce_pix),
.hs_in(hs_g),
.vs_in(vs_g),
.hb_in(hb_g),
@ -153,86 +142,51 @@ wire [DWIDTH_SD:0] rt = (scandoubler ? R_sd : R_gamma);
wire [DWIDTH_SD:0] gt = (scandoubler ? G_sd : G_gamma);
wire [DWIDTH_SD:0] bt = (scandoubler ? B_sd : B_gamma);
generate
if(!GAMMA && HALF_DEPTH) begin
wire [7:0] r = mono ? {gt,rt} : {rt,rt};
wire [7:0] g = mono ? {gt,rt} : {gt,gt};
wire [7:0] b = mono ? {gt,rt} : {bt,bt};
end else begin
wire [7:0] r = rt;
wire [7:0] g = gt;
wire [7:0] b = bt;
end
endgenerate
wire hs = (scandoubler ? hs_sd : hs_g);
wire vs = (scandoubler ? vs_sd : vs_g);
assign ce_pix_out = scandoubler ? ce_pix_sd : ce_pix;
reg scanline = 0;
always @(posedge clk_vid) begin
reg old_hs, old_vs;
old_hs <= hs;
old_vs <= vs;
if(old_hs && ~hs) scanline <= ~scanline;
if(old_vs && ~vs) scanline <= 0;
end
wire hde = scandoubler ? ~hb_sd : ~hb_g;
wire vde = scandoubler ? ~vb_sd : ~vb_g;
reg [7:0] v_r,v_g,v_b;
reg v_vs,v_hs,v_de;
always @(posedge clk_vid) begin
always @(posedge CLK_VIDEO) begin
reg [7:0] r,g,b;
reg hde,vde,hs,vs, old_vs;
reg old_hde;
reg old_ce;
reg ce_osc, fs_osc;
if(ce_pix_out) begin
case(scanlines & {scanline, scanline})
1: begin // reduce 25% = 1/2 + 1/4
v_r <= {1'b0, r[7:1]} + {2'b00, r[7:2]};
v_g <= {1'b0, g[7:1]} + {2'b00, g[7:2]};
v_b <= {1'b0, b[7:1]} + {2'b00, b[7:2]};
old_ce <= ce_pix;
ce_osc <= ce_osc | (old_ce ^ ce_pix);
old_vs <= vs;
if(~old_vs & vs) begin
fs_osc <= ce_osc;
ce_osc <= 0;
end
2: begin // reduce 50% = 1/2
v_r <= {1'b0, r[7:1]};
v_g <= {1'b0, g[7:1]};
v_b <= {1'b0, b[7:1]};
CE_PIXEL <= scandoubler ? ce_pix_sd : fs_osc ? (~old_ce & ce_pix) : ce_pix;
if(!GAMMA && HALF_DEPTH) begin
r <= {rt,rt};
g <= {gt,gt};
b <= {bt,bt};
end
else begin
r <= rt;
g <= gt;
b <= bt;
end
3: begin // reduce 75% = 1/4
v_r <= {2'b00, r[7:2]};
v_g <= {2'b00, g[7:2]};
v_b <= {2'b00, b[7:2]};
end
hde <= scandoubler ? ~hb_sd : ~hb_g;
vde <= scandoubler ? ~vb_sd : ~vb_g;
vs <= scandoubler ? vs_sd : vs_g;
hs <= scandoubler ? hs_sd : hs_g;
default: begin
v_r <= r;
v_g <= g;
v_b <= b;
end
endcase
if(CE_PIXEL) begin
VGA_R <= r;
VGA_G <= g;
VGA_B <= b;
v_vs <= vs;
v_hs <= hs;
VGA_VS <= vs;
VGA_HS <= hs;
old_hde <= hde;
if(~old_hde && hde) v_de <= vde;
if(old_hde && ~hde) v_de <= 0;
if(old_hde ^ hde) VGA_DE <= vde & hde;
end
end
always @(posedge clk_vid) if(ce_pix_out) begin
VGA_R <= v_r;
VGA_G <= v_g;
VGA_B <= v_b;
VGA_HS <= v_hs;
VGA_VS <= v_vs;
VGA_DE <= v_de;
end
endmodule