Skocz do zawartości

Pomocna odpowiedź

Napisano

Witam

Przykładowy kod dla Sumatora z  przypisywaną długością danych (assigned data leght). W kodzie użyłem pętli for by skrócić zapis informacji opisujących połączenia w układzie. Jest to mim zdaniem duże udogodnienie dla użytkownika i gdy zrozumiałem działanie tej funkcji używam jej często. Programiści znają tą pętlę doskonale lecz niektórzy mają problem z zastosowaniem w opisie sprzętu. Jeden ze sposobów użycia tej pętli dotyczy funkcji "generate". Przy używaniu tej funkcji oprogramowanie syntezy jest informowane jak mają wyglądać połączenia na przykład: między DataIn (Port wejść danych) a Zatrzask(Wewnętrzny zatrzask danych). Pętla for z funkcją generate na podstawie indeksu i iteruje przez wszystkie wybrane bity o numerze indeksu i w DataIn i przypisuje je do wybranych bitów o numerze indeksu i do Zatrzasku. I to w sumie tyle. Czego tu nie rozumieć? jest między c, c++ i vhdl zasadnicza różnica w wykonaniu poleceń. Synteza zachodzi analogicznie do kompilacji, ale w układach programowalnych nie możemy w ten sposób tworzyć układów sekwencyjnych. W języku vhd tworzone są w tym kodzie połączenia, a w języku c generowana jest iteracja dla procesora. W języku c procesor wykonuje polecenia jedno po drugim aż kod zostanie przerwany, a w układach cpld, fpga itp robi połączenia bo tam nie ma rdzenia procesora który mógłby wykonać te polecenia. Jedyne miejsce gdzie możemy użyć pętli by iterować przez polecenia analogicznie do wykonywania kodów w języku c to symulator i tam używamy zamiast słowa generate słowo loop na przykład tak

-- Pętla do generowania różnych kombinacji

for i in 0 to n-1 loop

G(i) <= '1';

P(i) <= '1';

wait for 10 ns;

-- Opóźnienie na symulację

G(i) <= '0';

P(i) <= '0';

end loop; -- no może nie do końca 😉

W kodzie użyłem też słowa generic dla zdefiniowania szerokości magistrali dla danych. Moim zdaniem bardzo przydatna funkcja. Generic ( n : integer := 8 przypisuje wartość 8 dla zmiennej n. Tą zmienną można manipulować zmieniając jej wartość w innych nadrzędnych blokach programu. Dzięki temu możemy we wszystkich sygnałach ze zmienną n zmienić ilość przypisanych linii wpisując wartość dla generic n. Bardzo elastyczne i mało wymagające rozwiązanie przy pisaniu kodu. Jak takich sygnałów mamy kilkadziesiąt to na pewno docenimy taki zapis...

A oto kod dla sumatora w języku VHDL.

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity ADDER_adl is
    Generic (
	        n : integer := 8); -- szerokość szyny danych
    Port ( A : in    STD_LOGIC_VECTOR (n - 1 downto 0);  -- dane wejściowe
           B : in    STD_LOGIC_VECTOR (n - 1 downto 0);  -- dane wejściowe
           Q : out   STD_LOGIC_VECTOR (n - 1 downto 0);  -- dane wyjściowe
           AS : in    STD_LOGIC;                     -- wybór instrukcji ADD = '0'/ SUB = '1'
           CI : in   STD_LOGIC;                      -- wejście przeniesienia
           CO : out  STD_LOGIC;                      -- wyjście przeniesienia
           Z : out   STD_LOGIC;                      -- flaga 0
           NE : out   STD_LOGIC;                     -- flaga liczba ujemna
           OV : out  STD_LOGIC);                     -- flaga przepełnienie
end ADDER_adl;

architecture Behavioral of ADDER_adl is

	signal RES : std_logic_vector (n - 1 downto 0);
	signal BX : std_logic_vector (n - 1 downto 0);
	signal CX : std_logic;
	signal P : std_logic_vector (n - 1 downto 0);
	signal G : std_logic_vector (n - 1 downto 0);
	signal C : std_logic_vector (n downto 0);

begin

-- Określenie operacji )dodawamie: B, odejmowanie: -B + 1)
BX <= (not A) when (AS = '1') else B;
CX <= (not CI) when (AS = '1') else CI;

-- Obliczanie propagacji i generacji
generic_pg : for i in 0 to (n - 1) generate
P(i) <= A(i) xor BX(i);
G(i) <= A(i) and BX(i);
end generate;

-- Obliczanie przeniesienia
C(0) <= CX;
generate_carry : for i in 0 to (n - 1) generate
C(i + 1) <= G(i) or (P(i) and C(i));
end generate;

-- Obliczanie sumy
generate_sum : for i in 0 to (n - 1) generate
RES(i) <= P(i) xor C(i);
end generate;

-- Dekoder bitów statusowych
CO <= C(n);
Z <= '1' when RES((n - 1) downto 0) = 0 else '0';
NE <= RES(n - 1);
OV <= C(n) xor C(n - 1);

-- wynik
Q <= RES;

end Behavioral;

Pozdrawiam.

  • Lubię! 2
  • 4 tygodnie później...

witam.

W kodzie który podałem wyżej wkradł się chochlik. (BX <= (not A) when (AS = '1') else B;) = źle / (BX <= (not B) when (AS = '1') else B;) = poprawnie; W kodzie w instrukcji odejmowania negujemy wejście B i dodajemy jeden, zamiast tego błędny zapis neguje wejście A.

Rozbudowałem kod do prostej jednostki ALU w której zaimplementowałem  funkcje : ADD AND OR XOR RRC RLC RR RL. RRC to przesunięcie w prawo najmłodszy bit jest zastąpiony wejściem CI najstarszy bit  przesunięty jest do CO. RR przesuwa wszystkie bity w prawo najmłodszy bit przesunięty jest w miejsce najstarszego. RLC i RL to przesunięcie w lewo odpowiednio z uwzględnieniem bitu przeniesienia i bez bitu przeniesienia. Dla zainteresowanych kod :

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity ALU_adl is
    Generic (
	        n : integer := 8); -- szerokość szyny danych
    Port ( A : in    STD_LOGIC_VECTOR (n - 1 downto 0);  -- dane wejściowe
           B : in    STD_LOGIC_VECTOR (n - 1 downto 0);  -- dane wejściowe
           Q : out   STD_LOGIC_VECTOR (n - 1 downto 0);  -- dane wyjściowe
           S : in    STD_LOGIC_VECTOR (2 downto 0);      -- wybór operacji
           AS : in    STD_LOGIC;                     -- wybór instrukcji ADD = '0'/ SUB = '1'
           CI : in   STD_LOGIC;                      -- wejście przeniesienia
           CO : out  STD_LOGIC;                      -- wyjście przeniesienia
           Z : out   STD_LOGIC;                      -- flaga 0
           NE : out   STD_LOGIC;                     -- flaga liczba ujemna
           OV : out  STD_LOGIC);                     -- flaga przepełnienie
end ALU_adl;

architecture Behavioral of ALU_adl is

	signal RES : std_logic_vector (n - 1 downto 0);
	signal BX : std_logic_vector (n - 1 downto 0);
	signal CX : std_logic;
	signal P : std_logic_vector (n - 1 downto 0);
	signal G : std_logic_vector (n - 1 downto 0);
	signal O : std_logic_vector (n - 1 downto 0);
	signal R : std_logic_vector (n - 1 downto 0);
	signal L : std_logic_vector (n - 1 downto 0);
	signal RC : std_logic_vector (n - 1 downto 0);
	signal LC : std_logic_vector (n - 1 downto 0);
	signal C : std_logic_vector (n downto 0);

