1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
|
; Many thanks to:
; https://michaelcmartin.github.io/Ophis/
; https://www.nesdev.org/obelisk-6502-guide/addressing.html
; https://www.masswerk.at/6502/6502_instruction_set.html
; The 6502 is little endian! (4 3 2 1)
; lables
; [a-z]: Normal label
; _[a-z]: Temporary label (only available in scope)
; * Anonymous label, use "+" for next anonymous, "++" for next after next anonymous
; and "-" for prev anonymous, "--" for prev before prev anonymous and so on.
; constants
; [0-9]+ decimal
; $[0-9]+ hex
; 0[0-9]+ octal
; %[01]+ binary
; '[ -~] ASCII character
; ".*" string, backslash escapes are available, produces a series of words/dwords
; addresses
; number := placing a constant signifies address of memory where value is stored
; #number := is immediate value, not an address to a value in memory, but the value itself
;
; implicit - number is interpreted, depending on the function (instruction) itself
; zero page - address is only 8 bits ($00 to $FF), limits only to first page in memory ($0000 to $00FF)
; zero page,x - same as zero page, but address is "value + x register" (where result wraps around, into the zero page)
; zero page,y - same as zero page, but address is "value + y register" (where result wraps around, into the zero page)
; absolute - 16 bit address ($0000 to $FFFF)
; absolute,x - 16 bit address + x register ($0000 to $FFFF; value wraps around)
; absolute,y - 16 bit address + y register ($0000 to $FFFF; value wraps around)
; (indirect) - the desired address can be found at the given address (i.e. the address to the value is stored in memory; only used in jump instruction?)
; operators (unary)
; < := low byte of a word
; > := high byte of a word
; [ ] := brackets for grouping expressions
; operators (binary)
; * / + - := arithmetic operators
; | & ^ := bitwise operators
; commands
; .byte := byte of data (placed directly)
; .org := from which addr onwards bytes are placed (origin; value of program counter)
; .word := word of data, 2 bytes, values as big endian (1 2 3 4)
; .dword := double word of data, 4 bytes, value as ?
;
; .advance := fill everything with 0, until the given address
;
; .scope := open scope
; .scend := end scope
; .alias := takes a name and an address, sets name to the address
;
; .include := inserts file at the given line
; .incbin := include binary data
; .require := include file if it hasn't been already
;
; .text := place bytes in the text "space" of the output (default)
; .data := place bytes in the data "space" of the output
; you use .org (right afterwards) to specify start of area
; .space := for variable name, "reserve" given bytes of data; used for label and address calculations
; .checkpc := assert program counter isn't at given address
; macros
; Instead of being "textual replacement", the arguments are evaulated before passed to macro.
; ONLY temporary labels, macros define their own scope on substitution.
; Arguments accessible via _1, _2, _3, ...; must be bytes or words
; .macro := starts a macro definition with the given name
; .macend := ends the macro definition
; .invoke := calls a macro by the given name and arguments
; synonymous with `macro_name
.outfile "hello.prg"
.require "basic_starter.oph.s"
.require "kernal.oph.s"
main: `print hello
rts
hello: .byte "HELLO, WORLD!", 0
|