Python代码模拟CPU工作原理

 更新时间:2023年01月27日 16:16:23   投稿:yin  
Python代码来实现一个最简单的CPU。用代码模拟大的部件,使大家从原理上理解CPU工作。使它可编程,支持加减法运算、读写内存、无条件跳转、条件跳转的功能。

理解 CPU 工作原理,重要的是理解 pc 不停地自增地址,顺序执行程序指令。当遇到跳转指令时,会将 pc 重置为新地址。在顺序执行程序指令的过程中,每一步都是解析程序指令、产生控制信号,进而控制所有 CPU 相关器件的工作状态,产生程序计算结果,保存进各寄存器或者RAM 中。

本文使用四十行 Python 代码来实现一个最简单的 CPU。使它可编程,支持加减法运算、读写内存、无条件跳转、条件跳转的功能。

Python层面的实验和书面上的概念,不足以支撑去论证从Python代码到CPU执行的复杂过程,也不足以支撑从CPU读的内存地址到Python内存管理上的内存地址之间复杂的关系,但算是针对此浅层现象的一个合理的猜想。

一、引言

从宏观上,CPU 工作原理是读取内存数据,在 ALU 中完成计算,然后保存进内存,输入输出系统完成了同其他外设交互;从中观上看,CPU 工作原理就是本文讲述的 pc 从 0 开始,读取程序指令寄存器,然后解析指令,控制各部件工作的具体过程;从微观上看,pc 程序计数器、ALU 数字逻辑运算单元,RAM 存储器在内的所有 CPU 相关部件,其实都是一个个三极管,这些三极管在电流作用下导通或者截止,完成了数字逻辑运算、保持记忆状态、产生脉冲信号的所有功能。

二、CPU工作原理

让我们分别介绍各部件工作原理,之后介绍它们怎么协同工作。

1 各部件工作原理

在真实 CPU 中,都有相应物理电路与其对应,它们的功能分别是:

    pc 计数器,从 0 开始产生 0,1,2,……计数可以清零,也可以从外部输入一个数,从这个数从新开始计数,这被称为置位。用于指示程序和数据存取位置。

    RAM,存储数据的随机存储器,支持根据地址(0x01 这种整形)读取数据,根据地址和写入信号 w 写入数据。用于存储程序和数据。

    寄存器,存储 8 bit 信息的存储器,根据 w 信号为 1 写入当前数据,w 为 0 表示读取。类似 RAM,但只能存储 8 bit 信息。常用于存储指令、地址和计算中间量。

    加法器,完成两数加减法运算,sub 为 1 时表示减法,ci 为 1 时表示进位。这个器件是核心器件,用于构成 ALU(算数逻辑单元)。真实 CPU 是采用逻辑门搭建,还有乘法器、逻辑运算单元,等等。

    21选择器,相当于单刀双掷开关,根据 s21 信号,决定 8 bit 输出来自或左或右 8 bit 输入端。

2 协同工作原理

整个数据通路从程序计数器 pc 开始,计数器从 0 开始输出数字 0,1,2,3,4……。指令 RAM 和数据 RAM 中分别存储程序代码和数据。RAM 采用数字表示的位置访问、存储数据。根据计数器地址 0,1,2之类,将 RAM 中的数据分别放入指令寄存器 IR 和数据寄存器 DR。寄存器相当于容器、变量,存储了 RAM 给它的数据。

指令寄存器中的指令码解码产生 CPU 控制指令,这些 0 和 1 分别表示低电平和高电平信号,而电平信号则控制诸如加法器进位与否,是否打开减法,是否使能寄存器写入,选择 21选择器哪一个输入作输出,是否重置计数器,等等。所以,指令其实是控制 CPU 各部件协同工作的电信号。

数据寄存器中的数据分别走向加法器 adder 来进行加法、减法运算后流向 21选择器,也可能直接流向 21选择器等待选择。21选择器选择后,数据进入累加寄存器 AC 。累加器的数据根据 ac 信号是否为高电平 1 ,来决定写入与否。AC累加器的数据会参与下次计算或者根据 w 信号存入数据 RAM 中。

至此,我们完成了一次计算,程序计数器加 1,然后执行下一次计算。如果本条指令是跳转指令的话,将跳转目的地址直接赋值给程序计数器,程序重新地址开始执行。

三、 Python 实现 CPU 各组成部分

1 RAM 存储器

我们用 list 来存储数据。这是一个很简单和直接的设计。

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

对存储器的读写,根据 pc 指针来,ramc[pc]=data 表示写入内存,读就是 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

真正的加法器使用逻辑门,相当于一堆开关按某种关系堆叠在一起,这里我们用高级语言模拟,极大简化了实现。这个加法器实现了 a 和 b 的加法,同时 ci 表示进位,sub 表示减法。

3 Register 寄存器

寄存器采用 Python 的闭包概念来设计,这是为了用自由变量记住寄存器上次的状态。当我们用 AC = register() 调用时,AC 相相当于返回的内部函数 register_inner,此时 temp 作为自由变量和 register_inner 同属一个闭包。所以此后对 temp 变量读、写都是一个持久的变量。相当于维持住了状态。

