diff --git a/BootROMs/cgb_boot.mif b/BootROMs/cgb_boot.mif index 18e6a38..78e362e 100644 --- a/BootROMs/cgb_boot.mif +++ b/BootROMs/cgb_boot.mif @@ -104,5 +104,41 @@ CONTENT BEGIN 08C8: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00; 08E0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00; 08F8: 00 00 00 00 00 00 00 00; -[0900..0FFF]: 00; + +-- DMG +0900: 31 FE FF AF 21 FF 9F 32 CB 7C 20 FB 21 26 FF 0E; +0910: 11 3E 80 32 E2 0C 3E F3 E2 32 3E 77 77 3E FC E0; +0920: 47 F0 50 FE 42 28 75 11 04 01 21 10 80 1A 4F CD; +0930: A0 00 CD A0 00 13 7B FE 34 20 F2 11 B2 00 06 08; +0940: 1A 22 22 13 05 20 F9 3E 19 EA 10 99 21 2F 99 0E; +0950: 0C 3D 28 08 32 0D 20 F9 2E 0F 18 F3 67 3E 64 57; +0960: E0 42 3E 91 E0 40 04 1E 02 0E 0C F0 44 FE 90 20; +0970: FA 0D 20 F7 1D 20 F2 0E 13 24 7C 1E 83 FE 62 28; +0980: 06 1E C1 FE 64 20 06 7B E2 0C 3E 87 E2 F0 42 90; +0990: E0 42 15 20 D2 05 20 64 16 20 18 CB E0 40 18 5C; +09A0: 06 04 C5 CB 11 17 C1 CB 11 17 05 20 F5 22 23 22; +09B0: 23 C9 3C 42 B9 A5 B9 A5 42 3C FF FF FF FF FF FF; +09C0: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF; +09D0: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF; +09E0: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF; +09F0: FF FF FF FF FF FF FF FF FF FF FF FF 3E 01 E0 50; + +--SGB +0A00: 31 FE FF 21 00 80 22 CB 6C 28 FB 3E 80 E0 26 E0; +0A10: 11 3E F3 E0 12 E0 25 3E 77 E0 24 3E 00 E0 47 11; +0A20: 04 01 21 10 80 1A 47 CD C9 00 CD C9 00 13 7B EE; +0A30: 34 20 F2 11 EA 00 0E 08 1A 13 22 23 0D 20 F9 3E; +0A40: 19 EA 10 99 21 2F 99 0E 0C 3D 28 08 32 0D 20 F9; +0A50: 2E 0F 18 F5 3E 91 E0 40 3E F1 E0 80 21 04 01 AF; +0A60: 4F AF E2 3E 30 E2 F0 80 CD B7 00 E5 06 0E 16 00; +0A70: CD AD 00 82 57 05 20 F8 CD B7 00 E1 06 0E CD AD; +0A80: 00 CD B7 00 05 20 F7 3E 20 E2 3E 30 E2 F0 80 C6; +0A90: 02 E0 80 3E 58 BD 20 C9 0E 13 3E C1 E2 0C 3E 07; +0AA0: E2 3E FC E0 47 3E 01 21 60 C0 C3 FE 00 3E 4F BD; +0AB0: 38 02 2A C9 23 AF C9 5F 16 08 3E 10 CB 1B 38 01; +0AC0: 87 E2 3E 30 E2 15 C8 18 F1 3E 04 0E 00 CB 20 F5; +0AD0: CB 11 F1 CB 11 3D 20 F5 79 22 23 22 23 C9 E5 21; +0AE0: 0F FF CB 86 CB 46 28 FC E1 C9 3C 42 B9 A5 B9 A5; +0AF0: 42 3C 00 00 00 00 00 00 00 00 00 00 00 00 E0 50; +[0B00..0FFF]: 00; END; diff --git a/Gameboy.sv b/Gameboy.sv index 2fd7df8..4a6499f 100644 --- a/Gameboy.sv +++ b/Gameboy.sv @@ -30,7 +30,7 @@ module emu input RESET, //Must be passed to hps_io module - inout [45:0] HPS_BUS, + inout [48:0] HPS_BUS, //Base video clock. Usually equals to CLK_SYS. output CLK_VIDEO, @@ -53,13 +53,14 @@ module emu output VGA_F1, output [1:0] VGA_SL, output VGA_SCALER, // Force VGA scaler + output VGA_DISABLE, // analog out is off input [11:0] HDMI_WIDTH, input [11:0] HDMI_HEIGHT, - output HDMI_FREEZE, + output HDMI_FREEZE, `ifdef MISTER_FB - // Use framebuffer in DDRAM (USE_FB=1 in qsf) + // Use framebuffer in DDRAM // FB_FORMAT: // [2:0] : 011=8bpp(palette) 100=16bpp 101=24bpp 110=32bpp // [3] : 0=16bits 565 1=16bits 1555 @@ -187,6 +188,7 @@ assign LED_POWER = 0; assign BUTTONS = 0; assign HDMI_FREEZE = 0; assign VGA_SCALER= 0; +assign VGA_DISABLE = 0; assign AUDIO_MIX = status[8:7]; @@ -202,13 +204,14 @@ assign DDRAM_WE = 0; // 0 1 2 3 4 5 6 // 01234567890123456789012345678901 23456789012345678901234567890123 // 0123456789ABCDEFGHIJKLMNOPQRSTUV 0123456789ABCDEFGHIJKLMNOPQRSTUV -// XXXXXX XXXXXXXXXXXXXXXXX X +// XXXXXX XXXX XXXXXXXXXXXX X XXXXX `include "build_id.v" localparam CONF_STR = { "GAMEBOY2P;SS3E000000:40000;", - "FS1,GBCGB ,Load ROM;", - "OEF,System,Auto,Gameboy,Gameboy Color;", + "FS1,GBCGB BIN,Load ROM;", + "OEF,System,Auto,Gameboy,Gameboy Color,MegaDuck;", + "D7o79,Mapper,Auto,WisdomTree,Mani161,MBC1,MBC3;", "-;", "h2R9,Load Backup RAM;", "h2RA,Save Backup RAM;", @@ -219,6 +222,7 @@ localparam CONF_STR = { "P1-;", "P1ON,Seperator Line,Off,On;", "P1OC,Inverted color,No,Yes;", + "h6P1o5,Use GBA Mode,No,Yes;", "P1O12,Custom Palette,Off,Auto,On;", "h1P1FC3,GBP,Load Palette;", "P1-;", @@ -233,7 +237,11 @@ localparam CONF_STR = { "P2,Misc.;", "P2-;", - "P2OB,Boot,Normal,Fast;", + "P2FC4,BIN,Load GBC Boot;", + "P2FC5,BIN,Load DMG Boot;", + "P2FC6,BIN,Load SGB Boot;", + "P2-;", + "P2o6,Rumble,On,Off;", "-;", "R0,Reset;", @@ -288,9 +296,14 @@ wire sd_buff_wr; wire img_mounted; wire img_readonly; wire [63:0] img_size; +wire [15:0] joy0_rumble, joy1_rumble; wire [32:0] RTC_time; +wire sys_auto = (status[15:14] == 0); +wire sys_gbc = (status[15:14] == 2); +wire sys_megaduck = (status[15:14] == 3); + hps_io #(.CONF_STR(CONF_STR), .WIDE(1)) hps_io ( .clk_sys(clk_sys), @@ -318,7 +331,7 @@ hps_io #(.CONF_STR(CONF_STR), .WIDE(1)) hps_io .buttons(buttons), .status(status), - .status_menumask({1'b0,isGBC,(cart1_ready & cart2_ready),sav_supported,|tint,1'b0}), + .status_menumask({sys_megaduck,using_real_cgb_bios,1'b0,isGBC,(cart1_ready & cart2_ready),sav_supported,|tint,1'b0}), .status_in(status), .status_set(1'b0), .direct_video(direct_video), @@ -331,6 +344,9 @@ hps_io #(.CONF_STR(CONF_STR), .WIDE(1)) hps_io .joystick_3(joystick_3), .joystick_l_analog_0(joystick_analog_0), .joystick_l_analog_1(joystick_analog_1), + + .joystick_0_rumble(joy0_rumble), + .joystick_1_rumble(joy1_rumble), .ps2_key(ps2_key), @@ -363,9 +379,13 @@ wire [22:0] mbc2_addr; wire gb2_nCS; -wire cart_download = ioctl_download && (filetype == 8'h01 || filetype == 8'h41 || filetype == 8'h80); +wire cart_download = ioctl_download && (filetype[5:0] == 6'h01 || filetype == 8'h80); +wire md_download = ioctl_download && (filetype == 8'h81); wire palette_download = ioctl_download && (filetype == 3 /*|| !filetype*/); -wire bios_download = ioctl_download && (filetype == 8'h40); +wire cgb_boot_download = ioctl_download && (filetype == 4); +wire dmg_boot_download = ioctl_download && (filetype == 5); +wire sgb_boot_download = ioctl_download && (filetype == 6); +wire boot_download = cgb_boot_download | dmg_boot_download | sgb_boot_download; wire [1:0] sdram_ds = cart_download ? 2'b11 : {mbc1_addr[0], ~mbc1_addr[0]}; wire [15:0] sdram_do; @@ -427,10 +447,15 @@ wire cart_has_save; wire [31:0] RTC_timestampOut; wire [47:0] RTC_savedtimeOut; wire RTC_inuse; +wire rumbling1, rumbling2; +wire [2:0] mapper_sel = status[41:39]; reg [127:0] palette = 128'h828214517356305A5F1A3B4900000000; +reg using_real_cgb_bios = 0; always @(posedge clk_sys) begin + if (cgb_boot_download) + using_real_cgb_bios <= 1; if (palette_download & ioctl_wr) begin palette[127:0] <= {palette[111:0], ioctl_dout[7:0], ioctl_dout[15:8]}; end @@ -438,18 +463,29 @@ end assign AUDIO_S = 0; -wire reset = (RESET | status[0] | buttons[1] | cart_download | bk_loading); +wire reset = (RESET | status[0] | buttons[1] | cart_download | boot_download | bk_loading); +reg megaduck = 0; reg isGBC = 0; always @(posedge clk_sys) if(reset) begin - if(status[15:14]) isGBC <= status[15]; - else if(cart_download) isGBC <= !filetype[7:4]; + if (cart_download) + megaduck <= sys_megaduck; + if (md_download) + megaduck <= sys_auto || sys_megaduck; + + if(~sys_auto) isGBC <= sys_gbc; + else if(cart_download) begin + if (!filetype[5:0]) isGBC <= isGBC_game; + else isGBC <= !filetype[7:6]; + end end // core 1 wire speed1; wire SaveStateBus_rst1; +assign joy0_rumble = {8'd0, ((rumbling1 & ~status[38]) ? 8'd128 : 8'd0)}; + cart_top cart1 ( .reset ( reset ), @@ -457,6 +493,8 @@ cart_top cart1 ( .ce_cpu ( ce1_cpu ), .ce_cpu2x ( ce1_cpu2x ), .speed ( speed1 ), + .megaduck ( megaduck ), + .mapper_sel ( mapper_sel ), .cart_addr ( cart1_addr ), .cart_a15 ( cart1_a15 ), @@ -518,7 +556,9 @@ cart_top cart1 ( .Savestate_CRAMAddr ( 0 ), .Savestate_CRAMRWrEn ( 0 ), .Savestate_CRAMWriteData( 0 ), - .Savestate_CRAMReadData ( ) + .Savestate_CRAMReadData ( ), + + .rumbling (rumbling1) ); wire [15:0] AUDIO_L1; @@ -532,11 +572,10 @@ gb gb1 ( .ce ( ce1_cpu ), // the whole gameboy runs on 4mhnz .ce_2x ( ce1_cpu2x ), // ~8MHz in dualspeed mode (GBC) - .fast_boot ( status[11] ), - .isGBC ( isGBC ), .isGBC_game ( isGBC_game ), .isSGB ( 1'b0 ), + .megaduck ( megaduck ), .joy_p54 ( joy1_p54 ), .joy_din ( joy1_do ), @@ -552,9 +591,14 @@ gb gb1 ( .nCS ( gb1_nCS ), - //gbc bios interface - .gbc_bios_addr ( bios1_addr ), - .gbc_bios_do ( bios1_do ), + .boot_gba_en ( status[37] && using_real_cgb_bios ), + + .cgb_boot_download ( cgb_boot_download ), + .dmg_boot_download ( dmg_boot_download ), + .sgb_boot_download ( sgb_boot_download ), + .ioctl_wr ( ioctl_wr ), + .ioctl_addr ( ioctl_addr ), + .ioctl_dout ( ioctl_dout ), // audio .audio_l ( AUDIO_L1 ), @@ -622,24 +666,12 @@ wire [3:0] joy1_dir = ~{ joystick_0[2], joystick_0[3], joystick_0[1], joysti wire [3:0] joy1_buttons = ~{ joystick_0[7], joystick_0[6], joystick_0[5], joystick_0[4] } | {4{joy1_p54[1]}}; wire [3:0] joy1_do = joy1_dir & joy1_buttons; -wire [7:0] bios1_do; -wire [11:0] bios1_addr; - -dpram_dif #(12,8,11,16,"BootROMs/cgb_boot.mif") boot_rom_gbc1 ( - .clock (clk_sys), - - .address_a (bios1_addr), - .q_a (bios1_do), - - .address_b (ioctl_addr[11:1]), - .wren_b (ioctl_wr && bios_download), - .data_b (ioctl_dout) -); - // core 2 wire speed2; wire SaveStateBus_rst2; +assign joy1_rumble = {8'd0, ((rumbling2 & ~status[38]) ? 8'd128 : 8'd0)}; + cart_top cart2 ( .reset ( reset ), @@ -647,6 +679,8 @@ cart_top cart2 ( .ce_cpu ( ce2_cpu ), .ce_cpu2x ( ce2_cpu2x ), .speed ( speed2 ), + .megaduck ( megaduck ), + .mapper_sel ( mapper_sel ), .cart_addr ( cart2_addr ), .cart_a15 ( cart2_a15 ), @@ -708,7 +742,9 @@ cart_top cart2 ( .Savestate_CRAMAddr ( 0 ), .Savestate_CRAMRWrEn ( 0 ), .Savestate_CRAMWriteData( 0 ), - .Savestate_CRAMReadData ( ) + .Savestate_CRAMReadData ( ), + + .rumbling (rumbling2) ); wire [15:0] AUDIO_L2; @@ -722,11 +758,11 @@ gb gb2 ( .ce ( ce2_cpu ), // the whole gameboy runs on 4mhnz .ce_2x ( ce2_cpu2x ), // ~8MHz in dualspeed mode (GBC) - .fast_boot ( status[11] ), .isGBC ( isGBC ), .isGBC_game ( isGBC_game ), .isSGB ( 1'b0 ), + .megaduck ( megaduck ), .joy_p54 ( joy2_p54 ), .joy_din ( joy2_do ), @@ -742,9 +778,14 @@ gb gb2 ( .nCS ( gb2_nCS ), - //gbc bios interface - .gbc_bios_addr ( bios2_addr ), - .gbc_bios_do ( bios2_do ), + .boot_gba_en ( status[37] && using_real_cgb_bios ), + + .cgb_boot_download ( cgb_boot_download ), + .dmg_boot_download ( dmg_boot_download ), + .sgb_boot_download ( sgb_boot_download ), + .ioctl_wr ( ioctl_wr ), + .ioctl_addr ( ioctl_addr ), + .ioctl_dout ( ioctl_dout ), // audio .audio_l ( AUDIO_L2 ), @@ -812,20 +853,6 @@ wire [3:0] joy2_dir = ~{ joystick_1[2], joystick_1[3], joystick_1[1], joysti wire [3:0] joy2_buttons = ~{ joystick_1[7], joystick_1[6], joystick_1[5], joystick_1[4] } | {4{joy2_p54[1]}}; wire [3:0] joy2_do = joy2_dir & joy2_buttons; -wire [7:0] bios2_do; -wire [11:0] bios2_addr; - -dpram_dif #(12,8,11,16,"BootROMs/cgb_boot.mif") boot_rom_gbc2 ( - .clock (clk_sys), - - .address_a (bios2_addr), - .q_a (bios2_do), - - .address_b (ioctl_addr[11:1]), - .wren_b (ioctl_wr && bios_download), - .data_b (ioctl_dout) -); - assign AUDIO_L = (status[17:16] == 3'd0) ? AUDIO_L1 : (status[17:16] == 3'd1) ? AUDIO_L2 : (status[17:16] == 3'd2) ? ({1'b0, AUDIO_L1[15:1]} + {1'b0, AUDIO_L2[15:1]}) : diff --git a/files.qip b/files.qip index b13ef91..daffe35 100644 --- a/files.qip +++ b/files.qip @@ -3,8 +3,8 @@ set_global_assignment -name SYSTEMVERILOG_FILE rtl/sdram.sv set_global_assignment -name SYSTEMVERILOG_FILE rtl/ddram.sv set_global_assignment -name VHDL_FILE rtl/spram.vhd set_global_assignment -name VHDL_FILE rtl/dpram.vhd -set_global_assignment -name VHDL_FILE rtl/boot_rom.vhd set_global_assignment -name SYSTEMVERILOG_FILE rtl/cheatcodes.sv +set_global_assignment -name SYSTEMVERILOG_FILE rtl/megaswizzle.sv set_global_assignment -name VERILOG_FILE rtl/video.v set_global_assignment -name VERILOG_FILE rtl/timer.v set_global_assignment -name VERILOG_FILE rtl/sprites.v @@ -15,6 +15,7 @@ set_global_assignment -name VHDL_FILE rtl/bus_savestates.vhd set_global_assignment -name VHDL_FILE rtl/reg_savestates.vhd set_global_assignment -name VHDL_FILE rtl/gb_statemanager.vhd set_global_assignment -name VHDL_FILE rtl/gb_savestates.vhd +set_global_assignment -name SYSTEMVERILOG_FILE rtl/savestate_ui.sv set_global_assignment -name VERILOG_FILE rtl/gb.v set_global_assignment -name VERILOG_FILE rtl/hdma.v set_global_assignment -name VERILOG_FILE rtl/link.v @@ -34,6 +35,7 @@ set_global_assignment -name VERILOG_FILE rtl/mappers/gb_camera.v set_global_assignment -name VERILOG_FILE rtl/mappers/tama.v set_global_assignment -name SYSTEMVERILOG_FILE rtl/mappers/rocket.sv set_global_assignment -name VERILOG_FILE rtl/mappers/sachen.v +set_global_assignment -name VERILOG_FILE rtl/mappers/megaduck.v +set_global_assignment -name VERILOG_FILE rtl/mappers/misc.v set_global_assignment -name SDC_FILE Gameboy.sdc -set_global_assignment -name SYSTEMVERILOG_FILE rtl/savestate_ui.sv set_global_assignment -name SYSTEMVERILOG_FILE Gameboy.sv diff --git a/releases/Gameboy2P_20220806.rbf b/releases/Gameboy2P_20220806.rbf new file mode 100644 index 0000000..b022024 Binary files /dev/null and b/releases/Gameboy2P_20220806.rbf differ diff --git a/rtl/boot_rom.vhd b/rtl/boot_rom.vhd deleted file mode 100644 index d3932f7..0000000 --- a/rtl/boot_rom.vhd +++ /dev/null @@ -1,107 +0,0 @@ -library ieee; -use ieee.std_logic_1164.all,ieee.numeric_std.all; - -entity boot_rom is -port ( - clk : in std_logic; - addr : in std_logic_vector(7 downto 0); - data : out std_logic_vector(7 downto 0) -); -end entity; - -architecture prom of boot_rom is - type rom is array(0 to 255) of std_logic_vector(7 downto 0); - signal rom_data: rom := ( - X"31",X"FE",X"FF",X"AF",X"21",X"FF",X"9F",X"32",X"CB",X"7C",X"20",X"FB",X"21",X"26",X"FF",X"0E", - X"11",X"3E",X"80",X"32",X"E2",X"0C",X"3E",X"F3",X"E2",X"32",X"3E",X"77",X"77",X"3E",X"FC",X"E0", - X"47",X"F0",X"50",X"FE",X"42",X"28",X"75",X"11",X"04",X"01",X"21",X"10",X"80",X"1A",X"4F",X"CD", - X"A0",X"00",X"CD",X"A0",X"00",X"13",X"7B",X"FE",X"34",X"20",X"F2",X"11",X"B2",X"00",X"06",X"08", - X"1A",X"22",X"22",X"13",X"05",X"20",X"F9",X"3E",X"19",X"EA",X"10",X"99",X"21",X"2F",X"99",X"0E", - X"0C",X"3D",X"28",X"08",X"32",X"0D",X"20",X"F9",X"2E",X"0F",X"18",X"F3",X"67",X"3E",X"64",X"57", - X"E0",X"42",X"3E",X"91",X"E0",X"40",X"04",X"1E",X"02",X"0E",X"0C",X"F0",X"44",X"FE",X"90",X"20", - X"FA",X"0D",X"20",X"F7",X"1D",X"20",X"F2",X"0E",X"13",X"24",X"7C",X"1E",X"83",X"FE",X"62",X"28", - X"06",X"1E",X"C1",X"FE",X"64",X"20",X"06",X"7B",X"E2",X"0C",X"3E",X"87",X"E2",X"F0",X"42",X"90", - X"E0",X"42",X"15",X"20",X"D2",X"05",X"20",X"64",X"16",X"20",X"18",X"CB",X"E0",X"40",X"18",X"5C", - X"06",X"04",X"C5",X"CB",X"11",X"17",X"C1",X"CB",X"11",X"17",X"05",X"20",X"F5",X"22",X"23",X"22", - X"23",X"C9",X"3C",X"42",X"B9",X"A5",X"B9",X"A5",X"42",X"3C",X"FF",X"FF",X"FF",X"FF",X"FF",X"FF", - X"FF",X"FF",X"FF",X"FF",X"FF",X"FF",X"FF",X"FF",X"FF",X"FF",X"FF",X"FF",X"FF",X"FF",X"FF",X"FF", - X"FF",X"FF",X"FF",X"FF",X"FF",X"FF",X"FF",X"FF",X"FF",X"FF",X"FF",X"FF",X"FF",X"FF",X"FF",X"FF", - X"FF",X"FF",X"FF",X"FF",X"FF",X"FF",X"FF",X"FF",X"FF",X"FF",X"FF",X"FF",X"FF",X"FF",X"FF",X"FF", - X"FF",X"FF",X"FF",X"FF",X"FF",X"FF",X"FF",X"FF",X"FF",X"FF",X"FF",X"FF",X"3E",X"01",X"E0",X"50"); -begin - -data <= rom_data(to_integer(unsigned(addr))) when rising_edge(clk); - -end architecture; - -library ieee; -use ieee.std_logic_1164.all,ieee.numeric_std.all; - -entity fast_boot_rom is -port ( - clk : in std_logic; - addr : in std_logic_vector(7 downto 0); - data : out std_logic_vector(7 downto 0) -); -end entity; - -architecture prom of fast_boot_rom is - type rom is array(0 to 255) of std_logic_vector(7 downto 0); - signal rom_data: rom := ( - X"31",X"FE",X"FF",X"21",X"00",X"80",X"22",X"CB",X"6C",X"28",X"FB",X"3E",X"80",X"E0",X"26",X"E0", - X"11",X"3E",X"F3",X"E0",X"12",X"E0",X"25",X"3E",X"77",X"E0",X"24",X"3E",X"FC",X"E0",X"47",X"11", - X"04",X"01",X"21",X"10",X"80",X"1A",X"47",X"CD",X"82",X"00",X"CD",X"82",X"00",X"13",X"7B",X"EE", - X"34",X"20",X"F2",X"11",X"B1",X"00",X"0E",X"08",X"1A",X"13",X"22",X"23",X"0D",X"20",X"F9",X"3E", - X"19",X"EA",X"10",X"99",X"21",X"2F",X"99",X"0E",X"0C",X"3D",X"28",X"08",X"32",X"0D",X"20",X"F9", - X"2E",X"0F",X"18",X"F5",X"3E",X"91",X"E0",X"40",X"06",X"2D",X"CD",X"A3",X"00",X"3E",X"83",X"CD", - X"AA",X"00",X"06",X"05",X"CD",X"A3",X"00",X"3E",X"C1",X"CD",X"AA",X"00",X"06",X"46",X"CD",X"A3", - X"00",X"21",X"B0",X"01",X"E5",X"F1",X"21",X"4D",X"01",X"01",X"13",X"00",X"11",X"D8",X"00",X"C3", - X"FE",X"00",X"3E",X"04",X"0E",X"00",X"CB",X"20",X"F5",X"CB",X"11",X"F1",X"CB",X"11",X"3D",X"20", - X"F5",X"79",X"22",X"23",X"22",X"23",X"C9",X"E5",X"21",X"0F",X"FF",X"CB",X"86",X"CB",X"46",X"28", - X"FC",X"E1",X"C9",X"CD",X"97",X"00",X"05",X"20",X"FA",X"C9",X"E0",X"13",X"3E",X"87",X"E0",X"14", - X"C9",X"3C",X"42",X"B9",X"A5",X"B9",X"A5",X"42",X"3C",X"00",X"00",X"00",X"00",X"00",X"00",X"00", - X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00", - X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00", - X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00", - X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"E0",X"50"); -begin - -data <= rom_data(to_integer(unsigned(addr))) when rising_edge(clk); - -end architecture; - -library ieee; -use ieee.std_logic_1164.all,ieee.numeric_std.all; - -entity boot_rom_sgb is -port ( - clk : in std_logic; - addr : in std_logic_vector(7 downto 0); - data : out std_logic_vector(7 downto 0) -); -end entity; - -architecture prom of boot_rom_sgb is - type rom is array(0 to 255) of std_logic_vector(7 downto 0); - signal rom_data: rom := ( - x"31",x"FE",x"FF",x"21",x"00",x"80",x"22",x"CB",x"6C",x"28",x"FB",x"3E",x"80",x"E0",x"26",x"E0", - x"11",x"3E",x"F3",x"E0",x"12",x"E0",x"25",x"3E",x"77",x"E0",x"24",x"3E",x"00",x"E0",x"47",x"11", - x"04",x"01",x"21",x"10",x"80",x"1A",x"47",x"CD",x"C9",x"00",x"CD",x"C9",x"00",x"13",x"7B",x"EE", - x"34",x"20",x"F2",x"11",x"EA",x"00",x"0E",x"08",x"1A",x"13",x"22",x"23",x"0D",x"20",x"F9",x"3E", - x"19",x"EA",x"10",x"99",x"21",x"2F",x"99",x"0E",x"0C",x"3D",x"28",x"08",x"32",x"0D",x"20",x"F9", - x"2E",x"0F",x"18",x"F5",x"3E",x"91",x"E0",x"40",x"3E",x"F1",x"E0",x"80",x"21",x"04",x"01",x"AF", - x"4F",x"AF",x"E2",x"3E",x"30",x"E2",x"F0",x"80",x"CD",x"B7",x"00",x"E5",x"06",x"0E",x"16",x"00", - x"CD",x"AD",x"00",x"82",x"57",x"05",x"20",x"F8",x"CD",x"B7",x"00",x"E1",x"06",x"0E",x"CD",x"AD", - x"00",x"CD",x"B7",x"00",x"05",x"20",x"F7",x"3E",x"20",x"E2",x"3E",x"30",x"E2",x"F0",x"80",x"C6", - x"02",x"E0",x"80",x"3E",x"58",x"BD",x"20",x"C9",x"0E",x"13",x"3E",x"C1",x"E2",x"0C",x"3E",x"07", - x"E2",x"3E",x"FC",x"E0",x"47",x"3E",x"01",x"21",x"60",x"C0",x"C3",x"FE",x"00",x"3E",x"4F",x"BD", - x"38",x"02",x"2A",x"C9",x"23",x"AF",x"C9",x"5F",x"16",x"08",x"3E",x"10",x"CB",x"1B",x"38",x"01", - x"87",x"E2",x"3E",x"30",x"E2",x"15",x"C8",x"18",x"F1",x"3E",x"04",x"0E",x"00",x"CB",x"20",x"F5", - x"CB",x"11",x"F1",x"CB",x"11",x"3D",x"20",x"F5",x"79",x"22",x"23",x"22",x"23",x"C9",x"E5",x"21", - x"0F",x"FF",x"CB",x"86",x"CB",x"46",x"28",x"FC",x"E1",x"C9",x"3C",x"42",x"B9",x"A5",x"B9",x"A5", - x"42",x"3C",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"E0",x"50"); -begin - -data <= rom_data(to_integer(unsigned(addr))) when rising_edge(clk); - -end architecture; diff --git a/rtl/cart.v b/rtl/cart.v index 8da9596..db52eb8 100644 --- a/rtl/cart.v +++ b/rtl/cart.v @@ -5,6 +5,8 @@ module cart_top ( input ce_cpu, input ce_cpu2x, input speed, + input megaduck, + input [2:0] mapper_sel, input [14:0] cart_addr, input cart_a15, @@ -66,7 +68,8 @@ module cart_top ( input [19:0] Savestate_CRAMAddr, input Savestate_CRAMRWrEn, input [7:0] Savestate_CRAMWriteData, - output [7:0] Savestate_CRAMReadData + output [7:0] Savestate_CRAMReadData, + output rumbling ); /////////////////////////////////////////////////// @@ -121,6 +124,10 @@ mappers mappers ( .tama ( tama ), .rocket ( rocket ), .sachen ( sachen), + .wisdom_tree ( wisdom_tree ), + .mani161 ( mani161 ), + + .megaduck ( megaduck_en ), .isGBC_game ( isGBC_game ), @@ -172,7 +179,8 @@ mappers mappers ( .mbc_addr ( mbc_addr ), .ram_enabled ( mbc_ram_enable ), - .has_battery ( mbc_battery ) + .has_battery ( mbc_battery ), + .rumbling ( cart_rumbling ) ); @@ -195,6 +203,7 @@ wire [3:0] ram_mask = // 0 - no ram 4'b1111; // 4 - 128k 16 banks // ROM size +/* wire [8:0] rom_mask = (cart_rom_size == 0)? 9'b000000001: // 0 - 2 banks, 32k direct mapped (cart_rom_size == 1)? 9'b000000011: // 1 - 4 banks = 64k @@ -209,23 +218,33 @@ wire [8:0] rom_mask = (cart_rom_size == 83)?9'b001111111: //$53 - 80 banks = 1.2M (cart_rom_size == 84)?9'b001111111: 9'b001111111; //$54 - 96 banks = 1.5M +*/ -wire mbc1 = (cart_mbc_type == 1) || (cart_mbc_type == 2) || (cart_mbc_type == 3); +reg [8:0] rom_mask; // get mask from file size + +wire mbc1 = (mapper_sel_r == 3'd3) || (cart_mbc_type == 1) || (cart_mbc_type == 2) || (cart_mbc_type == 3); wire mbc2 = (cart_mbc_type == 5) || (cart_mbc_type == 6); //wire mmm01 = (cart_mbc_type == 11) || (cart_mbc_type == 12) || (cart_mbc_type == 13) || (cart_mbc_type == 14); -wire mbc3 = (cart_mbc_type == 15) || (cart_mbc_type == 16) || (cart_mbc_type == 17) || (cart_mbc_type == 18) || (cart_mbc_type == 19); +wire mbc3 = (mapper_sel_r == 3'd4) || (cart_mbc_type == 15) || (cart_mbc_type == 16) || (cart_mbc_type == 17) || (cart_mbc_type == 18) || (cart_mbc_type == 19); wire mbc30 = mbc3 && ( (cart_rom_size == 7) || (cart_ram_size == 5) ); //wire mbc4 = (cart_mbc_type == 21) || (cart_mbc_type == 22) || (cart_mbc_type == 23); wire mbc5 = (cart_mbc_type == 25) || (cart_mbc_type == 26) || (cart_mbc_type == 27) || (cart_mbc_type == 28) || (cart_mbc_type == 29) || (cart_mbc_type == 30); wire mbc6 = (cart_mbc_type == 32); wire mbc7 = (cart_mbc_type == 34); wire rocket = (cart_mbc_type == 151) || (cart_mbc_type == 153); +wire megaduck_en = (cart_mbc_type == 250); // Use a wire to ensure enable is load while loading wire gb_camera = (cart_mbc_type == 252); wire tama = (cart_mbc_type == 253); wire HuC3 = (cart_mbc_type == 254); wire HuC1 = (cart_mbc_type == 255); +wire wisdom_tree = (mapper_sel_r == 3'd1); +wire mani161 = (mapper_sel_r == 3'd2); + +wire has_rumble = (cart_mbc_type[7:2] == 6'b0001_11); +wire cart_rumbling; +assign rumbling = has_rumble & cart_rumbling; assign isGBC_game = (cart_cgb_flag); assign isSGB_game = (cart_sgb_flag == 8'h03 && cart_old_licensee == 8'h33); @@ -244,6 +263,7 @@ wire mmm01_bank = (ioctl_addr[18:12] == 7'h78); // $78000+ wire cart_logo_match = &cart_logo_check; reg old_cart_download; +reg [2:0] mapper_sel_r; always @(posedge clk_sys) begin old_cart_download <= cart_download; @@ -254,70 +274,89 @@ always @(posedge clk_sys) begin mbc1m <= 0; mmm01 <= 0; { sachen, sachen_t1, sachen_t2 } <= 0; + mapper_sel_r <= mapper_sel; end if(cart_download & ioctl_wr) begin - if (~|ioctl_addr[24:12] || (mmm01_bank & mmm01) ) // MMM01 header is at the end of ROM - case(ioctl_addr[11:0]) - 12'h142: cart_cgb_flag <= ioctl_dout[15]; - 12'h146: begin - {cart_mbc_type, cart_sgb_flag} <= ioctl_dout; - // "Mani 4 in 1" have incorrectly set MBC3 in the header - if ( mmm01 && ioctl_dout[15:8] == 8'h11) cart_mbc_type <= 8'h0B; - end - 12'h148: { cart_ram_size, cart_rom_size } <= ioctl_dout; - 12'h14a: { cart_old_licensee } <= ioctl_dout[15:8]; - endcase - // Sachen - if (~|ioctl_addr[24:12]) begin - case(ioctl_addr[11:0]) - 12'h100: sachen_t1 <= (ioctl_dout[15:8] != 8'hC3); - 12'h140: sachen_t2 <= (ioctl_dout[ 7:0] == 8'hC3); // 0xC3 opcode is at $140 instead of $101 - 12'h150: begin /// CGB flag - if (sachen_t1 & sachen_t2) begin - sachen <= 1'b1; - cart_cgb_flag <= ioctl_dout[15]; - cart_mbc_type <= 0; - cart_sgb_flag <= 0; - cart_ram_size <= 0; - cart_rom_size <= 0; - cart_old_licensee <= 0; + rom_mask <= ioctl_addr[22:14]; + + if (megaduck) begin + cart_cgb_flag <= 0; + cart_sgb_flag <= 0; + mapper_sel_r <= 0; + if (ioctl_addr > 'h100) // Make sure there's time to reset the banks in the mapper + cart_mbc_type <= 8'd250; + end else begin + if (~|ioctl_addr[24:12] || (mmm01_bank & mmm01) ) // MMM01 header is at the end of ROM + case(ioctl_addr[11:0]) + 12'h142: cart_cgb_flag <= ioctl_dout[15]; + 12'h146: begin + {cart_mbc_type, cart_sgb_flag} <= ioctl_dout; + // "Mani 4 in 1" have incorrectly set MBC3 in the header + if ( mmm01 && ioctl_dout[15:8] == 8'h11) cart_mbc_type <= 8'h0B; + end + 12'h148: { cart_ram_size, cart_rom_size } <= ioctl_dout; + 12'h14a: { cart_old_licensee } <= ioctl_dout[15:8]; + endcase + + // Disable other mappers when a specific mapper has been selected + if (|mapper_sel_r) begin + cart_mbc_type <= 8'd0; + mbc1m <= 0; + mmm01 <= 0; + sachen <= 0; + end else begin + // Sachen + if (~|ioctl_addr[24:12]) begin + case(ioctl_addr[11:0]) + 12'h100: sachen_t1 <= (ioctl_dout[15:8] != 8'hC3); + 12'h140: sachen_t2 <= (ioctl_dout[ 7:0] == 8'hC3); // 0xC3 opcode is at $140 instead of $101 + 12'h150: begin /// CGB flag + if (sachen_t1 & sachen_t2) begin + sachen <= 1'b1; + cart_cgb_flag <= ioctl_dout[15]; + cart_mbc_type <= 0; + cart_sgb_flag <= 0; + cart_ram_size <= 0; + cart_old_licensee <= 0; + end + end + endcase + end + + //Store cart logo data + if (ioctl_addr >= 'h104 && ioctl_addr <= 'h112) begin + cart_logo_data[cart_logo_idx] <= ioctl_dout; + cart_logo_idx <= cart_logo_idx + 1'b1; + end + + // MBC1 Multicart detect: Compare 8 words of logo data at second 256KByte bank ($40000) + // MMM01 detect: Compare the last bank every 512KByte ($78000+) + if ( mbc1m_bank | mmm01_bank ) begin + if (ioctl_addr[11:0] >= 12'h104 && ioctl_addr[11:0] <= 12'h112) begin + cart_logo_check[cart_logo_idx] <= (ioctl_dout == cart_logo_data[cart_logo_idx]); + cart_logo_idx <= cart_logo_idx + 1'b1; + if (&cart_logo_idx) begin + if (mbc1m_bank) mbc1m_check_end <= 1; + if (mmm01_bank) mmm01_check_end <= 1; + end end end - endcase - end - //Store cart logo data - if (ioctl_addr >= 'h104 && ioctl_addr <= 'h112) begin - cart_logo_data[cart_logo_idx] <= ioctl_dout; - cart_logo_idx <= cart_logo_idx + 1'b1; - end + if (mbc1m_check_end) begin + mbc1m_check_end <= 0; + mbc1m <= cart_logo_match; + end - // MBC1 Multicart detect: Compare 8 words of logo data at second 256KByte bank ($40000) - // MMM01 detect: Compare the last bank every 512KByte ($78000+) - if ( mbc1m_bank | mmm01_bank ) begin - if (ioctl_addr[11:0] >= 12'h104 && ioctl_addr[11:0] <= 12'h112) begin - cart_logo_check[cart_logo_idx] <= (ioctl_dout == cart_logo_data[cart_logo_idx]); - cart_logo_idx <= cart_logo_idx + 1'b1; - if (&cart_logo_idx) begin - if (mbc1m_bank) mbc1m_check_end <= 1; - if (mmm01_bank) mmm01_check_end <= 1; + if (mmm01_check_end) begin + mmm01_check_end <= 0; + mmm01 <= cart_logo_match; + if (cart_logo_match) mbc1m <= 0; end end end end - - if (mbc1m_check_end) begin - mbc1m_check_end <= 0; - mbc1m <= cart_logo_match; - end - - if (mmm01_check_end) begin - mmm01_check_end <= 0; - mmm01 <= cart_logo_match; - if (cart_logo_match) mbc1m <= 0; - end end assign ram_size = cart_ram_size; diff --git a/rtl/gb.v b/rtl/gb.v index 347c6ee..24fff2d 100644 --- a/rtl/gb.v +++ b/rtl/gb.v @@ -26,7 +26,6 @@ module gb ( input ce, input ce_2x, - input fast_boot, input [7:0] joystick, input isGBC, input isGBC_game, @@ -45,14 +44,22 @@ module gb ( // WRAM or Cart RAM CS output nCS, - //gbc bios interface - output [11:0] gbc_bios_addr, - input [7:0] gbc_bios_do, - + input cgb_boot_download, + input dmg_boot_download, + input sgb_boot_download, + input ioctl_wr, + input [24:0] ioctl_addr, + input [15:0] ioctl_dout, + + input boot_gba_en, + // audio output [15:0] audio_l, output [15:0] audio_r, - + + // Megaduck? + input megaduck, + // lcd interface output lcd_clkena, output [14:0] lcd_data, @@ -154,6 +161,7 @@ wire sel_zpram = (cpu_addr[15:7] == 9'b111111111) && // 127 bytes zero pageram a (cpu_addr != 16'hffff); wire sel_audio = (cpu_addr[15:8] == 8'hff) && // audio reg ff10 - ff3f and ff76/ff77 PCM12/PCM34 (undocumented registers) ((cpu_addr[7:5] == 3'b001) || (cpu_addr[7:4] == 4'b0001) || (cpu_addr[7:0] == 8'h76) || (cpu_addr[7:0] == 8'h77)); + wire sel_ext_bus = sel_rom | sel_cram | sel_wram; wire sel_boot_rom, sel_boot_rom_cgb; @@ -203,9 +211,6 @@ wire hdma_sel_cram = hdma_source_addr[15:13] == 3'b101; // 8k cart ram at $a wire hdma_sel_wram = hdma_source_addr[15:13] == 3'b110; // 8k WRAM at $c000-$dff0 wire hdma_sel_ext_bus = hdma_sel_rom | hdma_sel_cram; -// the boot roms sees a special $42 flag in $ff50 if it's supposed to to a fast boot -wire sel_fast = fast_boot && cpu_addr == 16'hff50 && boot_rom_enabled; - wire sc_start; wire sc_shiftclock; wire [7:0] sc_r = {sc_start,6'h3F,sc_shiftclock}; @@ -232,8 +237,8 @@ wire [7:0] joy_do; wire [7:0] sb_o; wire [7:0] timer_do; wire [7:0] video_do; -wire [7:0] audio_do; -wire [7:0] bios_do; +reg [7:0] audio_do; +wire [7:0] boot_do; wire [7:0] vram_do; wire [7:0] vram1_do; wire [7:0] zpram_do; @@ -243,11 +248,10 @@ reg[7:0] FF72; reg[7:0] FF73; reg[7:0] FF74; reg[2:0] FF75; - + // http://gameboy.mongenel.com/dmg/asmmemmap.html wire [7:0] cpu_di = irq_ack?irq_vec: - sel_fast?8'h42: // fast boot flag sel_if?{3'b111, if_r}: // interrupt flag register sel_rp?8'h02: sel_wram_bank?{5'h1f,wram_bank}: @@ -261,7 +265,7 @@ wire [7:0] cpu_di = sel_video_reg?video_do: // video registers (sel_video_oam&&oam_cpu_allow)?video_do: // video object attribute memory sel_audio?audio_do: // audio registers - sel_boot_rom?bios_do: // boot rom + sel_boot_rom?boot_do: // boot rom isGBC&sel_wram ? wram_do: // wram on GBC sel_ext_bus?ext_bus_di: // wram (DMG) + cartridge rom/ram (sel_vram&&vram_cpu_allow)?(isGBC&&vram_bank)?vram1_do:vram_do: // vram (GBC bank 0+1) @@ -307,7 +311,15 @@ wire cpu_stop; wire genie_ovr; wire [7:0] genie_data; - +wire [15:0] cpu_addr_raw; + +megaduck_swizzle md_swizz +( + .megaduck (megaduck), + .a_in (cpu_addr_raw), + .a_out (cpu_addr) +); + GBse cpu ( .RESET_n ( !reset_ss ), .CLK_n ( clk_sys ), @@ -324,7 +336,7 @@ GBse cpu ( .RFSH_n ( ), .HALT_n ( ), .BUSAK_n ( ), - .A ( cpu_addr ), + .A ( cpu_addr_raw ), .DI ( genie_ovr ? genie_data : cpu_di), .DO ( cpu_do ), .STOP ( cpu_stop ), @@ -383,6 +395,25 @@ end wire audio_rd = !cpu_rd_n && sel_audio; wire audio_wr = !cpu_wr_n_edge && sel_audio; +reg [7:0] snd_d_in; +wire [7:0] snd_d_out; + +// Megaduck has reversed nybbles for some registers +always @(*) begin + snd_d_in = cpu_do; + audio_do = snd_d_out; + if (megaduck) begin + if (cpu_addr[7:4] == 1 && (cpu_addr_raw[3:0] == 1 || cpu_addr_raw[3:0] == 7)) + snd_d_in = {cpu_do[3:0], cpu_do[7:4]}; + if (cpu_addr[7:4] == 2 && (cpu_addr_raw[3:0] == 1 || cpu_addr_raw[3:0] == 2)) + snd_d_in = {cpu_do[3:0], cpu_do[7:4]}; + + if (cpu_addr[7:4] == 1 && (cpu_addr_raw[3:0] == 1 || cpu_addr_raw[3:0] == 7)) + audio_do = {snd_d_out[3:0], snd_d_out[7:4]}; + if (cpu_addr[7:4] == 2 && (cpu_addr_raw[3:0] == 1 || cpu_addr_raw[3:0] == 2)) + audio_do = {snd_d_out[3:0], snd_d_out[7:4]}; + end +end gbc_snd audio ( .clk ( clk_sys ), @@ -394,8 +425,8 @@ gbc_snd audio ( .s1_read ( audio_rd ), .s1_write ( audio_wr ), .s1_addr ( cpu_addr[6:0] ), - .s1_readdata ( audio_do ), - .s1_writedata ( cpu_do ), + .s1_readdata ( snd_d_out ), + .s1_writedata ( snd_d_in ), .snd_left ( audio_l ), .snd_right ( audio_r ), @@ -629,6 +660,7 @@ video video ( .ce_cpu ( ce_cpu ), //can be 2x in cgb double speed mode .isGBC ( isGBC ), .isGBC_game ( isGBC_game|boot_rom_enabled ), //enable GBC mode during bootstrap rom + .megaduck ( megaduck ), .irq ( video_irq ), .vblank_irq ( vblank_irq ), @@ -854,41 +886,61 @@ end // combine boot rom data with cartridge data -wire [7:0] boot_rom_do; -wire [7:0] fast_boot_rom_do; -wire [7:0] boot_rom_sgb_do; - wire [15:0] boot_rom_addr = (isGBC && hdma_rd) ? hdma_source_addr : cpu_addr; // 0- FF bootrom 1st part //100-1FF Cart Header //200-8FF bootrom 2nd part assign sel_boot_rom_cgb = isGBC && (boot_rom_addr[15:8] >= 8'h02 && boot_rom_addr[15:8] <= 8'h08); -assign sel_boot_rom = boot_rom_enabled && (!boot_rom_addr[15:8] || sel_boot_rom_cgb); +assign sel_boot_rom = boot_rom_enabled && (!boot_rom_addr[15:8] || sel_boot_rom_cgb) && ~megaduck; -assign bios_do = isGBC ? gbc_bios_do : - isSGB ? boot_rom_sgb_do : - fast_boot ? fast_boot_rom_do : boot_rom_do; -assign gbc_bios_addr = boot_rom_addr[11:0]; +// $000-8FF: GBC +// $900-9FF: DMG +// $A00-AFF: SGB +wire [11:0] boot_addr = + isGBC ? boot_rom_addr[11:0] : + isSGB ? { 4'hA, boot_rom_addr[7:0] } : + { 4'h9, boot_rom_addr[7:0] }; -boot_rom boot_rom ( - .addr ( cpu_addr[7:0] ), - .clk ( clk_sys ), - .data ( boot_rom_do ) +wire boot_download = cgb_boot_download | dmg_boot_download | sgb_boot_download; +wire [10:0] boot_wr_addr = + dmg_boot_download ? {4'h9, ioctl_addr[7:1] } : + sgb_boot_download ? {4'hA, ioctl_addr[7:1] } : + ioctl_addr[11:1]; + +wire [7:0] boot_q; +dpram_dif #(12,8,11,16,"BootROMs/cgb_boot.mif") boot_rom ( + .clock (clk_sys), + + .address_a (boot_addr), + .q_a (boot_q), + + .address_b (boot_wr_addr), + .wren_b (ioctl_wr && boot_download), + .data_b (ioctl_dout) ); -fast_boot_rom fast_boot_rom ( - .addr ( cpu_addr[7:0] ), - .clk ( clk_sys ), - .data ( fast_boot_rom_do ) -); +reg [7:0] boot_do_gba; -boot_rom_sgb boot_rom_sgb ( - .addr ( cpu_addr[7:0] ), - .clk ( clk_sys ), - .data ( boot_rom_sgb_do) -); +always begin + case (boot_addr) + 12'h0F2: boot_do_gba = 8'h00; + 12'h0F3: boot_do_gba = 8'h00; + 12'h0F5: boot_do_gba = 8'hCD; + 12'h0F6: boot_do_gba = 8'hD0; + 12'h0F7: boot_do_gba = 8'h05; + 12'h0F8: boot_do_gba = 8'hAF; + 12'h0F9: boot_do_gba = 8'hE0; + 12'h0FA: boot_do_gba = 8'h70; + 12'h0FB: boot_do_gba = 8'h04; + 12'h409: boot_do_gba = 8'h80; + 12'h40A: boot_do_gba = 8'hFF; + default: boot_do_gba = boot_q; + endcase +end + +assign boot_do = (isGBC & boot_gba_en) ? boot_do_gba : boot_q; // -------------------------------------------------------------------- // ------------------ External bus (WRAM, Cartridge) ------------------ diff --git a/rtl/mappers/mappers.v b/rtl/mappers/mappers.v index 41bb32a..9703321 100644 --- a/rtl/mappers/mappers.v +++ b/rtl/mappers/mappers.v @@ -21,6 +21,10 @@ module mappers( input tama, input rocket, input sachen, + input wisdom_tree, + input mani161, + + input megaduck, input isGBC_game, @@ -72,7 +76,8 @@ module mappers( output [22:0] mbc_addr, output ram_enabled, - output has_battery + output has_battery, + output rumbling ); @@ -92,12 +97,14 @@ tri0 RTC_inuse_b; wire ce = speed ? ce_cpu2x : ce_cpu; -wire no_mapper = ~(mbc1 | mbc2 | mbc3 | mbc5 | mbc6 | mbc7 | mmm01 | huc1 | huc3 | gb_camera | tama | rocket | sachen); +wire no_mapper = ~(mbc1 | mbc2 | mbc3 | mbc5 | mbc6 | mbc7 | mmm01 | huc1 | huc3 | gb_camera | tama | rocket | sachen | wisdom_tree | mani161 | megaduck); +wire no_mapper_single_bank = no_mapper & ~rom_mask[1]; +wire no_mapper_multi_bank = no_mapper & rom_mask[1]; // size > 32KB wire rom_override = (rocket); wire cart_oe_override = (mbc3 | mbc7 | huc1 | huc3 | gb_camera | tama); mbc1 map_mbc1 ( - .enable ( mbc1 ), + .enable ( mbc1 | no_mapper_multi_bank ), .mbc1m ( mbc1m ), .clk_sys ( clk_sys ), @@ -233,7 +240,8 @@ mbc5 map_mbc5 ( .mbc_addr_b ( mbc_addr_b ), .ram_enabled_b ( ram_enabled_b ), - .has_battery_b ( has_battery_b ) + .has_battery_b ( has_battery_b ), + .rumbling ( rumbling ) ); mbc6 map_mbc6 ( @@ -556,15 +564,76 @@ sachen map_sachen ( .has_battery_b ( has_battery_b ) ); +megaduck map_megaduck ( + .enable ( megaduck ), + + .clk_sys ( clk_sys ), + .ce_cpu ( ce ), + + .savestate_load ( savestate_load ), + .savestate_data ( savestate_data ), + .savestate_back_b ( savestate_back_b ), + + .has_ram ( has_ram ), + .ram_mask ( ram_mask ), + .rom_mask ( rom_mask ), + + .cart_addr ( cart_addr ), + .cart_a15 ( cart_a15 ), + + .cart_mbc_type ( cart_mbc_type ), + + .cart_wr ( cart_wr ), + .cart_di ( cart_di ), + + .cram_di ( cram_di ), + .cram_do_b ( cram_do_b ), + .cram_addr_b ( cram_addr_b ), + + .mbc_addr_b ( mbc_addr_b ), + .ram_enabled_b ( ram_enabled_b ), + .has_battery_b ( has_battery_b ) +); + +// Mani 4-in-1 DMG 601 & Wisdom Tree 32KB bank mappers +misc_mapper map_misc ( + .enable ( ~reset & (wisdom_tree | mani161) ), + + .clk_sys ( clk_sys ), + .ce_cpu ( ce ), + + .mapper_sel ( mani161 ), + + .savestate_load ( savestate_load ), + .savestate_data ( savestate_data ), + .savestate_back_b ( savestate_back_b ), + + .rom_mask ( rom_mask ), + + .cart_addr ( cart_addr ), + .cart_a15 ( cart_a15 ), + + .cart_wr ( cart_wr ), + .cart_di ( cart_di ), + + .cram_di ( cram_di ), + .cram_do_b ( cram_do_b ), + .cram_addr_b ( cram_addr_b ), + + .mbc_addr_b ( mbc_addr_b ), + .ram_enabled_b ( ram_enabled_b ), + .has_battery_b ( has_battery_b ) +); + assign { cram_do } = { cram_do_b }; assign { savestate_back, savestate_back2 } = { savestate_back_b, savestate_back2_b }; assign { RTC_timestampOut, RTC_savedtimeOut, RTC_inuse } = { RTC_timestampOut_b, RTC_savedtimeOut_b, RTC_inuse_b }; assign { cram_wr_do, cram_wr } = { cram_wr_do_b, cram_wr_b }; -assign mbc_addr = no_mapper ? {8'd0, cart_addr[14:0]} : mbc_addr_b; -assign cram_addr = no_mapper ? {4'd0, cart_addr[12:0]} : cram_addr_b; -assign has_battery = no_mapper ? (cart_mbc_type == 8'h09) : has_battery_b; -assign ram_enabled = no_mapper ? has_ram : ram_enabled_b; +assign mbc_addr = no_mapper_single_bank ? {8'd0, cart_addr[14:0]} : mbc_addr_b; +assign cram_addr = no_mapper_single_bank ? {4'd0, cart_addr[12:0]} : cram_addr_b; +assign has_battery = no_mapper_single_bank ? (cart_mbc_type == 8'h09) : has_battery_b; +assign ram_enabled = no_mapper_single_bank ? has_ram : ram_enabled_b; assign rom_do = rom_override ? rom_do_b : rom_di; assign cart_oe = cart_oe_override ? cart_oe_b : ((cart_rd & ~cart_a15) | (cram_rd & ram_enabled)); diff --git a/rtl/mappers/mbc5.v b/rtl/mappers/mbc5.v index 864a6fd..99a3efc 100644 --- a/rtl/mappers/mbc5.v +++ b/rtl/mappers/mbc5.v @@ -26,7 +26,8 @@ module mbc5 ( inout [22:0] mbc_addr_b, inout ram_enabled_b, - inout has_battery_b + inout has_battery_b, + output rumbling ); wire [22:0] mbc_addr; @@ -42,6 +43,7 @@ assign cram_addr_b = enable ? cram_addr : 17'hZ; assign ram_enabled_b = enable ? ram_enabled : 1'hZ; assign has_battery_b = enable ? has_battery : 1'hZ; assign savestate_back_b = enable ? savestate_back : 16'hZ; +assign rumbling = mbc_ram_bank_reg[3]; wire [3:0] mbc5_ram_bank = mbc_ram_bank_reg & ram_mask; diff --git a/rtl/mappers/megaduck.v b/rtl/mappers/megaduck.v new file mode 100644 index 0000000..41ebd8f --- /dev/null +++ b/rtl/mappers/megaduck.v @@ -0,0 +1,89 @@ +module megaduck ( + input enable, + + input clk_sys, + input ce_cpu, + + input savestate_load, + input [15:0] savestate_data, + inout [15:0] savestate_back_b, + + input has_ram, + input [1:0] ram_mask, + input [6:0] rom_mask, + + input [14:0] cart_addr, + input cart_a15, + + input [7:0] cart_mbc_type, + + input cart_wr, + input [7:0] cart_di, + + input [7:0] cram_di, + inout [7:0] cram_do_b, + inout [16:0] cram_addr_b, + + inout [22:0] mbc_addr_b, + inout ram_enabled_b, + inout has_battery_b +); + +wire [22:0] mbc_addr; +wire ram_enabled; +wire [7:0] cram_do; +wire [16:0] cram_addr; +wire has_battery; +wire [15:0] savestate_back; + +assign mbc_addr_b = enable ? mbc_addr : 23'hZ; +assign cram_do_b = enable ? cram_do : 8'hZ; +assign cram_addr_b = enable ? cram_addr : 17'hZ; +assign ram_enabled_b = enable ? ram_enabled : 1'hZ; +assign has_battery_b = enable ? has_battery : 1'hZ; +assign savestate_back_b = enable ? savestate_back : 16'hZ; + + +// Megaduck banks are pretty simple. They are broken up into chunks of 0x4000. So bank 0 +// is 0-0x3fff, bank 1 is 0x4000-0x7fff and so on. On most carts, only the top 0x4000 of the rom +// can be bank switched and the bottom is fixed at bank 0. In this case, the bank number is +// written to address 0x0001. Note that the bank can never be less than 1 for the upper bank. +// On some roms, a ram address is written instead which changes the entire visible rom space +// instead of just the upper slot. + +reg [7:0] bank_top, bank_bottom; + +// --------------------- CPU register interface ------------------ + +assign savestate_back[ 7: 0] = bank_bottom; +assign savestate_back[15: 8] = bank_top; // The top bank can never be less than 1 + +always @(posedge clk_sys) begin + if(savestate_load & enable) begin + bank_bottom <= savestate_data[7:0]; + bank_top <= savestate_data[15:8]; + end else if(~enable) begin + bank_bottom <= 8'd0; + bank_top <= 8'd1; + end else if(ce_cpu) begin + if (cart_wr) begin + if (~cart_a15 && cart_addr == 1) begin + bank_top <= (cart_di[7:0] == 0) ? 8'd1 : cart_di; + end + else if (cart_a15 && ~cart_addr[14]) begin + bank_top <= {cart_di[6:0], 1'b1}; + bank_bottom <= {cart_di[6:0], 1'b0}; + end + end + end +end + +assign mbc_addr = { 1'b0, (cart_addr[14] ? bank_top : bank_bottom), cart_addr[13:0] }; +assign ram_enabled = 0; + +assign cram_do = ram_enabled ? cram_di : 8'hFF; +assign cram_addr = 17'd0; +assign has_battery = 0; + + +endmodule \ No newline at end of file diff --git a/rtl/mappers/misc.v b/rtl/mappers/misc.v new file mode 100644 index 0000000..90be454 --- /dev/null +++ b/rtl/mappers/misc.v @@ -0,0 +1,86 @@ +module misc_mapper ( + input enable, + + input clk_sys, + input ce_cpu, + + input mapper_sel, // 0: Wisdom Tree, 1: Mani DMG-601 + + input savestate_load, + input [15:0] savestate_data, + inout [15:0] savestate_back_b, + + input [8:0] rom_mask, + + input [14:0] cart_addr, + input cart_a15, + + input cart_wr, + input [7:0] cart_di, + + input [7:0] cram_di, + inout [7:0] cram_do_b, + inout [16:0] cram_addr_b, + + inout [22:0] mbc_addr_b, + inout ram_enabled_b, + inout has_battery_b +); + +wire [22:0] mbc_addr; +wire ram_enabled; +wire [7:0] cram_do; +wire [16:0] cram_addr; +wire has_battery; +wire [15:0] savestate_back; + +assign mbc_addr_b = enable ? mbc_addr : 23'hZ; +assign cram_do_b = enable ? cram_do : 8'hZ; +assign cram_addr_b = enable ? cram_addr : 17'hZ; +assign ram_enabled_b = enable ? ram_enabled : 1'hZ; +assign has_battery_b = enable ? has_battery : 1'hZ; +assign savestate_back_b = enable ? savestate_back : 16'hZ; + +// --------------------- CPU register interface ------------------ +reg [7:0] rom_bank_reg; +reg map_disable; + +assign savestate_back[ 7: 0] = rom_bank_reg; +assign savestate_back[ 8] = map_disable; +assign savestate_back[15: 9] = 0; + +always @(posedge clk_sys) begin + if(savestate_load & enable) begin + rom_bank_reg <= savestate_data[ 7: 0]; //8'd0; + map_disable <= savestate_data[ 8]; //1'b0; + end else if(~enable) begin + rom_bank_reg <= 8'd0; + map_disable <= 1'b0; + end else if(ce_cpu) begin + if (cart_wr & ~cart_a15) begin + if (mapper_sel) begin + // Mani DMG-601 + if (~map_disable) begin + rom_bank_reg <= { 5'd0, cart_di[2:0] }; + map_disable <= 1'b1; + end + end else begin + // Wisdom Tree + rom_bank_reg <= cart_addr[7:0]; + end + end + end +end + +// mask address lines to enable proper mirroring +wire [7:0] rom_bank = rom_bank_reg & rom_mask[8:1]; + +assign mbc_addr = { rom_bank, cart_addr[14:0] }; + +assign cram_do = 8'hFF; +assign cram_addr = { 4'b0000, cart_addr[12:0] }; + +assign ram_enabled = 0; +assign has_battery = 0; + +endmodule \ No newline at end of file diff --git a/rtl/megaswizzle.sv b/rtl/megaswizzle.sv new file mode 100644 index 0000000..cdc211f --- /dev/null +++ b/rtl/megaswizzle.sv @@ -0,0 +1,54 @@ +module megaduck_swizzle +( + input megaduck, + input [15:0] a_in, + output [15:0] a_out +); + +// Swizzle around MegaDuck register to match GB registers. + + always_comb begin + a_out = a_in; + if (megaduck) begin + case (a_in) + 16'hFF10: a_out = 16'hFF40; // LCDC + 16'hFF11: a_out = 16'hFF41; // STAT + 16'hFF12: a_out = 16'hFF42; // SCY + 16'hFF13: a_out = 16'hFF43; // SCX + 16'hFF18: a_out = 16'hFF44; // LY + 16'hFF19: a_out = 16'hFF45; // LYC + 16'hFF1A: a_out = 16'hFF46; // DMA + 16'hFF1B: a_out = 16'hFF47; // BGP + 16'hFF14: a_out = 16'hFF48; // OBP0 + 16'hFF15: a_out = 16'hFF49; // OBP1 + 16'hFF16: a_out = 16'hFF4A; // WY + 16'hFF17: a_out = 16'hFF4B; // WX + + 16'hFF20: a_out = 16'hFF10; // Audio registers + 16'hFF21: a_out = 16'hFF12; + 16'hFF22: a_out = 16'hFF11; + 16'hFF23: a_out = 16'hFF13; + 16'hFF24: a_out = 16'hFF14; + 16'hFF25: a_out = 16'hFF16; + 16'hFF26: a_out = 16'hFF15; + 16'hFF27: a_out = 16'hFF17; + 16'hFF28: a_out = 16'hFF18; + 16'hFF29: a_out = 16'hFF19; + 16'hFF2A: a_out = 16'hFF1A; + 16'hFF2B: a_out = 16'hFF1B; + 16'hFF2C: a_out = 16'hFF1C; + 16'hFF2D: a_out = 16'hFF1D; + 16'hFF2E: a_out = 16'hFF1E; + 16'hFF2F: a_out = 16'hFF1F; + 16'hFF40: a_out = 16'hFF20; // The final 7 registers are after the audio ram + 16'hFF41: a_out = 16'hFF22; + 16'hFF42: a_out = 16'hFF21; + 16'hFF43: a_out = 16'hFF23; + 16'hFF44: a_out = 16'hFF24; + 16'hFF45: a_out = 16'hFF26; + 16'hFF46: a_out = 16'hFF25; + default: a_out = a_in; + endcase + end + end +endmodule \ No newline at end of file diff --git a/rtl/reg_savestates.vhd b/rtl/reg_savestates.vhd index f744393..c379824 100644 --- a/rtl/reg_savestates.vhd +++ b/rtl/reg_savestates.vhd @@ -27,7 +27,7 @@ package pReg_savestates is constant REG_SAVESTATE_Video2 : regmap_type := ( 10, 61, 0, 1, x"00000000FFFFFC00"); constant REG_SAVESTATE_BPalette : regmap_type := ( 11, 63, 0, 8, x"0000000000000000"); constant REG_SAVESTATE_OPalette : regmap_type := ( 19, 63, 0, 8, x"0000000000000000"); - constant REG_SAVESTATE_Video3 : regmap_type := ( 27, 62, 0, 1, x"0000000000000000"); + constant REG_SAVESTATE_Video3 : regmap_type := ( 27, 63, 0, 1, x"0000000000000000"); constant REG_SAVESTATE_Sound1 : regmap_type := ( 28, 63, 0, 1, x"0000000000000000"); constant REG_SAVESTATE_Sound2 : regmap_type := ( 29, 54, 0, 1, x"0000000000000000"); diff --git a/rtl/video.v b/rtl/video.v index 198288d..4c9d3c9 100644 --- a/rtl/video.v +++ b/rtl/video.v @@ -26,6 +26,7 @@ module video ( input ce_cpu, // 4 or 8Mhz input isGBC, input isGBC_game, + input megaduck, // cpu register adn oam interface input cpu_sel_oam, @@ -82,12 +83,12 @@ wire [60:0] SS_Video1; wire [60:0] SS_Video1_BACK; wire [61:0] SS_Video2; wire [61:0] SS_Video2_BACK; -wire [62:0] SS_Video3; -wire [62:0] SS_Video3_BACK; +wire [63:0] SS_Video3; +wire [63:0] SS_Video3_BACK; eReg_SavestateV #(0, 9, 60, 0, 64'h0000000000000000) iREG_SAVESTATE_Video1 (clk, SaveStateBus_Din, SaveStateBus_Adr, SaveStateBus_wren, SaveStateBus_rst, SaveStateBus_wired_or[ 0], SS_Video1_BACK, SS_Video1); eReg_SavestateV #(0, 10, 61, 0, 64'h00000000FFFFFC00) iREG_SAVESTATE_Video2 (clk, SaveStateBus_Din, SaveStateBus_Adr, SaveStateBus_wren, SaveStateBus_rst, SaveStateBus_wired_or[ 1], SS_Video2_BACK, SS_Video2); -eReg_SavestateV #(0, 27, 62, 0, 64'h0000000000000000) iREG_SAVESTATE_Video3 (clk, SaveStateBus_Din, SaveStateBus_Adr, SaveStateBus_wren, SaveStateBus_rst, SaveStateBus_wired_or[18], SS_Video3_BACK, SS_Video3); +eReg_SavestateV #(0, 27, 63, 0, 64'h0000000000000000) iREG_SAVESTATE_Video3 (clk, SaveStateBus_Din, SaveStateBus_Adr, SaveStateBus_wren, SaveStateBus_rst, SaveStateBus_wired_or[18], SS_Video3_BACK, SS_Video3); wire [63:0] SS_BPAL [7:0]; wire [63:0] SS_BPAL_BACK [7:0]; @@ -138,19 +139,19 @@ wire [7:0] oam_di = dma_active?dma_data:cpu_di; // $ff40 LCDC reg [7:0] lcdc; -wire lcdc_on = lcdc[7]; -wire lcdc_win_tile_map_sel = lcdc[6]; -wire lcdc_win_ena = lcdc[5]; -wire lcdc_tile_data_sel = lcdc[4]; -wire lcdc_bg_tile_map_sel = lcdc[3]; -wire lcdc_spr_siz = lcdc[2]; -wire lcdc_spr_ena = lcdc[1]; +wire lcdc_on = megaduck ? lcdc[7] : lcdc[7]; +wire lcdc_win_tile_map_sel = megaduck ? lcdc[3] : lcdc[6]; +wire lcdc_win_ena = megaduck ? lcdc[5] : lcdc[5]; +wire lcdc_tile_data_sel = megaduck ? lcdc[4] : lcdc[4]; +wire lcdc_bg_tile_map_sel = megaduck ? lcdc[2] : lcdc[3]; +wire lcdc_spr_siz = megaduck ? lcdc[1] : lcdc[2]; +wire lcdc_spr_ena = megaduck ? lcdc[0] : lcdc[1]; // "CGB in CGB Mode: BG and Window Master Priority // When Bit 0 is cleared, the background and window lose their priority // - the sprites will be always displayed on top of background and window, // independently of the priority flags in OAM and BG Map attributes." -wire lcdc_bg_ena = lcdc[0] | (isGBC&&isGBC_game); -wire lcdc_bg_prio = lcdc[0]; +wire lcdc_bg_ena = (megaduck ? lcdc[6] : lcdc[0]) | (isGBC&&isGBC_game); +wire lcdc_bg_prio = megaduck ? lcdc[6] : lcdc[0]; assign lcd_on = lcdc_on; @@ -665,9 +666,9 @@ wire [9:0] bg_tile_map_addr = window_ena ? win_map_addr : bg_map_addr; wire [2:0] tile_line = window_ena ? win_line[2:0] : bg_line[2:0]; -reg window_match, window_ena_d; +reg wy_match, window_match, window_ena_d; -wire win_start = mode3 && lcdc_win_ena && ~sprite_fetch_hold && ~skip_en && ~bg_shift_empty && (v_cnt >= wy) && (pcnt == wx) && (wx < 8'hA7); +wire win_start = ~window_match & mode3 && lcdc_win_ena && ~sprite_fetch_hold && ~skip_en && ~bg_shift_empty && wy_match && (pcnt == wx) && (wx < 8'hA7); assign window_ena = window_match & ~pcnt_reset & lcdc_win_ena; assign SS_Video3_BACK[39:33] = h_cnt ; @@ -676,6 +677,7 @@ assign SS_Video3_BACK[ 42] = window_match; assign SS_Video3_BACK[ 43] = window_ena_d; assign SS_Video3_BACK[48:44] = win_col ; assign SS_Video3_BACK[56:49] = win_line ; +assign SS_Video3_BACK[ 63] = wy_match ; always @(posedge clk) begin @@ -686,6 +688,7 @@ always @(posedge clk) begin window_ena_d <= SS_Video3[ 43]; // 1'b0; win_col <= SS_Video3[48:44]; // 5'd0; win_line <= SS_Video3[56:49]; // 8'd0; + wy_match <= SS_Video3[ 63]; // 1'b0; end else if (!lcdc_on) begin //reset counters h_cnt <= 7'd0; @@ -694,6 +697,7 @@ always @(posedge clk) begin window_ena_d <= 1'b0; win_col <= 5'd0; win_line <= 8'd0; + wy_match <= 1'b0; end else if (ce) begin h_div_cnt <= h_div_cnt + 1'b1; @@ -701,6 +705,12 @@ always @(posedge clk) begin h_cnt <= hcnt_end ? 7'd0 : h_cnt + 1'b1; end + if (vblank_l) begin + wy_match <= 1'b0; + end else if (h_clk_en & lcdc_win_ena & v_cnt == wy) begin + wy_match <= 1'b1; + end + if(win_start) begin window_match <= 1'b1; end @@ -711,12 +721,16 @@ always @(posedge clk) begin else if (window_ena_d & ~window_ena) win_line <= win_line + 1'b1; - if (window_match & ~mode3_end_l & mode3_end) begin - // DMG glitch: If WX = A6 then window_match stays high through VBlank - // until WY > v_cnt which means the window always appears on line 0. - if (isGBC || wx != 8'hA6 || wy > v_cnt) begin - window_match <= 1'b0; // next line starts with background + if (window_match) begin + if (~mode3_end_l & mode3_end) begin + // DMG glitch: If WX = A6 then window_match stays high through VBlank + // until WY > v_cnt which means the window always appears on line 0. + if (isGBC || wx != 8'hA6 || wy > v_cnt) begin + window_match <= 1'b0; // next line starts with background + end end + + if (~lcdc_win_ena) window_match <= 1'b0; end // Increment when fetching is done and not waiting for sprites. diff --git a/sys/arcade_video.v b/sys/arcade_video.v index ff554a5..f53b136 100644 --- a/sys/arcade_video.v +++ b/sys/arcade_video.v @@ -174,15 +174,17 @@ module screen_rotate input rotate_ccw, input no_rotate, + input flip, + output video_rotated, - output FB_EN, - output [4:0] FB_FORMAT, - output [11:0] FB_WIDTH, - output [11:0] FB_HEIGHT, - output [31:0] FB_BASE, - output [13:0] FB_STRIDE, - input FB_VBL, - input FB_LL, + output FB_EN, + output [4:0] FB_FORMAT, + output reg [11:0] FB_WIDTH, + output reg [11:0] FB_HEIGHT, + output [31:0] FB_BASE, + output [13:0] FB_STRIDE, + input FB_VBL, + input FB_LL, output DDRAM_CLK, input DDRAM_BUSY, @@ -196,6 +198,8 @@ module screen_rotate parameter MEM_BASE = 7'b0010010; // buffer at 0x24000000, 3x8MB +reg do_flip; + assign DDRAM_CLK = CLK_VIDEO; assign DDRAM_BURSTCNT = 1; assign DDRAM_ADDR = {MEM_BASE, i_fb, ram_addr[22:3]}; @@ -207,8 +211,6 @@ assign DDRAM_RD = 0; assign FB_EN = fb_en[2]; assign FB_FORMAT = 5'b00110; assign FB_BASE = {MEM_BASE,o_fb,23'd0}; -assign FB_WIDTH = vsz; -assign FB_HEIGHT = hsz; assign FB_STRIDE = stride; function [1:0] buf_next; @@ -220,6 +222,19 @@ function [1:0] buf_next; end endfunction +assign video_rotated = ~no_rotate; + +always @(posedge CLK_VIDEO) begin + do_flip <= no_rotate && flip; + if( do_flip ) begin + FB_WIDTH <= hsz; + FB_HEIGHT <= vsz; + end else begin + FB_WIDTH <= vsz; + FB_HEIGHT <= hsz; + end +end + reg [1:0] i_fb,o_fb; always @(posedge CLK_VIDEO) begin reg old_vbl,old_vs; @@ -251,20 +266,23 @@ always @(posedge CLK_VIDEO) begin if(CE_PIXEL) begin old_vs <= VGA_VS; old_de <= VGA_DE; - + hcnt <= hcnt + 1'd1; if(~old_de & VGA_DE) begin hcnt <= 1; vcnt <= vcnt + 1'd1; end - if(old_de & ~VGA_DE) hsz <= hcnt; + if(old_de & ~VGA_DE) begin + hsz <= hcnt; + if( do_flip ) bwidth <= hcnt + 2'd3; + end if(~old_vs & VGA_VS) begin vsz <= vcnt; - bwidth <= vcnt + 2'd3; + if( !do_flip ) bwidth <= vcnt + 2'd3; vcnt <= 0; - fb_en <= {fb_en[1:0], ~no_rotate}; + fb_en <= {fb_en[1:0], ~no_rotate | flip}; end - if(old_vs & ~VGA_VS) bufsize <= hsz * stride; + if(old_vs & ~VGA_VS) bufsize <= (do_flip ? vsz : hsz ) * stride; end end @@ -278,21 +296,25 @@ always @(posedge CLK_VIDEO) begin reg old_vs, old_de; ram_wr <= 0; - if(CE_PIXEL) begin + if(CE_PIXEL && FB_EN) begin old_vs <= VGA_VS; old_de <= VGA_DE; if(~old_vs & VGA_VS) begin - next_addr <= rotate_ccw ? (bufsize - stride) : {vsz-1'd1, 2'b00}; + next_addr <= + do_flip ? bufsize-3'd4 : + rotate_ccw ? (bufsize - stride) : {vsz-1'd1, 2'b00}; hcnt <= rotate_ccw ? 3'd4 : {vsz-2'd2, 2'b00}; end if(VGA_DE) begin ram_wr <= 1; - ram_data <= {VGA_B,VGA_G,VGA_R}; + ram_data <= {8'd0,VGA_B,VGA_G,VGA_R}; ram_addr <= next_addr; - next_addr <= rotate_ccw ? (next_addr - stride) : (next_addr + stride); + next_addr <= + do_flip ? next_addr-3'd4 : + rotate_ccw ? (next_addr - stride) : (next_addr + stride); end - if(old_de & ~VGA_DE) begin + if(old_de & ~VGA_DE & ~do_flip) begin next_addr <= rotate_ccw ? (bufsize - stride + hcnt) : hcnt; hcnt <= rotate_ccw ? (hcnt + 3'd4) : (hcnt - 3'd4); end diff --git a/sys/ascal.vhd b/sys/ascal.vhd index f157e9f..f3e5370 100644 --- a/sys/ascal.vhd +++ b/sys/ascal.vhd @@ -112,2466 +112,2803 @@ USE ieee.numeric_std.ALL; -- N_BURST : Burst size in bytes. Power of two. ENTITY ascal IS - GENERIC ( - MASK : unsigned(7 DOWNTO 0) :=x"FF"; - RAMBASE : unsigned(31 DOWNTO 0); - RAMSIZE : unsigned(31 DOWNTO 0) := x"0080_0000"; -- =8MB - INTER : boolean := true; - HEADER : boolean := true; - DOWNSCALE : boolean := true; - BYTESWAP : boolean := true; - PALETTE : boolean := true; - PALETTE2 : boolean := true; - FRAC : natural RANGE 4 TO 6 :=4; - OHRES : natural RANGE 1 TO 4096 :=2048; - IHRES : natural RANGE 1 TO 2048 :=2048; - N_DW : natural RANGE 64 TO 128 := 128; - N_AW : natural RANGE 8 TO 32 := 32; - N_BURST : natural := 256 -- 256 bytes per burst - ); - PORT ( - ------------------------------------ - -- Input video - i_r : IN unsigned(7 DOWNTO 0); - i_g : IN unsigned(7 DOWNTO 0); - i_b : IN unsigned(7 DOWNTO 0); - i_hs : IN std_logic; -- H sync - i_vs : IN std_logic; -- V sync - i_fl : IN std_logic; -- Interlaced field - i_de : IN std_logic; -- Display Enable - i_ce : IN std_logic; -- Clock Enable - i_clk : IN std_logic; -- Input clock - - ------------------------------------ - -- Output video - o_r : OUT unsigned(7 DOWNTO 0); - o_g : OUT unsigned(7 DOWNTO 0); - o_b : OUT unsigned(7 DOWNTO 0); - o_hs : OUT std_logic; -- H sync - o_vs : OUT std_logic; -- V sync - o_de : OUT std_logic; -- Display Enable - o_vbl : OUT std_logic; -- V blank - o_ce : IN std_logic; -- Clock Enable - o_clk : IN std_logic; -- Output clock - - -- Border colour R G B - o_border : IN unsigned(23 DOWNTO 0) := x"000000"; - - ------------------------------------ - -- Framebuffer mode - o_fb_ena : IN std_logic :='0'; -- Enable Framebuffer Mode - o_fb_hsize : IN natural RANGE 0 TO 4095 :=0; - o_fb_vsize : IN natural RANGE 0 TO 4095 :=0; - o_fb_format : IN unsigned(5 DOWNTO 0) :="000100"; - o_fb_base : IN unsigned(31 DOWNTO 0) :=x"0000_0000"; - o_fb_stride : IN unsigned(13 DOWNTO 0) :=(OTHERS =>'0'); - - -- Framebuffer palette in 8bpp mode - pal1_clk : IN std_logic :='0'; - pal1_dw : IN unsigned(47 DOWNTO 0) :=x"000000000000"; -- R1 G1 B1 R0 G0 B0 - pal1_dr : OUT unsigned(47 DOWNTO 0) :=x"000000000000"; - pal1_a : IN unsigned(6 DOWNTO 0) :="0000000"; -- Colour index/2 - pal1_wr : IN std_logic :='0'; + GENERIC ( + MASK : unsigned(7 DOWNTO 0) :=x"FF"; + RAMBASE : unsigned(31 DOWNTO 0); + RAMSIZE : unsigned(31 DOWNTO 0) := x"0080_0000"; -- =8MB + INTER : boolean := true; + HEADER : boolean := true; + DOWNSCALE : boolean := true; + BYTESWAP : boolean := true; + PALETTE : boolean := true; + PALETTE2 : boolean := true; + ADAPTIVE : boolean := true; + DOWNSCALE_NN : boolean := false; + FRAC : natural RANGE 4 TO 8 :=4; + OHRES : natural RANGE 1 TO 4096 :=2048; + IHRES : natural RANGE 1 TO 2048 :=2048; + N_DW : natural RANGE 64 TO 128 := 128; + N_AW : natural RANGE 8 TO 32 := 32; + N_BURST : natural := 256 -- 256 bytes per burst + ); + PORT ( + ------------------------------------ + -- Input video + i_r : IN unsigned(7 DOWNTO 0); + i_g : IN unsigned(7 DOWNTO 0); + i_b : IN unsigned(7 DOWNTO 0); + i_hs : IN std_logic; -- H sync + i_vs : IN std_logic; -- V sync + i_fl : IN std_logic; -- Interlaced field + i_de : IN std_logic; -- Display Enable + i_ce : IN std_logic; -- Clock Enable + i_clk : IN std_logic; -- Input clock - pal_n : IN std_logic :='0'; + ------------------------------------ + -- Output video + o_r : OUT unsigned(7 DOWNTO 0); + o_g : OUT unsigned(7 DOWNTO 0); + o_b : OUT unsigned(7 DOWNTO 0); + o_hs : OUT std_logic; -- H sync + o_vs : OUT std_logic; -- V sync + o_de : OUT std_logic; -- Display Enable + o_vbl : OUT std_logic; -- V blank + o_brd : OUT std_logic; -- border enable + o_ce : IN std_logic; -- Clock Enable + o_clk : IN std_logic; -- Output clock - pal2_clk : IN std_logic :='0'; - pal2_dw : IN unsigned(23 DOWNTO 0) :=x"000000"; -- R G B - pal2_dr : OUT unsigned(23 DOWNTO 0) :=x"000000"; - pal2_a : IN unsigned(7 DOWNTO 0) :="00000000"; -- Colour index - pal2_wr : IN std_logic :='0'; - - ------------------------------------ - -- Low lag PLL tuning - o_lltune : OUT unsigned(15 DOWNTO 0); - - ------------------------------------ - -- Input video parameters - iauto : IN std_logic :='1'; -- 1=Autodetect image size 0=Choose window - himin : IN natural RANGE 0 TO 4095 :=0; -- MIN < MAX, MIN >=0, MAX < DISP - himax : IN natural RANGE 0 TO 4095 :=0; - vimin : IN natural RANGE 0 TO 4095 :=0; - vimax : IN natural RANGE 0 TO 4095 :=0; + -- Border colour R G B + o_border : IN unsigned(23 DOWNTO 0) := x"000000"; - -- Detected input image size - i_hdmax : OUT natural RANGE 0 TO 4095; - i_vdmax : OUT natural RANGE 0 TO 4095; - - -- Output video parameters - run : IN std_logic :='1'; -- 1=Enable output image. 0=No image - freeze : IN std_logic :='0'; -- 1=Disable framebuffer writes - mode : IN unsigned(4 DOWNTO 0); - -- SYNC |_________________________/"""""""""\_______| - -- DE |""""""""""""""""""\________________________| - -- RGB | <#IMAGE#> ^HDISP | - -- ^HMIN ^HMAX ^HSSTART ^HSEND ^HTOTAL - htotal : IN natural RANGE 0 TO 4095; - hsstart : IN natural RANGE 0 TO 4095; - hsend : IN natural RANGE 0 TO 4095; - hdisp : IN natural RANGE 0 TO 4095; - hmin : IN natural RANGE 0 TO 4095; - hmax : IN natural RANGE 0 TO 4095; -- 0 <= hmin < hmax < hdisp - vtotal : IN natural RANGE 0 TO 4095; - vsstart : IN natural RANGE 0 TO 4095; - vsend : IN natural RANGE 0 TO 4095; - vdisp : IN natural RANGE 0 TO 4095; - vmin : IN natural RANGE 0 TO 4095; - vmax : IN natural RANGE 0 TO 4095; -- 0 <= vmin < vmax < vdisp - - -- Scaler format. 00=16bpp 565, 01=24bpp 10=32bpp - format : IN unsigned(1 DOWNTO 0) :="01"; - - ------------------------------------ - -- Polyphase filter coefficients - -- Order : - -- [Horizontal] [Vertical] - -- [0]...[2**FRAC-1] - -- [-1][0][1][2] - poly_clk : IN std_logic; - poly_dw : IN unsigned(8 DOWNTO 0); - poly_a : IN unsigned(FRAC+2 DOWNTO 0); - poly_wr : IN std_logic; - - ------------------------------------ - -- Avalon - avl_clk : IN std_logic; -- Avalon clock - avl_waitrequest : IN std_logic; - avl_readdata : IN std_logic_vector(N_DW-1 DOWNTO 0); - avl_readdatavalid : IN std_logic; - avl_burstcount : OUT std_logic_vector(7 DOWNTO 0); - avl_writedata : OUT std_logic_vector(N_DW-1 DOWNTO 0); - avl_address : OUT std_logic_vector(N_AW-1 DOWNTO 0); - avl_write : OUT std_logic; - avl_read : OUT std_logic; - avl_byteenable : OUT std_logic_vector(N_DW/8-1 DOWNTO 0); - - ------------------------------------ - reset_na : IN std_logic - ); + ------------------------------------ + -- Framebuffer mode + o_fb_ena : IN std_logic :='0'; -- Enable Framebuffer Mode + o_fb_hsize : IN natural RANGE 0 TO 4095 :=0; + o_fb_vsize : IN natural RANGE 0 TO 4095 :=0; + o_fb_format : IN unsigned(5 DOWNTO 0) :="000100"; + o_fb_base : IN unsigned(31 DOWNTO 0) :=x"0000_0000"; + o_fb_stride : IN unsigned(13 DOWNTO 0) :=(OTHERS =>'0'); + + -- Framebuffer palette in 8bpp mode + pal1_clk : IN std_logic :='0'; + pal1_dw : IN unsigned(47 DOWNTO 0) :=x"000000000000"; -- R1 G1 B1 R0 G0 B0 + pal1_dr : OUT unsigned(47 DOWNTO 0) :=x"000000000000"; + pal1_a : IN unsigned(6 DOWNTO 0) :="0000000"; -- Colour index/2 + pal1_wr : IN std_logic :='0'; + + pal_n : IN std_logic :='0'; + + pal2_clk : IN std_logic :='0'; + pal2_dw : IN unsigned(23 DOWNTO 0) :=x"000000"; -- R G B + pal2_dr : OUT unsigned(23 DOWNTO 0) :=x"000000"; + pal2_a : IN unsigned(7 DOWNTO 0) :="00000000"; -- Colour index + pal2_wr : IN std_logic :='0'; + + ------------------------------------ + -- Low lag PLL tuning + o_lltune : OUT unsigned(15 DOWNTO 0); + + ------------------------------------ + -- Input video parameters + iauto : IN std_logic :='1'; -- 1=Autodetect image size 0=Choose window + himin : IN natural RANGE 0 TO 4095 :=0; -- MIN < MAX, MIN >=0, MAX < DISP + himax : IN natural RANGE 0 TO 4095 :=0; + vimin : IN natural RANGE 0 TO 4095 :=0; + vimax : IN natural RANGE 0 TO 4095 :=0; + + -- Detected input image size + i_hdmax : OUT natural RANGE 0 TO 4095; + i_vdmax : OUT natural RANGE 0 TO 4095; + + -- Output video parameters + run : IN std_logic :='1'; -- 1=Enable output image. 0=No image + freeze : IN std_logic :='0'; -- 1=Disable framebuffer writes + mode : IN unsigned(4 DOWNTO 0); + -- SYNC |_________________________/"""""""""\_______| + -- DE |""""""""""""""""""\________________________| + -- RGB | <#IMAGE#> ^HDISP | + -- ^HMIN ^HMAX ^HSSTART ^HSEND ^HTOTAL + htotal : IN natural RANGE 0 TO 4095; + hsstart : IN natural RANGE 0 TO 4095; + hsend : IN natural RANGE 0 TO 4095; + hdisp : IN natural RANGE 0 TO 4095; + hmin : IN natural RANGE 0 TO 4095; + hmax : IN natural RANGE 0 TO 4095; -- 0 <= hmin < hmax < hdisp + vtotal : IN natural RANGE 0 TO 4095; + vsstart : IN natural RANGE 0 TO 4095; + vsend : IN natural RANGE 0 TO 4095; + vdisp : IN natural RANGE 0 TO 4095; + vmin : IN natural RANGE 0 TO 4095; + vmax : IN natural RANGE 0 TO 4095; -- 0 <= vmin < vmax < vdisp + vrr : IN std_logic := '0'; + vrrmax : IN natural RANGE 0 TO 4095 := 0; + + -- Scaler format. 00=16bpp 565, 01=24bpp 10=32bpp + format : IN unsigned(1 DOWNTO 0) :="01"; + + ------------------------------------ + -- Polyphase filter coefficients + -- Order : + -- [Horizontal] [Vertical] [Horizontal2] [Vertical2] + -- [0]...[2**FRAC-1] + -- [-1][0][1][2] + poly_clk : IN std_logic; + poly_dw : IN unsigned(9 DOWNTO 0); + poly_a : IN unsigned(FRAC+3 DOWNTO 0); + poly_wr : IN std_logic; + + ------------------------------------ + -- Avalon + avl_clk : IN std_logic; -- Avalon clock + avl_waitrequest : IN std_logic; + avl_readdata : IN std_logic_vector(N_DW-1 DOWNTO 0); + avl_readdatavalid : IN std_logic; + avl_burstcount : OUT std_logic_vector(7 DOWNTO 0); + avl_writedata : OUT std_logic_vector(N_DW-1 DOWNTO 0); + avl_address : OUT std_logic_vector(N_AW-1 DOWNTO 0); + avl_write : OUT std_logic; + avl_read : OUT std_logic; + avl_byteenable : OUT std_logic_vector(N_DW/8-1 DOWNTO 0); + + ------------------------------------ + reset_na : IN std_logic + ); BEGIN - ASSERT N_DW=64 OR N_DW=128 REPORT "DW" SEVERITY failure; - + ASSERT N_DW=64 OR N_DW=128 REPORT "DW" SEVERITY failure; + END ENTITY ascal; --############################################################################## ARCHITECTURE rtl OF ascal IS - - CONSTANT MASK_NEAREST : natural :=0; - CONSTANT MASK_BILINEAR : natural :=1; - CONSTANT MASK_SHARP_BILINEAR : natural :=2; - CONSTANT MASK_BICUBIC : natural :=3; - CONSTANT MASK_POLY : natural :=4; - - ---------------------------------------------------------- - FUNCTION ilog2 (CONSTANT v : natural) RETURN natural IS - VARIABLE r : natural := 1; - VARIABLE n : natural := 0; - BEGIN - WHILE v>r LOOP - n:=n+1; - r:=r*2; - END LOOP; - RETURN n; - END FUNCTION ilog2; - FUNCTION to_std_logic (a : boolean) RETURN std_logic IS - BEGIN - IF a THEN RETURN '1'; - ELSE RETURN '0'; - END IF; - END FUNCTION to_std_logic; - - ---------------------------------------------------------- - CONSTANT NB_BURST : natural :=ilog2(N_BURST); - CONSTANT NB_LA : natural :=ilog2(N_DW/8); -- Low address bits - CONSTANT BLEN : natural :=N_BURST / N_DW * 8; -- Burst length - - ---------------------------------------------------------- - TYPE arr_dw IS ARRAY (natural RANGE <>) OF unsigned(N_DW-1 DOWNTO 0); - - TYPE type_pix IS RECORD - r,g,b : unsigned(7 DOWNTO 0); -- 0.8 - END RECORD; - TYPE arr_pix IS ARRAY (natural RANGE <>) OF type_pix; - ATTRIBUTE ramstyle : string; - - SUBTYPE uint12 IS natural RANGE 0 TO 4095; - SUBTYPE uint13 IS natural RANGE 0 TO 8191; - - TYPE arr_uv48 IS ARRAY (natural RANGE <>) OF unsigned(47 DOWNTO 0); - TYPE arr_uv24 IS ARRAY (natural RANGE <>) OF unsigned(23 DOWNTO 0); - TYPE arr_uv36 IS ARRAY (natural RANGE <>) OF unsigned(35 DOWNTO 0); - TYPE arr_int9 IS ARRAY (natural RANGE <>) OF integer RANGE -256 TO 255; - TYPE arr_uint12 IS ARRAY (natural RANGE <>) OF uint12; - ---------------------------------------------------------- - -- Input image - SIGNAL i_pvs,i_pfl,i_pde,i_pce : std_logic; - SIGNAL i_ppix : type_pix; - SIGNAL i_freeze : std_logic; - SIGNAL i_count : unsigned(2 DOWNTO 0); - SIGNAL i_hsize,i_hmin,i_hmax,i_hcpt : uint12; - SIGNAL i_hrsize,i_vrsize : uint12; - SIGNAL i_himax,i_vimax : uint12; - SIGNAL i_vsize,i_vmaxmin,i_vmin,i_vmax,i_vcpt : uint12; - SIGNAL i_iauto : std_logic; - SIGNAL i_mode : unsigned(4 DOWNTO 0); - SIGNAL i_format : unsigned(1 DOWNTO 0); - SIGNAL i_ven,i_sof : std_logic; - SIGNAL i_wr : std_logic; - SIGNAL i_divstart,i_divrun : std_logic; - SIGNAL i_de_pre,i_vs_pre,i_fl_pre : std_logic; - SIGNAL i_de_delay : natural RANGE 0 TO 31; - SIGNAL i_intercnt : natural RANGE 0 TO 3; - SIGNAL i_inter,i_half,i_flm : std_logic; - SIGNAL i_write,i_wreq,i_alt,i_line,i_wline,i_wline_mem : std_logic; - SIGNAL i_walt,i_walt_mem,i_wreq_mem : std_logic; - SIGNAL i_wdelay : natural RANGE 0 TO 7; - SIGNAL i_push,i_pushend,i_pushend2 : std_logic; - SIGNAL i_eol : std_logic; - SIGNAL i_pushhead,i_pushhead2,i_pushhead3 : std_logic; - SIGNAL i_hburst,i_hbcpt : natural RANGE 0 TO 31; - SIGNAL i_shift : unsigned(0 TO 119) := (OTHERS =>'0'); - SIGNAL i_head : unsigned(127 DOWNTO 0); - SIGNAL i_acpt : natural RANGE 0 TO 15; - SIGNAL i_dpram : arr_dw(0 TO BLEN*2-1); - ATTRIBUTE ramstyle OF i_dpram : SIGNAL IS "no_rw_check"; - SIGNAL i_endframe0,i_endframe1,i_vss : std_logic; - SIGNAL i_wad : natural RANGE 0 TO BLEN*2-1; - SIGNAL i_dw : unsigned(N_DW-1 DOWNTO 0); - SIGNAL i_adrs,i_adrsi,i_wadrs,i_wadrs_mem : unsigned(31 DOWNTO 0); - SIGNAL i_reset_na : std_logic; - SIGNAL i_hnp,i_vnp : std_logic; - SIGNAL i_mem : arr_pix(0 TO IHRES-1); -- Downscale line buffer - ATTRIBUTE ramstyle OF i_mem : SIGNAL IS "no_rw_check"; - SIGNAL i_ohsize,i_ovsize : uint12; - SIGNAL i_vdivi : unsigned(12 DOWNTO 0); - SIGNAL i_vdivr : unsigned(24 DOWNTO 0); - SIGNAL i_div : unsigned(16 DOWNTO 0); - SIGNAL i_dir : unsigned(11 DOWNTO 0); - SIGNAL i_h_frac,i_v_frac : unsigned(11 DOWNTO 0); - SIGNAL i_hacc,i_vacc : uint13; - SIGNAL i_hdown,i_vdown : std_logic; - SIGNAL i_divcpt : natural RANGE 0 TO 36; - SIGNAL i_lwad,i_lrad : natural RANGE 0 TO OHRES-1; - SIGNAL i_lwr,i_bil : std_logic; - SIGNAL i_ldw,i_ldrm : type_pix; - SIGNAL i_hpixp,i_hpix0,i_hpix1,i_hpix2,i_hpix3,i_hpix4 : type_pix; - SIGNAL i_hpix,i_pix : type_pix; - SIGNAL i_hnp1,i_hnp2,i_hnp3,i_hnp4 : std_logic; - SIGNAL i_ven1,i_ven2,i_ven3,i_ven4,i_ven5,i_ven6 : std_logic; - - ---------------------------------------------------------- - -- Avalon - TYPE type_avl_state IS (sIDLE,sWRITE,sREAD); - SIGNAL avl_state : type_avl_state; - SIGNAL avl_write_i,avl_write_sync,avl_write_sync2 : std_logic; - SIGNAL avl_read_i,avl_read_sync,avl_read_sync2 : std_logic; - SIGNAL avl_read_pulse,avl_write_pulse : std_logic; - SIGNAL avl_read_sr,avl_write_sr,avl_read_clr,avl_write_clr : std_logic; - SIGNAL avl_rad,avl_rad_c,avl_wad : natural RANGE 0 TO 2*BLEN-1; - SIGNAL avl_walt,avl_wline,avl_rline : std_logic; - SIGNAL avl_dw,avl_dr : unsigned(N_DW-1 DOWNTO 0); - SIGNAL avl_wr : std_logic; - SIGNAL avl_readdataack,avl_readack : std_logic; - SIGNAL avl_radrs,avl_wadrs : unsigned(31 DOWNTO 0); - SIGNAL avl_i_offset0,avl_o_offset0 : unsigned(31 DOWNTO 0); - SIGNAL avl_i_offset1,avl_o_offset1 : unsigned(31 DOWNTO 0); - SIGNAL avl_reset_na : std_logic; - SIGNAL avl_o_vs_sync,avl_o_vs : std_logic; - SIGNAL avl_fb_ena : std_logic; - - FUNCTION buf_next(a,b : natural RANGE 0 TO 2; freeze : std_logic := '0') RETURN natural IS - BEGIN - IF (freeze='1') THEN RETURN a; END IF; - IF (a=0 AND b=1) OR (a=1 AND b=0) THEN RETURN 2; END IF; - IF (a=1 AND b=2) OR (a=2 AND b=1) THEN RETURN 0; END IF; - RETURN 1; - END FUNCTION; - FUNCTION buf_offset(b : natural RANGE 0 TO 2; - base : unsigned(31 DOWNTO 0); - size : unsigned(31 DOWNTO 0)) RETURN unsigned IS - BEGIN - IF b=1 THEN RETURN base+size; END IF; - IF b=2 THEN RETURN base+(size(30 DOWNTO 0) & '0'); END IF; - RETURN base; - END FUNCTION; - - ---------------------------------------------------------- - -- Output - SIGNAL o_run : std_logic; - SIGNAL o_freeze : std_logic; - SIGNAL o_mode,o_hmode,o_vmode : unsigned(4 DOWNTO 0); - SIGNAL o_format : unsigned(5 DOWNTO 0); - SIGNAL o_fb_pal_dr : unsigned(23 DOWNTO 0); - SIGNAL o_fb_pal_dr2 : unsigned(23 DOWNTO 0); - SIGNAL o_fb_pal_dr_x2 : unsigned(47 DOWNTO 0); - SIGNAL pal_idx: unsigned(7 DOWNTO 0); - SIGNAL pal_idx_lsb: std_logic; - SIGNAL pal1_mem : arr_uv48(0 TO 127); - SIGNAL pal2_mem : arr_uv24(0 TO 255); - ATTRIBUTE ramstyle of pal1_mem : signal is "no_rw_check"; - ATTRIBUTE ramstyle of pal2_mem : signal is "no_rw_check"; - SIGNAL o_htotal,o_hsstart,o_hsend : uint12; - SIGNAL o_hmin,o_hmax,o_hdisp : uint12; - SIGNAL o_hsize,o_vsize : uint12; - SIGNAL o_vtotal,o_vsstart,o_vsend : uint12; - SIGNAL o_vmin,o_vmax,o_vdisp : uint12; - SIGNAL o_divcpt : natural RANGE 0 TO 36; - SIGNAL o_iendframe0,o_iendframe02,o_iendframe1,o_iendframe12 : std_logic; - SIGNAL o_bufup0,o_bufup1,o_inter : std_logic; - SIGNAL o_ibuf0,o_ibuf1,o_obuf0,o_obuf1 : natural RANGE 0 TO 2; - TYPE enum_o_state IS (sDISP,sHSYNC,sREAD,sWAITREAD); - SIGNAL o_state : enum_o_state; - TYPE enum_o_copy IS (sWAIT,sSHIFT,sCOPY); - SIGNAL o_copy : enum_o_copy; - SIGNAL o_pshift : natural RANGE 0 TO 15; - SIGNAL o_readack,o_readack_sync,o_readack_sync2 : std_logic; - 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**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; - SIGNAL o_adturn : std_logic; - SIGNAL o_dr : unsigned(N_DW-1 DOWNTO 0); - SIGNAL o_shift : unsigned(0 TO N_DW+15); - SIGNAL o_sh,o_sh1,o_sh2,o_sh3,o_sh4 : std_logic; - SIGNAL o_reset_na : std_logic; - SIGNAL o_dpram : arr_dw(0 TO BLEN*2-1); - ATTRIBUTE ramstyle OF o_dpram : SIGNAL IS "no_rw_check"; - SIGNAL o_line0,o_line1,o_line2,o_line3 : arr_pix(0 TO OHRES-1); - ATTRIBUTE ramstyle OF o_line0 : SIGNAL IS "no_rw_check"; - ATTRIBUTE ramstyle OF o_line1 : SIGNAL IS "no_rw_check"; - ATTRIBUTE ramstyle OF o_line2 : SIGNAL IS "no_rw_check"; - ATTRIBUTE ramstyle OF o_line3 : SIGNAL IS "no_rw_check"; - SIGNAL o_wadl,o_radl : natural RANGE 0 TO OHRES-1; - SIGNAL o_ldw,o_ldr0,o_ldr1,o_ldr2,o_ldr3 : type_pix; - SIGNAL o_wr : unsigned(3 DOWNTO 0); - SIGNAL o_hcpt,o_vcpt,o_vcpt_pre,o_vcpt_pre2,o_vcpt_pre3 : uint12; - SIGNAL o_ihsize,o_ihsizem,o_ivsize : uint12; - SIGNAL o_ihsize_temp, o_ihsize_temp2 : natural RANGE 0 TO 32767; + CONSTANT MASK_NEAREST : natural :=0; + CONSTANT MASK_BILINEAR : natural :=1; + CONSTANT MASK_SHARP_BILINEAR : natural :=2; + CONSTANT MASK_BICUBIC : natural :=3; + CONSTANT MASK_POLY : natural :=4; - SIGNAL o_vfrac,o_hfrac,o_hfrac1,o_hfrac2,o_hfrac3,o_hfrac4 : unsigned(11 DOWNTO 0); - SIGNAL o_hacc,o_hacc_ini,o_hacc_next,o_vacc,o_vacc_next,o_vacc_ini : natural RANGE 0 TO 4*OHRES-1; - SIGNAL o_hsv,o_vsv,o_dev,o_pev,o_end : unsigned(0 TO 5); - SIGNAL o_hsp,o_vss : std_logic; - SIGNAL o_read,o_read_pre : std_logic; - SIGNAL o_readlev,o_copylev : natural RANGE 0 TO 2; - SIGNAL o_hburst,o_hbcpt : natural RANGE 0 TO 31; - SIGNAL o_fload : natural RANGE 0 TO 3; - SIGNAL o_acpt,o_acpt1,o_acpt2,o_acpt3,o_acpt4 : natural RANGE 0 TO 15; -- Alternance pixels FIFO - SIGNAL o_dshi : natural RANGE 0 TO 3; - SIGNAL o_first,o_last,o_last1,o_last2 : std_logic; - SIGNAL o_lastt1,o_lastt2,o_lastt3,o_lastt4 : std_logic; - SIGNAL o_alt,o_altx : unsigned(3 DOWNTO 0); - SIGNAL o_hdown,o_vdown : std_logic; - SIGNAL o_primv,o_lastv,o_bibv : unsigned(0 TO 2); - TYPE arr_uint4 IS ARRAY (natural RANGE <>) OF natural RANGE 0 TO 15; - SIGNAL o_off : arr_uint4(0 TO 2); - SIGNAL o_bibu : std_logic :='0'; - SIGNAL o_dcptv : arr_uint12(1 TO 8); - SIGNAL o_dcpt : uint12; - SIGNAL o_hpixs,o_hpix0,o_hpix1,o_hpix2,o_hpix3 : type_pix; - SIGNAL o_hpixq,o_vpixq,o_vpixq1 : arr_pix(0 TO 3); - - SIGNAL o_vpe : std_logic; - SIGNAL o_div,o_div2 : unsigned(18 DOWNTO 0); --uint12; - SIGNAL o_dir,o_dir2 : unsigned(11 DOWNTO 0); - SIGNAL o_vdivi : unsigned(12 DOWNTO 0); - SIGNAL o_vdivr : unsigned(24 DOWNTO 0); - SIGNAL o_divstart : std_logic; - SIGNAL o_divrun : std_logic; - SIGNAL o_hacpt,o_vacpt : unsigned(11 DOWNTO 0); - - ----------------------------------------------------------------------------- - FUNCTION shift_ishift(shift : unsigned(0 TO 119); - pix : type_pix; - format : unsigned(1 DOWNTO 0)) RETURN unsigned IS - BEGIN - CASE format IS - WHEN "01" => -- 24bpp - RETURN shift(24 TO 119) & pix.r & pix.g & pix.b; - WHEN "10" => -- 32bpp - RETURN shift(32 TO 119) & pix.r & pix.g & pix.b & x"00"; - WHEN OTHERS => -- 16bpp 565 - RETURN shift(16 TO 119) & - pix.g(4 DOWNTO 2) & pix.r(7 DOWNTO 3) & - pix.b(7 DOWNTO 3) & pix.g(7 DOWNTO 5); - END CASE; - END FUNCTION; - - FUNCTION shift_ipack(i_dw : unsigned(N_DW-1 DOWNTO 0); - acpt : natural RANGE 0 TO 15; - shift : unsigned(0 TO 119); - pix : type_pix; - format : unsigned(1 DOWNTO 0)) RETURN unsigned IS - VARIABLE dw : unsigned(N_DW-1 DOWNTO 0); - BEGIN - dw:=i_dw; - CASE format IS - WHEN "01" => -- 24bpp - IF N_DW=128 THEN - IF acpt=5 THEN dw:=shift(0 TO 119) & pix.r; - ELSIF acpt=10 THEN dw:=shift(8 TO 119) & pix.r & pix.g; - ELSIF acpt=15 THEN dw:=shift(16 TO 119) & pix.r & pix.g & pix.b; - END IF; - ELSE -- N_DW=64 - IF (acpt MOD 8)=2 THEN dw:=shift(72 TO 119) & pix.r & pix.g; - ELSIF (acpt MOD 8)=5 THEN dw:=shift(64 TO 119) & pix.r; - ELSIF (acpt MOD 8)=7 THEN dw:=shift(80 TO 119) & pix.r & pix.g & pix.b; - END IF; - END IF; - WHEN "10" => -- 32bpp - IF (N_DW=128 AND (acpt MOD 4)=3) OR (N_DW=64 AND (acpt MOD 8)=7) THEN - dw:=shift(128-N_DW+24 TO 119) & pix.r & pix.g & pix.b & x"00"; - END IF; - WHEN OTHERS => -- 16bpp 565 - IF (N_DW=128 AND (acpt MOD 8)=7) OR (N_DW=64 AND (acpt MOD 4)=3) THEN - dw:=shift(128-N_DW+8 TO 119) & pix.g(4 DOWNTO 2) & pix.r(7 DOWNTO 3) & - pix.b(7 DOWNTO 3) & pix.g(7 DOWNTO 5); - END IF; - END CASE; - RETURN dw; - END FUNCTION; - - FUNCTION shift_inext (acpt : natural RANGE 0 TO 15; - format : unsigned(1 DOWNTO 0)) RETURN boolean IS - BEGIN - CASE format IS - WHEN "01" => -- 24bpp - RETURN (N_DW=128 AND (acpt=5 OR acpt=10 OR acpt=15)) OR - (N_DW=64 AND ((acpt MOD 8)=2 OR (acpt MOD 8)=5 OR (acpt MOD 8)=7)); - WHEN "10" => -- 32bpp - RETURN (N_DW=128 AND ((acpt MOD 4)=3)) OR - (N_DW=64 AND ((acpt MOD 2)=1)); - WHEN OTHERS => -- 16bpp - RETURN (N_DW=128 AND ((acpt MOD 8)=7)) OR - (N_DW=64 AND ((acpt MOD 4)=3)); - END CASE; - END FUNCTION; - - FUNCTION shift_opack(acpt : natural RANGE 0 TO 15; - shift : unsigned(0 TO N_DW+15); - dr : unsigned(N_DW-1 DOWNTO 0); - format : unsigned(5 DOWNTO 0)) RETURN unsigned IS - VARIABLE shift_v : unsigned(0 TO N_DW+15); - BEGIN - CASE format(2 DOWNTO 0) IS - WHEN "011" => -- 8bpp - IF (N_DW=128 AND acpt=0) OR (N_DW=64 AND (acpt MOD 8)=0) THEN - shift_v:=dr & dr(15 DOWNTO 0); - ELSE - shift_v:=shift(8 TO N_DW+15) & dr(7 DOWNTO 0); - END IF; - - WHEN "100" => -- 16bpp - IF (N_DW=128 AND (acpt MOD 8)=0) OR (N_DW=64 AND (acpt MOD 4)=0) THEN - shift_v:=dr & dr(15 DOWNTO 0); - ELSE - shift_v:=shift(16 TO N_DW+15) & dr(15 DOWNTO 0); - END IF; - - WHEN "101" => -- 24bpp - IF N_DW=128 THEN - IF acpt=0 THEN - shift_v:=dr & dr(15 DOWNTO 0); - ELSIF acpt=5 THEN - shift_v:=shift(24 TO 31) & dr & dr(7 DOWNTO 0); - ELSIF acpt=10 THEN - shift_v:=shift(24 TO 39) & dr; - ELSE - shift_v:=shift(24 TO N_DW+15) & dr(23 DOWNTO 0); - END IF; - ELSE -- N_DW=64 - IF (acpt MOD 8)=0 THEN - shift_v:=dr & dr(15 DOWNTO 0); - ELSIF (acpt MOD 8)=2 THEN - shift_v:=shift(24 TO 39) & dr; - ELSIF (acpt MOD 8)=5 THEN - shift_v:=shift(24 TO 31) & dr & dr(7 DOWNTO 0); - ELSE - shift_v:=shift(24 TO N_DW+15) & dr(23 DOWNTO 0); - END IF; - END IF; - WHEN OTHERS => -- 32bpp - IF (N_DW=128 AND (acpt MOD 4)=0) OR (N_DW=64 AND (acpt MOD 2)=0) THEN - shift_v:=dr & dr(15 DOWNTO 0); - ELSE - shift_v:=shift(32 TO N_DW+15) & dr(31 DOWNTO 0); - END IF; - END CASE; - RETURN shift_v; - END FUNCTION; - - FUNCTION shift_onext (acpt : natural RANGE 0 TO 15; - format : unsigned(5 DOWNTO 0)) RETURN boolean IS - BEGIN - CASE format(2 DOWNTO 0) IS - WHEN "011" => -- 8bpp - RETURN (N_DW=128 AND acpt=0) OR - (N_DW=64 AND ((acpt MOD 8)=0)); - WHEN "100" => -- 16bpp - RETURN (N_DW=128 AND ((acpt MOD 8)=0)) OR - (N_DW=64 AND ((acpt MOD 4)=0)); - WHEN "101" => -- 24bpp - RETURN (N_DW=128 AND (acpt=0 OR acpt=5 OR acpt=10)) OR - (N_DW=64 AND ((acpt MOD 8)=0 OR (acpt MOD 8)=2 OR (acpt MOD 8)=5)); - WHEN OTHERS => -- 32bpp - RETURN (N_DW=128 AND ((acpt MOD 4)=0)) OR - (N_DW=64 AND ((acpt MOD 2)=0)); - END CASE; - END FUNCTION; - - FUNCTION shift_opix (shift : unsigned(0 TO N_DW+15); - format : unsigned(5 DOWNTO 0)) RETURN type_pix IS - BEGIN - CASE format(3 DOWNTO 0) IS - WHEN "0100" => -- 16bpp 565 - RETURN (b=>shift(8 TO 12) & shift(8 TO 10), - g=>shift(13 TO 15) & shift(0 TO 2) & shift(13 TO 14), - r=>shift(3 TO 7) & shift(3 TO 5)); - WHEN "1100" => -- 16bpp 1555 - RETURN (b=>shift(9 TO 13) & shift(9 TO 11), - g=>shift(14 TO 15) & shift(0 TO 2) & shift(14 TO 15) & shift(0), - r=>shift(3 TO 7) & shift(3 TO 5)); - WHEN "0101" | "0110" => -- 24bpp / 32bpp - RETURN (r=>shift(0 TO 7),g=>shift(8 TO 15),b=>shift(16 TO 23)); - - WHEN OTHERS => - RETURN (r=>shift(0 TO 7),g=>shift(8 TO 15),b=>shift(16 TO 23)); - - END CASE; - END FUNCTION; - - FUNCTION pixoffset(adrs : unsigned(31 DOWNTO 0); - format : unsigned (5 DOWNTO 0)) RETURN natural IS - BEGIN - CASE format(2 DOWNTO 0) IS - WHEN "011" => -- 8bbp - RETURN to_integer(adrs(NB_LA-1 DOWNTO 0)); - WHEN "100" => -- 16bpp 565 - RETURN to_integer(adrs(NB_LA-1 DOWNTO 1)); - WHEN OTHERS => -- 32bpp - RETURN to_integer(adrs(NB_LA-1 DOWNTO 2)); - END CASE; - END FUNCTION; - - FUNCTION swap(d : unsigned(N_DW-1 DOWNTO 0)) RETURN unsigned IS - VARIABLE e : unsigned(N_DW-1 DOWNTO 0); - BEGIN - IF BYTESWAP THEN - FOR i IN 0 TO N_DW/8-1 LOOP - e(i*8+7 DOWNTO i*8):=d(N_DW-i*8-1 DOWNTO N_DW-i*8-8); - END LOOP; - RETURN e; - ELSE - RETURN d; - END IF; - END FUNCTION swap; - - ----------------------------------------------------------------------------- - FUNCTION altx (a : unsigned(1 DOWNTO 0)) RETURN unsigned IS - BEGIN - CASE a IS - WHEN "00" => RETURN "0001"; - WHEN "01" => RETURN "0010"; - WHEN "10" => RETURN "0100"; - WHEN OTHERS => RETURN "1000"; - END CASE; - END FUNCTION; - - ----------------------------------------------------------------------------- - FUNCTION bound(a : unsigned; - s : natural) RETURN unsigned IS - BEGIN - IF a(a'left)='1' THEN - RETURN x"00"; - ELSIF a(a'left DOWNTO s)/=0 THEN - RETURN x"FF"; - ELSE - RETURN a(s-1 DOWNTO s-8); - END IF; - END FUNCTION bound; - - ----------------------------------------------------------------------------- - -- Nearest - FUNCTION near_frac(f : unsigned) RETURN unsigned IS - VARIABLE x : unsigned(FRAC-1 DOWNTO 0); - BEGIN - x:=(OTHERS =>f(f'left)); - RETURN x; - END FUNCTION; - - SIGNAL o_h_frac2,o_v_frac : unsigned(FRAC-1 DOWNTO 0); - SIGNAL o_h_bil_pix,o_v_bil_pix : type_pix; - - ----------------------------------------------------------------------------- - -- Nearest + Bilinear + Sharp Bilinear - FUNCTION bil_frac(f : unsigned) RETURN unsigned IS - BEGIN - RETURN f(f'left DOWNTO f'left+1-FRAC); - END FUNCTION; - - TYPE type_bil_t IS RECORD - r,g,b : unsigned(8+FRAC DOWNTO 0); - END RECORD; - FUNCTION bil_calc(f : unsigned(FRAC-1 DOWNTO 0); - p : arr_pix(0 TO 3)) RETURN type_bil_t IS - VARIABLE fp,fn : unsigned(FRAC DOWNTO 0); - VARIABLE u : unsigned(8+FRAC DOWNTO 0); - VARIABLE x : type_bil_t; - CONSTANT Z : unsigned(FRAC-1 DOWNTO 0):=(OTHERS =>'0'); - BEGIN - fp:='0' & f; - fn:=('1' & Z) - fp; - u:=p(2).r * fp + p(1).r * fn; - x.r:=u; - u:=p(2).g * fp + p(1).g * fn; - x.g:=u; - u:=p(2).b * fp + p(1).b * fn; - x.b:=u; - RETURN x; - END FUNCTION; - SIGNAL o_h_bil_t,o_v_bil_t : type_bil_t; - SIGNAL i_h_bil_t : type_bil_t; - - ----------------------------------------------------------------------------- - -- Sharp Bilinear - -- <0.5 : x*x*x*4 - -- >0.5 : 1 - (1-x)*(1-x)*(1-x)*4 - - TYPE type_sbil_tt IS RECORD - f : unsigned(FRAC-1 DOWNTO 0); - s : unsigned(FRAC-1 DOWNTO 0); - END RECORD; - - SIGNAL o_h_sbil_t,o_v_sbil_t : type_sbil_tt; - - FUNCTION sbil_frac1(f : unsigned(11 DOWNTO 0)) RETURN type_sbil_tt IS - VARIABLE u : unsigned(FRAC-1 DOWNTO 0); - VARIABLE v : unsigned(2*FRAC-1 DOWNTO 0); - VARIABLE x : type_sbil_tt; - BEGIN - IF f(11)='0' THEN - u:=f(11 DOWNTO 12-FRAC); - ELSE - u:=NOT f(11 DOWNTO 12-FRAC); - END IF; - v:=u*u; - x.f:=u; - x.s:=v(2*FRAC-2 DOWNTO FRAC-1); - RETURN x; - END FUNCTION; - - FUNCTION sbil_frac2(f : unsigned(11 DOWNTO 0); - t : type_sbil_tt) RETURN unsigned IS - VARIABLE v : unsigned(2*FRAC-1 DOWNTO 0); - BEGIN - v:=t.f*t.s; - IF f(11)='0' THEN - RETURN v(2*FRAC-2 DOWNTO FRAC-1); - ELSE - RETURN NOT v(2*FRAC-2 DOWNTO FRAC-1); - END IF; - END FUNCTION; - - ----------------------------------------------------------------------------- - -- Bicubic - TYPE type_bic_abcd IS RECORD - a : unsigned(7 DOWNTO 0); -- 0.8 - b : signed(8 DOWNTO 0); -- 0.9 - c : signed(11 DOWNTO 0); -- 3.9 - d : signed(10 DOWNTO 0); -- 2.9 - xx : signed(8 DOWNTO 0); -- X.X 1.8 - END RECORD; - TYPE type_bic_pix_abcd IS RECORD - r,g,b : type_bic_abcd; - END RECORD; - TYPE type_bic_tt1 IS RECORD -- Intermediate result - r_bx,g_bx,b_bx : signed(8 DOWNTO 0); -- B.X 1.8 - r_cxx,g_cxx,b_cxx : signed(11 DOWNTO 0); -- C.XX 3.9 - r_dxx,g_dxx,b_dxx : signed(10 DOWNTO 0); -- D.XX 2.9 - END RECORD; - TYPE type_bic_tt2 IS RECORD -- Intermediate result - r_abxcxx,g_abxcxx,b_abxcxx : signed(9 DOWNTO 0); -- A + B.X + C.XX 2.8 - r_dxxx,g_dxxx,b_dxxx : signed(9 DOWNTO 0); -- D.X.X.X 2.8 - END RECORD; - - ---------------------------------------------------------- - -- Y = A + B.X + C.X.X + D.X.X.X = A + X.(B + X.(C + X.D)) - -- A = Y(0) 0 .. 1 unsigned - -- B = Y(1)/2 - Y(-1)/2 -1/2 .. +1/2 signed - -- C = Y(-1) - 5*Y(0)/2 + 2*Y(1) - Y(2)/2 -3 .. +3 signed - -- D = -Y(-1)/2 + 3*Y(0)/2 - 3*Y(1)/2 + Y(2)/2 -2 .. +2 signed - - FUNCTION bic_calc0(f : unsigned(11 DOWNTO 0); - pm,p0,p1,p2 : unsigned(7 DOWNTO 0)) RETURN type_bic_abcd IS - VARIABLE xx : signed(2*FRAC+1 DOWNTO 0); -- 2.(2*FRAC) - BEGIN - xx := signed('0' & f(11 DOWNTO 12-FRAC)) * - signed('0' & f(11 DOWNTO 12-FRAC)); -- 2.(2*FRAC) - RETURN type_bic_abcd'( - a=>p0,-- 0.8 - b=>signed(('0' & p1) - ('0' & pm)), -- 0.9 - c=>signed(("000" & pm & '0') - ("00" & p0 & "00") - ("0000" & p0) + - ("00" & p1 & "00") - ("0000" & p2)), -- 3.9 - d=>signed(("00" & p0 & '0') - ("00" & p1 & '0') - ("000" & p1) + - ("000" & p0) + ("000" & p2) - ("000" & pm)), -- 2.9 - xx=>xx(2*FRAC DOWNTO 2*FRAC-8)); -- 1.8 - END FUNCTION; - FUNCTION bic_calc0(f : unsigned(11 DOWNTO 0); - p : arr_pix(0 TO 3)) RETURN type_bic_pix_abcd IS - BEGIN - RETURN type_bic_pix_abcd'(r=>bic_calc0(f,p(0).r,p(1).r,p(2).r,p(3).r), - g=>bic_calc0(f,p(0).g,p(1).g,p(2).g,p(3).g), - b=>bic_calc0(f,p(0).b,p(1).b,p(2).b,p(3).b)); - END FUNCTION; - - ---------------------------------------------------------- - -- Calc : B.X, C.XX, D.XX - FUNCTION bic_calc1(f : unsigned(11 DOWNTO 0); - abcd : type_bic_pix_abcd) RETURN type_bic_tt1 IS - VARIABLE t : type_bic_tt1; - VARIABLE bx : signed(9+FRAC DOWNTO 0); -- 1.(FRAC+9) - VARIABLE cxx : signed(20 DOWNTO 0); -- 4.17 - VARIABLE dxx : signed(19 DOWNTO 0); -- 3.17 - BEGIN - bx := abcd.r.b * signed('0' & f(11 DOWNTO 12-FRAC)); -- 1.(FRAC+9) - t.r_bx:=bx(9+FRAC DOWNTO 9+FRAC-8); -- 1.8 - cxx:= abcd.r.c * abcd.r.xx; -- 3.9 * 1.8 = 4.17 - t.r_cxx:=cxx(19 DOWNTO 8); -- 3.9 - dxx:= abcd.r.d * abcd.r.xx; -- 2.9 * 1.8 = 3.17 - t.r_dxx:=dxx(18 DOWNTO 8); -- 2.9 - bx := abcd.g.b * signed('0' & f(11 DOWNTO 12-FRAC)); -- 1.(FRAC+9) - t.g_bx:=bx(9+FRAC DOWNTO 9+FRAC-8); -- 1.8 - cxx:= abcd.g.c * abcd.g.xx; -- 3.9 * 1.8 = 4.17 - t.g_cxx:=cxx(19 DOWNTO 8); -- 3.9 - dxx:= abcd.g.d * abcd.g.xx; -- 2.9 * 1.8 = 3.17 - t.g_dxx:=dxx(18 DOWNTO 8); -- 2.9 - bx := abcd.b.b * signed('0' & f(11 DOWNTO 12-FRAC)); -- 1.(FRAC+9) - t.b_bx:=bx(9+FRAC DOWNTO 9+FRAC-8); -- 1.8 - cxx:= abcd.b.c * abcd.b.xx; -- 3.9 * 1.8 = 4.17 - t.b_cxx:=cxx(19 DOWNTO 8); -- 3.9 - dxx:= abcd.b.d * abcd.b.xx; -- 2.9 * 1.8 = 3.17 - t.b_dxx:=dxx(18 DOWNTO 8); -- 2.9 - RETURN t; - END FUNCTION; - - ---------------------------------------------------------- - -- Calc A + BX + CXX , X.DXX - FUNCTION bic_calc2(f : unsigned(11 DOWNTO 0); - t : type_bic_tt1; - abcd : type_bic_pix_abcd) RETURN type_bic_tt2 IS - VARIABLE u : type_bic_tt2; - VARIABLE x : signed(11+FRAC DOWNTO 0); -- 3.(9+FRAC) - BEGIN - u.r_abxcxx:=(t.r_bx(8) & t.r_bx) + ("00" & signed(abcd.r.a)) + t.r_cxx(10 DOWNTO 1); -- 2.8 - u.g_abxcxx:=(t.g_bx(8) & t.g_bx) + ("00" & signed(abcd.g.a)) + t.g_cxx(10 DOWNTO 1); -- 2.8 - u.b_abxcxx:=(t.b_bx(8) & t.b_bx) + ("00" & signed(abcd.b.a)) + t.b_cxx(10 DOWNTO 1); -- 2.8 + ---------------------------------------------------------- + FUNCTION ilog2 (CONSTANT v : natural) RETURN natural IS + VARIABLE r : natural := 1; + VARIABLE n : natural := 0; + BEGIN + WHILE v>r LOOP + n:=n+1; + r:=r*2; + END LOOP; + RETURN n; + END FUNCTION ilog2; + FUNCTION to_std_logic (a : boolean) RETURN std_logic IS + BEGIN + IF a THEN RETURN '1'; + ELSE RETURN '0'; + END IF; + END FUNCTION to_std_logic; - x:=t.r_dxx * signed('0' & f(11 DOWNTO 12-FRAC)); --2.9 * 1.FRAC =3.(9+FRAC) - u.r_dxxx:=x(10+FRAC DOWNTO 9+FRAC-8); -- 2.8 - x:=t.g_dxx * signed('0' & f(11 DOWNTO 12-FRAC)); --2.9 * 1.FRAC =3.(9+FRAC) - u.g_dxxx:=x(10+FRAC DOWNTO 9+FRAC-8); -- 2.8 - x:=t.b_dxx * signed('0' & f(11 DOWNTO 12-FRAC)); --2.9 * 1.FRAC =3.(9+FRAC) - u.b_dxxx:=x(10+FRAC DOWNTO 9+FRAC-8); -- 2.8 - RETURN u; - END FUNCTION; - - ---------------------------------------------------------- - -- Calc (A + BX + CXX) + (DXXX) - FUNCTION bic_calc3(f : unsigned(11 DOWNTO 0); - t : type_bic_tt2; - abcd : type_bic_pix_abcd) RETURN type_pix IS - VARIABLE x : type_pix; - VARIABLE v : signed(9 DOWNTO 0); -- 2.8 - BEGIN - v:=t.r_abxcxx + t.r_dxxx; - x.r:=bound(unsigned(v),8); - v:=t.g_abxcxx + t.g_dxxx; - x.g:=bound(unsigned(v),8); - v:=t.b_abxcxx + t.b_dxxx; - x.b:=bound(unsigned(v),8); - RETURN x; - END FUNCTION; - - ----------------------------------------------------------------------------- - SIGNAL o_h_bic_pix,o_v_bic_pix : type_pix; - SIGNAL o_h_bic_abcd1,o_h_bic_abcd2 : type_bic_pix_abcd; - SIGNAL o_v_bic_abcd1,o_v_bic_abcd2 : type_bic_pix_abcd; - SIGNAL o_h_bic_tt1,o_v_bic_tt1 : type_bic_tt1; - SIGNAL o_h_bic_tt2,o_v_bic_tt2 : type_bic_tt2; - - ----------------------------------------------------------------------------- - -- Polyphase - - CONSTANT POLY16 : arr_int9 := ( - -24,-21,-15,-9,-5,-1,4,8,6,8,5,4,3,1,0,0, - 176,174,169,160,150,131,115,85,58,27,4,-6,-20,-24,-26,-25, - -24,-25,-26,-24,-20,-6,4,27,58,85,115,131,150,160,169,174, - 0,0,0,1,3,4,5,8,6,8,4,-1,-5,-9,-15,-21); - - CONSTANT POLY32 : arr_int9 := ( - -24,-22,-20,-18,-16,-13,-11,-8,-6,-3,-1,0,2,3,5,5,6,6,6,5,5,4,4,3,2,1,1,0,0,0,0,0, - 176,175,174,172,169,164,160,153,147,138,129,119,109,96,84,71,58,40,22,12,3,-4,-12,-16,-20,-22,-25,-25,-26,-25,-25,-25, - -24,-25,-26,-26,-26,-24,-23,-19,-16,-10,-4,4,11,22,32,45,58,77,96,108,119,129,140,147,154,159,165,168,172,173,175,175, - 0,0,0,0,1,1,2,2,3,3,4,5,6,7,7,7,6,5,4,3,1,-1,-4,-6,-8,-10,-13,-15,-18,-20,-22,-22); - - FUNCTION init_poly RETURN arr_uv36 IS - VARIABLE m : arr_uv36(0 TO 2**FRAC-1) :=(OTHERS =>x"000000000"); - BEGIN - IF FRAC=4 THEN - FOR i IN 0 TO 15 LOOP - m(i):=unsigned(to_signed(POLY16(i),9) & to_signed(POLY16(i+16),9) & - to_signed(POLY16(i+32),9) & to_signed(POLY16(i+48),9)); - END LOOP; - ELSIF FRAC=5 THEN - FOR i IN 0 TO 31 LOOP - m(i):=unsigned(to_signed(POLY32(i),9) & to_signed(POLY32(i+32),9) & - to_signed(POLY32(i+64),9) & to_signed(POLY32(i+96),9)); - END LOOP; - END IF; - RETURN m; - END FUNCTION; - - SIGNAL o_h_poly : arr_uv36(0 TO 2**FRAC-1):=init_poly; - SIGNAL o_v_poly : arr_uv36(0 TO 2**FRAC-1):=init_poly; - ATTRIBUTE ramstyle OF o_h_poly : SIGNAL IS "no_rw_check"; - ATTRIBUTE ramstyle OF o_v_poly : SIGNAL IS "no_rw_check"; - SIGNAL o_h_poly_a,o_v_poly_a : integer RANGE 0 TO 2**FRAC-1; - SIGNAL o_h_poly_dr,o_h_poly_dr2,o_v_poly_dr,o_v_poly_dr2 : unsigned(35 DOWNTO 0); - SIGNAL o_h_poly_pix,o_v_poly_pix : type_pix; - SIGNAL poly_h_wr,poly_v_wr : std_logic; - SIGNAL poly_tdw : unsigned(35 DOWNTO 0); - SIGNAL poly_a2 : unsigned(FRAC-1 DOWNTO 0); - - TYPE type_poly_t IS RECORD - r0,r1,b0,b1,g0,g1 : signed(17 DOWNTO 0); - END RECORD; - - SIGNAL o_h_poly_t,o_v_poly_t : type_poly_t; - - FUNCTION poly_calc1(fi : unsigned(35 DOWNTO 0); - p : arr_pix(0 TO 3)) RETURN type_poly_t IS - VARIABLE t : type_poly_t; - BEGIN - -- 2.7 * 1.8 = 3.15 - t.r0:=(signed(fi(35 DOWNTO 27)) * signed('0' & p(0).r) + - signed(fi(26 DOWNTO 18)) * signed('0' & p(1).r)); - t.r1:=(signed(fi(17 DOWNTO 9)) * signed('0' & p(2).r) + - signed(fi( 8 DOWNTO 0)) * signed('0' & p(3).r)); - t.g0:=(signed(fi(35 DOWNTO 27)) * signed('0' & p(0).g) + - signed(fi(26 DOWNTO 18)) * signed('0' & p(1).g)); - t.g1:=(signed(fi(17 DOWNTO 9)) * signed('0' & p(2).g) + - signed(fi( 8 DOWNTO 0)) * signed('0' & p(3).g)); - t.b0:=(signed(fi(35 DOWNTO 27)) * signed('0' & p(0).b) + - signed(fi(26 DOWNTO 18)) * signed('0' & p(1).b)); - t.b1:=(signed(fi(17 DOWNTO 9)) * signed('0' & p(2).b) + - signed(fi( 8 DOWNTO 0)) * signed('0' & p(3).b)); - RETURN t; - END FUNCTION; - - FUNCTION poly_calc2(t : type_poly_t) RETURN type_pix IS - VARIABLE p : type_pix; - BEGIN - p.r:=bound(unsigned(t.r0+t.r1),15); - p.g:=bound(unsigned(t.g0+t.g1),15); - p.b:=bound(unsigned(t.b0+t.b1),15); - RETURN p; - END FUNCTION; - + ---------------------------------------------------------- + CONSTANT NB_BURST : natural :=ilog2(N_BURST); + CONSTANT NB_LA : natural :=ilog2(N_DW/8); -- Low address bits + CONSTANT BLEN : natural :=N_BURST / N_DW * 8; -- Burst length + + ---------------------------------------------------------- + TYPE arr_dw IS ARRAY (natural RANGE <>) OF unsigned(N_DW-1 DOWNTO 0); + + TYPE type_pix IS RECORD + r,g,b : unsigned(7 DOWNTO 0); -- 0.8 + END RECORD; + TYPE arr_pix IS ARRAY (natural RANGE <>) OF type_pix; + TYPE arr_pixq IS ARRAY(natural RANGE <>) OF arr_pix(0 TO 3); + ATTRIBUTE ramstyle : string; + + SUBTYPE uint12 IS natural RANGE 0 TO 4095; + SUBTYPE uint13 IS natural RANGE 0 TO 8191; + + TYPE arr_uv48 IS ARRAY (natural RANGE <>) OF unsigned(47 DOWNTO 0); + TYPE arr_uv24 IS ARRAY (natural RANGE <>) OF unsigned(23 DOWNTO 0); + TYPE arr_uv40 IS ARRAY (natural RANGE <>) OF unsigned(39 DOWNTO 0); + TYPE arr_int9 IS ARRAY (natural RANGE <>) OF integer RANGE -256 TO 255; + TYPE arr_uint12 IS ARRAY (natural RANGE <>) OF uint12; + TYPE arr_frac IS ARRAY (natural RANGE <>) OF unsigned(11 DOWNTO 0); + TYPE arr_div IS ARRAY (natural RANGE <>) OF unsigned(20 DOWNTO 0); + + ---------------------------------------------------------- + -- Input image + SIGNAL i_pvs,i_pfl,i_pde,i_pce : std_logic; + SIGNAL i_ppix : type_pix; + SIGNAL i_freeze : std_logic; + SIGNAL i_count : unsigned(2 DOWNTO 0); + SIGNAL i_hsize,i_hmin,i_hmax,i_hcpt : uint12; + SIGNAL i_hrsize,i_vrsize : uint12; + SIGNAL i_himax,i_vimax : uint12; + SIGNAL i_vsize,i_vmaxmin,i_vmin,i_vmax,i_vcpt : uint12; + SIGNAL i_iauto : std_logic; + SIGNAL i_mode : unsigned(4 DOWNTO 0); + SIGNAL i_format : unsigned(1 DOWNTO 0); + SIGNAL i_ven,i_sof : std_logic; + SIGNAL i_wr : std_logic; + SIGNAL i_divstart,i_divrun : std_logic; + SIGNAL i_de_pre,i_vs_pre,i_fl_pre : std_logic; + SIGNAL i_de_delay : natural RANGE 0 TO 31; + SIGNAL i_intercnt : natural RANGE 0 TO 3; + SIGNAL i_inter,i_half,i_flm : std_logic; + SIGNAL i_write,i_wreq,i_alt,i_line,i_wline,i_wline_mem : std_logic; + SIGNAL i_walt,i_walt_mem,i_wreq_mem : std_logic; + SIGNAL i_wdelay : natural RANGE 0 TO 7; + SIGNAL i_push,i_pushend,i_pushend2 : std_logic; + SIGNAL i_eol : std_logic; + SIGNAL i_pushhead,i_pushhead2,i_pushhead3 : std_logic; + SIGNAL i_hburst,i_hbcpt : natural RANGE 0 TO 31; + SIGNAL i_shift : unsigned(0 TO 119) := (OTHERS =>'0'); + SIGNAL i_head : unsigned(127 DOWNTO 0); + SIGNAL i_acpt : natural RANGE 0 TO 15; + SIGNAL i_dpram : arr_dw(0 TO BLEN*2-1); + ATTRIBUTE ramstyle OF i_dpram : SIGNAL IS "no_rw_check"; + SIGNAL i_endframe0,i_endframe1,i_vss : std_logic; + SIGNAL i_wad : natural RANGE 0 TO BLEN*2-1; + SIGNAL i_dw : unsigned(N_DW-1 DOWNTO 0); + SIGNAL i_adrs,i_adrsi,i_wadrs,i_wadrs_mem : unsigned(31 DOWNTO 0); + SIGNAL i_reset_na : std_logic; + SIGNAL i_hnp,i_vnp : std_logic; + SIGNAL i_mem : arr_pix(0 TO IHRES-1); -- Downscale line buffer + ATTRIBUTE ramstyle OF i_mem : SIGNAL IS "no_rw_check"; + SIGNAL i_ohsize,i_ovsize : uint12; + SIGNAL i_vdivi : unsigned(12 DOWNTO 0); + SIGNAL i_vdivr : unsigned(24 DOWNTO 0); + SIGNAL i_div : unsigned(16 DOWNTO 0); + SIGNAL i_dir : unsigned(11 DOWNTO 0); + SIGNAL i_h_frac,i_v_frac : unsigned(11 DOWNTO 0); + SIGNAL i_hacc,i_vacc : uint13; + SIGNAL i_hdown,i_vdown : std_logic; + SIGNAL i_divcpt : natural RANGE 0 TO 36; + SIGNAL i_lwad,i_lrad : natural RANGE 0 TO OHRES-1; + SIGNAL i_lwr,i_bil : std_logic; + SIGNAL i_ldw,i_ldrm : type_pix; + SIGNAL i_hpixp,i_hpix0,i_hpix1,i_hpix2,i_hpix3,i_hpix4 : type_pix; + SIGNAL i_hpix,i_pix : type_pix; + SIGNAL i_hnp1,i_hnp2,i_hnp3,i_hnp4 : std_logic; + SIGNAL i_ven1,i_ven2,i_ven3,i_ven4,i_ven5,i_ven6 : std_logic; + + ---------------------------------------------------------- + -- Avalon + TYPE type_avl_state IS (sIDLE,sWRITE,sREAD); + SIGNAL avl_state : type_avl_state; + SIGNAL avl_write_i,avl_write_sync,avl_write_sync2 : std_logic; + SIGNAL avl_read_i,avl_read_sync,avl_read_sync2 : std_logic; + SIGNAL avl_read_pulse,avl_write_pulse : std_logic; + SIGNAL avl_read_sr,avl_write_sr,avl_read_clr,avl_write_clr : std_logic; + SIGNAL avl_rad,avl_rad_c,avl_wad : natural RANGE 0 TO 2*BLEN-1; + SIGNAL avl_walt,avl_wline,avl_rline : std_logic; + SIGNAL avl_dw,avl_dr : unsigned(N_DW-1 DOWNTO 0); + SIGNAL avl_wr : std_logic; + SIGNAL avl_readdataack,avl_readack : std_logic; + SIGNAL avl_radrs,avl_wadrs : unsigned(31 DOWNTO 0); + SIGNAL avl_i_offset0,avl_o_offset0 : unsigned(31 DOWNTO 0); + SIGNAL avl_i_offset1,avl_o_offset1 : unsigned(31 DOWNTO 0); + SIGNAL avl_reset_na : std_logic; + SIGNAL avl_o_vs_sync,avl_o_vs : std_logic; + SIGNAL avl_fb_ena : std_logic; + + FUNCTION buf_next(a,b : natural RANGE 0 TO 2; freeze : std_logic := '0') RETURN natural IS + BEGIN + IF (freeze='1') THEN RETURN a; END IF; + IF (a=0 AND b=1) OR (a=1 AND b=0) THEN RETURN 2; END IF; + IF (a=1 AND b=2) OR (a=2 AND b=1) THEN RETURN 0; END IF; + RETURN 1; + END FUNCTION; + FUNCTION buf_offset(b : natural RANGE 0 TO 2; + base : unsigned(31 DOWNTO 0); + size : unsigned(31 DOWNTO 0)) RETURN unsigned IS + BEGIN + IF b=1 THEN RETURN base+size; END IF; + IF b=2 THEN RETURN base+(size(30 DOWNTO 0) & '0'); END IF; + RETURN base; + END FUNCTION; + + ---------------------------------------------------------- + -- Output + SIGNAL o_run : std_logic; + SIGNAL o_freeze : std_logic; + SIGNAL o_mode,o_hmode,o_vmode : unsigned(4 DOWNTO 0); + SIGNAL o_format : unsigned(5 DOWNTO 0); + SIGNAL o_fb_pal_dr : unsigned(23 DOWNTO 0); + SIGNAL o_fb_pal_dr2 : unsigned(23 DOWNTO 0); + SIGNAL o_fb_pal_dr_x2 : unsigned(47 DOWNTO 0); + SIGNAL pal_idx: unsigned(7 DOWNTO 0); + SIGNAL pal_idx_lsb: std_logic; + SIGNAL pal1_mem : arr_uv48(0 TO 127); + SIGNAL pal2_mem : arr_uv24(0 TO 255); + ATTRIBUTE ramstyle of pal1_mem : signal is "no_rw_check"; + ATTRIBUTE ramstyle of pal2_mem : signal is "no_rw_check"; + SIGNAL o_htotal,o_hsstart,o_hsend : uint12; + SIGNAL o_hmin,o_hmax,o_hdisp,o_v_hmin_adj : uint12; + SIGNAL o_hsize,o_vsize : uint12; + SIGNAL o_vtotal,o_vsstart,o_vsend : uint12; + SIGNAL o_vrr,o_isync,o_isync2 : std_logic; + SIGNAL o_vrr_sync,o_vrr_sync2 : boolean; + SIGNAL o_vrr_min,o_vrr_min2 : boolean; + SIGNAL o_vrr_max,o_vrr_max2 : boolean; + SIGNAL o_vcpt_sync,o_vcpt_sync2, o_vrrmax : uint12; + SIGNAL o_sync, o_sync_max : boolean; + SIGNAL o_vmin,o_vmax,o_vdisp : uint12; + SIGNAL o_divcpt : natural RANGE 0 TO 36; + SIGNAL o_iendframe0,o_iendframe02,o_iendframe1,o_iendframe12 : std_logic; + SIGNAL o_bufup0,o_bufup1,o_inter : std_logic; + SIGNAL o_ibuf0,o_ibuf1,o_obuf0,o_obuf1 : natural RANGE 0 TO 2; + TYPE enum_o_state IS (sDISP,sHSYNC,sREAD,sWAITREAD); + SIGNAL o_state : enum_o_state; + TYPE enum_o_copy IS (sWAIT,sSHIFT,sCOPY); + SIGNAL o_copy : enum_o_copy; + SIGNAL o_pshift : natural RANGE 0 TO 15; + SIGNAL o_readack,o_readack_sync,o_readack_sync2 : std_logic; + SIGNAL o_readdataack,o_readdataack_sync,o_readdataack_sync2 : std_logic; + SIGNAL o_copyv : unsigned(0 TO 14); + SIGNAL o_adrs : unsigned(31 DOWNTO 0); -- Avalon address + 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; + SIGNAL o_adturn : std_logic; + SIGNAL o_dr : unsigned(N_DW-1 DOWNTO 0); + SIGNAL o_shift : unsigned(0 TO N_DW+15); + SIGNAL o_sh,o_sh1,o_sh2,o_sh3,o_sh4 : std_logic; + SIGNAL o_reset_na : std_logic; + SIGNAL o_dpram : arr_dw(0 TO BLEN*2-1); + ATTRIBUTE ramstyle OF o_dpram : SIGNAL IS "no_rw_check"; + SIGNAL o_line0,o_line1,o_line2,o_line3 : arr_pix(0 TO OHRES-1); + ATTRIBUTE ramstyle OF o_line0 : SIGNAL IS "no_rw_check"; + ATTRIBUTE ramstyle OF o_line1 : SIGNAL IS "no_rw_check"; + ATTRIBUTE ramstyle OF o_line2 : SIGNAL IS "no_rw_check"; + ATTRIBUTE ramstyle OF o_line3 : SIGNAL IS "no_rw_check"; + SIGNAL o_wadl,o_radl0,o_radl1,o_radl2,o_radl3 : natural RANGE 0 TO OHRES-1; + SIGNAL o_ldw,o_ldr0,o_ldr1,o_ldr2,o_ldr3 : type_pix; + SIGNAL o_wr : unsigned(3 DOWNTO 0); + SIGNAL o_hcpt,o_vcpt,o_vcpt_pre,o_vcpt_pre2,o_vcpt_pre3,o_vcpt2 : uint12; + SIGNAL o_ihsize,o_ihsizem,o_ivsize : uint12; + SIGNAL o_ihsize_temp, o_ihsize_temp2 : natural RANGE 0 TO 32767; + + SIGNAL o_vfrac : unsigned(11 DOWNTO 0); + SIGNAL o_hfrac : arr_frac(0 TO 9); + ATTRIBUTE ramstyle OF o_hfrac : SIGNAL IS "logic"; -- avoid blockram shift register + + SIGNAL o_hacc,o_hacc_ini,o_hacc_next,o_vacc,o_vacc_next,o_vacc_ini : natural RANGE 0 TO 4*OHRES-1; + SIGNAL o_hsv,o_vsv,o_dev,o_pev,o_end : unsigned(0 TO 11); + SIGNAL o_hsp,o_vss : std_logic; + SIGNAL o_vcarrym,o_prim : boolean; + SIGNAL o_read,o_read_pre : std_logic; + SIGNAL o_readlev,o_copylev : natural RANGE 0 TO 2; + SIGNAL o_hburst,o_hbcpt : natural RANGE 0 TO 31; + SIGNAL o_fload : natural RANGE 0 TO 3; + SIGNAL o_acpt,o_acpt1,o_acpt2,o_acpt3,o_acpt4 : natural RANGE 0 TO 15; -- Alternance pixels FIFO + SIGNAL o_dshi : natural RANGE 0 TO 3; + SIGNAL o_first,o_last,o_last1,o_last2 : std_logic; + SIGNAL o_lastt1,o_lastt2,o_lastt3,o_lastt4 : std_logic; + SIGNAL o_alt,o_altx : unsigned(3 DOWNTO 0); + SIGNAL o_hdown,o_vdown : std_logic; + SIGNAL o_primv,o_lastv,o_bibv : unsigned(0 TO 2); + TYPE arr_uint4 IS ARRAY (natural RANGE <>) OF natural RANGE 0 TO 15; + SIGNAL o_off : arr_uint4(0 TO 2); + SIGNAL o_bibu : std_logic :='0'; + SIGNAL o_dcptv : arr_uint12(1 TO 14); + SIGNAL o_dcpt : uint12; + SIGNAL o_hpixs,o_hpix0,o_hpix1,o_hpix2,o_hpix3 : type_pix; + SIGNAL o_hpixq : arr_pixq(2 TO 8); + ATTRIBUTE ramstyle OF o_hpixq : SIGNAL IS "logic"; -- avoid blockram shift register + SIGNAL o_vpixq, o_vpixq_pre : arr_pix(0 TO 3); + SIGNAL o_vpix_outer : arr_pix(0 TO 2); + SIGNAL o_vpix_inner : arr_pix(0 TO 6); + + + SIGNAL o_vpe : std_logic; + SIGNAL o_div : arr_div(0 TO 2); --uint12; + SIGNAL o_dir : arr_frac(0 TO 2); + ATTRIBUTE ramstyle OF o_div, o_dir : SIGNAL IS "logic"; -- avoid blockram shift register + SIGNAL o_vdivi : unsigned(12 DOWNTO 0); + SIGNAL o_vdivr : unsigned(24 DOWNTO 0); + SIGNAL o_divstart : std_logic; + SIGNAL o_divrun : std_logic; + SIGNAL o_hacpt,o_vacpt : unsigned(11 DOWNTO 0); + SIGNAL o_vacptl : unsigned(1 DOWNTO 0); + + ----------------------------------------------------------------------------- + FUNCTION shift_ishift(shift : unsigned(0 TO 119); + pix : type_pix; + format : unsigned(1 DOWNTO 0)) RETURN unsigned IS + BEGIN + CASE format IS + WHEN "01" => -- 24bpp + RETURN shift(24 TO 119) & pix.r & pix.g & pix.b; + WHEN "10" => -- 32bpp + RETURN shift(32 TO 119) & pix.r & pix.g & pix.b & x"00"; + WHEN OTHERS => -- 16bpp 565 + RETURN shift(16 TO 119) & + pix.g(4 DOWNTO 2) & pix.r(7 DOWNTO 3) & + pix.b(7 DOWNTO 3) & pix.g(7 DOWNTO 5); + END CASE; + END FUNCTION; + + FUNCTION shift_ipack( i_dw : unsigned(N_DW-1 DOWNTO 0); + acpt : natural RANGE 0 TO 15; + shift : unsigned(0 TO 119); + pix : type_pix; + format : unsigned(1 DOWNTO 0)) RETURN unsigned IS + VARIABLE dw : unsigned(N_DW-1 DOWNTO 0); + BEGIN + dw:=i_dw; + CASE format IS + WHEN "01" => -- 24bpp + IF N_DW=128 THEN + IF acpt=5 THEN dw:=shift(0 TO 119) & pix.r; + ELSIF acpt=10 THEN dw:=shift(8 TO 119) & pix.r & pix.g; + ELSIF acpt=15 THEN dw:=shift(16 TO 119) & pix.r & pix.g & pix.b; + END IF; + ELSE -- N_DW=64 + IF (acpt MOD 8)=2 THEN dw:=shift(72 TO 119) & pix.r & pix.g; + ELSIF (acpt MOD 8)=5 THEN dw:=shift(64 TO 119) & pix.r; + ELSIF (acpt MOD 8)=7 THEN dw:=shift(80 TO 119) & pix.r & pix.g & pix.b; + END IF; + END IF; + WHEN "10" => -- 32bpp + IF (N_DW=128 AND (acpt MOD 4)=3) OR (N_DW=64 AND (acpt MOD 8)=7) THEN + dw:=shift(128-N_DW+24 TO 119) & pix.r & pix.g & pix.b & x"00"; + END IF; + WHEN OTHERS => -- 16bpp 565 + IF (N_DW=128 AND (acpt MOD 8)=7) OR (N_DW=64 AND (acpt MOD 4)=3) THEN + dw:=shift(128-N_DW+8 TO 119) & pix.g(4 DOWNTO 2) & pix.r(7 DOWNTO 3) & + pix.b(7 DOWNTO 3) & pix.g(7 DOWNTO 5); + END IF; + END CASE; + RETURN dw; + END FUNCTION; + + FUNCTION shift_inext (acpt : natural RANGE 0 TO 15; + format : unsigned(1 DOWNTO 0)) RETURN boolean IS + BEGIN + CASE format IS + WHEN "01" => -- 24bpp + RETURN (N_DW=128 AND (acpt=5 OR acpt=10 OR acpt=15)) OR + (N_DW=64 AND ((acpt MOD 8)=2 OR (acpt MOD 8)=5 OR (acpt MOD 8)=7)); + WHEN "10" => -- 32bpp + RETURN (N_DW=128 AND ((acpt MOD 4)=3)) OR + (N_DW=64 AND ((acpt MOD 2)=1)); + WHEN OTHERS => -- 16bpp + RETURN (N_DW=128 AND ((acpt MOD 8)=7)) OR + (N_DW=64 AND ((acpt MOD 4)=3)); + END CASE; + END FUNCTION; + + FUNCTION shift_opack(acpt : natural RANGE 0 TO 15; + shift : unsigned(0 TO N_DW+15); + dr : unsigned(N_DW-1 DOWNTO 0); + format : unsigned(5 DOWNTO 0)) RETURN unsigned IS + VARIABLE shift_v : unsigned(0 TO N_DW+15); + BEGIN + CASE format(2 DOWNTO 0) IS + WHEN "011" => -- 8bpp + IF (N_DW=128 AND acpt=0) OR (N_DW=64 AND (acpt MOD 8)=0) THEN + shift_v:=dr & dr(15 DOWNTO 0); + ELSE + shift_v:=shift(8 TO N_DW+15) & dr(7 DOWNTO 0); + END IF; + + WHEN "100" => -- 16bpp + IF (N_DW=128 AND (acpt MOD 8)=0) OR (N_DW=64 AND (acpt MOD 4)=0) THEN + shift_v:=dr & dr(15 DOWNTO 0); + ELSE + shift_v:=shift(16 TO N_DW+15) & dr(15 DOWNTO 0); + END IF; + + WHEN "101" => -- 24bpp + IF N_DW=128 THEN + IF acpt=0 THEN + shift_v:=dr & dr(15 DOWNTO 0); + ELSIF acpt=5 THEN + shift_v:=shift(24 TO 31) & dr & dr(7 DOWNTO 0); + ELSIF acpt=10 THEN + shift_v:=shift(24 TO 39) & dr; + ELSE + shift_v:=shift(24 TO N_DW+15) & dr(23 DOWNTO 0); + END IF; + ELSE -- N_DW=64 + IF (acpt MOD 8)=0 THEN + shift_v:=dr & dr(15 DOWNTO 0); + ELSIF (acpt MOD 8)=2 THEN + shift_v:=shift(24 TO 39) & dr; + ELSIF (acpt MOD 8)=5 THEN + shift_v:=shift(24 TO 31) & dr & dr(7 DOWNTO 0); + ELSE + shift_v:=shift(24 TO N_DW+15) & dr(23 DOWNTO 0); + END IF; + END IF; + WHEN OTHERS => -- 32bpp + IF (N_DW=128 AND (acpt MOD 4)=0) OR (N_DW=64 AND (acpt MOD 2)=0) THEN + shift_v:=dr & dr(15 DOWNTO 0); + ELSE + shift_v:=shift(32 TO N_DW+15) & dr(31 DOWNTO 0); + END IF; + END CASE; + RETURN shift_v; + END FUNCTION; + + FUNCTION shift_onext (acpt : natural RANGE 0 TO 15; + format : unsigned(5 DOWNTO 0)) RETURN boolean IS + BEGIN + CASE format(2 DOWNTO 0) IS + WHEN "011" => -- 8bpp + RETURN (N_DW=128 AND acpt=0) OR + (N_DW=64 AND ((acpt MOD 8)=0)); + WHEN "100" => -- 16bpp + RETURN (N_DW=128 AND ((acpt MOD 8)=0)) OR + (N_DW=64 AND ((acpt MOD 4)=0)); + WHEN "101" => -- 24bpp + RETURN (N_DW=128 AND (acpt=0 OR acpt=5 OR acpt=10)) OR + (N_DW=64 AND ((acpt MOD 8)=0 OR (acpt MOD 8)=2 OR (acpt MOD 8)=5)); + WHEN OTHERS => -- 32bpp + RETURN (N_DW=128 AND ((acpt MOD 4)=0)) OR + (N_DW=64 AND ((acpt MOD 2)=0)); + END CASE; + END FUNCTION; + + FUNCTION shift_opix (shift : unsigned(0 TO N_DW+15); + format : unsigned(5 DOWNTO 0)) RETURN type_pix IS + BEGIN + CASE format(3 DOWNTO 0) IS + WHEN "0100" => -- 16bpp 565 + RETURN (b=>shift(8 TO 12) & shift(8 TO 10), + g=>shift(13 TO 15) & shift(0 TO 2) & shift(13 TO 14), + r=>shift(3 TO 7) & shift(3 TO 5)); + WHEN "1100" => -- 16bpp 1555 + RETURN (b=>shift(9 TO 13) & shift(9 TO 11), + g=>shift(14 TO 15) & shift(0 TO 2) & shift(14 TO 15) & shift(0), + r=>shift(3 TO 7) & shift(3 TO 5)); + WHEN "0101" | "0110" => -- 24bpp / 32bpp + RETURN (r=>shift(0 TO 7),g=>shift(8 TO 15),b=>shift(16 TO 23)); + + WHEN OTHERS => + RETURN (r=>shift(0 TO 7),g=>shift(8 TO 15),b=>shift(16 TO 23)); + + END CASE; + END FUNCTION; + + FUNCTION pixoffset(adrs : unsigned(31 DOWNTO 0); + format : unsigned (5 DOWNTO 0)) RETURN natural IS + BEGIN + CASE format(2 DOWNTO 0) IS + WHEN "011" => -- 8bbp + RETURN to_integer(adrs(NB_LA-1 DOWNTO 0)); + WHEN "100" => -- 16bpp 565 + RETURN to_integer(adrs(NB_LA-1 DOWNTO 1)); + WHEN OTHERS => -- 32bpp + RETURN to_integer(adrs(NB_LA-1 DOWNTO 2)); + END CASE; + END FUNCTION; + + FUNCTION swap(d : unsigned(N_DW-1 DOWNTO 0)) RETURN unsigned IS + VARIABLE e : unsigned(N_DW-1 DOWNTO 0); + BEGIN + IF BYTESWAP THEN + FOR i IN 0 TO N_DW/8-1 LOOP + e(i*8+7 DOWNTO i*8):=d(N_DW-i*8-1 DOWNTO N_DW-i*8-8); + END LOOP; + RETURN e; + ELSE + RETURN d; + END IF; + END FUNCTION swap; + + ----------------------------------------------------------------------------- + FUNCTION altx (a : unsigned(1 DOWNTO 0)) RETURN unsigned IS + BEGIN + CASE a IS + WHEN "00" => RETURN "0001"; + WHEN "01" => RETURN "0010"; + WHEN "10" => RETURN "0100"; + WHEN OTHERS => RETURN "1000"; + END CASE; + END FUNCTION; + + ----------------------------------------------------------------------------- + FUNCTION bound(a : unsigned; + s : natural) RETURN unsigned IS + BEGIN + IF a(a'left)='1' THEN + RETURN x"00"; + ELSIF a(a'left DOWNTO s)/=0 THEN + RETURN x"FF"; + ELSE + RETURN a(s-1 DOWNTO s-8); + END IF; + END FUNCTION bound; + + ----------------------------------------------------------------------------- + -- Nearest + FUNCTION near_frac(f : unsigned) RETURN unsigned IS + VARIABLE x : unsigned(FRAC-1 DOWNTO 0); + BEGIN + x:=(OTHERS =>f(f'left)); + RETURN x; + END FUNCTION; + + SIGNAL o_h_near_frac,o_v_near_frac : unsigned(FRAC-1 DOWNTO 0); + SIGNAL o_h_bil_frac,o_v_bil_frac : unsigned(FRAC-1 DOWNTO 0); + SIGNAL o_h_bil_pix,o_v_bil_pix : type_pix; + + ----------------------------------------------------------------------------- + -- Nearest + Bilinear + Sharp Bilinear + FUNCTION bil_frac(f : unsigned) RETURN unsigned IS + BEGIN + RETURN f(f'left DOWNTO f'left+1-FRAC); + END FUNCTION; + + TYPE type_bil_t IS RECORD + r,g,b : unsigned(8+FRAC DOWNTO 0); + END RECORD; + + FUNCTION bil_calc(f : unsigned(FRAC-1 DOWNTO 0); + p : arr_pix(0 TO 3)) RETURN type_bil_t IS + VARIABLE fp,fn : unsigned(FRAC DOWNTO 0); + VARIABLE u : unsigned(8+FRAC DOWNTO 0); + VARIABLE x : type_bil_t; + CONSTANT Z : unsigned(FRAC-1 DOWNTO 0):=(OTHERS =>'0'); + BEGIN + fp:=('0' & f) + (Z & f(FRAC-1)); + fn:=('1' & Z) - fp; + u:=p(2).r * fp + p(1).r * fn; + x.r:=u; + u:=p(2).g * fp + p(1).g * fn; + x.g:=u; + u:=p(2).b * fp + p(1).b * fn; + x.b:=u; + RETURN x; + END FUNCTION; + + FUNCTION near_calc(f : unsigned(FRAC-1 DOWNTO 0); + p : arr_pix(0 TO 3)) RETURN type_bil_t IS + VARIABLE fp,fn : unsigned(FRAC DOWNTO 0); + VARIABLE u : unsigned(8+FRAC DOWNTO 0); + VARIABLE x : type_bil_t; + CONSTANT Z : unsigned(FRAC-1 DOWNTO 0):=(OTHERS =>'0'); + BEGIN + IF f(FRAC-1)='0' THEN + x.r := '0' & p(1).r & Z; + x.g := '0' & p(1).g & Z; + x.b := '0' & p(1).b & Z; + ELSE + x.r := '0' & p(2).r & Z; + x.g := '0' & p(2).g & Z; + x.b := '0' & p(2).b & Z; + END IF; + RETURN x; + END FUNCTION; + + SIGNAL o_h_bil_t,o_v_bil_t : type_bil_t; + SIGNAL o_h_near_t,o_v_near_t : type_bil_t; + SIGNAL i_h_bil_t : type_bil_t; + + ----------------------------------------------------------------------------- + -- Sharp Bilinear + -- <0.5 : x*x*x*4 + -- >0.5 : 1 - (1-x)*(1-x)*(1-x)*4 + + TYPE type_sbil_tt IS RECORD + f : unsigned(FRAC-1 DOWNTO 0); + s : unsigned(FRAC-1 DOWNTO 0); + END RECORD; + + SIGNAL o_h_sbil_t,o_v_sbil_t : type_sbil_tt; + + FUNCTION sbil_frac1(f : unsigned(11 DOWNTO 0)) RETURN type_sbil_tt IS + VARIABLE u : unsigned(FRAC-1 DOWNTO 0); + VARIABLE v : unsigned(2*FRAC-1 DOWNTO 0); + VARIABLE x : type_sbil_tt; + BEGIN + IF f(11)='0' THEN + u:=f(11 DOWNTO 12-FRAC); + ELSE + u:=NOT f(11 DOWNTO 12-FRAC); + END IF; + v:=u*u; + x.f:=u; + x.s:=v(2*FRAC-2 DOWNTO FRAC-1); + RETURN x; + END FUNCTION; + + FUNCTION sbil_frac2(f : unsigned(11 DOWNTO 0); + t : type_sbil_tt) RETURN unsigned IS + VARIABLE v : unsigned(2*FRAC-1 DOWNTO 0); + BEGIN + v:=t.f*t.s; + IF f(11)='0' THEN + RETURN v(2*FRAC-2 DOWNTO FRAC-1); + ELSE + RETURN NOT v(2*FRAC-2 DOWNTO FRAC-1); + END IF; + END FUNCTION; + + ----------------------------------------------------------------------------- + -- Bicubic + TYPE type_bic_abcd IS RECORD + a : unsigned(7 DOWNTO 0); -- 0.8 + b : signed(8 DOWNTO 0); -- 0.9 + c : signed(11 DOWNTO 0); -- 3.9 + d : signed(10 DOWNTO 0); -- 2.9 + xx : signed(8 DOWNTO 0); -- X.X 1.8 + END RECORD; + TYPE type_bic_pix_abcd IS RECORD + r,g,b : type_bic_abcd; + END RECORD; + TYPE type_bic_tt1 IS RECORD -- Intermediate result + r_bx,g_bx,b_bx : signed(8 DOWNTO 0); -- B.X 1.8 + r_cxx,g_cxx,b_cxx : signed(11 DOWNTO 0); -- C.XX 3.9 + r_dxx,g_dxx,b_dxx : signed(10 DOWNTO 0); -- D.XX 2.9 + END RECORD; + TYPE type_bic_tt2 IS RECORD -- Intermediate result + r_abxcxx,g_abxcxx,b_abxcxx : signed(9 DOWNTO 0); -- A + B.X + C.XX 2.8 + r_dxxx,g_dxxx,b_dxxx : signed(9 DOWNTO 0); -- D.X.X.X 2.8 + END RECORD; + + ---------------------------------------------------------- + -- Y = A + B.X + C.X.X + D.X.X.X = A + X.(B + X.(C + X.D)) + -- A = Y(0) 0 .. 1 unsigned + -- B = Y(1)/2 - Y(-1)/2 -1/2 .. +1/2 signed + -- C = Y(-1) - 5*Y(0)/2 + 2*Y(1) - Y(2)/2 -3 .. +3 signed + -- D = -Y(-1)/2 + 3*Y(0)/2 - 3*Y(1)/2 + Y(2)/2 -2 .. +2 signed + + FUNCTION bic_calc0(f : unsigned(11 DOWNTO 0); + pm,p0,p1,p2 : unsigned(7 DOWNTO 0)) RETURN type_bic_abcd IS + VARIABLE xx : signed(2*FRAC+1 DOWNTO 0); -- 2.(2*FRAC) + BEGIN + xx := signed('0' & f(11 DOWNTO 12-FRAC)) * + signed('0' & f(11 DOWNTO 12-FRAC)); -- 2.(2*FRAC) + RETURN type_bic_abcd'( + a=>p0,-- 0.8 + b=>signed(('0' & p1) - ('0' & pm)), -- 0.9 + c=>signed(("000" & pm & '0') - ("00" & p0 & "00") - ("0000" & p0) + + ("00" & p1 & "00") - ("0000" & p2)), -- 3.9 + d=>signed(("00" & p0 & '0') - ("00" & p1 & '0') - ("000" & p1) + + ("000" & p0) + ("000" & p2) - ("000" & pm)), -- 2.9 + xx=>xx(2*FRAC DOWNTO 2*FRAC-8)); -- 1.8 + END FUNCTION; + FUNCTION bic_calc0(f : unsigned(11 DOWNTO 0); + p : arr_pix(0 TO 3)) RETURN type_bic_pix_abcd IS + BEGIN + RETURN type_bic_pix_abcd'( r=>bic_calc0(f,p(0).r,p(1).r,p(2).r,p(3).r), + g=>bic_calc0(f,p(0).g,p(1).g,p(2).g,p(3).g), + b=>bic_calc0(f,p(0).b,p(1).b,p(2).b,p(3).b)); + END FUNCTION; + + ---------------------------------------------------------- + -- Calc : B.X, C.XX, D.XX + FUNCTION bic_calc1(f : unsigned(11 DOWNTO 0); + abcd : type_bic_pix_abcd) RETURN type_bic_tt1 IS + VARIABLE t : type_bic_tt1; + VARIABLE bx : signed(9+FRAC DOWNTO 0); -- 1.(FRAC+9) + VARIABLE cxx : signed(20 DOWNTO 0); -- 4.17 + VARIABLE dxx : signed(19 DOWNTO 0); -- 3.17 + BEGIN + bx := abcd.r.b * signed('0' & f(11 DOWNTO 12-FRAC)); -- 1.(FRAC+9) + t.r_bx:=bx(9+FRAC DOWNTO 9+FRAC-8); -- 1.8 + cxx:= abcd.r.c * abcd.r.xx; -- 3.9 * 1.8 = 4.17 + t.r_cxx:=cxx(19 DOWNTO 8); -- 3.9 + dxx:= abcd.r.d * abcd.r.xx; -- 2.9 * 1.8 = 3.17 + t.r_dxx:=dxx(18 DOWNTO 8); -- 2.9 + bx := abcd.g.b * signed('0' & f(11 DOWNTO 12-FRAC)); -- 1.(FRAC+9) + t.g_bx:=bx(9+FRAC DOWNTO 9+FRAC-8); -- 1.8 + cxx:= abcd.g.c * abcd.g.xx; -- 3.9 * 1.8 = 4.17 + t.g_cxx:=cxx(19 DOWNTO 8); -- 3.9 + dxx:= abcd.g.d * abcd.g.xx; -- 2.9 * 1.8 = 3.17 + t.g_dxx:=dxx(18 DOWNTO 8); -- 2.9 + bx := abcd.b.b * signed('0' & f(11 DOWNTO 12-FRAC)); -- 1.(FRAC+9) + t.b_bx:=bx(9+FRAC DOWNTO 9+FRAC-8); -- 1.8 + cxx:= abcd.b.c * abcd.b.xx; -- 3.9 * 1.8 = 4.17 + t.b_cxx:=cxx(19 DOWNTO 8); -- 3.9 + dxx:= abcd.b.d * abcd.b.xx; -- 2.9 * 1.8 = 3.17 + t.b_dxx:=dxx(18 DOWNTO 8); -- 2.9 + RETURN t; + END FUNCTION; + + ---------------------------------------------------------- + -- Calc A + BX + CXX , X.DXX + FUNCTION bic_calc2(f : unsigned(11 DOWNTO 0); + t : type_bic_tt1; + abcd : type_bic_pix_abcd) RETURN type_bic_tt2 IS + VARIABLE u : type_bic_tt2; + VARIABLE x : signed(11+FRAC DOWNTO 0); -- 3.(9+FRAC) + BEGIN + u.r_abxcxx:=(t.r_bx(8) & t.r_bx) + ("00" & signed(abcd.r.a)) + t.r_cxx(10 DOWNTO 1); -- 2.8 + u.g_abxcxx:=(t.g_bx(8) & t.g_bx) + ("00" & signed(abcd.g.a)) + t.g_cxx(10 DOWNTO 1); -- 2.8 + u.b_abxcxx:=(t.b_bx(8) & t.b_bx) + ("00" & signed(abcd.b.a)) + t.b_cxx(10 DOWNTO 1); -- 2.8 + + x:=t.r_dxx * signed('0' & f(11 DOWNTO 12-FRAC)); --2.9 * 1.FRAC =3.(9+FRAC) + u.r_dxxx:=x(10+FRAC DOWNTO 9+FRAC-8); -- 2.8 + x:=t.g_dxx * signed('0' & f(11 DOWNTO 12-FRAC)); --2.9 * 1.FRAC =3.(9+FRAC) + u.g_dxxx:=x(10+FRAC DOWNTO 9+FRAC-8); -- 2.8 + x:=t.b_dxx * signed('0' & f(11 DOWNTO 12-FRAC)); --2.9 * 1.FRAC =3.(9+FRAC) + u.b_dxxx:=x(10+FRAC DOWNTO 9+FRAC-8); -- 2.8 + RETURN u; + END FUNCTION; + + ---------------------------------------------------------- + -- Calc (A + BX + CXX) + (DXXX) + FUNCTION bic_calc3(f : unsigned(11 DOWNTO 0); + t : type_bic_tt2; + abcd : type_bic_pix_abcd) RETURN type_pix IS + VARIABLE x : type_pix; + VARIABLE v : signed(9 DOWNTO 0); -- 2.8 + BEGIN + v:=t.r_abxcxx + t.r_dxxx; + x.r:=bound(unsigned(v),8); + v:=t.g_abxcxx + t.g_dxxx; + x.g:=bound(unsigned(v),8); + v:=t.b_abxcxx + t.b_dxxx; + x.b:=bound(unsigned(v),8); + RETURN x; + END FUNCTION; + + ----------------------------------------------------------------------------- + SIGNAL o_h_bic_pix,o_v_bic_pix : type_pix; + SIGNAL o_h_bic_abcd1,o_h_bic_abcd2 : type_bic_pix_abcd; + SIGNAL o_v_bic_abcd1,o_v_bic_abcd2 : type_bic_pix_abcd; + SIGNAL o_h_bic_tt1,o_v_bic_tt1 : type_bic_tt1; + SIGNAL o_h_bic_tt2,o_v_bic_tt2 : type_bic_tt2; + + ----------------------------------------------------------------------------- + -- Polyphase + -- 2.7 + TYPE poly_phase_t IS RECORD + t0, t1, t2, t3 : signed(9 DOWNTO 0); + END RECORD; + + -- 4.14 + TYPE poly_phase_interp_t IS RECORD + t0, t1, t2, t3 : signed(17 DOWNTO 0); + END RECORD; + + -- 5.22 + TYPE type_poly_t IS RECORD + r0,r1,b0,b1,g0,g1 : signed(26 DOWNTO 0); + END RECORD; + + SIGNAL o_h_poly_mem : arr_uv40(0 TO 2**FRAC-1); + SIGNAL o_v_poly_mem : arr_uv40(0 TO 2**FRAC-1); + SIGNAL o_a_poly_mem : arr_uv40(0 TO 2**FRAC-1); + ATTRIBUTE ramstyle OF o_h_poly_mem : SIGNAL IS "no_rw_check"; + ATTRIBUTE ramstyle OF o_v_poly_mem : SIGNAL IS "no_rw_check"; + ATTRIBUTE ramstyle OF o_a_poly_mem : SIGNAL IS "no_rw_check"; + SIGNAL o_a_poly_addr, o_v_poly_addr : integer RANGE 0 TO 2**FRAC-1; + SIGNAL o_h_poly_phase_a,o_h_poly_phase_a2,o_h_poly_phase_a3, o_h_poly_phase_a4, o_h_poly_phase_a5 : poly_phase_t; + SIGNAL o_v_poly_phase_a,o_v_poly_phase_a2,o_v_poly_phase_a3, o_v_poly_phase_a4, o_v_poly_phase_a5 : poly_phase_t; + SIGNAL o_poly_phase_a, o_poly_phase_a2, o_poly_phase_a3 : poly_phase_t; + SIGNAL o_poly_phase_b,o_poly_phase_b2,o_poly_phase_b3 : poly_phase_t; + SIGNAL o_v_poly_phase, o_v_poly_phase2, o_h_poly_phase, o_poly_phase, o_poly_phase1 : poly_phase_interp_t; + SIGNAL o_v_poly_pix, o_h_poly_pix, o_h_lum_pix, o_v_lum_pix : type_pix; + SIGNAL o_poly_lum, o_poly_lum1 : unsigned(7 DOWNTO 0); + SIGNAL o_poly_lerp_ta, o_poly_lerp_tb : signed(9 DOWNTO 0); + SIGNAL o_h_poly_t,o_h_poly_t2,o_v_poly_t : type_poly_t; + + SIGNAL o_v_poly_adaptive, o_h_poly_adaptive, o_v_poly_use_adaptive, o_h_poly_use_adaptive : std_logic; + SIGNAL poly_wr_mode : std_logic_vector(2 DOWNTO 0); + SIGNAL poly_tdw : unsigned(39 DOWNTO 0); + SIGNAL poly_a2 : unsigned(FRAC-1 DOWNTO 0); + + FUNCTION poly_unpack(a : unsigned(39 DOWNTO 0)) RETURN poly_phase_t IS + VARIABLE v : poly_phase_t; + BEGIN + v.t0 := signed(a(39 DOWNTO 30)); + v.t1 := signed(a(29 DOWNTO 20)); + v.t2 := signed(a(19 DOWNTO 10)); + v.t3 := signed(a( 9 DOWNTO 0)); + RETURN v; + END FUNCTION; + + -- 6 DSP 18*18 + 18*18 + FUNCTION poly_calc(fi : poly_phase_interp_t; + p : arr_pix(0 TO 3)) RETURN type_poly_t IS + VARIABLE t : type_poly_t; + BEGIN + -- 3.15 * 1.8 = 4.23 + t.r0:=(fi.t0 * signed('0' & p(0).r) + + fi.t1 * signed('0' & p(1).r)); + t.r1:=(fi.t2 * signed('0' & p(2).r) + + fi.t3 * signed('0' & p(3).r)); + t.g0:=(fi.t0 * signed('0' & p(0).g) + + fi.t1 * signed('0' & p(1).g)); + t.g1:=(fi.t2 * signed('0' & p(2).g) + + fi.t3 * signed('0' & p(3).g)); + t.b0:=(fi.t0 * signed('0' & p(0).b) + + fi.t1 * signed('0' & p(1).b)); + t.b1:=(fi.t2 * signed('0' & p(2).b) + + fi.t3 * signed('0' & p(3).b)); + RETURN t; + END FUNCTION; + + FUNCTION poly_final(t : type_poly_t) RETURN type_pix IS + VARIABLE p : type_pix; + BEGIN + p.r:=bound(unsigned(t.r0(26 DOWNTO 8)+t.r1(26 DOWNTO 8)),15); + p.g:=bound(unsigned(t.g0(26 DOWNTO 8)+t.g1(26 DOWNTO 8)),15); + p.b:=bound(unsigned(t.b0(26 DOWNTO 8)+t.b1(26 DOWNTO 8)),15); + RETURN p; + END FUNCTION; + + -- 4 DSP 18*18 + 18*18 + FUNCTION poly_lerp(a : poly_phase_t; + b : poly_phase_t; + ta : SIGNED(9 DOWNTO 0); + tb : SIGNED(9 DOWNTO 0)) RETURN poly_phase_interp_t IS + VARIABLE v : poly_phase_interp_t; + VARIABLE t0,t1,t2,t3 : signed(19 DOWNTO 0); + BEGIN + -- 2.8 * 2.8 = 4.16 + t0 := (a.t0 * ta) + (b.t0 * tb); + t1 := (a.t1 * ta) + (b.t1 * tb); + t2 := (a.t2 * ta) + (b.t2 * tb); + t3 := (a.t3 * ta) + (b.t3 * tb); + + -- 4.16 -> 3.15 + v.t0 := t0(18 DOWNTO 1); + v.t1 := t1(18 DOWNTO 1); + v.t2 := t2(18 DOWNTO 1); + v.t3 := t3(18 DOWNTO 1); + + RETURN v; + END FUNCTION; + + FUNCTION poly_cvt(a : poly_phase_t) RETURN poly_phase_interp_t IS + VARIABLE v : poly_phase_interp_t; + BEGIN + v.t0 := resize(signed( a.t0 & "0000000" ), v.t0'length); + v.t1 := resize(signed( a.t1 & "0000000" ), v.t1'length); + v.t2 := resize(signed( a.t2 & "0000000" ), v.t2'length); + v.t3 := resize(signed( a.t3 & "0000000" ), v.t3'length); + RETURN v; + END FUNCTION; + + -- Nearest neighbor polyphase ceoffs + FUNCTION poly_nn(frac : unsigned(FRAC-1 DOWNTO 0)) RETURN poly_phase_t IS + VARIABLE v : poly_phase_t; + BEGIN + IF frac(frac'left)='0' THEN + v := (t1=>to_signed(256, 10), OTHERS=>to_signed(0, 10)); + ELSE + v := (t2=>to_signed(256, 10), OTHERS=>to_signed(0, 10)); + END IF; + RETURN v; + END FUNCTION; + + + FUNCTION poly_lum(p : type_pix) RETURN unsigned IS + VARIABLE v : UNSIGNED(7 DOWNTO 0); + BEGIN + -- 0.375 R + 0.5 G + 0.125 B + --v := ("00" & p.r(7 DOWNTO 2)) + ("000" & p.r(7 DOWNTO 3)) + ("0" & p.g(7 DOWNTO 1)) + ("000" & p.b(7 DOWNTO 3)); + + -- 0.25 R + 0.5 G + 0.25 B + -- v := ( ("00" & p.r(7 DOWNTO 2)) + ("0" & p.g(7 DOWNTO 1)) + ("00" & p.b(7 DOWNTO 2)) ); + + -- Just OR them all together + --v := (p.r OR p.g OR p.b); + + -- Maximum + IF p.r > p.g THEN + v := p.r; + ELSE + v := p.g; + END IF; + + IF p.b > v THEN + v := p.b; + END IF; + + -- 100% + -- v := "1111111"; + + RETURN v; + END FUNCTION; BEGIN - - ----------------------------------------------------------------------------- - i_reset_na<='0' WHEN reset_na='0' ELSE '1' WHEN rising_edge(i_clk); - o_reset_na<='0' WHEN reset_na='0' ELSE '1' WHEN rising_edge(o_clk); - avl_reset_na<='0' WHEN reset_na='0' ELSE '1' WHEN rising_edge(avl_clk); - - ----------------------------------------------------------------------------- - -- Input pixels FIFO and shreg - InAT:PROCESS(i_clk,i_reset_na) IS - CONSTANT Z : unsigned(FRAC-1 DOWNTO 0):=(OTHERS =>'0'); - VARIABLE frac_v : unsigned(FRAC-1 DOWNTO 0); - VARIABLE div_v : unsigned(16 DOWNTO 0); - VARIABLE dir_v : unsigned(11 DOWNTO 0); - VARIABLE bil_t_v : type_bil_t; - BEGIN - IF i_reset_na='0' THEN - i_write<='0'; - - ELSIF rising_edge(i_clk) THEN - i_push<='0'; - i_pushhead<='0'; - i_eol<='0'; -- End Of Line - i_freeze <=freeze; -- - i_iauto<=iauto; -- - i_wreq<='0'; - i_wr<='0'; - - ------------------------------------------------------ - i_head(127 DOWNTO 120)<=x"01"; -- Header type - i_head(119 DOWNTO 112)<="000000" & i_format; -- Header format - i_head(111 DOWNTO 96)<="0000" & to_unsigned(N_BURST,12); -- Header size - i_head(95 DOWNTO 80)<=x"0000"; -- Attributes. TBD - i_head(80)<=i_inter; - i_head(81)<=i_flm; - i_head(82)<=i_hdown; - i_head(83)<=i_vdown; - i_head(84)<=i_mode(3); - i_head(87 DOWNTO 85)<=i_count; - i_head(79 DOWNTO 64)<="0000" & to_unsigned(i_hrsize,12); -- Image width - i_head(63 DOWNTO 48)<="0000" & to_unsigned(i_vrsize,12); -- Image height - i_head(47 DOWNTO 32)<= - to_unsigned(N_BURST * i_hburst,16); -- Line Length. Bytes - i_head(31 DOWNTO 16)<="0000" & to_unsigned(i_ohsize,12); - i_head(15 DOWNTO 0) <="0000" & to_unsigned(i_ovsize,12); - - ------------------------------------------------------ - i_ppix<=(i_r,i_g,i_b); - i_pvs<=i_vs; - i_pfl<=i_fl; - i_pde<=i_de; - i_pce<=i_ce; - - ------------------------------------------------------ - IF i_pce='1' THEN - ---------------------------------------------------- - i_vs_pre<=i_pvs; - i_de_pre<=i_pde; - i_fl_pre<=i_pfl; - - ---------------------------------------------------- - -- Detect interlaced video - IF NOT INTER THEN - i_intercnt<=0; - ELSIF i_pfl/=i_fl_pre THEN - i_intercnt<=3; - ELSIF i_pvs='1' AND i_vs_pre='0' AND i_intercnt>0 THEN - i_intercnt<=i_intercnt-1; - END IF; - i_inter<=to_std_logic(i_intercnt>0); - - ---------------------------------------------------- - IF i_pvs='1' AND i_vs_pre='0' THEN - i_sof<='1'; - END IF; - - IF i_pde='1' AND i_de_pre='0' THEN - i_flm<=i_pfl; - END IF; - - IF i_pde='1' AND i_sof='1' THEN - i_sof<='0'; - i_vcpt<=0; - IF i_inter='1' AND i_flm='0' AND i_half='0' AND INTER THEN - i_line<='1'; - i_adrsi<=to_unsigned(N_BURST * i_hburst,32) + - to_unsigned(N_BURST * to_integer( - unsigned'("00") & to_std_logic(HEADER)),32); - ELSE - i_line<='0'; - i_adrsi<=to_unsigned(N_BURST * to_integer( - unsigned'("00") & to_std_logic(HEADER)),32); - END IF; - END IF; - - i_ven<=to_std_logic(i_hcpt>=i_hmin AND i_hcpt<=i_hmax AND - i_vcpt>=i_vmin AND i_vcpt<=i_vmax); - - -- Detects end of frame for triple buffering. - i_endframe0<=i_vs AND (NOT i_inter OR i_flm); - i_endframe1<=i_vs AND (NOT i_inter OR NOT i_flm); - - i_vss<=to_std_logic(i_vcpt>=i_vmin AND i_vcpt<=i_vmax); - - ---------------------------------------------------- - IF i_pde='1' AND i_de_pre='0' THEN - i_vimax<=i_vcpt; - i_hcpt<=0; - ELSE - i_hcpt<=(i_hcpt+1) MOD 4096; - END IF; - - IF i_pde='0' AND i_de_pre='1' THEN - i_himax<=i_hcpt; - END IF; - - IF i_iauto='1' THEN - -- Auto-size - i_hmin<=0; - i_hmax<=i_himax; - i_vmin<=0; - IF i_pvs='1' AND i_vs_pre='0' AND (i_inter='0' OR i_pfl='0') THEN - i_vmax<=i_vimax; - END IF; - ELSE - -- Forced image - i_hmin<=himin; -- - i_hmax<=himax; -- - i_vmin<=vimin; -- - IF i_pvs='1' AND i_vs_pre='0' AND (i_inter='0' OR i_pfl='0') THEN - i_vmax<=vimax; -- - END IF; - END IF; - - IF i_pvs='1' AND i_vs_pre='0' AND (i_inter='0' OR i_pfl='0') THEN - i_vdmax<=i_vimax; - END IF; - i_hdmax<=i_himax; - - IF i_format="00" OR i_format="11" THEN -- 16bpp - i_hburst<=(i_hrsize*2 + N_BURST - 1) / N_BURST; - ELSIF i_format="01" THEN -- 24bpp - i_hburst<=(i_hrsize*3 + N_BURST - 1) / N_BURST; - ELSE -- 32bpp - i_hburst<=(i_hrsize*4 + N_BURST - 1) / N_BURST; - END IF; - ---------------------------------------------------- - i_mode<=mode; -- - i_format<=format; -- - - -- Downscaling : Nearest or bilinear - i_bil<=to_std_logic(i_mode(2 DOWNTO 0)/="000" AND DOWNSCALE); - - i_hdown<=to_std_logic(i_hsize>i_ohsize AND DOWNSCALE); --H downscale - i_vdown<=to_std_logic(i_vsize>i_ovsize AND DOWNSCALE); --V downscale - - ---------------------------------------------------- - i_hsize <=(4096+i_hmax-i_hmin+1) MOD 4096; - i_vmaxmin<=(4096+i_vmax-i_vmin+1) MOD 4096; - - IF i_inter='0' THEN - -- Non interlaced - i_vsize<=i_vmaxmin; - i_half <='0'; - ELSIF i_ovsize<2*i_vmaxmin THEN - -- Interlaced, but downscaling, use only half frames - i_vsize<=i_vmaxmin; - i_half <='1'; - ELSE - -- Interlaced : Double image height - i_vsize<=2*i_vmaxmin; - i_half <='0'; - END IF; - - i_ohsize<=o_hsize; -- - i_ovsize<=o_vsize; -- - - ---------------------------------------------------- - -- Downscaling vertical - i_divstart<='0'; - IF i_de_delay=16 THEN - IF (i_vacc + 2*i_ovsize) < 2*i_vsize THEN - i_vacc<=(i_vacc + 2*i_ovsize) MOD 8192; - i_vnp<='0'; - ELSE - i_vacc<=(i_vacc + 2*i_ovsize - 2*i_vsize + 8192) MOD 8192; - i_vnp<='1'; - END IF; - i_divstart<='1'; - - IF i_vcpt=i_vmin THEN - i_vacc<=(i_vsize - i_ovsize + 8192) MOD 8192; - i_vnp<='1'; -- - END IF; - END IF; - - IF i_vdown='0' THEN - i_vnp<='1'; - END IF; - - -- Downscaling horizontal - IF i_ven='1' THEN - IF i_hacc + 2*i_ohsize < 2*i_hsize THEN - i_hacc<=(i_hacc + 2*i_ohsize) MOD 8192; - i_hnp<='0'; -- Skip. pix. - ELSE - i_hacc<=(i_hacc + 2*i_ohsize - 2*i_hsize + 8192) MOD 8192; - i_hnp<='1'; - END IF; - END IF; - IF i_hdown='0' THEN - i_hnp<='1'; - END IF; - - ---------------------------------------------------- - -- Downscaling interpolation - i_hpixp<=i_ppix; - i_hpix0<=i_hpixp; - i_hpix1<=i_hpix0; - i_hpix2<=i_hpix1; - i_hpix3<=i_hpix2; - i_hpix4<=i_hpix3; - - i_hnp1<=i_hnp; i_hnp2<=i_hnp1; i_hnp3<=i_hnp2; i_hnp4<=i_hnp3; - i_ven1<=i_ven; i_ven2<=i_ven1; i_ven3<=i_ven2; i_ven4<=i_ven3; - i_ven5<=i_ven4; i_ven6<=i_ven5; - - -- C1 : DIV 1. Pipelined 4 bits non-restoring divider - dir_v:=x"000"; - div_v:=to_unsigned(i_hacc * 16,17); - - div_v:=div_v-to_unsigned(i_hsize*16,17); - dir_v(11):=NOT div_v(16); - IF div_v(16)='0' THEN - div_v:=div_v-to_unsigned(i_hsize*8,17); - ELSE - div_v:=div_v+to_unsigned(i_hsize*8,17); - END IF; - dir_v(10):=NOT div_v(16); - i_div<=div_v; - i_dir<=dir_v; - - -- C2 : DIV 2. - div_v:=i_div; - dir_v:=i_dir; - IF div_v(16)='0' THEN - div_v:=div_v-to_unsigned(i_hsize*4,17); - ELSE - div_v:=div_v+to_unsigned(i_hsize*4,17); - END IF; - dir_v(9):=NOT div_v(16); - IF div_v(16)='0' THEN - div_v:=div_v-to_unsigned(i_hsize*2,17); - ELSE - div_v:=div_v+to_unsigned(i_hsize*2,17); - END IF; - dir_v(8):=NOT div_v(16); - i_h_frac<=dir_v; - - -- C4 : Horizontal Bilinear - IF i_bil='0' THEN - frac_v:=near_frac(i_h_frac); - ELSE - frac_v:=bil_frac(i_h_frac); - END IF; - - i_h_bil_t<=bil_calc(frac_v,(i_hpix2,i_hpix2,i_hpix3,i_hpix3)); - i_hpix.r<=bound(i_h_bil_t.r,8+FRAC); - i_hpix.g<=bound(i_h_bil_t.g,8+FRAC); - i_hpix.b<=bound(i_h_bil_t.b,8+FRAC); - - IF i_hdown='0' THEN - i_hpix<=i_hpix4; - END IF; - - -- C5 : Vertical Bilinear - IF i_bil='0' THEN - frac_v:=near_frac(i_v_frac(11 DOWNTO 0)); - ELSE - frac_v:=bil_frac(i_v_frac(11 DOWNTO 0)); - END IF; - - bil_t_v:=bil_calc(frac_v,(i_hpix,i_hpix,i_ldrm,i_ldrm)); - i_pix.r<=bound(bil_t_v.r,8+FRAC); - i_pix.g<=bound(bil_t_v.g,8+FRAC); - i_pix.b<=bound(bil_t_v.b,8+FRAC); - - IF i_vdown='0' THEN - i_pix<=i_hpix; - END IF; - - ---------------------------------------------------- - -- VNP : Vert. downscaling line enable - -- HNP : Horiz. downscaling pix. enable - -- VEN : Enable pixel within displayed window - - IF (i_hnp4='1' AND i_ven6='1') OR i_pushend='1' THEN - i_shift<=shift_ishift(i_shift,i_pix,i_format); - i_dw<=shift_ipack(i_dw,i_acpt,i_shift,i_pix,i_format); - - IF shift_inext(i_acpt,i_format) AND i_vnp='1' THEN - i_push<='1'; - i_pushend<='0'; - END IF; - i_acpt<=(i_acpt+1) MOD 16; - END IF; - - IF i_ven6='1' AND i_ven5='0' AND i_vnp='1' THEN - i_pushend<='1'; - END IF; - i_pushend2<=i_pushend; - - IF i_pushend2='1' AND i_pushend='0' THEN - i_eol<='1'; - END IF; - - IF i_pde='0' AND i_de_pre='1' THEN - i_de_delay<=0; - ELSIF i_de_delay<18 THEN - i_de_delay<=i_de_delay+1; - END IF; - - IF i_de_delay=16 THEN - i_lwad<=0; - i_lrad<=0; - i_vcpt<=i_vcpt+1; - i_hacc<=(i_hsize - i_ohsize + 8192) MOD 8192; - i_hbcpt<=0; - END IF; - IF i_de_delay=17 THEN - i_acpt<=0; - i_wad<=2*BLEN-1; - END IF; - - IF i_pvs='0' AND i_vs_pre='1' THEN - -- Push header - i_pushhead<=to_std_logic(HEADER); - END IF; - - END IF; -- IF i_pce='1' - - ------------------------------------------------------ - -- Push pixels to downscaling line buffer - i_lwr<=i_hnp4 AND i_ven5 AND i_pce; - IF i_lwr='1' THEN - i_lwad<=(i_lwad+1) MOD OHRES; - END IF; - i_ldw<=i_hpix; - - IF i_hnp3='1' AND i_ven4='1' AND i_pce='1' THEN - i_lrad<=(i_lrad+1) MOD OHRES; - END IF; - - ------------------------------------------------------ - -- Write image properties header - i_pushhead2<=i_pushhead; i_pushhead3<=i_pushhead2; - - IF i_pushhead='1' AND i_freeze='0' THEN - i_dw<=i_head(127 DOWNTO 128-N_DW); - i_count<=i_count+1; - i_wr<='1'; - i_wad<=0; - IF N_DW=128 THEN - i_alt<='0'; - i_wreq<=NOT i_freeze; - i_adrs<=(OTHERS =>'0'); - END IF; - END IF; - - IF i_pushhead2='1' AND i_freeze='0' AND N_DW=64 THEN - i_dw<=i_head(N_DW-1 DOWNTO 0); - i_wr<='1'; - i_wad<=1; - i_wreq<=NOT i_freeze; - i_alt<='0'; - i_adrs<=(OTHERS =>'0'); - END IF; - IF i_pushhead3='1' THEN - i_wad<=BLEN-1; - END IF; - - ------------------------------------------------------ - -- Push pixels to DPRAM - IF i_push='1' AND i_freeze='0' THEN - i_wr<='1'; - i_wad<=(i_wad+1) MOD (BLEN*2); - IF (i_wad+1) MOD BLEN=BLEN-1 AND i_hbcpt 12 - IDividers:PROCESS (i_clk,i_reset_na) IS - BEGIN - IF i_reset_na='0' THEN + ----------------------------------------------------------------------------- + i_reset_na<='0' WHEN reset_na='0' ELSE '1' WHEN rising_edge(i_clk); + o_reset_na<='0' WHEN reset_na='0' ELSE '1' WHEN rising_edge(o_clk); + avl_reset_na<='0' WHEN reset_na='0' ELSE '1' WHEN rising_edge(avl_clk); + + ----------------------------------------------------------------------------- + -- Input pixels FIFO and shreg + InAT:PROCESS(i_clk,i_reset_na) IS + CONSTANT Z : unsigned(FRAC-1 DOWNTO 0):=(OTHERS =>'0'); + VARIABLE frac_v : unsigned(FRAC-1 DOWNTO 0); + VARIABLE div_v : unsigned(16 DOWNTO 0); + VARIABLE dir_v : unsigned(11 DOWNTO 0); + VARIABLE bil_t_v : type_bil_t; + BEGIN + IF i_reset_na='0' THEN + i_write<='0'; + + ELSIF rising_edge(i_clk) THEN + i_push<='0'; + i_pushhead<='0'; + i_eol<='0'; -- End Of Line + i_freeze <=freeze; -- + i_iauto<=iauto; -- + i_wreq<='0'; + i_wr<='0'; + + ------------------------------------------------------ + i_head(127 DOWNTO 120)<=x"01"; -- Header type + i_head(119 DOWNTO 112)<="000000" & i_format; -- Header format + i_head(111 DOWNTO 96)<="0000" & to_unsigned(N_BURST,12); -- Header size + i_head(95 DOWNTO 80)<=x"0000"; -- Attributes. TBD + i_head(80)<=i_inter; + i_head(81)<=i_flm; + i_head(82)<=i_hdown; + i_head(83)<=i_vdown; + i_head(84)<=i_mode(3); + i_head(87 DOWNTO 85)<=i_count; + i_head(79 DOWNTO 64)<="0000" & to_unsigned(i_hrsize,12); -- Image width + i_head(63 DOWNTO 48)<="0000" & to_unsigned(i_vrsize,12); -- Image height + i_head(47 DOWNTO 32)<= to_unsigned(N_BURST * i_hburst,16); -- Line Length. Bytes + i_head(31 DOWNTO 16)<="0000" & to_unsigned(i_ohsize,12); + i_head(15 DOWNTO 0) <="0000" & to_unsigned(i_ovsize,12); + + ------------------------------------------------------ + i_ppix<=(i_r,i_g,i_b); + i_pvs<=i_vs; + i_pfl<=i_fl; + i_pde<=i_de; + i_pce<=i_ce; + + ------------------------------------------------------ + IF i_pce='1' THEN + ---------------------------------------------------- + i_vs_pre<=i_pvs; + i_de_pre<=i_pde; + i_fl_pre<=i_pfl; + + ---------------------------------------------------- + -- Detect interlaced video + IF NOT INTER THEN + i_intercnt<=0; + ELSIF i_pfl/=i_fl_pre THEN + i_intercnt<=3; + ELSIF i_pvs='1' AND i_vs_pre='0' AND i_intercnt>0 THEN + i_intercnt<=i_intercnt-1; + END IF; + i_inter<=to_std_logic(i_intercnt>0); + + ---------------------------------------------------- + IF i_pvs='1' AND i_vs_pre='0' THEN + i_sof<='1'; + END IF; + + IF i_pde='1' AND i_de_pre='0' THEN + i_flm<=i_pfl; + END IF; + + IF i_pde='1' AND i_sof='1' THEN + i_sof<='0'; + i_vcpt<=0; + IF i_inter='1' AND i_flm='0' AND i_half='0' AND INTER THEN + i_line<='1'; + i_adrsi<=to_unsigned(N_BURST * i_hburst,32) + + to_unsigned(N_BURST * to_integer( + unsigned'("00") & to_std_logic(HEADER)),32); + ELSE + i_line<='0'; + i_adrsi<=to_unsigned(N_BURST * to_integer( + unsigned'("00") & to_std_logic(HEADER)),32); + END IF; + END IF; + + i_ven<=to_std_logic(i_hcpt>=i_hmin AND i_hcpt<=i_hmax AND + i_vcpt>=i_vmin AND i_vcpt<=i_vmax); + + -- Detects end of frame for triple buffering. + i_endframe0<=i_vs AND (NOT i_inter OR i_flm); + i_endframe1<=i_vs AND (NOT i_inter OR NOT i_flm); + + i_vss<=to_std_logic(i_vcpt>=i_vmin AND i_vcpt<=i_vmax); + + ---------------------------------------------------- + IF i_pde='1' AND i_de_pre='0' THEN + i_vimax<=i_vcpt; + i_hcpt<=0; + ELSE + i_hcpt<=(i_hcpt+1) MOD 4096; + END IF; + + IF i_pde='0' AND i_de_pre='1' THEN + i_himax<=i_hcpt; + END IF; + + IF i_iauto='1' THEN + -- Auto-size + i_hmin<=0; + i_hmax<=i_himax; + i_vmin<=0; + IF i_pvs='1' AND i_vs_pre='0' AND (i_inter='0' OR i_pfl='0') THEN + i_vmax<=i_vimax; + END IF; + ELSE + -- Forced image + i_hmin<=himin; -- + i_hmax<=himax; -- + i_vmin<=vimin; -- + IF i_pvs='1' AND i_vs_pre='0' AND (i_inter='0' OR i_pfl='0') THEN + i_vmax<=vimax; -- + END IF; + END IF; + + IF i_pvs='1' AND i_vs_pre='0' AND (i_inter='0' OR i_pfl='0') THEN + i_vdmax<=i_vimax; + END IF; + i_hdmax<=i_himax; + + IF i_format="00" OR i_format="11" THEN -- 16bpp + i_hburst<=(i_hrsize*2 + N_BURST - 1) / N_BURST; + ELSIF i_format="01" THEN -- 24bpp + i_hburst<=(i_hrsize*3 + N_BURST - 1) / N_BURST; + ELSE -- 32bpp + i_hburst<=(i_hrsize*4 + N_BURST - 1) / N_BURST; + END IF; + ---------------------------------------------------- + i_mode<=mode; -- + i_format<=format; -- + + -- Downscaling : Nearest or bilinear + i_bil<=to_std_logic(i_mode(2 DOWNTO 0)/="000" AND NOT DOWNSCALE_NN); + + i_hdown<=to_std_logic(i_hsize>i_ohsize AND DOWNSCALE); --H downscale + i_vdown<=to_std_logic(i_vsize>i_ovsize AND DOWNSCALE); --V downscale + + ---------------------------------------------------- + i_hsize <=(4096+i_hmax-i_hmin+1) MOD 4096; + i_vmaxmin<=(4096+i_vmax-i_vmin+1) MOD 4096; + + IF i_inter='0' THEN + -- Non interlaced + i_vsize<=i_vmaxmin; + i_half <='0'; + ELSIF i_ovsize<2*i_vmaxmin THEN + -- Interlaced, but downscaling, use only half frames + i_vsize<=i_vmaxmin; + i_half <='1'; + ELSE + -- Interlaced : Double image height + i_vsize<=2*i_vmaxmin; + i_half <='0'; + END IF; + + i_ohsize<=o_hsize; -- + i_ovsize<=o_vsize; -- + + ---------------------------------------------------- + -- Downscaling vertical + i_divstart<='0'; + IF i_de_delay=16 THEN + IF (i_vacc + 2*i_ovsize) < 2*i_vsize THEN + i_vacc<=(i_vacc + 2*i_ovsize) MOD 8192; + i_vnp<='0'; + ELSE + i_vacc<=(i_vacc + 2*i_ovsize - 2*i_vsize + 8192) MOD 8192; + i_vnp<='1'; + END IF; + i_divstart<='1'; + + IF i_vcpt=i_vmin THEN + i_vacc<=(i_vsize - i_ovsize + 8192) MOD 8192; + i_vnp<='1'; -- + END IF; + END IF; + + IF i_vdown='0' THEN + i_vnp<='1'; + END IF; + + -- Downscaling horizontal + IF i_ven='1' THEN + IF i_hacc + 2*i_ohsize < 2*i_hsize THEN + i_hacc<=(i_hacc + 2*i_ohsize) MOD 8192; + i_hnp<='0'; -- Skip. pix. + ELSE + i_hacc<=(i_hacc + 2*i_ohsize - 2*i_hsize + 8192) MOD 8192; + i_hnp<='1'; + END IF; + END IF; + IF i_hdown='0' THEN + i_hnp<='1'; + END IF; + + ---------------------------------------------------- + -- Downscaling interpolation + i_hpixp<=i_ppix; + i_hpix0<=i_hpixp; + i_hpix1<=i_hpix0; + i_hpix2<=i_hpix1; + i_hpix3<=i_hpix2; + i_hpix4<=i_hpix3; + + i_hnp1<=i_hnp; i_hnp2<=i_hnp1; i_hnp3<=i_hnp2; i_hnp4<=i_hnp3; + i_ven1<=i_ven; i_ven2<=i_ven1; i_ven3<=i_ven2; i_ven4<=i_ven3; + i_ven5<=i_ven4; i_ven6<=i_ven5; + + -- C1 : DIV 1. Pipelined 4 bits non-restoring divider + dir_v:=x"000"; + div_v:=to_unsigned(i_hacc * 16,17); + + div_v:=div_v-to_unsigned(i_hsize*16,17); + dir_v(11):=NOT div_v(16); + IF div_v(16)='0' THEN + div_v:=div_v-to_unsigned(i_hsize*8,17); + ELSE + div_v:=div_v+to_unsigned(i_hsize*8,17); + END IF; + dir_v(10):=NOT div_v(16); + i_div<=div_v; + i_dir<=dir_v; + + -- C2 : DIV 2. + div_v:=i_div; + dir_v:=i_dir; + IF div_v(16)='0' THEN + div_v:=div_v-to_unsigned(i_hsize*4,17); + ELSE + div_v:=div_v+to_unsigned(i_hsize*4,17); + END IF; + dir_v(9):=NOT div_v(16); + + IF div_v(16)='0' THEN + div_v:=div_v-to_unsigned(i_hsize*2,17); + ELSE + div_v:=div_v+to_unsigned(i_hsize*2,17); + END IF; + dir_v(8):=NOT div_v(16); + i_h_frac<=dir_v; + + -- C4 : Horizontal Bilinear + IF i_bil='0' THEN + frac_v:=near_frac(i_h_frac); + i_h_bil_t<=near_calc(frac_v,(i_hpix2,i_hpix2,i_hpix3,i_hpix3)); + ELSE + frac_v:=bil_frac(i_h_frac); + i_h_bil_t<=bil_calc(frac_v,(i_hpix2,i_hpix2,i_hpix3,i_hpix3)); + END IF; + + i_hpix.r<=bound(i_h_bil_t.r,8+FRAC); + i_hpix.g<=bound(i_h_bil_t.g,8+FRAC); + i_hpix.b<=bound(i_h_bil_t.b,8+FRAC); + + IF i_hdown='0' THEN + i_hpix<=i_hpix4; + END IF; + + -- C5 : Vertical Bilinear + IF i_bil='0' THEN + frac_v:=near_frac(i_v_frac(11 DOWNTO 0)); + bil_t_v:=near_calc(frac_v,(i_hpix,i_hpix,i_ldrm,i_ldrm)); + ELSE + frac_v:=bil_frac(i_v_frac(11 DOWNTO 0)); + bil_t_v:=bil_calc(frac_v,(i_hpix,i_hpix,i_ldrm,i_ldrm)); + END IF; + + i_pix.r<=bound(bil_t_v.r,8+FRAC); + i_pix.g<=bound(bil_t_v.g,8+FRAC); + i_pix.b<=bound(bil_t_v.b,8+FRAC); + + IF i_vdown='0' THEN + i_pix<=i_hpix; + END IF; + + ---------------------------------------------------- + -- VNP : Vert. downscaling line enable + -- HNP : Horiz. downscaling pix. enable + -- VEN : Enable pixel within displayed window + + IF (i_hnp4='1' AND i_ven6='1') OR i_pushend='1' THEN + i_shift<=shift_ishift(i_shift,i_pix,i_format); + i_dw<=shift_ipack(i_dw,i_acpt,i_shift,i_pix,i_format); + + IF shift_inext(i_acpt,i_format) AND i_vnp='1' THEN + i_push<='1'; + i_pushend<='0'; + END IF; + i_acpt<=(i_acpt+1) MOD 16; + END IF; + + IF i_ven6='1' AND i_ven5='0' AND i_vnp='1' THEN + i_pushend<='1'; + END IF; + i_pushend2<=i_pushend; + + IF i_pushend2='1' AND i_pushend='0' THEN + i_eol<='1'; + END IF; + + IF i_pde='0' AND i_de_pre='1' THEN + i_de_delay<=0; + ELSIF i_de_delay<18 THEN + i_de_delay<=i_de_delay+1; + END IF; + + IF i_de_delay=16 THEN + i_lwad<=0; + i_lrad<=0; + i_vcpt<=i_vcpt+1; + i_hacc<=(i_hsize - i_ohsize + 8192) MOD 8192; + i_hbcpt<=0; + END IF; + IF i_de_delay=17 THEN + i_acpt<=0; + i_wad<=2*BLEN-1; + END IF; + + IF i_pvs='0' AND i_vs_pre='1' THEN + -- Push header + i_pushhead<=to_std_logic(HEADER); + END IF; + + END IF; -- IF i_pce='1' + + ------------------------------------------------------ + -- Push pixels to downscaling line buffer + i_lwr<=i_hnp4 AND i_ven5 AND i_pce; + IF i_lwr='1' THEN + i_lwad<=(i_lwad+1) MOD OHRES; + END IF; + i_ldw<=i_hpix; + + IF i_hnp3='1' AND i_ven4='1' AND i_pce='1' THEN + i_lrad<=(i_lrad+1) MOD OHRES; + END IF; + + ------------------------------------------------------ + -- Write image properties header + i_pushhead2<=i_pushhead; i_pushhead3<=i_pushhead2; + + IF i_pushhead='1' AND i_freeze='0' THEN + i_dw<=i_head(127 DOWNTO 128-N_DW); + i_count<=i_count+1; + i_wr<='1'; + i_wad<=0; + IF N_DW=128 THEN + i_alt<='0'; + i_wreq<=NOT i_freeze; + i_adrs<=(OTHERS =>'0'); + END IF; + END IF; + + IF i_pushhead2='1' AND i_freeze='0' AND N_DW=64 THEN + i_dw<=i_head(N_DW-1 DOWNTO 0); + i_wr<='1'; + i_wad<=1; + i_wreq<=NOT i_freeze; + i_alt<='0'; + i_adrs<=(OTHERS =>'0'); + END IF; + IF i_pushhead3='1' THEN + i_wad<=BLEN-1; + END IF; + + ------------------------------------------------------ + -- Push pixels to DPRAM + IF i_push='1' AND i_freeze='0' THEN + i_wr<='1'; + i_wad<=(i_wad+1) MOD (BLEN*2); + IF (i_wad+1) MOD BLEN=BLEN-1 AND i_hbcpt 12 + IDividers:PROCESS (i_clk,i_reset_na) IS + BEGIN + IF i_reset_na='0' THEN --pragma synthesis_off - i_v_frac<=x"000"; + i_v_frac<=x"000"; --pragma synthesis_on - NULL; - ELSIF rising_edge(i_clk) THEN - i_vdivi<=to_unsigned(2*i_vsize,13); - i_vdivr<=to_unsigned(i_vacc*4096,25); - - ------------------------------------------------------ - IF i_divstart='1' THEN - i_divcpt<=0; - i_divrun<='1'; - - ELSIF i_divrun='1' THEN - ---------------------------------------------------- - IF i_divcpt=6 THEN - i_divrun<='0'; - i_v_frac<=i_vdivr(4 DOWNTO 0) & NOT i_vdivr(24) & "000000"; - ELSE - i_divcpt<=i_divcpt+1; - END IF; - - IF i_vdivr(24)='0' THEN - i_vdivr(24 DOWNTO 12)<=i_vdivr(23 DOWNTO 11) - i_vdivi; - ELSE - i_vdivr(24 DOWNTO 12)<=i_vdivr(23 DOWNTO 11) + i_vdivi; - END IF; - i_vdivr(11 DOWNTO 0)<=i_vdivr(10 DOWNTO 0) & NOT i_vdivr(24); - - ---------------------------------------------------- - END IF; - END IF; - END PROCESS IDividers; + NULL; + ELSIF rising_edge(i_clk) THEN + i_vdivi<=to_unsigned(2*i_vsize,13); + i_vdivr<=to_unsigned(i_vacc*4096,25); - ----------------------------------------------------------------------------- - -- DPRAM Input. Double buffer for RAM bursts. - PROCESS (i_clk) IS - BEGIN - IF rising_edge(i_clk) THEN - IF i_wr='1' THEN - i_dpram(i_wad)<=i_dw; - END IF; - END IF; - END PROCESS; - - avl_dr<=i_dpram(avl_rad_c) WHEN rising_edge(avl_clk); - - -- Line buffer for downscaling with interpolation - DownLine:IF DOWNSCALE GENERATE - ILBUF:PROCESS(i_clk) IS - BEGIN - IF rising_edge(i_clk) THEN - IF i_lwr='1' THEN - i_mem(i_lwad MOD IHRES)<=i_ldw; - END IF; - IF i_pce='1' THEN - i_ldrm<=i_mem(i_lrad MOD IHRES); - END IF; - END IF; - END PROCESS ILBUF; - END GENERATE DownLine; - - ----------------------------------------------------------------------------- - -- AVALON interface - Avaloir:PROCESS(avl_clk,avl_reset_na) IS - VARIABLE adr_v : unsigned(31 DOWNTO 0); - BEGIN - IF avl_reset_na='0' THEN - avl_state<=sIDLE; - avl_write_sr<='0'; - avl_read_sr<='0'; - avl_readdataack<='0'; - avl_readack<='0'; - - ELSIF rising_edge(avl_clk) THEN - ---------------------------------- - avl_write_sync<=i_write; -- - avl_write_sync2<=avl_write_sync; - avl_write_pulse<=avl_write_sync XOR avl_write_sync2; - IF avl_write_pulse='1' THEN - avl_wadrs <=i_wadrs AND (RAMSIZE - 1); -- - avl_wline <=i_wline; -- - avl_walt <=i_walt; -- - END IF; - - ---------------------------------- - 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; -- - avl_rline <=o_rline; -- - - -------------------------------------------- - avl_o_vs_sync<=o_vsv(0); -- - avl_o_vs<=avl_o_vs_sync; - - avl_fb_ena<=o_fb_ena; -- - IF avl_fb_ena='0' THEN - IF HEADER THEN - avl_o_offset0<=buf_offset(o_obuf0,RAMBASE,RAMSIZE) + N_BURST; -- - avl_o_offset1<=buf_offset(o_obuf1,RAMBASE,RAMSIZE) + N_BURST; -- - ELSE - avl_o_offset0<=buf_offset(o_obuf0,RAMBASE,RAMSIZE); -- - avl_o_offset1<=buf_offset(o_obuf1,RAMBASE,RAMSIZE); -- - END IF; - ELSIF avl_o_vs_sync='0' AND avl_o_vs='1' THEN - -- Copy framebuffer base address at VS falling edge - avl_o_offset0<=o_fb_base; -- - avl_o_offset1<=o_fb_base; -- - END IF; - - avl_i_offset0<=buf_offset(o_ibuf0,RAMBASE,RAMSIZE); -- - avl_i_offset1<=buf_offset(o_ibuf1,RAMBASE,RAMSIZE); -- - - -------------------------------------------- - avl_dw<=swap(unsigned(avl_readdata)); - avl_read_i<='0'; - avl_write_i<='0'; - - avl_write_sr<=(avl_write_sr OR avl_write_pulse) AND NOT avl_write_clr; - avl_read_sr <=(avl_read_sr OR avl_read_pulse) AND NOT avl_read_clr; - avl_write_clr<='0'; - avl_read_clr <='0'; - - avl_rad<=avl_rad_c; - - -------------------------------------------- - CASE avl_state IS - WHEN sIDLE => - IF avl_write_sr='1' THEN - avl_state<=sWRITE; - avl_write_clr<='1'; - IF avl_walt='0' THEN - avl_rad<=0; - ELSE - avl_rad<=BLEN; - END IF; - IF avl_wline='0' THEN - avl_address<=std_logic_vector( - avl_wadrs(N_AW+NB_LA-1 DOWNTO NB_LA) + - avl_i_offset0(N_AW+NB_LA-1 DOWNTO NB_LA)); - ELSE - avl_address<=std_logic_vector( - avl_wadrs(N_AW+NB_LA-1 DOWNTO NB_LA) + - avl_i_offset1(N_AW+NB_LA-1 DOWNTO NB_LA)); - END IF; - ELSIF avl_read_sr='1' THEN - avl_state<=sREAD; - avl_read_clr<='1'; - END IF; - - WHEN sWRITE => - avl_write_i<='1'; - IF avl_write_i='1' AND avl_waitrequest='0' THEN - IF (avl_rad MOD BLEN)=BLEN-1 THEN - avl_write_i<='0'; - avl_state<=sIDLE; - END IF; - END IF; - - WHEN sREAD => - IF avl_rline='0' THEN - adr_v:=avl_radrs + avl_o_offset0; - ELSE - adr_v:=avl_radrs + avl_o_offset1; - END IF; - avl_address<=std_logic_vector(adr_v(N_AW+NB_LA-1 DOWNTO NB_LA)); - - avl_read_i<='1'; - IF avl_read_i='1' AND avl_waitrequest='0' THEN - avl_state<=sIDLE; - avl_read_i<='0'; - avl_readack<=NOT avl_readack; - END IF; - END CASE; - - -------------------------------------------- - -- Pipelined data read - avl_wr<='0'; - IF avl_readdatavalid='1' THEN - avl_wr<='1'; - avl_wad<=(avl_wad+1) MOD (2*BLEN); - IF (avl_wad MOD BLEN)=BLEN-2 THEN - avl_readdataack<=NOT avl_readdataack; - END IF; - END IF; + ------------------------------------------------------ + IF i_divstart='1' THEN + i_divcpt<=0; + i_divrun<='1'; - IF avl_o_vs_sync='0' AND avl_o_vs='1' THEN - avl_wad<=2*BLEN-1; - END IF; - - -------------------------------------------- - END IF; - END PROCESS Avaloir; - - avl_read<=avl_read_i; - avl_write<=avl_write_i; - avl_writedata<=std_logic_vector(swap(avl_dr)); - avl_burstcount<=std_logic_vector(to_unsigned(BLEN,8)); - avl_byteenable<=(OTHERS =>'1'); - - avl_rad_c<=(avl_rad+1) MOD (2*BLEN) - WHEN avl_write_i='1' AND avl_waitrequest='0' ELSE avl_rad; - - ----------------------------------------------------------------------------- - -- DPRAM Output. Double buffer for RAM bursts. - PROCESS (avl_clk) IS - BEGIN - IF rising_edge(avl_clk) THEN - IF avl_wr='1' THEN - o_dpram(avl_wad)<=avl_dw; - END IF; - END IF; - END PROCESS; - - o_dr<=o_dpram(o_ad3) WHEN rising_edge(o_clk); - - ----------------------------------------------------------------------------- - -- Output Vertical Divider - -- Vfrac = Vacc / Vsize - ODivider:PROCESS (o_clk,o_reset_na) IS - BEGIN - IF o_reset_na='0' THEN + ELSIF i_divrun='1' THEN + ---------------------------------------------------- + IF i_divcpt=6 THEN + i_divrun<='0'; + i_v_frac<=i_vdivr(4 DOWNTO 0) & NOT i_vdivr(24) & "000000"; + ELSE + i_divcpt<=i_divcpt+1; + END IF; + + IF i_vdivr(24)='0' THEN + i_vdivr(24 DOWNTO 12)<=i_vdivr(23 DOWNTO 11) - i_vdivi; + ELSE + i_vdivr(24 DOWNTO 12)<=i_vdivr(23 DOWNTO 11) + i_vdivi; + END IF; + i_vdivr(11 DOWNTO 0)<=i_vdivr(10 DOWNTO 0) & NOT i_vdivr(24); + + ---------------------------------------------------- + END IF; + END IF; + END PROCESS IDividers; + + ----------------------------------------------------------------------------- + -- DPRAM Input. Double buffer for RAM bursts. + PROCESS (i_clk) IS + BEGIN + IF rising_edge(i_clk) THEN + IF i_wr='1' THEN + i_dpram(i_wad)<=i_dw; + END IF; + END IF; + END PROCESS; + + avl_dr<=i_dpram(avl_rad_c) WHEN rising_edge(avl_clk); + + -- Line buffer for downscaling with interpolation + DownLine:IF DOWNSCALE GENERATE + ILBUF:PROCESS(i_clk) IS + BEGIN + IF rising_edge(i_clk) THEN + IF i_lwr='1' THEN + i_mem(i_lwad MOD IHRES)<=i_ldw; + END IF; + IF i_pce='1' THEN + i_ldrm<=i_mem(i_lrad MOD IHRES); + END IF; + END IF; + END PROCESS ILBUF; + END GENERATE DownLine; + + ----------------------------------------------------------------------------- + -- AVALON interface + Avaloir:PROCESS(avl_clk,avl_reset_na) IS + VARIABLE adr_v : unsigned(31 DOWNTO 0); + BEGIN + IF avl_reset_na='0' THEN + avl_state<=sIDLE; + avl_write_sr<='0'; + avl_read_sr<='0'; + avl_readdataack<='0'; + avl_readack<='0'; + + ELSIF rising_edge(avl_clk) THEN + ---------------------------------- + avl_write_sync<=i_write; -- + avl_write_sync2<=avl_write_sync; + avl_write_pulse<=avl_write_sync XOR avl_write_sync2; + IF avl_write_pulse='1' THEN + avl_wadrs <=i_wadrs AND (RAMSIZE - 1); -- + avl_wline <=i_wline; -- + avl_walt <=i_walt; -- + END IF; + + ---------------------------------- + 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; -- + avl_rline <=o_rline; -- + + -------------------------------------------- + avl_o_vs_sync<=o_vsv(0); -- + avl_o_vs<=avl_o_vs_sync; + + avl_fb_ena<=o_fb_ena; -- + IF avl_fb_ena='0' THEN + IF HEADER THEN + avl_o_offset0<=buf_offset(o_obuf0,RAMBASE,RAMSIZE) + N_BURST; -- + avl_o_offset1<=buf_offset(o_obuf1,RAMBASE,RAMSIZE) + N_BURST; -- + ELSE + avl_o_offset0<=buf_offset(o_obuf0,RAMBASE,RAMSIZE); -- + avl_o_offset1<=buf_offset(o_obuf1,RAMBASE,RAMSIZE); -- + END IF; + ELSIF avl_o_vs_sync='0' AND avl_o_vs='1' THEN + -- Copy framebuffer base address at VS falling edge + avl_o_offset0<=o_fb_base; -- + avl_o_offset1<=o_fb_base; -- + END IF; + + avl_i_offset0<=buf_offset(o_ibuf0,RAMBASE,RAMSIZE); -- + avl_i_offset1<=buf_offset(o_ibuf1,RAMBASE,RAMSIZE); -- + + -------------------------------------------- + avl_dw<=swap(unsigned(avl_readdata)); + avl_read_i<='0'; + avl_write_i<='0'; + + avl_write_sr<=(avl_write_sr OR avl_write_pulse) AND NOT avl_write_clr; + avl_read_sr <=(avl_read_sr OR avl_read_pulse) AND NOT avl_read_clr; + avl_write_clr<='0'; + avl_read_clr <='0'; + + avl_rad<=avl_rad_c; + + -------------------------------------------- + CASE avl_state IS + WHEN sIDLE => + IF avl_write_sr='1' THEN + avl_state<=sWRITE; + avl_write_clr<='1'; + IF avl_walt='0' THEN + avl_rad<=0; + ELSE + avl_rad<=BLEN; + END IF; + IF avl_wline='0' THEN + avl_address<=std_logic_vector( + avl_wadrs(N_AW+NB_LA-1 DOWNTO NB_LA) + + avl_i_offset0(N_AW+NB_LA-1 DOWNTO NB_LA)); + ELSE + avl_address<=std_logic_vector( + avl_wadrs(N_AW+NB_LA-1 DOWNTO NB_LA) + + avl_i_offset1(N_AW+NB_LA-1 DOWNTO NB_LA)); + END IF; + ELSIF avl_read_sr='1' THEN + avl_state<=sREAD; + avl_read_clr<='1'; + END IF; + + WHEN sWRITE => + avl_write_i<='1'; + IF avl_write_i='1' AND avl_waitrequest='0' THEN + IF (avl_rad MOD BLEN)=BLEN-1 THEN + avl_write_i<='0'; + avl_state<=sIDLE; + END IF; + END IF; + + WHEN sREAD => + IF avl_rline='0' THEN + adr_v:=avl_radrs + avl_o_offset0; + ELSE + adr_v:=avl_radrs + avl_o_offset1; + END IF; + avl_address<=std_logic_vector(adr_v(N_AW+NB_LA-1 DOWNTO NB_LA)); + + avl_read_i<='1'; + IF avl_read_i='1' AND avl_waitrequest='0' THEN + avl_state<=sIDLE; + avl_read_i<='0'; + avl_readack<=NOT avl_readack; + END IF; + END CASE; + + -------------------------------------------- + -- Pipelined data read + avl_wr<='0'; + IF avl_readdatavalid='1' THEN + avl_wr<='1'; + avl_wad<=(avl_wad+1) MOD (2*BLEN); + IF (avl_wad MOD BLEN)=BLEN-2 THEN + avl_readdataack<=NOT avl_readdataack; + END IF; + END IF; + + IF avl_o_vs_sync='0' AND avl_o_vs='1' THEN + avl_wad<=2*BLEN-1; + END IF; + + -------------------------------------------- + END IF; + END PROCESS Avaloir; + + avl_read<=avl_read_i; + avl_write<=avl_write_i; + avl_writedata<=std_logic_vector(swap(avl_dr)); + avl_burstcount<=std_logic_vector(to_unsigned(BLEN,8)); + avl_byteenable<=(OTHERS =>'1'); + + avl_rad_c<=(avl_rad+1) MOD (2*BLEN) + WHEN avl_write_i='1' AND avl_waitrequest='0' ELSE avl_rad; + + ----------------------------------------------------------------------------- + -- DPRAM Output. Double buffer for RAM bursts. + PROCESS (avl_clk) IS + BEGIN + IF rising_edge(avl_clk) THEN + IF avl_wr='1' THEN + o_dpram(avl_wad)<=avl_dw; + END IF; + END IF; + END PROCESS; + + o_dr<=o_dpram(o_ad3) WHEN rising_edge(o_clk); + + ----------------------------------------------------------------------------- + -- Output Vertical Divider + -- Vfrac = Vacc / Vsize + ODivider:PROCESS (o_clk,o_reset_na) IS + BEGIN + IF o_reset_na='0' THEN --pragma synthesis_off - o_vfrac<=x"000"; + o_vfrac<=x"000"; --pragma synthesis_on - ELSIF rising_edge(o_clk) THEN - o_vdivi<=to_unsigned(2*o_vsize,13); - o_vdivr<=to_unsigned(o_vacc*4096,25); - ------------------------------------------------------ - IF o_divstart='1' THEN - o_divcpt<=0; - o_divrun<='1'; - - ELSIF o_divrun='1' THEN - ---------------------------------------------------- - IF o_divcpt=12 THEN - o_divrun<='0'; - o_vfrac<=o_vdivr(10 DOWNTO 0) & NOT o_vdivr(24); - ELSE - o_divcpt<=o_divcpt+1; - END IF; - - IF o_vdivr(24)='0' THEN - o_vdivr(24 DOWNTO 12)<=o_vdivr(23 DOWNTO 11) - o_vdivi; - ELSE - o_vdivr(24 DOWNTO 12)<=o_vdivr(23 DOWNTO 11) + o_vdivi; - END IF; - o_vdivr(11 DOWNTO 0)<=o_vdivr(10 DOWNTO 0) & NOT o_vdivr(24); - ---------------------------------------------------- - END IF; - END IF; - END PROCESS ODivider; - - ----------------------------------------------------------------------------- - Scalaire:PROCESS (o_clk,o_reset_na) IS - VARIABLE lev_inc_v,lev_dec_v : std_logic; - VARIABLE prim_v,last_v,bib_v : std_logic; - VARIABLE shift_v : unsigned(0 TO N_DW+15); - VARIABLE hpix_v : type_pix; - VARIABLE hcarry_v,vcarry_v : boolean; - VARIABLE dif_v : natural RANGE 0 TO 8*OHRES-1; - VARIABLE off_v : natural RANGE 0 TO 15; - BEGIN - IF o_reset_na='0' THEN - o_copy<=sWAIT; - o_state<=sDISP; - o_read_pre<='0'; - o_readlev<=0; - o_copylev<=0; - o_hsp<='0'; - - ELSIF rising_edge(o_clk) THEN - ------------------------------------------------------ - o_mode <=mode; -- ? - o_format <="0001" & format; -- ? - - o_run <=run; -- ? - - o_htotal <=htotal; -- ? - o_hsstart<=hsstart; -- ? - o_hsend <=hsend; -- ? - o_hdisp <=hdisp; -- ? - o_hmin <=hmin; -- ? - o_hmax <=hmax; -- ? - - o_vtotal <=vtotal; -- ? - o_vsstart<=vsstart; -- ? - o_vsend <=vsend; -- ? - o_vdisp <=vdisp; -- ? - o_vmin <=vmin; -- ? - o_vmax <=vmax; -- ? - - o_hsize <=o_hmax - o_hmin + 1; - o_vsize <=o_vmax - o_vmin + 1; - - -------------------------------------------- - -- Triple buffering. - -- For intelaced video, half frames are updated independently - -- Input : Toggle buffer at end of input frame - o_freeze <= freeze; - o_inter <=i_inter; -- - o_iendframe0<=i_endframe0; -- - o_iendframe02<=o_iendframe0; - IF o_iendframe0='1' AND o_iendframe02='0' THEN - o_ibuf0<=buf_next(o_ibuf0,o_obuf0,o_freeze); - o_bufup0<='1'; - END IF; - o_iendframe1<=i_endframe1; -- - o_iendframe12<=o_iendframe1; - IF o_iendframe1='1' AND o_iendframe12='0' THEN - o_ibuf1<=buf_next(o_ibuf1,o_obuf1,o_freeze); - o_bufup1<='1'; - END IF; - - -- Output : Change framebuffer, and image properties, at VS falling edge - IF o_vsv(1)='1' AND o_vsv(0)='0' AND o_bufup0='1' THEN - o_obuf0<=buf_next(o_obuf0,o_ibuf0,o_freeze); - o_bufup0<='0'; - END IF; - IF o_vsv(1)='1' AND o_vsv(0)='0' AND o_bufup1='1' THEN - o_obuf1<=buf_next(o_obuf1,o_ibuf1,o_freeze); - o_bufup1<='0'; - o_ihsize<=i_hrsize; -- - o_ivsize<=i_vrsize; -- - o_hdown<=i_hdown; -- - o_vdown<=i_vdown; -- - END IF; - - -- Simultaneous change of input and output framebuffers - IF o_vsv(1)='1' AND o_vsv(0)='0' AND - o_iendframe0='1' AND o_iendframe02='0' THEN - o_bufup0<='0'; - o_obuf0<=o_ibuf0; - END IF; - IF o_vsv(1)='1' AND o_vsv(0)='0' AND - o_iendframe1='1' AND o_iendframe12='0' THEN - o_bufup1<='0'; - o_obuf1<=o_ibuf1; - END IF; - - -- Non-interlaced, use same buffer for even and odd lines - IF o_inter='0' THEN - o_ibuf1<=o_ibuf0; - o_obuf1<=o_obuf0; - END IF; - - -- Triple buffer disabled - IF o_mode(3)='0' THEN - o_obuf0<=0; - o_obuf1<=0; - o_ibuf0<=0; - o_ibuf1<=0; - END IF; - - -- Framebuffer mode. - IF o_fb_ena='1' THEN - o_ihsize<=o_fb_hsize; - o_ivsize<=o_fb_vsize; - o_format<=o_fb_format; - o_hdown<='0'; - o_vdown<='0'; - END IF; - - o_ihsize_temp <= o_ihsize * to_integer(o_format(2 DOWNTO 0) - 2); - o_ihsize_temp2 <= (o_ihsize_temp + N_BURST - 1); - o_hburst <= o_ihsize_temp2 / N_BURST; - - IF o_fb_ena='1' AND o_fb_stride /= 0 THEN - o_stride<=o_fb_stride; - ELSE - o_stride<=to_unsigned(o_ihsize_temp2,14); - o_stride(NB_BURST-1 DOWNTO 0)<=(OTHERS =>'0'); - END IF; - ------------------------------------------------------ - o_hmode<=o_mode; - IF o_hdown='1' AND DOWNSCALE THEN - -- Force nearest if downscaling : Downscaled framebuffer - o_hmode(2 DOWNTO 0)<="000"; - END IF; - - o_vmode<=o_mode; - IF o_vdown='1' AND DOWNSCALE THEN - -- Force nearest if downscaling : Downscaled framebuffer - o_vmode(2 DOWNTO 0)<="000"; - END IF; - - ------------------------------------------------------ - -- End DRAM READ - o_readack_sync<=avl_readack; -- - o_readack_sync2<=o_readack_sync; - o_readack<=o_readack_sync XOR o_readack_sync2; - - o_readdataack_sync<=avl_readdataack; -- - o_readdataack_sync2<=o_readdataack_sync; - o_readdataack<=o_readdataack_sync XOR o_readdataack_sync2; - - ------------------------------------------------------ - lev_inc_v:='0'; - lev_dec_v:='0'; - - -- acpt : Pixel position within current data word - -- dcpt : Destination image position - - -- Force preload 2 lines at top of screen - IF o_hsv(0)='1' AND o_hsv(1)='0' THEN - IF o_vcpt_pre3=o_vmin THEN - o_fload<=2; - o_bibu<='0'; - END IF; - o_hsp<='1'; - END IF; - - o_vpe<=to_std_logic(o_vcpt_pre=o_vmin); - o_divstart<='0'; - o_adrsa<='0'; - o_adrsb<=o_adrsa; - - o_vacc_ini<=(o_vsize - o_ivsize + 8192) MOD 8192; - o_hacc_ini<=(o_hsize + o_ihsize + 8192) MOD 8192; - - --Alternate phase - --o_vacc_ini<=o_ivsize; - --o_hacc_ini<=(2*o_hsize - o_ihsize + 8192) MOD 8192; - - CASE o_state IS - -------------------------------------------------- - WHEN sDISP => - IF o_hsp='1' THEN - o_state<=sHSYNC; - o_hsp<='0'; - END IF; - - -------------------------------------------------- - WHEN sHSYNC => - dif_v:=(o_vacc_next - 2*o_vsize + 16384) MOD 16384; - IF dif_v>=8192 THEN - o_vacc <=o_vacc_next; - o_vacc_next<=(o_vacc_next + 2*o_ivsize) MOD 8192; - vcarry_v:=false; - ELSE - o_vacc <=dif_v; - o_vacc_next<=(dif_v + 2*o_ivsize + 8192) MOD 8192; - vcarry_v:=true; - END IF; - o_divstart<='1'; - IF o_vcpt_pre2=o_vmin THEN - o_vacc <=o_vacc_ini; - o_vacc_next<=o_vacc_ini + 2*o_ivsize; - o_vacpt<=x"001"; - vcarry_v:=false; - END IF; - - IF vcarry_v THEN - o_vacpt<=o_vacpt+1; - END IF; - o_hbcpt<=0; -- Clear burst counter on line - IF (o_vpe='1' AND vcarry_v) OR o_fload>0 THEN - o_state<=sREAD; - ELSE - o_state<=sDISP; - END IF; - - WHEN sREAD => - -- Read a block - IF o_readlev<2 AND o_adrsb='1' THEN - lev_inc_v:='1'; - o_read_pre<=NOT o_read_pre; - o_state <=sWAITREAD; - o_bibu<=NOT o_bibu; - END IF; - prim_v:=to_std_logic(o_hbcpt=0); - last_v:=to_std_logic(o_hbcpt=o_hburst-1); - bib_v :=o_bibu; - off_v :=pixoffset(o_adrs + o_fb_base(NB_LA-1 DOWNTO 0),o_fb_format); - IF o_fb_ena='0' THEN - off_v:=0; - END IF; - o_adrsa<='1'; - - WHEN sWAITREAD => - IF o_readack='1' THEN - o_hbcpt<=o_hbcpt+1; - IF o_hbcpt=1 THEN - o_fload<=o_fload-1; - END IF; - END IF; - END IF; - - -------------------------------------------------- - END CASE; - - o_read<=o_read_pre AND o_run; - o_rline<=o_vacpt(0); -- Even/Odd line for interlaced video - - o_adrs_pre<=to_integer(o_vacpt) * to_integer(o_stride); - IF o_adrsa='1' THEN - IF o_fload=2 THEN - o_adrs<=to_unsigned(o_hbcpt * N_BURST,32); - o_alt<="1111"; - ELSIF o_fload=1 THEN - o_adrs<=to_unsigned(o_hbcpt * N_BURST,32) + o_stride; - o_alt<="0100"; - ELSE - o_adrs<=to_unsigned(o_adrs_pre + (o_hbcpt * N_BURST),32); - o_alt<=altx(o_vacpt(1 DOWNTO 0) + 1); - END IF; - END IF; - - ------------------------------------------------------ - -- Copy from buffered memory to pixel lines - o_sh<='0'; - CASE o_copy IS - WHEN sWAIT => - o_copyv(0)<='0'; - IF o_copylev>0 AND o_copyv(0)='0' THEN - o_copy<=sCOPY; - IF o_off(0)>0 AND o_primv(0)='1' THEN - o_copy<=sSHIFT; - END IF; - o_altx<=o_alt; - END IF; - o_adturn<='0'; - o_pshift<=o_off(0) -1; - IF o_primv(0)='1' THEN - -- First memcopy of a horizontal line, carriage return ! - o_ihsizem<=o_ihsize + o_off(0) - 2; - o_hacc <=o_hacc_ini; - o_hacc_next<=o_hacc_ini + 2*o_ihsize; - o_hacpt <=x"000"; - o_dcpt<=0; - o_dshi<=2; - o_acpt<=0; - o_first<='1'; - o_last<='0'; - END IF; - - IF o_bibv(0)='0' THEN - o_ad<=0; - ELSE - o_ad<=BLEN; - END IF; - - WHEN sSHIFT => - o_hacpt<=o_hacpt+1; - o_sh<='1'; - o_acpt<=(o_acpt+1) MOD 16; - IF shift_onext(o_acpt,o_format) THEN - o_ad<=(o_ad+1) MOD (2*BLEN); - END IF; - o_pshift<=o_pshift-1; - IF o_pshift=0 THEN - o_copy<=sCOPY; - END IF; - - WHEN sCOPY => - -- dshi : Force shift first two or three pixels of each line - IF o_dshi=0 THEN - dif_v:=(o_hacc_next - 2*o_hsize + (8*OHRES)) MOD (8*OHRES); - IF dif_v>=4*OHRES THEN - o_hacc<=o_hacc_next; - o_hacc_next<=o_hacc_next + 2*o_ihsize; - hcarry_v:=false; - ELSE - o_hacc<=dif_v; - o_hacc_next<=(dif_v + 2*o_ihsize + (4*OHRES)) MOD (4*OHRES); - hcarry_v:=true; - END IF; - o_dcpt<=(o_dcpt+1) MOD 4096; - ELSE - o_dshi<=o_dshi-1; - hcarry_v:=false; - END IF; - IF o_dshi<=1 THEN - o_copyv(0)<='1'; - END IF; - IF hcarry_v THEN - o_hacpt<=o_hacpt+1; - o_last <=to_std_logic(o_hacpt>=o_ihsizem); - END IF; - - IF hcarry_v OR o_dshi>0 THEN - o_sh<='1'; - o_acpt<=(o_acpt+1) MOD 16; - - -- Shift two more pixels to the right before ending line. - o_last1<=o_last; - o_last2<=o_last1; - - IF shift_onext(o_acpt,o_format) THEN - o_ad<=(o_ad+1) MOD (2*BLEN); - END IF; - - IF o_adturn='1' AND (shift_onext((o_acpt+1) MOD 16,o_format)) AND - (((o_ad MOD BLEN=0) AND o_lastv(0)='0') OR o_last2='1') THEN - o_copy<=sWAIT; - lev_dec_v:='1'; - END IF; - - IF o_ad MOD BLEN=4 THEN - o_adturn<='1'; - END IF; - END IF; - END CASE; - - o_acpt1<=o_acpt; o_acpt2<=o_acpt1; o_acpt3<=o_acpt2; o_acpt4<=o_acpt3; - o_ad1<=o_ad; o_ad2<=o_ad1; o_ad3<=o_ad2; - o_sh1<=o_sh; o_sh2<=o_sh1; o_sh3<=o_sh2; o_sh4<=o_sh3; - o_lastt1<=o_last; o_lastt2<=o_lastt1; - o_lastt3<=o_lastt2; o_lastt4<=o_lastt3; - - ------------------------------------------------------ - IF o_sh3='1' THEN - shift_v:=shift_opack(o_acpt4,o_shift,o_dr,o_format); - o_shift<=shift_v; - o_hpixs<=shift_opix(shift_v,o_format); - END IF; - - IF o_sh4='1' THEN - hpix_v:=o_hpixs; - IF o_format(4)='1' THEN -- Swap B <-> R - hpix_v:=(r=>o_hpixs.b,g=>o_hpixs.g,b=>o_hpixs.r); - END IF; - IF o_format(2 DOWNTO 0)="011" THEN - -- 8bpp indexed colour mode - hpix_v:=(r=>o_fb_pal_dr(23 DOWNTO 16),g=>o_fb_pal_dr(15 DOWNTO 8), - b=>o_fb_pal_dr(7 DOWNTO 0)); - END IF; - o_hpix0<=hpix_v; - o_hpix1<=o_hpix0; - o_hpix2<=o_hpix1; - o_hpix3<=o_hpix2; - - IF o_first='1' THEN - -- Left edge. Duplicate first pixel - o_hpix1<=hpix_v; - o_hpix2<=hpix_v; - o_first<='0'; - END IF; - IF o_lastt4='1' THEN - -- Right edge. Keep last pixel. - o_hpix0<=o_hpix0; - END IF; - END IF; - - ------------------------------------------------------ - -- lev_inc : read start - -- lev_dec : end of copy - -- READLEV : Number of ongoing Avalon Reads - IF lev_dec_v='0' AND lev_inc_v='1' THEN - o_readlev<=o_readlev+1; - ELSIF lev_dec_v='1' AND lev_inc_v='0' THEN - o_readlev<=o_readlev-1; - END IF; - - -- COPYLEV : Number of ongoing copies to line buffers - IF lev_dec_v='1' AND o_readdataack='0' THEN - o_copylev<=o_copylev-1; - ELSIF lev_dec_v='0' AND o_readdataack='1' THEN - o_copylev<=o_copylev+1; - END IF; - - -- FIFOs - IF lev_dec_v='1' THEN - o_primv(0 TO 1)<=o_primv(1 TO 2); -- First buffer of line - o_lastv(0 TO 1)<=o_lastv(1 TO 2); -- Last buffer of line - o_bibv (0 TO 1)<=o_bibv (1 TO 2); -- Double buffer select - o_off (0 TO 1)<=o_off (1 TO 2); -- Start offset - END IF; - - IF lev_inc_v='1' THEN - IF o_readlev=0 OR (o_readlev=1 AND lev_dec_v='1') THEN - o_primv(0)<=prim_v; - o_lastv(0)<=last_v; - o_bibv (0)<=bib_v; - o_off (0)<=off_v; - ELSIF (o_readlev=1 AND lev_dec_v='0') OR - (o_readlev=2 AND lev_dec_v='1') THEN - o_primv(1)<=prim_v; - o_lastv(1)<=last_v; - o_bibv (1)<=bib_v; - o_off (1)<=off_v; - END IF; - o_primv(2)<=prim_v; - o_lastv(2)<=last_v; - o_bibv (2)<=bib_v; - o_off (2)<=off_v; - END IF; - - ------------------------------------------------------ - END IF; - END PROCESS Scalaire; - - o_h_poly_a<=to_integer(o_hfrac1(11 DOWNTO 12-FRAC)); - o_v_poly_a<=to_integer(o_vfrac(11 DOWNTO 12-FRAC)); - - o_h_poly_dr<=o_h_poly(o_h_poly_a) WHEN rising_edge(o_clk); - o_v_poly_dr<=o_v_poly(o_v_poly_a) WHEN rising_edge(o_clk); - - -- Framebuffer palette - GenPal1:IF PALETTE GENERATE - Tempera1:PROCESS(pal1_clk) IS - BEGIN - IF rising_edge(pal1_clk) THEN - IF pal1_wr='1' THEN - pal1_mem(to_integer(pal1_a))<=pal1_dw; - END IF; - pal1_dr<=pal1_mem(to_integer(pal1_a)); - END IF; - END PROCESS; + ELSIF rising_edge(o_clk) THEN + o_vdivi<=to_unsigned(2*o_vsize,13); + o_vdivr<=to_unsigned(o_vacc*4096,25); + ------------------------------------------------------ + IF o_divstart='1' THEN + o_divcpt<=0; + o_divrun<='1'; - pal_idx <= shift_opack(o_acpt4,o_shift,o_dr,o_format)(0 TO 7); - pal_idx_lsb <= pal_idx(0) WHEN rising_edge(o_clk); - o_fb_pal_dr_x2 <= pal1_mem(to_integer(pal_idx(7 DOWNTO 1))) WHEN rising_edge(o_clk); - END GENERATE GenPal1; - - GenPal2:IF PALETTE and PALETTE2 GENERATE - Tempera2:PROCESS(pal2_clk) IS - BEGIN - IF rising_edge(pal2_clk) THEN - IF pal2_wr='1' THEN - pal2_mem(to_integer(pal2_a))<=pal2_dw; - END IF; - pal2_dr<=pal2_mem(to_integer(pal2_a)); - END IF; - END PROCESS; + ELSIF o_divrun='1' THEN + ---------------------------------------------------- + IF o_divcpt=12 THEN + o_divrun<='0'; + o_vfrac<=o_vdivr(10 DOWNTO 0) & NOT o_vdivr(24); + ELSE + o_divcpt<=o_divcpt+1; + END IF; - o_fb_pal_dr2 <= pal2_mem(to_integer(pal_idx(7 DOWNTO 0))) WHEN rising_edge(o_clk); - o_fb_pal_dr <= o_fb_pal_dr2 when pal_n = '1' else o_fb_pal_dr_x2(47 DOWNTO 24) WHEN pal_idx_lsb = '1' ELSE o_fb_pal_dr_x2(23 DOWNTO 0); - END GENERATE GenPal2; + IF o_vdivr(24)='0' THEN + o_vdivr(24 DOWNTO 12)<=o_vdivr(23 DOWNTO 11) - o_vdivi; + ELSE + o_vdivr(24 DOWNTO 12)<=o_vdivr(23 DOWNTO 11) + o_vdivi; + END IF; + o_vdivr(11 DOWNTO 0)<=o_vdivr(10 DOWNTO 0) & NOT o_vdivr(24); + ---------------------------------------------------- + END IF; + END IF; + END PROCESS ODivider; - GenPal1not2:IF PALETTE and not PALETTE2 GENERATE - o_fb_pal_dr <= o_fb_pal_dr_x2(47 DOWNTO 24) WHEN pal_idx_lsb = '1' ELSE o_fb_pal_dr_x2(23 DOWNTO 0); - END GENERATE GenPal1not2; - - GenNoPal:IF NOT PALETTE GENERATE - o_fb_pal_dr<=x"000000"; - END GENERATE GenNoPal; - - ----------------------------------------------------------------------------- - -- Polyphase ROMs - Polikarpov:PROCESS(poly_clk) IS - BEGIN - IF rising_edge(poly_clk) THEN - IF poly_wr='1' THEN - poly_tdw(8+9*(3-to_integer(poly_a(1 DOWNTO 0))) DOWNTO - 9*(3-to_integer(poly_a(1 DOWNTO 0))))<=poly_dw; - END IF; - - poly_h_wr<=poly_wr AND NOT poly_a(FRAC+2); - poly_v_wr<=poly_wr AND poly_a(FRAC+2); - poly_a2<=poly_a(FRAC+1 DOWNTO 2); - - IF poly_h_wr='1' THEN - o_h_poly(to_integer(poly_a2))<=poly_tdw; - END IF; - IF poly_v_wr='1' THEN - o_v_poly(to_integer(poly_a2))<=poly_tdw; - END IF; - END IF; - END PROCESS Polikarpov; - - ----------------------------------------------------------------------------- - -- Horizontal Scaler - HSCAL:PROCESS(o_clk) IS - VARIABLE div_v : unsigned(18 DOWNTO 0); - VARIABLE dir_v : unsigned(11 DOWNTO 0); - BEGIN - IF rising_edge(o_clk) THEN - -- Pipeline signals - ----------------------------------- - -- Pipelined 6 bits non-restoring divider. Cycle 1 - dir_v:=x"000"; - div_v:=to_unsigned(o_hacc * 64,19); - - div_v:=div_v-to_unsigned(o_hsize*64,19); - dir_v(11):=NOT div_v(18); - IF div_v(18)='0' THEN - div_v:=div_v-to_unsigned(o_hsize*32,19); - ELSE - div_v:=div_v+to_unsigned(o_hsize*32,19); - END IF; - dir_v(10):=NOT div_v(18); - o_div<=div_v; - o_dir<=dir_v; - - -- Cycle 2 - div_v:=o_div; - dir_v:=o_dir; - IF div_v(18)='0' THEN - div_v:=div_v-to_unsigned(o_hsize*16,19); - ELSE - div_v:=div_v+to_unsigned(o_hsize*16,19); - END IF; - dir_v( 9):=NOT div_v(18); + ----------------------------------------------------------------------------- + Scalaire:PROCESS (o_clk,o_reset_na) IS + VARIABLE lev_inc_v,lev_dec_v : std_logic; + VARIABLE prim_v,last_v,bib_v : std_logic; + VARIABLE shift_v : unsigned(0 TO N_DW+15); + VARIABLE hpix_v : type_pix; + VARIABLE hcarry_v,vcarry_v : boolean; + VARIABLE dif_v : natural RANGE 0 TO 8*OHRES-1; + VARIABLE off_v : natural RANGE 0 TO 15; + BEGIN + IF o_reset_na='0' THEN + o_copy<=sWAIT; + o_state<=sDISP; + o_read_pre<='0'; + o_readlev<=0; + o_copylev<=0; + o_hsp<='0'; - IF div_v(18)='0' THEN - div_v:=div_v-to_unsigned(o_hsize*8,19); - ELSE - div_v:=div_v+to_unsigned(o_hsize*8,19); - END IF; - dir_v(8):=NOT div_v(18); - o_div2<=div_v; - o_dir2<=dir_v; - - -- Cycle 3 - div_v:=o_div2; - dir_v:=o_dir2; - IF FRAC>4 THEN - IF div_v(18)='0' THEN - div_v:=div_v-to_unsigned(o_hsize*4,19); - ELSE - div_v:=div_v+to_unsigned(o_hsize*4,19); - END IF; - dir_v(7):=NOT div_v(18); - IF div_v(18)='0' THEN - div_v:=div_v-to_unsigned(o_hsize*2,19); - ELSE - div_v:=div_v+to_unsigned(o_hsize*2,19); - END IF; - dir_v(6):=NOT div_v(18); - END IF; - - ----------------------------------- - o_hfrac<=dir_v; - o_hfrac1<=o_hfrac; o_hfrac2<=o_hfrac1; - o_hfrac3<=o_hfrac2; o_hfrac4<=o_hfrac3; - - o_copyv(1 TO 8)<=o_copyv(0 TO 7); - - o_dcptv(1)<=o_dcpt; - IF o_dcptv(1)>=o_hsize THEN - o_copyv(2)<='0'; - END IF; - o_dcptv(2)<=o_dcptv(1) MOD OHRES; - o_dcptv(3 TO 8)<=o_dcptv(2 TO 7); - - o_hpixq<=(o_hpix3,o_hpix2,o_hpix1,o_hpix0); - - -- NEAREST / BILINEAR / SHARP BILINEAR --------------- - -- C1 : Pre-calc Sharp Bilinear - o_h_sbil_t<=sbil_frac1(o_hfrac1); - - -- C2 : Select - o_h_frac2<=(OTHERS =>'0'); - CASE o_hmode(1 DOWNTO 0) IS - WHEN "00" => -- Nearest - IF MASK(MASK_NEAREST)='1' THEN - o_h_frac2<=near_frac(o_hfrac2); - END IF; - WHEN "01" => -- Bilinear - IF MASK(MASK_BILINEAR)='1' THEN - o_h_frac2<=bil_frac(o_hfrac2); - END IF; - WHEN "10" => -- Sharp Bilinear - IF MASK(MASK_SHARP_BILINEAR)='1' THEN - o_h_frac2<=sbil_frac2(o_hfrac2,o_h_sbil_t); - END IF; - WHEN OTHERS => - NULL; - END CASE; - - -- C3 : Opposite frac - o_h_bil_t<=bil_calc(o_h_frac2,o_hpixq); - - -- C4 : Nearest / Bilinear / Sharp Bilinear - o_h_bil_pix.r<=bound(o_h_bil_t.r,8+FRAC); - o_h_bil_pix.g<=bound(o_h_bil_t.g,8+FRAC); - o_h_bil_pix.b<=bound(o_h_bil_t.b,8+FRAC); - - -- BICUBIC ------------------------------------------- - -- C1 : Bicubic coefficients A,B,C,D - - -- C2 : Bicubic calc T1 = X.D + C - o_h_bic_abcd1<=bic_calc0(o_hfrac2,(o_hpix3,o_hpix2,o_hpix1,o_hpix0)); - o_h_bic_tt1<=bic_calc1(o_hfrac2, - bic_calc0(o_hfrac2,(o_hpix3,o_hpix2,o_hpix1,o_hpix0))); - - -- C3 : Bicubic calc T2 = X.T1 + B - o_h_bic_abcd2<=o_h_bic_abcd1; - o_h_bic_tt2<=bic_calc2(o_hfrac3,o_h_bic_tt1,o_h_bic_abcd1); - - -- C4 : Bicubic final Y = X.T2 + A - o_h_bic_pix<=bic_calc3(o_hfrac4,o_h_bic_tt2,o_h_bic_abcd2); - - -- POLYPHASE ----------------------------------------- - -- C1 : Read memory - - -- C2 : Filter calc - o_h_poly_dr2<=o_h_poly_dr; - - -- C3 : Add - o_h_poly_t<=poly_calc1(o_h_poly_dr2,o_hpixq); - - -- C4 : Bounding - o_h_poly_pix<=poly_calc2(o_h_poly_t); - - -- C5 : Select interpoler ---------------------------- - o_wadl<=o_dcptv(8); - o_wr<=o_altx AND (o_copyv(8) & o_copyv(8) & o_copyv(8) & o_copyv(8)); - o_ldw<=(x"00",x"00",x"00"); - - CASE o_hmode(2 DOWNTO 0) IS - WHEN "000" | "001" | "010" => -- Nearest | Bilinear | Sharp Bilinear - IF MASK(MASK_NEAREST)='1' OR - MASK(MASK_BILINEAR)='1' OR - MASK(MASK_SHARP_BILINEAR)='1' THEN - o_ldw<=o_h_bil_pix; - END IF; - WHEN "011" => -- BiCubic - IF MASK(MASK_BICUBIC)='1' THEN - o_ldw<=o_h_bic_pix; - END IF; - WHEN OTHERS => -- PolyPhase - IF MASK(MASK_POLY)='1' THEN - o_ldw<=o_h_poly_pix; - END IF; - END CASE; - ------------------------------------------------------ - END IF; - END PROCESS HSCAL; - - ----------------------------------------------------------------------------- - -- Line buffers 4 x OHRES x (R+G+B) - OLBUF:PROCESS(o_clk) IS - BEGIN - IF rising_edge(o_clk) THEN - -- WRITES - IF o_wr(0)='1' THEN o_line0(o_wadl)<=o_ldw; END IF; - IF o_wr(1)='1' THEN o_line1(o_wadl)<=o_ldw; END IF; - IF o_wr(2)='1' THEN o_line2(o_wadl)<=o_ldw; END IF; - IF o_wr(3)='1' THEN o_line3(o_wadl)<=o_ldw; END IF; - - -- READS - o_ldr0<=o_line0(o_radl); - o_ldr1<=o_line1(o_radl); - o_ldr2<=o_line2(o_radl); - o_ldr3<=o_line3(o_radl); - END IF; - END PROCESS OLBUF; - - ----------------------------------------------------------------------------- - -- Output video sweep - OSWEEP:PROCESS(o_clk) IS - BEGIN - IF rising_edge(o_clk) THEN - IF o_ce='1' THEN - -- Output pixels count - IF o_hcpt+1=o_vtotal THEN - o_vcpt_pre3<=0; - ELSE - o_vcpt_pre3<=(o_vcpt_pre3+1) MOD 4096; - END IF; - o_vcpt_pre2<=o_vcpt_pre3; - o_vcpt_pre<=o_vcpt_pre2; - o_vcpt<=o_vcpt_pre; - END IF; - - o_end(0)<=to_std_logic(o_vcpt>=o_vdisp); - o_dev(0)<=to_std_logic(o_hcpt=o_hmin AND o_hcpt<=o_hmax AND - o_vcpt>=o_vmin AND o_vcpt<=o_vmax); - o_hsv(0)<=to_std_logic(o_hcpt>=o_hsstart AND o_hcpt=o_hsstart) OR - (o_vcpt>o_vsstart AND o_vcpt=o_vmin AND o_vcpt_pre2<=o_vmax); - o_hsv(1 TO 5)<=o_hsv(0 TO 4); - o_vsv(1 TO 5)<=o_vsv(0 TO 4); - o_dev(1 TO 5)<=o_dev(0 TO 4); - o_pev(1 TO 5)<=o_pev(0 TO 4); - o_end(1 TO 5)<=o_end(0 TO 4); - - IF o_run='0' THEN - o_hsv(2)<='0'; - o_vsv(2)<='0'; - o_dev(2)<='0'; - o_pev(2)<='0'; - o_end(2)<='0'; - END IF; - - END IF; - END IF; - - END PROCESS OSWEEP; - - ----------------------------------------------------------------------------- - -- Vertical Scaler - VSCAL:PROCESS(o_clk) IS - VARIABLE pixq_v : arr_pix(0 TO 3); - BEGIN - IF rising_edge(o_clk) THEN - IF o_ce='1' THEN - -- CYCLE 1 ----------------------------------------- - -- Read mem - o_radl<=(o_hcpt - o_hmin + OHRES) MOD OHRES; - - -- CYCLE 2 ----------------------------------------- - -- Lines reordering - CASE o_vacpt(1 DOWNTO 0) IS - WHEN "10" => pixq_v:=(o_ldr0,o_ldr1,o_ldr2,o_ldr3); - WHEN "11" => pixq_v:=(o_ldr1,o_ldr2,o_ldr3,o_ldr0); - WHEN "00" => pixq_v:=(o_ldr2,o_ldr3,o_ldr0,o_ldr1); - WHEN OTHERS => pixq_v:=(o_ldr3,o_ldr0,o_ldr1,o_ldr2); - END CASE; - - o_vpixq<=pixq_v; - - -- Bottom edge : replicate last line - IF to_integer(o_vacpt)=o_ivsize THEN - o_vpixq(2)<=pixq_v(2); - END IF; - IF to_integer(o_vacpt)>=o_ivsize+1 THEN - o_vpixq(2)<=pixq_v(1); - o_vpixq(1)<=pixq_v(1); - END IF; - - o_vpixq1<=o_vpixq; - - -- NEAREST / BILINEAR / SHARP BILINEAR ------------- - -- C3 : Pre-calc Sharp Bilinear - o_v_sbil_t<=sbil_frac1(o_vfrac); - - -- C4 : Select - o_v_frac<=(OTHERS =>'0'); - CASE o_vmode(1 DOWNTO 0) IS - WHEN "00" => -- Nearest - IF MASK(MASK_NEAREST)='1' THEN - o_v_frac<=near_frac(o_vfrac); - END IF; - WHEN "01" => -- Bilinear - IF MASK(MASK_BILINEAR)='1' THEN - o_v_frac<=bil_frac(o_vfrac); - END IF; - WHEN "10" => -- Sharp Bilinear - IF MASK(MASK_SHARP_BILINEAR)='1' THEN - o_v_frac<=sbil_frac2(o_vfrac,o_v_sbil_t); - END IF; - WHEN OTHERS => NULL; - END CASE; - - o_v_bil_t<=bil_calc(o_v_frac,o_vpixq1); - - -- C6 : Nearest / Bilinear / Sharp Bilinear - o_v_bil_pix.r<=bound(o_v_bil_t.r,8+FRAC); - o_v_bil_pix.g<=bound(o_v_bil_t.g,8+FRAC); - o_v_bil_pix.b<=bound(o_v_bil_t.b,8+FRAC); - - -- BICUBIC ----------------------------------------- - -- C3 : Bicubic coefficients A,B,C,D - - -- C4 : Bicubic calc T1 = X.D + C - o_v_bic_abcd1<=bic_calc0(o_vfrac,o_vpixq); - o_v_bic_tt1<=bic_calc1(o_vfrac,bic_calc0(o_vfrac,o_vpixq)); - - -- C5 : Bicubic calc T2 = X.T1 + B - o_v_bic_abcd2<=o_v_bic_abcd1; - o_v_bic_tt2<=bic_calc2(o_vfrac,o_v_bic_tt1,o_v_bic_abcd1); - - -- C6 : Bicubic final Y = X.T2 + A - o_v_bic_pix<=bic_calc3(o_vfrac,o_v_bic_tt2,o_v_bic_abcd2); - - -- POLYPHASE --------------------------------------- - -- C3 : Read memory - - -- C4 : Filter calc - o_v_poly_dr2<=o_v_poly_dr; - - -- C5 : Add - o_v_poly_t<=poly_calc1(o_v_poly_dr2,o_vpixq1); - - -- C6 : Bounding - o_v_poly_pix<=poly_calc2(o_v_poly_t); - - -- CYCLE 6 ----------------------------------------- - o_hs<=o_hsv(5); - o_vs<=o_vsv(5); - o_de<=o_dev(5); - o_vbl<=o_end(5); - o_r<=x"00"; - o_g<=x"00"; - o_b<=x"00"; - - CASE o_vmode(2 DOWNTO 0) IS - WHEN "000" | "001" | "010" => -- Nearest | Bilinear | Sharp Bilinear - IF MASK(MASK_NEAREST)='1' OR - MASK(MASK_BILINEAR)='1' OR - MASK(MASK_SHARP_BILINEAR)='1' THEN - o_r<=o_v_bil_pix.r; - o_g<=o_v_bil_pix.g; - o_b<=o_v_bil_pix.b; - END IF; - WHEN "011" => -- BiCubic - IF MASK(MASK_BICUBIC)='1' THEN - o_r<=o_v_bic_pix.r; - o_g<=o_v_bic_pix.g; - o_b<=o_v_bic_pix.b; - END IF; - - WHEN OTHERS => -- Polyphase - IF MASK(MASK_POLY)='1' THEN - o_r<=o_v_poly_pix.r; - o_g<=o_v_poly_pix.g; - o_b<=o_v_poly_pix.b; - END IF; - END CASE; - - IF o_pev(5)='0' THEN - o_r<=o_border(23 DOWNTO 16); -- Copy border colour - o_g<=o_border(15 DOWNTO 8); - o_b<=o_border(7 DOWNTO 0); - END IF; - - ---------------------------------------------------- - END IF; - END IF; + ELSIF rising_edge(o_clk) THEN + ------------------------------------------------------ + o_mode <=mode; -- ? + o_format <="0001" & format; -- ? - END PROCESS VSCAL; - - ----------------------------------------------------------------------------- - -- Low Lag syntoniser interface - o_lltune<=(0 => i_vss, - 1 => i_pde, - 2 => i_inter, - 3 => i_flm, - 4 => o_vss, - 5 => i_pce, - 6 => i_clk, - 7 => o_clk, - OTHERS =>'0'); - - ---------------------------------------------------------------------------- + o_run <=run; -- ? + + o_htotal <=htotal; -- ? + o_hsstart<=hsstart; -- ? + o_hsend <=hsend; -- ? + o_hdisp <=hdisp; -- ? + o_hmin <=hmin; -- ? + o_hmax <=hmax; -- ? + + o_vtotal <=vtotal; -- ? + o_vsstart<=vsstart; -- ? + o_vsend <=vsend; -- ? + o_vdisp <=vdisp; -- ? + o_vmin <=vmin; -- ? + o_vmax <=vmax; -- ? + + o_hsize <=o_hmax - o_hmin + 1; + o_vsize <=o_vmax - o_vmin + 1; + + o_vrr <=vrr; + o_vrrmax <= vrrmax; + + -------------------------------------------- + -- Triple buffering. + -- For intelaced video, half frames are updated independently + -- Input : Toggle buffer at end of input frame + o_isync <= '0'; + o_isync2 <= o_isync; + o_freeze <= freeze; + o_inter <=i_inter; -- + o_iendframe0<=i_endframe0; -- + o_iendframe02<=o_iendframe0; + IF o_iendframe0='1' AND o_iendframe02='0' THEN + o_ibuf0<=buf_next(o_ibuf0,o_obuf0,o_freeze); + o_bufup0<='1'; + o_isync <= '1'; + END IF; + o_iendframe1<=i_endframe1; -- + o_iendframe12<=o_iendframe1; + IF o_iendframe1='1' AND o_iendframe12='0' THEN + o_ibuf1<=buf_next(o_ibuf1,o_obuf1,o_freeze); + o_bufup1<='1'; + o_isync <= '1'; + END IF; + + -- Output : Change framebuffer, and image properties, at VS falling edge + IF o_vsv(1)='1' AND o_vsv(0)='0' AND o_bufup0='1' THEN + o_obuf0<=buf_next(o_obuf0,o_ibuf0,o_freeze); + o_bufup0<='0'; + END IF; + IF o_vsv(1)='1' AND o_vsv(0)='0' AND o_bufup1='1' THEN + o_obuf1<=buf_next(o_obuf1,o_ibuf1,o_freeze); + o_bufup1<='0'; + o_ihsize<=i_hrsize; -- + o_ivsize<=i_vrsize; -- + o_hdown<=i_hdown; -- + o_vdown<=i_vdown; -- + END IF; + + -- Simultaneous change of input and output framebuffers + IF o_vsv(1)='1' AND o_vsv(0)='0' AND + o_iendframe0='1' AND o_iendframe02='0' THEN + o_bufup0<='0'; + o_obuf0<=o_ibuf0; + END IF; + IF o_vsv(1)='1' AND o_vsv(0)='0' AND + o_iendframe1='1' AND o_iendframe12='0' THEN + o_bufup1<='0'; + o_obuf1<=o_ibuf1; + END IF; + + -- Non-interlaced, use same buffer for even and odd lines + IF o_inter='0' THEN + o_ibuf1<=o_ibuf0; + o_obuf1<=o_obuf0; + END IF; + + -- Triple buffer disabled + IF o_mode(3)='0' THEN + o_obuf0<=0; + o_obuf1<=0; + o_ibuf0<=0; + o_ibuf1<=0; + END IF; + + -- Framebuffer mode. + IF o_fb_ena='1' THEN + o_ihsize<=o_fb_hsize; + o_ivsize<=o_fb_vsize; + o_format<=o_fb_format; + o_hdown<='0'; + o_vdown<='0'; + END IF; + + -- 011=8bpp(palette) 100=16bpp 101=24bpp 110=32bpp + CASE o_format(2 DOWNTO 0) IS + WHEN "011" => o_ihsize_temp <= o_ihsize; + WHEN "100" => o_ihsize_temp <= o_ihsize * 2; + WHEN "110" => o_ihsize_temp <= o_ihsize * 4; + WHEN OTHERS => o_ihsize_temp <= o_ihsize * 3; + END CASE; + + o_ihsize_temp2 <= (o_ihsize_temp + N_BURST - 1); + o_hburst <= o_ihsize_temp2 / N_BURST; + + IF o_fb_ena='1' AND o_fb_stride /= 0 THEN + o_stride<=o_fb_stride; + ELSE + o_stride<=to_unsigned(o_ihsize_temp2,14); + o_stride(NB_BURST-1 DOWNTO 0)<=(OTHERS =>'0'); + END IF; + ------------------------------------------------------ + o_hmode<=o_mode; + IF o_hdown='1' AND DOWNSCALE THEN + -- Force nearest if downscaling : Downscaled framebuffer + o_hmode(2 DOWNTO 0)<="000"; + END IF; + + o_vmode<=o_mode; + IF o_vdown='1' AND DOWNSCALE THEN + -- Force nearest if downscaling : Downscaled framebuffer + o_vmode(2 DOWNTO 0)<="000"; + END IF; + + ------------------------------------------------------ + -- End DRAM READ + o_readack_sync<=avl_readack; -- + o_readack_sync2<=o_readack_sync; + o_readack<=o_readack_sync XOR o_readack_sync2; + + o_readdataack_sync<=avl_readdataack; -- + o_readdataack_sync2<=o_readdataack_sync; + o_readdataack<=o_readdataack_sync XOR o_readdataack_sync2; + + ------------------------------------------------------ + lev_inc_v:='0'; + lev_dec_v:='0'; + + -- acpt : Pixel position within current data word + -- dcpt : Destination image position + + -- Force preload 2 lines at top of screen + IF o_hsv(0)='1' AND o_hsv(1)='0' THEN + IF o_vcpt_pre3=o_vmin THEN + o_fload<=2; + o_bibu<='0'; + END IF; + o_hsp<='1'; + END IF; + + o_vpe<=to_std_logic(o_vcpt_pre=o_vmin); + o_divstart<='0'; + o_adrsa<='0'; + o_adrsb<=o_adrsa; + + o_vacc_ini<=(o_vsize - o_ivsize + 8192) MOD 8192; + o_hacc_ini<=(o_hsize + o_ihsize + 8192) MOD 8192; + + --Alternate phase + --o_vacc_ini<=o_ivsize; + --o_hacc_ini<=(2*o_hsize - o_ihsize + 8192) MOD 8192; + + CASE o_state IS + -------------------------------------------------- + WHEN sDISP => + IF o_hsp='1' THEN + o_state<=sHSYNC; + o_hsp<='0'; + END IF; + o_prim<=true; + o_vcarrym<=false; + + -------------------------------------------------- + WHEN sHSYNC => + dif_v :=(o_vacc_next - 2*o_vsize + 16384) MOD 16384; + IF o_prim THEN + IF dif_v>=8192 THEN + o_vacc <=o_vacc_next; + ELSE + o_vacc <=dif_v; + END IF; + END IF; + IF dif_v>=8192 THEN + o_vacc_next<=(o_vacc_next + 2*o_ivsize) MOD 8192; + vcarry_v:=false; + ELSE + o_vacc_next<=dif_v; + vcarry_v:=true; + END IF; + + IF o_vcpt_pre2=o_vmin THEN + o_vacc <=o_vacc_ini; + o_vacc_next<=o_vacc_ini + 2*o_ivsize; + o_vacpt <=x"001"; + o_vacptl<="01"; + vcarry_v:=false; + END IF; + + IF vcarry_v THEN + o_vacpt<=o_vacpt+1; + END IF; + IF vcarry_v AND o_prim THEN + o_vacptl<=o_vacptl+1; + END IF; + o_vcarrym <= o_vcarrym OR vcarry_v; + o_prim <= false; + o_hbcpt<=0; -- Clear burst counter on line + o_divstart<=to_std_logic(NOT vcarry_v); + IF NOT vcarry_v OR o_fload>0 THEN + IF (o_vpe='1' AND o_vcarrym) OR o_fload>0 THEN + o_state<=sREAD; + ELSE + o_state<=sDISP; + END IF; + END IF; + + WHEN sREAD => + -- Read a block + IF o_readlev<2 AND o_adrsb='1' THEN + lev_inc_v:='1'; + o_read_pre<=NOT o_read_pre; + o_state <=sWAITREAD; + o_bibu<=NOT o_bibu; + END IF; + prim_v:=to_std_logic(o_hbcpt=0); + last_v:=to_std_logic(o_hbcpt=o_hburst-1); + bib_v :=o_bibu; + off_v :=pixoffset(o_adrs + o_fb_base(NB_LA-1 DOWNTO 0),o_fb_format); + IF o_fb_ena='0' THEN + off_v:=0; + END IF; + o_adrsa<='1'; + + WHEN sWAITREAD => + IF o_readack='1' THEN + o_hbcpt<=o_hbcpt+1; + IF o_hbcpt=1 THEN + o_fload<=o_fload-1; + END IF; + END IF; + END IF; + + -------------------------------------------------- + END CASE; + + o_read<=o_read_pre AND o_run; + o_rline<=o_vacpt(0); -- Even/Odd line for interlaced video + + o_adrs_pre<=to_integer(o_vacpt) * to_integer(o_stride); + IF o_adrsa='1' THEN + IF o_fload=2 THEN + o_adrs<=to_unsigned(o_hbcpt * N_BURST,32); + o_alt<="1111"; + ELSIF o_fload=1 THEN + o_adrs<=to_unsigned(o_hbcpt * N_BURST,32) + o_stride; + o_alt<="0100"; + ELSE + o_adrs<=to_unsigned(o_adrs_pre + (o_hbcpt * N_BURST),32); + o_alt<=altx(o_vacptl + 1); + END IF; + END IF; + + ------------------------------------------------------ + -- Copy from buffered memory to pixel lines + o_sh<='0'; + CASE o_copy IS + WHEN sWAIT => + o_copyv(0)<='0'; + IF o_copylev>0 AND o_copyv(0)='0' THEN + o_copy<=sCOPY; + IF o_off(0)>0 AND o_primv(0)='1' THEN + o_copy<=sSHIFT; + END IF; + o_altx<=o_alt; + END IF; + o_adturn<='0'; + o_pshift<=o_off(0) -1; + IF o_primv(0)='1' THEN + -- First memcopy of a horizontal line, carriage return ! + o_ihsizem<=o_ihsize + o_off(0) - 2; + o_hacc <=o_hacc_ini; + o_hacc_next<=o_hacc_ini + 2*o_ihsize; + o_hacpt <=x"000"; + o_dcpt<=0; + o_dshi<=2; + o_acpt<=0; + o_first<='1'; + o_last<='0'; + END IF; + + IF o_bibv(0)='0' THEN + o_ad<=0; + ELSE + o_ad<=BLEN; + END IF; + + WHEN sSHIFT => + o_hacpt<=o_hacpt+1; + o_sh<='1'; + o_acpt<=(o_acpt+1) MOD 16; + IF shift_onext(o_acpt,o_format) THEN + o_ad<=(o_ad+1) MOD (2*BLEN); + END IF; + o_pshift<=o_pshift-1; + IF o_pshift=0 THEN + o_copy<=sCOPY; + END IF; + + WHEN sCOPY => + -- dshi : Force shift first two or three pixels of each line + IF o_dshi=0 THEN + dif_v:=(o_hacc_next - 2*o_hsize + (8*OHRES)) MOD (8*OHRES); + IF dif_v>=4*OHRES THEN + o_hacc<=o_hacc_next; + o_hacc_next<=o_hacc_next + 2*o_ihsize; + hcarry_v:=false; + ELSE + o_hacc<=dif_v; + o_hacc_next<=(dif_v + 2*o_ihsize + (4*OHRES)) MOD (4*OHRES); + hcarry_v:=true; + END IF; + o_dcpt<=(o_dcpt+1) MOD 4096; + ELSE + o_dshi<=o_dshi-1; + hcarry_v:=false; + END IF; + IF o_dshi<=1 THEN + o_copyv(0)<='1'; + END IF; + IF hcarry_v THEN + o_hacpt<=o_hacpt+1; + o_last <=to_std_logic(o_hacpt>=o_ihsizem); + END IF; + + IF hcarry_v OR o_dshi>0 THEN + o_sh<='1'; + o_acpt<=(o_acpt+1) MOD 16; + + -- Shift two more pixels to the right before ending line. + o_last1<=o_last; + o_last2<=o_last1; + + IF shift_onext(o_acpt,o_format) THEN + o_ad<=(o_ad+1) MOD (2*BLEN); + END IF; + + IF o_adturn='1' AND (shift_onext((o_acpt+1) MOD 16,o_format)) AND + (((o_ad MOD BLEN=0) AND o_lastv(0)='0') OR o_last2='1') THEN + o_copy<=sWAIT; + lev_dec_v:='1'; + END IF; + + IF o_ad MOD BLEN=4 THEN + o_adturn<='1'; + END IF; + END IF; + END CASE; + + o_acpt1<=o_acpt; o_acpt2<=o_acpt1; o_acpt3<=o_acpt2; o_acpt4<=o_acpt3; + o_ad1<=o_ad; o_ad2<=o_ad1; o_ad3<=o_ad2; + o_sh1<=o_sh; o_sh2<=o_sh1; o_sh3<=o_sh2; o_sh4<=o_sh3; + o_lastt1<=o_last; o_lastt2<=o_lastt1; + o_lastt3<=o_lastt2; o_lastt4<=o_lastt3; + + ------------------------------------------------------ + IF o_sh3='1' THEN + shift_v:=shift_opack(o_acpt4,o_shift,o_dr,o_format); + o_shift<=shift_v; + o_hpixs<=shift_opix(shift_v,o_format); + END IF; + + IF o_sh4='1' THEN + hpix_v:=o_hpixs; + IF o_format(4)='1' THEN -- Swap B <-> R + hpix_v:=(r=>o_hpixs.b,g=>o_hpixs.g,b=>o_hpixs.r); + END IF; + IF o_format(2 DOWNTO 0)="011" THEN + -- 8bpp indexed colour mode + hpix_v:=(r=>o_fb_pal_dr(23 DOWNTO 16),g=>o_fb_pal_dr(15 DOWNTO 8), + b=>o_fb_pal_dr(7 DOWNTO 0)); + END IF; + o_hpix0<=hpix_v; + o_hpix1<=o_hpix0; + o_hpix2<=o_hpix1; + o_hpix3<=o_hpix2; + + IF o_first='1' THEN + -- Left edge. Duplicate first pixel + o_hpix1<=hpix_v; + o_hpix2<=hpix_v; + o_first<='0'; + END IF; + IF o_lastt4='1' THEN + -- Right edge. Keep last pixel. + o_hpix0<=o_hpix0; + END IF; + END IF; + + ------------------------------------------------------ + -- lev_inc : read start + -- lev_dec : end of copy + -- READLEV : Number of ongoing Avalon Reads + IF lev_dec_v='0' AND lev_inc_v='1' THEN + o_readlev<=o_readlev+1; + ELSIF lev_dec_v='1' AND lev_inc_v='0' THEN + o_readlev<=o_readlev-1; + END IF; + + -- COPYLEV : Number of ongoing copies to line buffers + IF lev_dec_v='1' AND o_readdataack='0' THEN + o_copylev<=o_copylev-1; + ELSIF lev_dec_v='0' AND o_readdataack='1' THEN + o_copylev<=o_copylev+1; + END IF; + + -- FIFOs + IF lev_dec_v='1' THEN + o_primv(0 TO 1)<=o_primv(1 TO 2); -- First buffer of line + o_lastv(0 TO 1)<=o_lastv(1 TO 2); -- Last buffer of line + o_bibv (0 TO 1)<=o_bibv (1 TO 2); -- Double buffer select + o_off (0 TO 1)<=o_off (1 TO 2); -- Start offset + END IF; + + IF lev_inc_v='1' THEN + IF o_readlev=0 OR (o_readlev=1 AND lev_dec_v='1') THEN + o_primv(0)<=prim_v; + o_lastv(0)<=last_v; + o_bibv (0)<=bib_v; + o_off (0)<=off_v; + ELSIF (o_readlev=1 AND lev_dec_v='0') OR + (o_readlev=2 AND lev_dec_v='1') THEN + o_primv(1)<=prim_v; + o_lastv(1)<=last_v; + o_bibv (1)<=bib_v; + o_off (1)<=off_v; + END IF; + o_primv(2)<=prim_v; + o_lastv(2)<=last_v; + o_bibv (2)<=bib_v; + o_off (2)<=off_v; + END IF; + + ------------------------------------------------------ + END IF; + END PROCESS Scalaire; + + -- Fetch polyphase coefficients + PolyFetch:PROCESS (o_clk) IS + VARIABLE hfrac3_v, vfrac_v : unsigned(FRAC-1 DOWNTO 0); + BEGIN + IF rising_edge(o_clk) THEN + hfrac3_v:=o_hfrac(3)(11 DOWNTO 12-FRAC); + vfrac_v:=o_vfrac(11 DOWNTO 12-FRAC); + + o_v_poly_use_adaptive <= to_std_logic((o_vmode(2 DOWNTO 0)/="000") AND (o_v_poly_adaptive = '1')); + o_h_poly_use_adaptive <= to_std_logic((o_hmode(2 DOWNTO 0)/="000") AND (o_h_poly_adaptive = '1')); + o_v_poly_addr<=to_integer(o_vfrac(11 DOWNTO 12-FRAC)); + + -- C3 / HC3 / VC4 + IF o_vmode(2 DOWNTO 0)/="000" THEN + o_v_poly_phase_a<=poly_unpack(o_v_poly_mem(o_v_poly_addr)); + ELSE + o_v_poly_phase_a<=poly_nn(vfrac_v); + END IF; + + IF o_hmode(2 DOWNTO 0)/="000" THEN + o_h_poly_phase_a<=poly_unpack(o_h_poly_mem(to_integer(hfrac3_v))); + ELSE + o_h_poly_phase_a<=poly_nn(hfrac3_v); + END IF; + + IF o_v_poly_use_adaptive='1' THEN + o_poly_lum<=poly_lum(o_v_lum_pix); + o_a_poly_addr<=o_v_poly_addr; + ELSIF o_h_poly_use_adaptive='1' THEN + o_poly_lum<=poly_lum(o_h_lum_pix); + o_a_poly_addr<=to_integer(hfrac3_v); + END IF; + + -- C4 / HC4 / VC5 + o_poly_phase_b<=poly_unpack(o_a_poly_mem(o_a_poly_addr)); + + IF o_v_poly_use_adaptive='1' THEN + o_poly_phase_a<=o_v_poly_phase_a; + ELSIF o_h_poly_use_adaptive = '1' THEN + o_poly_phase_a<=o_h_poly_phase_a; + END IF; + + o_h_poly_phase_a2<=o_h_poly_phase_a; + o_v_poly_phase_a2<=o_v_poly_phase_a; + o_poly_lum1<=o_poly_lum; + + -- C5 / HC5 / VC6 + o_poly_lerp_ta<=signed(to_unsigned(256,10) - resize(o_poly_lum1,10)); + o_poly_lerp_tb<=signed(resize(o_poly_lum1,10)); + + o_poly_phase_b2<=o_poly_phase_b; + o_poly_phase_a2<=o_poly_phase_a; + + o_h_poly_phase_a3<=o_h_poly_phase_a2; + o_v_poly_phase_a3<=o_v_poly_phase_a2; + + -- C6 / HC6 / VC7 + o_poly_phase<=poly_lerp(o_poly_phase_a2, o_poly_phase_b2, o_poly_lerp_ta, o_poly_lerp_tb); + o_h_poly_phase_a4<=o_h_poly_phase_a3; + o_v_poly_phase_a4<=o_v_poly_phase_a3; + + -- C7 / HC7 / VC8 + o_h_poly_phase_a5<=o_h_poly_phase_a4; + o_v_poly_phase_a5<=o_v_poly_phase_a4; + o_poly_phase1<=o_poly_phase; + + -- C8 / HC8 / VC9 + o_v_poly_phase<=poly_cvt(o_v_poly_phase_a5); + o_h_poly_phase<=poly_cvt(o_h_poly_phase_a5); + + IF o_v_poly_use_adaptive = '1' THEN + o_v_poly_phase<=o_poly_phase1; + ELSIF o_h_poly_use_adaptive = '1' THEN + o_h_poly_phase<=o_poly_phase1; + END IF; + + END IF; + END PROCESS PolyFetch; + + + -- Framebuffer palette + GenPal1:IF PALETTE GENERATE + Tempera1:PROCESS(pal1_clk) IS + BEGIN + IF rising_edge(pal1_clk) THEN + IF pal1_wr='1' THEN + pal1_mem(to_integer(pal1_a))<=pal1_dw; + END IF; + pal1_dr<=pal1_mem(to_integer(pal1_a)); + END IF; + END PROCESS; + + pal_idx <= shift_opack(o_acpt4,o_shift,o_dr,o_format)(0 TO 7); + pal_idx_lsb <= pal_idx(0) WHEN rising_edge(o_clk); + o_fb_pal_dr_x2 <= pal1_mem(to_integer(pal_idx(7 DOWNTO 1))) WHEN rising_edge(o_clk); + END GENERATE GenPal1; + + GenPal2:IF PALETTE and PALETTE2 GENERATE + Tempera2:PROCESS(pal2_clk) IS + BEGIN + IF rising_edge(pal2_clk) THEN + IF pal2_wr='1' THEN + pal2_mem(to_integer(pal2_a))<=pal2_dw; + END IF; + pal2_dr<=pal2_mem(to_integer(pal2_a)); + END IF; + END PROCESS; + + o_fb_pal_dr2 <= pal2_mem(to_integer(pal_idx(7 DOWNTO 0))) WHEN rising_edge(o_clk); + o_fb_pal_dr <= o_fb_pal_dr2 when pal_n = '1' else o_fb_pal_dr_x2(47 DOWNTO 24) WHEN pal_idx_lsb = '1' ELSE o_fb_pal_dr_x2(23 DOWNTO 0); + END GENERATE GenPal2; + + GenPal1not2:IF PALETTE and not PALETTE2 GENERATE + o_fb_pal_dr <= o_fb_pal_dr_x2(47 DOWNTO 24) WHEN pal_idx_lsb = '1' ELSE o_fb_pal_dr_x2(23 DOWNTO 0); + END GENERATE GenPal1not2; + + GenNoPal:IF NOT PALETTE GENERATE + o_fb_pal_dr<=x"000000"; + END GENERATE GenNoPal; + + ----------------------------------------------------------------------------- + -- Polyphase ROMs + Polikarpov:PROCESS(poly_clk) IS + BEGIN + IF rising_edge(poly_clk) THEN + IF poly_wr='1' THEN + poly_tdw(9+10*(3-to_integer(poly_a(1 DOWNTO 0))) DOWNTO + 10*(3-to_integer(poly_a(1 DOWNTO 0))))<=poly_dw; + END IF; + + poly_wr_mode(0)<=poly_wr AND NOT poly_a(FRAC+2); + poly_wr_mode(1)<=poly_wr AND poly_a(FRAC+2); + poly_wr_mode(2)<=poly_wr AND poly_a(FRAC+3) AND to_std_logic(ADAPTIVE); + poly_a2<=poly_a(FRAC+1 DOWNTO 2); + + CASE poly_wr_mode IS + WHEN "001" => -- horiz + o_h_poly_mem(to_integer(poly_a2))<=poly_tdw; + o_h_poly_adaptive<='0'; + WHEN "010" => -- vert + o_v_poly_mem(to_integer(poly_a2))<=poly_tdw; + o_v_poly_adaptive<='0'; + WHEN "101" => -- horiz adaptive + o_a_poly_mem(to_integer(poly_a2))<=poly_tdw; + o_h_poly_adaptive<='1'; + WHEN "110" => -- vert adaptive + o_a_poly_mem(to_integer(poly_a2))<=poly_tdw; + o_v_poly_adaptive<='1'; + WHEN OTHERS => NULL; + END CASE; + END IF; + END PROCESS Polikarpov; + + ----------------------------------------------------------------------------- + -- Horizontal Scaler + HSCAL:PROCESS(o_clk) IS + VARIABLE div_v : unsigned(20 DOWNTO 0); + VARIABLE dir_v : unsigned(11 DOWNTO 0); + BEGIN + IF rising_edge(o_clk) THEN + -- Pipeline signals + ----------------------------------- + -- Pipelined 8 bits non-restoring divider. Cycle 1 + dir_v:=x"000"; + div_v:=to_unsigned(o_hacc * 256,21); + + div_v:=div_v-to_unsigned(o_hsize*256,21); + dir_v(11):=NOT div_v(20); + IF div_v(20)='0' THEN + div_v:=div_v-to_unsigned(o_hsize*128,21); + ELSE + div_v:=div_v+to_unsigned(o_hsize*128,21); + END IF; + dir_v(10):=NOT div_v(20); + + o_div(0)<=div_v; + o_dir(0)<=dir_v; + + -- Cycle 2 + div_v:=o_div(0); + dir_v:=o_dir(0); + IF div_v(20)='0' THEN + div_v:=div_v-to_unsigned(o_hsize*64,21); + ELSE + div_v:=div_v+to_unsigned(o_hsize*64,21); + END IF; + dir_v( 9):=NOT div_v(20); + + IF div_v(20)='0' THEN + div_v:=div_v-to_unsigned(o_hsize*32,21); + ELSE + div_v:=div_v+to_unsigned(o_hsize*32,21); + END IF; + dir_v( 8):=NOT div_v(20); + + o_div(1)<=div_v; + o_dir(1)<=dir_v; + + -- Cycle 3 + div_v:=o_div(1); + dir_v:=o_dir(1); + IF FRAC>4 THEN + IF div_v(20)='0' THEN + div_v:=div_v-to_unsigned(o_hsize*16,21); + ELSE + div_v:=div_v+to_unsigned(o_hsize*16,21); + END IF; + dir_v(7):=NOT div_v(20); + + IF div_v(20)='0' THEN + div_v:=div_v-to_unsigned(o_hsize*8,21); + ELSE + div_v:=div_v+to_unsigned(o_hsize*8,21); + END IF; + dir_v(6):=NOT div_v(20); + END IF; + o_div(2)<=div_v; + o_dir(2)<=dir_v; + + div_v:=o_div(2); + dir_v:=o_dir(2); + IF FRAC>6 THEN + IF div_v(20)='0' THEN + div_v:=div_v-to_unsigned(o_hsize*4,21); + ELSE + div_v:=div_v+to_unsigned(o_hsize*4,21); + END IF; + dir_v(5):=NOT div_v(20); + + IF div_v(20)='0' THEN + div_v:=div_v-to_unsigned(o_hsize*2,21); + ELSE + div_v:=div_v+to_unsigned(o_hsize*2,21); + END IF; + dir_v(4):=NOT div_v(20); + END IF; + + ----------------------------------- + o_hfrac(1)<=dir_v; + o_hfrac(2 TO 9) <= o_hfrac(1 TO 8); + + o_copyv(1 TO 14)<=o_copyv(0 TO 13); + + o_dcptv(1)<=o_dcpt; + IF o_dcptv(1)>=o_hsize THEN + o_copyv(2)<='0'; + END IF; + o_dcptv(2)<=o_dcptv(1) MOD OHRES; + o_dcptv(3 TO 14)<=o_dcptv(2 TO 13); + + -- C2 + o_hpixq(2)<=(o_hpix3,o_hpix2,o_hpix1,o_hpix0); + o_hpixq(3 TO 8)<=o_hpixq(2 TO 7); + + -- BILINEAR / SHARP BILINEAR --------------- + -- C7 : Pre-calc Sharp Bilinear + o_h_sbil_t<=sbil_frac1(o_hfrac(6)); + + -- C8 : Select + o_h_bil_frac<=(OTHERS =>'0'); + IF o_hmode(0)='1' THEN -- Bilinear + IF MASK(MASK_BILINEAR)='1' THEN + o_h_bil_frac<=bil_frac(o_hfrac(7)); + END IF; + ELSE -- Sharp Bilinear + IF MASK(MASK_SHARP_BILINEAR)='1' THEN + o_h_bil_frac<=sbil_frac2(o_hfrac(7),o_h_sbil_t); + END IF; + END IF; + + -- C9 : Opposite frac + o_h_bil_t<=bil_calc(o_h_bil_frac,o_hpixq(8)); + + -- C10 : Bilinear / Sharp Bilinear + o_h_bil_pix.r<=bound(o_h_bil_t.r,8+FRAC); + o_h_bil_pix.g<=bound(o_h_bil_t.g,8+FRAC); + o_h_bil_pix.b<=bound(o_h_bil_t.b,8+FRAC); + + -- BICUBIC ------------------------------------------- + -- C8 : Bicubic coefficients A,B,C,D + -- C8 : Bicubic calc T1 = X.D + C + o_h_bic_abcd1<=bic_calc0(o_hfrac(7),o_hpixq(6)); + o_h_bic_tt1<=bic_calc1(o_hfrac(7), + bic_calc0(o_hfrac(7),o_hpixq(6))); + + -- C9 : Bicubic calc T2 = X.T1 + B + o_h_bic_abcd2<=o_h_bic_abcd1; + o_h_bic_tt2<=bic_calc2(o_hfrac(8),o_h_bic_tt1,o_h_bic_abcd1); + + -- C10 : Bicubic final Y = X.T2 + A + o_h_bic_pix<=bic_calc3(o_hfrac(9),o_h_bic_tt2,o_h_bic_abcd2); + + -- POLYPHASE ----------------------------------------- + -- C2 + IF o_hfrac(2)(o_hfrac(2)'left)='0' THEN + o_h_lum_pix<=o_hpix2; + ELSE + o_h_lum_pix<=o_hpix1; + END IF; + + -- C3-C8 in PolyFetch + + -- C9 : Apply Polyphase + o_h_poly_t<=poly_calc(o_h_poly_phase,o_hpixq(8)); + + -- C10 : Sum and bound + o_h_poly_pix<=poly_final(o_h_poly_t); + + -- C11 : Select interpoler ---------------------------- + o_wadl<=o_dcptv(14); + o_wr<=o_altx AND (o_copyv(14) & o_copyv(14) & o_copyv(14) & o_copyv(14)); + o_ldw<=(x"00",x"00",x"00"); + + CASE o_hmode(2 DOWNTO 0) IS + WHEN "000" => -- Nearest + IF MASK(MASK_NEAREST)='1' THEN + o_ldw<=o_h_poly_pix; + END IF; + WHEN "001" | "010" => -- Bilinear | Sharp Bilinear + IF MASK(MASK_BILINEAR)='1' OR + MASK(MASK_SHARP_BILINEAR)='1' THEN + o_ldw<=o_h_bil_pix; + END IF; + WHEN "011" => -- BiCubic + IF MASK(MASK_BICUBIC)='1' THEN + o_ldw<=o_h_bic_pix; + END IF; + WHEN OTHERS => -- PolyPhase + IF MASK(MASK_POLY)='1' THEN + o_ldw<=o_h_poly_pix; + END IF; + END CASE; + ------------------------------------------------------ + END IF; + END PROCESS HSCAL; + + ----------------------------------------------------------------------------- + -- Line buffers 4 x OHRES x (R+G+B) + OLBUF:PROCESS(o_clk) IS + BEGIN + IF rising_edge(o_clk) THEN + -- WRITES + IF o_wr(0)='1' THEN o_line0(o_wadl)<=o_ldw; END IF; + IF o_wr(1)='1' THEN o_line1(o_wadl)<=o_ldw; END IF; + IF o_wr(2)='1' THEN o_line2(o_wadl)<=o_ldw; END IF; + IF o_wr(3)='1' THEN o_line3(o_wadl)<=o_ldw; END IF; + + -- READS + o_ldr0<=o_line0(o_radl0); + o_ldr1<=o_line1(o_radl1); + o_ldr2<=o_line2(o_radl2); + o_ldr3<=o_line3(o_radl3); + END IF; + END PROCESS OLBUF; + + ----------------------------------------------------------------------------- + -- Output video sweep + OSWEEP:PROCESS(o_clk) IS + BEGIN + IF rising_edge(o_clk) THEN + + IF o_ce='1' THEN + -- Output pixels count + IF o_hcpt+1=o_vtotal THEN + o_vcpt_pre3<=0; + ELSIF o_vrr_sync2 THEN + o_vcpt_pre3<=o_vsstart; + o_sync<=false; + ELSE + o_vcpt_pre3<=(o_vcpt_pre3+1) MOD 4096; + END IF; + + o_vcpt_pre2<=o_vcpt_pre3; + o_vcpt_pre<=o_vcpt_pre2; + o_vcpt<=o_vcpt_pre; + END IF; + + o_end(0)<=to_std_logic(o_vcpt>=o_vdisp); + o_dev(0)<=to_std_logic(o_hcpt=o_hmin AND o_hcpt<=o_hmax AND + o_vcpt>=o_vmin AND o_vcpt<=o_vmax); + o_hsv(0)<=to_std_logic(o_hcpt>=o_hsstart AND o_hcpt=o_hsstart) OR + (o_vcpt>o_vsstart AND o_vcpt=o_vmin AND o_vcpt_pre2<=o_vmax); + o_hsv(1 TO 11)<=o_hsv(0 TO 10); + o_vsv(1 TO 11)<=o_vsv(0 TO 10); + o_dev(1 TO 11)<=o_dev(0 TO 10); + o_pev(1 TO 11)<=o_pev(0 TO 10); + o_end(1 TO 11)<=o_end(0 TO 10); + + IF o_run='0' THEN + o_hsv(2)<='0'; + o_vsv(2)<='0'; + o_dev(2)<='0'; + o_pev(2)<='0'; + o_end(2)<='0'; + END IF; + END IF; + + o_vcpt_sync2<=o_vcpt_sync; + o_vrr_min<=(o_vcpt_sync2=o_vdisp AND o_vcpt2 o_radl1<=r2_v; + WHEN "11" => o_radl2<=r2_v; + WHEN "00" => o_radl3<=r2_v; + WHEN OTHERS => o_radl0<=r2_v; + END CASE; + ELSE + CASE o_vacptl IS + WHEN "10" => o_radl2<=r2_v; + WHEN "11" => o_radl3<=r2_v; + WHEN "00" => o_radl0<=r2_v; + WHEN OTHERS => o_radl1<=r2_v; + END CASE; + END IF; + + -- CYCLE 2 ----------------------------------------- + -- Lines reordering + CASE o_vacptl IS + WHEN "10" => pixq_v:=(o_ldr0,o_ldr1,o_ldr2,o_ldr3); + WHEN "11" => pixq_v:=(o_ldr1,o_ldr2,o_ldr3,o_ldr0); + WHEN "00" => pixq_v:=(o_ldr2,o_ldr3,o_ldr0,o_ldr1); + WHEN OTHERS => pixq_v:=(o_ldr3,o_ldr0,o_ldr1,o_ldr2); + END CASE; + + IF fracnn_v = '0' THEN + o_vpix_outer<=(pixq_v(0), pixq_v(2), pixq_v(3)); + o_vpix_inner(0)<=pixq_v(1); + ELSE + o_vpix_outer<=(pixq_v(0), pixq_v(1), pixq_v(3)); + o_vpix_inner(0)<=pixq_v(2); + END IF; + + -- CYCLE 3-7 + o_vpix_inner(1 TO 5)<=o_vpix_inner(0 TO 4); + + -- CYCLE 8 + IF to_integer(o_vacpt)>o_ivsize THEN + IF fracnn_v = '0' THEN + o_vpixq_pre<=(o_vpix_outer(0), o_vpix_inner(5), o_vpix_inner(5), o_vpix_inner(5)); + ELSE + o_vpixq_pre<=(o_vpix_outer(0), o_vpix_outer(1), o_vpix_outer(1), o_vpix_outer(1)); + END IF; + ELSIF to_integer(o_vacpt)=o_ivsize THEN + IF fracnn_v = '0' THEN + o_vpixq_pre<=(o_vpix_outer(0), o_vpix_inner(5), o_vpix_outer(1), o_vpix_outer(1)); + ELSE + o_vpixq_pre<=(o_vpix_outer(0), o_vpix_outer(1), o_vpix_inner(5), o_vpix_inner(5)); + END IF; + ELSE + IF fracnn_v = '0' THEN + o_vpixq_pre<=(o_vpix_outer(0), o_vpix_inner(5), o_vpix_outer(1), o_vpix_outer(2)); + ELSE + o_vpixq_pre<=(o_vpix_outer(0), o_vpix_outer(1), o_vpix_inner(5), o_vpix_outer(2)); + END IF; + END IF; + + -- CYCLE 9 + o_vpixq<=o_vpixq_pre; + + -- BILINEAR / SHARP BILINEAR ----------------------- + -- C8 : Pre-calc Sharp Bilinear + o_v_sbil_t<=sbil_frac1(o_vfrac); + + -- C9 : Select + o_v_bil_frac<=(OTHERS =>'0'); + IF o_vmode(0)='1' THEN -- Bilinear + IF MASK(MASK_BILINEAR)='1' THEN + o_v_bil_frac<=bil_frac(o_vfrac); + END IF; + ELSE -- Sharp Bilinear + IF MASK(MASK_SHARP_BILINEAR)='1' THEN + o_v_bil_frac<=sbil_frac2(o_vfrac,o_v_sbil_t); + END IF; + END IF; + + -- C10 : + o_v_bil_t<=bil_calc(o_v_bil_frac,o_vpixq); + + -- C11 : Nearest / Bilinear / Sharp Bilinear + o_v_bil_pix.r<=bound(o_v_bil_t.r,8+FRAC); + o_v_bil_pix.g<=bound(o_v_bil_t.g,8+FRAC); + o_v_bil_pix.b<=bound(o_v_bil_t.b,8+FRAC); + + -- BICUBIC ----------------------------------------- + -- C9 : Bicubic coefficients A,B,C,D + -- C9 : Bicubic calc T1 = X.D + C + o_v_bic_abcd1<=bic_calc0(o_vfrac,o_vpixq); + o_v_bic_tt1<=bic_calc1(o_vfrac,bic_calc0(o_vfrac,o_vpixq)); + + -- C10 : Bicubic calc T2 = X.T1 + B + o_v_bic_abcd2<=o_v_bic_abcd1; + o_v_bic_tt2<=bic_calc2(o_vfrac,o_v_bic_tt1,o_v_bic_abcd1); + + -- C11 : Bicubic final Y = X.T2 + A + o_v_bic_pix<=bic_calc3(o_vfrac,o_v_bic_tt2,o_v_bic_abcd2); + + -- POLYPHASE --------------------------------------- + -- C3 : Setup luminance + o_v_lum_pix<=o_vpix_inner(0); + + -- C4-C9 in PolyFetch + + -- C10 : Apply polyphase + o_v_poly_t<=poly_calc(o_v_poly_phase,o_vpixq); + + -- C11 : Bound + o_v_poly_pix<=poly_final(o_v_poly_t); + + -- CYCLE 12 ----------------------------------------- + o_hs<=o_hsv(11); + o_vs<=o_vsv(11); + o_de<=o_dev(11); + o_vbl<=o_end(11); + o_r<=x"00"; + o_g<=x"00"; + o_b<=x"00"; + o_brd<= not o_pev(11); + + CASE o_vmode(2 DOWNTO 0) IS + WHEN "000" => -- Nearest + IF MASK(MASK_NEAREST)='1' THEN + o_r<=o_v_poly_pix.r; + o_g<=o_v_poly_pix.g; + o_b<=o_v_poly_pix.b; + END IF; + WHEN "001" | "010" => -- Bilinear | Sharp Bilinear + IF MASK(MASK_BILINEAR)='1' OR + MASK(MASK_SHARP_BILINEAR)='1' THEN + o_r<=o_v_bil_pix.r; + o_g<=o_v_bil_pix.g; + o_b<=o_v_bil_pix.b; + END IF; + WHEN "011" => -- BiCubic + IF MASK(MASK_BICUBIC)='1' THEN + o_r<=o_v_bic_pix.r; + o_g<=o_v_bic_pix.g; + o_b<=o_v_bic_pix.b; + END IF; + + WHEN OTHERS => -- Polyphase + IF MASK(MASK_POLY)='1' THEN + o_r<=o_v_poly_pix.r; + o_g<=o_v_poly_pix.g; + o_b<=o_v_poly_pix.b; + END IF; + END CASE; + + IF o_pev(11)='0' THEN + o_r<=o_border(23 DOWNTO 16); -- Copy border colour + o_g<=o_border(15 DOWNTO 8); + o_b<=o_border(7 DOWNTO 0); + END IF; + + ---------------------------------------------------- + END IF; + END IF; + END PROCESS VSCAL; + + ----------------------------------------------------------------------------- + -- Low Lag syntoniser interface + o_lltune<=(0 => i_vss, + 1 => i_pde, + 2 => i_inter, + 3 => i_flm, + 4 => o_vss, + 5 => i_pce, + 6 => i_clk, + 7 => o_clk, + OTHERS =>'0'); + + ---------------------------------------------------------------------------- END ARCHITECTURE rtl; diff --git a/sys/hdmi_config.sv b/sys/hdmi_config.sv deleted file mode 100644 index 4a0a13d..0000000 --- a/sys/hdmi_config.sv +++ /dev/null @@ -1,239 +0,0 @@ - -module hdmi_config -( - // Host Side - input iCLK, - input iRST_N, - - input dvi_mode, - input audio_96k, - input [1:0] limited, - input ypbpr, - - output reg done, - - // I2C Side - output I2C_SCL, - inout I2C_SDA -); - -// Internal Registers/Wires -reg mI2C_GO = 0; -wire mI2C_END; -wire mI2C_ACK; -reg [15:0] LUT_DATA; -reg [7:0] LUT_INDEX = 0; - -i2c #(50_000_000, 20_000) i2c_av -( - .CLK(iCLK), - - .I2C_SCL(I2C_SCL), // I2C CLOCK - .I2C_SDA(I2C_SDA), // I2C DATA - - .I2C_ADDR('h39), // 0x39 is the Slave Address of the ADV7513 chip! - .I2C_WLEN(1), - .I2C_WDATA1(init_data[LUT_INDEX][15:8]), // SUB_ADDR - .I2C_WDATA2(init_data[LUT_INDEX][7:0]), // DATA - .START(mI2C_GO), // START transfer - .READ(0), - .END(mI2C_END), // END transfer - .ACK(mI2C_ACK) // ACK -); - -////////////////////// Config Control //////////////////////////// -always@(posedge iCLK or negedge iRST_N) begin - reg [1:0] mSetup_ST = 0; - - if(!iRST_N) begin - LUT_INDEX <= 0; - mSetup_ST <= 0; - mI2C_GO <= 0; - done <= 0; - end else begin - if(init_data[LUT_INDEX] != 16'hFFFF) begin - case(mSetup_ST) - 0: begin - mI2C_GO <= 1; - mSetup_ST <= 1; - end - 1: if(~mI2C_END) mSetup_ST <= 2; - 2: begin - mI2C_GO <= 0; - if(mI2C_END) begin - mSetup_ST <= 0; - if(!mI2C_ACK) LUT_INDEX <= LUT_INDEX + 8'd1; - end - end - endcase - end - else done <= 1; - end -end - -//////////////////////////////////////////////////////////////////// -///////////////////// Config Data LUT ////////////////////////// - -wire [15:0] init_data[82] = -'{ - 16'h9803, // ADI required Write. - - {8'hD6, 8'b1100_0000}, // [7:6] HPD Control... - // 00 = HPD is from both HPD pin or CDC HPD - // 01 = HPD is from CDC HPD - // 10 = HPD is from HPD pin - // 11 = HPD is always high - - 16'h4110, // Power Down control - 16'h9A70, // ADI required Write. - 16'h9C30, // ADI required Write. - {8'h9D, 8'b0110_0001}, // [7:4] must be b0110!. - // [3:2] b00 = Input clock not divided. b01 = Clk divided by 2. b10 = Clk divided by 4. b11 = invalid! - // [1:0] must be b01! - 16'hA2A4, // ADI required Write. - 16'hA3A4, // ADI required Write. - 16'hE0D0, // ADI required Write. - - - 16'h35_40, - 16'h36_D9, - 16'h37_0A, - 16'h38_00, - 16'h39_2D, - 16'h3A_00, - - {8'h16, 8'b0011_1000}, // Output Format 444 [7]=0. - // [6] must be 0! - // Colour Depth for Input Video data [5:4] b11 = 8-bit. - // Input Style [3:2] b10 = Style 1 (ignored when using 444 input). - // DDR Input Edge falling [1]=0 (not using DDR atm). - // Output Colour Space RGB [0]=0. - - {8'h17, 8'b01100010}, // Aspect ratio 16:9 [1]=1, 4:3 [1]=0 - - {8'h18, ypbpr ? 8'h86 : limited[0] ? 8'h8D : limited[1] ? 8'h8E : 8'h00}, // CSC Scaling Factors and Coefficients for RGB Full->Limited. - {8'h19, ypbpr ? 8'hDF : limited[0] ? 8'hBC : 8'hFE}, // Taken from table in ADV7513 Programming Guide. - {8'h1A, ypbpr ? 8'h1A : 8'h00}, // CSC Channel A. - {8'h1B, ypbpr ? 8'h3F : 8'h00}, - {8'h1C, ypbpr ? 8'h1E : 8'h00}, - {8'h1D, ypbpr ? 8'hE2 : 8'h00}, - {8'h1E, ypbpr ? 8'h07 : 8'h01}, - {8'h1F, ypbpr ? 8'hE7 : 8'h00}, - - {8'h20, ypbpr ? 8'h04 : 8'h00}, // CSC Channel B. - {8'h21, ypbpr ? 8'h1C : 8'h00}, - {8'h22, ypbpr ? 8'h08 : limited[0] ? 8'h0D : 8'h0E}, - {8'h23, ypbpr ? 8'h11 : limited[0] ? 8'hBC : 8'hFE}, - {8'h24, ypbpr ? 8'h01 : 8'h00}, - {8'h25, ypbpr ? 8'h91 : 8'h00}, - {8'h26, ypbpr ? 8'h01 : 8'h01}, - {8'h27, 8'h00}, - - {8'h28, ypbpr ? 8'h1D : 8'h00}, // CSC Channel C. - {8'h29, ypbpr ? 8'hAE : 8'h00}, - {8'h2A, ypbpr ? 8'h1B : 8'h00}, - {8'h2B, ypbpr ? 8'h73 : 8'h00}, - {8'h2C, ypbpr ? 8'h06 : limited[0] ? 8'h0D : 8'h0E}, - {8'h2D, ypbpr ? 8'hDF : limited[0] ? 8'hBC : 8'hFE}, - {8'h2E, ypbpr ? 8'h07 : 8'h01}, - {8'h2F, ypbpr ? 8'hE7 : 8'h00}, - - {8'h3B, 8'b0000_0000}, // Pixel repetition [6:5] b00 AUTO. [4:3] b00 x1 mult of input clock. [2:1] b00 x1 pixel rep to send to HDMI Rx. - - 16'h4000, // General Control Packet Enable - - {8'h48, 8'b0000_1000}, // [6]=0 Normal bus order! - // [5] DDR Alignment. - // [4:3] b01 Data right justified (for YCbCr 422 input modes). - - 16'h49A8, // ADI required Write. - 16'h4C00, // ADI required Write. - - {8'h55, 8'b0001_0000}, // [7] must be 0!. Set RGB444 in AVinfo Frame [6:5], Set active format [4]. - // AVI InfoFrame Valid [4]. - // Bar Info [3:2] b00 Bars invalid. b01 Bars vertical. b10 Bars horizontal. b11 Bars both. - // Scan Info [1:0] b00 (No data). b01 TV. b10 PC. b11 None. - - {8'h57, 1'b0, // [7] IT Content. 0 - No. 1 - Yes (type set in register h59). - 3'b000, // [6:4] Color space (ignored for RGB) - (ypbpr | limited) ? 2'b01 : 2'b10, // [3:2] RGB Quantization range - 2'b00}, // [1:0] Non-Uniform Scaled: 00 - None. 01 - Horiz. 10 - Vert. 11 - Both. - - 16'h7301, - - {8'h94, 8'b1000_0000}, // [7]=1 HPD Interrupt ENabled. - - 16'h9902, // ADI required Write. - 16'h9B18, // ADI required Write. - - 16'h9F00, // ADI required Write. - - {8'hA1, 8'b0000_0000}, // [6]=1 Monitor Sense Power Down DISabled. - - 16'hA408, // ADI required Write. - 16'hA504, // ADI required Write. - 16'hA600, // ADI required Write. - 16'hA700, // ADI required Write. - 16'hA800, // ADI required Write. - 16'hA900, // ADI required Write. - 16'hAA00, // ADI required Write. - 16'hAB40, // ADI required Write. - - {8'hAF, 6'b0000_01,~dvi_mode,1'b0}, // [7]=0 HDCP Disabled. - // [6:5] must be b00! - // [4]=0 Current frame is unencrypted - // [3:2] must be b01! - // [1]=1 HDMI Mode. - // [0] must be b0! - - 16'hB900, // ADI required Write. - - {8'hBA, 8'b0110_0000}, // [7:5] Input Clock delay... - // b000 = -1.2ns. - // b001 = -0.8ns. - // b010 = -0.4ns. - // b011 = No delay. - // b100 = 0.4ns. - // b101 = 0.8ns. - // b110 = 1.2ns. - // b111 = 1.6ns. - - 16'hBB00, // ADI required Write. - - 16'hDE9C, // ADI required Write. - 16'hE460, // ADI required Write. - 16'hFA7D, // Nbr of times to search for good phase - - - // (Audio stuff on Programming Guide, Page 66)... - - {8'h0A, 8'b0000_0000}, // [6:4] Audio Select. b000 = I2S. - // [3:2] Audio Mode. (HBR stuff, leave at 00!). - - {8'h0B, 8'b0000_1110}, // - - {8'h0C, 8'b0000_0100}, // [7] 0 = Use sampling rate from I2S stream. 1 = Use samp rate from I2C Register. - // [6] 0 = Use Channel Status bits from stream. 1 = Use Channel Status bits from I2C register. - // [2] 1 = I2S0 Enable. - // [1:0] I2S Format: 00 = Standard. 01 = Right Justified. 10 = Left Justified. 11 = AES. - - {8'h0D, 8'b0001_0000}, // [4:0] I2S Bit (Word) Width for Right-Justified. - {8'h14, 8'b0000_0010}, // [3:0] Audio Word Length. b0010 = 16 bits. - {8'h15, audio_96k, 7'b010_0000}, // I2S Sampling Rate [7:4]. b0000 = (44.1KHz). b0010 = 48KHz. - // Input ID [3:1] b000 (0) = 24-bit RGB 444 or YCrCb 444 with Separate Syncs. - - // Audio Clock Config - 16'h0100, // - audio_96k ? 16'h0230 : 16'h0218, // Set N Value 12288/6144 - 16'h0300, // - - 16'h0701, // - 16'h0822, // Set CTS Value 74250 - 16'h090A, // - - 16'hFFFF // END -}; - -//////////////////////////////////////////////////////////////////// - -endmodule \ No newline at end of file diff --git a/sys/hps_io.sv b/sys/hps_io.sv index 826b37c..9eee8ee 100644 --- a/sys/hps_io.sv +++ b/sys/hps_io.sv @@ -24,13 +24,13 @@ // Use buffer to access SD card. It's time-critical part. // // WIDE=1 for 16 bit file I/O -// VDNUM 1..4 +// VDNUM 1..10 // BLKSZ 0..7: 0 = 128, 1 = 256, 2 = 512(default), .. 7 = 16384 // module hps_io #(parameter CONF_STR, CONF_STR_BRAM=1, PS2DIV=0, WIDE=0, VDNUM=1, BLKSZ=2, PS2WE=0) ( input clk_sys, - inout [45:0] HPS_BUS, + inout [48:0] HPS_BUS, // buttons up to 32 output reg [31:0] joystick_0, @@ -55,6 +55,13 @@ module hps_io #(parameter CONF_STR, CONF_STR_BRAM=1, PS2DIV=0, WIDE=0, VDNUM=1, output reg [15:0] joystick_r_analog_4, output reg [15:0] joystick_r_analog_5, + input [15:0] joystick_0_rumble, // 15:8 - 'large' rumble motor magnitude, 7:0 'small' rumble motor magnitude + input [15:0] joystick_1_rumble, + input [15:0] joystick_2_rumble, + input [15:0] joystick_3_rumble, + input [15:0] joystick_4_rumble, + input [15:0] joystick_5_rumble, + // paddle 0..255 output reg [7:0] paddle_0, output reg [7:0] paddle_1, @@ -71,21 +78,47 @@ module hps_io #(parameter CONF_STR, CONF_STR_BRAM=1, PS2DIV=0, WIDE=0, VDNUM=1, output reg [8:0] spinner_4, output reg [8:0] spinner_5, + // ps2 keyboard emulation + output ps2_kbd_clk_out, + output ps2_kbd_data_out, + input ps2_kbd_clk_in, + input ps2_kbd_data_in, + + input [2:0] ps2_kbd_led_status, + input [2:0] ps2_kbd_led_use, + + output ps2_mouse_clk_out, + output ps2_mouse_data_out, + input ps2_mouse_clk_in, + input ps2_mouse_data_in, + + // ps2 alternative interface. + + // [8] - extended, [9] - pressed, [10] - toggles with every press/release + output reg [10:0] ps2_key = 0, + + // [24] - toggles with every event + output reg [24:0] ps2_mouse = 0, + output reg [15:0] ps2_mouse_ext = 0, // 15:8 - reserved(additional buttons), 7:0 - wheel movements + output [1:0] buttons, output forced_scandoubler, output direct_video, - - output reg [63:0] status, - input [63:0] status_in, - input status_set, - input [15:0] status_menumask, - - input info_req, - input [7:0] info, + input video_rotated, //toggle to force notify of video mode change input new_vmode, + inout [21:0] gamma_bus, + + output reg [127:0] status, + input [127:0] status_in, + input status_set, + input [15:0] status_menumask, + + input info_req, + input [7:0] info, + // SD config output reg [VD:0] img_mounted, // signaling that new image has been mounted output reg img_readonly, // mounted as read only. valid only for active bit in img_mounted @@ -111,7 +144,8 @@ module hps_io #(parameter CONF_STR, CONF_STR_BRAM=1, PS2DIV=0, WIDE=0, VDNUM=1, output reg [26:0] ioctl_addr, // in WIDE mode address will be incremented by 2 output reg [DW:0] ioctl_dout, output reg ioctl_upload = 0, // signal indicating an active upload - input ioctl_upload_req, + input ioctl_upload_req, // request to save (must be supported on HPS side for specific core) + input [7:0] ioctl_upload_index, input [DW:0] ioctl_din, output reg ioctl_rd, output reg [31:0] ioctl_file_ext, @@ -131,31 +165,6 @@ module hps_io #(parameter CONF_STR, CONF_STR_BRAM=1, PS2DIV=0, WIDE=0, VDNUM=1, output reg [7:0] uart_mode, output reg [31:0] uart_speed, - // ps2 keyboard emulation - output ps2_kbd_clk_out, - output ps2_kbd_data_out, - input ps2_kbd_clk_in, - input ps2_kbd_data_in, - - input [2:0] ps2_kbd_led_status, - input [2:0] ps2_kbd_led_use, - - output ps2_mouse_clk_out, - output ps2_mouse_data_out, - input ps2_mouse_clk_in, - input ps2_mouse_data_in, - - // ps2 alternative interface. - - // [8] - extended, [9] - pressed, [10] - toggles with every press/release - output reg [10:0] ps2_key = 0, - - // [24] - toggles with every event - output reg [24:0] ps2_mouse = 0, - output reg [15:0] ps2_mouse_ext = 0, // 15:8 - reserved(additional buttons), 7:0 - wheel movements - - inout [21:0] gamma_bus, - // for core-specific extensions inout [35:0] EXT_BUS ); @@ -215,6 +224,7 @@ video_calc video_calc .vs_hdmi(HPS_BUS[44]), .f1(HPS_BUS[45]), .new_vmode(new_vmode), + .video_rotated(video_rotated), .par_num(byte_cnt[3:0]), .dout(vc_dout) @@ -256,7 +266,7 @@ always@(posedge clk_sys) begin : uio_block reg [3:0] pdsp_idx; reg ps2skip = 0; reg [3:0] stflg = 0; - reg [63:0] status_req; + reg[127:0] status_req; reg old_status_set = 0; reg old_upload_req = 0; reg upload_req = 0; @@ -316,12 +326,23 @@ always@(posedge clk_sys) begin : uio_block 'h0X17, 'h0X18: begin sd_ack <= disk[VD:0]; sdn_ack <= io_din[11:8]; end 'h29: io_dout <= {4'hA, stflg}; - 'h2B: io_dout <= 1; +`ifdef MISTER_DISABLE_ADAPTIVE + 'h2B: io_dout <= {HPS_BUS[48:46],4'b0110}; +`else + 'h2B: io_dout <= {HPS_BUS[48:46],4'b0111}; +`endif 'h2F: io_dout <= 1; 'h32: io_dout <= gamma_bus[21]; 'h36: begin io_dout <= info_n; info_n <= 0; end 'h39: io_dout <= 1; - 'h3C: if(upload_req) begin io_dout <= 1; upload_req <= 0; end + 'h3C: if(upload_req) begin io_dout <= {ioctl_upload_index, 8'd1}; upload_req <= 0; end + 'h3E: io_dout <= 1; // shadow mask + 'h003F: io_dout <= joystick_0_rumble; + 'h013F: io_dout <= joystick_1_rumble; + 'h023F: io_dout <= joystick_2_rumble; + 'h033F: io_dout <= joystick_3_rumble; + 'h043F: io_dout <= joystick_4_rumble; + 'h053F: io_dout <= joystick_5_rumble; endcase sd_buff_addr <= 0; @@ -447,13 +468,17 @@ always@(posedge clk_sys) begin : uio_block // send image info 'h1d: if(byte_cnt<5) img_size[{byte_cnt-1'b1, 4'b0000} +:16] <= io_din; - // status, 64bit version - 'h1e: if(!byte_cnt[MAX_W:3]) begin - case(byte_cnt[2:0]) - 1: status[15:00] <= io_din; - 2: status[31:16] <= io_din; - 3: status[47:32] <= io_din; - 4: status[63:48] <= io_din; + // status, 128bit version + 'h1e: if(!byte_cnt[MAX_W:4]) begin + case(byte_cnt[3:0]) + 1: status[15:00] <= io_din; + 2: status[31:16] <= io_din; + 3: status[47:32] <= io_din; + 4: status[63:48] <= io_din; + 5: status[79:64] <= io_din; + 6: status[95:80] <= io_din; + 7: status[111:96] <= io_din; + 8: status[127:112] <= io_din; endcase end @@ -483,12 +508,16 @@ always@(posedge clk_sys) begin : uio_block 'h24: TIMESTAMP[(byte_cnt-6'd1)<<4 +:16] <= io_din; //status set - 'h29: if(!byte_cnt[MAX_W:3]) begin - case(byte_cnt[2:0]) + 'h29: if(!byte_cnt[MAX_W:4]) begin + case(byte_cnt[3:0]) 1: io_dout <= status_req[15:00]; 2: io_dout <= status_req[31:16]; 3: io_dout <= status_req[47:32]; 4: io_dout <= status_req[63:48]; + 5: io_dout <= status_req[79:64]; + 6: io_dout <= status_req[95:80]; + 7: io_dout <= status_req[111:96]; + 8: io_dout <= status_req[127:112]; endcase end @@ -841,6 +870,7 @@ module video_calc input vs_hdmi, input f1, input new_vmode, + input video_rotated, input [3:0] par_num, output reg [15:0] dout @@ -848,7 +878,7 @@ module video_calc always @(posedge clk_sys) begin case(par_num) - 1: dout <= {|vid_int, vid_nres}; + 1: dout <= {video_rotated, |vid_int, vid_nres}; 2: dout <= vid_hcnt[15:0]; 3: dout <= vid_hcnt[31:16]; 4: dout <= vid_vcnt[15:0]; diff --git a/sys/scanlines.v b/sys/scanlines.v index 59d29bd..43f890f 100644 --- a/sys/scanlines.v +++ b/sys/scanlines.v @@ -5,11 +5,11 @@ module scanlines #(parameter v2=0) input [1:0] scanlines, input [23:0] din, input hs_in,vs_in, - input de_in, + input de_in,ce_in, output reg [23:0] dout, output reg hs_out,vs_out, - output reg de_out + output reg de_out,ce_out ); reg [1:0] scanline; @@ -56,12 +56,13 @@ end always @(posedge clk) begin reg [23:0] dout1, dout2; - reg de1,de2,vs1,vs2,hs1,hs2; + reg de1,de2,vs1,vs2,hs1,hs2,ce1,ce2; dout <= dout2; dout2 <= dout1; dout1 <= d; vs_out <= vs2; vs2 <= vs1; vs1 <= vs_in; hs_out <= hs2; hs2 <= hs1; hs1 <= hs_in; de_out <= de2; de2 <= de1; de1 <= de_in; + ce_out <= ce2; ce2 <= ce1; ce1 <= ce_in; end endmodule diff --git a/sys/shadowmask.sv b/sys/shadowmask.sv new file mode 100644 index 0000000..572679c --- /dev/null +++ b/sys/shadowmask.sv @@ -0,0 +1,136 @@ +module shadowmask +( + input clk, + input clk_sys, + + input cmd_wr, + input [15:0] cmd_in, + + input [23:0] din, + input hs_in,vs_in, + input de_in, + input brd_in, + input enable, + + output reg [23:0] dout, + output reg hs_out,vs_out, + output reg de_out +); + + +reg [4:0] hmax; +reg [4:0] vmax; +reg [7:0] mask_idx; +reg mask_2x; +reg mask_rotate; +reg mask_enable; +reg [10:0] mask_lut[256]; + +always @(posedge clk) begin + reg [4:0] hcount; + reg [4:0] vcount; + reg [3:0] hindex; + reg [3:0] vindex; + reg [4:0] hmax2; + reg [4:0] vmax2; + reg [11:0] pcnt,pde; + reg old_hs, old_vs, old_brd; + reg next_v; + + old_hs <= hs_in; + old_vs <= vs_in; + old_brd<= brd_in; + + // hcount and vcount counts pixel rows and columns + // hindex and vindex half the value of the counters for double size patterns + // hindex2, vindex2 swap the h and v counters for drawing rotated masks + hindex <= mask_2x ? hcount[4:1] : hcount[3:0]; + vindex <= mask_2x ? vcount[4:1] : vcount[3:0]; + mask_idx <= mask_rotate ? {hindex,vindex} : {vindex,hindex}; + + // hmax and vmax store these sizes + // hmax2 and vmax2 swap the values to handle rotation + hmax2 <= ((mask_rotate ? vmax : hmax) << mask_2x) | mask_2x; + vmax2 <= ((mask_rotate ? hmax : vmax) << mask_2x) | mask_2x; + + pcnt <= pcnt+1'd1; + if(old_brd && ~brd_in) pde <= pcnt-4'd3; + + hcount <= hcount+1'b1; + if(hcount == hmax2 || pde == pcnt) hcount <= 0; + + if(~old_brd && brd_in) next_v <= 1; + if(old_vs && ~vs_in) vcount <= 0; + if(old_hs && ~hs_in) begin + vcount <= vcount + next_v; + next_v <= 0; + pcnt <= 0; + if (vcount == vmax2) vcount <= 0; + end +end + +reg [4:0] r_mul, g_mul, b_mul; // 1.4 fixed point multipliers +always @(posedge clk) begin + reg [10:0] lut; + + lut <= mask_lut[mask_idx]; + + r_mul <= 5'b10000; g_mul <= 5'b10000; b_mul <= 5'b10000; // default 100% to all channels + if (mask_enable) begin + r_mul <= lut[10] ? {1'b1,lut[7:4]} : {1'b0,lut[3:0]}; + g_mul <= lut[9] ? {1'b1,lut[7:4]} : {1'b0,lut[3:0]}; + b_mul <= lut[8] ? {1'b1,lut[7:4]} : {1'b0,lut[3:0]}; + end +end + +always @(posedge clk) begin + reg [11:0] vid; + reg [7:0] r1, g1, b1; + reg [7:0] r2, g2, b2; + reg [7:0] r3_x, g3_x, b3_x; // 6.25% + 12.5% + reg [8:0] r3_y, g3_y, b3_y; // 25% + 50% + 100% + reg [8:0] r4, g4, b4; + + // C1 - data input + {r1,g1,b1} <= din; + vid <= {vid[8:0],vs_in, hs_in, de_in}; + + // C2 - relax timings + {r2,g2,b2} <= {r1,g1,b1}; + + // C3 - perform multiplications + r3_x <= ({4{r_mul[0]}} & r2[7:4]) + ({8{r_mul[1]}} & r2[7:3]); + r3_y <= ({6{r_mul[2]}} & r2[7:2]) + ({7{r_mul[3]}} & r2[7:1]) + ({9{r_mul[4]}} & r2[7:0]); + g3_x <= ({4{g_mul[0]}} & g2[7:4]) + ({8{g_mul[1]}} & g2[7:3]); + g3_y <= ({6{g_mul[2]}} & g2[7:2]) + ({7{g_mul[3]}} & g2[7:1]) + ({9{g_mul[4]}} & g2[7:0]); + b3_x <= ({4{b_mul[0]}} & b2[7:4]) + ({8{b_mul[1]}} & b2[7:3]); + b3_y <= ({6{b_mul[2]}} & b2[7:2]) + ({7{b_mul[3]}} & b2[7:1]) + ({9{b_mul[4]}} & b2[7:0]); + + // C4 - combine results + r4 <= r3_x + r3_y; + g4 <= g3_x + g3_y; + b4 <= b3_x + b3_y; + + // C5 - clamp and output + dout <= {{8{r4[8]}} | r4[7:0], {8{g4[8]}} | g4[7:0], {8{b4[8]}} | b4[7:0]}; + {vs_out,hs_out,de_out} <= vid[11:9]; +end + +// clock in mask commands +always @(posedge clk_sys) begin + reg m_enable; + reg [7:0] idx; + + if (cmd_wr) begin + case(cmd_in[15:13]) + 3'b000: begin {m_enable, mask_rotate, mask_2x} <= cmd_in[3:1]; idx <= 0; end + 3'b001: vmax <= cmd_in[3:0]; + 3'b010: hmax <= cmd_in[3:0]; + 3'b011: begin mask_lut[idx] <= cmd_in[10:0]; idx <= idx + 1'd1; end + endcase + end + + mask_enable <= m_enable & enable; +end + +endmodule diff --git a/sys/sys.qip b/sys/sys.qip index 2854eaf..88acd72 100644 --- a/sys/sys.qip +++ b/sys/sys.qip @@ -7,6 +7,7 @@ set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) m 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) shadowmask.sv ] 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 ] @@ -24,7 +25,6 @@ set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) i set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) ltc2308.sv ] set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) sigma_delta_dac.v ] 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 ] diff --git a/sys/sys_dual_sdram.tcl b/sys/sys_dual_sdram.tcl index bffcdf4..cf90eab 100644 --- a/sys/sys_dual_sdram.tcl +++ b/sys/sys_dual_sdram.tcl @@ -45,6 +45,7 @@ set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM2_ set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM2_* set_instance_assignment -name FAST_OUTPUT_ENABLE_REGISTER ON -to SDRAM2_DQ[*] set_instance_assignment -name FAST_INPUT_REGISTER ON -to SDRAM2_DQ[*] +set_instance_assignment -name WEAK_PULL_UP_RESISTOR ON -to SDRAM2_DQ[*] set_instance_assignment -name ALLOW_SYNCH_CTRL_USAGE OFF -to *|SDRAM2_* -set_global_assignment -name VERILOG_MACRO "DUAL_SDRAM=1" +set_global_assignment -name VERILOG_MACRO "MISTER_DUAL_SDRAM=1" diff --git a/sys/sys_top.sdc b/sys/sys_top.sdc index cf2d492..0d8763f 100644 --- a/sys/sys_top.sdc +++ b/sys/sys_top.sdc @@ -28,11 +28,12 @@ set_false_path -to [get_ports {VGA_*}] set_false_path -to [get_ports {AUDIO_SPDIF}] set_false_path -to [get_ports {AUDIO_L}] set_false_path -to [get_ports {AUDIO_R}] +set_false_path -from {get_ports {SW[*]}} 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 {hdmi_width[*] hdmi_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 @@ -55,6 +56,7 @@ set_false_path -from {FB_BASE[*] FB_BASE[*] FB_WIDTH[*] FB_HEIGHT[*] LFB_HMIN[*] set_false_path -to {vol_att[*] scaler_flt[*] led_overtake[*] led_state[*]} set_false_path -from {vol_att[*] scaler_flt[*] led_overtake[*] led_state[*]} set_false_path -from {aflt_* acx* acy* areset* arc*} +set_false_path -from {arx* ary*} set_false_path -from {vs_line*} set_false_path -from {ascal|o_ihsize*} @@ -62,7 +64,7 @@ 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_hmin* ascal|o_hmax* ascal|o_vmin* ascal|o_vmax* ascal|o_vrrmax* ascal|o_vrr} 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*} diff --git a/sys/sys_top.v b/sys/sys_top.v index dbf8a8a..0b24d3d 100644 --- a/sys/sys_top.v +++ b/sys/sys_top.v @@ -168,7 +168,7 @@ assign LED = (led_overtake & led_state) | (~led_overtake & {1'b0,led_locked,1'b0 wire btn_r, btn_o, btn_u; `ifdef MISTER_DUAL_SDRAM - assign {btn_r,btn_o,btn_u} = {mcp_btn[1],mcp_btn[2],mcp_btn[0]}; + assign {btn_r,btn_o,btn_u} = SW[3] ? {mcp_btn[1],mcp_btn[2],mcp_btn[0]} : ~{SDRAM2_DQ[9],SDRAM2_DQ[13],SDRAM2_DQ[11]}; `else assign {btn_r,btn_o,btn_u} = ~{BTN_RESET,BTN_OSD,BTN_USER} | {mcp_btn[1],mcp_btn[2],mcp_btn[0]}; `endif @@ -212,13 +212,13 @@ end // gp_in[31] = 0 - quick flag that FPGA is initialized (HPS reads 1 when FPGA is not in user mode) // used to avoid lockups while JTAG loading -wire [31:0] gp_in = {1'b0, btn_user | btn[1], btn_osd | btn[0], SW[3], 8'd0, io_ver, io_ack, io_wide, io_dout}; +wire [31:0] gp_in = {1'b0, btn_user | btn[1], btn_osd | btn[0], SW[3], 8'd0, io_ver, io_ack, io_wide, io_dout | io_dout_sys}; wire [31:0] gp_out; wire [1:0] io_ver = 1; // 0 - obsolete. 1 - optimized HPS I/O. 2,3 - reserved for future. wire io_wait; wire io_wide; -wire [15:0] io_dout; +wire [15:0] io_dout; wire [15:0] io_din = gp_outr[15:0]; wire io_clk = gp_outr[17]; wire io_ss0 = gp_outr[18]; @@ -270,7 +270,6 @@ reg [15:0] cfg; reg cfg_set = 0; wire vga_fb = cfg[12] | vga_force_scaler; -wire [1:0] hdmi_limited = {cfg[11],cfg[8]}; `ifdef MISTER_DEBUG_NOHDMI wire direct_video = 1; @@ -278,12 +277,11 @@ wire direct_video = 1; wire direct_video = cfg[10]; `endif -wire dvi_mode = cfg[7]; wire audio_96k = cfg[6]; wire csync_en = cfg[3]; -wire ypbpr_en = cfg[5]; wire io_osd_vga = io_ss1 & ~io_ss2; `ifndef MISTER_DUAL_SDRAM + wire ypbpr_en = cfg[5]; wire sog = cfg[9]; wire vga_scaler = cfg[2] | vga_force_scaler; `endif @@ -295,8 +293,8 @@ reg [31:0] cfg_custom_p2; reg [4:0] vol_att; initial vol_att = 5'b11111; -reg [6:0] coef_addr; -reg [8:0] coef_data; +reg [11:0] coef_addr; +reg [9:0] coef_data; reg coef_wr = 0; wire[12:0] ARX, ARY; @@ -304,12 +302,13 @@ reg [11:0] VSET = 0, HSET = 0; reg FREESCALE = 0; reg [2:0] scaler_flt; reg lowlat = 0; -reg cfg_dis = 0; +reg cfg_done = 0; reg vs_wait = 0; reg [11:0] vs_line = 0; reg scaler_out = 0; +reg vrr_mode = 0; reg [31:0] aflt_rate = 7056000; reg [39:0] acx = 4258969; @@ -324,27 +323,33 @@ reg [12:0] arc1x = 0; reg [12:0] arc1y = 0; reg [12:0] arc2x = 0; reg [12:0] arc2y = 0; +reg [15:0] io_dout_sys; always@(posedge clk_sys) begin reg [7:0] cmd; reg has_cmd; - reg old_strobe; reg [7:0] cnt = 0; reg vs_d0,vs_d1,vs_d2; reg [4:0] acx_att; + reg [7:0] fb_crc; - old_strobe <= io_strobe; coef_wr <= 0; +`ifndef MISTER_DEBUG_NOHDMI + shadowmask_wr <= 0; +`endif + if(~io_uio) begin has_cmd <= 0; cmd <= 0; areset <= 0; acx_att <= 0; acx <= acx >> acx_att; + io_dout_sys <= 0; end else - if(~old_strobe & io_strobe) begin + if(io_strobe) begin + io_dout_sys <= 0; if(!has_cmd) begin has_cmd <= 1; cmd <= io_din[7:0]; @@ -361,8 +366,13 @@ always@(posedge clk_sys) begin acy2 <= -24'd2023767; areset <= 1; end + if(io_din[7:0] == 'h20) io_dout_sys <= 'b11; +`ifndef MISTER_DEBUG_NOHDMI + if(io_din[7:0] == 'h40) io_dout_sys <= fb_crc; +`endif end else begin + cnt <= cnt + 1'd1; if(cmd == 1) begin cfg <= io_din; cfg_set <= 1; @@ -370,17 +380,16 @@ always@(posedge clk_sys) begin end if(cmd == 'h20) begin cfg_set <= 0; - cnt <= cnt + 1'd1; if(cnt<8) begin case(cnt[2:0]) - 0: if(WIDTH != io_din[11:0]) WIDTH <= io_din[11:0]; - 1: if(HFP != io_din[11:0]) HFP <= io_din[11:0]; - 2: if(HS != io_din[11:0]) HS <= io_din[11:0]; - 3: if(HBP != io_din[11:0]) HBP <= io_din[11:0]; - 4: if(HEIGHT != io_din[11:0]) HEIGHT <= io_din[11:0]; - 5: if(VFP != io_din[11:0]) VFP <= io_din[11:0]; - 6: if(VS != io_din[11:0]) VS <= io_din[11:0]; - 7: if(VBP != io_din[11:0]) VBP <= io_din[11:0]; + 0: {HDMI_PR,vrr_mode,WIDTH} <= {io_din[15:14], io_din[11:0]}; + 1: HFP <= io_din[11:0]; + 2: HS <= {io_din[15], io_din[11:0]}; + 3: HBP <= io_din[11:0]; + 4: HEIGHT <= io_din[11:0]; + 5: VFP <= io_din[11:0]; + 6: VS <= {io_din[15],io_din[11:0]}; + 7: VBP <= io_din[11:0]; endcase `ifndef MISTER_DEBUG_NOHDMI if(cnt == 1) begin @@ -397,12 +406,11 @@ always@(posedge clk_sys) begin cfg_custom_t <= ~cfg_custom_t; cnt[2:0] <= 3'b100; end - if(cnt == 8) {lowlat,cfg_dis} <= io_din[15:14]; + if(cnt == 8) {lowlat,cfg_done} <= {io_din[15],1'b1}; `endif end end if(cmd == 'h2F) begin - cnt <= cnt + 1'd1; case(cnt[3:0]) 0: {LFB_EN,LFB_FLT,LFB_FMT} <= {io_din[15], io_din[14], io_din[5:0]}; 1: LFB_BASE[15:0] <= io_din[15:0]; @@ -419,12 +427,14 @@ always@(posedge clk_sys) begin if(cmd == 'h25) {led_overtake, led_state} <= io_din; if(cmd == 'h26) vol_att <= io_din[4:0]; if(cmd == 'h27) VSET <= io_din[11:0]; - if(cmd == 'h2A) {coef_wr,coef_addr,coef_data} <= {1'b1,io_din}; + if(cmd == 'h2A) begin + if(cnt[0]) {coef_wr,coef_data} <= {1'b1,io_din[9:0]}; + else coef_addr <= io_din[11:0]; + end if(cmd == 'h2B) scaler_flt <= io_din[2:0]; if(cmd == 'h37) {FREESCALE,HSET} <= {io_din[15],io_din[11:0]}; if(cmd == 'h38) vs_line <= io_din[11:0]; if(cmd == 'h39) begin - cnt <= cnt + 1'd1; case(cnt[3:0]) 0: acx_att <= io_din[4:0]; 1: aflt_rate[15:0] <= io_din; @@ -444,7 +454,6 @@ always@(posedge clk_sys) begin endcase end if(cmd == 'h3A) begin - cnt <= cnt + 1'd1; case(cnt[3:0]) 0: arc1x <= io_din[12:0]; 1: arc1y <= io_din[12:0]; @@ -452,9 +461,32 @@ always@(posedge clk_sys) begin 3: arc2y <= io_din[12:0]; endcase end +`ifndef MISTER_DEBUG_NOHDMI + if(cmd == 'h3E) {shadowmask_wr,shadowmask_data} <= {1'b1, io_din}; + if(cmd == 'h40) begin + case(cnt[3:0]) + 0: io_dout_sys <= {arxy, arx}; + 1: io_dout_sys <= {arxy, ary}; + 2: io_dout_sys <= {LFB_EN, FB_EN, FB_FMT}; + 3: io_dout_sys <= FB_WIDTH; + 4: io_dout_sys <= FB_HEIGHT; + 5: io_dout_sys <= FB_BASE[15:0]; + 6: io_dout_sys <= FB_BASE[31:16]; + 7: io_dout_sys <= FB_STRIDE; + endcase + end +`endif end end +`ifndef MISTER_DEBUG_NOHDMI + fb_crc <= {LFB_EN, FB_EN, FB_FMT} + ^ FB_WIDTH[7:0] ^ FB_WIDTH[11:8] + ^ FB_HEIGHT[7:0] ^ FB_HEIGHT[11:8] + ^ arx[7:0] ^ arx[11:8] ^ arxy + ^ ary[7:0] ^ ary[11:8]; +`endif + vs_d0 <= HDMI_TX_VS; if(vs_d0 == HDMI_TX_VS) vs_d1 <= vs_d0; @@ -618,7 +650,7 @@ wire [15:0] vbuf_byteenable; wire vbuf_write; wire [23:0] hdmi_data; -wire hdmi_vs, hdmi_hs, hdmi_de, hdmi_vbl; +wire hdmi_vs, hdmi_hs, hdmi_de, hdmi_vbl, hdmi_brd; wire freeze; `ifndef MISTER_DEBUG_NOHDMI @@ -627,6 +659,11 @@ wire clk_hdmi = hdmi_clk_out; ascal #( .RAMBASE(32'h20000000), +`ifdef MISTER_SMALL_VBUF + .RAMSIZE(32'h00200000), +`else + .RAMSIZE(32'h00800000), +`endif `ifndef MISTER_FB .PALETTE2("false"), `else @@ -634,6 +671,13 @@ ascal .PALETTE2("false"), `endif `endif +`ifdef MISTER_DISABLE_ADAPTIVE + .ADAPTIVE("false"), +`endif +`ifdef MISTER_DOWNSCALE_NN + .DOWNSCALE_NN("true"), +`endif + .FRAC(8), .N_DW(128), .N_AW(28) ) @@ -667,19 +711,22 @@ ascal .o_vs (hdmi_vs), .o_de (hdmi_de), .o_vbl (hdmi_vbl), + .o_brd (hdmi_brd), .o_lltune (lltune), - .htotal (WIDTH + HFP + HBP + HS), + .htotal (WIDTH + HFP + HBP + HS[11:0]), .hsstart (WIDTH + HFP), - .hsend (WIDTH + HFP + HS), + .hsend (WIDTH + HFP + HS[11:0]), .hdisp (WIDTH), .hmin (hmin), .hmax (hmax), - .vtotal (HEIGHT + VFP + VBP + VS), + .vtotal (HEIGHT + VFP + VBP + VS[11:0]), .vsstart (HEIGHT + VFP), - .vsend (HEIGHT + VFP + VS), + .vsend (HEIGHT + VFP + VS[11:0]), .vdisp (HEIGHT), .vmin (vmin), .vmax (vmax), + .vrr (vrr_mode), + .vrrmax (HEIGHT + VBP + VS[11:0] + 12'd1), .mode ({~lowlat,LFB_EN ? LFB_FLT : |scaler_flt,2'b00}), .poly_clk (clk_sys), @@ -789,37 +836,40 @@ reg [11:0] vmax; reg [11:0] hdmi_height; reg [11:0] hdmi_width; +reg [11:0] arx; +reg [11:0] ary; +reg arxy; + always @(posedge clk_vid) begin reg [11:0] hmini,hmaxi,vmini,vmaxi; - reg [11:0] wcalc,videow,arx; - reg [11:0] hcalc,videoh,ary; + reg [11:0] wcalc,videow; + reg [11:0] hcalc,videoh; reg [2:0] state; - reg xy; hdmi_height <= (VSET && (VSET < HEIGHT)) ? VSET : HEIGHT; - hdmi_width <= (HSET && (HSET < WIDTH)) ? HSET : WIDTH; + hdmi_width <= (HSET && (HSET < WIDTH)) ? HSET << HDMI_PR : WIDTH << HDMI_PR; if(!ARY) begin if(ARX == 1) begin - arx <= arc1x[11:0]; - ary <= arc1y[11:0]; - xy <= arc1x[12] | arc1y[12]; + arx <= arc1x[11:0]; + ary <= arc1y[11:0]; + arxy <= arc1x[12] | arc1y[12]; end else if(ARX == 2) begin - arx <= arc2x[11:0]; - ary <= arc2y[11:0]; - xy <= arc2x[12] | arc2y[12]; + arx <= arc2x[11:0]; + ary <= arc2y[11:0]; + arxy <= arc2x[12] | arc2y[12]; end else begin - arx <= 0; - ary <= 0; - xy <= 0; + arx <= 0; + ary <= 0; + arxy <= 0; end end else begin - arx <= ARX[11:0]; - ary <= ARY[11:0]; - xy <= ARX[12] | ARY[12]; + arx <= ARX[11:0]; + ary <= ARY[11:0]; + arxy <= ARX[12] | ARY[12]; end ar_md_start <= 0; @@ -837,7 +887,7 @@ always @(posedge clk_vid) begin hcalc <= hdmi_height; state <= 6; end - else if(xy) begin + else if(arxy) begin wcalc <= arx; hcalc <= ary; state <= 6; @@ -866,7 +916,7 @@ always @(posedge clk_vid) begin end 6: begin - videow <= (wcalc > hdmi_width) ? hdmi_width : wcalc[11:0]; + videow <= (wcalc > hdmi_width) ? (hdmi_width >> HDMI_PR) : (wcalc[11:0] >> HDMI_PR); videoh <= (hcalc > hdmi_height) ? hdmi_height : hcalc[11:0]; end @@ -892,7 +942,7 @@ pll_hdmi_adj pll_hdmi_adj .reset_na(~reset_req), .llena(lowlat), - .lltune({16{hdmi_config_done | cfg_dis}} & lltune), + .lltune({16{cfg_done}} & lltune), .locked(led_locked), .i_waitrequest(adj_waitrequest), .i_write(adj_write), @@ -940,14 +990,15 @@ pll_hdmi pll_hdmi `endif //1920x1080@60 PCLK=148.5MHz CEA -reg [11:0] WIDTH = 1920; -reg [11:0] HFP = 88; -reg [11:0] HS = 48; -reg [11:0] HBP = 148; -reg [11:0] HEIGHT = 1080; -reg [11:0] VFP = 4; -reg [11:0] VS = 5; -reg [11:0] VBP = 36; +reg [11:0] WIDTH = 1920; +reg [11:0] HFP = 88; +reg [12:0] HS = 48; +reg [11:0] HBP = 148; +reg [11:0] HEIGHT = 1080; +reg [11:0] VFP = 4; +reg [12:0] VS = 5; +reg [11:0] VBP = 36; +reg HDMI_PR = 0; wire [63:0] reconfig_to_pll; wire [63:0] reconfig_from_pll; @@ -1020,22 +1071,6 @@ wire cfg_ready = 1; `endif -wire hdmi_config_done; -hdmi_config hdmi_config -( - .iCLK(FPGA_CLK1_50), - .iRST_N(cfg_ready & ~HDMI_TX_INT & ~cfg_dis), - .done(hdmi_config_done), - - .I2C_SCL(HDMI_I2C_SCL), - .I2C_SDA(HDMI_I2C_SDA), - - .dvi_mode(dvi_mode), - .audio_96k(audio_96k), - .limited(hdmi_limited), - .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; @@ -1049,34 +1084,43 @@ cyclonev_hps_interface_peripheral_i2c hdmi_i2c ); `ifndef MISTER_DEBUG_NOHDMI -wire [23:0] hdmi_data_sl; -wire hdmi_de_sl, hdmi_vs_sl, hdmi_hs_sl; `ifdef MISTER_FB reg dis_output; always @(posedge clk_hdmi) begin reg dis; - dis <= fb_force_blank; + dis <= fb_force_blank & ~LFB_EN; dis_output <= dis; end `else wire dis_output = 0; `endif -scanlines #(1) HDMI_scanlines +wire [23:0] hdmi_data_mask; +wire hdmi_de_mask, hdmi_vs_mask, hdmi_hs_mask; + +reg [15:0] shadowmask_data; +reg shadowmask_wr = 0; + +shadowmask HDMI_shadowmask ( .clk(clk_hdmi), + .clk_sys(clk_sys), + + .cmd_wr(shadowmask_wr), + .cmd_in(shadowmask_data), - .scanlines(scanlines), .din(dis_output ? 24'd0 : hdmi_data), .hs_in(hdmi_hs), .vs_in(hdmi_vs), .de_in(hdmi_de), - - .dout(hdmi_data_sl), - .hs_out(hdmi_hs_sl), - .vs_out(hdmi_vs_sl), - .de_out(hdmi_de_sl) + .brd_in(hdmi_brd), + .enable(~LFB_EN), + + .dout(hdmi_data_mask), + .hs_out(hdmi_hs_mask), + .vs_out(hdmi_vs_mask), + .de_out(hdmi_de_mask) ); wire [23:0] hdmi_data_osd; @@ -1091,10 +1135,10 @@ osd hdmi_osd .io_din(io_din), .clk_video(clk_hdmi), - .din(hdmi_data_sl), - .hs_in(hdmi_hs_sl), - .vs_in(hdmi_vs_sl), - .de_in(hdmi_de_sl), + .din(hdmi_data_mask), + .hs_in(hdmi_hs_mask), + .vs_in(hdmi_vs_mask), + .de_in(hdmi_de_mask), .dout(hdmi_data_osd), .hs_out(hdmi_hs_osd), @@ -1111,7 +1155,7 @@ reg dv_hs, dv_vs, dv_de; always @(posedge clk_vid) begin reg [23:0] dv_d1, dv_d2; reg dv_de1, dv_de2, dv_hs1, dv_hs2, dv_vs1, dv_vs2; - reg [12:0] vsz, vcnt; + reg [12:0] vsz, vcnt, vcnt_l, vcnt_ll; reg old_hs, old_vs; reg vde; reg [3:0] hss; @@ -1123,7 +1167,11 @@ always @(posedge clk_vid) begin if(~old_hs && vga_hs_osd) begin old_vs <= vga_vs_osd; if(~&vcnt) vcnt <= vcnt + 1'd1; - if(~old_vs & vga_vs_osd & ~f1) vsz <= vcnt; + if(~old_vs & vga_vs_osd) begin + if (vcnt != vcnt_ll || vcnt < vcnt_l) vsz <= vcnt; + vcnt_l <= vcnt; + vcnt_ll <= vcnt_l; + end if(old_vs & ~vga_vs_osd) vcnt <= 0; if(vcnt == 1) vde <= 1; @@ -1190,13 +1238,21 @@ reg hdmi_out_de; reg [23:0] hdmi_out_d; always @(posedge hdmi_tx_clk) begin + reg [23:0] hdmi_dv_data; + reg hdmi_dv_hs, hdmi_dv_vs, hdmi_dv_de; + reg hs,vs,de; reg [23:0] d; - hs <= (~vga_fb & direct_video) ? dv_hs : (direct_video & csync_en) ? hdmi_cs_osd : hdmi_hs_osd; - vs <= (~vga_fb & direct_video) ? dv_vs : hdmi_vs_osd; - de <= (~vga_fb & direct_video) ? dv_de : hdmi_de_osd; - d <= (~vga_fb & direct_video) ? dv_data : hdmi_data_osd; + hdmi_dv_data <= dv_data; + hdmi_dv_hs <= dv_hs; + hdmi_dv_vs <= dv_vs; + hdmi_dv_de <= dv_de; + + hs <= (~vga_fb & direct_video) ? hdmi_dv_hs : (direct_video & csync_en) ? hdmi_cs_osd : hdmi_hs_osd; + vs <= (~vga_fb & direct_video) ? hdmi_dv_vs : hdmi_vs_osd; + de <= (~vga_fb & direct_video) ? hdmi_dv_de : hdmi_de_osd; + d <= (~vga_fb & direct_video) ? hdmi_dv_data : hdmi_data_osd; hdmi_out_hs <= hs; hdmi_out_vs <= vs; @@ -1212,7 +1268,7 @@ assign HDMI_TX_D = hdmi_out_d; ///////////////////////// VGA output ////////////////////////////////// wire [23:0] vga_data_sl; -wire vga_de_sl, vga_vs_sl, vga_hs_sl; +wire vga_de_sl, vga_ce_sl, vga_vs_sl, vga_hs_sl; scanlines #(0) VGA_scanlines ( .clk(clk_vid), @@ -1222,11 +1278,13 @@ scanlines #(0) VGA_scanlines .hs_in(hs_fix), .vs_in(vs_fix), .de_in(de_emu), + .ce_in(ce_pix), .dout(vga_data_sl), .hs_out(vga_hs_sl), .vs_out(vga_vs_sl), - .de_out(vga_de_sl) + .de_out(vga_de_sl), + .ce_out(vga_ce_sl) ); wire [23:0] vga_data_osd; @@ -1255,6 +1313,7 @@ wire vga_cs_osd; csync csync_vga(clk_vid, vga_hs_osd, vga_vs_osd, vga_cs_osd); `ifndef MISTER_DUAL_SDRAM + wire VGA_DISABLE; wire [23:0] vgas_o; wire vgas_hs, vgas_vs, vgas_cs; vga_out vga_scaler_out @@ -1289,11 +1348,11 @@ csync csync_vga(clk_vid, vga_hs_osd, vga_vs_osd, vga_cs_osd); 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] ; + assign VGA_VS = (VGA_EN | SW[3]) ? 1'bZ : (((vga_fb | vga_scaler) ? (~vgas_vs ^ VS[12]) : VGA_DISABLE ? 1'd1 : ~vga_vs) | csync_en); + assign VGA_HS = (VGA_EN | SW[3]) ? 1'bZ : ((vga_fb | vga_scaler) ? ((csync_en ? ~vgas_cs : ~vgas_hs) ^ HS[12]) : VGA_DISABLE ? 1'd1 : (csync_en ? ~vga_cs : ~vga_hs)); + assign VGA_R = (VGA_EN | SW[3]) ? 6'bZZZZZZ : (vga_fb | vga_scaler) ? vgas_o[23:18] : VGA_DISABLE ? 6'd0 : vga_o[23:18]; + assign VGA_G = (VGA_EN | SW[3]) ? 6'bZZZZZZ : (vga_fb | vga_scaler) ? vgas_o[15:10] : VGA_DISABLE ? 6'd0 : vga_o[15:10]; + assign VGA_B = (VGA_EN | SW[3]) ? 6'bZZZZZZ : (vga_fb | vga_scaler) ? vgas_o[7:2] : VGA_DISABLE ? 6'd0 : vga_o[7:2] ; `endif reg video_sync = 0; @@ -1461,13 +1520,13 @@ sync_fix sync_h(clk_vid, hs_emu, hs_fix); wire [6:0] user_out, user_in; assign clk_ihdmi= clk_vid; -assign ce_hpix = ce_pix; -assign hr_out = r_out; -assign hg_out = g_out; -assign hb_out = b_out; -assign hhs_fix = hs_fix; -assign hvs_fix = vs_fix; -assign hde_emu = de_emu; +assign ce_hpix = vga_ce_sl; +assign hr_out = vga_data_sl[23:16]; +assign hg_out = vga_data_sl[15:8]; +assign hb_out = vga_data_sl[7:0]; +assign hhs_fix = vga_hs_sl; +assign hvs_fix = vga_vs_sl; +assign hde_emu = vga_de_sl; wire uart_dtr; wire uart_dsr; @@ -1504,11 +1563,15 @@ wire [13:0] fb_stride; assign fb_stride = 0; `endif +reg [1:0] sl_r; +wire [1:0] sl = sl_r; +always @(posedge clk_sys) sl_r <= FB_EN ? 2'b00 : scanlines; + emu emu ( .CLK_50M(FPGA_CLK2_50), .RESET(reset), - .HPS_BUS({f1, HDMI_TX_VS, + .HPS_BUS({fb_en, sl, 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}), @@ -1522,6 +1585,10 @@ emu emu .VGA_F1(f1), .VGA_SCALER(vga_force_scaler), +`ifndef MISTER_DUAL_SDRAM + .VGA_DISABLE(VGA_DISABLE), +`endif + .HDMI_WIDTH(direct_video ? 12'd0 : hdmi_width), .HDMI_HEIGHT(direct_video ? 12'd0 : hdmi_height), .HDMI_FREEZE(freeze),