library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; use ieee.std_logic_unsigned.all; entity alu is port ( a, b: in std_logic_vector(7 downto 0); opcode: in std_logic_vector(2 downto 0); x: out std_logic_vector(7 downto 0) ); end alu; architecture arch of alu is begin process (a, b, opcode) case opcode is when I_AND => x <= a and b; when I_OR => x <= a or b; when I_NOT => x <= not a; when I_XOR => x <= a xor b; when I_ADD => x <= a + b; when I_SUB => x <= a - b; when I_ACC => x <= a; when I_DAT => x <= b; when others => x <= "XXXXXXXX"; end case; end process; end arch; package alu_pack is constant I_AND: std_logic_vector(2 downto 0) := "000"; ... end alu_pack;このALUのVHDL記述そのものは、意外と単純で、行う演算を指定する opcodeの値に応じて、出力xを、入力a, bから求める式を case文で切り替えているだけ、です。 (ちにみに後半のpackage以下で、演算の指定に使っている I_ANDなどの定数の値を定義しています。C言語での#defineのようなものと 理解しておいてください)
ここでちょっと面白いのは、その論理合成結果[p.77「論理回路図」]です。 1ビット分のALUは、入力であるa[n], b[n]からいろいろな演算回路を通し、、 そのうちの1つをopcaodeによって、セレクタを使って選ぶ、という 構成になっています。(※セレクタは[p.67]参照) 上から4つの論理演算は、そのまんま、なのですが、 真ん中の加算・減算のところが、ちょっと一工夫があります。 opcode=100のときは、xはa+b(加算)なので、加算器を通した 結果がxに出てきますが、この加算器のcin(下の桁からの桁上げ)は、 下半分の図からわかるように、最下位ビットのALUでは、opcode[0]に なっています。 opcode=100(加算)のときは、opcode[0]=0ですので、 まさに桁上げ伝播加算器(RCA)の構成となります。
ところがoppcode=101(減算)のときは、加算器のb側には b[n]をNOTゲートを通したもの(/b)が与えられています。 またこのときopcode[0]=1ですので、全体としては、 「a + /b + 1」が求められることになります。 ところが、/b + 1 とは、bの「2の補数」ですので、 2進数の数としては、bの符号を反転したもの(-b)と同じ意味となります。 (2の補数については、ここなどを参照) つまり出力xは、「a - b」と同じ意味となり、減算が行われていることに なります。