1
;---------------------------------------------------------------------------------------------------------
2
; Source code converted by MSXBAS2ASM - MSX BASIC TO Z80 ASSEMBLY CONVERTER
3
; MSXBAS2ASM developed by Amaury Carvalho, 2019, Brazil
4
; http://launchpad.net/msxbas2asm
5
;---------------------------------------------------------------------------------------------------------
7
;--------------------------------------------------------
8
; MSX BIOS DATA/FUNCTION POINTERS
9
;--------------------------------------------------------
11
;---------------------------------------------------------------------------------------------------------
13
;---------------------------------------------------------------------------------------------------------
15
BIOS_CALBAS: equ 0x0159
16
BIOS_OUTDO: equ 0x0018 ; output to current device (i.e. screen)
17
BIOS_CHPUT: equ 0x00A2
19
BIOS_POSIT: equ 0x00C6
21
BIOS_CHGET: equ 0x009F
22
BIOS_CHSNS: equ 0x009C
23
BIOS_INLIN: equ 0x00B1
24
BIOS_PINLIN: equ 0x00AE
25
BIOS_QINLIN: equ 0x00B4
26
BIOS_GTSTCK: equ 0x00D5
27
BIOS_GTTRIG: equ 0x00D8
28
BIOS_GTPAD: equ 0x00DB
29
BIOS_GTPDL: equ 0x00DE
30
BIOS_DISSCR: equ 0x0041
31
BIOS_ENASCR: equ 0x0044
32
BIOS_CHGMOD: equ 0x005F
33
BIOS_CHGCLR: equ 0x0062
34
BIOS_CLRSPR: equ 0x0069
35
BIOS_INITXT: equ 0x006C ; init text mode 40 columns
36
BIOS_INIT32: equ 0x006F ; init text mode 32 columns
37
BIOS_INIGRP: equ 0x0072
38
BIOS_INIMLT: equ 0x0075
39
BIOS_SETTXT: equ 0x0078 ; set text mode 40 columns
40
BIOS_SETT32: equ 0x007B ; set text mode 32 columns
41
BIOS_SETGRP: equ 0x007E
42
BIOS_SETMLT: equ 0x0081
43
BIOS_CALPAT: equ 0x0084
44
BIOS_CALATR: equ 0x0087
45
BIOS_GSPSIZ: equ 0x008A
46
BIOS_GRPPRT: equ 0x008D
47
BIOS_ERAFNK: equ 0x00CC
48
BIOS_DSPFNK: equ 0x00CF
49
BIOS_TOTEXT: equ 0x00D2
50
BIOS_BREAKX: equ 0x00B7
51
BIOS_ISCNTC: equ 0x03FB
52
BIOS_CHKRAM: equ 0x0000
53
BIOS_GICINI: equ 0x0090
54
BIOS_WRTPSG: equ 0x0093
55
BIOS_REDPSG: equ 0x0096
56
BIOS_STRTMS: equ 0x0099
57
BIOS_KEYINT: equ 0x0038
58
BIOS_CALSLT: equ 0x001C
59
BIOS_ENASLT: equ 0x0024
60
BIOS_RSLREG: equ 0x0138
61
BIOS_SCALXY: equ 0x010E
62
BIOS_MAPXYC: equ 0x0111 ; in BC = X, DE = Y
63
BIOS_READC: equ 0x011D ; out A = color of current pixel
64
BIOS_SETATR: equ 0x011A ; in A = color code
65
BIOS_SETC: equ 0x0120 ; set current pixel to color from SETATR
66
BIOS_NSETCX: equ 0x0123 ; in HL = pixel fill count
67
BIOS_SCANR: equ 0x012C ; in B=Fill switch, DE=Skip count, out DE=Skip remainder, HL=Pixel count
68
BIOS_SCANL: equ 0x012F ; out HL=Pixel count
69
BIOS_FETCHC: equ 0x0114 ; out A = cursor mask, HL = VRAM address of cursor
70
BIOS_STOREC: equ 0x0117 ; in A = cursor mask, HL = VRAM address of cursor
71
BIOS_RESET: equ 0x7D17 ; restart BASIC
72
BIOS_IOALLOC: equ 0X7e6b ; memory setup
74
BIOS_GETVCP: equ 0x0150 ; get PSG voice buffer address (in A = voice number, out HL = address of byte 2)
75
BIOS_GETVC2: equ 0x0153 ; get PSG voice buffer address (VOICEN = voice number, in L = byte number 0-36, out HL = address)
77
BIOS_CHPUT_LF: equ 0x0908
78
BIOS_CHPUT_CR: equ 0x0A81
79
BIOS_CHPUT_TAB: equ 0x0A71
82
BIOS_CHKNEW: equ 0x0165 ; C-flag set if screenmode = 5, 6, 7 or 8
83
BIOS_EXTROM: equ 0x015F
84
BIOS_SCALXY2: equ 0x008D ; in BC = X, DE = Y
85
BIOS_MAPXYC2: equ 0x0091 ; in BC = X, DE = Y
86
BIOS_SETC2: equ 0x009D ; set current pixel to color from SETATR
87
BIOS_READC2: equ 0x0095 ; out A = color of current pixel
88
BIOS_CHGMOD2: equ 0x00D1 ; in A = screenmode
89
BIOS_DOBOXF: equ 0x0079 ; hl = basic text pointer
90
BIOS_GRPPRT2: equ 0x0089 ; a = character
91
BIOS_CHGCLR2: equ 0x0111 ; change color, a = screen mode
92
BIOS_CALPAT2: equ 0x00F9
93
BIOS_CALATR2: equ 0x00FD
94
BIOS_GSPSIZ2: equ 0x0101
95
BIOS_CLRSPR2: equ 0x00F5
97
;---------------------------------------------------------------------------------------------------------
99
;---------------------------------------------------------------------------------------------------------
101
BIOS_VERSION: equ 0x002D ; 0 = MSX1, 1 = MSX2, 2 = MSX2+, 3 = MSXturboR
102
BIOS_FORCLR: equ 0xF3E9
103
BIOS_BAKCLR: equ 0xF3EA
104
BIOS_BDRCLR: equ 0xF3EB
105
BIOS_ATRBYT: equ 0xF3F2
106
BIOS_INTFLG: equ 0xFC9B
107
BIOS_EXPTBL: equ 0xFCC1
108
BIOS_JIFFY: equ 0xFC9E
109
BIOS_BOTTOM: equ 0xFC48
110
BIOS_HIMEM: equ 0xFC4A
111
BIOS_SCRMOD: equ 0xFCAF ; 0=40x24 Text Mode, 1=32x24 Text Mode, 2=Graphics Mode, 3=Multicolour Mode.
112
BIOS_CLIKSW: equ 0xF3DB ; 0=keyboard click off, 1=keyboard click on
113
BIOS_GRPACX: equ 0xFCB7
114
BIOS_GRPACY: equ 0xFCB9
115
BIOS_DATLIN: equ 0xF6A3 ; 2 - line number of DATA statement read by READ statement
116
BIOS_DATPTR: equ 0xF6C8 ; 2 - address of data read by executing READ statement
117
BIOS_FLGINP: equ 0xF6A6 ; 1 - flag used in INPUT or READ
118
BIOS_TEMP: equ 0xF6A7 ; 2
119
BIOS_TEMP2: equ 0xF6BC ; 2
120
BIOS_TEMP3: equ 0xF69D ; 2
121
BIOS_TEMP8: equ 0xF69F ; 2
122
BIOS_TEMP9: equ 0xF7B8 ; 2
123
BIOS_OLDSCR: equ 0xFCB0 ; screen mode of the last text mode set
124
BIOS_LINL40: equ 0xF3AE ; width for 40 columns screen mode
125
BIOS_LINL32: equ 0xF3AF ; width for 32 columns screen mode
126
BIOS_LINLEN: equ 0xF3B0 ; current width for text screen mode
127
BIOS_CLMLST: equ 0xF3B2 ; minimum number of columns that must still be available on a line for a CRLF
128
BIOS_TXTNAM: equ 0xF3B3 ; characters table name
130
BIOS_VOICEN: equ 0xFB38 ; PSG voice number
131
BIOS_MCLTAB: equ 0xF956
132
BIOS_PRSCNT: equ 0xFB35
133
BIOS_SAVSP: equ 0xFB36
134
BIOS_QUEUEN: equ 0xFB3E
135
BIOS_MUSICF: equ 0xFB3F ;contains 3 bit flags set by the STRTMS. Bits 0, 1 and 2 correspond to VOICAQ, VOICBQ and VOICCQ.
136
BIOS_PLYCNT: equ 0xFB40
138
BIOS_DRWFLG: equ 0xFCBB
139
BIOS_MCLFLG: equ 0xF958
141
BIOS_SLTROM: equ 0xFCC1
142
BIOS_RAMAD0: equ 0xF341 ; Main-RAM Slot (00000h~03FFFh)
143
BIOS_RAMAD1: equ 0xF342 ; Main-RAM Slot (04000h~07FFFh)
144
BIOS_RAMAD2: equ 0xF343 ; Main-RAM Slot (08000h~0BFFFh)
145
BIOS_RAMAD3: equ 0xF344 ; Main-RAM Slot (0C000h~0FFFFh)
149
;--------------------------------------------------------
150
; MSX BASIC DATA/FUNCTION POINTERS
151
;--------------------------------------------------------
153
;---------------------------------------------------------------------------------------------------------
154
; MSX BASIC FUNCTIONS
155
;---------------------------------------------------------------------------------------------------------
157
BASIC_AUTO: equ 0x3973
158
BASIC_AND: equ 0x3A18
159
BASIC_ATTR: equ 0x39FE
160
BASIC_BASE: equ 0x39BE
161
BASIC_BSAVE: equ 0x39CC
162
BASIC_BLOAD: equ 0x39CA
163
BASIC_BEEP: equ 0x39AC
164
BASIC_CALL: equ 0x39C0
165
BASIC_CLOSE: equ 0x3994
166
BASIC_COPY: equ 0x39D8
167
BASIC_CONT: equ 0x395E
168
BASIC_CLEAR: equ 0x3950
169
BASIC_CLOAD: equ 0x3962
170
BASIC_CSAVE: equ 0x3960
171
BASIC_CSRLIN: equ 0x39FC
172
BASIC_CIRCLE: equ 0x39A4
173
BASIC_COLOR: equ 0x39A6
174
BASIC_CLS: equ 0x396A
175
BASIC_CMD: equ 0x39DA
176
BASIC_DELETE: equ 0x397C
177
BASIC_DATA: equ 0x3934
178
BASIC_DIM: equ 0x3938
179
BASIC_DEFSTR: equ 0x3982
180
BASIC_DEFINT: equ 0x3984
181
BASIC_DEFSNG: equ 0x3986
182
BASIC_DEFDBL: equ 0x3988
183
BASIC_DSKO: equ 0x39CE
184
BASIC_DEF: equ 0x395A
185
BASIC_DSKI: equ 0x3A00
186
BASIC_DRAW: equ 0x39A8
187
BASIC_ELSE: equ 0x396E
188
BASIC_END: equ 0x392E
189
BASIC_ERASE: equ 0x3976
190
BASIC_ERROR: equ 0x3978
191
BASIC_ERL: equ 0x39EE
192
BASIC_ERR: equ 0x39F0
193
BASIC_EQU: equ 0x3A1E
194
BASIC_FOR: equ 0x3920
195
BASIC_FIELD: equ 0x398E
196
BASIC_FILES: equ 0x39AA
198
BASIC_GOTO: equ 0x393E
199
BASIC_GOSUB: equ 0x3948
200
BASIC_GET: equ 0x3990
201
BASIC_INPUT: equ 0x3936
203
BASIC_INSTR: equ 0x39F6
204
BASIC_IMP: equ 0x3A20
205
BASIC_INKEY: equ 0x3A04
206
BASIC_IPL: equ 0x39D6
207
BASIC_KILL: equ 0x39D4
208
BASIC_KEY: equ 0x3964
209
BASIC_LPRINT: equ 0x394C
210
BASIC_LLIST: equ 0x3968
211
BASIC_LET: equ 0x393C
212
BASIC_LOCATE: equ 0x39DC
213
BASIC_LINE: equ 0x398A
214
BASIC_LOAD: equ 0x3996
215
BASIC_LSET: equ 0x399C
216
BASIC_LIST: equ 0x3952
217
BASIC_LFILES: equ 0x39A2
218
BASIC_MOTOR: equ 0x39C8
219
BASIC_MERGE: equ 0x3998
220
BASIC_MOD: equ 0x3A22
221
BASIC_MAX: equ 0x39C6
222
BASIC_NEXT: equ 0x3932
223
BASIC_NAME: equ 0x39D2
224
BASIC_NEW: equ 0x3954
225
BASIC_NOT: equ 0x39EC
226
BASIC_OPEN: equ 0x398C
227
BASIC_OUT: equ 0x3964
230
BASIC_OFF: equ 0x3A02
231
BASIC_PRINT: equ 0x394E
232
BASIC_PUT: equ 0x3992
233
BASIC_POKE: equ 0x395C
234
BASIC_PSET: equ 0x39B0
235
BASIC_PRESET: equ 0x39B2
236
BASIC_POINT: equ 0x3A06
237
BASIC_PAINT: equ 0x39AA
238
BASIC_PLAY: equ 0x39AE
239
BASIC_RETURN: equ 0x3948
240
BASIC_READ: equ 0x393A
241
BASIC_RUN: equ 0x3940
242
BASIC_RESTORE:equ 0x3944
243
BASIC_REM: equ 0x394A
244
BASIC_RESUME: equ 0x397A
245
BASIC_RSET: equ 0x399E
246
BASIC_RENUM: equ 0x3980
247
BASIC_SCREEN: equ 0x39B6
248
BASIC_SPRITE: equ 0x39BA
249
BASIC_STOP: equ 0x394C
250
BASIC_SWAP: equ 0x3974
251
BASIC_SET: equ 0x39D0
252
BASIC_SAVE: equ 0x39A0
253
BASIC_SPC: equ 0x39EA
254
BASIC_STEP: equ 0x39E4
255
BASIC_STRING: equ 0x39F2
256
BASIC_SPACE1: equ 0x397E
257
BASIC_SOUND: equ 0x39B4
258
BASIC_THEN: equ 0x39E0
259
BASIC_TRON: equ 0x3970
260
BASIC_TROFF: equ 0x3972
261
BASIC_TAB: equ 0x39E2
263
BASIC_TIME: equ 0x39C2
264
BASIC_USING: equ 0x39F4
265
BASIC_USR: equ 0x39E6
266
BASIC_VARPTR: equ 0x39FA
267
BASIC_VDP: equ 0x39BC
268
BASIC_VPOKE: equ 0x39B8
269
BASIC_WIDTH: equ 0x396C
270
BASIC_WAIT: equ 0x3958
271
BASIC_XOR: equ 0x3A1C
272
BASIC_ABS: equ 0x39E8
273
BASIC_ATN: equ 0x39F8
274
BASIC_ASC: equ 0x3A06
275
BASIC_BIN: equ 0x3A16
276
BASIC_CINT: equ 0x3A18
277
BASIC_CSNG: equ 0x3A1A
278
BASIC_CDBL: equ 0x3A1C
279
BASIC_CVI: equ 0x3A2C
280
BASIC_CVS: equ 0x3A2E
281
BASIC_CVD: equ 0x3A30
282
BASIC_COS: equ 0x39F4
283
BASIC_CHR: equ 0x3A08
284
BASIC_DSKF: equ 0x3A28
285
BASIC_EXP: equ 0x39F2
286
BASIC_EOF: equ 0x3A32
287
BASIC_FRE: equ 0x39FA
288
BASIC_FIX: equ 0x3A1E
289
BASIC_FPOS: equ 0x3A2A
290
BASIC_HEX: equ 0x3A12
291
BASIC_INT: equ 0x39E6
292
BASIC_INP: equ 0x39FC
293
BASIC_LPOS: equ 0x3A14
294
BASIC_LOG: equ 0x39F0
295
BASIC_LOC: equ 0x3A34
296
BASIC_LEN: equ 0x3A00
297
BASIC_LEFT: equ 0x39DE
298
BASIC_LOF: equ 0x3A36
299
BASIC_MKI: equ 0x3A38
300
BASIC_MKS: equ 0x3A3A
301
BASIC_MKD: equ 0x3A3C
302
BASIC_MID: equ 0x39E2
303
BASIC_OCT: equ 0x3A10
304
BASIC_POS: equ 0x39FE
305
BASIC_PEEK: equ 0x3A0A
306
BASIC_PDL: equ 0x3A24
307
BASIC_PAD: equ 0x3A26
308
BASIC_RIGHT: equ 0x39E0
309
BASIC_RND: equ 0x39EC
310
BASIC_SGN: equ 0x39E4
311
BASIC_SQR: equ 0x39EA
312
BASIC_SIN: equ 0x39EE
313
BASIC_STR: equ 0x3A02
314
BASIC_SPACE2: equ 0x3A0E
315
BASIC_STICK: equ 0x3A20
316
BASIC_STRIG: equ 0x3A22
317
BASIC_TAN: equ 0x39F6
318
BASIC_VAL: equ 0x3A04
319
BASIC_VPEEK: equ 0x3A0C
321
BASIC_TRAP_ENABLE: equ 0x631B ; ON INTERVAL/KEY/SPRITE/STOP/STRIG - hl = pointer to trap block
322
BASIC_TRAP_DISABLE: equ 0x632B ; hl = pointer to trap block
323
BASIC_TRAP_ACKNW: equ 0x6358 ; hl, acknowledge trap (handle trap: sts=5? has handler? ackn, pause, run trap, sts=1? unpause)
324
BASIC_TRAP_PAUSE: equ 0x6331 ; hl
325
BASIC_TRAP_UNPAUSE: equ 0x633E ; hl
326
BASIC_TRAP_CLEAR: equ 0x636E
328
BASIC_PLAY_DIRECT: equ 0x744C
329
BASIC_DRAW_DIRECT: equ 0x568C
331
BASIC_READYR: equ 0x409B
332
BASIC_READYC: equ 0x7D17
333
BASIC_FACEVAL: equ 0x4DC7
335
BASIC_ERROR_HANDLER:equ 0x406F
336
BASIC_ERROR_SYNTAX: equ 0x4055
337
BASIC_ERROR_DIVZER: equ 0x4058
338
BASIC_ERROR_OVRFLW: equ 0x4067
339
BASIC_ERROR_ARRAY: equ 0x405E
340
BASIC_ERROR_TYPMIS: equ 0x406D
342
; BASIC ERROR CODES TO BASIC_ERROR_HANDLER
343
; 01 NEXT without FOR 19 Device I/O error
344
; 02 Syntax error 20 Verify error
345
; 03 RETURN without GOSUB 21 No RESUME
346
; 04 Out of DATA 22 RESUME without error
347
; 05 Illegal function call 23 Unprintable error
348
; 06 Overflow 24 Missing operand
349
; 07 Out of memory 25 Line buffer overflow
350
; 08 Undefined line number 50 FIELD overflow
351
; 09 Subscript out of range 51 Internal error
352
; 10 Redimensioned array 52 Bad file number
353
; 11 Division by zero 53 File not found
354
; 12 Illegal direct 54 File already open
355
; 13 Type mismatch 55 Input past end
356
; 14 Out of string space 56 Bad file name
357
; 15 String too long 57 Direct statement in file
358
; 16 String formula too complex 58 Sequential I/O only
359
; 17 Can't CONTINUE 59 File not OPEN
360
; 18 Undefined user function
362
;---------------------------------------------------------------------------------------------------------
363
; MSX BASIC WORK AREAS
364
;---------------------------------------------------------------------------------------------------------
366
BASIC_DAC: equ 0xF7F6 ; 16
367
BASIC_ARG: equ 0xF847 ; 16
368
BASIC_VALTYP: equ 0xF663
369
BASIC_RNDX: equ 0xF857
370
BASIC_BUF: equ 0xF55E ; 259
371
BASIC_KBUF: equ 0xF41F ; 318
372
BASIC_SWPTMP: equ 0xF7BC ; 8
373
BASIC_STRBUF: equ 0xF7C5 ; 43
374
BASIC_TXTTAB: equ 0xF676
375
BASIC_VARTAB: equ 0xF6C2
376
BASIC_ARYTAB: equ 0xF6C4
377
BASIC_STREND: equ 0xF6C6
378
BASIC_STKTOP: equ 0xF674
379
BASIC_FRETOP: equ 0xF69B
380
BASIC_MEMSIZ: equ 0xF672
382
BASIC_TEMPPT: equ 0xF678 ; 2 Starting address of unused area of temporary descriptor.
383
BASIC_TEMPST: equ 0xF67A ; 30 Temporary descriptors.
385
BASIC_DATPTR: equ 0xF6C8 ; 2 Pointer to next data to read from the instruction DATA. Modified by RESTORE.
386
BASIC_DATLIN: equ 0xF6A3 ; 2 Número de linha do comando DATA para o comando READ.
387
BASIC_DORES: equ 0xF664 ; 1 Usada pelo comando DATA para manter o texto no formato ASCII.
388
BASIC_DEFTBL: equ 0xF6CA ; 26 table of variables defined by DEFINT, DEFSTR, DEFSNG and DEFDBL for each alphabet letter (2 = integer, 3 = String, 4 = Simple precision, 8 = Double precision).
390
BASIC_CURLIN: equ 0xF41C ; BASIC current line number
391
BASIC_INTVAL: equ 0xFCA0 ; interval value
392
BASIC_INTCNT: equ 0xFCA2 ; interval current count
394
BASIC_PRMPRV: equ 0xF74C ; Pointer to previous parameter block in PARM1
396
BASIC_TRPTBL: equ 0xFC4C ; 78 trap table - array of 3 bytes - state[1] (bit 0=on, bit 1=stop, bit 2=active) + address[2]
398
BASIC_TRPTBL_KEY: equ 0xFC4C ; 30 ON KEY GOSUB
399
BASIC_TRPTBL_STOP: equ 0xFC6A ; 3 ON STOP GOSUB
400
BASIC_TRPTBL_SPRITE: equ 0xFC6D ; 3 ON SPRITE GOSUB
401
BASIC_TRPTBL_STRIG: equ 0xFC70 ; 15 ON STRIG GOSUB
402
BASIC_TRPTBL_INTERVAL: equ 0xFC7F ; 3 ON INTERVAL GOSUB
403
BASIC_TRPTBL_OTHER: equ 0xFC82 ; 24 reserved for expansion
405
BASIC_ONGSBF: equ 0xFBD8 ; 1 trap occurred counter (0=not occurred)
409
;--------------------------------------------------------
411
;--------------------------------------------------------
413
;--------------------------------------------------------
415
;--------------------------------------------------------
416
COMPILE_TO_ROM: EQU 1
418
MACRO __call_basic,CALL_PARM
423
if defined COMPILE_TO_DOS
425
MACRO __call_bios,CALL_PARM
426
;ld iy,(BIOS_EXPTBL-1)
428
call BIOS_CALBAS ; BIOS_CALSLT
433
MACRO __call_bios,CALL_PARM
440
push hl ; save parameter
444
pop iy ; restore PC of caller
445
pop hl ; get next parameter
446
push iy ; save PC of caller
450
pop iy ; restore PC of caller
451
push hl ; save return parameter
452
push iy ; save PC of caller
456
pop iy ; restore PC of caller
457
push hl ; save return parameter
458
push iy ; save PC of caller
462
MACRO set.line.number, line_number
463
ld bc, line_number ; current line number
464
ld (BASIC_CURLIN), bc
468
ld a, (BIOS_INTFLG) ; verify CTRL+BREAK
474
ld a, (BASIC_ONGSBF) ; trap occured counter
480
;---------------------------------------------------------------------------------------------------------
482
;---------------------------------------------------------------------------------------------------------
484
romSize: equ 0x8000 ; ROM size (32k)
485
pageSize: equ 0x4000 ; Page size (16k)
486
lowLimitSize: equ 0x400 ; 10% of a page size
488
if defined COMPILE_TO_BIN
490
pgmArea: equ 0x8000 ; page 2 - program area
491
ramArea: equ 0xc000 ; page 3 - free RAM start area
493
org pgmArea ; program binary type start address
494
db 0FEh ; binary file ID
495
dw start_pgm ; begin address
496
dw end_file - 1 ; end address
497
dw start_pgm ; program execution address (for ,R option)
500
if defined COMPILE_TO_ROM
502
pgmArea: equ 0x4000 ; page 1 and 2 - program area
503
ramArea: equ 0xc000 ; page 3 - free RAM start area
505
org pgmArea ; program rom type start address
506
db 'AB' ; rom file ID
508
dw 0x0000 ; STATEMENT
515
pgmArea: equ 0x8000 ; page 2 - program area
516
ramArea: equ 0xc000 ; page 3 - free RAM start area
518
org pgmArea ; program DOS type start address ; 0x0100
524
;---------------------------------------------------------------------------------------------------------
526
;---------------------------------------------------------------------------------------------------------
528
if defined COMPILE_TO_ROM
531
call PROGRAM_SLOT_2_RESTORE
532
__call_basic BASIC_READYR ; warm start Basic
537
call PROGRAM_SLOT_GET
538
ld (BIOS_RAMAD2), a ; Save RAM slot of page 8000h-BFFFh
541
PROGRAM_SLOT_2_RESTORE:
544
jp BIOS_ENASLT ; Select the RAM on page 8000h-BFFFh
546
PROGRAM_SLOT_2_ENABLE:
548
call PROGRAM_SLOT_ENABLE_SUB
550
jp BIOS_ENASLT ; Select the ROM on page 8000h-BFFFh
552
PROGRAM_SLOT_1_ENABLE:
556
call PROGRAM_SLOT_ENABLE_SUB
558
jp BIOS_ENASLT ; Select the ROM on page 4000h-7FFFh
560
PROGRAM_SLOT_ENABLE_SUB:
563
and 3 ;Keep bits corresponding to the page
582
; a <- slot ID formatted FxxxSSPP
583
; Modifies: af, bc, de, hl
584
; ref: https://www.msx.org/forum/msx-talk/development/fusion-c-and-htimi#comment-366469
588
jr z,PrimaryShiftContinue
593
PrimaryShiftContinue:
595
jr z,PrimaryShiftDone
610
inc hl ; move to SLTTBL
617
jr z,SecondaryShiftContinue
622
SecondaryShiftContinue:
624
jr nz,SecondaryShiftDone
634
if defined COMPILE_TO_DOS
639
__call_bios BIOS_ENASLT ; Select main ROM on page 0 (0000h~3FFFh)
645
__call_bios BIOS_ENASLT ; Select main ROM on page 1 (4000h~7FFFh)
652
;---------------------------------------------------------------------------------------------------------
654
;---------------------------------------------------------------------------------------------------------
656
start_pgm: ; start of the program
658
if defined COMPILE_TO_DOS
660
call BIOS_SLOT_ENABLE ; enable bios on page 0
661
call BASIC_SLOT_ENABLE ; enable basic on page 1
664
if defined COMPILE_TO_ROM
666
call PROGRAM_SLOT_2_SAVE ; save slot on page 2
667
call PROGRAM_SLOT_2_ENABLE ; enable program on page 2
672
__call_bios BIOS_ERAFNK ; turn off function keys display
673
__call_bios BIOS_GICINI ; initialize sound system
674
__call_bios BIOS_INITXT ; initialize text screen
676
ld (BIOS_CLIKSW), a ; disable keyboard click
678
ld (BASIC_CURLIN), bc ; interpreter in direct mode
679
__call_basic BASIC_TRAP_CLEAR ; clear traps work space
680
;call INITIALIZE_PARAMETERS ; initialize parameters stack
681
call memory.init ; initialize memory allocation
682
call INITIALIZE_VARIABLES ; initialize variables
686
set.line.number 10 ; current line number
689
set.line.number 20 ; current line number
690
ld hl, LIT_4 ; parameter
692
call SCREEN ; action call
695
set.line.number 25 ; current line number
696
ld hl, LIT_10 ; parameter
698
ld hl, LIT_9 ; parameter
700
ld hl, LIT_8 ; parameter
702
ld hl, LIT_7 ; parameter
704
call PSET.XY ; action call
705
call BOX ; action call
706
ld hl, LIT_14 ; parameter
708
ld hl, LIT_13 ; parameter
710
ld hl, LIT_12 ; parameter
712
ld hl, LIT_11 ; parameter
714
call PSET.XY ; action call
715
call BOX ; action call
716
ld hl, LIT_18 ; parameter
718
ld hl, LIT_17 ; parameter
720
ld hl, LIT_16 ; parameter
722
ld hl, LIT_15 ; parameter
724
call PSET.XY ; action call
725
call BOX ; action call
728
set.line.number 30 ; current line number
729
ld hl, LIT_21 ; parameter
731
ld hl, LIT_23 ; parameter
733
call ATN ; action call
734
call MATH.MULT ; action call
735
ld hl, IDF_19 ; parameter
737
call LET ; action call
740
set.line.number 35 ; current line number
743
set.line.number 40 ; current line number
744
FOR_1 : ; start of FOR command
745
ld hl, LIT_28 ; parameter
747
ld hl, IDF_27 ; parameter
749
call LET ; action call
750
jp FOR.WHILE_1 ; jump to test if end of FOR
751
FOR.STEP_1 : ; STEP action
752
ld hl, LIT_31 ; parameter
754
ld hl, IDF_19 ; parameter
756
call MATH.MULT ; action call
757
ld hl, LIT_32 ; parameter
759
call MATH.DIV ; action call
760
ld hl, IDF_27 ; parameter
762
call MATH.ADD ; action call
763
ld hl, IDF_27 ; parameter
765
call LET ; action call
766
FOR.WHILE_1 : ; test if end of FOR
767
ld hl, IDF_27 ; parameter
769
ld hl, LIT_36 ; parameter
771
ld hl, IDF_19 ; parameter
773
call MATH.MULT ; action call
774
call BOOLEAN.LE ; action call
775
call BOOLEAN.IF ; verify IF condition result, out in A
777
jp z, ENDFOR_1 ; end the loop if while condition is false
778
FOR.BODY_1 : ; start of FOR user code
781
set.line.number 45 ; current line number
784
set.line.number 50 ; current line number
785
FOR_2 : ; start of FOR command
786
ld hl, LIT_38 ; parameter
788
ld hl, IDF_37 ; parameter
790
call LET ; action call
791
jp FOR.WHILE_2 ; jump to test if end of FOR
792
FOR.STEP_2 : ; STEP action
793
ld hl, LIT_39 ; parameter
795
ld hl, IDF_37 ; parameter
797
call MATH.ADD ; action call
798
ld hl, IDF_37 ; parameter
800
call LET ; action call
801
FOR.WHILE_2 : ; test if end of FOR
802
ld hl, IDF_37 ; parameter
804
ld hl, LIT_40 ; parameter
806
call BOOLEAN.LE ; action call
807
call BOOLEAN.IF ; verify IF condition result, out in A
809
jp z, ENDFOR_2 ; end the loop if while condition is false
810
FOR.BODY_2 : ; start of FOR user code
813
set.line.number 60 ; current line number
814
ld hl, LIT_42 ; parameter
816
ld hl, LIT_43 ; parameter
818
ld hl, IDF_37 ; parameter
820
call MATH.ADD ; action call
821
ld hl, IDF_27 ; parameter
823
call SIN ; action call
824
call MATH.MULT ; action call
825
call MATH.ADD ; action call
826
ld hl, IDF_41 ; parameter
828
call LET ; action call
829
ld hl, LIT_46 ; parameter
831
ld hl, LIT_47 ; parameter
833
ld hl, IDF_37 ; parameter
835
call MATH.ADD ; action call
836
ld hl, IDF_27 ; parameter
838
call COS ; action call
839
call MATH.MULT ; action call
840
call MATH.ADD ; action call
841
ld hl, IDF_45 ; parameter
843
call LET ; action call
846
set.line.number 70 ; current line number
847
IF_1 : ; start of IF command
848
ld hl, IDF_27 ; parameter
850
ld hl, LIT_50 ; parameter
852
call BOOLEAN.EQ ; action call
853
call BOOLEAN.IF ; verify IF condition result, out in A
855
jp z, ELSE_1 ; if false, jump to ELSE actions
856
THEN_1 : ; THEN actions
858
jp ENDIF_1 ; jump to END of IF command
859
ELSE_1 : ; ELSE actions
860
ENDIF_1 : ; end of IF command
863
set.line.number 80 ; current line number
864
ld hl, LIT_59 ; parameter
866
call PSET.COLOR ; action call
867
ld hl, IDF_45 ; parameter
869
ld hl, IDF_41 ; parameter
871
ld hl, IDF_57 ; parameter
873
ld hl, IDF_56 ; parameter
875
call PSET.XY ; action call
876
call LINE ; action call
879
set.line.number 85 ; current line number
882
set.line.number 90 ; current line number
883
ld hl, IDF_41 ; parameter
885
ld hl, IDF_56 ; parameter
887
call LET ; action call
888
ld hl, IDF_45 ; parameter
890
ld hl, IDF_57 ; parameter
892
call LET ; action call
895
set.line.number 100 ; current line number
896
jp FOR.STEP_2 ; repeat actions
897
ENDFOR_2 : ; END of FOR command
898
jp FOR.STEP_1 ; repeat actions
899
ENDFOR_1 : ; END of FOR command
902
set.line.number 105 ; current line number
905
set.line.number 110 ; current line number
906
FOR_3 : ; start of FOR command
907
ld hl, LIT_61 ; parameter
909
ld hl, IDF_27 ; parameter
911
call LET ; action call
912
jp FOR.WHILE_3 ; jump to test if end of FOR
913
FOR.STEP_3 : ; STEP action
914
ld hl, LIT_62 ; parameter
916
ld hl, IDF_19 ; parameter
918
call MATH.MULT ; action call
919
ld hl, LIT_63 ; parameter
921
call MATH.DIV ; action call
922
ld hl, IDF_27 ; parameter
924
call MATH.ADD ; action call
925
ld hl, IDF_27 ; parameter
927
call LET ; action call
928
FOR.WHILE_3 : ; test if end of FOR
929
ld hl, IDF_27 ; parameter
931
ld hl, LIT_64 ; parameter
933
ld hl, IDF_19 ; parameter
935
call MATH.MULT ; action call
936
call BOOLEAN.LE ; action call
937
call BOOLEAN.IF ; verify IF condition result, out in A
939
jp z, ENDFOR_3 ; end the loop if while condition is false
940
FOR.BODY_3 : ; start of FOR user code
943
set.line.number 120 ; current line number
944
ld hl, LIT_65 ; parameter
946
ld hl, LIT_66 ; parameter
948
ld hl, IDF_27 ; parameter
950
call SIN ; action call
951
call MATH.MULT ; action call
952
call MATH.ADD ; action call
953
ld hl, IDF_41 ; parameter
955
call LET ; action call
956
ld hl, LIT_67 ; parameter
958
ld hl, LIT_68 ; parameter
960
ld hl, IDF_27 ; parameter
962
call COS ; action call
963
call MATH.MULT ; action call
964
call MATH.ADD ; action call
965
ld hl, IDF_45 ; parameter
967
call LET ; action call
970
set.line.number 130 ; current line number
971
ld hl, LIT_70 ; parameter
973
ld hl, LIT_71 ; parameter
975
ld hl, IDF_27 ; parameter
977
ld hl, IDF_19 ; parameter
979
ld hl, LIT_72 ; parameter
981
call MATH.DIV ; action call
982
call MATH.ADD ; action call
983
call SIN ; action call
984
call MATH.MULT ; action call
985
call MATH.ADD ; action call
986
ld hl, IDF_69 ; parameter
988
call LET ; action call
989
ld hl, LIT_74 ; parameter
991
ld hl, LIT_75 ; parameter
993
ld hl, IDF_27 ; parameter
995
ld hl, IDF_19 ; parameter
997
ld hl, LIT_76 ; parameter
999
call MATH.DIV ; action call
1000
call MATH.ADD ; action call
1001
call COS ; action call
1002
call MATH.MULT ; action call
1003
call MATH.ADD ; action call
1004
ld hl, IDF_73 ; parameter
1006
call LET ; action call
1009
set.line.number 140 ; current line number
1010
ld hl, LIT_78 ; parameter
1012
ld hl, LIT_79 ; parameter
1014
ld hl, IDF_27 ; parameter
1016
ld hl, IDF_19 ; parameter
1018
ld hl, LIT_80 ; parameter
1020
call MATH.DIV ; action call
1021
call MATH.SUB ; action call
1022
call SIN ; action call
1023
call MATH.MULT ; action call
1024
call MATH.ADD ; action call
1025
ld hl, IDF_77 ; parameter
1027
call LET ; action call
1028
ld hl, LIT_83 ; parameter
1030
ld hl, LIT_84 ; parameter
1032
ld hl, IDF_27 ; parameter
1034
ld hl, IDF_19 ; parameter
1036
ld hl, LIT_85 ; parameter
1038
call MATH.DIV ; action call
1039
call MATH.SUB ; action call
1040
call COS ; action call
1041
call MATH.MULT ; action call
1042
call MATH.ADD ; action call
1043
ld hl, IDF_82 ; parameter
1045
call LET ; action call
1048
set.line.number 150 ; current line number
1049
ld hl, LIT_86 ; parameter
1051
call PSET.COLOR ; action call
1052
ld hl, IDF_45 ; parameter
1054
ld hl, IDF_41 ; parameter
1056
ld hl, IDF_73 ; parameter
1058
ld hl, IDF_69 ; parameter
1060
call PSET.XY ; action call
1061
call LINE ; action call
1062
ld hl, LIT_87 ; parameter
1064
call PSET.COLOR ; action call
1065
ld hl, IDF_45 ; parameter
1067
ld hl, IDF_41 ; parameter
1069
ld hl, IDF_82 ; parameter
1071
ld hl, IDF_77 ; parameter
1073
call PSET.XY ; action call
1074
call LINE ; action call
1077
set.line.number 155 ; current line number
1080
set.line.number 160 ; current line number
1081
jp FOR.STEP_3 ; repeat actions
1082
ENDFOR_3 : ; END of FOR command
1085
set.line.number 200 ; current line number
1088
;---------------------------------------------------------------------------------------------------------
1090
;---------------------------------------------------------------------------------------------------------
1092
end_pgm: __call_bios BIOS_DSPFNK ; turn on function keys display
1094
ld (BIOS_CLIKSW), a ; enable keyboard click
1096
if defined COMPILE_TO_ROM
1099
__call_basic BASIC_READYR ; warm start Basic
1102
ret ; end of the program
1104
;__call_bios BIOS_GICINI ; initialize sound system
1105
;if defined COMPILE_TO_DOS or defined COMPILE_TO_ROM
1106
; __call_bios BIOS_RESET ; restart Basic
1108
; __call_basic BASIC_END ; end to Basic
1112
;---------------------------------------------------------------------------------------------------------
1113
; MSX BASIC KEYWORDS
1114
;---------------------------------------------------------------------------------------------------------
1119
; out IX = variable assigned address
1120
pop.parm ; get variable address parameter
1121
push hl ; just to transfer hl to ix
1123
ld a, (ix) ; get variable type
1124
cp 3 ; test if string
1125
jr nz, LET.PARM ; if not a string, it isn't necessary to free memory
1126
ld a, (ix + 3) ; get variable string length
1128
jr z, LET.PARM ; if zero, it isn't necessary to free memory
1129
ld c, (ix + 4) ; get old string address low
1130
ld b, (ix + 5) ; get old string address high
1131
push ix ; save variable address
1132
push bc ; just to transfer bc (old string address) to ix
1134
call memory.free ; free memory
1135
pop ix ; restore variable address
1136
LET.PARM: pop.parm ; get data address parameter (out hl = data address)
1137
ld a, (ix + 2) ; get variable type flag
1138
or a ; cp 0 - test type flag (0=any, 255=fixed)
1139
jr nz, LET.FIXED ; if type flag is fixed, so casting is necessary
1140
LET.ANY: push ix ; just to transfer ix (variable address) to de
1142
ldi ; copy 1 byte from hl (data address) to de (variable address)
1143
inc de ; go to variable data area
1145
inc hl ; go to data data area
1147
ld bc, 8 ; data = 8 bytes
1148
ldir ; copy bc bytes from hl (data address) to de (variable address)
1149
ld a, (ix) ; get variable type
1150
cp 3 ; test if string
1151
ret nz ; if not string, return
1152
jp LET.STRING ; else do string treatment (in ix = variable address)
1153
LET.FIXED: push ix ; save variable destination address
1154
push hl ; save variable source address
1155
ld a, (ix) ; get variable fixed type, and hl has parameter data address
1156
call CAST_TO ; cast data to type (in hl = variable address, a = type to, out hl = casted data address)
1158
pop ix ; restore variable address
1159
ld a, (ix) ; get variable destination type again
1160
cp 3 ; test if string
1161
jr nz, LET.VALUE ; if not string, do value treatment
1162
ld a, (de) ; get variable source type again
1163
cp 3 ; test if string
1164
jr nz, LET.FIX1 ; if not string, get casted string size
1169
ld (ix + 3), a ; source string size
1172
call GET_STR.LENGTH ; get string length (in HL, out B)
1174
ld (ix + 3), b ; set variable length
1175
LET.FIX2: ld (ix + 4), l ; casted data address low
1176
ld (ix + 5), h ; casted data address high
1177
jp LET.STRING ; do string treatment (in ix = variable address)
1178
LET.VALUE: push ix ; just to transfer ix (variable address) to de
1180
inc de ; go to variable data area (and the data from its casted)
1183
ld bc, 8 ; data = 8 bytes
1184
ldir ; copy bc bytes from hl (data address) to de (variable address)
1186
LET.STRING: ld a, (ix + 3) ; string size
1187
or a ; cp 0 - test if null
1188
jr nz, LET.ALLOC ; if not null, allocate new string (in ix = variable address)
1189
ld bc, LIT_NULL_STR ; else, set to a null string literal
1190
ld (ix + 4), c ; variable address low
1191
ld (ix + 5), b ; variable address high
1193
LET.ALLOC: push ix ; save variable address
1194
ld l, (ix + 4) ; source string address low
1195
ld h, (ix + 5) ; source string address high
1196
push hl ; save copy from address
1197
ld c, (ix + 3) ; get variable length
1199
inc bc ; string length have one more byte from zero terminator
1200
push bc ; save variable lenght + 1
1201
call memory.alloc ; in bc = size, out ix = address, nz=OK
1203
push ix ; just to transfer memory address from ix to de
1205
pop bc ; restore bytes to be copied
1206
pop hl ; restore copy from string address
1207
push de ; save copy to address
1208
ldir ; copy bc bytes from hl (data address) to de (variable address)
1211
pop de ; restore copy to address
1212
pop ix ; restore variable address
1213
ld (ix + 4), e ; put memory address low into variable
1214
ld (ix + 5), d ; put memory address high into variable
1215
ret ; variable assigned
1220
pop.parm ; get parameter boolean result in hl
1223
ld a, (ix+5) ; put boolean integer result in a
1229
pop.parm ; get first parameter
1231
call GET_INT.VALUE ; output BC with integer value
1232
ld a, c ; A = screen number (0 to 3)
1234
jr c, SCREEN.1 ; if mode < 9, jump
1235
ld a, 8 ; else, fix to 8
1237
if defined EXIST_DATA_SET
1238
call gfxSetScreenMode
1242
jp gfxClearTileScreen
1250
pop.parm ; get first parameter
1252
call GET_INT.VALUE ; output BC with integer value
1253
ld (GFX_TEMP1), bc ; dX
1254
pop.parm ; get second parameter
1256
call GET_INT.VALUE ; output BC with integer value
1261
ld bc, (GFX_TEMP1) ; dX
1262
xor a ; a = 0 (framed box)
1268
pop.parm ; get first parameter
1270
call GET_INT.VALUE ; output BC with integer value
1271
ld (BIOS_GRPACX), bc ; X
1272
pop.parm ; get second parameter
1274
call GET_INT.VALUE ; output BC with integer value
1275
ld (BIOS_GRPACY), bc ; Y
1281
pop.parm ; get parameter
1282
call COPY_TO.DAC ; put in DAC
1283
and 12 ; test if single/double
1284
jr nz, ATN.1 ; if already double
1285
__call_bios MATH_FRCDBL ; convert DAC to double
1286
ATN.1: __call_bios MATH_ATN ; get parameter from DAC and put result in DAC
1287
jp MATH.PARM.PUSH ; return a dummy double variable from DAC
1292
call MATH.PARM.POP ; get parameters into DAC/ARG
1293
ld a, (BASIC_VALTYP) ;
1294
cp 2 ; test if integer
1295
jp z, MATH.MULT.INT ;
1296
cp 3 ; test if string
1298
cp 4 ; test if single
1299
jp z, MATH.MULT.SGL ;
1300
jp MATH.MULT.DBL ; it is a double
1304
; abstract virtual FOR
1308
call MATH.PARM.POP ; get parameters into DAC/ARG
1309
ld a, (BASIC_VALTYP) ;
1310
cp 2 ; test if integer
1311
jp z, MATH.ADD.INT ;
1312
cp 3 ; test if string
1313
jp z, STRING.CONCAT ;
1314
cp 4 ; test if single
1315
jp z, MATH.ADD.SGL ;
1316
jp MATH.ADD.DBL ; it is a double
1321
call MATH.PARM.POP ; get parameters into DAC/ARG
1322
ld a, (BASIC_VALTYP) ;
1323
cp 2 ; test if integer
1324
jp z, MATH.DIV.INT ;
1325
cp 3 ; test if string
1327
cp 4 ; test if single
1328
jp z, MATH.DIV.SGL ;
1329
jp MATH.DIV.DBL ; it is a double
1334
call MATH.PARM.POP ; get parameters into DAC/ARG
1335
ld a, (BASIC_VALTYP) ;
1336
cp 2 ; test if integer
1337
jp z, BOOLEAN.LE.INT ;
1338
cp 3 ; test if string
1339
jp z, BOOLEAN.LE.STR ;
1340
cp 4 ; test if single
1341
jp z, BOOLEAN.LE.SGL ;
1342
jp BOOLEAN.LE.DBL ; it is a double
1347
pop.parm ; get parameter
1348
call COPY_TO.DAC ; put in DAC
1349
and 12 ; test if single/double
1350
jr nz, SIN.1 ; if already double
1351
__call_bios MATH_FRCDBL ; convert DAC to double
1352
SIN.1: __call_bios MATH_SIN ; get parameter from DAC and put result in DAC
1353
jp MATH.PARM.PUSH ; return a dummy double variable from DAC
1358
pop.parm ; get parameter
1359
call COPY_TO.DAC ; put in DAC
1360
and 12 ; test if single/double
1361
jr nz, COS.1 ; if already double
1362
__call_bios MATH_FRCDBL ; convert DAC to double
1363
COS.1: __call_bios MATH_COS ; get parameter from DAC and put result in DAC
1364
jp MATH.PARM.PUSH ; return a dummy double variable from DAC
1369
call MATH.PARM.POP ; get parameters into DAC/ARG
1370
ld a, (BASIC_VALTYP) ;
1371
cp 2 ; test if integer
1372
jp z, BOOLEAN.EQ.INT ;
1373
cp 3 ; test if string
1374
jp z, BOOLEAN.EQ.STR ;
1375
cp 4 ; test if single
1376
jp z, BOOLEAN.EQ.SGL ;
1377
jp BOOLEAN.EQ.DBL ; it is a double
1381
; abstract virtual GOTO
1385
pop.parm ; get first parameter
1387
call GET_INT.VALUE ; output BC with integer value
1388
ld (GFX_TEMP1), bc ; dX
1389
pop.parm ; get second parameter
1391
call GET_INT.VALUE ; output BC with integer value
1396
ld bc, (GFX_TEMP1) ; dX
1402
pop.parm ; get first parameter
1404
call GET_INT.VALUE ; output BC with integer value
1406
call gfxSetForeColor
1411
; abstract virtual NEXT
1415
call MATH.PARM.POP ; get parameters into DAC/ARG
1416
ld a, (BASIC_VALTYP) ;
1417
cp 2 ; test if integer
1418
jp z, MATH.SUB.INT ;
1419
cp 3 ; test if string
1421
cp 4 ; test if single
1422
jp z, MATH.SUB.SGL ;
1423
jp MATH.SUB.DBL ; it is a double
1427
;---------------------------------------------------------------------------------------------------------
1428
; MSX BASIC SUPPORT CODE
1429
;---------------------------------------------------------------------------------------------------------
1431
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
1435
RUN_TRAPS.1: push hl
1446
; in hl = trap block address (handle trap: sts=5? has handler? ackn, pause, run trap, sts=1? unpause)
1448
ld a, (hl) ; trap status
1449
cp 5 ; trap occured AND trap not paused AND trap enabled ?
1450
ret nz ; return if false
1452
ld e, (hl) ; get trap address
1459
ret z ; return if address zero
1461
__call_basic BASIC_TRAP_ACKNW
1462
__call_basic BASIC_TRAP_PAUSE
1463
ld hl, TRAP_HANDLER.1
1464
ld a, (BASIC_ONGSBF) ; save traps execution
1467
ld (BASIC_ONGSBF), a ; disable traps execution
1468
push hl ; next return will be to trap handler
1469
push de ; indirect jump to trap address
1471
TRAP_HANDLER.1: pop af
1472
ld (BASIC_ONGSBF), a ; restore traps execution
1475
cp 1 ; trap enabled?
1477
__call_basic BASIC_TRAP_UNPAUSE
1480
; hl = trap block, de = trap handler
1482
ld (hl), a ; trap block status
1484
ld (hl), e ; trap block handler (pointer)
1491
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
1494
ld (BIOS_TEMP), a ; save voice number
1498
ret nz ; return if not string
1501
ld (BIOS_TEMP2), a ; save string size
1502
push hl ; string address
1503
ld a, (BIOS_TEMP) ; restore voice number
1504
call BIOS_GETVCP ; get PSG voice buffer address (in A = voice number, out HL = address of byte 2)
1506
ld a, (BIOS_TEMP2) ; restore string size
1507
ld (hl), a ; string size
1509
ld (hl), e ; string address
1513
ld D,H ; voice stack
1528
ld hl, BIOS_TEMP ; voice count
1542
__call_basic BASIC_PLAY_DIRECT
1549
;---------------------------------------------------------------------------------------------------------
1550
; VARIABLES ROUTINES
1551
;---------------------------------------------------------------------------------------------------------
1553
; input hl = variable address
1554
; input bc = variable name
1555
; input d = variable type
1556
INIT_VAR: ld (hl), d ; variable type
1558
ld (hl), c ; variable name 1
1560
ld (hl), b ; variable name 2
1574
CLEAR.VAR.LOOP: inc hl
1575
ld (hl), 0 ; data address/value
1578
; input HL = variable address
1579
; input A = variable output type
1580
; output HL = casted data address
1590
; input HL = variable address
1591
; output HL = variable address
1592
CAST_TO.INT: ;push af
1597
jp z, CAST_STR_TO.INT
1599
jp z, CAST_SGL_TO.INT
1601
jp z, CAST_DBL_TO.INT
1604
; input HL = variable address
1605
; output HL = variable address
1606
CAST_TO.STR: ;push af
1609
jp z, CAST_INT_TO.STR
1613
jp z, CAST_SGL_TO.STR
1615
jp z, CAST_DBL_TO.STR
1618
; input HL = variable address
1619
; output HL = variable address
1620
CAST_TO.SGL: ;push af
1623
jp z, CAST_INT_TO.SGL
1625
jp z, CAST_STR_TO.SGL
1629
jp z, CAST_DBL_TO.SGL
1632
; input HL = variable address
1633
; output HL = variable address
1634
CAST_TO.DBL: ;push af
1637
jp z, CAST_INT_TO.DBL
1639
jp z, CAST_STR_TO.DBL
1641
jp z, CAST_SGL_TO.DBL
1646
CAST_SGL_TO.STR: ; same as CAST_INT_TO.STR
1647
CAST_DBL_TO.STR: ; same as CAST_INT_TO.STR
1648
CAST_INT_TO.STR: call COPY_TO.DAC
1650
__call_bios MATH_FOUT ; convert DAC to string
1653
CAST_INT_TO.SGL: call COPY_TO.DAC
1654
__call_bios MATH_FRCSGL
1657
CAST_INT_TO.DBL: call COPY_TO.DAC
1658
__call_bios MATH_FRCDBL
1661
CAST_SGL_TO.INT: ; same as CAST_DBL_TO.INT
1662
CAST_DBL_TO.INT: call COPY_TO.DAC
1663
__call_bios MATH_FRCINT
1666
CAST_STR_TO.INT: call CAST_STR_TO.VAL ;
1667
__call_bios MATH_FRCINT ;
1670
CAST_STR_TO.SGL: call CAST_STR_TO.VAL ;
1671
__call_bios MATH_FRCSGL ;
1674
CAST_STR_TO.DBL: call CAST_STR_TO.VAL ;
1675
__call_bios MATH_FRCDBL ;
1678
CAST_STR_TO.VAL: call GET_STR.ADDR ;
1680
__call_bios MATH_FIN ; convert string to a value type
1683
GET_INT.VALUE: inc hl ; output BC with integer value
1689
CAST_SGL_TO.DBL: ; same as GET_DBL.ADDR
1690
CAST_DBL_TO.SGL: ; same as GET_DBL.ADDR
1691
GET_INT.ADDR: ; same as GET_DBL.ADDR
1692
GET_SGL.ADDR: ; same as GET_DBL.ADDR
1693
GET_DBL.ADDR: inc hl
1698
GET_STR.ADDR: push hl
1704
; input hl = string address
1705
; output b = string length
1706
GET_STR.LENGTH: ld b, 0
1707
GET_STR.LEN.NEXT: ld a, (hl)
1714
jr z, GET_STR.LEN.ERR
1716
GET_STR.LEN.ERR: ld b, 0
1718
STRING.COMPARE: ld ix, (BASIC_DAC+1) ; string 1
1719
ld iy, (BASIC_ARG+1) ; string 2
1720
STRING.COMPARE.NX: ld a, (ix) ; next char from string 1
1721
cp (iy) ; char s1 = char s2?
1722
jr nz, STRING.COMPARE.NE ; if not equal...
1724
jr z, STRING.COMPARE.F1 ; if string 1 has finished...
1725
ld a, (iy) ; next char from string 2
1727
jr z, STRING.COMPARE.GT ; if s2 has finished, s1 has not finished yet, so s1 is greater than s2
1730
jr STRING.COMPARE.NX ; get next char pair
1731
STRING.COMPARE.F1: ld a, (iy) ; verify if string 2 has finished too
1733
jr z, STRING.COMPARE.EQ ; if s2 has finished, then they are equals
1734
jr STRING.COMPARE.LT ; else, result = s1 is less than s2
1735
STRING.COMPARE.NE: jr c, STRING.COMPARE.GT ; verify if s1 is greater than s2...
1736
STRING.COMPARE.LT: ld a, 1 ; ...else, result = s1 less than s2
1738
STRING.COMPARE.GT: ld a, 0xFF ; result = s1 is greater than s2
1740
STRING.COMPARE.EQ: xor a ; result = s1 is equal to s2
1742
STRING.CONCAT: ld ix, BASIC_DAC ; s1 size
1743
ld a, (BASIC_ARG) ; s2 size
1744
add a, (ix) ; s3 size = s1 size + s2 size
1748
inc bc ; add 1 byte to size
1749
call memory.alloc ; in bc size, out ix new memory address, nz=OK
1750
jp z, memory.error ;
1754
ld a, (BASIC_DAC) ; s1 size
1755
ld hl, (BASIC_DAC + 1) ; string 1
1756
call COPY_TO.STR ; copy to new memory
1757
ld a, (BASIC_ARG) ; s2 size
1758
ld hl, (BASIC_ARG + 1) ; string 2
1759
call COPY_TO.STR ; copy to new memory
1761
ld (de), a ; null terminated
1764
call COPY_TO.VAR_DUMMY.STR ;
1765
ret.parm ; WARNING - VERIFY STRING MEMORY LEAKs
1766
STRING.PRINT: ld a, (BIOS_SCRMOD) ; 0=40x24 Text Mode, 1=32x24 Text Mode, 2=Graphics Mode, 3=Multicolour Mode
1768
jr nc, STRING.PRINT.G2 ; jump if graphic screen mode MSX2 (>=5)
1770
jr nc, STRING.PRINT.G1 ; jump if graphic screen mode MSX1 (>=2)
1771
STRING.PRINT.T: ld a, (hl) ; get a char from a string parameter
1772
or a ; cp 0 - is it the string end?
1774
__call_bios BIOS_CHPUT ; put the char (a) into text screen
1776
jr STRING.PRINT.T ; repeat
1777
STRING.PRINT.G1: ld a, (hl) ; get a char from a string parameter
1778
or a ; cp 0 - is it the string end?
1780
__call_bios BIOS_GRPPRT ; put the char (a) into graphical screen
1782
jr STRING.PRINT.G1 ; repeat
1783
STRING.PRINT.G2: ld a, (hl) ; get a char from a string parameter
1784
or a ; cp 0 - is it the string end?
1786
ld ix, BIOS_GRPPRT2 ; put the char (a) into graphical screen
1789
jr STRING.PRINT.G2 ; repeat
1791
; a = string size to copy
1792
; input hl = string from
1793
; input de = string to
1795
ret z ; avoid copy if size = zero
1797
ld c, a ; string size
1798
ldir ; copy bc bytes from hl to de
1800
COPY_TO.BASIC_BUF: ld bc, BASIC_BUF
1801
ld a, (LIT_QUOTE_CHAR)
1804
COPY_BAS_BUF.LOOP: ld a, (hl)
1806
jr z, COPY_BAS_BUF.EXIT
1810
jr COPY_BAS_BUF.LOOP
1811
COPY_BAS_BUF.EXIT: ld a, (LIT_QUOTE_CHAR)
1818
COPY_TO.VAR_DUMMY: ld a, (BASIC_VALTYP) ; create dummy variable from VALTYPE
1820
jr nz, COPY_TO.VAR_DUMMY.DBL
1822
call GET_STR.LENGTH ; get string length
1824
ld a, b ; string length
1825
COPY_TO.VAR_DUMMY.STR: call GET_VAR_DUMMY.ADDR ; create dummy string variable from HL
1826
ld (ix), 3 ; data type string
1828
ld (ix+2), 255 ; var type fixed
1829
ld (ix+3), a ; string length
1830
ld (ix+4), l ; data address low
1831
ld (ix+5), h ; data address high
1832
;call GET_STR.LENGTH ; get string length
1833
;ld (ix+3), b ; string length
1834
push ix ; output var address...
1837
COPY_TO.VAR_DUMMY.INT: call GET_VAR_DUMMY.ADDR ; create dummy integer variable from BC
1838
ld (ix), 2 ; data type string
1849
push ix ; output var address...
1852
COPY_TO.VAR_DUMMY.DBL: call GET_VAR_DUMMY.ADDR ; create dummy value variable from DAC
1853
ld (ix), a ; data type
1858
push ix ; just to copy ix to de
1863
ldir ; copy bc bytes from hl (data address) to de (variable address)
1864
push ix ; output var address...
1867
GET_VAR_DUMMY.ADDR: push af ;
1870
ld ix, (VAR_DUMMY.POINTER) ;
1871
ld a, (VAR_DUMMY.COUNTER) ;
1872
GET_VAR_DUMMY.NEXT: add ix, de ;
1875
jr nz, GET_VAR_DUMMY.EXIT ;
1877
ld ix, VAR_DUMMY.DATA ;
1878
GET_VAR_DUMMY.EXIT: ld (VAR_DUMMY.POINTER), ix ;
1879
ld (VAR_DUMMY.COUNTER), a ;
1880
ld a, (ix) ; get last var dummy type
1881
cp 3 ; is it string?
1882
call z, GET_VAR_DUMMY.FREE ; free string memory
1889
ld l, (ix+4) ; get string data address
1893
call memory.free ; free memory
1897
; input hl = variable address
1898
COPY_TO.DAC: ld de, BASIC_DAC
1899
COPY_TO.DAC.DATA: ld a, (hl)
1900
ld (BASIC_VALTYP), a
1904
ld bc, 8 ; data = 8 bytes
1905
ldir ; copy bc bytes from hl (data address) to de (variable address)
1907
COPY_TO.ARG: ld de, BASIC_ARG ;
1908
jr COPY_TO.DAC.DATA ;
1909
COPY_TO.DAC_ARG: ld hl, BASIC_DAC ;
1911
ld bc, 8 ; data = 8 bytes
1912
ldir ; copy bc bytes from hl (data address) to de (variable address)
1914
COPY_TO.ARG_DAC: ld hl, BASIC_ARG ;
1916
ld bc, 8 ; data = 8 bytes
1917
ldir ; copy bc bytes from hl (data address) to de (variable address)
1919
COPY_TO.DAC_TMP: ld hl, BASIC_DAC ;
1920
ld de, BASIC_SWPTMP ;
1921
ld bc, 8 ; data = 8 bytes
1922
ldir ; copy bc bytes from hl (data address) to de (variable address)
1924
COPY_TO.TMP_DAC: ld hl, BASIC_SWPTMP ;
1926
ld bc, 8 ; data = 8 bytes
1927
ldir ; copy bc bytes from hl (data address) to de (variable address)
1930
exx ; save registers
1933
ld de, BASIC_SWPTMP ;
1934
ldir ; copy bc bytes from hl to de
1938
ldir ; copy bc bytes from hl to de
1940
ld hl, BASIC_SWPTMP ;
1942
ldir ; copy bc bytes from hl to de
1943
exx ; restore registers
1946
CLEAR.DAC: ld de, BASIC_DAC
1947
CLEAR.DAC.DATA: ld hl, BASIC_VALTYP
1950
ld bc, 8 ; data = 8 bytes
1951
ldir ; copy bc bytes from hl (data address) to de (variable address)
1953
CLEAR.ARG: ld de, BASIC_ARG
1958
;---------------------------------------------------------------------------------------------------------
1959
; MATH 16 BITS ROUTINES
1960
;---------------------------------------------------------------------------------------------------------
1962
MATH.PARM.POP: pop af ; get PC from caller stack
1963
ex af, af' ; save PC to temp
1964
pop.parm ; get first parameter
1965
call COPY_TO.ARG ; put HL in ARG (return var type in A)
1966
pop.parm ; get second parameter
1967
ex af, af' ; restore PC from temp
1968
push af ; put again PC from caller in stack
1969
ex af, af' ; restore 1st data type
1970
push af ; save 1st data type
1971
call COPY_TO.DAC ; put HL in DAC (return var type in A)
1972
pop bc ; restore 1st data type (ARG) in B
1973
cp b ; test if data type in A (DAC) = data type in B (ARG)
1974
ret z ; return if is equal data types
1975
MATH.PARM.CAST: push bc ; else cast both to double
1976
and 12 ; test if single/double
1977
jr nz, MATH.PARM.CST1 ; avoid cast if already single/double
1978
__call_bios MATH_FRCDBL ; convert DAC to double
1979
MATH.PARM.CST1: pop af ;
1980
and 12 ; test if single/double
1981
jr nz, MATH.PARM.CST2 ; avoid cast if already single/double
1982
ld (BASIC_VALTYP), a ;
1983
call COPY_TO.DAC_TMP ;
1984
call COPY_TO.ARG_DAC ;
1985
__call_bios MATH_FRCDBL ; convert ARG to double
1986
call COPY_TO.DAC_ARG ;
1987
call COPY_TO.TMP_DAC ;
1988
MATH.PARM.CST2: ld a, 8 ;
1989
ld (BASIC_VALTYP), a ;
1991
MATH.PARM.POP.INT: ; return result in DAC/ARG as integer
1992
pop af ; get PC from caller stack
1993
ex af, af' ; save PC to temp
1994
pop.parm ; get first parameter
1995
ld a, (hl) ; get parameter type
1996
and 2 ; test if integer
1997
jr z, MATH.PARM.POP.I1 ; do cast if not integer
1998
call COPY_TO.ARG ; put HL in ARG (return var type in A)
1999
jr MATH.PARM.POP.I2 ; go to next parameter
2000
MATH.PARM.POP.I1: call COPY_TO.DAC ; put HL in DAC (return var type in A)
2001
__call_bios MATH_FRCINT ; convert DAC to int
2002
call COPY_TO.DAC_ARG ; copy DAC to ARG
2003
MATH.PARM.POP.I2: pop.parm ; get second parameter
2004
call COPY_TO.DAC ; put HL in DAC (return var type in A)
2005
and 2 ; test if integer
2006
jr nz, MATH.PARM.POP.I3 ; avoid cast if already integer
2007
__call_bios MATH_FRCINT ; convert DAC to int
2009
ld (BASIC_VALTYP), a ;
2011
ex af, af' ; restore PC from temp
2012
push af ; put again PC from caller in stack
2014
MATH.PARM.PUSH: call COPY_TO.VAR_DUMMY ;
2020
; output in parm stack
2021
; http://www.z80.info/zip/zaks_book.pdf - page 104
2022
MATH.ADD.INT: ld hl, (BASIC_DAC+2) ;
2023
ld bc, (BASIC_ARG+2) ;
2025
ld (BASIC_DAC+2), hl ;
2030
if defined MATH.SUB or defined MATH.NEG
2033
; output in parm stack
2034
; http://www.z80.info/zip/zaks_book.pdf - page 104
2035
MATH.SUB.INT: ld hl, (BASIC_DAC+2) ;
2036
ld de, (BASIC_ARG+2) ;
2039
ld (BASIC_DAC+2), hl ;
2044
if defined MATH.MULT
2047
; output in parm stack
2048
MATH.MULT.INT: ld hl, (BASIC_DAC+2) ;
2049
ld bc, (BASIC_ARG+2) ;
2051
ld (BASIC_DAC+2), hl ;
2054
; input HL = multiplicand
2055
; input BC = multiplier
2056
; output HL = result
2057
; http://www.z80.info/zip/zaks_book.pdf - page 131
2058
MATH.MULT.16: ld a, c ; low multiplier
2059
ld c, b ; high multiplier
2061
ld d, h ; multiplicand
2064
MULT16LOOP: srl c ; right shift multiplier high
2065
rra ; rotate right multiplier low
2066
jr nc, MULT16NOADD ; test carry
2067
add hl, de ; add multiplicand to result
2068
MULT16NOADD: ex de, hl
2069
add hl, hl ; double - shift multiplicand
2076
if defined MATH.DIV or defined MATH.IDIV or defined MATH.MOD
2078
; input AC = dividend
2079
; input DE = divisor
2080
; output AC = quotient
2081
; output HL = remainder
2082
; http://www.z80.info/zip/zaks_book.pdf - page 140
2083
MATH.DIV.16: ld hl, 0 ; clear accumulator
2084
ld b, 16 ; set counter
2085
DIV16LOOP: rl c ; rotate accumulator result left
2087
adc hl, hl ; left shift
2088
sbc hl, de ; trial subtract divisor
2089
jr nc, $ + 3 ; subtract was OK ($ = current location)
2090
add hl, de ; restore accumulator
2091
ccf ; calculate result bit
2092
djnz DIV16LOOP ; counter not zero
2093
rl c ; shift in last result bit
2099
if defined GFX_FAST or defined LINE
2101
; compare two signed 16 bits integers
2102
; HL < DE: Carry flag
2103
; HL = DE: Zero flag
2104
; http://www.z80.info/zip/zaks_book.pdf - page 531
2105
MATH.COMP.S16: ld a, h ; test high order byte
2106
and 0x80 ; test sign, clear carry
2107
jr nz, MATH.COMP.S16.NEGM1 ; jump if hl is negative
2109
ret nz ; de is negative (and hl is positive)
2111
cp d ; signs are both positive, so normal compare
2113
ld a, l ; test low order byte
2116
MATH.COMP.S16.NEGM1:
2118
rla ; sign bit into carry
2119
ret c ; signs different
2121
cp d ; both signs negative
2131
MATH.ADD.SGL: ld a, 8 ;
2132
ld (BASIC_VALTYP), a ;
2133
MATH.ADD.DBL: __call_bios MATH_DECADD ;
2138
if defined MATH.SUB or defined MATH.NEG
2140
MATH.SUB.SGL: ld a, 8 ;
2141
ld (BASIC_VALTYP), a ;
2142
MATH.SUB.DBL: __call_bios MATH_DECSUB ;
2147
if defined MATH.MULT
2149
MATH.MULT.SGL: ld a, 8 ;
2150
ld (BASIC_VALTYP), a ;
2151
MATH.MULT.DBL: __call_bios MATH_DECMUL ;
2159
; output in parm stack
2160
MATH.DIV.INT: __call_bios MATH_FRCDBL ; convert DAC to double
2163
ld (BASIC_VALTYP), a ;
2164
__call_bios MATH_FRCDBL ; convert ARG to double
2166
MATH.DIV.SGL: ld a, 8 ;
2167
ld (BASIC_VALTYP), a ;
2168
MATH.DIV.DBL: __call_bios MATH_DECDIV ;
2173
if defined MATH.IDIV
2176
; output in parm stack
2177
MATH.IDIV.SGL: ld a, 8 ;
2178
ld (BASIC_VALTYP), a ;
2179
MATH.IDIV.DBL: __call_bios MATH_FRCINT ; convert DAC to integer
2182
ld (BASIC_VALTYP), a ;
2183
__call_bios MATH_FRCINT ; convert ARG to integer
2185
MATH.IDIV.INT: ld hl, (BASIC_DAC+2) ;
2188
ld de, (BASIC_ARG+2) ;
2192
ld (BASIC_DAC+2), hl ; quotient
2199
MATH.POW.INT: ld (BASIC_VALTYP), a ;
2200
__call_bios MATH_FRCDBL ; convert DAC to double
2203
ld (BASIC_VALTYP), a ;
2204
__call_bios MATH_FRCDBL ; convert ARG to double
2206
MATH.POW.SGL: ld a, 8 ;
2207
ld (BASIC_VALTYP), a ;
2208
MATH.POW.DBL: __call_bios MATH_DBLEXP ;
2215
;MATH.MOD.SGL: ld a, 8 ;
2216
; ld (BASIC_VALTYP), a ;
2217
;MATH.MOD.DBL: __call_bios MATH_FRCINT ; convert DAC to integer
2218
; call SWAP.DAC.ARG ;
2220
; ld (BASIC_VALTYP), a ;
2221
; __call_bios MATH_FRCINT ; convert ARG to integer
2222
; call SWAP.DAC.ARG ;
2223
MATH.MOD.INT: ld hl, (BASIC_DAC+2) ;
2226
ld de, (BASIC_ARG+2) ;
2228
ld (BASIC_DAC+2), hl ; remainder
2235
; fast 16-bit integer square root
2236
; http://www.retroprogramming.com/2017/07/a-fast-z80-integer-square-root.html
2237
; 92 bytes, 344-379 cycles (average 362)
2238
; v2 - 3 t-state optimization spotted by Russ McNulty
2239
; call with hl = number to square root
2240
; returns a = square root
2317
if defined RANDOMIZE or defined SEED
2319
MATH.RANDOMIZE: di ;
2320
ld bc, (BIOS_JIFFY) ;
2323
MATH.SEED: ld (BASIC_RNDX), bc ; seed to IRND
2324
push bc ; in bc = new integer seed
2328
ld (BASIC_DAC+2), bc ; copy bc to dac
2329
ld a, 2 ; type integer
2330
ld (BASIC_VALTYP), a ;
2331
__call_bios MATH_FRCDBL ; convert DAC integer to DAC double
2332
__call_bios MATH_NEG ; DAC = -DAC
2333
__call_bios MATH_RND ; put in DAC a new random number from previous DAC parameter
2338
MATH.ERROR: ld e, 13 ; type mismatch
2339
__call_basic BASIC_ERROR_HANDLER ;
2343
;---------------------------------------------------------------------------------------------------------
2345
;---------------------------------------------------------------------------------------------------------
2347
BOOLEAN.RET.TRUE: ld hl, LIT_TRUE ;
2349
BOOLEAN.RET.FALSE: ld hl, LIT_FALSE ;
2351
BOOLEAN.CMP.INT: ld hl, (BASIC_DAC+2) ;
2352
ld de, (BASIC_ARG+2) ;
2353
__call_bios MATH_ICOMP ;
2355
BOOLEAN.CMP.SGL: ld bc, (BASIC_ARG) ;
2356
ld de, (BASIC_ARG+2) ;
2357
__call_bios MATH_DCOMP ;
2359
BOOLEAN.CMP.DBL: __call_bios MATH_XDCOMP ;
2361
BOOLEAN.CMP.STR: call STRING.COMPARE ;
2364
if defined BOOLEAN.GT
2366
BOOLEAN.GT.INT: call BOOLEAN.CMP.INT ;
2368
BOOLEAN.GT.STR: call BOOLEAN.CMP.STR ;
2370
BOOLEAN.GT.SGL: call BOOLEAN.CMP.SGL ;
2372
BOOLEAN.GT.DBL: call BOOLEAN.CMP.DBL ;
2374
BOOLEAN.GT.RET: cp 0x01 ;
2375
jp z, BOOLEAN.RET.TRUE ;
2376
jp BOOLEAN.RET.FALSE ;
2379
if defined BOOLEAN.LT
2381
BOOLEAN.LT.INT: call BOOLEAN.CMP.INT ;
2383
BOOLEAN.LT.STR: call BOOLEAN.CMP.STR ;
2385
BOOLEAN.LT.SGL: call BOOLEAN.CMP.SGL ;
2387
BOOLEAN.LT.DBL: call BOOLEAN.CMP.DBL ;
2389
BOOLEAN.LT.RET: cp 0xFF ;
2390
jp z, BOOLEAN.RET.TRUE ;
2391
jp BOOLEAN.RET.FALSE ;
2395
if defined BOOLEAN.GE
2397
BOOLEAN.GE.INT: call BOOLEAN.CMP.INT ;
2399
BOOLEAN.GE.STR: call BOOLEAN.CMP.STR ;
2401
BOOLEAN.GE.SGL: call BOOLEAN.CMP.SGL ;
2403
BOOLEAN.GE.DBL: call BOOLEAN.CMP.DBL ;
2405
BOOLEAN.GE.RET: cp 0x01 ;
2406
jp z, BOOLEAN.RET.TRUE ;
2408
jp z, BOOLEAN.RET.TRUE ;
2409
jp BOOLEAN.RET.FALSE ;
2413
if defined BOOLEAN.LE
2415
BOOLEAN.LE.INT: call BOOLEAN.CMP.INT ;
2417
BOOLEAN.LE.STR: call BOOLEAN.CMP.STR ;
2419
BOOLEAN.LE.SGL: call BOOLEAN.CMP.SGL ;
2421
BOOLEAN.LE.DBL: call BOOLEAN.CMP.DBL ;
2423
BOOLEAN.LE.RET: cp 0xFF ;
2424
jp z, BOOLEAN.RET.TRUE ;
2426
jp z, BOOLEAN.RET.TRUE ;
2427
jp BOOLEAN.RET.FALSE ;
2431
if defined BOOLEAN.NE
2433
BOOLEAN.NE.INT: call BOOLEAN.CMP.INT ;
2435
BOOLEAN.NE.STR: call BOOLEAN.CMP.STR ;
2437
BOOLEAN.NE.SGL: call BOOLEAN.CMP.SGL ;
2439
BOOLEAN.NE.DBL: call BOOLEAN.CMP.DBL ;
2441
BOOLEAN.NE.RET: or a ; cp 0
2442
jp nz, BOOLEAN.RET.TRUE ;
2443
jp BOOLEAN.RET.FALSE ;
2447
if defined BOOLEAN.EQ
2449
BOOLEAN.EQ.INT: call BOOLEAN.CMP.INT ;
2451
BOOLEAN.EQ.STR: call BOOLEAN.CMP.STR ;
2453
BOOLEAN.EQ.SGL: call BOOLEAN.CMP.SGL ;
2455
BOOLEAN.EQ.DBL: call BOOLEAN.CMP.DBL ;
2457
BOOLEAN.EQ.RET: or a ; cp 0
2458
jp z, BOOLEAN.RET.TRUE ;
2459
jp BOOLEAN.RET.FALSE ;
2463
if defined BOOLEAN.AND
2465
BOOLEAN.AND.INT: ld a, (BASIC_DAC+2) ;
2466
ld hl, BASIC_ARG+2 ;
2468
ld (BASIC_DAC+2), a ;
2470
ld a, (BASIC_DAC+3) ;
2472
ld (BASIC_DAC+3), a ;
2478
if defined BOOLEAN.OR
2480
BOOLEAN.OR.INT: ld a, (BASIC_DAC+2) ;
2481
ld hl, BASIC_ARG+2 ;
2483
ld (BASIC_DAC+2), a ;
2485
ld a, (BASIC_DAC+3) ;
2487
ld (BASIC_DAC+3), a ;
2493
if defined BOOLEAN.XOR
2495
BOOLEAN.XOR.INT: ld a, (BASIC_DAC+2) ;
2496
ld hl, BASIC_ARG+2 ;
2498
ld (BASIC_DAC+2), a ;
2500
ld a, (BASIC_DAC+3) ;
2502
ld (BASIC_DAC+3), a ;
2508
if defined BOOLEAN.EQV
2510
BOOLEAN.EQV.INT: ld a, (BASIC_DAC+2) ;
2511
ld hl, BASIC_ARG+2 ;
2514
ld (BASIC_DAC+2), a ;
2516
ld a, (BASIC_DAC+3) ;
2519
ld (BASIC_DAC+3), a ;
2525
if defined BOOLEAN.IMP
2527
BOOLEAN.IMP.INT: ld a, (BASIC_DAC+2) ;
2528
ld hl, BASIC_ARG+2 ;
2531
ld (BASIC_DAC+2), a ;
2533
ld a, (BASIC_DAC+3) ;
2536
ld (BASIC_DAC+3), a ;
2542
if defined BOOLEAN.SHR
2544
BOOLEAN.SHR.INT: ld ix, BASIC_DAC+2 ; shift DAC integer to right (bits 15...0-->)
2545
ld a, (BASIC_ARG+2) ;
2547
jp z, MATH.PARM.PUSH ; return if not shift
2548
ld b, a ; shift count
2549
BOOLEAN.SHR.INT.N: rr (ix+1) ;
2552
djnz BOOLEAN.SHR.INT.N ; next shift
2554
jp MATH.PARM.PUSH ; return DAC
2558
if defined BOOLEAN.SHL
2560
BOOLEAN.SHL.INT: ld ix, BASIC_DAC+2 ; shift DAC integer to left (<--bits 15...0)
2561
ld a, (BASIC_ARG+2) ;
2563
jp z, MATH.PARM.PUSH ; return if not shift
2564
ld b, a ; shift count
2565
BOOLEAN.SHL.INT.N: rl (ix) ;
2568
djnz BOOLEAN.SHL.INT.N ; next shift
2570
jp MATH.PARM.PUSH ; return DAC
2574
if defined BOOLEAN.NOT
2576
BOOLEAN.NOT.INT: ld a, (BASIC_DAC+2) ;
2578
ld (BASIC_DAC+2), a ;
2579
ld a, (BASIC_DAC+3) ;
2581
ld (BASIC_DAC+3), a ;
2589
;---------------------------------------------------------------------------------------------------------
2590
; MEMORY ALLOCATION ROUTINES
2591
;---------------------------------------------------------------------------------------------------------
2592
; Adapted from memory allocator code by SamSaga2, Spain, 2015
2593
; https://www.msx.org/forum/msx-talk/development/asm-memory-allocator
2594
; https://www.msx.org/users/samsaga2
2595
;---------------------------------------------------------------------------------------------------------
2596
memory.heap_start: equ VAR_STACK.END + 1 ; start at end of variable stack
2597
memory.heap_end: equ 0xF0A0 - 100 ; end at start of work area for stack (100 bytes reserved), BIOS and BASIC interpreter
2598
block.next: equ 0 ; next free block address
2599
block.size: equ 2 ; size of block including header
2600
block: equ 4 ; block.next + block.size
2604
ld ix,memory.heap_start ; first block
2605
ld hl,memory.heap_start+block ; second block
2606
;; first block NEXT=secondblock, SIZE=0
2607
;; with this block we have a fixed start location
2608
;; because never will be allocated
2609
ld (ix+block.next),l
2610
ld (ix+block.next+1),h
2611
ld (ix+block.size),0
2612
ld (ix+block.size+1),0
2613
;; second block NEXT=0, SIZE=all
2614
;; the first and only free block have all available memory
2615
ld (ix+block.next+block),0
2616
ld (ix+block.next+block+1),0
2618
;ld hl,memory.heap_end ; size = @heap_end (stack) - heap_start - block_header * 2 - 100 (buffer for stack)
2621
ld de, memory.heap_start + (block * 2) + 100
2623
;ld de, block * 2 + 100
2625
ld (ix+block.size+block),l
2626
ld (ix+block.size+block+1),h
2630
;; IN BC=size, OUT IX=memptr, NZ=ok
2638
ld ix,memory.heap_start ; this
2641
ld l,(ix+block.size)
2642
ld h,(ix+block.size+1)
2645
jp z, memory.alloc.exactfit
2646
jp c, memory.alloc.nextblock
2647
;; split found block
2648
memory.alloc.splitfit:
2649
;; free space must allow at least two blocks headers (current + next)
2651
jr nz, memory.alloc.splitfit.do ; if free space > 0xFF, do split
2654
jr c, memory.alloc.nextblock ; if free space < 4, skip to next block
2655
memory.alloc.splitfit.do:
2656
;; newfreeblock = this + BC
2660
;; prevblock->next = newfreeblock
2661
ld (iy+block.next),l
2662
ld (iy+block.next+1),h
2663
;; newfreeblock->next = this->next
2665
pop iy ; iy = newfreeblock
2666
ld l,(ix+block.next)
2667
ld h,(ix+block.next+1)
2668
ld (iy+block.next),l
2669
ld (iy+block.next+1),h
2670
;; newfreeblock->size = this->size - BC
2671
ld l,(ix+block.size)
2672
ld h,(ix+block.size+1)
2675
ld (iy+block.size),l
2676
ld (iy+block.size+1),h
2678
ld (ix+block.size),c
2679
ld (ix+block.size+1),b
2681
;; use whole found block
2682
memory.alloc.exactfit:
2683
;; prevblock->next = this->next - remove block from free list
2684
ld l,(ix+block.next)
2685
ld h,(ix+block.next+1)
2686
ld (iy+block.next),l
2687
ld (iy+block.next+1),h
2696
memory.alloc.nextblock:
2697
ld l,(ix+block.next)
2698
ld h,(ix+block.next+1)
2705
;; this = this->next
2708
jp memory.alloc.find
2713
;; HL = IX - block_header_size
2720
ld ix,memory.heap_start
2722
ld e,(ix+block.next)
2723
ld d,(ix+block.next+1)
2726
jp z, memory.free.passedend
2727
sbc hl,de ; test this (HL) against next (DE)
2728
jr c, memory.free.found ; if DE > HL
2729
add hl,de ; restore hl value
2731
pop ix ; current = next
2734
;; ix=prev, hl=this, de=next
2736
add hl,de ; restore hl value
2737
ld (ix+block.next), l
2738
ld (ix+block.next+1), h ; prev->next = this
2741
ld (iy+block.next), e
2742
ld (iy+block.next+1), d ; this->next = next
2743
push ix ; prev x this
2748
call memory.free.coalesce
2749
pop ix ; this x next
2750
jr memory.free.coalesce
2754
memory.free.coalesce:
2755
ld c, (iy+block.size)
2756
ld b, (iy+block.size+1) ; bc = this->size
2760
adc hl, bc ; hl = this + this->size
2764
sbc hl, de ; if this + this->size == next, then this->size += next->size, this->next = next->next
2765
jr z, memory.free.coalesce.do
2766
push ix ; else, new *this = *next
2769
memory.free.coalesce.do:
2770
ld l, (ix+block.size)
2771
ld h, (ix+block.size+1) ; hl = next->size
2773
adc hl, bc ; hl += this->size
2774
ld (iy+block.size), l
2775
ld (iy+block.size+1), h ; this->size = hl
2776
ld l, (ix+block.next)
2777
ld h, (ix+block.next+1) ; hl = next->next
2778
ld (iy+block.next), l
2779
ld (iy+block.next+1), h ; this->next = hl
2782
memory.free.passedend:
2783
;; append block at the end of the free list
2784
ld (ix+block.next),l
2785
ld (ix+block.next+1),h
2788
ld (iy+block.next),0
2789
ld (iy+block.next+1),0
2795
ld ix,memory.heap_start
2797
memory.get_free.count:
2799
add a,(ix+block.size)
2802
adc a,(ix+block.size+1)
2804
ld l,(ix+block.next)
2805
ld h,(ix+block.next+1)
2811
jr memory.get_free.count
2813
memory.error: ld e, 7 ; out of memory
2814
__call_basic BASIC_ERROR_HANDLER ;
2819
;---------------------------------------------------------------------------------------------------------
2821
; By: Amaury Carvalho, 2019
2822
;---------------------------------------------------------------------------------------------------------
2824
; https://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm#Algorithm_for_integer_arithmetic
2825
; https://en.wikipedia.org/wiki/Midpoint_circle_algorithm
2826
; https://rosettacode.org/wiki/Bitmap/Midpoint_circle_algorithm#C
2827
; https://www.msx.org/wiki/MSX-BASIC_Instructions
2828
;---------------------------------------------------------------------------------------------------------
2830
;---------------------------------------------------------------------------------------------------------
2832
;---------------------------------------------------------------------------------------------------------
2834
BIOS_WRTVDP: EQU 0x0047
2835
BIOS_RDVRM: EQU 0x004A
2836
BIOS_WRTVRM: EQU 0x004D
2837
BIOS_LDIRVM: EQU 0x005C
2838
BIOS_LDIRMV: EQU 0x0059
2839
BIOS_PNTINI: EQU 0x18CF
2840
BIOS_RIGHTC: EQU 0x16C5 ; Move current pixel physical address right
2841
BIOS_TRIGHTC: EQU 0x16AC ; Test then RIGHTC if legal
2842
BIOS_LEFTC: EQU 0x16EE ; Move current pixel physical address left
2843
BIOS_TLEFTC: EQU 0x16D8 ; Test then LEFTC if legal
2844
BIOS_UPC: EQU 0x175D ; Move current pixel physical address up
2845
BIOS_TUPC: EQU 0x173C ; Test then UPC if legal
2846
BIOS_DOWNC: EQU 0x172A ; Move current pixel physical address down
2847
BIOS_TDOWNC: EQU 0x170A ; Test then DOWNC if legal
2848
BIOS_DCOMPR: EQU 0x146A ; compare HL and DE (Flag NC if HL>DE, Flag Z if HL=DE, Flag C if HL<DE)
2849
BIOS_FILVRM: EQU 0x0056 ; fill VRAM with value
2851
BIOS_BIGFIL: EQU 0x016B ; msx 2
2852
BIOS_NRDVRM: EQU 0x0174 ; msx 2
2853
BIOS_NWRVRM: EQU 0x0177 ; msx 2
2854
BIOS_NRDVDP: EQU 0x013E ; msx 2
2855
BIOS_VDPSTA: EQU 0x0131 ; msx 2
2856
BIOS_NWRVDP: EQU 0x012D ; msx 2 (0x0647)
2858
BASIC_SUB_LINE: equ 0x58fc
2859
BASIC_SUB_LINEBOX: equ 0x5912
2860
BASIC_SUB_LINEBOXFILLED: equ 0x58C1
2861
BASIC_SUB_CIRCLE: equ 0x5B19
2862
BASIC_SUB_PAINT1: equ 0x59DA ;0x59C8
2863
BASIC_SUB_PAINT2: equ 0x0069 ;0x2664 ;0x2651+3
2865
;---------------------------------------------------------------------------------------------------------
2867
;---------------------------------------------------------------------------------------------------------
2869
BIOS_RG0SAV: EQU 0xF3DF
2870
BIOS_RG1SAV: EQU 0xF3E0
2871
BIOS_RG8SAV: EQU 0xFFE7
2872
BIOS_BDRATR: EQU 0xFCB2
2873
BIOS_STATFL: EQU 0xF3E7 ; VDP status register
2875
BIOS_CXOFF: EQU 0xF945
2876
BIOS_CYOFF: EQU 0xF947
2877
BIOS_GXPOS: EQU 0xFCB3
2878
BIOS_GYPOS: EQU 0xFCB5
2880
BIOS_GRPNAM: EQU 0xF3C7 ; pattern name table
2881
BIOS_GRPCOL: EQU 0xF3C9 ; colour table
2882
BIOS_GRPCGP: EQU 0xF3CB ; pattern generator table
2883
BIOS_GRPATR: EQU 0xF3CD ; sprite attribute table
2884
BIOS_GRPPAT: EQU 0xF3CF ; sprite generator table
2885
BIOS_CGPNT: EQU 0xF920 ; 2 - current MSX Font location (0x1BBF)
2886
BIOS_ATRBAS: EQU 0xF928 ; sprite attribute table
2888
BIOS_MLTNAM: EQU 0xF3D1 ; pattern name table (screen 3, multicolor)
2889
BIOS_MLTCOL: EQU 0xF3D3 ; colour table (screen 3, multicolor)
2890
BIOS_MLTCGP: EQU 0xF3D5 ; pattern generator table (screen 3, multicolor)
2891
BIOS_MLTATR: EQU 0xF3D7 ; sprite attribute table (screen 3, multicolor)
2892
BIOS_MLTPAT: EQU 0xF3D9 ; sprite generator table (screen 3, multicolor)
2894
BIOS_ASPECT: equ 0xF931 ;2 Aspect ratio of the circle; set by <ratio> of CIRCLE.
2895
BIOS_CENCNT: equ 0xF933 ;2 Counter used by CIRCLE.
2896
BIOS_CLINEF: equ 0xF935 ;1 Flag to draw line to centre, Used set by CIRCLE
2897
BIOS_CNPNTS: equ 0xF936 ;2 Point to be plottted in a 45° segment, Used set by CIRCLE
2898
BIOS_CPLOTF: equ 0xF938 ;1 Plot polarity flag, Used set by CIRCLE
2899
BIOS_CPCNT: equ 0xF939 ;2 Number of points in 1/8 of circle, Used set by CIRCLE.
2900
BIOS_CPCNT8: equ 0xF93B ;2 Number of points in the circle. Used by CIRCLE.
2901
BIOS_CRCSUM: equ 0xF93D ;2 Cyclic redundancy check sum of the circle. Used by CIRCLE.
2902
BIOS_CSTCNT: equ 0xF93F ;2 Variable to maintain the number of points of the starting angle. Used by the instruction CIRCLE
2903
BIOS_CSCLXY: equ 0xF941 ;1 Scale of X & Y. Used by the instruction CIRCLE
2904
BIOS_ASPCT1: equ 0xF40B ;2 256/aspect ratio for Basic instruction CIRCLE.
2905
BIOS_ASPCT2: equ 0xF40D ;2 256*aspect ratio for Basic instruction CIRCLE.
2906
BIOS_MAXUPD: equ 0xF3EC ;3 Work area used by the instruction CIRCLE, contains JP 0000h at start.
2907
BIOS_MINUPD: equ 0xF3EF ;3 Work area used by the instruction CIRCLE, contains JP 0000h at start.
2909
BIOS_PARM1: EQU 0xF6E8 ; 100
2910
BIOS_PARM2: EQU 0xF750 ; 100
2912
GFX_TEMP: EQU BIOS_PARM1 ; 2
2913
GFX_TEMP1: EQU GFX_TEMP + 2 ; 2
2914
GFX_TEMP2: EQU GFX_TEMP1 + 2 ; 2
2915
GFX_TEMP3: EQU GFX_TEMP2 + 2 ; 2
2916
GFX_TEMP4: EQU GFX_TEMP3 + 2 ; 2
2917
GFX_TEMP5: EQU GFX_TEMP4 + 2 ; 2
2918
GFX_TEMP6: EQU GFX_TEMP5 + 2 ; 2
2919
GFX_TEMP7: EQU GFX_TEMP6 + 2 ; 2
2920
GFX_TEMP8: EQU GFX_TEMP7 + 2 ; 2
2921
GFX_TEMP9: EQU GFX_TEMP8 + 2 ; 2
2923
GFX_MAX_X: EQU 0xFCA4 ; 1 (CASSETE LOWLIM)
2924
GFX_MAX_Y: EQU 0xFCA5 ; 1 (CASSETE WINWID)
2926
GFX_SPRITE_FLAGS: EQU 0xF40A ; 1 (CASSETE HEADER) - bits 0=check screen limits, 1=check walls, 2=check hotspots,
2927
; 3=limit touched, 4=wall touched, 5=hotspot touched, 6=collided
2928
GFX_SPRITE_SIZE_DAT: EQU 0xF3FC ; 1 (CASSETE CS1200)
2929
GFX_SPRITE_SIZE_SCR: EQU 0xF3FD ; 1
2930
GFX_SPRITE_WALLS: EQU 0xF406 ; 2 (CASSETE LOW)
2931
GFX_SPRITE_HOTSPOTS: EQU 0xF408 ; 2 (CASSETE HIGH)
2932
GFX_SPRITE_HOTSPOT_TILE: EQU 0xF405 ; 1 (CASSETE CS2400)
2933
GFX_SPRITE_COLLIDER: EQU 0xF400 ; 1 (CASSETE CS1200)
2934
GFX_SPRITE_COLLISION: EQU 0xF7B5 ; 2 (ARYTA2)
2936
GFX_MUSIC_START: EQU 0xF401 ; 2 (CASSETE CS2400)
2937
GFX_MUSIC_NEXT: EQU 0xF403 ; 2
2938
GFX_MUSIC_PREV: EQU 0xF74C ; 2 (PRMPRV)
2940
GFX_TEMP10: EQU 0xF3FE ; 2 (CASSETE CS1200)
2942
;BIOS_SCR_SIZE_X: dw 240, 256, 256, 64, 256, 256, 512, 512, 256, 512, 256, 256, 256
2943
;BIOS_SCR_SIZE_Y: dw 192, 192, 192, 48, 192, 212, 212, 212, 212, 384, 212, 212, 212
2944
BIOS_SCR_SIZE_X: db 239, 255, 255, 63, 255, 255, 255, 255, 255, 255, 255, 255, 255
2945
BIOS_SCR_SIZE_Y: db 191, 191, 191, 47, 191, 211, 211, 211, 211, 255, 211, 211, 211
2948
;---------------------------------------------------------------------------------------------------------
2949
; gfxIsScreenModeMSX2
2950
; return if screen mode is from MSX 2
2951
; out C is set, if MSX2 and screen mode above 3
2952
;---------------------------------------------------------------------------------------------------------
2954
gfxIsScreenModeMSX2:
2955
ld a, (BIOS_VERSION)
2957
jp nz, BIOS_CHKNEW ; if not MSX1, jump to CHKNEW
2961
;---------------------------------------------------------------------------------------------------------
2963
; set current screen mode
2964
; in A = screen number
2965
;---------------------------------------------------------------------------------------------------------
2969
call gfxInitScreenWorkspace
2971
ld a, (BIOS_VERSION)
2973
jr nz, gfxSetScreenMode.1 ; if not MSX1, jump
2976
call nc, gfxSetScreenMode.0 ; if screen mode >= 4, change to screen 2
2977
__call_bios BIOS_CHGMOD ; change the screen mode (msx1)
2978
jr gfxSetScreenMode.2
2986
ld ix, BIOS_CHGMOD2 ; change the screen mode (msx2)
2990
call gfxGetScreenHeight
2991
call gfxGetScreenWidth
2992
call gfxGetSpriteSize
2993
jp gfxFillSpriteCollisionTable
2995
gfxInitScreenWorkspace:
2997
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
2999
ld (GFX_SPRITE_WALLS), a
3000
ld (GFX_SPRITE_WALLS+1), a
3001
ld (GFX_SPRITE_HOTSPOTS), a
3002
ld (GFX_SPRITE_HOTSPOTS+1), a
3003
ld (GFX_MUSIC_START), a
3004
ld (GFX_MUSIC_START+1), a
3005
ld (GFX_MUSIC_NEXT), a
3006
ld (GFX_MUSIC_NEXT+1), a
3007
ld (GFX_MUSIC_PREV), a
3008
ld (GFX_MUSIC_PREV+1), a
3009
ld (GFX_SPRITE_HOTSPOT_TILE), a
3010
ld (GFX_SPRITE_COLLIDER), a
3013
;---------------------------------------------------------------------------------------------------------
3015
; return current screen mode
3016
; out A = screen number (0=40x24 Text Mode, 1=32x24 Text Mode, 2=Graphics Mode, 3=Multicolour Mode)
3017
;---------------------------------------------------------------------------------------------------------
3023
;---------------------------------------------------------------------------------------------------------
3025
; set current screen location
3028
;---------------------------------------------------------------------------------------------------------
3031
ld (BIOS_GRPACX), bc ; x
3032
;ld (BIOS_GXPOS), bc
3033
ld (BIOS_GRPACY), de ; y
3034
;ld (BIOS_GYPOS), de
3037
;---------------------------------------------------------------------------------------------------------
3039
; refresh current screen location
3040
;---------------------------------------------------------------------------------------------------------
3043
ld bc, (BIOS_GRPACX) ; x
3044
ld de, (BIOS_GRPACY) ; y
3046
call gfxIsScreenModeMSX2
3047
jr nc, gfxRefreshXY.2 ; if MSX2 and screen mode above 3
3048
__call_bios BIOS_SCALXY ; BC = X, DE = Y
3049
__call_bios BIOS_MAPXYC ; in BC = X, DE = Y
3052
ld ix, BIOS_SCALXY2 ; BC = X, DE = Y
3054
ld ix, BIOS_MAPXYC2 ; in BC = X, DE = Y
3057
;---------------------------------------------------------------------------------------------------------
3059
; get current screen location
3062
;---------------------------------------------------------------------------------------------------------
3065
ld bc, (BIOS_GRPACX) ; x
3066
ld de, (BIOS_GRPACY) ; y
3069
;---------------------------------------------------------------------------------------------------------
3070
; gfxGetScreenHeight
3072
; out a = screen height
3073
;---------------------------------------------------------------------------------------------------------
3078
ld hl, BIOS_SCR_SIZE_Y
3089
;---------------------------------------------------------------------------------------------------------
3092
; out a = screen height
3093
;---------------------------------------------------------------------------------------------------------
3098
ld hl, BIOS_SCR_SIZE_X
3109
;---------------------------------------------------------------------------------------------------------
3111
; get sprite data size
3112
; out a = sprite data size
3113
;---------------------------------------------------------------------------------------------------------
3118
ld a, (BIOS_RG1SAV) ; bit 0 = double size, bit 1 = sprite size (0=8 pixels, 1=16 pixels)
3120
jr z, gfxGetSpriteSize.1
3125
jr z, gfxGetSpriteSize.2
3129
ld (GFX_SPRITE_SIZE_DAT), bc
3135
if defined GFX_FAST and defined PAINT
3137
;---------------------------------------------------------------------------------------------------------
3139
; move screen current location up
3140
; out: carry if off screen
3141
;---------------------------------------------------------------------------------------------------------
3146
ld de, (BIOS_GRPACY)
3151
ld (BIOS_GRPACY), de
3162
;---------------------------------------------------------------------------------------------------------
3164
; move screen current location down
3165
; out: carry if off screen
3166
;---------------------------------------------------------------------------------------------------------
3173
ld de, (BIOS_GRPACY)
3178
ld (BIOS_GRPACY), de
3189
;---------------------------------------------------------------------------------------------------------
3191
; move screen current location left
3192
; out: carry if off screen
3193
;---------------------------------------------------------------------------------------------------------
3198
ld de, (BIOS_GRPACX)
3203
ld (BIOS_GRPACX), de
3214
;---------------------------------------------------------------------------------------------------------
3216
; move screen current location right
3217
; out: carry if off screen
3218
;---------------------------------------------------------------------------------------------------------
3225
ld de, (BIOS_GRPACX)
3230
ld (BIOS_GRPACX), de
3243
;---------------------------------------------------------------------------------------------------------
3245
; push current screen location
3246
;---------------------------------------------------------------------------------------------------------
3251
ld iy, (BIOS_GRPACX) ; x
3253
ld iy, (BIOS_GRPACY) ; y
3259
;---------------------------------------------------------------------------------------------------------
3261
; pop current screen location
3264
;---------------------------------------------------------------------------------------------------------
3273
;---------------------------------------------------------------------------------------------------------
3275
; set current foreground color
3277
;---------------------------------------------------------------------------------------------------------
3280
ld (BIOS_FORCLR), a ; foreground color
3284
;---------------------------------------------------------------------------------------------------------
3286
; get current foreground color
3288
;---------------------------------------------------------------------------------------------------------
3291
ld a, (BIOS_FORCLR) ; foreground color
3294
;---------------------------------------------------------------------------------------------------------
3296
; set current background color
3298
;---------------------------------------------------------------------------------------------------------
3301
ld (BIOS_BAKCLR), a ; foreground color
3304
;---------------------------------------------------------------------------------------------------------
3306
; get current background color
3308
;---------------------------------------------------------------------------------------------------------
3311
ld a, (BIOS_BAKCLR) ; foreground color
3314
;---------------------------------------------------------------------------------------------------------
3316
; set current border color
3318
;---------------------------------------------------------------------------------------------------------
3321
ld (BIOS_BDRCLR), a ; border color
3324
;---------------------------------------------------------------------------------------------------------
3326
; get current border color
3328
;---------------------------------------------------------------------------------------------------------
3331
ld a, (BIOS_BDRCLR) ; border color
3334
;---------------------------------------------------------------------------------------------------------
3336
; set fill border color
3338
;---------------------------------------------------------------------------------------------------------
3341
ld (BIOS_BDRATR), a ; border color
3344
;---------------------------------------------------------------------------------------------------------
3346
; get fill border color
3348
;---------------------------------------------------------------------------------------------------------
3351
ld a, (BIOS_BDRATR) ; border color
3354
;---------------------------------------------------------------------------------------------------------
3356
; set current color (foreground, background and border)
3357
;---------------------------------------------------------------------------------------------------------
3362
jp nz, BIOS_CHGCLR2 ; change VDP colors - msx2
3364
jp nz, BIOS_CHGCLR2 ; change VDP colors - msx2
3365
jp BIOS_CHGCLR ; change VDP colors
3366
; __call_bios BIOS_SETATR ; change the pixel color
3369
;---------------------------------------------------------------------------------------------------------
3371
; set pixel in current position to current foreground color
3372
;---------------------------------------------------------------------------------------------------------
3375
call gfxIsScreenModeMSX2
3376
jr nc, gfxSetPixel.1 ; if MSX2 and screen mode above 3
3377
__call_bios BIOS_SETC
3383
;---------------------------------------------------------------------------------------------------------
3385
; get pixel color in current position
3386
; out A = pixel color
3387
;---------------------------------------------------------------------------------------------------------
3390
call gfxIsScreenModeMSX2
3391
jr nc, gfxGetPixel.1 ; if MSX2 and screen mode above 3
3392
__call_bios BIOS_READC
3400
;---------------------------------------------------------------------------------------------------------
3402
; plot a line from current position to informed destination
3403
; in BC = destination x
3404
; DE = destination y
3405
; https://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm#Algorithm_for_integer_arithmetic
3406
; https://rosettacode.org/wiki/Bitmap/Bresenham%27s_line_algorithm#C
3407
;---------------------------------------------------------------------------------------------------------
3408
;void line(int x0, int y0, int x1, int y1) {
3409
; int dx = abs(x1-x0), sx = x0<x1 ? 1 : -1;
3410
; int dy = abs(y1-y0), sy = y0<y1 ? 1 : -1;
3411
; int err = (dx>dy ? dx : -dy)/2, e2;
3414
; if (x0==x1 && y0==y1) break;
3416
; if (e2 >-dx) { err -= dy; x0 += sx; }
3417
; if (e2 < dy) { err += dx; y0 += sy; }
3422
if not defined GFX_FAST
3423
ld hl, (BIOS_GRPACX)
3425
ld hl, (BIOS_GRPACY)
3427
__call_basic BASIC_SUB_LINE
3432
ld (GFX_TEMP2), bc ; x
3433
ld (GFX_TEMP3), de ; y
3435
ld hl, (BIOS_GRPACX) ; x0
3436
ld de, (GFX_TEMP2) ; x
3439
;jp po, gfxLine.1 ; x0 >= x? else jump to endif
3441
jp c, gfxLine.1 ; x0 < x? jump
3444
ld (GFX_TEMP4), hl ; dx = x0 - x
3446
ld (GFX_TEMP5), hl ; sx = -1
3450
ld de, (BIOS_GRPACX) ; x0
3451
ld hl, (GFX_TEMP2) ; x
3454
ld (GFX_TEMP4), hl ; dx = x - x0
3456
ld (GFX_TEMP5), hl ; sx = 1
3459
ld hl, (BIOS_GRPACY) ; y0
3460
ld de, (GFX_TEMP3) ; y
3463
;jp po, gfxLine.3 ; y0 >= y? else, jump to endif
3465
jp c, gfxLine.3 ; y0 < y? jump
3468
ld (GFX_TEMP6), hl ; dy = y0 - y
3470
ld (GFX_TEMP7), hl ; sy = -1
3474
ld de, (BIOS_GRPACY) ; y0
3475
ld hl, (GFX_TEMP3) ; y
3478
ld (GFX_TEMP6), hl ; dy = y - y0
3480
ld (GFX_TEMP7), hl ; sy = 1
3483
ld hl, (GFX_TEMP6) ; dy
3486
jp z, gfxLine.h ; dy = 0?
3488
ld hl, (GFX_TEMP4) ; dx
3491
jp z, gfxLine.v ; dx = 0?
3493
ld de, (GFX_TEMP4) ; dx
3494
ld hl, (GFX_TEMP6) ; dy
3499
ld (GFX_TEMP9), hl ; dxy = dx + dy
3501
ld de, (GFX_TEMP4) ; dx
3502
ld hl, (GFX_TEMP6) ; dy
3505
;jp pe, gfxLine.5 ; dy < dx? else, jump to endif
3507
jp z, gfxLine.5 ; dy = dx? jump
3508
jp nc, gfxLine.5 ; dy > dx? jump
3510
ld de, (GFX_TEMP6) ; dy
3516
ld (GFX_TEMP8), de ; err = -dy / 2
3520
ld hl, (GFX_TEMP4) ; dx
3524
ld (GFX_TEMP8), hl ; err = dx/2
3529
ld hl, (GFX_TEMP9) ; dxy
3532
jp nc, gfxLine.loop.0 ; dxy > 0? jump
3533
;jp z, gfxLine.loop.0 ; dxy = 0? jump
3539
ld de, (GFX_TEMP4) ; dx
3542
ld de, (GFX_TEMP8) ; e2 = err
3546
;jp pe, gfxLine.loop.1 ; if -dx < e2, else jump to endif
3548
jp z, gfxLine.loop.1 ; -dx = e2? jump
3549
jp nc, gfxLine.loop.1 ; -dx > e2? jump
3550
ld hl, (GFX_TEMP8) ; err
3551
ld de, (GFX_TEMP6) ; dy
3554
ld (GFX_TEMP8), hl ; err -= dy
3556
ld hl, (GFX_TEMP9) ; dxy
3558
ld (GFX_TEMP9), hl ; dxy -= 1
3560
ld hl, (BIOS_GRPACX)
3564
ld (BIOS_GRPACX), hl ; x0 += sx
3568
ld de, (GFX_TEMP6) ; dy
3571
;jp pe, gfxLine.loop.2 ; if e2 < dy, else jump to endif
3573
jp z, gfxLine.loop.2 ; e2 = dy? jump
3574
jp nc, gfxLine.loop.2 ; e2 > dy? jump
3575
ld hl, (GFX_TEMP8) ; err
3576
ld de, (GFX_TEMP4) ; dx
3579
ld (GFX_TEMP8), hl ; err += dx
3581
ld hl, (GFX_TEMP9) ; dxy
3583
ld (GFX_TEMP9), hl ; dxy -= 1
3585
ld hl, (BIOS_GRPACY)
3589
ld (BIOS_GRPACY), hl ; y0 += sy
3596
ld a, (GFX_TEMP5) ; sx
3598
jr z, gfxLine.h.1 ; if a is positive
3599
ld hl, (BIOS_GRPACX)
3603
ld (BIOS_GRPACX), hl
3607
__call_bios BIOS_FETCHC
3608
ld hl, (GFX_TEMP4) ; dx
3610
call gfxDrawHorLine ; HL = pixel count
3614
ld a, (GFX_TEMP7) ; sy
3616
jr z, gfxLine.v.1 ; if a is positive
3617
ld hl, (BIOS_GRPACY)
3621
ld (BIOS_GRPACY), hl
3626
ld hl, (GFX_TEMP6) ; dy
3629
jp gfxBox.drawVerLine
3634
if defined BOX or defined FBOX or defined BOX_STEP or defined FBOX_STEP
3636
;---------------------------------------------------------------------------------------------------------
3638
; plot a box from current position to informed destination
3639
; in BC = destination x
3640
; DE = destination y
3641
; A = filled flag (0 = not filled, <>0 = filled)
3642
;---------------------------------------------------------------------------------------------------------
3646
if not defined GFX_FAST
3647
ld hl, (BIOS_GRPACX)
3649
ld hl, (BIOS_GRPACY)
3651
ld hl, BASIC_SUB_LINEBOX
3654
call gfxIsScreenModeMSX2
3656
ld hl, BASIC_SUB_LINEBOXFILLED
3661
jp BIOS_CALBAS ; BIOS_CALSLT
3672
call gfxAdjustDestXY
3674
jr nz, gfxBox.filled
3678
call gfxBox.drawHorLine
3680
ld de, (BIOS_GRPACX)
3684
ld (BIOS_GRPACX), hl
3686
call gfxBox.drawVerLine
3688
call gfxBox.drawVerLine
3689
call gfxBox.drawHorLine
3697
ld bc, (BIOS_GRPACX)
3699
call gfxBox.drawHorLine
3701
ld (BIOS_GRPACX), bc
3702
ld bc, (BIOS_GRPACY)
3704
ld (BIOS_GRPACY), bc
3710
jr nz, gfxBox.filled.loop
3722
gfxBox.drawVerLine.loop:
3730
jr nz, gfxBox.drawVerLine.loop
3733
;---------------------------------------------------------------------------------------------------------
3735
; draw a horizontal line
3737
;---------------------------------------------------------------------------------------------------------
3742
jr c, gfxDrawHorLine.2 ; if screen mode < 5 then jump
3744
ret nz ; return if negative
3747
jr nz, gfxDrawHorLine.1
3749
ret z ; return if hl = 0
3758
jr nz, gfxDrawHorLine.1
3762
__call_bios BIOS_NSETCX ; HL = fill count
3765
;---------------------------------------------------------------------------------------------------------
3767
; invert if dest XY is less than current XY position
3770
;---------------------------------------------------------------------------------------------------------
3774
ld (GFX_TEMP2), bc ; x
3775
ld (GFX_TEMP3), de ; y
3777
; verify x againt current position
3778
ld hl, (BIOS_GRPACX)
3781
sbc hl, de ; dx = x1 - x0
3782
bit 7, h ; result is negative?
3783
jr z, gfxAdjustDestXY.1
3785
ld (BIOS_GRPACX), hl
3793
; verify y againt current position
3794
ld hl, (BIOS_GRPACY)
3797
sbc hl, de ; dy = y1 - y0
3798
bit 7, h ; result is negative?
3799
jr z, gfxAdjustDestXY.2
3801
ld (BIOS_GRPACY), hl
3809
; refresh new position
3819
;---------------------------------------------------------------------------------------------------------
3821
; plot a circle centered in current position
3822
; BC = tracing end x
3823
; DE = tracing end y
3825
; A = filled flag (0 = not filled, <>0 = filled)
3826
; https://en.wikipedia.org/wiki/Midpoint_circle_algorithm
3827
; https://rosettacode.org/wiki/Bitmap/Midpoint_circle_algorithm#C
3828
;---------------------------------------------------------------------------------------------------------
3832
if not defined GFX_FAST
3834
ret nz ; return if negative radius
3835
ld (BIOS_GXPOS), hl ; circle ray
3837
ld bc, (BIOS_GRPACY)
3841
;jr nz, gfxDrawCircle.1
3848
__call_basic BASIC_SUB_CIRCLE
3851
ld (GFX_TEMP), hl ; radius
3854
ret z ; return if zero radius
3856
ret nz ; return if negative radius
3859
ld (GFX_TEMP1), bc ; x0
3860
ld (GFX_TEMP2), de ; y0
3863
jp nz, gfxCircle.filled
3865
gfxCircle.notFilled:
3867
ld de, (GFX_TEMP) ; radius
3870
ld (GFX_TEMP3), hl ; f = 1 - radius
3873
ld (GFX_TEMP4), hl ; ddF_x = 0
3882
ld (GFX_TEMP5), hl ; ddF_y = -2 * radius
3885
ld (GFX_TEMP6), hl ; x = 0
3888
ld (GFX_TEMP7), hl ; y = radius
3890
; plot(x0, y0 + radius)
3891
ld de, (GFX_TEMP) ; radius
3892
ld hl, (GFX_TEMP2) ; y0
3896
ld bc, (GFX_TEMP1) ; x0
3900
; plot(x0, y0 - radius)
3901
ld de, (GFX_TEMP) ; radius
3902
ld hl, (GFX_TEMP2) ; y0
3906
ld bc, (GFX_TEMP1) ; x0
3910
; plot(x0 + radius, y0)
3911
ld hl, (GFX_TEMP1) ; x0
3912
ld de, (GFX_TEMP) ; radius
3919
ld de, (GFX_TEMP2) ; y0
3923
; plot(x0 - radius, y0)
3924
ld hl, (GFX_TEMP1) ; x0
3925
ld de, (GFX_TEMP) ; radius
3932
ld de, (GFX_TEMP2) ; y0
3935
jp gfxCircle.notFilled.3
3937
gfxCircle.notFilled.1:
3938
ld hl, (GFX_TEMP3) ; f
3940
jr nz, gfxCircle.notFilled.2 ; if( f < 0 ), jump
3942
ld hl, (GFX_TEMP7) ; y -= 1
3946
ld hl, (GFX_TEMP5) ; ddF_y += 2
3951
ld hl, (GFX_TEMP3) ; f
3952
ld de, (GFX_TEMP5) ; ddF_y
3955
ld (GFX_TEMP3), hl ; f += ddF_y
3957
gfxCircle.notFilled.2:
3958
ld hl, (GFX_TEMP6) ; x
3960
ld (GFX_TEMP6), hl ; x++
3962
ld hl, (GFX_TEMP4) ; ddF_x += 2
3967
ld hl, (GFX_TEMP3) ; f
3968
ld de, (GFX_TEMP4) ; ddF_x
3972
ld (GFX_TEMP3), hl ; f += ddF_x + 1
3974
; plot(x0 + x, y0 + y)
3975
ld hl, (GFX_TEMP1) ; x0
3976
ld de, (GFX_TEMP6) ; x
3983
ld hl, (GFX_TEMP2) ; y0
3984
ld de, (GFX_TEMP7) ; y
3991
; plot(x0 - x, y0 + y)
3992
ld hl, (GFX_TEMP1) ; x0
3993
ld de, (GFX_TEMP6) ; x
4000
ld hl, (GFX_TEMP2) ; y0
4001
ld de, (GFX_TEMP7) ; y
4008
; plot(x0 + x, y0 - y)
4009
ld hl, (GFX_TEMP1) ; x0
4010
ld de, (GFX_TEMP6) ; x
4017
ld hl, (GFX_TEMP2) ; y0
4018
ld de, (GFX_TEMP7) ; y
4025
; plot(x0 - x, y0 - y)
4026
ld hl, (GFX_TEMP1) ; x0
4027
ld de, (GFX_TEMP6) ; x
4034
ld hl, (GFX_TEMP2) ; y0
4035
ld de, (GFX_TEMP7) ; y
4042
; plot(x0 + y, y0 + x)
4043
ld hl, (GFX_TEMP1) ; x0
4044
ld de, (GFX_TEMP7) ; y
4051
ld hl, (GFX_TEMP2) ; y0
4052
ld de, (GFX_TEMP6) ; x
4059
; plot(x0 - y, y0 + x)
4060
ld hl, (GFX_TEMP1) ; x0
4061
ld de, (GFX_TEMP7) ; y
4068
ld hl, (GFX_TEMP2) ; y0
4069
ld de, (GFX_TEMP6) ; x
4076
; plot(x0 + y, y0 - x)
4077
ld hl, (GFX_TEMP1) ; x0
4078
ld de, (GFX_TEMP7) ; y
4085
ld hl, (GFX_TEMP2) ; y0
4086
ld de, (GFX_TEMP6) ; x
4093
; plot(x0 - y, y0 - x)
4094
ld hl, (GFX_TEMP1) ; x0
4095
ld de, (GFX_TEMP7) ; y
4102
ld hl, (GFX_TEMP2) ; y0
4103
ld de, (GFX_TEMP6) ; x
4110
gfxCircle.notFilled.3:
4111
ld hl, (GFX_TEMP6) ; x
4112
ld de, (GFX_TEMP7) ; y
4115
jp c, gfxCircle.notFilled.1 ; while( x < y )
4116
ld bc, (GFX_TEMP1) ; x0
4117
ld de, (GFX_TEMP2) ; y0
4122
call gfxCircle.notFilled
4123
ld hl, (BIOS_BDRATR)
4125
ld hl, (BIOS_FORCLR)
4126
ld (BIOS_BDRATR), hl
4130
ld (BIOS_BDRATR), hl
4136
if defined PAINT or (defined CIRCLE and defined GFX_FAST)
4138
;---------------------------------------------------------------------------------------------------------
4140
; Fill current region delimited by border attribute color changing pixels to foreground color
4141
; in: a = fill type (0 = not symmetric, 1 = symmetric)
4142
;---------------------------------------------------------------------------------------------------------
4146
if not defined GFX_FAST
4148
ld bc, (BIOS_GRPACX)
4150
ld de, (BIOS_GRPACY)
4168
call gfxIsScreenModeMSX2
4169
jr nc, gfxBorderFill.1 ; if MSX2 and screen mode above 3, jump
4173
__call_basic BASIC_SUB_PAINT1
4177
__call_basic BASIC_SUB_PAINT1
4179
;ld ix, BASIC_SUB_PAINT2
4185
ld hl, (BIOS_GRPACY)
4187
call gfxBorderFill.down
4190
ld (BIOS_GRPACY), hl
4192
call gfxBorderFill.up
4194
ld (BIOS_GRPACY), hl
4199
call gfxBorderFill.line
4205
jr nz, gfxBorderFill.down
4209
call gfxBorderFill.line
4215
jr nz, gfxBorderFill.up
4219
ld de, (BIOS_GRPACX)
4222
ld de, 1 ; skip count
4223
__call_bios BIOS_SCANR
4225
;ld (GFX_TEMP2), hl ; pixel count transversed
4228
ld (BIOS_GRPACX), de
4231
;cp 0 ; 0 = not symmetric, 1 = symmetric
4232
;jr z, gfxBorderFill.line.1
4234
;__call_bios BIOS_NSETCX ; HL = fill count
4235
;jr gfxBorderFill.line.2
4236
gfxBorderFill.line.1:
4238
ld de, 0 ; skip count
4239
__call_bios BIOS_SCANL
4240
gfxBorderFill.line.2:
4242
ld (BIOS_GRPACX), de
4246
;---------------------------------------------------------------------------------------------------------
4248
; Fload fill current region changing current pixel color to foreground color
4249
; https://en.wikipedia.org/wiki/Flood_fill
4250
;---------------------------------------------------------------------------------------------------------
4254
ld (GFX_TEMP), a ; replacement-color
4255
call gfxFloadFill.recursive
4258
gfxFloadFill.recursive:
4259
; 1. If target-color is equal to replacement-color, return.
4265
; 2. ElseIf the color of node is not equal to target-color, return.
4271
; 3. Else Set the color of node to replacement-color.
4274
; 4. Perform Flood-fill (one step to the left of node, target-color, replacement-color).
4275
gfxFloadFill.recursive.left:
4277
jr c, gfxFloadFill.recursive.right
4278
call gfxFloadFill.recursive
4281
; Perform Flood-fill (one step to the right of node, target-color, replacement-color).
4282
gfxFloadFill.recursive.right:
4284
jr c, gfxFloadFill.recursive.up
4285
call gfxFloadFill.recursive
4288
; Perform Flood-fill (one step to the up of node, target-color, replacement-color).
4289
gfxFloadFill.recursive.up:
4291
jr c, gfxFloadFill.recursive.down
4292
call gfxFloadFill.recursive
4295
; Perform Flood-fill (one step to the down of node, target-color, replacement-color).
4296
gfxFloadFill.recursive.down:
4299
call gfxFloadFill.recursive
4307
if defined SPRITEMODE
4309
;---------------------------------------------------------------------------------------------------------
4311
; set current sprite mode
4313
; 0: Spritesize is 8 by 8 pixels - default value
4314
; 1: Spritesize is 8 by 8 pixels, magnified to 16 by 16 pixels
4315
; 2: Spritesize is 16 by 16 pixels
4316
; 3: Spritesize is 16 by 16 pixels, magnified to 32 by 32 pixels
4317
; RG1SAV bit 0 = magnify sprite (double size)
4318
; RG1SAV bit 1 = sprite size (0=8 pixels, 1=16 pixels)
4319
;---------------------------------------------------------------------------------------------------------
4322
and 3 ; keeps only bits 0 and 1 from A
4325
ld a, (BIOS_RG1SAV) ; get copy from register #1 of VDP
4326
and 0xFC ; clear bits 0 and 1 from A
4327
or b ; put parameter to A (bits 0 and 1)
4328
ld (BIOS_RG1SAV), a ; restore to register #1 of VDP
4329
ld b, a ; value to write
4330
ld c, 1 ; register number to write
4331
call gfxWRTVDP ; write register to VDP
4332
call gfxCLRSPR ; clear sprites
4334
call gfxGetSpriteSize
4335
jp gfxFillSpriteCollisionTable
4339
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
4341
;---------------------------------------------------------------------------------------------------------
4342
; gfxSetSpriteColorInt
4345
;---------------------------------------------------------------------------------------------------------
4347
gfxSetSpriteColorInt:
4348
ld b, a ; save sprite number
4349
call gfxCALATR ; get sprite attribute table address
4354
;call gfxSetSpriteColor.Adjust
4359
ret c ; if screen mode < 3, do not adjust sprite multicolor
4361
ld a, b ; recover sprite number
4362
call gfxGetSpriteColorTable
4365
;call gfxSetSpriteColor.Adjust
4366
ld b, 16 ; array of 16 bytes
4368
gfxSetSpriteColorInt.1:
4373
djnz gfxSetSpriteColorInt.1
4376
;gfxSetSpriteColor.Adjust:
4386
;---------------------------------------------------------------------------------------------------------
4387
; gfxSetSpriteColorStr
4389
; DE = address to color byte array
4390
; BC = color byte array size
4391
;---------------------------------------------------------------------------------------------------------
4393
gfxSetSpriteColorStr:
4394
ld b, a ; save sprite number
4397
call gfxCALATR ; get sprite attribute table
4401
ld a, c ; byte array zero length?
4409
;call gfxSetSpriteColor.Adjust
4414
ret c ; if screen mode < 3, do not adjust sprite mode 2
4416
ld a, b ; recover sprite number
4417
call gfxGetSpriteColorTable
4419
ld b, 16 ; array of 16 bytes (color table)
4420
ld a, c ; size of color array
4422
pop iy ; save array start
4424
gfxSetSpriteColorStr.1:
4427
;call gfxSetSpriteColor.Adjust
4433
jr nz, gfxSetSpriteColorStr.2
4434
ld a, c ; recover array size
4436
pop de ; recover array start
4438
gfxSetSpriteColorStr.2:
4439
djnz gfxSetSpriteColorStr.1
4444
;---------------------------------------------------------------------------------------------------------
4445
; gfxGetSpriteColorTable
4447
; HL = address to color table
4448
;---------------------------------------------------------------------------------------------------------
4450
gfxGetSpriteColorTable:
4454
ld l, a ; recover sprite number
4458
add hl, hl ; multiply by 16 (shift left 4)
4461
call gfxCALATR ; get sprite attribute table address
4466
sbc hl, de ; address of color table from sprite multicolor
4473
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
4475
;---------------------------------------------------------------------------------------------------------
4479
;---------------------------------------------------------------------------------------------------------
4483
call gfxCALATR ; get sprite attribute table address
4492
;---------------------------------------------------------------------------------------------------------
4493
; gfxSpriteStepCheck
4495
;---------------------------------------------------------------------------------------------------------
4502
ld de, (GFX_SPRITE_SIZE_DAT)
4503
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
4504
and 7 ; clear touched and collided flags
4505
ld (GFX_SPRITE_FLAGS), a
4508
jr z, gfxSpriteStepCheck.corners
4510
gfxSpriteStepCheck.limits:
4513
cp b ; jump if x > max_x?
4514
jr c, gfxSpriteStepCheck.limits.touched
4518
cp c ; jump if y > max_y?
4519
jr c, gfxSpriteStepCheck.limits.touched
4521
jr gfxSpriteStepCheck.corners
4523
gfxSpriteStepCheck.limits.touched:
4524
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
4525
or 8 ; set limit touched flag
4526
ld (GFX_SPRITE_FLAGS), a
4528
gfxSpriteStepCheck.corners:
4529
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
4530
and 2+4 ; check walls or hotspots
4531
jr z, gfxSpriteStepCheck.end
4534
call gfxSpriteStepCheck.corner
4536
ld a, (GFX_SPRITE_SIZE_DAT)
4539
call gfxSpriteStepCheck.corner
4541
ld a, (GFX_SPRITE_SIZE_DAT)
4544
call gfxSpriteStepCheck.corner
4547
ld a, (GFX_SPRITE_SIZE_DAT)
4550
call gfxSpriteStepCheck.corner
4552
gfxSpriteStepCheck.end:
4558
gfxSpriteStepCheck.corner:
4559
call gfxGetTileFromXY
4560
ld d, a ; tile to be searched
4562
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
4564
call nz, gfxSpriteStepCheck.walls
4566
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
4568
call nz, gfxSpriteStepCheck.hotspots
4571
gfxSpriteStepCheck.walls:
4572
ld hl, (GFX_SPRITE_WALLS)
4573
ld e, 16 ; bits 0=chk limits, 1=chk walls, 2=chk hotspots, 3=limit touched, 4=wall touched, 5=hotspot touched, 6=collided
4574
jp gfxSpriteStepCheck.search
4576
gfxSpriteStepCheck.hotspots:
4577
ld hl, (GFX_SPRITE_HOTSPOTS)
4578
ld e, 32 ; bits 0=chk limits, 1=chk walls, 2=chk hotspots, 3=limit touched, 4=wall touched, 5=hotspot touched, 6=collided
4579
call gfxSpriteStepCheck.search
4581
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
4586
ld (GFX_SPRITE_HOTSPOT_TILE), a
4589
; d = tile, hl = search table, e = flag
4590
gfxSpriteStepCheck.search:
4595
ld a, d ; search for this tile
4601
cpir ; inc HL searching for A until BC=0 (Z flag settled if found)
4605
gfxSpriteStepCheck.search.found:
4606
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
4607
or e ; set touched flag
4608
ld (GFX_SPRITE_FLAGS), a
4623
call gfxGetScreenTile ; b = y, c = x, a = tile
4629
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
4631
;---------------------------------------------------------------------------------------------------------
4632
; gfxSetSpritePattern
4634
; BC = pattern number
4635
;---------------------------------------------------------------------------------------------------------
4637
gfxSetSpritePattern:
4639
call gfxCALATR ; get sprite attribute table address
4643
ld a, (BIOS_RG1SAV) ; bit 0 = double size, bit 1 = sprite size (0=8 pixels, 1=16 pixels)
4645
jr z, gfxSetSpritePattern.1
4648
gfxSetSpritePattern.1:
4649
ld a, c ; pattern number
4657
;---------------------------------------------------------------------------------------------------------
4659
; HL = point to sprite data as a string of 8 or 32 characters according the sprites size (8x8 or 16x16)
4661
;---------------------------------------------------------------------------------------------------------
4666
call gfxCALPAT ; get sprite pattern data address
4668
call gfxGSPSIZ ; return in 'a' sprite default size
4672
jr z, gfxSetSpriteData.1
4673
jr nc, gfxSetSpriteData.1
4687
if defined GFX_SPRITES
4689
;---------------------------------------------------------------------------------------------------------
4691
; initialises all sprites
4692
;---------------------------------------------------------------------------------------------------------
4698
;---------------------------------------------------------------------------------------------------------
4700
; set sprite default x, y, pattern and color
4702
;---------------------------------------------------------------------------------------------------------
4707
ld a, (BIOS_GRPACY) ; y
4710
ld a, (BIOS_GRPACX) ; x
4716
ld a, (BIOS_FORCLR) ; color
4722
if defined EXIST_DATA_SET
4724
;---------------------------------------------------------------------------------------------------------
4726
;---------------------------------------------------------------------------------------------------------
4735
;---------------------------------------------------------------------------------------------------------
4736
; gfxClearTileScreen
4737
;---------------------------------------------------------------------------------------------------------
4742
ld hl, (BIOS_GRPNAM)
4746
call gfxSetTileDefaultColor
4748
call gfxSetTileDefaultColor
4750
jp gfxSetTileDefaultColor
4752
gfxSetTileDefaultColor
4753
call gfxGetTileColorAddr
4755
call gfxGetTileDefaultColor
4759
gfxGetTileDefaultColor:
4772
; HL = tile color pointer
4773
; BC = tile color size
4776
;---------------------------------------------------------------------------------------------------------
4779
; HL = tile data pointer
4780
; BC = tile data size
4782
; A = flip (0=no, 1=yes)
4783
;---------------------------------------------------------------------------------------------------------
4787
jr nz, gfxSetTileDataFlip
4789
gfxSetTileDataNoFlip:
4790
call gfxGetTileDataAddr
4794
call gfxGetTileDataAddr
4796
gfxSetTileDataFlip.Loop:
4805
jr nz, gfxSetTileDataFlip.Loop
4808
; in de = tile number
4809
; out de = tile number address
4815
add hl, hl ; tile number * 8
4816
ld de, (BIOS_GRPCGP)
4822
;---------------------------------------------------------------------------------------------------------
4825
; HL = tile color pointer
4826
; BC = tile color size
4828
;---------------------------------------------------------------------------------------------------------
4831
call gfxGetTileColorAddr
4834
; in de = tile number
4835
; out de = tile number address
4836
gfxGetTileColorAddr:
4841
add hl, hl ; tile number * 8
4842
ld de, (BIOS_GRPCOL)
4848
;---------------------------------------------------------------------------------------------------------
4850
; set screen tile at x,y
4854
;---------------------------------------------------------------------------------------------------------
4866
; ld l, b ; slow y * 32
4883
ld de, (BIOS_GRPNAM)
4890
if defined gfxGetTileFromXY or defined EXIST_DATA_SET
4892
;---------------------------------------------------------------------------------------------------------
4894
; get screen tile at x,y
4898
;---------------------------------------------------------------------------------------------------------
4920
ld de, (BIOS_GRPNAM)
4926
;---------------------------------------------------------------------------------------------------------
4927
; Sprite collision table routines
4928
;---------------------------------------------------------------------------------------------------------
4930
gfxInitSpriteCollisionTable:
4933
ld (GFX_SPRITE_COLLISION), ix
4936
; copy sprite attribute table to ram
4937
gfxFillSpriteCollisionTable:
4938
ld hl, (BIOS_ATRBAS) ; source: attribute table
4939
ld de, (GFX_SPRITE_COLLISION) ; dest: ram
4940
ld bc, 128 ; 32*4 = size of attribute table
4943
; pre-calculate each sprite width
4944
gfxCalculateSpriteCollisionTable:
4945
ld ix, (GFX_SPRITE_COLLISION) ; start of sprites attributes
4946
ld b, 32 ; sprite count
4948
gfxCalculateSpriteCollisionTable.start:
4949
ld a, (GFX_SPRITE_SIZE_DAT) ; sprite size
4951
ld d, 208 ; Y no-display flag
4955
cp 3 ; above screen 3?
4956
jr c, gfxCalculateSpriteCollisionTable.next
4957
ld d, 216 ; Y no-display flag
4959
gfxCalculateSpriteCollisionTable.next:
4960
; test IC flag (no collision) in color table
4961
; test EC flag (early clock, shift 32 dots to the left) in color table
4962
; set x1 = x + size, y1 = y + size
4964
cp d ; test if sprite will not be displayed
4977
djnz gfxCalculateSpriteCollisionTable.next
4980
; BC = sprite number to check
4981
gfxUpdateSpriteCollisionTable:
4989
ld hl, (GFX_SPRITE_COLLISION) ; dest: ram
4992
ld hl, (BIOS_ATRBAS) ; source: attribute table
4994
ld bc, 4 ; 4 = size of attribute table to 1 sprite]
4998
ld b, 1 ; sprite count
5000
call gfxCalculateSpriteCollisionTable.start
5003
ld a, (GFX_SPRITE_FLAGS)
5004
and 0xBF ; clear collision flag
5005
ld (GFX_SPRITE_FLAGS), a
5007
ld a, (BIOS_STATFL) ; verify if collision occurred
5010
jr gfxCheckSpriteCollisionTable.start
5012
; BC = sprite number to check
5013
gfxCheckSpriteCollisionTable:
5014
; get target sprite address (iy)
5018
ld de, (GFX_SPRITE_COLLISION)
5025
gfxCheckSpriteCollisionTable.start:
5026
; start test against others sprites
5027
ld ix, (GFX_SPRITE_COLLISION)
5029
ld d, 208 ; Y no-display flag
5033
cp 3 ; above screen 3?
5034
jr c, gfxCheckSpriteCollisionTable.test
5035
ld d, 216 ; Y no-display flag
5037
gfxCheckSpriteCollisionTable.test:
5038
; skip target sprite
5041
jr z, gfxCheckSpriteCollisionTable.next
5043
; test if x1 > nx and x < nx1 and y1 > ny and y < ny1
5045
cp d ; test if sprite will not be displayed
5046
ret z ; return false
5049
jr nc, gfxCheckSpriteCollisionTable.next
5053
jr nc, gfxCheckSpriteCollisionTable.next
5057
jr nc, gfxCheckSpriteCollisionTable.next
5061
jr nc, gfxCheckSpriteCollisionTable.next
5063
; if so, save collider sprite
5065
ld (GFX_SPRITE_COLLIDER), a
5067
ld a, (GFX_SPRITE_FLAGS)
5068
or 0x40 ; set collision flag
5069
ld (GFX_SPRITE_FLAGS), a
5073
gfxCheckSpriteCollisionTable.next:
5081
ret z ; return false
5082
jr gfxCheckSpriteCollisionTable.test
5086
;---------------------------------------------------------------------------------------------------------
5087
; VDP / VRAM support routines
5088
;---------------------------------------------------------------------------------------------------------
5092
; c = register number
5093
; a = register number
5096
ret nz ; is negative? read only
5098
ret z ; is register 8? then status register 0 (read only)
5099
jr nc, gfxWRTVDP.1 ; is > 8? then control registers numbers added 1
5114
;jp nz, BIOS_NWRVDP ; msx 2
5116
;jp nz, BIOS_NWRVDP ; msx 2
5117
jp BIOS_WRTVDP ; msx 1
5120
; in a = register number
5124
jr nz, gfxRDVDP.1 ; is negative? then status register 1 to 9
5126
jr z, gfxRDVDP.2 ; is register 8? then status register 0
5128
jr nc, gfxRDVDP.3 ; is >= 9? then control registers numbers added 1
5129
ld hl, BIOS_RG0SAV ; else is correct control registers numbers
5141
jp BIOS_NRDVDP ;BIOS_VDPSTA
5148
ld hl, BIOS_RG8SAV-9
5156
; in: A=Data byte, BC=Length, HL=VRAM address
5165
; in: A=Sprite pattern number
5166
; out: HL=Sprite pattern address
5176
; in: A=Sprite number
5177
; out: HL=Sprite attribute address
5187
; out: A=Bytes in sprite pattern (8 or 32)
5207
; in: BC=Length, dest DE=VRAM address, source HL=RAM address
5212
; in: BC=Length, dest DE=RAM address, source HL=VRAM address
5239
; 8 bytes / 206 cycles
5240
; http://www.retroprogramming.com/2014/01/fast-z80-bit-reversal.html
5247
djnz gfxReverseA.loop
5252
;---------------------------------------------------------------------------------------------------------
5254
;---------------------------------------------------------------------------------------------------------
5263
RET_MATH_LIB: call COPY_TO.TMP_DAC
5269
MATH_DECADD: ld ix, addSingle
5274
if defined MATH.SUB or defined MATH.NEG
5276
MATH_DECSUB: ld ix, subSingle
5281
if defined MATH.MULT
5283
MATH_DECMUL: ld ix, mulSingle
5290
MATH_DECDIV: ld ix, divSingle
5298
MATH_SNGEXP: ld ix, powSingle
5305
MATH_COS: ld ix, cosSingle
5312
MATH_SIN: ld ix, sinSingle
5319
MATH_TAN: ld ix, tanSingle
5326
MATH_ATN: ld ix, atanSingle
5333
MATH_SQR: ld ix, sqrtSingle
5340
MATH_LOG: ld ix, lnSingle
5347
MATH_EXP: ld ix, expSingle
5354
MATH_ABSFN: ld ix, absSingle
5359
if defined MATH.SEED or defined MATH.NEG
5361
MATH_NEG: ld ix, negSingle
5368
MATH_SGN: ld ix, sgnSingle
5373
if defined RND or defined MATH.SEED
5375
MATH_RND: ld ix, randSingle
5380
MATH_FRCINT: ld hl, BASIC_DAC
5393
ld (BASIC_VALTYP), a
5396
MATH_FRCDBL: ; same as MATH_FRCSGL
5397
MATH_FRCSGL: ld hl, BASIC_DAC+2 ; input address
5398
ld bc, BASIC_DAC ; output address
5401
ld (BASIC_VALTYP), a
5404
MATH_ICOMP: ld a, h ; cp hl, de (alternative to bios DCOMPR)
5406
jr nz, MATH_ICOMP.NE.HIGH
5409
jr nz, MATH_ICOMP.NE.LOW
5411
MATH_ICOMP.NE.HIGH: jr c, MATH_ICOMP.GT.HIGH
5413
jr nz, MATH_DCOMP.GT
5415
MATH_ICOMP.GT.HIGH: bit 7, d
5418
MATH_ICOMP.NE.LOW: jr c, MATH_DCOMP.GT
5421
MATH_XDCOMP: ; same as MATH_DCOMP
5422
MATH_DCOMP: ld ix, cmpSingle
5426
MATH_DCOMP.GT: ld a, 0xFF ; DAC > ARG
5428
MATH_DCOMP.EQ: ld a, 0 ; DAC = ARG
5430
MATH_DCOMP.LT: ld a, 1 ; DAC < ARG
5433
if defined CAST_STR_TO.VAL
5435
MATH_FIN: ; HL has the source string
5436
ld a, (BASIC_VALTYP)
5437
cp 2 ; test if integer
5439
ld hl, (BASIC_DAC+2)
5444
MATH_FIN.1: ld BC, BASIC_DAC
5450
if defined CAST_INT_TO.STR
5452
MATH_FOUT: ld a, (BASIC_VALTYP)
5453
cp 2 ; test if integer
5455
ld hl, (BASIC_DAC+2)
5460
MATH_FOUT.1: ld hl, BASIC_DAC
5471
;---------------------------------------------------------------------------------------------------------
5473
; Copyright 2018 Zeda A.K. Thomas
5474
;---------------------------------------------------------------------------------------------------------
5476
; https://github.com/Zeda/z80float
5477
; https://www.omnimaga.org/asm-language/(z80)-floating-point-routines/
5478
; https://en.wikipedia.org/wiki/Single-precision_floating-point_format
5479
;---------------------------------------------------------------------------------------------------------
5481
; HL points to the first operand
5482
; DE points to the second operand (if needed)
5483
; IX points to the third operand (if needed, rare)
5484
; BC points to where the result should be output
5485
; Floats are stored by a little-endian 24-bit mantissa. However, the highest bit
5486
; is taken as implicitly 1, so we replace it as a sign bit. Next comes an 8-bit
5487
; exponent biased by +128.
5488
;---------------------------------------------------------------------------------------------------------
5489
; Adapted to MSXBas2Asm by Amaury Carvalho, 2019
5490
;---------------------------------------------------------------------------------------------------------
5492
;---------------------------------------------------------------------------------------------------------
5494
;---------------------------------------------------------------------------------------------------------
5496
BASIC_HOLD8: equ 0xF806 ; 48 Work area for decimal multiplications.
5497
BASIC_HOLD2: equ 0xF836 ; 8 Work area in the execution of numerical operators.
5498
BASIC_HOLD: equ 0xF83E ; 8 Work area in the execution of numerical operators.
5499
scrap: equ BASIC_HOLD8
5500
seed0: equ BASIC_RNDX
5501
seed1: equ seed0 + 4
5502
var48: equ scrap + 4
5505
addend2: equ scrap+7 ;4 bytes
5506
var_x: equ BASIC_HOLD8 + 4 ;4 bytes
5507
var_y: equ var_x + 4 ;4 bytes
5508
var_z: equ var_y + 4 ;4 bytes
5509
var_a: equ var_z + 4 ;4 bytes
5510
var_b: equ var_a + 4 ;4 bytes
5511
var_c: equ var_b + 4 ;4 bytes
5512
temp: equ var_c + 4 ;4 bytes
5513
temp1: equ temp + 4 ;4 bytes
5514
temp2: equ temp1 + 4 ;4 bytes
5515
temp3: equ temp2 + 4 ;4 bytes
5517
pow10exp_single: equ scrap+9
5518
strout_single: equ 0xF750 ; PARM2 - BASIC_BUF ;pow10exp_single+2
5520
;---------------------------------------------------------------------------------------------------------
5522
;---------------------------------------------------------------------------------------------------------
5524
;;Still need to tend to special cases
5592
pop hl ;bigger float
5724
;;Need to adjust sign flag
5747
;;How many push/pops are needed?
5755
;;How many push/pops are needed?
5761
;;How many push/pops are needed?
5762
;;Return bigger number
5769
;---------------------------------------------------------------------------------------------------------
5771
;---------------------------------------------------------------------------------------------------------
5794
jp addInject ;jumps in to the addSingle routine
5796
;---------------------------------------------------------------------------------------------------------
5798
;---------------------------------------------------------------------------------------------------------
5801
;Inputs: HL points to float1, DE points to float2, BC points to where the result is copied
5802
;Outputs: float1*float2 is stored to (BC)
5803
;573+mul24+{0,35}+{0,30}
5806
;avg: 2055.13839751681cc
5832
;;return float in CHLB
5842
jr z,mulSingle_case0
5854
;jr z,mulSingle_case1
5858
jp z,mulSingle_case1
5863
rra ; |Lots of help from Runer112 and
5864
adc a,a ; |calc84maniac for optimizing
5865
jp po,bad ; |this exponent check.
5874
call mul24 ;BDE*CHL->HLBCDE, returns sign info
5931
;special*x = special
5952
;basically, if b|c has bit 5 set, return NaN
5985
;;avg :1464.9033203125cc (1464+925/1024)
5988
;avg: 1449.63839751681cc
6029
;---------------------------------------------------------------------------------------------------------
6031
;---------------------------------------------------------------------------------------------------------
6034
;;HL points to numerator
6035
;;DE points to denominator
6036
;;BC points to where the quotient gets written
6038
divSingle_no_pushpop:
6044
xor (hl) ; |Get sign of output
6051
ex de,hl ; |Get exponent
6158
call divsub1 ;34 or 66
6176
;34cc or 66cc or 93cc
6191
;---------------------------------------------------------------------------------------------------------
6193
; https://www.geeksforgeeks.org/write-a-c-program-to-calculate-powxn/
6194
; https://stackoverflow.com/questions/3518973/floating-point-exponentiation-without-power-function
6195
;---------------------------------------------------------------------------------------------------------
6196
;double mypow( double base, double power, double precision )
6198
; if ( power < 0 ) return 1 / mypow( base, -power, precision );
6199
; else if ( power >= 1 ) return base * mypow( base, power-1, precision );
6200
; else if ( precision >= 1 ) {
6201
; if( base >= 0 ) return sqrt( base );
6202
; else return sqrt( -base );
6203
; } else return sqrt( mypow( base, power*2, precision*2 ) );
6206
if defined MATH.POW or defined MATH_EXP or defined MATH_LOG or defined MATH_LN
6212
;;BC points to output
6216
ld bc, var_y ; power
6221
ld hl, const_precision
6222
ld bc, var_a ; precision
6225
ld bc, var_z ; result
6234
; if ( power < 0 ) return 1 / mypow( base, -power, precision );
6240
; else if ( power >= 1 ) return base * mypow( base, power-1, precision );
6246
; else if ( precision >= 1 ) {
6247
; if( base >= 0 ) return sqrt( base );
6248
; else return sqrt( -base );
6254
; } else return sqrt( mypow( base, power*2, precision*2 ) );
6279
; return 1 / mypow( base, -power, precision );
6298
; return base * mypow( base, power-1, precision );
6317
; if( base >= 0 ) return sqrt( base );
6318
; else return sqrt( -base );
6344
; 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)))))
6345
;Please note that usually I like to reduce to [-.5,.5] as the extra overhead is usually worth it.
6346
;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.
6349
;x-=int(x) ;leaves x in [0,1)
6351
;;if x==inf -> out==inf
6352
;;if x==-inf -> out==0
6353
;;if x==NAN -> out==NAN
6360
push af ;keep track of sign
6370
jr c,_pow_1 ;int(x)=0
6383
jr nz,exp_normalized
6394
jr exp_normalized ;.db $11 ;start of `ld de,**`
6401
jr comp_exp ;.db $06 ;start of 'ld b,*` just to eat the next byte
6410
jp z,exp_underflow+1
6411
;perform 1-(var48+10)--> var48+10
6419
;our 'x' is at var48+10
6420
;our `temp` is at var48+6 so as not to cause issues with mulSingle)
6421
;uses 14 bytes of RAM
6463
;-inf -> +0 because lim approaches 0 from the right
6485
;-inf -> +0 because lim approaches 0 from the right
6487
sbc a,a ;FF if should be 0,
6502
;---------------------------------------------------------------------------------------------------------
6504
;---------------------------------------------------------------------------------------------------------
6506
if defined MATH_SQR or defined MATH_EXP
6508
;Uses 3 bytes at scrap
6510
;552+{0,19}+8{0,3+{0,3}}+pushpop+sqrtHLIX
6529
jp z,sqrtSingle_special
6532
push af ;new exponent
6542
;AHL is the new remainder
6543
;Need to divide by 2, then divide by the 16-bit (var_x+4)
6547
;We are just going to approximate it
6629
;Output: DE is the sqrt, AHL is the remainder
6630
;speed: 754+{0,1}+6{0,6}+{0,3+{0,18}}+{0,38}+sqrtHL
6654
jr _15a ;.db $FE ;start of `cp *`
6668
jr _16a ;.db $FE ;start of `cp *`
6682
jr _17a ;.db $FE ;start of `cp *`
6696
jr _18a ;.db $FE ;start of `cp *`
6700
;Now we have four more iterations
6701
;The first two are no problem
6713
jr _19a ;.db $FE ;start of `cp *`
6727
jr _20a ;.db $FE ;start of `cp *`
6732
;On the next iteration, HL might temporarily overflow by 1 bit
6734
rl d ;sla e \ rl d \ inc e
6738
adc hl,hl ;This might overflow!
6739
jr c,sqrt32_iter15_br0
6752
;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
6755
ld b,a ;either 0x00 or 0x80
6776
;returns A as the sqrt, HL as the remainder, D = 0
6790
jr _23a ;.db $01 ;start of ld bc,** which is 10cc to skip the next two bytes.
6801
jr _24a ;.db $01 ;start of ld bc,** which is 10cc to skip the next two bytes.
6812
dec d ;this resets the low bit of D, so `srl d` resets carry.
6813
jr _25a ;.db $06 ;start of ld b,* which is 7cc to skip the next byte.
6835
jr _27a ;.db $01 ;start of ld bc,** which is 10cc to skip the next two bytes.
6848
jr _28a ;.db $01 ;start of ld bc,** which is 10cc to skip the next two bytes.
6870
;---------------------------------------------------------------------------------------------------------
6872
;---------------------------------------------------------------------------------------------------------
6874
if defined MATH_LOG or defined MATH_LN
6877
; x / (1 + x/(2-x+4x/(3-2x+9x/(4-3x+16x/(5-4x)))))
6878
; a * x ^ (1/a) - a, where a = 100
6881
ld de, const_100_inv
6883
call powSingle ; temp = x ^ (1/100)
6887
call mulSingle ; temp1 = temp * 100
6890
call subSingle ; bc = temp1 - 100
6895
;---------------------------------------------------------------------------------------------------------
6897
;---------------------------------------------------------------------------------------------------------
6914
;---------------------------------------------------------------------------------------------------------
6916
;---------------------------------------------------------------------------------------------------------
6923
;;BC points to the output
6928
;;DE points to lg(y), HL points to x, BC points to output
6937
;---------------------------------------------------------------------------------------------------------
6939
; https://en.wikipedia.org/wiki/List_of_trigonometric_identities
6940
; https://en.wikipedia.org/wiki/Taylor_series#Trigonometric_functions
6941
; https://cs.stackexchange.com/questions/89245/how-approximate-sine-using-taylor-series
6942
; https://stackoverflow.com/questions/42217069/approximating-sinex-with-a-taylor-series-in-c-and-having-a-lot-of-problems
6943
;---------------------------------------------------------------------------------------------------------
6945
if defined MATH_SIN or defined MATH_TAN or defined MATH_COS
6948
; taylor: x - x^3/6 + x^5/120 - x^7/5040
6949
; x(1 - x^2(1/6 - x^2(1/120 - x^2/5040)) )
6951
; var_b = round( x / (2*PI), 0 )
6952
; var_c = x - var_b*2*PI
6953
; temp1 = if( var_c >= 0, var_c, var_c + 2*PI )
6954
; temp2 = if( temp1 > PI, temp1 - PI, temp1 )
6955
; var_a = if( temp2 > PI/2, PI - temp2, temp2 ) * if( temp1 > PI, -1, 1 )
6962
call copySingle ; return 0
6966
call trigRangeReductionSinCos
6971
call mulSingle ; var_b = var_a * var_a
6975
call mulSingle ; temp = x^2/5040
6979
call subSingle ; temp1 = 1/120 - temp
6983
call mulSingle ; temp = x^2 * temp1
6987
call subSingle ; temp1 = 1/6 - temp
6991
call mulSingle ; temp = x^2 * temp1
6995
call subSingle ; temp1 = 1 - temp
6999
call mulSingle ; return x * temp1
7002
trigRangeReductionSinCos:
7005
; var_b = round( x / (2*PI), 0 )
7013
; var_c = x - var_b*2*PI
7017
call mulSingle ; temp = var_b*2*PI
7021
call subSingle ; var_c = x - temp
7022
; temp1 = if( var_c >= 0, var_c, var_c + 2*PI )
7026
jr nc, trigRangeReductionSinCos.else.2
7029
call copySingle ; temp1 = var_c
7030
jr trigRangeReductionSinCos.endif.2
7031
trigRangeReductionSinCos.else.2:
7035
call addSingle ; temp1 = var_c + 2*PI
7036
trigRangeReductionSinCos.endif.2:
7037
; temp2 = if( temp1 > PI, temp1 - PI, temp1 )
7041
jr c, trigRangeReductionSinCos.else.3
7042
jr z, trigRangeReductionSinCos.else.3
7046
call subSingle ; temp2
7047
jr trigRangeReductionSinCos.endif.3
7048
trigRangeReductionSinCos.else.3:
7051
call copySingle ; temp2 = temp1
7052
trigRangeReductionSinCos.endif.3:
7053
; var_a = if( temp2 > PI/2, PI - temp2, temp2 ) * if( temp1 > PI, -1, 1 )
7054
ld hl, const_half_pi
7057
jr c, trigRangeReductionSinCos.else.4
7058
jr z, trigRangeReductionSinCos.else.4
7062
call subSingle ; var_a
7063
jr trigRangeReductionSinCos.endif.4
7064
trigRangeReductionSinCos.else.4:
7067
call copySingle ; var_a = temp2
7068
trigRangeReductionSinCos.endif.4:
7069
; if( temp > PI, -1, 1 )
7073
jr nc, trigRangeReductionSinCos.endif.5
7077
ld (ix+2), a ; turn var_a to negative
7078
trigRangeReductionSinCos.endif.5:
7084
;---------------------------------------------------------------------------------------------------------
7086
;---------------------------------------------------------------------------------------------------------
7088
if defined MATH_COS or defined MATH_TAN
7091
; taylor: 1 - x^2/2 + x^4/24 - x^6/720
7092
; 1 - x^2(1/2 - x^2(1/24 - x^2/720) )
7093
; reduction: same as sin
7102
call copySingle ; return 1
7106
; 1 - x^2(1/2 - x^2(1/24 - x^2/720) )
7107
call trigRangeReductionSinCos
7112
call mulSingle ; var_b = var_a * var_a
7116
call mulSingle ; temp = x^2/720
7120
call subSingle ; temp1 = 1/24 - temp
7124
call mulSingle ; temp = x^2 * temp1
7128
call subSingle ; temp1 = 1/2 - temp
7132
call mulSingle ; temp = x^2 * temp1
7136
call subSingle ; temp1 = 1 - temp
7138
; temp3 = abs(var_c)
7139
; temp1 = temp1 * if( temp3 >= PI/2, -1, 1 ) ==> cos sign
7146
ld (ix+2), a ; temp3 = abs(var_c)
7148
ld de, const_half_pi
7149
call cmpSingle ; if temp3 >= PI/2 then temp1 = -temp1
7150
jr nc, cosSingle.endif.1
7154
ld (ix+2), a ; temp1 = -temp1
7158
call copySingle ; return temp1
7163
;---------------------------------------------------------------------------------------------------------
7165
;---------------------------------------------------------------------------------------------------------
7186
;---------------------------------------------------------------------------------------------------------
7188
;---------------------------------------------------------------------------------------------------------
7193
;taylor: x/(1 + x^2/(3 + (2*x)^2/(5 + (3*x)^2/(7+(4*x)^2/9) ) ) )
7194
; x < -1: atan - PI/2
7195
; x >= 1: PI/2 - atan
7196
;reduction: abs(X) > 1 : Y = 1 / X
7197
; abs(X) <= 1: Y = X
7206
call copySingle ; return 0
7210
;x/(1 + x^2/(3 + (2*x)^2/(5 + (3*x)^2/(7+(4*x)^2/9) ) ) )
7211
call trigRangeReductionAtan
7217
call mulSingle ; var_b = var_a * var_a
7221
call mulSingle ; temp = (4*x)^2
7225
call divSingle ; temp1 = temp/9
7229
call addSingle ; temp = 7 + temp1
7233
call mulSingle ; temp1 = var_b * 9
7237
call divSingle ; temp2 = temp1 / temp
7241
call addSingle ; temp = 5 + temp2
7245
call mulSingle ; temp1 = var_b * 4
7249
call divSingle ; temp2 = temp1 / temp
7253
call addSingle ; temp = 3 + temp2
7257
call divSingle ; temp2 = var_b / temp
7261
call addSingle ; temp = 1 + temp2
7265
call divSingle ; temp2 = var_a / temp
7267
; x >= 1: PI/2 - atan
7271
ld hl, const_half_pi
7278
; x < -1: atan - PI/2
7289
ld de, const_half_pi
7298
call copySingle ; return temp2
7301
trigRangeReductionAtan:
7302
;reduction: abs(X) > 1 : Y = 1 / X
7303
; abs(X) <= 1: Y = X
7312
ld (ix+2), a ; abs(x)
7316
jr nc, trigRangeReductionAtan.1
7322
jr trigRangeReductionAtan.2
7323
trigRangeReductionAtan.1:
7328
trigRangeReductionAtan.2:
7332
jr c, trigRangeReductionAtan.3
7336
ld (ix+2), a ; y = -y
7337
trigRangeReductionAtan.3:
7342
if defined MATH_SIN or defined MATH_TAN or defined MATH_COS
7344
;---------------------------------------------------------------------------------------------------------
7346
;---------------------------------------------------------------------------------------------------------
7360
;---------------------------------------------------------------------------------------------------------
7362
;---------------------------------------------------------------------------------------------------------
7431
if defined MATH_ABSFN
7433
;---------------------------------------------------------------------------------------------------------
7435
;---------------------------------------------------------------------------------------------------------
7438
;;HL points to the float
7439
;;BC points to where to output the result
7458
;---------------------------------------------------------------------------------------------------------
7460
;---------------------------------------------------------------------------------------------------------
7463
;;HL points to the float
7464
;;BC points to where to output the result
7469
if defined powSingle or defined sgnSingle or defined MATH_NEG
7471
;---------------------------------------------------------------------------------------------------------
7473
;---------------------------------------------------------------------------------------------------------
7476
;;HL points to the float
7477
;;BC points to where to output the result
7483
jr nz, negSingle.test.sign
7486
jr nz, negSingle.test.sign
7489
jr nz, negSingle.test.sign
7492
jr nz, negSingle.test.sign
7503
negSingle.test.sign:
7506
jr z, negSingle.positive
7510
call negSingle.positive
7529
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
7531
;---------------------------------------------------------------------------------------------------------
7533
;---------------------------------------------------------------------------------------------------------
7536
;Input: HL points to float1, DE points to float2
7538
; float1 >= float2 : nc
7539
; float1 < float2 : c,nz
7540
; float1 == float2 : z
7541
; There is a margin of error allowed in the lower 2 bits of the mantissa.
7543
;Currently fails when both numbers have magnitude less than about 2^-106
7578
ld a,(scrap+3) ;new power
7579
pop bc ;B is old power
7589
or 1 ;not equal, so reset z flag
7590
rla ;if negative, float1<float2, setting c flag as wanted, else nc.
7600
;---------------------------------------------------------------------------------------------------------
7602
;---------------------------------------------------------------------------------------------------------
7605
;Stores a pseudo-random number on [0,1)
7606
;it won't produce values on (0,2^-23)
7615
;DEHL is the mantissa, B is the exponent
7631
;If we needed to shift more than 8 bits, we'll load in more random data
7636
jp nc,rand_no_more_rand_data
7644
rand_no_more_rand_data:
7663
;;Tested and passes all CAcert tests
7664
;;Uses a very simple 32-bit LCG and 32-bit LFSR
7665
;;it has a period of 18,446,744,069,414,584,320
7666
;;roughly 18.4 quintillion.
7667
;;LFSR taps: 0,2,6,7 = 11000101
7669
;;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.
7670
;Uses 64 bits of state
7706
if defined MATH_FOUT
7708
;---------------------------------------------------------------------------------------------------------
7710
; in HL = Single address
7711
; BC = String address
7712
; out A = String size
7713
; http://0x80.pl/notesen/2015-12-29-float-to-string.html
7714
; http://0x80.pl/articles/convert-float-to-integer.html
7715
;---------------------------------------------------------------------------------------------------------
7729
; Move the float to scrap
7733
; Make the float negative, write a '-' if already negative
7742
ld a,'-' ; write '-' simbol
7750
; Check if the exponent field is 0 (a special value)
7757
; We should write '0' next. When rounding 9.999999... for example, not padding with a 0 will return '.' instead of '1.'
7765
; Now we need to perform signed (A-128)*77 (approximation of exponent*log10(2))
7773
ld (pow10exp_single),a ;The base-10 exponent
7777
ld de,pow10LUT ;get the table of 10^-(2^k)
7779
ld hl, pow10exp_single
7781
call singletostr_mul
7782
call singletostr_mul
7783
call singletostr_mul
7784
call singletostr_mul
7785
call singletostr_mul
7786
call singletostr_mul
7787
;now the number is pretty close to a nice value
7789
; If it is less than 1, multiply by 10
7794
;ld hl,scrap ;Since singletostr_mul returns BC = scrap, can do this cheaper
7800
ld hl,pow10exp_single
7806
; Convert to a fixed-point number !
7820
;We need to get 7 digits
7822
pop hl ;Points to the string
7824
;The first digit can be as large as 20, so it'll actually be two digits
7828
;Increment the exponent :)
7829
ld de,(pow10exp_single-1)
7831
ld (pow10exp_single-1),de
7840
; Get the remaining digits.
7847
call singletostrmul10
7852
;Save the pointer to the end of the string
7859
jr c,rounding_done_single
7860
jr _40a ;.db $DA ;start of `jp c,*` in order to skip the next instruction
7869
rounding_done_single:
7872
;Strip the leading zero if it exists (rounding may have bumped this to `1`)
7884
;Now lets move HL-DE bytes at DE+1 to DE
7896
;If z flag is reset, this means that the exponent should be bumped up 1
7897
ld a,(pow10exp_single)
7900
ld (pow10exp_single),a
7903
;if -4<=A<=6, then need to insert the decimal place somewhere.
7908
;for this, we need to insert the decimal after the first digit
7909
;Then, we need to append the exponent string
7911
ld de,strout_single-1
7913
cp '-' ;negative sign
7921
;remove any stray zeroes at the end before appending the exponent
7925
; Write the exponent
7928
ld a,(pow10exp_single)
7931
ld (hl),'-' ;negative sign
7949
ld de, strout_single
7952
ld a, l ; string size
7954
ld hl,strout_single-1
7958
ld a,(pow10exp_single)
7962
;need to put zeroes before everything
7965
cp '-' ;negative sign
7991
ld de,strout_single-1
7995
cp '-' ;negative sign
8006
ld hl,strout_single-1
8024
;multiply the 0.24 fixed point number at scrap by 10
8025
;overflow in A register
8060
;Check that the last digit isn't a decimal!
8114
;---------------------------------------------------------------------------------------------------------
8116
; https://www.ticalc.org/pub/86/asm/source/routines/atof.asm
8117
;---------------------------------------------------------------------------------------------------------
8122
ptr_sto: equ scrap+9
8124
;;#Routines/Single Precision
8126
;; HL points to the string
8127
;; BC points to where the float is output
8129
;; scrap+9 is the pointer to the end of the string
8131
;; 11 bytes at scrap ?
8136
;Check if there is a negative sign.
8145
;Skip all leading zeroes
8148
jr z,$-4 ;jumps back to the `inc hl`
8151
;Check if the next char is char_DEC
8153
or a ;to reset the carry flag
8155
jr _54a ;.db $FE ;start of cp *
8162
jr z,$-5 ;jumps back to the `dec b`
8165
;Now we read in the next 8 digits
8171
;Now `scrap` holds the 4-digit base-100 number.
8173
;if carry flag is set, just need to get rid of remaining digits
8174
;Otherwise, need to get rid of remaining digits, while incrementing the exponent
8185
jp z,strToSingle_inf
8188
;Now check for engineering `E` to modify the exponent
8192
;Gotta multiply the number at (scrap) by 2^24
8195
call scrap_times_256
8198
call scrap_times_256
8201
call scrap_times_256
8204
call scrap_times_256
8207
;Now scrap+3 is a 4-byte mantissa that needs to be normalized
8215
jp z,strToSingle_zero-1
8219
jp m,strToSingle_normed
8220
;Will need to iterate at most three times
8233
;Move the number to scrap
8242
;now (scrap) is our number, need to multiply by power of 10!
8243
;Power of 10 is stored in B, need to put in A first
8251
jp nc,strToSingle_inf+1
8254
jp nc,strToSingle_zero
8278
cp char_NEG ;negative exponent?
8330
call scrap_times_sub
8343
jr nz,strToSingle_inf
8361
if defined roundSingle or defined MATH_FRCSGL
8363
;---------------------------------------------------------------------------------------------------------
8365
; http://wikiti.brandonw.net/index.php?title=Z80_Routines:Math:Division#24.2F8_division
8366
;---------------------------------------------------------------------------------------------------------
8373
ld l, (ix) ; convert integer parameter to single float
8375
ld bc, 0x1000 ; bynary digits count + sign
8377
int2Single.test.zero:
8379
or h ; test if hl is not zero
8380
jr nz, int2Single.test.negative
8382
jr nz, int2Single.test.negative
8387
int2Single.test.negative:
8388
bit 7, h ; test if hl is negative
8389
jr z, int2Single.normalize
8390
ld c, 0x80 ; sign negative
8399
int2Single.normalize:
8402
jr nz, int2Single.mount
8405
jr int2Single.normalize
8408
res 7, h ; turn off upper bit
8410
ld a, c ; restore sign
8412
ld h, a ; ...into upper mantissa
8414
ld e, h ; sign+mantissa
8415
ld h, l ; high mantissa
8416
ld l, 0 ; low mantissa
8418
ld a, b ; binary digits count
8419
or 0x80 ; exponent bias
8424
ld (ix), l ; low mantissa
8425
ld (ix+1), h ; high mantissa
8426
ld (ix+2), e ; sign + mantissa
8427
ld (ix+3), d ; expoent
8436
if defined roundSingle or defined MATH_FRCINT
8438
;---------------------------------------------------------------------------------------------------------
8440
; http://0x80.pl/articles/convert-float-to-integer.html
8441
;---------------------------------------------------------------------------------------------------------
8444
; HL points to the single-precision float
8446
; HL is the 16-bit signed integer part of the float
8447
; BC points to 16-bit signed integer
8464
jr c,no_shift_single_to_int16
8466
jr nc,no_shift_single_to_int16
8488
jr _67a ;.db $11 ;start of ld de,*
8500
no_shift_single_to_int16:
8522
;---------------------------------------------------------------------------------------------------------
8523
; Auxiliary routines
8524
;---------------------------------------------------------------------------------------------------------
8531
const_pi: db $DB,$0F,$49,$81
8532
const_e: db $54,$f8,$2d,$81
8533
const_lg_e: db $3b,$AA,$38,$80
8534
const_ln_2: db $18,$72,$31,$7f
8535
const_log2: db $9b,$20,$1a,$7e
8536
const_lg10: db $78,$9a,$54,$81
8537
const_0: db $00,$00,$00,$00
8538
const_1: db $00,$00,$00,$80
8539
const_2: dw 0, 33024
8540
const_3: dw 0, 33088
8541
const_4: dw 0, 33280
8542
const_5: dw 0, 33312
8543
const_7: dw 0, 33376
8544
const_9: dw 0, 33552
8545
const_16: dw 0, 33792
8546
const_100: db $00,$00,$48,$86
8547
const_100_inv: dw 55050, 31011
8548
const_precision: db $77,$CC,$2B,$65 ;10^-8
8549
const_half_1: dw 0, 32512
8550
const_inf: db $00,$00,$40,$00
8551
const_NegInf: db $00,$00,$C0,$00
8552
const_NaN: db $00,$00,$20,$00
8553
const_log10_e: db $D9,$5B,$5E,$7E
8554
const_2pi: db $DB,$0F,$49,$82
8555
const_2pi_inv: db $83,$F9,$22,$7D
8556
const_half_pi: dw 4059, 32841
8557
const_p25: db $00,$00,$00,$7E
8558
const_p5: db $00,$00,$00,$7F
8561
sin_a1: dw 43691, 32042
8562
sin_a2: dw 34952, 30984
8563
sin_a3: dw 3329, 29520
8564
cos_a1: equ const_half_1
8565
cos_a2: dw 43691, 31530
8566
cos_a3: dw 2914, 30262
8567
exp_a1: db $15,$72,$31,$7F ;.693146989552
8568
exp_a2: db $CE,$FE,$75,$7D ;.2402298085906
8569
exp_a3: db $7B,$42,$63,$7B ;.0554833215071
8570
exp_a4: db $FD,$94,$1E,$79 ;.00967907584392
8571
exp_a5: db $5E,$01,$23,$76 ;.001243632065103
8572
exp_a6: db $5F,$B7,$63,$73 ;.0002171671843714
8573
const_1p40625: db $00,$00,$34,$80 ;1.40625
8575
if defined MATH_CONSTSINGLE
8583
;A is the constant ID#
8584
;returns nc if failed, c otherwise
8585
;HL points to the constant
8586
cp (end_const-start_const)>>2
8593
;#if ((end_const-4)>>8)!=(start_const>>8)
8606
db $CD,$CC,$4C,$7C ;.1
8607
db $0A,$D7,$23,$79 ;.01
8608
db $17,$B7,$51,$72 ;.0001
8609
db $77,$CC,$2B,$65 ;10^-8
8610
db $95,$95,$66,$4A ;10^-16
8611
db $1F,$B1,$4F,$15 ;10^-32
8614
db $00,$00,$20,$83 ;10
8615
db $00,$00,$48,$86 ;100
8616
db $00,$40,$1C,$8D ;10000
8617
db $20,$BC,$3E,$9A ;10^8
8618
db $CA,$1B,$0E,$B5 ;10^16
8619
db $AE,$C5,$1D,$EA ;10^32
8626
;C>=128 135+6{0,33+{0,1}}+{0,20+{0,8}}
8627
;C>=64 115+5{0,33+{0,1}}+{0,20+{0,8}}
8628
;C>=32 95+4{0,33+{0,1}}+{0,20+{0,8}}
8629
;C>=16 75+3{0,33+{0,1}}+{0,20+{0,8}}
8630
;C>=8 55+2{0,33+{0,1}}+{0,20+{0,8}}
8631
;C>=4 35+{0,33+{0,1}}+{0,20+{0,8}}
8632
;C>=2 15+{0,20+{0,8}}
8635
;avg: 349.21279907227cc
8726
;26 bytes, adds 118cc to the traditional routine
8761
;c flag means don't increment the exponent
8764
jr c,ascii_to_uint8_noexp
8766
jr z,ascii_to_uint8_noexp-2
8770
jr nc,ascii_to_uint8_noexp_end
8782
jr z,ascii_to_uint8_noexp_2nd
8786
jr nc,ascii_to_uint8_noexp_end
8797
ascii_to_uint8_noexp:
8800
jr nc,ascii_to_uint8_noexp_end
8807
ascii_to_uint8_noexp_2nd:
8812
jr nc,ascii_to_uint8_noexp_end
8815
jr ascii_2 ;.db $FE ;start of `cp **`, saves 1cc
8816
ascii_to_uint8_noexp_end:
8826
if defined MATH_RSUBSINGLE
8847
jp addInject ;jumps in to the addSingle routine
8851
if defined MATH_MOD1SINGLE
8853
;This routine performs `x mod 1`, returning a non-negative value.
8876
jr z,mod1Single_special
8889
;If it is zero, need to set exponent to zero and return
8912
;make sure it isn't zero else we need to add 1
8924
;If INF, need to return NaN instead
8925
;For 0 and NaN, just return itself :)
8945
if defined MATH_FOUT
8947
; --------------------------------------------------------------
8948
; Converts a signed integer value to a zero-terminated ASCII
8949
; string representative of that value (using radix 10).
8951
; Brandon Wilson WikiTI
8952
; http://wikiti.brandonw.net/index.php?title=Z80_Routines:Other:DispA#Decimal_Signed_Version
8953
; --------------------------------------------------------------
8955
; HL Value to convert (two's complement integer).
8956
; DE Base address of string destination. (pointer).
8957
; --------------------------------------------------------------
8960
; --------------------------------------------------------------
8961
; REGISTERS/MEMORY DESTROYED
8963
; --------------------------------------------------------------
8969
; Detect sign of HL.
8973
; HL is negative. Output '-' to string and negate HL.
8978
; Negate HL (using two's complement)
8982
ld a, 0 ; Note that XOR A or SUB A would disturb CF
8986
; Convert HL to digit characters
8988
ld b, 0 ; B will count character length of number
8991
call div_hl_c; HL = HL / A, A = remainder
8998
; Retrieve digits from stack
9006
; Terminate string with NULL
9017
ld a, l ; string size
9025
;===============================================================
9026
; Convert a string of base-10 digits to a 16-bit value.
9027
; http://z80-heaven.wikidot.com/math#toc32
9029
; DE points to the base 10 number string in RAM.
9031
; HL is the 16-bit value of the number
9032
; DE points to the byte after the number
9037
; A (actually, add 30h and you get the ending token)
9040
; n is the number of digits
9042
; at most 595 cycles for any 16-bit decimal value
9043
;===============================================================
9046
ld hl,0 ; 10 : 210000
9063
jr nc,ConvLoop ;12|23: 30EE
9065
jr ConvLoop ; --- : 18EB
9072
; return remainder in a
9073
; http://wikiti.brandonw.net/index.php?title=Z80_Routines:Math:Division
9094
; http://wikiti.brandonw.net/index.php?title=Z80_Routines:Math:Division#24.2F8_division
9124
djnz div_dehl_c.loop
9132
;---------------------------------------------------------------------------------------------------------
9133
; VARIABLES INITIALIZE
9134
;---------------------------------------------------------------------------------------------------------
9138
ld (VAR_DUMMY.COUNTER), a ; max circular queue = 8 dummys
9139
ld hl, VAR_DUMMY.DATA ; start of variable dummy circular queue
9140
ld (VAR_DUMMY.POINTER), hl
9141
ld b, VAR_DUMMY.LENGTH
9146
djnz INITIALIZE_DUMMY.1
9151
ld (BASIC_DATPTR), hl ; next DATA pointer to use by READ command
9153
ld (BASIC_DATLIN), hl ; index of DATA item to use by READ command
9156
INITIALIZE_VARIABLES:
9157
call INITIALIZE_DATA
9158
call INITIALIZE_DUMMY
9161
call gfxInitSpriteCollisionTable
9164
;if defined COMPILE_TO_ROM
9165
; ld ix, BIOS_JIFFY ; initialize rom clock
9173
ld d, 2 ; any = default integer
9174
ld c, 0 ; variable name 1 (variable number)
9175
ld b, 0 ; variable name 2 (type flag=any)
9176
call INIT_VAR ; variable initialize
9178
ld d, 2 ; any = default integer
9179
ld c, 1 ; variable name 1 (variable number)
9180
ld b, 0 ; variable name 2 (type flag=any)
9181
call INIT_VAR ; variable initialize
9183
ld d, 2 ; any = default integer
9184
ld c, 2 ; variable name 1 (variable number)
9185
ld b, 0 ; variable name 2 (type flag=any)
9186
call INIT_VAR ; variable initialize
9188
ld d, 2 ; any = default integer
9189
ld c, 3 ; variable name 1 (variable number)
9190
ld b, 0 ; variable name 2 (type flag=any)
9191
call INIT_VAR ; variable initialize
9193
ld d, 2 ; any = default integer
9194
ld c, 4 ; variable name 1 (variable number)
9195
ld b, 0 ; variable name 2 (type flag=any)
9196
call INIT_VAR ; variable initialize
9198
ld d, 2 ; any = default integer
9199
ld c, 5 ; variable name 1 (variable number)
9200
ld b, 0 ; variable name 2 (type flag=any)
9201
call INIT_VAR ; variable initialize
9203
ld d, 2 ; any = default integer
9204
ld c, 6 ; variable name 1 (variable number)
9205
ld b, 0 ; variable name 2 (type flag=any)
9206
call INIT_VAR ; variable initialize
9208
ld d, 2 ; any = default integer
9209
ld c, 7 ; variable name 1 (variable number)
9210
ld b, 0 ; variable name 2 (type flag=any)
9211
call INIT_VAR ; variable initialize
9213
ld d, 2 ; any = default integer
9214
ld c, 8 ; variable name 1 (variable number)
9215
ld b, 0 ; variable name 2 (type flag=any)
9216
call INIT_VAR ; variable initialize
9218
ld d, 2 ; any = default integer
9219
ld c, 9 ; variable name 1 (variable number)
9220
ld b, 0 ; variable name 2 (type flag=any)
9221
call INIT_VAR ; variable initialize
9223
ld d, 2 ; any = default integer
9224
ld c, 10 ; variable name 1 (variable number)
9225
ld b, 0 ; variable name 2 (type flag=any)
9226
call INIT_VAR ; variable initialize
9230
;---------------------------------------------------------------------------------------------------------
9231
; MAIN WORK AREA - LITERALS / VARIABLES / CONFIGURATIONS
9232
;---------------------------------------------------------------------------------------------------------
9234
if defined COMPILE_TO_ROM
9237
pgmPage1.pad: equ pageSize - (workAreaPad - pgmArea)
9239
if pgmPage1.pad >= 0
9242
; .WARNING "There's no free space left on program page 1"
9247
VAR_STACK.START: equ ramArea
9248
;VAR_STACK.END: equ VAR_STACK.START + 0x800 ; 2kb (~200 variables)
9250
VAR_STACK.POINTER: equ VAR_STACK.START
9252
PRINT.CRLF: db 3, 0, 0, 2
9253
dw PRINT.CRLF.DATA, 0, 0, 0
9254
PRINT.CRLF.DATA: db 13,10,0
9256
PRINT.TAB: db 3, 0, 0, 1
9257
dw PRINT.TAB.DATA, 0, 0, 0
9258
PRINT.TAB.DATA: db 09,0
9261
LIT_NULL_DBL: dw 0, 0, 0, 0
9267
LIT_QUOTE_CHAR: db '\"'
9270
LIT_TRUE: db 2, 0, 0
9274
LIT_FALSE: db 2, 0, 0
9331
IDF_19: equ VAR_STACK.POINTER + 0
9342
IDF_27: equ VAR_STACK.POINTER + 11
9361
IDF_37: equ VAR_STACK.POINTER + 22
9376
IDF_41: equ VAR_STACK.POINTER + 33
9387
IDF_45: equ VAR_STACK.POINTER + 44
9406
IDF_56: equ VAR_STACK.POINTER + 55
9409
IDF_57: equ VAR_STACK.POINTER + 66
9448
IDF_69: equ VAR_STACK.POINTER + 77
9463
IDF_73: equ VAR_STACK.POINTER + 88
9478
IDF_77: equ VAR_STACK.POINTER + 99
9493
IDF_82: equ VAR_STACK.POINTER + 110
9519
AFTER_LAST_VARIABLE: equ VAR_STACK.POINTER + 121
9521
VAR_DUMMY.START: equ AFTER_LAST_VARIABLE ; variable dummy circular queue area
9522
VAR_DUMMY.COUNTER: equ VAR_DUMMY.START ; variable dummy circular queue count
9523
VAR_DUMMY.POINTER: equ VAR_DUMMY.COUNTER + 1 ; pointer to next variable dummy
9524
VAR_DUMMY.DATA: equ VAR_DUMMY.POINTER + 2 ; first variable dummy
9526
VAR_DUMMY.SIZE: equ 8
9527
VAR_DUMMY.LENGTH: equ (11 * VAR_DUMMY.SIZE)
9528
VAR_DUMMY.END: equ VAR_DUMMY.DATA + VAR_DUMMY.LENGTH
9529
VAR_STACK.END: equ VAR_DUMMY.END + 1
9531
;--------------------------------------------------------
9533
;--------------------------------------------------------
9536
DATA_ITEMS_COUNT: equ 0
9538
DATA_SET_ITEMS_START:
9539
DATA_SET_ITEMS_COUNT: equ 0
9542
;---------------------------------------------------------------------------------------------------------
9544
;---------------------------------------------------------------------------------------------------------
9546
if defined COMPILE_TO_ROM
9550
pgmPage2.pad: equ romSize - (romPad - pgmArea)
9552
if pgmPage2.pad >= 0
9555
if pgmPage2.pad < lowLimitSize
9556
.WARNING "There's only less than 5% free space on this ROM"
9559
.ERROR "There's no free space left on this ROM"
9564
end_file: end start_pgm ; label start is the entry point