📄 compressor.vhd
字号:
StepV <= 1; else StepV <= 0; end if; NDe <= '0'; RFDInt <= '0'; when 1 => --Feeding of DCT1 with 64 pixels if RFD = '1' then --DCT1 ready for data (RFD) NDe <= '1'; ND <= NDe; --this way we delay ND one cycle to synchronize data if RFDInt = '0' then case Bloque is when "00" => --block Y DIND <= doutY(7 downto 0); when "01" => --block Cb DIND <= doutCb(7 downto 0); when others => --can only be block Cr DIND <= doutCr(7 downto 0); end case; else DIND <= RFDIntData; --to recover the "lost" cycle because RFD was 0 (if the DCT was such that RFD were 0 for more than a cycle it would be necessary to change this part) RFDInt <= '0'; end if; if Columna(2 downto 0) = "111" then Columna := Columna(9 downto 3) & "000"; Linea := Linea + 1; if Linea(2 downto 0) = "000" then --we've finished this StepV, now we'll wait for the results StepV <= 2; --we shall go to StepV 2 with the first column of the block Linea(3) := not Linea(3); --makes it rest in current block Primera := '1'; --to not let StepV 2 change Linea or Column in its 1st cycle because they already have adequate values end if; else Columna := Columna + 1; end if; else --to not lose the just read pixel (rememer that reads are ahead of their time!!) RFDInt <= '1'; case Bloque is when "00" => --block Y RFDIntData <= doutY(7 downto 0); when "01" => --block Cb RFDIntData <= doutCb(7 downto 0); when others => --can only be block Cr RFDIntData <= doutCr(7 downto 0); end case; --ND <= '0'; end if; weY2 <= '0'; weCb2 <= '0'; weCr2 <= '0'; addrQ <= Base; --DC Coefficient's Q (Base + Linea*8 + Columna) QDC := (others => '0'); when 2 => --we receive the data, quantize it, truncate it and save them back to the buffer --watch out because DCT1 outputs data column-wise (feeding was row-wise) NDe <= '0'; --it stayed high while sending data byte ND <= NDe; case Bloque is --needed to send the last data of the block (it is alright!!!) when "00" => --block Y DIND <= doutY(7 downto 0); when "01" => --block Cb DIND <= doutCb(7 downto 0); when others => --can only be block Cr DIND <= doutCr(7 downto 0); end case; if RDY = '1' then --output data ready!! if QDC /= 0 then DCTQ := MultiplierQ(DOUTD(14 downto 3), QDC); QDC := (others => '0'); else DCTQ := MultiplierQ(DOUTD(14 downto 3), DOUTQ); --multiply the DCT coefficient times Qyx fraction's numerator end if; --if DCTQ(24) = '0' then --it is positive, let's round DCTQ(24 downto 14) := DCTQ(24 downto 14) + DCTQ(13); --round to nearest integer --end if; --if DCTQ(24 downto 13) = "111111111111" then --it is less or equal than -0.5, roung to 0 -- DCTQ(24 downto 13) := "000000000000"; --or else it will be read as -1 --end if; case Bloque is --the "+ DCTQ(13)" is the nearest integer round! when "00" => --block Y dinY2 <= DCTQ(24) & DCTQ(24 downto 14);-- + DCTQ(13); --we divide (shifting right) by the general Q coefficient denominator (16384) and save the quantized coefficient --sign-extension weY2 <= '1'; when "01" => --block Cb dinCb2 <= DCTQ(24) & DCTQ(24 downto 14);-- + DCTQ(13); --we divide (shifting right) by the general Q coefficient denominator (16384) and save the quantized coefficient weCb2 <= '1'; when others => --can only be block Cr dinCr2 <= DCTQ(24) & DCTQ(24 downto 14);-- + DCTQ(13); --we divide (shifting right) by the general Q coefficient denominator (16384) and save the quantized coefficient weCr2 <= '1'; end case; --write column-wise if Linea(2 downto 0) = "111" and Primera = '0' then --have we reached this line's end? --Primera is used for the first cycle of StepV2 in which Columna and Linea arrive with the right value --so they need not be changed in order to get the correct address Linea := Linea(3) & "000"; Columna := Columna + 1; else if Primera = '1' then Primera := '0'; else Linea := Linea + 1; if Linea(2 downto 0) = "111" and Columna(2 downto 0) = "111" then --we have finished this StepV, now we must Huffman encode StepV <= 3; end if; end if; end if; --the following code is because we must load one cycle early the addrQ so that in the --current cycle we can have the right Q coefficient for current Linea and Columna values if Linea(2 downto 0) = "110" then --have we reached the end? --next coeff. is Linea 0 of the Coeff. Table and Columna is current plus one addrQ <= Base + Columna(2 downto 0) + 2; --Base + Linea*8 + Columna --> remember coefficient table is 8x8 else --next coeff is next Linea of the Coeff. Table and current Columna addrQ <= Base + ((Linea(2 downto 0) + 2) & "000") + Columna(2 downto 0); --Base + Linea*8 + Columna end if; else --during Latency cycles we will be here waiting until RDY is 1 --and also every X cycles when RDY becomes 0 for one cycle if QDC = 0 and addrQ = Base then --only happens when we enter this StepV from the previous one QDC := DOUTQ; --save the DC value because Q reading must be ahead by two cycles now addrQ <= Base + "1000"; --Base + Linea*8 + Columna (Linea=1, Columna=0) end if; weY2 <= '0'; weCr2 <= '0'; weCb2 <= '0'; end if; when 3 => weY2 <= '0'; weCr2 <= '0'; weCb2 <= '0'; --Make the "pointers" Linea and Columna point to the beginning of the next block --must do it here because in the last cycle of StepV2, when StepV becomes 3, Linea and Columna --must maintain their value Linea := Linea(3) & "000"; Columna := Columna + 1; if LumaBlock = '1' then --if we are processing the luminance block we can only save it when we have processed the 4 ones --that compose the 2x2 block of subsampling, there is no problem with the order of the chroma ones because these ones too --are saved when we have averaged four and that is controlled by the process RGB2YCbCr if Linea(3) = '1' and Columna(3) = '0' then --checked, it is alright (remember it points to the next block) StepV <= 4; Elemento := "00"; --process the first square (8x8 block) of the 2x2 luminance block (16x16 pixels, 2x2 squares) --Ready Linea and Columna to read element 00 that Huffman will receive Linea := (others => '0'); Columna := (Columna(9 downto 4) - 1) & "0000"; else --the three first squares of the 2x2 luminance block are not sent to Huffman yet (subsampling requirements) StepV <= 0; Done <= '1'; end if; else Columna := Columna - 1; Columna := Columna(9 downto 3) & "000"; --it is alright, because Columna arrives already adjusted to Cb and Cr. StepV <= 4; end if; WriteAdditionalBits <= '0'; when 4 => --with this dummy cycle we give time to the memory to give us address 0 --for the DC coefficient weY2 <= '0'; weCr2 <= '0'; weCb2 <= '0'; Save <= '0'; --just in case we left it high in last step we <= '0'; StepV <= 5; when 5 => --Linea and Columna point to the beginning of the block --If we change Linea and/or Columna in cycle 0 of this section, then the new address will --be sent to memory in cycle 1 and in cycle 2 doutX will have the asked data, so careful!! case Bloque is when "00" => --block Y Coef := doutY; when "01" => --block Cb Coef := doutCb; when others => --can only be block Cr Coef := doutCr; end case; we <= '0'; if Done = '0' then --this way it does not go to look for the DC when we change Block (upsetting FirstDC) if Save = '0' then if WriteAdditionalBits = '0' then if Coeficiente = 0 then --The previous component is read from the buffer varying Linea and Columna if IniDC = '1' then --we've not yet obtained the previous DC to calculate the difference if Linea = "0000" and Columna = "000000000" and FirstDC = '1' and GetPrevDC = '1' then --must do it this way --or else the luminance, which has 4 blocks in its first Huffmanear takes DC=0 for all --GetPrevDC = 1 is so that execution doesnt get here if in the previous cycle GetPrevDC became zero in the bottom "if" --and put Linea and Columna to zero --we are in the first block of the image, PrevDC is zero if Bloque = "10" then --if we are in the last, we zero it FirstDC := '0'; --because it has already been used by the three components (Y,Cb,Cr) end if; PrevDC := (others => '0'); IniDC := '0'; else if GetPrevDC = '1' then ColBk := Columna; --save the values of Linea and Columna LinBk := Linea; --Must obtain the quantized DC coefficient of the last processed block --as stated by specification, but actually the last block is indicated by MCU if Columna(9 downto 3) = "0000000" then --first block of the row? if LumaBlock = '1' then if Elemento = "00" then --Remember that DCTs are done when only the last line of all is left to be written in the block --so the DC of the previous block has already been overwritten, that's why we use LastBlockDCY PrevDC := LastBlockDCY; IniDC := '0'; --this way we skip the next StepV else --Elemento 10 need the DC of Elemento 01 Linea(3) := '0'; Columna(3) := '1'; end if; else --in chrominance ImgColumns has half the image's columns! if Bloque = "01" then --block Cb PrevDC := LastBlockDCCb; else --10 = block Cr PrevDC := LastBlockDCCr; end if; IniDC := '0'; end if; else if LumaBlock = '1' then case Elemento is when "00" => --DC of previous element 11 Columna := (Columna(9 downto 3)-1) & "000"; Linea(3) := '1'; when "01" => --DC of element 00 Columna(3) := '0'; Linea(3) := '0'; when "10" => --DC of element 01 Columna(3) := '1'; Linea(3) := '0'; when others => --11 DC of element 10 Columna(3) := '0'; Linea(3) := '1'; end case; else Columna := (Columna(9 downto 3) - 1) & "000"; --first column of previous block end if; end if; StepV <= 4; --wait one cycle for PrevDC GetPrevDC := '0'; else GetPrevDC := '1'; --we rise it for the next block IniDC := '0'; PrevDC := Coef; Linea := LinBk; Columna := ColBk; StepV <= 4; --wait one cycle to get back the current DC component to operate with it end if; end if; else --IniDC = '0' that is, we now have the PrevDC GetPrevDC := '1'; --we rise it for the second block after the first one of the image --in this "if" we see if this is the last block in the buffer and in that case --save its DC component if LumaBlock = '1' then if Columna(9 downto 3) = ImgColumns(9 downto 3) and Elemento="11" then LastBlockDCY := Coef; end if; else if Columna(9 downto 3) = ImgColumns(9 downto 4) then if Bloque = "01" then --block Cb LastBlockDCCb := Coef; else --block Cr LastBlockDCCr := Coef; end if;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -