In the previous section , we implemented a simple hello world program using ophis. Next, we will learn more about more outstanding features of ophis, which can greatly reduce the difficulty of development.
This section refers to Labels and aliases , Headers, Libraries, and Macros
label
The label of the assembly code must be unique, so as the length of the program increases, it will be more difficult to get a non-conflicting label. Ophis provides the following features to solve this problem.
1. Temporary Label
Temporary labels are similar to temporary variables declared in functions in C language, and are only valid in a block of statements.
int func() {
int a; //a仅在花括号内可被访问
}
Different from the curly braces of the C language, and is used in Ophis .scope
to .scend
indicate the start and end of a "block". Nested "blocks" are similar to the logic of sub-functions, and the declared variables are only valid in the innermost block. To distinguish global labels from temporary labels, temporary labels always _
start with an underscore .
.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. Anonymous tags
Anonymous tags are suitable for "short-distance" references. Use at the beginning of a line *
to add an anonymous tag, use in the line to +
access the next tag, and use to -
access the previous tag. ++
, --
, +++
, ---
And so on. It is worth noting that anonymous tags are not temporary tags and are not scope
restricted.
ldx #0
* lda hello, x
beq +
jsr $ffd2
inx
bne -
* rts
Alias
Aliases can be used to mark special memory addresses, such as function entry points, constants, and variable locations.
.alias chrout $ffd2
jsr chrout ; 调用KERNAL的打印字符子程序
Header files and libraries
PRG
The beginning of the file is always the same BASIC
code, and KERNAL
the position of the subroutine is constant, resulting in a lot of repetitive writing, and it is difficult to memorize the address of the function. To solve this problem, Ophis provides a wealth of header files for reference, located at ./platform
. There are three ways to cite files.
.include “file.oph”
Similar to the C language #include
, all the contents of the file in the quotation marks will be copied to the statement position.
.require “file.oph”
Similar to C language
#ifdef XXX
#include "xxx.h"
#endif
It will check file.oph
if it is referenced. If not, add a reference.
.incbin “file.bin”
Insert the binary data directly into the statement position. Up to two parameters can be provided to indicate the start position of reading and the number of bytes to be read.
Macro definition
Macro much like an inline function to .macro xxx
the .macend
package, xxx
as the macro name. You can also pass parameters to the macro, and the parameters must be parseable as an byte
or word
value. In the macro, you can _1
, _2
in turn use of the parameters. It is particularly worth noting that global/anonymous tags cannot be defined in the macro, and the macro comes with it scope
, so no additional writing is required.
.macro print
ldx #0
_loop: lda _1, x
beq _done
jsr chrout
inx
bne _loop
_done:
.macend
You can use the following two ways to quote macros
`print msg
.invoke print msg
appendix
./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"
Code examples that are more readable and reusable
.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