w 信号为 1 时写入,相当于寄存器使能端 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 设计当中,如何设计寄存器是一门大学问。即使在微机原理课程粗浅的 CPU 模型学习中,理解继电器和 三极管能记忆,也需要费一番心思。本文用高级语言模拟底层硬件,我们只能再兜兜转转一次,所以此处需要深刻理解闭包概念。

4 8bit 21选择器

21选择器是在 sel 端为 1 时,返回 b 。当 sel 为零时,返回 a。也就是两个输入端选择一个作为输出。

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

四、集成 CPU

当我们集成 CPU 各部件时,首先将各部件新建出来,然后进行初始化,最后将 pc 置零,开始无限循环。

循环过程中,首先将程序指令 RAM 中的数据写入指令寄存器,根据指令寄存器解码各控制信号,此后操作都是在指令控制信号控制下进行。

首先如果 IR 指令寄存器中是 HLt 停机指令的话,那么系统 Break。否则根据 dr 决定是否将数据信号写入 DR 数据寄存器。

对加法器的操作,是自动的,它的一个输入是 AC 累加器存器,另一个输入是 DR 数据寄存器,同时受到 sub 减法控制信号的控制。

加法运算器运算后,结果传到 21选择器,同数据总线上直接过来的数据一块,等待 s21 信号选择,再根据 ac 信号存进 AC 累加寄存器,以备下一计算。

zf 作为零标志位寄存器,如果 AC 累加器存起结果为零的话,则 zf 为 1。此时如果 pre 为 1 的话,那么就可以将 pc 设置为 DR 数据寄存器的值,实现了运算结果为零跳转功能。否则继续向下执行。

总体集成后,代码如下:

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):
    #辅助函数,整数转换为二进制字符串或者元祖。
    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 计数器从 0 开始,无限循环。
    IR, DR, AC = register(), register(), register() # 新建寄存器
    ramc = [0x18, 0x19, 0x1d, 0x02, 0x31, 0x30, 0x00] # 初始化代码
    ramd = [10, 2, 3, 0xff, 0x06, 0x02] # 初始化数据
 
    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) # 数据读写
        r = adder(AC(), DR(), sub=sub) # 加法器自动加法
        AC(b8_21selector(DR(), r, s21), w=ac) # 选择器选择后,累加寄存器读写
        ramd[pc] = AC() if w else ramd[pc] # 根据 w 信号,数据写入 RAM
        zf = (AC() == 0) # 零标志位寄存器
        pc = DR() if (pre == 1 and zf == True and s21 == 1) else pc + 1 # Jz 指令跳转
        pc = DR() if (pre == 1 and s21 == 0) else pc # 无条件跳转 Jmp
        print(AC()) 
if __name__ == '__main__':
    cpu()

到此这篇关于Python代码模拟CPU工作原理的文章就介绍到这了,更多相关Python模拟CPU内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • flask后端request获取参数的几种方式整理

    flask后端request获取参数的几种方式整理

    这篇文章主要为大家介绍了flask后端request获取参数的几种方式整理,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-06-06
  • Python实现京东抢秒杀功能

    Python实现京东抢秒杀功能

    这篇文章主要介绍了Python实现京东抢秒杀功能,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-01-01
  • Python 的可变和不可变对象详情

    Python 的可变和不可变对象详情

    本文通过详情描述Python 中的可变对象与不可变对象来看两者的区别,刚兴趣的朋友可以参考下文
    2021-08-08
  • Python3 获取一大段文本之间两个关键字之间的内容方法

    Python3 获取一大段文本之间两个关键字之间的内容方法

    今天小编就为大家分享一篇Python3 获取一大段文本之间两个关键字之间的内容方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-10-10
  • Python input()函数案例教程

    Python input()函数案例教程

    在 Python 中,input() 函数用于获取用于的输入,并给出提示。input() 函数,总是返回 string 类型,因此,我们可以使用 input() 函数,获取用户输入的任何数据类型 ,这篇文章主要介绍了Python input()函数案例详解,需要的朋友可以参考下
    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中的一个内置对象列表,经常被用于数据库操作,需要的朋友可以参考下
    2015-04-04
  • selenium在scrapy中的使用代码

    selenium在scrapy中的使用代码

    本文给大家分享selenium在scrapy中的使用代码,使用selenium可以很好的帮助我们获取一些重要数据信息,本文通过代码给大家详细介绍,感兴趣的朋友跟随小编一起看看吧
    2021-05-05
  • python中使用urllib2伪造HTTP报头的2个方法

    python中使用urllib2伪造HTTP报头的2个方法

    这篇文章主要介绍了python中使用urllib2伪造HTTP报头的2个方法,即伪造http头信息,需要的朋友可以参考下
    2014-07-07
  • Python文件时间操作步骤代码详解

    Python文件时间操作步骤代码详解

    这篇文章主要介绍了Python文件时间操作步骤代码详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-04-04

最新评论