CPU扫盲-自创指令集难吗?

  在CPU扫盲-CPU与指令集中阐述了CPU与指令集之间的关系,这篇文章则是针对指令集的专场,指令集顾名思义就是一套指令的集合。CPU扫盲-CPU与指令集中提到创造指令集并不难,难的是如何将指令集推广,那这篇文章我们就从创作者的角度去理解它,我们尝试创造一个只包含几个指令的指令集。当然这篇文章的目的不是摒弃全部现有指令集概念完全闭门造车,而是站在现有指令集概念的肩膀上从创造者的角度去更深入的理解它。

  在CPU的世界里只有0和1,指令就是通过特定顺序、特定数量的0和1的来定义相加赋值等行为。指令集则是一系列行为的集合,通过他们就可以指挥CPU为各种事物编码。

  目前界内的指令集分为两个派系CISC (Complex Instruction Set Computer / 复杂指令集计算机)和RISC (Reduced Instruction Set Computer / 精简指令集计算机),CISC和RISC 并不是具体的指令集,而是两种不同的指令体系,相当于指令集中的门派,是指令的设计思想。举个例子,就像中医与西医,中医讲究从整体上调理身体,西医则更多的是解决器质性病变。这就是两种不同的医疗思路,类似于 CISC 和 RISC 这两种指令体系。那什么是指令集呢?拿中医举例,像华伦、张仲景这两位医圣,他们虽然都是基于中医的思想治病,但医术各有特色,水平也不尽相同,这就相当于不同的指令集。

  CISC系列指令集的出现远早于RISC,那时候设计指令集就是摸着石头过河,考虑比较局限,当时的程序员还都在使用汇编语言编写代码,总期望着一个指令可以多干一些事情,把工作转移给硬件电路,这样程序员爽歪歪,这样做的结果就是指令越来越复杂,长短不一,参数繁多。CPU硬件电路的制造工艺虽然不断进步但其电路的设计始终被CISC的指令集限制,最终成为CPU性难以能提升、尺寸难以缩小的瓶颈。此时诞生了RISC。其实最开始并没有CISC这个名字,只是后面出现了RISC为了作区分就将RISC之前的指令集统称CISC。CISC中的指令集就是大杂烩,长短不一、使用频率不一、没有规则限定,而RISC相当于对CISC的一次重构,借鉴了 CISC 的经验,取其精华,弃其糟柏。在RISC中采用定长指令,大大提升译码效率将复杂指令拆分成多个简单指令,减少了硬件电路的复杂性,给予CPU微架构设计更多的发挥空间(苹果的M1)限制每个指令最多一个内存寻址操作数,推崇寄存器到寄存器的操作,保证每个指令都能在单个时钟周期内完成… RISC旨在提高每个指令的执行时间,以此来提升CPU工作流水线整体性能。

  无论是CISC还是RISC都是采用操作码+操作数的设计思路,指令集中的操作数可以是寄存器、立即数、内存地址三种,也对应了CPU寻址的三大类:

  1. 寄存器寻址:寄存器寻址就是操作数是某一个寄存器,CPU执行指令时需要从寄存器中获取或写入”数据“。如:mov ax, bx,将bx寄存器中的值写入ax寄存器。。
  2. 内存寻址:寄存器寻址就是操作数是一个内存地址,CPU执行指令时需要从内存中获取或写入”数据“。内存寻址又分为直接寻址、基址寻址、变址寻址、基址变址寻址。我们这里只用最容易理解直接寻址,就是将直接在操作数中给出的数字作为内存地址,告诉 CPU 取此地址中的”数据“作为操作数。如:mov ax, [0x3000],将0x3000 地址中的”数据“写入ax寄存器。
  3. 立即数寻址:立即数寻址就是操作数是一个常数。只所以叫立即数就是凸显这个”数据“CPU拿来立即可以使用,在执行指令时无需去内存或寄存器中寻址。如:mov ax, 0x18,将数据 0x18写入ax寄存器。

  接下来我们尝试来设计一个指令集,我们这里为了凸显寻址方式的不同多加个一个”寻址方式“字段,我们的指令集规则如下:在这里插入图片描述
