Add reverse LPF feature

reverse LPF can be used to mostly reverse the blur on pre 1-CHIP SNES.
For best results use 256x240 optimized mode.
This commit is contained in:
paulb-nl 2017-09-27 22:43:26 +02:00
parent 9d14cc776e
commit ac16008076
10 changed files with 1243 additions and 1153 deletions

View File

@ -238,4 +238,5 @@ set_global_assignment -name QIP_FILE rtl/pll_2x.qip
set_global_assignment -name QIP_FILE rtl/pll_3x.qip
set_global_assignment -name CDF_FILE output_files/Chain1.cdf
set_global_assignment -name SIGNALTAP_FILE output_files/ossc_la.stp
set_global_assignment -name SEED 27
set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top

View File

@ -61,7 +61,7 @@ set_false_path -from [get_clocks pclk_4x] -to [get_clocks {pclk_sdtv pclk_2x pcl
set_false_path -from [get_clocks pclk_5x] -to [get_clocks {pclk_sdtv pclk_2x pclk_3x pclk_4x}]
# Ignore paths which would result from pclk_act switchover during postprocess chain
set pclk_act_regs [get_cells {scanconverter:scanconverter_inst|R_out* \
set pclk_act_regs [get_registers {scanconverter:scanconverter_inst|R_out* \
scanconverter:scanconverter_inst|G_out* \
scanconverter:scanconverter_inst|B_out* \
scanconverter:scanconverter_inst|HSYNC_out* \
@ -69,7 +69,10 @@ set pclk_act_regs [get_cells {scanconverter:scanconverter_inst|R_out* \
scanconverter:scanconverter_inst|DE_out* \
scanconverter:scanconverter_inst|*_pp1* \
scanconverter:scanconverter_inst|*_pp2* \
scanconverter:scanconverter_inst|*_pp3*}]
scanconverter:scanconverter_inst|*_pp3* \
scanconverter:scanconverter_inst|*_pp4* \
scanconverter:scanconverter_inst|*_pp5* \
scanconverter:scanconverter_inst|*_pp6*}]
set_false_path -from [get_clocks {pclk_sdtv}] -to $pclk_act_regs
set_false_path -from [get_clocks {pclk_sdtv}] -to [get_ports HDMI_TX_*]

View File

@ -92,14 +92,17 @@ wire linebuf_rdclock;
//RGB signals&registers: 8 bits per component -> 16.7M colors
wire [7:0] R_act, G_act, B_act;
wire [7:0] R_lbuf, G_lbuf, B_lbuf;
reg [7:0] R_in_L, G_in_L, B_in_L, R_in_LL, G_in_LL, B_in_LL, R_1x, G_1x, B_1x, R_pp3, G_pp3, B_pp3;
reg [7:0] R_in_L, G_in_L, B_in_L, R_in_LL, G_in_LL, B_in_LL, R_1x, G_1x, B_1x;
reg [7:0] R_pp3, G_pp3, B_pp3, R_pp4, G_pp4, B_pp4, R_pp5, G_pp5, B_pp5, R_pp6, G_pp6, B_pp6;
reg [7:0] R_prev_pp2, G_prev_pp2, B_prev_pp2, R_prev_pp3, G_prev_pp3, B_prev_pp3, R_prev_pp4, G_prev_pp4, B_prev_pp4;
reg signed [14:0] R_diff_pp3, G_diff_pp3, B_diff_pp3, R_diff_pp4, G_diff_pp4, B_diff_pp4;
//H+V syncs + data enable signals&registers
wire HSYNC_act, VSYNC_act, DE_act;
reg HSYNC_in_L, VSYNC_in_L;
reg HSYNC_1x, HSYNC_2x, HSYNC_3x, HSYNC_4x, HSYNC_5x, HSYNC_pp1, HSYNC_pp2, HSYNC_pp3;
reg VSYNC_1x, VSYNC_2x, VSYNC_3x, VSYNC_4x, VSYNC_5x, VSYNC_pp1, VSYNC_pp2, VSYNC_pp3;
reg DE_1x, DE_2x, DE_3x, DE_4x, DE_5x, DE_pp1, DE_pp2, DE_pp3, DE_3x_prev4x;
reg HSYNC_1x, HSYNC_2x, HSYNC_3x, HSYNC_4x, HSYNC_5x, HSYNC_pp1, HSYNC_pp2, HSYNC_pp3, HSYNC_pp4, HSYNC_pp5, HSYNC_pp6;
reg VSYNC_1x, VSYNC_2x, VSYNC_3x, VSYNC_4x, VSYNC_5x, VSYNC_pp1, VSYNC_pp2, VSYNC_pp3, VSYNC_pp4, VSYNC_pp5, VSYNC_pp6;
reg DE_1x, DE_2x, DE_3x, DE_4x, DE_5x, DE_pp1, DE_pp2, DE_pp3, DE_pp4, DE_pp5, DE_pp6, DE_3x_prev4x;
//registers indicating line/frame change and field type
reg FID_cur, FID_prev, FID_1x;
@ -112,16 +115,18 @@ reg [11:0] hcnt_1x, hcnt_2x, hcnt_3x, hcnt_4x, hcnt_5x, hcnt_4x_aspfix, hcnt_2x_
reg [2:0] hcnt_2x_opt_ctr, hcnt_3x_opt_ctr, hcnt_4x_opt_ctr, hcnt_5x_opt_ctr;
wire [10:0] vcnt_act;
reg [10:0] vcnt_tvp, vcnt_1x, vcnt_2x, vcnt_3x, vcnt_4x, vcnt_5x; //max. 2047
reg [11:0] linebuf_hoffset_pp1;
reg hoffset_changed_pp1;
//other counters
wire [2:0] line_id_act, col_id_act;
reg [2:0] line_id_pp1, line_id_pp2, col_id_pp1, col_id_pp2;
reg [2:0] line_id_pp1, line_id_pp2, line_id_pp3, line_id_pp4, line_id_pp5, col_id_pp1, col_id_pp2, col_id_pp3, col_id_pp4, col_id_pp5;
reg [11:0] hmax[0:1];
reg line_idx;
reg [1:0] line_out_idx_2x, line_out_idx_3x, line_out_idx_4x;
reg [2:0] line_out_idx_5x;
reg [23:0] warn_h_unstable, warn_pll_lock_lost, warn_pll_lock_lost_3x;
reg mask_enable_pp1, mask_enable_pp2, mask_enable_pp3;
reg mask_enable_pp1, mask_enable_pp2, mask_enable_pp3, mask_enable_pp4, mask_enable_pp5, mask_enable_pp6;
//helper registers for sampling at synchronized clock edges
reg pclk_1x_prev3x;
@ -152,6 +157,8 @@ reg [2:0] H_OPT_SAMPLE_SEL;
reg [9:0] H_L5BORDER;
reg [3:0] X_MASK_BR;
reg [7:0] X_SCANLINESTR;
reg [5:0] X_REV_LPF_STR;
reg X_REV_LPF_ENABLE;
//clk27 related registers
reg VSYNC_in_cc_L, VSYNC_in_cc_LL, VSYNC_in_cc_LLL;
@ -197,6 +204,24 @@ function [7:0] apply_mask;
end
endfunction
function [7:0] apply_reverse_lpf;
input enable;
input [7:0] data;
input [7:0] data_prev;
input signed [14:0] diff;
reg signed [12:0] data_prev_x;
reg signed [10:0] result;
begin
data_prev_x = (data_prev << 4);
result = (data_prev_x - diff) >>> 4;
if (enable)
apply_reverse_lpf = (result < 0) ? 8'h00 : (result > 255) ? 8'hFF : result;
else
apply_reverse_lpf = data;
end
endfunction
//Mux for active data selection
//
@ -368,6 +393,8 @@ begin
line_id_pp1 <= line_id_act;
col_id_pp1 <= col_id_act;
mask_enable_pp1 <= ((hcnt_act < H_AVIDSTART+H_MASK) | (hcnt_act >= H_AVIDSTART+H_ACTIVE-H_MASK) | (vcnt_act < V_AVIDSTART+V_MASK) | (vcnt_act >= V_AVIDSTART+V_ACTIVE-V_MASK));
linebuf_hoffset_pp1 <= linebuf_hoffset;
hoffset_changed_pp1 <= (linebuf_hoffset_pp1 != linebuf_hoffset);
HSYNC_pp2 <= HSYNC_act;
VSYNC_pp2 <= VSYNC_act;
@ -375,21 +402,72 @@ begin
line_id_pp2 <= line_id_pp1;
col_id_pp2 <= col_id_pp1;
mask_enable_pp2 <= mask_enable_pp1;
// Optimized modes repeat pixels. Save previous pixel only when linebuffer offset changes.
if (hoffset_changed_pp1) begin
R_prev_pp2 <= R_act;
G_prev_pp2 <= G_act;
B_prev_pp2 <= B_act;
end
R_pp3 <= apply_scanlines(V_SCANLINEMODE, R_act, X_SCANLINESTR, V_SCANLINEID, line_id_pp2, col_id_pp2, FID_1x);
G_pp3 <= apply_scanlines(V_SCANLINEMODE, G_act, X_SCANLINESTR, V_SCANLINEID, line_id_pp2, col_id_pp2, FID_1x);
B_pp3 <= apply_scanlines(V_SCANLINEMODE, B_act, X_SCANLINESTR, V_SCANLINEID, line_id_pp2, col_id_pp2, FID_1x);
R_pp3 <= R_act;
G_pp3 <= G_act;
B_pp3 <= B_act;
HSYNC_pp3 <= HSYNC_pp2;
VSYNC_pp3 <= VSYNC_pp2;
DE_pp3 <= DE_pp2;
line_id_pp3 <= line_id_pp2;
col_id_pp3 <= col_id_pp2;
mask_enable_pp3 <= mask_enable_pp2;
R_out <= apply_mask(mask_enable_pp3, R_pp3, X_MASK_BR);
G_out <= apply_mask(mask_enable_pp3, G_pp3, X_MASK_BR);
B_out <= apply_mask(mask_enable_pp3, B_pp3, X_MASK_BR);
HSYNC_out <= HSYNC_pp3;
VSYNC_out <= VSYNC_pp3;
DE_out <= DE_pp3;
R_prev_pp3 <= R_prev_pp2;
G_prev_pp3 <= G_prev_pp2;
B_prev_pp3 <= B_prev_pp2;
// Reverse LPF step1
R_diff_pp3 <= (R_prev_pp2 - R_act);
G_diff_pp3 <= (G_prev_pp2 - G_act);
B_diff_pp3 <= (B_prev_pp2 - B_act);
R_pp4 <= R_pp3;
G_pp4 <= G_pp3;
B_pp4 <= B_pp3;
HSYNC_pp4 <= HSYNC_pp3;
VSYNC_pp4 <= VSYNC_pp3;
DE_pp4 <= DE_pp3;
line_id_pp4 <= line_id_pp3;
col_id_pp4 <= col_id_pp3;
mask_enable_pp4 <= mask_enable_pp3;
R_prev_pp4 <= R_prev_pp3;
G_prev_pp4 <= G_prev_pp3;
B_prev_pp4 <= B_prev_pp3;
// Reverse LPF step2
R_diff_pp4 <= (R_diff_pp3 * X_REV_LPF_STR);
G_diff_pp4 <= (G_diff_pp3 * X_REV_LPF_STR);
B_diff_pp4 <= (B_diff_pp3 * X_REV_LPF_STR);
R_pp5 <= apply_reverse_lpf(X_REV_LPF_ENABLE, R_pp4, R_prev_pp4, R_diff_pp4);
G_pp5 <= apply_reverse_lpf(X_REV_LPF_ENABLE, G_pp4, G_prev_pp4, G_diff_pp4);
B_pp5 <= apply_reverse_lpf(X_REV_LPF_ENABLE, B_pp4, B_prev_pp4, B_diff_pp4);
HSYNC_pp5 <= HSYNC_pp4;
VSYNC_pp5 <= VSYNC_pp4;
DE_pp5 <= DE_pp4;
line_id_pp5 <= line_id_pp4;
col_id_pp5 <= col_id_pp4;
mask_enable_pp5 <= mask_enable_pp4;
R_pp6 <= apply_scanlines(V_SCANLINEMODE, R_pp5, X_SCANLINESTR, V_SCANLINEID, line_id_pp5, col_id_pp5, FID_1x);
G_pp6 <= apply_scanlines(V_SCANLINEMODE, G_pp5, X_SCANLINESTR, V_SCANLINEID, line_id_pp5, col_id_pp5, FID_1x);
B_pp6 <= apply_scanlines(V_SCANLINEMODE, B_pp5, X_SCANLINESTR, V_SCANLINEID, line_id_pp5, col_id_pp5, FID_1x);
HSYNC_pp6 <= HSYNC_pp5;
VSYNC_pp6 <= VSYNC_pp5;
DE_pp6 <= DE_pp5;
mask_enable_pp6 <= mask_enable_pp5;
R_out <= apply_mask(mask_enable_pp6, R_pp6, X_MASK_BR);
G_out <= apply_mask(mask_enable_pp6, G_pp6, X_MASK_BR);
B_out <= apply_mask(mask_enable_pp6, B_pp6, X_MASK_BR);
HSYNC_out <= HSYNC_pp6;
VSYNC_out <= VSYNC_pp6;
DE_out <= DE_pp6;
end
//Generate a warning signal from horizontal instability or PLL sync loss
@ -559,6 +637,9 @@ begin
H_OPT_SAMPLE_MULT <= h_info2[12:10];
H_OPT_STARTOFF <= h_info2[9:0];
X_REV_LPF_ENABLE <= (extra_info[12:8] != 5'b00000);
X_REV_LPF_STR <= (extra_info[12:8] + 6'd16);
X_MASK_BR <= extra_info[7:4];
X_SCANLINESTR <= ((extra_info[3:0]+8'h01)<<4)-1'b1;
end

File diff suppressed because it is too large Load Diff

View File

@ -306,7 +306,8 @@ status_t get_status(tvp_input_t input, video_format format)
(tc.h_mask != cm.cc.h_mask) ||
(tc.v_mask != cm.cc.v_mask) ||
(tc.mask_br != cm.cc.mask_br) ||
(tc.ar_256col != cm.cc.ar_256col))
(tc.ar_256col != cm.cc.ar_256col) ||
(tc.reverse_lpf != cm.cc.reverse_lpf))
status = (status < INFO_CHANGE) ? INFO_CHANGE : status;
if (tc.sampler_phase != cm.cc.sampler_phase) {
@ -364,8 +365,8 @@ status_t get_status(tvp_input_t input, video_format format)
// v_info: [31:29] [28:27] [26] [25:20] [19:17] [16:11] [10:0]
// | V_MULTMODE[2:0] | V_SCANLINEMODE[1:0] | V_SCANLINEID | V_MASK[5:0] | V_SYNCLEN[2:0] | V_BACKPORCH[5:0] | V_ACTIVE[10:0] |
//
// extra: [31:8] [7:4] [3:0]
// | | H_MASK_BR[3:0] | H_SCANLINESTR[3:0] |
// extra: [31:13] [12:8] [7:4] [3:0]
// | | X_REV_LPF_STR | H_MASK_BR[3:0] | H_SCANLINESTR[3:0] |
//
void set_videoinfo()
{
@ -460,7 +461,8 @@ void set_videoinfo()
(video_modes[cm.id].v_synclen<<17) |
(v_backporch<<11) |
v_active);
IOWR_ALTERA_AVALON_PIO_DATA(PIO_6_BASE, (cm.cc.mask_br<<4) |
IOWR_ALTERA_AVALON_PIO_DATA(PIO_6_BASE, (cm.cc.reverse_lpf<<8) |
(cm.cc.mask_br<<4) |
cm.cc.sl_str);
}

View File

@ -33,6 +33,7 @@
#define VSYNC_THOLD_MAX 200
#define SD_SYNC_WIN_MAX 255
#define PLL_COAST_MAX 5
#define REVERSE_LPF_MAX 31
#define SL_MODE_MAX 2
#define SL_TYPE_MAX 2
@ -77,6 +78,7 @@ typedef struct {
alt_u8 post_coast;
alt_u8 full_tx_setup;
alt_u8 vga_ilace_fix;
alt_u8 reverse_lpf;
#ifdef ENABLE_AUDIO
alt_u8 audio_dw_sampl;
alt_u8 audio_swap_lr;

View File

@ -135,6 +135,7 @@ MENU(menu_postproc, P99_PROTECT({ \
{ LNG("Horizontal mask","スイヘイマスク"), OPT_AVCONFIG_NUMVALUE, { .num = { &tc.h_mask, OPT_NOWRAP, 0, HV_MASK_MAX, pixels_disp } } },
{ LNG("Vertical mask","スイチョクマスク"), OPT_AVCONFIG_NUMVALUE, { .num = { &tc.v_mask, OPT_NOWRAP, 0, HV_MASK_MAX, pixels_disp } } },
{ LNG("Mask brightness","マスクアカルサ"), OPT_AVCONFIG_NUMVALUE, { .num = { &tc.mask_br, OPT_NOWRAP, 0, HV_MASK_MAX_BR, value_disp } } },
{ "Reverse LPF", OPT_AVCONFIG_NUMVALUE, { .num = { &tc.reverse_lpf, OPT_NOWRAP, 0, REVERSE_LPF_MAX, value_disp } } },
}))
MENU(menu_compatibility, P99_PROTECT({ \

View File

@ -2,11 +2,11 @@
<sch:Settings xmlns:sch="http://www.altera.com/embeddedsw/bsp/schema">
<BspType>hal</BspType>
<BspVersion>default</BspVersion>
<BspGeneratedTimeStamp>Aug 8, 2017 11:42:37 PM</BspGeneratedTimeStamp>
<BspGeneratedUnixTimeStamp>1502224957695</BspGeneratedUnixTimeStamp>
<BspGeneratedLocation>./</BspGeneratedLocation>
<BspGeneratedTimeStamp>27-sep-2017 12:31:17</BspGeneratedTimeStamp>
<BspGeneratedUnixTimeStamp>1506508277524</BspGeneratedUnixTimeStamp>
<BspGeneratedLocation>D:\ossc\software\sys_controller_bsp</BspGeneratedLocation>
<BspSettingsFile>settings.bsp</BspSettingsFile>
<SopcDesignFile>../../sys.sopcinfo</SopcDesignFile>
<SopcDesignFile>..\..\sys.sopcinfo</SopcDesignFile>
<JdiFile>default</JdiFile>
<Cpu>nios2_qsys_0</Cpu>
<SchemaVersion>1.9</SchemaVersion>

View File

@ -1,11 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<EnsembleReport name="sys" kind="sys" version="1.0" fabric="QSYS">
<!-- Format version 17.0 595 (Future versions may contain additional information.) -->
<!-- 2017.08.09.23:56:57 -->
<!-- 2017.09.27.11:57:11 -->
<!-- A collection of modules and connections -->
<parameter name="AUTO_GENERATION_ID">
<type>java.lang.Integer</type>
<value>1502312217</value>
<value>1506506231</value>
<derived>false</derived>
<enabled>true</enabled>
<visible>false</visible>