begin

-- Określenie operacji )dodawamie: B, odejmowanie: -B + 1)
BX <= (not B) when (AS = '1') else B;
CX <= (not CI) when (AS = '1') else CI;

-- Obliczanie propagacji i generacji
generic_pg : for i in 0 to (n - 1) generate
P(i) <= A(i) xor BX(i);
G(i) <= A(i) and BX(i);
O(i) <= A(i) or BX(i);
end generate;

-- Obliczanie przeniesienia
C(0) <= CX;
generate_carry : for i in 0 to (n - 1) generate
C(i + 1) <= G(i) or (P(i) and C(i));
end generate;

-- Obliczanie sumy
generate_sum : for i in 0 to (n - 1) generate
RES(i) <= P(i) xor C(i);
end generate;

-- Przesunięcie w prawo 
R <= A(0) & A(n - 1 downto 1);

-- Przesunięcie w prawo + C
RC <= CI & A(n - 1 downto 1);

-- Przesunięcie w lewo
L <= A(n - 2 downto 0) & A(n - 1);

-- Przesunięcie w lewo + C
LC <= A(n - 2 downto 0) & CI;

-- Dekoder bitów statusowych
Z <= '1' when RES((n - 1) downto 0) = 0 else '0';
NE <= RES(n - 1);
OV <= C(n) xor C(n - 1);

-- wynik
with S select
Q  <= RES when "000",   -- ADD
      P   when "001",   -- XOR
	  G   when "010",   -- AND
	  O   when "011",   -- OR
	  RC  when "100",   -- RRC
	  LC  when "101",   -- RLC
	  R   when "110",   -- RR
	  L   when others;  -- RL

-- CO
with S select
CO <= A(0)     when "100",
      A(n - 1) when "101",
      C(n)     when others;

end Behavioral;

 

  • 8 miesiące później...
(edytowany)

Witam.

Zaimplementowałem jednostkę ALU w układzie CPLD. Kość XC9536XL-10 VQ44.

Architektura 8 bitowa z podstawowymi funkcjami jest moim zdaniem lepsza od kultowego 181... Budując układy oparte na architekturze retro i trzymanie się oryginalnych układów w imię ideologii nie jest moim priorytetem. Nie testowałem układu i jestem ciekawy, czy można upchnąć więcej instrukcji w takim układzie...

Kod programu:
ADD/SUB zawsze wykonuje operację sumy wyrażeń A i B
CI : wjście przeniesienia.
Z  : flaga zero
C  : flaga przepełnienia wyniku sumatora, lub rotacja przez carry
N  : flaga znak liczby w kodzie U2
OV: flaga przepełnienie dla liczby U2 w sumatorze
AS : wybór odejmowanie = 1, dodawanie = 0. Nie ma wpływu na resztę funkcji
S  : wybór funkcji 1 z 8
EN : Aktywacja wyjść. (wyjścia dwustanowe, nieaktywne =  0)
F : wynik wybranej funkcji
 

	-- S   EN
	-- 000 1  F = ADD/SUB
	-- 001 1  F = A AND B
   -- 010 1  F = A OR  B
	-- 011 1  F = A XOR B
	-- 100 1  F = ROL A
	-- 101 1  F = ROR A
	-- 110 1  F = RCL C < A < Ci
	-- 111 1  F = RCR Ci > A > C
	-- SSS 0  F = 0
	
	--     1  C = Cen
	--     0  C = 0
	
	--     1  Z = Zen
	--     0  Z = 0
	
	--     1  OV = OVen
	--     0  OV = 0
	
	--     AS
	--     1  SUB
	--     0  ADD
	
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity ALU9536XL is
    Port ( A  : in  STD_LOGIC_VECTOR (7 downto 0);
           B  : in  STD_LOGIC_VECTOR (7 downto 0);
			  S  : in  STD_LOGIC_VECTOR (2 downto 0);
           AS : in  STD_LOGIC;
           CI : in  STD_LOGIC;
           EN : in  STD_LOGIC;
           C  : out  STD_LOGIC;
           Z  : out  STD_LOGIC;
           N  : out  STD_LOGIC;
           OV : out  STD_LOGIC;
           F  : out  STD_LOGIC_VECTOR (7 downto 0));
