---- 整理自B站UP主 踌躇月光 的视频
文章目录
- 1. ALU改进
- 2. CPU 整体电路
- 3. 程序
- 4. 实验结果
1. ALU改进
此前的 ALU:
改进后的 ALU:
2. CPU 整体电路
3. 程序
# pin.py
MSR = 1
MAR = 2
MDR = 3
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
_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
SRC_R = 2 ** 10
SRC_W = 2 ** 11
DST_R = 2 ** 12
DST_W = 2 ** 13
PC_WE = 2 ** 14
PC_CS = 2 ** 15
PC_EN = 2 ** 16
PC_OUT = PC_CS
PC_IN = PC_CS | PC_WE
PC_INC = PC_CS | PC_WE | PC_EN
_OP_SHIFT = 17
OP_ADD = 0 << _OP_SHIFT
OP_SUB = 1 << _OP_SHIFT
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
CYC = 2 ** 30
HLT = 2 ** 31
# - 二地址指令IR对应
# - 1xxx [aa][bb]
# - 一地址指令IR对应
# - 01xx xx[aa]
# - 零地址指令IR对应
# - 00xx xxxx
ADDR2 = 1 << 7
ADDR1 = 1 << 6
ADDR2_SHIFT = 4
ADDR1_SHIFT = 2
AM_INS = 0 # 立即寻址 instant
AM_REG = 1 # 寄存器寻址
AM_DIR = 2 # 直接寻址 direct
AM_RAM = 3 # 寄存器间接寻址
# 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_SHIFT) | pin.ADDR2 # MOV指令定义为 1000 xxxx
ADD = (1 << pin.ADDR2_SHIFT) | pin.ADDR2 # ADD指令定义为 1001 xxxx
SUB = (2 << pin.ADDR2_SHIFT) | pin.ADDR2
INC = (0 << pin.ADDR1_SHIFT) | pin.ADDR1
DEC = (1 << pin.ADDR1_SHIFT) | pin.ADDR1
NOP = 0
HLT = 0x3f
INSTRUCTIONS = {
2: { # 二地址指令
MOV: { # MOV指令寻址方式
(pin.AM_REG, pin.AM_INS): [ # (寄存器寻址,立即寻址) ==> MOV A,5
pin.DST_W | pin.SRC_OUT, # 微指令:读取SRC寄存器里数据(5)送入DST指定的寄存器(A)中
],
(pin.AM_REG, pin.AM_REG): [ # MOV A, B
pin.DST_W | pin.SRC_R # 写寄存器(A),读寄存器(B)
],
(pin.AM_REG, pin.AM_DIR): [ # MOV A, [5]
pin.SRC_OUT | pin.MAR_IN, # 从SRC寄存器读,送到MAR寄存器(RAM地址上)
pin.DST_W | pin.RAM_OUT # 读取RAM指定地址的数据,写到寄存器(A),
],
(pin.AM_REG, pin.AM_RAM): [ # MOV A, [B]
pin.SRC_R | pin.MAR_IN, # 读取寄存器(B)数据,送到MAR寄存器(RAM地址上)
pin.DST_W | pin.RAM_OUT # 读取RAM指定地址的数据,写到寄存器(A)
],
(pin.AM_DIR, pin.AM_INS): [ # MOV [0x2f], 5
pin.DST_OUT | pin.MAR_IN, # 读取DST寄存器数据,送到MAR寄存器(RAM地址上)
pin.RAM_IN | pin.SRC_OUT # 从SRC寄存器读取数据5,写入RAM中
],
(pin.AM_DIR, pin.AM_REG): [ # MOV [0x2f], A
pin.DST_OUT | pin.MAR_IN,
pin.RAM_IN | pin.SRC_R
],
(pin.AM_DIR, pin.AM_DIR): [ # MOV [0x2f], [0x2e]
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): [ # MOV [0x2f], [A]
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): [ # MOV [A], 5
pin.DST_R | pin.MAR_IN,
pin.RAM_IN | pin.SRC_OUT
],
(pin.AM_RAM, pin.AM_REG): [ # MOV [A], B
pin.DST_R | pin.MAR_IN,
pin.RAM_IN | pin.SRC_R
],
(pin.AM_RAM, pin.AM_DIR): [ # MOV [A], [0x30]
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): [ # MOV [A], [B]
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): [ # ADD D, 5
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): [ # ADD D, C
pin.DST_R | pin.A_IN,
pin.SRC_R | pin.B_IN,
pin.OP_ADD | pin.ALU_OUT | pin.DST_W | pin.ALU_PSW
],
},
SUB: {
(pin.AM_REG, pin.AM_INS): [ # SUB D, 5
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): [ # SUB D, C
pin.DST_R | pin.A_IN,
pin.SRC_R | pin.B_IN,
pin.OP_SUB | 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
],
},
}, # 一地址指令
0: { # 零地址指令
NOP: [
pin.CYC, # 让指令周期清零,跳过这次指令
],
HLT: [
pin.HLT, # 指令停止
]
}
}
# print(bin(MOV))
# controller.py
import os
import pin
import assembly as ASM
dirname = os.path.dirname(__file__)
filename = os.path.join(dirname, 'micro.bin')
micro = [pin.HLT for _ in range(0x10000)]
def compile_addr2(addr, ir, psw, index):
global micro
# addr ==> | IR | PSW | CYC |
# 二地址指令IR对应 ==> 1xxx [aa][bb]
op = ir & 0xf0
amd = (ir >> 2) & 3 # [aa] 寻址方式
ams = ir & 3 # [bb] 寻址方式
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] # 找到IR和寻址方式
if index < len(EXEC): # 补到FETCH后面
micro[addr] = EXEC[index]
else:
micro[addr] = pin.CYC
# 01xx xx[bb]
def compile_addr1(addr, ir, psw, index):
global micro
# addr ==> | IR | PSW | CYC |
# 一地址指令IR对应 ==> 01xx xx[bb]
op = ir & 0xfc
amd = ir & 3 # [bb] 寻址方式
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] # 找到IR和寻址方式
if index < len(EXEC): # 补到FETCH后面
micro[addr] = EXEC[index]
else:
micro[addr] = pin.CYC
# 00xx xxxx
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
for addr in range(0x10000): # 指令集处理
# | IR | PSW | CYC |
# 8 4 4
ir = addr >> 8
psw = (addr >> 4) & 0xf
cyc = addr & 0xf
# 先处理 取指指令FETCH
if cyc < len(ASM.FETCH):
micro[addr] = ASM.FETCH[cyc]
continue
addr2 = ir & (1 << 7) # 二地址
addr1 = ir & (1 << 6) # 一地址
index = cyc - len(ASM.FETCH) # FETCH占据了前面的位置,这里表示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('Compile micro instruction finish!!!')
# compiler.py
import os
import re # re模块提供了各种各样的正则表达式方法
import pin
import assembly as ASM
dirname = os.path.dirname(__file__)
inputfile = os.path.join(dirname, 'program.asm')
outputfile = os.path.join(dirname, 'program.bin')
annotation = re.compile(r"(.*?);.*") # 这个正则表达式的目的是捕获分号;之前的所有内容
codes = []
OP2 = {
'MOV': ASM.MOV,
'ADD': ASM.ADD,
'SUB': ASM.SUB
}
OP1 = {
'INC': ASM.INC,
'DEC': ASM.DEC
}
OP0 = {
'NOP': ASM.NOP,
'HLT': ASM.HLT,
}
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,
}
class Code(object):
def __init__(self, number, source):
self.numer = number # 行号
self.source = source.upper() # 源代码
self.op = None
self.dst = None
self.src = None
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): # 获取目的操作数和源操作数
if not addr:
return None, None
if addr in REGISTERS: # 如果是寄存器,返回寄存器编码。示例就是A寄存器
return pin.AM_REG, REGISTERS[addr]
if re.match(r'^[0-9]+$', addr): # 如果是数字,返回立即数。示例就是5
return pin.AM_INS, int (addr)
if re.match(r'^0X[0-9A-F]+$', addr): # 如果是十六进制数,返回十六进制立即数
return pin.AM_INS, int(addr, 16)
match = re.match(r'^\[([0-9]+)\]$', addr)
if match:
return pin.AM_DIR, int(match.group(1))
match = re.match(r'^\[(0X[0-9A-F]+)\]$', addr)
if match:
return pin.AM_DIR, int(match.group(1), 16)
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): # 预处理汇编代码,以MOV A,5举例
tup = self.source.split(',') # 用逗号分隔
if len(tup) > 2:
raise SyntaxError(self)
if len(tup) == 2:
self.src = tup[1].strip() # 5赋值给源操作数
tup = re.split(r" +", tup[0]) # 正则表达式,将tup[0]字符串中的一个或多个连续空格作为分隔符,将字符串拆分成多个部分,并返回一个包含拆分后的所有部分的列表。将 MOV A拆分成了MOV和A
if len(tup) > 2:
raise SyntaxError(self)
if len(tup) == 2:
self.dst = tup[1].strip() # A赋值给了目的操作数
self.op = tup[0].strip() # MOV赋值给指令
def compile_code(self):
# 指令IR ==> op + amd + ams
# MOV ==> 1000 + [aa] + [bb]
op = self.get_op()
amd, dst = self.get_am(self.dst) # 预处理之后已经拿到self.dst=A
ams, src = self.get_am(self.src) # 预处理之后已经拿到self.src=5
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.numer}] - {self.source}'
class SyntaxError(Exception):
def __init__(self,code: Code, *args, **kwargs):
super().__init__(*args, **kwargs)
self.code = code
def compile_program():
with open(inputfile, encoding='utf8') as file: # 打开汇编源码
lines = file.readlines()
for index, line in enumerate(lines):
source = line.strip() # 将两端的空格去掉
if ';' in source: # 将;后面的去掉
match = annotation.match(source) # 使用之前定义的正则表达式annotation来匹配分号之前的内容
source = match.group(1)
if not source: # 检查source是否为空或只包含空白字符(例如空格、制表符、换行符等)
continue
code = Code(index + 1, source) # 传入行号和每行的汇编代码
codes.append(code)
with open(outputfile, 'wb') as file:
for code in codes:
values = code.compile_code()
for value in values:
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}')
return
print('compile program.asm finished!!!')
if __name__ == '__main__':
main()
# program.asm
; ; 1
; MOV D, 1;
; ADD D, 5;
; ; 2
; MOV D, 4
; MOV C, 7
; ADD D, C
; ; 3
; MOV D, 250
; MOV C, 250
; ADD D, C
; ; 4
; MOV D, 0
; MOV C, 0
; ADD D, C
; ; 5
; MOV D, 5
; SUB D, 5
; 6
MOV D, 0;
INC D;
INC D;
INC D;
INC D;
INC D;
; DEC D
; DEC D
; DEC D
; DEC D
; DEC D
HLT
4. 实验结果
依次将 3. 中的几种情况的注释打开,编译运行,这里只给出最后一次的结果。