【怀旧编程技术】Merlin 6502交叉汇编环境手册

 声明:本汇编语言及其汇编开发环境已被淘汰,这个教程只是面向古计算机爱好者的,Merlin的资料也有很多,完全可以拿来学(只不过全英你看不看得懂那是另一回事了)。因此,这篇教程只是我用来闲暇消磨时间写的了,至少这比天天玩游戏强得多。 

一、什么是Merlin?

        Merlin 32是一个在Windows、Linux和Mac OS X下运行的多通道交叉汇编程序,针对6502系列中的8位处理器(如6502和65c02)和16位65c816处理器。与Glen Bredon的Merlin 16+语法兼容,包括对宏、预处理器、逻辑表达式、条件运算、变量、循环、LABLE的支持等。

        Merlin 32可以构建固定位置的目标代码或可重定位的可执行文件(OMF v2.1),可以在16位Apple IIgs操作系统上找到,如Prodos 16或GS/OS(S16、Exe、CDA、NDA、FST、PIF、库、工具……)。也是Brutal Deluxe跨开发工具项目的一部分,此项目是Windows(和其他)平台上可用的全套实用程序,用于创建新的Apple IIgs软件:65c816汇编程序、65c816反汇编程序、65c816模拟器、图形文件转换器、资源捕获器。。。

用途

        在上世纪80年代欧美地区的IT圈中,此时主流高级语言也只不过是BASIC。其效率与速度非常拉跨,况且那个年代的CPU主频仅是几兆赫兹(MHz),若进行游戏、软件开发。那是及其的缓慢,此时程序员正经历着两种局面——一个是简单但性能实在糟糕的BASIC,一个是繁琐但能几乎完全利用机能的汇编语言(汇编本身并不复杂,只是繁琐和冗杂这一点是最讨厌的)。那个时候编程,也就只能是这样,如果想开发优质的东西你就必须会汇编,要学汇编你得有个汇编器。

        人们的眼光还算不错,市场上几款汇编器要不就是BUG多要不就是其他乱七八糟的东西(那统称为BUG也可以吧大概)。而Merlin作为以前最主流的汇编器。诸如《DONKEY KONG(大金刚)》,《MARIO BRODS(马里奥兄弟)》等从NES或街机移植过来的游戏程序也是均由Merlin编写。80年代的NES红白机的游戏开发环境中也包括Apple II,配套的开发包自然也包括Merlin。而外网中Merlin汇编器相比于其他汇编器也是最常出现的,这也说明了当年Merlin的在IT圈内的火爆。但是在国内完全没有任何关于此汇编器的资料,我们当年接触过计算机的人屈指可数,编程更是少之又少,更不用说汇编了,因此几乎没人认识这个东西。

        如今,Merlin已移植到现代系统中,就不再需要用模拟器或虚拟机去编写代码了。这样进行NES游戏等开发操作也就方便了不少(呃……是这样的吗?方便了吗?为什么不用CC65这些东西?)

如何运行到这些机器?(简略教程)

1、FC / NES / 红白机

2、SFC / SNES / 超级任天堂

3、Commodore 64 / Commodore 128

4、Apple II

  1. 准备四个软件:任意一个代码文本编辑器、Merlin汇编器、CiderPress、Apple II模拟器
  2. 写好程序,用Merlin汇编好后,会生成一个没有任何扩展名的文件。这个文件就是你的目标文件。
  3. 命名为此格式:<文件名>#XXYYYY.bin。其中,<文件名>是在Apple DOS上显示的文件名,XX是文件类型,YYYY是起始地址。
  4. 打开CiderPress,选择[File] -> New -> Disk image...新建一个FileSystem(文件系统)为DOS 3.3的磁盘,其他默认不用改。
  5. 选择[Action] -> Add File(或点击菜单栏上从左往右数第六个按钮),把你的bin文件导入进去。
  6. 此时你创建的磁盘已经导入你的Bin文件,那个磁盘可以用Apple II模拟器打开了。#1磁盘驱动器导入你创建的磁盘,在终端输入“CATALOG”,找到你的文件,最后输入“BRUN <你的文件名>”即可运行你的程序。 

