วันศุกร์ที่ 26 กุมภาพันธ์ พ.ศ. 2559

divider

จากโจทย์การทดลองให้ออกแบบวงจรหารแบบ Sequential สำหรับเลขจำนวนเต็ม Unsigned Integers ขนาด 32 bit

# Unsigned Integers คือ เลขจำนวนเต็มที่ไม่มี sign bit บอกว่าบวกหรือลบ ค่าที่ได้จะมีแต่ค่าบวก

ขา input มี
clk คือ สัญญาณ clk สำหรับควบคุมการทำงานของระบบตามขอบขาขึ้นของสัญญาณ
a ตัวตั้งขนาด 32 bit
b ตัวหารขนาด 16 bit
start ขา บังคับการทำงาน เมื่อให้เป็น 1 จะเริ่มการหาร

ขา output มี
q เป็น ผลหารขนาด 16 bit
r เป็น เศษผลหารขนาด 16 bit
done เป็น เมื่อเปลี่ยนจาก 0 เป็น 1 หมายถึงเสร็จกระบวนการหารแล้ว

โดยหลักการที่ใช้คือ 
ให้ a เป็น 1000 คือ 8
ให้ b เป็น 0010 คือ 2

เราจะให้ remainder เป็น a และ ดูว่า ถ้า remainder มากกว่า b ให้เอา b ลบ remainder และ shift quantient ไป ทางซ้าย และ ใส่ 1 ไว้ท้าย และ shift right b เพื่อเลื่อนหลัก

ถ้า remainder น้อยกว่า b ก็จะไม่ลบ remainder ด้วย b แต่จะ shift b ไปทางขวา และ shift left quantient และ assign 0 ไว้ท้าย

ทำแบบนี้ไปเรื่อยๆ จนกว่า remainder จะเป็น 0 ทั้งหมด หรือ เช็คไปจนครบ ขนาด quantient+1 รอบ
เช่น quantient ขนาด 32 bit ก็วนลูปเช็ค 33 รอบ หลังจากนั้นเมื่อตรงเงื่อนไขแล้วก็ latch ข้อมูล ให้ quatntient และ remainder ออกมาเป็น output

pseudocode



โจทย์ตัวอย่าง


เมื่อนำหลักการนี้มาออกแบบวงจรด้วย quartus เขียนด้วยภาษา vhdl

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.numeric_std.ALL;
use IEEe.STD_LOGIc_ARITH.ALL;
use IEEE.std_logic_unsigned.all;

entity divider is
generic (WIDTH :integer := 32);
port ( clk : in std_logic;
start : in std_logic;
done : out std_logic;
a : in std_logic_vector(WIDTH-1 downto 0);
b : in std_logic_vector((WIDTH/2)-1 downto 0);
q : out std_logic_vector((WIDTH/2)-1 downto 0);
r : out std_logic_vector((WIDTH/2)-1 downto 0)
);
end divider;

architecture behave of divider is
signal temp_b : std_logic_vector(WIDTH-1 downto 0);
signal temp_q : std_logic_vector((WIDTH/2)-1 downto 0);
signal temp_r : std_logic_vector(WIDTH-1 downto 0);
signal operate : std_logic := '1';  -- เอาไว้ตรวจสอบดูว่าหารเสร็จหรือยัง
signal count : integer := 0;

begin
process(clk)
begin
if rising_edge(clk) then
done <= operate;
if start = '1' then
temp_r <= a;
temp_b <= b&conv_std_logic_vector(0,WIDTH/2);
operate <= '0';  -- assign ให้เป็น 0 เพื่อให้รู้ว่ากำลังทำการหารอยู่

elsif count = (WIDTH/2)+1 then
count <= 0;  -- reset count
operate <= '1';  -- สิ้นสุดการหาร

elsif temp_r >= temp_b and operate = '0' then
temp_r <= temp_r-temp_b;
temp_q <= temp_q((WIDTH/2)-2 downto 0)&'1';  -- shift left
temp_b <= '0'&temp_b(WIDTH-1 downto 1);  -- shift right
count <= count + 1;

