在上一节中,我们利用ophis实现了简单的hello world程序。接下来我们将进一步了解ophis的更多出色功能,它们能大大降低开发难度。
本节参考了Labels and aliases、Headers, Libraries, and Macros
标签
汇编代码的标签必须要求唯一,因此随着程序长度的增加,起一个不冲突的标签将会愈发困难。Ophis提供了以下特性以解决该问题。
1. 临时标签
临时标签类似于C语言中函数中声明的临时变量,仅在一块语句中有效。
int func() {
int a; //a仅在花括号内可被访问
}
不同于C语言的花括号,在Ophis中使用.scope
与.scend
表示"块"的起始与终止。嵌套的"块"类似于子函数的逻辑,声明的变量仅在最内层块有效。为区别全局标签与临时标签,临时标签一律以下划线_
开头。
.word $0801
.org $0801 ; BASIC内存开始地址
; BASIC部分
.scope
.word _next, 10 ; 下一行与当前行号
.byte $9e,"2061",0 ; 调用机器代码语句: SYS 2061
_next: .word 0 ; 结束程序
.scend
.advance 2064 ; 补0直到内存0x0810(2064)位置
2. 匿名标签
匿名标签适用于"短距离"引用,在行开头使用*
可添加一个匿名标签,在行中使用+
访问下一个标签,使用-
访问上一个标签。++
、--
、+++
、---
以此类推。值得注意的是,匿名标签不是临时标签,不受scope
的限制。
ldx #0
* lda hello, x
beq +
jsr $ffd2
inx
bne -
* rts
别名
别名可用于标记特殊的内存地址,如函数入口点、常量、变量位置等。
.alias chrout $ffd2
jsr chrout ; 调用KERNAL的打印字符子程序
头文件和库
PRG
文件的开头总是一段相同的BASIC
代码,KERNAL
的子程序位置又恒定不变,产生了大量重复书写,而且记忆函数的地址也很难。Ophis为解决此问题,提供了丰富的头文件以供引用,位于./platform
。引用文件可使用三种方式。
.include “file.oph”
类似于C语言的#include
,将复制引号中文件的所有内容到语句位置。
.require “file.oph”
类似于C语言的
#ifdef XXX
#include "xxx.h"
#endif
它将检查file.oph
是否被引用。如没有,则增加引用。
.incbin “file.bin”
直接将二进制数据插入语句位置。可提供至多两个参数,指出读取开始位置与读取字节数。
宏定义
宏很像一个内联函数,以.macro xxx
与.macend
包裹,xxx
为宏名。还可以向宏传递参数,参数必须可解析为byte
或word
值。在宏中,可以_1
,_2
依次使用各参数。特别值得注意的是,在宏中不能定义全局/匿名标签,且宏内部自带scope
,无需额外书写。
.macro print
ldx #0
_loop: lda _1, x
beq _done
jsr chrout
inx
bne _loop
_done:
.macend
可使用如下两种方式引用宏
`print msg
.invoke print msg
附录
./platform/c64kernal.oph
; KERNAL routine aliases (C64)
.alias acptr $ffa5
.alias chkin $ffc6
.alias chkout $ffc9
.alias chrin $ffcf
.alias chrout $ffd2
.alias ciout $ffa8
.alias cint $ff81
.alias clall $ffe7
.alias close $ffc3
.alias clrchn $ffcc
.alias getin $ffe4
.alias iobase $fff3
.alias ioinit $ff84
.alias listen $ffb1
.alias load $ffd5
.alias membot $ff9c
.alias memtop $ff99
.alias open $ffc0
.alias plot $fff0
.alias ramtas $ff87
.alias rdtim $ffde
.alias readst $ffb7
.alias restor $ff8a
.alias save $ffd8
.alias scnkey $ff9f
.alias screen $ffed
.alias second $ff93
.alias setlfs $ffba
.alias setmsg $ff90
.alias setnam $ffbd
.alias settim $ffdb
.alias settmo $ffa2
.alias stop $ffe1
.alias talk $ffb4
.alias tksa $ff96
.alias udtim $ffea
.alias unlsn $ffae
.alias untlk $ffab
.alias vector $ff8d
; Character codes for the colors.
.alias color'0 144
.alias color'1 5
.alias color'2 28
.alias color'3 159
.alias color'4 156
.alias color'5 30
.alias color'6 31
.alias color'7 158
.alias color'8 129
.alias color'9 149
.alias color'10 150
.alias color'11 151
.alias color'12 152
.alias color'13 153
.alias color'14 154
.alias color'15 155
; ...and reverse video
.alias reverse'on 18
.alias reverse'off 146
; ...and character set
.alias upper'case 142
.alias lower'case 14
c64-1.oph
.word $0801
.org $0801
.scope
.word _next, 10 ; Next line and current line number
.byte $9e,"2061",0 ; SYS 2061
_next: .word 0 ; End of program
.scend
.require "../platform/c64kernal.oph"
可读性与重用率更高的代码示例
.include "c64-1.oph"
.outfile "hello.prg"
.macro print
ldx #0
_loop: lda _1, x
beq _done
jsr chrout
inx
bne _loop
_done:
.macend
.macro greet
`print hello1
`print _1
`print hello2
.macend
lda #147
jsr chrout ; 清屏
`greet target1
`greet target2
`greet target3
`greet target4
`greet target5
`greet target6
`greet target7
`greet target8
`greet target9
`greet target10
rts
hello1: .byte "HELLO, ",0
hello2: .byte "!", 13, 0
target1: .byte "PROGRAMMER", 0
target2: .byte "ROOM", 0
target3: .byte "BUILDING", 0
target4: .byte "NEIGHBORHOOD", 0
target5: .byte "CITY", 0
target6: .byte "NATION", 0
target7: .byte "WORLD", 0
target8: .byte "SOLAR SYSTEM", 0
target9: .byte "GALAXY", 0
target10: .byte "UNIVERSE", 0