理查一號 cpu - richard cpu1
DESCRIPTION
理查一號 CPU - Richard CPU1. 自己設計 CPU ,有可能嗎 ?. 想自己設計 CPU ,有可能嗎?這可是工業上的不傳之祕,哪有可能自己做一顆? 真的是這樣嗎? 或許 20 年前是這樣的,但現在可就不是了,有了 VHDL 與 FPGA 之後,我們真的可以用程式寫出一顆 CPU ,包含記憶體與測試案例都可以在你的 PC 上模擬出來後,燒到 FPGA 當中,就成了一顆 FPGA CPU 了。. 用程式寫出一顆 CPU. - PowerPoint PPT PresentationTRANSCRIPT
作者 : 陳鍾誠單位 : 金門技術學院資管系Email: [email protected] : http://ccc.kmit.edu.tw
日期 : 112/04/24
理查一號 CPU- Richard CPU1
自己設計 CPU ,有可能嗎 ? 想自己設計 CPU ,有可能嗎?這可是工業上的不傳之祕,哪有可能自己做一顆? 真的是這樣嗎? 或許 20 年前是這樣的,但現在可就不是了,有了 VHDL 與 FPGA 之後,我們真的可以用程式寫出一顆 CPU ,包含記憶體與測試案例都可以在你的 PC 上模擬出來後,燒到 FPGA 當中,就成了一顆 FPGA CPU 了。
2 陳鍾誠 - 112/04/24
用程式寫出一顆 CPU 當我在金門技術學院教計算機組織這門課的時候,開使對於自己設計一顆 CPU 有了 強烈的興趣,或許是因為我很喜歡程式設計,只要看到可以寫程式做出來的東西就 很想自己寫一個,因為、有了 FPGA 之後, CPU 居然變成一種軟體了。
3 陳鍾誠 - 112/04/24
失敗的嘗試 也可能是因為心虛,教計算機結構的老師沒有自己設計過 CPU ,那也太遜咖了, 於是、我花了三個星期,反覆的用 Altera 的 Quartus 設計修改一顆自己設計的 CPU , 但還是無法成功。
4 陳鍾誠 - 112/04/24
發現理查一號 最後、我決定看看網路上是否有人教人設計 CPU ,找到很多, 但是真正將程式與原理講得很清楚的很少,華聖頓大學的 William D. Richard 在 Introduction To Digital Logic And
Computer Design 課程中,將 CPU 的設計原理講得很清楚,然後更用 200 行的 VHDL 設計出一顆 CPU , 接著再加入記憶體後建構出一台測試電腦,總共寫了 315 行的 VHDL 程式,並且在 投影片 當中詳細的交待了其設計細節, 並給出模擬的結果,非常令人激賞。
以下我們將深入解析這顆 CPU 的設計方式與運作原理,我們將這顆 CPU 稱為 理察一號。 5 陳鍾誠 - 112/04/24
理查一號的架構
6 陳鍾誠 - 112/04/24
暫存器集 – 5 個 pc : 程式計數器 (Program Counter) alu : ALU 的輸出暫存器 (Arithmetic Unit Output) iReg : 指令暫存器 (Instruction Register) acc : 累積器 (Accumulator) iar : 間接定址暫存器 (Indirect Address Register)
7 陳鍾誠 - 112/04/24
signal pc: std_logic_vector(adrLength-1 downto 0); -- program counter, 程式計數器signal iReg: std_logic_vector(wordSize-1 downto 0); -- instruction register, 指令暫存器signal iar: std_logic_vector(adrLength-1 downto 0); -- indirect address register, 間接位址暫存器signal acc: std_logic_vector(wordSize-1 downto 0); -- accumulator, 累積器signal alu: std_logic_vector(wordSize-1 downto 0); -- alu output, 算術結果暫存器
理查一號的指令集代碼 指令 說明 運算方法0000 halt 暫停 (halt execution)0001 negate 反相 (negation) ACC := -ACC
1xxx load 立即載入 (immediate load) if sign bit of xxx is 0 then ACC := 0xxx else ACC := fxxx
2xxx dload 直接載入 (direct load) ACC := M[0xxx]
3xxx iload 間接載入 (indirect load) ACC := M[M[0xxx]]
4xxx dstore 直接儲存 (direct store) M[0xxx] := ACC
5xxx istore 間接儲存 (indirect store) M[M[0xxx]] := ACC
6xxx br 分枝 (branch) PC := 0xxx
7xxx brZero 零分枝 (branch if zero) if ACC = 0 then PC := 0xxx
8xxx brPos 正分枝 (branch if positive) if ACC > 0 then PC := 0xxx
9xxx brNeg 負分枝 (branch if negative) if ACC < 0 then PC := 0xxx
axxx add 加法 ACC := ACC + M[0xxx]8
指令集說明 在上述指令表中, halt 與 negate 由於沒有運算元 ( 參數 ) ,因此被編碼為 16 進位的 0000 與 0001
其他指令都具有一個記憶體位址運算元,這些指令的前 4 個 bit 用來表示運算碼, 後 12 個 bit 用來表示記憶體位址 ( 運算元 : 參數 )
指令共可分為四群,第一群為載入運算 (load, dload, iload) ,第二群為儲存 (dstore, istore) 第三群為分枝 (br, brZero, brZero, brPos, brNeg) , 第四群只有一個指令,就是加法運算 (add) 。
9 陳鍾誠 - 112/04/24
指令解碼器的設計
10 陳鍾誠 - 112/04/24
procedure decode is begin-- Instruction decoding.case iReg(15 downto 12) iswhen x"0" =>
if iReg(11 downto 0) = x"000" then state <= halt;
elsif iReg(11 downto 0) = x"001" then state <= negate;
end if;when x"1" => state <= mload;when x"2" => state <= dload;when x"3" => state <= iload;when x"4" => state <= dstore;when x"5" => state <= istore;when x"6" => state <= branch;when x"7" => state <= brZero;when x"8" => state <= brPos;when x"9" => state <= brNeg;when x"a" => state <= add;when others => state <= halt;end case;
end procedure decode;
指令提取階段 fetch
11 陳鍾誠 - 112/04/24
when fetch =>
-- 降 : if tick = t0 then m_en <= ‘1’; aBus <= pc; end if; 讓 aBus<=pc, 啟動記憶體 , 以讀取指令 if tick = t1 then -- 擷取狀態 , 時態 (t1)
iReg <= dBus; -- 此時, dBus 上應已有指令,將其放入指令暫存器 iReg
end if;
if tick = t2 then -- 擷取狀態 , 時態 (t2)
decode; pc <= pc + '1'; tick <= t0; -- 解碼,同時將 pc 前進到下一個指令,回到 t0
end if;
-- 降 : if tick = t2 then m_en <= '0'; aBus <= (aBus'range => '0'); end if; 關閉記憶體
算術指令
12 陳鍾誠 - 112/04/24
when halt => tick <= t0; -- do nothing -- 暫停狀態
when negate => acc <= alu; wrapup; -- 負號指令 , 將 alu 的輸出傳回累積器 acc 中
when add => -- 處理 add 加法指令-- 降 : if tick = t0 then m_en <= '1'; aBus <= x"0" & iReg(11 downto 0); end if;
if tick = t1 then acc <= alu; end if; -- t1, 將 alu 的輸出暫存器傳給累積器 acc
-- 降 : if tick = t2 then m_en <= '0'; aBus <= (aBus'range => '0'); end if;
if tick = t2 then wrapup; end if; -- t2, add 指令結束,前進到下一個指令
when others => state <= halt;
立即載入指令 mload
13 陳鍾誠 - 112/04/24
when mload => -- 處理 mload 立即值載入指令 ,
-- 擴展立即值 ireg(11..0) 為 16 位元,送到累積器 if iReg(11) = '0' then -- sign extension
acc <= x"0" & ireg(11 downto 0); -- 若符號位元為 0, 則將指令暫存器 ireg(11-0)
補 0
else
acc <= x"f" & ireg(11 downto 0); -- 若符號位元為 1, 則將指令暫存器 ireg(11-0) 補 1
end if;
wrapup; -- 本指令結束,前進到下一個指令
直接載入指令 dload
14 陳鍾誠 - 112/04/24
when dload => -- 處理 dload 記憶體載入指令-- t0 : 讓 aBus<=iReg(11..0), 啟動記憶體 , 以讀取資料-- 降 : if tick = t0 then m_en <= ‘1’; aBus <= x“0” & iReg(11 downto 0); end if;
if tick = t1 then acc <= dBus; end if; -- t1, 將資料匯流排 dBus 的資料傳給累積器 acc
-- 降 : if tick = t2 then m_en <= ‘0’; aBus <= (aBus‘range => ’0‘); end if; 關閉記憶體 if tick = t2 then wrapup; end if; -- t2, dload 指令結束,前進到下一個指令
間接載入指令 iload
15 陳鍾誠 - 112/04/24
when iload => -- 處理 iload 記憶體間接載入指令-- 降 : if tick = t0 then m_en <= '1'; aBus <= x"0" & iReg(11 downto 0); end if;
if tick = t1 then iar <= dBus; end if; -- t1, 將資料匯流排 dBus 的資料傳給間接位址暫存器 iar
-- 降 : if tick = t2 then m_en <= ‘0’; aBus <= (aBus‘range => ’0‘); end if; 關閉記憶體-- 降 : if tick = t3 then m_en <= ‘1’; aBus <= iar; end if; 讓 aBus<=iar, 啟動記憶體 , 以讀取資料if tick = t4 then acc <= dBus; end if; -- t4, 將資料匯流排 dBus 的資料傳給累積器 acc
-- 降 : if tick = t5 then m_en <= ‘0’; aBus <= (abus‘range => ’0‘); end if; 關閉記憶體if tick = t5 then wrapup; end if; -- t5, iload 指令結束,前進到下一個指令
直接儲存指令 dstore
16 陳鍾誠 - 112/04/24
when dstore => -- 處理 dstore 記憶體儲存指令-- 降 :if tick = t0 then m_en <= ‘1’; aBus <= x“0” & iReg(11 downto 0); end if;
-- 讓 aBus<=iReg(11..0), 啟動記憶體 , 以寫入資料-- 降 :if tick = t1 then m_rw <= ‘0’; dBus <= acc; end if;
-- 將累積器 acc 傳到資料匯流排 dBus, 等待寫出-- 降 :if tick = t3 then m_rw <= ‘1’; end if; 啟動寫出動作-- 降 :if tick = t4 then
-- 降 : m_en <= ‘0’; aBus <= (abus‘range => ’0‘); dBus <= (dBus’range => ‘Z’); 關閉記憶體-- 降 :end if;
if tick = t4 then wrapup; end if; -- t4, dstore 指令結束,前進到下一個指令
直接儲存指令 dstore
17 陳鍾誠 - 112/04/24
when istore => -- 處理 istore 記憶體間接儲存指令-- 降 :if tick = t0 then m_en <= '1'; aBus <= x"0" & iReg(11 downto 0); end if;
if tick = t1 then iar <= dBus; end if; -- t1, 將資料匯流排 dBus 的資料傳給間接位址暫存器 iar
-- 降 :if tick = t2 then m_en <= ‘0’; aBus <= (aBus‘range => ’0‘); end if; 關閉記憶體-- 降 :if tick = t3 then m_en <= ‘1’; aBus <= iar; end if; 讓 aBus<=iar, 啟動記憶體 , 以寫入資料-- 降 :if tick = t4 then m_rw <= ‘0’; dBus <= acc; end if; 關閉記憶體-- 降 :if tick = t6 then m_rw <= ‘1’; end if; 啟動寫出動作-- 降 :if tick = t7 then
-- 降 : m_en <= ‘0’; aBus <= (abus‘range => ’0‘); dBus <= (dBus’range => ‘Z’); 關閉記憶體-- 降 :end if;
if tick = t7 then wrapup; end if; -- t7, istore 指令結束,前進到下一個指令
跳躍指令
18 陳鍾誠 - 112/04/24
when branch => -- 處理 branch 無條件跳躍指令 pc <= x"0" & iReg(11 downto 0); -- 將跳躍位址 iReg(11..0) 傳給程式計數器 pc
wrapup; -- branch 指令結束,前進到下一個指令when brZero => -- 處理 brZero 零跳躍指令 if acc = x"0000" then pc <= x"0" & iReg(11 downto 0); end if; -- 如果累積器 acc=0, 則 pc<=iReg(11..0)
wrapup; -- brZero 指令結束,前進到下一個指令when brPos => -- 處理 brPos 正跳躍指令 if acc(15) = '0' and acc /= x"0000" then -- 如果累積器 acc > 0,
pc <= x"0" & iReg(11 downto 0); -- 則 pc<=iReg(11..0)
end if;
wrapup; -- brPos 指令結束,前進到下一個指令when brNeg => -- 處理 brNeg 負跳躍指令 if acc(15) = ‘1’ then pc <= x“0” & iReg(11 downto 0); end if; -- 如果累積器 acc < 0, 則 pc<=iReg(11..0)
wrapup; -- brNeg 指令結束,前進到下一個指令
理查一號的介面
19 陳鍾誠 - 112/04/24
entity cpu is port (clk, reset : in std_logic;m_en, m_rw : out std_logic; aBus : out std_logic_vector(adrLength-1 downto 0);dBus : inout std_logic_vector(wordSize-1 downto 0);
-- these signals "exported" so they can be monitored in post-P&R simulationpcX, iarX : out std_logic_vector(adrLength-1 downto 0);iregX, accX, aluX : out std_logic_vector(wordSize-1 downto 0));
end cpu;
ALU 的設計
20 陳鍾誠 - 112/04/24
alu <= (not acc) + x"0001" when state = negate else acc + dbus when state = add else (alu'range => '0');
理查一號的狀態 理查一號採用 Mealy 型有限狀態機的設計方式
Mealy 型狀態機的由輸入與狀態兩者決定。 在理查一號中,輸出由狀態 state 與時脈 t0-t7 決定。
理查一號當中的狀態有 標準狀態: reset, fetch, halt 指令狀態: negate, mload, dload, iload, dstore, istore, brahch, brZero,
brPos, brNeg, add 等。 每個指令最多分為 8 個時脈 (t0-t7) 。
21 陳鍾誠 - 112/04/24
type state_type is (reset_state, fetch, halt, negate, mload, dload, iload,dstore, istore, branch, brZero, brPos, brNeg, add
);
signal state: state_type;
type tick_type is (t0, t1, t2, t3, t4, t5, t6, t7);signal tick: tick_type;
重開機
22 陳鍾誠 - 112/04/24
if reset = '1' then state <= reset_state; tick <= t0; pc <= (pc'range => '0'); iReg <= (iReg'range => '0'); acc <= (acc'range => '0'); iar <= (iar'range => '0');else tick <= nextTick(tick) ; -- advance time by default case state is when reset_state => state <= fetch; tick <= t0; when fetch =>…
ALU 的 VHDL 程式
23 陳鍾誠 - 112/04/24
entity top is port(clk, reset: in STD_LOGIC;mem_enX, mem_rwX : out std_logic;aBusX : out std_logic_vector(adrLength-1 downto 0);dBusX : out std_logic_vector(wordSize-1 downto 0);pcX, iarX : out std_logic_vector(adrLength-1 downto 0);iregX, accX, aluX : out std_logic_vector(wordSize-1 downto 0));
end top;