二、Merlin的使用

1、命令列表

        在【命令提示符】窗口中运行Merlin32.exe,会显示如下文字:

C:\AppleIIgs>Merlin32.exe
Merlin32.exe v 1.0 (c) Brutal Deluxe 2011-2021
Using:Merlin32.exe [-V] <macro_folder_path> <source_file_path>.

        在Using中表面了此汇编器的用法:

语法:    Merlin32.exe [-V] <宏文件路径> <源文件路径>
例子:    Merlin32.exe -V c:\Merlin\Library c:\Source\Cogito\Cogito.s

一、如需汇编单个.asm文件,则把<宏文件路径>与<源文件路径>都为.asm文件及其所在路径
例子:    Merlin32.exe "c:\AsmProj\test.asm" "c:\AsmProj\test.asm"
  •         参数1:[-V]  可选可不选,设置会生成一个文本文件输出装配过程
  •         参数2:<宏文件路径>  包含所有宏定义文件
  •         参数3:<源文件路径>  要组装的主要源文件(或链接文件)的路径

        汇编过程中,会输出以下装配信息:

C:\AppleIIgs\Merlin\>Merlin32.exe -V C:\AppleIIgs\Merlin\Library C:\AppleIIgs\Source\Cogito\Cogito.s
Merlin32.exe v 1.0, (c) Brutal Deluxe 2011-2021
  + Assemble project files...                    - 组装项目文件...
    o Loading Sources files...                   - 加载源文件
        - Cogito.s
        - Cogito.Main.s
        - Cogito.Bout.s
    o Loading Macro files...                     - 加载宏文件
        - Int.Macs.s
        - Locator.Macs.s
        - Mem.Macs.s
        - Misc.Macs.s
        - Sound.Macs.s
        - Tool220.Macs.s
        - Util.Macs.s
    o Check for duplicated Macros...             - 检查重复宏
    o Decoding lines types...                    - 解码行类型
    o Process local/variable Labels...           - 处理局部变量/标签
    o Process Asterisk lines...                  - 处理星号"*"行
    o Build External table...                    - 构建外部表
    o Build Equivalence table...                 - 构建等价表
    o Build Variable table...                    - 构建变量表
    o Process Equivalence values...              - 处理等价值
    o Replace Lup with code...                    
    o Replace Macros with Code...
    o Process MX directives...
    o Process Conditional directives...
    o Build Label table...
    o Check for duplicated Labels...
    o Check for unknown Source lines...
    o Check for Dum lines...
    o Compute Operand Code size...
    o Compute Operand Data size...
    o Compute Line address...
    o Build Code Line...
    o Check for Err lines...
    o Build Data Line...
    o Build Object Code...
  + Link project files...
    o Build OMF output file...
        => Creating OMF file 'C:\AppleIIgs\Source\Cogito\Cogito'
  + Create Output Text file...
     => Creating Output file 'C:\AppleIIgs\Source\Cogito\Cogito_Output.txt'

         一切正常的话,会输出一个二进制文件(无扩展名),如果设置-V参数,则会生成一个构造过程的文本文件。通过这个输出文件,可以检查预处理器(替换宏、扩展 Lups、解析局部标签、计算表达式等)、汇编器(寻址、寄存器大小、目标代码等)和链接器(多个ORG、重定位处理等)的工作。

2、输出文本解析

        假设我们输入了如下程序:

;【示例程序】
START   ORG $0300
        LDY #$00
        LDX #$06
LOOP    LDA $6000,X
        JSR $FCA8
        LDA $C030
        DEY
        BNE LOOP
        DEX
        BPL LOOP
        BRK

         将此文件保存为Program.asm,送至Merlin32汇编后(带-V)会输出如下文本:

------+-------------------+-------------+----+---------+------+-----------------------+-------------------------------------------------------------------
 Line | # File       Line | Line Type   | MX |  Reloc  | Size | Address   Object Code |  Source Code                                                      
