Z80 汇编器





5.00/5 (15投票s)
早在 1984 年,我就想编写一个 Z80 汇编器。当时,这意味着要用 Z80 机器码来编写,但由于现代技术的便利,我现在用 C++ 完成了它。
实现
我再次使用自己的词法分析和解析库来实现汇编器。一个典型的规则看起来像这样
g_map[grules.push("opcode", "LD '(' HL ')' ',' integer")] = [](data& data)
{
data._memory.push_back(0x36);
data.push_byte();
};
汇编器有两种运行模式。如果只提供源文件,则源文件将连同操作码一起转储回 std::cout
。但是,如果提供了模板 .sna 文件和目标路径名,则会创建一个包含汇编代码的新 .sna 文件。
例如,如果您的源代码如下所示
ORG 23296
LD IX, 16384
LD DE, 6912
CALL 1366
RET
那么默认输出看起来像这样
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 的简单填充例程
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
这是 Sinclair Basic 中的驱动程序
10 CIRCLE 125,100,50
14 POKE 23296,25
16 POKE 23297,15
20 RANDOMIZE USR 23298
生成结果如下
Using the Code
用法: z80_assembler <路径名> [<源 .sna> <目标 .sna>]
这是一个正在进行中的工作,所以请务必报告任何问题。
历史
- 2020 年 10 月 3 日:发布
- 2020 年 10 月 3 日:添加了 Z80 源代码示例
- 2020 年 10 月 3 日:现在默认情况下转储带有操作码的
mnemonic
- 2020 年 10 月 4 日:现在支持整数以及 CALL 和 JP 的标签
- 2020 年 10 月 4 日:修复了规则 integer: Hex;
- 2020 年 10 月 4 日:修复了
wlabel()
- 2020 年 10 月 5 日:无法识别的反汇编操作码现在显示为 db nnn
- 2020 年 10 月 5 日:如果标签与操作码位于同一行,则正确计算地址
- 2020 年 10 月 15 日:现在检查是否超出内存末尾,并简化了代码。
- 2020 年 10 月 16 日:修复了 RST 指令。
- 2020 年 10 月 20 日:添加了缺少的指令。
- 2020 年 10 月 21 日:添加了基本表达式支持,并修复了大量无效索引。
- 2020 年 10 月 21 日:添加了 '*', '/', '|' 和 '&' 支持,并修复了更多索引。
- 2020 年 10 月 21 日:添加了 gcc Makefile。
- 2020 年 10 月 22 日:添加了未公开的指令。
- 2020 年 10 月 24 日:现在允许在 EQU、DB 和 DW 表达式中使用括号。
- 2020 年 1 月 10 日:修复了 DS/DEFS 以使其正常工作。 获取了 JSW 的反汇编,并成功地汇编并运行了它。
- 2020 年 1 月 16 日:添加了对所有指令的测试,并修复了许多指令的反汇编。
- 2020 年 1 月 17 日:修复了 DS 指令,在反汇编器中添加了缺少的空格,添加了另一个测试文件。
- 2020 年 1 月 19 日:将助记符验证添加到测试代码。
- 2020 年 2 月 2 日:汇编器现在记录字节范围的类型(代码、db、dw、ds),以辅助反汇编。
- 2021 年 2 月 3 日:始终在 dump() 中设置偏移量。
- 2021 年 7 月 3 日:更新了
parsertl
。 - 2021 年 8 月 30 日:引入了 program struct。
- 2021 年 9 月 1 日:修复了 disassem.cpp 中的求值顺序,并修复了 clang 警告。
- 2021 年 9 月 2 日:修复了使用 clang 和 -Wall 构建时的警告。
- 2022 年 3 月 15 日:添加了用于十六进制、十进制和相对跳转(偏移量、绝对)的开关。
- 2022 年 3 月 16 日:现在将 base 和 relative 传递给 main.cpp 中的 parse() 和 dump()。
- 2022 年 4 月 14 日:修复了命令行处理,并在十六进制模式下将“h”添加到 realtive 跳转中。
- 2022 年 4 月 17 日:反汇编器现在为 db 每行输出最多 4 个字节,为 dw 每行输出 2 个字。
- 2022 年 5 月 6 日:索引寄存器采用带符号的位移(在反汇编器中)。
- 2022 年 8 月 11 日:+/- 修复了
sbto_string()
- 2023 年 1 月 21 日:更新为使用最新版本的
parsertl
。 - 2023 年 1 月 31 日:更新为使用最新版本的
parsertl
。 - 2023 年 9 月 11 日:更新到最新的
lexertl
和parsertl
。 将lexertl
路径添加到 Makefile 和 .vcxproj。 - 2024 年 2 月 15 日:更新为使用
lexertl17
和parsertl17
。 - 2024 年 4 月 20 日:添加了
$
(程序计数器)支持。 - 2024 年 5 月 24 日:添加了
.skool
文件支持。