elsif temp_b >= temp_r and operate = '0' then
temp_q <= temp_q((WIDTH/2)-2 downto 0)&'0';  -- shift left
temp_b <= '0'&temp_b(WIDTH-1 downto 1);  -- shift right
count <= count + 1;

elsif operate = '1' or (temp_r = conv_std_logic_vector(0,WIDTH)) then
q <= temp_q;
r <= temp_r((WIDTH/2)-1 downto 0);
end if;
end if;
end process;
end behave;


รูป Vhdl Testbench (จำลองการทำงาน)



ทดลองหารแบบมีเศษเหลือ
126/8 ได้ 15เศษ6

4

ทดลองหารแบบลงตัว
250/5 ได้ 50เศษ0

multiple

จากโจทย์การทดลองให้ออกแบบวงจรคูณแบบ Sequential สำหรับเลขจำนวนเต็ม Unsigned Integers ขนาด 16 bit

# Unsigned Integers คือ เลขจำนวนเต็มที่ไม่มี sign bit บอกว่าบวกหรือลบ ค่าที่ได้จะมีแต่ค่าบวก

ขา input มี
clk คือ สัญญาณ clk สำหรับควบคุมการทำงานของของระบบ
a ตัวตั้งขนาด 16 bit
b ตัวคูณขนาด 16 bit
start ขา บังคับการทำงาน เมื่อให้เป็น 1 จะเริ่มการคูณ

ขา output มี
p เป็น ผลคูณขนาด 32 bit
done เป็น เมื่อเปลี่ยนจาก 0 เป็น 1 หมายถึงเสร็จกระบวนการคูณแล้ว

โดยหลักการที่ใช้คือ 
ให้ a เป็น 0101 คือ 5
ให้ b เป็น 0011 คือ 3

เราจะดูตำแหน่งตรง ตัวขวาสุดของ b ถ้าเป็น 1 ให้ เอา a มาบวกกับ product แล้วทำการ shift a ไปทางซ้ายเพื่อเป็นการเลื่อนหลัก และ shift b ไปทางขวาเพื่อเช็ค bit ถัดไป

ถ้าขวาสุดของ b เป็น 0 จะไม่เอา a มาบวกกับ product เพิ่ม จะ shift a กับ b อย่างเดียว

โดยที่จำนวนรอบในการเช็ค b จะวนแค่ เท่ากับขนาดของ ตัว b หรือเมื่อจนกว่าค่าของตัว b จะเป็น 0 ทั้งหมด เมื่อนับครบแล้วก็จะทำการ latch ข้อมูลผลคูณออกมาเป็น output

pseudocode


เมื่อนำหลักการนี้มาออกแบบวงจรด้วย quartus เขียนด้วยภาษา vhdl

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.numeric_std.ALL;
use IEEe.STD_LOGIc_ARITH.ALL;
use IEEE.std_logic_unsigned.all;

entity multiplier is
generic(WIDTH :integer := 32);
port( 
clk : in std_logic;
start : in std_logic;
done : out std_logic;
a : in std_logic_vector((WIDTH/2)-1 downto 0);
b : in std_logic_vector((WIDTH/2)-1 downto 0);
p : out std_logic_vector(WIDTH-1 downto 0)
);
end multiplier;

architecture behave of multiplier is
signal temp_a : std_logic_vector(WIDTH-1 downto 0);
signal temp_b : std_logic_vector((WIDTH/2)-1 downto 0);
signal count : integer := 0;
signal operate : std_logic := '1';  -- เอาไว้ตรวจสอบดูว่าคูณเสร็จหรือยัง
signal product : std_logic_vector(WIDTH-1 downto 0);
  
begin
process(clk)
begin
if rising_edge(clk) then
done <= operate;  
if start = '1' then
temp_a <= conv_std_logic_vector(0,WIDTH/2)&a;
temp_b <= b;
operate <= '0';  -- assign ให้เป็น 0 เพื่อให้รู้ว่ากำลังทำการคูณอยู่

