当前位置:   article > 正文

26 - 汇编编译器

26 - 汇编编译器

---- 整理自B站UP主 踌躇月光 的视频

1. CPU 电路

请添加图片描述

2. 汇编编译器

将上一节我们手动把 MOV A,5 转换成机器语言的方式,用汇编编译器实现。

# program.asm
MOV A, 5 ; this is annotation

MOV A, 5
MOV B, 10
MOV C, 0x10
MOV D, 20

MOV A, 0x30

HLT;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
# 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
}

OP1 = {
    
}

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 0, 0
        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)
        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 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():
    compile_program()
    # try:
    #     compile_program()
    # except SyntaxError as e:
    #     print(f'Syntax error at {e.code}')
    #     return

    print('compile program.asm finished!!!')
        
if __name__ == '__main__':
    main()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141

启动编译,我们可以得到 program.bin,需要将其加载到内存 RAM 中执行。

3. 实验

【26 - 汇编编译器】

请添加图片描述

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/515169
推荐阅读
相关标签
  

闽ICP备14008679号