------+-------------------+-------------+----+---------+------+-----------------------+-------------------------------------------------------------------
    1 |  1 114.asm      1 | Directive   | 11 |         |    0 | 00/8000               | START       ORG   $0300          
    2 |  1 114.asm      2 | Code        | 11 |         |    2 | 00/0300 : A0 00       |             LDY   #$00           
    3 |  1 114.asm      3 | Code        | 11 |         |    2 | 00/0302 : A2 06       |             LDX   #$06           
    4 |  1 114.asm      4 | Code        | 11 |         |    3 | 00/0304 : BD 00 60    | LOOP        LDA   $6000,X        
    5 |  1 114.asm      5 | Code        | 11 |         |    3 | 00/0307 : 20 A8 FC    |             JSR   $FCA8          
    6 |  1 114.asm      6 | Code        | 11 |         |    3 | 00/030A : AD 30 C0    |             LDA   $C030          
    7 |  1 114.asm      7 | Code        | 11 |         |    1 | 00/030D : 88          |             DEY                  
    8 |  1 114.asm      8 | Code        | 11 |         |    2 | 00/030E : D0 F4       |             BNE   LOOP           
    9 |  1 114.asm      9 | Code        | 11 |         |    1 | 00/0310 : CA          |             DEX                  
   10 |  1 114.asm     10 | Code        | 11 |         |    2 | 00/0311 : 10 F1       |             BPL   LOOP           
   11 |  1 114.asm     11 | Code        | 11 |         |    1 | 00/0313 : 00          |             BRK                  
------+-------------------+-------------+----+---------+------+-----------------------+-------------------------------------------------------------------
  •    Line(行号): 代码行号(从1到N)
  •    # File Line(文件与行号):源文件编号
  •    Line Type(行代码类型):源代码行的类型:NOP、注释、指令、等效、宏、代码或数据
  •    MX(累加器/索引寄存器大小):分辨Merlin32处理的是8-Bit代码还是16-Bit代码,MX 值通常由 MX 指令或 SEP/REP 操作码修改
  •    Reloc(重定位):对重定位的代码进行移位等操作的字节数
  •    Size(大小):每个代码的字节数
  •    Address(地址):总线地址(16位),若使用ORG指令,则从第一个地址开始。
  •    Object Code(目标代码):你的代码用机器码的表示
  •    Source Code(源代码):你的代码

3、限制

        在上一个版本(Merlin16+)中由于内存实在极为有限,因此诞生了以下规则:

  • 源文件不可大于64KB
  • 在源文件中,每一行字符数不可大于255个
  • 在源文件中,每个标签(LABLE)字符数不可大于26个
  • 操作数部分字符数不可大于80个(例如应用标签)
  • 外部文件的数量限制为 255
  • 宏可嵌套大于15个深度
  • 条件不可嵌套到8个深度
  • 符号表限制为 4096 个长度 < 12 的符号和 2048 个长度 < 12 的符号

        Merlin 32可忽略此限制,但如果需要移植到汇编器的上一个版本(Merlin16,有些机器只能用Merlin16)确保程序符合以上述规则。

4、语法

        本节是6502汇编语言中必须涉及到的一点,在源代码中,分为四个列:

  • LABEL(标签):在汇编中,指的是程序的地址,要想应用或转移至此地址可用此标签。标签可以是分支位置的标签、新宏的名称、变量的名称等。
  • OPCODE(操作码):指令中对CPU指定的操作,伪指令中指对编译器的操作,支持65c816操作码。
  • OPRAND(操作数):OPCODE(操作码)所要进行操作的对象。可以是立即数,标签(地址)以及宏参数。
  • COMMENT(注释):以分号“;”开头,编译器会完全忽略分号“;”后面的注释。

        Merlin 32对标签、宏、操作数、变量、等式等区分大小写……操作码写LDA或lda是可以的,但是PushLong和pushlong则不是同一个宏。

5、格式

        每一列可以用空白字符(如空格Tab制表符)来隔开,如图所示:

        在用Windows的文本编辑器中,不用担心缩进的问题,只需在单独的列中添加几个空格或制表符即可,注意标签字符数,规范整齐的代码更能让人阅读。

6、数据表示

        在6502汇编语言中都必然会出现诸如"#"、"$"之类的符号,这些符号都用于表示此操作数。下面是有关这些符号的解析。

