利用 Ophis 编写 Commodore 64 programs PRG 程序(二)

上一节中,我们利用ophis实现了简单的hello world程序。接下来我们将进一步了解ophis的更多出色功能,它们能大大降低开发难度。
本节参考了Labels and aliasesHeaders, 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为宏名。还可以向宏传递参数,参数必须可解析为byteword值。在宏中,可以_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

效果演示

c64

前往下一节

猜你喜欢

转载自blog.csdn.net/u011570312/article/details/114973458