欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Python代碼模擬CPU工作原理

 更新時間:2023年01月27日 16:16:23   投稿:yin  
Python代碼來實現(xiàn)一個最簡單的CPU。用代碼模擬大的部件,使大家從原理上理解CPU工作。使它可編程,支持加減法運算、讀寫內(nèi)存、無條件跳轉(zhuǎn)、條件跳轉(zhuǎn)的功能。

理解 CPU 工作原理,重要的是理解 pc 不停地自增地址,順序執(zhí)行程序指令。當(dāng)遇到跳轉(zhuǎn)指令時,會將 pc 重置為新地址。在順序執(zhí)行程序指令的過程中,每一步都是解析程序指令、產(chǎn)生控制信號,進而控制所有 CPU 相關(guān)器件的工作狀態(tài),產(chǎn)生程序計算結(jié)果,保存進各寄存器或者RAM 中。

本文使用四十行 Python 代碼來實現(xiàn)一個最簡單的 CPU。使它可編程,支持加減法運算、讀寫內(nèi)存、無條件跳轉(zhuǎn)、條件跳轉(zhuǎn)的功能。

Python層面的實驗和書面上的概念,不足以支撐去論證從Python代碼到CPU執(zhí)行的復(fù)雜過程,也不足以支撐從CPU讀的內(nèi)存地址到Python內(nèi)存管理上的內(nèi)存地址之間復(fù)雜的關(guān)系,但算是針對此淺層現(xiàn)象的一個合理的猜想。

一、引言

從宏觀上,CPU 工作原理是讀取內(nèi)存數(shù)據(jù),在 ALU 中完成計算,然后保存進內(nèi)存,輸入輸出系統(tǒng)完成了同其他外設(shè)交互;從中觀上看,CPU 工作原理就是本文講述的 pc 從 0 開始,讀取程序指令寄存器,然后解析指令,控制各部件工作的具體過程;從微觀上看,pc 程序計數(shù)器、ALU 數(shù)字邏輯運算單元,RAM 存儲器在內(nèi)的所有 CPU 相關(guān)部件,其實都是一個個三極管,這些三極管在電流作用下導(dǎo)通或者截止,完成了數(shù)字邏輯運算、保持記憶狀態(tài)、產(chǎn)生脈沖信號的所有功能。

二、CPU工作原理

讓我們分別介紹各部件工作原理,之后介紹它們怎么協(xié)同工作。

1 各部件工作原理

在真實 CPU 中,都有相應(yīng)物理電路與其對應(yīng),它們的功能分別是:

    pc 計數(shù)器,從 0 開始產(chǎn)生 0,1,2,……計數(shù)可以清零,也可以從外部輸入一個數(shù),從這個數(shù)從新開始計數(shù),這被稱為置位。用于指示程序和數(shù)據(jù)存取位置。

    RAM,存儲數(shù)據(jù)的隨機存儲器,支持根據(jù)地址(0x01 這種整形)讀取數(shù)據(jù),根據(jù)地址和寫入信號 w 寫入數(shù)據(jù)。用于存儲程序和數(shù)據(jù)。

    寄存器,存儲 8 bit 信息的存儲器,根據(jù) w 信號為 1 寫入當(dāng)前數(shù)據(jù),w 為 0 表示讀取。類似 RAM,但只能存儲 8 bit 信息。常用于存儲指令、地址和計算中間量。

    加法器,完成兩數(shù)加減法運算,sub 為 1 時表示減法,ci 為 1 時表示進位。這個器件是核心器件,用于構(gòu)成 ALU(算數(shù)邏輯單元)。真實 CPU 是采用邏輯門搭建,還有乘法器、邏輯運算單元,等等。

    21選擇器,相當(dāng)于單刀雙擲開關(guān),根據(jù) s21 信號,決定 8 bit 輸出來自或左或右 8 bit 輸入端。

2 協(xié)同工作原理

整個數(shù)據(jù)通路從程序計數(shù)器 pc 開始,計數(shù)器從 0 開始輸出數(shù)字 0,1,2,3,4……。指令 RAM 和數(shù)據(jù) RAM 中分別存儲程序代碼和數(shù)據(jù)。RAM 采用數(shù)字表示的位置訪問、存儲數(shù)據(jù)。根據(jù)計數(shù)器地址 0,1,2之類,將 RAM 中的數(shù)據(jù)分別放入指令寄存器 IR 和數(shù)據(jù)寄存器 DR。寄存器相當(dāng)于容器、變量,存儲了 RAM 給它的數(shù)據(jù)。

指令寄存器中的指令碼解碼產(chǎn)生 CPU 控制指令,這些 0 和 1 分別表示低電平和高電平信號,而電平信號則控制諸如加法器進位與否,是否打開減法,是否使能寄存器寫入,選擇 21選擇器哪一個輸入作輸出,是否重置計數(shù)器,等等。所以,指令其實是控制 CPU 各部件協(xié)同工作的電信號。