6-1 立即数

        带有井号"#"的表示立即数,没有符号的话,一般是立即数或者是地址,但大部分情况下汇编器有可能会识别不出(因为不清楚这个操作数是立即数还是指地址还是什么)。但对于只需要一种操作数(数据或地址)的操作码,如REP、PEA、JSR、MVN、STA……就不需要添加"#"了。

6-2 进制

           LDA   #0            ; 十进制立即数
           LDA   #$2000        ; 十六进制立即数
           LDA   #%11110000    ; 二进制立即数

           LDA   0             ; 十进制地址
           LDA   $2000         ; 十六进制地址
           LDA   %00100000     ; 二进制地址
  •  ' $ '美元符号代表十六进制(与Intel架构不同,Intel中' 0x '才是表示十六进制)
  •  ' % '百分号代表二进制(Intel中' 0b '表示二进制)
  • 前面什么都不写表示十进制

6-3 分割字节

        某些操作数表达式可能会大于累加器大小的值,通过在' # '后面使用一些运算符("<",">","^"):

6-4 字符串

        在Merlin中,字符串是一组用但引号(')或双引号(“)括起来的ASCII字符组合。

48 65 6C 6C 6F    ASC  'Hello'        ; 使用单引号, 最高位置0 (标准ASCII)
C8 E5 EC EC EF    ASC  "Hello"        ; 使用双引号, 最高位置1 (文本屏幕)

7、标签 

        标签可以在没有任何操作码的情况下使用。这种情况下这个标签的地址值与下一行相同。

        一般标签都是全局标签,以右中括号" ] "或冒号" : "开头的标签则是局部标签(又称本地标签),局部标签是不能在宏内部或与ENT/EXT指令一起使用的。

        以右中括号" ] "开头的局部标签只能用于向后分支,循环会使用向后面的代码中最近的同名局部标签。例如:

           LDX   #$00
]LOOP      LDA   TABLE1,X      ; 第1行局部标签
           BEQ   NEXT
           INX
           BRA   ]LOOP         ; 转移到第1行局部标签
NEXT       LDY   #$00
]LOOP      LDA   TABLE2,Y      ; 第2行局部标签
           BEQ   END
           INY
           BRA   ]LOOP         ; 转移到第2行局部标签
END        RTS

     以冒号" : "开头的局部标签向前向后都能用,范围仅在全局标签之内。


BEGIN      CPX   #$A0          ; :LOOP局部标签定义在全局标签BEGIN和END之内
           BEQ   :LOOP
           LDX   #$00
:LOOP      LDA   TABLE1,X
           BEQ   END
           INX
           BRA   :LOOP
END        RTS

8、表达式

        Merlin支持表达式计算,所支持的符号有:

<  =  >  #  	小于、等于、大于、不等于
+  -            加、减
*  /            乘、除(整数)
&  .  !         与、或、异或
-               一元否定
1024+$FF                 ; 1024 + 255 = 1279
"K"-"A"+1                ; Ascii K - Ascii A + 1 = $CB - $C1 + 1 = 11
LABEL+2                  ; LABEL - 2
LABEL2-LABEL1            ; LABEL2 - LABEL1 = 两个LABLE之间的字节数
*-2                      ; 当前地址 - 2
#$9F&"A"                 ; $9F AND $C1 = $81 (Control-A)
LABEL1/LABEL2            ; 0 当 LABEL1 < LABEL2, 1 当 LABEL1 >= LABEL2

9、变量 

        变量名称区分大小写,并且始终以右中括号" ] "开头。主要用于宏和循环。

; 声明变量
]LINE      =    $2000         ; 第一条地址是 $E1/2000

; 更改变量
]LINE      =    ]LINE+160     ; 下一行
           DA   ]LINE

        不允许正向引用变量,因此请在使用变量之前先定义变量。 

三、Merlin伪指令

        伪指令是汇编不可缺少的一部分,不同汇编器伪指令也不同。6502与65c816指令集、寻址方式等不在此处赘述,本节仅讨论伪指令及其作用,每小节最底下是程序例子。

1、数据定义类

