使用模拟电路制造CPU——从硬件到软件的设计

news2024/12/26 11:37:06

计算机中蕴藏的哲理

最基本的思想是:通过基本电路的接线,确立输入-输出规则,类似函数的入参和返回值,便构成一个功能电路单元。单元套单元组成新单元,如此往复。“一生二,二生三,三生万物”。这是硬件层面的。

软件层面的也是类似的道理。

向下不断的穷尽,我们会来到物理世界,最基本的电荷和磁场规则。再往里就是物理学还在探索的空间,未知。

向上不断的探索,我们会来到应用世界,充满了人类的欲望和需求。

一个领域依托于它的下一层,自己组织自己这一层级的基本单元之间的关系——本质就是排列组合的规则。

如果最基本的粒子是一,那么“一生二,二生三,三生万物”,物物相生相联,夫如是已。

本文的行文逻辑也是,从简入繁,由低向上,构建出一个“复杂”的CPU系统。虽是模拟,然代表了大致的脉络。

基本电路单元

参考:https://blog.csdn.net/windanchaos/article/details/81143641

主要是基本的电路单元
电路

八位加法器

使用工具:https://www.logiccircuit.org/
工具中有基本的逻辑电路单元、输入输出、分线器、晶振模拟器、显示装置模拟单元等。

如下:半加器是异或、与门电路接线构成。2个输入2个输出。

  • 半加器 HA(HalfAdder)

  • 半加器组成个全加器 FA(FullAdder)

  • 8位的求反RE
  • 半加器组合成8位的计算器

寄存器

仍然是基本电路往更复杂电路组合的逻辑。

只不过,这部分电路有个特征,术语叫时序电路,其最基本的特征是相对组合电路来讲的,组合电路特定输入就得到特定输出,时序电路则不然,它的输出和输入的对应关系是不确定的,其电路的输出会接到输入上,最终输出是由输入、输出和电路当前状态决定。话不多说直接上截图。

  • R-S触发器,输出Q确定后,Set、Clear、Prs不改变,那么电路是Q值是稳定的,可存储一位二进制。

e99dbf70-4edb-4466-8c02-25d9d34b9ea5.png

  • D触发器(R-S)组合起来,加了2个与门电路,具备控制是否可读可写的能力
    b3ae68dd-015a-43ee-9140-4fb3399bf81c.png

  • D边沿触发器,增加了时钟上升沿才可以操作的电路
    11403bbe-0a13-47d3-9246-5930ecb8fc73.png

  • T触发器,D基础上接线,具备输出按时钟周期变化的能力,是计数器的基本单元
    b5fd8971-196f-4037-8b1a-18668e735c09.png

  • D边沿触发器组成一个能存储1byte(8个位)的单元
    1cbd3f61-81fc-4a3a-bf3c-223fc0b41ef9.png

  • Byte单元增加各种控制输入,就组成1个8位寄存器
    bac99be7-d4dc-488e-80a0-d5071e052ed1.png

  • 3-8译码器,3个位(000),0和1变化有8种组合情况,特定组合选中特定的Byte单元,具有了寻址概念
    77626fcc-faf5-4ea0-b92a-6f5eef8949f0.png

  • 8x1电路,Ad是输入的3位地址
    576edeff-5512-4af5-a492-0264e6a651b7.png

最后演示一下001号寄存器被选中后的,执行写入和读取的操作。开始是重置255和清零,之后演示从0到8修改寄存器中值。

0f5c7c3d-6436-40ec-b2a7-96cdef9c757e.gif

加减法电路

利用已有的电路部件,搭建一个可以计算加法和减法的电路。此CPU计算单元雏形。

6b0628c7-0333-4ccc-8e24-85c3a927117c.png

上面的MC、RAM、PC、Reg、ALU都有控制选中(CS片选)、可写(不可写则可读)的输入,选中时对应灯泡点亮示意。
使用16位中的13位二进制的01来对应。
通过不同的排列组合即可定义每个时钟周期电路的状态(哪些单元可以被操控读写)。

下面是对应电路的控制单元的标识,或运算一组和,就是控制电路了。

import os
# 指令相关
# ABC寄存器
A_WE = 1
A_CS = 1 << 1

B_WE = 1 << 2
B_CS = 1 << 3

C_WE = 1 << 4
C_CS = 1 << 5

# 0为加,1为减
ALU_SUB = 1 << 6
ALU_EN = 1 << 7

MC_CS = 1 << 8
MC_WE = 1 << 9

PC_CS = 1 << 10
PC_WE = 1 << 11
PC_EN = 1 << 12
#空操作,未接线
NOTHING =  1 << 14
#停止(不再产生时钟信号)
HLT = 1 << 15

dirname = os.path.dirname(__file__)
fileName = os.path.join(dirname,'ins.bin')

micro = [
#启动电源PC=0    
#空操作,用于清0,清0后PC=1
NOTHING,
# PC加1,从RAM中读取1下标的数到A寄存器,PC=2
MC_CS|A_CS|A_WE|PC_WE|PC_EN|PC_CS,
# PC加1,从RAM中读取2下标的数到B寄存器,PC=3
MC_CS|B_CS|B_WE|PC_WE|PC_EN|PC_CS,
# 读取A、B寄存器数到ALU单元并计算
ALU_EN|A_CS|B_CS,
#ALU计算结果输出到C寄存器
ALU_EN|C_CS|C_WE,
# PC=3,控制MC操控ROM可写,写入C寄存器读取的值
MC_CS|MC_WE|C_CS,
HLT
]
# 二进制指令输出到ins.bin文本,通过ciruit加载到ROM中。
with open(fileName,'wb') as file:
    for value in micro:
        file.write(value.to_bytes(2,byteorder='little'))

print("finished compile")

以下是加法的gif演示(减法免了),演示从RAM中读取5和3到寄存器,使用ALU单元求和,输出到C寄存器,再写回到RAM。

7f0c6d7a-281d-4230-b87a-8ab3edca4e46.gif

组合CPU

