-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathvars.asm
177 lines (161 loc) · 4.85 KB
/
vars.asm
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
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
; vars.asm
; definitions and macros useful for creating variables pre-compiled,
; or variables residing in the gameboy ram
IF !DEF(VARS_ASM)
VARS_ASM SET 1
include "gbhw.inc"
include "dma.inc"
LowRamBase SET _RAM + $A0 ; available ram after OAM data
; (OAM data is the $A0 added to _RAM)
LowRamLimit SET LowRamBase + $1FF ; 512 bytes (variables) available
MidRamBase SET LowRamLimit
MidRamLimit SET MidRamBase + $0FFF ; 4096 bytes (var+space) available
HighRamBase SET DMA_END_LOC ; add 12... (size of dma code)
HighRamLimit SET HighRamBase + 20 ; limit of 20 variables
; OAM data is just a holding place where you can modify it. The OAM data
; will then get copied to OAM location in Video-Ram [$FE00 - $FEA0)
; LowRamByte is a macro you can call to assign a variable a byte-address in ram
; there's a LOT of available bytes: $C0A0 - $C29F (512)
; each time you call LowRamByte, it assigns your variable an address, then
; increments. You should have no fear of running out of space
; I've set an arbitrary limit so that I can define other sections of memory
; for other purposes
var_LowRamByte: MACRO
\1 EQU LowRamBase ; NOTICE I can't put a space before \1
LowRamBase Set LowRamBase + 1
IF (LowRamBase >= LowRamLimit)
PRINTT "\n\1 was last LowRamByte declared. "
FAIL "too many variables declared"
ENDC
ENDM
var_LowRamWord: MACRO
\1 EQU LowRamBase
LowRamBase Set LowRamBase + 2 ; \1 points to two bytes
IF (LowRamBase >= LowRamLimit)
PRINTT "\n\1 was last LowRamWord declared. "
FAIL "too many variables declared"
ENDC
ENDM
; call var_HighRamByte to allocate a variable in HIRAM. This is a critical 127
; bytes occupied by DMA-code and the stack. If we use to many variables, we
; run the risk of the stack overrunning into these.
var_HighRamByte: MACRO
\1 EQU HighRamBase
HighRamBase Set HighRamBase + 1
IF (HighRamBase >= HighRamLimit)
PRINTT "\n\1 was last HighRamByte declared. "
FAIL "too many HIRAM variables declared"
ENDC
ENDM
; call var_MidRamBytes to allocate memory space for a variable.
; argument 1 is the variable name
; argument 2 is the size of the variable
var_MidRamBytes: MACRO
\1 EQU MidRamBase
IF _NARG == 1
FAIL "var_MidRamBytes requires a size argument"
ENDC
MidRamBase Set MidRamBase + \2
IF (MidRamBase >= MidRamLimit)
PRINTT "\n$"
PRINTV MidRamBase
FAIL "\nMidRam space depleted"
ENDC
ENDM
; use this macro to load a word from ram. It loads the word into the specified
; register without trashing any other registers (it will push / pop to do so)
; (an optional 4th argument "trash AF" will prevent the push / pop)
; var_GetLowRamWord register_pair, variable_name
; e.g. var_GetLowRamWord b,c, player_coordinates
; following Z80 stack-pointer convention, the LSB is stored @address,
; and the MSB is stored @address + 1.
; this means that the example above is psuedo-code for
; ld c, [player_coordinates]
; ld b, [player_coordinates + 1]
; register A or F is not allowed because we make use of A
; FAST: 17/14 17 cycles, 14 bytes
var_GetWord: MACRO
IF STRIN("BCDEHL", STRUPR("\1")) == 0
FAIL "require a register (but not A). Got \1"
ENDC
IF STRIN("BCDEHL", STRUPR("\2")) == 0
FAIL "require a register (but not A). Got \2"
ENDC
preserve_AF SET 1
IF _NARG == 4
IF STRCMP(STRUPR("\4"), "TRASH AF") == 0
preserve_AF SET 0
ENDC
ENDC
IF preserve_AF == 1
push af ; save AF (we have to use A)
ENDC
lda [\3]
ld \2, a ; load LSB from address
lda [\3 + 1]
ld \1, a ; load MSB from address+1
IF preserve_AF == 1
pop af
ENDC
ENDM
; same deal as var_GetLowRamWord. Stores register pair in memory
; at specified address in ram. Sets LSB @address, MSB @address+1
; doesn't trash registers unless "Trash AF" passed as 4th argument.
; register A or F is not allowed because we make use of A
; FAST: 17/14 17 cycles, 14 bytes
var_SetWord: MACRO
IF STRIN("BCDEHL", STRUPR("\1")) == 0
FAIL "require a register (but not A). Got \1"
ENDC
IF STRIN("BCDEHL", STRUPR("\2")) == 0
FAIL "require a register (but not A). Got \2"
ENDC
preserve_AF SET 1
IF _NARG == 4
IF STRCMP(STRUPR("\4"), "TRASH AF") == 0
preserve_AF SET 0
ENDC
ENDC
IF preserve_AF == 1
push af ; save AF (we have to use A)
ENDC
lda \2
ld [\3], a ; store LSB at address
lda \1
ld [\3 + 1], a ; store MSB at address+1
IF preserve_AF == 1
pop af
ENDC
ENDM
; increment a word. Doesn't trash registers
; COST: 32/12
; COST: 26/18
var_WordIncrement: MACRO
push af
ld a, [\1]
inc a
ld [\1], a
; we only need to inc MSB if LSB overflowed to zero
jr nz, .done\@
ld a, [\1 + 1]
inc a
ld [\1 + 1], a
.done\@
pop af
ENDM
; COST: 29/19
var_WordDecrement: MACRO
push af
ld a, [\1]
dec a
ld [\1], a
inc a
; we only need to dec MSB if LSB was 0 before decrementing
jr nz, .done\@
ld a, [\1 + 1]
dec a
ld [\1 + 1], a
.done\@
pop af
ENDM
ENDC ; end vars.asm definitions