diff --git a/MacPlus.qsf b/MacPlus.qsf index c61cccd..56d2347 100644 --- a/MacPlus.qsf +++ b/MacPlus.qsf @@ -13,7 +13,7 @@ set_global_assignment -name PARTITION_NETLIST_TYPE SOURCE -section_id Top set_global_assignment -name PARTITION_FITTER_PRESERVATION_LEVEL PLACEMENT_AND_ROUTING -section_id Top set_global_assignment -name PARTITION_COLOR 16764057 -section_id Top -set_global_assignment -name LAST_QUARTUS_VERSION "17.0.2 Lite Edition" +set_global_assignment -name LAST_QUARTUS_VERSION "17.0.2 Standard Edition" set_global_assignment -name GENERATE_RBF_FILE ON set_global_assignment -name PROJECT_OUTPUT_DIRECTORY output_files diff --git a/MacPlus.sv b/MacPlus.sv index ee41455..673e58b 100644 --- a/MacPlus.sv +++ b/MacPlus.sv @@ -29,7 +29,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, @@ -39,9 +39,9 @@ module emu output CE_PIXEL, //Video aspect ratio for HDMI. Most retro systems have ratio 4:3. - //if VIDEO_ARX[12] or VIDEO_ARY[12] is set then [11:0] contains scaled size instead of aspect ratio. - output [12:0] VIDEO_ARX, - output [12:0] VIDEO_ARY, + //if VIDEO_ARX[12] or VIDEO_ARY[12] is set then [11:0] contains scaled size instead of aspect ratio. + output [12:0] VIDEO_ARX, + output [12:0] VIDEO_ARY, output [7:0] VGA_R, output [7:0] VGA_G, @@ -52,11 +52,12 @@ module emu output VGA_F1, output [1:0] VGA_SL, output VGA_SCALER, // Force VGA scaler - - input [11:0] HDMI_WIDTH, - input [11:0] HDMI_HEIGHT, -`ifdef USE_FB + input [11:0] HDMI_WIDTH, + input [11:0] HDMI_HEIGHT, + output HDMI_FREEZE, + +`ifdef MISTER_FB // Use framebuffer in DDRAM (USE_FB=1 in qsf) // FB_FORMAT: // [2:0] : 011=8bpp(palette) 100=16bpp 101=24bpp 110=32bpp @@ -74,6 +75,7 @@ module emu input FB_LL, output FB_FORCE_BLANK, +`ifdef MISTER_FB_PALETTE // Palette control for 8bit modes. // Ignored for other video modes. output FB_PAL_CLK, @@ -81,6 +83,7 @@ module emu output [23:0] FB_PAL_DOUT, input [23:0] FB_PAL_DIN, output FB_PAL_WR, +`endif `endif output LED_USER, // 1 - ON, 0 - OFF. @@ -112,7 +115,6 @@ module emu output SD_CS, input SD_CD, -`ifdef USE_DDRAM //High latency DDR3 RAM interface //Use for non-critical time purposes output DDRAM_CLK, @@ -125,9 +127,7 @@ module emu output [63:0] DDRAM_DIN, output [7:0] DDRAM_BE, output DDRAM_WE, -`endif -`ifdef USE_SDRAM //SDRAM interface with lower latency output SDRAM_CLK, output SDRAM_CKE, @@ -140,10 +140,10 @@ module emu output SDRAM_nCAS, output SDRAM_nRAS, output SDRAM_nWE, -`endif -`ifdef DUAL_SDRAM +`ifdef MISTER_DUAL_SDRAM //Secondary SDRAM + //Set all output SDRAM_* signals to Z ASAP if SDRAM2_EN is 0 input SDRAM2_EN, output SDRAM2_CLK, output [12:0] SDRAM2_A, @@ -184,6 +184,7 @@ assign LED_DISK = 0; assign LED_POWER = 0; assign BUTTONS = 0; assign VGA_SCALER= 0; +assign HDMI_FREEZE = 0; wire [1:0] ar = status[8:7]; video_freak video_freak @@ -265,13 +266,13 @@ end // the status register is controlled by the on screen display (OSD) wire [31:0] status; wire [1:0] buttons; -wire [31:0] sd_lba; +wire [31:0] sd_lba[2]; wire [1:0] sd_rd; wire [1:0] sd_wr; -wire sd_ack; +wire [1:0] sd_ack; wire [7:0] sd_buff_addr; wire [15:0] sd_buff_dout; -wire [15:0] sd_buff_din; +wire [15:0] sd_buff_din[2]; wire sd_buff_wr; wire [1:0] img_mounted; wire [31:0] img_size; @@ -288,13 +289,11 @@ wire [15:0] ioctl_data; wire [32:0] TIMESTAMP; -hps_io #(.STRLEN($size(CONF_STR)>>3), .VDNUM(2), .WIDE(1)) hps_io +hps_io #(.CONF_STR(CONF_STR), .VDNUM(2), .WIDE(1)) hps_io ( .clk_sys(clk_sys), .HPS_BUS(HPS_BUS), - .conf_str(CONF_STR), - .buttons(buttons), .status(status), @@ -303,7 +302,6 @@ hps_io #(.STRLEN($size(CONF_STR)>>3), .VDNUM(2), .WIDE(1)) hps_io .sd_wr(sd_wr), .sd_ack(sd_ack), - .sd_conf(0), .sd_buff_addr(sd_buff_addr), .sd_buff_dout(sd_buff_dout), .sd_buff_din(sd_buff_din), @@ -689,14 +687,16 @@ dataController_top dc0 // block device interface for scsi disk .img_mounted(img_mounted), .img_size(img_size), - .io_lba(sd_lba), + .io_lba0(sd_lba[0]), + .io_lba1(sd_lba[1]), .io_rd(sd_rd), .io_wr(sd_wr), .io_ack(sd_ack), .sd_buff_addr(sd_buff_addr), .sd_buff_dout(sd_buff_dout), - .sd_buff_din(sd_buff_din), + .sd_buff_din0(sd_buff_din[0]), + .sd_buff_din1(sd_buff_din[1]), .sd_buff_wr(sd_buff_wr) ); diff --git a/rtl/dataController_top.v b/rtl/dataController_top.v index 523d787..809c452 100644 --- a/rtl/dataController_top.v +++ b/rtl/dataController_top.v @@ -81,13 +81,15 @@ module dataController_top( // connections to io controller input [1:0] img_mounted, input [31:0] img_size, - output [31:0] io_lba, + output [31:0] io_lba0, + output [31:0] io_lba1, output [1:0] io_rd, output [1:0] io_wr, - input io_ack, + input [1:0] io_ack, input [7:0] sd_buff_addr, input [15:0] sd_buff_dout, - output [15:0] sd_buff_din, + output [15:0] sd_buff_din0, + output [15:0] sd_buff_din1, input sd_buff_wr ); @@ -179,14 +181,16 @@ module dataController_top( // connections to io controller .img_mounted( img_mounted ), .img_size( img_size ), - .io_lba ( io_lba ), + .io_lba0 ( io_lba0 ), + .io_lba1 ( io_lba1 ), .io_rd ( io_rd ), .io_wr ( io_wr ), .io_ack ( io_ack ), .sd_buff_addr(sd_buff_addr), .sd_buff_dout(sd_buff_dout), - .sd_buff_din(sd_buff_din), + .sd_buff_din0(sd_buff_din0), + .sd_buff_din1(sd_buff_din1), .sd_buff_wr(sd_buff_wr) ); diff --git a/rtl/ncr5380.v b/rtl/ncr5380.v index a8cc357..3229879 100644 --- a/rtl/ncr5380.v +++ b/rtl/ncr5380.v @@ -65,15 +65,16 @@ module ncr5380 input [1:0] img_mounted, input [31:0] img_size, - output [15:0] io_req_type, - output [31:0] io_lba, + output [31:0] io_lba0, + output [31:0] io_lba1, output [1:0] io_rd, output [1:0] io_wr, - input io_ack, + input [1:0] io_ack, input [7:0] sd_buff_addr, input [15:0] sd_buff_dout, - output [15:0] sd_buff_din, + output [15:0] sd_buff_din0, + output [15:0] sd_buff_din1, input sd_buff_wr ); @@ -278,17 +279,10 @@ module ncr5380 scsi6_bsy ? scsi6_dout : 8'h55; - assign io_lba = (scsi2_bsy) ? io_lba_2 : io_lba_6; - assign sd_buff_din = (scsi2_bsy) ? sd_buff_din_2 : sd_buff_din_6; - assign io_req_type = 16'h0000; // Not used atm. Could be used for CD-ROM sector requests later. ElectronAsh. - // input signals from target 2 wire scsi2_bsy, scsi2_msg, scsi2_io, scsi2_cd, scsi2_req; wire [7:0] scsi2_dout; - wire [31:0] io_lba_2; - wire [15:0] sd_buff_din_2; - // connect a target scsi #(.ID(2)) scsi2 ( @@ -312,15 +306,15 @@ module ncr5380 // to sd card .img_mounted(img_mounted[1]), .img_blocks(img_size[31:9]), - .io_lba ( io_lba_2 ), + .io_lba ( io_lba1 ), .io_rd ( io_rd[1] ), .io_wr ( io_wr[1] ), - .io_ack ( io_ack & scsi2_bsy ), + .io_ack ( io_ack[1] ), .sd_buff_addr( sd_buff_addr ), .sd_buff_dout( sd_buff_dout ), - .sd_buff_din( sd_buff_din_2 ), - .sd_buff_wr( sd_buff_wr & scsi2_bsy ) + .sd_buff_din( sd_buff_din1 ), + .sd_buff_wr( sd_buff_wr ) ); @@ -328,9 +322,6 @@ module ncr5380 wire scsi6_bsy, scsi6_msg, scsi6_io, scsi6_cd, scsi6_req; wire [7:0] scsi6_dout; - wire [31:0] io_lba_6; - wire [15:0] sd_buff_din_6; - scsi #(.ID(6)) scsi6 ( .clk ( clk ) , // input clk @@ -353,15 +344,15 @@ module ncr5380 // to sd card .img_mounted( img_mounted[0] ), .img_blocks( img_size[31:9] ), - .io_lba ( io_lba_6 ) , // output [31:0] io_lba + .io_lba ( io_lba0 ) , // output [31:0] io_lba .io_rd ( io_rd[0] ) , // output io_rd .io_wr ( io_wr[0] ) , // output io_wr - .io_ack ( io_ack & scsi6_bsy ) , // input io_ack + .io_ack ( io_ack[0] ) , // input io_ack .sd_buff_addr( sd_buff_addr ) , // input [8:0] sd_buff_addr .sd_buff_dout( sd_buff_dout ) , // input [7:0] sd_buff_dout - .sd_buff_din( sd_buff_din_6 ) , // output [7:0] sd_buff_din - .sd_buff_wr( sd_buff_wr & scsi6_bsy ) // input sd_buff_wr + .sd_buff_din( sd_buff_din0 ) , // output [7:0] sd_buff_din + .sd_buff_wr( sd_buff_wr ) // input sd_buff_wr ); diff --git a/rtl/scsi.v b/rtl/scsi.v index 4f07aac..2dd0a51 100644 --- a/rtl/scsi.v +++ b/rtl/scsi.v @@ -61,10 +61,10 @@ always @(posedge clk) sd_buff_din[15:8] <= buffer_out1[sd_buff_addr]; // ---------------- buffer write engine ---------------------- // the buffer itself. Can hold one sector reg [7:0] buffer_in0 [256]; -always @(posedge clk) if(sd_buff_wr) buffer_in0[sd_buff_addr] <= sd_buff_dout[7:0]; +always @(posedge clk) if(sd_buff_wr & io_ack) buffer_in0[sd_buff_addr] <= sd_buff_dout[7:0]; reg [7:0] buffer_in1 [256]; -always @(posedge clk) if(sd_buff_wr) buffer_in1[sd_buff_addr] <= sd_buff_dout[15:8]; +always @(posedge clk) if(sd_buff_wr & io_ack) buffer_in1[sd_buff_addr] <= sd_buff_dout[15:8]; // ----------------------------------------------------------- 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 a65ccc1..aa2af61 100644 --- a/sys/ascal.vhd +++ b/sys/ascal.vhd @@ -113,21 +113,23 @@ USE ieee.numeric_std.ALL; 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 + 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 ( ------------------------------------ @@ -151,6 +153,7 @@ ENTITY ascal IS 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 @@ -224,12 +227,12 @@ ENTITY ascal IS ------------------------------------ -- Polyphase filter coefficients -- Order : - -- [Horizontal] [Vertical] + -- [Horizontal] [Vertical] [Horizontal2] [Vertical2] -- [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_dw : IN unsigned(9 DOWNTO 0); + poly_a : IN unsigned(FRAC+3 DOWNTO 0); poly_wr : IN std_logic; ------------------------------------ @@ -294,6 +297,7 @@ ARCHITECTURE rtl OF ascal IS 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; @@ -301,9 +305,11 @@ ARCHITECTURE rtl OF ascal IS 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_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 @@ -382,8 +388,9 @@ ARCHITECTURE rtl OF ascal IS 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) RETURN natural IS + 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; @@ -400,6 +407,7 @@ ARCHITECTURE rtl OF ascal IS ---------------------------------------------------------- -- 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); @@ -412,7 +420,7 @@ ARCHITECTURE rtl OF ascal IS 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_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_vmin,o_vmax,o_vdisp : uint12; @@ -427,7 +435,7 @@ ARCHITECTURE rtl OF ascal IS 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_copyv : unsigned(0 TO 12); 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); @@ -445,17 +453,21 @@ ARCHITECTURE rtl OF ascal IS 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_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 : uint12; SIGNAL o_ihsize,o_ihsizem,o_ivsize : uint12; SIGNAL o_ihsize_temp, o_ihsize_temp2 : natural RANGE 0 TO 32767; - SIGNAL o_vfrac,o_hfrac,o_hfrac1,o_hfrac2,o_hfrac3,o_hfrac4 : unsigned(11 DOWNTO 0); + SIGNAL o_vfrac : unsigned(11 DOWNTO 0); + SIGNAL o_hfrac : arr_frac(0 TO 8); + 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 5); + SIGNAL o_hsv,o_vsv,o_dev,o_pev,o_end : unsigned(0 TO 9); 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; @@ -470,19 +482,28 @@ ARCHITECTURE rtl OF ascal IS 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_dcptv : arr_uint12(1 TO 12); 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_hpixq : arr_pixq(2 TO 6); + ATTRIBUTE ramstyle OF o_hpixq : SIGNAL IS "logic"; -- avoid blockram shift register + SIGNAL o_vpixq : arr_pix(0 TO 3); + SIGNAL o_vpix_outer : arr_pix(0 TO 2); + SIGNAL o_vpix_inner : arr_pix(0 TO 5); + + -- ATTRIBUTE ramstyle OF o_hpixq : SIGNAL IS "logic"; + 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_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); @@ -703,9 +724,10 @@ ARCHITECTURE rtl OF ascal IS RETURN x; END FUNCTION; - SIGNAL o_h_frac2,o_v_frac : unsigned(FRAC-1 DOWNTO 0); + 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 @@ -716,6 +738,7 @@ ARCHITECTURE rtl OF ascal IS 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); @@ -723,7 +746,7 @@ ARCHITECTURE rtl OF ascal IS VARIABLE x : type_bil_t; CONSTANT Z : unsigned(FRAC-1 DOWNTO 0):=(OTHERS =>'0'); BEGIN - fp:='0' & f; + fp:=('0' & f) + (Z & f(FRAC-1)); fn:=('1' & Z) - fp; u:=p(2).r * fp + p(1).r * fn; x.r:=u; @@ -733,7 +756,28 @@ ARCHITECTURE rtl OF ascal IS 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; ----------------------------------------------------------------------------- @@ -905,82 +949,160 @@ ARCHITECTURE rtl OF ascal IS ----------------------------------------------------------------------------- -- 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); + -- 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; - SIGNAL o_h_poly_t,o_v_poly_t : type_poly_t; + -- 5.22 + TYPE type_poly_t IS RECORD + r0,r1,b0,b1,g0,g1 : signed(26 DOWNTO 0); + END RECORD; - FUNCTION poly_calc1(fi : unsigned(35 DOWNTO 0); + + 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, o_h_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 : poly_phase_t; + SIGNAL o_v_poly_phase_a,o_v_poly_phase_a2,o_v_poly_phase_a3 : 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 : poly_phase_interp_t; + SIGNAL o_v_poly_pix, o_h_poly_pix : type_pix; + SIGNAL o_v_poly_lum, o_h_poly_lum, o_poly_lum : unsigned(7 DOWNTO 0); + SIGNAL o_poly_lerp_ta, o_poly_lerp_tb, o_poly_lerp_tb3 : 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 - -- 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)); + -- 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_calc2(t : type_poly_t) RETURN type_pix IS + FUNCTION poly_final(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); + 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 ----------------------------------------------------------------------------- @@ -1132,7 +1254,7 @@ BEGIN i_format<=format; -- -- Downscaling : Nearest or bilinear - i_bil<=to_std_logic(i_mode(2 DOWNTO 0)/="000" AND DOWNSCALE); + 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 @@ -1244,11 +1366,12 @@ BEGIN -- 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_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); @@ -1260,11 +1383,12 @@ BEGIN -- 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; - 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); @@ -1693,7 +1817,7 @@ BEGIN 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 + BEGIN IF o_reset_na='0' THEN o_copy<=sWAIT; o_state<=sDISP; @@ -1730,53 +1854,48 @@ BEGIN -- 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_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_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_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; - -- 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; - - IF o_vsv(1)='1' AND o_vsv(0)='0' AND o_bufup0='1' THEN - o_obuf0<=buf_next(o_obuf0,o_ibuf0); + -- 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; @@ -1790,6 +1909,32 @@ BEGIN 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 @@ -1848,35 +1993,51 @@ BEGIN 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; + 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 <=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; + o_vacc_next<=dif_v; 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"; + 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 - IF (o_vpe='1' AND vcarry_v) OR o_fload>0 THEN - o_state<=sREAD; - ELSE - o_state<=sDISP; + 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 => @@ -1926,7 +2087,7 @@ BEGIN 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); + o_alt<=altx(o_vacptl + 1); END IF; END IF; @@ -2053,7 +2214,7 @@ BEGIN 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; @@ -2113,13 +2274,83 @@ BEGIN ------------------------------------------------------ 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); - + + -- Fetch polyphase coefficients + PolyFetch:PROCESS (o_clk) IS + VARIABLE hfrac2_v, hfrac3_v, vfrac_v : unsigned(FRAC-1 DOWNTO 0); + VARIABLE o_poly_phase_v : poly_phase_interp_t; + BEGIN + IF rising_edge(o_clk) THEN + hfrac2_v:=o_hfrac(2)(11 DOWNTO 12-FRAC); + 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')); + + -- C2 / HC2 / VC3 + o_v_poly_addr<=to_integer(vfrac_v); + o_h_poly_addr<=to_integer(hfrac2_v); + IF o_v_poly_use_adaptive = '1' THEN + o_a_poly_addr<=to_integer(vfrac_v); + ELSIF o_h_poly_use_adaptive = '1' THEN + o_a_poly_addr<=to_integer(hfrac2_v); + END IF; + + -- 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(o_h_poly_addr)); + ELSE + o_h_poly_phase_a<=poly_nn(hfrac3_v); + END IF; + + IF o_v_poly_use_adaptive='1' THEN + o_poly_lum<=o_v_poly_lum; + ELSIF o_h_poly_use_adaptive='1' THEN + o_poly_lum<=o_h_poly_lum; + END IF; + + o_poly_phase_b<=poly_unpack(o_a_poly_mem(o_a_poly_addr)); + + -- C4 / HC4 / VC5 + o_poly_lerp_ta<=signed(to_unsigned(256,10) - resize(o_poly_lum,10)); + o_poly_lerp_tb<=signed(resize(o_poly_lum,10)); + + 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_phase_b2<=o_poly_phase_b; + + -- C5 / HC5 / VC6 + o_poly_phase<=poly_lerp(o_poly_phase_a, o_poly_phase_b2, o_poly_lerp_ta, o_poly_lerp_tb); + o_h_poly_phase_a3<=o_h_poly_phase_a2; + o_v_poly_phase_a3<=o_v_poly_phase_a2; + + -- C6 / HC6 / VC7 + o_v_poly_phase<=poly_cvt(o_v_poly_phase_a3); + o_h_poly_phase<=poly_cvt(o_h_poly_phase_a3); + + IF o_v_poly_use_adaptive = '1' THEN + o_v_poly_phase<=o_poly_phase; + ELSIF o_h_poly_use_adaptive = '1' THEN + o_h_poly_phase<=o_poly_phase; + END IF; + + END IF; + END PROCESS PolyFetch; + + -- Framebuffer palette GenPal1:IF PALETTE GENERATE Tempera1:PROCESS(pal1_clk) IS @@ -2166,167 +2397,199 @@ BEGIN 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; + 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_h_wr<=poly_wr AND NOT poly_a(FRAC+2); - poly_v_wr<=poly_wr AND poly_a(FRAC+2); + 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); - 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; + 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(18 DOWNTO 0); + VARIABLE div_v : unsigned(20 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 + -- Pipelined 8 bits non-restoring divider. Cycle 1 dir_v:=x"000"; - div_v:=to_unsigned(o_hacc * 64,19); + div_v:=to_unsigned(o_hacc * 256,21); - 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); + 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*32,19); + div_v:=div_v+to_unsigned(o_hsize*128,21); END IF; - dir_v(10):=NOT div_v(18); - o_div<=div_v; - o_dir<=dir_v; + dir_v(10):=NOT div_v(20); + + o_div(0)<=div_v; + o_dir(0)<=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); + 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*16,19); + div_v:=div_v+to_unsigned(o_hsize*64,21); END IF; - dir_v( 9):=NOT div_v(18); + dir_v( 9):=NOT div_v(20); - IF div_v(18)='0' THEN - div_v:=div_v-to_unsigned(o_hsize*8,19); + 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*8,19); + div_v:=div_v+to_unsigned(o_hsize*32,21); END IF; - dir_v(8):=NOT div_v(18); - o_div2<=div_v; - o_dir2<=dir_v; - + dir_v( 8):=NOT div_v(20); + + o_div(1)<=div_v; + o_dir(1)<=dir_v; + -- Cycle 3 - div_v:=o_div2; - dir_v:=o_dir2; + div_v:=o_div(1); + dir_v:=o_dir(1); IF FRAC>4 THEN - IF div_v(18)='0' THEN - div_v:=div_v-to_unsigned(o_hsize*4,19); + 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*4,19); + div_v:=div_v+to_unsigned(o_hsize*16,21); 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); + 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*2,19); + div_v:=div_v+to_unsigned(o_hsize*8,21); END IF; - dir_v(6):=NOT div_v(18); + 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<=dir_v; - o_hfrac1<=o_hfrac; o_hfrac2<=o_hfrac1; - o_hfrac3<=o_hfrac2; o_hfrac4<=o_hfrac3; + o_hfrac(1)<=dir_v; + o_hfrac(2 TO 6) <= o_hfrac(1 TO 5); - o_copyv(1 TO 8)<=o_copyv(0 TO 7); + o_copyv(1 TO 12)<=o_copyv(0 TO 11); 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_dcptv(3 TO 12)<=o_dcptv(2 TO 11); - o_hpixq<=(o_hpix3,o_hpix2,o_hpix1,o_hpix0); + -- C2 + o_hpixq(2)<=(o_hpix3,o_hpix2,o_hpix1,o_hpix0); + o_hpixq(3 TO 6)<=o_hpixq(2 TO 5); - -- NEAREST / BILINEAR / SHARP BILINEAR --------------- - -- C1 : Pre-calc Sharp Bilinear - o_h_sbil_t<=sbil_frac1(o_hfrac1); + -- BILINEAR / SHARP BILINEAR --------------- + -- C4 : Pre-calc Sharp Bilinear + o_h_sbil_t<=sbil_frac1(o_hfrac(3)); - -- 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; + -- C5 : 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(4)); + END IF; + ELSE -- Sharp Bilinear + IF MASK(MASK_SHARP_BILINEAR)='1' THEN + o_h_bil_frac<=sbil_frac2(o_hfrac(4),o_h_sbil_t); + END IF; + END IF; + + -- C6 : Opposite frac + o_h_bil_t<=bil_calc(o_h_bil_frac,o_hpixq(5)); - -- C3 : Opposite frac - o_h_bil_t<=bil_calc(o_h_frac2,o_hpixq); - - -- C4 : Nearest / Bilinear / Sharp Bilinear + -- C7 : 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 + -- C5 : Bicubic coefficients A,B,C,D + -- C5 : Bicubic calc T1 = X.D + C + o_h_bic_abcd1<=bic_calc0(o_hfrac(4),o_hpixq(4)); + o_h_bic_tt1<=bic_calc1(o_hfrac(4), + bic_calc0(o_hfrac(4),o_hpixq(4))); - -- 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 + -- C6 : 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); + o_h_bic_tt2<=bic_calc2(o_hfrac(5),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); + -- C7 : Bicubic final Y = X.T2 + A + o_h_bic_pix<=bic_calc3(o_hfrac(6),o_h_bic_tt2,o_h_bic_abcd2); -- POLYPHASE ----------------------------------------- - -- C1 : Read memory + -- C2 + IF o_hfrac(2)(o_hfrac(2)'left)='0' THEN + o_h_poly_lum<=poly_lum(o_hpix2); + ELSE + o_h_poly_lum<=poly_lum(o_hpix1); + END IF; + -- C3-C6 in PolyFetch + + -- C7 : Apply Polyphase + o_h_poly_t<=poly_calc(o_h_poly_phase,o_hpixq(6)); + + -- C8 : Sum and bound + o_h_poly_pix<=poly_final(o_h_poly_t); - -- 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)); + -- C9 : Select interpoler ---------------------------- + o_wadl<=o_dcptv(12); + o_wr<=o_altx AND (o_copyv(12) & o_copyv(12) & o_copyv(12) & o_copyv(12)); 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 + 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; @@ -2355,10 +2618,10 @@ BEGIN 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); + 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; @@ -2393,11 +2656,11 @@ BEGIN (o_vcpt=o_vsend AND o_hcpt=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); + o_hsv(1 TO 9)<=o_hsv(0 TO 8); + o_vsv(1 TO 9)<=o_vsv(0 TO 8); + o_dev(1 TO 9)<=o_dev(0 TO 8); + o_pev(1 TO 9)<=o_pev(0 TO 8); + o_end(1 TO 9)<=o_end(0 TO 8); IF o_run='0' THEN o_hsv(2)<='0'; @@ -2416,103 +2679,150 @@ BEGIN -- Vertical Scaler VSCAL:PROCESS(o_clk) IS VARIABLE pixq_v : arr_pix(0 TO 3); + VARIABLE vlumpix_v : type_pix; + VARIABLE r1_v, r2_v : natural RANGE 0 TO OHRES-1; + VARIABLE fracnn_v : std_logic; BEGIN IF rising_edge(o_clk) THEN IF o_ce='1' THEN + o_v_hmin_adj<=o_hmin + 4; + + fracnn_v := o_vfrac(o_vfrac'left); + r1_v := (o_hcpt - o_v_hmin_adj + OHRES) MOD OHRES; + r2_v := (o_hcpt - o_hmin + OHRES) MOD OHRES; + -- CYCLE 1 ----------------------------------------- -- Read mem - o_radl<=(o_hcpt - o_hmin + OHRES) MOD OHRES; - + o_radl0<=r1_v; + o_radl1<=r1_v; + o_radl2<=r1_v; + o_radl3<=r1_v; + + IF fracnn_v = '0' THEN + CASE o_vacptl IS + WHEN "10" => 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_vacpt(1 DOWNTO 0) IS + 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; - - o_vpixq<=pixq_v; - - -- Bottom edge : replicate last line - IF to_integer(o_vacpt)=o_ivsize THEN - o_vpixq(2)<=pixq_v(2); + + 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; - IF to_integer(o_vacpt)>=o_ivsize+1 THEN - o_vpixq(2)<=pixq_v(1); - o_vpixq(1)<=pixq_v(1); + + -- CYCLE 3-6 + o_vpix_inner(1 TO 4)<=o_vpix_inner(0 TO 3); + + -- CYCLE 7 + IF to_integer(o_vacpt)>o_ivsize THEN + IF fracnn_v = '0' THEN + o_vpixq<=(o_vpix_outer(0), o_vpix_inner(4), o_vpix_inner(4), o_vpix_inner(4)); + ELSE + o_vpixq<=(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<=(o_vpix_outer(0), o_vpix_inner(4), o_vpix_outer(1), o_vpix_outer(1)); + ELSE + o_vpixq<=(o_vpix_outer(0), o_vpix_outer(1), o_vpix_inner(4), o_vpix_inner(4)); + END IF; + ELSE + IF fracnn_v = '0' THEN + o_vpixq<=(o_vpix_outer(0), o_vpix_inner(4), o_vpix_outer(1), o_vpix_outer(2)); + ELSE + o_vpixq<=(o_vpix_outer(0), o_vpix_outer(1), o_vpix_inner(4), o_vpix_outer(2)); + END IF; END IF; - o_vpixq1<=o_vpixq; - - -- NEAREST / BILINEAR / SHARP BILINEAR ------------- - -- C3 : Pre-calc Sharp Bilinear + -- BILINEAR / SHARP BILINEAR ----------------------- + -- C6 : 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; + -- C7 : 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; + + -- C8 : + o_v_bil_t<=bil_calc(o_v_bil_frac,o_vpixq); - o_v_bil_t<=bil_calc(o_v_frac,o_vpixq1); - - -- C6 : Nearest / Bilinear / Sharp Bilinear + -- C9 : 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 + -- C7 : Bicubic coefficients A,B,C,D + -- C7 : 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 + -- C8 : 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 + -- C9 : 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); + -- C3 : Calculate Luminance + o_v_poly_lum<=poly_lum(o_vpix_inner(0)); + + -- C4-C7 in PolyFetch + + -- C8 : Apply polyphase + o_v_poly_t<=poly_calc(o_v_poly_phase,o_vpixq); + + -- C9 : Bound + o_v_poly_pix<=poly_final(o_v_poly_t); + + -- CYCLE 10 ----------------------------------------- + o_hs<=o_hsv(9); + o_vs<=o_vsv(9); + o_de<=o_dev(9); + o_vbl<=o_end(9); o_r<=x"00"; o_g<=x"00"; o_b<=x"00"; + o_brd<= not o_pev(9); 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 + 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; @@ -2533,7 +2843,7 @@ BEGIN END IF; END CASE; - IF o_pev(5)='0' THEN + IF o_pev(9)='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); diff --git a/sys/hps_io.v b/sys/hps_io.sv similarity index 82% rename from sys/hps_io.v rename to sys/hps_io.sv index 9431c95..d6616c5 100644 --- a/sys/hps_io.v +++ b/sys/hps_io.sv @@ -24,14 +24,13 @@ // Use buffer to access SD card. It's time-critical part. // // WIDE=1 for 16 bit file I/O -// VDNUM 1-4 -module hps_io #(parameter STRLEN=0, PS2DIV=0, WIDE=0, VDNUM=1, PS2WE=0) +// 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, - - // parameter STRLEN and the actual length of conf_str have to match - input [(8*STRLEN)-1:0] conf_str, + inout [48:0] HPS_BUS, // buttons up to 32 output reg [31:0] joystick_0, @@ -42,12 +41,19 @@ module hps_io #(parameter STRLEN=0, PS2DIV=0, WIDE=0, VDNUM=1, PS2WE=0) output reg [31:0] joystick_5, // analog -127..+127, Y: [15:8], X: [7:0] - output reg [15:0] joystick_analog_0, - output reg [15:0] joystick_analog_1, - output reg [15:0] joystick_analog_2, - output reg [15:0] joystick_analog_3, - output reg [15:0] joystick_analog_4, - output reg [15:0] joystick_analog_5, + output reg [15:0] joystick_l_analog_0, + output reg [15:0] joystick_l_analog_1, + output reg [15:0] joystick_l_analog_2, + output reg [15:0] joystick_l_analog_3, + output reg [15:0] joystick_l_analog_4, + output reg [15:0] joystick_l_analog_5, + + output reg [15:0] joystick_r_analog_0, + output reg [15:0] joystick_r_analog_1, + output reg [15:0] joystick_r_analog_2, + output reg [15:0] joystick_r_analog_3, + output reg [15:0] joystick_r_analog_4, + output reg [15:0] joystick_r_analog_5, // paddle 0..255 output reg [7:0] paddle_0, @@ -68,6 +74,10 @@ module hps_io #(parameter STRLEN=0, PS2DIV=0, WIDE=0, VDNUM=1, PS2WE=0) output [1:0] buttons, output forced_scandoubler, output direct_video, + input video_rotated, + + //toggle to force notify of video mode change + input new_vmode, output reg [63:0] status, input [63:0] status_in, @@ -77,31 +87,23 @@ module hps_io #(parameter STRLEN=0, PS2DIV=0, WIDE=0, VDNUM=1, PS2WE=0) input info_req, input [7:0] info, - //toggle to force notify of video mode change - input new_vmode, - // 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 output reg [63:0] img_size, // size of image in bytes. valid only for active bit in img_mounted // SD block level access - input [31:0] sd_lba, - input [VD:0] sd_rd, // only single sd_rd can be active at any given time - input [VD:0] sd_wr, // only single sd_wr can be active at any given time - output reg sd_ack, - - // do not use in new projects. - // CID and CSD are fake except CSD image size field. - input sd_conf, - output reg sd_ack_conf, + input [31:0] sd_lba[VDNUM], + input [5:0] sd_blk_cnt[VDNUM], // number of blocks-1, total size ((sd_blk_cnt+1)*(1<<(BLKSZ+7))) must be <= 16384! + input [VD:0] sd_rd, + input [VD:0] sd_wr, + output reg [VD:0] sd_ack, // SD byte level access. Signals for 2-PORT altsyncram. output reg [AW:0] sd_buff_addr, output reg [DW:0] sd_buff_dout, - input [DW:0] sd_buff_din, + input [DW:0] sd_buff_din[VDNUM], output reg sd_buff_wr, - input [15:0] sd_req_type, // ARM -> FPGA download output reg ioctl_download = 0, // signal indicating an active download @@ -110,6 +112,8 @@ module hps_io #(parameter STRLEN=0, PS2DIV=0, WIDE=0, VDNUM=1, PS2WE=0) 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, // 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, @@ -161,10 +165,8 @@ module hps_io #(parameter STRLEN=0, PS2DIV=0, WIDE=0, VDNUM=1, PS2WE=0) assign EXT_BUS[31:16] = HPS_BUS[31:16]; assign EXT_BUS[35:33] = HPS_BUS[35:33]; -localparam MAX_W = $clog2((512 > (STRLEN+1)) ? 512 : (STRLEN+1))-1; - localparam DW = (WIDE) ? 15 : 7; -localparam AW = (WIDE) ? 7 : 8; +localparam AW = (WIDE) ? 12 : 13; localparam VD = VDNUM-1; wire io_strobe= HPS_BUS[33]; @@ -187,22 +189,18 @@ assign forced_scandoubler = cfg[4]; //cfg[5] - ypbpr handled in sys_top assign direct_video = cfg[10]; -// command byte read by the io controller -wire [15:0] sd_cmd = -{ - 2'b00, - (VDNUM>=4) ? sd_wr[3] : 1'b0, - (VDNUM>=3) ? sd_wr[2] : 1'b0, - (VDNUM>=2) ? sd_wr[1] : 1'b0, +reg [3:0] sdn; +reg [3:0] sd_rrb = 0; +always_comb begin + int n, i; - (VDNUM>=4) ? sd_rd[3] : 1'b0, - (VDNUM>=3) ? sd_rd[2] : 1'b0, - (VDNUM>=2) ? sd_rd[1] : 1'b0, - - 4'h5, sd_conf, 1'b1, - sd_wr[0], - sd_rd[0] -}; + sdn = 0; + for(i = VDNUM - 1; i >= 0; i = i - 1) begin + n = i + sd_rrb; + if(n >= VDNUM) n = n - VDNUM; + if(sd_wr[n] | sd_rd[n]) sdn = n[3:0]; + end +end ///////////////////////////////////////////////////////// @@ -219,6 +217,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) @@ -226,6 +225,19 @@ video_calc video_calc ///////////////////////////////////////////////////////// +localparam STRLEN = $size(CONF_STR)>>3; +localparam MAX_W = $clog2((32 > (STRLEN+2)) ? 32 : (STRLEN+2))-1; + +wire [7:0] conf_byte; +generate + if(CONF_STR_BRAM) begin + confstr_rom #(CONF_STR, STRLEN) confstr_rom(.*, .conf_addr(byte_cnt - 1'd1)); + end + else begin + assign conf_byte = CONF_STR[{(STRLEN - byte_cnt),3'b000} +:8]; + end +endgenerate + assign gamma_bus[20:0] = {clk_sys, gamma_en, gamma_wr, gamma_wr_addr, gamma_value}; reg gamma_en; reg gamma_wr; @@ -237,6 +249,8 @@ wire pressed = (ps2_key_raw[15:8] != 8'hf0); wire extended = (~pressed ? (ps2_key_raw[23:16] == 8'he0) : (ps2_key_raw[15:8] == 8'he0)); reg [MAX_W:0] byte_cnt; +reg [3:0] sdn_ack; +wire [15:0] disk = 16'd1 << io_din[11:8]; always@(posedge clk_sys) begin : uio_block reg [15:0] cmd; @@ -247,16 +261,22 @@ always@(posedge clk_sys) begin : uio_block reg [3:0] stflg = 0; reg [63:0] status_req; reg old_status_set = 0; + reg old_upload_req = 0; + reg upload_req = 0; reg old_info = 0; reg [7:0] info_n = 0; reg [15:0] tmp1; reg [7:0] tmp2; + reg [3:0] sdn_r; old_status_set <= status_set; if(~old_status_set & status_set) begin stflg <= stflg + 1'd1; status_req <= status_in; end + + old_upload_req <= ioctl_upload_req; + if(~old_upload_req & ioctl_upload_req) upload_req <= 1; old_info <= info_req; if(~old_info & info_req) info_n <= info; @@ -282,7 +302,6 @@ always@(posedge clk_sys) begin : uio_block cmd <= 0; byte_cnt <= 0; sd_ack <= 0; - sd_ack_conf <= 0; io_dout <= 0; ps2skip <= 0; img_mounted <= 0; @@ -295,23 +314,29 @@ always@(posedge clk_sys) begin : uio_block if(byte_cnt == 0) begin cmd <= io_din; - case(io_din) - 'h19: sd_ack_conf <= 1; - 'h17, - 'h18: sd_ack <= 1; - 'h29: io_dout <= {4'hA, stflg}; - 'h2B: io_dout <= 1; - 'h2F: io_dout <= 1; - 'h32: io_dout <= gamma_bus[21]; - 'h36: begin io_dout <= info_n; info_n <= 0; end - 'h39: io_dout <= 1; + casex(io_din) + 'h16: begin io_dout <= {1'b1, sd_blk_cnt[sdn], BLKSZ[2:0], sdn, sd_wr[sdn], sd_rd[sdn]}; sdn_r <= sdn; end + 'h0X17, + 'h0X18: begin sd_ack <= disk[VD:0]; sdn_ack <= io_din[11:8]; end + 'h29: io_dout <= {4'hA, stflg}; +`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 <= {ioctl_upload_index, 8'd1}; upload_req <= 0; end + 'h3E: io_dout <= 1; // shadow mask endcase sd_buff_addr <= 0; if(io_din == 5) ps2_key_raw <= 0; end else begin - case(cmd) + casex(cmd) // buttons and switches 'h01: cfg <= io_din; 'h02: if(byte_cnt==1) joystick_0[15:0] <= io_din; else joystick_0[31:16] <= io_din; @@ -353,47 +378,41 @@ always@(posedge clk_sys) begin : uio_block end // reading config string, returning a byte from string - 'h14: if(byte_cnt < STRLEN + 1) io_dout[7:0] <= conf_str[(STRLEN - byte_cnt)<<3 +:8]; + 'h14: if(byte_cnt <= STRLEN) io_dout[7:0] <= conf_byte; // reading sd card status - 'h16: if(!byte_cnt[MAX_W:3]) begin - case(byte_cnt[2:0]) - 1: io_dout <= sd_cmd; - 2: io_dout <= sd_lba[15:0]; - 3: io_dout <= sd_lba[31:16]; - 4: io_dout <= sd_req_type; + 'h16: if(!byte_cnt[MAX_W:2]) begin + case(byte_cnt[1:0]) + 1: sd_rrb <= (sd_rrb == VD) ? 4'd0 : (sd_rrb + 1'd1); + 2: io_dout <= sd_lba[sdn_r][15:0]; + 3: io_dout <= sd_lba[sdn_r][31:16]; endcase end - // send SD config IO -> FPGA - // flag that download begins - // sd card knows data is config if sd_dout_strobe is asserted - // with sd_ack still being inactive (low) - 'h19, // send sector IO -> FPGA // flag that download begins - 'h17: begin + 'h0X17: begin sd_buff_dout <= io_din[DW:0]; b_wr <= 1; end // reading sd card write data - 'h18: begin + 'h0X18: begin if(~&sd_buff_addr) sd_buff_addr <= sd_buff_addr + 1'b1; - io_dout <= sd_buff_din; + io_dout <= sd_buff_din[sdn_ack]; end - // joystick analog + // joystick left analog 'h1a: if(!byte_cnt[MAX_W:2]) begin case(byte_cnt[1:0]) 1: {pdsp_idx,stick_idx} <= io_din[7:0]; // first byte is joystick index 2: case(stick_idx) - 0: joystick_analog_0 <= io_din; - 1: joystick_analog_1 <= io_din; - 2: joystick_analog_2 <= io_din; - 3: joystick_analog_3 <= io_din; - 4: joystick_analog_4 <= io_din; - 5: joystick_analog_5 <= io_din; + 0: joystick_l_analog_0 <= io_din; + 1: joystick_l_analog_1 <= io_din; + 2: joystick_l_analog_2 <= io_din; + 3: joystick_l_analog_3 <= io_din; + 4: joystick_l_analog_4 <= io_din; + 5: joystick_l_analog_5 <= io_din; 15: case(pdsp_idx) 0: paddle_0 <= io_din[7:0]; 1: paddle_1 <= io_din[7:0]; @@ -412,6 +431,21 @@ always@(posedge clk_sys) begin : uio_block endcase end + // joystick right analog + 'h3d: if(!byte_cnt[MAX_W:2]) begin + case(byte_cnt[1:0]) + 1: stick_idx <= io_din[3:0]; // first byte is joystick index + 2: case(stick_idx) + 0: joystick_r_analog_0 <= io_din; + 1: joystick_r_analog_1 <= io_din; + 2: joystick_r_analog_2 <= io_din; + 3: joystick_r_analog_3 <= io_din; + 4: joystick_r_analog_4 <= io_din; + 5: joystick_r_analog_5 <= io_din; + endcase + endcase + end + // notify image selection 'h1c: begin img_mounted <= io_din[VD:0] ? io_din[VD:0] : 1'b1; @@ -815,6 +849,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 @@ -822,7 +857,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]; @@ -936,3 +971,16 @@ always @(posedge clk_100) begin end endmodule + +module confstr_rom #(parameter CONF_STR, STRLEN) +( + input clk_sys, + input [$clog2(STRLEN+1)-1:0] conf_addr, + output reg [7:0] conf_byte +); + +wire [7:0] rom[STRLEN]; +initial for(int i = 0; i < STRLEN; i++) rom[i] = CONF_STR[((STRLEN-i)*8)-1 -:8]; +always @ (posedge clk_sys) conf_byte <= rom[conf_addr]; + +endmodule diff --git a/sys/osd.v b/sys/osd.v index a4fbdde..782fc81 100644 --- a/sys/osd.v +++ b/sys/osd.v @@ -72,7 +72,7 @@ always@(posedge clk_sys) begin // command 0x40: OSDCMDENABLE, OSDCMDDISABLE if(io_din[7:4] == 4) begin if(!io_din[0]) {osd_status,highres} <= 0; - else {osd_status,info} <= {~io_din[2],io_din[2]}; + else {osd_status,info} <= {~io_din[2] & ~io_din[3],io_din[2]}; bcnt <= 0; end // command 0x20: OSDCMDWRITE 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/sd_card.sv b/sys/sd_card.sv index a2aad7e..610c271 100644 --- a/sys/sd_card.sv +++ b/sys/sd_card.sv @@ -23,52 +23,55 @@ // // Made module syncrhronous. Total code refactoring. (Sorgelig) -// clk_spi must be at least 4 x sck for proper work. +// clk_spi must be at least 2 x sck for proper work. -module sd_card #(parameter WIDE = 0) +module sd_card #(parameter WIDE = 0, OCTAL=0) ( - input clk_sys, - input reset, + input clk_sys, + input reset, - input sdhc, - - output [31:0] sd_lba, - output reg sd_rd, - output reg sd_wr, - input sd_ack, - input sd_ack_conf, + input sdhc, + input img_mounted, + input [63:0] img_size, - input [AW:0] sd_buff_addr, - input [DW:0] sd_buff_dout, - output [DW:0] sd_buff_din, - input sd_buff_wr, + output reg [31:0] sd_lba, + output reg sd_rd, + output reg sd_wr, + input sd_ack, + + input [AW:0] sd_buff_addr, + input [DW:0] sd_buff_dout, + output [DW:0] sd_buff_din, + input sd_buff_wr, // SPI interface - input clk_spi, + input clk_spi, - input ss, - input sck, - input mosi, - output reg miso + input ss, + input sck, + input [SW:0] mosi, + output reg [SW:0] miso ); -localparam AW = WIDE ? 7 : 8; -localparam DW = WIDE ? 15 : 7; +localparam AW = WIDE ? 7 : 8; +localparam DW = WIDE ? 15 : 7; +localparam SZ = OCTAL ? 8 : 1; +localparam SW = SZ-1; -assign sd_lba = sdhc ? lba : {9'd0, lba[31:9]}; - -wire[31:0] OCR = { 1'b1, sdhc, 30'd0 }; // bit30 = 1 -> high capaciry card (sdhc) // bit31 = 0 -> card power up finished -wire [7:0] READ_DATA_TOKEN = 8'hfe; +wire [7:0] DATA_TOKEN_CMD25 = 8'hfc; +wire [7:0] STOP_TRAN = 8'hfd; +wire [7:0] DATA_TOKEN = 8'hfe; wire [7:0] WRITE_DATA_RESPONSE = 8'h05; // number of bytes to wait after a command before sending the reply -localparam NCR=3; +localparam NCR = 5+3; // 5 bytes are required (command length) localparam RD_STATE_IDLE = 0; -localparam RD_STATE_WAIT_IO = 1; -localparam RD_STATE_SEND_TOKEN = 2; -localparam RD_STATE_SEND_DATA = 3; -localparam RD_STATE_WAIT_M = 4; +localparam RD_STATE_START = 1; +localparam RD_STATE_WAIT_IO = 2; +localparam RD_STATE_SEND_TOKEN = 3; +localparam RD_STATE_SEND_DATA = 4; +localparam RD_STATE_WAIT_M = 5; localparam WR_STATE_IDLE = 0; localparam WR_STATE_EXP_DTOKEN = 1; @@ -78,460 +81,383 @@ localparam WR_STATE_RECV_CRC1 = 4; localparam WR_STATE_SEND_DRESP = 5; localparam WR_STATE_BUSY = 6; -sdbuf #(WIDE) buffer +localparam PREF_STATE_IDLE = 0; +localparam PREF_STATE_RD = 1; +localparam PREF_STATE_FINISH = 2; + +altsyncram sdbuf ( - .clock_a(clk_sys), - .address_a(sd_buff_addr), - .data_a(sd_buff_dout), - .wren_a(sd_ack & sd_buff_wr), - .q_a(sd_buff_din), + .clock0 (clk_sys), + .address_a ({sd_buf,sd_buff_addr}), + .data_a (sd_buff_dout), + .wren_a (sd_ack & sd_buff_wr), + .q_a (sd_buff_din), - .clock_b(clk_spi), - .address_b(buffer_ptr), - .data_b(buffer_din), - .wren_b(buffer_wr), - .q_b(buffer_dout) + .clock1 (clk_spi), + .address_b ({spi_buf,buffer_ptr}), + .data_b (buffer_din), + .wren_b (buffer_wr), + .q_b (buffer_dout), + + .aclr0(1'b0), + .aclr1(1'b0), + .addressstall_a(1'b0), + .addressstall_b(1'b0), + .byteena_a(1'b1), + .byteena_b(1'b1), + .clocken0(1'b1), + .clocken1(1'b1), + .clocken2(1'b1), + .clocken3(1'b1), + .eccstatus(), + .rden_a(1'b1), + .rden_b(1'b1) ); +defparam + sdbuf.numwords_a = 1<<(AW+3), + sdbuf.widthad_a = AW+3, + sdbuf.width_a = DW+1, + sdbuf.numwords_b = 2048, + sdbuf.widthad_b = 11, + sdbuf.width_b = 8, + sdbuf.address_reg_b = "CLOCK1", + sdbuf.clock_enable_input_a = "BYPASS", + sdbuf.clock_enable_input_b = "BYPASS", + sdbuf.clock_enable_output_a = "BYPASS", + sdbuf.clock_enable_output_b = "BYPASS", + sdbuf.indata_reg_b = "CLOCK1", + sdbuf.intended_device_family = "Cyclone V", + sdbuf.lpm_type = "altsyncram", + sdbuf.operation_mode = "BIDIR_DUAL_PORT", + sdbuf.outdata_aclr_a = "NONE", + sdbuf.outdata_aclr_b = "NONE", + sdbuf.outdata_reg_a = "UNREGISTERED", + sdbuf.outdata_reg_b = "UNREGISTERED", + sdbuf.power_up_uninitialized = "FALSE", + sdbuf.read_during_write_mode_port_a = "NEW_DATA_NO_NBE_READ", + sdbuf.read_during_write_mode_port_b = "NEW_DATA_NO_NBE_READ", + sdbuf.width_byteena_a = 1, + sdbuf.width_byteena_b = 1, + sdbuf.wrcontrol_wraddress_reg_b = "CLOCK1"; -sdbuf #(WIDE) conf -( - .clock_a(clk_sys), - .address_a(sd_buff_addr), - .data_a(sd_buff_dout), - .wren_a(sd_ack_conf & sd_buff_wr), +reg [26:0] csd_size; +reg csd_sdhc; +always @(posedge clk_sys) begin + if (img_mounted) begin + csd_sdhc <= sdhc; + if (sdhc) begin + csd_size[0] <= 0; + csd_size[22:1] <= img_size[40:19]; // in 512K units + csd_size[26:23] <= 0; + end + else begin + csd_size[2:0] <= 7; // C_SIZE_MULT + csd_size[14:3] <= 12'b101101101101; + csd_size[26:15] <= img_size[29:18]; // in 256K units ((2**(C_SIZE_MULT+2))*512) + end + end +end - .clock_b(clk_spi), - .address_b(buffer_ptr), - .q_b(config_dout) -); +wire [127:0] CSD = {1'b0,csd_sdhc,6'h00,8'h0e,8'h00,8'h32,8'h5b,8'h59,6'h00,csd_size,7'h7f,8'h80,8'h0a,8'h40,8'h40,8'hf1}; +wire [127:0] CID = {8'hcd,8'hc7,8'h00,8'h93,8'h6f,8'h2f,8'h73,8'h00,8'h00,8'h44,8'h32,8'h38,8'h34,8'h00,8'h00,8'h3e}; -reg [31:0] lba, new_lba; reg [8:0] buffer_ptr; reg [7:0] buffer_din; wire [7:0] buffer_dout; -wire [7:0] config_dout; reg buffer_wr; -always @(posedge clk_spi) begin - reg [2:0] read_state; - reg [2:0] write_state; - reg [6:0] sbuf; - reg cmd55; - reg [7:0] cmd; - reg [2:0] bit_cnt; - reg [3:0] byte_cnt; - reg [7:0] reply; - reg [7:0] reply0, reply1, reply2, reply3; - reg [3:0] reply_len; - reg tx_finish; - reg rx_finish; - reg old_sck; - reg synced; - reg [5:0] ack; - reg io_ack; - reg [4:0] idle_cnt = 0; - reg [2:0] wait_m_cnt; +reg [1:0] sd_buf, spi_buf; + +reg [6:0] sbuf; +reg [2:0] bit_cnt; + +wire last_bit = &bit_cnt || OCTAL; +wire [7:0] ibuf = OCTAL ? mosi : {sbuf,mosi[0]}; + +always @(posedge clk_spi) begin + reg [2:0] read_state; + reg [2:0] write_state; + reg [1:0] pref_state; + reg [5:0] cmd; + reg cmd55; + reg [39:0] reply; + reg [3:0] byte_cnt; + reg old_sck; + reg [2:0] ack; + reg [2:0] wait_m_cnt; + reg [31:0] arg; + + ack[1:0] <= {ack[0],sd_ack}; + if(ack[1] == ack[0]) ack[2] <= ack[1]; + + if(~ack[2] & ack[1]) {sd_rd,sd_wr} <= 0; + if( ack[2] & ~ack[1]) begin + sd_buf <= sd_buf + 1'd1; + sd_lba <= sd_lba + 1; + end - if(buffer_wr & ~&buffer_ptr) buffer_ptr <= buffer_ptr + 1'd1; buffer_wr <= 0; - ack <= {ack[4:0], sd_ack}; - if(ack[5:4] == 2'b10) io_ack <= 1; - if(ack[5:4] == 2'b01) {sd_rd,sd_wr} <= 0; - - old_sck <= sck; - - if(~ss) idle_cnt <= 31; - else if(~old_sck && sck && idle_cnt) idle_cnt <= idle_cnt - 1'd1; - - if(reset || !idle_cnt) begin + if(reset) begin bit_cnt <= 0; - byte_cnt <= 15; - synced <= 0; - miso <= 1; - sbuf <= 7'b1111111; - tx_finish <= 0; - rx_finish <= 0; + byte_cnt <= '1; + miso <= '1; + cmd <= 0; + sd_wr <= 0; + sd_rd <= 0; read_state <= RD_STATE_IDLE; write_state <= WR_STATE_IDLE; + pref_state <= PREF_STATE_IDLE; end + else begin - if(old_sck & ~sck & ~ss) begin - tx_finish <= 0; - miso <= 1; // default: send 1's (busy/wait) - - if(byte_cnt == 5+NCR) begin - miso <= reply[~bit_cnt]; - - if(bit_cnt == 7) begin - // these three commands all have a reply_len of 0 and will thus - // not send more than a single reply byte - - // CMD9: SEND_CSD - // CMD10: SEND_CID - if((cmd == 'h49) | (cmd == 'h4a)) - read_state <= RD_STATE_SEND_TOKEN; // jump directly to data transmission - - // CMD17/CMD18 - if((cmd == 'h51) | (cmd == 'h52)) begin - io_ack <= 0; - read_state <= RD_STATE_WAIT_IO; // start waiting for data from io controller - lba <= new_lba; - sd_rd <= 1; // trigger request to io controller - end + if(buffer_wr) begin + if(~&buffer_ptr) buffer_ptr <= buffer_ptr + 1'd1; + else begin + spi_buf <= spi_buf + 1'd1; + sd_wr <= 1; end end - else if((reply_len > 0) && (byte_cnt == 5+NCR+1)) miso <= reply0[~bit_cnt]; - else if((reply_len > 1) && (byte_cnt == 5+NCR+2)) miso <= reply1[~bit_cnt]; - else if((reply_len > 2) && (byte_cnt == 5+NCR+3)) miso <= reply2[~bit_cnt]; - else if((reply_len > 3) && (byte_cnt == 5+NCR+4)) miso <= reply3[~bit_cnt]; - else begin - if(byte_cnt > 5+NCR && read_state==RD_STATE_IDLE && write_state==WR_STATE_IDLE) tx_finish <= 1; - end - // ---------- read state machine processing ------------- - - case(read_state) - RD_STATE_IDLE: ; // do nothing - - - // waiting for io controller to return data - RD_STATE_WAIT_IO: begin - if(io_ack & (bit_cnt == 7)) read_state <= RD_STATE_SEND_TOKEN; - end - - // send data token - RD_STATE_SEND_TOKEN: begin - miso <= READ_DATA_TOKEN[~bit_cnt]; - - if(bit_cnt == 7) begin - read_state <= RD_STATE_SEND_DATA; // next: send data - buffer_ptr <= 0; - if(cmd == 'h49) buffer_ptr <= 16; + case(pref_state) + PREF_STATE_IDLE: + if(((sd_buf - spi_buf) <= 1) && (read_state != RD_STATE_IDLE) && (cmd == 17 || cmd == 18)) begin + sd_rd <= 1; + pref_state <= PREF_STATE_RD; end - end - // send data - RD_STATE_SEND_DATA: begin - - miso <= ((cmd == 'h49) | (cmd == 'h4A)) ? config_dout[~bit_cnt] : buffer_dout[~bit_cnt]; - - if(bit_cnt == 7) begin - - // sent 512 sector data bytes? - if((cmd == 'h51) & &buffer_ptr) read_state <= RD_STATE_IDLE; - else if((cmd == 'h52) & &buffer_ptr) begin - read_state <= RD_STATE_WAIT_M; - wait_m_cnt <= 0; - end - - // sent 16 cid/csd data bytes? - else if(((cmd == 'h49) | (cmd == 'h4a)) & (&buffer_ptr[3:0])) read_state <= RD_STATE_IDLE; - - // not done yet -> trigger read of next data byte - else buffer_ptr <= buffer_ptr + 1'd1; + PREF_STATE_RD: + if(read_state == RD_STATE_IDLE) begin + pref_state <= PREF_STATE_IDLE; end - end - - RD_STATE_WAIT_M: begin - if(bit_cnt == 7) begin - wait_m_cnt <= wait_m_cnt + 1'd1; - if(&wait_m_cnt) begin - lba <= lba + 1; - io_ack <= 0; - sd_rd <= 1; - read_state <= RD_STATE_WAIT_IO; - end + else if(ack[2] & ~ack[1]) begin + pref_state <= (cmd == 18) ? PREF_STATE_IDLE : PREF_STATE_FINISH; + end + + PREF_STATE_FINISH: + if(read_state == RD_STATE_IDLE) begin + pref_state <= PREF_STATE_IDLE; end - end endcase - // ------------------ write support ---------------------- - // send write data response - if(write_state == WR_STATE_SEND_DRESP) miso <= WRITE_DATA_RESPONSE[~bit_cnt]; - - // busy after write until the io controller sends ack - if(write_state == WR_STATE_BUSY) miso <= 0; - end - - if(~old_sck & sck & ~ss) begin - - if(synced) bit_cnt <= bit_cnt + 1'd1; - - // assemble byte - if(bit_cnt != 7) begin - sbuf[6:0] <= { sbuf[5:0], mosi }; - - // resync while waiting for token - if(write_state==WR_STATE_EXP_DTOKEN) begin - if(cmd == 'h58) begin - if({sbuf,mosi} == 8'hfe) begin - write_state <= WR_STATE_RECV_DATA; - buffer_ptr <= 0; - bit_cnt <= 0; - end - end - else begin - if({sbuf,mosi} == 8'hfc) begin - write_state <= WR_STATE_RECV_DATA; - buffer_ptr <= 0; - bit_cnt <= 0; - end - if({sbuf,mosi} == 8'hfd) begin - write_state <= WR_STATE_IDLE; - rx_finish <= 1; - bit_cnt <= 0; - end - end - end + old_sck <= sck; + if(ss) begin + bit_cnt <= 0; + byte_cnt <= '1; + miso <= '1; end - else begin - // finished reading one byte - // byte counter runs against 15 byte boundary - if(byte_cnt != 15) byte_cnt <= byte_cnt + 1'd1; + else if(old_sck & ~sck) begin + miso <= '1; // default: send 1's (busy/wait) + if(byte_cnt >= NCR) {miso,reply} <= {reply, {SZ{1'b1}}}; - // byte_cnt > 6 -> complete command received - // first byte of valid command is 01xxxxxx - // don't accept new commands once a write or read command has been accepted - if((byte_cnt > 5) & (write_state == WR_STATE_IDLE) & (read_state == RD_STATE_IDLE) && !rx_finish) begin - byte_cnt <= 0; - cmd <= { sbuf, mosi}; + // ---------- read state machine processing ------------- + case(read_state) + RD_STATE_IDLE: ; - // set cmd55 flag if previous command was 55 - cmd55 <= (cmd == 'h77); - end + RD_STATE_START: begin + if(byte_cnt == NCR && last_bit) read_state <= (cmd == 9 || cmd == 10) ? RD_STATE_SEND_TOKEN : RD_STATE_WAIT_IO; + end - if((byte_cnt > 5) & (read_state == RD_STATE_WAIT_M) && ({sbuf, mosi} == 8'h4c)) begin - byte_cnt <= 0; - rx_finish <= 0; - cmd <= {sbuf, mosi}; - read_state <= RD_STATE_IDLE; - end + // waiting for io controller to return data + RD_STATE_WAIT_IO: begin + if(sd_buf != spi_buf && last_bit) read_state <= RD_STATE_SEND_TOKEN; + end - // parse additional command bytes - if(byte_cnt == 0) new_lba[31:24] <= { sbuf, mosi}; - if(byte_cnt == 1) new_lba[23:16] <= { sbuf, mosi}; - if(byte_cnt == 2) new_lba[15:8] <= { sbuf, mosi}; - if(byte_cnt == 3) new_lba[7:0] <= { sbuf, mosi}; - - // last byte (crc) received, evaluate - if(byte_cnt == 4) begin - - // default: - reply <= 4; // illegal command - reply_len <= 0; // no extra reply bytes - rx_finish <= 1; - - case(cmd) - // CMD0: GO_IDLE_STATE - 'h40: reply <= 1; // ok, busy - - // CMD1: SEND_OP_COND - 'h41: reply <= 0; // ok, not busy - - // CMD8: SEND_IF_COND (V2 only) - 'h48: begin - reply <= 1; // ok, busy - - reply0 <= 'h00; - reply1 <= 'h00; - reply2 <= 'h01; - reply3 <= 'hAA; - reply_len <= 4; - end - - // CMD9: SEND_CSD - 'h49: reply <= 0; // ok - - // CMD10: SEND_CID - 'h4a: reply <= 0; // ok - - // CMD12: STOP_TRANSMISSION - 'h4c: reply <= 0; // ok - - // CMD13: SEND_STATUS - 'h4d: begin - reply <= 'h00; // ok - reply0 <='h00; - reply_len <= 1; - end - - // CMD16: SET_BLOCKLEN - 'h50: begin - // we only support a block size of 512 - if(new_lba == 512) reply <= 0; // ok - else reply <= 'h40; // parmeter error - end - - // CMD17: READ_SINGLE_BLOCK - 'h51: reply <= 0; // ok - - // CMD18: READ_MULTIPLE - 'h52: reply <= 0; // ok - // ACMD23: SET_WR_BLK_ERASE_COUNT - 'h57: reply <= 0; //ok - - // CMD24: WRITE_BLOCK - 'h58, - // CMD25: WRITE_MULTIPLE - 'h59: begin - reply <= 0; // ok - write_state <= WR_STATE_EXP_DTOKEN; // expect data token - rx_finish <=0; - lba <= new_lba; - end - - // ACMD41: APP_SEND_OP_COND - 'h69: if(cmd55) reply <= 0; // ok, not busy - - // CMD55: APP_COND - 'h77: reply <= 1; // ok, busy - - // CMD58: READ_OCR - 'h7a: begin - reply <= 0; // ok - - reply0 <= OCR[31:24]; // bit 30 = 1 -> high capacity card - reply1 <= OCR[23:16]; - reply2 <= OCR[15:8]; - reply3 <= OCR[7:0]; - reply_len <= 4; - end - - // CMD59: CRC_ON_OFF - 'h7b: reply <= 0; // ok - endcase - end - - // ---------- handle write ----------- - case(write_state) - // do nothing in idle state - WR_STATE_IDLE: ; - - // waiting for data token - WR_STATE_EXP_DTOKEN: begin - buffer_ptr <= 0; - if(cmd == 'h58) begin - if({sbuf,mosi} == 8'hfe) write_state <= WR_STATE_RECV_DATA; - end - else begin - if({sbuf,mosi} == 8'hfc) write_state <= WR_STATE_RECV_DATA; - if({sbuf,mosi} == 8'hfd) begin - write_state <= WR_STATE_IDLE; - rx_finish <= 1; - end + // send data token + RD_STATE_SEND_TOKEN: begin + miso <= DATA_TOKEN[~bit_cnt -:SZ]; + if(last_bit) begin + read_state <= RD_STATE_SEND_DATA; // next: send data + buffer_ptr <= 0; end end - // transfer 512 bytes - WR_STATE_RECV_DATA: begin - // push one byte into local buffer - buffer_wr <= 1; - buffer_din <= {sbuf, mosi}; + // send data + RD_STATE_SEND_DATA: begin - // all bytes written? - if(&buffer_ptr) write_state <= WR_STATE_RECV_CRC0; + miso <= (cmd == 9) ? CSD[{buffer_ptr[3:0],~bit_cnt} -:SZ] : (cmd == 10) ? CID[{buffer_ptr[3:0],~bit_cnt} -:SZ] : buffer_dout[~bit_cnt -:SZ]; + + if(last_bit) begin + + // sent 512 sector data bytes? + if(cmd == 17 && &buffer_ptr) read_state <= RD_STATE_IDLE; + else if(cmd == 18 && &buffer_ptr) begin + read_state <= RD_STATE_WAIT_M; + wait_m_cnt <= 0; + end + + // sent 16 cid/csd data bytes? + else if((cmd == 9 || cmd == 10) && &buffer_ptr[3:0]) read_state <= RD_STATE_IDLE; + + // not done yet -> trigger read of next data byte + else buffer_ptr <= buffer_ptr + 1'd1; + end end - // transfer 1st crc byte - WR_STATE_RECV_CRC0: - write_state <= WR_STATE_RECV_CRC1; + RD_STATE_WAIT_M: begin + if(last_bit) begin + wait_m_cnt <= wait_m_cnt + 1'd1; + if(&wait_m_cnt) begin + spi_buf <= spi_buf + 1'd1; + read_state <= RD_STATE_WAIT_IO; + end + end + end + endcase - // transfer 2nd crc byte - WR_STATE_RECV_CRC1: - write_state <= WR_STATE_SEND_DRESP; + // ------------------ write support ---------------------- + // send write data response + if(write_state == WR_STATE_SEND_DRESP) miso <= WRITE_DATA_RESPONSE[~bit_cnt -:SZ]; - // send data response - WR_STATE_SEND_DRESP: begin - write_state <= WR_STATE_BUSY; - io_ack <= 0; - sd_wr <= 1; + // busy after write until the io controller sends ack + if(write_state == WR_STATE_BUSY) miso <= 0; + end + else if(~old_sck & sck) begin + + sbuf[6:0] <= {sbuf[5:0],mosi[0]}; + bit_cnt <= bit_cnt + SZ[2:0]; + + if(last_bit) begin + // finished reading one byte + // byte counter runs against 15 byte boundary + if(~&byte_cnt) byte_cnt <= byte_cnt + 1'd1; + + // byte_cnt > 6 -> complete command received + // first byte of valid command is 01xxxxxx + // don't accept new commands once a write or read command has been accepted + if(byte_cnt > 5 && + ((write_state == WR_STATE_IDLE && read_state == RD_STATE_IDLE && ibuf[7:6] == 1) || + (read_state != RD_STATE_IDLE && ibuf == 8'h4c))) begin + byte_cnt <= 0; + cmd <= ibuf[5:0]; + cmd55 <= (cmd == 55); // set cmd55 flag if previous command was 55 + if(ibuf[5:0] == 12) read_state <= RD_STATE_IDLE; end - // wait for io controller to accept data - WR_STATE_BUSY: - if(io_ack) begin - if(cmd == 'h59) begin - write_state <= WR_STATE_EXP_DTOKEN; - lba <= lba + 1; + // parse additional command bytes + if(byte_cnt == 0) arg[31:24] <= ibuf; + if(byte_cnt == 1) arg[23:16] <= ibuf; + if(byte_cnt == 2) arg[15:8] <= ibuf; + if(byte_cnt == 3) arg[7:0] <= ibuf; + + // last byte (crc) received, evaluate + if(byte_cnt == 4) begin + + // default: + reply <= 40'h04FFFFFFFF; // illegal command + + case(cmd) + // CMD0: GO_IDLE_STATE + 0: reply[39:32] <= 1; // ok, busy + + // CMD1: SEND_OP_COND + 1: reply[39:32] <= 0; + + // CMD8: SEND_IF_COND (V2 only) + 8: reply <= 40'h01000001AA; // ok, busy + + // CMD9: SEND_CSD + 9, + // CMD10: SEND_CID + 10: begin + reply[39:32] <= 0; + read_state <= RD_STATE_START; + end + + // CMD12: STOP_TRANSMISSION + 12: reply[39:32] <= 0; + + // CMD13: SEND_STATUS + 13: reply[39:24] <= 16'h0000; + + // CMD16: SET_BLOCKLEN + 16: reply[39:32] <= (arg == 512) ? 8'h00 : 8'h40; // we only support a block size of 512 + + // CMD17: READ_SINGLE_BLOCK + 17, + // CMD18: READ_MULTIPLE + 18: begin + reply[39:32] <= 0; + read_state <= RD_STATE_START; + spi_buf <= 0; + sd_buf <= 0; + sd_lba <= csd_sdhc ? arg : {9'd0, arg[31:9]}; + end + + // ACMD23: SET_WR_BLK_ERASE_COUNT + 23: reply[39:32] <= 0; + + // CMD24: WRITE_BLOCK + 24, + // CMD25: WRITE_MULTIPLE + 25: begin + reply[39:32] <= 0; + write_state <= WR_STATE_EXP_DTOKEN; // expect data token + spi_buf <= 0; + sd_buf <= 0; + sd_lba <= csd_sdhc ? arg : {9'd0, arg[31:9]}; + end + + // ACMD41: APP_SEND_OP_COND + 41: if(cmd55) reply[39:32] <= 0; // ok, not busy + + // CMD55: APP_COND + 55: reply[39:32] <= 1; // ok, busy + + // CMD58: READ_OCR + 58: reply <= { 8'h00, 1'b1, csd_sdhc, 30'd0 }; // bit 30 = 1 -> high capacity card + + // CMD59: CRC_ON_OFF + 59: reply[39:32] <= 0; + endcase + end + + // ---------- handle write ----------- + case(write_state) + // do nothing in idle state + WR_STATE_IDLE: ; + + // waiting for data token + WR_STATE_EXP_DTOKEN: begin + buffer_ptr <= 0; + if(cmd == 24) begin + if(ibuf == DATA_TOKEN) write_state <= WR_STATE_RECV_DATA; end else begin - write_state <= WR_STATE_IDLE; - rx_finish <= 1; + if(ibuf == DATA_TOKEN_CMD25) write_state <= WR_STATE_RECV_DATA; + if(ibuf == STOP_TRAN) write_state <= WR_STATE_IDLE; end end - endcase - end - - // wait for first 0 bit until start counting bits - if(!synced && !mosi) begin - synced <= 1; - bit_cnt <= 1; // byte assembly prepare for next time loop - sbuf <= 7'b1111110; // byte assembly prepare for next time loop - rx_finish<= 0; - end else if (synced && tx_finish && rx_finish ) begin - synced <= 0; - bit_cnt <= 0; - rx_finish<= 0; + + // transfer 512 bytes + WR_STATE_RECV_DATA: begin + // push one byte into local buffer + buffer_wr <= 1; + buffer_din <= ibuf; + + // all bytes written? + if(&buffer_ptr) write_state <= WR_STATE_RECV_CRC0; + end + + // transfer 1st crc byte + WR_STATE_RECV_CRC0: + write_state <= WR_STATE_RECV_CRC1; + + // transfer 2nd crc byte + WR_STATE_RECV_CRC1: + write_state <= WR_STATE_SEND_DRESP; + + // send data response + WR_STATE_SEND_DRESP: + write_state <= WR_STATE_BUSY; + + // wait for io controller to accept data + WR_STATE_BUSY: + if(spi_buf == sd_buf) write_state <= (cmd == 25) ? WR_STATE_EXP_DTOKEN : WR_STATE_IDLE; + endcase + end end end end endmodule - -module sdbuf #(parameter WIDE) -( - input clock_a, - input [AW:0] address_a, - input [DW:0] data_a, - input wren_a, - output reg [DW:0] q_a, - - input clock_b, - input [8:0] address_b, - input [7:0] data_b, - input wren_b, - output reg [7:0] q_b -); - -localparam AW = WIDE ? 7 : 8; -localparam DW = WIDE ? 15 : 7; - -always@(posedge clock_a) begin - if(wren_a) begin - ram[address_a] <= data_a; - q_a <= data_a; - end - else begin - q_a <= ram[address_a]; - end -end - -generate - if(WIDE) begin - reg [1:0][7:0] ram[1<<8]; - always@(posedge clock_b) begin - if(wren_b) begin - ram[address_b[8:1]][address_b[0]] <= data_b; - q_b <= data_b; - end - else begin - q_b <= ram[address_b[8:1]][address_b[0]]; - end - end - end - else begin - reg [7:0] ram[1<<9]; - always@(posedge clock_b) begin - if(wren_b) begin - ram[address_b] <= data_b; - q_b <= data_b; - end - else begin - q_b <= ram[address_b]; - end - end - end -endgenerate - -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 eeae907..094dab7 100644 --- a/sys/sys.qip +++ b/sys/sys.qip @@ -7,10 +7,12 @@ 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 ] set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) video_freak.sv ] +set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) video_freezer.sv ] set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) arcade_video.v ] set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) osd.v ] set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) vga_out.sv ] @@ -29,4 +31,4 @@ set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) f set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) ddr_svc.sv ] set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) sysmem.sv ] set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) sd_card.sv ] -set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) hps_io.v ] +set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) hps_io.sv ] diff --git a/sys/sys_dual_sdram.tcl b/sys/sys_dual_sdram.tcl index bffcdf4..9da6c8e 100644 --- a/sys/sys_dual_sdram.tcl +++ b/sys/sys_dual_sdram.tcl @@ -47,4 +47,4 @@ 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 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 8187969..cf2d492 100644 --- a/sys/sys_top.sdc +++ b/sys/sys_top.sdc @@ -67,3 +67,5 @@ set_false_path -from {ascal|o_hdisp* ascal|o_vdisp*} set_false_path -from {ascal|o_htotal* ascal|o_vtotal*} set_false_path -from {ascal|o_hsstart* ascal|o_vsstart* ascal|o_hsend* ascal|o_vsend*} set_false_path -from {ascal|o_hsize* ascal|o_vsize*} + +set_false_path -from {mcp23009|sd_cd} diff --git a/sys/sys_top.v b/sys/sys_top.v index 8f0043c..635ae56 100644 --- a/sys/sys_top.v +++ b/sys/sys_top.v @@ -19,18 +19,6 @@ // //============================================================================ -`ifndef ARCADE_SYS - `define USE_DDRAM - `define USE_SDRAM -`endif - -`ifndef USE_DDRAM - `ifdef USE_FB - `define USE_DDRAM - `endif -`endif - - module sys_top ( /////////// CLOCK ////////// @@ -68,7 +56,7 @@ module sys_top output SDRAM_CLK, output SDRAM_CKE, -`ifdef DUAL_SDRAM +`ifdef MISTER_DUAL_SDRAM ////////// SDR #2 ////////// output [12:0] SDRAM2_A, inout [15:0] SDRAM2_DQ, @@ -139,20 +127,14 @@ module sys_top ////////////////////// Secondary SD /////////////////////////////////// wire SD_CS, SD_CLK, SD_MOSI; -`ifdef ARCADE_SYS - assign SD_CS = 1'bZ; - assign SD_CLK = 1'bZ; - assign SD_MOSI = 1'bZ; +`ifndef MISTER_DUAL_SDRAM + wire sd_miso = SW[3] | SDIO_DAT[0]; `else - `ifndef DUAL_SDRAM - wire sd_miso = SW[3] | SDIO_DAT[0]; - `else - wire sd_miso = 1; - `endif - wire SD_MISO = mcp_sdcd ? sd_miso : SD_SPI_MISO; + wire sd_miso = 1; `endif +wire SD_MISO = mcp_sdcd ? sd_miso : SD_SPI_MISO; -`ifndef DUAL_SDRAM +`ifndef MISTER_DUAL_SDRAM assign SDIO_DAT[2:1]= 2'bZZ; assign SDIO_DAT[3] = SW[3] ? 1'bZ : SD_CS; assign SDIO_CLK = SW[3] ? 1'bZ : SD_CLK; @@ -175,7 +157,7 @@ wire led_d = led_disk[1] ? ~led_disk[0] : ~(led_disk[0] | gp_out[29]); wire led_u = ~led_user; wire led_locked; -`ifndef DUAL_SDRAM +`ifndef MISTER_DUAL_SDRAM assign LED_POWER = (SW[3] | led_p) ? 1'bZ : 1'b0; assign LED_HDD = (SW[3] | led_d) ? 1'bZ : 1'b0; assign LED_USER = (SW[3] | led_u) ? 1'bZ : 1'b0; @@ -185,7 +167,7 @@ wire led_locked; assign LED = (led_overtake & led_state) | (~led_overtake & {1'b0,led_locked,1'b0, ~led_p, 1'b0, ~led_d, 1'b0, ~led_u}); wire btn_r, btn_o, btn_u; -`ifdef DUAL_SDRAM +`ifdef MISTER_DUAL_SDRAM assign {btn_r,btn_o,btn_u} = {mcp_btn[1],mcp_btn[2],mcp_btn[0]}; `else assign {btn_r,btn_o,btn_u} = ~{BTN_RESET,BTN_OSD,BTN_USER} | {mcp_btn[1],mcp_btn[2],mcp_btn[0]}; @@ -233,7 +215,7 @@ end 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_out; -wire [1:0] io_ver = 1; // 0 - standard MiST I/O (for quick porting of complex MiST cores). 1 - optimized HPS I/O. 2,3 - reserved for future. +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; @@ -243,7 +225,7 @@ wire io_ss0 = gp_outr[18]; wire io_ss1 = gp_outr[19]; wire io_ss2 = gp_outr[20]; -`ifndef DEBUG_NOHDMI +`ifndef MISTER_DEBUG_NOHDMI wire io_osd_hdmi = io_ss1 & ~io_ss0; `endif @@ -268,7 +250,7 @@ always @(posedge clk_sys) begin gp_outd <= gp_out; end -`ifdef DUAL_SDRAM +`ifdef MISTER_DUAL_SDRAM wire [7:0] core_type = 'hA8; // generic core, dual SDRAM. `else wire [7:0] core_type = 'hA4; // generic core. @@ -290,7 +272,7 @@ reg cfg_set = 0; wire vga_fb = cfg[12] | vga_force_scaler; wire [1:0] hdmi_limited = {cfg[11],cfg[8]}; -`ifdef DEBUG_NOHDMI +`ifdef MISTER_DEBUG_NOHDMI wire direct_video = 1; `else wire direct_video = cfg[10]; @@ -301,7 +283,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 DUAL_SDRAM +`ifndef MISTER_DUAL_SDRAM wire sog = cfg[9]; wire vga_scaler = cfg[2] | vga_force_scaler; `endif @@ -310,10 +292,11 @@ reg cfg_custom_t = 0; reg [5:0] cfg_custom_p1; reg [31:0] cfg_custom_p2; -reg [4:0] vol_att = 0; +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; @@ -353,6 +336,10 @@ always@(posedge clk_sys) begin old_strobe <= io_strobe; coef_wr <= 0; +`ifndef MISTER_DEBUG_NOHDMI + shadowmask_wr <= 0; +`endif + if(~io_uio) begin has_cmd <= 0; cmd <= 0; @@ -380,6 +367,7 @@ always@(posedge clk_sys) begin end end else begin + cnt <= cnt + 1'd1; if(cmd == 1) begin cfg <= io_din; cfg_set <= 1; @@ -387,19 +375,18 @@ 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: WIDTH <= 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 DEBUG_NOHDMI +`ifndef MISTER_DEBUG_NOHDMI if(cnt == 1) begin cfg_custom_p1 <= 0; cfg_custom_p2 <= 0; @@ -419,7 +406,6 @@ always@(posedge clk_sys) begin 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]; @@ -436,12 +422,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; @@ -461,7 +449,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]; @@ -469,6 +456,9 @@ 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}; +`endif end end @@ -481,9 +471,7 @@ end cyclonev_hps_interface_peripheral_uart uart ( - .ri(0) -`ifndef ARCADE_SYS - , + .ri(0), .dsr(uart_dsr), .dcd(uart_dsr), .dtr(uart_dtr), @@ -492,7 +480,6 @@ cyclonev_hps_interface_peripheral_uart uart .rts(uart_rts), .rxd(uart_rxd), .txd(uart_txd) -`endif ); wire aspi_sck,aspi_mosi,aspi_ss,aspi_miso; @@ -547,7 +534,6 @@ sysmem_lite sysmem //DE10-nano has no reset signal on GPIO, so core has to emulate cold reset button. .reset_hps_cold_req(btn_r), -`ifdef USE_DDRAM //64-bit DDR3 RAM access .ram1_clk(ram_clk), .ram1_address(ram_address), @@ -559,7 +545,6 @@ sysmem_lite sysmem .ram1_writedata(ram_writedata), .ram1_byteenable(ram_byteenable), .ram1_write(ram_write), -`endif //64-bit DDR3 RAM access .ram2_clk(clk_audio), @@ -640,17 +625,29 @@ 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 DEBUG_NOHDMI +`ifndef MISTER_DEBUG_NOHDMI wire clk_hdmi = hdmi_clk_out; ascal #( .RAMBASE(32'h20000000), -`ifndef USE_FB +`ifndef MISTER_FB .PALETTE2("false"), +`else + `ifndef MISTER_FB_PALETTE + .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) ) @@ -658,7 +655,7 @@ ascal ( .reset_na (~reset_req), .run (1), - .freeze (0), + .freeze (freeze), .i_clk (clk_ihdmi), .i_ce (ce_hpix), @@ -684,16 +681,17 @@ 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), @@ -709,13 +707,15 @@ ascal .pal1_a (pal_a), .pal1_wr (pal_wr), -`ifdef USE_FB - .pal2_clk (fb_pal_clk), - .pal2_dw (fb_pal_d), - .pal2_dr (fb_pal_q), - .pal2_a (fb_pal_a), - .pal2_wr (fb_pal_wr), - .pal_n (fb_en), +`ifdef MISTER_FB + `ifdef MISTER_FB_PALETTE + .pal2_clk (fb_pal_clk), + .pal2_dw (fb_pal_d), + .pal2_dr (fb_pal_q), + .pal2_a (fb_pal_a), + .pal2_wr (fb_pal_wr), + .pal_n (fb_en), + `endif `endif .o_fb_ena (FB_EN), @@ -775,7 +775,7 @@ always @(posedge clk_sys) begin end end -`ifdef USE_FB +`ifdef MISTER_FB reg fb_vbl; always @(posedge clk_vid) fb_vbl <= hdmi_vbl; `endif @@ -899,7 +899,7 @@ always @(posedge clk_vid) begin vmax <= vmaxi; end -`ifndef DEBUG_NOHDMI +`ifndef MISTER_DEBUG_NOHDMI wire [15:0] lltune; pll_hdmi_adj pll_hdmi_adj ( @@ -942,7 +942,7 @@ end ///////////////////////// HDMI output ///////////////////////////////// -`ifndef DEBUG_NOHDMI +`ifndef MISTER_DEBUG_NOHDMI wire hdmi_clk_out; pll_hdmi pll_hdmi ( @@ -957,11 +957,11 @@ pll_hdmi pll_hdmi //1920x1080@60 PCLK=148.5MHz CEA reg [11:0] WIDTH = 1920; reg [11:0] HFP = 88; -reg [11:0] HS = 48; +reg [12:0] HS = 48; reg [11:0] HBP = 148; reg [11:0] HEIGHT = 1080; reg [11:0] VFP = 4; -reg [11:0] VS = 5; +reg [12:0] VS = 5; reg [11:0] VBP = 36; wire [63:0] reconfig_to_pll; @@ -974,7 +974,7 @@ reg adj_write; reg [5:0] adj_address; reg [31:0] adj_data; -`ifndef DEBUG_NOHDMI +`ifndef MISTER_DEBUG_NOHDMI pll_cfg pll_cfg ( .mgmt_clk(FPGA_CLK1_50), @@ -1063,35 +1063,44 @@ cyclonev_hps_interface_peripheral_i2c hdmi_i2c .sda(HDMI_I2C_SDA) ); -`ifndef DEBUG_NOHDMI -wire [23:0] hdmi_data_sl; -wire hdmi_de_sl, hdmi_vs_sl, hdmi_hs_sl; +`ifndef MISTER_DEBUG_NOHDMI -`ifdef USE_FB +`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; @@ -1106,19 +1115,15 @@ 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), .vs_out(hdmi_vs_osd), .de_out(hdmi_de_osd) -`ifndef ARCADE_SYS - , - .osd_status(osd_status) -`endif ); `endif @@ -1167,7 +1172,7 @@ always @(posedge clk_vid) begin end wire hdmi_tx_clk; -`ifndef DEBUG_NOHDMI +`ifndef MISTER_DEBUG_NOHDMI cyclonev_clkselect hdmi_clk_sw ( .clkselect({1'b1, ~vga_fb & direct_video}), @@ -1209,13 +1214,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; @@ -1231,7 +1244,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), @@ -1241,11 +1254,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; @@ -1257,6 +1272,7 @@ osd vga_osd .io_osd(io_osd_vga), .io_strobe(io_strobe), .io_din(io_din), + .osd_status(osd_status), .clk_video(clk_vid), .din(vga_data_sl), @@ -1272,7 +1288,7 @@ osd vga_osd wire vga_cs_osd; csync csync_vga(clk_vid, vga_hs_osd, vga_vs_osd, vga_cs_osd); -`ifndef DUAL_SDRAM +`ifndef MISTER_DUAL_SDRAM wire [23:0] vgas_o; wire vgas_hs, vgas_vs, vgas_cs; vga_out vga_scaler_out @@ -1307,11 +1323,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 : ~vga_vs) | csync_en) ^ VS[12]); + 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)) ^ HS[12]); + assign VGA_R = (VGA_EN | SW[3]) ? 6'bZZZZZZ : (vga_fb | vga_scaler) ? vgas_o[23:18] : vga_o[23:18]; + assign VGA_G = (VGA_EN | SW[3]) ? 6'bZZZZZZ : (vga_fb | vga_scaler) ? vgas_o[15:10] : vga_o[15:10]; + assign VGA_B = (VGA_EN | SW[3]) ? 6'bZZZZZZ : (vga_fb | vga_scaler) ? vgas_o[7:2] : vga_o[7:2] ; `endif reg video_sync = 0; @@ -1343,7 +1359,7 @@ end assign SDCD_SPDIF =(SW[3] & ~spdif) ? 1'b0 : 1'bZ; -`ifndef DUAL_SDRAM +`ifndef MISTER_DUAL_SDRAM wire analog_l, analog_r; assign AUDIO_SPDIF = SW[3] ? 1'bZ : SW[0] ? HDMI_LRCLK : spdif; @@ -1390,7 +1406,7 @@ audio_out audio_out .i2s_bclk(HDMI_SCLK), .i2s_lrclk(HDMI_LRCLK), .i2s_data(HDMI_I2S), -`ifndef DUAL_SDRAM +`ifndef MISTER_DUAL_SDRAM .dac_l(analog_l), .dac_r(analog_r), `endif @@ -1457,18 +1473,16 @@ wire hvs_fix, hhs_fix, hde_emu; wire clk_vid, ce_pix, clk_ihdmi, ce_hpix; wire vga_force_scaler; -`ifdef USE_DDRAM - wire ram_clk; - wire [28:0] ram_address; - wire [7:0] ram_burstcount; - wire ram_waitrequest; - wire [63:0] ram_readdata; - wire ram_readdatavalid; - wire ram_read; - wire [63:0] ram_writedata; - wire [7:0] ram_byteenable; - wire ram_write; -`endif +wire ram_clk; +wire [28:0] ram_address; +wire [7:0] ram_burstcount; +wire ram_waitrequest; +wire [63:0] ram_readdata; +wire ram_readdatavalid; +wire ram_read; +wire [63:0] ram_writedata; +wire [7:0] ram_byteenable; +wire ram_write; wire led_user; wire [1:0] led_power; @@ -1480,32 +1494,23 @@ sync_fix sync_h(clk_vid, hs_emu, hs_fix); wire [6:0] user_out, user_in; -`ifndef USE_SDRAM -assign {SDRAM_DQ, SDRAM_A, SDRAM_BA, SDRAM_CLK, SDRAM_CKE, SDRAM_DQML, SDRAM_DQMH, SDRAM_nWE, SDRAM_nCAS, SDRAM_nRAS, SDRAM_nCS} = {39'bZ}; -`endif - 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; -`ifdef ARCADE_SYS - assign audio_mix = 0; - assign {ADC_SCK, ADC_SDI, ADC_CONVST} = 0; - assign btn = 0; -`else - wire uart_dtr; - wire uart_dsr; - wire uart_cts; - wire uart_rts; - wire uart_rxd; - wire uart_txd; - wire osd_status; -`endif +wire uart_dtr; +wire uart_dsr; +wire uart_cts; +wire uart_rts; +wire uart_rxd; +wire uart_txd; + +wire osd_status; wire fb_en; wire [4:0] fb_fmt; @@ -1514,13 +1519,16 @@ wire [11:0] fb_height; wire [31:0] fb_base; wire [13:0] fb_stride; -`ifdef USE_FB - wire fb_pal_clk; - wire [7:0] fb_pal_a; - wire [23:0] fb_pal_d; - wire [23:0] fb_pal_q; - wire fb_pal_wr; - wire fb_force_blank; + +`ifdef MISTER_FB + `ifdef MISTER_FB_PALETTE + wire fb_pal_clk; + wire [7:0] fb_pal_a; + wire [23:0] fb_pal_d; + wire [23:0] fb_pal_q; + wire fb_pal_wr; + `endif + wire fb_force_blank; `else assign fb_en = 0; assign fb_fmt = 0; @@ -1530,11 +1538,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}), @@ -1550,6 +1562,7 @@ emu emu .HDMI_WIDTH(direct_video ? 12'd0 : hdmi_width), .HDMI_HEIGHT(direct_video ? 12'd0 : hdmi_height), + .HDMI_FREEZE(freeze), .CLK_VIDEO(clk_vid), .CE_PIXEL(ce_pix), @@ -1557,7 +1570,7 @@ emu emu .VIDEO_ARX(ARX), .VIDEO_ARY(ARY), -`ifdef USE_FB +`ifdef MISTER_FB .FB_EN(fb_en), .FB_FORMAT(fb_fmt), .FB_WIDTH(fb_width), @@ -1568,11 +1581,14 @@ emu emu .FB_LL(lowlat), .FB_FORCE_BLANK(fb_force_blank), +`ifdef MISTER_FB_PALETTE .FB_PAL_CLK (fb_pal_clk), .FB_PAL_ADDR(fb_pal_a), .FB_PAL_DOUT(fb_pal_d), .FB_PAL_DIN (fb_pal_q), .FB_PAL_WR (fb_pal_wr), +`endif + `endif .LED_USER(led_user), @@ -1583,13 +1599,10 @@ emu emu .AUDIO_L(audio_l), .AUDIO_R(audio_r), .AUDIO_S(audio_s), - -`ifndef ARCADE_SYS .AUDIO_MIX(audio_mix), - .ADC_BUS({ADC_SCK,ADC_SDO,ADC_SDI,ADC_CONVST}), -`endif -`ifdef USE_DDRAM + .ADC_BUS({ADC_SCK,ADC_SDO,ADC_SDI,ADC_CONVST}), + .DDRAM_CLK(ram_clk), .DDRAM_ADDR(ram_address), .DDRAM_BURSTCNT(ram_burstcount), @@ -1600,9 +1613,7 @@ emu emu .DDRAM_DIN(ram_writedata), .DDRAM_BE(ram_byteenable), .DDRAM_WE(ram_write), -`endif -`ifdef USE_SDRAM .SDRAM_DQ(SDRAM_DQ), .SDRAM_A(SDRAM_A), .SDRAM_DQML(SDRAM_DQML), @@ -1614,9 +1625,8 @@ emu emu .SDRAM_nCAS(SDRAM_nCAS), .SDRAM_CLK(SDRAM_CLK), .SDRAM_CKE(SDRAM_CKE), -`endif -`ifdef DUAL_SDRAM +`ifdef MISTER_DUAL_SDRAM .SDRAM2_DQ(SDRAM2_DQ), .SDRAM2_A(SDRAM2_A), .SDRAM2_BA(SDRAM2_BA), @@ -1628,14 +1638,14 @@ emu emu .SDRAM2_EN(SW[3]), `endif -`ifndef ARCADE_SYS .BUTTONS(btn), .OSD_STATUS(osd_status), + .SD_SCK(SD_CLK), .SD_MOSI(SD_MOSI), .SD_MISO(SD_MISO), .SD_CS(SD_CS), -`ifdef DUAL_SDRAM +`ifdef MISTER_DUAL_SDRAM .SD_CD(mcp_sdcd), `else .SD_CD(mcp_sdcd & (SW[0] ? VGA_HS : (SW[3] | SDCD_SPDIF))), @@ -1647,7 +1657,6 @@ emu emu .UART_TXD(uart_rxd), .UART_DTR(uart_dsr), .UART_DSR(uart_dtr), -`endif .USER_OUT(user_out), .USER_IN(user_in) diff --git a/sys/vga_out.sv b/sys/vga_out.sv index 43927b2..fe8172b 100644 --- a/sys/vga_out.sv +++ b/sys/vga_out.sv @@ -25,27 +25,44 @@ wire [5:0] blue = din[7:2]; // Pb = 128 - 0.148*R - 0.291*G + 0.439*B (Pb = -0.169*R - 0.331*G + 0.500*B) // Pr = 128 + 0.439*R - 0.368*G - 0.071*B (Pr = 0.500*R - 0.419*G - 0.081*B) -reg [18:0] y_2, pb_2, pr_2; reg [7:0] y, pb, pr; -reg [23:0] din2, din3; -reg hsync2, vsync2, csync2; +reg [23:0] rgb; always @(posedge clk) begin - y_2 <= 19'd04096 + ({red, 8'd0} + {red, 3'd0}) + ({green, 9'd0} + {green, 2'd0}) + ({blue, 6'd0} + {blue, 5'd0} + {blue, 2'd0}); - pb_2 <= 19'd32768 - ({red, 7'd0} + {red, 4'd0} + {red, 3'd0}) - ({green, 8'd0} + {green, 5'd0} + {green, 3'd0}) + ({blue, 8'd0} + {blue, 7'd0} + {blue, 6'd0}); - pr_2 <= 19'd32768 + ({red, 8'd0} + {red, 7'd0} + {red, 6'd0}) - ({green, 8'd0} + {green, 6'd0} + {green, 5'd0} + {green, 4'd0} + {green, 3'd0}) - ({blue, 6'd0} + {blue , 3'd0}); + reg [18:0] y_1r, pb_1r, pr_1r; + reg [18:0] y_1g, pb_1g, pr_1g; + reg [18:0] y_1b, pb_1b, pr_1b; + reg [18:0] y_2, pb_2, pr_2; + reg [23:0] din1, din2; + reg hsync2, vsync2, csync2; + reg hsync1, vsync1, csync1; + + y_1r <= 19'd04096 + ({red, 8'd0} + {red, 3'd0}); + pb_1r <= 19'd32768 - ({red, 7'd0} + {red, 4'd0} + {red, 3'd0}); + pr_1r <= 19'd32768 + ({red, 8'd0} + {red, 7'd0} + {red, 6'd0}); + + y_1g <= {green, 9'd0} + {green, 2'd0}; + pb_1g <= {green, 8'd0} + {green, 5'd0} + {green, 3'd0}; + pr_1g <= {green, 8'd0} + {green, 6'd0} + {green, 5'd0} + {green, 4'd0} + {green, 3'd0}; + + y_1b <= {blue, 6'd0} + {blue, 5'd0} + {blue, 2'd0}; + pb_1b <= {blue, 8'd0} + {blue, 7'd0} + {blue, 6'd0}; + pr_1b <= {blue, 6'd0} + {blue, 3'd0}; + + y_2 <= y_1r + y_1g + y_1b; + pb_2 <= pb_1r - pb_1g + pb_1b; + pr_2 <= pr_1r - pr_1g - pr_1b; y <= ( y_2[18] || !y_2[17:12]) ? 8'd16 : (y_2[17:8] > 235) ? 8'd235 : y_2[15:8]; pb <= (pb_2[18] || !pb_2[17:12]) ? 8'd16 : (&pb_2[17:12]) ? 8'd240 : pb_2[15:8]; pr <= (pr_2[18] || !pr_2[17:12]) ? 8'd16 : (&pr_2[17:12]) ? 8'd240 : pr_2[15:8]; - hsync_o <= hsync2; hsync2 <= hsync; - vsync_o <= vsync2; vsync2 <= vsync; - csync_o <= csync2; csync2 <= csync; + hsync_o <= hsync2; hsync2 <= hsync1; hsync1 <= hsync; + vsync_o <= vsync2; vsync2 <= vsync1; vsync1 <= vsync; + csync_o <= csync2; csync2 <= csync1; csync1 <= csync; - din2 <= din; - din3 <= din2; + rgb <= din2; din2 <= din1; din1 <= din; end -assign dout = ypbpr_en ? {pr, y, pb} : din3; +assign dout = ypbpr_en ? {pr, y, pb} : rgb; endmodule diff --git a/sys/video_freezer.sv b/sys/video_freezer.sv new file mode 100644 index 0000000..24d2c65 --- /dev/null +++ b/sys/video_freezer.sv @@ -0,0 +1,143 @@ +// +// video freeze with sync +// (C) Alexey Melnikov +// +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 of the License, or (at your option) +// any later version. +// +// This program is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +// more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + +module video_freezer +( + input clk, + + output sync, + input freeze, + + input hs_in, + input vs_in, + input hbl_in, + input vbl_in, + + output hs_out, + output vs_out, + output hbl_out, + output vbl_out +); + +sync_lock #(33) vs_lock +( + .clk(clk), + .sync_in(vs_in), + .sync_out(vs_out), + .de_in(vbl_in), + .de_out(vbl_out), + .freeze(freeze) +); + +wire sync_pt; +sync_lock #(21) hs_lock +( + .clk(clk), + .sync_in(hs_in), + .sync_out(hs_out), + .de_in(hbl_in), + .de_out(hbl_out), + .freeze(freeze), + .sync_pt(sync_pt) +); + +reg sync_o; +always @(posedge clk) begin + reg old_hs, old_vs; + reg vs_sync; + + old_vs <= vs_out; + + if(~old_vs & vs_out) vs_sync <= 1; + if(sync_pt & vs_sync) begin + vs_sync <= 0; + sync_o <= ~sync_o; + end +end + +assign sync = sync_o; + +endmodule + + +module sync_lock #(parameter WIDTH) +( + input clk, + + input sync_in, + input de_in, + + output sync_out, + output de_out, + + input freeze, + output sync_pt, + output valid +); + +reg [WIDTH-1:0] f_len, s_len, de_start, de_end; +reg sync_valid; + +reg old_sync; +always @(posedge clk) old_sync <= sync_in; + +always @(posedge clk) begin + reg [WIDTH-1:0] cnti; + reg f_valid; + reg old_de; + + cnti <= cnti + 1'd1; + if(~old_sync & sync_in) begin + if(sync_valid) f_len <= cnti; + f_valid <= 1; + sync_valid <= f_valid; + cnti <= 0; + end + + if(old_sync & ~sync_in & sync_valid) s_len <= cnti; + + old_de <= de_in; + if(~old_de & de_in & sync_valid) de_start <= cnti; + if(old_de & ~de_in & sync_valid) de_end <= cnti; + + if(freeze) {f_valid, sync_valid} <= 0; +end + +reg sync_o, de_o, sync_o_pre; +always @(posedge clk) begin + reg [WIDTH-1:0] cnto; + + cnto <= cnto + 1'd1; + if(old_sync & ~sync_in & sync_valid) cnto <= s_len + 2'd2; + if(cnto == f_len) cnto <= 0; + + sync_o_pre <= (cnto == (s_len>>1)); // middle in sync + if(cnto == f_len) sync_o <= 1; + if(cnto == s_len) sync_o <= 0; + if(cnto == de_start) de_o <= 1; + if(cnto == de_end) de_o <= 0; +end + +assign sync_out = freeze ? sync_o : sync_in; +assign valid = sync_valid; +assign sync_pt = sync_o_pre; +assign de_out = freeze ? de_o : de_in; + +endmodule diff --git a/sys/video_mixer.sv b/sys/video_mixer.sv index 93b106e..e53e1c0 100644 --- a/sys/video_mixer.sv +++ b/sys/video_mixer.sv @@ -10,10 +10,7 @@ `timescale 1ns / 1ps // -// LINE_LENGTH: Length of display line in pixels -// Usually it's length from HSync to HSync. -// May be less if line_start is used. -// +// LINE_LENGTH: Length of display line in pixels when HBlank = 0; // HALF_DEPTH: If =1 then color dept is 4 bits per component // // altera message_off 10720 @@ -47,6 +44,12 @@ module video_mixer input HBlank, input VBlank, + // Freeze engine + // HDMI: displays last frame + // VGA: black screen with HSync and VSync + input HDMI_FREEZE, + output freeze_sync, + // video output signals output reg [7:0] VGA_R, output reg [7:0] VGA_G, @@ -60,19 +63,43 @@ localparam DWIDTH = HALF_DEPTH ? 3 : 7; localparam DWIDTH_SD = GAMMA ? 7 : DWIDTH; localparam HALF_DEPTH_SD = GAMMA ? 0 : HALF_DEPTH; +wire frz_hs, frz_vs; +wire frz_hbl, frz_vbl; +video_freezer freezer +( + .clk(CLK_VIDEO), + .freeze(HDMI_FREEZE), + .hs_in(HSync), + .vs_in(VSync), + .hbl_in(HBlank), + .vbl_in(VBlank), + .sync(freeze_sync), + .hs_out(frz_hs), + .vs_out(frz_vs), + .hbl_out(frz_hbl), + .vbl_out(frz_vbl) +); + +reg frz; +always @(posedge CLK_VIDEO) begin + reg frz1; + + frz1 <= HDMI_FREEZE; + frz <= frz1; +end + generate if(GAMMA && HALF_DEPTH) begin - wire [7:0] R_in = {R,R}; - wire [7:0] G_in = {G,G}; - wire [7:0] B_in = {B,B}; + wire [7:0] R_in = frz ? 8'd0 : {R,R}; + wire [7:0] G_in = frz ? 8'd0 : {G,G}; + wire [7:0] B_in = frz ? 8'd0 : {B,B}; end else begin - wire [DWIDTH:0] R_in = R; - wire [DWIDTH:0] G_in = G; - wire [DWIDTH:0] B_in = B; + wire [DWIDTH:0] R_in = frz ? 1'd0 : R; + wire [DWIDTH:0] G_in = frz ? 1'd0 : G; + wire [DWIDTH:0] B_in = frz ? 1'd0 : B; end endgenerate - wire hs_g, vs_g; wire hb_g, vb_g; wire [DWIDTH_SD:0] R_gamma, G_gamma, B_gamma; @@ -90,10 +117,10 @@ generate .gamma_wr_addr(gamma_bus[17:8]), .gamma_value(gamma_bus[7:0]), - .HSync(HSync), - .VSync(VSync), - .HBlank(HBlank), - .VBlank(VBlank), + .HSync(frz_hs), + .VSync(frz_vs), + .HBlank(frz_hbl), + .VBlank(frz_vbl), .RGB_in({R_in,G_in,B_in}), .HSync_out(hs_g), @@ -105,7 +132,7 @@ generate end else begin assign gamma_bus[21] = 0; assign {R_gamma,G_gamma,B_gamma} = {R_in,G_in,B_in}; - assign {hs_g, vs_g, hb_g, vb_g} = {HSync, VSync, HBlank, VBlank}; + assign {hs_g, vs_g, hb_g, vb_g} = {frz_hs, frz_vs, frz_hbl, frz_vbl}; end endgenerate