From 7d22fc77e80bd5adf82db968e2bec57ff9afd45d Mon Sep 17 00:00:00 2001 From: sorgelig Date: Wed, 3 Mar 2021 17:35:46 +0800 Subject: [PATCH] Update sys. HV-Integer scale. --- MacPlus.sv | 23 ++- sys/arcade_video.v | 4 +- sys/ascal.vhd | 4 +- sys/f2sdram_safe_terminator.sv | 250 ++++++++++++++++++++++++++++++ sys/i2c.v | 19 ++- sys/math.sv | 109 +++++++++++++ sys/scandoubler.v | 10 +- sys/spdif.v | 31 ++-- sys/sys.qip | 3 + sys/sys.tcl | 1 + sys/sys_top.sdc | 15 +- sys/sys_top.v | 198 +++++++++++++++++------- sys/sysmem.sv | 195 ++++++++++++++++++++---- sys/vga_out.sv | 48 +----- sys/video_freak.sv | 270 +++++++++++++++++++++++++++++++++ sys/video_mixer.sv | 152 +++++++------------ 16 files changed, 1069 insertions(+), 263 deletions(-) create mode 100644 sys/f2sdram_safe_terminator.sv create mode 100644 sys/math.sv create mode 100644 sys/video_freak.sv diff --git a/MacPlus.sv b/MacPlus.sv index 0fda29e..1de5d97 100644 --- a/MacPlus.sv +++ b/MacPlus.sv @@ -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, @@ -51,6 +52,9 @@ module emu output VGA_F1, 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) @@ -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;", "-;", diff --git a/sys/arcade_video.v b/sys/arcade_video.v index a1683f5..ff554a5 100644 --- a/sys/arcade_video.v +++ b/sys/arcade_video.v @@ -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), diff --git a/sys/ascal.vhd b/sys/ascal.vhd index 6d687ac..a65ccc1 100644 --- a/sys/ascal.vhd +++ b/sys/ascal.vhd @@ -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; -- avl_read_sync2<=avl_read_sync; avl_read_pulse<=avl_read_sync XOR avl_read_sync2; - avl_radrs <=o_adrs AND (RAMSIZE - 1); -- + avl_radrs <=o_adrs; -- avl_rline <=o_rline; -- -------------------------------------------- diff --git a/sys/f2sdram_safe_terminator.sv b/sys/f2sdram_safe_terminator.sv new file mode 100644 index 0000000..3586365 --- /dev/null +++ b/sys/f2sdram_safe_terminator.sv @@ -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 diff --git a/sys/i2c.v b/sys/i2c.v index d6d59d9..9ccba93 100644 --- a/sys/i2c.v +++ b/sys/i2c.v @@ -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; diff --git a/sys/math.sv b/sys/math.sv new file mode 100644 index 0000000..e7c0144 --- /dev/null +++ b/sys/math.sv @@ -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 diff --git a/sys/scandoubler.v b/sys/scandoubler.v index a1d5a44..81e7c3f 100644 --- a/sys/scandoubler.v +++ b/sys/scandoubler.v @@ -2,7 +2,7 @@ // scandoubler.v // // Copyright (c) 2015 Till Harbaum -// 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), diff --git a/sys/spdif.v b/sys/spdif.v index db5027c..eee2b08 100644 --- a/sys/spdif.v +++ b/sys/spdif.v @@ -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) - preamble_q <= 8'h00; -else if (load_subframe_q) - preamble_q <= preamble_r; +begin + if (rst_i == 1'b1) + begin + preamble_q <= 8'h00; + 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 diff --git a/sys/sys.qip b/sys/sys.qip index ac810d5..eeae907 100644 --- a/sys/sys.qip +++ b/sys/sys.qip @@ -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 ] diff --git a/sys/sys.tcl b/sys/sys.tcl index c12cfee..ce83683 100644 --- a/sys/sys.tcl +++ b/sys/sys.tcl @@ -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" diff --git a/sys/sys_top.sdc b/sys/sys_top.sdc index 46c761d..8187969 100644 --- a/sys/sys_top.sdc +++ b/sys/sys_top.sdc @@ -1,9 +1,10 @@ # Specify root clocks -create_clock -period "50.0 MHz" [get_ports FPGA_CLK1_50] -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 "50.0 MHz" [get_ports FPGA_CLK1_50] +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*} diff --git a/sys/sys_top.v b/sys/sys_top.v index 5e31b0d..8f0043c 100644 --- a/sys/sys_top.v +++ b/sys/sys_top.v @@ -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; + + hdmi_height <= (VSET && (VSET < HEIGHT)) ? VSET : HEIGHT; + hdmi_width <= (HSET && (HSET < WIDTH)) ? HSET : WIDTH; - height <= (VSET && (VSET < HEIGHT)) ? VSET : HEIGHT; - 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), diff --git a/sys/sysmem.sv b/sys/sysmem.sv index c90395e..8c17e86 100644 --- a/sys/sysmem.sv +++ b/sys/sysmem.sv @@ -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; diff --git a/sys/vga_out.sv b/sys/vga_out.sv index b66bef7..43927b2 100644 --- a/sys/vga_out.sv +++ b/sys/vga_out.sv @@ -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 diff --git a/sys/video_freak.sv b/sys/video_freak.sv new file mode 100644 index 0000000..b2ce6f1 --- /dev/null +++ b/sys/video_freak.sv @@ -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 diff --git a/sys/video_mixer.sv b/sys/video_mixer.sv index 8f204ee..93b106e 100644 --- a/sys/video_mixer.sv +++ b/sys/video_mixer.sv @@ -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), @@ -149,90 +138,55 @@ scandoubler #(.LENGTH(LINE_LENGTH), .HALF_DEPTH(HALF_DEPTH_SD)) sd .b_out(B_sd) ); -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); +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; + + old_ce <= ce_pix; + ce_osc <= ce_osc | (old_ce ^ ce_pix); - 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]}; - end + 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]}; - end + CE_PIXEL <= scandoubler ? ce_pix_sd : fs_osc ? (~old_ce & ce_pix) : ce_pix; - 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 + if(!GAMMA && HALF_DEPTH) begin + r <= {rt,rt}; + g <= {gt,gt}; + b <= {bt,bt}; + end + else begin + r <= rt; + g <= gt; + b <= bt; + end - default: begin - v_r <= r; - v_g <= g; - v_b <= b; - end - endcase + hde <= scandoubler ? ~hb_sd : ~hb_g; + vde <= scandoubler ? ~vb_sd : ~vb_g; + vs <= scandoubler ? vs_sd : vs_g; + hs <= scandoubler ? hs_sd : hs_g; - v_vs <= vs; - v_hs <= hs; + if(CE_PIXEL) begin + VGA_R <= r; + VGA_G <= g; + VGA_B <= b; + + 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