给每个逻辑元件添加控制单元以达到,不同输入组合对应不同的输出。由于我们已实现了寄存器(一种能够记住1byte的单元),那么遍可以控制其允许输入/输出。

不同的原件,同一时刻的允许输入输出状态就定义了当时单元和单元之间的关系,如A寄存器输出,B是输入,其他不设置,那么此刻完成了A寄存器向B寄存器传输数据的目的。如此类推。

控制单元 Control Unit

控制单元是CPU的核心部件,由寄存器控制器、读写控制器及其他输入输入构成。如下:

控制单元接线——总览

将寄存器控制器和读写控制器接线,输入32位,对应位实现不同目的:

  • 低10位分2组,5+5分别标识写和读,接线到RWC上输入哪个单元读、哪个单元写。
  • 第11-15位分别标识源读、源写,目的读、目的写
  • 第16-19位位PC计数
  • 第20-23位为四则运算组合,一种8种
  • 第24-28 为控制ALU单元组合
    46bf1f0b-4a56-4117-a8d3-c0dc718b5193.png

PC 计数器

时钟下降沿(1->0)时完成指令计数,重新计数。是控制指令周期用的。

寄存器控制 RC

说明,W\R是5位输入,通过一个5-32译码器转换成0-32,可识别32个寄存器。
1317f0bf-2c5e-40d3-bc27-41569615919f.png

读写控制器RWC

读写控制器也是5位输入,接寄存器控制器
9dd4e5b2-30d7-44b0-830a-3445f09a9649.png

ALU

A、B是8位输入,OP是3位,3-8译码器,转为1-8,可支持8种运算。
1=加法 2=减法 3=加1 4=减1 5=And 6=OR 7=XOR 8=取反
a1fbf119-52c4-42dd-a8ec-b1a224c2d35c.png

内存控制器MC

RAM代表内存,MC为其控制单元
ed3d26de-70ea-4d41-b941-0bcecb4ce211.png

CPU接线

a271acf2-c048-4198-b22e-934f82953808.png

指令系统

执行的模式

通电之后,时钟定时脉动,提供给整个电路电压变化。通过control Uinit旁边的ROM中写入指令(32位的01组合数),CU(control Unit) 的PC每加1,则指令ROM读取的index +1,输入后从CU的d进入,完成对整个单元的控制。
ccc237ff-1176-40c3-a961-44ad763572e2.png

  • 取指令:先从RAM中把指令取到IR寄存器,目的操作数取到DST中,原操作数取到SRC中。
  • 译指令,IR指令进入CU中,从L1输入,DST从L2输入,SRC从L3输入——拼出 控制信息 + 操作单元 的组合

最后对这些电路按设计转成代码,代码备注也由说明

管脚代码

# 寄存器,RAM=MC
MSR = 1
MAR = 2
MDR = 3
# RAM就是MC控制器
RAM = 4
IR = 5
DST = 6
SRC = 7
A = 8
B = 9
C = 10
D = 11
DI = 12
SI = 13
SP = 14
BP = 15
CS = 16
DS = 17
SS = 18
ES = 19
VEC = 20
T1 = 21
T2 = 22

# 寄存器输出到总线上
MSR_OUT = MSR
MAR_OUT = MAR
MDR_OUT = MDR
RAM_OUT = RAM
IR_OUT = IR
DST_OUT = DST
SRC_OUT = SRC
A_OUT = A
B_OUT = B
C_OUT = C
D_OUT = D
DI_OUT = DI
SI_OUT = SI
SP_OUT = SP
BP_OUT = BP
CS_OUT = CS
DS_OUT = DS
SS_OUT = SS
ES_OUT = ES
VEC_OUT = VEC
T1_OUT = T1
T2_OUT = T2

# 写入寄存器,暂时没搞懂为什么左移5位
_DST_SHIFT = 5
MSR_IN = MSR << _DST_SHIFT
MAR_IN = MAR << _DST_SHIFT
MDR_IN = MDR << _DST_SHIFT
RAM_IN = RAM << _DST_SHIFT
IR_IN = IR << _DST_SHIFT
DST_IN = DST << _DST_SHIFT
SRC_IN = SRC << _DST_SHIFT
A_IN = A << _DST_SHIFT
B_IN = B << _DST_SHIFT
C_IN = C << _DST_SHIFT
D_IN = D << _DST_SHIFT
DI_IN = DI << _DST_SHIFT
SI_IN = SI << _DST_SHIFT
SP_IN = SP << _DST_SHIFT
BP_IN = BP << _DST_SHIFT
CS_IN = CS << _DST_SHIFT
DS_IN = DS << _DST_SHIFT
SS_IN = SS << _DST_SHIFT
ES_IN = ES << _DST_SHIFT
VEC_IN = VEC << _DST_SHIFT
T1_IN = T1 << _DST_SHIFT
T2_IN = T2 << _DST_SHIFT

# 电路中11-14位作为RWC单元的输入,控制S和D的读写,软件层面确认不同时读写同一个单元
# src中的值对应的寄存器,读取其值
SRC_R = 1 << 10
SRC_W = 1 << 11
DST_R = 1 << 12
DST_W = 1 << 13

PC_CS = 1 << 14
PC_WE = 1 << 15
PC_EN = 1 << 16
PC_OUT = PC_CS
PC_IN = PC_CS | PC_WE | PC_EN
PC_INC = PC_CS | PC_WE

# ALU
_OP_SHIFT = 17
OP_ADD = 0
OP_SUB = 1 << _OP_SHIFT
# 加减1
OP_INC = 2 << _OP_SHIFT
OP_DEC = 3 << _OP_SHIFT
OP_AND = 4 << _OP_SHIFT
OP_OR = 5 << _OP_SHIFT
OP_XOR = 6 << _OP_SHIFT
OP_NOT = 7 << _OP_SHIFT
ALU_OUT = 1 << 20
ALU_PSW = 1 << 21
ALU_INT_W = 1 << 22
ALU_INT = 1 << 23

ALU_STI = ALU_INT_W
ALU_CLI = ALU_INT_W | ALU_INT