數(shù)據(jù)寄存器中的數(shù)據(jù)分別走向加法器 adder 來進行加法、減法運算后流向 21選擇器,也可能直接流向 21選擇器等待選擇。21選擇器選擇后,數(shù)據(jù)進入累加寄存器 AC 。累加器的數(shù)據(jù)根據(jù) ac 信號是否為高電平 1 ,來決定寫入與否。AC累加器的數(shù)據(jù)會參與下次計算或者根據(jù) w 信號存入數(shù)據(jù) RAM 中。

至此,我們完成了一次計算,程序計數(shù)器加 1,然后執(zhí)行下一次計算。如果本條指令是跳轉(zhuǎn)指令的話,將跳轉(zhuǎn)目的地址直接賦值給程序計數(shù)器,程序重新地址開始執(zhí)行。

三、 Python 實現(xiàn) CPU 各組成部分

1 RAM 存儲器

我們用 list 來存儲數(shù)據(jù)。這是一個很簡單和直接的設(shè)計。

ramc = [0x18, 0x19, 0x1d, 0x02, 0x31, 0x30, 0x00]

對存儲器的讀寫,根據(jù) pc 指針來,ramc[pc]=data 表示寫入內(nèi)存,讀就是 ramc[pc]。

2 Adder 加法器

def adder(a=0, b=0, ci=0, sub=0):
    return a-b+ci if sub == 1 else a+b+ci

真正的加法器使用邏輯門,相當(dāng)于一堆開關(guān)按某種關(guān)系堆疊在一起,這里我們用高級語言模擬,極大簡化了實現(xiàn)。這個加法器實現(xiàn)了 a 和 b 的加法,同時 ci 表示進位,sub 表示減法。

3 Register 寄存器

寄存器采用 Python 的閉包概念來設(shè)計,這是為了用自由變量記住寄存器上次的狀態(tài)。當(dāng)我們用 AC = register() 調(diào)用時,AC 相相當(dāng)于返回的內(nèi)部函數(shù) register_inner,此時 temp 作為自由變量和 register_inner 同屬一個閉包。所以此后對 temp 變量讀、寫都是一個持久的變量。相當(dāng)于維持住了狀態(tài)。

w 信號為 1 時寫入,相當(dāng)于寄存器使能端 w。

def register():
    temp = 0
 
    def register_inner(data=0, w=0):
        nonlocal temp
        if w == 1:
            temp = data
        return temp
    return register_inner

    真實 CPU 設(shè)計當(dāng)中,如何設(shè)計寄存器是一門大學(xué)問。即使在微機原理課程粗淺的 CPU 模型學(xué)習(xí)中,理解繼電器和 三極管能記憶,也需要費一番心思。本文用高級語言模擬底層硬件,我們只能再兜兜轉(zhuǎn)轉(zhuǎn)一次,所以此處需要深刻理解閉包概念。

4 8bit 21選擇器

21選擇器是在 sel 端為 1 時,返回 b 。當(dāng) sel 為零時,返回 a。也就是兩個輸入端選擇一個作為輸出。

def b8_21selector(a=0, b=0, sel=0):
    return a if sel == 0 else b

四、集成 CPU

當(dāng)我們集成 CPU 各部件時,首先將各部件新建出來,然后進行初始化,最后將 pc 置零,開始無限循環(huán)。

循環(huán)過程中,首先將程序指令 RAM 中的數(shù)據(jù)寫入指令寄存器,根據(jù)指令寄存器解碼各控制信號,此后操作都是在指令控制信號控制下進行。

首先如果 IR 指令寄存器中是 HLt 停機指令的話,那么系統(tǒng) Break。否則根據(jù) dr 決定是否將數(shù)據(jù)信號寫入 DR 數(shù)據(jù)寄存器。

對加法器的操作,是自動的,它的一個輸入是 AC 累加器存器,另一個輸入是 DR 數(shù)據(jù)寄存器,同時受到 sub 減法控制信號的控制。

加法運算器運算后,結(jié)果傳到 21選擇器,同數(shù)據(jù)總線上直接過來的數(shù)據(jù)一塊,等待 s21 信號選擇,再根據(jù) ac 信號存進 AC 累加寄存器,以備下一計算。

zf 作為零標(biāo)志位寄存器,如果 AC 累加器存起結(jié)果為零的話,則 zf 為 1。此時如果 pre 為 1 的話,那么就可以將 pc 設(shè)置為 DR 數(shù)據(jù)寄存器的值,實現(xiàn)了運算結(jié)果為零跳轉(zhuǎn)功能。否則繼續(xù)向下執(zhí)行。

總體集成后,代碼如下:

def adder(a=0, b=0, ci=0, sub=0):
    return a-b+ci if sub == 1 else a+b+ci
def b8_21selector(a=0, b=0, sel=0):
    return a if sel == 0 else b
def register():
    temp = 0
    def register_inner(data=0, w=0):
        nonlocal temp
        if w == 1:
            temp = data
        return temp
    return register_inner