end ALU9536XL;

architecture Behavioral of ALU9536XL is

	signal SE : std_logic_vector (7 downto 0);
	signal E8 : std_logic_vector (8 downto 0);
	signal BX : std_logic_vector (8 downto 0);
	signal E7 : std_logic_vector (7 downto 0);
	signal A7 : std_logic_vector (7 downto 0);
	signal O7 : std_logic_vector (7 downto 0);
	signal X7 : std_logic_vector (7 downto 0);
	signal R7 : std_logic_vector (7 downto 0);
	signal L7 : std_logic_vector (7 downto 0);
	signal LC : std_logic_vector (7 downto 0);
	signal RC : std_logic_vector (7 downto 0);
	signal FE : std_logic_vector (7 downto 0);
	signal CX : std_logic;
	signal CR : std_logic;
	signal CL : std_logic;
	signal CE : std_logic;
	signal Fen  : std_logic_vector (7 downto 0);
	signal Cen  : std_logic;
	signal Zen  : std_logic;
	signal Nen  : std_logic;
	signal OVen : std_logic;

begin

	with S select
		SE <= "00000001" when "000", -- 000 ADD/SUB
			   "00000010" when "001", -- 001 AND
				"00000100" when "010", -- 010 OR
				"00001000" when "011", -- 011 XOR
				"00010000" when "100", -- 100 ROL
				"00100000" when "101", -- 101 ROR
				"01000000" when "110", -- 110 RCL
				"10000000" when others;-- 111 RCR
				
	BX <= ('0' & B) xor (8 downto 0 => AS);
	CX <= CI xor AS;
	E8 <= ('0' & A) + BX + CX;
	CE  <= E8(8) and SE(0);
	CR  <= A(0) and SE(7);
	CL  <= A(7) and SE(6);
	E7 <= E8(7 downto 0)         and (7 downto 0 => SE(0));
	A7 <= (A and B)              and (7 downto 0 => SE(1));
	O7 <= (A  or B)              and (7 downto 0 => SE(2));
	X7 <= (A xor B)              and (7 downto 0 => SE(3));
	L7 <= (A(6 downto 0) & A(7)) and (7 downto 0 => SE(4));
	R7 <= (A(0) & A(7 downto 1)) and (7 downto 0 => SE(5));
	LC <= (A(6 downto 0) & CI) and (7 downto 0 => SE(6));
	RC <= (CI & A(7 downto 1)) and (7 downto 0 => SE(7));
	FE <= E7 or A7 or O7 or X7 or R7 or L7 or LC or RC;
	Cen  <= (CE or CR or CL) and EN;
	Fen  <= FE and (7 downto 0 => EN);
	Zen  <= (not (FE(7) or FE(6) or FE(5) or FE(4) or FE(3) or FE(2) or FE(1) or FE(0))) and EN;
	Nen  <= FE(7) and EN;
	OVen <= (E8(8) xor E8(7)) and EN;
	F  <= Fen;
	C  <= Cen;
	Z  <= Zen;
	N  <= Nen;
	OV <= OVen;

end Behavioral;

 

Edytowano przez kroszkanorber
  • Lubię! 1

Bądź aktywny - zaloguj się lub utwórz konto!

Tylko zarejestrowani użytkownicy mogą komentować zawartość tej strony

Utwórz konto w ~20 sekund!

Zarejestruj nowe konto, to proste!

Zarejestruj się »

Zaloguj się

Posiadasz własne konto? Użyj go!

Zaloguj się »
×
×
  • Utwórz nowe...