11 代表操作数为内存地址,10代表操作数为寄存器,00代表操作数为立即数。如:11 00 10 代表操作数1是内存地址,操作数2是立即数,操作数2是寄存器。
  现在开始设计指令完成一个内存变量和立即数相加后并赋值给内存变量的操作:C=A+B,A是内存变量值8内存地址是0x3000,B是立即数6,C的内存地址是0x3008。可以用寄存器有Ra、Rb、Rc。

  • 指令一:从内存获取数据存入寄存器,假设指令为 load
  • 指令二:将两个操作数相加并存入寄存器,假设指令为 add
  • 指令三:将寄存器中数据写入内存,假设指令为 store
    在这里插入图片描述
      像 load 0x002c Ra 0x3000这就是我这个指令集所对应的汇编语言,但操作码以及寄存器名称都是随便取的,因为汇编语言只是给人看的助记符,CPU并不关心这个,CPU只关心二进制的机器码。上图中寻址方式以及立即数和内存地址使用的是16进制,最终转换成2进制供CPU执行。操作码和寄存器的二进制机器指令对应关系如下:
    在这里插入图片描述
      至此我们操作数和操作码都有了,其实指令集己经完成了。不过在一长串的二进制01中,哪些是操作码,哪些是操作数呢?这就是指令格式的由来。我们人为规定个格式,规定操作码和操作数的大小及位置,然后CPU 硬件电路中写死这些规则,让 CPU 在硬件一级上识别这些格式,从而能识别出操作码和操作数。列如:操作码定长2bit、寻址方式定长6bit、操作数是寄存器时占2bit,是内存地址或立即数时占16bit(虽然操作数不定长,但当译码器分析出操作码后就能确定这个指令存在几个参数,分析完寻址方式就能确定每个操作数的长度)。
    按上面的指令格式我们需要执行的指令如下:
    在这里插入图片描述
  1. 步骤一:机器指令是 00 101100 00 0011000000000000,CPU识别出指令的前两位是00就知道是load指令,需要两个参数,然后再往后识别4位为10 11 CPU就能知道操作数1是寄存器寻址,操作数2是内存寻址,只有两个参数所以跳过寻址方式的后两位,整个译码过程都是写死在硬件中的规则,不同的指令有不同的规则。这时CPU已经知道该如何执行这条指令了,首先去0x3000地址获取”数据“,然后将数据存入Ra寄存器。
  2. 步骤二:机器指令是 01 100010 00 0000000000000110 01 ,CPU识别出指令的前两位是01就知道是add指令,需要三个参数,然后再往后识别6位为 10 00 10 CPU就知道三个操作数分别是 寄存器、立即数、寄存器。然后CPU执行指令将立即数6与寄存器Ra中的值相加并存入寄存器Rc。
  3. 步骤三:机器指令是 10 11000 0011000000001000 01 ,CPU识别出指令前两位是10就知道是store指令,需要两个参数,然后再往后识别4位为11 10 CPU就知道操作数1是内存地址寻址,操作数2是寄存器寻址,只有两个参数所以跳过寻址方式的后两位。然后CPU执行指令将Rc中的值写入内存0x3008。
      至此一个非常简易的指令集模型已经创造完毕,相信大家对指令集的理解更深刻了一些。假设上文自创的指令集不仅仅包含着三个指令,它的指令已经很完善了,并且已经可以量产使用此指令集的CPU了,这就代表自研指令集成功了嘛?
      答案是否定的,这仅仅是开始而已,相信大家能发现,因为不管是 操作码+寻址方式+操作数的指令格式,还是load、add、store这些汇编指令都是我随便设计的,也就是说这个CPU只有我懂怎么用,现有的软件在此CPU上都无法运行。因为相同的代码在不同指令集的编译器下,最终呈现的编译结果是不同的,虽然都是由01组成的二进制数字,但是长短和顺序是不同的,这就代表着不同指令集的CPU直接是语言不通,一个计算机换了不同指令集的CPU后原先的软件就不能用了,所以需要有人帮我去写各种编译器和解释器,将高级语言按照我的指令集规则进行编译,我的CPU才能正常工作,显然没人愿意。这些工作往往只能由指令集的厂商进行牵头推动,我显然没这么大的脸。通过这个自研的过程回过头来再看一下CPU扫盲-CPU与指令集中提到的**“创造指令集并不难,难的是如何将指令集推广”**这句话是否很有道理。指令集背后不仅是个计算机生态链,更重要的是全球经济链。
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

躺平程序猿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值