Add customasm definition file
[ROSE-8] / rose8.asm
1 ;; A ROSE-8 definition for customasm
2 ;;
3 ;; Differences from the original ROSE-8 assembler:
4 ;; - Label, comment, and literal syntax uses customasm rules, of course
5 ;; - Offset-based branches that take labels (`BEZI`, `JOFI`, `COFI`) will not work correctly if given bare integers (they will be treated as addresses rather than offsets)
6 ;; - There are no pseudo-instructions; use expressions instead (see Utility Functions, below)
7 ;; - There is no `.fragment`; use an explicit `#addr` or `#align NEXT_SEGMENT` to start a new segment, and just rely on concatenation otherwise.
8 ;; - `.nosplit` is implemented by `!nosplit <label>`; alternately you can `!assert_eq <value>, seg($)`
9 ;; - customasm does not have an equivalent to `.fill <count> <value>`. Sorry. Use `#res` for `.fill` with zeros, and `#d` for everything else.
10
11 #once
12
13 ;;
14 ;; SETUP
15 ;;
16
17 ;; A ROSE-8 binary is always the full size of memory as a single bank.
18 ;;
19 ;; See the ISA guide for the initial register state.
20 #bankdef full
21 {
22     #outp 0
23     #size 0x1_0000
24     #fill
25 }
26 #bank full
27
28 ;; An alias for use with the `#align` directive.
29 #const(noemit) NEXT_SEGMENT = 0x800
30
31
32 ;;
33 ;; UTILITY FUNCTIONS
34 ;;
35
36 ;; Returns the segment of `label`, as an 8-bit value
37 #fn seg(label) => (label / 256)`8
38
39 ;; Returns the address of `label` within its segment, as an 8-bit value
40 #fn addr(label) => (label % 256)`8
41
42 ;; Produces the segment of `label` followed by its address
43 ;;
44 ;; Intended to be used with `#d` for more clarity than a bare label.
45 #fn segAddr(label) => (label)`16 ; big-endian
46
47 ;; Produces the offset of `label` from the current address, as an 8-bit signed value
48 ;;
49 ;; Fails if `label` is out of range, though it does not need to be in the same segment.
50 #fn offset(label) => {
51     result = label - $
52     assert(result <=  0x7f, "offset is too far")
53     assert(result >= -0x80, "offset is too far")
54     result`8
55 }
56
57 ;; Slightly prettier way of writing a C string for the #d directive.
58 #fn c(str) => { str @ "\0" }
59
60 #ruledef directives
61 {
62     ;; Exposes `assert` functionality outside of rules.
63     ;;
64     ;; Can be used to verify that a function is in a particular segment.
65     !assert_eq {x}, {y} => {
66         assert(x == y)
67         0`0
68     }
69
70     ;; Asserts that `l` is in the same segment as the current address.
71     ;;
72     ;; Useful for checking that a `CABL` return will restore the code segment register to its previous state.
73     !nosplit {label: u16} => {
74         assert(seg(label) == seg($), "fragment has been split")
75         0`0
76     }
77 }
78
79
80 ;;
81 ;; INSTRUCTIONS
82 ;;
83
84 #ruledef simple_ops
85 {
86     STOP => 0b0000_0000
87     NOPE => 0b0000_0001
88     PRNT => 0b0000_0010
89     WAIT => 0b0000_0011
90
91     CABL => 0b0000_0100
92     ; unallocated
93     CABA => 0b0000_0110
94     COFA => 0b0000_0111
95
96     ZERO => 0b0000_1000
97     LSL1 => 0b0000_1001
98     LSR1 => 0b0000_1010
99     ASR1 => 0b0000_1011
100     INCR => 0b0000_1100
101     DECR => 0b0000_1101
102     COMP => 0b0000_1110
103     NEGT => 0b0000_1111
104
105     GET1 => 0b0001_0000
106     GET2 => 0b0001_0001
107     GETC => 0b0001_0010
108     GETL => 0b0001_0011
109
110     SET1 => 0b0001_1000
111     SET2 => 0b0001_1001
112     SETC => 0b0001_1010
113     SETL => 0b0001_1011
114 }
115
116 #subruledef register
117 {
118     r{value: u3} => value
119 }
120
121 #ruledef register_ops
122 {
123     GETR {r: register} => 0b001_00 @ r
124     SETR {r: register} => 0b001_01 @ r
125     SWAP {r: register} => 0b001_10 @ r
126     ISLT {r: register} => 0b001_11 @ r
127
128     ADDR {r: register} => 0b01_000 @ r
129     SUBR {r: register} => 0b01_001 @ r
130     ANDR {r: register} => 0b01_010 @ r
131     IORR {r: register} => 0b01_011 @ r
132     XORR {r: register} => 0b01_100 @ r
133     LSLR {r: register} => 0b01_101 @ r
134     LSRR {r: register} => 0b01_110 @ r
135     ASRR {r: register} => 0b01_111 @ r
136
137     LD1R {r: register} => 0b100_00 @ r
138     ST1R {r: register} => 0b100_01 @ r
139     LD1U {r: register} => 0b100_10 @ r
140     ST1U {r: register} => 0b100_11 @ r
141
142     LD2R {r: register} => 0b101_00 @ r
143     ST2R {r: register} => 0b101_01 @ r
144     LD2U {r: register} => 0b101_10 @ r
145     ST2U {r: register} => 0b101_11 @ r
146
147     LD2D {r: register} => 0b111_00 @ r
148     ST2D {r: register} => 0b111_01 @ r
149 }
150
151 #ruledef immediate_ops
152 {
153     ANDI {i: u8} => 0b1111_0000 @ i
154     IORI {i: u8} => 0b1111_0001 @ i
155     XORI {i: u8} => 0b1111_0010 @ i
156
157     ADDI {i: s8} => {
158         assert(i >= -64, "too negative")
159         0b1111_0011 @ i
160     }
161
162     ROLI {i: u3} => 0b1111_0011 @ 0b10_000 @ i
163     LSLI {i: u3} => 0b1111_0011 @ 0b10_001 @ i
164     LSRI {i: u3} => 0b1111_0011 @ 0b10_010 @ i
165     ASRI {i: u3} => 0b1111_0011 @ 0b10_011 @ i
166     EXTI {i: u3} => 0b1111_0011 @ 0b10_111 @ i
167
168     BEZI {l: u16} => 0b1111_0100 @ offset(l)
169     JOFI {l: u16} => 0b1111_0101 @ offset(l)
170     CABI {l: u16} => 0b1111_0110 @ addr(l)
171     COFI {l: u16} => 0b1111_0111 @ offset(l)
172
173     GETI {i: i8} => 0b1111_1110 @ i
174 }