# cyc标识当前指令执行完了,需要重置微程序的pc数
CYC = 1 << 30
HLT = 1 << 31

# 二地址指令和一地址 指令
ADDR2 = 1 << 7
ADDR1 = 1 << 6
ADDR2_SHIFT = 4
ADDR1_SHIFT = 2

# 四种寻址方式
AM_INS = 0  # 立即数
AM_REG = 1  # 寄存器
AM_DIR = 2  # 内存直接寻址
AM_RAM = 3  # 寄存器间接寻址


控制器代码controller.py

# 控制器

import os
import assembly as ASM
import pin

dirname = os.path.dirname(__file__)
filename = os.path.join(dirname, 'micro.bin')
micro = [pin.HLT for _ in range(0x10000)]
# 跳转转移指令
CJMPS = {ASM.JO, ASM.JNO, ASM.JZ, ASM.JNZ, ASM.JP, ASM.JNP}


def compile_addr2(addr, ir, psw, index):
    global micro
    # 操作
    op = ir & 0xf0
    amd = (ir >> 2) & 3  # 3 = 011
    ams = ir & 3
    INST = ASM.INSTRUCTIONS[2]
    if op not in INST:
        micro[addr] = pin.CYC
        return
    am = (amd, ams)
    if am not in INST[op]:
        micro[addr] = pin.CYC
        return
    EXEC = INST[op][am]
    if index < len(EXEC):
        micro[addr] = EXEC[index]
    else:
        micro[addr] = pin.CYC


def get_condition_jump(exec, op, psw):
    overflow = psw & 1
    zero = psw & 2
    parity = psw & 4
    if op == ASM.JO and overflow:
        return exec
    if op == ASM.JNO and not overflow:
        return exec
    if op == ASM.JZ and zero:
        return exec
    if op == ASM.JNZ and not zero:
        return exec
    if op == ASM.JP and parity:
        return exec
    if op == ASM.JNP and not parity:
        return exec
    return [pin.CYC]


def get_interrupt(exec, op, psw):
    interrupt = psw & 8
    if interrupt:
        return exec
    return [pin.CYC]


def compile_addr1(addr, ir, psw, index):
    global micro
    global CJMPS
    op = ir & 0xfc
    amd = ir & 3
    INST = ASM.INSTRUCTIONS[1]
    if op not in INST:
        micro[addr] = pin.CYC
        return
    if amd not in INST[op]:
        micro[addr] = pin.CYC
        return
    EXEC = INST[op][amd]
    if op in CJMPS:
        EXEC = get_condition_jump(EXEC, op, psw)
    if op == ASM.INT:
        EXEC = get_interrupt(EXEC, op, psw)
    if index < len(EXEC):
        micro[addr] = EXEC[index]
    else:
        micro[addr] = pin.CYC


def compile_addr0(addr, ir, psw, index):
    global micro
    # 操作
    op = ir
    INST = ASM.INSTRUCTIONS[0]
    if op not in INST:
        micro[addr] = pin.CYC
        return
    EXEC = INST[op]
    if index < len(EXEC):
        micro[addr] = EXEC[index]
    else:
        micro[addr] = pin.CYC


# 2^16次方是16进制的10000
# for循环对下标就行遍历赋值,ROM列有16个,一行一条指令。
# 16位组成:ir[8]+psw[4]+cyc[4],与运算高位和低位双截断
for addr in range(0x10000):
    ir = addr >> 8
    psw = (addr >> 4) & 0xf
    cyc = addr & 0xf
    # 小于取址长度,则写入取指令,6个时钟沿
    if cyc < len(ASM.FETCH):
        micro[addr] = ASM.FETCH[cyc]
        continue
    addr2 = ir & (1 << 7)
    addr1 = ir & (1 << 6)
    # 取指令之后的index
    index = cyc - len(ASM.FETCH)
    if addr2:
        compile_addr2(addr, ir, psw, index)
    elif addr1:
        compile_addr1(addr, ir, psw, index)
    else:
        compile_addr0(addr, ir, psw, index)
with open(filename, 'wb') as file:
    for var in micro:
        value = var.to_bytes(4, byteorder='little')
        file.write(value)
print('micro instruction compile finished! ')

程序代码 compiler.py

主要完成汇编转机器码的工作

import os
import pin
import assembly as ASM
import re

dirname = os.path.dirname(__file__)
inputFileName = os.path.join(dirname, 'program.asm')
outputFileName = os.path.join(dirname, 'program.bin')

# 代码的正则,分号是注释
annotation = re.compile(r"(.*?);.*")
# 代码
codes = []
# 标记,对应的代码
marks = {}
OP2 = {
    'MOV': ASM.MOV,
    'ADD': ASM.ADD,
    'CMP': ASM.CMP,
    'SUB': ASM.SUB,
    'AND': ASM.AND,
    'OR': ASM.OR,
    'XOR': ASM.XOR,
}
OP1 = {
    'INC': ASM.INC,
    'DEC': ASM.DEC,
    'NOT': ASM.NOT,
    'JMP': ASM.JMP,
    'JO': ASM.JO,
    'JNO': ASM.JNO,
    'JZ': ASM.JZ,
    'JNZ': ASM.JNZ,
    'JP': ASM.JP,
    'JNP': ASM.JNP,
    'PUSH': ASM.PUSH,
    'POP': ASM.POP,
    'CALL': ASM.CALL,
    'INT': ASM.INT,
}
OP0 = {
    'NOP': ASM.NOP,
    'HLT': ASM.HLT,
    'RET': ASM.RET,
    'STI': ASM.STI,
    'CLI': ASM.CLI,
    'IRET': ASM.IRET,
}

OP2SET = set(OP2.values())
OP1SET = set(OP1.values())
OP0SET = set(OP0.values())

# 可操作的寄存器
REGISTERS = {
    'A': pin.A,
    'B': pin.B,
    'C': pin.C,
    'D': pin.D,
    'SS': pin.SS,
    'CS': pin.CS,
    'SP': pin.SP,
}


