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
;---------------------------------------------------------------------------------------------------------
7
;--------------------------------------------------------
8
; MSX BIOS DATA/FUNCTION POINTERS
9
;--------------------------------------------------------
11
;---------------------------------------------------------------------------------------------------------
13
;---------------------------------------------------------------------------------------------------------
15
BIOS_CALBAS: equ 0x0159
16
BIOS_OUTDO: equ 0x0018 ; output to current device (i.e. screen)
17
BIOS_CHPUT: equ 0x00A2
19
BIOS_POSIT: equ 0x00C6
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
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)
77
BIOS_CHPUT_LF: equ 0x0908
78
BIOS_CHPUT_CR: equ 0x0A81
79
BIOS_CHPUT_TAB: equ 0x0A71
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
97
;---------------------------------------------------------------------------------------------------------
99
;---------------------------------------------------------------------------------------------------------
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
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
138
BIOS_DRWFLG: equ 0xFCBB
139
BIOS_MCLFLG: equ 0xF958
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)
149
;--------------------------------------------------------
150
; MSX BASIC DATA/FUNCTION POINTERS
151
;--------------------------------------------------------
153
;---------------------------------------------------------------------------------------------------------
154
; MSX BASIC FUNCTIONS
155
;---------------------------------------------------------------------------------------------------------
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
198
BASIC_GOTO: equ 0x393E
199
BASIC_GOSUB: equ 0x3948
200
BASIC_GET: equ 0x3990
201
BASIC_INPUT: equ 0x3936
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
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
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
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
328
BASIC_PLAY_DIRECT: equ 0x744C
329
BASIC_DRAW_DIRECT: equ 0x568C
331
BASIC_READYR: equ 0x409B
332
BASIC_READYC: equ 0x7D17
333
BASIC_FACEVAL: equ 0x4DC7
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
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
362
;---------------------------------------------------------------------------------------------------------
363
; MSX BASIC WORK AREAS
364
;---------------------------------------------------------------------------------------------------------
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
382
BASIC_TEMPPT: equ 0xF678 ; 2 Starting address of unused area of temporary descriptor.
383
BASIC_TEMPST: equ 0xF67A ; 30 Temporary descriptors.
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).
390
BASIC_CURLIN: equ 0xF41C ; BASIC current line number
391
BASIC_INTVAL: equ 0xFCA0 ; interval value
392
BASIC_INTCNT: equ 0xFCA2 ; interval current count
394
BASIC_PRMPRV: equ 0xF74C ; Pointer to previous parameter block in PARM1
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]
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
405
BASIC_ONGSBF: equ 0xFBD8 ; 1 trap occurred counter (0=not occurred)
409
;--------------------------------------------------------
411
;--------------------------------------------------------
413
;--------------------------------------------------------
415
;--------------------------------------------------------
416
COMPILE_TO_ROM: EQU 1
418
MACRO __call_basic,CALL_PARM
423
if defined COMPILE_TO_DOS
425
MACRO __call_bios,CALL_PARM
426
;ld iy,(BIOS_EXPTBL-1)
428
call BIOS_CALBAS ; BIOS_CALSLT
433
MACRO __call_bios,CALL_PARM
440
push hl ; save parameter
444
pop iy ; restore PC of caller
445
pop hl ; get next parameter
446
push iy ; save PC of caller
450
pop iy ; restore PC of caller
451
push hl ; save return parameter
452
push iy ; save PC of caller
456
pop iy ; restore PC of caller
457
push hl ; save return parameter
458
push iy ; save PC of caller
462
MACRO set.line.number, line_number
463
ld bc, line_number ; current line number
464
ld (BASIC_CURLIN), bc
468
ld a, (BIOS_INTFLG) ; verify CTRL+BREAK
474
ld a, (BASIC_ONGSBF) ; trap occured counter
480
;---------------------------------------------------------------------------------------------------------
482
;---------------------------------------------------------------------------------------------------------
484
romSize: equ 0x8000 ; ROM size (32k)
485
pageSize: equ 0x4000 ; Page size (16k)
486
lowLimitSize: equ 0x400 ; 10% of a page size
488
if defined COMPILE_TO_BIN
490
pgmArea: equ 0x8000 ; page 2 - program area
491
ramArea: equ 0xc000 ; page 3 - free RAM start area
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)
500
if defined COMPILE_TO_ROM
502
pgmArea: equ 0x4000 ; page 1 and 2 - program area
503
ramArea: equ 0xc000 ; page 3 - free RAM start area
505
org pgmArea ; program rom type start address
506
db 'AB' ; rom file ID
508
dw 0x0000 ; STATEMENT
515
pgmArea: equ 0x8000 ; page 2 - program area
516
ramArea: equ 0xc000 ; page 3 - free RAM start area
518
org pgmArea ; program DOS type start address ; 0x0100
524
;---------------------------------------------------------------------------------------------------------
526
;---------------------------------------------------------------------------------------------------------
528
if defined COMPILE_TO_ROM
531
call PROGRAM_SLOT_2_RESTORE
532
__call_basic BASIC_READYR ; warm start Basic
537
call PROGRAM_SLOT_GET
538
ld (BIOS_RAMAD2), a ; Save RAM slot of page 8000h-BFFFh
541
PROGRAM_SLOT_2_RESTORE:
544
jp BIOS_ENASLT ; Select the RAM on page 8000h-BFFFh
546
PROGRAM_SLOT_2_ENABLE:
548
call PROGRAM_SLOT_ENABLE_SUB
550
jp BIOS_ENASLT ; Select the ROM on page 8000h-BFFFh
552
PROGRAM_SLOT_1_ENABLE:
556
call PROGRAM_SLOT_ENABLE_SUB
558
jp BIOS_ENASLT ; Select the ROM on page 4000h-7FFFh
560
PROGRAM_SLOT_ENABLE_SUB:
563
and 3 ;Keep bits corresponding to the 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
588
jr z,PrimaryShiftContinue
593
PrimaryShiftContinue:
595
jr z,PrimaryShiftDone
610
inc hl ; move to SLTTBL
617
jr z,SecondaryShiftContinue
622
SecondaryShiftContinue:
624
jr nz,SecondaryShiftDone
634
if defined COMPILE_TO_DOS
639
__call_bios BIOS_ENASLT ; Select main ROM on page 0 (0000h~3FFFh)
645
__call_bios BIOS_ENASLT ; Select main ROM on page 1 (4000h~7FFFh)
652
;---------------------------------------------------------------------------------------------------------
654
;---------------------------------------------------------------------------------------------------------
656
start_pgm: ; start of the program
658
if defined COMPILE_TO_DOS
660
call BIOS_SLOT_ENABLE ; enable bios on page 0
661
call BASIC_SLOT_ENABLE ; enable basic on page 1
664
if defined COMPILE_TO_ROM
666
call PROGRAM_SLOT_2_SAVE ; save slot on page 2
667
call PROGRAM_SLOT_2_ENABLE ; enable program on page 2
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
676
ld (BIOS_CLIKSW), a ; disable keyboard click
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
686
set.line.number 10 ; current line number
687
ld hl, LIT_4 ; parameter
689
call SCREEN ; action call
692
set.line.number 20 ; current line number
693
ld hl, LIT_6 ; parameter
695
ld hl, IDF_5 ; parameter
697
call LET ; action call
700
set.line.number 30 ; current line number
701
ld hl, LIT_8 ; parameter
703
ld hl, IDF_7 ; parameter
705
call LET ; action call
708
set.line.number 40 ; current line number
709
ld hl, LIT_10 ; parameter
711
ld hl, IDF_9 ; parameter
713
call LET ; action call
716
set.line.number 50 ; current line number
717
ld hl, LIT_12 ; parameter
719
ld hl, IDF_11 ; parameter
721
call LET ; action call
724
set.line.number 70 ; current line number
725
ld hl, IDF_9 ; parameter
727
ld hl, IDF_5 ; parameter
729
call MATH.SUB ; action call
730
call ABS ; action call
731
ld hl, IDF_13 ; parameter
733
call LET ; action call
734
IF_1 : ; start of IF command
735
ld hl, IDF_5 ; parameter
737
ld hl, IDF_9 ; parameter
739
call BOOLEAN.LT ; action call
740
call BOOLEAN.IF ; verify IF condition result, out in A
742
jp z, ELSE_1 ; if false, jump to ELSE actions
743
THEN_1 : ; THEN actions
744
ld hl, LIT_21 ; parameter
746
ld hl, IDF_20 ; parameter
748
call LET ; action call
749
jp ENDIF_1 ; jump to END of IF command
750
ELSE_1 : ; ELSE actions
751
ld hl, LIT_23 ; parameter
753
call MATH.NEG ; action call
754
ld hl, IDF_20 ; parameter
756
call LET ; action call
757
ENDIF_1 : ; end of IF command
760
set.line.number 80 ; current line number
761
ld hl, IDF_11 ; parameter
763
ld hl, IDF_7 ; parameter
765
call MATH.SUB ; action call
766
call ABS ; action call
767
ld hl, IDF_25 ; parameter
769
call LET ; action call
770
IF_2 : ; start of IF command
771
ld hl, IDF_7 ; parameter
773
ld hl, IDF_11 ; parameter
775
call BOOLEAN.LT ; action call
776
call BOOLEAN.IF ; verify IF condition result, out in A
778
jp z, ELSE_2 ; if false, jump to ELSE actions
779
THEN_2 : ; THEN actions
780
ld hl, LIT_27 ; parameter
782
ld hl, IDF_26 ; parameter
784
call LET ; action call
785
jp ENDIF_2 ; jump to END of IF command
786
ELSE_2 : ; ELSE actions
787
ld hl, LIT_28 ; parameter
789
call MATH.NEG ; action call
790
ld hl, IDF_26 ; parameter
792
call LET ; action call
793
ENDIF_2 : ; end of IF command
796
set.line.number 85 ; current line number
797
IF_3 : ; start of IF command
798
ld hl, IDF_13 ; parameter
800
ld hl, IDF_25 ; parameter
802
call BOOLEAN.GT ; action call
803
call BOOLEAN.IF ; verify IF condition result, out in A
805
jp z, ELSE_3 ; if false, jump to ELSE actions
806
THEN_3 : ; THEN actions
807
ld hl, IDF_13 ; parameter
809
ld hl, LIT_31 ; parameter
811
call MATH.IDIV ; action call
812
ld hl, IDF_30 ; parameter
814
call LET ; action call
815
jp ENDIF_3 ; jump to END of IF command
816
ELSE_3 : ; ELSE actions
817
ld hl, IDF_25 ; parameter
819
call MATH.NEG ; action call
820
ld hl, LIT_33 ; parameter
822
call MATH.IDIV ; action call
823
ld hl, IDF_30 ; parameter
825
call LET ; action call
826
ENDIF_3 : ; end of IF command
829
set.line.number 90 ; current line number
830
ld hl, IDF_7 ; parameter
832
ld hl, IDF_5 ; parameter
834
call PSET.XY ; action call
835
call PSET ; action call
838
set.line.number 100 ; current line number
839
IF_4 : ; start of IF command
840
ld hl, IDF_5 ; parameter
842
ld hl, IDF_9 ; parameter
844
call BOOLEAN.EQ ; action call
845
ld hl, IDF_7 ; parameter
847
ld hl, IDF_11 ; parameter
849
call BOOLEAN.EQ ; action call
850
call BOOLEAN.AND ; action call
851
call BOOLEAN.IF ; verify IF condition result, out in A
853
jp z, ELSE_4 ; if false, jump to ELSE actions
854
THEN_4 : ; THEN actions
856
jp ENDIF_4 ; jump to END of IF command
857
ELSE_4 : ; ELSE actions
858
ENDIF_4 : ; end of IF command
861
set.line.number 110 ; current line number
862
ld hl, IDF_30 ; parameter
864
ld hl, IDF_40 ; parameter
866
call LET ; action call
869
set.line.number 120 ; current line number
870
IF_5 : ; start of IF command
871
ld hl, IDF_40 ; parameter
873
ld hl, IDF_13 ; parameter
875
call MATH.NEG ; action call
876
call BOOLEAN.GT ; action call
877
call BOOLEAN.IF ; verify IF condition result, out in A
879
jp z, ELSE_5 ; if false, jump to ELSE actions
880
THEN_5 : ; THEN actions
881
ld hl, IDF_30 ; parameter
883
ld hl, IDF_25 ; parameter
885
call MATH.SUB ; action call
886
ld hl, IDF_30 ; parameter
888
call LET ; action call
889
jp ENDIF_5 ; jump to END of IF command
890
ELSE_5 : ; ELSE actions
891
ENDIF_5 : ; end of IF command
894
set.line.number 130 ; current line number
895
IF_6 : ; start of IF command
896
ld hl, IDF_40 ; parameter
898
ld hl, IDF_13 ; parameter
900
call MATH.NEG ; action call
901
call BOOLEAN.GT ; action call
902
call BOOLEAN.IF ; verify IF condition result, out in A
904
jp z, ELSE_6 ; if false, jump to ELSE actions
905
THEN_6 : ; THEN actions
906
ld hl, IDF_5 ; parameter
908
ld hl, IDF_20 ; parameter
910
call MATH.ADD ; action call
911
ld hl, IDF_5 ; parameter
913
call LET ; action call
914
jp ENDIF_6 ; jump to END of IF command
915
ELSE_6 : ; ELSE actions
916
ENDIF_6 : ; end of IF command
919
set.line.number 140 ; current line number
920
IF_7 : ; start of IF command
921
ld hl, IDF_40 ; parameter
923
ld hl, IDF_25 ; parameter
925
call BOOLEAN.LT ; action call
926
call BOOLEAN.IF ; verify IF condition result, out in A
928
jp z, ELSE_7 ; if false, jump to ELSE actions
929
THEN_7 : ; THEN actions
930
ld hl, IDF_30 ; parameter
932
ld hl, IDF_13 ; parameter
934
call MATH.ADD ; action call
935
ld hl, IDF_30 ; parameter
937
call LET ; action call
938
jp ENDIF_7 ; jump to END of IF command
939
ELSE_7 : ; ELSE actions
940
ENDIF_7 : ; end of IF command
943
set.line.number 150 ; current line number
944
IF_8 : ; start of IF command
945
ld hl, IDF_40 ; parameter
947
ld hl, IDF_25 ; parameter
949
call BOOLEAN.LT ; action call
950
call BOOLEAN.IF ; verify IF condition result, out in A
952
jp z, ELSE_8 ; if false, jump to ELSE actions
953
THEN_8 : ; THEN actions
954
ld hl, IDF_7 ; parameter
956
ld hl, IDF_26 ; parameter
958
call MATH.ADD ; action call
959
ld hl, IDF_7 ; parameter
961
call LET ; action call
962
jp ENDIF_8 ; jump to END of IF command
963
ELSE_8 : ; ELSE actions
964
ENDIF_8 : ; end of IF command
967
set.line.number 160 ; current line number
970
;---------------------------------------------------------------------------------------------------------
972
;---------------------------------------------------------------------------------------------------------
974
end_pgm: __call_bios BIOS_DSPFNK ; turn on function keys display
976
ld (BIOS_CLIKSW), a ; enable keyboard click
978
if defined COMPILE_TO_ROM
981
__call_basic BASIC_READYR ; warm start Basic
984
ret ; end of the program
986
;__call_bios BIOS_GICINI ; initialize sound system
987
;if defined COMPILE_TO_DOS or defined COMPILE_TO_ROM
988
; __call_bios BIOS_RESET ; restart Basic
990
; __call_basic BASIC_END ; end to Basic
994
;---------------------------------------------------------------------------------------------------------
996
;---------------------------------------------------------------------------------------------------------
1001
; out IX = variable assigned address
1002
pop.parm ; get variable address parameter
1003
push hl ; just to transfer hl to ix
1005
ld a, (ix) ; get variable type
1006
cp 3 ; test if string
1007
jr nz, LET.PARM ; if not a string, it isn't necessary to free memory
1008
ld a, (ix + 3) ; get variable string length
1010
jr z, LET.PARM ; if zero, it isn't necessary to free memory
1011
ld c, (ix + 4) ; get old string address low
1012
ld b, (ix + 5) ; get old string address high
1013
push ix ; save variable address
1014
push bc ; just to transfer bc (old string address) to ix
1016
call memory.free ; free memory
1017
pop ix ; restore variable address
1018
LET.PARM: pop.parm ; get data address parameter (out hl = data address)
1019
ld a, (ix + 2) ; get variable type flag
1020
or a ; cp 0 - test type flag (0=any, 255=fixed)
1021
jr nz, LET.FIXED ; if type flag is fixed, so casting is necessary
1022
LET.ANY: push ix ; just to transfer ix (variable address) to de
1024
ldi ; copy 1 byte from hl (data address) to de (variable address)
1025
inc de ; go to variable data area
1027
inc hl ; go to data data area
1029
ld bc, 8 ; data = 8 bytes
1030
ldir ; copy bc bytes from hl (data address) to de (variable address)
1031
ld a, (ix) ; get variable type
1032
cp 3 ; test if string
1033
ret nz ; if not string, return
1034
jp LET.STRING ; else do string treatment (in ix = variable address)
1035
LET.FIXED: push ix ; save variable destination address
1036
push hl ; save variable source address
1037
ld a, (ix) ; get variable fixed type, and hl has parameter data address
1038
call CAST_TO ; cast data to type (in hl = variable address, a = type to, out hl = casted data address)
1040
pop ix ; restore variable address
1041
ld a, (ix) ; get variable destination type again
1042
cp 3 ; test if string
1043
jr nz, LET.VALUE ; if not string, do value treatment
1044
ld a, (de) ; get variable source type again
1045
cp 3 ; test if string
1046
jr nz, LET.FIX1 ; if not string, get casted string size
1051
ld (ix + 3), a ; source string size
1054
call GET_STR.LENGTH ; get string length (in HL, out B)
1056
ld (ix + 3), b ; set variable length
1057
LET.FIX2: ld (ix + 4), l ; casted data address low
1058
ld (ix + 5), h ; casted data address high
1059
jp LET.STRING ; do string treatment (in ix = variable address)
1060
LET.VALUE: push ix ; just to transfer ix (variable address) to de
1062
inc de ; go to variable data area (and the data from its casted)
1065
ld bc, 8 ; data = 8 bytes
1066
ldir ; copy bc bytes from hl (data address) to de (variable address)
1068
LET.STRING: ld a, (ix + 3) ; string size
1069
or a ; cp 0 - test if null
1070
jr nz, LET.ALLOC ; if not null, allocate new string (in ix = variable address)
1071
ld bc, LIT_NULL_STR ; else, set to a null string literal
1072
ld (ix + 4), c ; variable address low
1073
ld (ix + 5), b ; variable address high
1075
LET.ALLOC: push ix ; save variable address
1076
ld l, (ix + 4) ; source string address low
1077
ld h, (ix + 5) ; source string address high
1078
push hl ; save copy from address
1079
ld c, (ix + 3) ; get variable length
1081
inc bc ; string length have one more byte from zero terminator
1082
push bc ; save variable lenght + 1
1083
call memory.alloc ; in bc = size, out ix = address, nz=OK
1085
push ix ; just to transfer memory address from ix to de
1087
pop bc ; restore bytes to be copied
1088
pop hl ; restore copy from string address
1089
push de ; save copy to address
1090
ldir ; copy bc bytes from hl (data address) to de (variable address)
1093
pop de ; restore copy to address
1094
pop ix ; restore variable address
1095
ld (ix + 4), e ; put memory address low into variable
1096
ld (ix + 5), d ; put memory address high into variable
1097
ret ; variable assigned
1102
pop.parm ; get parameter boolean result in hl
1105
ld a, (ix+5) ; put boolean integer result in a
1111
pop.parm ; get first parameter
1113
call GET_INT.VALUE ; output BC with integer value
1114
ld a, c ; A = screen number (0 to 3)
1116
jr c, SCREEN.1 ; if mode < 9, jump
1117
ld a, 8 ; else, fix to 8
1119
if defined EXIST_DATA_SET
1120
call gfxSetScreenMode
1124
jp gfxClearTileScreen
1131
; abstract virtual ABS
1135
call MATH.PARM.POP ; get parameters into DAC/ARG
1136
ld a, (BASIC_VALTYP) ;
1137
cp 2 ; test if integer
1138
jp z, MATH.SUB.INT ;
1139
cp 3 ; test if string
1141
cp 4 ; test if single
1142
jp z, MATH.SUB.SGL ;
1143
jp MATH.SUB.DBL ; it is a double
1148
call MATH.PARM.POP ; get parameters into DAC/ARG
1149
ld a, (BASIC_VALTYP) ;
1150
cp 2 ; test if integer
1151
jp z, BOOLEAN.LT.INT ;
1152
cp 3 ; test if string
1153
jp z, BOOLEAN.LT.STR ;
1154
cp 4 ; test if single
1155
jp z, BOOLEAN.LT.SGL ;
1156
jp BOOLEAN.LT.DBL ; it is a double
1161
call CLEAR.DAC ; put zero in DAC
1162
pop.parm ; get parameter
1163
call COPY_TO.ARG ; put in ARG
1164
cp 2 ; test if integer
1165
jp z, MATH.SUB.INT ;
1166
cp 4 ; test if single
1167
jp z, MATH.SUB.SGL ;
1168
cp 8 ; test if double
1169
jp z, MATH.SUB.DBL ;
1175
call MATH.PARM.POP ; get parameters into DAC/ARG
1176
ld a, (BASIC_VALTYP) ;
1177
cp 2 ; test if integer
1178
jp z, BOOLEAN.GT.INT ;
1179
cp 3 ; test if string
1180
jp z, BOOLEAN.GT.STR ;
1181
cp 4 ; test if single
1182
jp z, BOOLEAN.GT.SGL ;
1183
jp BOOLEAN.GT.DBL ; it is a double
1188
call MATH.PARM.POP ; get parameters into DAC/ARG
1189
ld a, (BASIC_VALTYP) ;
1190
cp 2 ; test if integer
1191
jp z, MATH.IDIV.INT ;
1192
cp 3 ; test if string
1194
cp 4 ; test if single
1195
jp z, MATH.IDIV.SGL ;
1196
jp MATH.IDIV.DBL ; it is a double
1206
pop.parm ; get first parameter
1208
call GET_INT.VALUE ; output BC with integer value
1209
ld (BIOS_GRPACX), bc ; X
1210
pop.parm ; get second parameter
1212
call GET_INT.VALUE ; output BC with integer value
1213
ld (BIOS_GRPACY), bc ; Y
1219
call MATH.PARM.POP ; get parameters into DAC/ARG
1220
ld a, (BASIC_VALTYP) ;
1221
cp 2 ; test if integer
1222
jp z, BOOLEAN.EQ.INT ;
1223
cp 3 ; test if string
1224
jp z, BOOLEAN.EQ.STR ;
1225
cp 4 ; test if single
1226
jp z, BOOLEAN.EQ.SGL ;
1227
jp BOOLEAN.EQ.DBL ; it is a double
1232
call MATH.PARM.POP ; get parameters into DAC/ARG
1233
ld a, (BASIC_VALTYP) ;
1234
cp 2 ; test if integer
1235
jp z, BOOLEAN.AND.INT ;
1236
jp MATH.ERROR ; it is a double
1240
; abstract virtual GOTO
1244
call MATH.PARM.POP ; get parameters into DAC/ARG
1245
ld a, (BASIC_VALTYP) ;
1246
cp 2 ; test if integer
1247
jp z, MATH.ADD.INT ;
1248
cp 3 ; test if string
1249
jp z, STRING.CONCAT ;
1250
cp 4 ; test if single
1251
jp z, MATH.ADD.SGL ;
1252
jp MATH.ADD.DBL ; it is a double
1256
;---------------------------------------------------------------------------------------------------------
1257
; MSX BASIC SUPPORT CODE
1258
;---------------------------------------------------------------------------------------------------------
1260
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
1264
RUN_TRAPS.1: push hl
1275
; in hl = trap block address (handle trap: sts=5? has handler? ackn, pause, run trap, sts=1? unpause)
1277
ld a, (hl) ; trap status
1278
cp 5 ; trap occured AND trap not paused AND trap enabled ?
1279
ret nz ; return if false
1281
ld e, (hl) ; get trap address
1288
ret z ; return if address zero
1290
__call_basic BASIC_TRAP_ACKNW
1291
__call_basic BASIC_TRAP_PAUSE
1292
ld hl, TRAP_HANDLER.1
1293
ld a, (BASIC_ONGSBF) ; save traps execution
1296
ld (BASIC_ONGSBF), a ; disable traps execution
1297
push hl ; next return will be to trap handler
1298
push de ; indirect jump to trap address
1300
TRAP_HANDLER.1: pop af
1301
ld (BASIC_ONGSBF), a ; restore traps execution
1304
cp 1 ; trap enabled?
1306
__call_basic BASIC_TRAP_UNPAUSE
1309
; hl = trap block, de = trap handler
1311
ld (hl), a ; trap block status
1313
ld (hl), e ; trap block handler (pointer)
1320
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
1323
ld (BIOS_TEMP), a ; save voice number
1327
ret nz ; return if not string
1330
ld (BIOS_TEMP2), a ; save string size
1331
push hl ; string address
1332
ld a, (BIOS_TEMP) ; restore voice number
1333
call BIOS_GETVCP ; get PSG voice buffer address (in A = voice number, out HL = address of byte 2)
1335
ld a, (BIOS_TEMP2) ; restore string size
1336
ld (hl), a ; string size
1338
ld (hl), e ; string address
1342
ld D,H ; voice stack
1357
ld hl, BIOS_TEMP ; voice count
1371
__call_basic BASIC_PLAY_DIRECT
1378
;---------------------------------------------------------------------------------------------------------
1379
; VARIABLES ROUTINES
1380
;---------------------------------------------------------------------------------------------------------
1382
; input hl = variable address
1383
; input bc = variable name
1384
; input d = variable type
1385
INIT_VAR: ld (hl), d ; variable type
1387
ld (hl), c ; variable name 1
1389
ld (hl), b ; variable name 2
1403
CLEAR.VAR.LOOP: inc hl
1404
ld (hl), 0 ; data address/value
1407
; input HL = variable address
1408
; input A = variable output type
1409
; output HL = casted data address
1419
; input HL = variable address
1420
; output HL = variable address
1421
CAST_TO.INT: ;push af
1426
jp z, CAST_STR_TO.INT
1428
jp z, CAST_SGL_TO.INT
1430
jp z, CAST_DBL_TO.INT
1433
; input HL = variable address
1434
; output HL = variable address
1435
CAST_TO.STR: ;push af
1438
jp z, CAST_INT_TO.STR
1442
jp z, CAST_SGL_TO.STR
1444
jp z, CAST_DBL_TO.STR
1447
; input HL = variable address
1448
; output HL = variable address
1449
CAST_TO.SGL: ;push af
1452
jp z, CAST_INT_TO.SGL
1454
jp z, CAST_STR_TO.SGL
1458
jp z, CAST_DBL_TO.SGL
1461
; input HL = variable address
1462
; output HL = variable address
1463
CAST_TO.DBL: ;push af
1466
jp z, CAST_INT_TO.DBL
1468
jp z, CAST_STR_TO.DBL
1470
jp z, CAST_SGL_TO.DBL
1475
CAST_SGL_TO.STR: ; same as CAST_INT_TO.STR
1476
CAST_DBL_TO.STR: ; same as CAST_INT_TO.STR
1477
CAST_INT_TO.STR: call COPY_TO.DAC
1479
__call_bios MATH_FOUT ; convert DAC to string
1482
CAST_INT_TO.SGL: call COPY_TO.DAC
1483
__call_bios MATH_FRCSGL
1486
CAST_INT_TO.DBL: call COPY_TO.DAC
1487
__call_bios MATH_FRCDBL
1490
CAST_SGL_TO.INT: ; same as CAST_DBL_TO.INT
1491
CAST_DBL_TO.INT: call COPY_TO.DAC
1492
__call_bios MATH_FRCINT
1495
CAST_STR_TO.INT: call CAST_STR_TO.VAL ;
1496
__call_bios MATH_FRCINT ;
1499
CAST_STR_TO.SGL: call CAST_STR_TO.VAL ;
1500
__call_bios MATH_FRCSGL ;
1503
CAST_STR_TO.DBL: call CAST_STR_TO.VAL ;
1504
__call_bios MATH_FRCDBL ;
1507
CAST_STR_TO.VAL: call GET_STR.ADDR ;
1509
__call_bios MATH_FIN ; convert string to a value type
1512
GET_INT.VALUE: inc hl ; output BC with integer value
1518
CAST_SGL_TO.DBL: ; same as GET_DBL.ADDR
1519
CAST_DBL_TO.SGL: ; same as GET_DBL.ADDR
1520
GET_INT.ADDR: ; same as GET_DBL.ADDR
1521
GET_SGL.ADDR: ; same as GET_DBL.ADDR
1522
GET_DBL.ADDR: inc hl
1527
GET_STR.ADDR: push hl
1533
; input hl = string address
1534
; output b = string length
1535
GET_STR.LENGTH: ld b, 0
1536
GET_STR.LEN.NEXT: ld a, (hl)
1543
jr z, GET_STR.LEN.ERR
1545
GET_STR.LEN.ERR: ld b, 0
1547
STRING.COMPARE: ld ix, (BASIC_DAC+1) ; string 1
1548
ld iy, (BASIC_ARG+1) ; string 2
1549
STRING.COMPARE.NX: ld a, (ix) ; next char from string 1
1550
cp (iy) ; char s1 = char s2?
1551
jr nz, STRING.COMPARE.NE ; if not equal...
1553
jr z, STRING.COMPARE.F1 ; if string 1 has finished...
1554
ld a, (iy) ; next char from string 2
1556
jr z, STRING.COMPARE.GT ; if s2 has finished, s1 has not finished yet, so s1 is greater than s2
1559
jr STRING.COMPARE.NX ; get next char pair
1560
STRING.COMPARE.F1: ld a, (iy) ; verify if string 2 has finished too
1562
jr z, STRING.COMPARE.EQ ; if s2 has finished, then they are equals
1563
jr STRING.COMPARE.LT ; else, result = s1 is less than s2
1564
STRING.COMPARE.NE: jr c, STRING.COMPARE.GT ; verify if s1 is greater than s2...
1565
STRING.COMPARE.LT: ld a, 1 ; ...else, result = s1 less than s2
1567
STRING.COMPARE.GT: ld a, 0xFF ; result = s1 is greater than s2
1569
STRING.COMPARE.EQ: xor a ; result = s1 is equal to s2
1571
STRING.CONCAT: ld ix, BASIC_DAC ; s1 size
1572
ld a, (BASIC_ARG) ; s2 size
1573
add a, (ix) ; s3 size = s1 size + s2 size
1577
inc bc ; add 1 byte to size
1578
call memory.alloc ; in bc size, out ix new memory address, nz=OK
1579
jp z, memory.error ;
1583
ld a, (BASIC_DAC) ; s1 size
1584
ld hl, (BASIC_DAC + 1) ; string 1
1585
call COPY_TO.STR ; copy to new memory
1586
ld a, (BASIC_ARG) ; s2 size
1587
ld hl, (BASIC_ARG + 1) ; string 2
1588
call COPY_TO.STR ; copy to new memory
1590
ld (de), a ; null terminated
1593
call COPY_TO.VAR_DUMMY.STR ;
1594
ret.parm ; WARNING - VERIFY STRING MEMORY LEAKs
1595
STRING.PRINT: ld a, (BIOS_SCRMOD) ; 0=40x24 Text Mode, 1=32x24 Text Mode, 2=Graphics Mode, 3=Multicolour Mode
1597
jr nc, STRING.PRINT.G2 ; jump if graphic screen mode MSX2 (>=5)
1599
jr nc, STRING.PRINT.G1 ; jump if graphic screen mode MSX1 (>=2)
1600
STRING.PRINT.T: ld a, (hl) ; get a char from a string parameter
1601
or a ; cp 0 - is it the string end?
1603
__call_bios BIOS_CHPUT ; put the char (a) into text screen
1605
jr STRING.PRINT.T ; repeat
1606
STRING.PRINT.G1: ld a, (hl) ; get a char from a string parameter
1607
or a ; cp 0 - is it the string end?
1609
__call_bios BIOS_GRPPRT ; put the char (a) into graphical screen
1611
jr STRING.PRINT.G1 ; repeat
1612
STRING.PRINT.G2: ld a, (hl) ; get a char from a string parameter
1613
or a ; cp 0 - is it the string end?
1615
ld ix, BIOS_GRPPRT2 ; put the char (a) into graphical screen
1618
jr STRING.PRINT.G2 ; repeat
1620
; a = string size to copy
1621
; input hl = string from
1622
; input de = string to
1624
ret z ; avoid copy if size = zero
1626
ld c, a ; string size
1627
ldir ; copy bc bytes from hl to de
1629
COPY_TO.BASIC_BUF: ld bc, BASIC_BUF
1630
ld a, (LIT_QUOTE_CHAR)
1633
COPY_BAS_BUF.LOOP: ld a, (hl)
1635
jr z, COPY_BAS_BUF.EXIT
1639
jr COPY_BAS_BUF.LOOP
1640
COPY_BAS_BUF.EXIT: ld a, (LIT_QUOTE_CHAR)
1647
COPY_TO.VAR_DUMMY: ld a, (BASIC_VALTYP) ; create dummy variable from VALTYPE
1649
jr nz, COPY_TO.VAR_DUMMY.DBL
1651
call GET_STR.LENGTH ; get string length
1653
ld a, b ; string length
1654
COPY_TO.VAR_DUMMY.STR: call GET_VAR_DUMMY.ADDR ; create dummy string variable from HL
1655
ld (ix), 3 ; data type string
1657
ld (ix+2), 255 ; var type fixed
1658
ld (ix+3), a ; string length
1659
ld (ix+4), l ; data address low
1660
ld (ix+5), h ; data address high
1661
;call GET_STR.LENGTH ; get string length
1662
;ld (ix+3), b ; string length
1663
push ix ; output var address...
1666
COPY_TO.VAR_DUMMY.INT: call GET_VAR_DUMMY.ADDR ; create dummy integer variable from BC
1667
ld (ix), 2 ; data type string
1678
push ix ; output var address...
1681
COPY_TO.VAR_DUMMY.DBL: call GET_VAR_DUMMY.ADDR ; create dummy value variable from DAC
1682
ld (ix), a ; data type
1687
push ix ; just to copy ix to de
1692
ldir ; copy bc bytes from hl (data address) to de (variable address)
1693
push ix ; output var address...
1696
GET_VAR_DUMMY.ADDR: push af ;
1699
ld ix, (VAR_DUMMY.POINTER) ;
1700
ld a, (VAR_DUMMY.COUNTER) ;
1701
GET_VAR_DUMMY.NEXT: add ix, de ;
1704
jr nz, GET_VAR_DUMMY.EXIT ;
1706
ld ix, VAR_DUMMY.DATA ;
1707
GET_VAR_DUMMY.EXIT: ld (VAR_DUMMY.POINTER), ix ;
1708
ld (VAR_DUMMY.COUNTER), a ;
1709
ld a, (ix) ; get last var dummy type
1710
cp 3 ; is it string?
1711
call z, GET_VAR_DUMMY.FREE ; free string memory
1718
ld l, (ix+4) ; get string data address
1722
call memory.free ; free memory
1726
; input hl = variable address
1727
COPY_TO.DAC: ld de, BASIC_DAC
1728
COPY_TO.DAC.DATA: ld a, (hl)
1729
ld (BASIC_VALTYP), a
1733
ld bc, 8 ; data = 8 bytes
1734
ldir ; copy bc bytes from hl (data address) to de (variable address)
1736
COPY_TO.ARG: ld de, BASIC_ARG ;
1737
jr COPY_TO.DAC.DATA ;
1738
COPY_TO.DAC_ARG: ld hl, BASIC_DAC ;
1740
ld bc, 8 ; data = 8 bytes
1741
ldir ; copy bc bytes from hl (data address) to de (variable address)
1743
COPY_TO.ARG_DAC: ld hl, BASIC_ARG ;
1745
ld bc, 8 ; data = 8 bytes
1746
ldir ; copy bc bytes from hl (data address) to de (variable address)
1748
COPY_TO.DAC_TMP: ld hl, BASIC_DAC ;
1749
ld de, BASIC_SWPTMP ;
1750
ld bc, 8 ; data = 8 bytes
1751
ldir ; copy bc bytes from hl (data address) to de (variable address)
1753
COPY_TO.TMP_DAC: ld hl, BASIC_SWPTMP ;
1755
ld bc, 8 ; data = 8 bytes
1756
ldir ; copy bc bytes from hl (data address) to de (variable address)
1759
exx ; save registers
1762
ld de, BASIC_SWPTMP ;
1763
ldir ; copy bc bytes from hl to de
1767
ldir ; copy bc bytes from hl to de
1769
ld hl, BASIC_SWPTMP ;
1771
ldir ; copy bc bytes from hl to de
1772
exx ; restore registers
1775
CLEAR.DAC: ld de, BASIC_DAC
1776
CLEAR.DAC.DATA: ld hl, BASIC_VALTYP
1779
ld bc, 8 ; data = 8 bytes
1780
ldir ; copy bc bytes from hl (data address) to de (variable address)
1782
CLEAR.ARG: ld de, BASIC_ARG
1787
;---------------------------------------------------------------------------------------------------------
1788
; MATH 16 BITS ROUTINES
1789
;---------------------------------------------------------------------------------------------------------
1791
MATH.PARM.POP: pop af ; get PC from caller stack
1792
ex af, af' ; save PC to temp
1793
pop.parm ; get first parameter
1794
call COPY_TO.ARG ; put HL in ARG (return var type in A)
1795
pop.parm ; get second parameter
1796
ex af, af' ; restore PC from temp
1797
push af ; put again PC from caller in stack
1798
ex af, af' ; restore 1st data type
1799
push af ; save 1st data type
1800
call COPY_TO.DAC ; put HL in DAC (return var type in A)
1801
pop bc ; restore 1st data type (ARG) in B
1802
cp b ; test if data type in A (DAC) = data type in B (ARG)
1803
ret z ; return if is equal data types
1804
MATH.PARM.CAST: push bc ; else cast both to double
1805
and 12 ; test if single/double
1806
jr nz, MATH.PARM.CST1 ; avoid cast if already single/double
1807
__call_bios MATH_FRCDBL ; convert DAC to double
1808
MATH.PARM.CST1: pop af ;
1809
and 12 ; test if single/double
1810
jr nz, MATH.PARM.CST2 ; avoid cast if already single/double
1811
ld (BASIC_VALTYP), a ;
1812
call COPY_TO.DAC_TMP ;
1813
call COPY_TO.ARG_DAC ;
1814
__call_bios MATH_FRCDBL ; convert ARG to double
1815
call COPY_TO.DAC_ARG ;
1816
call COPY_TO.TMP_DAC ;
1817
MATH.PARM.CST2: ld a, 8 ;
1818
ld (BASIC_VALTYP), a ;
1820
MATH.PARM.POP.INT: ; return result in DAC/ARG as integer
1821
pop af ; get PC from caller stack
1822
ex af, af' ; save PC to temp
1823
pop.parm ; get first parameter
1824
ld a, (hl) ; get parameter type
1825
and 2 ; test if integer
1826
jr z, MATH.PARM.POP.I1 ; do cast if not integer
1827
call COPY_TO.ARG ; put HL in ARG (return var type in A)
1828
jr MATH.PARM.POP.I2 ; go to next parameter
1829
MATH.PARM.POP.I1: call COPY_TO.DAC ; put HL in DAC (return var type in A)
1830
__call_bios MATH_FRCINT ; convert DAC to int
1831
call COPY_TO.DAC_ARG ; copy DAC to ARG
1832
MATH.PARM.POP.I2: pop.parm ; get second parameter
1833
call COPY_TO.DAC ; put HL in DAC (return var type in A)
1834
and 2 ; test if integer
1835
jr nz, MATH.PARM.POP.I3 ; avoid cast if already integer
1836
__call_bios MATH_FRCINT ; convert DAC to int
1838
ld (BASIC_VALTYP), a ;
1840
ex af, af' ; restore PC from temp
1841
push af ; put again PC from caller in stack
1843
MATH.PARM.PUSH: call COPY_TO.VAR_DUMMY ;
1849
; output in parm stack
1850
; http://www.z80.info/zip/zaks_book.pdf - page 104
1851
MATH.ADD.INT: ld hl, (BASIC_DAC+2) ;
1852
ld bc, (BASIC_ARG+2) ;
1854
ld (BASIC_DAC+2), hl ;
1859
if defined MATH.SUB or defined MATH.NEG
1862
; output in parm stack
1863
; http://www.z80.info/zip/zaks_book.pdf - page 104
1864
MATH.SUB.INT: ld hl, (BASIC_DAC+2) ;
1865
ld de, (BASIC_ARG+2) ;
1868
ld (BASIC_DAC+2), hl ;
1873
if defined MATH.MULT
1876
; output in parm stack
1877
MATH.MULT.INT: ld hl, (BASIC_DAC+2) ;
1878
ld bc, (BASIC_ARG+2) ;
1880
ld (BASIC_DAC+2), hl ;
1883
; input HL = multiplicand
1884
; input BC = multiplier
1885
; output HL = result
1886
; http://www.z80.info/zip/zaks_book.pdf - page 131
1887
MATH.MULT.16: ld a, c ; low multiplier
1888
ld c, b ; high multiplier
1890
ld d, h ; multiplicand
1893
MULT16LOOP: srl c ; right shift multiplier high
1894
rra ; rotate right multiplier low
1895
jr nc, MULT16NOADD ; test carry
1896
add hl, de ; add multiplicand to result
1897
MULT16NOADD: ex de, hl
1898
add hl, hl ; double - shift multiplicand
1905
if defined MATH.DIV or defined MATH.IDIV or defined MATH.MOD
1907
; input AC = dividend
1908
; input DE = divisor
1909
; output AC = quotient
1910
; output HL = remainder
1911
; http://www.z80.info/zip/zaks_book.pdf - page 140
1912
MATH.DIV.16: ld hl, 0 ; clear accumulator
1913
ld b, 16 ; set counter
1914
DIV16LOOP: rl c ; rotate accumulator result left
1916
adc hl, hl ; left shift
1917
sbc hl, de ; trial subtract divisor
1918
jr nc, $ + 3 ; subtract was OK ($ = current location)
1919
add hl, de ; restore accumulator
1920
ccf ; calculate result bit
1921
djnz DIV16LOOP ; counter not zero
1922
rl c ; shift in last result bit
1928
if defined GFX_FAST or defined LINE
1930
; compare two signed 16 bits integers
1931
; HL < DE: Carry flag
1932
; HL = DE: Zero flag
1933
; http://www.z80.info/zip/zaks_book.pdf - page 531
1934
MATH.COMP.S16: ld a, h ; test high order byte
1935
and 0x80 ; test sign, clear carry
1936
jr nz, MATH.COMP.S16.NEGM1 ; jump if hl is negative
1938
ret nz ; de is negative (and hl is positive)
1940
cp d ; signs are both positive, so normal compare
1942
ld a, l ; test low order byte
1945
MATH.COMP.S16.NEGM1:
1947
rla ; sign bit into carry
1948
ret c ; signs different
1950
cp d ; both signs negative
1960
MATH.ADD.SGL: ld a, 8 ;
1961
ld (BASIC_VALTYP), a ;
1962
MATH.ADD.DBL: __call_bios MATH_DECADD ;
1967
if defined MATH.SUB or defined MATH.NEG
1969
MATH.SUB.SGL: ld a, 8 ;
1970
ld (BASIC_VALTYP), a ;
1971
MATH.SUB.DBL: __call_bios MATH_DECSUB ;
1976
if defined MATH.MULT
1978
MATH.MULT.SGL: ld a, 8 ;
1979
ld (BASIC_VALTYP), a ;
1980
MATH.MULT.DBL: __call_bios MATH_DECMUL ;
1988
; output in parm stack
1989
MATH.DIV.INT: __call_bios MATH_FRCDBL ; convert DAC to double
1992
ld (BASIC_VALTYP), a ;
1993
__call_bios MATH_FRCDBL ; convert ARG to double
1995
MATH.DIV.SGL: ld a, 8 ;
1996
ld (BASIC_VALTYP), a ;
1997
MATH.DIV.DBL: __call_bios MATH_DECDIV ;
2002
if defined MATH.IDIV
2005
; output in parm stack
2006
MATH.IDIV.SGL: ld a, 8 ;
2007
ld (BASIC_VALTYP), a ;
2008
MATH.IDIV.DBL: __call_bios MATH_FRCINT ; convert DAC to integer
2011
ld (BASIC_VALTYP), a ;
2012
__call_bios MATH_FRCINT ; convert ARG to integer
2014
MATH.IDIV.INT: ld hl, (BASIC_DAC+2) ;
2017
ld de, (BASIC_ARG+2) ;
2021
ld (BASIC_DAC+2), hl ; quotient
2028
MATH.POW.INT: ld (BASIC_VALTYP), a ;
2029
__call_bios MATH_FRCDBL ; convert DAC to double
2032
ld (BASIC_VALTYP), a ;
2033
__call_bios MATH_FRCDBL ; convert ARG to double
2035
MATH.POW.SGL: ld a, 8 ;
2036
ld (BASIC_VALTYP), a ;
2037
MATH.POW.DBL: __call_bios MATH_DBLEXP ;
2044
;MATH.MOD.SGL: ld a, 8 ;
2045
; ld (BASIC_VALTYP), a ;
2046
;MATH.MOD.DBL: __call_bios MATH_FRCINT ; convert DAC to integer
2047
; call SWAP.DAC.ARG ;
2049
; ld (BASIC_VALTYP), a ;
2050
; __call_bios MATH_FRCINT ; convert ARG to integer
2051
; call SWAP.DAC.ARG ;
2052
MATH.MOD.INT: ld hl, (BASIC_DAC+2) ;
2055
ld de, (BASIC_ARG+2) ;
2057
ld (BASIC_DAC+2), hl ; remainder
2064
; fast 16-bit integer square root
2065
; http://www.retroprogramming.com/2017/07/a-fast-z80-integer-square-root.html
2066
; 92 bytes, 344-379 cycles (average 362)
2067
; v2 - 3 t-state optimization spotted by Russ McNulty
2068
; call with hl = number to square root
2069
; returns a = square root
2146
if defined RANDOMIZE or defined SEED
2148
MATH.RANDOMIZE: di ;
2149
ld bc, (BIOS_JIFFY) ;
2152
MATH.SEED: ld (BASIC_RNDX), bc ; seed to IRND
2153
push bc ; in bc = new integer seed
2157
ld (BASIC_DAC+2), bc ; copy bc to dac
2158
ld a, 2 ; type integer
2159
ld (BASIC_VALTYP), a ;
2160
__call_bios MATH_FRCDBL ; convert DAC integer to DAC double
2161
__call_bios MATH_NEG ; DAC = -DAC
2162
__call_bios MATH_RND ; put in DAC a new random number from previous DAC parameter
2167
MATH.ERROR: ld e, 13 ; type mismatch
2168
__call_basic BASIC_ERROR_HANDLER ;
2172
;---------------------------------------------------------------------------------------------------------
2174
;---------------------------------------------------------------------------------------------------------
2176
BOOLEAN.RET.TRUE: ld hl, LIT_TRUE ;
2178
BOOLEAN.RET.FALSE: ld hl, LIT_FALSE ;
2180
BOOLEAN.CMP.INT: ld hl, (BASIC_DAC+2) ;
2181
ld de, (BASIC_ARG+2) ;
2182
__call_bios MATH_ICOMP ;
2184
BOOLEAN.CMP.SGL: ld bc, (BASIC_ARG) ;
2185
ld de, (BASIC_ARG+2) ;
2186
__call_bios MATH_DCOMP ;
2188
BOOLEAN.CMP.DBL: __call_bios MATH_XDCOMP ;
2190
BOOLEAN.CMP.STR: call STRING.COMPARE ;
2193
if defined BOOLEAN.GT
2195
BOOLEAN.GT.INT: call BOOLEAN.CMP.INT ;
2197
BOOLEAN.GT.STR: call BOOLEAN.CMP.STR ;
2199
BOOLEAN.GT.SGL: call BOOLEAN.CMP.SGL ;
2201
BOOLEAN.GT.DBL: call BOOLEAN.CMP.DBL ;
2203
BOOLEAN.GT.RET: cp 0x01 ;
2204
jp z, BOOLEAN.RET.TRUE ;
2205
jp BOOLEAN.RET.FALSE ;
2208
if defined BOOLEAN.LT
2210
BOOLEAN.LT.INT: call BOOLEAN.CMP.INT ;
2212
BOOLEAN.LT.STR: call BOOLEAN.CMP.STR ;
2214
BOOLEAN.LT.SGL: call BOOLEAN.CMP.SGL ;
2216
BOOLEAN.LT.DBL: call BOOLEAN.CMP.DBL ;
2218
BOOLEAN.LT.RET: cp 0xFF ;
2219
jp z, BOOLEAN.RET.TRUE ;
2220
jp BOOLEAN.RET.FALSE ;
2224
if defined BOOLEAN.GE
2226
BOOLEAN.GE.INT: call BOOLEAN.CMP.INT ;
2228
BOOLEAN.GE.STR: call BOOLEAN.CMP.STR ;
2230
BOOLEAN.GE.SGL: call BOOLEAN.CMP.SGL ;
2232
BOOLEAN.GE.DBL: call BOOLEAN.CMP.DBL ;
2234
BOOLEAN.GE.RET: cp 0x01 ;
2235
jp z, BOOLEAN.RET.TRUE ;
2237
jp z, BOOLEAN.RET.TRUE ;
2238
jp BOOLEAN.RET.FALSE ;
2242
if defined BOOLEAN.LE
2244
BOOLEAN.LE.INT: call BOOLEAN.CMP.INT ;
2246
BOOLEAN.LE.STR: call BOOLEAN.CMP.STR ;
2248
BOOLEAN.LE.SGL: call BOOLEAN.CMP.SGL ;
2250
BOOLEAN.LE.DBL: call BOOLEAN.CMP.DBL ;
2252
BOOLEAN.LE.RET: cp 0xFF ;
2253
jp z, BOOLEAN.RET.TRUE ;
2255
jp z, BOOLEAN.RET.TRUE ;
2256
jp BOOLEAN.RET.FALSE ;
2260
if defined BOOLEAN.NE
2262
BOOLEAN.NE.INT: call BOOLEAN.CMP.INT ;
2264
BOOLEAN.NE.STR: call BOOLEAN.CMP.STR ;
2266
BOOLEAN.NE.SGL: call BOOLEAN.CMP.SGL ;
2268
BOOLEAN.NE.DBL: call BOOLEAN.CMP.DBL ;
2270
BOOLEAN.NE.RET: or a ; cp 0
2271
jp nz, BOOLEAN.RET.TRUE ;
2272
jp BOOLEAN.RET.FALSE ;
2276
if defined BOOLEAN.EQ
2278
BOOLEAN.EQ.INT: call BOOLEAN.CMP.INT ;
2280
BOOLEAN.EQ.STR: call BOOLEAN.CMP.STR ;
2282
BOOLEAN.EQ.SGL: call BOOLEAN.CMP.SGL ;
2284
BOOLEAN.EQ.DBL: call BOOLEAN.CMP.DBL ;
2286
BOOLEAN.EQ.RET: or a ; cp 0
2287
jp z, BOOLEAN.RET.TRUE ;
2288
jp BOOLEAN.RET.FALSE ;
2292
if defined BOOLEAN.AND
2294
BOOLEAN.AND.INT: ld a, (BASIC_DAC+2) ;
2295
ld hl, BASIC_ARG+2 ;
2297
ld (BASIC_DAC+2), a ;
2299
ld a, (BASIC_DAC+3) ;
2301
ld (BASIC_DAC+3), a ;
2307
if defined BOOLEAN.OR
2309
BOOLEAN.OR.INT: ld a, (BASIC_DAC+2) ;
2310
ld hl, BASIC_ARG+2 ;
2312
ld (BASIC_DAC+2), a ;
2314
ld a, (BASIC_DAC+3) ;
2316
ld (BASIC_DAC+3), a ;
2322
if defined BOOLEAN.XOR
2324
BOOLEAN.XOR.INT: ld a, (BASIC_DAC+2) ;
2325
ld hl, BASIC_ARG+2 ;
2327
ld (BASIC_DAC+2), a ;
2329
ld a, (BASIC_DAC+3) ;
2331
ld (BASIC_DAC+3), a ;
2337
if defined BOOLEAN.EQV
2339
BOOLEAN.EQV.INT: ld a, (BASIC_DAC+2) ;
2340
ld hl, BASIC_ARG+2 ;
2343
ld (BASIC_DAC+2), a ;
2345
ld a, (BASIC_DAC+3) ;
2348
ld (BASIC_DAC+3), a ;
2354
if defined BOOLEAN.IMP
2356
BOOLEAN.IMP.INT: ld a, (BASIC_DAC+2) ;
2357
ld hl, BASIC_ARG+2 ;
2360
ld (BASIC_DAC+2), a ;
2362
ld a, (BASIC_DAC+3) ;
2365
ld (BASIC_DAC+3), a ;
2371
if defined BOOLEAN.SHR
2373
BOOLEAN.SHR.INT: ld ix, BASIC_DAC+2 ; shift DAC integer to right (bits 15...0-->)
2374
ld a, (BASIC_ARG+2) ;
2376
jp z, MATH.PARM.PUSH ; return if not shift
2377
ld b, a ; shift count
2378
BOOLEAN.SHR.INT.N: rr (ix+1) ;
2381
djnz BOOLEAN.SHR.INT.N ; next shift
2383
jp MATH.PARM.PUSH ; return DAC
2387
if defined BOOLEAN.SHL
2389
BOOLEAN.SHL.INT: ld ix, BASIC_DAC+2 ; shift DAC integer to left (<--bits 15...0)
2390
ld a, (BASIC_ARG+2) ;
2392
jp z, MATH.PARM.PUSH ; return if not shift
2393
ld b, a ; shift count
2394
BOOLEAN.SHL.INT.N: rl (ix) ;
2397
djnz BOOLEAN.SHL.INT.N ; next shift
2399
jp MATH.PARM.PUSH ; return DAC
2403
if defined BOOLEAN.NOT
2405
BOOLEAN.NOT.INT: ld a, (BASIC_DAC+2) ;
2407
ld (BASIC_DAC+2), a ;
2408
ld a, (BASIC_DAC+3) ;
2410
ld (BASIC_DAC+3), a ;
2418
;---------------------------------------------------------------------------------------------------------
2419
; MEMORY ALLOCATION ROUTINES
2420
;---------------------------------------------------------------------------------------------------------
2421
; Adapted from memory allocator code by SamSaga2, Spain, 2015
2422
; https://www.msx.org/forum/msx-talk/development/asm-memory-allocator
2423
; https://www.msx.org/users/samsaga2
2424
;---------------------------------------------------------------------------------------------------------
2425
memory.heap_start: equ VAR_STACK.END + 1 ; start at end of variable stack
2426
memory.heap_end: equ 0xF0A0 - 100 ; end at start of work area for stack (100 bytes reserved), BIOS and BASIC interpreter
2427
block.next: equ 0 ; next free block address
2428
block.size: equ 2 ; size of block including header
2429
block: equ 4 ; block.next + block.size
2433
ld ix,memory.heap_start ; first block
2434
ld hl,memory.heap_start+block ; second block
2435
;; first block NEXT=secondblock, SIZE=0
2436
;; with this block we have a fixed start location
2437
;; because never will be allocated
2438
ld (ix+block.next),l
2439
ld (ix+block.next+1),h
2440
ld (ix+block.size),0
2441
ld (ix+block.size+1),0
2442
;; second block NEXT=0, SIZE=all
2443
;; the first and only free block have all available memory
2444
ld (ix+block.next+block),0
2445
ld (ix+block.next+block+1),0
2447
;ld hl,memory.heap_end ; size = @heap_end (stack) - heap_start - block_header * 2 - 100 (buffer for stack)
2450
ld de, memory.heap_start + (block * 2) + 100
2452
;ld de, block * 2 + 100
2454
ld (ix+block.size+block),l
2455
ld (ix+block.size+block+1),h
2459
;; IN BC=size, OUT IX=memptr, NZ=ok
2467
ld ix,memory.heap_start ; this
2470
ld l,(ix+block.size)
2471
ld h,(ix+block.size+1)
2474
jp z, memory.alloc.exactfit
2475
jp c, memory.alloc.nextblock
2476
;; split found block
2477
memory.alloc.splitfit:
2478
;; free space must allow at least two blocks headers (current + next)
2480
jr nz, memory.alloc.splitfit.do ; if free space > 0xFF, do split
2483
jr c, memory.alloc.nextblock ; if free space < 4, skip to next block
2484
memory.alloc.splitfit.do:
2485
;; newfreeblock = this + BC
2489
;; prevblock->next = newfreeblock
2490
ld (iy+block.next),l
2491
ld (iy+block.next+1),h
2492
;; newfreeblock->next = this->next
2494
pop iy ; iy = newfreeblock
2495
ld l,(ix+block.next)
2496
ld h,(ix+block.next+1)
2497
ld (iy+block.next),l
2498
ld (iy+block.next+1),h
2499
;; newfreeblock->size = this->size - BC
2500
ld l,(ix+block.size)
2501
ld h,(ix+block.size+1)
2504
ld (iy+block.size),l
2505
ld (iy+block.size+1),h
2507
ld (ix+block.size),c
2508
ld (ix+block.size+1),b
2510
;; use whole found block
2511
memory.alloc.exactfit:
2512
;; prevblock->next = this->next - remove block from free list
2513
ld l,(ix+block.next)
2514
ld h,(ix+block.next+1)
2515
ld (iy+block.next),l
2516
ld (iy+block.next+1),h
2525
memory.alloc.nextblock:
2526
ld l,(ix+block.next)
2527
ld h,(ix+block.next+1)
2534
;; this = this->next
2537
jp memory.alloc.find
2542
;; HL = IX - block_header_size
2549
ld ix,memory.heap_start
2551
ld e,(ix+block.next)
2552
ld d,(ix+block.next+1)
2555
jp z, memory.free.passedend
2556
sbc hl,de ; test this (HL) against next (DE)
2557
jr c, memory.free.found ; if DE > HL
2558
add hl,de ; restore hl value
2560
pop ix ; current = next
2563
;; ix=prev, hl=this, de=next
2565
add hl,de ; restore hl value
2566
ld (ix+block.next), l
2567
ld (ix+block.next+1), h ; prev->next = this
2570
ld (iy+block.next), e
2571
ld (iy+block.next+1), d ; this->next = next
2572
push ix ; prev x this
2577
call memory.free.coalesce
2578
pop ix ; this x next
2579
jr memory.free.coalesce
2583
memory.free.coalesce:
2584
ld c, (iy+block.size)
2585
ld b, (iy+block.size+1) ; bc = this->size
2589
adc hl, bc ; hl = this + this->size
2593
sbc hl, de ; if this + this->size == next, then this->size += next->size, this->next = next->next
2594
jr z, memory.free.coalesce.do
2595
push ix ; else, new *this = *next
2598
memory.free.coalesce.do:
2599
ld l, (ix+block.size)
2600
ld h, (ix+block.size+1) ; hl = next->size
2602
adc hl, bc ; hl += this->size
2603
ld (iy+block.size), l
2604
ld (iy+block.size+1), h ; this->size = hl
2605
ld l, (ix+block.next)
2606
ld h, (ix+block.next+1) ; hl = next->next
2607
ld (iy+block.next), l
2608
ld (iy+block.next+1), h ; this->next = hl
2611
memory.free.passedend:
2612
;; append block at the end of the free list
2613
ld (ix+block.next),l
2614
ld (ix+block.next+1),h
2617
ld (iy+block.next),0
2618
ld (iy+block.next+1),0
2624
ld ix,memory.heap_start
2626
memory.get_free.count:
2628
add a,(ix+block.size)
2631
adc a,(ix+block.size+1)
2633
ld l,(ix+block.next)
2634
ld h,(ix+block.next+1)
2640
jr memory.get_free.count
2642
memory.error: ld e, 7 ; out of memory
2643
__call_basic BASIC_ERROR_HANDLER ;
2648
;---------------------------------------------------------------------------------------------------------
2650
; By: Amaury Carvalho, 2019
2651
;---------------------------------------------------------------------------------------------------------
2653
; https://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm#Algorithm_for_integer_arithmetic
2654
; https://en.wikipedia.org/wiki/Midpoint_circle_algorithm
2655
; https://rosettacode.org/wiki/Bitmap/Midpoint_circle_algorithm#C
2656
; https://www.msx.org/wiki/MSX-BASIC_Instructions
2657
;---------------------------------------------------------------------------------------------------------
2659
;---------------------------------------------------------------------------------------------------------
2661
;---------------------------------------------------------------------------------------------------------
2663
BIOS_WRTVDP: EQU 0x0047
2664
BIOS_RDVRM: EQU 0x004A
2665
BIOS_WRTVRM: EQU 0x004D
2666
BIOS_LDIRVM: EQU 0x005C
2667
BIOS_LDIRMV: EQU 0x0059
2668
BIOS_PNTINI: EQU 0x18CF
2669
BIOS_RIGHTC: EQU 0x16C5 ; Move current pixel physical address right
2670
BIOS_TRIGHTC: EQU 0x16AC ; Test then RIGHTC if legal
2671
BIOS_LEFTC: EQU 0x16EE ; Move current pixel physical address left
2672
BIOS_TLEFTC: EQU 0x16D8 ; Test then LEFTC if legal
2673
BIOS_UPC: EQU 0x175D ; Move current pixel physical address up
2674
BIOS_TUPC: EQU 0x173C ; Test then UPC if legal
2675
BIOS_DOWNC: EQU 0x172A ; Move current pixel physical address down
2676
BIOS_TDOWNC: EQU 0x170A ; Test then DOWNC if legal
2677
BIOS_DCOMPR: EQU 0x146A ; compare HL and DE (Flag NC if HL>DE, Flag Z if HL=DE, Flag C if HL<DE)
2678
BIOS_FILVRM: EQU 0x0056 ; fill VRAM with value
2680
BIOS_BIGFIL: EQU 0x016B ; msx 2
2681
BIOS_NRDVRM: EQU 0x0174 ; msx 2
2682
BIOS_NWRVRM: EQU 0x0177 ; msx 2
2683
BIOS_NRDVDP: EQU 0x013E ; msx 2
2684
BIOS_VDPSTA: EQU 0x0131 ; msx 2
2685
BIOS_NWRVDP: EQU 0x012D ; msx 2 (0x0647)
2687
BASIC_SUB_LINE: equ 0x58fc
2688
BASIC_SUB_LINEBOX: equ 0x5912
2689
BASIC_SUB_LINEBOXFILLED: equ 0x58C1
2690
BASIC_SUB_CIRCLE: equ 0x5B19
2691
BASIC_SUB_PAINT1: equ 0x59DA ;0x59C8
2692
BASIC_SUB_PAINT2: equ 0x0069 ;0x2664 ;0x2651+3
2694
;---------------------------------------------------------------------------------------------------------
2696
;---------------------------------------------------------------------------------------------------------
2698
BIOS_RG0SAV: EQU 0xF3DF
2699
BIOS_RG1SAV: EQU 0xF3E0
2700
BIOS_RG8SAV: EQU 0xFFE7
2701
BIOS_BDRATR: EQU 0xFCB2
2702
BIOS_STATFL: EQU 0xF3E7 ; VDP status register
2704
BIOS_CXOFF: EQU 0xF945
2705
BIOS_CYOFF: EQU 0xF947
2706
BIOS_GXPOS: EQU 0xFCB3
2707
BIOS_GYPOS: EQU 0xFCB5
2709
BIOS_GRPNAM: EQU 0xF3C7 ; pattern name table
2710
BIOS_GRPCOL: EQU 0xF3C9 ; colour table
2711
BIOS_GRPCGP: EQU 0xF3CB ; pattern generator table
2712
BIOS_GRPATR: EQU 0xF3CD ; sprite attribute table
2713
BIOS_GRPPAT: EQU 0xF3CF ; sprite generator table
2714
BIOS_CGPNT: EQU 0xF920 ; 2 - current MSX Font location (0x1BBF)
2715
BIOS_ATRBAS: EQU 0xF928 ; sprite attribute table
2717
BIOS_MLTNAM: EQU 0xF3D1 ; pattern name table (screen 3, multicolor)
2718
BIOS_MLTCOL: EQU 0xF3D3 ; colour table (screen 3, multicolor)
2719
BIOS_MLTCGP: EQU 0xF3D5 ; pattern generator table (screen 3, multicolor)
2720
BIOS_MLTATR: EQU 0xF3D7 ; sprite attribute table (screen 3, multicolor)
2721
BIOS_MLTPAT: EQU 0xF3D9 ; sprite generator table (screen 3, multicolor)
2723
BIOS_ASPECT: equ 0xF931 ;2 Aspect ratio of the circle; set by <ratio> of CIRCLE.
2724
BIOS_CENCNT: equ 0xF933 ;2 Counter used by CIRCLE.
2725
BIOS_CLINEF: equ 0xF935 ;1 Flag to draw line to centre, Used set by CIRCLE
2726
BIOS_CNPNTS: equ 0xF936 ;2 Point to be plottted in a 45° segment, Used set by CIRCLE
2727
BIOS_CPLOTF: equ 0xF938 ;1 Plot polarity flag, Used set by CIRCLE
2728
BIOS_CPCNT: equ 0xF939 ;2 Number of points in 1/8 of circle, Used set by CIRCLE.
2729
BIOS_CPCNT8: equ 0xF93B ;2 Number of points in the circle. Used by CIRCLE.
2730
BIOS_CRCSUM: equ 0xF93D ;2 Cyclic redundancy check sum of the circle. Used by CIRCLE.
2731
BIOS_CSTCNT: equ 0xF93F ;2 Variable to maintain the number of points of the starting angle. Used by the instruction CIRCLE
2732
BIOS_CSCLXY: equ 0xF941 ;1 Scale of X & Y. Used by the instruction CIRCLE
2733
BIOS_ASPCT1: equ 0xF40B ;2 256/aspect ratio for Basic instruction CIRCLE.
2734
BIOS_ASPCT2: equ 0xF40D ;2 256*aspect ratio for Basic instruction CIRCLE.
2735
BIOS_MAXUPD: equ 0xF3EC ;3 Work area used by the instruction CIRCLE, contains JP 0000h at start.
2736
BIOS_MINUPD: equ 0xF3EF ;3 Work area used by the instruction CIRCLE, contains JP 0000h at start.
2738
BIOS_PARM1: EQU 0xF6E8 ; 100
2739
BIOS_PARM2: EQU 0xF750 ; 100
2741
GFX_TEMP: EQU BIOS_PARM1 ; 2
2742
GFX_TEMP1: EQU GFX_TEMP + 2 ; 2
2743
GFX_TEMP2: EQU GFX_TEMP1 + 2 ; 2
2744
GFX_TEMP3: EQU GFX_TEMP2 + 2 ; 2
2745
GFX_TEMP4: EQU GFX_TEMP3 + 2 ; 2
2746
GFX_TEMP5: EQU GFX_TEMP4 + 2 ; 2
2747
GFX_TEMP6: EQU GFX_TEMP5 + 2 ; 2
2748
GFX_TEMP7: EQU GFX_TEMP6 + 2 ; 2
2749
GFX_TEMP8: EQU GFX_TEMP7 + 2 ; 2
2750
GFX_TEMP9: EQU GFX_TEMP8 + 2 ; 2
2752
GFX_MAX_X: EQU 0xFCA4 ; 1 (CASSETE LOWLIM)
2753
GFX_MAX_Y: EQU 0xFCA5 ; 1 (CASSETE WINWID)
2755
GFX_SPRITE_FLAGS: EQU 0xF40A ; 1 (CASSETE HEADER) - bits 0=check screen limits, 1=check walls, 2=check hotspots,
2756
; 3=limit touched, 4=wall touched, 5=hotspot touched, 6=collided
2757
GFX_SPRITE_SIZE_DAT: EQU 0xF3FC ; 1 (CASSETE CS1200)
2758
GFX_SPRITE_SIZE_SCR: EQU 0xF3FD ; 1
2759
GFX_SPRITE_WALLS: EQU 0xF406 ; 2 (CASSETE LOW)
2760
GFX_SPRITE_HOTSPOTS: EQU 0xF408 ; 2 (CASSETE HIGH)
2761
GFX_SPRITE_HOTSPOT_TILE: EQU 0xF405 ; 1 (CASSETE CS2400)
2762
GFX_SPRITE_COLLIDER: EQU 0xF400 ; 1 (CASSETE CS1200)
2763
GFX_SPRITE_COLLISION: EQU 0xF7B5 ; 2 (ARYTA2)
2765
GFX_MUSIC_START: EQU 0xF401 ; 2 (CASSETE CS2400)
2766
GFX_MUSIC_NEXT: EQU 0xF403 ; 2
2767
GFX_MUSIC_PREV: EQU 0xF74C ; 2 (PRMPRV)
2769
GFX_TEMP10: EQU 0xF3FE ; 2 (CASSETE CS1200)
2771
;BIOS_SCR_SIZE_X: dw 240, 256, 256, 64, 256, 256, 512, 512, 256, 512, 256, 256, 256
2772
;BIOS_SCR_SIZE_Y: dw 192, 192, 192, 48, 192, 212, 212, 212, 212, 384, 212, 212, 212
2773
BIOS_SCR_SIZE_X: db 239, 255, 255, 63, 255, 255, 255, 255, 255, 255, 255, 255, 255
2774
BIOS_SCR_SIZE_Y: db 191, 191, 191, 47, 191, 211, 211, 211, 211, 255, 211, 211, 211
2777
;---------------------------------------------------------------------------------------------------------
2778
; gfxIsScreenModeMSX2
2779
; return if screen mode is from MSX 2
2780
; out C is set, if MSX2 and screen mode above 3
2781
;---------------------------------------------------------------------------------------------------------
2783
gfxIsScreenModeMSX2:
2784
ld a, (BIOS_VERSION)
2786
jp nz, BIOS_CHKNEW ; if not MSX1, jump to CHKNEW
2790
;---------------------------------------------------------------------------------------------------------
2792
; set current screen mode
2793
; in A = screen number
2794
;---------------------------------------------------------------------------------------------------------
2798
call gfxInitScreenWorkspace
2800
ld a, (BIOS_VERSION)
2802
jr nz, gfxSetScreenMode.1 ; if not MSX1, jump
2805
call nc, gfxSetScreenMode.0 ; if screen mode >= 4, change to screen 2
2806
__call_bios BIOS_CHGMOD ; change the screen mode (msx1)
2807
jr gfxSetScreenMode.2
2815
ld ix, BIOS_CHGMOD2 ; change the screen mode (msx2)
2819
call gfxGetScreenHeight
2820
call gfxGetScreenWidth
2821
call gfxGetSpriteSize
2822
jp gfxFillSpriteCollisionTable
2824
gfxInitScreenWorkspace:
2826
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
2828
ld (GFX_SPRITE_WALLS), a
2829
ld (GFX_SPRITE_WALLS+1), a
2830
ld (GFX_SPRITE_HOTSPOTS), a
2831
ld (GFX_SPRITE_HOTSPOTS+1), a
2832
ld (GFX_MUSIC_START), a
2833
ld (GFX_MUSIC_START+1), a
2834
ld (GFX_MUSIC_NEXT), a
2835
ld (GFX_MUSIC_NEXT+1), a
2836
ld (GFX_MUSIC_PREV), a
2837
ld (GFX_MUSIC_PREV+1), a
2838
ld (GFX_SPRITE_HOTSPOT_TILE), a
2839
ld (GFX_SPRITE_COLLIDER), a
2842
;---------------------------------------------------------------------------------------------------------
2844
; return current screen mode
2845
; out A = screen number (0=40x24 Text Mode, 1=32x24 Text Mode, 2=Graphics Mode, 3=Multicolour Mode)
2846
;---------------------------------------------------------------------------------------------------------
2852
;---------------------------------------------------------------------------------------------------------
2854
; set current screen location
2857
;---------------------------------------------------------------------------------------------------------
2860
ld (BIOS_GRPACX), bc ; x
2861
;ld (BIOS_GXPOS), bc
2862
ld (BIOS_GRPACY), de ; y
2863
;ld (BIOS_GYPOS), de
2866
;---------------------------------------------------------------------------------------------------------
2868
; refresh current screen location
2869
;---------------------------------------------------------------------------------------------------------
2872
ld bc, (BIOS_GRPACX) ; x
2873
ld de, (BIOS_GRPACY) ; y
2875
call gfxIsScreenModeMSX2
2876
jr nc, gfxRefreshXY.2 ; if MSX2 and screen mode above 3
2877
__call_bios BIOS_SCALXY ; BC = X, DE = Y
2878
__call_bios BIOS_MAPXYC ; in BC = X, DE = Y
2881
ld ix, BIOS_SCALXY2 ; BC = X, DE = Y
2883
ld ix, BIOS_MAPXYC2 ; in BC = X, DE = Y
2886
;---------------------------------------------------------------------------------------------------------
2888
; get current screen location
2891
;---------------------------------------------------------------------------------------------------------
2894
ld bc, (BIOS_GRPACX) ; x
2895
ld de, (BIOS_GRPACY) ; y
2898
;---------------------------------------------------------------------------------------------------------
2899
; gfxGetScreenHeight
2901
; out a = screen height
2902
;---------------------------------------------------------------------------------------------------------
2907
ld hl, BIOS_SCR_SIZE_Y
2918
;---------------------------------------------------------------------------------------------------------
2921
; out a = screen height
2922
;---------------------------------------------------------------------------------------------------------
2927
ld hl, BIOS_SCR_SIZE_X
2938
;---------------------------------------------------------------------------------------------------------
2940
; get sprite data size
2941
; out a = sprite data size
2942
;---------------------------------------------------------------------------------------------------------
2947
ld a, (BIOS_RG1SAV) ; bit 0 = double size, bit 1 = sprite size (0=8 pixels, 1=16 pixels)
2949
jr z, gfxGetSpriteSize.1
2954
jr z, gfxGetSpriteSize.2
2958
ld (GFX_SPRITE_SIZE_DAT), bc
2964
if defined GFX_FAST and defined PAINT
2966
;---------------------------------------------------------------------------------------------------------
2968
; move screen current location up
2969
; out: carry if off screen
2970
;---------------------------------------------------------------------------------------------------------
2975
ld de, (BIOS_GRPACY)
2980
ld (BIOS_GRPACY), de
2991
;---------------------------------------------------------------------------------------------------------
2993
; move screen current location down
2994
; out: carry if off screen
2995
;---------------------------------------------------------------------------------------------------------
3002
ld de, (BIOS_GRPACY)
3007
ld (BIOS_GRPACY), de
3018
;---------------------------------------------------------------------------------------------------------
3020
; move screen current location left
3021
; out: carry if off screen
3022
;---------------------------------------------------------------------------------------------------------
3027
ld de, (BIOS_GRPACX)
3032
ld (BIOS_GRPACX), de
3043
;---------------------------------------------------------------------------------------------------------
3045
; move screen current location right
3046
; out: carry if off screen
3047
;---------------------------------------------------------------------------------------------------------
3054
ld de, (BIOS_GRPACX)
3059
ld (BIOS_GRPACX), de
3072
;---------------------------------------------------------------------------------------------------------
3074
; push current screen location
3075
;---------------------------------------------------------------------------------------------------------
3080
ld iy, (BIOS_GRPACX) ; x
3082
ld iy, (BIOS_GRPACY) ; y
3088
;---------------------------------------------------------------------------------------------------------
3090
; pop current screen location
3093
;---------------------------------------------------------------------------------------------------------
3102
;---------------------------------------------------------------------------------------------------------
3104
; set current foreground color
3106
;---------------------------------------------------------------------------------------------------------
3109
ld (BIOS_FORCLR), a ; foreground color
3113
;---------------------------------------------------------------------------------------------------------
3115
; get current foreground color
3117
;---------------------------------------------------------------------------------------------------------
3120
ld a, (BIOS_FORCLR) ; foreground color
3123
;---------------------------------------------------------------------------------------------------------
3125
; set current background color
3127
;---------------------------------------------------------------------------------------------------------
3130
ld (BIOS_BAKCLR), a ; foreground color
3133
;---------------------------------------------------------------------------------------------------------
3135
; get current background color
3137
;---------------------------------------------------------------------------------------------------------
3140
ld a, (BIOS_BAKCLR) ; foreground color
3143
;---------------------------------------------------------------------------------------------------------
3145
; set current border color
3147
;---------------------------------------------------------------------------------------------------------
3150
ld (BIOS_BDRCLR), a ; border color
3153
;---------------------------------------------------------------------------------------------------------
3155
; get current border color
3157
;---------------------------------------------------------------------------------------------------------
3160
ld a, (BIOS_BDRCLR) ; border color
3163
;---------------------------------------------------------------------------------------------------------
3165
; set fill border color
3167
;---------------------------------------------------------------------------------------------------------
3170
ld (BIOS_BDRATR), a ; border color
3173
;---------------------------------------------------------------------------------------------------------
3175
; get fill border color
3177
;---------------------------------------------------------------------------------------------------------
3180
ld a, (BIOS_BDRATR) ; border color
3183
;---------------------------------------------------------------------------------------------------------
3185
; set current color (foreground, background and border)
3186
;---------------------------------------------------------------------------------------------------------
3191
jp nz, BIOS_CHGCLR2 ; change VDP colors - msx2
3193
jp nz, BIOS_CHGCLR2 ; change VDP colors - msx2
3194
jp BIOS_CHGCLR ; change VDP colors
3195
; __call_bios BIOS_SETATR ; change the pixel color
3198
;---------------------------------------------------------------------------------------------------------
3200
; set pixel in current position to current foreground color
3201
;---------------------------------------------------------------------------------------------------------
3204
call gfxIsScreenModeMSX2
3205
jr nc, gfxSetPixel.1 ; if MSX2 and screen mode above 3
3206
__call_bios BIOS_SETC
3212
;---------------------------------------------------------------------------------------------------------
3214
; get pixel color in current position
3215
; out A = pixel color
3216
;---------------------------------------------------------------------------------------------------------
3219
call gfxIsScreenModeMSX2
3220
jr nc, gfxGetPixel.1 ; if MSX2 and screen mode above 3
3221
__call_bios BIOS_READC
3229
;---------------------------------------------------------------------------------------------------------
3231
; plot a line from current position to informed destination
3232
; in BC = destination x
3233
; DE = destination y
3234
; https://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm#Algorithm_for_integer_arithmetic
3235
; https://rosettacode.org/wiki/Bitmap/Bresenham%27s_line_algorithm#C
3236
;---------------------------------------------------------------------------------------------------------
3237
;void line(int x0, int y0, int x1, int y1) {
3238
; int dx = abs(x1-x0), sx = x0<x1 ? 1 : -1;
3239
; int dy = abs(y1-y0), sy = y0<y1 ? 1 : -1;
3240
; int err = (dx>dy ? dx : -dy)/2, e2;
3243
; if (x0==x1 && y0==y1) break;
3245
; if (e2 >-dx) { err -= dy; x0 += sx; }
3246
; if (e2 < dy) { err += dx; y0 += sy; }
3251
if not defined GFX_FAST
3252
ld hl, (BIOS_GRPACX)
3254
ld hl, (BIOS_GRPACY)
3256
__call_basic BASIC_SUB_LINE
3261
ld (GFX_TEMP2), bc ; x
3262
ld (GFX_TEMP3), de ; y
3264
ld hl, (BIOS_GRPACX) ; x0
3265
ld de, (GFX_TEMP2) ; x
3268
;jp po, gfxLine.1 ; x0 >= x? else jump to endif
3270
jp c, gfxLine.1 ; x0 < x? jump
3273
ld (GFX_TEMP4), hl ; dx = x0 - x
3275
ld (GFX_TEMP5), hl ; sx = -1
3279
ld de, (BIOS_GRPACX) ; x0
3280
ld hl, (GFX_TEMP2) ; x
3283
ld (GFX_TEMP4), hl ; dx = x - x0
3285
ld (GFX_TEMP5), hl ; sx = 1
3288
ld hl, (BIOS_GRPACY) ; y0
3289
ld de, (GFX_TEMP3) ; y
3292
;jp po, gfxLine.3 ; y0 >= y? else, jump to endif
3294
jp c, gfxLine.3 ; y0 < y? jump
3297
ld (GFX_TEMP6), hl ; dy = y0 - y
3299
ld (GFX_TEMP7), hl ; sy = -1
3303
ld de, (BIOS_GRPACY) ; y0
3304
ld hl, (GFX_TEMP3) ; y
3307
ld (GFX_TEMP6), hl ; dy = y - y0
3309
ld (GFX_TEMP7), hl ; sy = 1
3312
ld hl, (GFX_TEMP6) ; dy
3315
jp z, gfxLine.h ; dy = 0?
3317
ld hl, (GFX_TEMP4) ; dx
3320
jp z, gfxLine.v ; dx = 0?
3322
ld de, (GFX_TEMP4) ; dx
3323
ld hl, (GFX_TEMP6) ; dy
3328
ld (GFX_TEMP9), hl ; dxy = dx + dy
3330
ld de, (GFX_TEMP4) ; dx
3331
ld hl, (GFX_TEMP6) ; dy
3334
;jp pe, gfxLine.5 ; dy < dx? else, jump to endif
3336
jp z, gfxLine.5 ; dy = dx? jump
3337
jp nc, gfxLine.5 ; dy > dx? jump
3339
ld de, (GFX_TEMP6) ; dy
3345
ld (GFX_TEMP8), de ; err = -dy / 2
3349
ld hl, (GFX_TEMP4) ; dx
3353
ld (GFX_TEMP8), hl ; err = dx/2
3358
ld hl, (GFX_TEMP9) ; dxy
3361
jp nc, gfxLine.loop.0 ; dxy > 0? jump
3362
;jp z, gfxLine.loop.0 ; dxy = 0? jump
3368
ld de, (GFX_TEMP4) ; dx
3371
ld de, (GFX_TEMP8) ; e2 = err
3375
;jp pe, gfxLine.loop.1 ; if -dx < e2, else jump to endif
3377
jp z, gfxLine.loop.1 ; -dx = e2? jump
3378
jp nc, gfxLine.loop.1 ; -dx > e2? jump
3379
ld hl, (GFX_TEMP8) ; err
3380
ld de, (GFX_TEMP6) ; dy
3383
ld (GFX_TEMP8), hl ; err -= dy
3385
ld hl, (GFX_TEMP9) ; dxy
3387
ld (GFX_TEMP9), hl ; dxy -= 1
3389
ld hl, (BIOS_GRPACX)
3393
ld (BIOS_GRPACX), hl ; x0 += sx
3397
ld de, (GFX_TEMP6) ; dy
3400
;jp pe, gfxLine.loop.2 ; if e2 < dy, else jump to endif
3402
jp z, gfxLine.loop.2 ; e2 = dy? jump
3403
jp nc, gfxLine.loop.2 ; e2 > dy? jump
3404
ld hl, (GFX_TEMP8) ; err
3405
ld de, (GFX_TEMP4) ; dx
3408
ld (GFX_TEMP8), hl ; err += dx
3410
ld hl, (GFX_TEMP9) ; dxy
3412
ld (GFX_TEMP9), hl ; dxy -= 1
3414
ld hl, (BIOS_GRPACY)
3418
ld (BIOS_GRPACY), hl ; y0 += sy
3425
ld a, (GFX_TEMP5) ; sx
3427
jr z, gfxLine.h.1 ; if a is positive
3428
ld hl, (BIOS_GRPACX)
3432
ld (BIOS_GRPACX), hl
3436
__call_bios BIOS_FETCHC
3437
ld hl, (GFX_TEMP4) ; dx
3439
call gfxDrawHorLine ; HL = pixel count
3443
ld a, (GFX_TEMP7) ; sy
3445
jr z, gfxLine.v.1 ; if a is positive
3446
ld hl, (BIOS_GRPACY)
3450
ld (BIOS_GRPACY), hl
3455
ld hl, (GFX_TEMP6) ; dy
3458
jp gfxBox.drawVerLine
3463
if defined BOX or defined FBOX or defined BOX_STEP or defined FBOX_STEP
3465
;---------------------------------------------------------------------------------------------------------
3467
; plot a box from current position to informed destination
3468
; in BC = destination x
3469
; DE = destination y
3470
; A = filled flag (0 = not filled, <>0 = filled)
3471
;---------------------------------------------------------------------------------------------------------
3475
if not defined GFX_FAST
3476
ld hl, (BIOS_GRPACX)
3478
ld hl, (BIOS_GRPACY)
3480
ld hl, BASIC_SUB_LINEBOX
3483
call gfxIsScreenModeMSX2
3485
ld hl, BASIC_SUB_LINEBOXFILLED
3490
jp BIOS_CALBAS ; BIOS_CALSLT
3501
call gfxAdjustDestXY
3503
jr nz, gfxBox.filled
3507
call gfxBox.drawHorLine
3509
ld de, (BIOS_GRPACX)
3513
ld (BIOS_GRPACX), hl
3515
call gfxBox.drawVerLine
3517
call gfxBox.drawVerLine
3518
call gfxBox.drawHorLine
3526
ld bc, (BIOS_GRPACX)
3528
call gfxBox.drawHorLine
3530
ld (BIOS_GRPACX), bc
3531
ld bc, (BIOS_GRPACY)
3533
ld (BIOS_GRPACY), bc
3539
jr nz, gfxBox.filled.loop
3551
gfxBox.drawVerLine.loop:
3559
jr nz, gfxBox.drawVerLine.loop
3562
;---------------------------------------------------------------------------------------------------------
3564
; draw a horizontal line
3566
;---------------------------------------------------------------------------------------------------------
3571
jr c, gfxDrawHorLine.2 ; if screen mode < 5 then jump
3573
ret nz ; return if negative
3576
jr nz, gfxDrawHorLine.1
3578
ret z ; return if hl = 0
3587
jr nz, gfxDrawHorLine.1
3591
__call_bios BIOS_NSETCX ; HL = fill count
3594
;---------------------------------------------------------------------------------------------------------
3596
; invert if dest XY is less than current XY position
3599
;---------------------------------------------------------------------------------------------------------
3603
ld (GFX_TEMP2), bc ; x
3604
ld (GFX_TEMP3), de ; y
3606
; verify x againt current position
3607
ld hl, (BIOS_GRPACX)
3610
sbc hl, de ; dx = x1 - x0
3611
bit 7, h ; result is negative?
3612
jr z, gfxAdjustDestXY.1
3614
ld (BIOS_GRPACX), hl
3622
; verify y againt current position
3623
ld hl, (BIOS_GRPACY)
3626
sbc hl, de ; dy = y1 - y0
3627
bit 7, h ; result is negative?
3628
jr z, gfxAdjustDestXY.2
3630
ld (BIOS_GRPACY), hl
3638
; refresh new position
3648
;---------------------------------------------------------------------------------------------------------
3650
; plot a circle centered in current position
3651
; BC = tracing end x
3652
; DE = tracing end y
3654
; A = filled flag (0 = not filled, <>0 = filled)
3655
; https://en.wikipedia.org/wiki/Midpoint_circle_algorithm
3656
; https://rosettacode.org/wiki/Bitmap/Midpoint_circle_algorithm#C
3657
;---------------------------------------------------------------------------------------------------------
3661
if not defined GFX_FAST
3663
ret nz ; return if negative radius
3664
ld (BIOS_GXPOS), hl ; circle ray
3666
ld bc, (BIOS_GRPACY)
3670
;jr nz, gfxDrawCircle.1
3677
__call_basic BASIC_SUB_CIRCLE
3680
ld (GFX_TEMP), hl ; radius
3683
ret z ; return if zero radius
3685
ret nz ; return if negative radius
3688
ld (GFX_TEMP1), bc ; x0
3689
ld (GFX_TEMP2), de ; y0
3692
jp nz, gfxCircle.filled
3694
gfxCircle.notFilled:
3696
ld de, (GFX_TEMP) ; radius
3699
ld (GFX_TEMP3), hl ; f = 1 - radius
3702
ld (GFX_TEMP4), hl ; ddF_x = 0
3711
ld (GFX_TEMP5), hl ; ddF_y = -2 * radius
3714
ld (GFX_TEMP6), hl ; x = 0
3717
ld (GFX_TEMP7), hl ; y = radius
3719
; plot(x0, y0 + radius)
3720
ld de, (GFX_TEMP) ; radius
3721
ld hl, (GFX_TEMP2) ; y0
3725
ld bc, (GFX_TEMP1) ; x0
3729
; plot(x0, y0 - radius)
3730
ld de, (GFX_TEMP) ; radius
3731
ld hl, (GFX_TEMP2) ; y0
3735
ld bc, (GFX_TEMP1) ; x0
3739
; plot(x0 + radius, y0)
3740
ld hl, (GFX_TEMP1) ; x0
3741
ld de, (GFX_TEMP) ; radius
3748
ld de, (GFX_TEMP2) ; y0
3752
; plot(x0 - radius, y0)
3753
ld hl, (GFX_TEMP1) ; x0
3754
ld de, (GFX_TEMP) ; radius
3761
ld de, (GFX_TEMP2) ; y0
3764
jp gfxCircle.notFilled.3
3766
gfxCircle.notFilled.1:
3767
ld hl, (GFX_TEMP3) ; f
3769
jr nz, gfxCircle.notFilled.2 ; if( f < 0 ), jump
3771
ld hl, (GFX_TEMP7) ; y -= 1
3775
ld hl, (GFX_TEMP5) ; ddF_y += 2
3780
ld hl, (GFX_TEMP3) ; f
3781
ld de, (GFX_TEMP5) ; ddF_y
3784
ld (GFX_TEMP3), hl ; f += ddF_y
3786
gfxCircle.notFilled.2:
3787
ld hl, (GFX_TEMP6) ; x
3789
ld (GFX_TEMP6), hl ; x++
3791
ld hl, (GFX_TEMP4) ; ddF_x += 2
3796
ld hl, (GFX_TEMP3) ; f
3797
ld de, (GFX_TEMP4) ; ddF_x
3801
ld (GFX_TEMP3), hl ; f += ddF_x + 1
3803
; plot(x0 + x, y0 + y)
3804
ld hl, (GFX_TEMP1) ; x0
3805
ld de, (GFX_TEMP6) ; x
3812
ld hl, (GFX_TEMP2) ; y0
3813
ld de, (GFX_TEMP7) ; y
3820
; plot(x0 - x, y0 + y)
3821
ld hl, (GFX_TEMP1) ; x0
3822
ld de, (GFX_TEMP6) ; x
3829
ld hl, (GFX_TEMP2) ; y0
3830
ld de, (GFX_TEMP7) ; y
3837
; plot(x0 + x, y0 - y)
3838
ld hl, (GFX_TEMP1) ; x0
3839
ld de, (GFX_TEMP6) ; x
3846
ld hl, (GFX_TEMP2) ; y0
3847
ld de, (GFX_TEMP7) ; y
3854
; plot(x0 - x, y0 - y)
3855
ld hl, (GFX_TEMP1) ; x0
3856
ld de, (GFX_TEMP6) ; x
3863
ld hl, (GFX_TEMP2) ; y0
3864
ld de, (GFX_TEMP7) ; y
3871
; plot(x0 + y, y0 + x)
3872
ld hl, (GFX_TEMP1) ; x0
3873
ld de, (GFX_TEMP7) ; y
3880
ld hl, (GFX_TEMP2) ; y0
3881
ld de, (GFX_TEMP6) ; x
3888
; plot(x0 - y, y0 + x)
3889
ld hl, (GFX_TEMP1) ; x0
3890
ld de, (GFX_TEMP7) ; y
3897
ld hl, (GFX_TEMP2) ; y0
3898
ld de, (GFX_TEMP6) ; x
3905
; plot(x0 + y, y0 - x)
3906
ld hl, (GFX_TEMP1) ; x0
3907
ld de, (GFX_TEMP7) ; y
3914
ld hl, (GFX_TEMP2) ; y0
3915
ld de, (GFX_TEMP6) ; x
3922
; plot(x0 - y, y0 - x)
3923
ld hl, (GFX_TEMP1) ; x0
3924
ld de, (GFX_TEMP7) ; y
3931
ld hl, (GFX_TEMP2) ; y0
3932
ld de, (GFX_TEMP6) ; x
3939
gfxCircle.notFilled.3:
3940
ld hl, (GFX_TEMP6) ; x
3941
ld de, (GFX_TEMP7) ; y
3944
jp c, gfxCircle.notFilled.1 ; while( x < y )
3945
ld bc, (GFX_TEMP1) ; x0
3946
ld de, (GFX_TEMP2) ; y0
3951
call gfxCircle.notFilled
3952
ld hl, (BIOS_BDRATR)
3954
ld hl, (BIOS_FORCLR)
3955
ld (BIOS_BDRATR), hl
3959
ld (BIOS_BDRATR), hl
3965
if defined PAINT or (defined CIRCLE and defined GFX_FAST)
3967
;---------------------------------------------------------------------------------------------------------
3969
; Fill current region delimited by border attribute color changing pixels to foreground color
3970
; in: a = fill type (0 = not symmetric, 1 = symmetric)
3971
;---------------------------------------------------------------------------------------------------------
3975
if not defined GFX_FAST
3977
ld bc, (BIOS_GRPACX)
3979
ld de, (BIOS_GRPACY)
3997
call gfxIsScreenModeMSX2
3998
jr nc, gfxBorderFill.1 ; if MSX2 and screen mode above 3, jump
4002
__call_basic BASIC_SUB_PAINT1
4006
__call_basic BASIC_SUB_PAINT1
4008
;ld ix, BASIC_SUB_PAINT2
4014
ld hl, (BIOS_GRPACY)
4016
call gfxBorderFill.down
4019
ld (BIOS_GRPACY), hl
4021
call gfxBorderFill.up
4023
ld (BIOS_GRPACY), hl
4028
call gfxBorderFill.line
4034
jr nz, gfxBorderFill.down
4038
call gfxBorderFill.line
4044
jr nz, gfxBorderFill.up
4048
ld de, (BIOS_GRPACX)
4051
ld de, 1 ; skip count
4052
__call_bios BIOS_SCANR
4054
;ld (GFX_TEMP2), hl ; pixel count transversed
4057
ld (BIOS_GRPACX), de
4060
;cp 0 ; 0 = not symmetric, 1 = symmetric
4061
;jr z, gfxBorderFill.line.1
4063
;__call_bios BIOS_NSETCX ; HL = fill count
4064
;jr gfxBorderFill.line.2
4065
gfxBorderFill.line.1:
4067
ld de, 0 ; skip count
4068
__call_bios BIOS_SCANL
4069
gfxBorderFill.line.2:
4071
ld (BIOS_GRPACX), de
4075
;---------------------------------------------------------------------------------------------------------
4077
; Fload fill current region changing current pixel color to foreground color
4078
; https://en.wikipedia.org/wiki/Flood_fill
4079
;---------------------------------------------------------------------------------------------------------
4083
ld (GFX_TEMP), a ; replacement-color
4084
call gfxFloadFill.recursive
4087
gfxFloadFill.recursive:
4088
; 1. If target-color is equal to replacement-color, return.
4094
; 2. ElseIf the color of node is not equal to target-color, return.
4100
; 3. Else Set the color of node to replacement-color.
4103
; 4. Perform Flood-fill (one step to the left of node, target-color, replacement-color).
4104
gfxFloadFill.recursive.left:
4106
jr c, gfxFloadFill.recursive.right
4107
call gfxFloadFill.recursive
4110
; Perform Flood-fill (one step to the right of node, target-color, replacement-color).
4111
gfxFloadFill.recursive.right:
4113
jr c, gfxFloadFill.recursive.up
4114
call gfxFloadFill.recursive
4117
; Perform Flood-fill (one step to the up of node, target-color, replacement-color).
4118
gfxFloadFill.recursive.up:
4120
jr c, gfxFloadFill.recursive.down
4121
call gfxFloadFill.recursive
4124
; Perform Flood-fill (one step to the down of node, target-color, replacement-color).
4125
gfxFloadFill.recursive.down:
4128
call gfxFloadFill.recursive
4136
if defined SPRITEMODE
4138
;---------------------------------------------------------------------------------------------------------
4140
; set current sprite mode
4142
; 0: Spritesize is 8 by 8 pixels - default value
4143
; 1: Spritesize is 8 by 8 pixels, magnified to 16 by 16 pixels
4144
; 2: Spritesize is 16 by 16 pixels
4145
; 3: Spritesize is 16 by 16 pixels, magnified to 32 by 32 pixels
4146
; RG1SAV bit 0 = magnify sprite (double size)
4147
; RG1SAV bit 1 = sprite size (0=8 pixels, 1=16 pixels)
4148
;---------------------------------------------------------------------------------------------------------
4151
and 3 ; keeps only bits 0 and 1 from A
4154
ld a, (BIOS_RG1SAV) ; get copy from register #1 of VDP
4155
and 0xFC ; clear bits 0 and 1 from A
4156
or b ; put parameter to A (bits 0 and 1)
4157
ld (BIOS_RG1SAV), a ; restore to register #1 of VDP
4158
ld b, a ; value to write
4159
ld c, 1 ; register number to write
4160
call gfxWRTVDP ; write register to VDP
4161
call gfxCLRSPR ; clear sprites
4163
call gfxGetSpriteSize
4164
jp gfxFillSpriteCollisionTable
4168
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
4170
;---------------------------------------------------------------------------------------------------------
4171
; gfxSetSpriteColorInt
4174
;---------------------------------------------------------------------------------------------------------
4176
gfxSetSpriteColorInt:
4177
ld b, a ; save sprite number
4178
call gfxCALATR ; get sprite attribute table address
4183
;call gfxSetSpriteColor.Adjust
4188
ret c ; if screen mode < 3, do not adjust sprite multicolor
4190
ld a, b ; recover sprite number
4191
call gfxGetSpriteColorTable
4194
;call gfxSetSpriteColor.Adjust
4195
ld b, 16 ; array of 16 bytes
4197
gfxSetSpriteColorInt.1:
4202
djnz gfxSetSpriteColorInt.1
4205
;gfxSetSpriteColor.Adjust:
4215
;---------------------------------------------------------------------------------------------------------
4216
; gfxSetSpriteColorStr
4218
; DE = address to color byte array
4219
; BC = color byte array size
4220
;---------------------------------------------------------------------------------------------------------
4222
gfxSetSpriteColorStr:
4223
ld b, a ; save sprite number
4226
call gfxCALATR ; get sprite attribute table
4230
ld a, c ; byte array zero length?
4238
;call gfxSetSpriteColor.Adjust
4243
ret c ; if screen mode < 3, do not adjust sprite mode 2
4245
ld a, b ; recover sprite number
4246
call gfxGetSpriteColorTable
4248
ld b, 16 ; array of 16 bytes (color table)
4249
ld a, c ; size of color array
4251
pop iy ; save array start
4253
gfxSetSpriteColorStr.1:
4256
;call gfxSetSpriteColor.Adjust
4262
jr nz, gfxSetSpriteColorStr.2
4263
ld a, c ; recover array size
4265
pop de ; recover array start
4267
gfxSetSpriteColorStr.2:
4268
djnz gfxSetSpriteColorStr.1
4273
;---------------------------------------------------------------------------------------------------------
4274
; gfxGetSpriteColorTable
4276
; HL = address to color table
4277
;---------------------------------------------------------------------------------------------------------
4279
gfxGetSpriteColorTable:
4283
ld l, a ; recover sprite number
4287
add hl, hl ; multiply by 16 (shift left 4)
4290
call gfxCALATR ; get sprite attribute table address
4295
sbc hl, de ; address of color table from sprite multicolor
4302
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
4304
;---------------------------------------------------------------------------------------------------------
4308
;---------------------------------------------------------------------------------------------------------
4312
call gfxCALATR ; get sprite attribute table address
4321
;---------------------------------------------------------------------------------------------------------
4322
; gfxSpriteStepCheck
4324
;---------------------------------------------------------------------------------------------------------
4331
ld de, (GFX_SPRITE_SIZE_DAT)
4332
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
4333
and 7 ; clear touched and collided flags
4334
ld (GFX_SPRITE_FLAGS), a
4337
jr z, gfxSpriteStepCheck.corners
4339
gfxSpriteStepCheck.limits:
4342
cp b ; jump if x > max_x?
4343
jr c, gfxSpriteStepCheck.limits.touched
4347
cp c ; jump if y > max_y?
4348
jr c, gfxSpriteStepCheck.limits.touched
4350
jr gfxSpriteStepCheck.corners
4352
gfxSpriteStepCheck.limits.touched:
4353
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
4354
or 8 ; set limit touched flag
4355
ld (GFX_SPRITE_FLAGS), a
4357
gfxSpriteStepCheck.corners:
4358
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
4359
and 2+4 ; check walls or hotspots
4360
jr z, gfxSpriteStepCheck.end
4363
call gfxSpriteStepCheck.corner
4365
ld a, (GFX_SPRITE_SIZE_DAT)
4368
call gfxSpriteStepCheck.corner
4370
ld a, (GFX_SPRITE_SIZE_DAT)
4373
call gfxSpriteStepCheck.corner
4376
ld a, (GFX_SPRITE_SIZE_DAT)
4379
call gfxSpriteStepCheck.corner
4381
gfxSpriteStepCheck.end:
4387
gfxSpriteStepCheck.corner:
4388
call gfxGetTileFromXY
4389
ld d, a ; tile to be searched
4391
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
4393
call nz, gfxSpriteStepCheck.walls
4395
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
4397
call nz, gfxSpriteStepCheck.hotspots
4400
gfxSpriteStepCheck.walls:
4401
ld hl, (GFX_SPRITE_WALLS)
4402
ld e, 16 ; bits 0=chk limits, 1=chk walls, 2=chk hotspots, 3=limit touched, 4=wall touched, 5=hotspot touched, 6=collided
4403
jp gfxSpriteStepCheck.search
4405
gfxSpriteStepCheck.hotspots:
4406
ld hl, (GFX_SPRITE_HOTSPOTS)
4407
ld e, 32 ; bits 0=chk limits, 1=chk walls, 2=chk hotspots, 3=limit touched, 4=wall touched, 5=hotspot touched, 6=collided
4408
call gfxSpriteStepCheck.search
4410
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
4415
ld (GFX_SPRITE_HOTSPOT_TILE), a
4418
; d = tile, hl = search table, e = flag
4419
gfxSpriteStepCheck.search:
4424
ld a, d ; search for this tile
4430
cpir ; inc HL searching for A until BC=0 (Z flag settled if found)
4434
gfxSpriteStepCheck.search.found:
4435
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
4436
or e ; set touched flag
4437
ld (GFX_SPRITE_FLAGS), a
4452
call gfxGetScreenTile ; b = y, c = x, a = tile
4458
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
4460
;---------------------------------------------------------------------------------------------------------
4461
; gfxSetSpritePattern
4463
; BC = pattern number
4464
;---------------------------------------------------------------------------------------------------------
4466
gfxSetSpritePattern:
4468
call gfxCALATR ; get sprite attribute table address
4472
ld a, (BIOS_RG1SAV) ; bit 0 = double size, bit 1 = sprite size (0=8 pixels, 1=16 pixels)
4474
jr z, gfxSetSpritePattern.1
4477
gfxSetSpritePattern.1:
4478
ld a, c ; pattern number
4486
;---------------------------------------------------------------------------------------------------------
4488
; HL = point to sprite data as a string of 8 or 32 characters according the sprites size (8x8 or 16x16)
4490
;---------------------------------------------------------------------------------------------------------
4495
call gfxCALPAT ; get sprite pattern data address
4497
call gfxGSPSIZ ; return in 'a' sprite default size
4501
jr z, gfxSetSpriteData.1
4502
jr nc, gfxSetSpriteData.1
4516
if defined GFX_SPRITES
4518
;---------------------------------------------------------------------------------------------------------
4520
; initialises all sprites
4521
;---------------------------------------------------------------------------------------------------------
4527
;---------------------------------------------------------------------------------------------------------
4529
; set sprite default x, y, pattern and color
4531
;---------------------------------------------------------------------------------------------------------
4536
ld a, (BIOS_GRPACY) ; y
4539
ld a, (BIOS_GRPACX) ; x
4545
ld a, (BIOS_FORCLR) ; color
4551
if defined EXIST_DATA_SET
4553
;---------------------------------------------------------------------------------------------------------
4555
;---------------------------------------------------------------------------------------------------------
4564
;---------------------------------------------------------------------------------------------------------
4565
; gfxClearTileScreen
4566
;---------------------------------------------------------------------------------------------------------
4571
ld hl, (BIOS_GRPNAM)
4575
call gfxSetTileDefaultColor
4577
call gfxSetTileDefaultColor
4579
jp gfxSetTileDefaultColor
4581
gfxSetTileDefaultColor
4582
call gfxGetTileColorAddr
4584
call gfxGetTileDefaultColor
4588
gfxGetTileDefaultColor:
4601
; HL = tile color pointer
4602
; BC = tile color size
4605
;---------------------------------------------------------------------------------------------------------
4608
; HL = tile data pointer
4609
; BC = tile data size
4611
; A = flip (0=no, 1=yes)
4612
;---------------------------------------------------------------------------------------------------------
4616
jr nz, gfxSetTileDataFlip
4618
gfxSetTileDataNoFlip:
4619
call gfxGetTileDataAddr
4623
call gfxGetTileDataAddr
4625
gfxSetTileDataFlip.Loop:
4634
jr nz, gfxSetTileDataFlip.Loop
4637
; in de = tile number
4638
; out de = tile number address
4644
add hl, hl ; tile number * 8
4645
ld de, (BIOS_GRPCGP)
4651
;---------------------------------------------------------------------------------------------------------
4654
; HL = tile color pointer
4655
; BC = tile color size
4657
;---------------------------------------------------------------------------------------------------------
4660
call gfxGetTileColorAddr
4663
; in de = tile number
4664
; out de = tile number address
4665
gfxGetTileColorAddr:
4670
add hl, hl ; tile number * 8
4671
ld de, (BIOS_GRPCOL)
4677
;---------------------------------------------------------------------------------------------------------
4679
; set screen tile at x,y
4683
;---------------------------------------------------------------------------------------------------------
4695
; ld l, b ; slow y * 32
4712
ld de, (BIOS_GRPNAM)
4719
if defined gfxGetTileFromXY or defined EXIST_DATA_SET
4721
;---------------------------------------------------------------------------------------------------------
4723
; get screen tile at x,y
4727
;---------------------------------------------------------------------------------------------------------
4749
ld de, (BIOS_GRPNAM)
4755
;---------------------------------------------------------------------------------------------------------
4756
; Sprite collision table routines
4757
;---------------------------------------------------------------------------------------------------------
4759
gfxInitSpriteCollisionTable:
4762
ld (GFX_SPRITE_COLLISION), ix
4765
; copy sprite attribute table to ram
4766
gfxFillSpriteCollisionTable:
4767
ld hl, (BIOS_ATRBAS) ; source: attribute table
4768
ld de, (GFX_SPRITE_COLLISION) ; dest: ram
4769
ld bc, 128 ; 32*4 = size of attribute table
4772
; pre-calculate each sprite width
4773
gfxCalculateSpriteCollisionTable:
4774
ld ix, (GFX_SPRITE_COLLISION) ; start of sprites attributes
4775
ld b, 32 ; sprite count
4777
gfxCalculateSpriteCollisionTable.start:
4778
ld a, (GFX_SPRITE_SIZE_DAT) ; sprite size
4780
ld d, 208 ; Y no-display flag
4784
cp 3 ; above screen 3?
4785
jr c, gfxCalculateSpriteCollisionTable.next
4786
ld d, 216 ; Y no-display flag
4788
gfxCalculateSpriteCollisionTable.next:
4789
; test IC flag (no collision) in color table
4790
; test EC flag (early clock, shift 32 dots to the left) in color table
4791
; set x1 = x + size, y1 = y + size
4793
cp d ; test if sprite will not be displayed
4806
djnz gfxCalculateSpriteCollisionTable.next
4809
; BC = sprite number to check
4810
gfxUpdateSpriteCollisionTable:
4818
ld hl, (GFX_SPRITE_COLLISION) ; dest: ram
4821
ld hl, (BIOS_ATRBAS) ; source: attribute table
4823
ld bc, 4 ; 4 = size of attribute table to 1 sprite]
4827
ld b, 1 ; sprite count
4829
call gfxCalculateSpriteCollisionTable.start
4832
ld a, (GFX_SPRITE_FLAGS)
4833
and 0xBF ; clear collision flag
4834
ld (GFX_SPRITE_FLAGS), a
4836
ld a, (BIOS_STATFL) ; verify if collision occurred
4839
jr gfxCheckSpriteCollisionTable.start
4841
; BC = sprite number to check
4842
gfxCheckSpriteCollisionTable:
4843
; get target sprite address (iy)
4847
ld de, (GFX_SPRITE_COLLISION)
4854
gfxCheckSpriteCollisionTable.start:
4855
; start test against others sprites
4856
ld ix, (GFX_SPRITE_COLLISION)
4858
ld d, 208 ; Y no-display flag
4862
cp 3 ; above screen 3?
4863
jr c, gfxCheckSpriteCollisionTable.test
4864
ld d, 216 ; Y no-display flag
4866
gfxCheckSpriteCollisionTable.test:
4867
; skip target sprite
4870
jr z, gfxCheckSpriteCollisionTable.next
4872
; test if x1 > nx and x < nx1 and y1 > ny and y < ny1
4874
cp d ; test if sprite will not be displayed
4875
ret z ; return false
4878
jr nc, gfxCheckSpriteCollisionTable.next
4882
jr nc, gfxCheckSpriteCollisionTable.next
4886
jr nc, gfxCheckSpriteCollisionTable.next
4890
jr nc, gfxCheckSpriteCollisionTable.next
4892
; if so, save collider sprite
4894
ld (GFX_SPRITE_COLLIDER), a
4896
ld a, (GFX_SPRITE_FLAGS)
4897
or 0x40 ; set collision flag
4898
ld (GFX_SPRITE_FLAGS), a
4902
gfxCheckSpriteCollisionTable.next:
4910
ret z ; return false
4911
jr gfxCheckSpriteCollisionTable.test
4915
;---------------------------------------------------------------------------------------------------------
4916
; VDP / VRAM support routines
4917
;---------------------------------------------------------------------------------------------------------
4921
; c = register number
4922
; a = register number
4925
ret nz ; is negative? read only
4927
ret z ; is register 8? then status register 0 (read only)
4928
jr nc, gfxWRTVDP.1 ; is > 8? then control registers numbers added 1
4943
;jp nz, BIOS_NWRVDP ; msx 2
4945
;jp nz, BIOS_NWRVDP ; msx 2
4946
jp BIOS_WRTVDP ; msx 1
4949
; in a = register number
4953
jr nz, gfxRDVDP.1 ; is negative? then status register 1 to 9
4955
jr z, gfxRDVDP.2 ; is register 8? then status register 0
4957
jr nc, gfxRDVDP.3 ; is >= 9? then control registers numbers added 1
4958
ld hl, BIOS_RG0SAV ; else is correct control registers numbers
4970
jp BIOS_NRDVDP ;BIOS_VDPSTA
4977
ld hl, BIOS_RG8SAV-9
4985
; in: A=Data byte, BC=Length, HL=VRAM address
4994
; in: A=Sprite pattern number
4995
; out: HL=Sprite pattern address
5005
; in: A=Sprite number
5006
; out: HL=Sprite attribute address
5016
; out: A=Bytes in sprite pattern (8 or 32)
5036
; in: BC=Length, dest DE=VRAM address, source HL=RAM address
5041
; in: BC=Length, dest DE=RAM address, source HL=VRAM address
5068
; 8 bytes / 206 cycles
5069
; http://www.retroprogramming.com/2014/01/fast-z80-bit-reversal.html
5076
djnz gfxReverseA.loop
5081
;---------------------------------------------------------------------------------------------------------
5083
;---------------------------------------------------------------------------------------------------------
5092
RET_MATH_LIB: call COPY_TO.TMP_DAC
5098
MATH_DECADD: ld ix, addSingle
5103
if defined MATH.SUB or defined MATH.NEG
5105
MATH_DECSUB: ld ix, subSingle
5110
if defined MATH.MULT
5112
MATH_DECMUL: ld ix, mulSingle
5119
MATH_DECDIV: ld ix, divSingle
5127
MATH_SNGEXP: ld ix, powSingle
5134
MATH_COS: ld ix, cosSingle
5141
MATH_SIN: ld ix, sinSingle
5148
MATH_TAN: ld ix, tanSingle
5155
MATH_ATN: ld ix, atanSingle
5162
MATH_SQR: ld ix, sqrtSingle
5169
MATH_LOG: ld ix, lnSingle
5176
MATH_EXP: ld ix, expSingle
5183
MATH_ABSFN: ld ix, absSingle
5188
if defined MATH.SEED or defined MATH.NEG
5190
MATH_NEG: ld ix, negSingle
5197
MATH_SGN: ld ix, sgnSingle
5202
if defined RND or defined MATH.SEED
5204
MATH_RND: ld ix, randSingle
5209
MATH_FRCINT: ld hl, BASIC_DAC
5222
ld (BASIC_VALTYP), a
5225
MATH_FRCDBL: ; same as MATH_FRCSGL
5226
MATH_FRCSGL: ld hl, BASIC_DAC+2 ; input address
5227
ld bc, BASIC_DAC ; output address
5230
ld (BASIC_VALTYP), a
5233
MATH_ICOMP: ld a, h ; cp hl, de (alternative to bios DCOMPR)
5235
jr nz, MATH_ICOMP.NE.HIGH
5238
jr nz, MATH_ICOMP.NE.LOW
5240
MATH_ICOMP.NE.HIGH: jr c, MATH_ICOMP.GT.HIGH
5242
jr nz, MATH_DCOMP.GT
5244
MATH_ICOMP.GT.HIGH: bit 7, d
5247
MATH_ICOMP.NE.LOW: jr c, MATH_DCOMP.GT
5250
MATH_XDCOMP: ; same as MATH_DCOMP
5251
MATH_DCOMP: ld ix, cmpSingle
5255
MATH_DCOMP.GT: ld a, 0xFF ; DAC > ARG
5257
MATH_DCOMP.EQ: ld a, 0 ; DAC = ARG
5259
MATH_DCOMP.LT: ld a, 1 ; DAC < ARG
5262
if defined CAST_STR_TO.VAL
5264
MATH_FIN: ; HL has the source string
5265
ld a, (BASIC_VALTYP)
5266
cp 2 ; test if integer
5268
ld hl, (BASIC_DAC+2)
5273
MATH_FIN.1: ld BC, BASIC_DAC
5279
if defined CAST_INT_TO.STR
5281
MATH_FOUT: ld a, (BASIC_VALTYP)
5282
cp 2 ; test if integer
5284
ld hl, (BASIC_DAC+2)
5289
MATH_FOUT.1: ld hl, BASIC_DAC
5300
;---------------------------------------------------------------------------------------------------------
5302
; Copyright 2018 Zeda A.K. Thomas
5303
;---------------------------------------------------------------------------------------------------------
5305
; https://github.com/Zeda/z80float
5306
; https://www.omnimaga.org/asm-language/(z80)-floating-point-routines/
5307
; https://en.wikipedia.org/wiki/Single-precision_floating-point_format
5308
;---------------------------------------------------------------------------------------------------------
5310
; HL points to the first operand
5311
; DE points to the second operand (if needed)
5312
; IX points to the third operand (if needed, rare)
5313
; BC points to where the result should be output
5314
; Floats are stored by a little-endian 24-bit mantissa. However, the highest bit
5315
; is taken as implicitly 1, so we replace it as a sign bit. Next comes an 8-bit
5316
; exponent biased by +128.
5317
;---------------------------------------------------------------------------------------------------------
5318
; Adapted to MSXBas2Asm by Amaury Carvalho, 2019
5319
;---------------------------------------------------------------------------------------------------------
5321
;---------------------------------------------------------------------------------------------------------
5323
;---------------------------------------------------------------------------------------------------------
5325
BASIC_HOLD8: equ 0xF806 ; 48 Work area for decimal multiplications.
5326
BASIC_HOLD2: equ 0xF836 ; 8 Work area in the execution of numerical operators.
5327
BASIC_HOLD: equ 0xF83E ; 8 Work area in the execution of numerical operators.
5328
scrap: equ BASIC_HOLD8
5329
seed0: equ BASIC_RNDX
5330
seed1: equ seed0 + 4
5331
var48: equ scrap + 4
5334
addend2: equ scrap+7 ;4 bytes
5335
var_x: equ BASIC_HOLD8 + 4 ;4 bytes
5336
var_y: equ var_x + 4 ;4 bytes
5337
var_z: equ var_y + 4 ;4 bytes
5338
var_a: equ var_z + 4 ;4 bytes
5339
var_b: equ var_a + 4 ;4 bytes
5340
var_c: equ var_b + 4 ;4 bytes
5341
temp: equ var_c + 4 ;4 bytes
5342
temp1: equ temp + 4 ;4 bytes
5343
temp2: equ temp1 + 4 ;4 bytes
5344
temp3: equ temp2 + 4 ;4 bytes
5346
pow10exp_single: equ scrap+9
5347
strout_single: equ 0xF750 ; PARM2 - BASIC_BUF ;pow10exp_single+2
5349
;---------------------------------------------------------------------------------------------------------
5351
;---------------------------------------------------------------------------------------------------------
5353
;;Still need to tend to special cases
5421
pop hl ;bigger float
5553
;;Need to adjust sign flag
5576
;;How many push/pops are needed?
5584
;;How many push/pops are needed?
5590
;;How many push/pops are needed?
5591
;;Return bigger number
5598
;---------------------------------------------------------------------------------------------------------
5600
;---------------------------------------------------------------------------------------------------------
5623
jp addInject ;jumps in to the addSingle routine
5625
;---------------------------------------------------------------------------------------------------------
5627
;---------------------------------------------------------------------------------------------------------
5630
;Inputs: HL points to float1, DE points to float2, BC points to where the result is copied
5631
;Outputs: float1*float2 is stored to (BC)
5632
;573+mul24+{0,35}+{0,30}
5635
;avg: 2055.13839751681cc
5661
;;return float in CHLB
5671
jr z,mulSingle_case0
5683
;jr z,mulSingle_case1
5687
jp z,mulSingle_case1
5692
rra ; |Lots of help from Runer112 and
5693
adc a,a ; |calc84maniac for optimizing
5694
jp po,bad ; |this exponent check.
5703
call mul24 ;BDE*CHL->HLBCDE, returns sign info
5760
;special*x = special
5781
;basically, if b|c has bit 5 set, return NaN
5814
;;avg :1464.9033203125cc (1464+925/1024)
5817
;avg: 1449.63839751681cc
5858
;---------------------------------------------------------------------------------------------------------
5860
;---------------------------------------------------------------------------------------------------------
5863
;;HL points to numerator
5864
;;DE points to denominator
5865
;;BC points to where the quotient gets written
5867
divSingle_no_pushpop:
5873
xor (hl) ; |Get sign of output
5880
ex de,hl ; |Get exponent
5987
call divsub1 ;34 or 66
6005
;34cc or 66cc or 93cc
6020
;---------------------------------------------------------------------------------------------------------
6022
; https://www.geeksforgeeks.org/write-a-c-program-to-calculate-powxn/
6023
; https://stackoverflow.com/questions/3518973/floating-point-exponentiation-without-power-function
6024
;---------------------------------------------------------------------------------------------------------
6025
;double mypow( double base, double power, double precision )
6027
; if ( power < 0 ) return 1 / mypow( base, -power, precision );
6028
; else if ( power >= 1 ) return base * mypow( base, power-1, precision );
6029
; else if ( precision >= 1 ) {
6030
; if( base >= 0 ) return sqrt( base );
6031
; else return sqrt( -base );
6032
; } else return sqrt( mypow( base, power*2, precision*2 ) );
6035
if defined MATH.POW or defined MATH_EXP or defined MATH_LOG or defined MATH_LN
6041
;;BC points to output
6045
ld bc, var_y ; power
6050
ld hl, const_precision
6051
ld bc, var_a ; precision
6054
ld bc, var_z ; result
6063
; if ( power < 0 ) return 1 / mypow( base, -power, precision );
6069
; else if ( power >= 1 ) return base * mypow( base, power-1, precision );
6075
; else if ( precision >= 1 ) {
6076
; if( base >= 0 ) return sqrt( base );
6077
; else return sqrt( -base );
6083
; } else return sqrt( mypow( base, power*2, precision*2 ) );
6108
; return 1 / mypow( base, -power, precision );
6127
; return base * mypow( base, power-1, precision );
6146
; if( base >= 0 ) return sqrt( base );
6147
; else return sqrt( -base );
6173
; 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)))))
6174
;Please note that usually I like to reduce to [-.5,.5] as the extra overhead is usually worth it.
6175
;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.
6178
;x-=int(x) ;leaves x in [0,1)
6180
;;if x==inf -> out==inf
6181
;;if x==-inf -> out==0
6182
;;if x==NAN -> out==NAN
6189
push af ;keep track of sign
6199
jr c,_pow_1 ;int(x)=0
6212
jr nz,exp_normalized
6223
jr exp_normalized ;.db $11 ;start of `ld de,**`
6230
jr comp_exp ;.db $06 ;start of 'ld b,*` just to eat the next byte
6239
jp z,exp_underflow+1
6240
;perform 1-(var48+10)--> var48+10
6248
;our 'x' is at var48+10
6249
;our `temp` is at var48+6 so as not to cause issues with mulSingle)
6250
;uses 14 bytes of RAM
6292
;-inf -> +0 because lim approaches 0 from the right
6314
;-inf -> +0 because lim approaches 0 from the right
6316
sbc a,a ;FF if should be 0,
6331
;---------------------------------------------------------------------------------------------------------
6333
;---------------------------------------------------------------------------------------------------------
6335
if defined MATH_SQR or defined MATH_EXP
6337
;Uses 3 bytes at scrap
6339
;552+{0,19}+8{0,3+{0,3}}+pushpop+sqrtHLIX
6358
jp z,sqrtSingle_special
6361
push af ;new exponent
6371
;AHL is the new remainder
6372
;Need to divide by 2, then divide by the 16-bit (var_x+4)
6376
;We are just going to approximate it
6458
;Output: DE is the sqrt, AHL is the remainder
6459
;speed: 754+{0,1}+6{0,6}+{0,3+{0,18}}+{0,38}+sqrtHL
6483
jr _15a ;.db $FE ;start of `cp *`
6497
jr _16a ;.db $FE ;start of `cp *`
6511
jr _17a ;.db $FE ;start of `cp *`
6525
jr _18a ;.db $FE ;start of `cp *`
6529
;Now we have four more iterations
6530
;The first two are no problem
6542
jr _19a ;.db $FE ;start of `cp *`
6556
jr _20a ;.db $FE ;start of `cp *`
6561
;On the next iteration, HL might temporarily overflow by 1 bit
6563
rl d ;sla e \ rl d \ inc e
6567
adc hl,hl ;This might overflow!
6568
jr c,sqrt32_iter15_br0
6581
;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
6584
ld b,a ;either 0x00 or 0x80
6605
;returns A as the sqrt, HL as the remainder, D = 0
6619
jr _23a ;.db $01 ;start of ld bc,** which is 10cc to skip the next two bytes.
6630
jr _24a ;.db $01 ;start of ld bc,** which is 10cc to skip the next two bytes.
6641
dec d ;this resets the low bit of D, so `srl d` resets carry.
6642
jr _25a ;.db $06 ;start of ld b,* which is 7cc to skip the next byte.
6664
jr _27a ;.db $01 ;start of ld bc,** which is 10cc to skip the next two bytes.
6677
jr _28a ;.db $01 ;start of ld bc,** which is 10cc to skip the next two bytes.
6699
;---------------------------------------------------------------------------------------------------------
6701
;---------------------------------------------------------------------------------------------------------
6703
if defined MATH_LOG or defined MATH_LN
6706
; x / (1 + x/(2-x+4x/(3-2x+9x/(4-3x+16x/(5-4x)))))
6707
; a * x ^ (1/a) - a, where a = 100
6710
ld de, const_100_inv
6712
call powSingle ; temp = x ^ (1/100)
6716
call mulSingle ; temp1 = temp * 100
6719
call subSingle ; bc = temp1 - 100
6724
;---------------------------------------------------------------------------------------------------------
6726
;---------------------------------------------------------------------------------------------------------
6743
;---------------------------------------------------------------------------------------------------------
6745
;---------------------------------------------------------------------------------------------------------
6752
;;BC points to the output
6757
;;DE points to lg(y), HL points to x, BC points to output
6766
;---------------------------------------------------------------------------------------------------------
6768
; https://en.wikipedia.org/wiki/List_of_trigonometric_identities
6769
; https://en.wikipedia.org/wiki/Taylor_series#Trigonometric_functions
6770
; https://cs.stackexchange.com/questions/89245/how-approximate-sine-using-taylor-series
6771
; https://stackoverflow.com/questions/42217069/approximating-sinex-with-a-taylor-series-in-c-and-having-a-lot-of-problems
6772
;---------------------------------------------------------------------------------------------------------
6774
if defined MATH_SIN or defined MATH_TAN or defined MATH_COS
6777
; taylor: x - x^3/6 + x^5/120 - x^7/5040
6778
; x(1 - x^2(1/6 - x^2(1/120 - x^2/5040)) )
6780
; var_b = round( x / (2*PI), 0 )
6781
; var_c = x - var_b*2*PI
6782
; temp1 = if( var_c >= 0, var_c, var_c + 2*PI )
6783
; temp2 = if( temp1 > PI, temp1 - PI, temp1 )
6784
; var_a = if( temp2 > PI/2, PI - temp2, temp2 ) * if( temp1 > PI, -1, 1 )
6791
call copySingle ; return 0
6795
call trigRangeReductionSinCos
6800
call mulSingle ; var_b = var_a * var_a
6804
call mulSingle ; temp = x^2/5040
6808
call subSingle ; temp1 = 1/120 - temp
6812
call mulSingle ; temp = x^2 * temp1
6816
call subSingle ; temp1 = 1/6 - temp
6820
call mulSingle ; temp = x^2 * temp1
6824
call subSingle ; temp1 = 1 - temp
6828
call mulSingle ; return x * temp1
6831
trigRangeReductionSinCos:
6834
; var_b = round( x / (2*PI), 0 )
6842
; var_c = x - var_b*2*PI
6846
call mulSingle ; temp = var_b*2*PI
6850
call subSingle ; var_c = x - temp
6851
; temp1 = if( var_c >= 0, var_c, var_c + 2*PI )
6855
jr nc, trigRangeReductionSinCos.else.2
6858
call copySingle ; temp1 = var_c
6859
jr trigRangeReductionSinCos.endif.2
6860
trigRangeReductionSinCos.else.2:
6864
call addSingle ; temp1 = var_c + 2*PI
6865
trigRangeReductionSinCos.endif.2:
6866
; temp2 = if( temp1 > PI, temp1 - PI, temp1 )
6870
jr c, trigRangeReductionSinCos.else.3
6871
jr z, trigRangeReductionSinCos.else.3
6875
call subSingle ; temp2
6876
jr trigRangeReductionSinCos.endif.3
6877
trigRangeReductionSinCos.else.3:
6880
call copySingle ; temp2 = temp1
6881
trigRangeReductionSinCos.endif.3:
6882
; var_a = if( temp2 > PI/2, PI - temp2, temp2 ) * if( temp1 > PI, -1, 1 )
6883
ld hl, const_half_pi
6886
jr c, trigRangeReductionSinCos.else.4
6887
jr z, trigRangeReductionSinCos.else.4
6891
call subSingle ; var_a
6892
jr trigRangeReductionSinCos.endif.4
6893
trigRangeReductionSinCos.else.4:
6896
call copySingle ; var_a = temp2
6897
trigRangeReductionSinCos.endif.4:
6898
; if( temp > PI, -1, 1 )
6902
jr nc, trigRangeReductionSinCos.endif.5
6906
ld (ix+2), a ; turn var_a to negative
6907
trigRangeReductionSinCos.endif.5:
6913
;---------------------------------------------------------------------------------------------------------
6915
;---------------------------------------------------------------------------------------------------------
6917
if defined MATH_COS or defined MATH_TAN
6920
; taylor: 1 - x^2/2 + x^4/24 - x^6/720
6921
; 1 - x^2(1/2 - x^2(1/24 - x^2/720) )
6922
; reduction: same as sin
6931
call copySingle ; return 1
6935
; 1 - x^2(1/2 - x^2(1/24 - x^2/720) )
6936
call trigRangeReductionSinCos
6941
call mulSingle ; var_b = var_a * var_a
6945
call mulSingle ; temp = x^2/720
6949
call subSingle ; temp1 = 1/24 - temp
6953
call mulSingle ; temp = x^2 * temp1
6957
call subSingle ; temp1 = 1/2 - temp
6961
call mulSingle ; temp = x^2 * temp1
6965
call subSingle ; temp1 = 1 - temp
6967
; temp3 = abs(var_c)
6968
; temp1 = temp1 * if( temp3 >= PI/2, -1, 1 ) ==> cos sign
6975
ld (ix+2), a ; temp3 = abs(var_c)
6977
ld de, const_half_pi
6978
call cmpSingle ; if temp3 >= PI/2 then temp1 = -temp1
6979
jr nc, cosSingle.endif.1
6983
ld (ix+2), a ; temp1 = -temp1
6987
call copySingle ; return temp1
6992
;---------------------------------------------------------------------------------------------------------
6994
;---------------------------------------------------------------------------------------------------------
7015
;---------------------------------------------------------------------------------------------------------
7017
;---------------------------------------------------------------------------------------------------------
7022
;taylor: x/(1 + x^2/(3 + (2*x)^2/(5 + (3*x)^2/(7+(4*x)^2/9) ) ) )
7023
; x < -1: atan - PI/2
7024
; x >= 1: PI/2 - atan
7025
;reduction: abs(X) > 1 : Y = 1 / X
7026
; abs(X) <= 1: Y = X
7035
call copySingle ; return 0
7039
;x/(1 + x^2/(3 + (2*x)^2/(5 + (3*x)^2/(7+(4*x)^2/9) ) ) )
7040
call trigRangeReductionAtan
7046
call mulSingle ; var_b = var_a * var_a
7050
call mulSingle ; temp = (4*x)^2
7054
call divSingle ; temp1 = temp/9
7058
call addSingle ; temp = 7 + temp1
7062
call mulSingle ; temp1 = var_b * 9
7066
call divSingle ; temp2 = temp1 / temp
7070
call addSingle ; temp = 5 + temp2
7074
call mulSingle ; temp1 = var_b * 4
7078
call divSingle ; temp2 = temp1 / temp
7082
call addSingle ; temp = 3 + temp2
7086
call divSingle ; temp2 = var_b / temp
7090
call addSingle ; temp = 1 + temp2
7094
call divSingle ; temp2 = var_a / temp
7096
; x >= 1: PI/2 - atan
7100
ld hl, const_half_pi
7107
; x < -1: atan - PI/2
7118
ld de, const_half_pi
7127
call copySingle ; return temp2
7130
trigRangeReductionAtan:
7131
;reduction: abs(X) > 1 : Y = 1 / X
7132
; abs(X) <= 1: Y = X
7141
ld (ix+2), a ; abs(x)
7145
jr nc, trigRangeReductionAtan.1
7151
jr trigRangeReductionAtan.2
7152
trigRangeReductionAtan.1:
7157
trigRangeReductionAtan.2:
7161
jr c, trigRangeReductionAtan.3
7165
ld (ix+2), a ; y = -y
7166
trigRangeReductionAtan.3:
7171
if defined MATH_SIN or defined MATH_TAN or defined MATH_COS
7173
;---------------------------------------------------------------------------------------------------------
7175
;---------------------------------------------------------------------------------------------------------
7189
;---------------------------------------------------------------------------------------------------------
7191
;---------------------------------------------------------------------------------------------------------
7260
if defined MATH_ABSFN
7262
;---------------------------------------------------------------------------------------------------------
7264
;---------------------------------------------------------------------------------------------------------
7267
;;HL points to the float
7268
;;BC points to where to output the result
7287
;---------------------------------------------------------------------------------------------------------
7289
;---------------------------------------------------------------------------------------------------------
7292
;;HL points to the float
7293
;;BC points to where to output the result
7298
if defined powSingle or defined sgnSingle or defined MATH_NEG
7300
;---------------------------------------------------------------------------------------------------------
7302
;---------------------------------------------------------------------------------------------------------
7305
;;HL points to the float
7306
;;BC points to where to output the result
7312
jr nz, negSingle.test.sign
7315
jr nz, negSingle.test.sign
7318
jr nz, negSingle.test.sign
7321
jr nz, negSingle.test.sign
7332
negSingle.test.sign:
7335
jr z, negSingle.positive
7339
call negSingle.positive
7358
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
7360
;---------------------------------------------------------------------------------------------------------
7362
;---------------------------------------------------------------------------------------------------------
7365
;Input: HL points to float1, DE points to float2
7367
; float1 >= float2 : nc
7368
; float1 < float2 : c,nz
7369
; float1 == float2 : z
7370
; There is a margin of error allowed in the lower 2 bits of the mantissa.
7372
;Currently fails when both numbers have magnitude less than about 2^-106
7407
ld a,(scrap+3) ;new power
7408
pop bc ;B is old power
7418
or 1 ;not equal, so reset z flag
7419
rla ;if negative, float1<float2, setting c flag as wanted, else nc.
7429
;---------------------------------------------------------------------------------------------------------
7431
;---------------------------------------------------------------------------------------------------------
7434
;Stores a pseudo-random number on [0,1)
7435
;it won't produce values on (0,2^-23)
7444
;DEHL is the mantissa, B is the exponent
7460
;If we needed to shift more than 8 bits, we'll load in more random data
7465
jp nc,rand_no_more_rand_data
7473
rand_no_more_rand_data:
7492
;;Tested and passes all CAcert tests
7493
;;Uses a very simple 32-bit LCG and 32-bit LFSR
7494
;;it has a period of 18,446,744,069,414,584,320
7495
;;roughly 18.4 quintillion.
7496
;;LFSR taps: 0,2,6,7 = 11000101
7498
;;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.
7499
;Uses 64 bits of state
7535
if defined MATH_FOUT
7537
;---------------------------------------------------------------------------------------------------------
7539
; in HL = Single address
7540
; BC = String address
7541
; out A = String size
7542
; http://0x80.pl/notesen/2015-12-29-float-to-string.html
7543
; http://0x80.pl/articles/convert-float-to-integer.html
7544
;---------------------------------------------------------------------------------------------------------
7558
; Move the float to scrap
7562
; Make the float negative, write a '-' if already negative
7571
ld a,'-' ; write '-' simbol
7579
; Check if the exponent field is 0 (a special value)
7586
; We should write '0' next. When rounding 9.999999... for example, not padding with a 0 will return '.' instead of '1.'
7594
; Now we need to perform signed (A-128)*77 (approximation of exponent*log10(2))
7602
ld (pow10exp_single),a ;The base-10 exponent
7606
ld de,pow10LUT ;get the table of 10^-(2^k)
7608
ld hl, pow10exp_single
7610
call singletostr_mul
7611
call singletostr_mul
7612
call singletostr_mul
7613
call singletostr_mul
7614
call singletostr_mul
7615
call singletostr_mul
7616
;now the number is pretty close to a nice value
7618
; If it is less than 1, multiply by 10
7623
;ld hl,scrap ;Since singletostr_mul returns BC = scrap, can do this cheaper
7629
ld hl,pow10exp_single
7635
; Convert to a fixed-point number !
7649
;We need to get 7 digits
7651
pop hl ;Points to the string
7653
;The first digit can be as large as 20, so it'll actually be two digits
7657
;Increment the exponent :)
7658
ld de,(pow10exp_single-1)
7660
ld (pow10exp_single-1),de
7669
; Get the remaining digits.
7676
call singletostrmul10
7681
;Save the pointer to the end of the string
7688
jr c,rounding_done_single
7689
jr _40a ;.db $DA ;start of `jp c,*` in order to skip the next instruction
7698
rounding_done_single:
7701
;Strip the leading zero if it exists (rounding may have bumped this to `1`)
7713
;Now lets move HL-DE bytes at DE+1 to DE
7725
;If z flag is reset, this means that the exponent should be bumped up 1
7726
ld a,(pow10exp_single)
7729
ld (pow10exp_single),a
7732
;if -4<=A<=6, then need to insert the decimal place somewhere.
7737
;for this, we need to insert the decimal after the first digit
7738
;Then, we need to append the exponent string
7740
ld de,strout_single-1
7742
cp '-' ;negative sign
7750
;remove any stray zeroes at the end before appending the exponent
7754
; Write the exponent
7757
ld a,(pow10exp_single)
7760
ld (hl),'-' ;negative sign
7778
ld de, strout_single
7781
ld a, l ; string size
7783
ld hl,strout_single-1
7787
ld a,(pow10exp_single)
7791
;need to put zeroes before everything
7794
cp '-' ;negative sign
7820
ld de,strout_single-1
7824
cp '-' ;negative sign
7835
ld hl,strout_single-1
7853
;multiply the 0.24 fixed point number at scrap by 10
7854
;overflow in A register
7889
;Check that the last digit isn't a decimal!
7943
;---------------------------------------------------------------------------------------------------------
7945
; https://www.ticalc.org/pub/86/asm/source/routines/atof.asm
7946
;---------------------------------------------------------------------------------------------------------
7951
ptr_sto: equ scrap+9
7953
;;#Routines/Single Precision
7955
;; HL points to the string
7956
;; BC points to where the float is output
7958
;; scrap+9 is the pointer to the end of the string
7960
;; 11 bytes at scrap ?
7965
;Check if there is a negative sign.
7974
;Skip all leading zeroes
7977
jr z,$-4 ;jumps back to the `inc hl`
7980
;Check if the next char is char_DEC
7982
or a ;to reset the carry flag
7984
jr _54a ;.db $FE ;start of cp *
7991
jr z,$-5 ;jumps back to the `dec b`
7994
;Now we read in the next 8 digits
8000
;Now `scrap` holds the 4-digit base-100 number.
8002
;if carry flag is set, just need to get rid of remaining digits
8003
;Otherwise, need to get rid of remaining digits, while incrementing the exponent
8014
jp z,strToSingle_inf
8017
;Now check for engineering `E` to modify the exponent
8021
;Gotta multiply the number at (scrap) by 2^24
8024
call scrap_times_256
8027
call scrap_times_256
8030
call scrap_times_256
8033
call scrap_times_256
8036
;Now scrap+3 is a 4-byte mantissa that needs to be normalized
8044
jp z,strToSingle_zero-1
8048
jp m,strToSingle_normed
8049
;Will need to iterate at most three times
8062
;Move the number to scrap
8071
;now (scrap) is our number, need to multiply by power of 10!
8072
;Power of 10 is stored in B, need to put in A first
8080
jp nc,strToSingle_inf+1
8083
jp nc,strToSingle_zero
8107
cp char_NEG ;negative exponent?
8159
call scrap_times_sub
8172
jr nz,strToSingle_inf
8190
if defined roundSingle or defined MATH_FRCSGL
8192
;---------------------------------------------------------------------------------------------------------
8194
; http://wikiti.brandonw.net/index.php?title=Z80_Routines:Math:Division#24.2F8_division
8195
;---------------------------------------------------------------------------------------------------------
8202
ld l, (ix) ; convert integer parameter to single float
8204
ld bc, 0x1000 ; bynary digits count + sign
8206
int2Single.test.zero:
8208
or h ; test if hl is not zero
8209
jr nz, int2Single.test.negative
8211
jr nz, int2Single.test.negative
8216
int2Single.test.negative:
8217
bit 7, h ; test if hl is negative
8218
jr z, int2Single.normalize
8219
ld c, 0x80 ; sign negative
8228
int2Single.normalize:
8231
jr nz, int2Single.mount
8234
jr int2Single.normalize
8237
res 7, h ; turn off upper bit
8239
ld a, c ; restore sign
8241
ld h, a ; ...into upper mantissa
8243
ld e, h ; sign+mantissa
8244
ld h, l ; high mantissa
8245
ld l, 0 ; low mantissa
8247
ld a, b ; binary digits count
8248
or 0x80 ; exponent bias
8253
ld (ix), l ; low mantissa
8254
ld (ix+1), h ; high mantissa
8255
ld (ix+2), e ; sign + mantissa
8256
ld (ix+3), d ; expoent
8265
if defined roundSingle or defined MATH_FRCINT
8267
;---------------------------------------------------------------------------------------------------------
8269
; http://0x80.pl/articles/convert-float-to-integer.html
8270
;---------------------------------------------------------------------------------------------------------
8273
; HL points to the single-precision float
8275
; HL is the 16-bit signed integer part of the float
8276
; BC points to 16-bit signed integer
8293
jr c,no_shift_single_to_int16
8295
jr nc,no_shift_single_to_int16
8317
jr _67a ;.db $11 ;start of ld de,*
8329
no_shift_single_to_int16:
8351
;---------------------------------------------------------------------------------------------------------
8352
; Auxiliary routines
8353
;---------------------------------------------------------------------------------------------------------
8360
const_pi: db $DB,$0F,$49,$81
8361
const_e: db $54,$f8,$2d,$81
8362
const_lg_e: db $3b,$AA,$38,$80
8363
const_ln_2: db $18,$72,$31,$7f
8364
const_log2: db $9b,$20,$1a,$7e
8365
const_lg10: db $78,$9a,$54,$81
8366
const_0: db $00,$00,$00,$00
8367
const_1: db $00,$00,$00,$80
8368
const_2: dw 0, 33024
8369
const_3: dw 0, 33088
8370
const_4: dw 0, 33280
8371
const_5: dw 0, 33312
8372
const_7: dw 0, 33376
8373
const_9: dw 0, 33552
8374
const_16: dw 0, 33792
8375
const_100: db $00,$00,$48,$86
8376
const_100_inv: dw 55050, 31011
8377
const_precision: db $77,$CC,$2B,$65 ;10^-8
8378
const_half_1: dw 0, 32512
8379
const_inf: db $00,$00,$40,$00
8380
const_NegInf: db $00,$00,$C0,$00
8381
const_NaN: db $00,$00,$20,$00
8382
const_log10_e: db $D9,$5B,$5E,$7E
8383
const_2pi: db $DB,$0F,$49,$82
8384
const_2pi_inv: db $83,$F9,$22,$7D
8385
const_half_pi: dw 4059, 32841
8386
const_p25: db $00,$00,$00,$7E
8387
const_p5: db $00,$00,$00,$7F
8390
sin_a1: dw 43691, 32042
8391
sin_a2: dw 34952, 30984
8392
sin_a3: dw 3329, 29520
8393
cos_a1: equ const_half_1
8394
cos_a2: dw 43691, 31530
8395
cos_a3: dw 2914, 30262
8396
exp_a1: db $15,$72,$31,$7F ;.693146989552
8397
exp_a2: db $CE,$FE,$75,$7D ;.2402298085906
8398
exp_a3: db $7B,$42,$63,$7B ;.0554833215071
8399
exp_a4: db $FD,$94,$1E,$79 ;.00967907584392
8400
exp_a5: db $5E,$01,$23,$76 ;.001243632065103
8401
exp_a6: db $5F,$B7,$63,$73 ;.0002171671843714
8402
const_1p40625: db $00,$00,$34,$80 ;1.40625
8404
if defined MATH_CONSTSINGLE
8412
;A is the constant ID#
8413
;returns nc if failed, c otherwise
8414
;HL points to the constant
8415
cp (end_const-start_const)>>2
8422
;#if ((end_const-4)>>8)!=(start_const>>8)
8435
db $CD,$CC,$4C,$7C ;.1
8436
db $0A,$D7,$23,$79 ;.01
8437
db $17,$B7,$51,$72 ;.0001
8438
db $77,$CC,$2B,$65 ;10^-8
8439
db $95,$95,$66,$4A ;10^-16
8440
db $1F,$B1,$4F,$15 ;10^-32
8443
db $00,$00,$20,$83 ;10
8444
db $00,$00,$48,$86 ;100
8445
db $00,$40,$1C,$8D ;10000
8446
db $20,$BC,$3E,$9A ;10^8
8447
db $CA,$1B,$0E,$B5 ;10^16
8448
db $AE,$C5,$1D,$EA ;10^32
8455
;C>=128 135+6{0,33+{0,1}}+{0,20+{0,8}}
8456
;C>=64 115+5{0,33+{0,1}}+{0,20+{0,8}}
8457
;C>=32 95+4{0,33+{0,1}}+{0,20+{0,8}}
8458
;C>=16 75+3{0,33+{0,1}}+{0,20+{0,8}}
8459
;C>=8 55+2{0,33+{0,1}}+{0,20+{0,8}}
8460
;C>=4 35+{0,33+{0,1}}+{0,20+{0,8}}
8461
;C>=2 15+{0,20+{0,8}}
8464
;avg: 349.21279907227cc
8555
;26 bytes, adds 118cc to the traditional routine
8590
;c flag means don't increment the exponent
8593
jr c,ascii_to_uint8_noexp
8595
jr z,ascii_to_uint8_noexp-2
8599
jr nc,ascii_to_uint8_noexp_end
8611
jr z,ascii_to_uint8_noexp_2nd
8615
jr nc,ascii_to_uint8_noexp_end
8626
ascii_to_uint8_noexp:
8629
jr nc,ascii_to_uint8_noexp_end
8636
ascii_to_uint8_noexp_2nd:
8641
jr nc,ascii_to_uint8_noexp_end
8644
jr ascii_2 ;.db $FE ;start of `cp **`, saves 1cc
8645
ascii_to_uint8_noexp_end:
8655
if defined MATH_RSUBSINGLE
8676
jp addInject ;jumps in to the addSingle routine
8680
if defined MATH_MOD1SINGLE
8682
;This routine performs `x mod 1`, returning a non-negative value.
8705
jr z,mod1Single_special
8718
;If it is zero, need to set exponent to zero and return
8741
;make sure it isn't zero else we need to add 1
8753
;If INF, need to return NaN instead
8754
;For 0 and NaN, just return itself :)
8774
if defined MATH_FOUT
8776
; --------------------------------------------------------------
8777
; Converts a signed integer value to a zero-terminated ASCII
8778
; string representative of that value (using radix 10).
8780
; Brandon Wilson WikiTI
8781
; http://wikiti.brandonw.net/index.php?title=Z80_Routines:Other:DispA#Decimal_Signed_Version
8782
; --------------------------------------------------------------
8784
; HL Value to convert (two's complement integer).
8785
; DE Base address of string destination. (pointer).
8786
; --------------------------------------------------------------
8789
; --------------------------------------------------------------
8790
; REGISTERS/MEMORY DESTROYED
8792
; --------------------------------------------------------------
8798
; Detect sign of HL.
8802
; HL is negative. Output '-' to string and negate HL.
8807
; Negate HL (using two's complement)
8811
ld a, 0 ; Note that XOR A or SUB A would disturb CF
8815
; Convert HL to digit characters
8817
ld b, 0 ; B will count character length of number
8820
call div_hl_c; HL = HL / A, A = remainder
8827
; Retrieve digits from stack
8835
; Terminate string with NULL
8846
ld a, l ; string size
8854
;===============================================================
8855
; Convert a string of base-10 digits to a 16-bit value.
8856
; http://z80-heaven.wikidot.com/math#toc32
8858
; DE points to the base 10 number string in RAM.
8860
; HL is the 16-bit value of the number
8861
; DE points to the byte after the number
8866
; A (actually, add 30h and you get the ending token)
8869
; n is the number of digits
8871
; at most 595 cycles for any 16-bit decimal value
8872
;===============================================================
8875
ld hl,0 ; 10 : 210000
8892
jr nc,ConvLoop ;12|23: 30EE
8894
jr ConvLoop ; --- : 18EB
8901
; return remainder in a
8902
; http://wikiti.brandonw.net/index.php?title=Z80_Routines:Math:Division
8923
; http://wikiti.brandonw.net/index.php?title=Z80_Routines:Math:Division#24.2F8_division
8953
djnz div_dehl_c.loop
8961
;---------------------------------------------------------------------------------------------------------
8962
; VARIABLES INITIALIZE
8963
;---------------------------------------------------------------------------------------------------------
8967
ld (VAR_DUMMY.COUNTER), a ; max circular queue = 8 dummys
8968
ld hl, VAR_DUMMY.DATA ; start of variable dummy circular queue
8969
ld (VAR_DUMMY.POINTER), hl
8970
ld b, VAR_DUMMY.LENGTH
8975
djnz INITIALIZE_DUMMY.1
8980
ld (BASIC_DATPTR), hl ; next DATA pointer to use by READ command
8982
ld (BASIC_DATLIN), hl ; index of DATA item to use by READ command
8985
INITIALIZE_VARIABLES:
8986
call INITIALIZE_DATA
8987
call INITIALIZE_DUMMY
8990
call gfxInitSpriteCollisionTable
8993
;if defined COMPILE_TO_ROM
8994
; ld ix, BIOS_JIFFY ; initialize rom clock
9002
ld d, 2 ; any = default integer
9003
ld c, 0 ; variable name 1 (variable number)
9004
ld b, 0 ; variable name 2 (type flag=any)
9005
call INIT_VAR ; variable initialize
9007
ld d, 2 ; any = default integer
9008
ld c, 1 ; variable name 1 (variable number)
9009
ld b, 0 ; variable name 2 (type flag=any)
9010
call INIT_VAR ; variable initialize
9012
ld d, 2 ; any = default integer
9013
ld c, 2 ; variable name 1 (variable number)
9014
ld b, 0 ; variable name 2 (type flag=any)
9015
call INIT_VAR ; variable initialize
9017
ld d, 2 ; any = default integer
9018
ld c, 3 ; variable name 1 (variable number)
9019
ld b, 0 ; variable name 2 (type flag=any)
9020
call INIT_VAR ; variable initialize
9022
ld d, 2 ; any = default integer
9023
ld c, 4 ; variable name 1 (variable number)
9024
ld b, 0 ; variable name 2 (type flag=any)
9025
call INIT_VAR ; variable initialize
9027
ld d, 2 ; any = default integer
9028
ld c, 5 ; variable name 1 (variable number)
9029
ld b, 0 ; variable name 2 (type flag=any)
9030
call INIT_VAR ; variable initialize
9032
ld d, 2 ; any = default integer
9033
ld c, 6 ; variable name 1 (variable number)
9034
ld b, 0 ; variable name 2 (type flag=any)
9035
call INIT_VAR ; variable initialize
9037
ld d, 2 ; any = default integer
9038
ld c, 7 ; variable name 1 (variable number)
9039
ld b, 0 ; variable name 2 (type flag=any)
9040
call INIT_VAR ; variable initialize
9042
ld d, 2 ; any = default integer
9043
ld c, 8 ; variable name 1 (variable number)
9044
ld b, 0 ; variable name 2 (type flag=any)
9045
call INIT_VAR ; variable initialize
9047
ld d, 2 ; any = default integer
9048
ld c, 9 ; variable name 1 (variable number)
9049
ld b, 0 ; variable name 2 (type flag=any)
9050
call INIT_VAR ; variable initialize
9054
;---------------------------------------------------------------------------------------------------------
9055
; MAIN WORK AREA - LITERALS / VARIABLES / CONFIGURATIONS
9056
;---------------------------------------------------------------------------------------------------------
9058
if defined COMPILE_TO_ROM
9061
pgmPage1.pad: equ pageSize - (workAreaPad - pgmArea)
9063
if pgmPage1.pad >= 0
9066
; .WARNING "There's no free space left on program page 1"
9071
VAR_STACK.START: equ ramArea
9072
;VAR_STACK.END: equ VAR_STACK.START + 0x800 ; 2kb (~200 variables)
9074
VAR_STACK.POINTER: equ VAR_STACK.START
9076
PRINT.CRLF: db 3, 0, 0, 2
9077
dw PRINT.CRLF.DATA, 0, 0, 0
9078
PRINT.CRLF.DATA: db 13,10,0
9080
PRINT.TAB: db 3, 0, 0, 1
9081
dw PRINT.TAB.DATA, 0, 0, 0
9082
PRINT.TAB.DATA: db 09,0
9085
LIT_NULL_DBL: dw 0, 0, 0, 0
9091
LIT_QUOTE_CHAR: db '\"'
9094
LIT_TRUE: db 2, 0, 0
9098
LIT_FALSE: db 2, 0, 0
9107
IDF_5: equ VAR_STACK.POINTER + 0
9114
IDF_7: equ VAR_STACK.POINTER + 11
9121
IDF_9: equ VAR_STACK.POINTER + 22
9128
IDF_11: equ VAR_STACK.POINTER + 33
9135
IDF_13: equ VAR_STACK.POINTER + 44
9138
IDF_20: equ VAR_STACK.POINTER + 55
9149
IDF_25: equ VAR_STACK.POINTER + 66
9152
IDF_26: equ VAR_STACK.POINTER + 77
9163
IDF_30: equ VAR_STACK.POINTER + 88
9178
IDF_40: equ VAR_STACK.POINTER + 99
9184
AFTER_LAST_VARIABLE: equ VAR_STACK.POINTER + 110
9186
VAR_DUMMY.START: equ AFTER_LAST_VARIABLE ; variable dummy circular queue area
9187
VAR_DUMMY.COUNTER: equ VAR_DUMMY.START ; variable dummy circular queue count
9188
VAR_DUMMY.POINTER: equ VAR_DUMMY.COUNTER + 1 ; pointer to next variable dummy
9189
VAR_DUMMY.DATA: equ VAR_DUMMY.POINTER + 2 ; first variable dummy
9191
VAR_DUMMY.SIZE: equ 8
9192
VAR_DUMMY.LENGTH: equ (11 * VAR_DUMMY.SIZE)
9193
VAR_DUMMY.END: equ VAR_DUMMY.DATA + VAR_DUMMY.LENGTH
9194
VAR_STACK.END: equ VAR_DUMMY.END + 1
9196
;--------------------------------------------------------
9198
;--------------------------------------------------------
9201
DATA_ITEMS_COUNT: equ 0
9203
DATA_SET_ITEMS_START:
9204
DATA_SET_ITEMS_COUNT: equ 0
9207
;---------------------------------------------------------------------------------------------------------
9209
;---------------------------------------------------------------------------------------------------------
9211
if defined COMPILE_TO_ROM
9215
pgmPage2.pad: equ romSize - (romPad - pgmArea)
9217
if pgmPage2.pad >= 0
9220
if pgmPage2.pad < lowLimitSize
9221
.WARNING "There's only less than 5% free space on this ROM"
9224
.ERROR "There's no free space left on this ROM"
9229
end_file: end start_pgm ; label start is the entry point