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
145
;--------------------------------------------------------
146
; MSX BASIC DATA/FUNCTION POINTERS
147
;--------------------------------------------------------
149
;---------------------------------------------------------------------------------------------------------
150
; MSX BASIC FUNCTIONS
151
;---------------------------------------------------------------------------------------------------------
153
BASIC_AUTO: equ 0x3973
154
BASIC_AND: equ 0x3A18
155
BASIC_ATTR: equ 0x39FE
156
BASIC_BASE: equ 0x39BE
157
BASIC_BSAVE: equ 0x39CC
158
BASIC_BLOAD: equ 0x39CA
159
BASIC_BEEP: equ 0x39AC
160
BASIC_CALL: equ 0x39C0
161
BASIC_CLOSE: equ 0x3994
162
BASIC_COPY: equ 0x39D8
163
BASIC_CONT: equ 0x395E
164
BASIC_CLEAR: equ 0x3950
165
BASIC_CLOAD: equ 0x3962
166
BASIC_CSAVE: equ 0x3960
167
BASIC_CSRLIN: equ 0x39FC
168
BASIC_CIRCLE: equ 0x39A4
169
BASIC_COLOR: equ 0x39A6
170
BASIC_CLS: equ 0x396A
171
BASIC_CMD: equ 0x39DA
172
BASIC_DELETE: equ 0x397C
173
BASIC_DATA: equ 0x3934
174
BASIC_DIM: equ 0x3938
175
BASIC_DEFSTR: equ 0x3982
176
BASIC_DEFINT: equ 0x3984
177
BASIC_DEFSNG: equ 0x3986
178
BASIC_DEFDBL: equ 0x3988
179
BASIC_DSKO: equ 0x39CE
180
BASIC_DEF: equ 0x395A
181
BASIC_DSKI: equ 0x3A00
182
BASIC_DRAW: equ 0x39A8
183
BASIC_ELSE: equ 0x396E
184
BASIC_END: equ 0x392E
185
BASIC_ERASE: equ 0x3976
186
BASIC_ERROR: equ 0x3978
187
BASIC_ERL: equ 0x39EE
188
BASIC_ERR: equ 0x39F0
189
BASIC_EQU: equ 0x3A1E
190
BASIC_FOR: equ 0x3920
191
BASIC_FIELD: equ 0x398E
192
BASIC_FILES: equ 0x39AA
194
BASIC_GOTO: equ 0x393E
195
BASIC_GOSUB: equ 0x3948
196
BASIC_GET: equ 0x3990
197
BASIC_INPUT: equ 0x3936
199
BASIC_INSTR: equ 0x39F6
200
BASIC_IMP: equ 0x3A20
201
BASIC_INKEY: equ 0x3A04
202
BASIC_IPL: equ 0x39D6
203
BASIC_KILL: equ 0x39D4
204
BASIC_KEY: equ 0x3964
205
BASIC_LPRINT: equ 0x394C
206
BASIC_LLIST: equ 0x3968
207
BASIC_LET: equ 0x393C
208
BASIC_LOCATE: equ 0x39DC
209
BASIC_LINE: equ 0x398A
210
BASIC_LOAD: equ 0x3996
211
BASIC_LSET: equ 0x399C
212
BASIC_LIST: equ 0x3952
213
BASIC_LFILES: equ 0x39A2
214
BASIC_MOTOR: equ 0x39C8
215
BASIC_MERGE: equ 0x3998
216
BASIC_MOD: equ 0x3A22
217
BASIC_MAX: equ 0x39C6
218
BASIC_NEXT: equ 0x3932
219
BASIC_NAME: equ 0x39D2
220
BASIC_NEW: equ 0x3954
221
BASIC_NOT: equ 0x39EC
222
BASIC_OPEN: equ 0x398C
223
BASIC_OUT: equ 0x3964
226
BASIC_OFF: equ 0x3A02
227
BASIC_PRINT: equ 0x394E
228
BASIC_PUT: equ 0x3992
229
BASIC_POKE: equ 0x395C
230
BASIC_PSET: equ 0x39B0
231
BASIC_PRESET: equ 0x39B2
232
BASIC_POINT: equ 0x3A06
233
BASIC_PAINT: equ 0x39AA
234
BASIC_PLAY: equ 0x39AE
235
BASIC_RETURN: equ 0x3948
236
BASIC_READ: equ 0x393A
237
BASIC_RUN: equ 0x3940
238
BASIC_RESTORE:equ 0x3944
239
BASIC_REM: equ 0x394A
240
BASIC_RESUME: equ 0x397A
241
BASIC_RSET: equ 0x399E
242
BASIC_RENUM: equ 0x3980
243
BASIC_SCREEN: equ 0x39B6
244
BASIC_SPRITE: equ 0x39BA
245
BASIC_STOP: equ 0x394C
246
BASIC_SWAP: equ 0x3974
247
BASIC_SET: equ 0x39D0
248
BASIC_SAVE: equ 0x39A0
249
BASIC_SPC: equ 0x39EA
250
BASIC_STEP: equ 0x39E4
251
BASIC_STRING: equ 0x39F2
252
BASIC_SPACE1: equ 0x397E
253
BASIC_SOUND: equ 0x39B4
254
BASIC_THEN: equ 0x39E0
255
BASIC_TRON: equ 0x3970
256
BASIC_TROFF: equ 0x3972
257
BASIC_TAB: equ 0x39E2
259
BASIC_TIME: equ 0x39C2
260
BASIC_USING: equ 0x39F4
261
BASIC_USR: equ 0x39E6
262
BASIC_VARPTR: equ 0x39FA
263
BASIC_VDP: equ 0x39BC
264
BASIC_VPOKE: equ 0x39B8
265
BASIC_WIDTH: equ 0x396C
266
BASIC_WAIT: equ 0x3958
267
BASIC_XOR: equ 0x3A1C
268
BASIC_ABS: equ 0x39E8
269
BASIC_ATN: equ 0x39F8
270
BASIC_ASC: equ 0x3A06
271
BASIC_BIN: equ 0x3A16
272
BASIC_CINT: equ 0x3A18
273
BASIC_CSNG: equ 0x3A1A
274
BASIC_CDBL: equ 0x3A1C
275
BASIC_CVI: equ 0x3A2C
276
BASIC_CVS: equ 0x3A2E
277
BASIC_CVD: equ 0x3A30
278
BASIC_COS: equ 0x39F4
279
BASIC_CHR: equ 0x3A08
280
BASIC_DSKF: equ 0x3A28
281
BASIC_EXP: equ 0x39F2
282
BASIC_EOF: equ 0x3A32
283
BASIC_FRE: equ 0x39FA
284
BASIC_FIX: equ 0x3A1E
285
BASIC_FPOS: equ 0x3A2A
286
BASIC_HEX: equ 0x3A12
287
BASIC_INT: equ 0x39E6
288
BASIC_INP: equ 0x39FC
289
BASIC_LPOS: equ 0x3A14
290
BASIC_LOG: equ 0x39F0
291
BASIC_LOC: equ 0x3A34
292
BASIC_LEN: equ 0x3A00
293
BASIC_LEFT: equ 0x39DE
294
BASIC_LOF: equ 0x3A36
295
BASIC_MKI: equ 0x3A38
296
BASIC_MKS: equ 0x3A3A
297
BASIC_MKD: equ 0x3A3C
298
BASIC_MID: equ 0x39E2
299
BASIC_OCT: equ 0x3A10
300
BASIC_POS: equ 0x39FE
301
BASIC_PEEK: equ 0x3A0A
302
BASIC_PDL: equ 0x3A24
303
BASIC_PAD: equ 0x3A26
304
BASIC_RIGHT: equ 0x39E0
305
BASIC_RND: equ 0x39EC
306
BASIC_SGN: equ 0x39E4
307
BASIC_SQR: equ 0x39EA
308
BASIC_SIN: equ 0x39EE
309
BASIC_STR: equ 0x3A02
310
BASIC_SPACE2: equ 0x3A0E
311
BASIC_STICK: equ 0x3A20
312
BASIC_STRIG: equ 0x3A22
313
BASIC_TAN: equ 0x39F6
314
BASIC_VAL: equ 0x3A04
315
BASIC_VPEEK: equ 0x3A0C
317
BASIC_TRAP_ENABLE: equ 0x631B ; ON INTERVAL/KEY/SPRITE/STOP/STRIG - hl = pointer to trap block
318
BASIC_TRAP_DISABLE: equ 0x632B ; hl = pointer to trap block
319
BASIC_TRAP_ACKNW: equ 0x6358 ; hl, acknowledge trap (handle trap: sts=5? has handler? ackn, pause, run trap, sts=1? unpause)
320
BASIC_TRAP_PAUSE: equ 0x6331 ; hl
321
BASIC_TRAP_UNPAUSE: equ 0x633E ; hl
322
BASIC_TRAP_CLEAR: equ 0x636E
324
BASIC_PLAY_DIRECT: equ 0x744C
325
BASIC_DRAW_DIRECT: equ 0x568C
327
BASIC_READYR: equ 0x409B
328
BASIC_READYC: equ 0x7D17
329
BASIC_FACEVAL: equ 0x4DC7
331
BASIC_ERROR_HANDLER:equ 0x406F
332
BASIC_ERROR_SYNTAX: equ 0x4055
333
BASIC_ERROR_DIVZER: equ 0x4058
334
BASIC_ERROR_OVRFLW: equ 0x4067
335
BASIC_ERROR_ARRAY: equ 0x405E
336
BASIC_ERROR_TYPMIS: equ 0x406D
338
; BASIC ERROR CODES TO BASIC_ERROR_HANDLER
339
; 01 NEXT without FOR 19 Device I/O error
340
; 02 Syntax error 20 Verify error
341
; 03 RETURN without GOSUB 21 No RESUME
342
; 04 Out of DATA 22 RESUME without error
343
; 05 Illegal function call 23 Unprintable error
344
; 06 Overflow 24 Missing operand
345
; 07 Out of memory 25 Line buffer overflow
346
; 08 Undefined line number 50 FIELD overflow
347
; 09 Subscript out of range 51 Internal error
348
; 10 Redimensioned array 52 Bad file number
349
; 11 Division by zero 53 File not found
350
; 12 Illegal direct 54 File already open
351
; 13 Type mismatch 55 Input past end
352
; 14 Out of string space 56 Bad file name
353
; 15 String too long 57 Direct statement in file
354
; 16 String formula too complex 58 Sequential I/O only
355
; 17 Can't CONTINUE 59 File not OPEN
356
; 18 Undefined user function
358
;---------------------------------------------------------------------------------------------------------
359
; MSX BASIC WORK AREAS
360
;---------------------------------------------------------------------------------------------------------
362
BASIC_DAC: equ 0xF7F6 ; 16
363
BASIC_ARG: equ 0xF847 ; 16
364
BASIC_VALTYP: equ 0xF663
365
BASIC_RNDX: equ 0xF857
366
BASIC_BUF: equ 0xF55E ; 259
367
BASIC_KBUF: equ 0xF41F ; 318
368
BASIC_SWPTMP: equ 0xF7BC ; 8
369
BASIC_STRBUF: equ 0xF7C5 ; 43
370
BASIC_TXTTAB: equ 0xF676
371
BASIC_VARTAB: equ 0xF6C2
372
BASIC_ARYTAB: equ 0xF6C4
373
BASIC_STREND: equ 0xF6C6
374
BASIC_STKTOP: equ 0xF674
375
BASIC_FRETOP: equ 0xF69B
376
BASIC_MEMSIZ: equ 0xF672
378
BASIC_TEMPPT: equ 0xF678 ; 2 Starting address of unused area of temporary descriptor.
379
BASIC_TEMPST: equ 0xF67A ; 30 Temporary descriptors.
381
BASIC_DATPTR: equ 0xF6C8 ; 2 Pointer to next data to read from the instruction DATA. Modified by RESTORE.
382
BASIC_DATLIN: equ 0xF6A3 ; 2 Número de linha do comando DATA para o comando READ.
383
BASIC_DORES: equ 0xF664 ; 1 Usada pelo comando DATA para manter o texto no formato ASCII.
384
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).
386
BASIC_CURLIN: equ 0xF41C ; BASIC current line number
387
BASIC_INTVAL: equ 0xFCA0 ; interval value
388
BASIC_INTCNT: equ 0xFCA2 ; interval current count
390
BASIC_PRMPRV: equ 0xF74C ; Pointer to previous parameter block in PARM1
392
BASIC_TRPTBL: equ 0xFC4C ; 78 trap table - array of 3 bytes - state[1] (bit 0=on, bit 1=stop, bit 2=active) + address[2]
394
BASIC_TRPTBL_KEY: equ 0xFC4C ; 30 ON KEY GOSUB
395
BASIC_TRPTBL_STOP: equ 0xFC6A ; 3 ON STOP GOSUB
396
BASIC_TRPTBL_SPRITE: equ 0xFC6D ; 3 ON SPRITE GOSUB
397
BASIC_TRPTBL_STRIG: equ 0xFC70 ; 15 ON STRIG GOSUB
398
BASIC_TRPTBL_INTERVAL: equ 0xFC7F ; 3 ON INTERVAL GOSUB
399
BASIC_TRPTBL_OTHER: equ 0xFC82 ; 24 reserved for expansion
401
BASIC_ONGSBF: equ 0xFBD8 ; 1 trap occurred counter (0=not occurred)
405
;--------------------------------------------------------
407
;--------------------------------------------------------
409
;--------------------------------------------------------
411
;--------------------------------------------------------
412
COMPILE_TO_ROM: EQU 1
414
MACRO __call_basic,CALL_PARM
415
;ld iy,(BIOS_EXPTBL-1)
423
;ld iy, (BIOS_SLTROM+1)
433
if defined COMPILE_TO_DOS
435
MACRO __call_bios,CALL_PARM
436
;ld iy,(BIOS_EXPTBL-1)
438
call BIOS_CALBAS ; BIOS_CALSLT
443
MACRO __call_bios,CALL_PARM
444
;ld iy,(BIOS_EXPTBL-1)
452
;ld iy, (BIOS_SLTROM+1)
464
push hl ; save parameter
468
pop iy ; restore PC of caller
469
pop hl ; get next parameter
470
push iy ; save PC of caller
474
pop iy ; restore PC of caller
475
push hl ; save return parameter
476
push iy ; save PC of caller
480
pop iy ; restore PC of caller
481
push hl ; save return parameter
482
push iy ; save PC of caller
486
MACRO set.line.number, line_number
487
ld bc, line_number ; current line number
488
ld (BASIC_CURLIN), bc
492
ld a, (BIOS_INTFLG) ; verify CTRL+BREAK
498
ld a, (BASIC_ONGSBF) ; trap occured counter
504
;---------------------------------------------------------------------------------------------------------
506
;---------------------------------------------------------------------------------------------------------
508
pageSize: equ 0x4000 ; 8k
510
if defined COMPILE_TO_BIN
512
pgmArea: equ 0x8000 ; page 2 - program area
513
ramArea: equ 0xc000 ; page 3 - free RAM start area
515
org pgmArea ; program binary type start address
516
db 0FEh ; binary file ID
517
dw start_pgm ; begin address
518
dw end_file - 1 ; end address
519
dw start_pgm ; program execution address (for ,R option)
522
if defined COMPILE_TO_ROM
524
pgmArea: equ 0x4000 ; page 1 and 2 - program area
525
ramArea: equ 0xc000 ; page 3 - free RAM start area
527
org pgmArea ; program rom type start address
528
db 'AB' ; rom file ID
530
dw 0x0000 ; STATEMENT
537
pgmArea: equ 0x8000 ; page 2 - program area
538
ramArea: equ 0xc000 ; page 3 - free RAM start area
540
org pgmArea ; program DOS type start address ; 0x0100
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
;---------------------------------------------------------------------------------------------------------
584
;---------------------------------------------------------------------------------------------------------
586
start_pgm: ; start of the program
588
;call BIOS_BASIC_SLOT_ENABLE ; enable bios and basic on page 0 and 1
590
call PROGRAM_SLOT_2_ENABLE
592
__call_bios BIOS_ERAFNK ; turn off function keys display
593
__call_bios BIOS_GICINI ; initialize sound system
594
__call_bios BIOS_INITXT ; initialize text screen
596
ld (BIOS_CLIKSW), a ; disable keyboard click
598
ld (BASIC_CURLIN), bc ; interpreter in direct mode
599
__call_basic BASIC_TRAP_CLEAR ; clear traps work space
600
;call INITIALIZE_PARAMETERS ; initialize parameters stack
601
call memory.init ; initialize memory allocation
602
call INITIALIZE_VARIABLES ; initialize variables
607
check.traps ; check traps
610
check.traps ; check traps
613
check.traps ; check traps
616
check.traps ; check traps
619
check.traps ; check traps
622
check.traps ; check traps
623
call INTERVAL_OFF ; action call
624
call SPRITE_OFF ; action call
625
ld hl, LIT_6 ; parameter
627
call SCREEN ; action call
628
ld hl, LIT_13 ; parameter
630
call COLOR_BORDER ; action call
631
ld hl, LIT_11 ; parameter
633
call COLOR_BACKGROUND ; action call
634
ld hl, LIT_9 ; parameter
636
call COLOR_FOREGROUND ; action call
637
call COLOR ; action call
638
ld hl, LIT_15 ; parameter
640
ld hl, IDF_14 ; parameter
642
call LET ; action call
643
ld hl, LIT_17 ; parameter
645
ld hl, IDF_16 ; parameter
647
call LET ; action call
650
check.traps ; check traps
651
ld hl, LIT_19 ; parameter
653
ld hl, IDF_18 ; parameter
655
call LET ; action call
656
ld hl, LIT_21 ; parameter
658
ld hl, IDF_20 ; parameter
660
call LET ; action call
661
ld hl, LIT_23 ; parameter
663
ld hl, IDF_22 ; parameter
665
call LET ; action call
666
ld hl, LIT_25 ; parameter
668
ld hl, IDF_24 ; parameter
670
call LET ; action call
673
check.traps ; check traps
674
ld hl, LIT_27 ; parameter
676
ld hl, IDF_26 ; parameter
678
call LET ; action call
679
call CLS ; action call
682
check.traps ; check traps
683
ld hl, LIT_31 ; parameter
685
ld hl, LIT_30 ; parameter
687
call LOCATE ; action call
688
ld hl, LIT_33 ; parameter
690
call PRINT ; action call
691
ld hl, PRINT.CRLF ; parameter
693
call PRINT ; action call
696
check.traps ; check traps
697
ld hl, LIT_35 ; parameter
699
ld hl, LIT_34 ; parameter
701
call LOCATE ; action call
702
ld hl, LIT_36 ; parameter
704
call PRINT ; action call
705
ld hl, PRINT.CRLF ; parameter
707
call PRINT ; action call
710
check.traps ; check traps
711
ld hl, LIT_38 ; parameter
713
ld hl, LIT_37 ; parameter
715
call LOCATE ; action call
716
ld hl, LIT_39 ; parameter
718
call PRINT ; action call
719
ld hl, PRINT.CRLF ; parameter
721
call PRINT ; action call
724
check.traps ; check traps
725
;ld hl, IDF_26 ; parameter
727
;call SET_PLAY_VOICE_1 ; action call
728
;call DO_PLAY ; action call
731
check.traps ; check traps
732
ld hl, LIT_45 ; parameter
734
call STRIG ; action call
735
ld hl, LIT_46 ; parameter
737
call STRIG ; action call
738
call BOOLEAN.OR ; action call
739
ld hl, IDF_42 ; parameter
741
call LET ; action call
742
IF_1 : ; start of IF command
743
ld hl, IDF_42 ; parameter
745
call BOOLEAN.IF ; verify IF condition result, out in A
747
jp z, ELSE_1 ; if false, jump to ELSE actions
748
THEN_1 : ; THEN actions
749
call CLS ; action call
751
jp ENDIF_1 ; jump to END of IF command
752
ELSE_1 : ; ELSE actions
753
ENDIF_1 : ; end of IF command
756
check.traps ; check traps
757
IF_2 : ; start of IF command
758
ld hl, LIT_53 ; parameter
760
call PLAY ; action call
761
call BOOLEAN.IF ; verify IF condition result, out in A
763
jp z, ELSE_2 ; if false, jump to ELSE actions
764
THEN_2 : ; THEN actions
766
jp ENDIF_2 ; jump to END of IF command
767
ELSE_2 : ; ELSE actions
769
ENDIF_2 : ; end of IF command
772
check.traps ; check traps
773
call BEEP ; action call
774
ld hl, LIT_58 ; parameter
776
call SCREEN ; action call
777
ld hl, LIT_60 ; parameter
779
call SPRITEMODE ; action call
780
call RESTORE ; action call
783
check.traps ; check traps
787
check.traps ; check traps
788
ld hl, LIT_65 ; parameter
790
call ON_SPRITE ; action call
793
check.traps ; check traps
794
ld hl, LIT_68 ; parameter
796
ld hl, LIT_67 ; parameter
798
call ON_INTERVAL ; action call
801
check.traps ; check traps
802
FOR_1 : ; start of FOR command
803
ld hl, LIT_72 ; parameter
805
ld hl, IDF_71 ; parameter
807
call LET ; action call
808
jp FOR.WHILE_1 ; jump to test if end of FOR
809
FOR.STEP_1 : ; STEP action
810
ld hl, LIT_75 ; parameter
812
ld hl, IDF_71 ; parameter
814
call MATH.ADD ; action call
815
ld hl, IDF_71 ; parameter
817
call LET ; action call
818
FOR.WHILE_1 : ; test if end of FOR
819
ld hl, IDF_71 ; parameter
821
ld hl, LIT_78 ; parameter
823
call BOOLEAN.LE ; action call
824
call BOOLEAN.IF ; verify IF condition result, out in A
826
jp z, ENDFOR_1 ; end the loop if while condition is false
827
FOR.BODY_1 : ; start of FOR user code
828
ld hl, LIT_81 ; parameter
830
call RND ; action call
831
ld hl, LIT_82 ; parameter
833
call MATH.MULT ; action call
834
call INT ; action call
835
ld hl, IDF_42 ; parameter
837
call LET ; action call
838
ld hl, IDF_42 ; parameter
840
call PSET.COLOR ; action call
841
ld hl, LIT_88 ; parameter
843
call RND ; action call
844
ld hl, LIT_89 ; parameter
846
call MATH.MULT ; action call
847
call INT ; action call
848
ld hl, LIT_86 ; parameter
850
call RND ; action call
851
ld hl, LIT_87 ; parameter
853
call MATH.MULT ; action call
854
call INT ; action call
855
call PSET.XY ; action call
856
call PSET ; action call
857
jp FOR.STEP_1 ; repeat actions
858
ENDFOR_1 : ; END of FOR command
861
check.traps ; check traps
863
ld hl, LIT_95 ; parameter
865
call COLOR_BORDER ; action call
866
ld hl, LIT_94 ; parameter
868
call COLOR_BACKGROUND ; action call
869
ld hl, LIT_93 ; parameter
871
call COLOR_FOREGROUND ; action call
872
call COLOR ; action call
873
call INTERVAL_ON ; action call
874
call SPRITE_ON ; action call
877
check.traps ; check traps
878
ld hl, LIT_99 ; parameter
880
call STICK ; action call
881
ld hl, LIT_100 ; parameter
883
call STICK ; action call
884
call BOOLEAN.OR ; action call
885
ld hl, IDF_42 ; parameter
887
call LET ; action call
890
check.traps ; check traps
891
IF_3 : ; start of IF command
892
ld hl, IDF_42 ; parameter
894
ld hl, LIT_101 ; parameter
896
call BOOLEAN.EQ ; action call
897
ld hl, IDF_18 ; parameter
899
ld hl, LIT_103 ; parameter
901
call BOOLEAN.LT ; action call
902
call BOOLEAN.AND ; action call
903
call BOOLEAN.IF ; verify IF condition result, out in A
905
jp z, ELSE_3 ; if false, jump to ELSE actions
906
THEN_3 : ; THEN actions
907
ld hl, IDF_18 ; parameter
909
ld hl, LIT_106 ; parameter
911
call MATH.ADD ; action call
912
ld hl, IDF_18 ; parameter
914
call LET ; action call
915
jp ENDIF_3 ; jump to END of IF command
916
ELSE_3 : ; ELSE actions
917
ENDIF_3 : ; end of IF command
920
check.traps ; check traps
921
IF_4 : ; start of IF command
922
ld hl, IDF_42 ; parameter
924
ld hl, LIT_107 ; parameter
926
call BOOLEAN.EQ ; action call
927
ld hl, IDF_18 ; parameter
929
ld hl, LIT_108 ; parameter
931
call BOOLEAN.GT ; action call
932
call BOOLEAN.AND ; action call
933
call BOOLEAN.IF ; verify IF condition result, out in A
935
jp z, ELSE_4 ; if false, jump to ELSE actions
936
THEN_4 : ; THEN actions
937
ld hl, IDF_18 ; parameter
939
ld hl, LIT_110 ; parameter
941
call MATH.SUB ; action call
942
ld hl, IDF_18 ; parameter
944
call LET ; action call
945
jp ENDIF_4 ; jump to END of IF command
946
ELSE_4 : ; ELSE actions
947
ENDIF_4 : ; end of IF command
950
check.traps ; check traps
951
ld hl, LIT_114 ; parameter
953
ld hl, IDF_20 ; parameter
955
ld hl, IDF_18 ; parameter
957
ld hl, LIT_113 ; parameter
959
call PUT_SPRITE_COLOR ; action call
962
check.traps ; check traps
963
IF_5 : ; start of IF command
964
ld hl, IDF_16 ; parameter
966
ld hl, LIT_115 ; parameter
968
call BOOLEAN.EQ ; action call
969
call BOOLEAN.IF ; verify IF condition result, out in A
971
jp z, ELSE_5 ; if false, jump to ELSE actions
972
THEN_5 : ; THEN actions
974
jp ENDIF_5 ; jump to END of IF command
975
ELSE_5 : ; ELSE actions
976
ENDIF_5 : ; end of IF command
979
check.traps ; check traps
980
ld hl, LIT_119 ; parameter
982
ld hl, IDF_22 ; parameter
984
ld hl, IDF_118 ; parameter
986
ld hl, LIT_117 ; parameter
988
call PUT_SPRITE_COLOR ; action call
991
check.traps ; check traps
992
ld hl, LIT_120 ; parameter
994
call STRIG ; action call
995
ld hl, LIT_121 ; parameter
997
call STRIG ; action call
998
call BOOLEAN.OR ; action call
999
ld hl, IDF_42 ; parameter
1001
call LET ; action call
1002
IF_6 : ; start of IF command
1003
ld hl, IDF_42 ; parameter
1005
call BOOLEAN.IF ; verify IF condition result, out in A
1007
jp z, ELSE_6 ; if false, jump to ELSE actions
1008
THEN_6 : ; THEN actions
1010
jp ENDIF_6 ; jump to END of IF command
1011
ELSE_6 : ; ELSE actions
1012
ENDIF_6 : ; end of IF command
1015
check.traps ; check traps
1019
check.traps ; check traps
1020
call SPRITE_OFF ; action call
1021
ld hl, LIT_126 ; parameter
1023
ld hl, LIT_125 ; parameter
1025
ld hl, IDF_118 ; parameter
1027
ld hl, LIT_124 ; parameter
1029
call PUT_SPRITE_COLOR ; action call
1030
ld hl, LIT_127 ; parameter
1032
call COLOR_BORDER ; action call
1033
call COLOR ; action call
1034
;ld hl, LIT_128 ; parameter
1036
;call SET_PLAY_VOICE_1 ; action call
1037
;call DO_PLAY ; action call
1040
check.traps ; check traps
1041
ld hl, IDF_14 ; parameter
1043
ld hl, LIT_129 ; parameter
1045
call MATH.ADD ; action call
1046
ld hl, IDF_14 ; parameter
1048
call LET ; action call
1049
ld hl, LIT_130 ; parameter
1051
call COLOR_BORDER ; action call
1052
call COLOR ; action call
1053
call TAG_190 ; gosub
1054
call SPRITE_ON ; action call
1058
check.traps ; check traps
1059
call SPRITE_OFF ; action call
1060
ld hl, LIT_134 ; parameter
1062
ld hl, IDF_22 ; parameter
1064
ld hl, IDF_118 ; parameter
1066
ld hl, LIT_133 ; parameter
1068
call PUT_SPRITE_COLOR ; action call
1069
;ld hl, LIT_135 ; parameter
1071
;call SET_PLAY_VOICE_1 ; action call
1072
;call DO_PLAY ; action call
1073
ld hl, IDF_16 ; parameter
1075
ld hl, LIT_136 ; parameter
1077
call MATH.SUB ; action call
1078
ld hl, IDF_16 ; parameter
1080
call LET ; action call
1083
check.traps ; check traps
1084
ld hl, LIT_140 ; parameter
1086
ld hl, LIT_138 ; parameter
1088
call MATH.NEG ; action call
1089
ld hl, IDF_118 ; parameter
1091
ld hl, LIT_137 ; parameter
1093
call PUT_SPRITE_COLOR ; action call
1094
call SPRITE_ON ; action call
1097
check.traps ; check traps
1098
ld hl, LIT_141 ; parameter
1100
ld hl, IDF_22 ; parameter
1102
call LET ; action call
1103
ld hl, LIT_142 ; parameter
1105
call RND ; action call
1106
ld hl, LIT_143 ; parameter
1108
call MATH.MULT ; action call
1109
ld hl, LIT_144 ; parameter
1111
call MATH.ADD ; action call
1112
call INT ; action call
1113
ld hl, IDF_118 ; parameter
1115
call LET ; action call
1116
IF_7 : ; start of IF command
1117
ld hl, IDF_118 ; parameter
1119
ld hl, LIT_145 ; parameter
1121
call MATH.MOD ; action call
1122
ld hl, LIT_147 ; parameter
1124
call BOOLEAN.EQ ; action call
1125
call BOOLEAN.IF ; verify IF condition result, out in A
1127
jp z, ELSE_7 ; if false, jump to ELSE actions
1128
THEN_7 : ; THEN actions
1129
ld hl, LIT_148 ; parameter
1131
ld hl, IDF_24 ; parameter
1133
call LET ; action call
1134
jp ENDIF_7 ; jump to END of IF command
1135
ELSE_7 : ; ELSE actions
1136
ld hl, LIT_149 ; parameter
1138
ld hl, IDF_24 ; parameter
1140
call LET ; action call
1141
ENDIF_7 : ; end of IF command
1144
check.traps ; check traps
1145
ld hl, LIT_155 ; parameter
1147
call PSET.COLOR ; action call
1148
ld hl, LIT_154 ; parameter
1150
ld hl, LIT_153 ; parameter
1152
ld hl, LIT_152 ; parameter
1154
ld hl, LIT_151 ; parameter
1156
call PSET.XY ; action call
1157
call FBOX ; action call
1160
check.traps ; check traps
1161
ld hl, LIT_156 ; parameter
1163
call COLOR_FOREGROUND ; action call
1164
call COLOR ; action call
1165
ld hl, LIT_158 ; parameter
1167
ld hl, LIT_157 ; parameter
1169
call LOCATE ; action call
1170
ld hl, LIT_159 ; parameter
1172
call PRINT ; action call
1173
ld hl, IDF_14 ; parameter
1175
call PRINT ; action call
1176
ld hl, LIT_160 ; parameter
1178
call PRINT ; action call
1179
ld hl, IDF_16 ; parameter
1181
call PRINT ; action call
1182
ld hl, PRINT.CRLF ; parameter
1184
call PRINT ; action call
1188
check.traps ; check traps
1189
call INTERVAL_OFF ; action call
1190
call SPRITE_OFF ; action call
1191
ld hl, LIT_161 ; parameter
1193
call SCREEN ; action call
1194
ld hl, LIT_163 ; parameter
1196
ld hl, LIT_162 ; parameter
1198
call LOCATE ; action call
1199
ld hl, LIT_164 ; parameter
1201
call PRINT ; action call
1202
ld hl, PRINT.CRLF ; parameter
1204
call PRINT ; action call
1207
check.traps ; check traps
1208
;ld hl, LIT_165 ; parameter
1210
;call SET_PLAY_VOICE_1 ; action call
1211
;call DO_PLAY ; action call
1214
check.traps ; check traps
1215
IF_8 : ; start of IF command
1216
ld hl, LIT_166 ; parameter
1218
call PLAY ; action call
1219
call BOOLEAN.IF ; verify IF condition result, out in A
1221
jp z, ELSE_8 ; if false, jump to ELSE actions
1222
THEN_8 : ; THEN actions
1224
jp ENDIF_8 ; jump to END of IF command
1225
ELSE_8 : ; ELSE actions
1226
call CLS ; action call
1228
ENDIF_8 : ; end of IF command
1231
check.traps ; check traps
1232
IF_9 : ; start of IF command
1233
ld hl, IDF_22 ; parameter
1235
ld hl, LIT_169 ; parameter
1237
call BOOLEAN.LT ; action call
1238
call BOOLEAN.IF ; verify IF condition result, out in A
1240
jp z, ELSE_9 ; if false, jump to ELSE actions
1241
THEN_9 : ; THEN actions
1242
ld hl, IDF_22 ; parameter
1244
ld hl, IDF_24 ; parameter
1246
call MATH.ADD ; action call
1247
ld hl, IDF_22 ; parameter
1249
call LET ; action call
1250
jp ENDIF_9 ; jump to END of IF command
1251
ELSE_9 : ; ELSE actions
1252
call TAG_185 ; gosub
1253
ENDIF_9 : ; end of IF command
1256
check.traps ; check traps
1260
check.traps ; check traps
1261
ld hl, LIT_172 ; parameter
1263
ld hl, IDF_171 ; parameter
1265
call LET ; action call
1266
FOR_2 : ; start of FOR command
1267
ld hl, LIT_173 ; parameter
1269
ld hl, IDF_71 ; parameter
1271
call LET ; action call
1272
jp FOR.WHILE_2 ; jump to test if end of FOR
1273
FOR.STEP_2 : ; STEP action
1274
ld hl, LIT_174 ; parameter
1276
ld hl, IDF_71 ; parameter
1278
call MATH.ADD ; action call
1279
ld hl, IDF_71 ; parameter
1281
call LET ; action call
1282
FOR.WHILE_2 : ; test if end of FOR
1283
ld hl, IDF_71 ; parameter
1285
ld hl, LIT_175 ; parameter
1287
call BOOLEAN.LE ; action call
1288
call BOOLEAN.IF ; verify IF condition result, out in A
1290
jp z, ENDFOR_2 ; end the loop if while condition is false
1291
FOR.BODY_2 : ; start of FOR user code
1292
ld hl, IDF_177 ; parameter
1294
call READ ; action call
1295
ld hl, IDF_171 ; parameter
1297
ld hl, IDF_177 ; parameter
1299
call CHR ; action call
1300
call MATH.ADD ; action call
1301
ld hl, IDF_171 ; parameter
1303
call LET ; action call
1304
jp FOR.STEP_2 ; repeat actions
1305
ENDFOR_2 : ; END of FOR command
1308
check.traps ; check traps
1309
ld hl, LIT_180 ; parameter
1311
ld hl, IDF_179 ; parameter
1313
call LET ; action call
1314
FOR_3 : ; start of FOR command
1315
ld hl, LIT_181 ; parameter
1317
ld hl, IDF_71 ; parameter
1319
call LET ; action call
1320
jp FOR.WHILE_3 ; jump to test if end of FOR
1321
FOR.STEP_3 : ; STEP action
1322
ld hl, LIT_182 ; parameter
1324
ld hl, IDF_71 ; parameter
1326
call MATH.ADD ; action call
1327
ld hl, IDF_71 ; parameter
1329
call LET ; action call
1330
FOR.WHILE_3 : ; test if end of FOR
1331
ld hl, IDF_71 ; parameter
1333
ld hl, LIT_183 ; parameter
1335
call BOOLEAN.LE ; action call
1336
call BOOLEAN.IF ; verify IF condition result, out in A
1338
jp z, ENDFOR_3 ; end the loop if while condition is false
1339
FOR.BODY_3 : ; start of FOR user code
1340
ld hl, IDF_177 ; parameter
1342
call READ ; action call
1343
ld hl, IDF_179 ; parameter
1345
ld hl, IDF_177 ; parameter
1347
call CHR ; action call
1348
call MATH.ADD ; action call
1349
ld hl, IDF_179 ; parameter
1351
call LET ; action call
1352
jp FOR.STEP_3 ; repeat actions
1353
ENDFOR_3 : ; END of FOR command
1356
check.traps ; check traps
1357
ld hl, IDF_171 ; parameter
1359
ld hl, LIT_185 ; parameter
1361
call SPRITE ; action call
1362
ld hl, IDF_179 ; parameter
1364
ld hl, LIT_186 ; parameter
1366
call SPRITE ; action call
1369
check.traps ; check traps
1373
check.traps ; check traps
1376
check.traps ; check traps
1379
check.traps ; check traps
1382
check.traps ; check traps
1385
check.traps ; check traps
1388
check.traps ; check traps
1391
check.traps ; check traps
1394
check.traps ; check traps
1397
check.traps ; check traps
1400
check.traps ; check traps
1403
check.traps ; check traps
1406
check.traps ; check traps
1409
check.traps ; check traps
1412
check.traps ; check traps
1415
check.traps ; check traps
1418
check.traps ; check traps
1421
check.traps ; check traps
1424
check.traps ; check traps
1426
;---------------------------------------------------------------------------------------------------------
1428
;---------------------------------------------------------------------------------------------------------
1430
end_pgm: __call_bios BIOS_DSPFNK ; turn on function keys display
1432
ld (BIOS_CLIKSW), a ; enable keyboard click
1434
;if defined COMPILE_TO_DOS or defined COMPILE_TO_ROM
1435
; __call_bios BIOS_RESET ; restart Basic
1437
; __call_basic BASIC_END ; end to Basic
1440
__call_basic BASIC_READYR ; warm start Basic
1442
;__call_bios BIOS_GICINI ; initialize sound system
1444
ret ; end of the program
1448
DATA_SET_ITEMS_START:
1449
DATA_SET_ITEMS_COUNT: equ 0
1452
;--------------------------------------------------------
1453
; MSX BASIC KEYWORDS
1454
;--------------------------------------------------------
1459
; out IX = variable assigned address
1460
pop.parm ; get variable address parameter
1461
push hl ; just to transfer hl to ix
1463
ld a, (ix) ; get variable type
1464
cp 3 ; test if string
1465
jr nz, LET.PARM ; if not a string, it isn't necessary to free memory
1466
ld a, (ix + 3) ; get variable string length
1468
jr z, LET.PARM ; if zero, it isn't necessary to free memory
1469
ld c, (ix + 4) ; get old string address low
1470
ld b, (ix + 5) ; get old string address high
1471
push ix ; save variable address
1472
push bc ; just to transfer bc (old string address) to ix
1474
call memory.free ; free memory
1475
pop ix ; restore variable address
1476
LET.PARM: pop.parm ; get data address parameter (out hl = data address)
1477
ld a, (ix + 2) ; get variable type flag
1478
or a ; cp 0 - test type flag (0=any, 255=fixed)
1479
jr nz, LET.FIXED ; if type flag is fixed, so casting is necessary
1480
LET.ANY: push ix ; just to transfer ix (variable address) to de
1482
ldi ; copy 1 byte from hl (data address) to de (variable address)
1483
inc de ; go to variable data area
1485
inc hl ; go to data data area
1487
ld bc, 8 ; data = 8 bytes
1488
ldir ; copy bc bytes from hl (data address) to de (variable address)
1489
ld a, (ix) ; get variable type
1490
cp 3 ; test if string
1491
ret nz ; if not string, return
1492
jp LET.STRING ; else do string treatment (in ix = variable address)
1493
LET.FIXED: push ix ; save variable destination address
1494
push hl ; save variable source address
1495
ld a, (ix) ; get variable fixed type, and hl has parameter data address
1496
call CAST_TO ; cast data to type (in hl = variable address, a = type to, out hl = casted data address)
1498
pop ix ; restore variable address
1499
ld a, (ix) ; get variable destination type again
1500
cp 3 ; test if string
1501
jr nz, LET.VALUE ; if not string, do value treatment
1502
ld a, (de) ; get variable source type again
1503
cp 3 ; test if string
1504
jr nz, LET.FIX1 ; if not string, get casted string size
1509
ld (ix + 3), a ; source string size
1512
call GET_STR.LENGTH ; get string length (in HL, out B)
1514
ld (ix + 3), b ; set variable length
1515
LET.FIX2: ld (ix + 4), l ; casted data address low
1516
ld (ix + 5), h ; casted data address high
1517
jp LET.STRING ; do string treatment (in ix = variable address)
1518
LET.VALUE: push ix ; just to transfer ix (variable address) to de
1520
inc de ; go to variable data area (and the data from its casted)
1523
ld bc, 8 ; data = 8 bytes
1524
ldir ; copy bc bytes from hl (data address) to de (variable address)
1526
LET.STRING: ld a, (ix + 3) ; string size
1527
or a ; cp 0 - test if null
1528
jr nz, LET.ALLOC ; if not null, allocate new string (in ix = variable address)
1529
ld bc, LIT_NULL_STR ; else, set to a null string literal
1530
ld (ix + 4), c ; variable address low
1531
ld (ix + 5), b ; variable address high
1533
LET.ALLOC: push ix ; save variable address
1534
ld l, (ix + 4) ; source string address low
1535
ld h, (ix + 5) ; source string address high
1536
push hl ; save copy from address
1537
ld c, (ix + 3) ; get variable length
1539
inc bc ; string length have one more byte from zero terminator
1540
push bc ; save variable lenght + 1
1541
call memory.alloc ; in bc = size, out ix = address, nz=OK
1543
push ix ; just to transfer memory address from ix to de
1545
pop bc ; restore bytes to be copied
1546
pop hl ; restore copy from string address
1547
push de ; save copy to address
1548
ldir ; copy bc bytes from hl (data address) to de (variable address)
1551
pop de ; restore copy to address
1552
pop ix ; restore variable address
1553
ld (ix + 4), e ; put memory address low into variable
1554
ld (ix + 5), d ; put memory address high into variable
1555
ret ; variable assigned
1560
pop.parm ; get parameter boolean result in hl
1563
ld a, (ix+5) ; put boolean integer result in a
1569
ld hl, BASIC_TRPTBL_INTERVAL
1570
__call_basic BASIC_TRAP_DISABLE
1576
ld hl, BASIC_TRPTBL_SPRITE
1577
__call_basic BASIC_TRAP_DISABLE
1583
pop.parm ; get first parameter
1585
call GET_INT.VALUE ; output BC with integer value
1586
ld a, c ; A = screen number (0 to 3)
1588
jr c, SCREEN.1 ; if mode < 9, jump
1589
ld a, 8 ; else, fix to 8
1591
if DATA_SET_ITEMS_COUNT > 0
1592
call gfxSetScreenMode
1596
jp gfxClearTileScreen
1605
__call_bios BIOS_CHGCLR ; change VDP colors
1611
pop.parm ; get first parameter
1613
call GET_INT.VALUE ; output BC with integer value
1614
ld a, c ; A = pixel color
1615
;call gfxSetForeColor
1616
ld (BIOS_FORCLR), a ; foreground color
1623
pop.parm ; get first parameter
1625
call GET_INT.VALUE ; output BC with integer value
1626
ld a, c ; A = pixel color
1627
;call gfxSetBackColor
1628
ld (BIOS_BAKCLR), a ; foreground color
1634
pop.parm ; get first parameter
1636
call GET_INT.VALUE ; output BC with integer value
1637
ld a, c ; A = pixel color
1638
;call gfxSetBorderColor
1639
ld (BIOS_BDRCLR), a ; border color
1645
if DATA_SET_ITEMS_COUNT > 0
1647
jp z, gfxClearTileScreen
1649
xor a ; reset Z flag
1650
__call_bios BIOS_CLS ; clear screen
1656
pop.parm ; get first parameter
1658
call GET_INT.VALUE ; output BC with integer value
1659
pop.parm ; get second parameter
1660
push bc ; save first parameter as integer
1662
call GET_INT.VALUE ; output BC with integer value
1663
inc c ; BASIC has start position on 0,0 instead of 1,1 of BIOS
1664
ld l, c ; set second parameter (L = Y position)
1665
pop bc ; restore first parameter as integer
1666
inc c ; BASIC has start position on 0,0 instead of 1,1 of BIOS
1667
ld h, c ; set first parameter (H = X position)
1668
ld a, (BIOS_SCRMOD) ; 0=40x24 Text Mode, 1=32x24 Text Mode, 2=Graphics Mode, 3=Multicolour Mode
1670
jr nc, LOCATE.G ; jump if graphic screen mode (not a < 2)
1671
LOCATE.T: __call_bios BIOS_POSIT ; H = X, L = Y
1677
ld (BIOS_GRPACX), bc ;
1678
ld (BIOS_GRPACY), de ;
1679
__call_bios BIOS_SCALXY ; BC = X, DE = Y
1680
__call_bios BIOS_MAPXYC ; BC = X, DE = Y
1686
pop.parm ; get first parameter
1689
ret z ; return if string size zero
1690
if DATA_SET_ITEMS_COUNT > 0
1691
ld (BIOS_TEMP), a ; size of string
1695
; discard if first char < 32 or > 126
1702
; adjust default color
1706
sra a ; Y / 8 = bank
1715
call gfxSetTileDefaultColor
1722
ld hl, (BIOS_GRPACY)
1724
;call MATH.MULT.16 ; slow y * 32
1734
ld de, (BIOS_GRPACX)
1736
ld de, (BIOS_GRPNAM)
1762
pop.parm ; get first parameter
1764
call GET_INT.VALUE ; output BC with integer value
1766
__call_bios BIOS_GTTRIG
1768
jp z, BOOLEAN.RET.FALSE ;
1774
call MATH.PARM.POP ; get parameters into DAC/ARG
1775
ld a, (BASIC_VALTYP) ;
1776
cp 2 ; test if integer
1777
jp z, BOOLEAN.OR.INT ;
1778
jp MATH.ERROR ; it is a double
1782
; abstract virtual GOTO
1788
call GET_INT.VALUE ; output BC with integer value
1804
jp z, BOOLEAN.RET.FALSE ;
1810
__call_bios BIOS_BEEP ; play a beep in the system speaker
1816
pop.parm ; get first parameter
1818
call GET_INT.VALUE ; output BC with integer value
1819
ld a, c ; A = sprite mode (0 to 3)
1826
ld (BASIC_DATPTR), hl ; data items pointer
1828
ld (BASIC_DATLIN), hl ; data items index
1833
; abstract virtual GOSUB
1837
pop.parm ; get first parameter in HL
1839
call GET_INT.VALUE ; put parameter into BC (trap handler)
1844
ld hl, BASIC_TRPTBL_SPRITE
1845
jp SET_TRAP ; hl = trap block, de = trap handler pointer
1850
pop.parm ; get first parameter in HL
1852
call GET_INT.VALUE ; put parameter into BC (interval value)
1854
ld (BASIC_INTVAL), bc
1855
ld (BASIC_INTCNT), bc
1857
pop.parm ; get first parameter in HL
1859
call GET_INT.VALUE ; put parameter into BC (trap handler)
1864
ld hl, BASIC_TRPTBL_INTERVAL
1865
jp SET_TRAP ; hl = trap block, de = trap handler pointer
1869
; abstract virtual FOR
1873
call MATH.PARM.POP ; get parameters into DAC/ARG
1874
ld a, (BASIC_VALTYP) ;
1875
cp 2 ; test if integer
1876
jp z, MATH.ADD.INT ;
1877
cp 3 ; test if string
1878
jp z, STRING.CONCAT ;
1879
cp 4 ; test if single
1880
jp z, MATH.ADD.SGL ;
1881
jp MATH.ADD.DBL ; it is a double
1886
call MATH.PARM.POP ; get parameters into DAC/ARG
1887
ld a, (BASIC_VALTYP) ;
1888
cp 2 ; test if integer
1889
jp z, BOOLEAN.LE.INT ;
1890
cp 3 ; test if string
1891
jp z, BOOLEAN.LE.STR ;
1892
cp 4 ; test if single
1893
jp z, BOOLEAN.LE.SGL ;
1894
jp BOOLEAN.LE.DBL ; it is a double
1899
pop.parm ; get first parameter in HL
1901
call GET_INT.VALUE ; put parameter into BC
1902
call COPY_TO.VAR_DUMMY.INT ; create a fake integer variable from BC in HL
1908
pop.parm ; get parameter
1909
call COPY_TO.DAC ; put in DAC
1910
and 12 ; test if single/double
1911
jr nz, RND.1 ; if already double
1912
__call_bios MATH_FRCDBL ; convert DAC to double
1913
RND.1: __call_bios MATH_RND ; put in DAC a new random number from previous DAC parameter
1914
jp MATH.PARM.PUSH ; return a dummy double variable from DAC
1919
call MATH.PARM.POP ; get parameters into DAC/ARG
1920
ld a, (BASIC_VALTYP) ;
1921
cp 2 ; test if integer
1922
jp z, MATH.MULT.INT ;
1923
cp 3 ; test if string
1925
cp 4 ; test if single
1926
jp z, MATH.MULT.SGL ;
1927
jp MATH.MULT.DBL ; it is a double
1937
pop.parm ; get first parameter
1939
call GET_INT.VALUE ; output BC with integer value
1940
ld (BIOS_GRPACX), bc ; X
1941
pop.parm ; get second parameter
1943
call GET_INT.VALUE ; output BC with integer value
1944
ld (BIOS_GRPACY), bc ; Y
1950
pop.parm ; get first parameter
1952
call GET_INT.VALUE ; output BC with integer value
1954
call gfxSetForeColor
1959
; abstract virtual NEXT
1963
ld hl, BASIC_TRPTBL_INTERVAL
1964
__call_basic BASIC_TRAP_ENABLE
1970
ld hl, BASIC_TRPTBL_SPRITE
1971
__call_basic BASIC_TRAP_ENABLE
1977
pop.parm ; get first parameter
1979
call GET_INT.VALUE ; output BC with integer value
1981
__call_bios BIOS_GTSTCK
1984
call COPY_TO.VAR_DUMMY.INT ; create a fake integer variable from BC in HL
1990
call MATH.PARM.POP ; get parameters into DAC/ARG
1991
ld a, (BASIC_VALTYP) ;
1992
cp 2 ; test if integer
1993
jp z, BOOLEAN.EQ.INT ;
1994
cp 3 ; test if string
1995
jp z, BOOLEAN.EQ.STR ;
1996
cp 4 ; test if single
1997
jp z, BOOLEAN.EQ.SGL ;
1998
jp BOOLEAN.EQ.DBL ; it is a double
2003
call MATH.PARM.POP ; get parameters into DAC/ARG
2004
ld a, (BASIC_VALTYP) ;
2005
cp 2 ; test if integer
2006
jp z, BOOLEAN.LT.INT ;
2007
cp 3 ; test if string
2008
jp z, BOOLEAN.LT.STR ;
2009
cp 4 ; test if single
2010
jp z, BOOLEAN.LT.SGL ;
2011
jp BOOLEAN.LT.DBL ; it is a double
2016
call MATH.PARM.POP ; get parameters into DAC/ARG
2017
ld a, (BASIC_VALTYP) ;
2018
cp 2 ; test if integer
2019
jp z, BOOLEAN.AND.INT ;
2020
jp MATH.ERROR ; it is a double
2025
call MATH.PARM.POP ; get parameters into DAC/ARG
2026
ld a, (BASIC_VALTYP) ;
2027
cp 2 ; test if integer
2028
jp z, BOOLEAN.GT.INT ;
2029
cp 3 ; test if string
2030
jp z, BOOLEAN.GT.STR ;
2031
cp 4 ; test if single
2032
jp z, BOOLEAN.GT.SGL ;
2033
jp BOOLEAN.GT.DBL ; it is a double
2038
call MATH.PARM.POP ; get parameters into DAC/ARG
2039
ld a, (BASIC_VALTYP) ;
2040
cp 2 ; test if integer
2041
jp z, MATH.SUB.INT ;
2042
cp 3 ; test if string
2044
cp 4 ; test if single
2045
jp z, MATH.SUB.SGL ;
2046
jp MATH.SUB.DBL ; it is a double
2051
pop.parm ; get sprite number
2053
call GET_INT.VALUE ; output BC with integer value
2054
ld (GFX_TEMP), bc ; sprite number
2058
call GET_INT.VALUE ; output BC with integer value
2059
ld (GFX_TEMP1), bc ; X
2063
call GET_INT.VALUE ; output BC with integer value
2064
ld (GFX_TEMP2), bc ; Y
2066
pop.parm ; get color
2068
call GET_INT.VALUE ; output BC with integer value
2069
ld (GFX_TEMP3), bc ; color
2079
call gfxSetSpriteColorInt
2081
ld bc, (GFX_TEMP) ; sprite number
2082
jp gfxUpdateSpriteCollisionTable
2086
; abstract virtual RETURN
2090
call CLEAR.DAC ; put zero in DAC
2091
pop.parm ; get parameter
2092
call COPY_TO.ARG ; put in ARG
2093
cp 2 ; test if integer
2094
jp z, MATH.SUB.INT ;
2095
cp 4 ; test if single
2096
jp z, MATH.SUB.SGL ;
2097
cp 8 ; test if double
2098
jp z, MATH.SUB.DBL ;
2104
call MATH.PARM.POP.INT ; get parameters as integer into DAC/ARG
2110
pop.parm ; get first parameter
2112
call GET_INT.VALUE ; output BC with integer value
2113
ld (GFX_TEMP1), bc ; dX
2114
pop.parm ; get second parameter
2116
call GET_INT.VALUE ; output BC with integer value
2121
ld bc, (GFX_TEMP1) ; dX
2122
or 1 ; a = 1 (filled box)
2128
pop.parm ; get first parameter (variable to be read)
2129
push hl ; save input variable...
2131
ld hl, (BASIC_DATLIN) ; index of data items
2132
ld de, DATA_ITEMS_COUNT ; count of data items
2133
sbc hl, de ; compare hl >= de
2134
jr z, READ.END ; jump if equal
2135
jr nc, READ.END ; jump if above
2136
pop de ; restore saved input variable to DE
2137
ld ix, (BASIC_DATPTR) ; data items pointer
2140
push.parm ; LET parameter 2 - data as right operand
2141
ex de, hl ; put DE into HL
2142
push.parm ; LET parameter 1 - input variable as left operand
2143
call LET ; put data into variable
2144
ld hl, (BASIC_DATLIN) ; old index of data items
2146
ld (BASIC_DATLIN), hl ; save new index of data items
2147
ld hl, (BASIC_DATPTR) ; old data items pointer
2151
ld (BASIC_DATPTR), hl ; save new data items pointer
2158
pop.parm ; get first parameter
2160
call GET_INT.VALUE ; output BC with integer value
2162
ld bc, 2 ; string size
2163
call memory.alloc ; in bc size, out ix new memory address, nz=OK
2164
jp z, memory.error ;
2173
call COPY_TO.VAR_DUMMY.STR ; create a fake string variable from HL in HL
2179
pop.parm ; get sprite number
2181
call GET_INT.VALUE ; output BC with integer value
2182
ld (GFX_TEMP), bc ; sprite number
2184
pop.parm ; get sprite data
2189
call GET_STR.ADDR ; put string address into hl
2191
ret z ; is string empty?
2193
ld c, a ; string size
2194
ld a, (GFX_TEMP) ; sprite number
2195
call gfxSetSpriteData
2199
ld c, a ; sprite number
2200
call gfxSetSpritePattern
2206
call gfxSetSpriteColorInt
2212
; abstract virtual DATA
2216
;---------------------------------------------------------------------------------------------------------
2217
; VARIABLES INITIALIZE
2218
;---------------------------------------------------------------------------------------------------------
2222
ld (VAR_DUMMY.COUNTER), a ; max circular queue = 8 dummys
2223
ld hl, VAR_DUMMY.DATA ; start of variable dummy circular queue
2224
ld (VAR_DUMMY.POINTER), hl
2225
ld b, VAR_DUMMY.LENGTH
2230
djnz INITIALIZE_DUMMY.1
2235
ld (BASIC_DATPTR), hl ; next DATA pointer to use by READ command
2237
ld (BASIC_DATLIN), hl ; index of DATA item to use by READ command
2240
INITIALIZE_VARIABLES:
2241
call INITIALIZE_DATA
2242
call INITIALIZE_DUMMY
2245
call gfxInitSpriteCollisionTable
2248
;if defined COMPILE_TO_ROM
2249
; ld ix, BIOS_JIFFY ; initialize rom clock
2258
ld d, 2 ; any = default integer
2259
ld c, 0 ; variable name 1 (variable number)
2260
ld b, 0 ; variable name 2 (type flag=any)
2261
call INIT_VAR ; variable initialize
2263
ld d, 2 ; any = default integer
2264
ld c, 1 ; variable name 1 (variable number)
2265
ld b, 0 ; variable name 2 (type flag=any)
2266
call INIT_VAR ; variable initialize
2268
ld d, 2 ; any = default integer
2269
ld c, 2 ; variable name 1 (variable number)
2270
ld b, 0 ; variable name 2 (type flag=any)
2271
call INIT_VAR ; variable initialize
2273
ld d, 2 ; any = default integer
2274
ld c, 3 ; variable name 1 (variable number)
2275
ld b, 0 ; variable name 2 (type flag=any)
2276
call INIT_VAR ; variable initialize
2278
ld d, 2 ; any = default integer
2279
ld c, 4 ; variable name 1 (variable number)
2280
ld b, 0 ; variable name 2 (type flag=any)
2281
call INIT_VAR ; variable initialize
2283
ld d, 2 ; any = default integer
2284
ld c, 5 ; variable name 1 (variable number)
2285
ld b, 0 ; variable name 2 (type flag=any)
2286
call INIT_VAR ; variable initialize
2289
ld c, 6 ; variable name 1 (variable number)
2290
ld b, 255 ; variable name 2 (type flag=fixed)
2291
call INIT_VAR ; variable initialize
2294
ld c, 7 ; variable name 1 (variable number)
2295
ld b, 255 ; variable name 2 (type flag=fixed)
2296
call INIT_VAR ; variable initialize
2298
ld d, 2 ; any = default integer
2299
ld c, 8 ; variable name 1 (variable number)
2300
ld b, 0 ; variable name 2 (type flag=any)
2301
call INIT_VAR ; variable initialize
2303
ld d, 2 ; any = default integer
2304
ld c, 9 ; variable name 1 (variable number)
2305
ld b, 0 ; variable name 2 (type flag=any)
2306
call INIT_VAR ; variable initialize
2309
ld c, 10 ; variable name 1 (variable number)
2310
ld b, 255 ; variable name 2 (type flag=fixed)
2311
call INIT_VAR ; variable initialize
2313
ld d, 2 ; any = default integer
2314
ld c, 11 ; variable name 1 (variable number)
2315
ld b, 0 ; variable name 2 (type flag=any)
2316
call INIT_VAR ; variable initialize
2319
ld c, 12 ; variable name 1 (variable number)
2320
ld b, 255 ; variable name 2 (type flag=fixed)
2321
call INIT_VAR ; variable initialize
2325
;---------------------------------------------------------------------------------------------------------
2327
;---------------------------------------------------------------------------------------------------------
2329
BIOS_BASIC_SLOT_ENABLE:
2332
__call_bios BIOS_ENASLT ; Select main ROM on page 0 (0000h~3FFFh)
2334
if defined COMPILE_TO_BIN or defined COMPILE_TO_DOS
2338
__call_bios BIOS_ENASLT ; Select main ROM on page 1 (4000h~7FFFh)
2344
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
2348
RUN_TRAPS.1: push hl
2359
; in hl = trap block address (handle trap: sts=5? has handler? ackn, pause, run trap, sts=1? unpause)
2361
ld a, (hl) ; trap status
2362
cp 5 ; trap occured AND trap not paused AND trap enabled ?
2363
ret nz ; return if false
2365
ld e, (hl) ; get trap address
2372
ret z ; return if address zero
2374
__call_basic BASIC_TRAP_ACKNW
2375
__call_basic BASIC_TRAP_PAUSE
2376
ld hl, TRAP_HANDLER.1
2377
ld a, (BASIC_ONGSBF) ; save traps execution
2380
ld (BASIC_ONGSBF), a ; disable traps execution
2381
push hl ; next return will be to trap handler
2382
push de ; indirect jump to trap address
2384
TRAP_HANDLER.1: pop af
2385
ld (BASIC_ONGSBF), a ; restore traps execution
2388
cp 1 ; trap enabled?
2390
__call_basic BASIC_TRAP_UNPAUSE
2393
; hl = trap block, de = trap handler
2395
ld (hl), a ; trap block status
2397
ld (hl), e ; trap block handler (pointer)
2404
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
2407
ld (BIOS_TEMP), a ; save voice number
2411
ret nz ; return if not string
2414
ld (BIOS_TEMP2), a ; save string size
2415
push hl ; string address
2416
ld a, (BIOS_TEMP) ; restore voice number
2417
__call_bios BIOS_GETVCP ; get PSG voice buffer address (in A = voice number, out HL = address of byte 2)
2419
ld a, (BIOS_TEMP2) ; restore string size
2420
ld (hl), a ; string size
2422
ld (hl), e ; string address
2426
ld D,H ; voice stack
2441
;---------------------------------------------------------------------------------------------------------
2442
; VARIABLES ROUTINES
2443
;---------------------------------------------------------------------------------------------------------
2445
; input hl = variable address
2446
; input bc = variable name
2447
; input d = variable type
2448
INIT_VAR: ld (hl), d ; variable type
2450
ld (hl), c ; variable name 1
2452
ld (hl), b ; variable name 2
2466
CLEAR.VAR.LOOP: inc hl
2467
ld (hl), 0 ; data address/value
2470
; input HL = variable address
2471
; input A = variable output type
2472
; output HL = casted data address
2482
; input HL = variable address
2483
; output HL = variable address
2484
CAST_TO.INT: ;push af
2489
jp z, CAST_STR_TO.INT
2491
jp z, CAST_SGL_TO.INT
2493
jp z, CAST_DBL_TO.INT
2496
; input HL = variable address
2497
; output HL = variable address
2498
CAST_TO.STR: ;push af
2501
jp z, CAST_INT_TO.STR
2505
jp z, CAST_SGL_TO.STR
2507
jp z, CAST_DBL_TO.STR
2510
; input HL = variable address
2511
; output HL = variable address
2512
CAST_TO.SGL: ;push af
2515
jp z, CAST_INT_TO.SGL
2517
jp z, CAST_STR_TO.SGL
2521
jp z, CAST_DBL_TO.SGL
2524
; input HL = variable address
2525
; output HL = variable address
2526
CAST_TO.DBL: ;push af
2529
jp z, CAST_INT_TO.DBL
2531
jp z, CAST_STR_TO.DBL
2533
jp z, CAST_SGL_TO.DBL
2538
CAST_SGL_TO.STR: ; same as CAST_INT_TO.STR
2539
CAST_DBL_TO.STR: ; same as CAST_INT_TO.STR
2540
CAST_INT_TO.STR: call COPY_TO.DAC
2542
__call_bios MATH_FOUT ; convert DAC to string
2545
CAST_INT_TO.SGL: call COPY_TO.DAC
2546
__call_bios MATH_FRCSGL
2549
CAST_INT_TO.DBL: call COPY_TO.DAC
2550
__call_bios MATH_FRCDBL
2553
CAST_SGL_TO.INT: ; same as CAST_DBL_TO.INT
2554
CAST_DBL_TO.INT: call COPY_TO.DAC
2555
__call_bios MATH_FRCINT
2558
CAST_STR_TO.INT: call CAST_STR_TO.VAL ;
2559
__call_bios MATH_FRCINT ;
2562
CAST_STR_TO.SGL: call CAST_STR_TO.VAL ;
2563
__call_bios MATH_FRCSGL ;
2566
CAST_STR_TO.DBL: call CAST_STR_TO.VAL ;
2567
__call_bios MATH_FRCDBL ;
2570
CAST_STR_TO.VAL: call GET_STR.ADDR ;
2572
__call_bios MATH_FIN ; convert string to a value type
2575
GET_INT.VALUE: inc hl ; output BC with integer value
2581
CAST_SGL_TO.DBL: ; same as GET_DBL.ADDR
2582
CAST_DBL_TO.SGL: ; same as GET_DBL.ADDR
2583
GET_INT.ADDR: ; same as GET_DBL.ADDR
2584
GET_SGL.ADDR: ; same as GET_DBL.ADDR
2585
GET_DBL.ADDR: inc hl
2590
GET_STR.ADDR: push hl
2596
; input hl = string address
2597
; output b = string length
2598
GET_STR.LENGTH: ld b, 0
2599
GET_STR.LEN.NEXT: ld a, (hl)
2606
jr z, GET_STR.LEN.ERR
2608
GET_STR.LEN.ERR: ld b, 0
2610
STRING.COMPARE: ld ix, (BASIC_DAC+1) ; string 1
2611
ld iy, (BASIC_ARG+1) ; string 2
2612
STRING.COMPARE.NX: ld a, (ix) ; next char from string 1
2613
cp (iy) ; char s1 = char s2?
2614
jr nz, STRING.COMPARE.NE ; if not equal...
2616
jr z, STRING.COMPARE.F1 ; if string 1 has finished...
2617
ld a, (iy) ; next char from string 2
2619
jr z, STRING.COMPARE.GT ; if s2 has finished, s1 has not finished yet, so s1 is greater than s2
2622
jr STRING.COMPARE.NX ; get next char pair
2623
STRING.COMPARE.F1: ld a, (iy) ; verify if string 2 has finished too
2625
jr z, STRING.COMPARE.EQ ; if s2 has finished, then they are equals
2626
jr STRING.COMPARE.LT ; else, result = s1 is less than s2
2627
STRING.COMPARE.NE: jr c, STRING.COMPARE.GT ; verify if s1 is greater than s2...
2628
STRING.COMPARE.LT: ld a, 1 ; ...else, result = s1 less than s2
2630
STRING.COMPARE.GT: ld a, 0xFF ; result = s1 is greater than s2
2632
STRING.COMPARE.EQ: xor a ; result = s1 is equal to s2
2634
STRING.CONCAT: ld ix, BASIC_DAC ; s1 size
2635
ld a, (BASIC_ARG) ; s2 size
2636
add a, (ix) ; s3 size = s1 size + s2 size
2640
inc bc ; add 1 byte to size
2641
call memory.alloc ; in bc size, out ix new memory address, nz=OK
2642
jp z, memory.error ;
2646
ld a, (BASIC_DAC) ; s1 size
2647
ld hl, (BASIC_DAC + 1) ; string 1
2648
call COPY_TO.STR ; copy to new memory
2649
ld a, (BASIC_ARG) ; s2 size
2650
ld hl, (BASIC_ARG + 1) ; string 2
2651
call COPY_TO.STR ; copy to new memory
2653
ld (de), a ; null terminated
2656
call COPY_TO.VAR_DUMMY.STR ;
2657
ret.parm ; WARNING - VERIFY STRING MEMORY LEAKs
2658
STRING.PRINT: ld a, (BIOS_SCRMOD) ; 0=40x24 Text Mode, 1=32x24 Text Mode, 2=Graphics Mode, 3=Multicolour Mode
2660
jr nc, STRING.PRINT.G2 ; jump if graphic screen mode MSX2 (>=5)
2662
jr nc, STRING.PRINT.G1 ; jump if graphic screen mode MSX1 (>=2)
2663
STRING.PRINT.T: ld a, (hl) ; get a char from a string parameter
2664
or a ; cp 0 - is it the string end?
2666
__call_bios BIOS_CHPUT ; put the char (a) into text screen
2668
jr STRING.PRINT.T ; repeat
2669
STRING.PRINT.G1: ld a, (hl) ; get a char from a string parameter
2670
or a ; cp 0 - is it the string end?
2672
__call_bios BIOS_GRPPRT ; put the char (a) into graphical screen
2674
jr STRING.PRINT.G1 ; repeat
2675
STRING.PRINT.G2: ld a, (hl) ; get a char from a string parameter
2676
or a ; cp 0 - is it the string end?
2678
ld ix, BIOS_GRPPRT2 ; put the char (a) into graphical screen
2681
jr STRING.PRINT.G2 ; repeat
2683
; a = string size to copy
2684
; input hl = string from
2685
; input de = string to
2687
ret z ; avoid copy if size = zero
2689
ld c, a ; string size
2690
ldir ; copy bc bytes from hl to de
2692
COPY_TO.BASIC_BUF: ld bc, BASIC_BUF
2693
ld a, (LIT_QUOTE_CHAR)
2696
COPY_BAS_BUF.LOOP: ld a, (hl)
2698
jr z, COPY_BAS_BUF.EXIT
2702
jr COPY_BAS_BUF.LOOP
2703
COPY_BAS_BUF.EXIT: ld a, (LIT_QUOTE_CHAR)
2710
COPY_TO.VAR_DUMMY: ld a, (BASIC_VALTYP) ; create dummy variable from VALTYPE
2712
jr nz, COPY_TO.VAR_DUMMY.DBL
2714
call GET_STR.LENGTH ; get string length
2716
ld a, b ; string length
2717
COPY_TO.VAR_DUMMY.STR: call GET_VAR_DUMMY.ADDR ; create dummy string variable from HL
2718
ld (ix), 3 ; data type string
2720
ld (ix+2), 255 ; var type fixed
2721
ld (ix+3), a ; string length
2722
ld (ix+4), l ; data address low
2723
ld (ix+5), h ; data address high
2724
;call GET_STR.LENGTH ; get string length
2725
;ld (ix+3), b ; string length
2726
push ix ; output var address...
2729
COPY_TO.VAR_DUMMY.INT: call GET_VAR_DUMMY.ADDR ; create dummy integer variable from BC
2730
ld (ix), 2 ; data type string
2741
push ix ; output var address...
2744
COPY_TO.VAR_DUMMY.DBL: call GET_VAR_DUMMY.ADDR ; create dummy value variable from DAC
2745
ld (ix), a ; data type
2750
push ix ; just to copy ix to de
2755
ldir ; copy bc bytes from hl (data address) to de (variable address)
2756
push ix ; output var address...
2759
GET_VAR_DUMMY.ADDR: push af ;
2762
ld ix, (VAR_DUMMY.POINTER) ;
2763
ld a, (VAR_DUMMY.COUNTER) ;
2764
GET_VAR_DUMMY.NEXT: add ix, de ;
2767
jr nz, GET_VAR_DUMMY.EXIT ;
2769
ld ix, VAR_DUMMY.DATA ;
2770
GET_VAR_DUMMY.EXIT: ld (VAR_DUMMY.POINTER), ix ;
2771
ld (VAR_DUMMY.COUNTER), a ;
2772
ld a, (ix) ; get last var dummy type
2773
cp 3 ; is it string?
2774
call z, GET_VAR_DUMMY.FREE ; free string memory
2781
ld l, (ix+4) ; get string data address
2785
call memory.free ; free memory
2789
; input hl = variable address
2790
COPY_TO.DAC: ld de, BASIC_DAC
2791
COPY_TO.DAC.DATA: ld a, (hl)
2792
ld (BASIC_VALTYP), a
2796
ld bc, 8 ; data = 8 bytes
2797
ldir ; copy bc bytes from hl (data address) to de (variable address)
2799
COPY_TO.ARG: ld de, BASIC_ARG ;
2800
jr COPY_TO.DAC.DATA ;
2801
COPY_TO.DAC_ARG: ld hl, BASIC_DAC ;
2803
ld bc, 8 ; data = 8 bytes
2804
ldir ; copy bc bytes from hl (data address) to de (variable address)
2806
COPY_TO.ARG_DAC: ld hl, BASIC_ARG ;
2808
ld bc, 8 ; data = 8 bytes
2809
ldir ; copy bc bytes from hl (data address) to de (variable address)
2811
COPY_TO.DAC_TMP: ld hl, BASIC_DAC ;
2812
ld de, BASIC_SWPTMP ;
2813
ld bc, 8 ; data = 8 bytes
2814
ldir ; copy bc bytes from hl (data address) to de (variable address)
2816
COPY_TO.TMP_DAC: ld hl, BASIC_SWPTMP ;
2818
ld bc, 8 ; data = 8 bytes
2819
ldir ; copy bc bytes from hl (data address) to de (variable address)
2822
exx ; save registers
2825
ld de, BASIC_SWPTMP ;
2826
ldir ; copy bc bytes from hl to de
2830
ldir ; copy bc bytes from hl to de
2832
ld hl, BASIC_SWPTMP ;
2834
ldir ; copy bc bytes from hl to de
2835
exx ; restore registers
2838
CLEAR.DAC: ld de, BASIC_DAC
2839
CLEAR.DAC.DATA: ld hl, BASIC_VALTYP
2842
ld bc, 8 ; data = 8 bytes
2843
ldir ; copy bc bytes from hl (data address) to de (variable address)
2845
CLEAR.ARG: ld de, BASIC_ARG
2851
;---------------------------------------------------------------------------------------------------------
2852
; MATH 16 BITS ROUTINES
2853
;---------------------------------------------------------------------------------------------------------
2855
MATH.PARM.POP: pop af ; get PC from caller stack
2856
ex af, af' ; save PC to temp
2857
pop.parm ; get first parameter
2858
call COPY_TO.ARG ; put HL in ARG (return var type in A)
2859
pop.parm ; get second parameter
2860
ex af, af' ; restore PC from temp
2861
push af ; put again PC from caller in stack
2862
ex af, af' ; restore 1st data type
2863
push af ; save 1st data type
2864
call COPY_TO.DAC ; put HL in DAC (return var type in A)
2865
pop bc ; restore 1st data type (ARG) in B
2866
cp b ; test if data type in A (DAC) = data type in B (ARG)
2867
ret z ; return if is equal data types
2868
MATH.PARM.CAST: push bc ; else cast both to double
2869
and 12 ; test if single/double
2870
jr nz, MATH.PARM.CST1 ; avoid cast if already single/double
2871
__call_bios MATH_FRCDBL ; convert DAC to double
2872
MATH.PARM.CST1: pop af ;
2873
and 12 ; test if single/double
2874
jr nz, MATH.PARM.CST2 ; avoid cast if already single/double
2875
ld (BASIC_VALTYP), a ;
2876
call COPY_TO.DAC_TMP ;
2877
call COPY_TO.ARG_DAC ;
2878
__call_bios MATH_FRCDBL ; convert ARG to double
2879
call COPY_TO.DAC_ARG ;
2880
call COPY_TO.TMP_DAC ;
2881
MATH.PARM.CST2: ld a, 8 ;
2882
ld (BASIC_VALTYP), a ;
2884
MATH.PARM.POP.INT: ; return result in DAC/ARG as integer
2885
pop af ; get PC from caller stack
2886
ex af, af' ; save PC to temp
2887
pop.parm ; get first parameter
2888
ld a, (hl) ; get parameter type
2889
and 2 ; test if integer
2890
jr z, MATH.PARM.POP.I1 ; do cast if not integer
2891
call COPY_TO.ARG ; put HL in ARG (return var type in A)
2892
jr MATH.PARM.POP.I2 ; go to next parameter
2893
MATH.PARM.POP.I1: call COPY_TO.DAC ; put HL in DAC (return var type in A)
2894
__call_bios MATH_FRCINT ; convert DAC to int
2895
call COPY_TO.DAC_ARG ; copy DAC to ARG
2896
MATH.PARM.POP.I2: pop.parm ; get second parameter
2897
call COPY_TO.DAC ; put HL in DAC (return var type in A)
2898
and 2 ; test if integer
2899
jr nz, MATH.PARM.POP.I3 ; avoid cast if already integer
2900
__call_bios MATH_FRCINT ; convert DAC to int
2902
ld (BASIC_VALTYP), a ;
2904
ex af, af' ; restore PC from temp
2905
push af ; put again PC from caller in stack
2907
MATH.PARM.PUSH: call COPY_TO.VAR_DUMMY ;
2913
; output in parm stack
2914
; http://www.z80.info/zip/zaks_book.pdf - page 104
2915
MATH.ADD.INT: ld hl, (BASIC_DAC+2) ;
2916
ld bc, (BASIC_ARG+2) ;
2918
ld (BASIC_DAC+2), hl ;
2923
if defined MATH.SUB or defined MATH.NEG
2926
; output in parm stack
2927
; http://www.z80.info/zip/zaks_book.pdf - page 104
2928
MATH.SUB.INT: ld hl, (BASIC_DAC+2) ;
2929
ld de, (BASIC_ARG+2) ;
2932
ld (BASIC_DAC+2), hl ;
2937
if defined MATH.MULT
2940
; output in parm stack
2941
MATH.MULT.INT: ld hl, (BASIC_DAC+2) ;
2942
ld bc, (BASIC_ARG+2) ;
2944
ld (BASIC_DAC+2), hl ;
2947
; input HL = multiplicand
2948
; input BC = multiplier
2949
; output HL = result
2950
; http://www.z80.info/zip/zaks_book.pdf - page 131
2951
MATH.MULT.16: ld a, c ; low multiplier
2952
ld c, b ; high multiplier
2954
ld d, h ; multiplicand
2957
MULT16LOOP: srl c ; right shift multiplier high
2958
rra ; rotate right multiplier low
2959
jr nc, MULT16NOADD ; test carry
2960
add hl, de ; add multiplicand to result
2961
MULT16NOADD: ex de, hl
2962
add hl, hl ; double - shift multiplicand
2969
if defined MATH.DIV or defined MATH.IDIV or defined MATH.MOD
2971
; input AC = dividend
2972
; input DE = divisor
2973
; output AC = quotient
2974
; output HL = remainder
2975
; http://www.z80.info/zip/zaks_book.pdf - page 140
2976
MATH.DIV.16: ld hl, 0 ; clear accumulator
2977
ld b, 16 ; set counter
2978
DIV16LOOP: rl c ; rotate accumulator result left
2980
adc hl, hl ; left shift
2981
sbc hl, de ; trial subtract divisor
2982
jr nc, $ + 3 ; subtract was OK ($ = current location)
2983
add hl, de ; restore accumulator
2984
ccf ; calculate result bit
2985
djnz DIV16LOOP ; counter not zero
2986
rl c ; shift in last result bit
2992
if defined GFX_FAST or defined LINE
2994
; compare two signed 16 bits integers
2995
; HL < DE: Carry flag
2996
; HL = DE: Zero flag
2997
; http://www.z80.info/zip/zaks_book.pdf - page 531
2998
MATH.COMP.S16: ld a, h ; test high order byte
2999
and 0x80 ; test sign, clear carry
3000
jr nz, MATH.COMP.S16.NEGM1 ; jump if hl is negative
3002
ret nz ; de is negative (and hl is positive)
3004
cp d ; signs are both positive, so normal compare
3006
ld a, l ; test low order byte
3009
MATH.COMP.S16.NEGM1:
3011
rla ; sign bit into carry
3012
ret c ; signs different
3014
cp d ; both signs negative
3024
MATH.ADD.SGL: ld a, 8 ;
3025
ld (BASIC_VALTYP), a ;
3026
MATH.ADD.DBL: __call_bios MATH_DECADD ;
3031
if defined MATH.SUB or defined MATH.NEG
3033
MATH.SUB.SGL: ld a, 8 ;
3034
ld (BASIC_VALTYP), a ;
3035
MATH.SUB.DBL: __call_bios MATH_DECSUB ;
3040
if defined MATH.MULT
3042
MATH.MULT.SGL: ld a, 8 ;
3043
ld (BASIC_VALTYP), a ;
3044
MATH.MULT.DBL: __call_bios MATH_DECMUL ;
3052
; output in parm stack
3053
MATH.DIV.INT: __call_bios MATH_FRCDBL ; convert DAC to double
3056
ld (BASIC_VALTYP), a ;
3057
__call_bios MATH_FRCDBL ; convert ARG to double
3059
MATH.DIV.SGL: ld a, 8 ;
3060
ld (BASIC_VALTYP), a ;
3061
MATH.DIV.DBL: __call_bios MATH_DECDIV ;
3066
if defined MATH.IDIV
3069
; output in parm stack
3070
MATH.IDIV.SGL: ld a, 8 ;
3071
ld (BASIC_VALTYP), a ;
3072
MATH.IDIV.DBL: __call_bios MATH_FRCINT ; convert DAC to integer
3075
ld (BASIC_VALTYP), a ;
3076
__call_bios MATH_FRCINT ; convert ARG to integer
3078
MATH.IDIV.INT: ld hl, (BASIC_DAC+2) ;
3081
ld de, (BASIC_ARG+2) ;
3085
ld (BASIC_DAC+2), hl ; quotient
3092
MATH.POW.INT: ld (BASIC_VALTYP), a ;
3093
__call_bios MATH_FRCDBL ; convert DAC to double
3096
ld (BASIC_VALTYP), a ;
3097
__call_bios MATH_FRCDBL ; convert ARG to double
3099
MATH.POW.SGL: ld a, 8 ;
3100
ld (BASIC_VALTYP), a ;
3101
MATH.POW.DBL: __call_bios MATH_DBLEXP ;
3108
;MATH.MOD.SGL: ld a, 8 ;
3109
; ld (BASIC_VALTYP), a ;
3110
;MATH.MOD.DBL: __call_bios MATH_FRCINT ; convert DAC to integer
3111
; call SWAP.DAC.ARG ;
3113
; ld (BASIC_VALTYP), a ;
3114
; __call_bios MATH_FRCINT ; convert ARG to integer
3115
; call SWAP.DAC.ARG ;
3116
MATH.MOD.INT: ld hl, (BASIC_DAC+2) ;
3119
ld de, (BASIC_ARG+2) ;
3121
ld (BASIC_DAC+2), hl ; remainder
3128
; fast 16-bit integer square root
3129
; http://www.retroprogramming.com/2017/07/a-fast-z80-integer-square-root.html
3130
; 92 bytes, 344-379 cycles (average 362)
3131
; v2 - 3 t-state optimization spotted by Russ McNulty
3132
; call with hl = number to square root
3133
; returns a = square root
3210
if defined RANDOMIZE or defined SEED
3212
MATH.RANDOMIZE: di ;
3213
ld bc, (BIOS_JIFFY) ;
3216
MATH.SEED: ld (BASIC_RNDX), bc ; seed to IRND
3217
push bc ; in bc = new integer seed
3221
ld (BASIC_DAC+2), bc ; copy bc to dac
3222
ld a, 2 ; type integer
3223
ld (BASIC_VALTYP), a ;
3224
__call_bios MATH_FRCDBL ; convert DAC integer to DAC double
3225
__call_bios MATH_NEG ; DAC = -DAC
3226
__call_bios MATH_RND ; put in DAC a new random number from previous DAC parameter
3231
MATH.ERROR: ld e, 13 ; type mismatch
3232
__call_basic BASIC_ERROR_HANDLER ;
3236
;---------------------------------------------------------------------------------------------------------
3238
;---------------------------------------------------------------------------------------------------------
3240
BOOLEAN.RET.TRUE: ld hl, LIT_TRUE ;
3242
BOOLEAN.RET.FALSE: ld hl, LIT_FALSE ;
3244
BOOLEAN.CMP.INT: ld hl, (BASIC_DAC+2) ;
3245
ld de, (BASIC_ARG+2) ;
3246
__call_bios MATH_ICOMP ;
3248
BOOLEAN.CMP.SGL: ld bc, (BASIC_ARG) ;
3249
ld de, (BASIC_ARG+2) ;
3250
__call_bios MATH_DCOMP ;
3252
BOOLEAN.CMP.DBL: __call_bios MATH_XDCOMP ;
3254
BOOLEAN.CMP.STR: call STRING.COMPARE ;
3257
if defined BOOLEAN.GT
3259
BOOLEAN.GT.INT: call BOOLEAN.CMP.INT ;
3261
BOOLEAN.GT.STR: call BOOLEAN.CMP.STR ;
3263
BOOLEAN.GT.SGL: call BOOLEAN.CMP.SGL ;
3265
BOOLEAN.GT.DBL: call BOOLEAN.CMP.DBL ;
3267
BOOLEAN.GT.RET: cp 0x01 ;
3268
jp z, BOOLEAN.RET.TRUE ;
3269
jp BOOLEAN.RET.FALSE ;
3272
if defined BOOLEAN.LT
3274
BOOLEAN.LT.INT: call BOOLEAN.CMP.INT ;
3276
BOOLEAN.LT.STR: call BOOLEAN.CMP.STR ;
3278
BOOLEAN.LT.SGL: call BOOLEAN.CMP.SGL ;
3280
BOOLEAN.LT.DBL: call BOOLEAN.CMP.DBL ;
3282
BOOLEAN.LT.RET: cp 0xFF ;
3283
jp z, BOOLEAN.RET.TRUE ;
3284
jp BOOLEAN.RET.FALSE ;
3288
if defined BOOLEAN.GE
3290
BOOLEAN.GE.INT: call BOOLEAN.CMP.INT ;
3292
BOOLEAN.GE.STR: call BOOLEAN.CMP.STR ;
3294
BOOLEAN.GE.SGL: call BOOLEAN.CMP.SGL ;
3296
BOOLEAN.GE.DBL: call BOOLEAN.CMP.DBL ;
3298
BOOLEAN.GE.RET: cp 0x01 ;
3299
jp z, BOOLEAN.RET.TRUE ;
3301
jp z, BOOLEAN.RET.TRUE ;
3302
jp BOOLEAN.RET.FALSE ;
3306
if defined BOOLEAN.LE
3308
BOOLEAN.LE.INT: call BOOLEAN.CMP.INT ;
3310
BOOLEAN.LE.STR: call BOOLEAN.CMP.STR ;
3312
BOOLEAN.LE.SGL: call BOOLEAN.CMP.SGL ;
3314
BOOLEAN.LE.DBL: call BOOLEAN.CMP.DBL ;
3316
BOOLEAN.LE.RET: cp 0xFF ;
3317
jp z, BOOLEAN.RET.TRUE ;
3319
jp z, BOOLEAN.RET.TRUE ;
3320
jp BOOLEAN.RET.FALSE ;
3324
if defined BOOLEAN.NE
3326
BOOLEAN.NE.INT: call BOOLEAN.CMP.INT ;
3328
BOOLEAN.NE.STR: call BOOLEAN.CMP.STR ;
3330
BOOLEAN.NE.SGL: call BOOLEAN.CMP.SGL ;
3332
BOOLEAN.NE.DBL: call BOOLEAN.CMP.DBL ;
3334
BOOLEAN.NE.RET: or a ; cp 0
3335
jp nz, BOOLEAN.RET.TRUE ;
3336
jp BOOLEAN.RET.FALSE ;
3340
if defined BOOLEAN.EQ
3342
BOOLEAN.EQ.INT: call BOOLEAN.CMP.INT ;
3344
BOOLEAN.EQ.STR: call BOOLEAN.CMP.STR ;
3346
BOOLEAN.EQ.SGL: call BOOLEAN.CMP.SGL ;
3348
BOOLEAN.EQ.DBL: call BOOLEAN.CMP.DBL ;
3350
BOOLEAN.EQ.RET: or a ; cp 0
3351
jp z, BOOLEAN.RET.TRUE ;
3352
jp BOOLEAN.RET.FALSE ;
3356
if defined BOOLEAN.AND
3358
BOOLEAN.AND.INT: ld a, (BASIC_DAC+2) ;
3359
ld hl, BASIC_ARG+2 ;
3361
ld (BASIC_DAC+2), a ;
3363
ld a, (BASIC_DAC+3) ;
3365
ld (BASIC_DAC+3), a ;
3371
if defined BOOLEAN.OR
3373
BOOLEAN.OR.INT: ld a, (BASIC_DAC+2) ;
3374
ld hl, BASIC_ARG+2 ;
3376
ld (BASIC_DAC+2), a ;
3378
ld a, (BASIC_DAC+3) ;
3380
ld (BASIC_DAC+3), a ;
3386
if defined BOOLEAN.XOR
3388
BOOLEAN.XOR.INT: ld a, (BASIC_DAC+2) ;
3389
ld hl, BASIC_ARG+2 ;
3391
ld (BASIC_DAC+2), a ;
3393
ld a, (BASIC_DAC+3) ;
3395
ld (BASIC_DAC+3), a ;
3401
if defined BOOLEAN.EQV
3403
BOOLEAN.EQV.INT: ld a, (BASIC_DAC+2) ;
3404
ld hl, BASIC_ARG+2 ;
3407
ld (BASIC_DAC+2), a ;
3409
ld a, (BASIC_DAC+3) ;
3412
ld (BASIC_DAC+3), a ;
3418
if defined BOOLEAN.IMP
3420
BOOLEAN.IMP.INT: ld a, (BASIC_DAC+2) ;
3421
ld hl, BASIC_ARG+2 ;
3424
ld (BASIC_DAC+2), a ;
3426
ld a, (BASIC_DAC+3) ;
3429
ld (BASIC_DAC+3), a ;
3435
if defined BOOLEAN.SHR
3437
BOOLEAN.SHR.INT: ld ix, BASIC_DAC+2 ; shift DAC integer to right (bits 15...0-->)
3438
ld a, (BASIC_ARG+2) ;
3440
jp z, MATH.PARM.PUSH ; return if not shift
3441
ld b, a ; shift count
3442
BOOLEAN.SHR.INT.N: rr (ix+1) ;
3445
djnz BOOLEAN.SHR.INT.N ; next shift
3447
jp MATH.PARM.PUSH ; return DAC
3451
if defined BOOLEAN.SHL
3453
BOOLEAN.SHL.INT: ld ix, BASIC_DAC+2 ; shift DAC integer to left (<--bits 15...0)
3454
ld a, (BASIC_ARG+2) ;
3456
jp z, MATH.PARM.PUSH ; return if not shift
3457
ld b, a ; shift count
3458
BOOLEAN.SHL.INT.N: rl (ix) ;
3461
djnz BOOLEAN.SHL.INT.N ; next shift
3463
jp MATH.PARM.PUSH ; return DAC
3467
if defined BOOLEAN.NOT
3469
BOOLEAN.NOT.INT: ld a, (BASIC_DAC+2) ;
3471
ld (BASIC_DAC+2), a ;
3472
ld a, (BASIC_DAC+3) ;
3474
ld (BASIC_DAC+3), a ;
3483
;---------------------------------------------------------------------------------------------------------
3484
; MEMORY ALLOCATION ROUTINES
3485
;---------------------------------------------------------------------------------------------------------
3486
; Adapted from memory allocator code by SamSaga2, Spain, 2015
3487
; https://www.msx.org/forum/msx-talk/development/asm-memory-allocator
3488
; https://www.msx.org/users/samsaga2
3489
;---------------------------------------------------------------------------------------------------------
3490
memory.heap_start: equ VAR_STACK.END + 1 ; start at end of variable stack
3491
memory.heap_end: equ 0xF0A0 - 100 ; end at start of work area for stack (100 bytes reserved), BIOS and BASIC interpreter
3492
block.next: equ 0 ; next free block address
3493
block.size: equ 2 ; size of block including header
3494
block: equ 4 ; block.next + block.size
3498
ld ix,memory.heap_start ; first block
3499
ld hl,memory.heap_start+block ; second block
3500
;; first block NEXT=secondblock, SIZE=0
3501
;; with this block we have a fixed start location
3502
;; because never will be allocated
3503
ld (ix+block.next),l
3504
ld (ix+block.next+1),h
3505
ld (ix+block.size),0
3506
ld (ix+block.size+1),0
3507
;; second block NEXT=0, SIZE=all
3508
;; the first and only free block have all available memory
3509
ld (ix+block.next+block),0
3510
ld (ix+block.next+block+1),0
3512
;ld hl,memory.heap_end ; size = @heap_end (stack) - heap_start - block_header * 2 - 100 (buffer for stack)
3515
ld de, memory.heap_start + (block * 2) + 100
3517
;ld de, block * 2 + 100
3519
ld (ix+block.size+block),l
3520
ld (ix+block.size+block+1),h
3524
;; IN BC=size, OUT IX=memptr, NZ=ok
3532
ld ix,memory.heap_start ; this
3535
ld l,(ix+block.size)
3536
ld h,(ix+block.size+1)
3539
jp z, memory.alloc.exactfit
3540
jp c, memory.alloc.nextblock
3541
;; split found block
3542
memory.alloc.splitfit:
3543
;; free space must allow at least two blocks headers (current + next)
3545
jr nz, memory.alloc.splitfit.do ; if free space > 0xFF, do split
3548
jr c, memory.alloc.nextblock ; if free space < 4, skip to next block
3549
memory.alloc.splitfit.do:
3550
;; newfreeblock = this + BC
3554
;; prevblock->next = newfreeblock
3555
ld (iy+block.next),l
3556
ld (iy+block.next+1),h
3557
;; newfreeblock->next = this->next
3559
pop iy ; iy = newfreeblock
3560
ld l,(ix+block.next)
3561
ld h,(ix+block.next+1)
3562
ld (iy+block.next),l
3563
ld (iy+block.next+1),h
3564
;; newfreeblock->size = this->size - BC
3565
ld l,(ix+block.size)
3566
ld h,(ix+block.size+1)
3569
ld (iy+block.size),l
3570
ld (iy+block.size+1),h
3572
ld (ix+block.size),c
3573
ld (ix+block.size+1),b
3575
;; use whole found block
3576
memory.alloc.exactfit:
3577
;; prevblock->next = this->next - remove block from free list
3578
ld l,(ix+block.next)
3579
ld h,(ix+block.next+1)
3580
ld (iy+block.next),l
3581
ld (iy+block.next+1),h
3590
memory.alloc.nextblock:
3591
ld l,(ix+block.next)
3592
ld h,(ix+block.next+1)
3599
;; this = this->next
3602
jp memory.alloc.find
3607
;; HL = IX - block_header_size
3614
ld ix,memory.heap_start
3616
ld e,(ix+block.next)
3617
ld d,(ix+block.next+1)
3620
jp z, memory.free.passedend
3621
sbc hl,de ; test this (HL) against next (DE)
3622
jr c, memory.free.found ; if DE > HL
3623
add hl,de ; restore hl value
3625
pop ix ; current = next
3628
;; ix=prev, hl=this, de=next
3630
add hl,de ; restore hl value
3631
ld (ix+block.next), l
3632
ld (ix+block.next+1), h ; prev->next = this
3635
ld (iy+block.next), e
3636
ld (iy+block.next+1), d ; this->next = next
3637
push ix ; prev x this
3642
call memory.free.coalesce
3643
pop ix ; this x next
3644
jr memory.free.coalesce
3648
memory.free.coalesce:
3649
ld c, (iy+block.size)
3650
ld b, (iy+block.size+1) ; bc = this->size
3654
adc hl, bc ; hl = this + this->size
3658
sbc hl, de ; if this + this->size == next, then this->size += next->size, this->next = next->next
3659
jr z, memory.free.coalesce.do
3660
push ix ; else, new *this = *next
3663
memory.free.coalesce.do:
3664
ld l, (ix+block.size)
3665
ld h, (ix+block.size+1) ; hl = next->size
3667
adc hl, bc ; hl += this->size
3668
ld (iy+block.size), l
3669
ld (iy+block.size+1), h ; this->size = hl
3670
ld l, (ix+block.next)
3671
ld h, (ix+block.next+1) ; hl = next->next
3672
ld (iy+block.next), l
3673
ld (iy+block.next+1), h ; this->next = hl
3676
memory.free.passedend:
3677
;; append block at the end of the free list
3678
ld (ix+block.next),l
3679
ld (ix+block.next+1),h
3682
ld (iy+block.next),0
3683
ld (iy+block.next+1),0
3689
ld ix,memory.heap_start
3691
memory.get_free.count:
3693
add a,(ix+block.size)
3696
adc a,(ix+block.size+1)
3698
ld l,(ix+block.next)
3699
ld h,(ix+block.next+1)
3705
jr memory.get_free.count
3707
memory.error: ld e, 7 ; out of memory
3708
__call_basic BASIC_ERROR_HANDLER ;
3715
;---------------------------------------------------------------------------------------------------------
3717
; By: Amaury Carvalho, 2019
3718
;---------------------------------------------------------------------------------------------------------
3720
; https://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm#Algorithm_for_integer_arithmetic
3721
; https://en.wikipedia.org/wiki/Midpoint_circle_algorithm
3722
; https://rosettacode.org/wiki/Bitmap/Midpoint_circle_algorithm#C
3723
; https://www.msx.org/wiki/MSX-BASIC_Instructions
3724
;---------------------------------------------------------------------------------------------------------
3726
;---------------------------------------------------------------------------------------------------------
3728
;---------------------------------------------------------------------------------------------------------
3730
BIOS_WRTVDP: EQU 0x0047
3731
BIOS_RDVRM: EQU 0x004A
3732
BIOS_WRTVRM: EQU 0x004D
3733
BIOS_LDIRVM: EQU 0x005C
3734
BIOS_LDIRMV: EQU 0x0059
3735
BIOS_PNTINI: EQU 0x18CF
3736
BIOS_RIGHTC: EQU 0x16C5 ; Move current pixel physical address right
3737
BIOS_TRIGHTC: EQU 0x16AC ; Test then RIGHTC if legal
3738
BIOS_LEFTC: EQU 0x16EE ; Move current pixel physical address left
3739
BIOS_TLEFTC: EQU 0x16D8 ; Test then LEFTC if legal
3740
BIOS_UPC: EQU 0x175D ; Move current pixel physical address up
3741
BIOS_TUPC: EQU 0x173C ; Test then UPC if legal
3742
BIOS_DOWNC: EQU 0x172A ; Move current pixel physical address down
3743
BIOS_TDOWNC: EQU 0x170A ; Test then DOWNC if legal
3744
BIOS_DCOMPR: EQU 0x146A ; compare HL and DE (Flag NC if HL>DE, Flag Z if HL=DE, Flag C if HL<DE)
3745
BIOS_FILVRM: EQU 0x0056 ; fill VRAM with value
3747
BIOS_BIGFIL: EQU 0x016B ; msx 2
3748
BIOS_NRDVRM: EQU 0x0174 ; msx 2
3749
BIOS_NWRVRM: EQU 0x0177 ; msx 2
3750
BIOS_NRDVDP: EQU 0x013E ; msx 2
3751
BIOS_VDPSTA: EQU 0x0131 ; msx 2
3752
BIOS_NWRVDP: EQU 0x012D ; msx 2 (0x0647)
3754
BASIC_SUB_LINE: equ 0x58fc
3755
BASIC_SUB_LINEBOX: equ 0x5912
3756
BASIC_SUB_LINEBOXFILLED: equ 0x58C1
3757
BASIC_SUB_CIRCLE: equ 0x5B19
3758
BASIC_SUB_PAINT1: equ 0x59DA ;0x59C8
3759
BASIC_SUB_PAINT2: equ 0x0069 ;0x2664 ;0x2651+3
3761
;---------------------------------------------------------------------------------------------------------
3763
;---------------------------------------------------------------------------------------------------------
3765
BIOS_RG0SAV: EQU 0xF3DF
3766
BIOS_RG1SAV: EQU 0xF3E0
3767
BIOS_RG8SAV: EQU 0xFFE7
3768
BIOS_BDRATR: EQU 0xFCB2
3769
BIOS_STATFL: EQU 0xF3E7 ; VDP status register
3771
BIOS_CXOFF: EQU 0xF945
3772
BIOS_CYOFF: EQU 0xF947
3773
BIOS_GXPOS: EQU 0xFCB3
3774
BIOS_GYPOS: EQU 0xFCB5
3776
BIOS_GRPNAM: EQU 0xF3C7 ; pattern name table
3777
BIOS_GRPCOL: EQU 0xF3C9 ; colour table
3778
BIOS_GRPCGP: EQU 0xF3CB ; pattern generator table
3779
BIOS_GRPATR: EQU 0xF3CD ; sprite attribute table
3780
BIOS_GRPPAT: EQU 0xF3CF ; sprite generator table
3781
BIOS_CGPNT: EQU 0xF920 ; 2 - current MSX Font location (0x1BBF)
3782
BIOS_ATRBAS: EQU 0xF928 ; sprite attribute table
3784
BIOS_MLTNAM: EQU 0xF3D1 ; pattern name table (screen 3, multicolor)
3785
BIOS_MLTCOL: EQU 0xF3D3 ; colour table (screen 3, multicolor)
3786
BIOS_MLTCGP: EQU 0xF3D5 ; pattern generator table (screen 3, multicolor)
3787
BIOS_MLTATR: EQU 0xF3D7 ; sprite attribute table (screen 3, multicolor)
3788
BIOS_MLTPAT: EQU 0xF3D9 ; sprite generator table (screen 3, multicolor)
3790
BIOS_ASPECT: equ 0xF931 ;2 Aspect ratio of the circle; set by <ratio> of CIRCLE.
3791
BIOS_CENCNT: equ 0xF933 ;2 Counter used by CIRCLE.
3792
BIOS_CLINEF: equ 0xF935 ;1 Flag to draw line to centre, Used set by CIRCLE
3793
BIOS_CNPNTS: equ 0xF936 ;2 Point to be plottted in a 45° segment, Used set by CIRCLE
3794
BIOS_CPLOTF: equ 0xF938 ;1 Plot polarity flag, Used set by CIRCLE
3795
BIOS_CPCNT: equ 0xF939 ;2 Number of points in 1/8 of circle, Used set by CIRCLE.
3796
BIOS_CPCNT8: equ 0xF93B ;2 Number of points in the circle. Used by CIRCLE.
3797
BIOS_CRCSUM: equ 0xF93D ;2 Cyclic redundancy check sum of the circle. Used by CIRCLE.
3798
BIOS_CSTCNT: equ 0xF93F ;2 Variable to maintain the number of points of the starting angle. Used by the instruction CIRCLE
3799
BIOS_CSCLXY: equ 0xF941 ;1 Scale of X & Y. Used by the instruction CIRCLE
3800
BIOS_ASPCT1: equ 0xF40B ;2 256/aspect ratio for Basic instruction CIRCLE.
3801
BIOS_ASPCT2: equ 0xF40D ;2 256*aspect ratio for Basic instruction CIRCLE.
3802
BIOS_MAXUPD: equ 0xF3EC ;3 Work area used by the instruction CIRCLE, contains JP 0000h at start.
3803
BIOS_MINUPD: equ 0xF3EF ;3 Work area used by the instruction CIRCLE, contains JP 0000h at start.
3805
BIOS_PARM1: EQU 0xF6E8 ; 100
3806
BIOS_PARM2: EQU 0xF750 ; 100
3808
GFX_TEMP: EQU BIOS_PARM1 ; 2
3809
GFX_TEMP1: EQU GFX_TEMP + 2 ; 2
3810
GFX_TEMP2: EQU GFX_TEMP1 + 2 ; 2
3811
GFX_TEMP3: EQU GFX_TEMP2 + 2 ; 2
3812
GFX_TEMP4: EQU GFX_TEMP3 + 2 ; 2
3813
GFX_TEMP5: EQU GFX_TEMP4 + 2 ; 2
3814
GFX_TEMP6: EQU GFX_TEMP5 + 2 ; 2
3815
GFX_TEMP7: EQU GFX_TEMP6 + 2 ; 2
3816
GFX_TEMP8: EQU GFX_TEMP7 + 2 ; 2
3817
GFX_TEMP9: EQU GFX_TEMP8 + 2 ; 2
3819
GFX_MAX_X: EQU 0xFCA4 ; 1 (CASSETE LOWLIM)
3820
GFX_MAX_Y: EQU 0xFCA5 ; 1 (CASSETE WINWID)
3822
GFX_SPRITE_FLAGS: EQU 0xF40A ; 1 (CASSETE HEADER) - bits 0=check screen limits, 1=check walls, 2=check hotspots,
3823
; 3=limit touched, 4=wall touched, 5=hotspot touched, 6=collided
3824
GFX_SPRITE_SIZE_DAT: EQU 0xF3FC ; 1 (CASSETE CS1200)
3825
GFX_SPRITE_SIZE_SCR: EQU 0xF3FD ; 1
3826
GFX_SPRITE_WALLS: EQU 0xF406 ; 2 (CASSETE LOW)
3827
GFX_SPRITE_HOTSPOTS: EQU 0xF408 ; 2 (CASSETE HIGH)
3828
GFX_SPRITE_HOTSPOT_TILE: EQU 0xF405 ; 1 (CASSETE CS2400)
3829
GFX_SPRITE_COLLIDER: EQU 0xF400 ; 1 (CASSETE CS1200)
3830
GFX_SPRITE_COLLISION: EQU 0xF7B5 ; 2 (ARYTA2)
3832
GFX_MUSIC_START: EQU 0xF401 ; 2 (CASSETE CS2400)
3833
GFX_MUSIC_NEXT: EQU 0xF403 ; 2
3834
GFX_MUSIC_PREV: EQU 0xF74C ; 2 (PRMPRV)
3836
GFX_TEMP10: EQU 0xF3FE ; 2 (CASSETE CS1200)
3838
;BIOS_SCR_SIZE_X: dw 240, 256, 256, 64, 256, 256, 512, 512, 256, 512, 256, 256, 256
3839
;BIOS_SCR_SIZE_Y: dw 192, 192, 192, 48, 192, 212, 212, 212, 212, 384, 212, 212, 212
3840
BIOS_SCR_SIZE_X: db 239, 255, 255, 63, 255, 255, 255, 255, 255, 255, 255, 255, 255
3841
BIOS_SCR_SIZE_Y: db 191, 191, 191, 47, 191, 211, 211, 211, 211, 255, 211, 211, 211
3844
;---------------------------------------------------------------------------------------------------------
3845
; gfxIsScreenModeMSX2
3846
; return if screen mode is from MSX 2
3847
; out C is set, if MSX2 and screen mode above 3
3848
;---------------------------------------------------------------------------------------------------------
3850
gfxIsScreenModeMSX2:
3851
ld a, (BIOS_VERSION)
3853
jp nz, BIOS_CHKNEW ; if not MSX1, jump to CHKNEW
3857
;---------------------------------------------------------------------------------------------------------
3859
; set current screen mode
3860
; in A = screen number
3861
;---------------------------------------------------------------------------------------------------------
3865
call gfxInitScreenWorkspace
3867
ld a, (BIOS_VERSION)
3869
jr nz, gfxSetScreenMode.1 ; if not MSX1, jump
3872
call nc, gfxSetScreenMode.0 ; if screen mode >= 4, change to screen 2
3873
__call_bios BIOS_CHGMOD ; change the screen mode (msx1)
3874
jr gfxSetScreenMode.2
3882
ld ix, BIOS_CHGMOD2 ; change the screen mode (msx2)
3886
call gfxGetScreenHeight
3887
call gfxGetScreenWidth
3888
call gfxGetSpriteSize
3889
jp gfxFillSpriteCollisionTable
3891
gfxInitScreenWorkspace:
3893
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
3895
ld (GFX_SPRITE_WALLS), a
3896
ld (GFX_SPRITE_WALLS+1), a
3897
ld (GFX_SPRITE_HOTSPOTS), a
3898
ld (GFX_SPRITE_HOTSPOTS+1), a
3899
ld (GFX_MUSIC_START), a
3900
ld (GFX_MUSIC_START+1), a
3901
ld (GFX_MUSIC_NEXT), a
3902
ld (GFX_MUSIC_NEXT+1), a
3903
ld (GFX_MUSIC_PREV), a
3904
ld (GFX_MUSIC_PREV+1), a
3905
ld (GFX_SPRITE_HOTSPOT_TILE), a
3906
ld (GFX_SPRITE_COLLIDER), a
3909
;---------------------------------------------------------------------------------------------------------
3911
; return current screen mode
3912
; out A = screen number (0=40x24 Text Mode, 1=32x24 Text Mode, 2=Graphics Mode, 3=Multicolour Mode)
3913
;---------------------------------------------------------------------------------------------------------
3919
;---------------------------------------------------------------------------------------------------------
3921
; set current screen location
3924
;---------------------------------------------------------------------------------------------------------
3927
ld (BIOS_GRPACX), bc ; x
3928
;ld (BIOS_GXPOS), bc
3929
ld (BIOS_GRPACY), de ; y
3930
;ld (BIOS_GYPOS), de
3933
;---------------------------------------------------------------------------------------------------------
3935
; refresh current screen location
3936
;---------------------------------------------------------------------------------------------------------
3939
ld bc, (BIOS_GRPACX) ; x
3940
ld de, (BIOS_GRPACY) ; y
3942
call gfxIsScreenModeMSX2
3943
jr nc, gfxRefreshXY.2 ; if MSX2 and screen mode above 3
3944
__call_bios BIOS_SCALXY ; BC = X, DE = Y
3945
__call_bios BIOS_MAPXYC ; in BC = X, DE = Y
3948
ld ix, BIOS_SCALXY2 ; BC = X, DE = Y
3950
ld ix, BIOS_MAPXYC2 ; in BC = X, DE = Y
3953
;---------------------------------------------------------------------------------------------------------
3955
; get current screen location
3958
;---------------------------------------------------------------------------------------------------------
3961
ld bc, (BIOS_GRPACX) ; x
3962
ld de, (BIOS_GRPACY) ; y
3965
;---------------------------------------------------------------------------------------------------------
3966
; gfxGetScreenHeight
3968
; out a = screen height
3969
;---------------------------------------------------------------------------------------------------------
3974
ld hl, BIOS_SCR_SIZE_Y
3985
;---------------------------------------------------------------------------------------------------------
3988
; out a = screen height
3989
;---------------------------------------------------------------------------------------------------------
3994
ld hl, BIOS_SCR_SIZE_X
4005
;---------------------------------------------------------------------------------------------------------
4007
; get sprite data size
4008
; out a = sprite data size
4009
;---------------------------------------------------------------------------------------------------------
4014
ld a, (BIOS_RG1SAV) ; bit 0 = double size, bit 1 = sprite size (0=8 pixels, 1=16 pixels)
4016
jr z, gfxGetSpriteSize.1
4021
jr z, gfxGetSpriteSize.2
4025
ld (GFX_SPRITE_SIZE_DAT), bc
4031
if defined GFX_FAST and defined PAINT
4033
;---------------------------------------------------------------------------------------------------------
4035
; move screen current location up
4036
; out: carry if off screen
4037
;---------------------------------------------------------------------------------------------------------
4042
ld de, (BIOS_GRPACY)
4047
ld (BIOS_GRPACY), de
4058
;---------------------------------------------------------------------------------------------------------
4060
; move screen current location down
4061
; out: carry if off screen
4062
;---------------------------------------------------------------------------------------------------------
4069
ld de, (BIOS_GRPACY)
4074
ld (BIOS_GRPACY), de
4085
;---------------------------------------------------------------------------------------------------------
4087
; move screen current location left
4088
; out: carry if off screen
4089
;---------------------------------------------------------------------------------------------------------
4094
ld de, (BIOS_GRPACX)
4099
ld (BIOS_GRPACX), de
4110
;---------------------------------------------------------------------------------------------------------
4112
; move screen current location right
4113
; out: carry if off screen
4114
;---------------------------------------------------------------------------------------------------------
4121
ld de, (BIOS_GRPACX)
4126
ld (BIOS_GRPACX), de
4139
;---------------------------------------------------------------------------------------------------------
4141
; push current screen location
4142
;---------------------------------------------------------------------------------------------------------
4147
ld iy, (BIOS_GRPACX) ; x
4149
ld iy, (BIOS_GRPACY) ; y
4155
;---------------------------------------------------------------------------------------------------------
4157
; pop current screen location
4160
;---------------------------------------------------------------------------------------------------------
4169
;---------------------------------------------------------------------------------------------------------
4171
; set current foreground color
4173
;---------------------------------------------------------------------------------------------------------
4176
ld (BIOS_FORCLR), a ; foreground color
4180
;---------------------------------------------------------------------------------------------------------
4182
; get current foreground color
4184
;---------------------------------------------------------------------------------------------------------
4187
ld a, (BIOS_FORCLR) ; foreground color
4190
;---------------------------------------------------------------------------------------------------------
4192
; set current background color
4194
;---------------------------------------------------------------------------------------------------------
4197
ld (BIOS_BAKCLR), a ; foreground color
4200
;---------------------------------------------------------------------------------------------------------
4202
; get current background color
4204
;---------------------------------------------------------------------------------------------------------
4207
ld a, (BIOS_BAKCLR) ; foreground color
4210
;---------------------------------------------------------------------------------------------------------
4212
; set current border color
4214
;---------------------------------------------------------------------------------------------------------
4217
ld (BIOS_BDRCLR), a ; border color
4220
;---------------------------------------------------------------------------------------------------------
4222
; get current border color
4224
;---------------------------------------------------------------------------------------------------------
4227
ld a, (BIOS_BDRCLR) ; border color
4230
;---------------------------------------------------------------------------------------------------------
4232
; set fill border color
4234
;---------------------------------------------------------------------------------------------------------
4237
ld (BIOS_BDRATR), a ; border color
4240
;---------------------------------------------------------------------------------------------------------
4242
; get fill border color
4244
;---------------------------------------------------------------------------------------------------------
4247
ld a, (BIOS_BDRATR) ; border color
4250
;---------------------------------------------------------------------------------------------------------
4252
; set current color (foreground, background and border)
4253
;---------------------------------------------------------------------------------------------------------
4258
jp nz, BIOS_CHGCLR2 ; change VDP colors - msx2
4260
jp nz, BIOS_CHGCLR2 ; change VDP colors - msx2
4261
jp BIOS_CHGCLR ; change VDP colors
4262
; __call_bios BIOS_SETATR ; change the pixel color
4265
;---------------------------------------------------------------------------------------------------------
4267
; set pixel in current position to current foreground color
4268
;---------------------------------------------------------------------------------------------------------
4271
call gfxIsScreenModeMSX2
4272
jr nc, gfxSetPixel.1 ; if MSX2 and screen mode above 3
4273
__call_bios BIOS_SETC
4279
;---------------------------------------------------------------------------------------------------------
4281
; get pixel color in current position
4282
; out A = pixel color
4283
;---------------------------------------------------------------------------------------------------------
4286
call gfxIsScreenModeMSX2
4287
jr nc, gfxGetPixel.1 ; if MSX2 and screen mode above 3
4288
__call_bios BIOS_READC
4296
;---------------------------------------------------------------------------------------------------------
4298
; plot a line from current position to informed destination
4299
; in BC = destination x
4300
; DE = destination y
4301
; https://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm#Algorithm_for_integer_arithmetic
4302
; https://rosettacode.org/wiki/Bitmap/Bresenham%27s_line_algorithm#C
4303
;---------------------------------------------------------------------------------------------------------
4304
;void line(int x0, int y0, int x1, int y1) {
4305
; int dx = abs(x1-x0), sx = x0<x1 ? 1 : -1;
4306
; int dy = abs(y1-y0), sy = y0<y1 ? 1 : -1;
4307
; int err = (dx>dy ? dx : -dy)/2, e2;
4310
; if (x0==x1 && y0==y1) break;
4312
; if (e2 >-dx) { err -= dy; x0 += sx; }
4313
; if (e2 < dy) { err += dx; y0 += sy; }
4318
if not defined GFX_FAST
4319
ld hl, (BIOS_GRPACX)
4321
ld hl, (BIOS_GRPACY)
4323
__call_basic BASIC_SUB_LINE
4328
ld (GFX_TEMP2), bc ; x
4329
ld (GFX_TEMP3), de ; y
4331
ld hl, (BIOS_GRPACX) ; x0
4332
ld de, (GFX_TEMP2) ; x
4335
;jp po, gfxLine.1 ; x0 >= x? else jump to endif
4337
jp c, gfxLine.1 ; x0 < x? jump
4340
ld (GFX_TEMP4), hl ; dx = x0 - x
4342
ld (GFX_TEMP5), hl ; sx = -1
4346
ld de, (BIOS_GRPACX) ; x0
4347
ld hl, (GFX_TEMP2) ; x
4350
ld (GFX_TEMP4), hl ; dx = x - x0
4352
ld (GFX_TEMP5), hl ; sx = 1
4355
ld hl, (BIOS_GRPACY) ; y0
4356
ld de, (GFX_TEMP3) ; y
4359
;jp po, gfxLine.3 ; y0 >= y? else, jump to endif
4361
jp c, gfxLine.3 ; y0 < y? jump
4364
ld (GFX_TEMP6), hl ; dy = y0 - y
4366
ld (GFX_TEMP7), hl ; sy = -1
4370
ld de, (BIOS_GRPACY) ; y0
4371
ld hl, (GFX_TEMP3) ; y
4374
ld (GFX_TEMP6), hl ; dy = y - y0
4376
ld (GFX_TEMP7), hl ; sy = 1
4379
ld hl, (GFX_TEMP6) ; dy
4382
jp z, gfxLine.h ; dy = 0?
4384
ld hl, (GFX_TEMP4) ; dx
4387
jp z, gfxLine.v ; dx = 0?
4389
ld de, (GFX_TEMP4) ; dx
4390
ld hl, (GFX_TEMP6) ; dy
4395
ld (GFX_TEMP9), hl ; dxy = dx + dy
4397
ld de, (GFX_TEMP4) ; dx
4398
ld hl, (GFX_TEMP6) ; dy
4401
;jp pe, gfxLine.5 ; dy < dx? else, jump to endif
4403
jp z, gfxLine.5 ; dy = dx? jump
4404
jp nc, gfxLine.5 ; dy > dx? jump
4406
ld de, (GFX_TEMP6) ; dy
4412
ld (GFX_TEMP8), de ; err = -dy / 2
4416
ld hl, (GFX_TEMP4) ; dx
4420
ld (GFX_TEMP8), hl ; err = dx/2
4425
ld hl, (GFX_TEMP9) ; dxy
4428
jp nc, gfxLine.loop.0 ; dxy > 0? jump
4429
;jp z, gfxLine.loop.0 ; dxy = 0? jump
4435
ld de, (GFX_TEMP4) ; dx
4438
ld de, (GFX_TEMP8) ; e2 = err
4442
;jp pe, gfxLine.loop.1 ; if -dx < e2, else jump to endif
4444
jp z, gfxLine.loop.1 ; -dx = e2? jump
4445
jp nc, gfxLine.loop.1 ; -dx > e2? jump
4446
ld hl, (GFX_TEMP8) ; err
4447
ld de, (GFX_TEMP6) ; dy
4450
ld (GFX_TEMP8), hl ; err -= dy
4452
ld hl, (GFX_TEMP9) ; dxy
4454
ld (GFX_TEMP9), hl ; dxy -= 1
4456
ld hl, (BIOS_GRPACX)
4460
ld (BIOS_GRPACX), hl ; x0 += sx
4464
ld de, (GFX_TEMP6) ; dy
4467
;jp pe, gfxLine.loop.2 ; if e2 < dy, else jump to endif
4469
jp z, gfxLine.loop.2 ; e2 = dy? jump
4470
jp nc, gfxLine.loop.2 ; e2 > dy? jump
4471
ld hl, (GFX_TEMP8) ; err
4472
ld de, (GFX_TEMP4) ; dx
4475
ld (GFX_TEMP8), hl ; err += dx
4477
ld hl, (GFX_TEMP9) ; dxy
4479
ld (GFX_TEMP9), hl ; dxy -= 1
4481
ld hl, (BIOS_GRPACY)
4485
ld (BIOS_GRPACY), hl ; y0 += sy
4492
ld a, (GFX_TEMP5) ; sx
4494
jr z, gfxLine.h.1 ; if a is positive
4495
ld hl, (BIOS_GRPACX)
4499
ld (BIOS_GRPACX), hl
4503
__call_bios BIOS_FETCHC
4504
ld hl, (GFX_TEMP4) ; dx
4506
call gfxDrawHorLine ; HL = pixel count
4510
ld a, (GFX_TEMP7) ; sy
4512
jr z, gfxLine.v.1 ; if a is positive
4513
ld hl, (BIOS_GRPACY)
4517
ld (BIOS_GRPACY), hl
4522
ld hl, (GFX_TEMP6) ; dy
4525
jp gfxBox.drawVerLine
4530
if defined BOX or defined FBOX or defined BOX_STEP or defined FBOX_STEP
4532
;---------------------------------------------------------------------------------------------------------
4534
; plot a box from current position to informed destination
4535
; in BC = destination x
4536
; DE = destination y
4537
; A = filled flag (0 = not filled, <>0 = filled)
4538
;---------------------------------------------------------------------------------------------------------
4542
if not defined GFX_FAST
4543
ld hl, (BIOS_GRPACX)
4545
ld hl, (BIOS_GRPACY)
4547
ld hl, BASIC_SUB_LINEBOX
4550
call gfxIsScreenModeMSX2
4552
ld hl, BASIC_SUB_LINEBOXFILLED
4557
jp BIOS_CALBAS ; BIOS_CALSLT
4568
call gfxAdjustDestXY
4570
jr nz, gfxBox.filled
4574
call gfxBox.drawHorLine
4576
ld de, (BIOS_GRPACX)
4580
ld (BIOS_GRPACX), hl
4582
call gfxBox.drawVerLine
4584
call gfxBox.drawVerLine
4585
call gfxBox.drawHorLine
4593
ld bc, (BIOS_GRPACX)
4595
call gfxBox.drawHorLine
4597
ld (BIOS_GRPACX), bc
4598
ld bc, (BIOS_GRPACY)
4600
ld (BIOS_GRPACY), bc
4606
jr nz, gfxBox.filled.loop
4618
gfxBox.drawVerLine.loop:
4626
jr nz, gfxBox.drawVerLine.loop
4629
;---------------------------------------------------------------------------------------------------------
4631
; draw a horizontal line
4633
;---------------------------------------------------------------------------------------------------------
4638
jr c, gfxDrawHorLine.2 ; if screen mode < 5 then jump
4640
ret nz ; return if negative
4643
jr nz, gfxDrawHorLine.1
4645
ret z ; return if hl = 0
4654
jr nz, gfxDrawHorLine.1
4658
__call_bios BIOS_NSETCX ; HL = fill count
4661
;---------------------------------------------------------------------------------------------------------
4663
; invert if dest XY is less than current XY position
4666
;---------------------------------------------------------------------------------------------------------
4670
ld (GFX_TEMP2), bc ; x
4671
ld (GFX_TEMP3), de ; y
4673
; verify x againt current position
4674
ld hl, (BIOS_GRPACX)
4677
sbc hl, de ; dx = x1 - x0
4678
bit 7, h ; result is negative?
4679
jr z, gfxAdjustDestXY.1
4681
ld (BIOS_GRPACX), hl
4689
; verify y againt current position
4690
ld hl, (BIOS_GRPACY)
4693
sbc hl, de ; dy = y1 - y0
4694
bit 7, h ; result is negative?
4695
jr z, gfxAdjustDestXY.2
4697
ld (BIOS_GRPACY), hl
4705
; refresh new position
4715
;---------------------------------------------------------------------------------------------------------
4717
; plot a circle centered in current position
4718
; BC = tracing end x
4719
; DE = tracing end y
4721
; A = filled flag (0 = not filled, <>0 = filled)
4722
; https://en.wikipedia.org/wiki/Midpoint_circle_algorithm
4723
; https://rosettacode.org/wiki/Bitmap/Midpoint_circle_algorithm#C
4724
;---------------------------------------------------------------------------------------------------------
4728
if not defined GFX_FAST
4730
ret nz ; return if negative radius
4731
ld (BIOS_GXPOS), hl ; circle ray
4733
ld bc, (BIOS_GRPACY)
4737
;jr nz, gfxDrawCircle.1
4744
__call_basic BASIC_SUB_CIRCLE
4747
ld (GFX_TEMP), hl ; radius
4750
ret z ; return if zero radius
4752
ret nz ; return if negative radius
4755
ld (GFX_TEMP1), bc ; x0
4756
ld (GFX_TEMP2), de ; y0
4759
jp nz, gfxCircle.filled
4761
gfxCircle.notFilled:
4763
ld de, (GFX_TEMP) ; radius
4766
ld (GFX_TEMP3), hl ; f = 1 - radius
4769
ld (GFX_TEMP4), hl ; ddF_x = 0
4778
ld (GFX_TEMP5), hl ; ddF_y = -2 * radius
4781
ld (GFX_TEMP6), hl ; x = 0
4784
ld (GFX_TEMP7), hl ; y = radius
4786
; plot(x0, y0 + radius)
4787
ld de, (GFX_TEMP) ; radius
4788
ld hl, (GFX_TEMP2) ; y0
4792
ld bc, (GFX_TEMP1) ; x0
4796
; plot(x0, y0 - radius)
4797
ld de, (GFX_TEMP) ; radius
4798
ld hl, (GFX_TEMP2) ; y0
4802
ld bc, (GFX_TEMP1) ; x0
4806
; plot(x0 + radius, y0)
4807
ld hl, (GFX_TEMP1) ; x0
4808
ld de, (GFX_TEMP) ; radius
4815
ld de, (GFX_TEMP2) ; y0
4819
; plot(x0 - radius, y0)
4820
ld hl, (GFX_TEMP1) ; x0
4821
ld de, (GFX_TEMP) ; radius
4828
ld de, (GFX_TEMP2) ; y0
4831
jp gfxCircle.notFilled.3
4833
gfxCircle.notFilled.1:
4834
ld hl, (GFX_TEMP3) ; f
4836
jr nz, gfxCircle.notFilled.2 ; if( f < 0 ), jump
4838
ld hl, (GFX_TEMP7) ; y -= 1
4842
ld hl, (GFX_TEMP5) ; ddF_y += 2
4847
ld hl, (GFX_TEMP3) ; f
4848
ld de, (GFX_TEMP5) ; ddF_y
4851
ld (GFX_TEMP3), hl ; f += ddF_y
4853
gfxCircle.notFilled.2:
4854
ld hl, (GFX_TEMP6) ; x
4856
ld (GFX_TEMP6), hl ; x++
4858
ld hl, (GFX_TEMP4) ; ddF_x += 2
4863
ld hl, (GFX_TEMP3) ; f
4864
ld de, (GFX_TEMP4) ; ddF_x
4868
ld (GFX_TEMP3), hl ; f += ddF_x + 1
4870
; plot(x0 + x, y0 + y)
4871
ld hl, (GFX_TEMP1) ; x0
4872
ld de, (GFX_TEMP6) ; x
4879
ld hl, (GFX_TEMP2) ; y0
4880
ld de, (GFX_TEMP7) ; y
4887
; plot(x0 - x, y0 + y)
4888
ld hl, (GFX_TEMP1) ; x0
4889
ld de, (GFX_TEMP6) ; x
4896
ld hl, (GFX_TEMP2) ; y0
4897
ld de, (GFX_TEMP7) ; y
4904
; plot(x0 + x, y0 - y)
4905
ld hl, (GFX_TEMP1) ; x0
4906
ld de, (GFX_TEMP6) ; x
4913
ld hl, (GFX_TEMP2) ; y0
4914
ld de, (GFX_TEMP7) ; y
4921
; plot(x0 - x, y0 - y)
4922
ld hl, (GFX_TEMP1) ; x0
4923
ld de, (GFX_TEMP6) ; x
4930
ld hl, (GFX_TEMP2) ; y0
4931
ld de, (GFX_TEMP7) ; y
4938
; plot(x0 + y, y0 + x)
4939
ld hl, (GFX_TEMP1) ; x0
4940
ld de, (GFX_TEMP7) ; y
4947
ld hl, (GFX_TEMP2) ; y0
4948
ld de, (GFX_TEMP6) ; x
4955
; plot(x0 - y, y0 + x)
4956
ld hl, (GFX_TEMP1) ; x0
4957
ld de, (GFX_TEMP7) ; y
4964
ld hl, (GFX_TEMP2) ; y0
4965
ld de, (GFX_TEMP6) ; x
4972
; plot(x0 + y, y0 - x)
4973
ld hl, (GFX_TEMP1) ; x0
4974
ld de, (GFX_TEMP7) ; y
4981
ld hl, (GFX_TEMP2) ; y0
4982
ld de, (GFX_TEMP6) ; x
4989
; plot(x0 - y, y0 - x)
4990
ld hl, (GFX_TEMP1) ; x0
4991
ld de, (GFX_TEMP7) ; y
4998
ld hl, (GFX_TEMP2) ; y0
4999
ld de, (GFX_TEMP6) ; x
5006
gfxCircle.notFilled.3:
5007
ld hl, (GFX_TEMP6) ; x
5008
ld de, (GFX_TEMP7) ; y
5011
jp c, gfxCircle.notFilled.1 ; while( x < y )
5012
ld bc, (GFX_TEMP1) ; x0
5013
ld de, (GFX_TEMP2) ; y0
5018
call gfxCircle.notFilled
5019
ld hl, (BIOS_BDRATR)
5021
ld hl, (BIOS_FORCLR)
5022
ld (BIOS_BDRATR), hl
5026
ld (BIOS_BDRATR), hl
5032
if defined PAINT or (defined CIRCLE and defined GFX_FAST)
5034
;---------------------------------------------------------------------------------------------------------
5036
; Fill current region delimited by border attribute color changing pixels to foreground color
5037
; in: a = fill type (0 = not symmetric, 1 = symmetric)
5038
;---------------------------------------------------------------------------------------------------------
5042
if not defined GFX_FAST
5044
ld bc, (BIOS_GRPACX)
5046
ld de, (BIOS_GRPACY)
5064
call gfxIsScreenModeMSX2
5065
jr nc, gfxBorderFill.1 ; if MSX2 and screen mode above 3, jump
5069
__call_basic BASIC_SUB_PAINT1
5073
__call_basic BASIC_SUB_PAINT1
5075
;ld ix, BASIC_SUB_PAINT2
5081
ld hl, (BIOS_GRPACY)
5083
call gfxBorderFill.down
5086
ld (BIOS_GRPACY), hl
5088
call gfxBorderFill.up
5090
ld (BIOS_GRPACY), hl
5095
call gfxBorderFill.line
5101
jr nz, gfxBorderFill.down
5105
call gfxBorderFill.line
5111
jr nz, gfxBorderFill.up
5115
ld de, (BIOS_GRPACX)
5118
ld de, 1 ; skip count
5119
__call_bios BIOS_SCANR
5121
;ld (GFX_TEMP2), hl ; pixel count transversed
5124
ld (BIOS_GRPACX), de
5127
;cp 0 ; 0 = not symmetric, 1 = symmetric
5128
;jr z, gfxBorderFill.line.1
5130
;__call_bios BIOS_NSETCX ; HL = fill count
5131
;jr gfxBorderFill.line.2
5132
gfxBorderFill.line.1:
5134
ld de, 0 ; skip count
5135
__call_bios BIOS_SCANL
5136
gfxBorderFill.line.2:
5138
ld (BIOS_GRPACX), de
5142
;---------------------------------------------------------------------------------------------------------
5144
; Fload fill current region changing current pixel color to foreground color
5145
; https://en.wikipedia.org/wiki/Flood_fill
5146
;---------------------------------------------------------------------------------------------------------
5150
ld (GFX_TEMP), a ; replacement-color
5151
call gfxFloadFill.recursive
5154
gfxFloadFill.recursive:
5155
; 1. If target-color is equal to replacement-color, return.
5161
; 2. ElseIf the color of node is not equal to target-color, return.
5167
; 3. Else Set the color of node to replacement-color.
5170
; 4. Perform Flood-fill (one step to the left of node, target-color, replacement-color).
5171
gfxFloadFill.recursive.left:
5173
jr c, gfxFloadFill.recursive.right
5174
call gfxFloadFill.recursive
5177
; Perform Flood-fill (one step to the right of node, target-color, replacement-color).
5178
gfxFloadFill.recursive.right:
5180
jr c, gfxFloadFill.recursive.up
5181
call gfxFloadFill.recursive
5184
; Perform Flood-fill (one step to the up of node, target-color, replacement-color).
5185
gfxFloadFill.recursive.up:
5187
jr c, gfxFloadFill.recursive.down
5188
call gfxFloadFill.recursive
5191
; Perform Flood-fill (one step to the down of node, target-color, replacement-color).
5192
gfxFloadFill.recursive.down:
5195
call gfxFloadFill.recursive
5203
if defined SPRITEMODE
5205
;---------------------------------------------------------------------------------------------------------
5207
; set current sprite mode
5209
; 0: Spritesize is 8 by 8 pixels - default value
5210
; 1: Spritesize is 8 by 8 pixels, magnified to 16 by 16 pixels
5211
; 2: Spritesize is 16 by 16 pixels
5212
; 3: Spritesize is 16 by 16 pixels, magnified to 32 by 32 pixels
5213
; RG1SAV bit 0 = magnify sprite (double size)
5214
; RG1SAV bit 1 = sprite size (0=8 pixels, 1=16 pixels)
5215
;---------------------------------------------------------------------------------------------------------
5218
and 3 ; keeps only bits 0 and 1 from A
5221
ld a, (BIOS_RG1SAV) ; get copy from register #1 of VDP
5222
and 0xFC ; clear bits 0 and 1 from A
5223
or b ; put parameter to A (bits 0 and 1)
5224
ld (BIOS_RG1SAV), a ; restore to register #1 of VDP
5225
ld b, a ; value to write
5226
ld c, 1 ; register number to write
5227
call gfxWRTVDP ; write register to VDP
5228
call gfxCLRSPR ; clear sprites
5230
call gfxGetSpriteSize
5231
jp gfxFillSpriteCollisionTable
5235
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
5237
;---------------------------------------------------------------------------------------------------------
5238
; gfxSetSpriteColorInt
5241
;---------------------------------------------------------------------------------------------------------
5243
gfxSetSpriteColorInt:
5244
ld b, a ; save sprite number
5245
call gfxCALATR ; get sprite attribute table address
5250
;call gfxSetSpriteColor.Adjust
5255
ret c ; if screen mode < 3, do not adjust sprite multicolor
5257
ld a, b ; recover sprite number
5258
call gfxGetSpriteColorTable
5261
;call gfxSetSpriteColor.Adjust
5262
ld b, 16 ; array of 16 bytes
5264
gfxSetSpriteColorInt.1:
5269
djnz gfxSetSpriteColorInt.1
5272
;gfxSetSpriteColor.Adjust:
5282
;---------------------------------------------------------------------------------------------------------
5283
; gfxSetSpriteColorStr
5285
; DE = address to color byte array
5286
; BC = color byte array size
5287
;---------------------------------------------------------------------------------------------------------
5289
gfxSetSpriteColorStr:
5290
ld b, a ; save sprite number
5293
call gfxCALATR ; get sprite attribute table
5297
ld a, c ; byte array zero length?
5305
;call gfxSetSpriteColor.Adjust
5310
ret c ; if screen mode < 3, do not adjust sprite mode 2
5312
ld a, b ; recover sprite number
5313
call gfxGetSpriteColorTable
5315
ld b, 16 ; array of 16 bytes (color table)
5316
ld a, c ; size of color array
5318
pop iy ; save array start
5320
gfxSetSpriteColorStr.1:
5323
;call gfxSetSpriteColor.Adjust
5329
jr nz, gfxSetSpriteColorStr.2
5330
ld a, c ; recover array size
5332
pop de ; recover array start
5334
gfxSetSpriteColorStr.2:
5335
djnz gfxSetSpriteColorStr.1
5340
;---------------------------------------------------------------------------------------------------------
5341
; gfxGetSpriteColorTable
5343
; HL = address to color table
5344
;---------------------------------------------------------------------------------------------------------
5346
gfxGetSpriteColorTable:
5350
ld l, a ; recover sprite number
5354
add hl, hl ; multiply by 16 (shift left 4)
5357
call gfxCALATR ; get sprite attribute table address
5362
sbc hl, de ; address of color table from sprite multicolor
5369
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
5371
;---------------------------------------------------------------------------------------------------------
5375
;---------------------------------------------------------------------------------------------------------
5379
call gfxCALATR ; get sprite attribute table address
5388
;---------------------------------------------------------------------------------------------------------
5389
; gfxSpriteStepCheck
5391
;---------------------------------------------------------------------------------------------------------
5398
ld de, (GFX_SPRITE_SIZE_DAT)
5399
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
5400
and 7 ; clear touched and collided flags
5401
ld (GFX_SPRITE_FLAGS), a
5404
jr z, gfxSpriteStepCheck.corners
5406
gfxSpriteStepCheck.limits:
5409
cp b ; jump if x > max_x?
5410
jr c, gfxSpriteStepCheck.limits.touched
5414
cp c ; jump if y > max_y?
5415
jr c, gfxSpriteStepCheck.limits.touched
5417
jr gfxSpriteStepCheck.corners
5419
gfxSpriteStepCheck.limits.touched:
5420
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
5421
or 8 ; set limit touched flag
5422
ld (GFX_SPRITE_FLAGS), a
5424
gfxSpriteStepCheck.corners:
5425
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
5426
and 2+4 ; check walls or hotspots
5427
jr z, gfxSpriteStepCheck.end
5430
call gfxSpriteStepCheck.corner
5432
ld a, (GFX_SPRITE_SIZE_DAT)
5435
call gfxSpriteStepCheck.corner
5437
ld a, (GFX_SPRITE_SIZE_DAT)
5440
call gfxSpriteStepCheck.corner
5443
ld a, (GFX_SPRITE_SIZE_DAT)
5446
call gfxSpriteStepCheck.corner
5448
gfxSpriteStepCheck.end:
5454
gfxSpriteStepCheck.corner:
5455
call gfxGetTileFromXY
5456
ld d, a ; tile to be searched
5458
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
5460
call nz, gfxSpriteStepCheck.walls
5462
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
5464
call nz, gfxSpriteStepCheck.hotspots
5467
gfxSpriteStepCheck.walls:
5468
ld hl, (GFX_SPRITE_WALLS)
5469
ld e, 16 ; bits 0=chk limits, 1=chk walls, 2=chk hotspots, 3=limit touched, 4=wall touched, 5=hotspot touched, 6=collided
5470
jp gfxSpriteStepCheck.search
5472
gfxSpriteStepCheck.hotspots:
5473
ld hl, (GFX_SPRITE_HOTSPOTS)
5474
ld e, 32 ; bits 0=chk limits, 1=chk walls, 2=chk hotspots, 3=limit touched, 4=wall touched, 5=hotspot touched, 6=collided
5475
call gfxSpriteStepCheck.search
5477
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
5482
ld (GFX_SPRITE_HOTSPOT_TILE), a
5485
; d = tile, hl = search table, e = flag
5486
gfxSpriteStepCheck.search:
5491
ld a, d ; search for this tile
5497
cpir ; inc HL searching for A until BC=0 (Z flag settled if found)
5501
gfxSpriteStepCheck.search.found:
5502
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
5503
or e ; set touched flag
5504
ld (GFX_SPRITE_FLAGS), a
5519
call gfxGetScreenTile ; b = y, c = x, a = tile
5525
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
5527
;---------------------------------------------------------------------------------------------------------
5528
; gfxSetSpritePattern
5530
; BC = pattern number
5531
;---------------------------------------------------------------------------------------------------------
5533
gfxSetSpritePattern:
5535
call gfxCALATR ; get sprite attribute table address
5539
ld a, (BIOS_RG1SAV) ; bit 0 = double size, bit 1 = sprite size (0=8 pixels, 1=16 pixels)
5541
jr z, gfxSetSpritePattern.1
5544
gfxSetSpritePattern.1:
5545
ld a, c ; pattern number
5553
;---------------------------------------------------------------------------------------------------------
5555
; HL = point to sprite data as a string of 8 or 32 characters according the sprites size (8x8 or 16x16)
5557
;---------------------------------------------------------------------------------------------------------
5562
call gfxCALPAT ; get sprite pattern data address
5564
call gfxGSPSIZ ; return in 'a' sprite default size
5568
jr z, gfxSetSpriteData.1
5569
jr nc, gfxSetSpriteData.1
5583
if defined GFX_SPRITES
5585
;---------------------------------------------------------------------------------------------------------
5587
; initialises all sprites
5588
;---------------------------------------------------------------------------------------------------------
5594
;---------------------------------------------------------------------------------------------------------
5596
; set sprite default x, y, pattern and color
5598
;---------------------------------------------------------------------------------------------------------
5603
ld a, (BIOS_GRPACY) ; y
5606
ld a, (BIOS_GRPACX) ; x
5612
ld a, (BIOS_FORCLR) ; color
5618
if DATA_SET_ITEMS_COUNT > 0
5620
;---------------------------------------------------------------------------------------------------------
5622
;---------------------------------------------------------------------------------------------------------
5631
;---------------------------------------------------------------------------------------------------------
5632
; gfxClearTileScreen
5633
;---------------------------------------------------------------------------------------------------------
5638
ld hl, (BIOS_GRPNAM)
5642
call gfxSetTileDefaultColor
5644
call gfxSetTileDefaultColor
5646
jp gfxSetTileDefaultColor
5648
gfxSetTileDefaultColor
5649
call gfxGetTileColorAddr
5651
call gfxGetTileDefaultColor
5655
gfxGetTileDefaultColor:
5668
; HL = tile color pointer
5669
; BC = tile color size
5672
;---------------------------------------------------------------------------------------------------------
5675
; HL = tile data pointer
5676
; BC = tile data size
5678
; A = flip (0=no, 1=yes)
5679
;---------------------------------------------------------------------------------------------------------
5683
jr nz, gfxSetTileDataFlip
5685
gfxSetTileDataNoFlip:
5686
call gfxGetTileDataAddr
5690
call gfxGetTileDataAddr
5692
gfxSetTileDataFlip.Loop:
5701
jr nz, gfxSetTileDataFlip.Loop
5704
; in de = tile number
5705
; out de = tile number address
5711
add hl, hl ; tile number * 8
5712
ld de, (BIOS_GRPCGP)
5718
;---------------------------------------------------------------------------------------------------------
5721
; HL = tile color pointer
5722
; BC = tile color size
5724
;---------------------------------------------------------------------------------------------------------
5727
call gfxGetTileColorAddr
5730
; in de = tile number
5731
; out de = tile number address
5732
gfxGetTileColorAddr:
5737
add hl, hl ; tile number * 8
5738
ld de, (BIOS_GRPCOL)
5744
;---------------------------------------------------------------------------------------------------------
5746
; set screen tile at x,y
5750
;---------------------------------------------------------------------------------------------------------
5762
; ld l, b ; slow y * 32
5779
ld de, (BIOS_GRPNAM)
5786
if defined gfxGetTileFromXY or DATA_SET_ITEMS_COUNT > 0
5788
;---------------------------------------------------------------------------------------------------------
5790
; get screen tile at x,y
5794
;---------------------------------------------------------------------------------------------------------
5816
ld de, (BIOS_GRPNAM)
5822
;---------------------------------------------------------------------------------------------------------
5823
; Sprite collision table routines
5824
;---------------------------------------------------------------------------------------------------------
5826
gfxInitSpriteCollisionTable:
5829
ld (GFX_SPRITE_COLLISION), ix
5832
; copy sprite attribute table to ram
5833
gfxFillSpriteCollisionTable:
5834
ld hl, (BIOS_ATRBAS) ; source: attribute table
5835
ld de, (GFX_SPRITE_COLLISION) ; dest: ram
5836
ld bc, 128 ; 32*4 = size of attribute table
5839
; pre-calculate each sprite width
5840
gfxCalculateSpriteCollisionTable:
5841
ld ix, (GFX_SPRITE_COLLISION) ; start of sprites attributes
5842
ld b, 32 ; sprite count
5844
gfxCalculateSpriteCollisionTable.start:
5845
ld a, (GFX_SPRITE_SIZE_DAT) ; sprite size
5847
ld d, 208 ; Y no-display flag
5851
cp 3 ; above screen 3?
5852
jr c, gfxCalculateSpriteCollisionTable.next
5853
ld d, 216 ; Y no-display flag
5855
gfxCalculateSpriteCollisionTable.next:
5856
; test IC flag (no collision) in color table
5857
; test EC flag (early clock, shift 32 dots to the left) in color table
5858
; set x1 = x + size, y1 = y + size
5860
cp d ; test if sprite will not be displayed
5873
djnz gfxCalculateSpriteCollisionTable.next
5876
; BC = sprite number to check
5877
gfxUpdateSpriteCollisionTable:
5885
ld hl, (GFX_SPRITE_COLLISION) ; dest: ram
5888
ld hl, (BIOS_ATRBAS) ; source: attribute table
5890
ld bc, 4 ; 4 = size of attribute table to 1 sprite]
5894
ld b, 1 ; sprite count
5896
call gfxCalculateSpriteCollisionTable.start
5899
ld a, (GFX_SPRITE_FLAGS)
5900
and 0xBF ; clear collision flag
5901
ld (GFX_SPRITE_FLAGS), a
5903
ld a, (BIOS_STATFL) ; verify if collision occurred
5906
jr gfxCheckSpriteCollisionTable.start
5908
; BC = sprite number to check
5909
gfxCheckSpriteCollisionTable:
5910
; get target sprite address (iy)
5914
ld de, (GFX_SPRITE_COLLISION)
5921
gfxCheckSpriteCollisionTable.start:
5922
; start test against others sprites
5923
ld ix, (GFX_SPRITE_COLLISION)
5925
ld d, 208 ; Y no-display flag
5929
cp 3 ; above screen 3?
5930
jr c, gfxCheckSpriteCollisionTable.test
5931
ld d, 216 ; Y no-display flag
5933
gfxCheckSpriteCollisionTable.test:
5934
; skip target sprite
5937
jr z, gfxCheckSpriteCollisionTable.next
5939
; test if x1 > nx and x < nx1 and y1 > ny and y < ny1
5941
cp d ; test if sprite will not be displayed
5942
ret z ; return false
5945
jr nc, gfxCheckSpriteCollisionTable.next
5949
jr nc, gfxCheckSpriteCollisionTable.next
5953
jr nc, gfxCheckSpriteCollisionTable.next
5957
jr nc, gfxCheckSpriteCollisionTable.next
5959
; if so, save collider sprite
5961
ld (GFX_SPRITE_COLLIDER), a
5963
ld a, (GFX_SPRITE_FLAGS)
5964
or 0x40 ; set collision flag
5965
ld (GFX_SPRITE_FLAGS), a
5969
gfxCheckSpriteCollisionTable.next:
5977
ret z ; return false
5978
jr gfxCheckSpriteCollisionTable.test
5982
;---------------------------------------------------------------------------------------------------------
5983
; VDP / VRAM support routines
5984
;---------------------------------------------------------------------------------------------------------
5988
; c = register number
5989
; a = register number
5992
ret nz ; is negative? read only
5994
ret z ; is register 8? then status register 0 (read only)
5995
jr nc, gfxWRTVDP.1 ; is > 8? then control registers numbers added 1
6010
;jp nz, BIOS_NWRVDP ; msx 2
6012
;jp nz, BIOS_NWRVDP ; msx 2
6013
jp BIOS_WRTVDP ; msx 1
6016
; in a = register number
6020
jr nz, gfxRDVDP.1 ; is negative? then status register 1 to 9
6022
jr z, gfxRDVDP.2 ; is register 8? then status register 0
6024
jr nc, gfxRDVDP.3 ; is >= 9? then control registers numbers added 1
6025
ld hl, BIOS_RG0SAV ; else is correct control registers numbers
6037
jp BIOS_NRDVDP ;BIOS_VDPSTA
6044
ld hl, BIOS_RG8SAV-9
6052
; in: A=Data byte, BC=Length, HL=VRAM address
6061
; in: A=Sprite pattern number
6062
; out: HL=Sprite pattern address
6072
; in: A=Sprite number
6073
; out: HL=Sprite attribute address
6083
; out: A=Bytes in sprite pattern (8 or 32)
6103
; in: BC=Length, dest DE=VRAM address, source HL=RAM address
6108
; in: BC=Length, dest DE=RAM address, source HL=VRAM address
6135
; 8 bytes / 206 cycles
6136
; http://www.retroprogramming.com/2014/01/fast-z80-bit-reversal.html
6143
djnz gfxReverseA.loop
6149
;---------------------------------------------------------------------------------------------------------
6151
;---------------------------------------------------------------------------------------------------------
6160
RET_MATH_LIB: call COPY_TO.TMP_DAC
6166
MATH_DECADD: ld ix, addSingle
6171
if defined MATH.SUB or defined MATH.NEG
6173
MATH_DECSUB: ld ix, subSingle
6178
if defined MATH.MULT
6180
MATH_DECMUL: ld ix, mulSingle
6187
MATH_DECDIV: ld ix, divSingle
6195
MATH_SNGEXP: ld ix, powSingle
6202
MATH_COS: ld ix, cosSingle
6209
MATH_SIN: ld ix, sinSingle
6216
MATH_TAN: ld ix, tanSingle
6223
MATH_ATN: ld ix, atanSingle
6230
MATH_SQR: ld ix, sqrtSingle
6237
MATH_LOG: ld ix, lnSingle
6244
MATH_EXP: ld ix, expSingle
6251
MATH_ABSFN: ld ix, absSingle
6256
if defined MATH.SEED or defined MATH.NEG
6258
MATH_NEG: ld ix, negSingle
6265
MATH_SGN: ld ix, sgnSingle
6270
if defined RND or defined MATH.SEED
6272
MATH_RND: ld ix, randSingle
6277
MATH_FRCINT: ld hl, BASIC_DAC
6290
ld (BASIC_VALTYP), a
6293
MATH_FRCDBL: ; same as MATH_FRCSGL
6294
MATH_FRCSGL: ld hl, BASIC_DAC+2 ; input address
6295
ld bc, BASIC_DAC ; output address
6298
ld (BASIC_VALTYP), a
6301
MATH_ICOMP: ld a, h ; cp hl, de (alternative to bios DCOMPR)
6303
jr nz, MATH_ICOMP.NE.HIGH
6306
jr nz, MATH_ICOMP.NE.LOW
6308
MATH_ICOMP.NE.HIGH: jr c, MATH_ICOMP.GT.HIGH
6310
jr nz, MATH_DCOMP.GT
6312
MATH_ICOMP.GT.HIGH: bit 7, d
6315
MATH_ICOMP.NE.LOW: jr c, MATH_DCOMP.GT
6318
MATH_XDCOMP: ; same as MATH_DCOMP
6319
MATH_DCOMP: ld ix, cmpSingle
6323
MATH_DCOMP.GT: ld a, 0xFF ; DAC > ARG
6325
MATH_DCOMP.EQ: ld a, 0 ; DAC = ARG
6327
MATH_DCOMP.LT: ld a, 1 ; DAC < ARG
6330
if defined CAST_STR_TO.VAL
6332
MATH_FIN: ; HL has the source string
6333
ld a, (BASIC_VALTYP)
6334
cp 2 ; test if integer
6336
ld hl, (BASIC_DAC+2)
6341
MATH_FIN.1: ld BC, BASIC_DAC
6347
if defined CAST_INT_TO.STR
6349
MATH_FOUT: ld a, (BASIC_VALTYP)
6350
cp 2 ; test if integer
6352
ld hl, (BASIC_DAC+2)
6357
MATH_FOUT.1: ld hl, BASIC_DAC
6368
;---------------------------------------------------------------------------------------------------------
6370
; Copyright 2018 Zeda A.K. Thomas
6371
;---------------------------------------------------------------------------------------------------------
6373
; https://github.com/Zeda/z80float
6374
; https://www.omnimaga.org/asm-language/(z80)-floating-point-routines/
6375
; https://en.wikipedia.org/wiki/Single-precision_floating-point_format
6376
;---------------------------------------------------------------------------------------------------------
6378
; HL points to the first operand
6379
; DE points to the second operand (if needed)
6380
; IX points to the third operand (if needed, rare)
6381
; BC points to where the result should be output
6382
; Floats are stored by a little-endian 24-bit mantissa. However, the highest bit
6383
; is taken as implicitly 1, so we replace it as a sign bit. Next comes an 8-bit
6384
; exponent biased by +128.
6385
;---------------------------------------------------------------------------------------------------------
6386
; Adapted to MSXBas2Asm by Amaury Carvalho, 2019
6387
;---------------------------------------------------------------------------------------------------------
6389
;---------------------------------------------------------------------------------------------------------
6391
;---------------------------------------------------------------------------------------------------------
6393
BASIC_HOLD8: equ 0xF806 ; 48 Work area for decimal multiplications.
6394
BASIC_HOLD2: equ 0xF836 ; 8 Work area in the execution of numerical operators.
6395
BASIC_HOLD: equ 0xF83E ; 8 Work area in the execution of numerical operators.
6396
scrap: equ BASIC_HOLD8
6397
seed0: equ BASIC_RNDX
6398
seed1: equ seed0 + 4
6399
var48: equ scrap + 4
6402
addend2: equ scrap+7 ;4 bytes
6403
var_x: equ BASIC_HOLD8 + 4 ;4 bytes
6404
var_y: equ var_x + 4 ;4 bytes
6405
var_z: equ var_y + 4 ;4 bytes
6406
var_a: equ var_z + 4 ;4 bytes
6407
var_b: equ var_a + 4 ;4 bytes
6408
var_c: equ var_b + 4 ;4 bytes
6409
temp: equ var_c + 4 ;4 bytes
6410
temp1: equ temp + 4 ;4 bytes
6411
temp2: equ temp1 + 4 ;4 bytes
6412
temp3: equ temp2 + 4 ;4 bytes
6414
pow10exp_single: equ scrap+9
6415
strout_single: equ 0xF750 ; PARM2 - BASIC_BUF ;pow10exp_single+2
6417
;---------------------------------------------------------------------------------------------------------
6419
;---------------------------------------------------------------------------------------------------------
6421
;;Still need to tend to special cases
6489
pop hl ;bigger float
6621
;;Need to adjust sign flag
6644
;;How many push/pops are needed?
6652
;;How many push/pops are needed?
6658
;;How many push/pops are needed?
6659
;;Return bigger number
6666
;---------------------------------------------------------------------------------------------------------
6668
;---------------------------------------------------------------------------------------------------------
6691
jp addInject ;jumps in to the addSingle routine
6693
;---------------------------------------------------------------------------------------------------------
6695
;---------------------------------------------------------------------------------------------------------
6698
;Inputs: HL points to float1, DE points to float2, BC points to where the result is copied
6699
;Outputs: float1*float2 is stored to (BC)
6700
;573+mul24+{0,35}+{0,30}
6703
;avg: 2055.13839751681cc
6729
;;return float in CHLB
6739
jr z,mulSingle_case0
6751
;jr z,mulSingle_case1
6755
jp z,mulSingle_case1
6760
rra ; |Lots of help from Runer112 and
6761
adc a,a ; |calc84maniac for optimizing
6762
jp po,bad ; |this exponent check.
6771
call mul24 ;BDE*CHL->HLBCDE, returns sign info
6828
;special*x = special
6849
;basically, if b|c has bit 5 set, return NaN
6882
;;avg :1464.9033203125cc (1464+925/1024)
6885
;avg: 1449.63839751681cc
6926
;---------------------------------------------------------------------------------------------------------
6928
;---------------------------------------------------------------------------------------------------------
6931
;;HL points to numerator
6932
;;DE points to denominator
6933
;;BC points to where the quotient gets written
6935
divSingle_no_pushpop:
6941
xor (hl) ; |Get sign of output
6948
ex de,hl ; |Get exponent
7055
call divsub1 ;34 or 66
7073
;34cc or 66cc or 93cc
7088
;---------------------------------------------------------------------------------------------------------
7090
; https://www.geeksforgeeks.org/write-a-c-program-to-calculate-powxn/
7091
; https://stackoverflow.com/questions/3518973/floating-point-exponentiation-without-power-function
7092
;---------------------------------------------------------------------------------------------------------
7093
;double mypow( double base, double power, double precision )
7095
; if ( power < 0 ) return 1 / mypow( base, -power, precision );
7096
; else if ( power >= 1 ) return base * mypow( base, power-1, precision );
7097
; else if ( precision >= 1 ) {
7098
; if( base >= 0 ) return sqrt( base );
7099
; else return sqrt( -base );
7100
; } else return sqrt( mypow( base, power*2, precision*2 ) );
7103
if defined MATH.POW or defined MATH_EXP or defined MATH_LOG or defined MATH_LN
7109
;;BC points to output
7113
ld bc, var_y ; power
7118
ld hl, const_precision
7119
ld bc, var_a ; precision
7122
ld bc, var_z ; result
7131
; if ( power < 0 ) return 1 / mypow( base, -power, precision );
7137
; else if ( power >= 1 ) return base * mypow( base, power-1, precision );
7143
; else if ( precision >= 1 ) {
7144
; if( base >= 0 ) return sqrt( base );
7145
; else return sqrt( -base );
7151
; } else return sqrt( mypow( base, power*2, precision*2 ) );
7176
; return 1 / mypow( base, -power, precision );
7195
; return base * mypow( base, power-1, precision );
7214
; if( base >= 0 ) return sqrt( base );
7215
; else return sqrt( -base );
7241
; 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)))))
7242
;Please note that usually I like to reduce to [-.5,.5] as the extra overhead is usually worth it.
7243
;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.
7246
;x-=int(x) ;leaves x in [0,1)
7248
;;if x==inf -> out==inf
7249
;;if x==-inf -> out==0
7250
;;if x==NAN -> out==NAN
7257
push af ;keep track of sign
7267
jr c,_pow_1 ;int(x)=0
7280
jr nz,exp_normalized
7291
jr exp_normalized ;.db $11 ;start of `ld de,**`
7298
jr comp_exp ;.db $06 ;start of 'ld b,*` just to eat the next byte
7307
jp z,exp_underflow+1
7308
;perform 1-(var48+10)--> var48+10
7316
;our 'x' is at var48+10
7317
;our `temp` is at var48+6 so as not to cause issues with mulSingle)
7318
;uses 14 bytes of RAM
7360
;-inf -> +0 because lim approaches 0 from the right
7382
;-inf -> +0 because lim approaches 0 from the right
7384
sbc a,a ;FF if should be 0,
7399
;---------------------------------------------------------------------------------------------------------
7401
;---------------------------------------------------------------------------------------------------------
7403
if defined MATH_SQR or defined MATH_EXP
7405
;Uses 3 bytes at scrap
7407
;552+{0,19}+8{0,3+{0,3}}+pushpop+sqrtHLIX
7426
jp z,sqrtSingle_special
7429
push af ;new exponent
7439
;AHL is the new remainder
7440
;Need to divide by 2, then divide by the 16-bit (var_x+4)
7444
;We are just going to approximate it
7526
;Output: DE is the sqrt, AHL is the remainder
7527
;speed: 754+{0,1}+6{0,6}+{0,3+{0,18}}+{0,38}+sqrtHL
7551
jr _15a ;.db $FE ;start of `cp *`
7565
jr _16a ;.db $FE ;start of `cp *`
7579
jr _17a ;.db $FE ;start of `cp *`
7593
jr _18a ;.db $FE ;start of `cp *`
7597
;Now we have four more iterations
7598
;The first two are no problem
7610
jr _19a ;.db $FE ;start of `cp *`
7624
jr _20a ;.db $FE ;start of `cp *`
7629
;On the next iteration, HL might temporarily overflow by 1 bit
7631
rl d ;sla e \ rl d \ inc e
7635
adc hl,hl ;This might overflow!
7636
jr c,sqrt32_iter15_br0
7649
;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
7652
ld b,a ;either 0x00 or 0x80
7673
;returns A as the sqrt, HL as the remainder, D = 0
7687
jr _23a ;.db $01 ;start of ld bc,** which is 10cc to skip the next two bytes.
7698
jr _24a ;.db $01 ;start of ld bc,** which is 10cc to skip the next two bytes.
7709
dec d ;this resets the low bit of D, so `srl d` resets carry.
7710
jr _25a ;.db $06 ;start of ld b,* which is 7cc to skip the next byte.
7732
jr _27a ;.db $01 ;start of ld bc,** which is 10cc to skip the next two bytes.
7745
jr _28a ;.db $01 ;start of ld bc,** which is 10cc to skip the next two bytes.
7767
;---------------------------------------------------------------------------------------------------------
7769
;---------------------------------------------------------------------------------------------------------
7771
if defined MATH_LOG or defined MATH_LN
7774
; x / (1 + x/(2-x+4x/(3-2x+9x/(4-3x+16x/(5-4x)))))
7775
; a * x ^ (1/a) - a, where a = 100
7778
ld de, const_100_inv
7780
call powSingle ; temp = x ^ (1/100)
7784
call mulSingle ; temp1 = temp * 100
7787
call subSingle ; bc = temp1 - 100
7792
;---------------------------------------------------------------------------------------------------------
7794
;---------------------------------------------------------------------------------------------------------
7811
;---------------------------------------------------------------------------------------------------------
7813
;---------------------------------------------------------------------------------------------------------
7820
;;BC points to the output
7825
;;DE points to lg(y), HL points to x, BC points to output
7834
;---------------------------------------------------------------------------------------------------------
7836
; https://en.wikipedia.org/wiki/List_of_trigonometric_identities
7837
; https://en.wikipedia.org/wiki/Taylor_series#Trigonometric_functions
7838
; https://cs.stackexchange.com/questions/89245/how-approximate-sine-using-taylor-series
7839
; https://stackoverflow.com/questions/42217069/approximating-sinex-with-a-taylor-series-in-c-and-having-a-lot-of-problems
7840
;---------------------------------------------------------------------------------------------------------
7842
if defined MATH_SIN or defined MATH_TAN or defined MATH_COS
7845
; taylor: x - x^3/6 + x^5/120 - x^7/5040
7846
; x(1 - x^2(1/6 - x^2(1/120 - x^2/5040)) )
7848
; var_b = round( x / (2*PI), 0 )
7849
; var_c = x - var_b*2*PI
7850
; temp1 = if( var_c >= 0, var_c, var_c + 2*PI )
7851
; temp2 = if( temp1 > PI, temp1 - PI, temp1 )
7852
; var_a = if( temp2 > PI/2, PI - temp2, temp2 ) * if( temp1 > PI, -1, 1 )
7859
call copySingle ; return 0
7863
call trigRangeReductionSinCos
7868
call mulSingle ; var_b = var_a * var_a
7872
call mulSingle ; temp = x^2/5040
7876
call subSingle ; temp1 = 1/120 - temp
7880
call mulSingle ; temp = x^2 * temp1
7884
call subSingle ; temp1 = 1/6 - temp
7888
call mulSingle ; temp = x^2 * temp1
7892
call subSingle ; temp1 = 1 - temp
7896
call mulSingle ; return x * temp1
7899
trigRangeReductionSinCos:
7902
; var_b = round( x / (2*PI), 0 )
7910
; var_c = x - var_b*2*PI
7914
call mulSingle ; temp = var_b*2*PI
7918
call subSingle ; var_c = x - temp
7919
; temp1 = if( var_c >= 0, var_c, var_c + 2*PI )
7923
jr nc, trigRangeReductionSinCos.else.2
7926
call copySingle ; temp1 = var_c
7927
jr trigRangeReductionSinCos.endif.2
7928
trigRangeReductionSinCos.else.2:
7932
call addSingle ; temp1 = var_c + 2*PI
7933
trigRangeReductionSinCos.endif.2:
7934
; temp2 = if( temp1 > PI, temp1 - PI, temp1 )
7938
jr c, trigRangeReductionSinCos.else.3
7939
jr z, trigRangeReductionSinCos.else.3
7943
call subSingle ; temp2
7944
jr trigRangeReductionSinCos.endif.3
7945
trigRangeReductionSinCos.else.3:
7948
call copySingle ; temp2 = temp1
7949
trigRangeReductionSinCos.endif.3:
7950
; var_a = if( temp2 > PI/2, PI - temp2, temp2 ) * if( temp1 > PI, -1, 1 )
7951
ld hl, const_half_pi
7954
jr c, trigRangeReductionSinCos.else.4
7955
jr z, trigRangeReductionSinCos.else.4
7959
call subSingle ; var_a
7960
jr trigRangeReductionSinCos.endif.4
7961
trigRangeReductionSinCos.else.4:
7964
call copySingle ; var_a = temp2
7965
trigRangeReductionSinCos.endif.4:
7966
; if( temp > PI, -1, 1 )
7970
jr nc, trigRangeReductionSinCos.endif.5
7974
ld (ix+2), a ; turn var_a to negative
7975
trigRangeReductionSinCos.endif.5:
7981
;---------------------------------------------------------------------------------------------------------
7983
;---------------------------------------------------------------------------------------------------------
7985
if defined MATH_COS or defined MATH_TAN
7988
; taylor: 1 - x^2/2 + x^4/24 - x^6/720
7989
; 1 - x^2(1/2 - x^2(1/24 - x^2/720) )
7990
; reduction: same as sin
7999
call copySingle ; return 1
8003
; 1 - x^2(1/2 - x^2(1/24 - x^2/720) )
8004
call trigRangeReductionSinCos
8009
call mulSingle ; var_b = var_a * var_a
8013
call mulSingle ; temp = x^2/720
8017
call subSingle ; temp1 = 1/24 - temp
8021
call mulSingle ; temp = x^2 * temp1
8025
call subSingle ; temp1 = 1/2 - temp
8029
call mulSingle ; temp = x^2 * temp1
8033
call subSingle ; temp1 = 1 - temp
8035
; temp3 = abs(var_c)
8036
; temp1 = temp1 * if( temp3 >= PI/2, -1, 1 ) ==> cos sign
8043
ld (ix+2), a ; temp3 = abs(var_c)
8045
ld de, const_half_pi
8046
call cmpSingle ; if temp3 >= PI/2 then temp1 = -temp1
8047
jr nc, cosSingle.endif.1
8051
ld (ix+2), a ; temp1 = -temp1
8055
call copySingle ; return temp1
8060
;---------------------------------------------------------------------------------------------------------
8062
;---------------------------------------------------------------------------------------------------------
8083
;---------------------------------------------------------------------------------------------------------
8085
;---------------------------------------------------------------------------------------------------------
8090
;taylor: x/(1 + x^2/(3 + (2*x)^2/(5 + (3*x)^2/(7+(4*x)^2/9) ) ) )
8091
; x < -1: atan - PI/2
8092
; x >= 1: PI/2 - atan
8093
;reduction: abs(X) > 1 : Y = 1 / X
8094
; abs(X) <= 1: Y = X
8103
call copySingle ; return 0
8107
;x/(1 + x^2/(3 + (2*x)^2/(5 + (3*x)^2/(7+(4*x)^2/9) ) ) )
8108
call trigRangeReductionAtan
8114
call mulSingle ; var_b = var_a * var_a
8118
call mulSingle ; temp = (4*x)^2
8122
call divSingle ; temp1 = temp/9
8126
call addSingle ; temp = 7 + temp1
8130
call mulSingle ; temp1 = var_b * 9
8134
call divSingle ; temp2 = temp1 / temp
8138
call addSingle ; temp = 5 + temp2
8142
call mulSingle ; temp1 = var_b * 4
8146
call divSingle ; temp2 = temp1 / temp
8150
call addSingle ; temp = 3 + temp2
8154
call divSingle ; temp2 = var_b / temp
8158
call addSingle ; temp = 1 + temp2
8162
call divSingle ; temp2 = var_a / temp
8164
; x >= 1: PI/2 - atan
8168
ld hl, const_half_pi
8175
; x < -1: atan - PI/2
8186
ld de, const_half_pi
8195
call copySingle ; return temp2
8198
trigRangeReductionAtan:
8199
;reduction: abs(X) > 1 : Y = 1 / X
8200
; abs(X) <= 1: Y = X
8209
ld (ix+2), a ; abs(x)
8213
jr nc, trigRangeReductionAtan.1
8219
jr trigRangeReductionAtan.2
8220
trigRangeReductionAtan.1:
8225
trigRangeReductionAtan.2:
8229
jr c, trigRangeReductionAtan.3
8233
ld (ix+2), a ; y = -y
8234
trigRangeReductionAtan.3:
8239
if defined MATH_SIN or defined MATH_TAN or defined MATH_COS
8241
;---------------------------------------------------------------------------------------------------------
8243
;---------------------------------------------------------------------------------------------------------
8257
;---------------------------------------------------------------------------------------------------------
8259
;---------------------------------------------------------------------------------------------------------
8328
if defined MATH_ABSFN
8330
;---------------------------------------------------------------------------------------------------------
8332
;---------------------------------------------------------------------------------------------------------
8335
;;HL points to the float
8336
;;BC points to where to output the result
8355
;---------------------------------------------------------------------------------------------------------
8357
;---------------------------------------------------------------------------------------------------------
8360
;;HL points to the float
8361
;;BC points to where to output the result
8366
if defined powSingle or defined sgnSingle or defined MATH_NEG
8368
;---------------------------------------------------------------------------------------------------------
8370
;---------------------------------------------------------------------------------------------------------
8373
;;HL points to the float
8374
;;BC points to where to output the result
8380
jr nz, negSingle.test.sign
8383
jr nz, negSingle.test.sign
8386
jr nz, negSingle.test.sign
8389
jr nz, negSingle.test.sign
8400
negSingle.test.sign:
8403
jr z, negSingle.positive
8407
call negSingle.positive
8426
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
8428
;---------------------------------------------------------------------------------------------------------
8430
;---------------------------------------------------------------------------------------------------------
8433
;Input: HL points to float1, DE points to float2
8435
; float1 >= float2 : nc
8436
; float1 < float2 : c,nz
8437
; float1 == float2 : z
8438
; There is a margin of error allowed in the lower 2 bits of the mantissa.
8440
;Currently fails when both numbers have magnitude less than about 2^-106
8475
ld a,(scrap+3) ;new power
8476
pop bc ;B is old power
8486
or 1 ;not equal, so reset z flag
8487
rla ;if negative, float1<float2, setting c flag as wanted, else nc.
8497
;---------------------------------------------------------------------------------------------------------
8499
;---------------------------------------------------------------------------------------------------------
8502
;Stores a pseudo-random number on [0,1)
8503
;it won't produce values on (0,2^-23)
8512
;DEHL is the mantissa, B is the exponent
8528
;If we needed to shift more than 8 bits, we'll load in more random data
8533
jp nc,rand_no_more_rand_data
8541
rand_no_more_rand_data:
8560
;;Tested and passes all CAcert tests
8561
;;Uses a very simple 32-bit LCG and 32-bit LFSR
8562
;;it has a period of 18,446,744,069,414,584,320
8563
;;roughly 18.4 quintillion.
8564
;;LFSR taps: 0,2,6,7 = 11000101
8566
;;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.
8567
;Uses 64 bits of state
8603
if defined MATH_FOUT
8605
;---------------------------------------------------------------------------------------------------------
8607
; in HL = Single address
8608
; BC = String address
8609
; out A = String size
8610
; http://0x80.pl/notesen/2015-12-29-float-to-string.html
8611
; http://0x80.pl/articles/convert-float-to-integer.html
8612
;---------------------------------------------------------------------------------------------------------
8626
; Move the float to scrap
8630
; Make the float negative, write a '-' if already negative
8639
ld a,'-' ; write '-' simbol
8647
; Check if the exponent field is 0 (a special value)
8654
; We should write '0' next. When rounding 9.999999... for example, not padding with a 0 will return '.' instead of '1.'
8662
; Now we need to perform signed (A-128)*77 (approximation of exponent*log10(2))
8670
ld (pow10exp_single),a ;The base-10 exponent
8674
ld de,pow10LUT ;get the table of 10^-(2^k)
8676
ld hl, pow10exp_single
8678
call singletostr_mul
8679
call singletostr_mul
8680
call singletostr_mul
8681
call singletostr_mul
8682
call singletostr_mul
8683
call singletostr_mul
8684
;now the number is pretty close to a nice value
8686
; If it is less than 1, multiply by 10
8691
;ld hl,scrap ;Since singletostr_mul returns BC = scrap, can do this cheaper
8697
ld hl,pow10exp_single
8703
; Convert to a fixed-point number !
8717
;We need to get 7 digits
8719
pop hl ;Points to the string
8721
;The first digit can be as large as 20, so it'll actually be two digits
8725
;Increment the exponent :)
8726
ld de,(pow10exp_single-1)
8728
ld (pow10exp_single-1),de
8737
; Get the remaining digits.
8744
call singletostrmul10
8749
;Save the pointer to the end of the string
8756
jr c,rounding_done_single
8757
jr _40a ;.db $DA ;start of `jp c,*` in order to skip the next instruction
8766
rounding_done_single:
8769
;Strip the leading zero if it exists (rounding may have bumped this to `1`)
8781
;Now lets move HL-DE bytes at DE+1 to DE
8793
;If z flag is reset, this means that the exponent should be bumped up 1
8794
ld a,(pow10exp_single)
8797
ld (pow10exp_single),a
8800
;if -4<=A<=6, then need to insert the decimal place somewhere.
8805
;for this, we need to insert the decimal after the first digit
8806
;Then, we need to append the exponent string
8808
ld de,strout_single-1
8810
cp '-' ;negative sign
8818
;remove any stray zeroes at the end before appending the exponent
8822
; Write the exponent
8825
ld a,(pow10exp_single)
8828
ld (hl),'-' ;negative sign
8846
ld de, strout_single
8849
ld a, l ; string size
8851
ld hl,strout_single-1
8855
ld a,(pow10exp_single)
8859
;need to put zeroes before everything
8862
cp '-' ;negative sign
8888
ld de,strout_single-1
8892
cp '-' ;negative sign
8903
ld hl,strout_single-1
8921
;multiply the 0.24 fixed point number at scrap by 10
8922
;overflow in A register
8957
;Check that the last digit isn't a decimal!
9011
;---------------------------------------------------------------------------------------------------------
9013
; https://www.ticalc.org/pub/86/asm/source/routines/atof.asm
9014
;---------------------------------------------------------------------------------------------------------
9019
ptr_sto: equ scrap+9
9021
;;#Routines/Single Precision
9023
;; HL points to the string
9024
;; BC points to where the float is output
9026
;; scrap+9 is the pointer to the end of the string
9028
;; 11 bytes at scrap ?
9033
;Check if there is a negative sign.
9042
;Skip all leading zeroes
9045
jr z,$-4 ;jumps back to the `inc hl`
9048
;Check if the next char is char_DEC
9050
or a ;to reset the carry flag
9052
jr _54a ;.db $FE ;start of cp *
9059
jr z,$-5 ;jumps back to the `dec b`
9062
;Now we read in the next 8 digits
9068
;Now `scrap` holds the 4-digit base-100 number.
9070
;if carry flag is set, just need to get rid of remaining digits
9071
;Otherwise, need to get rid of remaining digits, while incrementing the exponent
9082
jp z,strToSingle_inf
9085
;Now check for engineering `E` to modify the exponent
9089
;Gotta multiply the number at (scrap) by 2^24
9092
call scrap_times_256
9095
call scrap_times_256
9098
call scrap_times_256
9101
call scrap_times_256
9104
;Now scrap+3 is a 4-byte mantissa that needs to be normalized
9112
jp z,strToSingle_zero-1
9116
jp m,strToSingle_normed
9117
;Will need to iterate at most three times
9130
;Move the number to scrap
9139
;now (scrap) is our number, need to multiply by power of 10!
9140
;Power of 10 is stored in B, need to put in A first
9148
jp nc,strToSingle_inf+1
9151
jp nc,strToSingle_zero
9175
cp char_NEG ;negative exponent?
9227
call scrap_times_sub
9240
jr nz,strToSingle_inf
9258
if defined roundSingle or defined MATH_FRCSGL
9260
;---------------------------------------------------------------------------------------------------------
9262
; http://wikiti.brandonw.net/index.php?title=Z80_Routines:Math:Division#24.2F8_division
9263
;---------------------------------------------------------------------------------------------------------
9270
ld l, (ix) ; convert integer parameter to single float
9272
ld bc, 0x1000 ; bynary digits count + sign
9274
int2Single.test.zero:
9276
or h ; test if hl is not zero
9277
jr nz, int2Single.test.negative
9279
jr nz, int2Single.test.negative
9284
int2Single.test.negative:
9285
bit 7, h ; test if hl is negative
9286
jr z, int2Single.normalize
9287
ld c, 0x80 ; sign negative
9296
int2Single.normalize:
9299
jr nz, int2Single.mount
9302
jr int2Single.normalize
9305
res 7, h ; turn off upper bit
9307
ld a, c ; restore sign
9309
ld h, a ; ...into upper mantissa
9311
ld e, h ; sign+mantissa
9312
ld h, l ; high mantissa
9313
ld l, 0 ; low mantissa
9315
ld a, b ; binary digits count
9316
or 0x80 ; exponent bias
9321
ld (ix), l ; low mantissa
9322
ld (ix+1), h ; high mantissa
9323
ld (ix+2), e ; sign + mantissa
9324
ld (ix+3), d ; expoent
9333
if defined roundSingle or defined MATH_FRCINT
9335
;---------------------------------------------------------------------------------------------------------
9337
; http://0x80.pl/articles/convert-float-to-integer.html
9338
;---------------------------------------------------------------------------------------------------------
9341
; HL points to the single-precision float
9343
; HL is the 16-bit signed integer part of the float
9344
; BC points to 16-bit signed integer
9361
jr c,no_shift_single_to_int16
9363
jr nc,no_shift_single_to_int16
9385
jr _67a ;.db $11 ;start of ld de,*
9397
no_shift_single_to_int16:
9419
;---------------------------------------------------------------------------------------------------------
9420
; Auxiliary routines
9421
;---------------------------------------------------------------------------------------------------------
9428
const_pi: db $DB,$0F,$49,$81
9429
const_e: db $54,$f8,$2d,$81
9430
const_lg_e: db $3b,$AA,$38,$80
9431
const_ln_2: db $18,$72,$31,$7f
9432
const_log2: db $9b,$20,$1a,$7e
9433
const_lg10: db $78,$9a,$54,$81
9434
const_0: db $00,$00,$00,$00
9435
const_1: db $00,$00,$00,$80
9436
const_2: dw 0, 33024
9437
const_3: dw 0, 33088
9438
const_4: dw 0, 33280
9439
const_5: dw 0, 33312
9440
const_7: dw 0, 33376
9441
const_9: dw 0, 33552
9442
const_16: dw 0, 33792
9443
const_100: db $00,$00,$48,$86
9444
const_100_inv: dw 55050, 31011
9445
const_precision: db $77,$CC,$2B,$65 ;10^-8
9446
const_half_1: dw 0, 32512
9447
const_inf: db $00,$00,$40,$00
9448
const_NegInf: db $00,$00,$C0,$00
9449
const_NaN: db $00,$00,$20,$00
9450
const_log10_e: db $D9,$5B,$5E,$7E
9451
const_2pi: db $DB,$0F,$49,$82
9452
const_2pi_inv: db $83,$F9,$22,$7D
9453
const_half_pi: dw 4059, 32841
9454
const_p25: db $00,$00,$00,$7E
9455
const_p5: db $00,$00,$00,$7F
9458
sin_a1: dw 43691, 32042
9459
sin_a2: dw 34952, 30984
9460
sin_a3: dw 3329, 29520
9461
cos_a1: equ const_half_1
9462
cos_a2: dw 43691, 31530
9463
cos_a3: dw 2914, 30262
9464
exp_a1: db $15,$72,$31,$7F ;.693146989552
9465
exp_a2: db $CE,$FE,$75,$7D ;.2402298085906
9466
exp_a3: db $7B,$42,$63,$7B ;.0554833215071
9467
exp_a4: db $FD,$94,$1E,$79 ;.00967907584392
9468
exp_a5: db $5E,$01,$23,$76 ;.001243632065103
9469
exp_a6: db $5F,$B7,$63,$73 ;.0002171671843714
9470
const_1p40625: db $00,$00,$34,$80 ;1.40625
9472
if defined MATH_CONSTSINGLE
9480
;A is the constant ID#
9481
;returns nc if failed, c otherwise
9482
;HL points to the constant
9483
cp (end_const-start_const)>>2
9490
;#if ((end_const-4)>>8)!=(start_const>>8)
9503
db $CD,$CC,$4C,$7C ;.1
9504
db $0A,$D7,$23,$79 ;.01
9505
db $17,$B7,$51,$72 ;.0001
9506
db $77,$CC,$2B,$65 ;10^-8
9507
db $95,$95,$66,$4A ;10^-16
9508
db $1F,$B1,$4F,$15 ;10^-32
9511
db $00,$00,$20,$83 ;10
9512
db $00,$00,$48,$86 ;100
9513
db $00,$40,$1C,$8D ;10000
9514
db $20,$BC,$3E,$9A ;10^8
9515
db $CA,$1B,$0E,$B5 ;10^16
9516
db $AE,$C5,$1D,$EA ;10^32
9523
;C>=128 135+6{0,33+{0,1}}+{0,20+{0,8}}
9524
;C>=64 115+5{0,33+{0,1}}+{0,20+{0,8}}
9525
;C>=32 95+4{0,33+{0,1}}+{0,20+{0,8}}
9526
;C>=16 75+3{0,33+{0,1}}+{0,20+{0,8}}
9527
;C>=8 55+2{0,33+{0,1}}+{0,20+{0,8}}
9528
;C>=4 35+{0,33+{0,1}}+{0,20+{0,8}}
9529
;C>=2 15+{0,20+{0,8}}
9532
;avg: 349.21279907227cc
9623
;26 bytes, adds 118cc to the traditional routine
9658
;c flag means don't increment the exponent
9661
jr c,ascii_to_uint8_noexp
9663
jr z,ascii_to_uint8_noexp-2
9667
jr nc,ascii_to_uint8_noexp_end
9679
jr z,ascii_to_uint8_noexp_2nd
9683
jr nc,ascii_to_uint8_noexp_end
9694
ascii_to_uint8_noexp:
9697
jr nc,ascii_to_uint8_noexp_end
9704
ascii_to_uint8_noexp_2nd:
9709
jr nc,ascii_to_uint8_noexp_end
9712
jr ascii_2 ;.db $FE ;start of `cp **`, saves 1cc
9713
ascii_to_uint8_noexp_end:
9723
if defined MATH_RSUBSINGLE
9744
jp addInject ;jumps in to the addSingle routine
9748
if defined MATH_MOD1SINGLE
9750
;This routine performs `x mod 1`, returning a non-negative value.
9773
jr z,mod1Single_special
9786
;If it is zero, need to set exponent to zero and return
9809
;make sure it isn't zero else we need to add 1
9821
;If INF, need to return NaN instead
9822
;For 0 and NaN, just return itself :)
9842
if defined MATH_FOUT
9844
; --------------------------------------------------------------
9845
; Converts a signed integer value to a zero-terminated ASCII
9846
; string representative of that value (using radix 10).
9848
; Brandon Wilson WikiTI
9849
; http://wikiti.brandonw.net/index.php?title=Z80_Routines:Other:DispA#Decimal_Signed_Version
9850
; --------------------------------------------------------------
9852
; HL Value to convert (two's complement integer).
9853
; DE Base address of string destination. (pointer).
9854
; --------------------------------------------------------------
9857
; --------------------------------------------------------------
9858
; REGISTERS/MEMORY DESTROYED
9860
; --------------------------------------------------------------
9866
; Detect sign of HL.
9870
; HL is negative. Output '-' to string and negate HL.
9875
; Negate HL (using two's complement)
9879
ld a, 0 ; Note that XOR A or SUB A would disturb CF
9883
; Convert HL to digit characters
9885
ld b, 0 ; B will count character length of number
9888
call div_hl_c; HL = HL / A, A = remainder
9895
; Retrieve digits from stack
9903
; Terminate string with NULL
9914
ld a, l ; string size
9922
;===============================================================
9923
; Convert a string of base-10 digits to a 16-bit value.
9924
; http://z80-heaven.wikidot.com/math#toc32
9926
; DE points to the base 10 number string in RAM.
9928
; HL is the 16-bit value of the number
9929
; DE points to the byte after the number
9934
; A (actually, add 30h and you get the ending token)
9937
; n is the number of digits
9939
; at most 595 cycles for any 16-bit decimal value
9940
;===============================================================
9943
ld hl,0 ; 10 : 210000
9960
jr nc,ConvLoop ;12|23: 30EE
9962
jr ConvLoop ; --- : 18EB
9969
; return remainder in a
9970
; http://wikiti.brandonw.net/index.php?title=Z80_Routines:Math:Division
9991
; http://wikiti.brandonw.net/index.php?title=Z80_Routines:Math:Division#24.2F8_division
10004
djnz div_ehl_d.loop
10021
djnz div_dehl_c.loop
10028
romSize: equ 0x8000 ; ROM size (32k)
10030
workAreaSize: equ 0x500
10031
workAreaPad: ds romSize - workAreaPad - workAreaSize, 0
10034
;---------------------------------------------------------------------------------------------------------
10035
; MAIN WORK AREA - LITERALS / VARIABLES / CONFIGURATIONS
10036
;---------------------------------------------------------------------------------------------------------
10038
VAR_STACK.START: equ ramArea
10039
;VAR_STACK.END: equ VAR_STACK.START + 0x800 ; 2kb (~200 variables)
10041
VAR_STACK.POINTER: equ VAR_STACK.START
10043
PRINT.CRLF: db 3, 0, 0, 2
10044
dw PRINT.CRLF.DATA, 0, 0, 0
10045
PRINT.CRLF.DATA: db 13,10,0
10047
PRINT.TAB: db 3, 0, 0, 1
10048
dw PRINT.TAB.DATA, 0, 0, 0
10049
PRINT.TAB.DATA: db 09,0
10052
LIT_NULL_DBL: dw 0, 0, 0, 0
10058
LIT_QUOTE_CHAR: db '\"'
10061
LIT_TRUE: db 2, 0, 0
10065
LIT_FALSE: db 2, 0, 0
10070
; numerical literal
10074
; numerical literal
10078
; numerical literal
10082
; numerical literal
10087
IDF_14: equ VAR_STACK.POINTER + 0
10089
; numerical literal
10094
IDF_16: equ VAR_STACK.POINTER + 11
10096
; numerical literal
10101
IDF_18: equ VAR_STACK.POINTER + 22
10103
; numerical literal
10108
IDF_20: equ VAR_STACK.POINTER + 33
10110
; numerical literal
10115
IDF_22: equ VAR_STACK.POINTER + 44
10117
; numerical literal
10122
IDF_24: equ VAR_STACK.POINTER + 55
10124
; numerical literal
10129
IDF_26: equ VAR_STACK.POINTER + 66
10132
LIT_27: db 3, 0, 0, 17
10133
dw LIT_27_DATA, 0, 0
10135
LIT_27_DATA: db "O4L8EBGBEAO5C#O4A", 0
10137
; numerical literal
10141
; numerical literal
10146
LIT_33: db 3, 0, 0, 12
10147
dw LIT_33_DATA, 0, 0
10149
LIT_33_DATA: db "CATA-METEORO", 0
10151
; numerical literal
10155
; numerical literal
10160
LIT_36: db 3, 0, 0, 12
10161
dw LIT_36_DATA, 0, 0
10163
LIT_36_DATA: db "************", 0
10165
; numerical literal
10169
; numerical literal
10174
LIT_39: db 3, 0, 0, 16
10175
dw LIT_39_DATA, 0, 0
10177
LIT_39_DATA: db "CLUBE MSX - 2019", 0
10180
IDF_42: equ VAR_STACK.POINTER + 77
10182
; numerical literal
10186
; numerical literal
10190
; numerical literal
10194
; numerical literal
10198
; numerical literal
10202
; numerical literal
10206
; numerical literal
10210
; numerical literal
10214
; numerical literal
10218
; numerical literal
10220
dw 0, TAG_180, 0, 0
10222
; numerical literal
10226
; numerical literal
10228
dw 0, TAG_230, 0, 0
10231
IDF_71: equ VAR_STACK.POINTER + 88
10233
; numerical literal
10237
; numerical literal
10241
; numerical literal
10245
; numerical literal
10249
; numerical literal
10253
; numerical literal
10257
; numerical literal
10261
; numerical literal
10265
; numerical literal
10269
; numerical literal
10273
; numerical literal
10277
; numerical literal
10281
; numerical literal
10285
; numerical literal
10289
; numerical literal
10290
LIT_100: db 2, 0, 0
10293
; numerical literal
10294
LIT_101: db 2, 0, 0
10297
; numerical literal
10298
LIT_103: db 2, 0, 0
10301
; numerical literal
10302
LIT_106: db 2, 0, 0
10305
; numerical literal
10306
LIT_107: db 2, 0, 0
10309
; numerical literal
10310
LIT_108: db 2, 0, 0
10313
; numerical literal
10314
LIT_110: db 2, 0, 0
10317
; numerical literal
10318
LIT_113: db 2, 0, 0
10321
; numerical literal
10322
LIT_114: db 2, 0, 0
10325
; numerical literal
10326
LIT_115: db 2, 0, 0
10329
; numerical literal
10330
LIT_116: db 2, 0, 0
10333
; numerical literal
10334
LIT_117: db 2, 0, 0
10338
IDF_118: equ VAR_STACK.POINTER + 99
10340
; numerical literal
10341
LIT_119: db 2, 0, 0
10344
; numerical literal
10345
LIT_120: db 2, 0, 0
10348
; numerical literal
10349
LIT_121: db 2, 0, 0
10352
; numerical literal
10353
LIT_122: db 2, 0, 0
10356
; numerical literal
10357
LIT_123: db 2, 0, 0
10360
; numerical literal
10361
LIT_124: db 2, 0, 0
10364
; numerical literal
10365
LIT_125: db 2, 0, 0
10368
; numerical literal
10369
LIT_126: db 2, 0, 0
10372
; numerical literal
10373
LIT_127: db 2, 0, 0
10377
LIT_128: db 3, 0, 0, 5
10378
dw LIT_128_DATA, 0, 0
10380
LIT_128_DATA: db "L8DC-", 0
10382
; numerical literal
10383
LIT_129: db 2, 0, 0
10386
; numerical literal
10387
LIT_130: db 2, 0, 0
10390
; numerical literal
10391
LIT_131: db 2, 0, 0
10394
; numerical literal
10395
LIT_133: db 2, 0, 0
10398
; numerical literal
10399
LIT_134: db 2, 0, 0
10403
LIT_135: db 3, 0, 0, 5
10404
dw LIT_135_DATA, 0, 0
10406
LIT_135_DATA: db "L8C+C", 0
10408
; numerical literal
10409
LIT_136: db 2, 0, 0
10412
; numerical literal
10413
LIT_137: db 2, 0, 0
10416
; numerical literal
10417
LIT_138: db 2, 0, 0
10420
; numerical literal
10421
LIT_140: db 2, 0, 0
10424
; numerical literal
10425
LIT_141: db 2, 0, 0
10428
; numerical literal
10429
LIT_142: db 2, 0, 0
10432
; numerical literal
10433
LIT_143: db 2, 0, 0
10436
; numerical literal
10437
LIT_144: db 2, 0, 0
10440
; numerical literal
10441
LIT_145: db 2, 0, 0
10444
; numerical literal
10445
LIT_147: db 2, 0, 0
10448
; numerical literal
10449
LIT_148: db 2, 0, 0
10452
; numerical literal
10453
LIT_149: db 2, 0, 0
10456
; numerical literal
10457
LIT_151: db 2, 0, 0
10460
; numerical literal
10461
LIT_152: db 2, 0, 0
10464
; numerical literal
10465
LIT_153: db 2, 0, 0
10468
; numerical literal
10469
LIT_154: db 2, 0, 0
10472
; numerical literal
10473
LIT_155: db 2, 0, 0
10476
; numerical literal
10477
LIT_156: db 2, 0, 0
10480
; numerical literal
10481
LIT_157: db 2, 0, 0
10484
; numerical literal
10485
LIT_158: db 2, 0, 0
10489
LIT_159: db 3, 0, 0, 7
10490
dw LIT_159_DATA, 0, 0
10492
LIT_159_DATA: db "PLACAR:", 0
10495
LIT_160: db 3, 0, 0, 14
10496
dw LIT_160_DATA, 0, 0
10498
LIT_160_DATA: db " ENERGIA:", 0
10500
; numerical literal
10501
LIT_161: db 2, 0, 0
10504
; numerical literal
10505
LIT_162: db 2, 0, 0
10508
; numerical literal
10509
LIT_163: db 2, 0, 0
10513
LIT_164: db 3, 0, 0, 12
10514
dw LIT_164_DATA, 0, 0
10516
LIT_164_DATA: db "FIM DE JOGO!", 0
10519
LIT_165: db 3, 0, 0, 56
10520
dw LIT_165_DATA, 0, 0
10522
LIT_165_DATA: db "A3R15A4R15A8R15A3R15O5C5O4R15B8R15B5R15A8R15A5R15A8R15A1", 0
10524
; numerical literal
10525
LIT_166: db 2, 0, 0
10528
; numerical literal
10529
LIT_167: db 2, 0, 0
10532
; numerical literal
10533
LIT_168: db 2, 0, 0
10536
; numerical literal
10537
LIT_169: db 2, 0, 0
10540
; numerical literal
10541
LIT_170: db 2, 0, 0
10545
IDF_171: equ VAR_STACK.POINTER + 110
10548
LIT_172: db 3, 0, 0, 0
10549
dw LIT_172_DATA, 0, 0
10551
LIT_172_DATA: db "", 0
10553
; numerical literal
10554
LIT_173: db 2, 0, 0
10557
; numerical literal
10558
LIT_174: db 2, 0, 0
10561
; numerical literal
10562
LIT_175: db 2, 0, 0
10566
IDF_177: equ VAR_STACK.POINTER + 121
10569
IDF_179: equ VAR_STACK.POINTER + 132
10572
LIT_180: db 3, 0, 0, 0
10573
dw LIT_180_DATA, 0, 0
10575
LIT_180_DATA: db "", 0
10577
; numerical literal
10578
LIT_181: db 2, 0, 0
10581
; numerical literal
10582
LIT_182: db 2, 0, 0
10585
; numerical literal
10586
LIT_183: db 2, 0, 0
10589
; numerical literal
10590
LIT_185: db 2, 0, 0
10593
; numerical literal
10594
LIT_186: db 2, 0, 0
10597
; numerical literal
10598
LIT_188: db 2, 0, 0
10599
dw 0, &x00011000, 0, 0
10601
; numerical literal
10602
LIT_189: db 2, 0, 0
10603
dw 0, &x00100100, 0, 0
10605
; numerical literal
10606
LIT_190: db 2, 0, 0
10607
dw 0, &x01110110, 0, 0
10609
; numerical literal
10610
LIT_191: db 2, 0, 0
10611
dw 0, &x11011111, 0, 0
10613
; numerical literal
10614
LIT_192: db 2, 0, 0
10615
dw 0, &x11001111, 0, 0
10617
; numerical literal
10618
LIT_193: db 2, 0, 0
10619
dw 0, &x01100110, 0, 0
10621
; numerical literal
10622
LIT_194: db 2, 0, 0
10623
dw 0, &x00110100, 0, 0
10625
; numerical literal
10626
LIT_195: db 2, 0, 0
10627
dw 0, &x00011000, 0, 0
10629
; numerical literal
10630
LIT_196: db 2, 0, 0
10631
dw 0, &x10000001, 0, 0
10633
; numerical literal
10634
LIT_197: db 2, 0, 0
10635
dw 0, &x10000001, 0, 0
10637
; numerical literal
10638
LIT_198: db 2, 0, 0
10639
dw 0, &x10000001, 0, 0
10641
; numerical literal
10642
LIT_199: db 2, 0, 0
10643
dw 0, &x11000011, 0, 0
10645
; numerical literal
10646
LIT_200: db 2, 0, 0
10647
dw 0, &x11000011, 0, 0
10649
; numerical literal
10650
LIT_201: db 2, 0, 0
10651
dw 0, &x11111111, 0, 0
10653
; numerical literal
10654
LIT_202: db 2, 0, 0
10655
dw 0, &x11111111, 0, 0
10657
; numerical literal
10658
LIT_203: db 2, 0, 0
10659
dw 0, &x11000011, 0, 0
10661
AFTER_LAST_VARIABLE: equ VAR_STACK.POINTER + 143
10663
VAR_DUMMY.START: equ AFTER_LAST_VARIABLE ; variable dummy circular queue area
10664
VAR_DUMMY.COUNTER: equ VAR_DUMMY.START ; variable dummy circular queue count
10665
VAR_DUMMY.POINTER: equ VAR_DUMMY.COUNTER + 1 ; pointer to next variable dummy
10666
VAR_DUMMY.DATA: equ VAR_DUMMY.POINTER + 2 ; first variable dummy
10668
VAR_DUMMY.SIZE: equ 8
10669
VAR_DUMMY.LENGTH: equ (11 * VAR_DUMMY.SIZE)
10670
VAR_DUMMY.END: equ VAR_DUMMY.DATA + VAR_DUMMY.LENGTH
10671
VAR_STACK.END: equ VAR_DUMMY.END + 1
10674
;--------------------------------------------------------
10676
;--------------------------------------------------------
10695
DATA_ITEMS_COUNT: equ 16
10700
ld (BIOS_MCLTAB),HL
10703
ld hl, BIOS_TEMP ; voice count
10707
ld (BIOS_PRSCNT), a
10709
ld (BIOS_VOICEN), a
10710
ld (BIOS_QUEUEN), a
10711
ld (BIOS_MUSICF), a
10717
;__call_basic BASIC_PLAY_DIRECT
10720
; ix = address to call
10722
ld iy, CALL_BIOS.return
10725
call BASIC_SLOT_ENABLE
10728
call PROGRAM_SLOT_1_ENABLE_2
10734
ld a, (BIOS_EXPTBL)
10736
call BIOS_ENASLT ; Select main ROM on page 0 (0000h~3FFFh)
10740
ld a, (BIOS_EXPTBL)
10742
call BIOS_ENASLT ; Select main ROM on page 1 (4000h~7FFFh)
10745
PROGRAM_SLOT_1_ENABLE_2:
10749
call PROGRAM_SLOT_ENABLE_SUB_2
10751
jp BIOS_ENASLT ; Select the ROM on page 4000h-7FFFh
10753
PROGRAM_SLOT_ENABLE_SUB_2:
10756
and 3 ;Keep bits corresponding to the page
10774
;---------------------------------------------------------------------------------------------------------
10776
;---------------------------------------------------------------------------------------------------------
10778
if defined COMPILE_TO_ROM
10780
romPad: ds romSize - (romPad - pgmArea), 0
10784
end_file: end start_pgm ; label start is the entry point