elsif count = WIDTH/2 then
count <= 0;  -- reset count
operate <= '1';  -- สิ้นสุดการคูณ

elsif temp_b(0) = '1' and operate = '0' then
product <= product+temp_a;
temp_b <= '0'&temp_b((WIDTH/2)-1 downto 1);  -- shift_right
temp_a <= temp_a(WIDTH-2 downto 0)&'0';  -- shift_left
count <= count + 1;
elsif temp_b(0) = '0' and operate = '0' then
temp_b <= '0'&temp_b((WIDTH/2)-1 downto 1);  -- shift_right
temp_a <= temp_a(WIDTH-2 downto 0)&'0';  -- shift_left
count <= count + 1;
elsif operate = '1' or (temp_b = conv_std_logic_vector(0,WIDTH/2)) then -- ถ้า คูณครบจำนวน bit หรือ ตัวคูณ b เป็น 0 ทั้งหมดให้ latch ข้อมูลออกเป็น output
p <= product;
end if;
end if;
end process;
end behave;

รูป Vhdl Testbench (จำลองการทำงาน)



ทดลอง ให้ a และ b เป็น 12 ได้ ผลลัพธ์ 144





ทดลอง ให้ a และ b เป็น 23 กับ 12 ได้ ผลลัพธ์ 276


full adder n bit

ในการทำ full adder ขนาด n bit คือการนำ full adder 1 bit มาต่ออนุกรมกันโดย โดย carryout(เลขทด
จาก bit ก่อนหน้า)จะต่อไปยัง carry in ของ bit ถัดไป และ



รูปวงจร full adder ขนาด 8 bit


ที่มา:ไฟล์ pdf handout2 ประกอบการเรียนวิชา computer organization

จากรูปจะมีขาควบคุมการ บวกและลบอยู่เรียก sub ถ้าเป็น 0 ให้บวก ถ้า เป็น 1 ให้ ลบ
โดยการลบกันของเลขฐานสองก็คือ การบวกด้วยเลขจำนวนเต็มลบ
เช่น 7-3 คือ 7+(-3) = 4

โดยการจะเปลี่ยนค่าจาก 3 เป็น -3 เพื่อ จะนำมาบวกในวงจร full adder จะใช้วิธีการ 2 Complement

เลข 3 คือ 0011 ให้สลับเลขทุก bit เป็นค่าตรงกันข้ามและ บวก 1
และค่อยนำค่าที่ทำ 2Complement แล้วไป บวกกับ ตัวตั้ง(A)

เมื่อนำหลักการนี้มาออกแบบวงจรด้วย quartus เขียนด้วยภาษา vhdl

library ieee;
use ieee.std_logic_1164.all;
entity add_sub is 
generic(WIDTH : integer := 8);
    Port ( a : in  STD_LOGIC_VECTOR (WIDTH-1 downto 0);
           b : in  STD_LOGIC_VECTOR (WIDTH-1 downto 0);
           addsub : in  STD_LOGIC;
           o : out  STD_LOGIC_VECTOR (WIDTH-1 downto 0);
           cout : out  STD_LOGIC);
end add_sub;

architecture behave of add_sub is
signal carry : std_LOGIC_VECTOR(WIDTH downto 0);
signal b_xor_sub : std_LOGIC_VECTOR(WIDTH-1 downto 0);
component full_adder is
port( 
      a , b, c_in : in std_logic;  -- a เป็นตัวตั้ง, b เป็นตัวบวก, c_in คือ ตัวทดจากหลักก่อนหน้า
      sum,c_out   : out std_logic);  -- sub คือผลบวก, c_out คือตัวทดไปหลักถัดไป
end component;
component xor2 is
port(
a: in std_logic;
b: in std_logic;
y: out std_logic
);
end component;
begin
U0: xor2 port map(addsub,'0',carry(0));
adder : for i in 0 to WIDTH-1 generate
U1 : xor2 port map(b(i),addsub,b_xor_sub(i));
adder : full_adder port map(a(i),b_xor_sub(i),carry(i),o(i),carry(i+1));
end generate;
U2: xor2 port map(carry(WIDTH),addsub,cout);

end behave;

รูป Vhdl Testbench (จำลองการทำงาน)



เมื่อให้ขา addsub เป็น 0 คือ การนำ a และ b มา บวกกัน 22+80 ได้ 102



เมื่อให้ขา addsub เป็น 1 คือ การนำ a และ b มาลบกัน 22-80 ได้ -58


วันพฤหัสบดีที่ 25 กุมภาพันธ์ พ.ศ. 2559

logic gate 'xor2'

อีกหนึ่ง component ที่ต้องใช้ในการออกแบบวงจร add_sub เลขฐานสอง คือ logic gate xor2

ตารางค่าความจริงของ xor

ที่มา:https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiEuhzaObAKtLod_66wZS-32fwslIk6Uw_cgJEbhQTTO8934UCom49hD7xEzkbYVsmiuO97BtwwlNvb4l0rbsXdRwhYEU1b2bzWpq1OnY_Gpe5Cqj9eY-j0oW3_G1myvbVNB6vKCScvHMvQ/s1600/xor_gate_truth_table.png

# ถ้า x1กับ x0 เหมือนกัน z จะมีค่าเป็น 0 ถ้า ต่างกัน z จะเป็น 1

code:
vhdl logic gate xor2 

library ieee;
use ieee.std_logic_1164.all;
entity xor2 is
port(
a: in std_logic;
b: in std_logic;
y: out std_logic
);
end xor2;

architecture dataflow of xor2 is
begin
y <= a xor b;

end dataflow;

รูปสัญลักษณ์ของ logic gate xor2


ที่มา:https://upload.wikimedia.org/wikipedia/commons/thumb/0/01/XOR_ANSI.svg/800px-XOR_ANSI.svg.png

วงจร full adder

จะทำวงจร add_sub เลขฐานสอง component ที่ต้องใช้อย่างแรกคือ full adder โดยหลักการคือ ขา
input จะต้องมี
A ค่าตัวตั้ง
B ค่าที่จะมาบวก
Cin คือเลขที่ทดมาจาก bit ก่อนหน้า

output จะมี
S ผลบวก
Cout เลขทดสำหรับ bit ถัดไป

ที่มา:https://www.electronics-micros.com/img/electronics/full-adder2.jpg

full adder table จากตารางจะเห็นว่า ค่า sub จะเป็น 1 เมื่อ
1) aและ b แค่ตัวใดตัวหนึ่งเป็น 1 และ C in เป็น 0
2) aและ b เป็น 1 ทั้งคู่ แต่ม่ Cin มาบวกเพิ่ม

ค่า Cout จะเป็น 1 เมื่อ
1) a และ b เป็น 1 ทั้งคู่
2) a หรือ b เป็น 1 ตัวใดตัวหนึ่ง และ มี Cin มาบวกเพิ่ม

 เมื่อนำหลักการนี้มาเขียนออกแบบวงจรโดยใช้ภาษา vhdl

library ieee;
use ieee.std_logic_1164.all;

entity full_adder is
port( 
      a , b, c_in : in std_logic;  -- a เป็นตัวตั้ง, b เป็นตัวบวก, c_in คือ ตัวทดจากหลักก่อนหน้า
      sum,c_out   : out std_logic);  -- sub คือผลบวก, c_out คือตัวทดไปหลักถัดไป
end full_adder;

architecture dataflow of full_adder is
begin
  c_out <= ((a xor b) and c_in) or (a and b);
  sum   <= (a xor b) xor c_in;
end dataflow;

รูปขา i/o ของ single bit full adder

ที่มา:http://www.circuitstoday.com/wp-content/uploads/2010/04/Single-bit-Full-Adder.gif

รูป logic ภายใน full adder

ที่มา:https://upload.wikimedia.org/wikipedia/commons/thumb/a/a9/Full-adder.svg/550px-Full-adder.svg.png