~amaurycarvalho/msxbas2asm/trunk

« back to all changes in this revision

Viewing changes to test/testgfx.asm

  • Committer: Amaury Carvalho
  • Date: 2020-06-12 13:08:59 UTC
  • Revision ID: amauryspires@gmail.com-20200612130859-3qm5vl1jiqr2brok
Commit on 12/06/2020 10:08:59  -03 by amaury

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
;---------------------------------------------------------------------------------------------------------
2
 
; Source code converted by MSXBAS2ASM - MSX BASIC TO Z80 ASSEMBLY CONVERTER
3
 
; MSXBAS2ASM developed by Amaury Carvalho, 2019, Brazil
4
 
; http://launchpad.net/msxbas2asm
5
 
;---------------------------------------------------------------------------------------------------------
6
 
 
7
 
;--------------------------------------------------------
8
 
; MSX BIOS DATA/FUNCTION POINTERS
9
 
;--------------------------------------------------------
10
 
 
11
 
;---------------------------------------------------------------------------------------------------------
12
 
; BIOS FUNCTIONS
13
 
;---------------------------------------------------------------------------------------------------------
14
 
 
15
 
BIOS_CALBAS:    equ 0x0159
16
 
BIOS_OUTDO:     equ 0x0018   ; output to current device (i.e. screen)
17
 
BIOS_CHPUT:     equ 0x00A2
18
 
BIOS_CLS:       equ 0x00C3
19
 
BIOS_POSIT:     equ 0x00C6
20
 
BIOS_BEEP:      equ 0x00C0
21
 
BIOS_CHGET:     equ 0x009F
22
 
BIOS_CHSNS:     equ 0x009C
23
 
BIOS_INLIN:     equ 0x00B1
24
 
BIOS_PINLIN:    equ 0x00AE
25
 
BIOS_QINLIN:    equ 0x00B4
26
 
BIOS_GTSTCK:    equ 0x00D5
27
 
BIOS_GTTRIG:    equ 0x00D8
28
 
BIOS_GTPAD:     equ 0x00DB
29
 
BIOS_GTPDL:     equ 0x00DE
30
 
BIOS_DISSCR:    equ 0x0041
31
 
BIOS_ENASCR:    equ 0x0044
32
 
BIOS_CHGMOD:    equ 0x005F
33
 
BIOS_CHGCLR:    equ 0x0062
34
 
BIOS_CLRSPR:    equ 0x0069
35
 
BIOS_INITXT:    equ 0x006C    ; init text mode 40 columns
36
 
BIOS_INIT32:    equ 0x006F    ; init text mode 32 columns
37
 
BIOS_INIGRP:    equ 0x0072
38
 
BIOS_INIMLT:    equ 0x0075
39
 
BIOS_SETTXT:    equ 0x0078    ; set text mode 40 columns
40
 
BIOS_SETT32:    equ 0x007B    ; set text mode 32 columns
41
 
BIOS_SETGRP:    equ 0x007E
42
 
BIOS_SETMLT:    equ 0x0081
43
 
BIOS_CALPAT:    equ 0x0084
44
 
BIOS_CALATR:    equ 0x0087
45
 
BIOS_GSPSIZ:    equ 0x008A
46
 
BIOS_GRPPRT:    equ 0x008D
47
 
BIOS_ERAFNK:    equ 0x00CC
48
 
BIOS_DSPFNK:    equ 0x00CF
49
 
BIOS_TOTEXT:    equ 0x00D2
50
 
BIOS_BREAKX:    equ 0x00B7
51
 
BIOS_ISCNTC:    equ 0x03FB
52
 
BIOS_CHKRAM:    equ 0x0000
53
 
BIOS_GICINI:    equ 0x0090
54
 
BIOS_WRTPSG:    equ 0x0093
55
 
BIOS_REDPSG:    equ 0x0096
56
 
BIOS_STRTMS:    equ 0x0099
57
 
BIOS_KEYINT:    equ 0x0038
58
 
BIOS_CALSLT:    equ 0x001C
59
 
BIOS_ENASLT:    equ 0x0024
60
 
BIOS_RSLREG:    equ 0x0138
61
 
BIOS_SCALXY:    equ 0x010E
62
 
BIOS_MAPXYC:    equ 0x0111      ; in BC = X, DE = Y
63
 
BIOS_READC:     equ 0x011D      ; out A = color of current pixel
64
 
BIOS_SETATR:    equ 0x011A      ; in A = color code
65
 
BIOS_SETC:      equ 0x0120      ; set current pixel to color from SETATR
66
 
BIOS_NSETCX:    equ 0x0123      ; in HL = pixel fill count
67
 
BIOS_SCANR:     equ 0x012C      ; in B=Fill switch, DE=Skip count, out DE=Skip remainder, HL=Pixel count
68
 
BIOS_SCANL:     equ 0x012F      ; out HL=Pixel count
69
 
BIOS_FETCHC:    equ 0x0114      ; out A = cursor mask, HL = VRAM address of cursor
70
 
BIOS_STOREC:    equ 0x0117      ; in A = cursor mask, HL = VRAM address of cursor
71
 
BIOS_RESET:     equ 0x7D17      ; restart BASIC
72
 
BIOS_IOALLOC:   equ 0X7e6b      ; memory setup
73
 
 
74
 
BIOS_GETVCP:    equ 0x0150      ; get PSG voice buffer address (in A = voice number, out HL = address of byte 2)
75
 
BIOS_GETVC2:    equ 0x0153      ; get PSG voice buffer address (VOICEN = voice number, in L = byte number 0-36, out HL = address)
76
 
 
77
 
BIOS_CHPUT_LF:  equ 0x0908
78
 
BIOS_CHPUT_CR:  equ 0x0A81
79
 
BIOS_CHPUT_TAB: equ 0x0A71
80
 
 
81
 
; MSX2
82
 
BIOS_CHKNEW:    equ 0x0165      ; C-flag set if screenmode = 5, 6, 7 or 8
83
 
BIOS_EXTROM:    equ     0x015F
84
 
BIOS_SCALXY2:   equ 0x008D      ; in BC = X, DE = Y
85
 
BIOS_MAPXYC2:   equ 0x0091      ; in BC = X, DE = Y
86
 
BIOS_SETC2:     equ 0x009D      ; set current pixel to color from SETATR
87
 
BIOS_READC2:    equ 0x0095      ; out A = color of current pixel
88
 
BIOS_CHGMOD2:   equ 0x00D1      ; in A = screenmode
89
 
BIOS_DOBOXF:    equ 0x0079      ; hl = basic text pointer
90
 
BIOS_GRPPRT2:   equ 0x0089      ; a = character
91
 
BIOS_CHGCLR2:   equ 0x0111      ; change color, a = screen mode
92
 
BIOS_CALPAT2:   equ 0x00F9
93
 
BIOS_CALATR2:   equ 0x00FD
94
 
BIOS_GSPSIZ2:   equ 0x0101
95
 
BIOS_CLRSPR2:   equ 0x00F5
96
 
 
97
 
;---------------------------------------------------------------------------------------------------------
98
 
; BIOS WORK AREAS
99
 
;---------------------------------------------------------------------------------------------------------
100
 
 
101
 
BIOS_VERSION:   equ 0x002D   ; 0 = MSX1, 1 = MSX2, 2 = MSX2+, 3 = MSXturboR
102
 
BIOS_FORCLR:    equ 0xF3E9
103
 
BIOS_BAKCLR:    equ 0xF3EA
104
 
BIOS_BDRCLR:    equ 0xF3EB
105
 
BIOS_ATRBYT:    equ 0xF3F2
106
 
BIOS_INTFLG:    equ 0xFC9B
107
 
BIOS_EXPTBL:    equ 0xFCC1
108
 
BIOS_JIFFY:     equ 0xFC9E
109
 
BIOS_BOTTOM:    equ 0xFC48
110
 
BIOS_HIMEM:     equ 0xFC4A
111
 
BIOS_SCRMOD:    equ 0xFCAF   ; 0=40x24 Text Mode, 1=32x24 Text Mode, 2=Graphics Mode, 3=Multicolour Mode.
112
 
BIOS_CLIKSW:    equ 0xF3DB   ; 0=keyboard click off, 1=keyboard click on
113
 
BIOS_GRPACX:    equ 0xFCB7
114
 
BIOS_GRPACY:    equ 0xFCB9
115
 
BIOS_DATLIN:    equ 0xF6A3   ; 2 - line number of DATA statement read by READ statement
116
 
BIOS_DATPTR:    equ 0xF6C8   ; 2 - address of data read by executing READ statement
117
 
BIOS_FLGINP:    equ 0xF6A6   ; 1 - flag used in INPUT or READ
118
 
BIOS_TEMP:      equ 0xF6A7   ; 2
119
 
BIOS_TEMP2:     equ 0xF6BC   ; 2
120
 
BIOS_TEMP3:     equ 0xF69D   ; 2
121
 
BIOS_TEMP8:     equ 0xF69F   ; 2
122
 
BIOS_TEMP9:     equ 0xF7B8   ; 2
123
 
BIOS_OLDSCR:    equ 0xFCB0   ; screen mode of the last text mode set
124
 
BIOS_LINL40:    equ 0xF3AE   ; width for 40 columns screen mode
125
 
BIOS_LINL32:    equ 0xF3AF   ; width for 32 columns screen mode
126
 
BIOS_LINLEN:    equ 0xF3B0   ; current width for text screen mode
127
 
BIOS_CLMLST:    equ 0xF3B2   ; minimum number of columns that must still be available on a line for a CRLF
128
 
BIOS_TXTNAM:    equ 0xF3B3   ; characters table name
129
 
 
130
 
BIOS_VOICEN:    equ 0xFB38   ; PSG voice number
131
 
BIOS_MCLTAB:    equ 0xF956
132
 
BIOS_PRSCNT:    equ 0xFB35
133
 
BIOS_SAVSP:     equ 0xFB36
134
 
BIOS_QUEUEN:    equ 0xFB3E
135
 
BIOS_MUSICF:    equ 0xFB3F   ;contains 3 bit flags set by the STRTMS. Bits 0, 1 and 2 correspond to VOICAQ, VOICBQ and VOICCQ.
136
 
BIOS_PLYCNT:    equ 0xFB40
137
 
 
138
 
BIOS_DRWFLG:    equ 0xFCBB
139
 
BIOS_MCLFLG:    equ 0xF958
140
 
 
141
 
BIOS_SLTROM:    equ 0xFCC1
142
 
BIOS_RAMAD0:    equ     0xF341  ; Main-RAM Slot (00000h~03FFFh)
143
 
BIOS_RAMAD1:    equ     0xF342  ; Main-RAM Slot (04000h~07FFFh)
144
 
BIOS_RAMAD2:    equ     0xF343  ; Main-RAM Slot (08000h~0BFFFh)
145
 
BIOS_RAMAD3:    equ     0xF344  ; Main-RAM Slot (0C000h~0FFFFh)
146
 
 
147
 
 
148
 
 
149
 
;--------------------------------------------------------
150
 
; MSX BASIC DATA/FUNCTION POINTERS
151
 
;--------------------------------------------------------
152
 
 
153
 
;---------------------------------------------------------------------------------------------------------
154
 
; MSX BASIC FUNCTIONS
155
 
;---------------------------------------------------------------------------------------------------------
156
 
 
157
 
BASIC_AUTO:   equ 0x3973
158
 
BASIC_AND:    equ 0x3A18
159
 
BASIC_ATTR:   equ 0x39FE
160
 
BASIC_BASE:   equ 0x39BE
161
 
BASIC_BSAVE:  equ 0x39CC
162
 
BASIC_BLOAD:  equ 0x39CA
163
 
BASIC_BEEP:   equ 0x39AC
164
 
BASIC_CALL:   equ 0x39C0
165
 
BASIC_CLOSE:  equ 0x3994
166
 
BASIC_COPY:   equ 0x39D8
167
 
BASIC_CONT:   equ 0x395E
168
 
BASIC_CLEAR:  equ 0x3950
169
 
BASIC_CLOAD:  equ 0x3962
170
 
BASIC_CSAVE:  equ 0x3960
171
 
BASIC_CSRLIN: equ 0x39FC
172
 
BASIC_CIRCLE: equ 0x39A4
173
 
BASIC_COLOR:  equ 0x39A6
174
 
BASIC_CLS:    equ 0x396A
175
 
BASIC_CMD:    equ 0x39DA
176
 
BASIC_DELETE: equ 0x397C
177
 
BASIC_DATA:   equ 0x3934
178
 
BASIC_DIM:    equ 0x3938
179
 
BASIC_DEFSTR: equ 0x3982
180
 
BASIC_DEFINT: equ 0x3984
181
 
BASIC_DEFSNG: equ 0x3986
182
 
BASIC_DEFDBL: equ 0x3988
183
 
BASIC_DSKO:   equ 0x39CE
184
 
BASIC_DEF:    equ 0x395A
185
 
BASIC_DSKI:   equ 0x3A00
186
 
BASIC_DRAW:   equ 0x39A8
187
 
BASIC_ELSE:   equ 0x396E
188
 
BASIC_END:    equ 0x392E
189
 
BASIC_ERASE:  equ 0x3976
190
 
BASIC_ERROR:  equ 0x3978
191
 
BASIC_ERL:    equ 0x39EE
192
 
BASIC_ERR:    equ 0x39F0
193
 
BASIC_EQU:    equ 0x3A1E
194
 
BASIC_FOR:    equ 0x3920
195
 
BASIC_FIELD:  equ 0x398E
196
 
BASIC_FILES:  equ 0x39AA
197
 
BASIC_FN:     equ 0x39E8
198
 
BASIC_GOTO:   equ 0x393E
199
 
BASIC_GOSUB:  equ 0x3948
200
 
BASIC_GET:    equ 0x3990
201
 
BASIC_INPUT:  equ 0x3936
202
 
BASIC_IF:     equ 0x3942
203
 
BASIC_INSTR:  equ 0x39F6
204
 
BASIC_IMP:    equ 0x3A20
205
 
BASIC_INKEY:  equ 0x3A04
206
 
BASIC_IPL:    equ 0x39D6
207
 
BASIC_KILL:   equ 0x39D4
208
 
BASIC_KEY:    equ 0x3964
209
 
BASIC_LPRINT: equ 0x394C
210
 
BASIC_LLIST:  equ 0x3968
211
 
BASIC_LET:    equ 0x393C
212
 
BASIC_LOCATE: equ 0x39DC
213
 
BASIC_LINE:   equ 0x398A
214
 
BASIC_LOAD:   equ 0x3996
215
 
BASIC_LSET:   equ 0x399C
216
 
BASIC_LIST:   equ 0x3952
217
 
BASIC_LFILES: equ 0x39A2
218
 
BASIC_MOTOR:  equ 0x39C8
219
 
BASIC_MERGE:  equ 0x3998
220
 
BASIC_MOD:    equ 0x3A22
221
 
BASIC_MAX:    equ 0x39C6
222
 
BASIC_NEXT:   equ 0x3932
223
 
BASIC_NAME:   equ 0x39D2
224
 
BASIC_NEW:    equ 0x3954
225
 
BASIC_NOT:    equ 0x39EC
226
 
BASIC_OPEN:   equ 0x398C
227
 
BASIC_OUT:    equ 0x3964
228
 
BASIC_ON:     equ 0x3956
229
 
BASIC_OR:     equ 0x3A1A
230
 
BASIC_OFF:    equ 0x3A02
231
 
BASIC_PRINT:  equ 0x394E
232
 
BASIC_PUT:    equ 0x3992
233
 
BASIC_POKE:   equ 0x395C
234
 
BASIC_PSET:   equ 0x39B0
235
 
BASIC_PRESET: equ 0x39B2
236
 
BASIC_POINT:  equ 0x3A06
237
 
BASIC_PAINT:  equ 0x39AA
238
 
BASIC_PLAY:   equ 0x39AE
239
 
BASIC_RETURN: equ 0x3948
240
 
BASIC_READ:   equ 0x393A
241
 
BASIC_RUN:    equ 0x3940
242
 
BASIC_RESTORE:equ 0x3944
243
 
BASIC_REM:    equ 0x394A
244
 
BASIC_RESUME: equ 0x397A
245
 
BASIC_RSET:   equ 0x399E
246
 
BASIC_RENUM:  equ 0x3980
247
 
BASIC_SCREEN: equ 0x39B6
248
 
BASIC_SPRITE: equ 0x39BA
249
 
BASIC_STOP:   equ 0x394C
250
 
BASIC_SWAP:   equ 0x3974
251
 
BASIC_SET:    equ 0x39D0
252
 
BASIC_SAVE:   equ 0x39A0
253
 
BASIC_SPC:    equ 0x39EA
254
 
BASIC_STEP:   equ 0x39E4
255
 
BASIC_STRING: equ 0x39F2
256
 
BASIC_SPACE1: equ 0x397E
257
 
BASIC_SOUND:  equ 0x39B4
258
 
BASIC_THEN:   equ 0x39E0
259
 
BASIC_TRON:   equ 0x3970
260
 
BASIC_TROFF:  equ 0x3972
261
 
BASIC_TAB:    equ 0x39E2
262
 
BASIC_TO:     equ 0x39DE
263
 
BASIC_TIME:   equ 0x39C2
264
 
BASIC_USING:  equ 0x39F4
265
 
BASIC_USR:    equ 0x39E6
266
 
BASIC_VARPTR: equ 0x39FA
267
 
BASIC_VDP:    equ 0x39BC
268
 
BASIC_VPOKE:  equ 0x39B8
269
 
BASIC_WIDTH:  equ 0x396C
270
 
BASIC_WAIT:   equ 0x3958
271
 
BASIC_XOR:    equ 0x3A1C
272
 
BASIC_ABS:    equ 0x39E8
273
 
BASIC_ATN:    equ 0x39F8
274
 
BASIC_ASC:    equ 0x3A06
275
 
BASIC_BIN:    equ 0x3A16
276
 
BASIC_CINT:   equ 0x3A18
277
 
BASIC_CSNG:   equ 0x3A1A
278
 
BASIC_CDBL:   equ 0x3A1C
279
 
BASIC_CVI:    equ 0x3A2C
280
 
BASIC_CVS:    equ 0x3A2E
281
 
BASIC_CVD:    equ 0x3A30
282
 
BASIC_COS:    equ 0x39F4
283
 
BASIC_CHR:    equ 0x3A08
284
 
BASIC_DSKF:   equ 0x3A28
285
 
BASIC_EXP:    equ 0x39F2
286
 
BASIC_EOF:    equ 0x3A32
287
 
BASIC_FRE:    equ 0x39FA
288
 
BASIC_FIX:    equ 0x3A1E
289
 
BASIC_FPOS:   equ 0x3A2A
290
 
BASIC_HEX:    equ 0x3A12
291
 
BASIC_INT:    equ 0x39E6
292
 
BASIC_INP:    equ 0x39FC
293
 
BASIC_LPOS:   equ 0x3A14
294
 
BASIC_LOG:    equ 0x39F0
295
 
BASIC_LOC:    equ 0x3A34
296
 
BASIC_LEN:    equ 0x3A00
297
 
BASIC_LEFT:   equ 0x39DE
298
 
BASIC_LOF:    equ 0x3A36
299
 
BASIC_MKI:    equ 0x3A38
300
 
BASIC_MKS:    equ 0x3A3A
301
 
BASIC_MKD:    equ 0x3A3C
302
 
BASIC_MID:    equ 0x39E2
303
 
BASIC_OCT:    equ 0x3A10
304
 
BASIC_POS:    equ 0x39FE
305
 
BASIC_PEEK:   equ 0x3A0A
306
 
BASIC_PDL:    equ 0x3A24
307
 
BASIC_PAD:    equ 0x3A26
308
 
BASIC_RIGHT:  equ 0x39E0
309
 
BASIC_RND:    equ 0x39EC
310
 
BASIC_SGN:    equ 0x39E4
311
 
BASIC_SQR:    equ 0x39EA
312
 
BASIC_SIN:    equ 0x39EE
313
 
BASIC_STR:    equ 0x3A02
314
 
BASIC_SPACE2: equ 0x3A0E
315
 
BASIC_STICK:  equ 0x3A20
316
 
BASIC_STRIG:  equ 0x3A22
317
 
BASIC_TAN:    equ 0x39F6
318
 
BASIC_VAL:    equ 0x3A04
319
 
BASIC_VPEEK:  equ 0x3A0C
320
 
 
321
 
BASIC_TRAP_ENABLE:  equ 0x631B    ; ON INTERVAL/KEY/SPRITE/STOP/STRIG - hl = pointer to trap block
322
 
BASIC_TRAP_DISABLE: equ 0x632B    ; hl = pointer to trap block
323
 
BASIC_TRAP_ACKNW:   equ 0x6358    ; hl, acknowledge trap (handle trap: sts=5? has handler? ackn, pause, run trap, sts=1? unpause)
324
 
BASIC_TRAP_PAUSE:   equ 0x6331    ; hl
325
 
BASIC_TRAP_UNPAUSE: equ 0x633E    ; hl
326
 
BASIC_TRAP_CLEAR:   equ 0x636E
327
 
 
328
 
BASIC_PLAY_DIRECT:  equ 0x744C
329
 
BASIC_DRAW_DIRECT:  equ 0x568C
330
 
 
331
 
BASIC_READYR:       equ 0x409B
332
 
BASIC_READYC:       equ 0x7D17
333
 
BASIC_FACEVAL:      equ 0x4DC7
334
 
 
335
 
BASIC_ERROR_HANDLER:equ 0x406F
336
 
BASIC_ERROR_SYNTAX: equ 0x4055
337
 
BASIC_ERROR_DIVZER: equ 0x4058
338
 
BASIC_ERROR_OVRFLW: equ 0x4067
339
 
BASIC_ERROR_ARRAY:  equ 0x405E
340
 
BASIC_ERROR_TYPMIS: equ 0x406D
341
 
 
342
 
; BASIC ERROR CODES TO BASIC_ERROR_HANDLER
343
 
; 01 NEXT without FOR             19 Device I/O error
344
 
; 02 Syntax error                 20 Verify error
345
 
; 03 RETURN without GOSUB         21 No RESUME
346
 
; 04 Out of DATA                  22 RESUME without error
347
 
; 05 Illegal function call        23 Unprintable error
348
 
; 06 Overflow                     24 Missing operand
349
 
; 07 Out of memory                25 Line buffer overflow
350
 
; 08 Undefined line number        50 FIELD overflow
351
 
; 09 Subscript out of range       51 Internal error
352
 
; 10 Redimensioned array          52 Bad file number
353
 
; 11 Division by zero             53 File not found
354
 
; 12 Illegal direct               54 File already open
355
 
; 13 Type mismatch                55 Input past end
356
 
; 14 Out of string space          56 Bad file name
357
 
; 15 String too long              57 Direct statement in file
358
 
; 16 String formula too complex   58 Sequential I/O only
359
 
; 17 Can't CONTINUE               59 File not OPEN
360
 
; 18 Undefined user function
361
 
 
362
 
;---------------------------------------------------------------------------------------------------------
363
 
; MSX BASIC WORK AREAS
364
 
;---------------------------------------------------------------------------------------------------------
365
 
 
366
 
BASIC_DAC:    equ 0xF7F6    ; 16
367
 
BASIC_ARG:    equ 0xF847    ; 16
368
 
BASIC_VALTYP: equ 0xF663
369
 
BASIC_RNDX:   equ 0xF857
370
 
BASIC_BUF:    equ 0xF55E    ; 259
371
 
BASIC_KBUF:   equ 0xF41F    ; 318
372
 
BASIC_SWPTMP: equ 0xF7BC    ; 8
373
 
BASIC_STRBUF: equ 0xF7C5    ; 43
374
 
BASIC_TXTTAB: equ 0xF676
375
 
BASIC_VARTAB: equ 0xF6C2
376
 
BASIC_ARYTAB: equ 0xF6C4
377
 
BASIC_STREND: equ 0xF6C6
378
 
BASIC_STKTOP: equ 0xF674
379
 
BASIC_FRETOP: equ 0xF69B
380
 
BASIC_MEMSIZ: equ 0xF672
381
 
 
382
 
BASIC_TEMPPT: equ 0xF678    ; 2 Starting address of unused area of temporary descriptor.
383
 
BASIC_TEMPST: equ 0xF67A    ; 30 Temporary descriptors.
384
 
 
385
 
BASIC_DATPTR: equ 0xF6C8    ; 2 Pointer to next data to read from the instruction DATA. Modified by RESTORE.
386
 
BASIC_DATLIN: equ 0xF6A3    ; 2 Número de linha do comando DATA para o comando READ.
387
 
BASIC_DORES:  equ 0xF664    ; 1 Usada pelo comando DATA para manter o texto no formato ASCII.
388
 
BASIC_DEFTBL: equ 0xF6CA    ; 26 table of variables defined by DEFINT, DEFSTR, DEFSNG and DEFDBL for each alphabet letter (2 = integer, 3 = String, 4 = Simple precision, 8 = Double precision).
389
 
 
390
 
BASIC_CURLIN: equ 0xF41C    ; BASIC current line number
391
 
BASIC_INTVAL: equ 0xFCA0    ; interval value
392
 
BASIC_INTCNT: equ 0xFCA2    ; interval current count
393
 
 
394
 
BASIC_PRMPRV: equ 0xF74C    ; Pointer to previous parameter block in PARM1
395
 
 
396
 
BASIC_TRPTBL: equ 0xFC4C    ; 78 trap table - array of 3 bytes - state[1] (bit 0=on, bit 1=stop, bit 2=active) + address[2]
397
 
 
398
 
BASIC_TRPTBL_KEY:        equ 0xFC4C  ; 30 ON KEY GOSUB
399
 
BASIC_TRPTBL_STOP:       equ 0xFC6A  ; 3  ON STOP GOSUB
400
 
BASIC_TRPTBL_SPRITE:     equ 0xFC6D  ; 3  ON SPRITE GOSUB
401
 
BASIC_TRPTBL_STRIG:      equ 0xFC70  ; 15 ON STRIG GOSUB
402
 
BASIC_TRPTBL_INTERVAL:   equ 0xFC7F  ; 3  ON INTERVAL GOSUB
403
 
BASIC_TRPTBL_OTHER:      equ 0xFC82  ; 24 reserved for expansion
404
 
 
405
 
BASIC_ONGSBF:            equ 0xFBD8  ; 1  trap occurred counter (0=not occurred)
406
 
 
407
 
 
408
 
 
409
 
;--------------------------------------------------------
410
 
; MATH PACK ROUTINES
411
 
;--------------------------------------------------------
412
 
 
413
 
;--------------------------------------------------------
414
 
; SUPPORT MACROS
415
 
;--------------------------------------------------------
416
 
COMPILE_TO_ROM: EQU 1
417
 
 
418
 
MACRO __call_basic,CALL_PARM
419
 
    ld ix, CALL_PARM
420
 
    call BIOS_CALBAS
421
 
ENDM
422
 
 
423
 
if defined COMPILE_TO_DOS
424
 
 
425
 
  MACRO __call_bios,CALL_PARM
426
 
    ;ld iy,(BIOS_EXPTBL-1)
427
 
    ld ix, CALL_PARM
428
 
    call BIOS_CALBAS   ; BIOS_CALSLT
429
 
  ENDM
430
 
 
431
 
else
432
 
 
433
 
  MACRO __call_bios,CALL_PARM
434
 
    call CALL_PARM
435
 
  ENDM
436
 
 
437
 
endif
438
 
 
439
 
MACRO push.parm
440
 
    push hl ; save parameter
441
 
ENDM
442
 
 
443
 
MACRO pop.parm
444
 
    pop iy  ; restore PC of caller
445
 
    pop hl  ; get next parameter
446
 
    push iy ; save PC of caller
447
 
ENDM
448
 
 
449
 
MACRO push.ret.parm
450
 
    pop iy  ; restore PC of caller
451
 
    push hl ; save return parameter
452
 
    push iy ; save PC of caller
453
 
ENDM
454
 
 
455
 
MACRO ret.parm
456
 
    pop iy         ; restore PC of caller
457
 
    push hl        ; save return parameter
458
 
    push iy        ; save PC of caller
459
 
    ret            ; return
460
 
ENDM
461
 
 
462
 
MACRO set.line.number, line_number
463
 
    ld bc, line_number          ; current line number
464
 
    ld (BASIC_CURLIN), bc
465
 
ENDM
466
 
 
467
 
MACRO verify.break
468
 
    ld a, (BIOS_INTFLG)         ; verify CTRL+BREAK
469
 
    or a
470
 
    jp nz, end_pgm
471
 
ENDM
472
 
 
473
 
MACRO check.traps
474
 
     ld a, (BASIC_ONGSBF)       ; trap occured counter
475
 
     or a
476
 
     call nz, RUN_TRAPS
477
 
ENDM
478
 
 
479
 
 
480
 
;---------------------------------------------------------------------------------------------------------
481
 
; PROGRAM HEADER
482
 
;---------------------------------------------------------------------------------------------------------
483
 
 
484
 
    romSize:       equ  0x8000                 ; ROM size (32k)
485
 
    pageSize:      equ  0x4000                 ; Page size (16k)
486
 
    lowLimitSize:  equ  0x400                  ; 10% of a page size
487
 
 
488
 
if defined COMPILE_TO_BIN
489
 
 
490
 
    pgmArea:    equ  0x8000                 ; page 2 - program area
491
 
    ramArea:    equ  0xc000                 ; page 3 - free RAM start area
492
 
 
493
 
    org  pgmArea                ; program binary type start address
494
 
    db   0FEh                       ; binary file ID
495
 
    dw   start_pgm                  ; begin address
496
 
    dw   end_file - 1           ; end address
497
 
    dw   start_pgm                  ; program execution address (for ,R option)
498
 
 
499
 
else
500
 
if defined COMPILE_TO_ROM
501
 
 
502
 
    pgmArea:    equ  0x4000                 ; page 1 and 2 - program area
503
 
    ramArea:    equ  0xc000                 ; page 3 - free RAM start area
504
 
 
505
 
    org  pgmArea                ; program rom type start address
506
 
    db   'AB'                   ; rom file ID
507
 
    dw   start_pgm              ; INIT
508
 
    dw   0x0000                 ; STATEMENT
509
 
    dw   0x0000                 ; DEVICE
510
 
    dw   0x0000                 ; TEXT
511
 
    ds   6,0                    ; RESERVED
512
 
 
513
 
else
514
 
 
515
 
    pgmArea:    equ  0x8000                 ; page 2 - program area
516
 
    ramArea:    equ  0xc000                 ; page 3 - free RAM start area
517
 
 
518
 
    org  pgmArea                ; program DOS type start address    ; 0x0100
519
 
 
520
 
endif
521
 
endif
522
 
 
523
 
 
524
 
;---------------------------------------------------------------------------------------------------------
525
 
; PROGRAM ROUTINES
526
 
;---------------------------------------------------------------------------------------------------------
527
 
 
528
 
if defined COMPILE_TO_ROM
529
 
 
530
 
PROGRAM_TO_BASIC:
531
 
    call PROGRAM_SLOT_2_RESTORE
532
 
    __call_basic BASIC_READYR    ; warm start Basic
533
 
    ret
534
 
 
535
 
PROGRAM_SLOT_2_SAVE:
536
 
    ld h,080h
537
 
    call PROGRAM_SLOT_GET
538
 
    ld (BIOS_RAMAD2), a ; Save RAM slot of page 8000h-BFFFh
539
 
    ret
540
 
 
541
 
PROGRAM_SLOT_2_RESTORE:
542
 
    ld a, (BIOS_RAMAD2)
543
 
        ld h,080h
544
 
        jp BIOS_ENASLT      ; Select the RAM on page 8000h-BFFFh
545
 
 
546
 
PROGRAM_SLOT_2_ENABLE:
547
 
    call BIOS_RSLREG
548
 
    call PROGRAM_SLOT_ENABLE_SUB
549
 
        ld      h,080h
550
 
        jp BIOS_ENASLT          ; Select the ROM on page 8000h-BFFFh
551
 
 
552
 
PROGRAM_SLOT_1_ENABLE:
553
 
    call BIOS_RSLREG
554
 
        rrca
555
 
        rrca
556
 
    call PROGRAM_SLOT_ENABLE_SUB
557
 
        ld      h,040h
558
 
        jp BIOS_ENASLT  ; Select the ROM on page 4000h-7FFFh
559
 
 
560
 
PROGRAM_SLOT_ENABLE_SUB:
561
 
        rrca
562
 
        rrca
563
 
        and     3       ;Keep bits corresponding to the page
564
 
        ld      c,a
565
 
        ld      b,0
566
 
        ld      hl,BIOS_EXPTBL
567
 
        add     hl,bc
568
 
        ld      a,(hl)
569
 
        and     80h
570
 
        or      c
571
 
        ld      c,a
572
 
        inc     hl
573
 
        inc     hl
574
 
        inc     hl
575
 
        inc     hl
576
 
        ld      a,(hl)
577
 
        and     0Ch
578
 
        or      c
579
 
    ret
580
 
 
581
 
; h = memory page
582
 
; a <- slot ID formatted FxxxSSPP
583
 
; Modifies: af, bc, de, hl
584
 
; ref: https://www.msx.org/forum/msx-talk/development/fusion-c-and-htimi#comment-366469
585
 
PROGRAM_SLOT_GET:
586
 
        call BIOS_RSLREG
587
 
        bit 7,h
588
 
        jr z,PrimaryShiftContinue
589
 
        rrca
590
 
        rrca
591
 
        rrca
592
 
        rrca
593
 
PrimaryShiftContinue:
594
 
        bit 6,h
595
 
        jr z,PrimaryShiftDone
596
 
        rrca
597
 
        rrca
598
 
PrimaryShiftDone:
599
 
        and 00000011B
600
 
        ld c,a
601
 
        ld b,0
602
 
        ex de,hl
603
 
        ld hl,BIOS_EXPTBL
604
 
        add hl,bc
605
 
        ld c,a
606
 
        ld a,(hl)
607
 
        and 80H
608
 
        or c
609
 
        ld c,a
610
 
        inc hl  ; move to SLTTBL
611
 
        inc hl
612
 
        inc hl
613
 
        inc hl
614
 
        ld a,(hl)
615
 
        ex de,hl
616
 
        bit 7,h
617
 
        jr z,SecondaryShiftContinue
618
 
        rrca
619
 
        rrca
620
 
        rrca
621
 
        rrca
622
 
SecondaryShiftContinue:
623
 
        bit 6,h
624
 
        jr nz,SecondaryShiftDone
625
 
        rlca
626
 
        rlca
627
 
SecondaryShiftDone:
628
 
        and 00001100B
629
 
        or c
630
 
        ret
631
 
 
632
 
endif
633
 
 
634
 
if defined COMPILE_TO_DOS
635
 
 
636
 
BIOS_SLOT_ENABLE:
637
 
               ld a, (BIOS_EXPTBL)
638
 
               ld hl,0
639
 
               __call_bios BIOS_ENASLT ; Select main ROM on page 0 (0000h~3FFFh)
640
 
               ret
641
 
 
642
 
BASIC_SLOT_ENABLE:
643
 
               ld a, (BIOS_EXPTBL)
644
 
               ld hl,04000h
645
 
               __call_bios BIOS_ENASLT ; Select main ROM on page 1 (4000h~7FFFh)
646
 
               ret
647
 
 
648
 
endif
649
 
 
650
 
 
651
 
 
652
 
;---------------------------------------------------------------------------------------------------------
653
 
; PROGRAM MAIN CODE
654
 
;---------------------------------------------------------------------------------------------------------
655
 
 
656
 
start_pgm:                               ; start of the program
657
 
 
658
 
    if defined COMPILE_TO_DOS
659
 
 
660
 
       call BIOS_SLOT_ENABLE   ; enable bios on page 0
661
 
       call BASIC_SLOT_ENABLE  ; enable basic on page 1
662
 
 
663
 
    else
664
 
       if defined COMPILE_TO_ROM
665
 
 
666
 
          call PROGRAM_SLOT_2_SAVE     ; save slot on page 2
667
 
          call PROGRAM_SLOT_2_ENABLE   ; enable program on page 2
668
 
 
669
 
       endif
670
 
    endif
671
 
 
672
 
    __call_bios BIOS_ERAFNK      ; turn off function keys display
673
 
    __call_bios BIOS_GICINI      ; initialize sound system
674
 
    __call_bios BIOS_INITXT      ; initialize text screen
675
 
    xor a
676
 
    ld (BIOS_CLIKSW), a          ; disable keyboard click
677
 
    ld bc, 0xFFFF                ;
678
 
    ld (BASIC_CURLIN), bc        ; interpreter in direct mode
679
 
    __call_basic BASIC_TRAP_CLEAR        ; clear traps work space
680
 
    ;call INITIALIZE_PARAMETERS   ; initialize parameters stack
681
 
    call memory.init             ; initialize memory allocation
682
 
    call INITIALIZE_VARIABLES    ; initialize variables
683
 
 
684
 
 
685
 
TAG_10:
686
 
            set.line.number     10      ; current line number
687
 
            ld hl, LIT_4                ; parameter
688
 
            push.parm
689
 
            call SCREEN                 ; action call
690
 
 
691
 
TAG_20:
692
 
            set.line.number     20      ; current line number
693
 
            ld hl, LIT_10               ; parameter
694
 
            push.parm
695
 
            call PSET.COLOR             ; action call
696
 
            ld hl, LIT_8                ; parameter
697
 
            push.parm
698
 
            ld hl, LIT_7                ; parameter
699
 
            push.parm
700
 
            call PSET.XY                ; action call
701
 
            call PSET                   ; action call
702
 
 
703
 
TAG_30:
704
 
            set.line.number     30      ; current line number
705
 
            ld hl, LIT_13               ; parameter
706
 
            push.parm
707
 
            call PSET.COLOR             ; action call
708
 
            ld hl, LIT_12               ; parameter
709
 
            push.parm
710
 
            ld hl, LIT_11               ; parameter
711
 
            push.parm
712
 
            call PSET.XY                ; action call
713
 
            call PSET                   ; action call
714
 
 
715
 
TAG_40:
716
 
            set.line.number     40      ; current line number
717
 
            ld hl, LIT_19               ; parameter
718
 
            push.parm
719
 
            call PSET.COLOR             ; action call
720
 
            ld hl, LIT_18               ; parameter
721
 
            push.parm
722
 
            ld hl, LIT_17               ; parameter
723
 
            push.parm
724
 
            ld hl, LIT_16               ; parameter
725
 
            push.parm
726
 
            ld hl, LIT_15               ; parameter
727
 
            push.parm
728
 
            call PSET.XY                ; action call
729
 
            call LINE                   ; action call
730
 
 
731
 
TAG_50:
732
 
            set.line.number     50      ; current line number
733
 
            ld hl, LIT_24               ; parameter
734
 
            push.parm
735
 
            call PSET.COLOR             ; action call
736
 
            ld hl, LIT_23               ; parameter
737
 
            push.parm
738
 
            ld hl, LIT_22               ; parameter
739
 
            push.parm
740
 
            ld hl, LIT_21               ; parameter
741
 
            push.parm
742
 
            ld hl, LIT_20               ; parameter
743
 
            push.parm
744
 
            call PSET.XY                ; action call
745
 
            call LINE                   ; action call
746
 
 
747
 
TAG_60:
748
 
            set.line.number     60      ; current line number
749
 
            ld hl, LIT_29               ; parameter
750
 
            push.parm
751
 
            call PSET.COLOR             ; action call
752
 
            ld hl, LIT_28               ; parameter
753
 
            push.parm
754
 
            ld hl, LIT_27               ; parameter
755
 
            push.parm
756
 
            ld hl, LIT_26               ; parameter
757
 
            push.parm
758
 
            ld hl, LIT_25               ; parameter
759
 
            push.parm
760
 
            call PSET.XY                ; action call
761
 
            call LINE                   ; action call
762
 
 
763
 
TAG_70:
764
 
            set.line.number     70      ; current line number
765
 
            ld hl, LIT_35               ; parameter
766
 
            push.parm
767
 
            call PSET.COLOR             ; action call
768
 
            ld hl, LIT_34               ; parameter
769
 
            push.parm
770
 
            ld hl, LIT_33               ; parameter
771
 
            push.parm
772
 
            ld hl, LIT_32               ; parameter
773
 
            push.parm
774
 
            ld hl, LIT_31               ; parameter
775
 
            push.parm
776
 
            call PSET.XY                ; action call
777
 
            call BOX                    ; action call
778
 
 
779
 
TAG_80:
780
 
            set.line.number     80      ; current line number
781
 
            ld hl, LIT_41               ; parameter
782
 
            push.parm
783
 
            call PSET.COLOR             ; action call
784
 
            ld hl, LIT_40               ; parameter
785
 
            push.parm
786
 
            ld hl, LIT_39               ; parameter
787
 
            push.parm
788
 
            ld hl, LIT_38               ; parameter
789
 
            push.parm
790
 
            ld hl, LIT_37               ; parameter
791
 
            push.parm
792
 
            call PSET.XY                ; action call
793
 
            call FBOX                   ; action call
794
 
 
795
 
TAG_90:
796
 
            set.line.number     90      ; current line number
797
 
            ld hl, LIT_46               ; parameter
798
 
            push.parm
799
 
            call PSET.COLOR             ; action call
800
 
            ld hl, LIT_45               ; parameter
801
 
            push.parm
802
 
            ld hl, LIT_44               ; parameter
803
 
            push.parm
804
 
            ld hl, LIT_43               ; parameter
805
 
            push.parm
806
 
            ld hl, LIT_42               ; parameter
807
 
            push.parm
808
 
            call PSET.XY                ; action call
809
 
            call LINE                   ; action call
810
 
 
811
 
TAG_100:
812
 
            set.line.number    100      ; current line number
813
 
            ld hl, LIT_51               ; parameter
814
 
            push.parm
815
 
            call PSET.COLOR             ; action call
816
 
            ld hl, LIT_50               ; parameter
817
 
            push.parm
818
 
            ld hl, LIT_49               ; parameter
819
 
            push.parm
820
 
            ld hl, LIT_48               ; parameter
821
 
            push.parm
822
 
            ld hl, LIT_47               ; parameter
823
 
            push.parm
824
 
            call PSET.XY                ; action call
825
 
            call LINE                   ; action call
826
 
 
827
 
TAG_110:
828
 
            set.line.number    110      ; current line number
829
 
            ld hl, LIT_56               ; parameter
830
 
            push.parm
831
 
            call PSET.COLOR             ; action call
832
 
            ld hl, LIT_55               ; parameter
833
 
            push.parm
834
 
            ld hl, LIT_54               ; parameter
835
 
            push.parm
836
 
            ld hl, LIT_53               ; parameter
837
 
            push.parm
838
 
            call PSET.XY                ; action call
839
 
            call CIRCLE                 ; action call
840
 
 
841
 
TAG_120:
842
 
            set.line.number    120      ; current line number
843
 
            ld hl, LIT_62               ; parameter
844
 
            push.parm
845
 
            call PAINT.BORDER           ; action call
846
 
            ld hl, LIT_60               ; parameter
847
 
            push.parm
848
 
            call PSET.COLOR             ; action call
849
 
            ld hl, LIT_59               ; parameter
850
 
            push.parm
851
 
            ld hl, LIT_58               ; parameter
852
 
            push.parm
853
 
            call PSET.XY                ; action call
854
 
            call PAINT                  ; action call
855
 
 
856
 
TAG_130:
857
 
            set.line.number    130      ; current line number
858
 
            jp TAG_130                  ; go to
859
 
 
860
 
;---------------------------------------------------------------------------------------------------------
861
 
; PROGRAM END CODE
862
 
;---------------------------------------------------------------------------------------------------------
863
 
 
864
 
    end_pgm:    __call_bios BIOS_DSPFNK      ; turn on function keys display
865
 
                ld a, 1                      ;
866
 
                ld (BIOS_CLIKSW), a          ; enable keyboard click
867
 
 
868
 
                if defined COMPILE_TO_ROM
869
 
                    jp PROGRAM_TO_BASIC
870
 
                else
871
 
                    __call_basic BASIC_READYR    ; warm start Basic
872
 
                endif
873
 
 
874
 
                ret                          ; end of the program
875
 
 
876
 
                ;__call_bios BIOS_GICINI      ; initialize sound system
877
 
                ;if defined COMPILE_TO_DOS or defined COMPILE_TO_ROM
878
 
                ;   __call_bios BIOS_RESET       ; restart Basic
879
 
                ;else
880
 
                ;   __call_basic BASIC_END       ; end to Basic
881
 
                ;endif
882
 
 
883
 
 
884
 
;---------------------------------------------------------------------------------------------------------
885
 
; MSX BASIC KEYWORDS
886
 
;---------------------------------------------------------------------------------------------------------
887
 
 
888
 
; keyword
889
 
LET:
890
 
 
891
 
                    ; out IX = variable assigned address
892
 
                    pop.parm                ; get variable address parameter
893
 
                    push hl                 ; just to transfer hl to ix
894
 
                    pop ix                  ;
895
 
                    ld a, (ix)              ; get variable type
896
 
                    cp 3                    ; test if string
897
 
                    jr nz, LET.PARM         ; if not a string, it isn't necessary to free memory
898
 
                    ld a, (ix + 3)          ; get variable string length
899
 
                    or a                    ; cp 0
900
 
                    jr z, LET.PARM          ; if zero, it isn't necessary to free memory
901
 
                    ld c, (ix + 4)          ; get old string address low
902
 
                    ld b, (ix + 5)          ; get old string address high
903
 
                    push ix                 ; save variable address
904
 
                      push bc               ; just to transfer bc (old string address) to ix
905
 
                      pop ix                ;
906
 
                      call memory.free      ; free memory
907
 
                    pop ix                  ; restore variable address
908
 
        LET.PARM:   pop.parm                ; get data address parameter (out hl = data address)
909
 
                    ld a, (ix + 2)          ; get variable type flag
910
 
                    or a                    ; cp 0 - test type flag (0=any, 255=fixed)
911
 
                    jr nz, LET.FIXED        ; if type flag is fixed, so casting is necessary
912
 
        LET.ANY:    push ix                 ; just to transfer ix (variable address) to de
913
 
                    pop de                  ;
914
 
                    ldi                     ; copy 1 byte from hl (data address) to de (variable address)
915
 
                    inc de                  ; go to variable data area
916
 
                    inc de                  ;
917
 
                    inc hl                  ; go to data data area
918
 
                    inc hl                  ;
919
 
                    ld bc, 8                ; data = 8 bytes
920
 
                    ldir                    ; copy bc bytes from hl (data address) to de (variable address)
921
 
                    ld a, (ix)              ; get variable type
922
 
                    cp 3                    ; test if string
923
 
                    ret nz                  ; if not string, return
924
 
                    jp LET.STRING           ; else do string treatment (in ix = variable address)
925
 
        LET.FIXED:  push ix                 ; save variable destination address
926
 
                            push hl                 ; save variable source address
927
 
                      ld a, (ix)            ; get variable fixed type, and hl has parameter data address
928
 
                      call CAST_TO          ; cast data to type (in hl = variable address, a = type to, out hl = casted data address)
929
 
                                        pop de
930
 
                    pop ix                  ; restore variable address
931
 
                    ld a, (ix)              ; get variable destination type again
932
 
                    cp 3                    ; test if string
933
 
                    jr nz, LET.VALUE        ; if not string, do value treatment
934
 
                                        ld a, (de)              ; get variable source type again
935
 
                    cp 3                    ; test if string
936
 
                    jr nz, LET.FIX1         ; if not string, get casted string size
937
 
                                        inc de
938
 
                                        inc de
939
 
                                        inc de
940
 
                                        ld a, (de)
941
 
                                        ld (ix + 3), a          ; source string size
942
 
                                        jr LET.FIX2
943
 
                LET.FIX1:   push hl
944
 
                              call GET_STR.LENGTH   ; get string length (in HL, out B)
945
 
                                        pop hl
946
 
                    ld (ix + 3), b          ; set variable length
947
 
                LET.FIX2:   ld (ix + 4), l          ; casted data address low
948
 
                    ld (ix + 5), h          ; casted data address high
949
 
                    jp LET.STRING           ; do string treatment (in ix = variable address)
950
 
        LET.VALUE:  push ix                 ; just to transfer ix (variable address) to de
951
 
                    pop de                  ;
952
 
                    inc de                  ; go to variable data area (and the data from its casted)
953
 
                    inc de                  ;
954
 
                    inc de                  ;
955
 
                    ld bc, 8                ; data = 8 bytes
956
 
                    ldir                    ; copy bc bytes from hl (data address) to de (variable address)
957
 
                    ret                     ;
958
 
        LET.STRING: ld a, (ix + 3)          ; string size
959
 
                    or a                    ; cp 0 - test if null
960
 
                    jr nz, LET.ALLOC        ; if not null, allocate new string (in ix = variable address)
961
 
                    ld bc, LIT_NULL_STR     ; else, set to a null string literal
962
 
                    ld (ix + 4), c          ; variable address low
963
 
                    ld (ix + 5), b          ; variable address high
964
 
                    ret                     ;
965
 
        LET.ALLOC:  push ix                 ; save variable address
966
 
                      ld l, (ix + 4)        ; source string address low
967
 
                      ld h, (ix + 5)        ; source string address high
968
 
                      push hl               ; save copy from address
969
 
                        ld c, (ix + 3)      ; get variable length
970
 
                        ld b, 0             ;
971
 
                        inc bc              ; string length have one more byte from zero terminator
972
 
                        push bc             ; save variable lenght + 1
973
 
                          call memory.alloc ; in bc = size, out ix = address, nz=OK
974
 
                                  jp z, memory.error
975
 
                          push ix           ; just to transfer memory address from ix to de
976
 
                          pop de            ;
977
 
                        pop bc              ; restore bytes to be copied
978
 
                      pop hl                ; restore copy from string address
979
 
                      push de               ; save copy to address
980
 
                        ldir                ; copy bc bytes from hl (data address) to de (variable address)
981
 
                                                ;xor a
982
 
                                                ;ld (de), a
983
 
                      pop de                ; restore copy to address
984
 
                    pop ix                  ; restore variable address
985
 
                    ld (ix + 4), e          ; put memory address low into variable
986
 
                    ld (ix + 5), d          ; put memory address high into variable
987
 
                    ret                     ; variable assigned
988
 
        
989
 
; keyword
990
 
BOOLEAN.IF:
991
 
 
992
 
                       pop.parm               ; get parameter boolean result in hl
993
 
                       push hl                ; ix = hl
994
 
                       pop ix                 ;
995
 
                       ld a, (ix+5)           ; put boolean integer result in a
996
 
                       ret                    ;
997
 
        
998
 
; keyword
999
 
SCREEN:
1000
 
 
1001
 
                    pop.parm                ; get first parameter
1002
 
                    call CAST_TO.INT        ;
1003
 
                    call GET_INT.VALUE      ; output BC with integer value
1004
 
                    ld a, c                 ; A = screen number (0 to 3)
1005
 
                    cp 9
1006
 
                    jr c, SCREEN.1          ; if mode < 9, jump
1007
 
                    ld a, 8                 ; else, fix to 8
1008
 
         SCREEN.1:
1009
 
             if defined EXIST_DATA_SET
1010
 
                    call gfxSetScreenMode
1011
 
                    call gfxIsTileMode
1012
 
                    ret nz
1013
 
 
1014
 
                    jp gfxClearTileScreen
1015
 
             else
1016
 
                    jp gfxSetScreenMode
1017
 
             endif
1018
 
        
1019
 
; keyword
1020
 
PSET:
1021
 
 
1022
 
                    jp gfxSetPixel
1023
 
        
1024
 
; keyword
1025
 
PSET.XY:
1026
 
 
1027
 
                    pop.parm                ; get first parameter
1028
 
                    call CAST_TO.INT        ;
1029
 
                    call GET_INT.VALUE      ; output BC with integer value
1030
 
                    ld (BIOS_GRPACX), bc    ; X
1031
 
                    pop.parm                ; get second parameter
1032
 
                    call CAST_TO.INT        ;
1033
 
                    call GET_INT.VALUE      ; output BC with integer value
1034
 
                    ld (BIOS_GRPACY), bc    ; Y
1035
 
                    jp gfxRefreshXY
1036
 
        
1037
 
; keyword
1038
 
PSET.COLOR:
1039
 
 
1040
 
                    pop.parm                ; get first parameter
1041
 
                    call CAST_TO.INT        ;
1042
 
                    call GET_INT.VALUE      ; output BC with integer value
1043
 
                    ld a, c
1044
 
                    call gfxSetForeColor
1045
 
                    jp gfxSetColor
1046
 
        
1047
 
; keyword
1048
 
LINE:
1049
 
 
1050
 
                    pop.parm                ; get first parameter
1051
 
                    call CAST_TO.INT        ;
1052
 
                    call GET_INT.VALUE      ; output BC with integer value
1053
 
                    ld (GFX_TEMP1), bc      ; dX
1054
 
                    pop.parm                ; get second parameter
1055
 
                    call CAST_TO.INT        ;
1056
 
                    call GET_INT.VALUE      ; output BC with integer value
1057
 
                    ;push bc                 ; dY
1058
 
                    ;pop de
1059
 
                                        ld d, b
1060
 
                                        ld e, c
1061
 
                    ld bc, (GFX_TEMP1)      ; dX
1062
 
                    jp gfxDrawLine
1063
 
        
1064
 
; keyword
1065
 
BOX:
1066
 
 
1067
 
                    pop.parm                ; get first parameter
1068
 
                    call CAST_TO.INT        ;
1069
 
                    call GET_INT.VALUE      ; output BC with integer value
1070
 
                    ld (GFX_TEMP1), bc      ; dX
1071
 
                    pop.parm                ; get second parameter
1072
 
                    call CAST_TO.INT        ;
1073
 
                    call GET_INT.VALUE      ; output BC with integer value
1074
 
                    ;push bc                 ; dY
1075
 
                    ;pop de
1076
 
                                        ld d, b
1077
 
                                        ld e, c
1078
 
                    ld bc, (GFX_TEMP1)      ; dX
1079
 
                    xor a                   ; a = 0 (framed box)
1080
 
                    jp gfxDrawBox
1081
 
        
1082
 
; keyword
1083
 
FBOX:
1084
 
 
1085
 
                    pop.parm                ; get first parameter
1086
 
                    call CAST_TO.INT        ;
1087
 
                    call GET_INT.VALUE      ; output BC with integer value
1088
 
                    ld (GFX_TEMP1), bc      ; dX
1089
 
                    pop.parm                ; get second parameter
1090
 
                    call CAST_TO.INT        ;
1091
 
                    call GET_INT.VALUE      ; output BC with integer value
1092
 
                    ;push bc                 ; dY
1093
 
                    ;pop de
1094
 
                                        ld d, b
1095
 
                                        ld e, c
1096
 
                    ld bc, (GFX_TEMP1)      ; dX
1097
 
                    or 1                    ; a = 1 (filled box)
1098
 
                    jp gfxDrawBox
1099
 
        
1100
 
; keyword
1101
 
CIRCLE:
1102
 
 
1103
 
                    pop.parm                ; get first parameter
1104
 
                    call CAST_TO.INT        ;
1105
 
                    call GET_INT.VALUE      ; output BC with integer value
1106
 
                                        ;push bc
1107
 
                                        ;pop hl                  ; radius
1108
 
                                        ld h, b
1109
 
                                        ld l, c
1110
 
                                        xor a                   ; not filled
1111
 
                    jp gfxDrawCircle
1112
 
        
1113
 
; keyword
1114
 
PAINT:
1115
 
 
1116
 
                                        xor a                   ; not symmetric
1117
 
                    jp gfxBorderFill
1118
 
        
1119
 
; keyword
1120
 
PAINT.BORDER:
1121
 
 
1122
 
                    pop.parm                ; get first parameter
1123
 
                    call CAST_TO.INT        ;
1124
 
                    call GET_INT.VALUE      ; output BC with integer value
1125
 
                    ld a, c
1126
 
                    jp gfxSetBorderFill
1127
 
                    ;call gfxSetColor
1128
 
                    ;ret
1129
 
        
1130
 
; keyword
1131
 
GOTO:
1132
 
; abstract virtual GOTO
1133
 
 
1134
 
 
1135
 
;---------------------------------------------------------------------------------------------------------
1136
 
; MSX BASIC SUPPORT CODE
1137
 
;---------------------------------------------------------------------------------------------------------
1138
 
 
1139
 
if defined ON_ERROR or defined ON_INTERVAL or defined ON_KEY_START or defined ON_SPRITE or defined ON_STOP or defined ON_STRIG_START or defined TRAP_ENABLED or defined TRAP_DISABLED or defined TRAP_PAUSE or defined TRAP_UNPAUSE
1140
 
 
1141
 
RUN_TRAPS:    ld b, 26
1142
 
              ld hl, BASIC_TRPTBL
1143
 
RUN_TRAPS.1:  push hl
1144
 
                push bc
1145
 
                  call TRAP_HANDLER
1146
 
                pop bc
1147
 
              pop hl
1148
 
              inc hl
1149
 
              inc hl
1150
 
              inc hl
1151
 
              djnz RUN_TRAPS.1
1152
 
              ret
1153
 
 
1154
 
; in hl = trap block address (handle trap: sts=5? has handler? ackn, pause, run trap, sts=1? unpause)
1155
 
TRAP_HANDLER:
1156
 
                ld a, (hl)    ; trap status
1157
 
                cp 5          ; trap occured AND trap not paused AND trap enabled ?
1158
 
                ret nz        ; return if false
1159
 
                inc hl
1160
 
                ld e, (hl)    ; get trap address
1161
 
                inc hl
1162
 
                ld d, (hl)
1163
 
                dec hl
1164
 
                dec hl
1165
 
                ld a, d
1166
 
                or e
1167
 
                ret z         ; return if address zero
1168
 
                push hl
1169
 
                  __call_basic BASIC_TRAP_ACKNW
1170
 
                  __call_basic BASIC_TRAP_PAUSE
1171
 
                  ld hl, TRAP_HANDLER.1
1172
 
                  ld a, (BASIC_ONGSBF)  ; save traps execution
1173
 
                  push af
1174
 
                  xor a
1175
 
                  ld (BASIC_ONGSBF), a  ; disable traps execution
1176
 
                  push hl  ; next return will be to trap handler
1177
 
                  push de  ; indirect jump to trap address
1178
 
                  ret
1179
 
TRAP_HANDLER.1: pop af
1180
 
                ld (BASIC_ONGSBF), a    ; restore traps execution
1181
 
                pop hl
1182
 
                ld a, (hl)
1183
 
                cp 1       ; trap enabled?
1184
 
                ret z
1185
 
                __call_basic BASIC_TRAP_UNPAUSE
1186
 
                ret
1187
 
 
1188
 
; hl = trap block, de = trap handler
1189
 
SET_TRAP:       xor a
1190
 
                ld (hl), a                  ; trap block status
1191
 
                inc hl
1192
 
                ld (hl), e                  ; trap block handler (pointer)
1193
 
                inc hl
1194
 
                ld (hl), d
1195
 
                ret
1196
 
 
1197
 
endif
1198
 
 
1199
 
if defined SET_PLAY_VOICE_1 or defined SET_PLAY_VOICE_2 or defined SET_PLAY_VOICE_3 or defined DO_PLAY or defined MUSIC_PLAY or defined MUSIC_NEXT or defined MUSIC_STOP
1200
 
 
1201
 
   SET_PLAY_VOICE:
1202
 
        ld (BIOS_TEMP), a       ; save voice number
1203
 
        pop.parm
1204
 
                ld a, (hl)
1205
 
                cp 3
1206
 
                ret nz                  ; return if not string
1207
 
        call GET_STR.ADDR
1208
 
    SET_PLAY_VOICE.1:
1209
 
                ld (BIOS_TEMP2), a      ; save string size
1210
 
        push hl                 ; string address
1211
 
                  ld a, (BIOS_TEMP)     ; restore voice number
1212
 
                  call BIOS_GETVCP      ; get PSG voice buffer address (in A = voice number, out HL = address of byte 2)
1213
 
                pop de
1214
 
                ld a, (BIOS_TEMP2)      ; restore string size
1215
 
                ld (hl), a              ; string size
1216
 
                inc hl
1217
 
                ld (hl), e              ; string address
1218
 
                inc hl
1219
 
                ld (hl), d
1220
 
                inc hl
1221
 
        ld D,H                  ; voice stack
1222
 
        ld E,L
1223
 
        ld BC,001CH
1224
 
        add HL,BC
1225
 
        ex DE,HL
1226
 
        ld (HL),E
1227
 
        inc HL
1228
 
        ld (HL),D
1229
 
                ret
1230
 
 
1231
 
    START_PLAY:
1232
 
        ld HL, 0x752E
1233
 
        ld (BIOS_MCLTAB),HL
1234
 
        ld a, 1
1235
 
        ld (BIOS_MCLFLG),A
1236
 
        ld hl, BIOS_TEMP      ; voice count
1237
 
        ld a, 3
1238
 
        sub (hl)
1239
 
        dec a
1240
 
        ld (BIOS_PRSCNT), a
1241
 
        xor a
1242
 
        ld (BIOS_VOICEN), a
1243
 
        ld (BIOS_QUEUEN), a
1244
 
                ld (BIOS_MUSICF), a
1245
 
        ld HL,-12 ; -10
1246
 
                add HL,SP
1247
 
        ld (BIOS_SAVSP),HL
1248
 
                ld HL, BIOS_PLYCNT
1249
 
                ld (HL), 0
1250
 
                __call_basic BASIC_PLAY_DIRECT
1251
 
                ret
1252
 
 
1253
 
endif
1254
 
 
1255
 
 
1256
 
 
1257
 
;---------------------------------------------------------------------------------------------------------
1258
 
; VARIABLES ROUTINES
1259
 
;---------------------------------------------------------------------------------------------------------
1260
 
 
1261
 
; input hl = variable address
1262
 
; input bc = variable name
1263
 
; input d =  variable type
1264
 
INIT_VAR:          ld (hl), d    ; variable type
1265
 
                   inc hl
1266
 
                   ld (hl), c    ; variable name 1
1267
 
                   inc hl
1268
 
                   ld (hl), b    ; variable name 2
1269
 
                   ld a, d
1270
 
                   cp 3
1271
 
                   jp nz, CLEAR.VAR
1272
 
                   ld de, LIT_NULL_STR
1273
 
                   inc hl
1274
 
                   ld (hl), 0
1275
 
                   inc hl
1276
 
                   ld (hl), e
1277
 
                   inc hl
1278
 
                   ld (hl), d
1279
 
                   ld b, 5
1280
 
                   jr CLEAR.VAR.LOOP
1281
 
CLEAR.VAR:         ld b, 8
1282
 
CLEAR.VAR.LOOP:    inc hl
1283
 
                   ld (hl), 0    ; data address/value
1284
 
                   djnz CLEAR.VAR.LOOP
1285
 
                   ret
1286
 
; input HL = variable address
1287
 
; input A = variable output type
1288
 
; output HL = casted data address
1289
 
CAST_TO:           cp 2
1290
 
                   jp z, CAST_TO.INT
1291
 
                   cp 3
1292
 
                   jp z, CAST_TO.STR
1293
 
                   cp 4
1294
 
                   jp z, CAST_TO.SGL
1295
 
                   cp 8
1296
 
                   jp z, CAST_TO.DBL
1297
 
                   ret
1298
 
; input HL = variable address
1299
 
; output HL = variable address
1300
 
CAST_TO.INT:       ;push af
1301
 
                     ld a, (HL)
1302
 
                     cp 2
1303
 
                     jp z, GET_INT.ADDR
1304
 
                     cp 3
1305
 
                     jp z, CAST_STR_TO.INT
1306
 
                     cp 4
1307
 
                     jp z, CAST_SGL_TO.INT
1308
 
                     cp 8
1309
 
                     jp z, CAST_DBL_TO.INT
1310
 
                   ;pop af
1311
 
                   ret
1312
 
; input HL = variable address
1313
 
; output HL = variable address
1314
 
CAST_TO.STR:       ;push af
1315
 
                     ld a, (HL)
1316
 
                     cp 2
1317
 
                     jp z, CAST_INT_TO.STR
1318
 
                     cp 3
1319
 
                     jp z, GET_STR.ADDR
1320
 
                     cp 4
1321
 
                     jp z, CAST_SGL_TO.STR
1322
 
                     cp 8
1323
 
                     jp z, CAST_DBL_TO.STR
1324
 
                   ;pop af
1325
 
                   ret
1326
 
; input HL = variable address
1327
 
; output HL = variable address
1328
 
CAST_TO.SGL:       ;push af
1329
 
                     ld a, (HL)
1330
 
                     cp 2
1331
 
                     jp z, CAST_INT_TO.SGL
1332
 
                     cp 3
1333
 
                     jp z, CAST_STR_TO.SGL
1334
 
                     cp 4
1335
 
                     jp z, GET_SGL.ADDR
1336
 
                     cp 8
1337
 
                     jp z, CAST_DBL_TO.SGL
1338
 
                   ;pop af
1339
 
                   ret
1340
 
; input HL = variable address
1341
 
; output HL = variable address
1342
 
CAST_TO.DBL:       ;push af
1343
 
                     ld a, (hl)
1344
 
                     cp 2
1345
 
                     jp z, CAST_INT_TO.DBL
1346
 
                     cp 3
1347
 
                     jp z, CAST_STR_TO.DBL
1348
 
                     cp 4
1349
 
                     jp z, CAST_SGL_TO.DBL
1350
 
                     cp 8
1351
 
                     jp z, GET_DBL.ADDR
1352
 
                   ;pop af
1353
 
                   ret
1354
 
CAST_SGL_TO.STR:                           ; same as CAST_INT_TO.STR
1355
 
CAST_DBL_TO.STR:                           ; same as CAST_INT_TO.STR
1356
 
CAST_INT_TO.STR:   call COPY_TO.DAC
1357
 
                   xor a
1358
 
                   __call_bios MATH_FOUT    ; convert DAC to string
1359
 
                   ;pop af
1360
 
                   ret
1361
 
CAST_INT_TO.SGL:   call COPY_TO.DAC
1362
 
                   __call_bios MATH_FRCSGL
1363
 
                   ld hl, BASIC_DAC
1364
 
                   ret
1365
 
CAST_INT_TO.DBL:   call COPY_TO.DAC
1366
 
                   __call_bios MATH_FRCDBL
1367
 
                   ld hl, BASIC_DAC
1368
 
                   ret
1369
 
CAST_SGL_TO.INT:                           ; same as CAST_DBL_TO.INT
1370
 
CAST_DBL_TO.INT:   call COPY_TO.DAC
1371
 
                   __call_bios MATH_FRCINT
1372
 
                   ld hl, BASIC_DAC
1373
 
                   ret
1374
 
CAST_STR_TO.INT:   call CAST_STR_TO.VAL    ;
1375
 
                   __call_bios MATH_FRCINT ;
1376
 
                   ld hl, BASIC_DAC        ;
1377
 
                   ret                     ;
1378
 
CAST_STR_TO.SGL:   call CAST_STR_TO.VAL    ;
1379
 
                   __call_bios MATH_FRCSGL ;
1380
 
                   ld hl, BASIC_DAC        ;
1381
 
                   ret                     ;
1382
 
CAST_STR_TO.DBL:   call CAST_STR_TO.VAL    ;
1383
 
                   __call_bios MATH_FRCDBL ;
1384
 
                   ld hl, BASIC_DAC        ;
1385
 
                   ret                     ;
1386
 
CAST_STR_TO.VAL:   call GET_STR.ADDR       ;
1387
 
                   ld a, (hl)              ;
1388
 
                   __call_bios MATH_FIN    ; convert string to a value type
1389
 
                   ld hl, BASIC_DAC        ;
1390
 
                   ret                     ;
1391
 
GET_INT.VALUE:     inc hl                  ; output BC with integer value
1392
 
                   inc hl                  ;
1393
 
                   ld c, (hl)              ;
1394
 
                   inc hl                  ;
1395
 
                   ld b, (hl)              ;
1396
 
                   ret                     ;
1397
 
CAST_SGL_TO.DBL:                           ; same as GET_DBL.ADDR
1398
 
CAST_DBL_TO.SGL:                           ; same as GET_DBL.ADDR
1399
 
GET_INT.ADDR:                              ; same as GET_DBL.ADDR
1400
 
GET_SGL.ADDR:                              ; same as GET_DBL.ADDR
1401
 
GET_DBL.ADDR:      inc hl
1402
 
                   inc hl
1403
 
                   inc hl
1404
 
                   ;pop af
1405
 
                   ret
1406
 
GET_STR.ADDR:      push hl
1407
 
                   pop ix
1408
 
                                   ld a, (ix + 3)
1409
 
                   ld l, (ix + 4)
1410
 
                   ld h, (ix + 5)
1411
 
                   ret
1412
 
; input hl = string address
1413
 
; output b = string length
1414
 
GET_STR.LENGTH:    ld b, 0
1415
 
GET_STR.LEN.NEXT:  ld a, (hl)
1416
 
                   or a                     ; cp 0
1417
 
                   ret z
1418
 
                   inc b
1419
 
                   inc hl
1420
 
                   ld a, b
1421
 
                   cp 255
1422
 
                   jr z, GET_STR.LEN.ERR
1423
 
                   jr GET_STR.LEN.NEXT
1424
 
GET_STR.LEN.ERR:   ld b, 0
1425
 
                   ret
1426
 
STRING.COMPARE:    ld ix, (BASIC_DAC+1)     ; string 1
1427
 
                   ld iy, (BASIC_ARG+1)     ; string 2
1428
 
STRING.COMPARE.NX: ld a, (ix)               ; next char from string 1
1429
 
                   cp (iy)                  ; char s1 = char s2?
1430
 
                   jr nz, STRING.COMPARE.NE ; if not equal...
1431
 
                   cp 0                     ;
1432
 
                   jr z, STRING.COMPARE.F1  ; if string 1 has finished...
1433
 
                   ld a, (iy)               ; next char from string 2
1434
 
                   cp 0                     ;
1435
 
                   jr z, STRING.COMPARE.GT  ; if s2 has finished, s1 has not finished yet, so s1 is greater than s2
1436
 
                   inc ix                   ;
1437
 
                   inc iy                   ;
1438
 
                   jr STRING.COMPARE.NX     ; get next char pair
1439
 
STRING.COMPARE.F1: ld a, (iy)               ; verify if string 2 has finished too
1440
 
                   cp 0                     ;
1441
 
                   jr z, STRING.COMPARE.EQ  ; if s2 has finished, then they are equals
1442
 
                   jr STRING.COMPARE.LT     ; else, result = s1 is less than s2
1443
 
STRING.COMPARE.NE: jr c, STRING.COMPARE.GT  ; verify if s1 is greater than s2...
1444
 
STRING.COMPARE.LT: ld a, 1                  ; ...else, result = s1 less than s2
1445
 
                   ret                      ;
1446
 
STRING.COMPARE.GT: ld a, 0xFF               ; result = s1 is greater than s2
1447
 
                   ret                      ;
1448
 
STRING.COMPARE.EQ: xor a                    ; result = s1 is equal to s2
1449
 
                   ret                      ;
1450
 
STRING.CONCAT:     ld ix, BASIC_DAC           ; s1 size
1451
 
                                   ld a, (BASIC_ARG)          ; s2 size
1452
 
                                   add a, (ix)                ; s3 size = s1 size + s2 size
1453
 
                                   push af
1454
 
                     ld b, 0
1455
 
                     ld c, a                    ;
1456
 
                     inc bc                     ; add 1 byte to size
1457
 
                     call memory.alloc          ; in bc size, out ix new memory address, nz=OK
1458
 
                     jp z, memory.error         ;
1459
 
                     push ix                    ; save ix
1460
 
                       push ix                  ; save ix
1461
 
                       pop de                   ; de = ix
1462
 
                                           ld a, (BASIC_DAC)        ; s1 size
1463
 
                       ld hl, (BASIC_DAC + 1)   ; string 1
1464
 
                       call COPY_TO.STR         ; copy to new memory
1465
 
                                           ld a, (BASIC_ARG)        ; s2 size
1466
 
                       ld hl, (BASIC_ARG + 1)   ; string 2
1467
 
                       call COPY_TO.STR         ; copy to new memory
1468
 
                                           xor a
1469
 
                                           ld (de), a               ; null terminated
1470
 
                     pop hl                     ; hl = ix
1471
 
                   pop af
1472
 
                   call COPY_TO.VAR_DUMMY.STR ;
1473
 
                   ret.parm                   ; WARNING - VERIFY STRING MEMORY LEAKs
1474
 
STRING.PRINT:      ld a, (BIOS_SCRMOD)        ; 0=40x24 Text Mode, 1=32x24 Text Mode, 2=Graphics Mode, 3=Multicolour Mode
1475
 
                   cp 5                       ;
1476
 
                   jr nc, STRING.PRINT.G2     ; jump if graphic screen mode MSX2 (>=5)
1477
 
                   cp 2                       ;
1478
 
                   jr nc, STRING.PRINT.G1     ; jump if graphic screen mode MSX1 (>=2)
1479
 
STRING.PRINT.T:    ld a, (hl)                 ; get a char from a string parameter
1480
 
                   or a                       ; cp 0 - is it the string end?
1481
 
                   ret z                      ; exit if yes
1482
 
                   __call_bios BIOS_CHPUT     ; put the char (a) into text screen
1483
 
                   inc hl                     ; next char
1484
 
                   jr STRING.PRINT.T          ; repeat
1485
 
STRING.PRINT.G1:   ld a, (hl)                 ; get a char from a string parameter
1486
 
                   or a                       ; cp 0 - is it the string end?
1487
 
                   ret z                      ; exit if yes
1488
 
                   __call_bios BIOS_GRPPRT    ; put the char (a) into graphical screen
1489
 
                   inc hl                     ; next char
1490
 
                   jr STRING.PRINT.G1         ; repeat
1491
 
STRING.PRINT.G2:   ld a, (hl)                 ; get a char from a string parameter
1492
 
                   or a                       ; cp 0 - is it the string end?
1493
 
                   ret z                      ; exit if yes
1494
 
                   ld ix, BIOS_GRPPRT2        ; put the char (a) into graphical screen
1495
 
                   call BIOS_EXTROM
1496
 
                   inc hl                     ; next char
1497
 
                   jr STRING.PRINT.G2         ; repeat
1498
 
 
1499
 
; a = string size to copy
1500
 
; input hl = string from
1501
 
; input de = string to
1502
 
COPY_TO.STR:       or a
1503
 
                   ret z                      ; avoid copy if size = zero
1504
 
                   ld b, 0
1505
 
                   ld c, a                    ; string size
1506
 
                   ldir                       ; copy bc bytes from hl to de
1507
 
                   ret                        ;
1508
 
COPY_TO.BASIC_BUF: ld bc, BASIC_BUF
1509
 
                   ld a, (LIT_QUOTE_CHAR)
1510
 
                   ld (bc), a
1511
 
                   inc bc
1512
 
COPY_BAS_BUF.LOOP: ld a, (hl)
1513
 
                   or a                      ; cp 0
1514
 
                   jr z, COPY_BAS_BUF.EXIT
1515
 
                   ld (bc), a
1516
 
                   inc bc
1517
 
                   inc hl
1518
 
                   jr COPY_BAS_BUF.LOOP
1519
 
COPY_BAS_BUF.EXIT: ld a, (LIT_QUOTE_CHAR)
1520
 
                   ld (bc), a
1521
 
                   inc bc
1522
 
                   xor a
1523
 
                   ld (bc), a
1524
 
                   ld hl, BASIC_BUF
1525
 
                   ret
1526
 
COPY_TO.VAR_DUMMY:     ld a, (BASIC_VALTYP)    ; create dummy variable from VALTYPE
1527
 
                       cp 3                    ;
1528
 
                       jr nz, COPY_TO.VAR_DUMMY.DBL
1529
 
                                           push hl
1530
 
                                             call GET_STR.LENGTH   ; get string length
1531
 
                                           pop hl
1532
 
                       ld a, b                 ; string length
1533
 
COPY_TO.VAR_DUMMY.STR: call GET_VAR_DUMMY.ADDR ; create dummy string variable from HL
1534
 
                       ld (ix), 3            ; data type string
1535
 
                       ld (ix+1), 0          ;
1536
 
                       ld (ix+2), 255        ; var type fixed
1537
 
                       ld (ix+3), a          ; string length
1538
 
                       ld (ix+4), l          ; data address low
1539
 
                       ld (ix+5), h          ; data address high
1540
 
                       ;call GET_STR.LENGTH   ; get string length
1541
 
                       ;ld (ix+3), b          ; string length
1542
 
                       push ix               ; output var address...
1543
 
                       pop hl                ; ...into hl
1544
 
                       ret                   ;
1545
 
COPY_TO.VAR_DUMMY.INT: call GET_VAR_DUMMY.ADDR ; create dummy integer variable from BC
1546
 
                       ld (ix),    2           ; data type string
1547
 
                       ld (ix+1),  0           ;
1548
 
                       ld (ix+2),  0           ;
1549
 
                       ld (ix+3),  0           ;
1550
 
                       ld (ix+4),  0           ;
1551
 
                       ld (ix+5),  c           ;
1552
 
                       ld (ix+6),  b           ;
1553
 
                       ld (ix+7),  0           ;
1554
 
                       ld (ix+8),  0           ;
1555
 
                       ld (ix+9),  0           ;
1556
 
                       ld (ix+10), 0           ;
1557
 
                       push ix                 ; output var address...
1558
 
                       pop hl                  ; ...into hl
1559
 
                       ret                     ;
1560
 
COPY_TO.VAR_DUMMY.DBL: call GET_VAR_DUMMY.ADDR  ; create dummy value variable from DAC
1561
 
                       ld (ix), a            ; data type
1562
 
                       ld (ix+1), 0          ;
1563
 
                       ld (ix+2), 0          ;
1564
 
                       ld bc, 8              ;
1565
 
                       ld hl, BASIC_DAC      ;
1566
 
                       push ix               ; just to copy ix to de
1567
 
                       pop de                ;
1568
 
                       inc de                ;
1569
 
                       inc de                ;
1570
 
                       inc de                ;
1571
 
                       ldir                  ; copy bc bytes from hl (data address) to de (variable address)
1572
 
                       push ix               ; output var address...
1573
 
                       pop hl                ; ...into hl
1574
 
                       ret                   ;
1575
 
GET_VAR_DUMMY.ADDR:    push af                       ;
1576
 
                       push de
1577
 
                         ld de, 11                   ;
1578
 
                         ld ix, (VAR_DUMMY.POINTER)  ;
1579
 
                         ld a, (VAR_DUMMY.COUNTER)   ;
1580
 
GET_VAR_DUMMY.NEXT:      add ix, de                  ;
1581
 
                         inc a                       ;
1582
 
                         cp VAR_DUMMY.SIZE           ;
1583
 
                         jr nz, GET_VAR_DUMMY.EXIT   ;
1584
 
                           xor a                     ;
1585
 
                           ld ix, VAR_DUMMY.DATA     ;
1586
 
GET_VAR_DUMMY.EXIT:      ld (VAR_DUMMY.POINTER), ix  ;
1587
 
                         ld (VAR_DUMMY.COUNTER), a   ;
1588
 
                                                 ld a, (ix)                  ; get last var dummy type
1589
 
                                                 cp 3                        ; is it string?
1590
 
                                                 call z, GET_VAR_DUMMY.FREE  ; free string memory
1591
 
                       pop de
1592
 
                       pop af                        ;
1593
 
                       ret                           ;
1594
 
GET_VAR_DUMMY.FREE:
1595
 
                   push hl
1596
 
                   push ix
1597
 
                                     ld l, (ix+4)                    ; get string data address
1598
 
                                         ld h, (ix+5)
1599
 
                                         push hl
1600
 
                                         pop ix
1601
 
                     call memory.free      ; free memory
1602
 
                                   pop ix
1603
 
                                   pop hl
1604
 
                                   ret
1605
 
; input hl = variable address
1606
 
COPY_TO.DAC:       ld de, BASIC_DAC
1607
 
COPY_TO.DAC.DATA:  ld a, (hl)
1608
 
                   ld (BASIC_VALTYP), a
1609
 
                   inc hl
1610
 
                   inc hl
1611
 
                   inc hl
1612
 
                   ld bc, 8                ; data = 8 bytes
1613
 
                   ldir                    ; copy bc bytes from hl (data address) to de (variable address)
1614
 
                   ret
1615
 
COPY_TO.ARG:       ld de, BASIC_ARG        ;
1616
 
                   jr COPY_TO.DAC.DATA     ;
1617
 
COPY_TO.DAC_ARG:   ld hl, BASIC_DAC        ;
1618
 
                   ld de, BASIC_ARG        ;
1619
 
                   ld bc, 8                ; data = 8 bytes
1620
 
                   ldir                    ; copy bc bytes from hl (data address) to de (variable address)
1621
 
                   ret                     ;
1622
 
COPY_TO.ARG_DAC:   ld hl, BASIC_ARG        ;
1623
 
                   ld de, BASIC_DAC        ;
1624
 
                   ld bc, 8                ; data = 8 bytes
1625
 
                   ldir                    ; copy bc bytes from hl (data address) to de (variable address)
1626
 
                   ret                     ;
1627
 
COPY_TO.DAC_TMP:   ld hl, BASIC_DAC        ;
1628
 
                   ld de, BASIC_SWPTMP     ;
1629
 
                   ld bc, 8                ; data = 8 bytes
1630
 
                   ldir                    ; copy bc bytes from hl (data address) to de (variable address)
1631
 
                   ret                     ;
1632
 
COPY_TO.TMP_DAC:   ld hl, BASIC_SWPTMP     ;
1633
 
                   ld de, BASIC_DAC        ;
1634
 
                   ld bc, 8                ; data = 8 bytes
1635
 
                   ldir                    ; copy bc bytes from hl (data address) to de (variable address)
1636
 
                   ret                     ;
1637
 
SWAP.DAC.ARG:      di
1638
 
                   exx                     ; save registers
1639
 
                     ld bc, 8              ;
1640
 
                     ld hl, BASIC_DAC      ;
1641
 
                     ld de, BASIC_SWPTMP   ;
1642
 
                     ldir                  ; copy bc bytes from hl to de
1643
 
                     ld bc, 8              ;
1644
 
                     ld hl, BASIC_ARG      ;
1645
 
                     ld de, BASIC_DAC      ;
1646
 
                     ldir                  ; copy bc bytes from hl to de
1647
 
                     ld bc, 8              ;
1648
 
                     ld hl, BASIC_SWPTMP   ;
1649
 
                     ld de, BASIC_ARG      ;
1650
 
                     ldir                  ; copy bc bytes from hl to de
1651
 
                   exx                     ; restore registers
1652
 
                   ei
1653
 
                   ret                     ;
1654
 
CLEAR.DAC:         ld de, BASIC_DAC
1655
 
CLEAR.DAC.DATA:    ld hl, BASIC_VALTYP
1656
 
                   ld (hl), 2
1657
 
                   ld hl, LIT_NULL_DBL
1658
 
                   ld bc, 8                ; data = 8 bytes
1659
 
                   ldir                    ; copy bc bytes from hl (data address) to de (variable address)
1660
 
                   ret
1661
 
CLEAR.ARG:         ld de, BASIC_ARG
1662
 
                   jr CLEAR.DAC.DATA
1663
 
 
1664
 
 
1665
 
 
1666
 
;---------------------------------------------------------------------------------------------------------
1667
 
; MATH 16 BITS ROUTINES
1668
 
;---------------------------------------------------------------------------------------------------------
1669
 
 
1670
 
MATH.PARM.POP:  pop af                       ; get PC from caller stack
1671
 
                ex af, af'                   ; save PC to temp
1672
 
                  pop.parm                   ; get first parameter
1673
 
                  call COPY_TO.ARG           ; put HL in ARG (return var type in A)
1674
 
                  pop.parm                   ; get second parameter
1675
 
                ex af, af'                   ; restore PC from temp
1676
 
                push af                      ; put again PC from caller in stack
1677
 
                ex af, af'                   ; restore 1st data type
1678
 
                push af                      ; save 1st data type
1679
 
                  call COPY_TO.DAC           ; put HL in DAC (return var type in A)
1680
 
                pop bc                       ; restore 1st data type (ARG) in B
1681
 
                cp b                         ; test if data type in A (DAC) = data type in B (ARG)
1682
 
                ret z                        ; return if is equal data types
1683
 
MATH.PARM.CAST: push bc                      ; else cast both to double
1684
 
                  and 12                     ; test if single/double
1685
 
                  jr nz, MATH.PARM.CST1      ; avoid cast if already single/double
1686
 
                  __call_bios MATH_FRCDBL    ; convert DAC to double
1687
 
MATH.PARM.CST1: pop af                       ;
1688
 
                and 12                       ; test if single/double
1689
 
                jr nz, MATH.PARM.CST2        ; avoid cast if already single/double
1690
 
                ld (BASIC_VALTYP), a         ;
1691
 
                call COPY_TO.DAC_TMP         ;
1692
 
                call COPY_TO.ARG_DAC         ;
1693
 
                __call_bios MATH_FRCDBL      ; convert ARG to double
1694
 
                call COPY_TO.DAC_ARG         ;
1695
 
                call COPY_TO.TMP_DAC         ;
1696
 
MATH.PARM.CST2: ld a, 8                      ;
1697
 
                ld (BASIC_VALTYP), a         ;
1698
 
                ret                          ;
1699
 
MATH.PARM.POP.INT:                           ; return result in DAC/ARG as integer
1700
 
                pop af                       ; get PC from caller stack
1701
 
                  ex af, af'                 ; save PC to temp
1702
 
                    pop.parm                 ; get first parameter
1703
 
                    ld a, (hl)               ; get parameter type
1704
 
                    and 2                    ; test if integer
1705
 
                    jr z, MATH.PARM.POP.I1   ; do cast if not integer
1706
 
                    call COPY_TO.ARG         ; put HL in ARG (return var type in A)
1707
 
                    jr MATH.PARM.POP.I2      ; go to next parameter
1708
 
MATH.PARM.POP.I1:   call COPY_TO.DAC         ; put HL in DAC (return var type in A)
1709
 
                    __call_bios MATH_FRCINT  ; convert DAC to int
1710
 
                    call COPY_TO.DAC_ARG     ; copy DAC to ARG
1711
 
MATH.PARM.POP.I2:   pop.parm                 ; get second parameter
1712
 
                    call COPY_TO.DAC         ; put HL in DAC (return var type in A)
1713
 
                    and 2                    ; test if integer
1714
 
                    jr nz, MATH.PARM.POP.I3  ; avoid cast if already integer
1715
 
                    __call_bios MATH_FRCINT  ; convert DAC to int
1716
 
                    ld a, 2                  ;
1717
 
                    ld (BASIC_VALTYP), a     ;
1718
 
MATH.PARM.POP.I3:
1719
 
                    ex af, af'                 ; restore PC from temp
1720
 
                push af                      ; put again PC from caller in stack
1721
 
                ret                          ;
1722
 
MATH.PARM.PUSH: call COPY_TO.VAR_DUMMY       ;
1723
 
                ret.parm                     ;
1724
 
 
1725
 
if defined MATH.ADD
1726
 
 
1727
 
; input DAC, ARG
1728
 
; output in parm stack
1729
 
; http://www.z80.info/zip/zaks_book.pdf - page 104
1730
 
MATH.ADD.INT:  ld hl, (BASIC_DAC+2)  ;
1731
 
               ld bc, (BASIC_ARG+2)  ;
1732
 
               add hl, bc            ;
1733
 
               ld (BASIC_DAC+2), hl  ;
1734
 
               jp MATH.PARM.PUSH     ;
1735
 
 
1736
 
endif
1737
 
 
1738
 
if defined MATH.SUB or defined MATH.NEG
1739
 
 
1740
 
; input DAC, ARG
1741
 
; output in parm stack
1742
 
; http://www.z80.info/zip/zaks_book.pdf - page 104
1743
 
MATH.SUB.INT:  ld hl, (BASIC_DAC+2)  ;
1744
 
               ld de, (BASIC_ARG+2)  ;
1745
 
               and a                 ; clear carry
1746
 
               sbc hl, de            ;
1747
 
               ld (BASIC_DAC+2), hl  ;
1748
 
               jp MATH.PARM.PUSH     ;
1749
 
 
1750
 
endif
1751
 
 
1752
 
if defined MATH.MULT
1753
 
 
1754
 
; input DAC, ARG
1755
 
; output in parm stack
1756
 
MATH.MULT.INT: ld hl, (BASIC_DAC+2)  ;
1757
 
               ld bc, (BASIC_ARG+2)  ;
1758
 
               call MATH.MULT.16     ;
1759
 
               ld (BASIC_DAC+2), hl  ;
1760
 
               jp MATH.PARM.PUSH     ;
1761
 
 
1762
 
; input HL = multiplicand
1763
 
; input BC = multiplier
1764
 
; output HL = result
1765
 
; http://www.z80.info/zip/zaks_book.pdf - page 131
1766
 
MATH.MULT.16:  ld a, c                          ; low multiplier
1767
 
               ld c, b                          ; high multiplier
1768
 
               ld b, 16
1769
 
               ld d, h                  ; multiplicand
1770
 
               ld e, l
1771
 
               ld hl, 0
1772
 
MULT16LOOP:    srl c                            ; right shift multiplier high
1773
 
               rra                                      ; rotate right multiplier low
1774
 
               jr nc, MULT16NOADD       ; test carry
1775
 
               add hl, de                       ; add multiplicand to result
1776
 
MULT16NOADD:   ex de, hl
1777
 
               add hl, hl                       ; double - shift multiplicand
1778
 
               ex de, hl
1779
 
               djnz MULT16LOOP
1780
 
               ret
1781
 
 
1782
 
endif
1783
 
 
1784
 
if defined MATH.DIV or defined MATH.IDIV or defined MATH.MOD
1785
 
 
1786
 
; input AC = dividend
1787
 
; input DE = divisor
1788
 
; output AC = quotient
1789
 
; output HL = remainder
1790
 
; http://www.z80.info/zip/zaks_book.pdf - page 140
1791
 
MATH.DIV.16:   ld hl, 0                         ; clear accumulator
1792
 
               ld b, 16                         ; set counter
1793
 
DIV16LOOP:     rl c                                     ; rotate accumulator result left
1794
 
               rla
1795
 
               adc hl, hl                               ; left shift
1796
 
               sbc hl, de                               ; trial subtract divisor
1797
 
               jr nc, $ + 3                     ; subtract was OK ($ = current location)
1798
 
               add hl, de                               ; restore accumulator
1799
 
               ccf                                              ; calculate result bit
1800
 
               djnz DIV16LOOP                   ; counter not zero
1801
 
               rl c                                     ; shift in last result bit
1802
 
               rla
1803
 
               ret
1804
 
 
1805
 
endif
1806
 
 
1807
 
if defined GFX_FAST or defined LINE
1808
 
 
1809
 
; compare two signed 16 bits integers
1810
 
; HL < DE: Carry flag
1811
 
; HL = DE: Zero flag
1812
 
; http://www.z80.info/zip/zaks_book.pdf - page 531
1813
 
MATH.COMP.S16: ld a, h                       ; test high order byte
1814
 
               and 0x80                      ; test sign, clear carry
1815
 
                           jr nz, MATH.COMP.S16.NEGM1    ; jump if hl is negative
1816
 
                           bit 7, d
1817
 
                           ret nz                        ; de is negative (and hl is positive)
1818
 
                           ld a, h
1819
 
                           cp d                          ; signs are both positive, so normal compare
1820
 
                           ret nz
1821
 
                           ld a, l                       ; test low order byte
1822
 
                           cp e
1823
 
               ret
1824
 
MATH.COMP.S16.NEGM1:
1825
 
               xor d
1826
 
               rla                           ; sign bit into carry
1827
 
               ret c                         ; signs different
1828
 
               ld a, h
1829
 
               cp d                          ; both signs negative
1830
 
                           ret nz
1831
 
                           ld a, l
1832
 
                           cp e
1833
 
                           ret
1834
 
 
1835
 
endif
1836
 
 
1837
 
if defined MATH.ADD
1838
 
 
1839
 
MATH.ADD.SGL:  ld a, 8                  ;
1840
 
               ld (BASIC_VALTYP), a     ;
1841
 
MATH.ADD.DBL:  __call_bios MATH_DECADD  ;
1842
 
               jp MATH.PARM.PUSH        ;
1843
 
 
1844
 
endif
1845
 
 
1846
 
if defined MATH.SUB or defined MATH.NEG
1847
 
 
1848
 
MATH.SUB.SGL:  ld a, 8                  ;
1849
 
               ld (BASIC_VALTYP), a     ;
1850
 
MATH.SUB.DBL:  __call_bios MATH_DECSUB  ;
1851
 
               jp MATH.PARM.PUSH        ;
1852
 
 
1853
 
endif
1854
 
 
1855
 
if defined MATH.MULT
1856
 
 
1857
 
MATH.MULT.SGL: ld a, 8                  ;
1858
 
               ld (BASIC_VALTYP), a     ;
1859
 
MATH.MULT.DBL: __call_bios MATH_DECMUL  ;
1860
 
               jp MATH.PARM.PUSH        ;
1861
 
 
1862
 
endif
1863
 
 
1864
 
if defined MATH.DIV
1865
 
 
1866
 
; input DAC, ARG
1867
 
; output in parm stack
1868
 
MATH.DIV.INT:  __call_bios MATH_FRCDBL  ; convert DAC to double
1869
 
               call SWAP.DAC.ARG        ;
1870
 
               ld a, 2                  ;
1871
 
               ld (BASIC_VALTYP), a     ;
1872
 
               __call_bios MATH_FRCDBL  ; convert ARG to double
1873
 
               call SWAP.DAC.ARG        ;
1874
 
MATH.DIV.SGL:  ld a, 8                  ;
1875
 
               ld (BASIC_VALTYP), a     ;
1876
 
MATH.DIV.DBL:  __call_bios MATH_DECDIV  ;
1877
 
               jp MATH.PARM.PUSH        ;
1878
 
 
1879
 
endif
1880
 
 
1881
 
if defined MATH.IDIV
1882
 
 
1883
 
; input DAC, ARG
1884
 
; output in parm stack
1885
 
MATH.IDIV.SGL: ld a, 8                  ;
1886
 
               ld (BASIC_VALTYP), a     ;
1887
 
MATH.IDIV.DBL: __call_bios MATH_FRCINT  ; convert DAC to integer
1888
 
               call SWAP.DAC.ARG        ;
1889
 
               ld a, 8                  ;
1890
 
               ld (BASIC_VALTYP), a     ;
1891
 
               __call_bios MATH_FRCINT  ; convert ARG to integer
1892
 
               call SWAP.DAC.ARG        ;
1893
 
MATH.IDIV.INT: ld hl, (BASIC_DAC+2)     ;
1894
 
               ld a, h                  ;
1895
 
               ld c, l                  ;
1896
 
               ld de, (BASIC_ARG+2)     ;
1897
 
               call MATH.DIV.16         ;
1898
 
               ld h, a                  ;
1899
 
               ld l, c                  ;
1900
 
               ld (BASIC_DAC+2), hl     ; quotient
1901
 
               jp MATH.PARM.PUSH        ;
1902
 
 
1903
 
endif
1904
 
 
1905
 
if defined MATH.POW
1906
 
 
1907
 
MATH.POW.INT:  ld (BASIC_VALTYP), a     ;
1908
 
               __call_bios MATH_FRCDBL  ; convert DAC to double
1909
 
               call SWAP.DAC.ARG        ;
1910
 
               ld a, 2                  ;
1911
 
               ld (BASIC_VALTYP), a     ;
1912
 
               __call_bios MATH_FRCDBL  ; convert ARG to double
1913
 
               call SWAP.DAC.ARG        ;
1914
 
MATH.POW.SGL:  ld a, 8                  ;
1915
 
               ld (BASIC_VALTYP), a     ;
1916
 
MATH.POW.DBL:  __call_bios MATH_DBLEXP  ;
1917
 
               jp MATH.PARM.PUSH        ;
1918
 
 
1919
 
endif
1920
 
 
1921
 
if defined MATH.MOD
1922
 
 
1923
 
;MATH.MOD.SGL:  ld a, 8                  ;
1924
 
;               ld (BASIC_VALTYP), a     ;
1925
 
;MATH.MOD.DBL:  __call_bios MATH_FRCINT  ; convert DAC to integer
1926
 
;               call SWAP.DAC.ARG        ;
1927
 
;                        ld a, 8                  ;
1928
 
;               ld (BASIC_VALTYP), a     ;
1929
 
;               __call_bios MATH_FRCINT  ; convert ARG to integer
1930
 
;               call SWAP.DAC.ARG        ;
1931
 
MATH.MOD.INT:  ld hl, (BASIC_DAC+2)     ;
1932
 
               ld a, h                  ;
1933
 
               ld c, l                  ;
1934
 
               ld de, (BASIC_ARG+2)     ;
1935
 
               call MATH.DIV.16         ;
1936
 
               ld (BASIC_DAC+2), hl     ; remainder
1937
 
               jp MATH.PARM.PUSH        ;
1938
 
 
1939
 
endif
1940
 
 
1941
 
if defined ISQR
1942
 
 
1943
 
; fast 16-bit integer square root
1944
 
; http://www.retroprogramming.com/2017/07/a-fast-z80-integer-square-root.html
1945
 
; 92 bytes, 344-379 cycles (average 362)
1946
 
; v2 - 3 t-state optimization spotted by Russ McNulty
1947
 
; call with hl = number to square root
1948
 
; returns    a = square root
1949
 
; corrupts  hl, de
1950
 
 
1951
 
MATH.INT.SQR:
1952
 
  ld a,h
1953
 
  ld de,0B0C0h
1954
 
  add a,e
1955
 
  jr c,sq7
1956
 
  ld a,h
1957
 
  ld d,0F0h
1958
 
sq7:
1959
 
  add a,d
1960
 
  jr nc,sq6
1961
 
  res 5,d
1962
 
  db 254
1963
 
sq6:
1964
 
  sub d
1965
 
  sra d
1966
 
  set 2,d
1967
 
  add a,d
1968
 
  jr nc,sq5
1969
 
  res 3,d
1970
 
  db 254
1971
 
sq5:
1972
 
  sub d
1973
 
  sra d
1974
 
  inc d
1975
 
  add a,d
1976
 
  jr nc,sq4
1977
 
  res 1,d
1978
 
  db 254
1979
 
sq4:
1980
 
  sub d
1981
 
  sra d
1982
 
  ld h,a
1983
 
  add hl,de
1984
 
  jr nc,sq3
1985
 
  ld e,040h
1986
 
  db 210
1987
 
sq3:
1988
 
  sbc hl,de
1989
 
  sra d
1990
 
  ld a,e
1991
 
  rra
1992
 
  or 010h
1993
 
  ld e,a
1994
 
  add hl,de
1995
 
  jr nc,sq2
1996
 
  and 0DFh
1997
 
  db 218
1998
 
sq2:
1999
 
  sbc hl,de
2000
 
  sra d
2001
 
  rra
2002
 
  or 04h
2003
 
  ld e,a
2004
 
  add hl,de
2005
 
  jr nc,sq1
2006
 
  and 0F7h
2007
 
  db 218
2008
 
sq1:
2009
 
  sbc hl,de
2010
 
  sra d
2011
 
  rra
2012
 
  inc a
2013
 
  ld e,a
2014
 
  add hl,de
2015
 
  jr nc,sq0
2016
 
  and 0FDh
2017
 
sq0:
2018
 
  sra d
2019
 
  rra
2020
 
  cpl
2021
 
  ret
2022
 
 
2023
 
endif
2024
 
 
2025
 
if defined RANDOMIZE or defined SEED
2026
 
 
2027
 
MATH.RANDOMIZE:    di                          ;
2028
 
                     ld bc, (BIOS_JIFFY)       ;
2029
 
                   ei                          ;
2030
 
 
2031
 
MATH.SEED:         ld (BASIC_RNDX), bc         ; seed to IRND
2032
 
                   push bc                     ; in bc = new integer seed
2033
 
                     call CLEAR.DAC            ;
2034
 
                   pop bc                      ;
2035
 
                   ;ld ix, BASIC_DAC            ;
2036
 
                   ld (BASIC_DAC+2), bc        ; copy bc to dac
2037
 
                   ld a, 2                     ; type integer
2038
 
                   ld (BASIC_VALTYP), a        ;
2039
 
                   __call_bios MATH_FRCDBL     ; convert DAC integer to DAC double
2040
 
                   __call_bios MATH_NEG        ; DAC = -DAC
2041
 
                   __call_bios MATH_RND        ; put in DAC a new random number from previous DAC parameter
2042
 
                   ret                         ;
2043
 
 
2044
 
endif
2045
 
 
2046
 
MATH.ERROR:        ld e, 13                          ; type mismatch
2047
 
                   __call_basic BASIC_ERROR_HANDLER  ;
2048
 
                   ret
2049
 
 
2050
 
 
2051
 
;---------------------------------------------------------------------------------------------------------
2052
 
; BOOLEAN ROUTINES
2053
 
;---------------------------------------------------------------------------------------------------------
2054
 
 
2055
 
BOOLEAN.RET.TRUE:  ld hl, LIT_TRUE             ;
2056
 
                   ret.parm                    ;
2057
 
BOOLEAN.RET.FALSE: ld hl, LIT_FALSE            ;
2058
 
                   ret.parm                    ;
2059
 
BOOLEAN.CMP.INT:   ld hl, (BASIC_DAC+2)        ;
2060
 
                   ld de, (BASIC_ARG+2)        ;
2061
 
                   __call_bios MATH_ICOMP      ;
2062
 
                   ret                         ;
2063
 
BOOLEAN.CMP.SGL:   ld bc, (BASIC_ARG)          ;
2064
 
                   ld de, (BASIC_ARG+2)        ;
2065
 
                   __call_bios MATH_DCOMP      ;
2066
 
                   ret                         ;
2067
 
BOOLEAN.CMP.DBL:   __call_bios MATH_XDCOMP     ;
2068
 
                   ret                         ;
2069
 
BOOLEAN.CMP.STR:   call STRING.COMPARE         ;
2070
 
                   ret                         ;
2071
 
 
2072
 
if defined BOOLEAN.GT
2073
 
 
2074
 
BOOLEAN.GT.INT:    call BOOLEAN.CMP.INT        ;
2075
 
                   jr BOOLEAN.GT.RET           ;
2076
 
BOOLEAN.GT.STR:    call BOOLEAN.CMP.STR        ;
2077
 
                   jr BOOLEAN.GT.RET           ;
2078
 
BOOLEAN.GT.SGL:    call BOOLEAN.CMP.SGL        ;
2079
 
                   jr BOOLEAN.GT.RET           ;
2080
 
BOOLEAN.GT.DBL:    call BOOLEAN.CMP.DBL        ;
2081
 
                   jr BOOLEAN.GT.RET           ;
2082
 
BOOLEAN.GT.RET:    cp 0x01                     ;
2083
 
                   jp z, BOOLEAN.RET.TRUE      ;
2084
 
                   jp BOOLEAN.RET.FALSE        ;
2085
 
endif
2086
 
 
2087
 
if defined BOOLEAN.LT
2088
 
 
2089
 
BOOLEAN.LT.INT:    call BOOLEAN.CMP.INT        ;
2090
 
                   jr BOOLEAN.LT.RET           ;
2091
 
BOOLEAN.LT.STR:    call BOOLEAN.CMP.STR        ;
2092
 
                   jr BOOLEAN.LT.RET           ;
2093
 
BOOLEAN.LT.SGL:    call BOOLEAN.CMP.SGL        ;
2094
 
                   jr BOOLEAN.LT.RET           ;
2095
 
BOOLEAN.LT.DBL:    call BOOLEAN.CMP.DBL        ;
2096
 
                   jr BOOLEAN.LT.RET           ;
2097
 
BOOLEAN.LT.RET:    cp 0xFF                     ;
2098
 
                   jp z, BOOLEAN.RET.TRUE      ;
2099
 
                   jp BOOLEAN.RET.FALSE        ;
2100
 
 
2101
 
endif
2102
 
 
2103
 
if defined BOOLEAN.GE
2104
 
 
2105
 
BOOLEAN.GE.INT:    call BOOLEAN.CMP.INT        ;
2106
 
                   jr BOOLEAN.GE.RET           ;
2107
 
BOOLEAN.GE.STR:    call BOOLEAN.CMP.STR        ;
2108
 
                   jr BOOLEAN.GE.RET           ;
2109
 
BOOLEAN.GE.SGL:    call BOOLEAN.CMP.SGL        ;
2110
 
                   jr BOOLEAN.GE.RET           ;
2111
 
BOOLEAN.GE.DBL:    call BOOLEAN.CMP.DBL        ;
2112
 
                   jr BOOLEAN.GE.RET           ;
2113
 
BOOLEAN.GE.RET:    cp 0x01                     ;
2114
 
                   jp z, BOOLEAN.RET.TRUE      ;
2115
 
                   or a                        ; cp 0
2116
 
                   jp z, BOOLEAN.RET.TRUE      ;
2117
 
                   jp BOOLEAN.RET.FALSE        ;
2118
 
 
2119
 
endif
2120
 
 
2121
 
if defined BOOLEAN.LE
2122
 
 
2123
 
BOOLEAN.LE.INT:    call BOOLEAN.CMP.INT        ;
2124
 
                   jr BOOLEAN.LE.RET           ;
2125
 
BOOLEAN.LE.STR:    call BOOLEAN.CMP.STR        ;
2126
 
                   jr BOOLEAN.LE.RET           ;
2127
 
BOOLEAN.LE.SGL:    call BOOLEAN.CMP.SGL        ;
2128
 
                   jr BOOLEAN.LE.RET           ;
2129
 
BOOLEAN.LE.DBL:    call BOOLEAN.CMP.DBL        ;
2130
 
                   jr BOOLEAN.LE.RET           ;
2131
 
BOOLEAN.LE.RET:    cp 0xFF                     ;
2132
 
                   jp z, BOOLEAN.RET.TRUE      ;
2133
 
                   or a                        ; cp 0
2134
 
                   jp z, BOOLEAN.RET.TRUE      ;
2135
 
                   jp BOOLEAN.RET.FALSE        ;
2136
 
 
2137
 
endif
2138
 
 
2139
 
if defined BOOLEAN.NE
2140
 
 
2141
 
BOOLEAN.NE.INT:    call BOOLEAN.CMP.INT        ;
2142
 
                   jr BOOLEAN.NE.RET           ;
2143
 
BOOLEAN.NE.STR:    call BOOLEAN.CMP.STR        ;
2144
 
                   jr BOOLEAN.NE.RET           ;
2145
 
BOOLEAN.NE.SGL:    call BOOLEAN.CMP.SGL        ;
2146
 
                   jr BOOLEAN.NE.RET           ;
2147
 
BOOLEAN.NE.DBL:    call BOOLEAN.CMP.DBL        ;
2148
 
                   jr BOOLEAN.NE.RET           ;
2149
 
BOOLEAN.NE.RET:    or a                        ; cp 0
2150
 
                   jp nz, BOOLEAN.RET.TRUE     ;
2151
 
                   jp BOOLEAN.RET.FALSE        ;
2152
 
 
2153
 
endif
2154
 
 
2155
 
if defined BOOLEAN.EQ
2156
 
 
2157
 
BOOLEAN.EQ.INT:    call BOOLEAN.CMP.INT        ;
2158
 
                   jr BOOLEAN.EQ.RET           ;
2159
 
BOOLEAN.EQ.STR:    call BOOLEAN.CMP.STR        ;
2160
 
                   jr BOOLEAN.EQ.RET           ;
2161
 
BOOLEAN.EQ.SGL:    call BOOLEAN.CMP.SGL        ;
2162
 
                   jr BOOLEAN.EQ.RET           ;
2163
 
BOOLEAN.EQ.DBL:    call BOOLEAN.CMP.DBL        ;
2164
 
                   jr BOOLEAN.EQ.RET           ;
2165
 
BOOLEAN.EQ.RET:    or a                        ; cp 0
2166
 
                   jp z, BOOLEAN.RET.TRUE      ;
2167
 
                   jp BOOLEAN.RET.FALSE        ;
2168
 
 
2169
 
endif
2170
 
 
2171
 
if defined BOOLEAN.AND
2172
 
 
2173
 
BOOLEAN.AND.INT:   ld a, (BASIC_DAC+2)         ;
2174
 
                   ld hl, BASIC_ARG+2          ;
2175
 
                   and (hl)                    ;
2176
 
                   ld (BASIC_DAC+2), a         ;
2177
 
                   inc hl                      ;
2178
 
                   ld a, (BASIC_DAC+3)         ;
2179
 
                   and (hl)                    ;
2180
 
                   ld (BASIC_DAC+3), a         ;
2181
 
                   ld a, 2                     ;
2182
 
                   jp MATH.PARM.PUSH           ;
2183
 
 
2184
 
endif
2185
 
 
2186
 
if defined BOOLEAN.OR
2187
 
 
2188
 
BOOLEAN.OR.INT:    ld a, (BASIC_DAC+2)         ;
2189
 
                   ld hl, BASIC_ARG+2          ;
2190
 
                   or (hl)                     ;
2191
 
                   ld (BASIC_DAC+2), a         ;
2192
 
                   inc hl                      ;
2193
 
                   ld a, (BASIC_DAC+3)         ;
2194
 
                   or (hl)                     ;
2195
 
                   ld (BASIC_DAC+3), a         ;
2196
 
                   ld a, 2                     ;
2197
 
                   jp MATH.PARM.PUSH           ;
2198
 
 
2199
 
endif
2200
 
 
2201
 
if defined BOOLEAN.XOR
2202
 
 
2203
 
BOOLEAN.XOR.INT:   ld a, (BASIC_DAC+2)         ;
2204
 
                   ld hl, BASIC_ARG+2          ;
2205
 
                   xor (hl)                    ;
2206
 
                   ld (BASIC_DAC+2), a         ;
2207
 
                   inc hl                      ;
2208
 
                   ld a, (BASIC_DAC+3)         ;
2209
 
                   xor (hl)                    ;
2210
 
                   ld (BASIC_DAC+3), a         ;
2211
 
                   ld a, 2                     ;
2212
 
                   jp MATH.PARM.PUSH           ;
2213
 
 
2214
 
endif
2215
 
 
2216
 
if defined BOOLEAN.EQV
2217
 
 
2218
 
BOOLEAN.EQV.INT:   ld a, (BASIC_DAC+2)         ;
2219
 
                   ld hl, BASIC_ARG+2          ;
2220
 
                   xor (hl)                    ;
2221
 
                   cpl                         ;
2222
 
                   ld (BASIC_DAC+2), a         ;
2223
 
                   inc hl                      ;
2224
 
                   ld a, (BASIC_DAC+3)         ;
2225
 
                   xor (hl)                    ;
2226
 
                   cpl                         ;
2227
 
                   ld (BASIC_DAC+3), a         ;
2228
 
                   ld a, 2                     ;
2229
 
                   jp MATH.PARM.PUSH           ;
2230
 
 
2231
 
endif
2232
 
 
2233
 
if defined BOOLEAN.IMP
2234
 
 
2235
 
BOOLEAN.IMP.INT:   ld a, (BASIC_DAC+2)         ;
2236
 
                   ld hl, BASIC_ARG+2          ;
2237
 
                   cpl                         ;
2238
 
                   or (hl)                     ;
2239
 
                   ld (BASIC_DAC+2), a         ;
2240
 
                   inc hl                      ;
2241
 
                   ld a, (BASIC_DAC+3)         ;
2242
 
                   cpl                         ;
2243
 
                   or (hl)                     ;
2244
 
                   ld (BASIC_DAC+3), a         ;
2245
 
                   ld a, 2                     ;
2246
 
                   jp MATH.PARM.PUSH           ;
2247
 
 
2248
 
endif
2249
 
 
2250
 
if defined BOOLEAN.SHR
2251
 
 
2252
 
BOOLEAN.SHR.INT:   ld ix, BASIC_DAC+2          ; shift DAC integer to right (bits 15...0-->)
2253
 
                   ld a, (BASIC_ARG+2)         ;
2254
 
                   or a                        ; clear carry
2255
 
                   jp z, MATH.PARM.PUSH        ; return if not shift
2256
 
                   ld b, a                     ; shift count
2257
 
BOOLEAN.SHR.INT.N: rr (ix+1)                   ;
2258
 
                   rr (ix)                     ;
2259
 
                   or a                        ; clear carry
2260
 
                   djnz BOOLEAN.SHR.INT.N      ; next shift
2261
 
                   ld a, 2                     ;
2262
 
                   jp MATH.PARM.PUSH           ; return DAC
2263
 
 
2264
 
endif
2265
 
 
2266
 
if defined BOOLEAN.SHL
2267
 
 
2268
 
BOOLEAN.SHL.INT:   ld ix, BASIC_DAC+2          ; shift DAC integer to left (<--bits 15...0)
2269
 
                   ld a, (BASIC_ARG+2)         ;
2270
 
                   or a                        ; clear carry
2271
 
                   jp z, MATH.PARM.PUSH        ; return if not shift
2272
 
                   ld b, a                     ; shift count
2273
 
BOOLEAN.SHL.INT.N: rl (ix)                     ;
2274
 
                   rl (ix+1)                   ;
2275
 
                   or a                        ; clear carry
2276
 
                   djnz BOOLEAN.SHL.INT.N      ; next shift
2277
 
                   ld a, 2                     ;
2278
 
                   jp MATH.PARM.PUSH           ; return DAC
2279
 
 
2280
 
endif
2281
 
 
2282
 
if defined BOOLEAN.NOT
2283
 
 
2284
 
BOOLEAN.NOT.INT:   ld a, (BASIC_DAC+2)         ;
2285
 
                   cpl                         ;
2286
 
                   ld (BASIC_DAC+2), a         ;
2287
 
                   ld a, (BASIC_DAC+3)         ;
2288
 
                   cpl                         ;
2289
 
                   ld (BASIC_DAC+3), a         ;
2290
 
                   ld a, 2                     ;
2291
 
                   jp MATH.PARM.PUSH           ;
2292
 
 
2293
 
endif
2294
 
 
2295
 
 
2296
 
 
2297
 
;---------------------------------------------------------------------------------------------------------
2298
 
; MEMORY ALLOCATION ROUTINES
2299
 
;---------------------------------------------------------------------------------------------------------
2300
 
; Adapted from memory allocator code by SamSaga2, Spain, 2015
2301
 
; https://www.msx.org/forum/msx-talk/development/asm-memory-allocator
2302
 
; https://www.msx.org/users/samsaga2
2303
 
;---------------------------------------------------------------------------------------------------------
2304
 
memory.heap_start: equ VAR_STACK.END + 1    ; start at end of variable stack
2305
 
memory.heap_end:   equ 0xF0A0 - 100         ; end at start of work area for stack (100 bytes reserved), BIOS and BASIC interpreter
2306
 
block.next:        equ 0                    ; next free block address
2307
 
block.size:        equ 2                    ; size of block including header
2308
 
block:             equ 4                    ; block.next + block.size
2309
 
 
2310
 
;; init
2311
 
memory.init:
2312
 
       ld ix,memory.heap_start              ; first block
2313
 
       ld hl,memory.heap_start+block        ; second block
2314
 
       ;; first block NEXT=secondblock, SIZE=0
2315
 
       ;; with this block we have a fixed start location
2316
 
       ;; because never will be allocated
2317
 
       ld (ix+block.next),l
2318
 
       ld (ix+block.next+1),h
2319
 
       ld (ix+block.size),0
2320
 
       ld (ix+block.size+1),0
2321
 
       ;; second block NEXT=0, SIZE=all
2322
 
       ;; the first and only free block have all available memory
2323
 
       ld (ix+block.next+block),0
2324
 
       ld (ix+block.next+block+1),0
2325
 
       xor a
2326
 
       ;ld hl,memory.heap_end          ; size = @heap_end (stack) - heap_start - block_header * 2 - 100 (buffer for stack)
2327
 
           ld (BIOS_TEMP), sp
2328
 
           ld hl, (BIOS_TEMP)
2329
 
       ld de, memory.heap_start + (block * 2) + 100
2330
 
       sbc hl,de
2331
 
           ;ld de, block * 2 + 100
2332
 
           ;sbc hl, de
2333
 
       ld (ix+block.size+block),l
2334
 
       ld (ix+block.size+block+1),h
2335
 
       ret
2336
 
 
2337
 
;; alloc
2338
 
;; IN BC=size, OUT IX=memptr, NZ=ok
2339
 
memory.alloc:
2340
 
       ld hl,block
2341
 
       add hl,bc
2342
 
       ;push hl
2343
 
       ;pop bc
2344
 
           ld b, h
2345
 
           ld c, l
2346
 
       ld ix,memory.heap_start       ; this
2347
 
       ld iy,0                       ; prev
2348
 
memory.alloc.find:
2349
 
       ld l,(ix+block.size)
2350
 
       ld h,(ix+block.size+1)
2351
 
       xor a
2352
 
       sbc hl,bc
2353
 
       jp z, memory.alloc.exactfit
2354
 
       jp c, memory.alloc.nextblock
2355
 
;; split found block
2356
 
memory.alloc.splitfit:
2357
 
       ;; free space must allow at least two blocks headers (current + next)
2358
 
           or h
2359
 
           jr nz, memory.alloc.splitfit.do   ; if free space > 0xFF, do split
2360
 
             ld a, l
2361
 
             cp 4
2362
 
             jr c, memory.alloc.nextblock    ; if free space < 4, skip to next block
2363
 
memory.alloc.splitfit.do:
2364
 
       ;; newfreeblock = this + BC
2365
 
       push ix
2366
 
       pop hl
2367
 
       add hl,bc
2368
 
       ;; prevblock->next = newfreeblock
2369
 
       ld (iy+block.next),l
2370
 
       ld (iy+block.next+1),h
2371
 
       ;; newfreeblock->next = this->next
2372
 
       push hl
2373
 
       pop iy                        ; iy = newfreeblock
2374
 
       ld l,(ix+block.next)
2375
 
       ld h,(ix+block.next+1)
2376
 
       ld (iy+block.next),l
2377
 
       ld (iy+block.next+1),h
2378
 
       ;; newfreeblock->size = this->size - BC
2379
 
       ld l,(ix+block.size)
2380
 
       ld h,(ix+block.size+1)
2381
 
       xor a
2382
 
       sbc hl,bc
2383
 
       ld (iy+block.size),l
2384
 
       ld (iy+block.size+1),h
2385
 
       ;; this->size = BC
2386
 
       ld (ix+block.size),c
2387
 
       ld (ix+block.size+1),b
2388
 
       jr memory.alloc.ok
2389
 
;; use whole found block
2390
 
memory.alloc.exactfit:
2391
 
       ;; prevblock->next = this->next - remove block from free list
2392
 
       ld l,(ix+block.next)
2393
 
       ld h,(ix+block.next+1)
2394
 
       ld (iy+block.next),l
2395
 
       ld (iy+block.next+1),h
2396
 
memory.alloc.ok:
2397
 
       ;; ix = first byte
2398
 
       ld de,block
2399
 
       add ix,de
2400
 
       ;; enable z-flag
2401
 
       ld a,1
2402
 
       or a
2403
 
       ret
2404
 
memory.alloc.nextblock:
2405
 
       ld l,(ix+block.next)
2406
 
       ld h,(ix+block.next+1)
2407
 
       ld a,l
2408
 
       cp h
2409
 
       ret z
2410
 
         ;; prevblock = this
2411
 
         push ix
2412
 
         pop iy
2413
 
         ;; this = this->next
2414
 
         push hl
2415
 
         pop ix
2416
 
         jp memory.alloc.find
2417
 
 
2418
 
;; free
2419
 
;; IN IX=memptr
2420
 
memory.free:
2421
 
       ;; HL = IX - block_header_size
2422
 
       push ix
2423
 
       pop hl
2424
 
       ld de, block
2425
 
           xor a
2426
 
       sbc hl,de
2427
 
       ;; start of search
2428
 
       ld ix,memory.heap_start
2429
 
memory.free.find:
2430
 
       ld e,(ix+block.next)
2431
 
       ld d,(ix+block.next+1)
2432
 
       ld a,d
2433
 
       or e
2434
 
       jp z, memory.free.passedend
2435
 
         sbc hl,de                     ; test this (HL) against next (DE)
2436
 
         jr c, memory.free.found       ; if DE > HL
2437
 
           add hl,de                     ; restore hl value
2438
 
               push de
2439
 
               pop ix                        ; current = next
2440
 
           jr memory.free.find
2441
 
 
2442
 
;; ix=prev, hl=this, de=next
2443
 
memory.free.found:
2444
 
       add hl,de                     ; restore hl value
2445
 
           ld (ix+block.next), l
2446
 
           ld (ix+block.next+1), h       ; prev->next = this
2447
 
           push hl
2448
 
           pop iy
2449
 
           ld (iy+block.next), e
2450
 
           ld (iy+block.next+1), d       ; this->next = next
2451
 
           push ix                                           ; prev x this
2452
 
           pop iy
2453
 
           push hl
2454
 
           pop ix
2455
 
           push de
2456
 
             call memory.free.coalesce
2457
 
           pop ix                        ; this x next
2458
 
       jr memory.free.coalesce
2459
 
 
2460
 
;; parm1 = *next
2461
 
;; parm2 = *this
2462
 
memory.free.coalesce:
2463
 
           ld c, (iy+block.size)
2464
 
           ld b, (iy+block.size+1)  ; bc = this->size
2465
 
       push iy
2466
 
           pop hl
2467
 
           xor a
2468
 
           adc hl, bc     ; hl = this + this->size
2469
 
           push ix
2470
 
           pop de
2471
 
           xor a
2472
 
           sbc hl, de     ; if this + this->size == next, then this->size += next->size, this->next = next->next
2473
 
           jr z, memory.free.coalesce.do
2474
 
             push ix                ; else, new *this = *next
2475
 
         pop iy
2476
 
                 ret
2477
 
memory.free.coalesce.do:
2478
 
       ld l, (ix+block.size)
2479
 
           ld h, (ix+block.size+1)  ; hl = next->size
2480
 
           xor a
2481
 
           adc hl, bc               ; hl += this->size
2482
 
           ld (iy+block.size), l
2483
 
           ld (iy+block.size+1), h  ; this->size = hl
2484
 
           ld l, (ix+block.next)
2485
 
           ld h, (ix+block.next+1)  ; hl = next->next
2486
 
       ld (iy+block.next), l
2487
 
           ld (iy+block.next+1), h  ; this->next = hl
2488
 
           ret
2489
 
 
2490
 
memory.free.passedend:
2491
 
       ;; append block at the end of the free list
2492
 
       ld (ix+block.next),l
2493
 
       ld (ix+block.next+1),h
2494
 
       push hl
2495
 
       pop iy
2496
 
       ld (iy+block.next),0
2497
 
       ld (iy+block.next+1),0
2498
 
           ret
2499
 
 
2500
 
;; get_free
2501
 
;; OUT BC=freespace
2502
 
memory.get_free:
2503
 
       ld ix,memory.heap_start
2504
 
       ld bc,0
2505
 
memory.get_free.count:
2506
 
       ld a,c
2507
 
       add a,(ix+block.size)
2508
 
       ld c,a
2509
 
       ld a,b
2510
 
       adc a,(ix+block.size+1)
2511
 
       ld b,a
2512
 
       ld l,(ix+block.next)
2513
 
       ld h,(ix+block.next+1)
2514
 
       ld a,h
2515
 
       or l
2516
 
       ret z
2517
 
       push hl
2518
 
       pop ix
2519
 
       jr memory.get_free.count
2520
 
 
2521
 
memory.error:  ld e, 7                           ; out of memory
2522
 
               __call_basic BASIC_ERROR_HANDLER  ;
2523
 
               ret
2524
 
 
2525
 
 
2526
 
 
2527
 
;---------------------------------------------------------------------------------------------------------
2528
 
; GRAPHICS LIBRARY
2529
 
; By: Amaury Carvalho, 2019
2530
 
;---------------------------------------------------------------------------------------------------------
2531
 
; References:
2532
 
; https://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm#Algorithm_for_integer_arithmetic
2533
 
; https://en.wikipedia.org/wiki/Midpoint_circle_algorithm
2534
 
; https://rosettacode.org/wiki/Bitmap/Midpoint_circle_algorithm#C
2535
 
; https://www.msx.org/wiki/MSX-BASIC_Instructions
2536
 
;---------------------------------------------------------------------------------------------------------
2537
 
 
2538
 
;---------------------------------------------------------------------------------------------------------
2539
 
; Bios functions
2540
 
;---------------------------------------------------------------------------------------------------------
2541
 
 
2542
 
BIOS_WRTVDP:  EQU 0x0047
2543
 
BIOS_RDVRM:   EQU 0x004A
2544
 
BIOS_WRTVRM:  EQU 0x004D
2545
 
BIOS_LDIRVM:  EQU 0x005C
2546
 
BIOS_LDIRMV:  EQU 0x0059
2547
 
BIOS_PNTINI:  EQU 0x18CF
2548
 
BIOS_RIGHTC:  EQU 0x16C5 ; Move current pixel physical address right
2549
 
BIOS_TRIGHTC: EQU 0x16AC ; Test then RIGHTC if legal
2550
 
BIOS_LEFTC:   EQU 0x16EE ; Move current pixel physical address left
2551
 
BIOS_TLEFTC:  EQU 0x16D8 ; Test then LEFTC if legal
2552
 
BIOS_UPC:     EQU 0x175D ; Move current pixel physical address up
2553
 
BIOS_TUPC:    EQU 0x173C ; Test then UPC if legal
2554
 
BIOS_DOWNC:   EQU 0x172A ; Move current pixel physical address down
2555
 
BIOS_TDOWNC:  EQU 0x170A ; Test then DOWNC if legal
2556
 
BIOS_DCOMPR:  EQU 0x146A ; compare HL and DE (Flag NC if HL>DE, Flag Z if HL=DE, Flag C if HL<DE)
2557
 
BIOS_FILVRM:  EQU 0x0056 ; fill VRAM with value
2558
 
 
2559
 
BIOS_BIGFIL:  EQU 0x016B ; msx 2
2560
 
BIOS_NRDVRM:  EQU 0x0174 ; msx 2
2561
 
BIOS_NWRVRM:  EQU 0x0177 ; msx 2
2562
 
BIOS_NRDVDP:  EQU 0x013E ; msx 2
2563
 
BIOS_VDPSTA:  EQU 0x0131 ; msx 2
2564
 
BIOS_NWRVDP:  EQU 0x012D ; msx 2 (0x0647)
2565
 
 
2566
 
BASIC_SUB_LINE:           equ 0x58fc
2567
 
BASIC_SUB_LINEBOX:        equ 0x5912
2568
 
BASIC_SUB_LINEBOXFILLED:  equ 0x58C1
2569
 
BASIC_SUB_CIRCLE:         equ 0x5B19
2570
 
BASIC_SUB_PAINT1:         equ 0x59DA   ;0x59C8
2571
 
BASIC_SUB_PAINT2:         equ 0x0069   ;0x2664   ;0x2651+3
2572
 
 
2573
 
;---------------------------------------------------------------------------------------------------------
2574
 
; Work areas
2575
 
;---------------------------------------------------------------------------------------------------------
2576
 
 
2577
 
BIOS_RG0SAV: EQU 0xF3DF
2578
 
BIOS_RG1SAV: EQU 0xF3E0
2579
 
BIOS_RG8SAV: EQU 0xFFE7
2580
 
BIOS_BDRATR: EQU 0xFCB2
2581
 
BIOS_STATFL: EQU 0xF3E7  ; VDP status register
2582
 
 
2583
 
BIOS_CXOFF:  EQU 0xF945
2584
 
BIOS_CYOFF:  EQU 0xF947
2585
 
BIOS_GXPOS:  EQU 0xFCB3
2586
 
BIOS_GYPOS:  EQU 0xFCB5
2587
 
 
2588
 
BIOS_GRPNAM: EQU 0xF3C7  ; pattern name table
2589
 
BIOS_GRPCOL: EQU 0xF3C9  ; colour table
2590
 
BIOS_GRPCGP: EQU 0xF3CB  ; pattern generator table
2591
 
BIOS_GRPATR: EQU 0xF3CD  ; sprite attribute table
2592
 
BIOS_GRPPAT: EQU 0xF3CF  ; sprite generator table
2593
 
BIOS_CGPNT:  EQU 0xF920  ; 2 - current MSX Font location (0x1BBF)
2594
 
BIOS_ATRBAS: EQU 0xF928  ; sprite attribute table
2595
 
 
2596
 
BIOS_MLTNAM: EQU 0xF3D1  ; pattern name table (screen 3, multicolor)
2597
 
BIOS_MLTCOL: EQU 0xF3D3  ; colour table (screen 3, multicolor)
2598
 
BIOS_MLTCGP: EQU 0xF3D5  ; pattern generator table (screen 3, multicolor)
2599
 
BIOS_MLTATR: EQU 0xF3D7  ; sprite attribute table (screen 3, multicolor)
2600
 
BIOS_MLTPAT: EQU 0xF3D9  ; sprite generator table (screen 3, multicolor)
2601
 
 
2602
 
BIOS_ASPECT:       equ 0xF931   ;2      Aspect ratio of the circle; set by <ratio> of CIRCLE.
2603
 
BIOS_CENCNT:       equ 0xF933   ;2  Counter used by CIRCLE.
2604
 
BIOS_CLINEF:       equ 0xF935   ;1      Flag to draw line to centre, Used set by CIRCLE
2605
 
BIOS_CNPNTS:       equ 0xF936   ;2      Point to be plottted in a 45° segment, Used set by CIRCLE
2606
 
BIOS_CPLOTF:       equ 0xF938   ;1      Plot polarity flag, Used set by CIRCLE
2607
 
BIOS_CPCNT:        equ 0xF939   ;2      Number of points in 1/8 of circle, Used set by CIRCLE.
2608
 
BIOS_CPCNT8:       equ 0xF93B   ;2      Number of points in the circle. Used by CIRCLE.
2609
 
BIOS_CRCSUM:       equ 0xF93D   ;2      Cyclic redundancy check sum of the circle. Used by CIRCLE.
2610
 
BIOS_CSTCNT:       equ 0xF93F   ;2      Variable to maintain the number of points of the starting angle. Used by the instruction CIRCLE
2611
 
BIOS_CSCLXY:       equ 0xF941   ;1      Scale of X & Y. Used by the instruction CIRCLE
2612
 
BIOS_ASPCT1:       equ 0xF40B   ;2      256/aspect ratio for Basic instruction CIRCLE.
2613
 
BIOS_ASPCT2:       equ 0xF40D   ;2      256*aspect ratio for Basic instruction CIRCLE.
2614
 
BIOS_MAXUPD:       equ 0xF3EC   ;3      Work area used by the instruction CIRCLE, contains JP 0000h at start.
2615
 
BIOS_MINUPD:       equ 0xF3EF   ;3      Work area used by the instruction CIRCLE, contains JP 0000h at start.
2616
 
 
2617
 
BIOS_PARM1:  EQU 0xF6E8 ; 100
2618
 
BIOS_PARM2:  EQU 0xF750 ; 100
2619
 
 
2620
 
GFX_TEMP:   EQU BIOS_PARM1     ; 2
2621
 
GFX_TEMP1:  EQU GFX_TEMP  + 2  ; 2
2622
 
GFX_TEMP2:  EQU GFX_TEMP1 + 2  ; 2
2623
 
GFX_TEMP3:  EQU GFX_TEMP2 + 2  ; 2
2624
 
GFX_TEMP4:  EQU GFX_TEMP3 + 2  ; 2
2625
 
GFX_TEMP5:  EQU GFX_TEMP4 + 2  ; 2
2626
 
GFX_TEMP6:  EQU GFX_TEMP5 + 2  ; 2
2627
 
GFX_TEMP7:  EQU GFX_TEMP6 + 2  ; 2
2628
 
GFX_TEMP8:  EQU GFX_TEMP7 + 2  ; 2
2629
 
GFX_TEMP9:  EQU GFX_TEMP8 + 2  ; 2
2630
 
 
2631
 
GFX_MAX_X:           EQU 0xFCA4  ; 1 (CASSETE LOWLIM)
2632
 
GFX_MAX_Y:           EQU 0xFCA5  ; 1 (CASSETE WINWID)
2633
 
 
2634
 
GFX_SPRITE_FLAGS:        EQU 0xF40A  ; 1 (CASSETE HEADER) - bits 0=check screen limits, 1=check walls, 2=check hotspots,
2635
 
                                     ;                           3=limit touched, 4=wall touched, 5=hotspot touched, 6=collided
2636
 
GFX_SPRITE_SIZE_DAT:     EQU 0xF3FC  ; 1 (CASSETE CS1200)
2637
 
GFX_SPRITE_SIZE_SCR:     EQU 0xF3FD  ; 1
2638
 
GFX_SPRITE_WALLS:        EQU 0xF406  ; 2 (CASSETE LOW)
2639
 
GFX_SPRITE_HOTSPOTS:     EQU 0xF408  ; 2 (CASSETE HIGH)
2640
 
GFX_SPRITE_HOTSPOT_TILE: EQU 0xF405  ; 1 (CASSETE CS2400)
2641
 
GFX_SPRITE_COLLIDER:     EQU 0xF400  ; 1 (CASSETE CS1200)
2642
 
GFX_SPRITE_COLLISION:    EQU 0xF7B5  ; 2 (ARYTA2)
2643
 
 
2644
 
GFX_MUSIC_START:         EQU 0xF401  ; 2 (CASSETE CS2400)
2645
 
GFX_MUSIC_NEXT:          EQU 0xF403  ; 2
2646
 
GFX_MUSIC_PREV:          EQU 0xF74C  ; 2 (PRMPRV)
2647
 
 
2648
 
GFX_TEMP10:              EQU 0xF3FE  ; 2 (CASSETE CS1200)
2649
 
 
2650
 
;BIOS_SCR_SIZE_X: dw 240, 256, 256, 64, 256, 256, 512, 512, 256, 512, 256, 256, 256
2651
 
;BIOS_SCR_SIZE_Y: dw 192, 192, 192, 48, 192, 212, 212, 212, 212, 384, 212, 212, 212
2652
 
BIOS_SCR_SIZE_X: db 239, 255, 255, 63, 255, 255, 255, 255, 255, 255, 255, 255, 255
2653
 
BIOS_SCR_SIZE_Y: db 191, 191, 191, 47, 191, 211, 211, 211, 211, 255, 211, 211, 211
2654
 
 
2655
 
 
2656
 
;---------------------------------------------------------------------------------------------------------
2657
 
; gfxIsScreenModeMSX2
2658
 
; return if screen mode is from MSX 2
2659
 
; out C is set, if MSX2 and screen mode above 3
2660
 
;---------------------------------------------------------------------------------------------------------
2661
 
 
2662
 
gfxIsScreenModeMSX2:
2663
 
  ld a, (BIOS_VERSION)
2664
 
  or 0
2665
 
  jp nz, BIOS_CHKNEW  ; if not MSX1, jump to CHKNEW
2666
 
  scf
2667
 
  ret
2668
 
 
2669
 
;---------------------------------------------------------------------------------------------------------
2670
 
; gfxSetScreenMode
2671
 
; set current screen mode
2672
 
; in A = screen number
2673
 
;---------------------------------------------------------------------------------------------------------
2674
 
 
2675
 
gfxSetScreenMode:
2676
 
  push af
2677
 
    call gfxInitScreenWorkspace
2678
 
    xor a
2679
 
    ld a, (BIOS_VERSION)
2680
 
    or 0
2681
 
    jr nz, gfxSetScreenMode.1  ; if not MSX1, jump
2682
 
  pop af
2683
 
  cp 4
2684
 
  call nc, gfxSetScreenMode.0  ; if screen mode >= 4, change to screen 2
2685
 
  __call_bios BIOS_CHGMOD      ; change the screen mode (msx1)
2686
 
  jr gfxSetScreenMode.2
2687
 
 
2688
 
gfxSetScreenMode.0:
2689
 
  ld a, 2
2690
 
  ret
2691
 
 
2692
 
gfxSetScreenMode.1:
2693
 
  pop af
2694
 
  ld ix, BIOS_CHGMOD2          ; change the screen mode (msx2)
2695
 
  call BIOS_EXTROM
2696
 
 
2697
 
gfxSetScreenMode.2:
2698
 
  call gfxGetScreenHeight
2699
 
  call gfxGetScreenWidth
2700
 
  call gfxGetSpriteSize
2701
 
  jp gfxFillSpriteCollisionTable
2702
 
 
2703
 
gfxInitScreenWorkspace:
2704
 
  ld a, 1
2705
 
  ld (GFX_SPRITE_FLAGS), a     ; bits 0=chk limits, 1=chk walls, 2=chk hotspots, 3=limit touched, 4=wall touched, 5=hotspot touched, 6=collided
2706
 
  xor a
2707
 
  ld (GFX_SPRITE_WALLS), a
2708
 
  ld (GFX_SPRITE_WALLS+1), a
2709
 
  ld (GFX_SPRITE_HOTSPOTS), a
2710
 
  ld (GFX_SPRITE_HOTSPOTS+1), a
2711
 
  ld (GFX_MUSIC_START), a
2712
 
  ld (GFX_MUSIC_START+1), a
2713
 
  ld (GFX_MUSIC_NEXT), a
2714
 
  ld (GFX_MUSIC_NEXT+1), a
2715
 
  ld (GFX_MUSIC_PREV), a
2716
 
  ld (GFX_MUSIC_PREV+1), a
2717
 
  ld (GFX_SPRITE_HOTSPOT_TILE), a
2718
 
  ld (GFX_SPRITE_COLLIDER), a
2719
 
  ret
2720
 
 
2721
 
;---------------------------------------------------------------------------------------------------------
2722
 
; gfxGetScreenMode
2723
 
; return current screen mode
2724
 
; out A = screen number (0=40x24 Text Mode, 1=32x24 Text Mode, 2=Graphics Mode, 3=Multicolour Mode)
2725
 
;---------------------------------------------------------------------------------------------------------
2726
 
 
2727
 
gfxGetScreenMode:
2728
 
  ld a, (BIOS_SCRMOD)
2729
 
  ret
2730
 
 
2731
 
;---------------------------------------------------------------------------------------------------------
2732
 
; gfxSetXY
2733
 
; set current screen location
2734
 
; in BC = x
2735
 
;    DE = y
2736
 
;---------------------------------------------------------------------------------------------------------
2737
 
 
2738
 
gfxSetXY:
2739
 
  ld (BIOS_GRPACX), bc    ; x
2740
 
  ;ld (BIOS_GXPOS), bc
2741
 
  ld (BIOS_GRPACY), de    ; y
2742
 
  ;ld (BIOS_GYPOS), de
2743
 
  jr gfxRefreshXY.1
2744
 
 
2745
 
;---------------------------------------------------------------------------------------------------------
2746
 
; gfxRefreshXY
2747
 
; refresh current screen location
2748
 
;---------------------------------------------------------------------------------------------------------
2749
 
 
2750
 
gfxRefreshXY:
2751
 
  ld bc, (BIOS_GRPACX)    ; x
2752
 
  ld de, (BIOS_GRPACY)    ; y
2753
 
gfxRefreshXY.1:
2754
 
  call gfxIsScreenModeMSX2
2755
 
  jr nc, gfxRefreshXY.2  ; if MSX2 and screen mode above 3
2756
 
    __call_bios BIOS_SCALXY ; BC = X, DE = Y
2757
 
    __call_bios BIOS_MAPXYC ; in BC = X, DE = Y
2758
 
        ret
2759
 
gfxRefreshXY.2:
2760
 
  ld ix, BIOS_SCALXY2 ; BC = X, DE = Y
2761
 
  call BIOS_EXTROM
2762
 
  ld ix, BIOS_MAPXYC2 ; in BC = X, DE = Y
2763
 
  jp BIOS_EXTROM
2764
 
 
2765
 
;---------------------------------------------------------------------------------------------------------
2766
 
; gfxGetXY
2767
 
; get current screen location
2768
 
; out BC = x
2769
 
;     DE = y
2770
 
;---------------------------------------------------------------------------------------------------------
2771
 
 
2772
 
gfxGetXY:
2773
 
  ld bc, (BIOS_GRPACX)    ; x
2774
 
  ld de, (BIOS_GRPACY)    ; y
2775
 
  ret
2776
 
 
2777
 
;---------------------------------------------------------------------------------------------------------
2778
 
; gfxGetScreenHeight
2779
 
; get screen height
2780
 
; out a = screen height
2781
 
;---------------------------------------------------------------------------------------------------------
2782
 
 
2783
 
gfxGetScreenHeight:
2784
 
  push hl
2785
 
  push de
2786
 
    ld hl, BIOS_SCR_SIZE_Y
2787
 
    ld a, (BIOS_SCRMOD)
2788
 
    ld d, 0
2789
 
    ld e, a
2790
 
    add hl, de
2791
 
    ld a, (hl)
2792
 
        ld (GFX_MAX_Y), a
2793
 
  pop de
2794
 
  pop hl
2795
 
  ret
2796
 
 
2797
 
;---------------------------------------------------------------------------------------------------------
2798
 
; gfxGetScreenWidth
2799
 
; get screen width
2800
 
; out a = screen height
2801
 
;---------------------------------------------------------------------------------------------------------
2802
 
 
2803
 
gfxGetScreenWidth:
2804
 
  push hl
2805
 
  push de
2806
 
    ld hl, BIOS_SCR_SIZE_X
2807
 
    ld a, (BIOS_SCRMOD)
2808
 
    ld d, 0
2809
 
    ld e, a
2810
 
    add hl, de
2811
 
    ld a, (hl)
2812
 
        ld (GFX_MAX_X), a
2813
 
  pop de
2814
 
  pop hl
2815
 
  ret
2816
 
 
2817
 
;---------------------------------------------------------------------------------------------------------
2818
 
; gfxGetSpriteSize
2819
 
; get sprite data size
2820
 
; out a = sprite data size
2821
 
;---------------------------------------------------------------------------------------------------------
2822
 
 
2823
 
gfxGetSpriteSize:
2824
 
  push bc
2825
 
    ld bc, 0x0808
2826
 
    ld a, (BIOS_RG1SAV)                 ; bit 0 = double size, bit 1 = sprite size (0=8 pixels, 1=16 pixels)
2827
 
    bit 1, a
2828
 
    jr z, gfxGetSpriteSize.1
2829
 
      ld bc, 0x1010
2830
 
 
2831
 
gfxGetSpriteSize.1:
2832
 
    bit 0, a
2833
 
    jr z, gfxGetSpriteSize.2
2834
 
      sll b
2835
 
 
2836
 
gfxGetSpriteSize.2:
2837
 
    ld (GFX_SPRITE_SIZE_DAT), bc
2838
 
    ld a, c
2839
 
  pop bc
2840
 
  ret
2841
 
 
2842
 
 
2843
 
if defined GFX_FAST and defined PAINT
2844
 
 
2845
 
;---------------------------------------------------------------------------------------------------------
2846
 
; gfxUp
2847
 
; move screen current location up
2848
 
; out: carry if off screen
2849
 
;---------------------------------------------------------------------------------------------------------
2850
 
 
2851
 
gfxUp:
2852
 
  push bc
2853
 
    ld hl, 0
2854
 
        ld de, (BIOS_GRPACY)
2855
 
        or a
2856
 
        sbc hl, de
2857
 
        jr z, gfxUp.1
2858
 
    dec de
2859
 
        ld (BIOS_GRPACY), de
2860
 
    call gfxRefreshXY
2861
 
        scf
2862
 
        ccf
2863
 
        jr gfxUp.2
2864
 
gfxUp.1:
2865
 
        scf
2866
 
gfxUp.2:
2867
 
  pop bc
2868
 
  ret
2869
 
 
2870
 
;---------------------------------------------------------------------------------------------------------
2871
 
; gfxDown
2872
 
; move screen current location down
2873
 
; out: carry if off screen
2874
 
;---------------------------------------------------------------------------------------------------------
2875
 
 
2876
 
gfxDown:
2877
 
  push bc
2878
 
    ld a, (GFX_MAX_Y)
2879
 
    ld l, a
2880
 
    ld h, 0
2881
 
        ld de, (BIOS_GRPACY)
2882
 
        or a
2883
 
    sbc hl, de
2884
 
        jr z, gfxDown.1
2885
 
    inc de
2886
 
        ld (BIOS_GRPACY), de
2887
 
    call gfxRefreshXY
2888
 
        scf
2889
 
        ccf
2890
 
        jr gfxDown.2
2891
 
gfxDown.1:
2892
 
        scf
2893
 
gfxDown.2:
2894
 
  pop bc
2895
 
  ret
2896
 
 
2897
 
;---------------------------------------------------------------------------------------------------------
2898
 
; gfxLeft
2899
 
; move screen current location left
2900
 
; out: carry if off screen
2901
 
;---------------------------------------------------------------------------------------------------------
2902
 
 
2903
 
gfxLeft:
2904
 
  push bc
2905
 
    ld hl, 0
2906
 
        ld de, (BIOS_GRPACX)
2907
 
        or a
2908
 
        sbc hl, de
2909
 
        jr z, gfxLeft.1
2910
 
    dec de
2911
 
        ld (BIOS_GRPACX), de
2912
 
    call gfxRefreshXY
2913
 
        scf
2914
 
        ccf
2915
 
        jr gfxLeft.2
2916
 
gfxLeft.1:
2917
 
        scf
2918
 
gfxLeft.2:
2919
 
  pop bc
2920
 
  ret
2921
 
 
2922
 
;---------------------------------------------------------------------------------------------------------
2923
 
; gfxRight
2924
 
; move screen current location right
2925
 
; out: carry if off screen
2926
 
;---------------------------------------------------------------------------------------------------------
2927
 
 
2928
 
gfxRight:
2929
 
  push bc
2930
 
    ld a, (GFX_MAX_X)
2931
 
    ld l, a
2932
 
    ld h, 0
2933
 
        ld de, (BIOS_GRPACX)
2934
 
        or a
2935
 
    sbc hl, de
2936
 
        jr z, gfxRight.1
2937
 
    inc de
2938
 
        ld (BIOS_GRPACX), de
2939
 
    call gfxRefreshXY
2940
 
        scf
2941
 
        ccf
2942
 
        jr gfxRight.2
2943
 
gfxRight.1:
2944
 
        scf
2945
 
gfxRight.2:
2946
 
  pop bc
2947
 
  ret
2948
 
 
2949
 
endif
2950
 
 
2951
 
;---------------------------------------------------------------------------------------------------------
2952
 
; gfxPushXY
2953
 
; push current screen location
2954
 
;---------------------------------------------------------------------------------------------------------
2955
 
 
2956
 
gfxPushXY:
2957
 
  di
2958
 
    pop  ix
2959
 
    ld iy, (BIOS_GRPACX)    ; x
2960
 
    push iy
2961
 
    ld iy, (BIOS_GRPACY)    ; y
2962
 
    push iy
2963
 
    push ix
2964
 
  ei
2965
 
  ret
2966
 
 
2967
 
;---------------------------------------------------------------------------------------------------------
2968
 
; gfxPopXY
2969
 
; pop current screen location
2970
 
; out BC = x
2971
 
;     DE = y
2972
 
;---------------------------------------------------------------------------------------------------------
2973
 
 
2974
 
gfxPopXY:
2975
 
  pop  ix
2976
 
  pop  de     ; y
2977
 
  pop  bc     ; x
2978
 
  push ix
2979
 
  jp gfxSetXY
2980
 
 
2981
 
;---------------------------------------------------------------------------------------------------------
2982
 
; gfxSetForeColor
2983
 
; set current foreground color
2984
 
; A = color
2985
 
;---------------------------------------------------------------------------------------------------------
2986
 
 
2987
 
gfxSetForeColor:
2988
 
  ld (BIOS_FORCLR), a     ; foreground color
2989
 
  ld (BIOS_ATRBYT), a
2990
 
  ret
2991
 
 
2992
 
;---------------------------------------------------------------------------------------------------------
2993
 
; gfxGetForeColor
2994
 
; get current foreground color
2995
 
; out A = color
2996
 
;---------------------------------------------------------------------------------------------------------
2997
 
 
2998
 
gfxGetForeColor:
2999
 
  ld a, (BIOS_FORCLR)     ; foreground color
3000
 
  ret
3001
 
 
3002
 
;---------------------------------------------------------------------------------------------------------
3003
 
; gfxSetBackColor
3004
 
; set current background color
3005
 
; A = color
3006
 
;---------------------------------------------------------------------------------------------------------
3007
 
 
3008
 
gfxSetBackColor:
3009
 
  ld (BIOS_BAKCLR), a     ; foreground color
3010
 
  ret
3011
 
 
3012
 
;---------------------------------------------------------------------------------------------------------
3013
 
; gfxGetBackColor
3014
 
; get current background color
3015
 
; out A = color
3016
 
;---------------------------------------------------------------------------------------------------------
3017
 
 
3018
 
gfxGetBackColor:
3019
 
  ld a, (BIOS_BAKCLR)     ; foreground color
3020
 
  ret
3021
 
 
3022
 
;---------------------------------------------------------------------------------------------------------
3023
 
; gfxSetBorderColor
3024
 
; set current border color
3025
 
; A = color
3026
 
;---------------------------------------------------------------------------------------------------------
3027
 
 
3028
 
gfxSetBorderColor:
3029
 
  ld (BIOS_BDRCLR), a     ; border color
3030
 
  ret
3031
 
 
3032
 
;---------------------------------------------------------------------------------------------------------
3033
 
; gfxGetBorderColor
3034
 
; get current border color
3035
 
; out A = color
3036
 
;---------------------------------------------------------------------------------------------------------
3037
 
 
3038
 
gfxGetBorderColor:
3039
 
  ld a, (BIOS_BDRCLR)     ; border color
3040
 
  ret
3041
 
 
3042
 
;---------------------------------------------------------------------------------------------------------
3043
 
; gfxSetBorderFill
3044
 
; set fill border color
3045
 
; A = color
3046
 
;---------------------------------------------------------------------------------------------------------
3047
 
 
3048
 
gfxSetBorderFill:
3049
 
  ld (BIOS_BDRATR), a     ; border color
3050
 
  ret
3051
 
 
3052
 
;---------------------------------------------------------------------------------------------------------
3053
 
; gfxGetBorderFill
3054
 
; get fill border color
3055
 
; out A = color
3056
 
;---------------------------------------------------------------------------------------------------------
3057
 
 
3058
 
gfxGetBorderFill:
3059
 
  ld a, (BIOS_BDRATR)     ; border color
3060
 
  ret
3061
 
 
3062
 
;---------------------------------------------------------------------------------------------------------
3063
 
; gfxSetColor
3064
 
; set current color (foreground, background and border)
3065
 
;---------------------------------------------------------------------------------------------------------
3066
 
 
3067
 
gfxSetColor:
3068
 
  ld a, (BIOS_SCRMOD)
3069
 
  bit 3, a
3070
 
  jp nz, BIOS_CHGCLR2 ; change VDP colors - msx2
3071
 
  bit 2, a
3072
 
  jp nz, BIOS_CHGCLR2 ; change VDP colors - msx2
3073
 
  jp BIOS_CHGCLR      ; change VDP colors
3074
 
  ; __call_bios BIOS_SETATR ; change the pixel color
3075
 
  ;ret
3076
 
 
3077
 
;---------------------------------------------------------------------------------------------------------
3078
 
; gfxSetPixel
3079
 
; set pixel in current position to current foreground color
3080
 
;---------------------------------------------------------------------------------------------------------
3081
 
 
3082
 
gfxSetPixel:
3083
 
  call gfxIsScreenModeMSX2
3084
 
  jr nc, gfxSetPixel.1  ; if MSX2 and screen mode above 3
3085
 
    __call_bios BIOS_SETC
3086
 
        ret
3087
 
gfxSetPixel.1:
3088
 
  ld ix, BIOS_SETC2
3089
 
  jp BIOS_EXTROM
3090
 
 
3091
 
;---------------------------------------------------------------------------------------------------------
3092
 
; gfxGetPixel
3093
 
; get pixel color in current position
3094
 
; out A = pixel color
3095
 
;---------------------------------------------------------------------------------------------------------
3096
 
 
3097
 
gfxGetPixel:
3098
 
  call gfxIsScreenModeMSX2
3099
 
  jr nc, gfxGetPixel.1  ; if MSX2 and screen mode above 3
3100
 
    __call_bios BIOS_READC
3101
 
        ret
3102
 
gfxGetPixel.1:
3103
 
  ld ix, BIOS_READC2
3104
 
  jp BIOS_EXTROM
3105
 
 
3106
 
if defined LINE
3107
 
 
3108
 
;---------------------------------------------------------------------------------------------------------
3109
 
; gfxDrawLine
3110
 
; plot a line from current position to informed destination
3111
 
; in BC = destination x
3112
 
;    DE = destination y
3113
 
; https://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm#Algorithm_for_integer_arithmetic
3114
 
; https://rosettacode.org/wiki/Bitmap/Bresenham%27s_line_algorithm#C
3115
 
;---------------------------------------------------------------------------------------------------------
3116
 
;void line(int x0, int y0, int x1, int y1) {
3117
 
;  int dx = abs(x1-x0), sx = x0<x1 ? 1 : -1;
3118
 
;  int dy = abs(y1-y0), sy = y0<y1 ? 1 : -1;
3119
 
;  int err = (dx>dy ? dx : -dy)/2, e2;
3120
 
;  for(;;){
3121
 
;    setPixel(x0,y0);
3122
 
;    if (x0==x1 && y0==y1) break;
3123
 
;    e2 = err;
3124
 
;    if (e2 >-dx) { err -= dy; x0 += sx; }
3125
 
;    if (e2 < dy) { err += dx; y0 += sy; }
3126
 
;  }
3127
 
;}
3128
 
 
3129
 
gfxDrawLine:
3130
 
if not defined GFX_FAST
3131
 
  ld hl, (BIOS_GRPACX)
3132
 
  ld (BIOS_GXPOS), hl
3133
 
  ld hl, (BIOS_GRPACY)
3134
 
  ld (BIOS_GYPOS), hl
3135
 
  __call_basic BASIC_SUB_LINE
3136
 
  ret
3137
 
 
3138
 
else
3139
 
 
3140
 
  ld (GFX_TEMP2), bc        ; x
3141
 
  ld (GFX_TEMP3), de        ; y
3142
 
 
3143
 
  ld hl, (BIOS_GRPACX)      ; x0
3144
 
  ld de, (GFX_TEMP2)        ; x
3145
 
  ;or a
3146
 
  ;sbc hl, de
3147
 
  ;jp po, gfxLine.1            ; x0 >= x? else jump to endif
3148
 
  call MATH.COMP.S16
3149
 
  jp c, gfxLine.1             ; x0 < x? jump
3150
 
    or a
3151
 
    sbc hl, de
3152
 
    ld (GFX_TEMP4), hl        ; dx = x0 - x
3153
 
    ld hl, 0xffff
3154
 
    ld (GFX_TEMP5), hl        ; sx = -1
3155
 
    jr gfxLine.2
3156
 
 
3157
 
gfxLine.1:
3158
 
  ld de, (BIOS_GRPACX)      ; x0
3159
 
  ld hl, (GFX_TEMP2)        ; x
3160
 
  or a
3161
 
  sbc hl, de
3162
 
  ld (GFX_TEMP4), hl        ; dx = x - x0
3163
 
  ld hl, 1
3164
 
  ld (GFX_TEMP5), hl        ; sx = 1
3165
 
 
3166
 
gfxLine.2:
3167
 
  ld hl, (BIOS_GRPACY)      ; y0
3168
 
  ld de, (GFX_TEMP3)        ; y
3169
 
  ;or a
3170
 
  ;sbc hl, de
3171
 
  ;jp po, gfxLine.3           ; y0 >= y? else, jump to endif
3172
 
  call MATH.COMP.S16
3173
 
  jp c, gfxLine.3             ; y0 < y? jump
3174
 
    or a
3175
 
    sbc hl, de
3176
 
    ld (GFX_TEMP6), hl        ; dy =  y0 - y
3177
 
    ld hl, 0xffff
3178
 
    ld (GFX_TEMP7), hl        ; sy = -1
3179
 
    jr gfxLine.4
3180
 
 
3181
 
gfxLine.3:
3182
 
  ld de, (BIOS_GRPACY)      ; y0
3183
 
  ld hl, (GFX_TEMP3)        ; y
3184
 
  or a
3185
 
  sbc hl, de
3186
 
  ld (GFX_TEMP6), hl        ; dy = y - y0
3187
 
  ld hl, 1
3188
 
  ld (GFX_TEMP7), hl        ; sy = 1
3189
 
 
3190
 
gfxLine.4:
3191
 
  ld hl, (GFX_TEMP6)       ; dy
3192
 
  ld de, 0
3193
 
  call MATH.COMP.S16
3194
 
  jp z, gfxLine.h          ; dy = 0?
3195
 
 
3196
 
  ld hl, (GFX_TEMP4)       ; dx
3197
 
  ld de, 0
3198
 
  call MATH.COMP.S16
3199
 
  jp z, gfxLine.v          ; dx = 0?
3200
 
 
3201
 
  ld de, (GFX_TEMP4)       ; dx
3202
 
  ld hl, (GFX_TEMP6)       ; dy
3203
 
  or a
3204
 
  adc hl, de
3205
 
  dec hl
3206
 
  dec hl
3207
 
  ld (GFX_TEMP9), hl       ; dxy = dx + dy
3208
 
 
3209
 
  ld de, (GFX_TEMP4)       ; dx
3210
 
  ld hl, (GFX_TEMP6)       ; dy
3211
 
  ;or a
3212
 
  ;sbc hl, de
3213
 
  ;jp pe, gfxLine.5         ; dy < dx? else, jump to endif
3214
 
  call MATH.COMP.S16
3215
 
  jp z, gfxLine.5          ; dy = dx? jump
3216
 
  jp nc, gfxLine.5         ; dy > dx? jump
3217
 
    ;ld hl, 0
3218
 
    ld de, (GFX_TEMP6)     ; dy
3219
 
        or a
3220
 
    srl d
3221
 
    rr e                   ; dy / 2
3222
 
        ;or a
3223
 
        ;sbc hl, de             ; -dy
3224
 
    ld (GFX_TEMP8), de     ; err = -dy / 2
3225
 
    jr gfxLine.loop
3226
 
 
3227
 
gfxLine.5:
3228
 
  ld hl, (GFX_TEMP4)       ; dx
3229
 
  or a
3230
 
  srl h
3231
 
  rr l
3232
 
  ld (GFX_TEMP8), hl       ; err = dx/2
3233
 
 
3234
 
gfxLine.loop:
3235
 
  call gfxSetPixel
3236
 
 
3237
 
  ld hl, (GFX_TEMP9)         ; dxy
3238
 
  ld de, 0
3239
 
  call MATH.COMP.S16
3240
 
  jp nc, gfxLine.loop.0      ; dxy > 0? jump
3241
 
  ;jp z, gfxLine.loop.0      ; dxy = 0? jump
3242
 
 
3243
 
  ret
3244
 
 
3245
 
gfxLine.loop.0:
3246
 
  ld hl, 0
3247
 
  ld de, (GFX_TEMP4)     ; dx
3248
 
  or a
3249
 
  sbc hl, de             ; -dx
3250
 
  ld de, (GFX_TEMP8)     ; e2 = err
3251
 
  push de
3252
 
    ;or a
3253
 
    ;sbc hl, de
3254
 
    ;jp pe, gfxLine.loop.1  ; if -dx < e2, else jump to endif
3255
 
        call MATH.COMP.S16
3256
 
        jp z, gfxLine.loop.1   ; -dx = e2? jump
3257
 
        jp nc, gfxLine.loop.1  ; -dx > e2? jump
3258
 
      ld hl, (GFX_TEMP8)   ; err
3259
 
      ld de, (GFX_TEMP6)   ; dy
3260
 
      or a
3261
 
      sbc hl, de
3262
 
      ld (GFX_TEMP8), hl   ; err -= dy
3263
 
 
3264
 
      ld hl, (GFX_TEMP9)   ; dxy
3265
 
      dec hl
3266
 
      ld (GFX_TEMP9), hl   ; dxy -= 1
3267
 
 
3268
 
      ld hl, (BIOS_GRPACX)
3269
 
      ld de, (GFX_TEMP5)
3270
 
      or a
3271
 
      adc hl, de
3272
 
      ld (BIOS_GRPACX), hl  ; x0 += sx
3273
 
 
3274
 
gfxLine.loop.1:
3275
 
  pop hl                    ; e2
3276
 
  ld de, (GFX_TEMP6)        ; dy
3277
 
  ;or a
3278
 
  ;sbc hl, de
3279
 
  ;jp pe, gfxLine.loop.2     ; if e2 < dy, else jump to endif
3280
 
  call MATH.COMP.S16
3281
 
  jp z, gfxLine.loop.2      ; e2 = dy? jump
3282
 
  jp nc, gfxLine.loop.2     ; e2 > dy? jump
3283
 
    ld hl, (GFX_TEMP8)      ; err
3284
 
    ld de, (GFX_TEMP4)      ; dx
3285
 
    or a
3286
 
    adc hl, de
3287
 
    ld (GFX_TEMP8), hl      ; err += dx
3288
 
 
3289
 
    ld hl, (GFX_TEMP9)      ; dxy
3290
 
    dec hl
3291
 
    ld (GFX_TEMP9), hl      ; dxy -= 1
3292
 
 
3293
 
    ld hl, (BIOS_GRPACY)
3294
 
    ld de, (GFX_TEMP7)
3295
 
    or a
3296
 
    adc hl, de
3297
 
    ld (BIOS_GRPACY), hl    ; y0 += sy
3298
 
 
3299
 
gfxLine.loop.2:
3300
 
  call gfxRefreshXY
3301
 
  jp gfxLine.loop
3302
 
 
3303
 
gfxLine.h:
3304
 
  ld a, (GFX_TEMP5)        ; sx
3305
 
  bit 7, a
3306
 
  jr z, gfxLine.h.1        ; if a is positive
3307
 
    ld hl, (BIOS_GRPACX)
3308
 
    ld de, (GFX_TEMP4)
3309
 
    or a
3310
 
    sbc hl, de
3311
 
    ld (BIOS_GRPACX), hl
3312
 
    call gfxRefreshXY
3313
 
 
3314
 
gfxLine.h.1:
3315
 
  __call_bios BIOS_FETCHC
3316
 
  ld hl, (GFX_TEMP4)       ; dx
3317
 
  inc hl
3318
 
  call gfxDrawHorLine      ; HL = pixel count
3319
 
  ret
3320
 
 
3321
 
gfxLine.v:
3322
 
  ld a, (GFX_TEMP7)        ; sy
3323
 
  bit 7, a
3324
 
  jr z, gfxLine.v.1        ; if a is positive
3325
 
    ld hl, (BIOS_GRPACY)
3326
 
    ld de, (GFX_TEMP6)
3327
 
    or a
3328
 
    sbc hl, de
3329
 
    ld (BIOS_GRPACY), hl
3330
 
    call gfxRefreshXY
3331
 
 
3332
 
gfxLine.v.1:
3333
 
  call gfxSetPixel
3334
 
  ld hl, (GFX_TEMP6)       ; dy
3335
 
  inc hl
3336
 
  ld (GFX_TEMP3), hl
3337
 
  jp gfxBox.drawVerLine
3338
 
endif
3339
 
 
3340
 
endif
3341
 
 
3342
 
if defined BOX or defined FBOX or defined BOX_STEP or defined FBOX_STEP
3343
 
 
3344
 
;---------------------------------------------------------------------------------------------------------
3345
 
; gfxDrawBox
3346
 
; plot a box from current position to informed destination
3347
 
; in BC = destination x
3348
 
;    DE = destination y
3349
 
;    A  = filled flag (0 = not filled, <>0 = filled)
3350
 
;---------------------------------------------------------------------------------------------------------
3351
 
 
3352
 
gfxDrawBox:
3353
 
 
3354
 
if not defined GFX_FAST
3355
 
  ld hl, (BIOS_GRPACX)
3356
 
  ld (BIOS_GXPOS), hl
3357
 
  ld hl, (BIOS_GRPACY)
3358
 
  ld (BIOS_GYPOS), hl
3359
 
  ld hl, BASIC_SUB_LINEBOX
3360
 
  or 0
3361
 
  jr z, gfxDrawBox.1
3362
 
    call gfxIsScreenModeMSX2
3363
 
    jr nc, gfxDrawBox.2
3364
 
    ld hl, BASIC_SUB_LINEBOXFILLED
3365
 
 
3366
 
gfxDrawBox.1:
3367
 
  push hl
3368
 
  pop ix
3369
 
  jp BIOS_CALBAS   ; BIOS_CALSLT
3370
 
 
3371
 
 
3372
 
gfxDrawBox.2:
3373
 
  xor a
3374
 
  ld hl, BASIC_BUF
3375
 
  ld (hl), a
3376
 
  ld ix, BIOS_DOBOXF
3377
 
  jp BIOS_EXTROM
3378
 
 
3379
 
else
3380
 
  call gfxAdjustDestXY
3381
 
  or 0
3382
 
  jr nz, gfxBox.filled
3383
 
 
3384
 
gfxBox.notFilled:
3385
 
  call gfxPushXY
3386
 
    call gfxBox.drawHorLine
3387
 
    ld hl, (GFX_TEMP2)
3388
 
    ld de, (BIOS_GRPACX)
3389
 
    or a
3390
 
    adc hl, de
3391
 
    dec hl
3392
 
    ld (BIOS_GRPACX), hl
3393
 
    call gfxRefreshXY
3394
 
    call gfxBox.drawVerLine
3395
 
  call gfxPopXY
3396
 
  call gfxBox.drawVerLine
3397
 
  call gfxBox.drawHorLine
3398
 
  ret
3399
 
 
3400
 
gfxBox.filled:
3401
 
  ld hl, (GFX_TEMP3)
3402
 
  ;inc hl
3403
 
gfxBox.filled.loop:
3404
 
  push hl
3405
 
    ld bc, (BIOS_GRPACX)
3406
 
        push bc
3407
 
      call gfxBox.drawHorLine
3408
 
        pop bc
3409
 
        ld (BIOS_GRPACX), bc
3410
 
        ld bc, (BIOS_GRPACY)
3411
 
        inc bc
3412
 
        ld (BIOS_GRPACY), bc
3413
 
    call gfxRefreshXY
3414
 
  pop hl
3415
 
  ld de, 1
3416
 
  or a
3417
 
  sbc hl, de
3418
 
  jr nz, gfxBox.filled.loop
3419
 
  ret
3420
 
 
3421
 
gfxBox.drawHorLine:
3422
 
  ld hl, (GFX_TEMP2)
3423
 
  ;inc hl
3424
 
  call gfxDrawHorLine
3425
 
  ret
3426
 
 
3427
 
gfxBox.drawVerLine:
3428
 
  ld hl, (GFX_TEMP3)
3429
 
  dec hl
3430
 
gfxBox.drawVerLine.loop:
3431
 
  push hl
3432
 
    call gfxDown
3433
 
        call gfxSetPixel
3434
 
  pop hl
3435
 
  ld de, 1
3436
 
  or a
3437
 
  sbc hl, de
3438
 
  jr nz, gfxBox.drawVerLine.loop
3439
 
  ret
3440
 
 
3441
 
;---------------------------------------------------------------------------------------------------------
3442
 
; gfxDrawHorLine
3443
 
; draw a horizontal line
3444
 
; HL = pixel count
3445
 
;---------------------------------------------------------------------------------------------------------
3446
 
 
3447
 
gfxDrawHorLine:
3448
 
  ld a, (BIOS_SCRMOD)
3449
 
  cp 5
3450
 
  jr c, gfxDrawHorLine.2 ; if screen mode < 5 then jump
3451
 
    bit 7, h
3452
 
    ret nz               ; return if negative
3453
 
    xor a
3454
 
    cp h
3455
 
    jr nz, gfxDrawHorLine.1
3456
 
    cp l
3457
 
    ret z                ; return if hl = 0
3458
 
    call gfxPushXY
3459
 
gfxDrawHorLine.1:
3460
 
    push hl
3461
 
          call gfxSetPixel
3462
 
      call gfxRight
3463
 
    pop hl
3464
 
    ld de, 1
3465
 
    sbc hl, de
3466
 
    jr nz, gfxDrawHorLine.1
3467
 
    call gfxPopXY
3468
 
    ret
3469
 
gfxDrawHorLine.2:
3470
 
  __call_bios BIOS_NSETCX    ; HL = fill count
3471
 
  ret
3472
 
 
3473
 
;---------------------------------------------------------------------------------------------------------
3474
 
; gfxAdjustDestXY
3475
 
; invert if dest XY is less than current XY position
3476
 
; BC = dest x
3477
 
; DE = dest y
3478
 
;---------------------------------------------------------------------------------------------------------
3479
 
 
3480
 
gfxAdjustDestXY:
3481
 
  push af
3482
 
    ld (GFX_TEMP2), bc        ; x
3483
 
        ld (GFX_TEMP3), de        ; y
3484
 
 
3485
 
    ; verify x againt current position
3486
 
    ld hl, (BIOS_GRPACX)
3487
 
        ld de, (GFX_TEMP2)
3488
 
        and a
3489
 
        sbc hl, de                ; dx = x1 - x0
3490
 
        bit 7, h                  ; result is negative?
3491
 
        jr z, gfxAdjustDestXY.1
3492
 
        add hl, de
3493
 
        ld (BIOS_GRPACX), hl
3494
 
    ex de, hl
3495
 
    or a
3496
 
        sbc hl, de
3497
 
gfxAdjustDestXY.1:
3498
 
    inc hl
3499
 
        ld (GFX_TEMP2), hl
3500
 
 
3501
 
    ; verify y againt current position
3502
 
    ld hl, (BIOS_GRPACY)
3503
 
        ld de, (GFX_TEMP3)
3504
 
        and a
3505
 
        sbc hl, de                ; dy = y1 - y0
3506
 
        bit 7, h                  ; result is negative?
3507
 
        jr z, gfxAdjustDestXY.2
3508
 
        add hl, de
3509
 
        ld (BIOS_GRPACY), hl
3510
 
    ex de, hl
3511
 
    or a
3512
 
        sbc hl, de
3513
 
gfxAdjustDestXY.2:
3514
 
    inc hl
3515
 
        ld (GFX_TEMP3), hl
3516
 
 
3517
 
        ; refresh new position
3518
 
        call gfxRefreshXY
3519
 
  pop af
3520
 
  ret
3521
 
endif
3522
 
 
3523
 
endif
3524
 
 
3525
 
if defined CIRCLE
3526
 
 
3527
 
;---------------------------------------------------------------------------------------------------------
3528
 
; gfxDrawCircle
3529
 
; plot a circle centered in current position
3530
 
; BC = tracing end x
3531
 
; DE = tracing end y
3532
 
; HL = radius
3533
 
; A  = filled flag (0 = not filled, <>0 = filled)
3534
 
; https://en.wikipedia.org/wiki/Midpoint_circle_algorithm
3535
 
; https://rosettacode.org/wiki/Bitmap/Midpoint_circle_algorithm#C
3536
 
;---------------------------------------------------------------------------------------------------------
3537
 
 
3538
 
gfxDrawCircle:
3539
 
 
3540
 
if not defined GFX_FAST
3541
 
  bit 7,h
3542
 
  ret nz                ; return if negative radius
3543
 
  ld (BIOS_GXPOS), hl   ; circle ray
3544
 
  ld de, (BIOS_GXPOS)
3545
 
  ld bc, (BIOS_GRPACY)
3546
 
  ld (BIOS_GYPOS), bc
3547
 
  xor a
3548
 
  ;cp h
3549
 
  ;jr nz, gfxDrawCircle.1
3550
 
  ;cp l
3551
 
  ;ret z
3552
 
gfxDrawCircle.1:
3553
 
  ld hl, BASIC_BUF
3554
 
  ld (hl), a
3555
 
  ld ix, 0xFFFF
3556
 
  __call_basic BASIC_SUB_CIRCLE
3557
 
  ret
3558
 
else
3559
 
  ld (GFX_TEMP),  hl   ; radius
3560
 
  ld de, 0
3561
 
  sbc hl, de
3562
 
  ret z                ; return if zero radius
3563
 
  bit 7,h
3564
 
  ret nz               ; return if negative radius
3565
 
 
3566
 
  call gfxGetXY
3567
 
  ld (GFX_TEMP1), bc   ; x0
3568
 
  ld (GFX_TEMP2), de   ; y0
3569
 
 
3570
 
  or 0
3571
 
  jp nz, gfxCircle.filled
3572
 
 
3573
 
gfxCircle.notFilled:
3574
 
  ld hl, 1
3575
 
  ld de, (GFX_TEMP)    ; radius
3576
 
  or a
3577
 
  sbc hl, de
3578
 
  ld (GFX_TEMP3), hl   ; f = 1 - radius
3579
 
 
3580
 
  ld hl, 0
3581
 
  ld (GFX_TEMP4), hl   ; ddF_x = 0
3582
 
 
3583
 
  ld hl, (GFX_TEMP)
3584
 
  or a
3585
 
  adc hl, hl
3586
 
  ex de, hl
3587
 
  ld hl, 0
3588
 
  or a
3589
 
  sbc hl, de
3590
 
  ld (GFX_TEMP5), hl   ; ddF_y = -2 * radius
3591
 
 
3592
 
  ld hl, 0
3593
 
  ld (GFX_TEMP6), hl   ; x = 0
3594
 
 
3595
 
  ld hl, (GFX_TEMP)
3596
 
  ld (GFX_TEMP7), hl   ; y = radius
3597
 
 
3598
 
  ; plot(x0, y0 + radius)
3599
 
  ld de, (GFX_TEMP)    ; radius
3600
 
  ld hl, (GFX_TEMP2)   ; y0
3601
 
  or a
3602
 
  adc hl, de
3603
 
  ex de, hl
3604
 
  ld bc, (GFX_TEMP1)   ; x0
3605
 
  call gfxSetXY
3606
 
  call gfxSetPixel
3607
 
 
3608
 
  ; plot(x0, y0 - radius)
3609
 
  ld de, (GFX_TEMP)    ; radius
3610
 
  ld hl, (GFX_TEMP2)   ; y0
3611
 
  or a
3612
 
  sbc hl, de
3613
 
  ex de, hl
3614
 
  ld bc, (GFX_TEMP1)   ; x0
3615
 
  call gfxSetXY
3616
 
  call gfxSetPixel
3617
 
 
3618
 
  ; plot(x0 + radius, y0)
3619
 
  ld hl, (GFX_TEMP1)   ; x0
3620
 
  ld de, (GFX_TEMP)    ; radius
3621
 
  or a
3622
 
  adc hl, de
3623
 
  ;push hl
3624
 
  ;pop bc
3625
 
  ld b, h
3626
 
  ld c, l
3627
 
  ld de, (GFX_TEMP2)   ; y0
3628
 
  call gfxSetXY
3629
 
  call gfxSetPixel
3630
 
 
3631
 
  ; plot(x0 - radius, y0)
3632
 
  ld hl, (GFX_TEMP1)   ; x0
3633
 
  ld de, (GFX_TEMP)    ; radius
3634
 
  or a
3635
 
  sbc hl, de
3636
 
  ;push hl
3637
 
  ;pop bc
3638
 
  ld b, h
3639
 
  ld c, l
3640
 
  ld de, (GFX_TEMP2)   ; y0
3641
 
  call gfxSetXY
3642
 
  call gfxSetPixel
3643
 
  jp gfxCircle.notFilled.3
3644
 
 
3645
 
gfxCircle.notFilled.1:
3646
 
  ld hl, (GFX_TEMP3)   ; f
3647
 
  bit 7, h
3648
 
  jr nz, gfxCircle.notFilled.2  ; if( f < 0 ), jump
3649
 
 
3650
 
    ld hl, (GFX_TEMP7)        ; y -= 1
3651
 
    dec hl
3652
 
    ld (GFX_TEMP7), hl
3653
 
 
3654
 
    ld hl, (GFX_TEMP5)        ; ddF_y += 2
3655
 
    inc hl
3656
 
    inc hl
3657
 
    ld (GFX_TEMP5), hl
3658
 
 
3659
 
    ld hl, (GFX_TEMP3)        ; f
3660
 
    ld de, (GFX_TEMP5)        ; ddF_y
3661
 
    or a
3662
 
    adc hl, de
3663
 
    ld (GFX_TEMP3), hl        ; f += ddF_y
3664
 
 
3665
 
gfxCircle.notFilled.2:
3666
 
  ld hl, (GFX_TEMP6)   ; x
3667
 
  inc hl
3668
 
  ld (GFX_TEMP6), hl   ; x++
3669
 
 
3670
 
  ld hl, (GFX_TEMP4)   ; ddF_x += 2
3671
 
  inc hl
3672
 
  inc hl
3673
 
  ld (GFX_TEMP4), hl
3674
 
 
3675
 
  ld hl, (GFX_TEMP3)   ; f
3676
 
  ld de, (GFX_TEMP4)   ; ddF_x
3677
 
  or a
3678
 
  adc hl, de
3679
 
  inc hl
3680
 
  ld (GFX_TEMP3), hl   ; f += ddF_x + 1
3681
 
 
3682
 
  ; plot(x0 + x, y0 + y)
3683
 
  ld hl, (GFX_TEMP1)   ; x0
3684
 
  ld de, (GFX_TEMP6)   ; x
3685
 
  or a
3686
 
  adc hl, de
3687
 
  ;push hl
3688
 
  ;pop bc
3689
 
  ld b, h
3690
 
  ld c, l
3691
 
  ld hl, (GFX_TEMP2)   ; y0
3692
 
  ld de, (GFX_TEMP7)   ; y
3693
 
  or a
3694
 
  adc hl, de
3695
 
  ex de, hl
3696
 
  call gfxSetXY
3697
 
  call gfxSetPixel
3698
 
 
3699
 
  ; plot(x0 - x, y0 + y)
3700
 
  ld hl, (GFX_TEMP1)   ; x0
3701
 
  ld de, (GFX_TEMP6)   ; x
3702
 
  or a
3703
 
  sbc hl, de
3704
 
  ;push hl
3705
 
  ;pop bc
3706
 
  ld b, h
3707
 
  ld c, l
3708
 
  ld hl, (GFX_TEMP2)   ; y0
3709
 
  ld de, (GFX_TEMP7)   ; y
3710
 
  or a
3711
 
  adc hl, de
3712
 
  ex de, hl
3713
 
  call gfxSetXY
3714
 
  call gfxSetPixel
3715
 
 
3716
 
  ; plot(x0 + x, y0 - y)
3717
 
  ld hl, (GFX_TEMP1)   ; x0
3718
 
  ld de, (GFX_TEMP6)   ; x
3719
 
  or a
3720
 
  adc hl, de
3721
 
  ;push hl
3722
 
  ;pop bc
3723
 
  ld b, h
3724
 
  ld c, l
3725
 
  ld hl, (GFX_TEMP2)   ; y0
3726
 
  ld de, (GFX_TEMP7)   ; y
3727
 
  or a
3728
 
  sbc hl, de
3729
 
  ex de, hl
3730
 
  call gfxSetXY
3731
 
  call gfxSetPixel
3732
 
 
3733
 
  ; plot(x0 - x, y0 - y)
3734
 
  ld hl, (GFX_TEMP1)   ; x0
3735
 
  ld de, (GFX_TEMP6)   ; x
3736
 
  or a
3737
 
  sbc hl, de
3738
 
  ;push hl
3739
 
  ;pop bc
3740
 
  ld b, h
3741
 
  ld c, l
3742
 
  ld hl, (GFX_TEMP2)   ; y0
3743
 
  ld de, (GFX_TEMP7)   ; y
3744
 
  or a
3745
 
  sbc hl, de
3746
 
  ex de, hl
3747
 
  call gfxSetXY
3748
 
  call gfxSetPixel
3749
 
 
3750
 
  ; plot(x0 + y, y0 + x)
3751
 
  ld hl, (GFX_TEMP1)   ; x0
3752
 
  ld de, (GFX_TEMP7)   ; y
3753
 
  or a
3754
 
  adc hl, de
3755
 
  ;push hl
3756
 
  ;pop bc
3757
 
  ld b, h
3758
 
  ld c, l
3759
 
  ld hl, (GFX_TEMP2)   ; y0
3760
 
  ld de, (GFX_TEMP6)   ; x
3761
 
  or a
3762
 
  adc hl, de
3763
 
  ex de, hl
3764
 
  call gfxSetXY
3765
 
  call gfxSetPixel
3766
 
 
3767
 
  ; plot(x0 - y, y0 + x)
3768
 
  ld hl, (GFX_TEMP1)   ; x0
3769
 
  ld de, (GFX_TEMP7)   ; y
3770
 
  or a
3771
 
  sbc hl, de
3772
 
  ;push hl
3773
 
  ;pop bc
3774
 
  ld b, h
3775
 
  ld c, l
3776
 
  ld hl, (GFX_TEMP2)   ; y0
3777
 
  ld de, (GFX_TEMP6)   ; x
3778
 
  or a
3779
 
  adc hl, de
3780
 
  ex de, hl
3781
 
  call gfxSetXY
3782
 
  call gfxSetPixel
3783
 
 
3784
 
  ; plot(x0 + y, y0 - x)
3785
 
  ld hl, (GFX_TEMP1)   ; x0
3786
 
  ld de, (GFX_TEMP7)   ; y
3787
 
  or a
3788
 
  adc hl, de
3789
 
  ;push hl
3790
 
  ;pop bc
3791
 
  ld b, h
3792
 
  ld c, l
3793
 
  ld hl, (GFX_TEMP2)   ; y0
3794
 
  ld de, (GFX_TEMP6)   ; x
3795
 
  or a
3796
 
  sbc hl, de
3797
 
  ex de, hl
3798
 
  call gfxSetXY
3799
 
  call gfxSetPixel
3800
 
 
3801
 
  ; plot(x0 - y, y0 - x)
3802
 
  ld hl, (GFX_TEMP1)   ; x0
3803
 
  ld de, (GFX_TEMP7)   ; y
3804
 
  or a
3805
 
  sbc hl, de
3806
 
  ;push hl
3807
 
  ;pop bc
3808
 
  ld b, h
3809
 
  ld c, l
3810
 
  ld hl, (GFX_TEMP2)   ; y0
3811
 
  ld de, (GFX_TEMP6)   ; x
3812
 
  or a
3813
 
  sbc hl, de
3814
 
  ex de, hl
3815
 
  call gfxSetXY
3816
 
  call gfxSetPixel
3817
 
 
3818
 
gfxCircle.notFilled.3:
3819
 
  ld hl, (GFX_TEMP6)           ; x
3820
 
  ld de, (GFX_TEMP7)           ; y
3821
 
  or a
3822
 
  sbc hl, de
3823
 
  jp c, gfxCircle.notFilled.1  ; while( x < y )
3824
 
  ld bc, (GFX_TEMP1)   ; x0
3825
 
  ld de, (GFX_TEMP2)   ; y0
3826
 
  call gfxSetXY
3827
 
  ret
3828
 
 
3829
 
gfxCircle.filled
3830
 
  call gfxCircle.notFilled
3831
 
  ld hl, (BIOS_BDRATR)
3832
 
  push hl
3833
 
        ld hl, (BIOS_FORCLR)
3834
 
        ld (BIOS_BDRATR), hl
3835
 
        ld a, 1
3836
 
        call gfxBorderFill
3837
 
  pop hl
3838
 
  ld (BIOS_BDRATR), hl
3839
 
  ret
3840
 
endif
3841
 
 
3842
 
endif
3843
 
 
3844
 
if defined PAINT or (defined CIRCLE and defined GFX_FAST)
3845
 
 
3846
 
;---------------------------------------------------------------------------------------------------------
3847
 
; gfxBorderFill
3848
 
; Fill current region delimited by border attribute color changing pixels to foreground color
3849
 
; in: a = fill type (0 = not symmetric, 1 = symmetric)
3850
 
;---------------------------------------------------------------------------------------------------------
3851
 
 
3852
 
gfxBorderFill:
3853
 
 
3854
 
if not defined GFX_FAST
3855
 
 
3856
 
  ld bc, (BIOS_GRPACX)
3857
 
  ld (BIOS_GXPOS), bc
3858
 
  ld de, (BIOS_GRPACY)
3859
 
  ld (BIOS_GYPOS), de
3860
 
  push bc
3861
 
  push de
3862
 
 
3863
 
  xor a
3864
 
  ld hl, BASIC_BUF
3865
 
  ld (hl), a
3866
 
 
3867
 
  ld a, (BIOS_BDRATR)
3868
 
  xor b
3869
 
  ld e, a
3870
 
  ld a, (BIOS_ATRBYT)
3871
 
  xor d
3872
 
  ld c, a
3873
 
  ;ld ix, 0xFFFF
3874
 
  ;ld iy, 0xFFFF
3875
 
 
3876
 
  call gfxIsScreenModeMSX2
3877
 
  jr nc, gfxBorderFill.1  ; if MSX2 and screen mode above 3, jump
3878
 
    ld a, (BIOS_BDRATR)
3879
 
    ld (BIOS_ATRBYT), a
3880
 
    ld e, a
3881
 
    __call_basic BASIC_SUB_PAINT1
3882
 
    ret
3883
 
 
3884
 
gfxBorderFill.1:
3885
 
  __call_basic BASIC_SUB_PAINT1
3886
 
  ret
3887
 
  ;ld ix, BASIC_SUB_PAINT2
3888
 
  ;jp BIOS_EXTROM
3889
 
 
3890
 
else
3891
 
 
3892
 
  ld (GFX_TEMP1), a
3893
 
  ld hl, (BIOS_GRPACY)
3894
 
  push hl
3895
 
    call gfxBorderFill.down
3896
 
  pop hl
3897
 
  push hl
3898
 
    ld (BIOS_GRPACY), hl
3899
 
    call gfxRefreshXY
3900
 
    call gfxBorderFill.up
3901
 
  pop hl
3902
 
  ld (BIOS_GRPACY), hl
3903
 
  call gfxRefreshXY
3904
 
  ret
3905
 
 
3906
 
gfxBorderFill.down:
3907
 
  call gfxBorderFill.line
3908
 
  call gfxDown
3909
 
  ret c
3910
 
  call gfxGetPixel
3911
 
  ld hl, BIOS_BDRATR
3912
 
  cp (hl)
3913
 
  jr nz, gfxBorderFill.down
3914
 
  ret
3915
 
 
3916
 
gfxBorderFill.up:
3917
 
  call gfxBorderFill.line
3918
 
  call gfxUp
3919
 
  ret c
3920
 
  call gfxGetPixel
3921
 
  ld hl, BIOS_BDRATR
3922
 
  cp (hl)
3923
 
  jr nz, gfxBorderFill.up
3924
 
  ret
3925
 
 
3926
 
gfxBorderFill.line:
3927
 
  ld de, (BIOS_GRPACX)
3928
 
  push de
3929
 
    ld b, 1    ; fill flag
3930
 
    ld de, 1   ; skip count
3931
 
    __call_bios BIOS_SCANR
3932
 
        ;inc hl
3933
 
        ;ld (GFX_TEMP2), hl        ; pixel count transversed
3934
 
  pop de
3935
 
  push de
3936
 
    ld (BIOS_GRPACX), de
3937
 
    call gfxRefreshXY
3938
 
    ;ld a, (GFX_TEMP1)
3939
 
    ;cp 0                       ; 0 = not symmetric, 1 = symmetric
3940
 
        ;jr z, gfxBorderFill.line.1
3941
 
        ;ld hl, (GFX_TEMP2)
3942
 
        ;__call_bios BIOS_NSETCX    ; HL = fill count
3943
 
        ;jr gfxBorderFill.line.2
3944
 
gfxBorderFill.line.1:
3945
 
    ld b, 1    ; fill flag
3946
 
    ld de, 0   ; skip count
3947
 
    __call_bios BIOS_SCANL
3948
 
gfxBorderFill.line.2:
3949
 
  pop de
3950
 
  ld (BIOS_GRPACX), de
3951
 
  call gfxRefreshXY
3952
 
  ret
3953
 
 
3954
 
;---------------------------------------------------------------------------------------------------------
3955
 
; gfxFloadFill
3956
 
; Fload fill current region changing current pixel color to foreground color
3957
 
; https://en.wikipedia.org/wiki/Flood_fill
3958
 
;---------------------------------------------------------------------------------------------------------
3959
 
 
3960
 
gfxFloadFill:
3961
 
  call gfxGetPixel
3962
 
  ld (GFX_TEMP), a    ; replacement-color
3963
 
  call gfxFloadFill.recursive
3964
 
  ret
3965
 
 
3966
 
gfxFloadFill.recursive:
3967
 
  ; 1. If target-color is equal to replacement-color, return.
3968
 
  ld a, (GFX_TEMP)
3969
 
  ld hl, BIOS_FORCLR
3970
 
  cp (hl)
3971
 
  ret z
3972
 
 
3973
 
  ; 2. ElseIf the color of node is not equal to target-color, return.
3974
 
  call gfxGetPixel
3975
 
  ld hl, GFX_TEMP
3976
 
  cp (hl)
3977
 
  ret nz
3978
 
 
3979
 
  ; 3. Else Set the color of node to replacement-color.
3980
 
  call gfxSetPixel
3981
 
 
3982
 
  ; 4. Perform Flood-fill (one step to the left of node, target-color, replacement-color).
3983
 
gfxFloadFill.recursive.left:
3984
 
  call gfxLeft
3985
 
  jr c, gfxFloadFill.recursive.right
3986
 
    call gfxFloadFill.recursive
3987
 
    call gfxRight
3988
 
 
3989
 
  ;    Perform Flood-fill (one step to the right of node, target-color, replacement-color).
3990
 
gfxFloadFill.recursive.right:
3991
 
  call gfxRight
3992
 
  jr c, gfxFloadFill.recursive.up
3993
 
    call gfxFloadFill.recursive
3994
 
    call gfxLeft
3995
 
 
3996
 
  ;    Perform Flood-fill (one step to the up of node, target-color, replacement-color).
3997
 
gfxFloadFill.recursive.up:
3998
 
  call gfxUp
3999
 
  jr c, gfxFloadFill.recursive.down
4000
 
    call gfxFloadFill.recursive
4001
 
    call gfxDown
4002
 
 
4003
 
  ;    Perform Flood-fill (one step to the down of node, target-color, replacement-color).
4004
 
gfxFloadFill.recursive.down:
4005
 
  call gfxDown
4006
 
  ret c
4007
 
    call gfxFloadFill.recursive
4008
 
    call gfxUp
4009
 
  ret
4010
 
 
4011
 
endif
4012
 
 
4013
 
endif
4014
 
 
4015
 
if defined SPRITEMODE
4016
 
 
4017
 
;---------------------------------------------------------------------------------------------------------
4018
 
; gfxSetSpriteMode
4019
 
; set current sprite mode
4020
 
; A = sprite mode
4021
 
;     0: Spritesize is 8 by 8 pixels - default value
4022
 
;     1: Spritesize is 8 by 8 pixels, magnified to 16 by 16 pixels
4023
 
;     2: Spritesize is 16 by 16 pixels
4024
 
;     3: Spritesize is 16 by 16 pixels, magnified to 32 by 32 pixels
4025
 
; RG1SAV bit 0 = magnify sprite (double size)
4026
 
; RG1SAV bit 1 = sprite size (0=8 pixels, 1=16 pixels)
4027
 
;---------------------------------------------------------------------------------------------------------
4028
 
 
4029
 
gfxSetSpriteMode:
4030
 
  and 3                        ; keeps only bits 0 and 1 from A
4031
 
  ld b, a
4032
 
  di
4033
 
    ld a, (BIOS_RG1SAV)         ; get copy from register #1 of VDP
4034
 
    and 0xFC                    ; clear bits 0 and 1 from A
4035
 
    or b                        ; put parameter to A (bits 0 and 1)
4036
 
    ld (BIOS_RG1SAV), a         ; restore to register #1 of VDP
4037
 
    ld b, a                     ; value to write
4038
 
    ld c, 1                     ; register number to write
4039
 
    call gfxWRTVDP     ; write register to VDP
4040
 
    call gfxCLRSPR     ; clear sprites
4041
 
  ei
4042
 
  call gfxGetSpriteSize
4043
 
  jp gfxFillSpriteCollisionTable
4044
 
 
4045
 
endif
4046
 
 
4047
 
if defined SPRITE or defined COLOR_SPRITE or defined PUT_SPRITE_COLOR or defined PUT_SPRITE_STEP_COLOR or defined PUT_SPRITE_COLOR_PATNUM or defined PUT_SPRITE_STEP_COLOR_PATNUM or defined LOAD_SET
4048
 
 
4049
 
;---------------------------------------------------------------------------------------------------------
4050
 
; gfxSetSpriteColorInt
4051
 
; A = sprite number
4052
 
; BC = color number
4053
 
;---------------------------------------------------------------------------------------------------------
4054
 
 
4055
 
gfxSetSpriteColorInt:
4056
 
  ld b, a         ; save sprite number
4057
 
  call gfxCALATR    ; get sprite attribute table address
4058
 
  inc hl
4059
 
  inc hl
4060
 
  inc hl
4061
 
  ld a, c         ; color
4062
 
  ;call gfxSetSpriteColor.Adjust
4063
 
  call gfxWRTVRM
4064
 
 
4065
 
  ld a, (BIOS_SCRMOD)
4066
 
  cp 3
4067
 
  ret c           ; if screen mode < 3, do not adjust sprite multicolor
4068
 
 
4069
 
  ld a, b         ; recover sprite number
4070
 
  call gfxGetSpriteColorTable
4071
 
 
4072
 
  ld a, c         ; color
4073
 
  ;call gfxSetSpriteColor.Adjust
4074
 
  ld b, 16        ; array of 16 bytes
4075
 
 
4076
 
gfxSetSpriteColorInt.1:
4077
 
  push bc
4078
 
    call gfxWRTVRM
4079
 
  pop bc
4080
 
  inc hl
4081
 
  djnz gfxSetSpriteColorInt.1
4082
 
  ret
4083
 
 
4084
 
;gfxSetSpriteColor.Adjust:
4085
 
;  cp 0x0f
4086
 
;  ret z
4087
 
;  ret c
4088
 
;  srl a
4089
 
;  srl a
4090
 
;  srl a
4091
 
;  srl a
4092
 
;  ret
4093
 
 
4094
 
;---------------------------------------------------------------------------------------------------------
4095
 
; gfxSetSpriteColorStr
4096
 
; A = sprite number
4097
 
; DE = address to color byte array
4098
 
; BC = color byte array size
4099
 
;---------------------------------------------------------------------------------------------------------
4100
 
 
4101
 
gfxSetSpriteColorStr:
4102
 
  ld b, a         ; save sprite number
4103
 
  push bc
4104
 
  push de
4105
 
    call gfxCALATR    ; get sprite attribute table
4106
 
  pop de
4107
 
  pop bc
4108
 
 
4109
 
  ld a, c         ; byte array zero length?
4110
 
  or a
4111
 
  ret z
4112
 
 
4113
 
  inc hl
4114
 
  inc hl
4115
 
  inc hl
4116
 
  ld a, (de)      ; color
4117
 
  ;call gfxSetSpriteColor.Adjust
4118
 
  call gfxWRTVRM
4119
 
 
4120
 
  ld a, (BIOS_SCRMOD)
4121
 
  cp 3
4122
 
  ret c           ; if screen mode < 3, do not adjust sprite mode 2
4123
 
 
4124
 
  ld a, b         ; recover sprite number
4125
 
  call gfxGetSpriteColorTable
4126
 
 
4127
 
  ld b, 16        ; array of 16 bytes (color table)
4128
 
  ld a, c         ; size of color array
4129
 
  push de
4130
 
  pop iy          ; save array start
4131
 
 
4132
 
gfxSetSpriteColorStr.1:
4133
 
  push af
4134
 
    ld a, (de)
4135
 
    ;call gfxSetSpriteColor.Adjust
4136
 
    call gfxWRTVRM
4137
 
    inc hl
4138
 
    inc de
4139
 
  pop af
4140
 
  dec a
4141
 
  jr nz, gfxSetSpriteColorStr.2
4142
 
    ld a, c      ; recover array size
4143
 
        push iy
4144
 
        pop de       ; recover array start
4145
 
 
4146
 
gfxSetSpriteColorStr.2:
4147
 
  djnz gfxSetSpriteColorStr.1
4148
 
  ret
4149
 
 
4150
 
 
4151
 
 
4152
 
;---------------------------------------------------------------------------------------------------------
4153
 
; gfxGetSpriteColorTable
4154
 
; A = sprite number
4155
 
; HL = address to color table
4156
 
;---------------------------------------------------------------------------------------------------------
4157
 
 
4158
 
gfxGetSpriteColorTable:
4159
 
  push af
4160
 
  push de
4161
 
    ld h, 0
4162
 
    ld l, a         ; recover sprite number
4163
 
    add hl, hl
4164
 
    add hl, hl
4165
 
    add hl, hl
4166
 
    add hl, hl      ; multiply by 16 (shift left 4)
4167
 
    push hl
4168
 
      xor a
4169
 
      call gfxCALATR    ; get sprite attribute table address
4170
 
    pop de
4171
 
    add hl, de
4172
 
    xor a
4173
 
    ld de, 512
4174
 
    sbc hl, de      ; address of color table from sprite multicolor
4175
 
  pop de
4176
 
  pop af
4177
 
  ret
4178
 
 
4179
 
endif
4180
 
 
4181
 
if defined PUT_SPRITE or defined PUT_SPRITE_STEP or defined PUT_SPRITE_COLOR or defined PUT_SPRITE_STEP_COLOR or defined PUT_SPRITE_COLOR_PATNUM or defined PUT_SPRITE_STEP_COLOR_PATNUM or defined PUT_SPRITE_PATNUM or defined PUT_SPRITE_STEP_PATNUM
4182
 
 
4183
 
;---------------------------------------------------------------------------------------------------------
4184
 
; gfxSetSpriteXY
4185
 
; A = sprite number
4186
 
; BC = XY
4187
 
;---------------------------------------------------------------------------------------------------------
4188
 
 
4189
 
gfxSetSpriteXY:
4190
 
  push bc
4191
 
    call gfxCALATR  ; get sprite attribute table address
4192
 
  pop bc
4193
 
  ld a, c                  ; y
4194
 
  call gfxWRTVRM
4195
 
  inc hl
4196
 
  ld a, b                  ; x
4197
 
  call gfxWRTVRM
4198
 
  ret
4199
 
 
4200
 
;---------------------------------------------------------------------------------------------------------
4201
 
; gfxSpriteStepCheck
4202
 
; BC = XY
4203
 
;---------------------------------------------------------------------------------------------------------
4204
 
 
4205
 
gfxSpriteStepCheck:
4206
 
  push hl
4207
 
  push de
4208
 
  push bc
4209
 
 
4210
 
    ld de, (GFX_SPRITE_SIZE_DAT)
4211
 
    ld a, (GFX_SPRITE_FLAGS)   ; bits 0=chk limits, 1=chk walls, 2=chk hotspots, 3=limit touched, 4=wall touched, 5=hotspot touched, 6=collided
4212
 
    and 7                      ; clear touched and collided flags
4213
 
    ld (GFX_SPRITE_FLAGS), a
4214
 
 
4215
 
    bit 0, a
4216
 
    jr z, gfxSpriteStepCheck.corners
4217
 
 
4218
 
gfxSpriteStepCheck.limits:
4219
 
      ld a, (GFX_MAX_X)
4220
 
      sub e                    ; sprite size
4221
 
      cp b                     ; jump if x > max_x?
4222
 
      jr c, gfxSpriteStepCheck.limits.touched
4223
 
 
4224
 
      ld a, (GFX_MAX_Y)
4225
 
      sub e                    ; sprite size
4226
 
      cp c                     ; jump if y > max_y?
4227
 
      jr c, gfxSpriteStepCheck.limits.touched
4228
 
 
4229
 
      jr gfxSpriteStepCheck.corners
4230
 
 
4231
 
gfxSpriteStepCheck.limits.touched:
4232
 
      ld a, (GFX_SPRITE_FLAGS)   ; bits 0=chk limits, 1=chk walls, 2=chk hotspots, 3=limit touched, 4=wall touched, 5=hotspot touched, 6=collided
4233
 
      or 8                       ; set limit touched flag
4234
 
      ld (GFX_SPRITE_FLAGS), a
4235
 
 
4236
 
gfxSpriteStepCheck.corners:
4237
 
    ld a, (GFX_SPRITE_FLAGS)   ; bits 0=chk limits, 1=chk walls, 2=chk hotspots, 3=limit touched, 4=wall touched, 5=hotspot touched, 6=collided
4238
 
    and 2+4                    ; check walls or hotspots
4239
 
    jr z, gfxSpriteStepCheck.end
4240
 
 
4241
 
      ld (GFX_TEMP10), bc
4242
 
      call gfxSpriteStepCheck.corner
4243
 
 
4244
 
      ld a, (GFX_SPRITE_SIZE_DAT)
4245
 
      add a, b
4246
 
      ld b, a
4247
 
      call gfxSpriteStepCheck.corner
4248
 
 
4249
 
      ld a, (GFX_SPRITE_SIZE_DAT)
4250
 
      add a, c
4251
 
      ld c, a
4252
 
      call gfxSpriteStepCheck.corner
4253
 
 
4254
 
      ld bc, (GFX_TEMP10)
4255
 
      ld a, (GFX_SPRITE_SIZE_DAT)
4256
 
      add a, c
4257
 
      ld c, a
4258
 
      call gfxSpriteStepCheck.corner
4259
 
 
4260
 
gfxSpriteStepCheck.end:
4261
 
  pop bc
4262
 
  pop de
4263
 
  pop hl
4264
 
  ret
4265
 
 
4266
 
gfxSpriteStepCheck.corner:
4267
 
  call gfxGetTileFromXY
4268
 
  ld d, a                ; tile to be searched
4269
 
 
4270
 
  ld a, (GFX_SPRITE_FLAGS)   ; bits 0=chk limits, 1=chk walls, 2=chk hotspots, 3=limit touched, 4=wall touched, 5=hotspot touched, 6=collided
4271
 
  bit 1, a
4272
 
  call nz, gfxSpriteStepCheck.walls
4273
 
 
4274
 
  ld a, (GFX_SPRITE_FLAGS)   ; bits 0=chk limits, 1=chk walls, 2=chk hotspots, 3=limit touched, 4=wall touched, 5=hotspot touched, 6=collided
4275
 
  bit 2, a
4276
 
  call nz, gfxSpriteStepCheck.hotspots
4277
 
  ret
4278
 
 
4279
 
gfxSpriteStepCheck.walls:
4280
 
  ld hl, (GFX_SPRITE_WALLS)
4281
 
  ld e, 16   ; bits 0=chk limits, 1=chk walls, 2=chk hotspots, 3=limit touched, 4=wall touched, 5=hotspot touched, 6=collided
4282
 
  jp gfxSpriteStepCheck.search
4283
 
 
4284
 
gfxSpriteStepCheck.hotspots:
4285
 
  ld hl, (GFX_SPRITE_HOTSPOTS)
4286
 
  ld e, 32   ; bits 0=chk limits, 1=chk walls, 2=chk hotspots, 3=limit touched, 4=wall touched, 5=hotspot touched, 6=collided
4287
 
  call gfxSpriteStepCheck.search
4288
 
 
4289
 
  ld a, (GFX_SPRITE_FLAGS)   ; bits 0=chk limits, 1=chk walls, 2=chk hotspots, 3=limit touched, 4=wall touched, 5=hotspot touched, 6=collided
4290
 
  bit 5, a
4291
 
  ret z
4292
 
 
4293
 
  ld a, (GFX_TEMP1)
4294
 
  ld (GFX_SPRITE_HOTSPOT_TILE), a
4295
 
  ret
4296
 
 
4297
 
; d = tile, hl = search table, e = flag
4298
 
gfxSpriteStepCheck.search:
4299
 
  ld a, h
4300
 
  or l
4301
 
  ret z
4302
 
 
4303
 
  ld a, d   ; search for this tile
4304
 
  push bc
4305
 
     ld c, (hl)
4306
 
     inc hl
4307
 
     ld b, (hl)
4308
 
     inc hl
4309
 
     cpir             ; inc HL searching for A until BC=0 (Z flag settled if found)
4310
 
  pop bc
4311
 
  ret nz
4312
 
 
4313
 
gfxSpriteStepCheck.search.found:
4314
 
  ld a, (GFX_SPRITE_FLAGS)   ; bits 0=chk limits, 1=chk walls, 2=chk hotspots, 3=limit touched, 4=wall touched, 5=hotspot touched, 6=collided
4315
 
  or e                       ; set touched flag
4316
 
  ld (GFX_SPRITE_FLAGS), a
4317
 
  ret
4318
 
 
4319
 
; b = x, c = y
4320
 
gfxGetTileFromXY:
4321
 
  push bc
4322
 
    ld a, c   ; y
4323
 
    srl b     ; divide by 2
4324
 
    srl b     ; divide by 4
4325
 
    srl b     ; divide by 8
4326
 
    ld c, b
4327
 
    srl a
4328
 
    srl a
4329
 
    srl a
4330
 
    ld b, a
4331
 
    call gfxGetScreenTile   ; b = y, c = x, a = tile
4332
 
  pop bc
4333
 
  ret
4334
 
 
4335
 
endif
4336
 
 
4337
 
if defined SPRITE or defined PUT_SPRITE or defined PUT_SPRITE_PATNUM or defined PUT_SPRITE_STEP_PATNUM or defined PUT_SPRITE_COLOR_PATNUM or defined PUT_SPRITE_STEP_COLOR_PATNUM
4338
 
 
4339
 
;---------------------------------------------------------------------------------------------------------
4340
 
; gfxSetSpritePattern
4341
 
; A = sprite number
4342
 
; BC = pattern number
4343
 
;---------------------------------------------------------------------------------------------------------
4344
 
 
4345
 
gfxSetSpritePattern:
4346
 
  push bc
4347
 
    call gfxCALATR   ; get sprite attribute table address
4348
 
  pop bc
4349
 
  inc hl
4350
 
  inc hl
4351
 
  ld a, (BIOS_RG1SAV)           ; bit 0 = double size, bit 1 = sprite size (0=8 pixels, 1=16 pixels)
4352
 
  bit 1, a
4353
 
  jr z, gfxSetSpritePattern.1
4354
 
    sll c
4355
 
    sll c
4356
 
gfxSetSpritePattern.1:
4357
 
  ld a, c                   ; pattern number
4358
 
  call gfxWRTVRM
4359
 
  ret
4360
 
 
4361
 
endif
4362
 
 
4363
 
if defined SPRITE
4364
 
 
4365
 
;---------------------------------------------------------------------------------------------------------
4366
 
; gfxSetSpriteData
4367
 
; HL = point to sprite data as a string of 8 or 32 characters according the sprites size (8x8 or 16x16)
4368
 
; A = sprite number
4369
 
;---------------------------------------------------------------------------------------------------------
4370
 
 
4371
 
gfxSetSpriteData:
4372
 
  push AF
4373
 
    push HL
4374
 
      call gfxCALPAT    ; get sprite pattern data address
4375
 
      ex DE, HL
4376
 
      call gfxGSPSIZ    ; return in 'a' sprite default size
4377
 
    pop HL
4378
 
    ld b, 0
4379
 
        cp c
4380
 
        jr z,  gfxSetSpriteData.1
4381
 
        jr nc, gfxSetSpriteData.1
4382
 
      ld c, a
4383
 
gfxSetSpriteData.1:
4384
 
        push bc
4385
 
          ld c, a
4386
 
      xor a
4387
 
          call gfxFILVRM
4388
 
        pop bc
4389
 
  pop AF
4390
 
  call gfxLDIRVM
4391
 
  ret
4392
 
 
4393
 
endif
4394
 
 
4395
 
if defined GFX_SPRITES
4396
 
 
4397
 
;---------------------------------------------------------------------------------------------------------
4398
 
; gfxInitSprites
4399
 
; initialises all sprites
4400
 
;---------------------------------------------------------------------------------------------------------
4401
 
 
4402
 
gfxInitSprites:
4403
 
  call gfxCLRSPR
4404
 
  ret
4405
 
 
4406
 
;---------------------------------------------------------------------------------------------------------
4407
 
; gfxSetSpriteAttrs
4408
 
; set sprite default x, y, pattern and color
4409
 
; A = sprite number
4410
 
;---------------------------------------------------------------------------------------------------------
4411
 
 
4412
 
gfxSetSpriteAttrs:
4413
 
  push af
4414
 
    call gfxCALATR
4415
 
    ld a, (BIOS_GRPACY)   ; y
4416
 
        call gfxWRTVRM
4417
 
        inc hl
4418
 
    ld a, (BIOS_GRPACX)   ; x
4419
 
        call gfxWRTVRM
4420
 
        inc hl
4421
 
  pop af                  ; pattern
4422
 
  call gfxWRTVRM
4423
 
  inc hl
4424
 
  ld a, (BIOS_FORCLR)     ; color
4425
 
  call gfxWRTVRM
4426
 
  ret
4427
 
 
4428
 
endif
4429
 
 
4430
 
if defined EXIST_DATA_SET
4431
 
 
4432
 
;---------------------------------------------------------------------------------------------------------
4433
 
; gfxIsTileMode
4434
 
;---------------------------------------------------------------------------------------------------------
4435
 
 
4436
 
gfxIsTileMode:
4437
 
    ld a, (BIOS_SCRMOD)
4438
 
    cp 2
4439
 
    ret z
4440
 
    cp 4
4441
 
    ret
4442
 
 
4443
 
;---------------------------------------------------------------------------------------------------------
4444
 
; gfxClearTileScreen
4445
 
;---------------------------------------------------------------------------------------------------------
4446
 
 
4447
 
gfxClearTileScreen:
4448
 
    ld a, 0x20           ; space
4449
 
    ld bc, 768
4450
 
    ld hl, (BIOS_GRPNAM)
4451
 
    call gfxFILVRM
4452
 
 
4453
 
    ld de, 0x0020
4454
 
    call gfxSetTileDefaultColor
4455
 
    ld de, 0x0120
4456
 
    call gfxSetTileDefaultColor
4457
 
    ld de, 0x0220
4458
 
    jp gfxSetTileDefaultColor
4459
 
 
4460
 
gfxSetTileDefaultColor
4461
 
    call gfxGetTileColorAddr
4462
 
    ex de, hl
4463
 
    call gfxGetTileDefaultColor
4464
 
    ld bc, 8
4465
 
    jp gfxFILVRM
4466
 
 
4467
 
gfxGetTileDefaultColor:
4468
 
    ld a, (BIOS_FORCLR)
4469
 
    sla a
4470
 
    sla a
4471
 
    sla a
4472
 
    sla a
4473
 
    push hl
4474
 
      ld hl, BIOS_BAKCLR
4475
 
      or (hl)
4476
 
    pop hl
4477
 
    ret
4478
 
 
4479
 
; set tile color
4480
 
; HL = tile color pointer
4481
 
; BC = tile color size
4482
 
; DE = tile number
4483
 
 
4484
 
;---------------------------------------------------------------------------------------------------------
4485
 
; gfxSetTileData
4486
 
; set tile data
4487
 
; HL = tile data pointer
4488
 
; BC = tile data size
4489
 
; DE = tile number
4490
 
; A = flip (0=no, 1=yes)
4491
 
;---------------------------------------------------------------------------------------------------------
4492
 
 
4493
 
gfxSetTileData:
4494
 
  or a
4495
 
  jr nz, gfxSetTileDataFlip
4496
 
 
4497
 
gfxSetTileDataNoFlip:
4498
 
  call gfxGetTileDataAddr
4499
 
  jp gfxLDIRVM
4500
 
 
4501
 
gfxSetTileDataFlip:
4502
 
  call gfxGetTileDataAddr
4503
 
  ex de, hl
4504
 
gfxSetTileDataFlip.Loop:
4505
 
  ld a, (de)
4506
 
  call gfxReverseA
4507
 
  call gfxWRTVRM
4508
 
  inc de
4509
 
  inc hl
4510
 
  dec bc
4511
 
  ld a, b
4512
 
  cp c
4513
 
  jr nz, gfxSetTileDataFlip.Loop
4514
 
  ret
4515
 
 
4516
 
; in de = tile number
4517
 
; out de = tile number address
4518
 
gfxGetTileDataAddr:
4519
 
  push hl
4520
 
    ex de, hl
4521
 
    add hl, hl
4522
 
    add hl, hl
4523
 
    add hl, hl   ; tile number * 8
4524
 
    ld de, (BIOS_GRPCGP)
4525
 
    add hl, de
4526
 
    ex de, hl
4527
 
  pop hl
4528
 
  ret
4529
 
 
4530
 
;---------------------------------------------------------------------------------------------------------
4531
 
; gfxSetTileColor
4532
 
; set tile color
4533
 
; HL = tile color pointer
4534
 
; BC = tile color size
4535
 
; DE = tile number
4536
 
;---------------------------------------------------------------------------------------------------------
4537
 
 
4538
 
gfxSetTileColor:
4539
 
  call gfxGetTileColorAddr
4540
 
  jp gfxLDIRVM
4541
 
 
4542
 
; in de = tile number
4543
 
; out de = tile number address
4544
 
gfxGetTileColorAddr:
4545
 
  push hl
4546
 
    ex de, hl
4547
 
    add hl, hl
4548
 
    add hl, hl
4549
 
    add hl, hl   ; tile number * 8
4550
 
    ld de, (BIOS_GRPCOL)
4551
 
    add hl, de
4552
 
    ex de, hl
4553
 
  pop hl
4554
 
  ret
4555
 
 
4556
 
;---------------------------------------------------------------------------------------------------------
4557
 
; gfxSetScreenTile
4558
 
; set screen tile at x,y
4559
 
; C = x
4560
 
; B = y
4561
 
; a = tile number
4562
 
;---------------------------------------------------------------------------------------------------------
4563
 
 
4564
 
gfxSetScreenTile:
4565
 
  ex af, af'
4566
 
  ld a, 23
4567
 
  cp b
4568
 
  ret c
4569
 
  ld a, 31
4570
 
  cp c
4571
 
  ret c
4572
 
  ;push bc
4573
 
  ;  ld h, 0
4574
 
  ;  ld l, b      ; slow y * 32
4575
 
  ;  ld bc, 32
4576
 
  ;  call MATH.MULT.16
4577
 
  ;pop bc
4578
 
  ld h, b
4579
 
  sra h
4580
 
  sra h
4581
 
  sra h
4582
 
  ld l, b
4583
 
  sla l
4584
 
  sla l
4585
 
  sla l
4586
 
  sla l
4587
 
  sla l            ; fast y * 32
4588
 
  ld d, 0
4589
 
  ld e, c        ; x
4590
 
  add hl, de
4591
 
  ld de, (BIOS_GRPNAM)
4592
 
  add hl, de
4593
 
  ex af, af'
4594
 
  jp gfxWRTVRM
4595
 
 
4596
 
endif
4597
 
 
4598
 
if defined gfxGetTileFromXY or defined EXIST_DATA_SET
4599
 
 
4600
 
;---------------------------------------------------------------------------------------------------------
4601
 
; gfxGetScreenTile
4602
 
; get screen tile at x,y
4603
 
; C = x
4604
 
; B = y
4605
 
; a = tile number
4606
 
;---------------------------------------------------------------------------------------------------------
4607
 
 
4608
 
gfxGetScreenTile:
4609
 
  ld a, 23
4610
 
  cp b
4611
 
  ret c
4612
 
  ld a, 31
4613
 
  cp c
4614
 
  ret c
4615
 
  ld h, b
4616
 
  sra h
4617
 
  sra h
4618
 
  sra h
4619
 
  ld l, b
4620
 
  sla l
4621
 
  sla l
4622
 
  sla l
4623
 
  sla l
4624
 
  sla l            ; fast y * 32
4625
 
  ld d, 0
4626
 
  ld e, c        ; x
4627
 
  add hl, de
4628
 
  ld de, (BIOS_GRPNAM)
4629
 
  add hl, de
4630
 
  jp gfxRDVRM
4631
 
 
4632
 
endif
4633
 
 
4634
 
;---------------------------------------------------------------------------------------------------------
4635
 
; Sprite collision table routines
4636
 
;---------------------------------------------------------------------------------------------------------
4637
 
 
4638
 
gfxInitSpriteCollisionTable:
4639
 
  ld bc, 128
4640
 
  call memory.alloc
4641
 
  ld (GFX_SPRITE_COLLISION), ix
4642
 
  ret
4643
 
 
4644
 
; copy sprite attribute table to ram
4645
 
gfxFillSpriteCollisionTable:
4646
 
  ld hl, (BIOS_ATRBAS)          ; source: attribute table
4647
 
  ld de, (GFX_SPRITE_COLLISION) ; dest: ram
4648
 
  ld bc, 128                    ; 32*4 = size of attribute table
4649
 
  call gfxLDIRMV
4650
 
 
4651
 
; pre-calculate each sprite width
4652
 
gfxCalculateSpriteCollisionTable:
4653
 
  ld ix, (GFX_SPRITE_COLLISION)   ; start of sprites attributes
4654
 
  ld b, 32                        ; sprite count
4655
 
 
4656
 
gfxCalculateSpriteCollisionTable.start:
4657
 
  ld a, (GFX_SPRITE_SIZE_DAT)     ; sprite size
4658
 
  ld c, a
4659
 
  ld d, 208                       ; Y no-display flag
4660
 
 
4661
 
  ; test screen mode
4662
 
  ld a, (BIOS_SCRMOD)
4663
 
  cp 3           ; above screen 3?
4664
 
  jr c, gfxCalculateSpriteCollisionTable.next
4665
 
        ld d, 216    ; Y no-display flag
4666
 
 
4667
 
gfxCalculateSpriteCollisionTable.next:
4668
 
  ; test IC flag (no collision) in color table
4669
 
  ; test EC flag (early clock, shift 32 dots to the left) in color table
4670
 
  ; set x1 = x + size, y1 = y + size
4671
 
  ld a, (ix)   ; y
4672
 
  cp d         ; test if sprite will not be displayed
4673
 
  ret z
4674
 
 
4675
 
  add a, c
4676
 
  ld (ix+2), a ; y1
4677
 
  ld a, (ix+1) ; x
4678
 
  add a, c
4679
 
  ld (ix+3), a ; x1
4680
 
 
4681
 
  inc ix
4682
 
  inc ix
4683
 
  inc ix
4684
 
  inc ix
4685
 
  djnz gfxCalculateSpriteCollisionTable.next
4686
 
  ret
4687
 
 
4688
 
; BC = sprite number to check
4689
 
gfxUpdateSpriteCollisionTable:
4690
 
  ld (BIOS_TEMP), bc
4691
 
  ld h, b
4692
 
  ld l, c
4693
 
  add hl, hl
4694
 
  add hl, hl
4695
 
  ld b, h
4696
 
  ld c, l
4697
 
  ld hl, (GFX_SPRITE_COLLISION) ; dest: ram
4698
 
  add hl, bc
4699
 
  ex de, hl
4700
 
  ld hl, (BIOS_ATRBAS)          ; source: attribute table
4701
 
  add hl, bc
4702
 
  ld bc, 4                      ; 4 = size of attribute table to 1 sprite]
4703
 
  push de
4704
 
    call gfxLDIRMV
4705
 
  pop ix
4706
 
  ld b, 1                       ; sprite count
4707
 
  push ix
4708
 
    call gfxCalculateSpriteCollisionTable.start
4709
 
  pop iy
4710
 
 
4711
 
  ld a, (GFX_SPRITE_FLAGS)
4712
 
  and 0xBF                      ; clear collision flag
4713
 
  ld (GFX_SPRITE_FLAGS), a
4714
 
 
4715
 
  ld a, (BIOS_STATFL)           ; verify if collision occurred
4716
 
  bit 5, a
4717
 
  ret z
4718
 
  jr gfxCheckSpriteCollisionTable.start
4719
 
 
4720
 
; BC = sprite number to check
4721
 
gfxCheckSpriteCollisionTable:
4722
 
  ; get target sprite address (iy)
4723
 
  ld (BIOS_TEMP), bc
4724
 
  ld h, b
4725
 
  ld l, c
4726
 
  ld de, (GFX_SPRITE_COLLISION)
4727
 
  add hl, hl            ; x4
4728
 
  add hl, hl
4729
 
  add hl, de
4730
 
  push hl
4731
 
  pop iy
4732
 
 
4733
 
gfxCheckSpriteCollisionTable.start:
4734
 
  ; start test against others sprites
4735
 
  ld ix, (GFX_SPRITE_COLLISION)
4736
 
  ld bc, 0
4737
 
  ld d, 208      ; Y no-display flag
4738
 
 
4739
 
  ; test screen mode
4740
 
  ld a, (BIOS_SCRMOD)
4741
 
  cp 3           ; above screen 3?
4742
 
  jr c, gfxCheckSpriteCollisionTable.test
4743
 
    ld d, 216    ; Y no-display flag
4744
 
 
4745
 
gfxCheckSpriteCollisionTable.test:
4746
 
  ; skip target sprite
4747
 
  ld a, (BIOS_TEMP)
4748
 
  cp c
4749
 
  jr z, gfxCheckSpriteCollisionTable.next
4750
 
 
4751
 
  ; test if x1 > nx and x < nx1 and y1 > ny and y < ny1
4752
 
  ld a, (ix)   ; ny
4753
 
  cp d         ; test if sprite will not be displayed
4754
 
  ret z        ; return false
4755
 
 
4756
 
  cp (iy+2)    ; y1
4757
 
  jr nc, gfxCheckSpriteCollisionTable.next
4758
 
 
4759
 
  ld a, (ix+1) ; nx
4760
 
  cp (iy+3)    ; x1
4761
 
  jr nc, gfxCheckSpriteCollisionTable.next
4762
 
 
4763
 
  ld a, (iy+1) ; x
4764
 
  cp (ix+3)    ; nx1
4765
 
  jr nc, gfxCheckSpriteCollisionTable.next
4766
 
 
4767
 
  ld a, (iy)   ; y
4768
 
  cp (ix+2)    ; ny1
4769
 
  jr nc, gfxCheckSpriteCollisionTable.next
4770
 
 
4771
 
  ; if so, save collider sprite
4772
 
  ld a, c
4773
 
  ld (GFX_SPRITE_COLLIDER), a
4774
 
 
4775
 
  ld a, (GFX_SPRITE_FLAGS)
4776
 
  or 0x40                      ; set collision flag
4777
 
  ld (GFX_SPRITE_FLAGS), a
4778
 
  ret                          ; return true
4779
 
 
4780
 
  ; else, next
4781
 
gfxCheckSpriteCollisionTable.next:
4782
 
  inc c
4783
 
  inc ix
4784
 
  inc ix
4785
 
  inc ix
4786
 
  inc ix
4787
 
  ld a, 32
4788
 
  cp c
4789
 
  ret z                           ; return false
4790
 
  jr gfxCheckSpriteCollisionTable.test
4791
 
 
4792
 
 
4793
 
 
4794
 
;---------------------------------------------------------------------------------------------------------
4795
 
; VDP / VRAM support routines
4796
 
;---------------------------------------------------------------------------------------------------------
4797
 
 
4798
 
; WRITE TO VDP
4799
 
; in b = data
4800
 
;    c = register number
4801
 
;    a = register number
4802
 
gfxWRTVDP:
4803
 
  bit 7, a
4804
 
  ret nz                ; is negative? read only
4805
 
  cp 8
4806
 
  ret z                 ; is register 8? then status register 0 (read only)
4807
 
  jr nc, gfxWRTVDP.1    ; is > 8? then control registers numbers added 1
4808
 
  jr gfxWRTVDP.3
4809
 
gfxWRTVDP.1:
4810
 
  ld ix, BIOS_SCRMOD
4811
 
  bit 3, (ix)
4812
 
  jr nz, gfxWRTVDP.2
4813
 
  bit 2, (ix)
4814
 
  jr nz, gfxWRTVDP.2
4815
 
  ret
4816
 
gfxWRTVDP.2:
4817
 
  dec a
4818
 
  ld c, a
4819
 
gfxWRTVDP.3:
4820
 
  ;ld ix, BIOS_SCRMOD
4821
 
  ;bit 3, (ix)
4822
 
  ;jp nz, BIOS_NWRVDP    ; msx 2
4823
 
  ;bit 2, (ix)
4824
 
  ;jp nz, BIOS_NWRVDP    ; msx 2
4825
 
  jp BIOS_WRTVDP        ; msx 1
4826
 
 
4827
 
; READ FROM VDP
4828
 
; in  a = register number
4829
 
; out a = data
4830
 
gfxRDVDP:
4831
 
  bit 7, a
4832
 
  jr nz, gfxRDVDP.1     ; is negative? then status register 1 to 9
4833
 
  cp 8
4834
 
  jr z,  gfxRDVDP.2     ; is register 8? then status register 0
4835
 
  cp 9
4836
 
  jr nc, gfxRDVDP.3     ; is >= 9? then control registers numbers added 1
4837
 
    ld hl, BIOS_RG0SAV  ; else is correct control registers numbers
4838
 
    jr gfxRDVDP.4
4839
 
gfxRDVDP.1:
4840
 
  ld ix, BIOS_SCRMOD
4841
 
  bit 3, (ix)
4842
 
  jr nz, gfxRDVDP.1.a
4843
 
  bit 2, (ix)
4844
 
  jr nz, gfxRDVDP.1.a
4845
 
  xor a
4846
 
  ret
4847
 
gfxRDVDP.1.a:
4848
 
  neg
4849
 
  jp BIOS_NRDVDP   ;BIOS_VDPSTA
4850
 
gfxRDVDP.2:
4851
 
  ld a, (BIOS_STATFL)
4852
 
  ret
4853
 
  ;xor a
4854
 
  ;jp BIOS_VDPSTA
4855
 
gfxRDVDP.3:
4856
 
  ld hl, BIOS_RG8SAV-9
4857
 
gfxRDVDP.4:
4858
 
  ld d, 0
4859
 
  ld e, a
4860
 
  add hl,de
4861
 
  ld a, (hl)
4862
 
  ret
4863
 
 
4864
 
; in: A=Data byte, BC=Length, HL=VRAM address
4865
 
gfxFILVRM:
4866
 
  ld ix, BIOS_SCRMOD
4867
 
  bit 3, (ix)
4868
 
  jp nz, BIOS_BIGFIL
4869
 
  bit 2, (ix)
4870
 
  jp nz, BIOS_BIGFIL
4871
 
  jp BIOS_FILVRM
4872
 
 
4873
 
; in: A=Sprite pattern number
4874
 
; out: HL=Sprite pattern address
4875
 
gfxCALPAT:
4876
 
  ld iy, BIOS_SCRMOD
4877
 
  ld ix, BIOS_CALPAT2
4878
 
  bit 3, (iy)
4879
 
  jp nz, BIOS_EXTROM
4880
 
  bit 2, (iy)
4881
 
  jp nz, BIOS_EXTROM
4882
 
  jp BIOS_CALPAT
4883
 
 
4884
 
; in: A=Sprite number
4885
 
; out: HL=Sprite attribute address
4886
 
gfxCALATR:
4887
 
  ld iy, BIOS_SCRMOD
4888
 
  ld ix, BIOS_CALATR2
4889
 
  bit 3, (iy)
4890
 
  jp nz, BIOS_EXTROM
4891
 
  bit 2, (iy)
4892
 
  jp nz, BIOS_EXTROM
4893
 
  jp BIOS_CALATR
4894
 
 
4895
 
; out: A=Bytes in sprite pattern (8 or 32)
4896
 
gfxGSPSIZ:
4897
 
  ld iy, BIOS_SCRMOD
4898
 
  ld ix, BIOS_GSPSIZ2
4899
 
  bit 3, (iy)
4900
 
  jp nz, BIOS_EXTROM
4901
 
  bit 2, (iy)
4902
 
  jp nz, BIOS_EXTROM
4903
 
  jp BIOS_GSPSIZ
4904
 
 
4905
 
gfxCLRSPR:
4906
 
  ld iy, BIOS_SCRMOD
4907
 
  ld ix, BIOS_CLRSPR2
4908
 
  bit 3, (iy)
4909
 
  jp nz, BIOS_EXTROM
4910
 
  bit 2, (iy)
4911
 
  jp nz, BIOS_EXTROM
4912
 
  jp BIOS_CLRSPR
4913
 
 
4914
 
; RAM to VRAM
4915
 
; in: BC=Length, dest DE=VRAM address, source HL=RAM address
4916
 
gfxLDIRVM:
4917
 
  jp BIOS_LDIRVM
4918
 
 
4919
 
; VRAM to RAM
4920
 
; in: BC=Length, dest DE=RAM address, source HL=VRAM address
4921
 
gfxLDIRMV:
4922
 
  jp BIOS_LDIRMV
4923
 
 
4924
 
; WRITE TO VRAM
4925
 
; in hl = address
4926
 
;     a = data
4927
 
gfxWRTVRM:
4928
 
  ld ix, BIOS_SCRMOD
4929
 
  bit 3, (ix)
4930
 
  jp nz, BIOS_NWRVRM
4931
 
  bit 2, (ix)
4932
 
  jp nz, BIOS_NWRVRM
4933
 
  jp BIOS_WRTVRM
4934
 
 
4935
 
; READ FROM VRAM
4936
 
; in hl = address
4937
 
; out a = data
4938
 
gfxRDVRM:
4939
 
  ld ix, BIOS_SCRMOD
4940
 
  bit 3, (ix)
4941
 
  jp nz, BIOS_NRDVRM
4942
 
  bit 2, (ix)
4943
 
  jp nz, BIOS_NRDVRM
4944
 
  jp BIOS_RDVRM
4945
 
 
4946
 
; reverse bits in A
4947
 
; 8 bytes / 206 cycles
4948
 
; http://www.retroprogramming.com/2014/01/fast-z80-bit-reversal.html
4949
 
gfxReverseA:
4950
 
  ld b,8
4951
 
  ld l,a
4952
 
gfxReverseA.loop:
4953
 
  rl l
4954
 
  rra
4955
 
  djnz gfxReverseA.loop
4956
 
  ret
4957
 
 
4958
 
 
4959
 
 
4960
 
;---------------------------------------------------------------------------------------------------------
4961
 
; MATH PACK WRAPPER
4962
 
;---------------------------------------------------------------------------------------------------------
4963
 
 
4964
 
CALL_MATH_LIB: exx
4965
 
                             ld hl, RET_MATH_LIB
4966
 
                             push hl
4967
 
                   ld hl, BASIC_DAC
4968
 
                   ld de, BASIC_ARG
4969
 
                               ld bc, BASIC_SWPTMP
4970
 
                   jp (ix)
4971
 
RET_MATH_LIB:    call COPY_TO.TMP_DAC
4972
 
               exx
4973
 
               ret
4974
 
 
4975
 
if defined MATH.ADD
4976
 
 
4977
 
MATH_DECADD:   ld ix, addSingle
4978
 
               jp CALL_MATH_LIB
4979
 
 
4980
 
endif
4981
 
 
4982
 
if defined MATH.SUB or defined MATH.NEG
4983
 
 
4984
 
MATH_DECSUB:   ld ix, subSingle
4985
 
                           jp CALL_MATH_LIB
4986
 
 
4987
 
endif
4988
 
 
4989
 
if defined MATH.MULT
4990
 
 
4991
 
MATH_DECMUL:   ld ix, mulSingle
4992
 
                           jp CALL_MATH_LIB
4993
 
 
4994
 
endif
4995
 
 
4996
 
if defined MATH.DIV
4997
 
 
4998
 
MATH_DECDIV:   ld ix, divSingle
4999
 
                           jp CALL_MATH_LIB
5000
 
 
5001
 
endif
5002
 
 
5003
 
if defined MATH.POW
5004
 
 
5005
 
MATH_DBLEXP:
5006
 
MATH_SNGEXP:   ld ix, powSingle
5007
 
                           jp CALL_MATH_LIB
5008
 
 
5009
 
endif
5010
 
 
5011
 
if defined COS
5012
 
 
5013
 
MATH_COS:      ld ix, cosSingle
5014
 
                           jp CALL_MATH_LIB
5015
 
 
5016
 
endif
5017
 
 
5018
 
if defined SIN
5019
 
 
5020
 
MATH_SIN:      ld ix, sinSingle
5021
 
                           jp CALL_MATH_LIB
5022
 
 
5023
 
endif
5024
 
 
5025
 
if defined TAN
5026
 
 
5027
 
MATH_TAN:      ld ix, tanSingle
5028
 
                           jp CALL_MATH_LIB
5029
 
 
5030
 
endif
5031
 
 
5032
 
if defined ATN
5033
 
 
5034
 
MATH_ATN:      ld ix, atanSingle
5035
 
                           jp CALL_MATH_LIB
5036
 
 
5037
 
endif
5038
 
 
5039
 
if defined SQR
5040
 
 
5041
 
MATH_SQR:      ld ix, sqrtSingle
5042
 
                           jp CALL_MATH_LIB
5043
 
 
5044
 
endif
5045
 
 
5046
 
if defined LOG
5047
 
 
5048
 
MATH_LOG:      ld ix, lnSingle
5049
 
                           jp CALL_MATH_LIB
5050
 
 
5051
 
endif
5052
 
 
5053
 
if defined EXP
5054
 
 
5055
 
MATH_EXP:      ld ix, expSingle
5056
 
                           jp CALL_MATH_LIB
5057
 
 
5058
 
endif
5059
 
 
5060
 
if defined ABS
5061
 
 
5062
 
MATH_ABSFN:    ld ix, absSingle
5063
 
                           jp CALL_MATH_LIB
5064
 
 
5065
 
endif
5066
 
 
5067
 
if defined MATH.SEED or defined MATH.NEG
5068
 
 
5069
 
MATH_NEG:      ld ix, negSingle
5070
 
                           jp CALL_MATH_LIB
5071
 
 
5072
 
endif
5073
 
 
5074
 
if defined SGN
5075
 
 
5076
 
MATH_SGN:      ld ix, sgnSingle
5077
 
                           jp CALL_MATH_LIB
5078
 
 
5079
 
endif
5080
 
 
5081
 
if defined RND or defined MATH.SEED
5082
 
 
5083
 
MATH_RND:      ld ix, randSingle
5084
 
               jp CALL_MATH_LIB
5085
 
 
5086
 
endif
5087
 
 
5088
 
MATH_FRCINT:   ld hl, BASIC_DAC
5089
 
               ld bc, BASIC_DAC+2
5090
 
                           call single2Int
5091
 
                           ld ix, BASIC_DAC
5092
 
                           ld (ix), 0
5093
 
                           ld (ix+1), 0
5094
 
                           ;ld (ix+2), l
5095
 
                           ;ld (ix+3), h
5096
 
                           ld (ix+4), 0
5097
 
                           ld (ix+5), 0
5098
 
                           ld (ix+6), 0
5099
 
                           ld (ix+7), 0
5100
 
               ld a, 2
5101
 
               ld (BASIC_VALTYP), a
5102
 
               ret
5103
 
 
5104
 
MATH_FRCDBL:                         ; same as MATH_FRCSGL
5105
 
MATH_FRCSGL:   ld hl, BASIC_DAC+2    ; input address
5106
 
               ld bc, BASIC_DAC      ; output address
5107
 
               call int2Single
5108
 
               ld a, 8
5109
 
               ld (BASIC_VALTYP), a
5110
 
               ret
5111
 
 
5112
 
MATH_ICOMP:         ld a, h   ; cp hl, de (alternative to bios DCOMPR)
5113
 
                    cp d
5114
 
                                jr nz, MATH_ICOMP.NE.HIGH
5115
 
                                  ld a, l
5116
 
                                  cp e
5117
 
                                  jr nz, MATH_ICOMP.NE.LOW
5118
 
                        jr MATH_DCOMP.EQ
5119
 
MATH_ICOMP.NE.HIGH: jr c, MATH_ICOMP.GT.HIGH
5120
 
                    bit 7, a
5121
 
                    jr nz, MATH_DCOMP.GT
5122
 
                                  jr MATH_DCOMP.LT
5123
 
MATH_ICOMP.GT.HIGH: bit 7, d
5124
 
                    jr z, MATH_DCOMP.GT
5125
 
                                  jr MATH_DCOMP.LT
5126
 
MATH_ICOMP.NE.LOW:  jr c, MATH_DCOMP.GT
5127
 
                                  jr MATH_DCOMP.LT
5128
 
 
5129
 
MATH_XDCOMP:                          ; same as MATH_DCOMP
5130
 
MATH_DCOMP:    ld ix, cmpSingle
5131
 
                           call CALL_MATH_LIB
5132
 
                           jr z, MATH_DCOMP.EQ
5133
 
                           jr c, MATH_DCOMP.LT
5134
 
MATH_DCOMP.GT: ld a, 0xFF             ; DAC > ARG
5135
 
               ret
5136
 
MATH_DCOMP.EQ: ld a, 0                ; DAC = ARG
5137
 
               ret
5138
 
MATH_DCOMP.LT: ld a, 1                ; DAC < ARG
5139
 
               ret
5140
 
 
5141
 
if defined CAST_STR_TO.VAL
5142
 
 
5143
 
MATH_FIN:      ; HL has the source string
5144
 
               ld a, (BASIC_VALTYP)
5145
 
               cp 2                   ; test if integer
5146
 
                           jr nz, MATH_FIN.1
5147
 
                           ld hl, (BASIC_DAC+2)
5148
 
                           ld de, BASIC_STRBUF
5149
 
                           call StrToInt
5150
 
                           ld hl, BASIC_STRBUF
5151
 
                           ret
5152
 
MATH_FIN.1:        ld BC, BASIC_DAC
5153
 
                           call str2single
5154
 
               ret
5155
 
 
5156
 
endif
5157
 
 
5158
 
if defined CAST_INT_TO.STR
5159
 
 
5160
 
MATH_FOUT:     ld a, (BASIC_VALTYP)
5161
 
               cp 2                   ; test if integer
5162
 
                           jr nz, MATH_FOUT.1
5163
 
                           ld hl, (BASIC_DAC+2)
5164
 
                           ld de, BASIC_STRBUF
5165
 
                           call IntToStr
5166
 
                           ld hl, BASIC_STRBUF
5167
 
                           ret
5168
 
MATH_FOUT.1:   ld hl, BASIC_DAC
5169
 
               ld bc, BASIC_STRBUF
5170
 
               call single2str
5171
 
                           ld hl, BASIC_STRBUF
5172
 
               ret
5173
 
 
5174
 
endif
5175
 
 
5176
 
 
5177
 
 
5178
 
 
5179
 
;---------------------------------------------------------------------------------------------------------
5180
 
; Z80FLOAT LIBRARY
5181
 
; Copyright 2018 Zeda A.K. Thomas
5182
 
;---------------------------------------------------------------------------------------------------------
5183
 
; References:
5184
 
; https://github.com/Zeda/z80float
5185
 
; https://www.omnimaga.org/asm-language/(z80)-floating-point-routines/
5186
 
; https://en.wikipedia.org/wiki/Single-precision_floating-point_format
5187
 
;---------------------------------------------------------------------------------------------------------
5188
 
; Parameters:
5189
 
; HL points to the first operand
5190
 
; DE points to the second operand (if needed)
5191
 
; IX points to the third operand (if needed, rare)
5192
 
; BC points to where the result should be output
5193
 
; Floats are stored by a little-endian 24-bit mantissa. However, the highest bit
5194
 
; is taken as implicitly 1, so we replace it as a sign bit. Next comes an 8-bit
5195
 
; exponent biased by +128.
5196
 
;---------------------------------------------------------------------------------------------------------
5197
 
; Adapted to MSXBas2Asm by Amaury Carvalho, 2019
5198
 
;---------------------------------------------------------------------------------------------------------
5199
 
 
5200
 
;---------------------------------------------------------------------------------------------------------
5201
 
; Work area
5202
 
;---------------------------------------------------------------------------------------------------------
5203
 
 
5204
 
BASIC_HOLD8: equ 0xF806  ;      48      Work area for decimal multiplications.
5205
 
BASIC_HOLD2: equ 0xF836  ;      8       Work area in the execution of numerical operators.
5206
 
BASIC_HOLD:  equ 0xF83E  ;  8   Work area in the execution of numerical operators.
5207
 
scrap:   equ BASIC_HOLD8
5208
 
seed0:   equ BASIC_RNDX
5209
 
seed1:   equ seed0 + 4
5210
 
var48:   equ scrap + 4
5211
 
quot:    equ scrap + 1
5212
 
addend:  equ scrap
5213
 
addend2: equ scrap+7           ;4 bytes
5214
 
var_x:   equ BASIC_HOLD8 + 4   ;4 bytes
5215
 
var_y:   equ var_x + 4         ;4 bytes
5216
 
var_z:   equ var_y + 4         ;4 bytes
5217
 
var_a:   equ var_z + 4         ;4 bytes
5218
 
var_b:   equ var_a + 4         ;4 bytes
5219
 
var_c:   equ var_b + 4         ;4 bytes
5220
 
temp:    equ var_c + 4         ;4 bytes
5221
 
temp1:   equ temp  + 4         ;4 bytes
5222
 
temp2:   equ temp1 + 4         ;4 bytes
5223
 
temp3:   equ temp2 + 4         ;4 bytes
5224
 
 
5225
 
pow10exp_single: equ scrap+9
5226
 
strout_single:   equ 0xF750    ;  PARM2 - BASIC_BUF   ;pow10exp_single+2
5227
 
 
5228
 
;---------------------------------------------------------------------------------------------------------
5229
 
; addSingle
5230
 
;---------------------------------------------------------------------------------------------------------
5231
 
 
5232
 
;;Still need to tend to special cases
5233
 
addSingle:
5234
 
;;x+y
5235
 
    push af
5236
 
    push hl
5237
 
    push de
5238
 
    push bc
5239
 
addInject:
5240
 
    inc de
5241
 
    inc de
5242
 
    inc hl
5243
 
    inc hl
5244
 
    ld a,(de)
5245
 
    xor (hl)
5246
 
    push af
5247
 
    inc de
5248
 
    inc hl
5249
 
    ex de,hl
5250
 
    ld a,(de)
5251
 
    sub (hl)
5252
 
    ex de,hl
5253
 
    jr nc,$+5
5254
 
    ex de,hl
5255
 
    neg
5256
 
    cp 24
5257
 
    jp nc,add_unneeded
5258
 
    push hl
5259
 
    ld hl,addend+6
5260
 
    dec de
5261
 
    ld bc,0408h
5262
 
    dec hl
5263
 
    ld (hl),0
5264
 
    sub c
5265
 
    jr nc,$-5
5266
 
    add a,c
5267
 
    push af
5268
 
    push hl
5269
 
    ex de,hl
5270
 
    ld a,(hl)
5271
 
    or 80h
5272
 
    ld (de),a
5273
 
    dec de
5274
 
    dec hl
5275
 
    ldd
5276
 
    ldd
5277
 
    ex de,hl
5278
 
    dec b
5279
 
    jr z,$+7
5280
 
    ld (hl),0
5281
 
    dec hl
5282
 
    djnz $-3
5283
 
    pop hl
5284
 
    pop af
5285
 
    ld b,a
5286
 
    jr z,noshift
5287
 
    set 7,(hl)
5288
 
_1:
5289
 
    push hl
5290
 
    srl (hl)
5291
 
    dec hl
5292
 
    rr (hl)
5293
 
    dec hl
5294
 
    rr (hl)
5295
 
    dec hl
5296
 
    rr (hl)
5297
 
    pop hl
5298
 
    djnz _1
5299
 
noshift:
5300
 
    pop hl  ;bigger float
5301
 
    dec hl
5302
 
    ld b,(hl)
5303
 
    dec hl
5304
 
    dec hl
5305
 
    ex de,hl
5306
 
    pop af
5307
 
    jp m,subtract
5308
 
    ld hl,addend+2
5309
 
    ld a,(hl)
5310
 
    rla
5311
 
    inc hl
5312
 
    ld a,(de)
5313
 
    adc a,(hl)
5314
 
    ld (hl),a
5315
 
    inc hl
5316
 
    inc de
5317
 
    ld a,(de)
5318
 
    adc a,(hl)
5319
 
    ld (hl),a
5320
 
    inc hl
5321
 
    inc de
5322
 
    ld a,(de)
5323
 
    set 7,a
5324
 
    adc a,(hl)
5325
 
    ld (hl),a
5326
 
    inc hl
5327
 
    inc de
5328
 
    ld a,(de)
5329
 
    ld (hl),a
5330
 
    jp nc,add_done
5331
 
    inc (hl)
5332
 
    jp z,add_overflow
5333
 
    dec hl
5334
 
    rr (hl)
5335
 
    dec hl
5336
 
    rr (hl)
5337
 
    dec hl
5338
 
    rr (hl)
5339
 
    jp add_done
5340
 
subtract:
5341
 
    ld hl,addend
5342
 
    xor a
5343
 
    ld c,a
5344
 
    sub (hl)
5345
 
    ld (hl),a
5346
 
    inc hl
5347
 
    ld a,c
5348
 
    sbc a,(hl)
5349
 
    ld (hl),a
5350
 
    inc hl
5351
 
    ld a,c
5352
 
    sbc a,(hl)
5353
 
    ld (hl),a
5354
 
    inc hl
5355
 
    ld a,(de)
5356
 
    sbc a,(hl)
5357
 
    ld (hl),a
5358
 
    inc hl
5359
 
    inc de
5360
 
    ld a,(de)
5361
 
    sbc a,(hl)
5362
 
    ld (hl),a
5363
 
    inc hl
5364
 
    inc de
5365
 
    ld a,(de)
5366
 
    set 7,a
5367
 
    sbc a,(hl)
5368
 
    ld (hl),a
5369
 
    inc hl
5370
 
    inc de
5371
 
    ld a,(de)
5372
 
    ld (hl),a
5373
 
    dec de
5374
 
    ex de,hl
5375
 
    jr nc,negated
5376
 
    ld hl,addend
5377
 
    ld a,80h
5378
 
    xor b
5379
 
    ld b,a
5380
 
    ld a,c
5381
 
    sub (hl)
5382
 
    ld (hl),a
5383
 
    inc hl
5384
 
    ld a,c
5385
 
    sbc a,(hl)
5386
 
    ld (hl),a
5387
 
    inc hl
5388
 
    ld a,c
5389
 
    sbc a,(hl)
5390
 
    ld (hl),a
5391
 
    inc hl
5392
 
    ld a,c
5393
 
    sbc a,(hl)
5394
 
    ld (hl),a
5395
 
    inc hl
5396
 
    ld a,c
5397
 
    sbc a,(hl)
5398
 
    ld (hl),a
5399
 
    inc hl
5400
 
    ld a,c
5401
 
    sbc a,(hl)
5402
 
    ld (hl),a
5403
 
negated:
5404
 
    jp m,add_done
5405
 
    push bc
5406
 
    ld hl,(addend)
5407
 
    ld de,(addend+2)
5408
 
    ld bc,(addend+4)
5409
 
    ld a,h
5410
 
    or l
5411
 
    or d
5412
 
    or e
5413
 
    or b
5414
 
    or c
5415
 
    jp z,add_underflow
5416
 
    ld a,(addend+6)
5417
 
normalize:
5418
 
    dec a
5419
 
    jr z,add_underflow
5420
 
    add hl,hl
5421
 
    rl e
5422
 
    rl d
5423
 
    rl c
5424
 
    rl b
5425
 
    jp p,normalize
5426
 
    ld (addend),hl
5427
 
    ld (addend+2),de
5428
 
    ld (addend+4),bc
5429
 
    ld (addend+6),a
5430
 
    pop bc
5431
 
add_done:
5432
 
;;Need to adjust sign flag
5433
 
    ld hl,addend+5
5434
 
    ld a,(hl)
5435
 
    rla
5436
 
    rl b
5437
 
    rra
5438
 
    ld (hl),a
5439
 
    dec hl
5440
 
    dec hl
5441
 
add_copy:
5442
 
    pop de
5443
 
    push de
5444
 
    ldi
5445
 
    ldi
5446
 
    ldi
5447
 
    ld a,(hl)
5448
 
    ld (de),a
5449
 
    pop bc
5450
 
    pop de
5451
 
    pop hl
5452
 
    pop af
5453
 
    ret
5454
 
add_underflow:
5455
 
;;How many push/pops are needed?
5456
 
;;return ZERO
5457
 
    ld hl,0
5458
 
    ld (addend+3),hl
5459
 
    ld (addend+5),hl
5460
 
    pop bc
5461
 
    jr add_done
5462
 
add_overflow:
5463
 
;;How many push/pops are needed?
5464
 
;;return INF
5465
 
    dec hl
5466
 
    ld (hl),40h
5467
 
    jr add_done
5468
 
add_unneeded:
5469
 
;;How many push/pops are needed?
5470
 
;;Return bigger number
5471
 
    pop af
5472
 
    dec hl
5473
 
    dec hl
5474
 
    dec hl
5475
 
    jr add_copy
5476
 
 
5477
 
;---------------------------------------------------------------------------------------------------------
5478
 
; subSingle
5479
 
;---------------------------------------------------------------------------------------------------------
5480
 
 
5481
 
subSingle:
5482
 
;;x-y
5483
 
    push af
5484
 
    push hl
5485
 
    push de
5486
 
    push bc
5487
 
    push hl
5488
 
    ex de,hl
5489
 
    ld de,addend2
5490
 
    ldi
5491
 
    ldi
5492
 
    ld a,(hl)
5493
 
    xor 80h
5494
 
    ld (de),a
5495
 
    inc de
5496
 
    inc hl
5497
 
    ld a,(hl)
5498
 
    ld (de),a
5499
 
    ex de,hl
5500
 
    pop hl
5501
 
    ld de,addend2
5502
 
    jp addInject    ;jumps in to the addSingle routine
5503
 
 
5504
 
;---------------------------------------------------------------------------------------------------------
5505
 
; mulSingle
5506
 
;---------------------------------------------------------------------------------------------------------
5507
 
 
5508
 
mulSingle:
5509
 
;Inputs: HL points to float1, DE points to float2, BC points to where the result is copied
5510
 
;Outputs: float1*float2 is stored to (BC)
5511
 
;573+mul24+{0,35}+{0,30}
5512
 
;min: 1398cc
5513
 
;max: 2564cc
5514
 
;avg: 2055.13839751681cc
5515
 
    push af
5516
 
    push hl
5517
 
    push de
5518
 
    push bc
5519
 
 
5520
 
    call _2   ;CHLB
5521
 
    ld a,c
5522
 
    ex de,hl
5523
 
    pop hl
5524
 
    push hl
5525
 
    ld (hl),b
5526
 
    inc hl
5527
 
    ld (hl),e
5528
 
    inc hl
5529
 
    ld (hl),d
5530
 
    inc hl
5531
 
    ld (hl),a
5532
 
    pop bc
5533
 
    pop de
5534
 
    pop hl
5535
 
    pop af
5536
 
    ret
5537
 
 
5538
 
 
5539
 
_2:
5540
 
;;return float in CHLB
5541
 
    push de
5542
 
    ld e,(hl)
5543
 
    inc hl
5544
 
    ld d,(hl)
5545
 
    inc hl
5546
 
    ld c,(hl)
5547
 
    inc hl
5548
 
    ld a,(hl)
5549
 
    or a
5550
 
    jr z,mulSingle_case0
5551
 
    ex de,hl
5552
 
    ex (sp),hl
5553
 
    ld e,(hl)
5554
 
    inc hl
5555
 
    ld d,(hl)
5556
 
    inc hl
5557
 
    ld b,(hl)
5558
 
    inc hl
5559
 
 
5560
 
    ;inc (hl)
5561
 
    ;dec (hl)
5562
 
    ;jr z,mulSingle_case1
5563
 
    push af
5564
 
    ld a, (hl)
5565
 
    or a
5566
 
    jp z,mulSingle_case1
5567
 
    pop af
5568
 
 
5569
 
    add a,(hl)      ;\
5570
 
    pop hl          ; |
5571
 
    rra             ; |Lots of help from Runer112 and
5572
 
    adc a,a         ; |calc84maniac for optimizing
5573
 
    jp po,bad       ; |this exponent check.
5574
 
    xor 80h         ; |
5575
 
    jr z,underflow  ;/
5576
 
    push af         ;exponent
5577
 
    ld a,b
5578
 
    xor c
5579
 
    push af         ;sign
5580
 
    set 7,b
5581
 
    set 7,c
5582
 
    call mul24      ;BDE*CHL->HLBCDE, returns sign info
5583
 
    pop de
5584
 
    ld a,e
5585
 
    pop de
5586
 
    jp m,_3
5587
 
    rl c
5588
 
    rl b
5589
 
    adc hl,hl
5590
 
    dec d
5591
 
_3:
5592
 
    inc d
5593
 
    jr z,overflow
5594
 
    rl c
5595
 
    ld c,d
5596
 
    ld de,0
5597
 
    push af
5598
 
    ld a,b
5599
 
    adc a,e
5600
 
    ld b,a
5601
 
    adc hl,de
5602
 
    jr nc,_4
5603
 
    inc c
5604
 
    jr z,overflow
5605
 
    rr h
5606
 
    rr l
5607
 
    rr b
5608
 
_4:
5609
 
    pop af
5610
 
    cpl
5611
 
    and $80
5612
 
    xor h
5613
 
    ld h,a
5614
 
    ret
5615
 
bad:
5616
 
    jr nc,overflow
5617
 
underflow:
5618
 
    ld hl,0
5619
 
    rl b
5620
 
    rr h
5621
 
    ld c,l
5622
 
    ld b,l
5623
 
    ret
5624
 
overflow:
5625
 
    ld hl,$8000
5626
 
    jr underflow+3
5627
 
mulSingle_case1:
5628
 
;x*0   -> 0
5629
 
;x*inf -> inf
5630
 
;x*NaN -> NaN
5631
 
  pop af
5632
 
  pop hl
5633
 
  ld h,b
5634
 
  ld l,d
5635
 
  ld b,e
5636
 
  ld c,0
5637
 
  ret
5638
 
mulSingle_case0:
5639
 
;special*x = special
5640
 
;NaN*x = NaN
5641
 
;0*0 = 0
5642
 
;0*NaN = NaN
5643
 
;0*Inf = NaN
5644
 
;Inf*Inf  = Inf
5645
 
;Inf*-Inf =-Inf
5646
 
  ;0CDE
5647
 
  pop hl
5648
 
  inc hl
5649
 
  inc hl
5650
 
  inc hl
5651
 
  ld a,(hl)
5652
 
  or a
5653
 
  jr z,_5
5654
 
  ld h,c
5655
 
  ld c,0
5656
 
  ret
5657
 
_5:
5658
 
  dec hl
5659
 
  ld b,(hl)
5660
 
;basically, if b|c has bit 5 set, return NaN
5661
 
  ld a,b
5662
 
  or c
5663
 
  ld h,$20
5664
 
  and h
5665
 
  jr z,_6
5666
 
  ld c,0
5667
 
  ret
5668
 
_6:
5669
 
  ld a,c
5670
 
  xor b
5671
 
  rl b
5672
 
  rlca
5673
 
  rr b
5674
 
  res 4,b
5675
 
 
5676
 
  rl c
5677
 
  rrca
5678
 
  rr c
5679
 
 
5680
 
  ld a,c
5681
 
  and $E0
5682
 
  add a,b
5683
 
  rra
5684
 
  ld h,a
5685
 
  ld c,0
5686
 
  ret
5687
 
mul24:
5688
 
;;BDE*CHL -> HLBCDE
5689
 
;;155 bytes
5690
 
;;402+3*C_Times_BDE
5691
 
;;fastest:1201cc
5692
 
;;slowest:1753cc
5693
 
;;avg    :1464.9033203125cc (1464+925/1024)
5694
 
;min: 825cc
5695
 
;max: 1926cc
5696
 
;avg: 1449.63839751681cc
5697
 
 
5698
 
    push bc
5699
 
    ld c,l
5700
 
    push hl
5701
 
    call C_Times_BDE
5702
 
    ld (var48),hl
5703
 
    ld l,a
5704
 
    ld h,c
5705
 
    ld (var48+2),hl
5706
 
 
5707
 
    pop hl
5708
 
    ld c,h
5709
 
    call C_Times_BDE
5710
 
    push bc
5711
 
    ld bc,(var48+1)
5712
 
    add hl,bc
5713
 
    ld (var48+1),hl
5714
 
    pop bc
5715
 
    ld b,c
5716
 
    ld c,a
5717
 
    ld hl,(var48+3)
5718
 
    ld h,0
5719
 
    adc hl,bc
5720
 
    ld (var48+3),hl
5721
 
 
5722
 
    pop bc
5723
 
    call C_Times_BDE
5724
 
    ld de,(var48+2)
5725
 
    add hl,de
5726
 
    ld (var48+2),hl
5727
 
    ld d,c
5728
 
    ld e,a
5729
 
    ld b,h
5730
 
    ld c,l
5731
 
    ld hl,(var48+4)
5732
 
    ld h,0
5733
 
    adc hl,de
5734
 
    ld de,(var48)
5735
 
    ret
5736
 
 
5737
 
;---------------------------------------------------------------------------------------------------------
5738
 
; divSingle
5739
 
;---------------------------------------------------------------------------------------------------------
5740
 
 
5741
 
divSingle:
5742
 
;;HL points to numerator
5743
 
;;DE points to denominator
5744
 
;;BC points to where the quotient gets written
5745
 
  call pushpop
5746
 
divSingle_no_pushpop:
5747
 
    inc hl
5748
 
    inc de
5749
 
    inc hl
5750
 
    inc de
5751
 
    ld a,(de)   ;\
5752
 
    xor (hl)    ; |Get sign of output
5753
 
    add a,a     ; |
5754
 
    push af     ;/
5755
 
    push bc
5756
 
    inc hl
5757
 
    inc de
5758
 
    ld a,(hl)   ;\
5759
 
    ex de,hl    ; |Get exponent
5760
 
    sub (hl)    ; |
5761
 
    ex de,hl    ; |
5762
 
 
5763
 
    ld b,-1
5764
 
    jr nc,_7
5765
 
    dec b
5766
 
_7:
5767
 
    add a,128
5768
 
    jr nc,_8
5769
 
    inc b
5770
 
_8:
5771
 
    inc b
5772
 
    jr z,_9
5773
 
    jp p,divunderflow
5774
 
    jp m,divoverflow
5775
 
_9:
5776
 
    ld (quot+3),a
5777
 
    dec hl
5778
 
    dec de
5779
 
    ld b,(hl)
5780
 
    dec hl
5781
 
    ld a,(hl)
5782
 
    dec hl
5783
 
    ld l,(hl)
5784
 
    ld h,a
5785
 
    ex de,hl
5786
 
 
5787
 
    ld c,(hl)
5788
 
    dec hl
5789
 
    ld a,(hl)
5790
 
    dec hl
5791
 
    ld l,(hl)
5792
 
    ld h,a
5793
 
    ex de,hl
5794
 
 
5795
 
    set 7,c
5796
 
    ld a,b
5797
 
    or 80h
5798
 
    sbc hl,de
5799
 
    sbc a,c
5800
 
    jr nz,_10
5801
 
    or h
5802
 
    or l
5803
 
    jr z,setmantissa0
5804
 
    xor a
5805
 
_10:
5806
 
    jr nc,startdiv
5807
 
    ld b,a
5808
 
    ld a,(quot+3)
5809
 
    dec a
5810
 
    ld (quot+3),a
5811
 
    ld a,b
5812
 
    add hl,hl
5813
 
    adc a,a
5814
 
    add hl,de
5815
 
    adc a,c
5816
 
startdiv:
5817
 
    ld b,1
5818
 
    call divsub0+3
5819
 
    ld (quot+1),bc
5820
 
    call divsub0
5821
 
    ld (quot),bc
5822
 
    call divsub0
5823
 
    ld (quot-1),bc
5824
 
    add hl,hl
5825
 
    rla
5826
 
    jr c,_11
5827
 
    sbc hl,de
5828
 
    sbc a,c
5829
 
    ccf
5830
 
_11:
5831
 
    ld hl,(quot)
5832
 
    ld de,(quot+2)
5833
 
    ld bc,0
5834
 
    adc hl,bc
5835
 
    ex de,hl
5836
 
    adc hl,bc
5837
 
    ld b,h
5838
 
    ld c,l
5839
 
writeback:
5840
 
    pop hl
5841
 
    ld (hl),e
5842
 
    inc hl
5843
 
    ld (hl),d
5844
 
    inc hl
5845
 
    rl c
5846
 
    pop af
5847
 
    rr c
5848
 
    ld (hl),c
5849
 
    inc hl
5850
 
    ld (hl),b
5851
 
    ret
5852
 
divoverflow:
5853
 
    ld b,$40
5854
 
    jr _12
5855
 
divunderflow:
5856
 
  ld b,0
5857
 
  jr _12
5858
 
setmantissa0:
5859
 
  ld bc,(quot+2)
5860
 
_12:
5861
 
  ld de,0
5862
 
  ld c,e
5863
 
  jr writeback
5864
 
divsub0:
5865
 
;;882cc max
5866
 
    call divsub1    ;34 or 66
5867
 
    call divsub1    ;
5868
 
    call divsub1
5869
 
    call divsub1
5870
 
    call divsub1
5871
 
    call divsub1
5872
 
    call divsub1
5873
 
    call divsub1
5874
 
    or a
5875
 
    sbc hl,de
5876
 
    sbc a,c
5877
 
    inc b
5878
 
    ret nc
5879
 
    dec b
5880
 
    add hl,de
5881
 
    adc a,c
5882
 
    ret
5883
 
divsub1:
5884
 
;34cc or 66cc or 93cc
5885
 
    sla b
5886
 
    add hl,hl
5887
 
    rla
5888
 
    ret nc
5889
 
    or a
5890
 
    inc b
5891
 
    sbc hl,de
5892
 
    sbc a,c
5893
 
    ret c
5894
 
    inc b
5895
 
    sbc hl,de
5896
 
    sbc a,c
5897
 
    ret
5898
 
 
5899
 
;---------------------------------------------------------------------------------------------------------
5900
 
; powSingle
5901
 
; https://www.geeksforgeeks.org/write-a-c-program-to-calculate-powxn/
5902
 
; https://stackoverflow.com/questions/3518973/floating-point-exponentiation-without-power-function
5903
 
;---------------------------------------------------------------------------------------------------------
5904
 
;double mypow( double base, double power, double precision )
5905
 
;{
5906
 
;   if ( power < 0 ) return 1 / mypow( base, -power, precision );
5907
 
;   else if ( power >= 1 ) return base * mypow( base, power-1, precision );
5908
 
;   else if ( precision >= 1 ) {
5909
 
;          if( base >= 0 ) return sqrt( base );
5910
 
;          else return sqrt( -base );
5911
 
;   } else return sqrt( mypow( base, power*2, precision*2 ) );
5912
 
;}
5913
 
 
5914
 
if defined MATH.POW or defined MATH_EXP or defined MATH_LOG or defined MATH_LN
5915
 
 
5916
 
powSingle:
5917
 
;;Computes y^x
5918
 
;;HL points to y
5919
 
;;DE points to x
5920
 
;;BC points to output
5921
 
    call pushpop
5922
 
    push bc
5923
 
      push de
5924
 
            ld bc, var_y     ; power
5925
 
            call copySingle
5926
 
          pop hl
5927
 
          ld bc, var_x       ; base
5928
 
          call copySingle
5929
 
          ld hl, const_precision
5930
 
          ld bc, var_a       ; precision
5931
 
          call copySingle
5932
 
          ld hl, const_0
5933
 
          ld bc, var_z       ; result
5934
 
          call copySingle
5935
 
          call powSingle.loop
5936
 
        pop bc
5937
 
        ld hl, var_z
5938
 
        call copySingle
5939
 
        ret
5940
 
 
5941
 
powSingle.loop:
5942
 
;   if ( power < 0 ) return 1 / mypow( base, -power, precision );
5943
 
    ld hl, var_y
5944
 
        ld de, const_0
5945
 
        call cmpSingle
5946
 
        jp c, powSingle.1
5947
 
 
5948
 
;   else if ( power >= 1 ) return base * mypow( base, power-1, precision );
5949
 
    ld hl, var_y
5950
 
        ld de, const_1
5951
 
        call cmpSingle
5952
 
        jp nc, powSingle.2
5953
 
 
5954
 
;   else if ( precision >= 1 ) {
5955
 
;          if( base >= 0 ) return sqrt( base );
5956
 
;          else return sqrt( -base );
5957
 
    ld hl, var_a
5958
 
        ld de, const_1
5959
 
        call cmpSingle
5960
 
        jp nc, powSingle.3
5961
 
 
5962
 
;   } else return sqrt( mypow( base, power*2, precision*2 ) );
5963
 
    ld hl, var_y
5964
 
        ld de, const_2
5965
 
        ld bc, var_b
5966
 
        call mulSingle
5967
 
        ld hl, var_b
5968
 
        ld bc, var_y
5969
 
        call copySingle
5970
 
    ld hl, var_a
5971
 
        ld de, const_2
5972
 
        ld bc, var_b
5973
 
        call mulSingle
5974
 
        ld hl, var_b
5975
 
        ld bc, var_a
5976
 
        call copySingle
5977
 
        call powSingle.loop
5978
 
        ld hl, var_z
5979
 
        ld bc, var_b
5980
 
        call sqrtSingle
5981
 
        ld hl, var_b
5982
 
        ld bc, var_z
5983
 
        call copySingle
5984
 
        ret
5985
 
 
5986
 
powSingle.1:
5987
 
; return 1 / mypow( base, -power, precision );
5988
 
    ld hl, const_0
5989
 
        ld de, var_y
5990
 
        ld bc, var_b
5991
 
        call subSingle
5992
 
        ld hl, var_b
5993
 
        ld bc, var_y
5994
 
        call copySingle
5995
 
        call powSingle.loop
5996
 
        ld hl, const_1
5997
 
        ld de, var_z
5998
 
        ld bc, var_b
5999
 
        call divSingle
6000
 
        ld hl, var_b
6001
 
        ld bc, var_z
6002
 
        call copySingle
6003
 
    ret
6004
 
 
6005
 
powSingle.2:
6006
 
; return base * mypow( base, power-1, precision );
6007
 
    ld hl, var_y
6008
 
        ld de, const_1
6009
 
        ld bc, var_b
6010
 
        call subSingle
6011
 
        ld hl, var_b
6012
 
        ld bc, var_y
6013
 
        call copySingle
6014
 
        call powSingle.loop
6015
 
        ld hl, var_z
6016
 
        ld de, var_x
6017
 
        ld bc, var_b
6018
 
        call mulSingle
6019
 
        ld hl, var_b
6020
 
        ld bc, var_z
6021
 
        call copySingle
6022
 
    ret
6023
 
 
6024
 
powSingle.3:
6025
 
;          if( base >= 0 ) return sqrt( base );
6026
 
;          else return sqrt( -base );
6027
 
    ld hl, var_x
6028
 
        ld de, const_0
6029
 
        call cmpSingle
6030
 
        jp nc, powSingle.1
6031
 
        ;ld hl, var_x
6032
 
        ld bc, var_b
6033
 
        call negSingle
6034
 
        ld hl, var_b
6035
 
        ;ld bc, var_z
6036
 
        ;call sqrtSingle
6037
 
        ;ret
6038
 
 
6039
 
powSingle.3.1:
6040
 
    ;ld hl, var_x
6041
 
        ld bc, var_z
6042
 
        call sqrtSingle
6043
 
    ret
6044
 
 
6045
 
pow2Single:
6046
 
;;Computes 2^x
6047
 
  call pushpop
6048
 
  push bc
6049
 
 
6050
 
exp_inject:
6051
 
;if x is on [0,1):
6052
 
;  2^x = 1.000000001752 + x * (0.693146989552 + x * (0.2402298085906 + x * (5.54833215071e-2 + x * (9.67907584392e-3 + x * (1.243632065103e-3 + x * 2.171671843714e-4)))))
6053
 
;Please note that usually I like to reduce to [-.5,.5] as the extra overhead is usually worth it.
6054
 
;In this case, our polynomial is the same degree, with error different by less than 1 bit, so it's just a waste to range-reduce in this way.
6055
 
;
6056
 
;int(x) -> out_exp
6057
 
;x-=int(x)  ;leaves x in [0,1)
6058
 
;;If x==0    -> out==1
6059
 
;;if x==inf  -> out==inf
6060
 
;;if x==-inf -> out==0
6061
 
;;if x==NAN  -> out==NAN
6062
 
  ld de,var48+10
6063
 
  call mov4
6064
 
  ld hl,(var48+10)
6065
 
  ld de,(var48+12)
6066
 
  ld a,e
6067
 
  add a,a
6068
 
  push af   ;keep track of sign
6069
 
  rrca
6070
 
  ld (var48+12),a
6071
 
  ld c,a
6072
 
  ld a,d
6073
 
    or a
6074
 
    jp z,exp_spec
6075
 
    cp 80h-23
6076
 
    jp c,exp_underflow
6077
 
    sub 128   ; sub a,128
6078
 
    jr c,_pow_1 ;int(x)=0
6079
 
    inc a
6080
 
    cp 7
6081
 
    jp nc,exp_overflow
6082
 
    set 7,c
6083
 
    ld b,a
6084
 
    xor a
6085
 
    add hl,hl
6086
 
    rl c
6087
 
    rla
6088
 
    djnz $-4
6089
 
    ld b,7Fh
6090
 
    bit 7,c
6091
 
    jr nz,exp_normalized
6092
 
    ld e,a
6093
 
    ld a,h
6094
 
    or l
6095
 
    or c
6096
 
    ld a,e
6097
 
    jr z,exp_zeroed
6098
 
    dec b
6099
 
    add hl,hl
6100
 
    rl c
6101
 
    jp p,$-4
6102
 
    jr exp_normalized  ;.db $11 ;start of `ld de,**`
6103
 
exp_zeroed:
6104
 
    ld b,0
6105
 
exp_normalized:
6106
 
    ld (var48+10),hl
6107
 
    res 7,c
6108
 
    ld (var48+12),bc
6109
 
    jr comp_exp   ;.db $06 ;start of 'ld b,*` just to eat the next byte
6110
 
_pow_1:
6111
 
    xor a
6112
 
comp_exp:
6113
 
  pop hl
6114
 
  rr l
6115
 
  jr nc,_pow_2
6116
 
  cpl
6117
 
  or a
6118
 
  jp z,exp_underflow+1
6119
 
  ;perform 1-(var48+10)--> var48+10
6120
 
  ld hl,const_1
6121
 
  ld de,var48+10
6122
 
  ld b,d
6123
 
  ld c,e
6124
 
  call subSingle
6125
 
_pow_2:
6126
 
  push af
6127
 
;our 'x' is at var48+10
6128
 
;our `temp` is at var48+6 so as not to cause issues with mulSingle)
6129
 
;uses 14 bytes of RAM
6130
 
  ld hl,var48+10
6131
 
  ld de,exp_a6
6132
 
  ld bc,var48+6
6133
 
  call mulSingle
6134
 
  ld d,b
6135
 
  ld e,c
6136
 
  ld hl,exp_a5
6137
 
  call addSingle
6138
 
  ld hl,var48+10
6139
 
  call mulSingle
6140
 
  ld hl,exp_a4
6141
 
  call addSingle
6142
 
  ld hl,var48+10
6143
 
  call mulSingle
6144
 
  ld hl,exp_a3
6145
 
  call addSingle
6146
 
  ld hl,var48+10
6147
 
  call mulSingle
6148
 
  ld hl,exp_a2
6149
 
  call addSingle
6150
 
  ld hl,var48+10
6151
 
  call mulSingle
6152
 
  ld hl,exp_a1
6153
 
  call addSingle
6154
 
  ld hl,var48+10
6155
 
  call mulSingle
6156
 
  ld hl,const_1
6157
 
  call addSingle
6158
 
  ld hl,var48+9
6159
 
  pop af
6160
 
  add a,(hl)
6161
 
  ld (hl),a
6162
 
  ex de,hl
6163
 
  pop de
6164
 
  jp mov4
6165
 
exp_spec:
6166
 
;bit 6 means INF
6167
 
;bit 5 means NAN
6168
 
;no bits means zero
6169
 
;NAN -> NAN
6170
 
;+inf -> +inf
6171
 
;-inf -> +0  because lim approaches 0 from the right
6172
 
    ld a,c
6173
 
    add a,a
6174
 
    jr z,exp_zero
6175
 
    jp m,exp_inf
6176
 
;exp_NAN
6177
 
    pop af
6178
 
    ld de,0040h
6179
 
exp_return_spec:
6180
 
    pop hl
6181
 
    rr e
6182
 
    ld (hl),a
6183
 
    inc hl
6184
 
    ld (hl),a
6185
 
    inc hl
6186
 
    ld (hl),e
6187
 
    inc hl
6188
 
    ld (hl),d
6189
 
    ret
6190
 
exp_overflow:
6191
 
exp_inf:
6192
 
;+inf -> +inf
6193
 
;-inf -> +0  because lim approaches 0 from the right
6194
 
    pop af
6195
 
    sbc a,a ;FF if should be 0,
6196
 
    cpl
6197
 
    and 80h
6198
 
    ld d,0
6199
 
    ld e,a
6200
 
    jr exp_return_spec
6201
 
exp_underflow:
6202
 
exp_zero:
6203
 
    pop af
6204
 
    or a
6205
 
    ld de,$8000
6206
 
    jr exp_return_spec
6207
 
 
6208
 
endif
6209
 
 
6210
 
;---------------------------------------------------------------------------------------------------------
6211
 
; sqrtSingle
6212
 
;---------------------------------------------------------------------------------------------------------
6213
 
 
6214
 
if defined MATH_SQR or defined MATH_EXP
6215
 
 
6216
 
;Uses 3 bytes at scrap
6217
 
sqrtSingle:
6218
 
;552+{0,19}+8{0,3+{0,3}}+pushpop+sqrtHLIX
6219
 
;min: 1784
6220
 
;max: 1987
6221
 
;avg: 1872
6222
 
  call pushpop
6223
 
  push bc
6224
 
  ld c,(hl)
6225
 
  inc hl
6226
 
  ld e,(hl)
6227
 
  inc hl
6228
 
  ld a,(hl)
6229
 
  add a,a
6230
 
  jp c,sqrtSingle_NaN
6231
 
  scf
6232
 
  rra
6233
 
  ld d,a
6234
 
  inc hl
6235
 
  ld a,(hl)
6236
 
  or a
6237
 
  jp z,sqrtSingle_special
6238
 
  add a,80h
6239
 
  rra
6240
 
  push af   ;new exponent
6241
 
  jr c,_13
6242
 
  srl d
6243
 
  rr e
6244
 
  rr c
6245
 
_13:
6246
 
  ex de,hl
6247
 
  ld ixh,c
6248
 
  ld ixl,0
6249
 
  call sqrtHLIX
6250
 
;AHL is the new remainder
6251
 
;Need to divide by 2, then divide by the 16-bit (var_x+4)
6252
 
  rra
6253
 
  ld a,h
6254
 
;HL/DE to 8 bits
6255
 
;We are just going to approximate it
6256
 
  res 0,l
6257
 
  jr c,$+5
6258
 
  cp d
6259
 
  jr c,$+4
6260
 
  sub d
6261
 
  inc l
6262
 
  sla l
6263
 
  rla
6264
 
  jr c,$+5
6265
 
  cp d
6266
 
  jr c,$+4
6267
 
  sub d
6268
 
  inc l
6269
 
  sla l
6270
 
  rla
6271
 
  jr c,$+5
6272
 
  cp d
6273
 
  jr c,$+4
6274
 
  sub d
6275
 
  inc l
6276
 
  sla l
6277
 
  rla
6278
 
  jr c,$+5
6279
 
  cp d
6280
 
  jr c,$+4
6281
 
  sub d
6282
 
  inc l
6283
 
  sla l
6284
 
  rla
6285
 
  jr c,$+5
6286
 
  cp d
6287
 
  jr c,$+4
6288
 
  sub d
6289
 
  inc l
6290
 
  sla l
6291
 
  rla
6292
 
  jr c,$+5
6293
 
  cp d
6294
 
  jr c,$+4
6295
 
  sub d
6296
 
  inc l
6297
 
  sla l
6298
 
  rla
6299
 
  jr c,$+5
6300
 
  cp d
6301
 
  jr c,$+4
6302
 
  sub d
6303
 
  inc l
6304
 
  sla l
6305
 
  rla
6306
 
  jr c,$+5
6307
 
  cp d
6308
 
  jr c,$+4
6309
 
  sub d
6310
 
  inc l
6311
 
 
6312
 
  pop bc
6313
 
  ld a,l
6314
 
  pop hl
6315
 
  ;BDEA
6316
 
  ld (hl),a
6317
 
  inc hl
6318
 
  ld (hl),e
6319
 
  inc hl
6320
 
  res 7,d
6321
 
  ld (hl),d
6322
 
  inc hl
6323
 
  ld (hl),b
6324
 
  ret
6325
 
sqrtSingle_NaN:
6326
 
  ld hl,const_NaN
6327
 
  pop de
6328
 
  jp mov4
6329
 
sqrtSingle_special:
6330
 
  dec hl
6331
 
  dec hl
6332
 
  pop de
6333
 
  jp mov4
6334
 
 
6335
 
sqrtHLIX:
6336
 
;Input: HLIX
6337
 
;Output: DE is the sqrt, AHL is the remainder
6338
 
;speed: 754+{0,1}+6{0,6}+{0,3+{0,18}}+{0,38}+sqrtHL
6339
 
;min: 1130
6340
 
;max: 1266
6341
 
;avg: 1190.5
6342
 
 
6343
 
 
6344
 
  call sqrtHL
6345
 
  add a,a
6346
 
  ld e,a
6347
 
  jr nc,_14
6348
 
  inc d
6349
 
_14:
6350
 
 
6351
 
  ld a,ixh
6352
 
  sll e
6353
 
  rl d
6354
 
  add a,a
6355
 
  adc hl,hl
6356
 
  add a,a
6357
 
  adc hl,hl
6358
 
  sbc hl,de
6359
 
  jr nc,_15
6360
 
  add hl,de
6361
 
  dec e
6362
 
  jr _15a      ;.db $FE     ;start of `cp *`
6363
 
_15:
6364
 
  inc e
6365
 
_15a:
6366
 
  sll e
6367
 
  rl d
6368
 
  add a,a
6369
 
  adc hl,hl
6370
 
  add a,a
6371
 
  adc hl,hl
6372
 
  sbc hl,de
6373
 
  jr nc,_16
6374
 
  add hl,de
6375
 
  dec e
6376
 
  jr _16a   ;.db $FE     ;start of `cp *`
6377
 
_16:
6378
 
  inc e
6379
 
_16a:
6380
 
  sll e
6381
 
  rl d
6382
 
  add a,a
6383
 
  adc hl,hl
6384
 
  add a,a
6385
 
  adc hl,hl
6386
 
  sbc hl,de
6387
 
  jr nc,_17
6388
 
  add hl,de
6389
 
  dec e
6390
 
  jr _17a  ;.db $FE     ;start of `cp *`
6391
 
_17:
6392
 
  inc e
6393
 
_17a:
6394
 
  sll e
6395
 
  rl d
6396
 
  add a,a
6397
 
  adc hl,hl
6398
 
  add a,a
6399
 
  adc hl,hl
6400
 
  sbc hl,de
6401
 
  jr nc,_18
6402
 
  add hl,de
6403
 
  dec e
6404
 
  jr _18a  ;.db $FE     ;start of `cp *`
6405
 
_18:
6406
 
  inc e
6407
 
_18a:
6408
 
;Now we have four more iterations
6409
 
;The first two are no problem
6410
 
  ld a,ixl
6411
 
  sll e
6412
 
  rl d
6413
 
  add a,a
6414
 
  adc hl,hl
6415
 
  add a,a
6416
 
  adc hl,hl
6417
 
  sbc hl,de
6418
 
  jr nc,_19
6419
 
  add hl,de
6420
 
  dec e
6421
 
  jr _19a  ;.db $FE     ;start of `cp *`
6422
 
_19:
6423
 
  inc e
6424
 
_19a:
6425
 
  sll e
6426
 
  rl d
6427
 
  add a,a
6428
 
  adc hl,hl
6429
 
  add a,a
6430
 
  adc hl,hl
6431
 
  sbc hl,de
6432
 
  jr nc,_20
6433
 
  add hl,de
6434
 
  dec e
6435
 
  jr _20a  ;.db $FE     ;start of `cp *`
6436
 
_20:
6437
 
  inc e
6438
 
_20a:
6439
 
sqrt32_iter15:
6440
 
;On the next iteration, HL might temporarily overflow by 1 bit
6441
 
  sll e
6442
 
  rl d      ;sla e \ rl d \ inc e
6443
 
  add a,a
6444
 
  adc hl,hl
6445
 
  add a,a
6446
 
  adc hl,hl       ;This might overflow!
6447
 
  jr c,sqrt32_iter15_br0
6448
 
;
6449
 
  sbc hl,de
6450
 
  jr nc,_21
6451
 
  add hl,de
6452
 
  dec e
6453
 
  jr sqrt32_iter16
6454
 
sqrt32_iter15_br0:
6455
 
  or a
6456
 
  sbc hl,de
6457
 
_21:
6458
 
  inc e
6459
 
 
6460
 
;On the next iteration, HL is allowed to overflow, DE could overflow with our current routine, but it needs to be shifted right at the end, anyways
6461
 
sqrt32_iter16:
6462
 
  add a,a
6463
 
  ld b,a        ;either 0x00 or 0x80
6464
 
  adc hl,hl
6465
 
  rla
6466
 
  adc hl,hl
6467
 
  rla
6468
 
;AHL - (DE+DE+1)
6469
 
  sbc hl,de
6470
 
  sbc a,b
6471
 
  inc e
6472
 
  or a
6473
 
  sbc hl,de
6474
 
  sbc a,b
6475
 
  ret p
6476
 
  add hl,de
6477
 
  adc a,b
6478
 
  dec e
6479
 
  add hl,de
6480
 
  adc a,b
6481
 
  ret
6482
 
 
6483
 
sqrtHL:
6484
 
;returns A as the sqrt, HL as the remainder, D = 0
6485
 
;min: 376cc
6486
 
;max: 416cc
6487
 
;avg: 393cc
6488
 
  ld de,$5040
6489
 
  ld a,h
6490
 
  sub e
6491
 
  jr nc,_22
6492
 
  add a,e
6493
 
  ld d,$10
6494
 
_22:
6495
 
  sub d
6496
 
  jr nc,_23
6497
 
  add a,d
6498
 
  jr _23a  ;.db $01   ;start of ld bc,** which is 10cc to skip the next two bytes.
6499
 
_23:
6500
 
  set 5,d
6501
 
_23a:
6502
 
  res 4,d
6503
 
  srl d
6504
 
 
6505
 
  set 2,d
6506
 
  sub d
6507
 
  jr nc,_24
6508
 
  add a,d
6509
 
  jr _24a  ;.db $01   ;start of ld bc,** which is 10cc to skip the next two bytes.
6510
 
_24:
6511
 
  set 3,d
6512
 
_24a:
6513
 
  res 2,d
6514
 
  srl d
6515
 
 
6516
 
  inc d
6517
 
  sub d
6518
 
  jr nc,_25
6519
 
  add a,d
6520
 
  dec d   ;this resets the low bit of D, so `srl d` resets carry.
6521
 
  jr _25a  ;.db $06   ;start of ld b,* which is 7cc to skip the next byte.
6522
 
_25:
6523
 
  inc d
6524
 
_25a:
6525
 
  srl d
6526
 
  ld h,a
6527
 
 
6528
 
 
6529
 
  sbc hl,de
6530
 
  ld a,e
6531
 
  jr nc,_26
6532
 
  add hl,de
6533
 
_26:
6534
 
  ccf
6535
 
  rra
6536
 
  srl d
6537
 
  rra
6538
 
  ld e,a
6539
 
 
6540
 
  sbc hl,de
6541
 
  jr nc,_27
6542
 
  add hl,de
6543
 
  jr _27a  ;.db $01   ;start of ld bc,** which is 10cc to skip the next two bytes.
6544
 
_27:
6545
 
  or %00100000
6546
 
_27a:
6547
 
  xor %00011000
6548
 
  srl d
6549
 
  rra
6550
 
  ld e,a
6551
 
 
6552
 
 
6553
 
  sbc hl,de
6554
 
  jr nc,_28
6555
 
  add hl,de
6556
 
  jr _28a  ;.db $01   ;start of ld bc,** which is 10cc to skip the next two bytes.
6557
 
_28:
6558
 
  or %00001000
6559
 
_28a:
6560
 
  xor %00000110
6561
 
  srl d
6562
 
  rra
6563
 
  ld e,a
6564
 
  sbc hl,de
6565
 
  jr nc,_29
6566
 
  add hl,de
6567
 
  srl d
6568
 
  rra
6569
 
  ret
6570
 
_29:
6571
 
  inc a
6572
 
  srl d
6573
 
  rra
6574
 
  ret
6575
 
 
6576
 
endif
6577
 
 
6578
 
;---------------------------------------------------------------------------------------------------------
6579
 
; lnSingle
6580
 
;---------------------------------------------------------------------------------------------------------
6581
 
 
6582
 
if defined MATH_LOG or defined MATH_LN
6583
 
 
6584
 
lnSingle:
6585
 
; x / (1 + x/(2-x+4x/(3-2x+9x/(4-3x+16x/(5-4x)))))
6586
 
; a * x ^ (1/a) - a, where a = 100
6587
 
  call pushpop
6588
 
  push bc
6589
 
    ld de, const_100_inv
6590
 
        ld bc, temp
6591
 
        call powSingle         ; temp = x ^ (1/100)
6592
 
        ld hl, temp
6593
 
        ld de, const_100
6594
 
        ld bc, temp1
6595
 
        call mulSingle         ; temp1 = temp * 100
6596
 
        ld hl, temp1
6597
 
  pop bc
6598
 
  call subSingle           ; bc = temp1 - 100
6599
 
  ret
6600
 
 
6601
 
endif
6602
 
 
6603
 
;---------------------------------------------------------------------------------------------------------
6604
 
; logSingle
6605
 
;---------------------------------------------------------------------------------------------------------
6606
 
 
6607
 
if defined MATH_LOG
6608
 
 
6609
 
logSingle:
6610
 
  call pushpop
6611
 
  push bc
6612
 
    ld bc, temp
6613
 
    call lnSingle
6614
 
    ld hl, temp
6615
 
    ld de, const_lg10
6616
 
  pop bc
6617
 
  call divSingle
6618
 
  ret
6619
 
 
6620
 
endif
6621
 
 
6622
 
;---------------------------------------------------------------------------------------------------------
6623
 
; expSingle
6624
 
;---------------------------------------------------------------------------------------------------------
6625
 
 
6626
 
if defined MATH_EXP
6627
 
 
6628
 
expSingle:
6629
 
;;Computes e^x
6630
 
;;HL points to x
6631
 
;;BC points to the output
6632
 
  call pushpop
6633
 
  ld de,const_lg_e
6634
 
  push bc
6635
 
pow_inject:
6636
 
;;DE points to lg(y), HL points to x, BC points to output
6637
 
  ld bc,var_x
6638
 
  call mulSingle
6639
 
  ld h,b
6640
 
  ld l,c
6641
 
  jp exp_inject
6642
 
 
6643
 
endif
6644
 
 
6645
 
;---------------------------------------------------------------------------------------------------------
6646
 
; sinSingle
6647
 
; https://en.wikipedia.org/wiki/List_of_trigonometric_identities
6648
 
; https://en.wikipedia.org/wiki/Taylor_series#Trigonometric_functions
6649
 
; https://cs.stackexchange.com/questions/89245/how-approximate-sine-using-taylor-series
6650
 
; https://stackoverflow.com/questions/42217069/approximating-sinex-with-a-taylor-series-in-c-and-having-a-lot-of-problems
6651
 
;---------------------------------------------------------------------------------------------------------
6652
 
 
6653
 
if defined MATH_SIN or defined MATH_TAN or defined MATH_COS
6654
 
 
6655
 
sinSingle:
6656
 
; taylor: x - x^3/6 + x^5/120 - x^7/5040
6657
 
;         x(1 - x^2(1/6 - x^2(1/120 - x^2/5040)) )
6658
 
; reduction:
6659
 
;         var_b = round( x / (2*PI), 0 )
6660
 
;         var_c = x - var_b*2*PI
6661
 
;         temp1 = if( var_c >= 0, var_c, var_c + 2*PI )
6662
 
;         temp2 = if( temp1 > PI, temp1 - PI, temp1 )
6663
 
;         var_a = if( temp2 > PI/2, PI - temp2, temp2 ) * if( temp1 > PI, -1, 1 )
6664
 
 
6665
 
  call pushpop
6666
 
  ld de, const_0
6667
 
  call cmpSingle
6668
 
  jr nz, sinSingle.1
6669
 
 
6670
 
  call copySingle      ; return 0
6671
 
  ret
6672
 
 
6673
 
sinSingle.1:
6674
 
  call trigRangeReductionSinCos
6675
 
  push bc
6676
 
    ld hl, var_a
6677
 
    ld de, var_a
6678
 
    ld bc, var_b
6679
 
    call mulSingle    ; var_b = var_a * var_a
6680
 
    ld hl, var_b
6681
 
    ld de, sin_a3
6682
 
    ld bc, temp
6683
 
    call mulSingle    ; temp = x^2/5040
6684
 
    ld hl, sin_a2
6685
 
    ld de, temp
6686
 
    ld bc, temp1
6687
 
    call subSingle    ; temp1 = 1/120 - temp
6688
 
    ld hl, var_b
6689
 
    ld de, temp1
6690
 
    ld bc, temp
6691
 
    call mulSingle    ; temp = x^2 * temp1
6692
 
    ld hl, sin_a1
6693
 
    ld de, temp
6694
 
    ld bc, temp1
6695
 
    call subSingle    ; temp1 = 1/6 - temp
6696
 
    ld hl, var_b
6697
 
    ld de, temp1
6698
 
    ld bc, temp
6699
 
    call mulSingle    ; temp = x^2 * temp1
6700
 
    ld hl, const_1
6701
 
    ld de, temp
6702
 
    ld bc, temp1
6703
 
    call subSingle    ; temp1 = 1 - temp
6704
 
    ld hl, var_a
6705
 
    ld de, temp1
6706
 
  pop bc
6707
 
  call mulSingle      ; return x * temp1
6708
 
  ret
6709
 
 
6710
 
trigRangeReductionSinCos:
6711
 
  call pushpop
6712
 
  push hl
6713
 
; var_b = round( x / (2*PI), 0 )
6714
 
    ld de, const_2pi
6715
 
    ld bc, var_c
6716
 
    call divSingle
6717
 
    ld hl, var_c
6718
 
        ld de, 0
6719
 
        ld bc, var_b
6720
 
        call roundSingle
6721
 
; var_c = x - var_b*2*PI
6722
 
    ld hl, var_b
6723
 
    ld de, const_2pi
6724
 
    ld bc, temp
6725
 
    call mulSingle     ; temp = var_b*2*PI
6726
 
  pop hl
6727
 
  ld de, temp
6728
 
  ld bc, var_c
6729
 
  call subSingle     ; var_c = x - temp
6730
 
; temp1 = if( var_c >= 0, var_c, var_c + 2*PI )
6731
 
  ld hl, var_c
6732
 
  ld de, const_0
6733
 
  call cmpSingle
6734
 
  jr nc, trigRangeReductionSinCos.else.2
6735
 
    ld hl, var_c
6736
 
    ld bc, temp1
6737
 
    call copySingle     ; temp1 = var_c
6738
 
    jr trigRangeReductionSinCos.endif.2
6739
 
trigRangeReductionSinCos.else.2:
6740
 
    ld hl, var_c
6741
 
    ld de, const_2pi
6742
 
    ld bc, temp1
6743
 
    call addSingle     ; temp1 = var_c + 2*PI
6744
 
trigRangeReductionSinCos.endif.2:
6745
 
; temp2 = if( temp1 > PI, temp1 - PI, temp1 )
6746
 
  ld hl, const_pi
6747
 
  ld de, temp1
6748
 
  call cmpSingle
6749
 
  jr c, trigRangeReductionSinCos.else.3
6750
 
  jr z, trigRangeReductionSinCos.else.3
6751
 
    ld hl, temp1
6752
 
    ld de, const_pi
6753
 
    ld bc, temp2
6754
 
    call subSingle     ; temp2
6755
 
    jr trigRangeReductionSinCos.endif.3
6756
 
trigRangeReductionSinCos.else.3:
6757
 
    ld hl, temp1
6758
 
    ld bc, temp2
6759
 
    call copySingle     ; temp2 = temp1
6760
 
trigRangeReductionSinCos.endif.3:
6761
 
; var_a = if( temp2 > PI/2, PI - temp2, temp2 ) * if( temp1 > PI, -1, 1 )
6762
 
  ld hl, const_half_pi
6763
 
  ld de, temp2
6764
 
  call cmpSingle
6765
 
  jr c, trigRangeReductionSinCos.else.4
6766
 
  jr z, trigRangeReductionSinCos.else.4
6767
 
    ld hl, const_pi
6768
 
    ld de, temp2
6769
 
    ld bc, var_a
6770
 
    call subSingle     ; var_a
6771
 
    jr trigRangeReductionSinCos.endif.4
6772
 
trigRangeReductionSinCos.else.4:
6773
 
    ld hl, temp2
6774
 
    ld bc, var_a
6775
 
    call copySingle     ; var_a = temp2
6776
 
trigRangeReductionSinCos.endif.4:
6777
 
; if( temp > PI, -1, 1 )
6778
 
  ld hl, temp1
6779
 
  ld de, const_pi
6780
 
  call cmpSingle
6781
 
  jr nc, trigRangeReductionSinCos.endif.5
6782
 
    ld ix, var_a
6783
 
    ld a, (ix+2)
6784
 
    set 7, a
6785
 
    ld (ix+2), a   ; turn var_a to negative
6786
 
trigRangeReductionSinCos.endif.5:
6787
 
; return var_a
6788
 
  ret
6789
 
 
6790
 
endif
6791
 
 
6792
 
;---------------------------------------------------------------------------------------------------------
6793
 
; cosSingle
6794
 
;---------------------------------------------------------------------------------------------------------
6795
 
 
6796
 
if defined MATH_COS or defined MATH_TAN
6797
 
 
6798
 
cosSingle:
6799
 
; taylor: 1 - x^2/2 + x^4/24 - x^6/720
6800
 
;         1 - x^2(1/2 - x^2(1/24 - x^2/720) )
6801
 
; reduction: same as sin
6802
 
;            cos = cos * sign
6803
 
 
6804
 
  call pushpop
6805
 
  ld de, const_0
6806
 
  call cmpSingle
6807
 
  jr nz, cosSingle.1
6808
 
 
6809
 
  ld hl, const_1
6810
 
  call copySingle      ; return 1
6811
 
  ret
6812
 
 
6813
 
cosSingle.1:
6814
 
  ; 1 - x^2(1/2 - x^2(1/24 - x^2/720) )
6815
 
  call trigRangeReductionSinCos
6816
 
  push bc
6817
 
    ld hl, var_a
6818
 
    ld de, var_a
6819
 
    ld bc, var_b
6820
 
    call mulSingle    ; var_b = var_a * var_a
6821
 
    ld hl, var_b
6822
 
    ld de, cos_a3
6823
 
    ld bc, temp
6824
 
    call mulSingle    ; temp = x^2/720
6825
 
    ld hl, cos_a2
6826
 
    ld de, temp
6827
 
    ld bc, temp1
6828
 
    call subSingle    ; temp1 = 1/24 - temp
6829
 
    ld hl, var_b
6830
 
    ld de, temp1
6831
 
    ld bc, temp
6832
 
    call mulSingle    ; temp = x^2 * temp1
6833
 
    ld hl, cos_a1
6834
 
    ld de, temp
6835
 
    ld bc, temp1
6836
 
    call subSingle    ; temp1 = 1/2 - temp
6837
 
    ld hl, var_b
6838
 
    ld de, temp1
6839
 
    ld bc, temp
6840
 
    call mulSingle    ; temp = x^2 * temp1
6841
 
    ld hl, const_1
6842
 
    ld de, temp
6843
 
    ld bc, temp1
6844
 
    call subSingle    ; temp1 = 1 - temp
6845
 
 
6846
 
    ; temp3 = abs(var_c)
6847
 
    ; temp1 = temp1 * if( temp3 >= PI/2, -1, 1 )       ==> cos sign
6848
 
        ld hl, var_c
6849
 
        ld bc, temp3
6850
 
        call copySingle
6851
 
        ld ix, temp3
6852
 
        ld a, (ix+2)
6853
 
    res 7, a
6854
 
        ld (ix+2), a      ; temp3 = abs(var_c)
6855
 
        ld hl, temp3
6856
 
        ld de, const_half_pi
6857
 
    call cmpSingle    ; if temp3 >= PI/2 then temp1 = -temp1
6858
 
    jr nc, cosSingle.endif.1
6859
 
        ld ix, temp1
6860
 
        ld a, (ix+2)
6861
 
    set 7, a
6862
 
        ld (ix+2), a      ; temp1 = -temp1
6863
 
    cosSingle.endif.1:
6864
 
  pop bc
6865
 
  ld hl, temp1
6866
 
  call copySingle      ; return temp1
6867
 
  ret
6868
 
 
6869
 
endif
6870
 
 
6871
 
;---------------------------------------------------------------------------------------------------------
6872
 
; tanSingle
6873
 
;---------------------------------------------------------------------------------------------------------
6874
 
 
6875
 
if defined MATH_TAN
6876
 
 
6877
 
tanSingle:
6878
 
  call pushpop
6879
 
  push bc
6880
 
  ;HL points to input
6881
 
  ld bc,var_z
6882
 
  ld d,b
6883
 
  ld e,c
6884
 
  call cosSingle
6885
 
  ld bc,var_x
6886
 
  call sinSingle
6887
 
  ld h,b
6888
 
  ld l,c
6889
 
  pop bc
6890
 
  jp divSingle
6891
 
 
6892
 
endif
6893
 
 
6894
 
;---------------------------------------------------------------------------------------------------------
6895
 
; atanSingle
6896
 
;---------------------------------------------------------------------------------------------------------
6897
 
 
6898
 
if defined MATH_ATN
6899
 
 
6900
 
atanSingle:
6901
 
;taylor:    x/(1 + x^2/(3 + (2*x)^2/(5 + (3*x)^2/(7+(4*x)^2/9) ) ) )
6902
 
;           x < -1: atan - PI/2
6903
 
;           x >= 1: PI/2 - atan
6904
 
;reduction: abs(X) > 1 : Y = 1 / X
6905
 
;           abs(X) <= 1: Y = X
6906
 
;           X < 0: Y = -Y
6907
 
 
6908
 
  call pushpop
6909
 
  ld de, const_0
6910
 
  call cmpSingle
6911
 
  jr nz, atanSingle.1
6912
 
 
6913
 
  ld hl, const_0
6914
 
  call copySingle      ; return 0
6915
 
  ret
6916
 
 
6917
 
atanSingle.1:
6918
 
  ;x/(1 + x^2/(3 + (2*x)^2/(5 + (3*x)^2/(7+(4*x)^2/9) ) ) )
6919
 
  call trigRangeReductionAtan
6920
 
  push bc
6921
 
  push hl
6922
 
    ld hl, var_a
6923
 
    ld de, var_a
6924
 
    ld bc, var_b
6925
 
    call mulSingle    ; var_b = var_a * var_a
6926
 
    ld hl, var_b
6927
 
    ld de, const_16
6928
 
    ld bc, temp
6929
 
    call mulSingle    ; temp = (4*x)^2
6930
 
    ld hl, temp
6931
 
    ld de, const_9
6932
 
    ld bc, temp1
6933
 
    call divSingle    ; temp1 = temp/9
6934
 
    ld hl, temp1
6935
 
    ld de, const_7
6936
 
    ld bc, temp
6937
 
    call addSingle    ; temp = 7 + temp1
6938
 
    ld hl, var_b
6939
 
    ld de, const_9
6940
 
    ld bc, temp1
6941
 
    call mulSingle    ; temp1 = var_b * 9
6942
 
    ld hl, temp1
6943
 
    ld de, temp
6944
 
    ld bc, temp2
6945
 
    call divSingle    ; temp2 = temp1 / temp
6946
 
    ld hl, temp2
6947
 
    ld de, const_5
6948
 
    ld bc, temp
6949
 
    call addSingle    ; temp = 5 + temp2
6950
 
    ld hl, var_b
6951
 
    ld de, const_4
6952
 
    ld bc, temp1
6953
 
    call mulSingle    ; temp1 = var_b * 4
6954
 
    ld hl, temp1
6955
 
    ld de, temp
6956
 
    ld bc, temp2
6957
 
    call divSingle    ; temp2 = temp1 / temp
6958
 
    ld hl, temp2
6959
 
    ld de, const_3
6960
 
    ld bc, temp
6961
 
    call addSingle    ; temp = 3 + temp2
6962
 
    ld hl, var_b
6963
 
    ld de, temp
6964
 
    ld bc, temp2
6965
 
    call divSingle    ; temp2 = var_b / temp
6966
 
    ld hl, temp2
6967
 
    ld de, const_1
6968
 
    ld bc, temp
6969
 
    call addSingle    ; temp = 1 + temp2
6970
 
    ld hl, var_a
6971
 
    ld de, temp
6972
 
    ld bc, temp2
6973
 
    call divSingle    ; temp2 = var_a / temp
6974
 
  pop hl
6975
 
; x >= 1: PI/2 - atan
6976
 
  ld de, const_1
6977
 
  call cmpSingle
6978
 
  jr nc, atanSingle.2
6979
 
    ld hl, const_half_pi
6980
 
    ld de, temp2
6981
 
    ld bc, temp
6982
 
    call subSingle
6983
 
    ld hl, temp
6984
 
    jr atanSingle.4
6985
 
atanSingle.2:
6986
 
; x < -1: atan - PI/2
6987
 
  push hl
6988
 
    ld hl, const_0
6989
 
        ld de, const_1
6990
 
        ld bc, temp
6991
 
        call subSingle
6992
 
  pop hl
6993
 
  ld de, temp
6994
 
  call cmpSingle
6995
 
  jr c, atanSingle.3
6996
 
    ld hl, temp2
6997
 
    ld de, const_half_pi
6998
 
    ld bc, temp
6999
 
    call subSingle
7000
 
    ld hl, temp
7001
 
    jr atanSingle.4
7002
 
atanSingle.3:
7003
 
  ld hl, temp2
7004
 
atanSingle.4:
7005
 
  pop bc
7006
 
  call copySingle      ; return temp2
7007
 
  ret
7008
 
 
7009
 
trigRangeReductionAtan:
7010
 
;reduction: abs(X) > 1 : Y = 1 / X
7011
 
;           abs(X) <= 1: Y = X
7012
 
;           X < 0: Y = -Y
7013
 
  call pushpop
7014
 
  push hl
7015
 
    ld bc, temp
7016
 
    call copySingle
7017
 
    ld ix, temp
7018
 
    ld a, (ix+2)
7019
 
    res 7, a
7020
 
    ld (ix+2), a   ; abs(x)
7021
 
    ld hl, temp
7022
 
    ld de, const_1
7023
 
    call cmpSingle
7024
 
    jr nc, trigRangeReductionAtan.1
7025
 
      ld hl, const_1
7026
 
          pop de
7027
 
          push de
7028
 
          ld bc, var_a
7029
 
          call divSingle
7030
 
          jr trigRangeReductionAtan.2
7031
 
trigRangeReductionAtan.1:
7032
 
          pop hl
7033
 
          push hl
7034
 
          ld bc, var_a
7035
 
          call copySingle
7036
 
trigRangeReductionAtan.2:
7037
 
  pop hl
7038
 
  ld de, const_0
7039
 
  call cmpSingle
7040
 
  jr c, trigRangeReductionAtan.3
7041
 
    ld ix, var_a
7042
 
    ld a, (ix+2)
7043
 
    set 7, a
7044
 
    ld (ix+2), a   ; y = -y
7045
 
trigRangeReductionAtan.3:
7046
 
  ret
7047
 
 
7048
 
endif
7049
 
 
7050
 
if defined MATH_SIN or defined MATH_TAN or defined MATH_COS
7051
 
 
7052
 
;---------------------------------------------------------------------------------------------------------
7053
 
; copySingle
7054
 
;---------------------------------------------------------------------------------------------------------
7055
 
 
7056
 
copySingle:
7057
 
    call pushpop
7058
 
        ;push bc
7059
 
        ;pop de
7060
 
        ld d, b
7061
 
        ld e, c
7062
 
        ldi
7063
 
        ldi
7064
 
        ldi
7065
 
        ldi
7066
 
        ret
7067
 
 
7068
 
;---------------------------------------------------------------------------------------------------------
7069
 
; roundSingle
7070
 
;---------------------------------------------------------------------------------------------------------
7071
 
 
7072
 
roundSingle:
7073
 
    call pushpop
7074
 
        call copySingle
7075
 
        ;push bc
7076
 
        ;pop hl
7077
 
        ld h, b
7078
 
        ld l, c
7079
 
        push de
7080
 
          ld a, e
7081
 
          ld de, const_10
7082
 
roundSingle.1:
7083
 
          or 0
7084
 
          jr z, roundSingle.2
7085
 
          ld bc, temp
7086
 
          call mulSingle
7087
 
          ;push hl
7088
 
          ;pop bc
7089
 
          ld b, h
7090
 
          ld c, l
7091
 
          ld hl, temp
7092
 
          call copySingle
7093
 
          ;push bc
7094
 
          ;pop hl
7095
 
          ld h, b
7096
 
          ld l, c
7097
 
          dec a
7098
 
          jr roundSingle.1
7099
 
roundSingle.2:
7100
 
      ld de, const_half_1
7101
 
          ld bc, temp
7102
 
          call addSingle
7103
 
      push hl
7104
 
            ld hl, temp
7105
 
            ld bc, temp1
7106
 
            call single2Int
7107
 
            ld hl, temp1
7108
 
          pop bc
7109
 
          call int2Single
7110
 
          ;push bc
7111
 
          ;pop hl
7112
 
          ld h, b
7113
 
          ld l, c
7114
 
        pop de
7115
 
    ld a, e
7116
 
        ld de, const_10
7117
 
roundSingle.3:
7118
 
        or 0
7119
 
        jr z, roundSingle.4
7120
 
        ld bc, temp
7121
 
        call divSingle
7122
 
        ;push hl
7123
 
        ;pop bc
7124
 
        ld b, h
7125
 
        ld c, l
7126
 
        ld hl, temp
7127
 
        call copySingle
7128
 
        ;push bc
7129
 
        ;pop hl
7130
 
        ld h, b
7131
 
        ld l, c
7132
 
        dec a
7133
 
        jr roundSingle.3
7134
 
roundSingle.4:
7135
 
        ret
7136
 
 
7137
 
endif
7138
 
 
7139
 
if defined MATH_ABSFN
7140
 
 
7141
 
;---------------------------------------------------------------------------------------------------------
7142
 
; absSingle
7143
 
;---------------------------------------------------------------------------------------------------------
7144
 
 
7145
 
absSingle:
7146
 
;;HL points to the float
7147
 
;;BC points to where to output the result
7148
 
    call pushpop
7149
 
    ld d,b
7150
 
    ld e,c
7151
 
    ldi
7152
 
    ldi
7153
 
    ld a,(hl)
7154
 
    and %01111111
7155
 
    ld (de),a
7156
 
    inc hl
7157
 
    inc de
7158
 
    ld a,(hl)
7159
 
    ld (de),a
7160
 
    ret
7161
 
 
7162
 
endif
7163
 
 
7164
 
if defined MATH_SGN
7165
 
 
7166
 
;---------------------------------------------------------------------------------------------------------
7167
 
; sgnSingle
7168
 
;---------------------------------------------------------------------------------------------------------
7169
 
 
7170
 
sgnSingle:
7171
 
;;HL points to the float
7172
 
;;BC points to where to output the result
7173
 
    jp negSingle
7174
 
 
7175
 
endif
7176
 
 
7177
 
if defined powSingle or defined sgnSingle or defined MATH_NEG
7178
 
 
7179
 
;---------------------------------------------------------------------------------------------------------
7180
 
; negSingle
7181
 
;---------------------------------------------------------------------------------------------------------
7182
 
 
7183
 
negSingle:
7184
 
;;HL points to the float
7185
 
;;BC points to where to output the result
7186
 
    call pushpop
7187
 
        push hl
7188
 
        pop ix
7189
 
        ld a, (ix+3)
7190
 
        or 0
7191
 
        jr nz, negSingle.test.sign
7192
 
        ld a, (ix+2)
7193
 
        or 0
7194
 
        jr nz, negSingle.test.sign
7195
 
        ld a, (ix+1)
7196
 
        or 0
7197
 
        jr nz, negSingle.test.sign
7198
 
        ld a, (ix)
7199
 
        or 0
7200
 
        jr nz, negSingle.test.sign
7201
 
    ;push bc
7202
 
    ;pop de
7203
 
        ld d, b
7204
 
        ld e, c
7205
 
    ld hl, const_0
7206
 
    ldi
7207
 
    ldi
7208
 
    ldi
7209
 
    ldi
7210
 
    ret
7211
 
negSingle.test.sign:
7212
 
        ld a, (ix+2)
7213
 
        bit 7, a
7214
 
        jr z, negSingle.positive
7215
 
negSingle.negative:
7216
 
    push bc
7217
 
        pop ix
7218
 
        call negSingle.positive
7219
 
        ld a, (ix+2)
7220
 
        set 7, a
7221
 
        ld (ix+2), a
7222
 
    ret
7223
 
negSingle.positive:
7224
 
    ;push bc
7225
 
    ;pop de
7226
 
        ld d, b
7227
 
        ld e, c
7228
 
    ld hl, const_1
7229
 
    ldi
7230
 
    ldi
7231
 
    ldi
7232
 
    ldi
7233
 
    ret
7234
 
 
7235
 
endif
7236
 
 
7237
 
if defined MATH_DCOMP or defined MATH.POW or defined MATH_EXP or defined MATH_LOG or defined MATH_LN or defined MATH_SIN or defined MATH_TAN or defined MATH_COS or defined MATH_ATN
7238
 
 
7239
 
;---------------------------------------------------------------------------------------------------------
7240
 
; cmpSingle
7241
 
;---------------------------------------------------------------------------------------------------------
7242
 
 
7243
 
cmpSingle:
7244
 
;Input: HL points to float1, DE points to float2
7245
 
;Output:
7246
 
;      float1 >= float2 : nc
7247
 
;      float1 <  float2 : c,nz
7248
 
;      float1 == float2 : z
7249
 
;  There is a margin of error allowed in the lower 2 bits of the mantissa.
7250
 
;
7251
 
;Currently fails when both numbers have magnitude less than about 2^-106
7252
 
  push hl
7253
 
  push de
7254
 
  push bc
7255
 
  ld c, a
7256
 
  push bc
7257
 
    ex de, hl
7258
 
    call _30
7259
 
  pop bc
7260
 
  ld a, c
7261
 
  pop bc
7262
 
  pop de
7263
 
  pop hl
7264
 
  ret
7265
 
_30:
7266
 
  inc de
7267
 
  inc de
7268
 
  inc de
7269
 
  ld a,(de)
7270
 
  inc hl
7271
 
  inc hl
7272
 
  inc hl
7273
 
  cp (hl)
7274
 
  jr nc,_31
7275
 
  ld a,(hl)
7276
 
_31:
7277
 
  dec hl
7278
 
  dec hl
7279
 
  dec hl
7280
 
  dec de
7281
 
  dec de
7282
 
  dec de
7283
 
  push af
7284
 
  ld bc,scrap
7285
 
  call subSingle
7286
 
  ld a,(scrap+3)    ;new power
7287
 
  pop bc            ;B is old power
7288
 
  or a
7289
 
  jr z,cmp_close
7290
 
  sub b
7291
 
  jr nc,cmp_is_sign
7292
 
  dec a
7293
 
  add a,22
7294
 
  jr nc,cmp_close
7295
 
cmp_is_sign:
7296
 
  ld a,(scrap+2)
7297
 
  or 1    ;not equal, so reset z flag
7298
 
  rla     ;if negative, float1<float2, setting c flag as wanted, else nc.
7299
 
  ret
7300
 
cmp_close:
7301
 
  xor a
7302
 
  ret
7303
 
 
7304
 
endif
7305
 
 
7306
 
if defined MATH_RND
7307
 
 
7308
 
;---------------------------------------------------------------------------------------------------------
7309
 
; randSingle
7310
 
;---------------------------------------------------------------------------------------------------------
7311
 
 
7312
 
randSingle:
7313
 
;Stores a pseudo-random number on [0,1)
7314
 
;it won't produce values on (0,2^-23)
7315
 
  call pushpop
7316
 
  push bc
7317
 
  call rand
7318
 
  push hl
7319
 
  call rand
7320
 
  pop de
7321
 
  ex de,hl
7322
 
  ld bc,$207F
7323
 
;DEHL is the mantissa, B is the exponent
7324
 
  ld a,d
7325
 
  or a
7326
 
  jp m,rand_normed
7327
 
_32:
7328
 
  dec c
7329
 
  add hl,hl
7330
 
  rl e
7331
 
  rl d
7332
 
  jp m,rand_normed
7333
 
  djnz _32
7334
 
rand_zero:
7335
 
  ld c,l
7336
 
  ld b,l
7337
 
  jr rand_done
7338
 
rand_normed:
7339
 
;If we needed to shift more than 8 bits, we'll load in more random data
7340
 
  ld a,b
7341
 
  cp 8
7342
 
  jr c,rand_zero
7343
 
  sub 24
7344
 
  jp nc,rand_no_more_rand_data
7345
 
  push bc
7346
 
  push de
7347
 
  call rand
7348
 
  pop de
7349
 
  ld e,h
7350
 
  ld h,l
7351
 
  pop bc
7352
 
rand_no_more_rand_data:
7353
 
  ld b,e
7354
 
  ld e,d
7355
 
  ld d,c
7356
 
  ld c,h
7357
 
  res 7,e
7358
 
rand_done:
7359
 
  pop hl
7360
 
  ;DEBC
7361
 
  ld (hl),b
7362
 
  inc hl
7363
 
  ld (hl),c
7364
 
  inc hl
7365
 
  ld (hl),e
7366
 
  inc hl
7367
 
  ld (hl),d
7368
 
  ret
7369
 
 
7370
 
rand:
7371
 
;;Tested and passes all CAcert tests
7372
 
;;Uses a very simple 32-bit LCG and 32-bit LFSR
7373
 
;;it has a period of 18,446,744,069,414,584,320
7374
 
;;roughly 18.4 quintillion.
7375
 
;;LFSR taps: 0,2,6,7  = 11000101
7376
 
;;323cc
7377
 
;;Thanks to Runer112 for his help on optimizing the LCG and suggesting to try the much simpler LCG. On their own, the two are terrible, but together they are great.
7378
 
;Uses 64 bits of state
7379
 
  ld hl,(seed0)
7380
 
  ld de,(seed0+2)
7381
 
  ld b,h
7382
 
  ld c,l
7383
 
  add hl,hl
7384
 
  rl e
7385
 
  rl d
7386
 
  add hl,hl
7387
 
  rl e
7388
 
  rl d
7389
 
  inc l
7390
 
  add hl,bc
7391
 
  ld (seed0),hl
7392
 
  ld hl,(seed0+2)
7393
 
  adc hl,de
7394
 
  ld (seed0+2),hl
7395
 
  ex de,hl
7396
 
;;lfsr
7397
 
  ld hl,(seed1)
7398
 
  ld bc,(seed1+2)
7399
 
  add hl,hl
7400
 
  rl c
7401
 
  rl b
7402
 
  ld (seed1+2),bc
7403
 
  sbc a,a
7404
 
  and %11000101
7405
 
  xor l
7406
 
  ld l,a
7407
 
  ld (seed1),hl
7408
 
  ex de,hl
7409
 
  add hl,bc
7410
 
  ret
7411
 
 
7412
 
endif
7413
 
 
7414
 
if defined MATH_FOUT
7415
 
 
7416
 
;---------------------------------------------------------------------------------------------------------
7417
 
; single2Str
7418
 
; in  HL = Single address
7419
 
;     BC = String address
7420
 
; out A = String size
7421
 
; http://0x80.pl/notesen/2015-12-29-float-to-string.html
7422
 
; http://0x80.pl/articles/convert-float-to-integer.html
7423
 
;---------------------------------------------------------------------------------------------------------
7424
 
 
7425
 
single2str:
7426
 
  call pushpop
7427
 
  push bc
7428
 
  call _33
7429
 
  pop de
7430
 
  xor a
7431
 
  cp (hl)
7432
 
  ldi
7433
 
  jr nz,$-3
7434
 
 
7435
 
  ret
7436
 
_33:
7437
 
; Move the float to scrap
7438
 
  ld de,scrap
7439
 
  call mov4
7440
 
 
7441
 
; Make the float negative, write a '-' if already negative
7442
 
  ld de,strout_single
7443
 
  ld hl,scrap+2
7444
 
  ld a,(hl)
7445
 
  ;rlca
7446
 
  ;scf
7447
 
  ;rra
7448
 
  bit 7, a
7449
 
  jr z, _34
7450
 
  ld a,'-'      ; write '-' simbol
7451
 
  ld (de),a
7452
 
  inc de
7453
 
  ld a,(hl)
7454
 
_34:
7455
 
  set 7, a
7456
 
  ld (hl),a
7457
 
 
7458
 
; Check if the exponent field is 0 (a special value)
7459
 
  inc hl
7460
 
  ld a,(hl)
7461
 
  or a
7462
 
  jp z,strcase_single
7463
 
 
7464
 
 
7465
 
; We should write '0' next. When rounding 9.999999... for example, not padding with a 0 will return '.' instead of '1.'
7466
 
  ex de,hl
7467
 
  ld (hl),'0'
7468
 
  inc hl
7469
 
 
7470
 
; Save the pointer
7471
 
  push hl
7472
 
 
7473
 
; Now we need to perform signed (A-128)*77 (approximation of exponent*log10(2))
7474
 
  ld de,77
7475
 
  ld h,a
7476
 
  ld l,d
7477
 
  call mul8_preset
7478
 
  ld de,-77*128
7479
 
  add hl,de
7480
 
  ld a,h
7481
 
  ld (pow10exp_single),a    ;The base-10 exponent
7482
 
  ld de,pown10LUT
7483
 
  jr c,_35
7484
 
  neg
7485
 
  ld de,pow10LUT   ;get the table of 10^-(2^k)
7486
 
_35:
7487
 
  ld hl, pow10exp_single
7488
 
  ld bc,scrap
7489
 
  call singletostr_mul
7490
 
  call singletostr_mul
7491
 
  call singletostr_mul
7492
 
  call singletostr_mul
7493
 
  call singletostr_mul
7494
 
  call singletostr_mul
7495
 
;now the number is pretty close to a nice value
7496
 
 
7497
 
; If it is less than 1, multiply by 10
7498
 
  ld a,(scrap+3)
7499
 
  sub 128
7500
 
  jr nc,_36
7501
 
  ld de,const_10
7502
 
  ;ld hl,scrap    ;Since singletostr_mul returns BC = scrap, can do this cheaper
7503
 
  ;ld b,h
7504
 
  ;ld c,l
7505
 
  ld h,b
7506
 
  ld l,c
7507
 
  call mulSingle
7508
 
  ld hl,pow10exp_single
7509
 
  dec (hl)
7510
 
  ld a,(scrap+3)
7511
 
  sub 128
7512
 
_36:
7513
 
 
7514
 
; Convert to a fixed-point number !
7515
 
  inc a
7516
 
  ld b,a
7517
 
  xor a
7518
 
_37:
7519
 
  ld hl,scrap
7520
 
  sla (hl)
7521
 
  inc hl
7522
 
  rl (hl)
7523
 
  inc hl
7524
 
  rl (hl)
7525
 
  rla
7526
 
  djnz _37
7527
 
 
7528
 
;We need to get 7 digits
7529
 
  ld b,6
7530
 
  pop hl    ;Points to the string
7531
 
 
7532
 
;The first digit can be as large as 20, so it'll actually be two digits
7533
 
  cp 10
7534
 
  jr c,_38
7535
 
  dec b
7536
 
;Increment the exponent :)
7537
 
  ld de,(pow10exp_single-1)
7538
 
  inc d
7539
 
  ld (pow10exp_single-1),de
7540
 
;
7541
 
  ld (hl),'0'-1
7542
 
  inc (hl)
7543
 
  sub 10
7544
 
  jr nc,$-3
7545
 
  add a,10
7546
 
  inc hl
7547
 
_38:
7548
 
; Get the remaining digits.
7549
 
_39:
7550
 
  add a,'0'
7551
 
  ld (hl),a
7552
 
  inc hl
7553
 
  push hl
7554
 
  push bc
7555
 
  call singletostrmul10
7556
 
  pop bc
7557
 
  pop hl
7558
 
  djnz _39
7559
 
 
7560
 
;Save the pointer to the end of the string
7561
 
  ld d,h
7562
 
  ld e,l
7563
 
  ;ld (hl), 0
7564
 
 
7565
 
;Now let's round!
7566
 
  cp 5
7567
 
  jr c,rounding_done_single
7568
 
  jr _40a  ;.db $DA ;start of `jp c,*` in order to skip the next instruction
7569
 
_40:
7570
 
  ld (hl),'0'
7571
 
_40a:
7572
 
  dec hl
7573
 
  inc (hl)
7574
 
  ld a,(hl)
7575
 
  cp $3A
7576
 
  jr z,_40
7577
 
rounding_done_single:
7578
 
 
7579
 
 
7580
 
;Strip the leading zero if it exists (rounding may have bumped this to `1`)
7581
 
  ld hl,strout_single
7582
 
  ld a,(hl)
7583
 
  cp '-'
7584
 
  jr nz,_41
7585
 
  inc hl
7586
 
  ld a,(hl)
7587
 
_41:
7588
 
  cp '0'
7589
 
  jr nz,_42
7590
 
  dec de
7591
 
  ex de,hl
7592
 
  ;Now lets move HL-DE bytes at DE+1 to DE
7593
 
  sbc hl,de
7594
 
  ld b,h
7595
 
  ld c,l
7596
 
  ld h,d
7597
 
  ld l,e
7598
 
  inc hl
7599
 
  ldir
7600
 
  cp a
7601
 
_42:
7602
 
 
7603
 
  push de
7604
 
;If z flag is reset, this means that the exponent should be bumped up 1
7605
 
  ld a,(pow10exp_single)
7606
 
  jr z,_43
7607
 
  inc a
7608
 
  ld (pow10exp_single),a
7609
 
_43:
7610
 
 
7611
 
  ;if -4<=A<=6, then need to insert the decimal place somewhere.
7612
 
  add a,4
7613
 
  cp 10
7614
 
  jp c,movdec_single
7615
 
_44:
7616
 
  ;for this, we need to insert the decimal after the first digit
7617
 
  ;Then, we need to append the exponent string
7618
 
  ld hl,strout_single
7619
 
  ld de,strout_single-1
7620
 
  ld a,(hl)
7621
 
  cp '-'    ;negative sign
7622
 
  jr nz,_45
7623
 
  ldi
7624
 
_45:
7625
 
  ldi
7626
 
  ld a,'.'
7627
 
  ld (de),a
7628
 
 
7629
 
;remove any stray zeroes at the end before appending the exponent
7630
 
  pop hl
7631
 
  call strip_zeroes
7632
 
 
7633
 
; Write the exponent
7634
 
  ld (hl),'e'
7635
 
  inc hl
7636
 
  ld a,(pow10exp_single)
7637
 
  or a
7638
 
  jp p,_46
7639
 
  ld (hl),'-'    ;negative sign
7640
 
  inc hl
7641
 
  neg
7642
 
_46:
7643
 
  cp 10
7644
 
  jr c,_47
7645
 
  ld (hl),'0'-1
7646
 
  inc (hl)
7647
 
  sub 10
7648
 
  jr nc,$-3
7649
 
  add a,10
7650
 
  inc hl
7651
 
_47:
7652
 
  add a,'0'
7653
 
  ld (hl),a
7654
 
  inc hl
7655
 
  ld (hl),0
7656
 
 
7657
 
  ld de, strout_single
7658
 
  xor a
7659
 
  sbc hl, de
7660
 
  ld a, l         ; string size
7661
 
 
7662
 
  ld hl,strout_single-1
7663
 
  ret
7664
 
 
7665
 
movdec_single:
7666
 
  ld a,(pow10exp_single)
7667
 
  or a
7668
 
  jp p,posdec_single
7669
 
  ld l,a
7670
 
;need to put zeroes before everything
7671
 
  ld de,strout_single
7672
 
  ld a,(de)
7673
 
  cp '-'    ;negative sign
7674
 
  push af
7675
 
  ld a,'0'
7676
 
  jr z,$+3
7677
 
_48:
7678
 
  dec de
7679
 
  ld (de),a
7680
 
  inc l
7681
 
  jr nz,_48
7682
 
_49:
7683
 
  ex de,hl
7684
 
  ld (hl),'.'
7685
 
  pop af
7686
 
  jr nz,_50
7687
 
  dec hl
7688
 
  ld (hl),a
7689
 
_50:
7690
 
  ex de,hl
7691
 
  pop hl
7692
 
  call strip_zeroes
7693
 
  ld (hl),0
7694
 
  ex de,hl
7695
 
  ret
7696
 
 
7697
 
posdec_single:
7698
 
  ld hl,strout_single
7699
 
  ld de,strout_single-1
7700
 
  ld c,a
7701
 
  ld a,(hl)
7702
 
  ld b,0
7703
 
  cp '-'    ;negative sign
7704
 
  jr nz,_51
7705
 
  inc c
7706
 
_51:
7707
 
  inc c
7708
 
  ldir
7709
 
  ld a,'.'
7710
 
  ld (de),a
7711
 
  pop hl
7712
 
  call strip_zeroes
7713
 
  ld (hl),0
7714
 
  ld hl,strout_single-1
7715
 
  ret
7716
 
 
7717
 
strcase_single:
7718
 
  ld hl,str_Zero
7719
 
  ld a,(scrap+2)
7720
 
  add a,a
7721
 
  and $C0
7722
 
  jr z,_52
7723
 
  ld hl,str_Inf
7724
 
  jp pe,_52
7725
 
  ld hl,str_NaN
7726
 
_52:
7727
 
  call mov4
7728
 
  ld hl,strout_single
7729
 
  ret
7730
 
 
7731
 
singletostrmul10:
7732
 
;multiply the 0.24 fixed point number at scrap by 10
7733
 
;overflow in A register
7734
 
  ld a,(scrap+2)
7735
 
  ld e,a
7736
 
  ld hl,(scrap)
7737
 
  xor a
7738
 
  ld d,e
7739
 
  ld b,h
7740
 
  ld c,l
7741
 
  add hl,hl
7742
 
  rl d
7743
 
  rla
7744
 
  add hl,hl
7745
 
  rl d
7746
 
  rla
7747
 
  add hl,bc
7748
 
  ld b,a
7749
 
  ld a,d
7750
 
  adc a,e
7751
 
  ld d,a
7752
 
  ld a,b
7753
 
  adc a,0
7754
 
  add hl,hl
7755
 
  rl d
7756
 
  rla
7757
 
  ld (scrap+1),de
7758
 
  ld (scrap),hl
7759
 
  ret
7760
 
 
7761
 
strip_zeroes:
7762
 
  ld a,'0'
7763
 
_53:
7764
 
  dec hl
7765
 
  cp (hl)
7766
 
  jr z,_53
7767
 
 
7768
 
;Check that the last  digit isn't a decimal!
7769
 
  ld a,'.'
7770
 
  cp (hl)
7771
 
  ret z
7772
 
  inc hl
7773
 
  ret
7774
 
 
7775
 
singletostr_mul:
7776
 
  rra
7777
 
  call c,_54
7778
 
  ld hl,4
7779
 
  add hl,de
7780
 
  ex de,hl
7781
 
  ret
7782
 
_54:
7783
 
  ld h,b
7784
 
  ld l,c
7785
 
  jp mulSingle
7786
 
mul8:
7787
 
;H*E => HL
7788
 
  ld l,0
7789
 
  ld d,l
7790
 
mul8_preset:
7791
 
  sla h
7792
 
  jr nc,$+3
7793
 
  ld l,e
7794
 
  add hl,hl
7795
 
  jr nc,$+3
7796
 
  add hl,de
7797
 
  add hl,hl
7798
 
  jr nc,$+3
7799
 
  add hl,de
7800
 
  add hl,hl
7801
 
  jr nc,$+3
7802
 
  add hl,de
7803
 
  add hl,hl
7804
 
  jr nc,$+3
7805
 
  add hl,de
7806
 
  add hl,hl
7807
 
  jr nc,$+3
7808
 
  add hl,de
7809
 
  add hl,hl
7810
 
  jr nc,$+3
7811
 
  add hl,de
7812
 
  add hl,hl
7813
 
  ret nc
7814
 
  add hl,de
7815
 
  ret
7816
 
 
7817
 
endif
7818
 
 
7819
 
 
7820
 
if defined MATH_FIN
7821
 
 
7822
 
;---------------------------------------------------------------------------------------------------------
7823
 
; str2Single
7824
 
; https://www.ticalc.org/pub/86/asm/source/routines/atof.asm
7825
 
;---------------------------------------------------------------------------------------------------------
7826
 
 
7827
 
char_NEG: equ  '-'
7828
 
char_ENG: equ  ','
7829
 
char_DEC: equ  '.'
7830
 
ptr_sto: equ scrap+9
7831
 
 
7832
 
;;#Routines/Single Precision
7833
 
;;Inputs:
7834
 
;;  HL points to the string
7835
 
;;  BC points to where the float is output
7836
 
;;Output:
7837
 
;;  scrap+9 is the pointer to the end of the string
7838
 
;;Destroys:
7839
 
;;  11 bytes at scrap ?
7840
 
 
7841
 
str2single:
7842
 
  call pushpop
7843
 
  push bc
7844
 
;Check if there is a negative sign.
7845
 
;   Save for later
7846
 
;   Advance ptr
7847
 
  ld a,(hl)
7848
 
  sub char_NEG
7849
 
  sub 1
7850
 
  push af
7851
 
  jr nc,$+3
7852
 
  inc hl
7853
 
;Skip all leading zeroes
7854
 
  ld a,(hl)
7855
 
  cp '0'
7856
 
  jr z,$-4      ;jumps back to the `inc hl`
7857
 
;Set exponent to 0
7858
 
  ld b,0
7859
 
;Check if the next char is char_DEC
7860
 
  sub char_DEC
7861
 
  or a      ;to reset the carry flag
7862
 
  jr nz,_55
7863
 
  jr _54a   ;.db $FE   ;start of cp *
7864
 
;Get rid of zeroes
7865
 
  dec b
7866
 
_54a:
7867
 
  inc hl
7868
 
  ld a,(hl)
7869
 
  cp '0'
7870
 
  jr z,$-5      ;jumps back to the `dec b`
7871
 
  scf
7872
 
_55:
7873
 
;Now we read in the next 8 digits
7874
 
  ld de,scrap+3
7875
 
  call ascii_to_uint8
7876
 
  call ascii_to_uint8
7877
 
  call ascii_to_uint8
7878
 
  call ascii_to_uint8
7879
 
;Now `scrap` holds the 4-digit base-100 number.
7880
 
;b is the exponent
7881
 
;if carry flag is set, just need to get rid of remaining digits
7882
 
;Otherwise, need to get rid of remaining digits, while incrementing the exponent
7883
 
  sbc a,a
7884
 
  inc a
7885
 
  ld c,a
7886
 
_56:
7887
 
  ld a,(hl)
7888
 
  cp 30h
7889
 
  jr nz,_57
7890
 
  inc hl
7891
 
  ld a,b
7892
 
  add a,c
7893
 
  jp z,strToSingle_inf
7894
 
  ld b,a
7895
 
  jr _56
7896
 
;Now check for engineering `E` to modify the exponent
7897
 
_57:
7898
 
  cp char_NEG
7899
 
  call z,str_eng_exp
7900
 
;Gotta multiply the number at (scrap) by 2^24
7901
 
  ld (ptr_sto),hl
7902
 
  ld d,100
7903
 
  call scrap_times_256
7904
 
  ld a,c
7905
 
  ld (scrap+6),a
7906
 
  call scrap_times_256
7907
 
  ld a,c
7908
 
  ld (scrap+5),a
7909
 
  call scrap_times_256
7910
 
  ld a,c
7911
 
  ld (scrap+4),a
7912
 
  call scrap_times_256
7913
 
  ld a,c
7914
 
  ld (scrap+3),a
7915
 
;Now scrap+3 is a 4-byte mantissa that needs to be normalized
7916
 
;
7917
 
  ld hl,(scrap+3)
7918
 
  ld a,h
7919
 
  or l
7920
 
  ld hl,(scrap+5)
7921
 
  or l
7922
 
  or h
7923
 
  jp z,strToSingle_zero-1
7924
 
  ld c,$7F
7925
 
  ld a,h
7926
 
  or a
7927
 
  jp m,strToSingle_normed
7928
 
  ;Will need to iterate at most three times
7929
 
_58:
7930
 
  dec c
7931
 
  ld hl,scrap+3
7932
 
  sla (hl)
7933
 
  inc hl
7934
 
  rl (hl)
7935
 
  inc hl
7936
 
  rl (hl)
7937
 
  inc hl
7938
 
  adc a,a
7939
 
  jp p,_58
7940
 
strToSingle_normed:
7941
 
;Move the number to scrap
7942
 
  ld hl,(scrap+4)
7943
 
  ld (scrap),hl
7944
 
  ld l,a
7945
 
  ld h,c
7946
 
  sla l
7947
 
  pop af
7948
 
  rr l
7949
 
  ld (scrap+2),hl
7950
 
;now (scrap) is our number, need to multiply by power of 10!
7951
 
;Power of 10 is stored in B, need to put in A first
7952
 
  xor a
7953
 
  sub b
7954
 
  ld de,pown10LUT
7955
 
  jp p,_59
7956
 
  ld a,b
7957
 
  ld de,pow10LUT
7958
 
  cp 40
7959
 
  jp nc,strToSingle_inf+1
7960
 
_59:
7961
 
  cp 40
7962
 
  jp nc,strToSingle_zero
7963
 
  ld hl,scrap
7964
 
  ld b,h
7965
 
  ld c,l
7966
 
  call _60
7967
 
  call _60
7968
 
  call _60
7969
 
  call _60
7970
 
  call _60
7971
 
  call _60
7972
 
  pop de
7973
 
  jp mov4
7974
 
_60:
7975
 
  rra
7976
 
  call c,mulSingle
7977
 
  inc de
7978
 
  inc de
7979
 
  inc de
7980
 
  inc de
7981
 
  ret
7982
 
str_eng_exp:
7983
 
  ld de,0
7984
 
  inc hl
7985
 
  ld a,(hl)
7986
 
  cp char_NEG    ;negative exponent?
7987
 
  push af
7988
 
  jr nz,$+3
7989
 
  inc hl
7990
 
_61:
7991
 
  ld a,(hl)
7992
 
  sub 3Ah
7993
 
  add a,10
7994
 
  jr nc,_62
7995
 
  inc hl
7996
 
  push hl
7997
 
  ld h,d
7998
 
  ld l,e
7999
 
  add hl,hl
8000
 
  add hl,hl
8001
 
  add hl,de
8002
 
  add hl,hl
8003
 
  add a,l
8004
 
  ld l,a
8005
 
  ex de,hl
8006
 
  pop hl
8007
 
  jp c,eng_overflow
8008
 
  inc d
8009
 
  dec d
8010
 
  jp z,_61
8011
 
  jp nz,eng_overflow
8012
 
_62:
8013
 
  ld a,e
8014
 
  cp 40
8015
 
  jr nc,eng_overflow
8016
 
  pop af
8017
 
  ld a,b
8018
 
  jr nz,_63
8019
 
  sub e
8020
 
  ld b,a
8021
 
  ret
8022
 
_63:
8023
 
  add a,e
8024
 
  ld b,a
8025
 
  ret
8026
 
scrap_times_256:
8027
 
  ld e,8
8028
 
_64:
8029
 
  or a
8030
 
  ld hl,scrap
8031
 
  call _65
8032
 
  call _65
8033
 
  rl c
8034
 
  dec e
8035
 
  jr nz,_64
8036
 
  ret
8037
 
_65:
8038
 
  call scrap_times_sub
8039
 
scrap_times_sub:
8040
 
  ld a,(hl)
8041
 
  rla
8042
 
  cp d
8043
 
  jr c,$+3
8044
 
  sub d
8045
 
  ld (hl),a
8046
 
  inc hl
8047
 
  ccf
8048
 
  ret
8049
 
eng_overflow:
8050
 
  pop af
8051
 
  jr nz,strToSingle_inf
8052
 
  pop af
8053
 
strToSingle_zero:
8054
 
  ld hl,const_0
8055
 
  pop de
8056
 
  jp mov4
8057
 
strToSingle_inf:
8058
 
;return inf
8059
 
  pop af
8060
 
  ld hl,const_inf
8061
 
  jr nc,_66
8062
 
  ld hl,const_NegInf
8063
 
_66:
8064
 
  pop de
8065
 
  jp mov4
8066
 
 
8067
 
endif
8068
 
 
8069
 
if defined roundSingle or defined MATH_FRCSGL
8070
 
 
8071
 
;---------------------------------------------------------------------------------------------------------
8072
 
; int2Single
8073
 
; http://wikiti.brandonw.net/index.php?title=Z80_Routines:Math:Division#24.2F8_division
8074
 
;---------------------------------------------------------------------------------------------------------
8075
 
 
8076
 
int2Single:
8077
 
    call pushpop
8078
 
        push bc
8079
 
            push hl
8080
 
                pop ix
8081
 
            ld l, (ix)            ; convert integer parameter to single float
8082
 
                ld h, (ix+1)
8083
 
                ld bc, 0x1000         ; bynary digits count + sign
8084
 
 
8085
 
int2Single.test.zero:
8086
 
        xor a
8087
 
                or h                  ; test if hl is not zero
8088
 
                jr nz, int2Single.test.negative
8089
 
                or l
8090
 
                jr nz, int2Single.test.negative
8091
 
                ld hl, 0
8092
 
                ld de, 0
8093
 
                jp int2Single.save
8094
 
 
8095
 
int2Single.test.negative:
8096
 
        bit 7, h              ; test if hl is negative
8097
 
                jr z, int2Single.normalize
8098
 
                ld c, 0x80            ; sign negative
8099
 
                ld a, h               ;\
8100
 
                cpl                   ; |
8101
 
                ld h, a               ; | abs(hl)
8102
 
                ld a, l               ; |
8103
 
                cpl                   ; |
8104
 
                ld l, a               ;/
8105
 
                inc hl
8106
 
 
8107
 
int2Single.normalize:
8108
 
        dec b
8109
 
        bit 7, h
8110
 
                jr nz, int2Single.mount
8111
 
                sla l
8112
 
                rl h
8113
 
                jr int2Single.normalize
8114
 
 
8115
 
int2Single.mount:
8116
 
                res 7, h              ; turn off upper bit
8117
 
 
8118
 
        ld a, c               ; restore sign
8119
 
        or h                  ; put sign...
8120
 
        ld h, a               ; ...into upper mantissa
8121
 
 
8122
 
                ld e, h               ; sign+mantissa
8123
 
                ld h, l               ; high mantissa
8124
 
                ld l, 0               ; low mantissa
8125
 
 
8126
 
        ld a, b               ; binary digits count
8127
 
        or 0x80               ; exponent bias
8128
 
        ld d, a               ; exponent
8129
 
 
8130
 
int2Single.save:
8131
 
    pop ix
8132
 
        ld (ix),   l          ; low mantissa
8133
 
        ld (ix+1), h          ; high mantissa
8134
 
        ld (ix+2), e          ; sign + mantissa
8135
 
        ld (ix+3), d          ; expoent
8136
 
        ld (ix+4), 0
8137
 
        ld (ix+5), 0
8138
 
        ld (ix+6), 0
8139
 
        ld (ix+7), 0
8140
 
        ret
8141
 
 
8142
 
endif
8143
 
 
8144
 
if defined roundSingle or defined MATH_FRCINT
8145
 
 
8146
 
;---------------------------------------------------------------------------------------------------------
8147
 
; single2Int
8148
 
; http://0x80.pl/articles/convert-float-to-integer.html
8149
 
;---------------------------------------------------------------------------------------------------------
8150
 
single2Int:
8151
 
;Input:
8152
 
; HL points to the single-precision float
8153
 
;Output:
8154
 
; HL is the 16-bit signed integer part of the float
8155
 
; BC points to 16-bit signed integer
8156
 
  call pushpop
8157
 
  push bc
8158
 
    ld e,(hl)
8159
 
    inc hl
8160
 
    ld d,(hl)
8161
 
    inc hl
8162
 
    ld a,(hl)
8163
 
    add a,a
8164
 
    push af
8165
 
    scf
8166
 
    rra
8167
 
    ld c,a
8168
 
    inc hl
8169
 
    ld a,(hl)
8170
 
    ld hl,0
8171
 
    sub 80h
8172
 
    jr c,no_shift_single_to_int16
8173
 
    cp 39
8174
 
    jr nc,no_shift_single_to_int16
8175
 
    sub 8
8176
 
    jr c,_67
8177
 
    ld l,c
8178
 
    ld c,d
8179
 
    ld d,e
8180
 
    ld e,h
8181
 
    sub 8
8182
 
    jr c,_67
8183
 
    ld h,l
8184
 
    ld l,c
8185
 
    ld c,d
8186
 
    ld d,e
8187
 
    sub 8
8188
 
    jr c,_67
8189
 
    ld h,l
8190
 
    ld l,c
8191
 
    ld c,d
8192
 
    sub 8
8193
 
    jr c,_67
8194
 
    ld h,l
8195
 
    ld l,c
8196
 
    jr _67a ;.db $11 ;start of ld de,*
8197
 
_67:
8198
 
    add a,9
8199
 
_67a:
8200
 
    ld b,a
8201
 
    ld a,e
8202
 
_68:
8203
 
    add a,a
8204
 
    rl d
8205
 
    rl c
8206
 
    adc hl,hl
8207
 
    djnz _68
8208
 
no_shift_single_to_int16:
8209
 
    pop af
8210
 
    jr nc,_69
8211
 
    ;need to negate
8212
 
    xor a
8213
 
    sub e
8214
 
    ld e,0
8215
 
    ld a,e
8216
 
    sbc a,d
8217
 
    ld a,e
8218
 
    sbc a,c
8219
 
    ld d,e
8220
 
    ex de,hl
8221
 
    sbc hl,de
8222
 
_69:
8223
 
  pop ix
8224
 
  ld (ix), l
8225
 
  ld (ix+1), h
8226
 
  ret
8227
 
 
8228
 
endif
8229
 
 
8230
 
;---------------------------------------------------------------------------------------------------------
8231
 
; Auxiliary routines
8232
 
;---------------------------------------------------------------------------------------------------------
8233
 
 
8234
 
str_Zero: db "0",0
8235
 
str_Inf:  db "inf",0
8236
 
str_NaN:  db "NaN",0
8237
 
 
8238
 
start_const:
8239
 
const_pi:      db $DB,$0F,$49,$81
8240
 
const_e:       db $54,$f8,$2d,$81
8241
 
const_lg_e:    db $3b,$AA,$38,$80
8242
 
const_ln_2:    db $18,$72,$31,$7f
8243
 
const_log2:    db $9b,$20,$1a,$7e
8244
 
const_lg10:    db $78,$9a,$54,$81
8245
 
const_0:       db $00,$00,$00,$00
8246
 
const_1:       db $00,$00,$00,$80
8247
 
const_2:       dw 0, 33024
8248
 
const_3:       dw 0, 33088
8249
 
const_4:       dw 0, 33280
8250
 
const_5:       dw 0, 33312
8251
 
const_7:       dw 0, 33376
8252
 
const_9:       dw 0, 33552
8253
 
const_16:      dw 0, 33792
8254
 
const_100:     db $00,$00,$48,$86
8255
 
const_100_inv: dw 55050, 31011
8256
 
const_precision: db $77,$CC,$2B,$65  ;10^-8
8257
 
const_half_1:  dw 0, 32512
8258
 
const_inf:     db $00,$00,$40,$00
8259
 
const_NegInf:  db $00,$00,$C0,$00
8260
 
const_NaN:     db $00,$00,$20,$00
8261
 
const_log10_e: db $D9,$5B,$5E,$7E
8262
 
const_2pi:     db $DB,$0F,$49,$82
8263
 
const_2pi_inv: db $83,$F9,$22,$7D
8264
 
const_half_pi: dw 4059, 32841
8265
 
const_p25:     db $00,$00,$00,$7E
8266
 
const_p5:      db $00,$00,$00,$7F
8267
 
;     db $,$,$,$
8268
 
end_const:
8269
 
sin_a1: dw 43691, 32042
8270
 
sin_a2: dw 34952, 30984
8271
 
sin_a3: dw 3329, 29520
8272
 
cos_a1: equ const_half_1
8273
 
cos_a2: dw 43691, 31530
8274
 
cos_a3: dw 2914, 30262
8275
 
exp_a1: db $15,$72,$31,$7F  ;.693146989552
8276
 
exp_a2: db $CE,$FE,$75,$7D  ;.2402298085906
8277
 
exp_a3: db $7B,$42,$63,$7B  ;.0554833215071
8278
 
exp_a4: db $FD,$94,$1E,$79  ;.00967907584392
8279
 
exp_a5: db $5E,$01,$23,$76  ;.001243632065103
8280
 
exp_a6: db $5F,$B7,$63,$73  ;.0002171671843714
8281
 
const_1p40625: db $00,$00,$34,$80  ;1.40625
8282
 
 
8283
 
if defined MATH_CONSTSINGLE
8284
 
 
8285
 
iconstSingle:
8286
 
    ex (sp),hl
8287
 
    ld a,(hl)
8288
 
    inc hl
8289
 
    ex (sp),hl
8290
 
constSingle:
8291
 
;A is the constant ID#
8292
 
;returns nc if failed, c otherwise
8293
 
;HL points to the constant
8294
 
    cp (end_const-start_const)>>2
8295
 
    ret nc
8296
 
    ld hl,start_const
8297
 
    add a,a
8298
 
    add a,a
8299
 
    add a,l
8300
 
    ld l,a
8301
 
;#if ((end_const-4)>>8)!=(start_const>>8)
8302
 
;    ccf
8303
 
;    ret c
8304
 
;    inc h
8305
 
;#endif
8306
 
    scf
8307
 
    ret
8308
 
 
8309
 
endif
8310
 
 
8311
 
;;LUTs used
8312
 
lut:
8313
 
pown10LUT:
8314
 
db $CD,$CC,$4C,$7C  ;.1
8315
 
db $0A,$D7,$23,$79  ;.01
8316
 
db $17,$B7,$51,$72  ;.0001
8317
 
db $77,$CC,$2B,$65  ;10^-8
8318
 
db $95,$95,$66,$4A  ;10^-16
8319
 
db $1F,$B1,$4F,$15  ;10^-32
8320
 
pow10LUT:
8321
 
const_10:
8322
 
db $00,$00,$20,$83 ;10
8323
 
db $00,$00,$48,$86 ;100
8324
 
db $00,$40,$1C,$8D ;10000
8325
 
db $20,$BC,$3E,$9A ;10^8
8326
 
db $CA,$1B,$0E,$B5 ;10^16
8327
 
db $AE,$C5,$1D,$EA ;10^32
8328
 
 
8329
 
C_Times_BDE:
8330
 
;;C*BDE => CAHL
8331
 
;C = 0     157
8332
 
;C = 1     141
8333
 
;141+
8334
 
;C>=128    135+6{0,33+{0,1}}+{0,20+{0,8}}
8335
 
;C>=64     115+5{0,33+{0,1}}+{0,20+{0,8}}
8336
 
;C>=32     95+4{0,33+{0,1}}+{0,20+{0,8}}
8337
 
;C>=16     75+3{0,33+{0,1}}+{0,20+{0,8}}
8338
 
;C>=8      55+2{0,33+{0,1}}+{0,20+{0,8}}
8339
 
;C>=4      35+{0,33+{0,1}}+{0,20+{0,8}}
8340
 
;C>=2      15+{0,20+{0,8}}
8341
 
;min: 141cc
8342
 
;max: 508cc
8343
 
;avg: 349.21279907227cc
8344
 
 
8345
 
  ld a,b
8346
 
  ld h,d
8347
 
  ld l,e
8348
 
  sla c
8349
 
  jr c,mul8_24_1
8350
 
  sla c
8351
 
  jr c,mul8_24_2
8352
 
  sla c
8353
 
  jr c,mul8_24_3
8354
 
  sla c
8355
 
  jr c,mul8_24_4
8356
 
  sla c
8357
 
  jr c,mul8_24_5
8358
 
  sla c
8359
 
  jr c,mul8_24_6
8360
 
  sla c
8361
 
  jr c,mul8_24_7
8362
 
  sla c
8363
 
  ret c
8364
 
  ld a,c
8365
 
  ld h,c
8366
 
  ld l,c
8367
 
  ret
8368
 
mul8_24_1:
8369
 
    add hl,hl
8370
 
    rla
8371
 
    rl c
8372
 
    jr nc,$+7
8373
 
    add hl,de
8374
 
    adc a,b
8375
 
    jr nc,$+3
8376
 
    inc c
8377
 
mul8_24_2:
8378
 
    add hl,hl
8379
 
    rla
8380
 
    rl c
8381
 
    jr nc,$+7
8382
 
    add hl,de
8383
 
    adc a,b
8384
 
    jr nc,$+3
8385
 
    inc c
8386
 
mul8_24_3:
8387
 
    add hl,hl
8388
 
    rla
8389
 
    rl c
8390
 
    jr nc,$+7
8391
 
    add hl,de
8392
 
    adc a,b
8393
 
    jr nc,$+3
8394
 
    inc c
8395
 
mul8_24_4:
8396
 
    add hl,hl
8397
 
    rla
8398
 
    rl c
8399
 
    jr nc,$+7
8400
 
    add hl,de
8401
 
    adc a,b
8402
 
    jr nc,$+3
8403
 
    inc c
8404
 
mul8_24_5:
8405
 
    add hl,hl
8406
 
    rla
8407
 
    rl c
8408
 
    jr nc,$+7
8409
 
    add hl,de
8410
 
    adc a,b
8411
 
    jr nc,$+3
8412
 
    inc c
8413
 
mul8_24_6:
8414
 
    add hl,hl
8415
 
    rla
8416
 
    rl c
8417
 
    jr nc,$+7
8418
 
    add hl,de
8419
 
    adc a,b
8420
 
    jr nc,$+3
8421
 
    inc c
8422
 
mul8_24_7:
8423
 
    add hl,hl
8424
 
    rla
8425
 
    rl c
8426
 
    ret nc
8427
 
    add hl,de
8428
 
    adc a,b
8429
 
    ret nc
8430
 
    inc c
8431
 
    ret
8432
 
 
8433
 
pushpop:
8434
 
;26 bytes, adds 118cc to the traditional routine
8435
 
  ex (sp),hl
8436
 
  push de
8437
 
  push bc
8438
 
  push af
8439
 
  push hl
8440
 
  ld hl,pushpopret
8441
 
  ex (sp),hl
8442
 
  push hl
8443
 
  push af
8444
 
  ld hl,12
8445
 
  add hl,sp
8446
 
  ld a,(hl)
8447
 
  inc hl
8448
 
  ld h,(hl)
8449
 
  ld l,a
8450
 
  pop af
8451
 
  ret
8452
 
pushpopret:
8453
 
  pop af
8454
 
  pop bc
8455
 
  pop de
8456
 
  pop hl
8457
 
  ret
8458
 
 
8459
 
mov4:
8460
 
  ldi
8461
 
  ldi
8462
 
  ldi
8463
 
  ldi
8464
 
  ret
8465
 
 
8466
 
if defined MATH_FIN
8467
 
 
8468
 
ascii_to_uint8:
8469
 
;c flag means don't increment the exponent
8470
 
  ld c,0
8471
 
  ld a,(hl)
8472
 
  jr c,ascii_to_uint8_noexp
8473
 
  cp char_DEC
8474
 
  jr z,ascii_to_uint8_noexp-2
8475
 
_70:
8476
 
  sub 3Ah
8477
 
  add a,10
8478
 
  jr nc,ascii_to_uint8_noexp_end
8479
 
  inc b
8480
 
  ld c,a
8481
 
  add a,a
8482
 
  add a,a
8483
 
  add a,c
8484
 
  add a,a
8485
 
  ld c,a
8486
 
  inc hl
8487
 
_71:
8488
 
  ld a,(hl)
8489
 
  cp char_DEC
8490
 
  jr z,ascii_to_uint8_noexp_2nd
8491
 
_72:
8492
 
  sub 3Ah
8493
 
  add a,10
8494
 
  jr nc,ascii_to_uint8_noexp_end
8495
 
  inc b
8496
 
  add a,c
8497
 
  inc hl
8498
 
  ld (de),a
8499
 
  dec de
8500
 
  or a
8501
 
  ret
8502
 
 
8503
 
  inc hl
8504
 
  ld a,(hl)
8505
 
ascii_to_uint8_noexp:
8506
 
  sub 3Ah
8507
 
  add a,10
8508
 
  jr nc,ascii_to_uint8_noexp_end
8509
 
  ld c,a
8510
 
  add a,a
8511
 
  add a,a
8512
 
  add a,c
8513
 
  add a,a
8514
 
  ld c,a
8515
 
ascii_to_uint8_noexp_2nd:
8516
 
  inc hl
8517
 
  ld a,(hl)
8518
 
  sub 3Ah
8519
 
  add a,10
8520
 
  jr nc,ascii_to_uint8_noexp_end
8521
 
  add a,c
8522
 
  inc hl
8523
 
  jr ascii_2  ;.db $FE   ;start of `cp **`, saves 1cc
8524
 
ascii_to_uint8_noexp_end:
8525
 
  ld a,c
8526
 
ascii_2:
8527
 
  ld (de),a
8528
 
  dec de
8529
 
  scf
8530
 
  ret
8531
 
 
8532
 
endif
8533
 
 
8534
 
if defined MATH_RSUBSINGLE
8535
 
 
8536
 
rsubSingle:
8537
 
;;-x+y
8538
 
    push af
8539
 
    push hl
8540
 
    push de
8541
 
    push bc
8542
 
    push de
8543
 
    ld de,addend2
8544
 
    ldi
8545
 
    ldi
8546
 
    ld a,(hl)
8547
 
    xor 80h
8548
 
    ld (de),a
8549
 
    inc de
8550
 
    inc hl
8551
 
    ld a,(hl)
8552
 
    ld (de),a
8553
 
    pop de
8554
 
    ld hl,addend2
8555
 
    jp addInject    ;jumps in to the addSingle routine
8556
 
 
8557
 
endif
8558
 
 
8559
 
if defined MATH_MOD1SINGLE
8560
 
 
8561
 
;This routine performs `x mod 1`, returning a non-negative value.
8562
 
;+inf -> NaN
8563
 
;-inf -> NaN
8564
 
;NaN  -> NaN
8565
 
mod1Single:
8566
 
  call pushpop
8567
 
  push bc
8568
 
  ld e,(hl)
8569
 
  inc hl
8570
 
  ld d,(hl)
8571
 
  inc hl
8572
 
  ld c,(hl)
8573
 
  ld a,c
8574
 
  xor 80h
8575
 
  push af
8576
 
  jp p,mod1Single.1
8577
 
  ld c,a
8578
 
mod1Single.1:
8579
 
 
8580
 
  inc hl
8581
 
  ld a,(hl)
8582
 
  ld b,a
8583
 
  or a
8584
 
  jr z,mod1Single_special
8585
 
  sub $80
8586
 
  jr c,mod1_end
8587
 
  inc a
8588
 
  ld b,a
8589
 
  ld a,c
8590
 
  ex de,hl
8591
 
mod1Single.2:
8592
 
  add hl,hl
8593
 
  rla
8594
 
  djnz mod1Single.2
8595
 
  ld c,a
8596
 
 
8597
 
;If it is zero, need to set exponent to zero and return
8598
 
  or h
8599
 
  or l
8600
 
  ex de,hl
8601
 
  jr z,mod1_end
8602
 
 
8603
 
;Need to normalize
8604
 
  ld b,$7F
8605
 
  ld a,c
8606
 
  or a
8607
 
  jp m,mod1_end
8608
 
  ex de,hl
8609
 
mod1Single.3:
8610
 
  dec b
8611
 
  add hl,hl
8612
 
  adc a,a
8613
 
  jp p,mod1Single.3
8614
 
  ld c,a
8615
 
  ex de,hl
8616
 
mod1_end:
8617
 
  pop af
8618
 
  pop hl
8619
 
  jp m,mod1Single.4
8620
 
  ;make sure it isn't zero else we need to add 1
8621
 
  ld a,b
8622
 
  or a
8623
 
  jr z,mod1Single.4
8624
 
  ld (scrap),de
8625
 
  ld (scrap+2),bc
8626
 
  ld b,h
8627
 
  ld c,l
8628
 
  ld hl,scrap
8629
 
  ld de,const_1
8630
 
  jp addSingle
8631
 
mod1Single_special:
8632
 
;If INF, need to return NaN instead
8633
 
;For 0 and NaN, just return itself :)
8634
 
  pop af
8635
 
  pop hl
8636
 
  ld a,c
8637
 
  add a,a
8638
 
  jp p,mod1Single.4
8639
 
  ld c,$40
8640
 
mod1Single.4:
8641
 
  res 7,c
8642
 
  ld (hl),e
8643
 
  inc hl
8644
 
  ld (hl),d
8645
 
  inc hl
8646
 
  ld (hl),c
8647
 
  inc hl
8648
 
  ld (hl),b
8649
 
  ret
8650
 
 
8651
 
endif
8652
 
 
8653
 
if defined MATH_FOUT
8654
 
 
8655
 
; --------------------------------------------------------------
8656
 
; Converts a signed integer value to a zero-terminated ASCII
8657
 
; string representative of that value (using radix 10).
8658
 
; References:
8659
 
; Brandon Wilson WikiTI
8660
 
; http://wikiti.brandonw.net/index.php?title=Z80_Routines:Other:DispA#Decimal_Signed_Version
8661
 
; --------------------------------------------------------------
8662
 
; INPUTS:
8663
 
;     HL     Value to convert (two's complement integer).
8664
 
;     DE     Base address of string destination. (pointer).
8665
 
; --------------------------------------------------------------
8666
 
; OUTPUTS:
8667
 
;     A      Size of string
8668
 
; --------------------------------------------------------------
8669
 
; REGISTERS/MEMORY DESTROYED
8670
 
; AF HL
8671
 
; --------------------------------------------------------------
8672
 
 
8673
 
IntToStr:
8674
 
   push    de
8675
 
   push    bc
8676
 
 
8677
 
; Detect sign of HL.
8678
 
    bit    7, h
8679
 
    jr     z, _DoConvert
8680
 
 
8681
 
; HL is negative. Output '-' to string and negate HL.
8682
 
    ld     a, '-'
8683
 
    ld     (de), a
8684
 
    inc    de
8685
 
 
8686
 
; Negate HL (using two's complement)
8687
 
    xor    a
8688
 
    sub    l
8689
 
    ld     l, a
8690
 
    ld     a, 0     ; Note that XOR A or SUB A would disturb CF
8691
 
    sbc    a, h
8692
 
    ld     h, a
8693
 
 
8694
 
; Convert HL to digit characters
8695
 
_DoConvert:
8696
 
    ld     b, 0     ; B will count character length of number
8697
 
_DoConvert.1:
8698
 
    ld     c, 10
8699
 
    call div_hl_c; HL = HL / A, A = remainder
8700
 
    push   af
8701
 
    inc    b
8702
 
    ld     a, h
8703
 
    or     l
8704
 
    jr     nz, _DoConvert.1
8705
 
 
8706
 
; Retrieve digits from stack
8707
 
_DoConvert.2:
8708
 
    pop    af
8709
 
    or     $30
8710
 
    ld     (de), a
8711
 
    inc    de
8712
 
    djnz   _DoConvert.2
8713
 
 
8714
 
; Terminate string with NULL
8715
 
    xor    a
8716
 
    ld     (de), a
8717
 
 
8718
 
    ld h, d
8719
 
    ld l, e
8720
 
 
8721
 
    pop    bc
8722
 
    pop    de
8723
 
 
8724
 
    sbc hl, de
8725
 
    ld a, l           ; string size
8726
 
 
8727
 
    ret
8728
 
 
8729
 
endif
8730
 
 
8731
 
if defined MATH_FIN
8732
 
 
8733
 
;===============================================================
8734
 
; Convert a string of base-10 digits to a 16-bit value.
8735
 
; http://z80-heaven.wikidot.com/math#toc32
8736
 
;Input:
8737
 
;     DE points to the base 10 number string in RAM.
8738
 
;Outputs:
8739
 
;     HL is the 16-bit value of the number
8740
 
;     DE points to the byte after the number
8741
 
;     BC is HL/10
8742
 
;     z flag reset (nz)
8743
 
;     c flag reset (nc)
8744
 
;Destroys:
8745
 
;     A (actually, add 30h and you get the ending token)
8746
 
;Size:  23 bytes
8747
 
;Speed: 104n+42+11c
8748
 
;       n is the number of digits
8749
 
;       c is at most n-2
8750
 
;       at most 595 cycles for any 16-bit decimal value
8751
 
;===============================================================
8752
 
 
8753
 
StrToInt:
8754
 
     ld hl,0          ;  10 : 210000
8755
 
ConvLoop:             ;
8756
 
     ld a,(de)        ;   7 : 1A
8757
 
     sub 30h          ;   7 : D630
8758
 
     cp 10            ;   7 : FE0A
8759
 
     ret nc           ;5|11 : D0
8760
 
     inc de           ;   6 : 13
8761
 
                      ;
8762
 
     ld b,h           ;   4 : 44
8763
 
     ld c,l           ;   4 : 4D
8764
 
     add hl,hl        ;  11 : 29
8765
 
     add hl,hl        ;  11 : 29
8766
 
     add hl,bc        ;  11 : 09
8767
 
     add hl,hl        ;  11 : 29
8768
 
                      ;
8769
 
     add a,l          ;   4 : 85
8770
 
     ld l,a           ;   4 : 6F
8771
 
     jr nc,ConvLoop   ;12|23: 30EE
8772
 
     inc h            ; --- : 24
8773
 
     jr ConvLoop      ; --- : 18EB
8774
 
 
8775
 
endif
8776
 
 
8777
 
if defined IntToStr
8778
 
 
8779
 
; divides hl by c
8780
 
; return remainder in a
8781
 
; http://wikiti.brandonw.net/index.php?title=Z80_Routines:Math:Division
8782
 
div_hl_c:
8783
 
   push bc
8784
 
   xor  a
8785
 
   ld   b, 16
8786
 
div_hl_c.loop:
8787
 
   add  hl, hl
8788
 
   rla
8789
 
   jr   c, $+5
8790
 
   cp   c
8791
 
   jr   c, $+4
8792
 
   sub  c
8793
 
   inc  l
8794
 
   djnz div_hl_c.loop
8795
 
   pop bc
8796
 
   ret
8797
 
 
8798
 
endif
8799
 
 
8800
 
if defined DIV_EHL
8801
 
 
8802
 
; http://wikiti.brandonw.net/index.php?title=Z80_Routines:Math:Division#24.2F8_division
8803
 
div_ehl_d:
8804
 
   xor  a
8805
 
   ld   b, 24
8806
 
div_ehl_d.loop:
8807
 
   add  hl, hl
8808
 
   rl   e
8809
 
   rla
8810
 
   jr   c, $+5
8811
 
   cp   d
8812
 
   jr   c, $+4
8813
 
   sub  d
8814
 
   inc  l
8815
 
   djnz div_ehl_d.loop
8816
 
   ret
8817
 
 
8818
 
div_dehl_c:
8819
 
   push bc
8820
 
   xor  a
8821
 
   ld   b, 32
8822
 
div_dehl_c.loop:
8823
 
   add  hl, hl
8824
 
   rl   e
8825
 
   rl   d
8826
 
   rla
8827
 
   jr   c, $+5
8828
 
   cp   c
8829
 
   jr   c, $+4
8830
 
   sub  c
8831
 
   inc  l
8832
 
   djnz div_dehl_c.loop
8833
 
   pop bc
8834
 
   ret
8835
 
 
8836
 
endif
8837
 
 
8838
 
 
8839
 
 
8840
 
;---------------------------------------------------------------------------------------------------------
8841
 
; VARIABLES INITIALIZE
8842
 
;---------------------------------------------------------------------------------------------------------
8843
 
 
8844
 
INITIALIZE_DUMMY:
8845
 
    xor a
8846
 
    ld (VAR_DUMMY.COUNTER), a                    ; max circular queue = 8 dummys
8847
 
    ld hl, VAR_DUMMY.DATA                        ; start of variable dummy circular queue
8848
 
    ld (VAR_DUMMY.POINTER), hl
8849
 
    ld b, VAR_DUMMY.LENGTH
8850
 
    ld c, 0
8851
 
INITIALIZE_DUMMY.1:
8852
 
    ld (hl), a
8853
 
    inc hl
8854
 
    djnz INITIALIZE_DUMMY.1
8855
 
    ret
8856
 
 
8857
 
INITIALIZE_DATA:
8858
 
    ld hl, DATA_ITEMS
8859
 
    ld (BASIC_DATPTR), hl        ; next DATA pointer to use by READ command
8860
 
    ld hl, 0
8861
 
    ld (BASIC_DATLIN), hl        ; index of DATA item to use by READ command
8862
 
    ret
8863
 
 
8864
 
INITIALIZE_VARIABLES:
8865
 
    call INITIALIZE_DATA
8866
 
    call INITIALIZE_DUMMY
8867
 
 
8868
 
    if defined SCREEN
8869
 
       call gfxInitSpriteCollisionTable
8870
 
    endif
8871
 
 
8872
 
    ;if defined COMPILE_TO_ROM
8873
 
    ;   ld ix, BIOS_JIFFY            ; initialize rom clock
8874
 
    ;   di
8875
 
    ;     ld (ix), 0
8876
 
    ;     ld (ix+1), 0
8877
 
    ;   ei
8878
 
    ;endif
8879
 
 
8880
 
              ret
8881
 
 
8882
 
 
8883
 
;---------------------------------------------------------------------------------------------------------
8884
 
; MAIN WORK AREA - LITERALS / VARIABLES / CONFIGURATIONS
8885
 
;---------------------------------------------------------------------------------------------------------
8886
 
 
8887
 
if defined COMPILE_TO_ROM
8888
 
 
8889
 
   workAreaPad:
8890
 
   pgmPage1.pad: equ pageSize - (workAreaPad - pgmArea)
8891
 
 
8892
 
   if pgmPage1.pad >= 0
8893
 
      ds pgmPage1.pad, 0
8894
 
   ;else
8895
 
   ;   .WARNING "There's no free space left on program page 1"
8896
 
   endif
8897
 
 
8898
 
endif
8899
 
 
8900
 
VAR_STACK.START:     equ ramArea
8901
 
    ;VAR_STACK.END:       equ VAR_STACK.START + 0x800   ; 2kb (~200 variables)
8902
 
 
8903
 
VAR_STACK.POINTER:   equ VAR_STACK.START
8904
 
 
8905
 
PRINT.CRLF:      db 3, 0, 0, 2
8906
 
                 dw PRINT.CRLF.DATA, 0, 0, 0
8907
 
PRINT.CRLF.DATA: db 13,10,0
8908
 
 
8909
 
PRINT.TAB:       db 3, 0, 0, 1
8910
 
                 dw PRINT.TAB.DATA, 0, 0, 0
8911
 
PRINT.TAB.DATA:  db 09,0
8912
 
 
8913
 
; null double
8914
 
LIT_NULL_DBL: dw 0, 0, 0, 0
8915
 
 
8916
 
; null string
8917
 
LIT_NULL_STR: db 0
8918
 
 
8919
 
; quote string
8920
 
LIT_QUOTE_CHAR: db '\"'
8921
 
 
8922
 
; logical true
8923
 
LIT_TRUE: db 2, 0, 0
8924
 
          dw 0, 0xFFFF, 0, 0
8925
 
 
8926
 
; logical false
8927
 
LIT_FALSE: db 2, 0, 0
8928
 
           dw 0, 0, 0, 0
8929
 
 
8930
 
 
8931
 
; numerical literal
8932
 
LIT_4:   db 2, 0, 0
8933
 
      dw 0, 5, 0, 0
8934
 
 
8935
 
; numerical literal
8936
 
LIT_7:   db 2, 0, 0
8937
 
      dw 0, 28, 0, 0
8938
 
 
8939
 
; numerical literal
8940
 
LIT_8:   db 2, 0, 0
8941
 
      dw 0, 30, 0, 0
8942
 
 
8943
 
; numerical literal
8944
 
LIT_10:   db 2, 0, 0
8945
 
      dw 0, 6, 0, 0
8946
 
 
8947
 
; numerical literal
8948
 
LIT_11:   db 2, 0, 0
8949
 
      dw 0, 62, 0, 0
8950
 
 
8951
 
; numerical literal
8952
 
LIT_12:   db 2, 0, 0
8953
 
      dw 0, 60, 0, 0
8954
 
 
8955
 
; numerical literal
8956
 
LIT_13:   db 2, 0, 0
8957
 
      dw 0, 6, 0, 0
8958
 
 
8959
 
; numerical literal
8960
 
LIT_15:   db 2, 0, 0
8961
 
      dw 0, 30, 0, 0
8962
 
 
8963
 
; numerical literal
8964
 
LIT_16:   db 2, 0, 0
8965
 
      dw 0, 30, 0, 0
8966
 
 
8967
 
; numerical literal
8968
 
LIT_17:   db 2, 0, 0
8969
 
      dw 0, 60, 0, 0
8970
 
 
8971
 
; numerical literal
8972
 
LIT_18:   db 2, 0, 0
8973
 
      dw 0, 60, 0, 0
8974
 
 
8975
 
; numerical literal
8976
 
LIT_19:   db 2, 0, 0
8977
 
      dw 0, 6, 0, 0
8978
 
 
8979
 
; numerical literal
8980
 
LIT_20:   db 2, 0, 0
8981
 
      dw 0, 150, 0, 0
8982
 
 
8983
 
; numerical literal
8984
 
LIT_21:   db 2, 0, 0
8985
 
      dw 0, 60, 0, 0
8986
 
 
8987
 
; numerical literal
8988
 
LIT_22:   db 2, 0, 0
8989
 
      dw 0, 120, 0, 0
8990
 
 
8991
 
; numerical literal
8992
 
LIT_23:   db 2, 0, 0
8993
 
      dw 0, 30, 0, 0
8994
 
 
8995
 
; numerical literal
8996
 
LIT_24:   db 2, 0, 0
8997
 
      dw 0, 1, 0, 0
8998
 
 
8999
 
; numerical literal
9000
 
LIT_25:   db 2, 0, 0
9001
 
      dw 0, 160, 0, 0
9002
 
 
9003
 
; numerical literal
9004
 
LIT_26:   db 2, 0, 0
9005
 
      dw 0, 60, 0, 0
9006
 
 
9007
 
; numerical literal
9008
 
LIT_27:   db 2, 0, 0
9009
 
      dw 0, 190, 0, 0
9010
 
 
9011
 
; numerical literal
9012
 
LIT_28:   db 2, 0, 0
9013
 
      dw 0, 30, 0, 0
9014
 
 
9015
 
; numerical literal
9016
 
LIT_29:   db 2, 0, 0
9017
 
      dw 0, 1, 0, 0
9018
 
 
9019
 
; numerical literal
9020
 
LIT_31:   db 2, 0, 0
9021
 
      dw 0, 200, 0, 0
9022
 
 
9023
 
; numerical literal
9024
 
LIT_32:   db 2, 0, 0
9025
 
      dw 0, 30, 0, 0
9026
 
 
9027
 
; numerical literal
9028
 
LIT_33:   db 2, 0, 0
9029
 
      dw 0, 230, 0, 0
9030
 
 
9031
 
; numerical literal
9032
 
LIT_34:   db 2, 0, 0
9033
 
      dw 0, 60, 0, 0
9034
 
 
9035
 
; numerical literal
9036
 
LIT_35:   db 2, 0, 0
9037
 
      dw 0, 6, 0, 0
9038
 
 
9039
 
; numerical literal
9040
 
LIT_37:   db 2, 0, 0
9041
 
      dw 0, 65, 0, 0
9042
 
 
9043
 
; numerical literal
9044
 
LIT_38:   db 2, 0, 0
9045
 
      dw 0, 30, 0, 0
9046
 
 
9047
 
; numerical literal
9048
 
LIT_39:   db 2, 0, 0
9049
 
      dw 0, 95, 0, 0
9050
 
 
9051
 
; numerical literal
9052
 
LIT_40:   db 2, 0, 0
9053
 
      dw 0, 60, 0, 0
9054
 
 
9055
 
; numerical literal
9056
 
LIT_41:   db 2, 0, 0
9057
 
      dw 0, 6, 0, 0
9058
 
 
9059
 
; numerical literal
9060
 
LIT_42:   db 2, 0, 0
9061
 
      dw 0, 30, 0, 0
9062
 
 
9063
 
; numerical literal
9064
 
LIT_43:   db 2, 0, 0
9065
 
      dw 0, 45, 0, 0
9066
 
 
9067
 
; numerical literal
9068
 
LIT_44:   db 2, 0, 0
9069
 
      dw 0, 60, 0, 0
9070
 
 
9071
 
; numerical literal
9072
 
LIT_45:   db 2, 0, 0
9073
 
      dw 0, 45, 0, 0
9074
 
 
9075
 
; numerical literal
9076
 
LIT_46:   db 2, 0, 0
9077
 
      dw 0, 8, 0, 0
9078
 
 
9079
 
; numerical literal
9080
 
LIT_47:   db 2, 0, 0
9081
 
      dw 0, 45, 0, 0
9082
 
 
9083
 
; numerical literal
9084
 
LIT_48:   db 2, 0, 0
9085
 
      dw 0, 30, 0, 0
9086
 
 
9087
 
; numerical literal
9088
 
LIT_49:   db 2, 0, 0
9089
 
      dw 0, 45, 0, 0
9090
 
 
9091
 
; numerical literal
9092
 
LIT_50:   db 2, 0, 0
9093
 
      dw 0, 60, 0, 0
9094
 
 
9095
 
; numerical literal
9096
 
LIT_51:   db 2, 0, 0
9097
 
      dw 0, 8, 0, 0
9098
 
 
9099
 
; numerical literal
9100
 
LIT_53:   db 2, 0, 0
9101
 
      dw 0, 100, 0, 0
9102
 
 
9103
 
; numerical literal
9104
 
LIT_54:   db 2, 0, 0
9105
 
      dw 0, 100, 0, 0
9106
 
 
9107
 
; numerical literal
9108
 
LIT_55:   db 2, 0, 0
9109
 
      dw 0, 30, 0, 0
9110
 
 
9111
 
; numerical literal
9112
 
LIT_56:   db 2, 0, 0
9113
 
      dw 0, 9, 0, 0
9114
 
 
9115
 
; numerical literal
9116
 
LIT_58:   db 2, 0, 0
9117
 
      dw 0, 100, 0, 0
9118
 
 
9119
 
; numerical literal
9120
 
LIT_59:   db 2, 0, 0
9121
 
      dw 0, 100, 0, 0
9122
 
 
9123
 
; numerical literal
9124
 
LIT_60:   db 2, 0, 0
9125
 
      dw 0, 9, 0, 0
9126
 
 
9127
 
; numerical literal
9128
 
LIT_62:   db 2, 0, 0
9129
 
      dw 0, 9, 0, 0
9130
 
 
9131
 
; numerical literal
9132
 
LIT_64:   db 2, 0, 0
9133
 
      dw 0, 130, 0, 0
9134
 
 
9135
 
AFTER_LAST_VARIABLE:   equ VAR_STACK.POINTER + 0
9136
 
 
9137
 
VAR_DUMMY.START:       equ AFTER_LAST_VARIABLE    ; variable dummy circular queue area
9138
 
VAR_DUMMY.COUNTER:     equ VAR_DUMMY.START        ; variable dummy circular queue count
9139
 
VAR_DUMMY.POINTER:     equ VAR_DUMMY.COUNTER + 1  ; pointer to next variable dummy
9140
 
VAR_DUMMY.DATA:        equ VAR_DUMMY.POINTER + 2  ; first variable dummy
9141
 
 
9142
 
VAR_DUMMY.SIZE:        equ 8
9143
 
VAR_DUMMY.LENGTH:      equ (11 * VAR_DUMMY.SIZE)
9144
 
VAR_DUMMY.END:         equ VAR_DUMMY.DATA + VAR_DUMMY.LENGTH
9145
 
VAR_STACK.END:         equ VAR_DUMMY.END + 1
9146
 
 
9147
 
;--------------------------------------------------------
9148
 
; DATA SIMBOLS
9149
 
;--------------------------------------------------------
9150
 
 
9151
 
DATA_ITEMS:
9152
 
DATA_ITEMS_COUNT:   equ 0
9153
 
 
9154
 
DATA_SET_ITEMS_START:
9155
 
DATA_SET_ITEMS_COUNT:   equ 0
9156
 
 
9157
 
 
9158
 
;---------------------------------------------------------------------------------------------------------
9159
 
; PROGRAM FOOTER
9160
 
;---------------------------------------------------------------------------------------------------------
9161
 
 
9162
 
    if defined COMPILE_TO_ROM
9163
 
 
9164
 
        romPad:
9165
 
 
9166
 
        pgmPage2.pad: equ romSize - (romPad - pgmArea)
9167
 
 
9168
 
        if pgmPage2.pad >= 0
9169
 
           ds pgmPage2.pad, 0
9170
 
 
9171
 
           if pgmPage2.pad < lowLimitSize
9172
 
                .WARNING "There's only less than 5% free space on this ROM"
9173
 
           endif
9174
 
        else
9175
 
           .ERROR "There's no free space left on this ROM"
9176
 
        endif
9177
 
 
9178
 
    endif
9179
 
 
9180
 
    end_file: end start_pgm           ; label start is the entry point
9181