汇编器是一种将汇编语言代码转换为机器代码的程序。在本文中,将探讨如何开发一个汇编器,以及如何使用它来编写和运行汇编程序。
开发一个汇编器需要对目标处理器的指令集有深入的了解。以Z80处理器为例,需要创建一个映射表,将汇编指令映射到相应的机器码。例如,如果想要实现一个加载指令(LD),可以定义一个规则如下:
C++
g_map[grules.push(
"
opcode"
,
"
LD '(' HL ')' ',' integer"
)] = [](data& data)
{
data._memory.push_back(
0x36
);
data.push_byte();
};
这个规则定义了一个函数,当遇到LD指令时,它会将机器码0x36添加到内存中,并将其推送到输出流中。
汇编器可以以两种模式运行。如果只提供了源文件,那么汇编器将把源代码和对应的操作码输出到标准输出(std::cout)。如果提供了模板文件(.sna)和目标路径名,那么汇编器将创建一个新的.sna文件,其中包含了汇编后的代码。
例如,如果源代码如下:
ASM
ORG 23296
LD IX,
16384
LD DE,
6912
CALL
1366
RET
那么默认输出将如下所示:
ASM
23296
221
33
0
64
LD IX,
16384
23300
17
0
27
LD DE,
6912
23303
205
86
5
CALL
1366
23306
201
RET
下面是一个简单的填充例程,用于Sinclair ZX Spectrum:
ASM
ORG 23298
LD BC, (23296)
CALL
GetScreenPos
Line:
CALL
FillLine
CALL
GetNextLine
LD A, (HL)
OR
A
JR Z, Line
RET
FillLine:
PUSH
HL
CALL
FillLeft
POP
HL
PUSH
HL
INC
HL
CALL
FillRight
POP
HL
RET
FillLeft:
LD A, (HL)
OR
A
JR NZ, MaskLeft
LD (HL),
255
DEC
HL
JR FillLeft
MaskLeft:
LD B,
0
PUSH
AF
LeftAgain:
BIT
0
, A
JR NZ, EndFillLeft
SLA B
SET
0
, B
SRA A
JR LeftAgain
EndFillLeft:
POP
AF
OR
B
LD (HL), A
RET
FillRight:
LD A, (HL)
OR
A
JR NZ, MaskRight
LD (HL),
255
INC
HL
JR FillRight
MaskRight:
LD B,
0
PUSH
AF
RightAgain:
BIT
7
, A
JR NZ, EndFillRight
SRA B
SET
7
, B
SLA A
JR RightAgain
EndFillRight:
POP
AF
OR
B
LD (HL), A
RET
GetScreenPos:
LD A, C
AND
%00111000
RLCA
RLCA
OR
B
LD L, A
LD A, C
AND
%00000111
LD H, A
LD A, C
AND
%11000000
RRCA
RRCA
RRCA
OR
H
OR
&40
LD H, A
RET
;
Takes HL as Screen Address
GetNextLine:
INC
H
LD A, H
AND
7
RET
NZ
LD A, L
ADD
A,
32
LD L, A
RET
C
LD A, H
SUB
8
LD H, A
RET
要使用汇编器,需要提供源文件的路径名。例如:
USAGE: z80_assembler [ ]