class Code(object):
    # 代码
    CODE = 1
    # 标记
    LABEL = 2

    def __init__(self, number, source: str, code_type=CODE):
        self.number = number
        self.source = source.upper()
        self.op = None
        self.dst = None
        self.src = None
        self.code_type = code_type
        # 代码行
        self.index = 0
        self.prepare_source()

    def get_op(self):
        if self.op in OP2:
            return OP2[self.op]
        if self.op in OP1:
            return OP1[self.op]
        if self.op in OP0:
            return OP0[self.op]
        raise SyntaxError(self)

    # 获取操作数类型和其操作值
    def get_am(self, addr):
        global marks
        if not addr:
            return None, None
        if addr in marks:
            # 一行代码占3个字节
            return pin.AM_INS, marks[addr].index * 3
        if addr in REGISTERS:
            return pin.AM_REG, REGISTERS[addr]
        if re.match(r'^[0-9]+$', addr):
            return pin.AM_INS, int(addr)
        if re.match(r'^0X[0-9A-F]+$', addr):
            return pin.AM_INS, int(addr, 16)
        # 匹配直接寻址,内存单元取址送出10进制
        match = re.match(r'^\[([0-9]+)\]$', addr)
        if match:
            return pin.AM_DIR, int(match.group(1))
        # 匹配直接寻址,内存单元取址送出16进制
        match = re.match(r'^\[0X([0-9A-F]+)\]$', addr)
        if match:
            return pin.AM_DIR, int(match.group(1), 16)
        # 寄存器间接寻址,即将寄存器中的值作为ROM下标取出值送出
        match = re.match(r'^\[(.+)\]$', addr)
        if match and match.group(1) in REGISTERS:
            return pin.AM_RAM, REGISTERS[match.group(1)]
        raise SyntaxError(self)

    # 文本预处理,获取到指令-源操作数-目的操作数
    def prepare_source(self):
        if self.source.endswith(":"):
            self.type = self.LABEL
            self.name = self.source.strip(':')
            return
        # 逗号分割,如果大于2就是错误
        tup = self.source.split(',')
        if len(tup) > 2:
            raise SyntaxError(self)
        if len(tup) == 2:
            self.src = tup[1].strip()
        # 将指令和操作数分开
        tup = re.split(r' +', tup[0])
        if len(tup) > 2:
            raise SyntaxError(self)
        elif len(tup) == 2:
            self.dst = tup[1].strip()
        self.op = tup[0].strip()

    # 计算指令-目的操作数-源操作数的二进制值
    def compile_code(self):
        op = self.get_op()
        amd, dst = self.get_am(self.dst)
        ams, src = self.get_am(self.src)
        if src is not None and (amd, ams) not in ASM.INSTRUCTIONS[2][op]:
            raise SyntaxError(self)
        if src is None and dst and amd not in ASM.INSTRUCTIONS[1][op]:
            raise SyntaxError(self)
        if src is None and dst is None and op not in ASM.INSTRUCTIONS[0]:
            raise SyntaxError(self)
        amd = amd or 0
        ams = ams or 0
        dst = dst or 0
        src = src or 0
        if op in OP2SET:
            ir = op | (amd << 2) | ams
        elif op in OP1SET:
            ir = op | amd
        else:
            ir = op
        return [ir, dst, src]

    def __repr__(self):
        return f'[{self.number}] - {self.source}'


class SyntaxError(Exception):
    def __init__(self, code: Code, *args, **kwargs):
        super.__init__(*args, **kwargs)
        self.code = code


def compile_program():
    global codes
    global marks
    with open(inputFileName, encoding='utf8') as file:
        lines = file.readlines()
    # 遍历行
    for index, line in enumerate(lines):
        # 去掉空格符
        source = line.strip()
        # 去掉分号及后的备注,分号就是标识代码用的(简版),冒号是标识LAB的
        if ';' in source:
            match = annotation.match(source)
            source = match.group(1)
            code = Code(index + 1, source)
            codes.append(code)
            continue
        if source.endswith(":"):
            codes.append(Code(index + 2, source, Code.LABEL))
            continue
        if not source:
            continue
    result = []
    current = None
    # 从后往前遍历代码行
    for var in range(len(codes) - 1, -1, -1):
        code = codes[var]
        if code.code_type == Code.CODE:
            current = code
            result.insert(0, code)
            continue
        if code.type == Code.LABEL:
            # 这里指向的是code的引用,后边的遍历改index不影响
            marks[code.name] = current
            continue
        raise SyntaxError(code)
    # 更新索引index
    for index, var in enumerate(result):
        var.index = index
    with open(outputFileName, 'wb') as file:
        for code in result:
            values = code.compile_code()
            for value in values:
                if value is not None:
                    result = value.to_bytes(1, byteorder='little')
                    file.write(result)


def main():
    try:
        compile_program()
    except SyntaxError as e:
        print(f'Syntax Error at {e.code}')
    print(f'program compile finished')


if __name__ == '__main__':
    main()


汇编定义代码assembly.py

主要定义,不同指令的电路组合状态。电路组合状态从管脚中定义的基本电路控制单元,或运算得到。

import pin

# 汇编

# 取址
FETCH = [
    pin.PC_OUT | pin.MAR_IN,
    pin.RAM_OUT | pin.IR_IN | pin.PC_INC,

    pin.PC_OUT | pin.MAR_IN,
    pin.RAM_OUT | pin.DST_IN | pin.PC_INC,

    pin.PC_OUT | pin.MAR_IN,
    pin.RAM_OUT | pin.SRC_IN | pin.PC_INC,
]
# 指令定义
MOV = 0 | pin.ADDR2
ADD = (1 << pin.ADDR2_SHIFT) | pin.ADDR2
SUB = (2 << pin.ADDR2_SHIFT) | pin.ADDR2
CMP = (3 << pin.ADDR2_SHIFT) | pin.ADDR2
AND = (4 << pin.ADDR2_SHIFT) | pin.ADDR2
OR = (5 << pin.ADDR2_SHIFT) | pin.ADDR2
XOR = (6 << pin.ADDR2_SHIFT) | pin.ADDR2

