# 全能编译器 **Repository Path**: zeng_ge/zg-assembler-next ## Basic Information - **Project Name**: 全能编译器 - **Description**: 一个VSCode的插件,支持 6502 / 65c816 / z80-gb / spc700 汇编指令 - **Primary Language**: TypeScript - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 2 - **Forks**: 1 - **Created**: 2023-02-01 - **Last Updated**: 2025-09-02 ## Categories & Tags **Categories**: Uncategorized **Tags**: 6502, 65c816, z80-gb, spc700 ## README # Zeng Ge Assembler [English](./doc/README-en.md) 一个 VSCode 的编译器插件,可以编译 6502 / 65c816 / z80-gb / SPC700 [![MIT License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE.md) ![GitHub package.json version](https://img.shields.io/github/package-json/v/zyr2288/zg-assembler) 测试项目文件: [![Test Files](https://img.shields.io/badge/github-black?logo=github)](https://github.com/zyr2288/zg-assembler-test) [![Test Files](https://img.shields.io/badge/gitee-red?logo=gitee)](https://gitee.com/zeng_ge/zgassembler-test) > 注意:编译器只监视 `*.asm` 文件,并不是 `*.65s` 文件 ## 所有编译器命令 1. [.BASE](#base) 2. [.ORG](#org) 3. [.DEF](#def) 4. [.ENUM .ENDE](#enum-ende) 5. [.DB .DW .DL](#db-dw-dl) 6. [.DBG .DWG .DLG .ENDD](#dbg-dwg-dlg-endd) 7. [.HEX](#hex) 8. [.IF .ELSEIF .ELSE .ENDIF](#if-elseif-else-endif) 9. [.IFDEF .IFNDEF .ELSE .ENDIF](#ifdef-ifndef-else-endif) 10. [.INCBIN](#incbin) 11. [.INCLUDE](#include) 12. [.MACRO .ENDM](#macro-endm) 13. [.REPEAT .ENDR](#repeat-endr) 14. [.MSG .ERROR](#msg-error) --- ## 配置文件 - [编译器插件地址](https://marketplace.visualstudio.com/items?itemName=ZENG-GE.zg-assembler) - 或者可以在 VSCode 插件里搜索 `ZG Assembler` 即可找到插件 - 一个 [VSCode](https://code.visualstudio.com/) 的可扩展的编译器,目前支持 `6502` `65c816`(感谢 Thirteen) `z80-gb`,将来会加入更多适应平台。 - 配置文件,当打开汇编文件会在目录下创建 `project-settings.json` 文件,默认以下配置 - 如果你想单独编译内核,请使用 `npm run build-core`,详情请查看 [内核单独编译方法](doc/内核单独编译方法.md) ```json { "platform": "6502", // 选择平台 "intellisense": true, // 是否开启智能提示 "outOfRangeWarning": true, // 编译结果越界警告 "entry": "main.asm", // 入口文件 "compileTimes": 2, // 编译次数,至少两次,否则会出错 "outputEntryFile": "", // 输出入口文件,不写则不输出 "outputSingleFile": "", // 单个文件输出,不写则不输出 "copyToClipboard": true, // 结果是否复制到剪贴板 "includes": ["**/*.asm"], // 项目包含的文件 "excludes": [] // 项目排除的文件 } ``` --- ## 功能介绍 ### 编译 - 在`asm`文件下的编辑器内,点击鼠标右键则会出现编译菜单。 --- ### 固定寻址长度 通常情况下,编译器将自动优化寻址方式,以 `6502` 为例: ``` .ORG $0 LDA $00F0,X ``` 由于编译器的自动优化,这里的编译结果是 `B5 F0`,但是在某些情况下需要寻址长度为 2,需要固定寻址长度,此时可以改成以下形式: ``` .ORG 0 LDA.2 $00F0,X ; 固定寻址长度为2字节 ``` 此时编译的结果为 `BD F0 00` --- ### 标签 - 在这个版本增加了子标签的功能,可以使用例如 `player.x` `player.y` 这样的子标签,并且智能提示能更好的协助你。 - 按 vscode 的查找定义快捷键(默认 F12)可直接找到标签定义位置。 - 编译器定义的 `xx = yy` 是作为变量,编译器将不会检查重复定义的变量。如要定义常量,请使用 `.DEF` 命令。 --- ### 局部标签 - 若文件内使用标签(非编译器指令)以.(点)开头,则该标签的有效范围仅仅于本文件。 - 这样有利于可以在不同文件使用相同名称的标签。 --- ### 简易标签 - 当标签以全部是+号或全部是-号的时候,则是简易标签。例如: ``` -- LDA $2002 BPL -- LDA $0 BEQ + BPL ++ JMP $9000 + JMP $8000 ++ JMP $A000 ; AD 02 20 10 FB A5 00 F0 05 10 06 4C 00 90 4C 00 80 4C 00 A0 ``` --- ### 运算符 > 注意:由于内核使用的是 JS,所有运算符是以 JS 的运算符计算方法进行计算。例如: ~$A -> -11 ``` + - * / & | ~ ^ >> << && || ! == != >= <= ``` --- ### 特殊运算符 1. `>` 与 `<` 都有特殊的意义,例如 `>$1234` 即取高位 ($12), `<$1234` 取低位 ($34) 2. `*` 有当不作为乘号时有特殊的意义,表示当前行的 `ORG` 地址 3. `$` 作为单独符号出现(即不为 16 进制标识符),表示当前行的 `BASE` 地址 --- ### 字符串 有时候数据以字符串形式出现,例如 `.DB "HELLO WORLD"` 但是由于一些特殊限制,比如此字符串中的空格是十六进制 `00`,可以通过简单的变换,结果如下: `.DB "HELLO\x00WORLD"` Unicode 形式 `.DB "HELLO\u{00}WORLD"` --- ### 注释与折叠 - 当包含 `;` 字符,该行 `;` 之后所有内容都是注释 - 注释为 `;+` `;-` 则为折叠,方便折叠部分代码 --- ### 关于智能提示 插件默认关闭基于字词的建议,想启用该功能,在 vscode 的设置内加入 ```json { "[zg-assembly]": { "editor.wordBasedSuggestions": "matchingDocuments" } } ``` --- ## 编译器命令 > 以下命令内中括号为可选参数 ---
.BASE ### `.BASE` ``` .BASE 文件起始位置 ``` - 设置生成文件地址,**默认为 `.BASE 0` **,这里不等同与 `.ORG`。 - 例如:若 `.BASE $10` ,则生成的文件编译内容从 `$10` 开始写入,之前的 `$F` 个地址为 `0`。 > 注意 > > 1. 编译自上而下,一些第一次编译需要赋值的变量如果第一次编译未知则编译不成功。 > 2. 如果使用`.BASE`命令,则在`.ORG`之后,否则编译错误。
---
.ORG ### `.ORG` ``` .ORG 编译起始位置 ``` - 设置开始编译地址,例如:`.ORG $8000`,则编译将从$8000 开始。 - 也可以使用`.ORG *`,表示从当前地址开始编译。不过要知道当前地址,否则编译器报错。 - 注意:如果使用 `.BASE` 命令,则在 `.ORG` 之后,否则编译错误。
---
.DEF ### `.DEF` ``` .DEF 标签, 表达式 ``` - 定义一个常量,例如:`.DEF idefined, $12`。 > 注意:`temp = $12` 虽然也能定义,用等号可重复定义。
---
.ENUM .ENDE ### `.ENUM` `.ENDE` ``` .ENUM 起始地址 标签, 字节长度 ... .ENDE ``` - 定义一系列连续的地址,通常用于定义一系列内存地址 - 例如: ``` .ENUM $300 music.counter, 1 ; 类似 .DEF music.counter, $300 music.addrHigh, 2 ; 类似 .DEF music.addrHigh, $301 (music.counter + 1) music.addrLow, 3 ; 类似 .DEF music.addrLow, $303 (music.addrHigh + 2) .ENDE ```
---
.DB .DW .DL ### `.DB` `.DW` `.DL` ``` .DB 数据1 [, 数据2, 数据3...] ;1字节 .DW 数据1 [, 数据2, 数据3...] ;2字节 .DL 数据1 [, 数据2, 数据3...] ;4字节 ``` - 一系列数据。
---
.DBG .DWG .DLG .ENDD ### `.DBG` `.DWG` `.DLG` `.ENDD` - 数据组,用于定位数据位置。 ``` .DWG 标签 .data1, .data2, .data3, .data1 .ENDD LDA 标签:.data1 ;0 LDA 标签:.data3 ;2 LDA 标签:.data1:1 ;3 ```
---
.HEX ### `.HEX` ``` .HEX 16进制字符串 .HEX 12 34567 89 ;12 34 56 07 89 ``` - 一段 16 进制数据,可以用空格隔开。 > 注意:之后只能输入 16 进制数据,否则编译器会报错。
---
.IF .ELSEIF .ELSE .ENDIF ### `.IF` `.ELSEIF` `.ELSE` `.ENDIF` - 这里是一套判断条件,根据条件是否成立是否编译相应内容。 > 注意:必须要在使用这些之前知道参数的信息,否则编译报错 ``` .IF a == 5 ..... .ELSEIF b >= 5 ..... .ELSEIF c != 3 ..... .ELSE ..... .ENDIF ```
---
.IFDEF .IFNDEF .ELSE .ENDIF ### `.IFDEF` `.IFNDEF` `.ELSE` `.ENDIF` ``` .IFDEF 标签或自定义函数 ..... .ELSE ..... .ENDIF ``` - 这里是一套判断条件,根据条件是否成立是否编译相应内容。 - 用法同 `.IF` 的命令类似,后面可以用 `.ELSE` `.ENDIF` - 这里是判断变量或自定义函数是否存在,`.IFDEF`为判断变量或自定义函数存在,`.IFNDEF`为判断变量或自定义函数不存在。 > 注:必须要在使用这些之前知道参数的信息,否则编译报错
---
.INCBIN ### `.INCBIN` ``` .INCBIN 文件相对路径[, 读取文件起始位置, 读取长度] ``` - 可以读取引用文件的二进制内容,后面双引号内请填写本文件的相对路径。 例如: ``` .INCBIN "文件夹\文件.bin", 0, 100 ```
---
.INCLUDE ### `.INCLUDE` ``` .INCLUDE 文件相对路径 ``` - 可以引用文件,后面双引号内请填写本文件的相对路径。 - 如果引用文件内也有引用文件,请相对于主编译文件路径填写。 例如: ``` .INCLUDE "文件夹\文件.asm"。 ```
---
.MACRO .ENDM ### `.MACRO` `.ENDM` ``` .MACRO 自定义函数名称[, 参数1, 参数2...] ..... .ENDM ``` > 注意:用这里的指令可以自定义函数,所要使用的函数要在编译之前定义好,否则编译器会报错。 > 注意:所有自定义函数内的 **标签** 属于 **局部变量**,请勿在函数外部使用。 > 注意:所有自定义函数内定义的 **变量** 均为 **全局变量**。 实例 1: ``` .MACRO TXY TXA TAY .ENDM TXY ``` - 编译之后结果为:`8A A8` 实例 2: ``` .MACRO test, a, b .IF 3 == a LDA 3 .ELSEIF 4 == a LDX 4 .ELSEIF 5 == a && 5 == b LDY 5 .ELSE LDA 6 STA 6 .ENDIF .ENDM test 3,3 test 4,3 test 5,4 test 5,5 ``` - 编译之后结果为:`A5 03 A6 04 A5 06 85 06 A4 05`
---
.REPEAT .ENDR ### `.REPEAT` `.ENDR` ``` .REPEAT 重复次数 ..... .ENDR ``` - 可以重复某个指令多次,在 `.REPEAT` 后输入表达式即可。 > 注意:每个 `.REPEAT` 和 `.ENDR` 必须成对出现,可以嵌套。 ``` .REPEAT 2 NOP .REPEAT 3 ASL .ENDR .ENDR ``` - 对应编译的结果相当于:`NOP ASL ASL ASL NOP ASL ASL ASL`
---
.MSG .ERROR ### `.MSG` `.ERROR` ``` .MSG 输出信息[, 参数1, 参数2...] .ERROR 输出信息[, 参数1, 参数2...] ``` - MSG 为可输出一条信息 - ERROR 为输出一条信息并停止编译 ``` .ORG $8000 .DEF test1, 10 .DEF test2, 11 .MSG "测试案例 {0}, ${1}, @{0}", test1, test2 .IF test1 == 10 .ERROR "这里的 test1: {0}", test1 .ENDIF ``` - 这里输出的信息是: > 测试案例 10, $B, @0000 1010 > > 这里的 test1: 10