数据定义类中有关定义字符串的伪指令是服务于Apple II平台的汇编环境,如INV,FLS等指令,因为这些指令定义的字符串的以Apple II的ASCII字符映射表来分配的。

        EQU                 EQUivalence - 等于

        用于定义常量,为各个值赋予名称。不允许正向引用,因此在使用常量之前(大多数时候在程序开始时)先定义常量,可用等于号“=”代替。

        HEX                 define HEXadecimal data - 定义十六进制数据

        此指令不必在标注十六进制符号‘$’,用于标定十六进制数。可用逗号或空格隔开,其个数不得是奇数,例如:

00 01 02 03     HEX  00010203
00 01 02 03     HEX  00,01,02,03
00 01 02 03     HEX  0001,0203
不能这样:       HEX  000,102,03

        DFBDB        DeFine Byte - 定义字节

        操作数即是数据,以字节为主。用逗号隔开,支持进制符号。除非使用>符号(获取高字节),否则始终取表达式的低字节。

        DADW        Define Address or Define Word - 定义地址/定义字

        操作数即是数据,以两个字节(一个字)为主。用逗号隔开,支持进制符号。默认低字节。

        ADR           Define ADdRess - 3 bytes - 定义三字节地址

        操作数即是数据,以三个字节为主。用逗号隔开,支持进制符号。默认低字节。

        ADRL           Define Long ADdRess - 4 bytes - 定义双字地址

        操作数即是数据,以四个字节(双字)为主。用逗号隔开,支持进制符号。默认低字节。

        DS           Define Storage - 定义存储区

        为数据提供字节保留空间(设为$00),可提供两个操作数。第一个操作数表示要填充空间的数量,反斜杠"\"表示填充至下一个页(255字节)的边界。第二个操作数是要填充的值(省略第二个操作数默认为$00)

        ASC           define ASCii text - 定义ASCII码数据

        此伪指令用于定义ASCII码字符或字符串数据

        DCI           Dextral Character Inverter - 数字字符转换

        这将在目标代码中放置一个分隔的ASCII字符串,最后一个字符的高位与其他字符相反

        INV           define INVerse text - 定义反转文本

        反色仅适用于大写与个别符号,文本会以反色的形式向目标代码发送字符串数据

        FLS           define FLaShing text - 定义闪烁文本

        闪烁仅适用于大写与个别符号,文本会以闪烁的形式向目标代码发送字符串数据

        REV           define REVerse text - 定义反向文本

        此伪指令会以相反的顺序向目标代码发送字符串数据

        STR           define STRing with leading length byte - 带长度前导字节定义字符串

        此伪指令在字符串数据的首部给出字符串所用字节数,即字符串的长度。

        STRL           define Long STRing with leading length word - 带长度前导字定义字符串

        此伪指令在字符串数据的首部给出字符串所用字(WORD)数,即字符串的长度。

2、程序控制类

        LUP          Loop - 循环

        仅一个操作数,用于规定循环次数,例如:

           LUP   10
           ASL

        则表示循环ASL十次。如果想要标签的程序循环,则在标签后打上“@”号,例如:

           LUP    3
LOOP@      INC    $004C
           BNE    LOOP@

        LOOP则会循环执行3次。

        DO...ELSE...FIN / IF...ELSE...FIN        Condition - 条件

        有时候程序会在不同型号的机器上运行,我们的程序要根据机子的配置、型号等因素做出合理的安排与处理,根据不同情况构建不同的代码(6502/65c02处理器、8bit/16bit环境、ROM/RAM上下文、宏内部代码……)在Merlin 32中使用条件伪操作码有两种方法:DO...ELSE...FIN与IF...ELSE...FIN。​​​​​​​

        ORG        ORiGin - 起始地址

3、宏类

        MAC         Macro -

        EOM"<<<"        End of Macro - 结束宏

        USE        USE - 使用宏定义

4、文件类

        PUT

        PUTBIN

        DSK

        SAV

        LNK

        TYP

5、格式化类

        LST

        EXP

        PAU

        PAG

        AST

        SKP

        TR

6、其他类

        DUM

        DEND

        END

        CHK

        DAT

​​​​​​​        ERR

四、Merlin的输出

  • 10
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值