INC = (0 << pin.ADDR1_SHIFT) | pin.ADDR1
DEC = (1 << pin.ADDR1_SHIFT) | pin.ADDR1
NOT = (2 << pin.ADDR1_SHIFT) | pin.ADDR1
JMP = (3 << pin.ADDR1_SHIFT) | pin.ADDR1
# 条件转移
# 溢出和非溢出
JO = (4 << pin.ADDR1_SHIFT) | pin.ADDR1
JNO = (5 << pin.ADDR1_SHIFT) | pin.ADDR1
# 零和非0
JZ = (6 << pin.ADDR1_SHIFT) | pin.ADDR1
JNZ = (7 << pin.ADDR1_SHIFT) | pin.ADDR1
# 奇数和非奇数
JP = (8 << pin.ADDR1_SHIFT) | pin.ADDR1
JNP = (9 << pin.ADDR1_SHIFT) | pin.ADDR1
PUSH = (10 << pin.ADDR1_SHIFT) | pin.ADDR1
POP = (11 << pin.ADDR1_SHIFT) | pin.ADDR1
CALL = (12 << pin.ADDR1_SHIFT) | pin.ADDR1
INT = (13 << pin.ADDR1_SHIFT) | pin.ADDR1

# SUB = (2 << pin.ADDR2_SHIFT) | pin.ADDR2
# SUB = (2 << pin.ADDR2_SHIFT) | pin.ADDR2
# SUB = (2 << pin.ADDR2_SHIFT) | pin.ADDR2
# 0操作数指令
# 啥也不干
NOP = 0
RET = 1
# 中断返回
IRET = 2
# 开中断
STI = 3
# 关中断
CLI = 4
# 停止
HLT = 0x3f  # 111111