def int2bin(data=0, length=8, tuple_=1, string=0, humanOrder=0):
    #輔助函數(shù),整數(shù)轉(zhuǎn)換為二進制字符串或者元祖。
    r = bin(data)[2:].zfill(length)
    r = r[::-1] if humanOrder == 0 else r
    return r if string == 1 else tuple(int(c) for c in r)
def cpu():
    pc = 0 # pc 計數(shù)器從 0 開始,無限循環(huán)。
    IR, DR, AC = register(), register(), register() # 新建寄存器
    ramc = [0x18, 0x19, 0x1d, 0x02, 0x31, 0x30, 0x00] # 初始化代碼
    ramd = [10, 2, 3, 0xff, 0x06, 0x02] # 初始化數(shù)據(jù)
 
    IR(0, w=1) # 初始化寄存器
    DR(0, w=1)
    AC(0, w=1)
    while True:
        IR(ramc[pc], w=1) # 指令讀寫
        *_, pre, dr, ac, sub, w, s21 = int2bin(IR(), humanOrder=1) # 指令解碼
        if IR() == 0:
            break # HLT信號
        DR(ramd[pc], w=dr) # 數(shù)據(jù)讀寫
        r = adder(AC(), DR(), sub=sub) # 加法器自動加法
        AC(b8_21selector(DR(), r, s21), w=ac) # 選擇器選擇后,累加寄存器讀寫
        ramd[pc] = AC() if w else ramd[pc] # 根據(jù) w 信號,數(shù)據(jù)寫入 RAM
        zf = (AC() == 0) # 零標(biāo)志位寄存器
        pc = DR() if (pre == 1 and zf == True and s21 == 1) else pc + 1 # Jz 指令跳轉(zhuǎn)
        pc = DR() if (pre == 1 and s21 == 0) else pc # 無條件跳轉(zhuǎn) Jmp
        print(AC()) 
if __name__ == '__main__':
    cpu()

到此這篇關(guān)于Python代碼模擬CPU工作原理的文章就介紹到這了,更多相關(guān)Python模擬CPU內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • flask后端request獲取參數(shù)的幾種方式整理

    flask后端request獲取參數(shù)的幾種方式整理

    這篇文章主要為大家介紹了flask后端request獲取參數(shù)的幾種方式整理,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-06-06
  • Python實現(xiàn)京東搶秒殺功能

    Python實現(xiàn)京東搶秒殺功能

    這篇文章主要介紹了Python實現(xiàn)京東搶秒殺功能,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-01-01
  • Python 的可變和不可變對象詳情

    Python 的可變和不可變對象詳情

    本文通過詳情描述Python 中的可變對象與不可變對象來看兩者的區(qū)別,剛興趣的朋友可以參考下文
    2021-08-08
  • Python3 獲取一大段文本之間兩個關(guān)鍵字之間的內(nèi)容方法

    Python3 獲取一大段文本之間兩個關(guān)鍵字之間的內(nèi)容方法

    今天小編就為大家分享一篇Python3 獲取一大段文本之間兩個關(guān)鍵字之間的內(nèi)容方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-10-10
  • Python input()函數(shù)案例教程

    Python input()函數(shù)案例教程

    在 Python 中,input() 函數(shù)用于獲取用于的輸入,并給出提示。input() 函數(shù),總是返回 string 類型,因此,我們可以使用 input() 函數(shù),獲取用戶輸入的任何數(shù)據(jù)類型 ,這篇文章主要介紹了Python input()函數(shù)案例詳解,需要的朋友可以參考下
    2023-01-01
  • Python中easy_install 和 pip 的安裝及使用

    Python中easy_install 和 pip 的安裝及使用

    本篇文章主要介紹了Python中easy_install 和 pip 的安裝及使用,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-06-06
  • 介紹Python的Django框架中的QuerySets

    介紹Python的Django框架中的QuerySets

    這篇文章主要介紹了Python的Django框架中的QuerySets,QuerySet是Django中的一個內(nèi)置對象列表,經(jīng)常被用于數(shù)據(jù)庫操作,需要的朋友可以參考下
    2015-04-04
  • selenium在scrapy中的使用代碼

    selenium在scrapy中的使用代碼

    本文給大家分享selenium在scrapy中的使用代碼,使用selenium可以很好的幫助我們獲取一些重要數(shù)據(jù)信息,本文通過代碼給大家詳細(xì)介紹,感興趣的朋友跟隨小編一起看看吧
    2021-05-05
  • python中使用urllib2偽造HTTP報頭的2個方法

    python中使用urllib2偽造HTTP報頭的2個方法

    這篇文章主要介紹了python中使用urllib2偽造HTTP報頭的2個方法,即偽造http頭信息,需要的朋友可以參考下
    2014-07-07
  • Python文件時間操作步驟代碼詳解

    Python文件時間操作步驟代碼詳解

    這篇文章主要介紹了Python文件時間操作步驟代碼詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-04-04

最新評論