diff --git a/sys/ascal.vhd b/sys/ascal.vhd index 6d74c74..30d6287 100644 --- a/sys/ascal.vhd +++ b/sys/ascal.vhd @@ -1,14 +1,14 @@ -------------------------------------------------------------------------------- -- AVALON SCALER -------------------------------------------------------------------------------- --- TEMLIB 10/2018 +-- TEMLIB 2018 - 2020 -------------------------------------------------------------------------------- -- This code can be freely distributed and used for any purpose, but, if you -- find any bug, or want to suggest an enhancement, you ought to send a mail -- to info@temlib.org. -------------------------------------------------------------------------------- --- Features : +-- Features -- - Arbitrary output video format -- - Autodetect input image size or fixed window -- - Progressive and interlaced input @@ -30,7 +30,7 @@ -- below 1x) them. -------------------------------------------- --- 5 clock domains : +-- 5 clock domains -- i_xxx : Input video -- o_xxx : Output video -- avl_xxx : Avalon memory bus @@ -54,10 +54,10 @@ -- 1 : Pixel format -- 0 : 16 bits/pixel, RGB : RRRRRGGGGGGBBBBB -- 1 : 24 bits/pixel, RGB --- 2 : 32 bits/pixels RGB0 +-- 2 : 32 bits/pixel, RGB0 -- 3:2 : Header size : Offset to start of picture (= N_BURST). 12 bits --- 5:4 : Attributes. TBD +-- 5:4 : Attributes -- b0 ; Interlaced -- b1 : Field number -- b2 : Horizontal downscaled @@ -83,7 +83,7 @@ USE ieee.numeric_std.ALL; -- 100 : Polyphase -- 101 : TBD -- 110 : TBD --- 111 : TEST +-- 111 : TBD -- MODE[3] -- 0 : Direct. Single framebuffer. @@ -98,7 +98,8 @@ USE ieee.numeric_std.ALL; -- Must be a power of two -- INTER : True=Autodetect interlaced video False=Force progressive scan -- HEADER : True=Add image properties header --- PALETTE : Enable palette for framebuffer -8bpp mode +-- PALETTE : Enable palette for framebuffer 8bpp mode +-- PALETTE2 : Enable palette for framebuffer 8bpp mode supplied by core -- DOWNSCALE : True=Support downscaling False=Downscaling disabled -- BYTESWAP : Little/Big endian byte swap -- FRAC : Fractional bits, subpixel resolution @@ -120,6 +121,7 @@ ENTITY ascal IS 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; @@ -148,9 +150,9 @@ ENTITY ascal IS o_hs : OUT std_logic; -- H sync o_vs : OUT std_logic; -- V sync o_de : OUT std_logic; -- Display Enable - o_vbl : OUT std_logic; -- V blank + o_vbl : OUT std_logic; -- V blank o_ce : IN std_logic; -- Clock Enable - o_clk : IN std_logic; -- Output clock + o_clk : IN std_logic; -- Output clock -- Border colour R G B o_border : IN unsigned(23 DOWNTO 0) := x"000000"; @@ -162,14 +164,22 @@ ENTITY ascal IS o_fb_vsize : IN natural RANGE 0 TO 4095 :=0; o_fb_format : IN unsigned(5 DOWNTO 0) :="000100"; o_fb_base : IN unsigned(31 DOWNTO 0) :=x"0000_0000"; - o_fb_stride : IN unsigned(13 DOWNTO 0) :=(OTHERS =>'0'); -- must be multiple of data bus width in bytes (8 or 16) - + o_fb_stride : IN unsigned(13 DOWNTO 0) :=(OTHERS =>'0'); + -- Framebuffer palette in 8bpp mode - pal_clk : IN std_logic :='0'; - pal_dw : IN unsigned(47 DOWNTO 0) :=x"000000000000"; -- R1 G1 B1 R0 G0 B0 - pal_dr : OUT unsigned(47 DOWNTO 0) :=x"000000000000"; - pal_a : IN unsigned(6 DOWNTO 0) :="0000000"; -- Colour index/2 - pal_wr : IN std_logic :='0'; + pal1_clk : IN std_logic :='0'; + pal1_dw : IN unsigned(47 DOWNTO 0) :=x"000000000000"; -- R1 G1 B1 R0 G0 B0 + pal1_dr : OUT unsigned(47 DOWNTO 0) :=x"000000000000"; + pal1_a : IN unsigned(6 DOWNTO 0) :="0000000"; -- Colour index/2 + pal1_wr : IN std_logic :='0'; + + pal_n : IN std_logic :='0'; + + pal2_clk : IN std_logic :='0'; + pal2_dw : IN unsigned(23 DOWNTO 0) :=x"000000"; -- R G B + pal2_dr : OUT unsigned(23 DOWNTO 0) :=x"000000"; + pal2_a : IN unsigned(7 DOWNTO 0) :="00000000"; -- Colour index + pal2_wr : IN std_logic :='0'; ------------------------------------ -- Low lag PLL tuning @@ -177,11 +187,15 @@ ENTITY ascal IS ------------------------------------ -- Input video parameters - iauto : IN std_logic; -- 1=Autodetect image size 0=Choose window - himin : IN natural RANGE 0 TO 4095; -- MIN < MAX, MIN >=0, MAX < DISP - himax : IN natural RANGE 0 TO 4095; - vimin : IN natural RANGE 0 TO 4095; - vimax : IN natural RANGE 0 TO 4095; + iauto : IN std_logic :='1'; -- 1=Autodetect image size 0=Choose window + himin : IN natural RANGE 0 TO 4095 :=0; -- MIN < MAX, MIN >=0, MAX < DISP + himax : IN natural RANGE 0 TO 4095 :=0; + vimin : IN natural RANGE 0 TO 4095 :=0; + vimax : IN natural RANGE 0 TO 4095 :=0; + + -- Detected input image size + i_hdmax : OUT natural RANGE 0 TO 4095; + i_vdmax : OUT natural RANGE 0 TO 4095; -- Output video parameters run : IN std_logic :='1'; -- 1=Enable output image. 0=No image @@ -189,7 +203,7 @@ ENTITY ascal IS mode : IN unsigned(4 DOWNTO 0); -- SYNC |_________________________/"""""""""\_______| -- DE |""""""""""""""""""\________________________| - -- RGB | <#IMAGE#> ^HDISP | + -- RGB | <#IMAGE#> ^HDISP | -- ^HMIN ^HMAX ^HSSTART ^HSEND ^HTOTAL htotal : IN natural RANGE 0 TO 4095; hsstart : IN natural RANGE 0 TO 4095; @@ -205,7 +219,7 @@ ENTITY ascal IS vmax : IN natural RANGE 0 TO 4095; -- 0 <= vmin < vmax < vdisp -- Scaler format. 00=16bpp 565, 01=24bpp 10=32bpp - format : IN unsigned(1 DOWNTO 0) :="01"; + format : IN unsigned(1 DOWNTO 0) :="01"; ------------------------------------ -- Polyphase filter coefficients @@ -286,6 +300,7 @@ ARCHITECTURE rtl OF ascal IS SUBTYPE uint13 IS natural RANGE 0 TO 8191; TYPE arr_uv48 IS ARRAY (natural RANGE <>) OF unsigned(47 DOWNTO 0); + TYPE arr_uv24 IS ARRAY (natural RANGE <>) OF unsigned(23 DOWNTO 0); TYPE arr_uv36 IS ARRAY (natural RANGE <>) OF unsigned(35 DOWNTO 0); TYPE arr_int9 IS ARRAY (natural RANGE <>) OF integer RANGE -256 TO 255; TYPE arr_uint12 IS ARRAY (natural RANGE <>) OF uint12; @@ -388,11 +403,14 @@ ARCHITECTURE rtl OF ascal IS SIGNAL o_mode,o_hmode,o_vmode : unsigned(4 DOWNTO 0); SIGNAL o_format : unsigned(5 DOWNTO 0); SIGNAL o_fb_pal_dr : unsigned(23 DOWNTO 0); + SIGNAL o_fb_pal_dr2 : unsigned(23 DOWNTO 0); SIGNAL o_fb_pal_dr_x2 : unsigned(47 DOWNTO 0); SIGNAL pal_idx: unsigned(7 DOWNTO 0); SIGNAL pal_idx_lsb: std_logic; - SIGNAL pal_mem : arr_uv48(0 TO 127); - ATTRIBUTE ramstyle of pal_mem : signal is "no_rw_check"; + SIGNAL pal1_mem : arr_uv48(0 TO 127); + SIGNAL pal2_mem : arr_uv24(0 TO 255); + ATTRIBUTE ramstyle of pal1_mem : signal is "no_rw_check"; + ATTRIBUTE ramstyle of pal2_mem : signal is "no_rw_check"; SIGNAL o_htotal,o_hsstart,o_hsend : uint12; SIGNAL o_hmin,o_hmax,o_hdisp : uint12; SIGNAL o_hsize,o_vsize : uint12; @@ -402,15 +420,18 @@ ARCHITECTURE rtl OF ascal IS SIGNAL o_iendframe0,o_iendframe02,o_iendframe1,o_iendframe12 : std_logic; SIGNAL o_bufup0,o_bufup1,o_inter : std_logic; SIGNAL o_ibuf0,o_ibuf1,o_obuf0,o_obuf1 : natural RANGE 0 TO 2; - TYPE type_o_state IS (sDISP,sHSYNC,sREAD,sWAITREAD); - SIGNAL o_state : type_o_state; - SIGNAL o_copy,o_readack,o_readack_sync,o_readack_sync2 : std_logic; + TYPE enum_o_state IS (sDISP,sHSYNC,sREAD,sWAITREAD); + SIGNAL o_state : enum_o_state; + TYPE enum_o_copy IS (sWAIT,sSHIFT,sCOPY); + SIGNAL o_copy : enum_o_copy; + SIGNAL o_pshift : natural RANGE 0 TO 15; + SIGNAL o_readack,o_readack_sync,o_readack_sync2 : std_logic; SIGNAL o_readdataack,o_readdataack_sync,o_readdataack_sync2 : std_logic; SIGNAL o_copyv : unsigned(0 TO 8); SIGNAL o_adrs : unsigned(31 DOWNTO 0); -- Avalon address - SIGNAL o_adrs_pre : natural RANGE 0 TO 8388607; - SIGNAL o_stride : unsigned(13 DOWNTO 0); - SIGNAL o_adrsa,o_rline : std_logic; + SIGNAL o_adrs_pre : natural RANGE 0 TO 2**23-1; + SIGNAL o_stride : unsigned(13 DOWNTO 0); + SIGNAL o_adrsa,o_adrsb,o_rline : std_logic; SIGNAL o_ad,o_ad1,o_ad2,o_ad3 : natural RANGE 0 TO 2*BLEN-1; SIGNAL o_adturn : std_logic; SIGNAL o_dr : unsigned(N_DW-1 DOWNTO 0); @@ -428,7 +449,7 @@ ARCHITECTURE rtl OF ascal IS 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_ivsize : 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); @@ -446,6 +467,8 @@ ARCHITECTURE rtl OF ascal IS SIGNAL o_alt,o_altx : unsigned(3 DOWNTO 0); SIGNAL o_hdown,o_vdown : std_logic; SIGNAL o_primv,o_lastv,o_bibv : unsigned(0 TO 2); + TYPE arr_uint4 IS ARRAY (natural RANGE <>) OF natural RANGE 0 TO 15; + SIGNAL o_off : arr_uint4(0 TO 2); SIGNAL o_bibu : std_logic :='0'; SIGNAL o_dcptv : arr_uint12(1 TO 8); SIGNAL o_dcpt : uint12; @@ -599,7 +622,7 @@ ARCHITECTURE rtl OF ascal IS (N_DW=64 AND ((acpt MOD 2)=0)); END CASE; END FUNCTION; - + FUNCTION shift_opix (shift : unsigned(0 TO N_DW+15); format : unsigned(5 DOWNTO 0)) RETURN type_pix IS BEGIN @@ -621,6 +644,19 @@ ARCHITECTURE rtl OF ascal IS END CASE; END FUNCTION; + FUNCTION pixoffset(adrs : unsigned(31 DOWNTO 0); + format : unsigned (5 DOWNTO 0)) RETURN natural IS + BEGIN + CASE format(2 DOWNTO 0) IS + WHEN "011" => -- 8bbp + RETURN to_integer(adrs(NB_LA-1 DOWNTO 0)); + WHEN "100" => -- 16bpp 565 + RETURN to_integer(adrs(NB_LA-1 DOWNTO 1)); + WHEN OTHERS => -- 32bpp + RETURN to_integer(adrs(NB_LA-1 DOWNTO 2)); + END CASE; + END FUNCTION; + FUNCTION swap(d : unsigned(N_DW-1 DOWNTO 0)) RETURN unsigned IS VARIABLE e : unsigned(N_DW-1 DOWNTO 0); BEGIN @@ -1074,9 +1110,16 @@ BEGIN i_hmin<=himin; -- i_hmax<=himax; -- i_vmin<=vimin; -- - i_vmax<=vimax; -- + IF i_pvs='1' AND i_vs_pre='0' AND (i_inter='0' OR i_pfl='0') THEN + i_vmax<=vimax; -- + END IF; END IF; - + + IF i_pvs='1' AND i_vs_pre='0' AND (i_inter='0' OR i_pfl='0') THEN + i_vdmax<=i_vimax; + END IF; + i_hdmax<=i_himax; + IF i_format="00" OR i_format="11" THEN -- 16bpp i_hburst<=(i_hrsize*2 + N_BURST - 1) / N_BURST; ELSIF i_format="01" THEN -- 24bpp @@ -1452,6 +1495,7 @@ BEGIN ----------------------------------------------------------------------------- -- AVALON interface Avaloir:PROCESS(avl_clk,avl_reset_na) IS + VARIABLE adr_v : unsigned(31 DOWNTO 0); BEGIN IF avl_reset_na='0' THEN avl_state<=sIDLE; @@ -1532,7 +1576,6 @@ BEGIN avl_wadrs(N_AW+NB_LA-1 DOWNTO NB_LA) + avl_i_offset1(N_AW+NB_LA-1 DOWNTO NB_LA)); END IF; - ELSIF avl_read_sr='1' THEN avl_state<=sREAD; avl_read_clr<='1'; @@ -1549,14 +1592,12 @@ BEGIN WHEN sREAD => IF avl_rline='0' THEN - avl_address<=std_logic_vector( - avl_radrs(N_AW+NB_LA-1 DOWNTO NB_LA) + - avl_o_offset0(N_AW+NB_LA-1 DOWNTO NB_LA)); + adr_v:=avl_radrs + avl_o_offset0; ELSE - avl_address<=std_logic_vector( - avl_radrs(N_AW+NB_LA-1 DOWNTO NB_LA) + - avl_o_offset1(N_AW+NB_LA-1 DOWNTO NB_LA)); - END IF; + adr_v:=avl_radrs + avl_o_offset1; + END IF; + avl_address<=std_logic_vector(adr_v(N_AW+NB_LA-1 DOWNTO NB_LA)); + avl_read_i<='1'; IF avl_read_i='1' AND avl_waitrequest='0' THEN avl_state<=sIDLE; @@ -1651,9 +1692,10 @@ BEGIN VARIABLE hpix_v : type_pix; VARIABLE hcarry_v,vcarry_v : boolean; VARIABLE dif_v : natural RANGE 0 TO 8*OHRES-1; + VARIABLE off_v : natural RANGE 0 TO 15; BEGIN IF o_reset_na='0' THEN - o_copy<='0'; + o_copy<=sWAIT; o_state<=sDISP; o_read_pre<='0'; o_readlev<=0; @@ -1663,7 +1705,7 @@ BEGIN ELSIF rising_edge(o_clk) THEN ------------------------------------------------------ o_mode <=mode; -- ? - o_format <="0001" & format; -- ? + o_format <="0001" & format; -- ? o_run <=run; -- ? @@ -1714,20 +1756,21 @@ BEGIN IF o_fb_ena='1' THEN o_ihsize<=o_fb_hsize; o_ivsize<=o_fb_vsize; - o_format<=o_fb_format; + 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; - o_stride(NB_LA-1 downto 0)<=(OTHERS=>'0'); - ELSE - o_stride <= to_unsigned(o_ihsize_temp2,14); - o_stride(NB_BURST-1 DOWNTO 0) <= (OTHERS =>'0'); - END IF; + 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); @@ -1789,13 +1832,15 @@ BEGIN o_vpe<=to_std_logic(o_vcpt_pre=o_vmin); o_divstart<='0'; o_adrsa<='0'; - + o_adrsb<=o_adrsa; + o_vacc_ini<=(o_vsize - o_ivsize + 8192) MOD 8192; o_hacc_ini<=(o_hsize + o_ihsize + 8192) MOD 8192; + --Alternate phase --o_vacc_ini<=o_ivsize; --o_hacc_ini<=(2*o_hsize - o_ihsize + 8192) MOD 8192; - + CASE o_state IS -------------------------------------------------- WHEN sDISP => @@ -1817,13 +1862,13 @@ BEGIN vcarry_v:=true; END IF; o_divstart<='1'; - IF o_vcpt_pre2=o_vmin THEN --pe='0' THEN + IF o_vcpt_pre2=o_vmin THEN o_vacc <=o_vacc_ini; o_vacc_next<=o_vacc_ini + 2*o_ivsize; o_vacpt<=x"001"; vcarry_v:=false; END IF; - + IF vcarry_v THEN o_vacpt<=o_vacpt+1; END IF; @@ -1836,7 +1881,7 @@ BEGIN WHEN sREAD => -- Read a block - IF o_readlev<2 THEN + IF o_readlev<2 AND o_adrsb='1' THEN lev_inc_v:='1'; o_read_pre<=NOT o_read_pre; o_state <=sWAITREAD; @@ -1845,6 +1890,10 @@ BEGIN prim_v:=to_std_logic(o_hbcpt=0); last_v:=to_std_logic(o_hbcpt=o_hburst-1); bib_v :=o_bibu; + off_v :=pixoffset(o_adrs + o_fb_base(NB_LA-1 DOWNTO 0),o_fb_format); + IF o_fb_ena='0' THEN + off_v:=0; + END IF; o_adrsa<='1'; WHEN sWAITREAD => @@ -1865,100 +1914,117 @@ BEGIN END CASE; o_read<=o_read_pre AND o_run; - - o_adrs_pre<=to_integer(o_vacpt) * to_integer(o_stride); - o_rline<=o_vacpt(0); -- Even/Odd line for interlaced video - IF o_adrsa='1' THEN - IF o_fload=2 THEN - o_adrs<=to_unsigned(o_hbcpt * N_BURST,32); - o_alt<="1111"; - ELSIF o_fload=1 THEN - o_adrs<=to_unsigned(o_hbcpt * N_BURST,32) + o_stride; - o_alt<="0100"; - ELSE - o_adrs<=to_unsigned(o_adrs_pre + (o_hbcpt * N_BURST),32); - o_alt<=altx(o_vacpt(1 DOWNTO 0) + 1); - END IF; - END IF; + o_rline<=o_vacpt(0); -- Even/Odd line for interlaced video + + o_adrs_pre<=to_integer(o_vacpt) * to_integer(o_stride); + IF o_adrsa='1' THEN + IF o_fload=2 THEN + o_adrs<=to_unsigned(o_hbcpt * N_BURST,32); + o_alt<="1111"; + ELSIF o_fload=1 THEN + o_adrs<=to_unsigned(o_hbcpt * N_BURST,32) + o_stride; + o_alt<="0100"; + ELSE + o_adrs<=to_unsigned(o_adrs_pre + (o_hbcpt * N_BURST),32); + o_alt<=altx(o_vacpt(1 DOWNTO 0) + 1); + END IF; + END IF; ------------------------------------------------------ -- Copy from buffered memory to pixel lines o_sh<='0'; - IF o_copy='0' THEN - o_copyv(0)<='0'; - IF o_copylev>0 AND o_copyv(0)='0' THEN - o_copy<='1'; - o_altx<=o_alt; - END IF; - o_adturn<='0'; - - IF o_primv(0)='1' THEN - -- First memcopy of a horizontal line, carriage return ! - o_hacc <=o_hacc_ini; - o_hacc_next<=o_hacc_ini + 2*o_ihsize; - o_hacpt <=x"000"; - o_dcpt<=0; - o_dshi<=2; - o_acpt<=0; - o_first<='1'; - o_last<='0'; - END IF; - - IF o_bibv(0)='0' THEN - o_ad<=0; - ELSE - o_ad<=BLEN; - END IF; - - ELSE - -- dshi : Force shift first two or three pixels of each line - IF o_dshi=0 THEN - dif_v:=(o_hacc_next - 2*o_hsize + (8*OHRES)) MOD (8*OHRES); - IF dif_v>=4*OHRES THEN - o_hacc<=o_hacc_next; - o_hacc_next<=o_hacc_next + 2*o_ihsize; - hcarry_v:=false; - ELSE - o_hacc<=dif_v; - o_hacc_next<=(dif_v + 2*o_ihsize + (4*OHRES)) MOD (4*OHRES); - hcarry_v:=true; + CASE o_copy IS + WHEN sWAIT => + o_copyv(0)<='0'; + IF o_copylev>0 AND o_copyv(0)='0' THEN + o_copy<=sCOPY; + IF o_off(0)>0 AND o_primv(0)='1' THEN + o_copy<=sSHIFT; + END IF; + o_altx<=o_alt; END IF; - o_dcpt<=(o_dcpt+1) MOD 4096; - ELSE - o_dshi<=o_dshi-1; - hcarry_v:=false; - END IF; - IF o_dshi<=1 THEN - o_copyv(0)<='1'; - END IF; - IF hcarry_v THEN + o_adturn<='0'; + o_pshift<=o_off(0) -1; + IF o_primv(0)='1' THEN + -- First memcopy of a horizontal line, carriage return ! + o_ihsizem<=o_ihsize + o_off(0) - 2; + o_hacc <=o_hacc_ini; + o_hacc_next<=o_hacc_ini + 2*o_ihsize; + o_hacpt <=x"000"; + o_dcpt<=0; + o_dshi<=2; + o_acpt<=0; + o_first<='1'; + o_last<='0'; + END IF; + + IF o_bibv(0)='0' THEN + o_ad<=0; + ELSE + o_ad<=BLEN; + END IF; + + WHEN sSHIFT => o_hacpt<=o_hacpt+1; - o_last<=to_std_logic(o_hacpt>=o_ihsize-2); - END IF; - - IF hcarry_v OR o_dshi>0 THEN o_sh<='1'; o_acpt<=(o_acpt+1) MOD 16; - - -- Shift two more pixels to the right before ending line. - o_last1<=o_last; - o_last2<=o_last1; - IF shift_onext(o_acpt,o_format) THEN o_ad<=(o_ad+1) MOD (2*BLEN); END IF; - - IF o_adturn='1' AND (shift_onext((o_acpt+1) MOD 16,o_format)) AND - (((o_ad MOD BLEN=0) AND o_lastv(0)='0') OR o_last2='1') THEN - o_copy<='0'; - lev_dec_v:='1'; + o_pshift<=o_pshift-1; + IF o_pshift=0 THEN + o_copy<=sCOPY; END IF; - IF o_ad MOD BLEN=4 THEN - o_adturn<='1'; + WHEN sCOPY => + -- dshi : Force shift first two or three pixels of each line + IF o_dshi=0 THEN + dif_v:=(o_hacc_next - 2*o_hsize + (8*OHRES)) MOD (8*OHRES); + IF dif_v>=4*OHRES THEN + o_hacc<=o_hacc_next; + o_hacc_next<=o_hacc_next + 2*o_ihsize; + hcarry_v:=false; + ELSE + o_hacc<=dif_v; + o_hacc_next<=(dif_v + 2*o_ihsize + (4*OHRES)) MOD (4*OHRES); + hcarry_v:=true; + END IF; + o_dcpt<=(o_dcpt+1) MOD 4096; + ELSE + o_dshi<=o_dshi-1; + hcarry_v:=false; END IF; - END IF; - END IF; + IF o_dshi<=1 THEN + o_copyv(0)<='1'; + END IF; + IF hcarry_v THEN + o_hacpt<=o_hacpt+1; + o_last <=to_std_logic(o_hacpt>=o_ihsizem); + END IF; + + IF hcarry_v OR o_dshi>0 THEN + o_sh<='1'; + o_acpt<=(o_acpt+1) MOD 16; + + -- Shift two more pixels to the right before ending line. + o_last1<=o_last; + o_last2<=o_last1; + + IF shift_onext(o_acpt,o_format) THEN + o_ad<=(o_ad+1) MOD (2*BLEN); + END IF; + + IF o_adturn='1' AND (shift_onext((o_acpt+1) MOD 16,o_format)) AND + (((o_ad MOD BLEN=0) AND o_lastv(0)='0') OR o_last2='1') THEN + o_copy<=sWAIT; + lev_dec_v:='1'; + END IF; + + IF o_ad MOD BLEN=4 THEN + o_adturn<='1'; + END IF; + END IF; + END CASE; o_acpt1<=o_acpt; o_acpt2<=o_acpt1; o_acpt3<=o_acpt2; o_acpt4<=o_acpt3; o_ad1<=o_ad; o_ad2<=o_ad1; o_ad3<=o_ad2; @@ -2021,6 +2087,7 @@ BEGIN o_primv(0 TO 1)<=o_primv(1 TO 2); -- First buffer of line o_lastv(0 TO 1)<=o_lastv(1 TO 2); -- Last buffer of line o_bibv (0 TO 1)<=o_bibv (1 TO 2); -- Double buffer select + o_off (0 TO 1)<=o_off (1 TO 2); -- Start offset END IF; IF lev_inc_v='1' THEN @@ -2028,15 +2095,18 @@ BEGIN o_primv(0)<=prim_v; o_lastv(0)<=last_v; o_bibv (0)<=bib_v; + o_off (0)<=off_v; ELSIF (o_readlev=1 AND lev_dec_v='0') OR (o_readlev=2 AND lev_dec_v='1') THEN o_primv(1)<=prim_v; o_lastv(1)<=last_v; o_bibv (1)<=bib_v; + o_off (1)<=off_v; END IF; o_primv(2)<=prim_v; o_lastv(2)<=last_v; o_bibv (2)<=bib_v; + o_off (2)<=off_v; END IF; ------------------------------------------------------ @@ -2050,22 +2120,40 @@ BEGIN o_v_poly_dr<=o_v_poly(o_v_poly_a) WHEN rising_edge(o_clk); -- Framebuffer palette - GenPal:IF PALETTE GENERATE - Tempera:PROCESS(pal_clk) IS + GenPal1:IF PALETTE GENERATE + Tempera1:PROCESS(pal1_clk) IS BEGIN - IF rising_edge(pal_clk) THEN - IF pal_wr='1' THEN - pal_mem(to_integer(pal_a))<=pal_dw; + IF rising_edge(pal1_clk) THEN + IF pal1_wr='1' THEN + pal1_mem(to_integer(pal1_a))<=pal1_dw; END IF; - pal_dr<=pal_mem(to_integer(pal_a)); + pal1_dr<=pal1_mem(to_integer(pal1_a)); END IF; END PROCESS; pal_idx <= shift_opack(o_acpt4,o_shift,o_dr,o_format)(0 TO 7); pal_idx_lsb <= pal_idx(0) WHEN rising_edge(o_clk); - o_fb_pal_dr_x2 <= pal_mem(to_integer(pal_idx(7 DOWNTO 1))) WHEN rising_edge(o_clk); + o_fb_pal_dr_x2 <= pal1_mem(to_integer(pal_idx(7 DOWNTO 1))) WHEN rising_edge(o_clk); + END GENERATE GenPal1; + + GenPal2:IF PALETTE and PALETTE2 GENERATE + Tempera2:PROCESS(pal2_clk) IS + BEGIN + IF rising_edge(pal2_clk) THEN + IF pal2_wr='1' THEN + pal2_mem(to_integer(pal2_a))<=pal2_dw; + END IF; + pal2_dr<=pal2_mem(to_integer(pal2_a)); + END IF; + END PROCESS; + + o_fb_pal_dr2 <= pal2_mem(to_integer(pal_idx(7 DOWNTO 0))) WHEN rising_edge(o_clk); + o_fb_pal_dr <= o_fb_pal_dr2 when pal_n = '1' else o_fb_pal_dr_x2(47 DOWNTO 24) WHEN pal_idx_lsb = '1' ELSE o_fb_pal_dr_x2(23 DOWNTO 0); + END GENERATE GenPal2; + + GenPal1not2:IF PALETTE and not PALETTE2 GENERATE o_fb_pal_dr <= o_fb_pal_dr_x2(47 DOWNTO 24) WHEN pal_idx_lsb = '1' ELSE o_fb_pal_dr_x2(23 DOWNTO 0); - END GENERATE GenPal; + END GENERATE GenPal1not2; GenNoPal:IF NOT PALETTE GENERATE o_fb_pal_dr<=x"000000"; @@ -2294,7 +2382,7 @@ BEGIN o_vcpt<=o_vcpt_pre; END IF; - o_end(0)<=to_std_logic(o_vcpt>=o_vdisp); + o_end(0)<=to_std_logic(o_vcpt>=o_vdisp); o_dev(0)<=to_std_logic(o_hcpt=o_hmin AND o_hcpt<=o_hmax AND o_vcpt>=o_vmin AND o_vcpt<=o_vmax); @@ -2302,20 +2390,20 @@ BEGIN o_vsv(0)<=to_std_logic((o_vcpt=o_vsstart AND o_hcpt>=o_hsstart) OR (o_vcpt>o_vsstart AND o_vcpt=o_vmin AND o_vcpt_pre2<=o_vmax); o_hsv(1 TO 5)<=o_hsv(0 TO 4); o_vsv(1 TO 5)<=o_vsv(0 TO 4); o_dev(1 TO 5)<=o_dev(0 TO 4); o_pev(1 TO 5)<=o_pev(0 TO 4); - o_end(1 TO 5)<=o_end(0 TO 4); + o_end(1 TO 5)<=o_end(0 TO 4); IF o_run='0' THEN o_hsv(2)<='0'; o_vsv(2)<='0'; o_dev(2)<='0'; o_pev(2)<='0'; - o_end(2)<='0'; + o_end(2)<='0'; END IF; END IF; @@ -2332,7 +2420,7 @@ BEGIN IF o_ce='1' THEN -- CYCLE 1 ----------------------------------------- -- Read mem - o_radl<=(o_hcpt-o_hmin+OHRES) MOD OHRES; + o_radl<=(o_hcpt - o_hmin + OHRES) MOD OHRES; -- CYCLE 2 ----------------------------------------- -- Lines reordering @@ -2415,7 +2503,7 @@ BEGIN o_hs<=o_hsv(5); o_vs<=o_vsv(5); o_de<=o_dev(5); - o_vbl<=o_end(5); + o_vbl<=o_end(5); o_r<=x"00"; o_g<=x"00"; o_b<=x"00"; @@ -2470,4 +2558,3 @@ BEGIN ---------------------------------------------------------------------------- END ARCHITECTURE rtl; - diff --git a/sys/audio_out.v b/sys/audio_out.v index 3c24f25..0f748e0 100644 --- a/sys/audio_out.v +++ b/sys/audio_out.v @@ -54,11 +54,11 @@ reg mclk_ce; always @(posedge clk) begin reg [31:0] cnt; - mclk_ce <= 0; + mclk_ce = 0; cnt = cnt + real_ce; if(cnt >= CLK_RATE) begin cnt = cnt - CLK_RATE; - mclk_ce <= 1; + mclk_ce = 1; end end @@ -132,11 +132,11 @@ reg flt_ce; always @(posedge clk) begin reg [31:0] cnt = 0; - flt_ce <= 0; + flt_ce = 0; cnt = cnt + {flt_rate[30:0],1'b0}; if(cnt >= CLK_RATE) begin cnt = cnt - CLK_RATE; - flt_ce <= 1; + flt_ce = 1; end end diff --git a/sys/hps_io.v b/sys/hps_io.v index e79a84f..23ade3f 100644 --- a/sys/hps_io.v +++ b/sys/hps_io.v @@ -105,10 +105,13 @@ module hps_io #(parameter STRLEN=0, PS2DIV=0, WIDE=0, VDNUM=1, PS2WE=0) // ARM -> FPGA download output reg ioctl_download = 0, // signal indicating an active download - output reg [7:0] ioctl_index, // menu index used to upload the file + output reg [15:0] ioctl_index, // menu index used to upload the file output reg ioctl_wr, 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 [DW:0] ioctl_din, + output reg ioctl_rd, output reg [31:0] ioctl_file_ext, input ioctl_wait, @@ -163,9 +166,9 @@ localparam DW = (WIDE) ? 15 : 7; localparam AW = (WIDE) ? 7 : 8; localparam VD = VDNUM-1; -wire io_strobe= HPS_BUS[33]; +wire io_strobe= HPS_BUS[33]; wire io_enable= HPS_BUS[34]; -wire fp_enable= HPS_BUS[35]; +wire fp_enable= HPS_BUS[35]; wire io_wide = (WIDE) ? 1'b1 : 1'b0; wire [15:0] io_din = HPS_BUS[31:16]; reg [15:0] io_dout; @@ -173,7 +176,7 @@ reg [15:0] io_dout; assign HPS_BUS[37] = ioctl_wait; assign HPS_BUS[36] = clk_sys; assign HPS_BUS[32] = io_wide; -assign HPS_BUS[15:0] = EXT_BUS[32] ? EXT_BUS[15:0] : io_dout; +assign HPS_BUS[15:0] = EXT_BUS[32] ? EXT_BUS[15:0] : fp_enable ? fp_dout : io_dout; reg [15:0] cfg; assign buttons = cfg[1:0]; @@ -234,7 +237,7 @@ wire extended = (~pressed ? (ps2_key_raw[23:16] == 8'he0) : (ps2_key_raw[1 reg [MAX_W:0] byte_cnt; -always@(posedge clk_sys) begin +always@(posedge clk_sys) begin : uio_block reg [15:0] cmd; reg [2:0] b_wr; reg [3:0] stick_idx; @@ -551,18 +554,20 @@ endgenerate /////////////////////////////// DOWNLOADING /////////////////////////////// -localparam UIO_FILE_TX = 8'h53; -localparam UIO_FILE_TX_DAT = 8'h54; -localparam UIO_FILE_INDEX = 8'h55; -localparam UIO_FILE_INFO = 8'h56; +localparam FIO_FILE_TX = 8'h53; +localparam FIO_FILE_TX_DAT = 8'h54; +localparam FIO_FILE_INDEX = 8'h55; +localparam FIO_FILE_INFO = 8'h56; -always@(posedge clk_sys) begin +reg [15:0] fp_dout; +always@(posedge clk_sys) begin : fio_block reg [15:0] cmd; reg [2:0] cnt; reg has_cmd; reg [26:0] addr; reg wr; + ioctl_rd <= 0; ioctl_wr <= wr; wr <= 0; @@ -577,7 +582,7 @@ always@(posedge clk_sys) begin end else begin case(cmd) - UIO_FILE_INFO: + FIO_FILE_INFO: if(~cnt[1]) begin case(cnt) 0: ioctl_file_ext[31:16] <= io_din; @@ -586,29 +591,54 @@ always@(posedge clk_sys) begin cnt <= cnt + 1'd1; end - UIO_FILE_INDEX: + FIO_FILE_INDEX: begin - ioctl_index <= io_din[7:0]; + ioctl_index <= io_din[15:0]; end - UIO_FILE_TX: + FIO_FILE_TX: begin - if(io_din[7:0]) begin - addr <= 0; - ioctl_download <= 1; - end else begin - ioctl_addr <= addr; - ioctl_download <= 0; - end + cnt <= cnt + 1'd1; + case(cnt) + 0: if(io_din[7:0] == 8'hAA) begin + ioctl_addr <= 0; + ioctl_upload <= 1; + ioctl_rd <= 1; + end + else if(io_din[7:0]) begin + addr <= 0; + ioctl_download <= 1; + end + else begin + if(ioctl_download) ioctl_addr <= addr; + ioctl_download <= 0; + ioctl_upload <= 0; + end + + 1: begin + ioctl_addr[15:0] <= io_din; + addr[15:0] <= io_din; + end + + 2: begin + ioctl_addr[26:16] <= io_din[10:0]; + addr[26:16] <= io_din[10:0]; + end + endcase end - UIO_FILE_TX_DAT: - begin + FIO_FILE_TX_DAT: + if(ioctl_download) begin ioctl_addr <= addr; ioctl_dout <= io_din[DW:0]; wr <= 1; addr <= addr + (WIDE ? 2'd2 : 2'd1); end + else begin + ioctl_addr <= ioctl_addr + (WIDE ? 2'd2 : 2'd1); + fp_dout <= ioctl_din; + ioctl_rd <= 1; + end endcase end end @@ -665,7 +695,7 @@ always@(posedge clk_sys) begin tx_empty <= ((wptr == rptr) && (tx_state == 0)); - if(we) begin + if(we && !has_data) begin fifo[wptr] <= wdata; wptr <= wptr + 1'd1; end @@ -705,6 +735,8 @@ always@(posedge clk_sys) begin ps2_dat_out <= 1; has_data <= 1; rx_state <= 0; + rptr <= 0; + wptr <= 0; end endcase end else begin diff --git a/sys/iir_filter.v b/sys/iir_filter.v index 988a432..b8bcf4f 100644 --- a/sys/iir_filter.v +++ b/sys/iir_filter.v @@ -111,6 +111,8 @@ iir_filter_tap iir_tap_2 .tap(tap2) ); +wire [15:0] y_clamp = (~y[39] & |y[38:35]) ? 16'h7FFF : (y[39] & ~&y[38:35]) ? 16'h8000 : y[35:20]; + reg ch = 0; reg [15:0] out_l, out_r, out_m; reg [15:0] inp, inp_m; @@ -118,18 +120,18 @@ always @(posedge clk) if (ce) begin if(!stereo) begin ch <= 0; inp <= input_l; - out_l <= y[35:20]; - out_r <= y[35:20]; + out_l <= y_clamp; + out_r <= y_clamp; end else begin ch <= ~ch; if(ch) begin - out_m <= y[35:20]; + out_m <= y_clamp; inp <= inp_m; end else begin out_l <= out_m; - out_r <= y[35:20]; + out_r <= y_clamp; inp <= input_l; inp_m <= input_r; end diff --git a/sys/sd_card.sv b/sys/sd_card.sv index 9fa82aa..6d90015 100644 --- a/sys/sd_card.sv +++ b/sys/sd_card.sv @@ -361,6 +361,8 @@ always @(posedge clk_spi) begin // CMD18: READ_MULTIPLE 'h52: reply <= 0; // ok + // ACMD23: SET_WR_BLK_ERASE_COUNT + 'h57: reply <= 0; //ok // CMD24: WRITE_BLOCK 'h58, diff --git a/sys/sys_top.v b/sys/sys_top.v index 8290fb4..c795a6b 100644 --- a/sys/sys_top.v +++ b/sys/sys_top.v @@ -518,12 +518,11 @@ always @(posedge FPGA_CLK2_50) begin resetd2 <= resetd; end -wire clk_100m; -wire clk_pal = FPGA_CLK3_50; - //////////////////// SYSTEM MEMORY & SCALER ///////////////////////// wire reset; +wire clk_100m; + sysmem_lite sysmem ( //Reset/Clock @@ -613,6 +612,8 @@ ddr_svc ddr_svc .ch1_ready(pal_wr) ); +wire clk_pal = clk_audio; + wire [27:0] vbuf_address; wire [7:0] vbuf_burstcount; @@ -633,6 +634,9 @@ wire clk_hdmi = hdmi_clk_out; ascal #( .RAMBASE(32'h20000000), +`ifndef USE_FB + .PALETTE2("false"), +`endif .N_DW(128), .N_AW(28) ) @@ -686,10 +690,19 @@ ascal .poly_dw (coef_data), .poly_wr (coef_wr), - .pal_clk (clk_pal), - .pal_dw (pal_d), - .pal_a (pal_a), - .pal_wr (pal_wr), + .pal1_clk (clk_pal), + .pal1_dw (pal_d), + .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), +`endif .o_fb_ena (FB_EN), .o_fb_hsize (FB_WIDTH), @@ -830,12 +843,14 @@ wire pal_wr; reg [28:0] pal_addr; reg pal_req = 0; always @(posedge clk_pal) begin - reg old_vs; + reg old_vs1, old_vs2; - pal_addr <= FB_BASE[31:3] - 29'd512; + pal_addr <= LFB_BASE[31:3] - 29'd512; - old_vs <= hdmi_vs; - if(~old_vs & hdmi_vs & ~FB_FMT[2] & FB_FMT[1] & FB_FMT[0] & FB_EN) pal_req <= ~pal_req; + old_vs1 <= hdmi_vs; + old_vs2 <= old_vs1; + + if(~old_vs2 & old_vs1 & ~FB_FMT[2] & FB_FMT[1] & FB_FMT[0] & FB_EN) pal_req <= ~pal_req; end @@ -952,12 +967,24 @@ hdmi_config hdmi_config `ifndef DEBUG_NOHDMI wire [23:0] hdmi_data_sl; wire hdmi_de_sl, hdmi_vs_sl, hdmi_hs_sl; + +`ifdef USE_FB +reg dis_output; +always @(posedge clk_hdmi) begin + reg dis; + dis <= fb_force_blank; + dis_output <= dis; +end +`else +wire dis_output = 0; +`endif + scanlines #(1) HDMI_scanlines ( .clk(clk_hdmi), .scanlines(scanlines), - .din(hdmi_data), + .din(dis_output ? 24'd0 : hdmi_data), .hs_in(hdmi_hs), .vs_in(hdmi_vs), .de_in(hdmi_de), @@ -1366,7 +1393,14 @@ wire [11:0] fb_height; wire [31:0] fb_base; wire [13:0] fb_stride; -`ifndef USE_FB +`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; +`else assign fb_en = 0; assign fb_fmt = 0; assign fb_width = 0; @@ -1404,6 +1438,13 @@ emu emu .FB_STRIDE(fb_stride), .FB_VBL(fb_vbl), .FB_LL(lowlat), + .FB_FORCE_BLANK(fb_force_blank), + + .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 .LED_USER(led_user),