INSTRUCTIONS = {
    2: {
        MOV: {
            # 立即数寻址,将立即数放入SRC寄存器,存入DST种存放的具体寄存器(地址)中,这里只定义指令动作,具体执行之后解析
            (pin.AM_REG, pin.AM_INS): [
                pin.DST_W | pin.SRC_OUT,
            ],
            (pin.AM_REG, pin.AM_REG): [
                pin.DST_W | pin.SRC_R,
            ],
            (pin.AM_REG, pin.AM_DIR): [
                pin.SRC_OUT | pin.MAR_IN,
                pin.DST_W | pin.RAM_OUT,
            ],
            (pin.AM_REG, pin.AM_RAM): [
                pin.SRC_R | pin.MAR_IN,
                pin.DST_W | pin.RAM_OUT,
            ],
            (pin.AM_DIR, pin.AM_INS): [
                pin.DST_OUT | pin.MAR_IN,
                pin.RAM_IN | pin.SRC_OUT,
            ],
            (pin.AM_DIR, pin.AM_DIR): [
                pin.SRC_OUT | pin.MAR_IN,
                pin.RAM_OUT | pin.T1_IN,
                pin.DST_OUT | pin.MAR_IN,
                pin.RAM_IN | pin.T1_OUT,
            ],
            (pin.AM_DIR, pin.AM_RAM): [
                pin.SRC_R | pin.MAR_IN,
                pin.RAM_OUT | pin.T1_IN,
                pin.DST_OUT | pin.MAR_IN,
                pin.RAM_IN | pin.T1_OUT,
            ],
            (pin.AM_RAM, pin.AM_INS): [
                pin.DST_R | pin.MAR_IN,
                pin.RAM_IN | pin.SRC_OUT,
            ],
            (pin.AM_RAM, pin.AM_REG): [
                pin.DST_R | pin.MAR_IN,
                pin.RAM_IN | pin.SRC_R,
            ],
            (pin.AM_RAM, pin.AM_DIR): [
                pin.SRC_OUT | pin.MAR_IN,
                pin.RAM_OUT | pin.T1_IN,
                pin.DST_R | pin.MAR_IN,
                pin.RAM_IN | pin.T1_OUT,
            ],
            (pin.AM_RAM, pin.AM_RAM): [
                pin.SRC_R | pin.MAR_IN,
                pin.RAM_OUT | pin.T1_IN,
                pin.DST_R | pin.MAR_IN,
                pin.RAM_IN | pin.T1_OUT,
            ],
        },
        ADD: {
            (pin.AM_REG, pin.AM_INS): [
                pin.DST_R | pin.A_IN,
                pin.SRC_OUT | pin.B_IN,
                pin.OP_ADD | pin.ALU_OUT | pin.DST_W | pin.ALU_PSW,
            ],
            (pin.AM_REG, pin.AM_REG): [
                pin.DST_R | pin.A_IN,
                pin.SRC_R | pin.B_IN,
                pin.OP_ADD | pin.ALU_OUT | pin.DST_W | pin.ALU_PSW,
            ],
        },
        CMP: {
            (pin.AM_REG, pin.AM_INS): [
                pin.DST_R | pin.A_IN,
                pin.SRC_OUT | pin.B_IN,
                pin.OP_SUB | pin.ALU_PSW,
            ],
            (pin.AM_REG, pin.AM_REG): [
                pin.DST_R | pin.A_IN,
                pin.SRC_R | pin.B_IN,
                pin.OP_SUB | pin.ALU_PSW,

            ],
        },
        SUB: {
            (pin.AM_REG, pin.AM_INS): [
                pin.DST_R | pin.A_IN,
                pin.SRC_OUT | pin.B_IN,
                pin.OP_SUB | pin.ALU_OUT | pin.DST_W | pin.ALU_PSW
            ],
            (pin.AM_REG, pin.AM_REG): [
                pin.DST_R | pin.A_IN,
                pin.SRC_R | pin.B_IN,
                pin.OP_SUB | pin.ALU_OUT | pin.DST_W | pin.ALU_PSW
            ],
        },
        AND: {
            (pin.AM_REG, pin.AM_INS): [
                pin.DST_R | pin.A_IN,
                pin.SRC_OUT | pin.B_IN,
                pin.OP_AND | pin.ALU_OUT | pin.DST_W | pin.ALU_PSW
            ],
            (pin.AM_REG, pin.AM_REG): [
                pin.DST_R | pin.A_IN,
                pin.SRC_R | pin.B_IN,
                pin.OP_AND | pin.ALU_OUT | pin.DST_W | pin.ALU_PSW
            ],
        },
        OR: {
            (pin.AM_REG, pin.AM_INS): [
                pin.DST_R | pin.A_IN,
                pin.SRC_OUT | pin.B_IN,
                pin.OP_OR | pin.ALU_OUT | pin.DST_W | pin.ALU_PSW
            ],
            (pin.AM_REG, pin.AM_REG): [
                pin.DST_R | pin.A_IN,
                pin.SRC_R | pin.B_IN,
                pin.OP_OR | pin.ALU_OUT | pin.DST_W | pin.ALU_PSW
            ],
        },
        XOR: {
            (pin.AM_REG, pin.AM_INS): [
                pin.DST_R | pin.A_IN,
                pin.SRC_OUT | pin.B_IN,
                pin.OP_XOR | pin.ALU_OUT | pin.DST_W | pin.ALU_PSW
            ],
            (pin.AM_REG, pin.AM_REG): [
                pin.DST_R | pin.A_IN,
                pin.SRC_R | pin.B_IN,
                pin.OP_XOR | pin.ALU_OUT | pin.DST_W | pin.ALU_PSW
            ],
        },
    },
    1: {
        INC: {
            pin.AM_REG: [
                pin.DST_R | pin.A_IN,
                pin.OP_INC | pin.ALU_OUT | pin.DST_W | pin.ALU_PSW
            ],
        },
        DEC: {
            pin.AM_REG: [
                pin.DST_R | pin.A_IN,
                pin.OP_DEC | pin.ALU_OUT | pin.DST_W | pin.ALU_PSW,
            ],
        },
        NOT: {
            pin.AM_REG: [
                pin.DST_R | pin.A_IN,
                pin.OP_NOT | pin.ALU_OUT | pin.DST_W | pin.ALU_PSW,
            ],
        },
        JMP: {
            # 立即数写入到PC
            pin.AM_INS: [
                pin.DST_OUT | pin.PC_IN
            ],
        },
        JO: {
            pin.AM_INS: [
                pin.DST_OUT | pin.PC_IN
            ],
        },
        JNO: {
            pin.AM_INS: [
                pin.DST_OUT | pin.PC_IN
            ],
        },
        JZ: {
            pin.AM_INS: [
                pin.DST_OUT | pin.PC_IN
            ],
        },
        JNZ: {
            pin.AM_INS: [
                pin.DST_OUT | pin.PC_IN
            ],
        },
        JP: {
            pin.AM_INS: [
                pin.DST_OUT | pin.PC_IN
            ],
        },
        JNP: {
            pin.AM_INS: [
                pin.DST_OUT | pin.PC_IN
            ],
        },
        PUSH: {
            pin.AM_INS: [
                # 栈顶指针减一获取栈地址
                pin.SP_OUT | pin.A_IN,
                pin.SP_IN | pin.ALU_OUT | pin.OP_DEC,
                pin.SP_OUT | pin.MAR_IN,
                # 栈段地址送到MSR寄存器
                pin.SS_OUT | pin.MSR_IN,
                # 读取目的寄存器的值到RAM,地址由MSR+MAR
                pin.DST_OUT | pin.RAM_IN,
                # 恢复MSR到代码段
                pin.CS_OUT | pin.MSR_IN,
            ],
            pin.AM_REG: [
                # 栈顶指针减一获取栈地址
                pin.SP_OUT | pin.A_IN,
                pin.SP_IN | pin.ALU_OUT | pin.OP_DEC,
                pin.SP_OUT | pin.MAR_IN,
                # 栈段地址送到MSR寄存器
                pin.SS_OUT | pin.MSR_IN,
                # 读取目的寄存器的值到RAM,地址由MSR+MAR
                pin.DST_R | pin.RAM_IN,
                # 恢复MSR到代码段
                pin.CS_OUT | pin.MSR_IN,
            ],
        },
        POP: {
            pin.AM_REG: [
                # 栈段地址送到MSR寄存器
                pin.SS_OUT | pin.MSR_IN,
                pin.SP_OUT | pin.MAR_IN,
                # RAM读取值到目的寄存器,地址由MSR+MAR
                pin.DST_W | pin.RAM_OUT,
                pin.SP_OUT | pin.A_IN,
                pin.SP_IN | pin.ALU_OUT | pin.OP_INC,
                # 恢复MSR到代码段
                pin.CS_OUT | pin.MSR_IN,
            ],
        },
        CALL: {
            pin.AM_INS: [
                # 栈顶指针减一获取栈地址
                pin.SP_OUT | pin.A_IN,
                pin.SP_IN | pin.ALU_OUT | pin.OP_DEC,
                pin.SP_OUT | pin.MAR_IN,
                # 栈段地址送到MSR寄存器
                pin.SS_OUT | pin.MSR_IN,
                # 保存当前pc到RAM
                pin.PC_OUT | pin.RAM_IN,
                # 读取目的寄存器的值PC
                pin.DST_OUT | pin.PC_IN,
                # 恢复MSR到代码段
                pin.CS_OUT | pin.MSR_IN,
            ],
            pin.AM_REG: [
                # 栈顶指针减一获取栈地址
                pin.SP_OUT | pin.A_IN,
                pin.SP_IN | pin.ALU_OUT | pin.OP_DEC,
                pin.SP_OUT | pin.MAR_IN,
                # 栈段地址送到MSR寄存器
                pin.SS_OUT | pin.MSR_IN,
                # 保存当前pc到RAM
                pin.PC_OUT | pin.RAM_IN,
                # 读取目的寄存器的值PC
                pin.DST_R | pin.PC_IN,
                # 恢复MSR到代码段
                pin.CS_OUT | pin.MSR_IN,
            ],
        },
        INT: {
            pin.AM_INS: [
                # 栈顶指针减一获取栈地址
                pin.SP_OUT | pin.A_IN,
                pin.SP_IN | pin.ALU_OUT | pin.OP_DEC,
                pin.SP_OUT | pin.MAR_IN,
                # 栈段地址送到MSR寄存器
                pin.SS_OUT | pin.MSR_IN,
                # 保存当前pc到RAM
                pin.PC_OUT | pin.RAM_IN,
                # 读取目的寄存器的值PC
                pin.DST_OUT | pin.PC_IN,
                # 恢复MSR到代码段
                pin.CS_OUT | pin.MSR_IN | pin.ALU_PSW | pin.ALU_CLI,
            ],
            pin.AM_REG: [
                # 栈顶指针减一获取栈地址
                pin.SP_OUT | pin.A_IN,
                pin.SP_IN | pin.ALU_OUT | pin.OP_DEC,
                pin.SP_OUT | pin.MAR_IN,
                # 栈段地址送到MSR寄存器
                pin.SS_OUT | pin.MSR_IN,
                # 保存当前pc到RAM
                pin.PC_OUT | pin.RAM_IN,
                # 读取目的寄存器的值PC
                pin.DST_R | pin.PC_IN,
                # 恢复MSR到代码段
                pin.CS_OUT | pin.MSR_IN | pin.ALU_PSW | pin.ALU_CLI,
            ],
        },

    },
    0: {
        NOP: [pin.CYC],
        HLT: [pin.HLT],
        RET: [
            # 栈段地址送到MSR寄存器
            pin.SS_OUT | pin.MSR_IN,
            pin.SP_OUT | pin.MAR_IN,
            # RAM读取值写回PC计数器
            pin.PC_IN | pin.RAM_OUT,
            pin.SP_OUT | pin.A_IN,
            pin.SP_IN | pin.ALU_OUT | pin.OP_INC,
            # 恢复MSR到代码段
            pin.CS_OUT | pin.MSR_IN,
        ],
        IRET: [
            # 栈段地址送到MSR寄存器
            pin.SS_OUT | pin.MSR_IN,
            pin.SP_OUT | pin.MAR_IN,
            # RAM读取值写回PC计数器
            pin.PC_IN | pin.RAM_OUT,
            pin.SP_OUT | pin.A_IN,
            pin.SP_IN | pin.ALU_OUT | pin.OP_INC,
            # 恢复MSR到代码段
            pin.CS_OUT | pin.MSR_IN | pin.ALU_PSW | pin.ALU_STI,
        ],
        STI: [
            pin.ALU_PSW | pin.ALU_STI,
        ],
        CLI: [
            pin.ALU_PSW | pin.ALU_CLI,
        ],
    }
}

实现的指令

二地址指令

  • MOV
  • ADD
  • CMP
  • SUB
  • AND
  • OR
  • XOR

一地址指令

  • INC
  • DEC
  • NOT
  • JMP 跳转
  • JO 溢出跳转
  • JNO 非溢出跳转
  • JZ 零转
  • JNZ
  • JP 奇偶
  • JNP
  • PUSH
  • POP
  • CALL
  • INT中断(内部的)

零地址指令

  • NOP
  • HLT
  • RET call对应恢复
  • IRET 中断恢复
  • STI start中断
  • CLI close中断

演示

下面演示汇编代码的执行。

MOV D,3;
MOV C,4;
ADD D,C;
HLT;

该代码先被汇编解析代码编译到program.bin的二进制文件中,加载CPU的RAM,作为程序源。
然后控制器代码生成的二进制文件加载到CPU的ROM中,作为指令源。
最后,加法的输出结果是一个是7,在ALU旁输出和D寄存器中都是。。。
e56a756c-f8ab-4a79-833e-f836edce129f.gif

尾声

有了能支持汇编代码的基础,在此基础上,我们能够持续向上“生万物”,这是一条辉煌而又艰辛的道路。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/713478.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

盒马上市,即时零售最大“变量”

若盒马年内成功上市&#xff0c;等待完成下一轮融资的朴朴超市的处境恐将更加尴尬&#xff0c;另区域性中小商超或将迎来新一轮倒闭潮。 疫情过后&#xff0c;国内消费市场一直处于走弱态势。据商务大数据监测&#xff0c;今年端午假期&#xff0c;部分地区零售和餐饮数据远不及…

数据结构记录和leetcode刷题记录

背景 时间复杂度 算法的执行时间与输入值之间的关系。 参考&#xff1a;算法中七种常见的时间复杂度 - 掘金 参考视频&#xff1a;1. 算法的时间复杂度_哔哩哔哩_bilibili 空间复杂度 算法的存储空间与输入值之间的关系。 参考&#xff1a;2. 算法的空间复杂度_哔哩哔哩_bili…

【花雕】全国青少年机器人技术一级考试备考实操搭建手册1

目录 1、秋千 2、跷跷板 3、搅拌器 4、奇怪的钟 5、起重机 6、烤肉架 7、手摇风扇 8、履带车 9、直升机 10、后轮驱动车 秋千 &#xff08;闽南语、广东话称千秋&#xff09;是一种座椅&#xff0c;常见于儿童游乐场、杂技演员马戏团或门廊上放松的地方。 秋千的座位通常悬挂在…

蘑菇街被裁后,成功入职字节跳动的那一天,我哭了...

前言 先说一下个人情况&#xff0c;18 届应届生&#xff0c;通过校招进入到了蘑菇街&#xff0c;然后一待就待了差不多 2 年多的时间&#xff0c;可惜的是今年 4 月份受疫情影响遇到了大裁员&#xff0c;而他也是其中一员。好在早有预感&#xff0c;提前做了准备&#xff0c;之…

C++primer(第五版)第九章(顺序容器)

简单来说存入顺序和取出顺序一致的容器被称为顺序容器. 9.1顺序容器概述 vector和string将元素保存在连续的内存空间中,所以每次添加或删除元素都会非常耗时,但是通过下标计算内存地址来读取元素是非常快的. list和forward_list为链表,添加或删除元素的操作很快,但是不支持元…

QT——使用QListWidget、QListWidgetItem、QWidget实现自定义管理列表

作者&#xff1a;小 琛 欢迎转载&#xff0c;请标明出处 文章目录 需求场景思路描述Qt模块QListWidgetQListWidgetItem自定义QWidget配合QListWidget 例子&#xff1a;实现一个json文件管理窗口 需求场景 因工作需要&#xff0c;开发一个文件管理窗口&#xff0c;要让使用者可…

蓝牙通过串口获取电量!!!

问题&#xff1a;样机短时间出现电池没电情况&#xff08;异常放电&#xff09;&#xff0c;经过检查&#xff0c;蓝牙在休眠是会有2.1V左右的电压&#xff0c;导致电池电量消耗过快。机器由于有语音功能&#xff0c;播放语音时需要很大电流&#xff0c;给机器装的是两节南孚电…

UE4/5数字人Metahuman与iClone的使用【数字人与动画】

iClone软件下载 iClone 8 是一款由Reallusion开发的3D动画软件&#xff0c;接下来就不多说了&#xff0c;首先进入官网&#xff0c;我们可以看到两个下载的东西&#xff0c;左边是下面这个软件&#xff0c;直接下载即可&#xff0c;右边的我们在后面下载&#xff1a; iClone插…

将DES解密用Python实现

将此段代码用python实现 var CryptoJS require("crypto-js"); var ciphertext "1MpdxK203ZrnyxuJRrYatKSBxHUIi1TSdQF2BQKXOG54plwfaB2GA"; var key CryptoJS.enc.Utf8.parse("11"); var parsedCiphertext CryptoJS.enc.Base64.parse(ciphe…

6月VR大数据:Quest 2下跌2个百分点,SteamVR统计加入大朋E4

Hello大家好&#xff0c;每月一期的VR内容/硬件大数据统计又和大家见面了。 想了解VR软硬件行情么&#xff1f;关注这里就对了。我们会统计Steam平台的用户及内容等数据&#xff0c;每月初准时为你推送&#xff0c;不要错过喔&#xff01; 本数据报告包含&#xff1a;Steam VR硬…

计算机找不到msvcr120.dll无法安装启动,三招修复方法

在安装运行软件的时候&#xff0c;计算机提示“找不到msvcr120.dll”&#xff0c;“msvcr120.dll缺失”无法启动运行是什么原因呢&#xff1f;msvcr120.dll是一个Windows系统的动态链接库&#xff0c;它是Microsoft Visual C Redistributable for Visual Studio 2013的一部分。…

Rosetta从头蛋白抗体设计、结构优化及在药物研发中的应用专题

第一天 时间:AM9:00~9:50 内容:一.从蛋白质折叠到蛋白质设计 教学目标&#xff1a;了解本方向内容、理论基础、研究意义。主要知识点 主要知识点:1蛋白质折叠与结构预测简介 1.1主链二面角与二级结构 1.2侧链堆积与三级结构 2蛋白质设计简介 2.1蛋白质设计的分类及应用 时间:AM…

DataGrip编写SQL语句操作Spark(Spark ThriftServer)

文章目录 1.Spark ThriftServer2.启动 Spark ThriftServer3.Beeline方式连接4.DataGrip方式连接5. 代码方式6. SparkSQL运行方式7.参考文章 1.Spark ThriftServer Spark ThriftServer 相当于一个持续性的Spark on Hive集成模式&#xff0c;可以启动并监听在10000端口&#xff…

盘口策略 | 交易中最重要的是什么?

量化策略开发&#xff0c;高质量社群&#xff0c;交易思路分享等相关内容 『正文』 ˇ 交易中最重要的是什么&#xff1f; 当然是Timing啊~~~ “时机是这个世界上最难得到&#xff0c;又最容易失去的东西”夫难得而易失者,时也&#xff1b;时至而不旋踵者,机也,故圣人常顺时…

浅谈Java8中map的新方法

Map在java8中新增了两个replace的方法 1.replace(k,v) 在指定的键已经存在并且有与之相关的映射值时才会将指定的键映射到指定的值&#xff08;新值&#xff09; 在指定的键不存在时&#xff0c;方法会return回来一个null javadoc的注释解释了该默认值方法的实现的等价Java…

Web安全-Godzilla(哥斯拉)Webshell管理工具使用

为方便您的阅读&#xff0c;可点击下方蓝色字体&#xff0c;进行跳转↓↓↓ 01 工具下载地址02 运行环境03 工具介绍04 使用案例 01 工具下载地址 https://github.com/BeichenDream/Godzilla点击页面右侧"releases"&#xff0c;进入工具的版本下载页面。 在个人终端…

安装配置云计算模板机

安装虚拟机模板机 一、在VMware上安装Centos虚拟机二、修改虚拟机的ip、网关、DNS三、更换yum源3.1 更换本地yum源3.2 更换国内互联网Yum源 四、 安装net-tools和bash-completion五、 关闭防火墙和SELinux 学习云计算后续需要多个虚拟机&#xff0c;作为云计算集群的节点&#…

数据结构--初识栈和队列

1.栈 1.1栈的概念及结构 栈&#xff1a;一种特殊的线性表&#xff0c;其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶&#xff0c;另一端称为栈底。栈中的数据元素遵守后进先出LIFO&#xff08;Last In First Out&#xff09;的原则。 压…

神级 IDEA 插件!效率提升 50 倍!

安装好Intellij idea之后&#xff0c;进行如下的初始化操作&#xff0c;工作效率提升50倍。 一. 安装插件 1. Codota 代码智能提示插件 只要打出首字母就能联想出一整条语句&#xff0c;这也太智能了&#xff0c;还显示了每条语句使用频率。原因是它学习了我的项目代码&#…

4.从CPU缓存结构到原子操作

一、CPU缓存结构 1.1 CPU的多级缓存 因为CPU的计算速度非常快&#xff0c;但内存的访问速度相对较慢。因此&#xff0c;如果CPU每次都要从内存读取数据&#xff0c;会造成大量的等待时间&#xff0c;降低整体性能。 通过引入多级缓存&#xff0c;可以在CPU和内存之间建立数据…