📄 compressor.vhd
字号:
return result; end CompressDC; begin with Save select addr <= addribk when '1', addri when others; with CompressingInt select addrY <= addrY2 when '1', addrY1 when others; with CompressingInt select addrCb <= addrCb2 when '1', addrCb1 when others; with CompressingInt select addrCr <= addrCr2 when '1', addrCr1 when others; with CompressingInt select weY <= weY2 when '1', weY1 when others; with CompressingInt select weCb <= weCb2 when '1', weCb1 when others; with CompressingInt select weCr <= weCr2 when '1', weCr1 when others; with CompressingInt select dinY <= dinY2 when '1', dinY1 when others; with CompressingInt select dinCb <= dinCb2 when '1', dinCb1 when others; with CompressingInt select dinCr <= dinCr2 when '1', dinCr1 when others; DCT1 : dct2d port map (ND,RDY,RFD,clk,DIND,DOUTD); buffer_compY : buffer_comp port map (addrY,clk,dinY,doutY,weY); buffer_compCb : buffer_comp_chrom port map (addrCb,clk,dinCb,doutCb,weCb); buffer_compCr : buffer_comp_chrom port map (addrCr,clk,dinCr,doutCr,weCr); Q_ROM1 : q_rom port map (addrQ,clk,doutQ); Huffman_ROM : huff_rom port map (addrH,clk,doutH); Tabla_Q1 : tabla_q port map(addrTablaQ,clk,doutTablaQ); RGB2YCbCr : process(reset, clk) --It applies the transformation from RGB to YCBCr and pass it to the JPEG process -- but what we are going to save in the buffers will be the pixels of the components with -- the JPEG level shift already applied, so that the transformation's last addition: [0;128;128] will become -[128;0;0] variable Baton : integer range 0 to 3 := 0; --indicates the current state of the FSM variable Red1 : std_logic_vector(17 downto 0); variable Red2 : std_logic_vector(17 downto 0); variable Red3 : std_logic_vector(17 downto 0); variable Green1 : std_logic_vector(17 downto 0); variable Green2 : std_logic_vector(17 downto 0); variable Green3 : std_logic_vector(17 downto 0); variable Blue1 : std_logic_vector(17 downto 0); variable Blue2 : std_logic_vector(17 downto 0); variable Blue3 : std_logic_vector(17 downto 0); variable Cb, Cr : std_logic_vector(10 downto 0); begin if (reset = '1') then Compressing <= '0'; addrY1 <= (others => '0'); addrCb1 <= (others => '0'); addrCr1 <= (others => '0'); weY1 <= '0'; weCb1 <= '0'; weCr1 <= '0'; dinCb1 <= (others => '0'); dinCr1 <= (others => '0'); dinY1 <= (others => '0'); LineToCompress <= "0000"; LineAbsToCompress <= (others => '0'); ColumnToCompress <= (others => '0'); Baton := 0; Cb := (others => '0'); Cr := (others => '0'); ProcessingRGB <= '0'; MakeDCT <= '0'; Red1 := (others => '0'); Red2 := (others => '0'); Red3 := (others => '0'); Green1 := (others => '0'); Green2 := (others => '0'); Green3 := (others => '0'); Blue1 := (others => '0'); Blue2 := (others => '0'); Blue3 := (others => '0'); elsif (clk = '1' and clk'event) then if CompressImage = '1' then Compressing <= '1'; addrY1 <= (others => '0'); addrCb1 <= (others => '0'); addrCr1 <= (others => '0'); weY1 <= '0'; weCb1 <= '0'; weCr1 <= '0'; LineToCompress <= "0000"; LineAbsToCompress <= (others => '0'); ColumnToCompress <= (others => '0'); Baton := 0; ProcessingRGB <= '0'; end if; if (ProcessRGB = '1') then ProcessingRGB <= '1'; --while this one is high, there won't be another ProcessRGB='1' Baton := 1; end if; addrY1 <= Mult_Columns(LineToCompress) + ColumnToCompress; addrCb1 <= Mult_Half_Columns(LineToCompress(3 downto 1)) + (ColumnToCompress(9 downto 1)); --for the subsampling addrCr1 <= Mult_Half_Columns(LineToCompress(3 downto 1)) + (ColumnToCompress(9 downto 1)); --we pre-read the saved data, so as to average the chroma components Cb and Cr --to be able to do a proper subsampling 2x2 1x1 1x1 case Baton is when 0 => weY1 <= '0'; weCb1 <= '0'; weCr1 <= '0'; MakeDCT <= '0'; when 1 => --we apply only the transformation RGB to YCbCr Red1 := Multiplier(Red, "0010011001"); --153 Red2 := Multiplier(Red, "0010101101"); --173 Red3 := "0000000000" & Red; --1 Green1 := Multiplier(Green, "1001011001"); --601 Green2 := Multiplier(Green, "0101010011"); --339 Green3 := Multiplier(Green, "0110101101"); --429 Blue1 := Multiplier(Blue, "0001110101"); --117 Blue2 := "0000000000" & Blue; --1 Blue3 := Multiplier(Blue, "0001010011"); --83 --the largest obtainable result would be 255*601=153255 (100101011010100111) Baton := 2; MakeDCT <= '0'; when 2 => --dinY1 <= "111110000000"; --for debugging, to make Y zero, so that in the resulting image the Blue channel will be Cb and the Red one will be Cr dinY1 <= "0000" & (Red1(16 downto 9) + Green1(17 downto 10) + Blue1(17 downto 10) - "10000000");-- + Red1(8) + Green1(9) + Blue1(9)); --Red1/512+Green1/1024+Blue1/1024 and with -128 for the level shift if Mono = '1' then Cb := (others => '0'); Cr := (others => '0'); else Cb := "000" & (Blue2(8 downto 1) - Red2(17 downto 10) - Green2(17 downto 10)); -- + Blue2(0) - Red2(9) - Green2(9)); --Red & Green between 1024 and Blue between 2 Cr := "000" & (Red3(8 downto 1) - Green3(17 downto 10) - Blue3(17 downto 10)); -- + Red3(0) - Green3(9) - Blue3(9)); --between 1024 all but Red --debug: the bits added/substracted at the end are the nearest integer rounding end if; --Subsampling: average groups of 4 pixels in blocks of 2x2 if LineAbsToCompress(0) = '0' and ColumnToCompress(0) = '0' then --element (0,0) --dinCb1 <= "0000" & Cb(7 downto 0); --dinCr1 <= "0000" & Cr(7 downto 0); dinCb1 <= "0000" & Cb(7 downto 0); dinCr1 <= "0000" & Cr(7 downto 0); elsif LineAbsToCompress(0) = '0' and ColumnToCompress(0) = '1' then --element (0,1) Cb := (Cb(7) & Cb(7) & Cb(7) & Cb(7 downto 0)) + (doutCb(7) & doutCb(7 downto 0)); Cr := (Cr(7) & Cr(7) & Cr(7) & Cr(7 downto 0)) + (doutCr(7) & doutCr(7 downto 0)); dinCb1 <= "000" & Cb(8 downto 0); dinCr1 <= "000" & Cr(8 downto 0); elsif LineAbsToCompress(0) = '1' and ColumnToCompress(0) = '0' then --element (1,0) Cb := (Cb(7) & Cb(7) & Cb(7) & Cb(7 downto 0)) + (doutCb(8) & doutCb(8 downto 0)); Cr := (Cr(7) & Cr(7) & Cr(7) & Cr(7 downto 0)) + (doutCr(8) & doutCr(8 downto 0)); dinCb1 <= "00" & Cb(9 downto 0); dinCr1 <= "00" & Cr(9 downto 0); else --element (1,1) before, we have added directly, now we add and write the average of the 4 pixels, so as to not lose precission Cb := (Cb(7) & Cb(7) & Cb(7) & Cb(7 downto 0)) + (doutCb(9) & doutCb(9 downto 0)); Cr := (Cr(7) & Cr(7) & Cr(7) & Cr(7 downto 0)) + (doutCr(9) & doutCr(9 downto 0)); dinCb1 <= "0000" & Cb(9 downto 2); dinCr1 <= "0000" & Cr(9 downto 2); --next lines are for debugging purposes (instead of the last if,elsifs and else to write just --one chrominance value for Cb and Cr instead of averaging) --Cb := (Cb(7) & Cb(7) & Cb(7) & Cb(7 downto 2)) + (doutCb(7) & doutCb(7 downto 0)); --Cr := (Cr(7) & Cr(7) & Cr(7) & Cr(7 downto 2)) + (doutCr(7) & doutCr(7 downto 0)); --dinCb1 <= "0000" & Cb(7 downto 0); --dinCr1 <= "0000" & Cr(7 downto 0); --weCb1 <= '1'; --weCr1 <= '1'; --else --weCb1 <= '0'; --weCr1 <= '0'; end if; weY1 <= '1'; weCb1 <= '1'; weCr1 <= '1'; if (LineToCompress(2 downto 0) = "111") then if (ColumnToCompress(2 downto 0) = "111") then --we've just written pixel 64 of the block [of 64 pixels] MakeDCT <= '1'; else MakeDCT <= '0'; end if; else MakeDCT <= '0'; end if; if (ColumnToCompress = ImgColumns) then LineToCompress <= LineToCompress + 1; LineAbsToCompress <= LineAbsToCompress + 1; ColumnToCompress <= (others => '0'); else ColumnToCompress <= ColumnToCompress + 1; end if; Baton := 3; when 3 => --with this dummy cycle we give time to CompressingInt to rise, if it must, and make the following "if" work fine weY1 <= '0'; weCb1 <= '0'; weCr1 <= '0'; MakeDCT <= '0'; Baton := 0; end case; --MakeDCT is rised in cycle 0, in cycle 1 it is read by the process JPEG which then rises CompressingInt --and in cycle 2 this process reads CompressingInt='1' so that in that intermediate cycle 1 is when --the case "when 3 =>" gets executed and the following "if", in which MakeDCT is 1 and CompressingInt is 0 --but it is going to be inverted. if (Baton = 0 and MakeDCT = '0' and CompressingInt = '0') then --it is fine! if (LineAbsToCompress > ImgLines) then Compressing <= '0'; --Compression has ended, image ready LineAbsToCompress <= (others => '0'); --absolutely incredible, without this line it will only work for the --first image (it took me much time to debug this one, folks) end if; ProcessingRGB <= '0'; end if; end if; end process RGB2YCbCr; JPEG : process (reset, clk) --in this process data are sent to the DCT1 component, its output is quantized and written back --in the same addresses where they were read (buffers) to be sent to DCT1. variable Columna : std_logic_vector(9 downto 0); variable Linea : std_logic_vector(3 downto 0); --0 to 15 variable Bloque : std_logic_vector(1 downto 0); variable DCTQ : std_logic_vector(24 downto 0); --for multiplication of the result of the DCT with numerator of Q variable Base : std_logic_vector(8 downto 0); --to access Q coefficients from the tables in ROM variable BaseH : std_logic_vector(8 downto 0); --for the Huffman tables ROM variable BaseQ : std_logic_vector(8 downto 0); --for the Q tables ROM variable HuffmanWord : std_logic_vector(22 downto 0); variable HuffmanWordPos : integer range -1 to 22; variable LumaBlock : std_logic; variable Elemento : std_logic_vector(1 downto 0); variable Coeficiente : integer range 0 to 63; --indicates which is the next coefficient to be processed by Huffman variable PrevDC : std_logic_vector(11 downto 0); --previous value of luminance DC variable Coef : std_logic_vector(11 downto 0); --current coefficient's value variable LastBlockDCY : std_logic_vector(11 downto 0); variable LastBlockDCCb : std_logic_vector(11 downto 0); variable LastBlockDCCr : std_logic_vector(11 downto 0); variable IniDC : std_logic; variable FirstDC : std_logic; variable GetPrevDC : std_logic; variable ColBk : std_logic_vector(9 downto 0); variable LinBk : std_logic_vector(3 downto 0); --0 to 15 variable Hlength : integer range 0 to 15; variable ZeroRun : integer range 0 to 16; variable ZRL : integer range 0 to 3; variable WriteZRL : std_logic; variable Cat : integer range 0 to 11; variable Sign : std_logic; variable Primera : std_logic; variable HeaderFinal : std_logic; --to know if we've already written EOI (End Of Image) variable VarTamImg : std_logic_vector(10 downto 0); variable DatoHeader : integer range 0 to 7 := 0; --to know where we are in the writing of the header's image size variable TempCompDC : std_logic_vector(14 downto 0); variable AddVal : std_logic_vector(11 downto 0); variable QDC : std_logic_vector(12 downto 0); --pragma translate_off --I couldn't find any testbench where I could read or write binary files and the ones I found were overcomplex --so I experimented and found this to be a useful way to do it without any complications. type ByteT is (c0,c1,c2,c3,c4,c5,c6,c7,c8,c9,c10,c11,c12,c13,c14,c15,c16,c17,c18,c19,c20,c21,c22,c23,c24,c25,c26,c27,c28,c29,c30,c31,c32,c33,c34,c35,c36,c37,c38,c39,c40,c41,c42,c43,c44,c45,c46,c47,c48,c49,c50,c51,c52,c53,c54,c55,c56,c57,c58,c59,c60,c61,c62,c63,c64,c65,c66,c67,c68,c69,c70,c71,c72,c73,c74,c75,c76,c77,c78,c79,c80,c81,c82,c83,c84,c85,c86,c87,c88,c89,c90,c91,c92,c93,c94,c95,c96,c97,c98,c99,c100,c101,c102,c103,c104,c105,c106,c107,c108,c109,c110,c111,c112,c113,c114,c115,c116,c117,c118,c119,c120,c121,c122,c123,c124,c125,c126,c127,c128,c129,c130,c131,c132,c133,c134,c135,c136,c137,c138,c139,c140,c141,c142,c143,c144,c145,c146,c147,c148,c149,c150,c151,c152,c153,c154,c155,c156,c157,c158,c159,c160,c161,c162,c163,c164,c165,c166,c167,c168,c169,c170,c171,c172,c173,c174,c175,c176,c177,c178,c179,c180,c181,c182,c183,c184,c185,c186,c187,c188,c189,c190,c191,c192,c193,c194,c195,c196,c197,c198,c199,c200,c201,c202,c203,c204,c205,c206,c207,c208,c209,c210,c211,c212,c213,c214,c215,c216,c217,c218,c219,c220,c221,c222,c223,c224,c225,c226,c227,c228,c229,c230,c231,c232,c233,c234,c235,c236,c237,c238,c239,c240,c241,c242,c243,c244,c245,c246,c247,c248,c249,c250,c251,c252,c253,c254,c255);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -