[8位二進制CPU的設計和實現] CPU基本電路的實現


CPU基本電路的實現

本文是對B站UP躊躇月光出的8位二進制CPU的設計和實現的文字教程復現第一部分 CPU基本電路的實現
相關 github 地址:https://github.com/StevenBaby/computer
PS:有錯誤的地方請指正,謝謝!共同學習,一起進步!

概述

這個視頻主要是分享8位二進制CPU的設計和實現。
首先,解釋一下為什么做這個視頻。眾所周知,計算機專業眾多課程中有一門課是計算機組成原理,這門課程實際上並不那么好理解,因為他涉及到了硬件。但是組成原理這門課又沒有對硬件部分做充分的描述,導致這門課沒有其他課那么容易學習,特別是中央處理器(CPU)部分的實現。那么我們一起來實現一個8位二進制CPU,就可以更加自然的理解計算機組成原理究竟說了些什么。
其次,關於做CPU或者說做一台計算機,做一台什么樣的計算機的問題,圖靈(1912-1954)給出過答案,圖靈在他的論文<可計算性>中給出了什么樣的事情是計算機可以做的,什么是做不到的,以及給出了計算機的抽象模型-圖靈機,其中就描述了計算機和機器的區別,區別就是支持任何條件轉移指令的機器就是計算機,也就是說我們要做一個支持條件轉移的計算機,在這篇論文中還介紹了另一種測試計算機的方法,這就是人們熟知的圖靈測試。最早引入條件轉移指令的人是英國數學家和經濟學家查爾斯.巴貝奇(1792-1871),大約在19世紀,巴貝奇就有了制造解析機的想法,不過巴貝奇的解析機並沒有在他有生之年實現。那么我們要做的CPU就是可以支持條件轉移指令的機器,這里推薦大家兩本書,一本是查爾斯的《編碼:隱匿在計算機軟硬件背后的語言》,也是這本書讓up有了想做此視頻的想法,第二本是李忠的《穿越計算機的迷霧》,可以作為前一本書的補充,值得大家一讀再讀。以上兩本就作為教材了,如果想盡快了解做什么,可以去下載這兩本書先讀一讀。工欲善其事必先利其器,本教程使用一個電路仿真的軟件logiccircuit(下面會提到)來制作CPU電路。

准備工作

  • 小白可以看看上面的兩本書的前面部分或者快速入門數電基礎

  • 下載仿真軟件logiccircuit下載地址

logiccircuit軟件使用方法

打開軟件,主窗口由以下幾個部分組成

  • 軟件提供模塊:軟件自身提供的一些基本輸入輸出單元和基本模塊
  • 自建模塊:通過下面的軟件提供模塊搭建的特殊功能模塊
  • 搭建操作窗口:拖動模塊連線和仿真展示的窗口
  • 開啟仿真按鈕:模塊搭建和連線之后開啟仿真的按鈕

輸入輸出單元

  • 輸入單元
    • 位寬:可選位寬如1位,8位
    • :搭建模塊時選擇接口位置
  • 輸出單元
    • 位寬:可選位寬如1位,8位
    • :搭建模塊時選擇接口位置
  • 按鈕/切換器
    • 符號:名字是模塊內部用的,特別是展示真值表時顯示。符號是模塊上表示該引腳的一個代號。
    • 切換器:切換器是鎖定狀態的,和按鈕不同,按鈕按下是一個狀態,彈開是一個狀態,切換器每按下彈起一次切換一次狀態
    • 針腳:和邊類似,搭建模塊時選擇接口位置
  • 常量:和輸入單元差不多,只不過是常量
  • 傳感器:暫時不涉及
  • 時鍾:提供時鍾信號
  • 分路器:用來合並分路針腳為總線
    • 分路針腳數目:引腳多的一端的針腳數
    • 分路針腳位寬:引腳多的一端的單個針腳的位寬
    • 組合針腳位置:單總線的位寬=分路針腳數目x分路針腳位寬,位置決定是輸入還是輸出,有三角標志的是低位
  • LED:方便顯示邏輯電平輸出,1 亮 0滅
  • 7段數碼管:顯示數字
  • LED矩陣
  • 圖形序列
  • 蜂鳴器
  • 探針:方便看某一處的電平輸出

基本元件

  • 非門

    • 邏輯表達式\(L=\overline{A}\)
    • 真值表
    A L
    0 1
    1 0
  • 三態門(上)

  • 三態門(下)

  • 與門

    • 邏輯表達式\(L=A\cdot B=AB\)
    • 真值表
    A B L
    0 0 0
    0 1 0
    1 0 0
    1 1 1
  • 與非門

    • 邏輯表達式\(L=\overline{A\cdot B}=\overline{AB}\)
    • 真值表
    A B L
    0 0 1
    0 1 1
    1 0 1
    1 1 0
  • 或門

    • 邏輯表達式\(L=A + B\)
    • 真值表
    A B L
    0 0 0
    0 1 1
    1 0 1
    1 1 1
  • 或非門

    • 邏輯表達式\(L=\overline{A + B}\)
    • 真值表
    A B L
    0 0 1
    0 1 0
    1 0 0
    1 1 0
  • 異或門

    • 邏輯表達式\(L=A\overline{B} + \overline{A}B\)
    • 真值表
    A B L
    0 0 0
    0 1 1
    1 0 1
    1 1 0
  • 同或門

    • 邏輯表達式\(L=\overline{A} \overline{B} + AB\)
    • 真值表
    A B L
    0 0 1
    0 1 0
    1 0 0
    1 1 1
  • ROM:只讀存儲器

  • RAM:隨機存儲器

真值表:選中自建模塊后,確保有輸入輸出單元,然后點擊菜單欄電路-真值表,即可查看該模塊的真值表

操作方法

總結的一些操作方法,有的可以在遇到了再回來看看

  • 新建模塊
    點擊菜單欄電路-新建邏輯電路,即可新建模塊
  • 修改自建模塊名稱
    選中模塊,點擊菜單欄電路-邏輯電路,即可修改名字,符號,類別
  • 交叉線的畫法
    按住Alt,點擊交叉點
  • 旋轉元器件
    ctrl+L

基本邏輯電路

半加器 Half Adder

參考工程:03 半加器

單位二進制加法:0 + 0 = 0(無進位)0 + 1 = 1(無進位)1 + 0 = 1(無進位)1 + 1 = 0(進位1)

寫成真值表(A,B輸入,S輸出,C進位輸出)為

A B S C
0 0 0 0
0 1 1 0
1 0 1 0
1 1 0 1

實現這樣一個運算的邏輯電路稱為半加器

半加器電路是指對兩個輸入數據位相加,輸出一個結果位進位沒有進位輸入的加法器電路。 是實現兩個一位二進制數加法運算電路

根據經驗我們得知,邏輯表達式為

\[\begin{aligned} S=\overline{A}B+A\overline{B} = A\oplus B\\ C=AB \end{aligned}\]

打開logiccircuit根據上面異或和與關系搭建門電路,驗證

  • 異或(XOR)門門實現出來

XOR

  • 然后用異或(XOR)門與門共同搭建半加器(Half Adder)

HA

  • 搭建完之后通過按鍵LED測試,符合真值表邏輯即可

Test

全加器 Full Adder 和加法器 8Adder

參考工程:04 全加器和加法器

全加器 Full Adder

全加器英語名稱為Full Adder,是用門電路實現兩個二進制數相加並求出和的組合線路,稱為一位全加器。一位全加器可以處理低位進位,並輸出本位加法進位。

將上面真值表補齊(CI是輸入低位進位)

A B CI S CO
0 0 0 0 0
0 0 1 1 0
0 1 0 1 0
0 1 1 0 1
1 0 0 1 0
1 0 1 0 1
1 1 0 0 1
1 1 1 1 1
  • 通過兩個半加器設計全加器

  • 搭建完之后通過按鍵LED測試,符合真值表邏輯即可

Test

補充:也可以通過ROM存儲器地址映射的方式實現全加器

CIAB當做地址的三位,S(低位)CO當做數據的兩位,填入

也可以實現全加器的功能。

8位加法器 8Adder

  • 將8個全加器級聯

  • 制作測試器測試
    • 8位開關
    • 8位LED

將其組合在一起測試

補充:這種全加器叫串形加法器,由於高位的運算需要等待低位的進位輸出,所以會有延遲,效率不是很高。
還有一種並行加法器可以實現同步,這里不多做介紹。事實上還可以通過前面的ROM實現方法實現低延遲運算。

補碼和減法

參考工程:05 補碼與減法

關於補碼:因為計算機采用的二進制,沒有符號位的概念,因此沒法實現減法操作,所以誕生出了補碼的概念。
這里拿時鍾舉例,時鍾有12點,12=01+11=01-1=0,所以1的補碼就是111減去1就是1加上1的補碼(11)

在二進制中,一個二進制數的補碼即為該二進制數的反碼+1,反碼則是每一位都取反,例如0001反碼1110補碼1111

取反器 Invert

  • 一位取反器

其實就是非門,只不過加上一位使能位E

E I O
0 0 0
0 1 1
1 0 1
1 1 0

根據以上真值表,采用異或門

  • 8位取反器

將八個取反器並聯

減法運算

  • 按鍵實現了取反+1的操作
  • 與門非門是為了在減法運算時屏蔽最高位的進位。

數碼管和譯碼電路設計

數碼管簡介

數碼管本質上就是LED,不同的位控制不同的LED,如下圖,從第0位到第7位,通過控制不同的LED來組合出數字。

通過以下電路測試一下

七段十六進制數碼管

參考工程:06 七段十六進制進制數碼管的制作

通過四位二進制輸入顯示0~F十六個數碼符號

A3 A2 A1 A0 number
0 0 0 0 0
0 0 0 1 1
0 0 1 0 2
0 0 1 1 3
0 1 0 0 4
0 1 0 1 5
0 1 1 0 6
0 1 1 1 7
1 0 0 0 8
1 0 0 1 9
1 0 1 0 A
1 0 1 1 b
1 1 0 0 C
1 1 0 1 d
1 1 1 0 E
1 1 1 1 F

以上也叫段碼表

單十六進制數碼管譯碼電路

陽極段碼表

A3 A2 A1 A0 number HEX
0 0 0 0 0 0x3F
0 0 0 1 1 0x06
0 0 1 0 2 0x5B
0 0 1 1 3 0x4F
0 1 0 0 4 0x66
0 1 0 1 5 0x6D
0 1 1 0 6 0x7D
0 1 1 1 7 0x07
1 0 0 0 8 0x7F
1 0 0 1 9 0x6F
1 0 1 0 A 0x77
1 0 1 1 b 0x7C
1 1 0 0 C 0x39
1 1 0 1 d 0x5E
1 1 1 0 E 0x79
1 1 1 1 F 0x71
  • 采用ROM映射4路地址線到8個數據上

將上述數字填入ROM的存儲單元中

將按鍵換成輸入即模塊的制作

雙十六進制數碼管譯碼電路
  • 將兩個單十六進制數碼管並聯,即可制作雙十六進制數碼管

  • 將雙數碼管放到之前制作的加法器中,即可測試數碼管

七段十進制數碼管

參考工程:07 七段十進制進制數碼管的制作

  • 同理,向ROM中寫入固定數據

  • 點擊另存為,將二進制文件保存到桌面,用vscode打開(下載插件Hex Editor)

這里我已經寫入了數據

  • 通過Python腳本寫入數據
import os
dirname = os.path.dirname(os.path.abspath(__file__))
with open(os.path.join(dirname,'test.bin'),'wb') as file:
    for var in range(256):
        var=str(var)
        var=int(var,base=16)
        byte = var.to_bytes(2,byteorder='little')
        file.write(byte)
  • 然后將二進制文件載入

數碼管高位消隱

要想讓高位為零時不亮,可以考慮先給單個數碼管加一個使能位。

解決思路就是做一個8位的二選一選擇器

單位二選一選擇器

當EN為0時,輸出等於B,與A無關
當EN為1時,輸出等於A,與B無關

八位二選一選擇器

8個二選一選擇器並聯

數碼管使能

如果EN為1,則數碼管使能,如果EN為0,則數碼管熄滅

消隱電路實現
  • 十六進制(雙數碼管)

將高位的輸入接入通過或門接入使能端,當全為0時,EN為0,數碼管熄滅

  • 十進制(三數碼管)

同理,將兩個高位的輸入用或門接入使能端,同時,防止出現例如208時中間的零被消隱掉,中間一位的或門需要加入最高位。

再放到原來的電路中測試一下

前面一部分都是組合邏輯電路部分,現在開始時序邏輯電路部分,區別在於,時序邏輯電路能夠保存電路狀態。

RS觸發器

參考工程:08 R-S觸發器

我們先看一下RS觸發器的真值表

R S Q Q'
0 0 不變 不變
0 1 1 0
1 0 0 1
1 1 0 0

該電路有以下特點:

  • 剛上電時,輸出的狀態是不確定的,只確定兩個輸出是相反的。
  • 當其中一個輸出為1時,輸出狀態立刻確定,見上面真值表。
  • 當兩個輸出都為0時,輸出狀態保持不變。
  • 當兩個輸出都為1時,輸出都為0,則無法通過單個輸出判斷狀態,此時觸發器狀態不確定(應避免此情況)。

該電路主要作用在於:如果R和S都為0時,電路狀態可以得到保存,這個功能也叫作鎖存器。

D觸發器

參考工程:09 D 觸發器

拋棄掉RS的鎖存功能,R和S總是相反的,將D接到S端,D取反接到R端,兩個輸入合成一個輸入,就構成了D觸發器。

再添加一個EN,作為鎖存功能(這樣做的目的是方便對鎖存功能進行統一管理)。具體實現如下:

D邊沿觸發器

參考工程:10 D 邊沿觸發器

上升沿觸發器:En上升沿的時候,D數據才會 寫到Q

這樣做的目的是在時鍾信號輸入時,只對上升沿信號做出動作(LED亮),忽略下降沿信號,這樣,時鍾信號一個周期完成一個動作。

解決初始狀態問題

上面的不管是RS觸發器還是D觸發器還是D邊沿觸發器,都存在剛上電時狀態不確定的情況,因此,需要添加設置其初始狀態的功能。

  • RS觸發器

  • D觸發器

  • D邊沿觸發器

D邊沿觸發器的應用

上面說到D邊沿觸發器可以讓時鍾信號一個周期完成一個動作。見下面一個應用電路:

  • 首先,上電,按下按鈕,完成給第一個D邊沿觸發器置1,其他清0的動作(如上,第一個LED亮)
  • 松開按鈕之后,第一個輸出=第二個輸入為1,其他輸入為0,時鍾信號一個周期將所有輸入寫入到輸出,此時變第一個輸出為1為第二個輸出為1=第三個輸入為1,其他為0,這樣一個周期,LED進行一次位移,形成跑馬燈的效果。

T觸發器和行波計數器

參考工程:11 T 觸發器和行波計數器

T觸發器的T的意思是Toggle,即翻轉,如果說D邊沿觸發器是一個周期做一個動作,T觸發器就是一個周期翻轉一次狀態(具體的動作),原理就是把輸出的非再接入到輸入。

T觸發器的應用-行波計數器

上面說到,T觸發器一個周期完成一次翻轉,兩次翻轉即構成輸出的一次周期。見下面的電路

第一個T觸發器的兩個周期構成第二個T觸發器的一個周期,第二個T觸發器的兩個周期構成第三個T觸發器的一個周期,依次類推。即構成了一個8位計數器,從0到255。

三態門和寄存器

參考工程:12 三態門和寄存器

上面提到的D邊沿觸發器可以在上升沿中將輸入寫入輸出,利用這樣的功能我們可以實現一個單字節存儲器

功能:通過Clear清0 ,Pre置1,在DI端輸入8位數據,給CP一個上升沿,DI數據就被寫入到DO上

問題:
總線沖突問題:如果將多個存儲器連到一起做數據交換,那么就會存在一個輸入會連到多個輸出的問題,就會發生數據沖突,那么有沒有辦法在需要數據交換時將兩個寄存器單獨連接在一起。這個辦法就是三態門。

三態門

三態門的作用就是當B失能時,輸入與輸出處於斷開狀態(高阻態),當B使能時,輸入與輸出處於連接狀態。

將八個三態門並聯得到八位三態門電路

這樣我們就可以解決上面說的總線沖突問題

寄存器

存儲器加上三態門可以構成寄存器

  • 端口S僅做比較有三態門和無三態門時的區別,實際並無此端口
  • 當W使能時,和時鍾信號一起作用,可以將存儲器輸入寫到存儲器輸出
  • 當R使能時,三態門連通,存儲器輸出連到寄存器輸出;當R不使能時,寄存器輸出處於高阻態。

R沒有使能

R使能后

三八譯碼器和存儲器組織

參考工程:13 三八譯碼器和存儲器組織

三八譯碼器

三八譯碼器,顧名思義,就是三位向八位的一個譯碼器,其真值表如下:

A2 A1 A0 O7 O6 O5 O4 O3 O2 O1 O0
0 0 0 1
0 0 1 1
0 1 0 1
0 1 1 1
1 0 0 1
1 0 1 1
1 1 0 1
1 1 1 1

邏輯電路

存儲器

前面我們實現了一個1byte的存儲器,或者說寄存器,現在我們要實現一個8byte寄存器,基本思路就是用一個三八譯碼器實現三位地址線對8個1byte存儲器的選擇。

  • 測試讀寫功能

存儲器擴展和讀寫

參考工程:14 存儲器擴展15 關於存儲器讀寫的問題

存儲器擴展

存儲器擴展分為字擴展位擴展

這里首先談一下位擴展,例如前面是8x1byte存儲器,現在擴展為8x2byte存儲器,只要將輸入輸出的位擴寬即可

其次是字擴展,例如前面是8x1byte存儲器,現在擴展為16x1byte存儲器,擴寬一位地址線(加一個二選一)即可

  • 加寬高位地址線

  • 加寬低位地址線

存儲器讀寫問題

這里存儲器的讀和寫是獨立開來的,這樣會在某些時刻造成沖突,所以要解決這個問題,就是讓存儲器在寫的時候沒法讀。做出以下修改:

  • 單字節存儲器

  • 8x1byte存儲器

  • 8x2byte存儲器

  • 16x1byteH存儲器

  • 16x1byteL存儲器


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM