You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

144 lines
4.3 KiB
Python

import os
import re
import pin
import assembly as ASM
from controller import get_hex_str, save_hex_str
# 允许操作的寄存器
ALLOW_REGISTER_MAP = {
"a": pin.A,
"b": pin.B,
"c": pin.C,
"d": pin.D,
}
OP2_STR_MAP = {
"mov": ASM.MOV,
}
OP1_STR_MAP = {
}
OP0_STR_MAP = {
"nop": ASM.NOP,
"hlt": ASM.HLT,
}
OP2_VALUE_SET = set(OP2_STR_MAP.values())
OP1_VALUE_SET = set(OP1_STR_MAP.values())
OP0_VALUE_SET = set(OP0_STR_MAP.values())
class Code:
def __init__(self, number, source):
self.number: int = number # 行号
self.source: str = source # 源代码
self._op_str = self._src = self._dst = None
self.prepare_source()
def __repr__(self):
return f"[{self.number}] - op: {self._op_str}, dst: {self._dst}, src: {self._src} - '{self.source}'"
def prepare_source(self):
tup = self.source.split(",")
if len(tup) > 2:
raise Exception("指令格式错误")
if len(tup) == 2:
self._src = tup[1].strip()
tup = re.split(r" +", tup[0])
if len(tup) > 2:
raise Exception("指令格式错误")
if len(tup) == 2:
self._dst = tup[1].strip()
self._op_str = tup[0]
@property
def op(self):
# 根据 mov, add 等指令得到对应的操作二进制码
if self._op_str in OP2_STR_MAP:
op = OP2_STR_MAP[self._op_str]
elif self._op_str in OP1_STR_MAP:
op = OP1_STR_MAP[self._op_str]
else:
op = OP0_STR_MAP[self._op_str]
return op
def get_am(self, addr: str):
# 得到目的操作数和源操作数, 返回(寻址方式, 地址)
if addr is None:
return None, None
if addr in ALLOW_REGISTER_MAP: # 如果是寄存器寻址, 且必须是允许的寄存器
return pin.AM_REG, ALLOW_REGISTER_MAP[addr]
if re.match(r"^[0-9]+$", addr): # 如果是立即数
return pin.AM_INS, int(addr)
if re.match(r"^0[Xx][0-9A-Za-z]+$", addr): # 如果是16进制立即数
return pin.AM_INS, int(addr, 16)
if re.match(r"^\[[0-9]+\]$", addr): # 如果是立即数
return pin.AM_DIR, int(addr[1:-1])
if re.match(r"^\[0[Xx][0-9A-Za-z]+\]$", addr): # 如果是16进制立即数
return pin.AM_DIR, int(addr[1:-1], 16)
if re.match(r"^\[.+\]$", addr): # 如果是 [a]
reg = addr[1:-1]
if reg in ALLOW_REGISTER_MAP:
return pin.AM_RAM, ALLOW_REGISTER_MAP[reg]
raise Exception(f"操作数 地址错误: {self}")
def compile_code(self):
amd, dst = self.get_am(self._dst) # 目的操作数
ams, src = self.get_am(self._src) # 源操作数
# print(amd, dst, ams, src)
if src and (amd, ams) not in ASM.INSTRUCTIONS[2][self.op]:
raise Exception(f"操作数 地址错误: {self}")
elif src is None and dst and amd not in ASM.INSTRUCTIONS[1][self.op]:
raise Exception(f"操作数 地址错误: {self}")
elif src is None and dst is None and self.op not in ASM.INSTRUCTIONS[0]:
raise Exception(f"操作数 地址错误: {self}")
if not src and not dst:
amd = dst = ams = src = 0
# 根据op, 构建 ir寄存器
if self.op in OP2_VALUE_SET:
ir = self.op | amd << 2 | ams
elif self.op in OP1_VALUE_SET:
ir = self.op | amd
else:
ir = self.op
return ir, dst, src
def compile_program(input_file: str):
codes = []
with open(input_file, "r") as f:
lines = f.readlines()
for idx, line in enumerate(lines):
source = line.strip().split(";")[0] # 去掉空格和注释
if len(source) == 0:
continue
code = Code(idx + 1, source)
codes.append(code)
return codes
if __name__ == '__main__':
data_width = 8
addr_width = 16
input_file = "./test_mov.asm"
output_file = "test_mov.bin"
program_bin_data = []
for code in compile_program(input_file):
values = code.compile_code()
for value in values:
program_bin_data.append(value)
print(get_hex_str(program_bin_data, data_width / 4))
save_hex_str(get_hex_str(program_bin_data, data_width / 4), 8, "program.bin")