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_BASIC: 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_SCALXY: equ 0x010E
61
BIOS_MAPXYC: equ 0x0111 ; in BC = X, DE = Y
62
BIOS_READC: equ 0x011D ; out A = color of current pixel
63
BIOS_SETATR: equ 0x011A ; in A = color code
64
BIOS_SETC: equ 0x0120 ; set current pixel to color from SETATR
65
BIOS_NSETCX: equ 0x0123 ; in HL = pixel fill count
66
BIOS_SCANR: equ 0x012C ; in B=Fill switch, DE=Skip count, out DE=Skip remainder, HL=Pixel count
67
BIOS_SCANL: equ 0x012F ; out HL=Pixel count
68
BIOS_FETCHC: equ 0x0114 ; out A = cursor mask, HL = VRAM address of cursor
69
BIOS_STOREC: equ 0x0117 ; in A = cursor mask, HL = VRAM address of cursor
70
BIOS_RESET: equ 0x7D17 ; restart BASIC
71
BIOS_IOALLOC: equ 0X7e6b ; memory setup
73
BIOS_GETVCP: equ 0x0150 ; get PSG voice buffer address (in A = voice number, out HL = address of byte 2)
74
BIOS_GETVC2: equ 0x0153 ; get PSG voice buffer address (VOICEN = voice number, in L = byte number 0-36, out HL = address)
76
BIOS_CHPUT_LF: equ 0x0908
77
BIOS_CHPUT_CR: equ 0x0A81
78
BIOS_CHPUT_TAB: equ 0x0A71
81
BIOS_CHKNEW: equ 0x0165 ; C-flag set if screenmode = 5, 6, 7 or 8
82
BIOS_EXTROM: equ 0x015F
83
BIOS_SCALXY2: equ 0x008D ; in BC = X, DE = Y
84
BIOS_MAPXYC2: equ 0x0091 ; in BC = X, DE = Y
85
BIOS_SETC2: equ 0x009D ; set current pixel to color from SETATR
86
BIOS_READC2: equ 0x0095 ; out A = color of current pixel
87
BIOS_CHGMOD2: equ 0x00D1 ; in A = screenmode
88
BIOS_DOBOXF: equ 0x0079 ; hl = basic text pointer
89
BIOS_GRPPRT2: equ 0x0089 ; a = character
90
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
98
;---------------------------------------------------------------------------------------------------------
100
;---------------------------------------------------------------------------------------------------------
102
BIOS_VERSION: equ 0x002D ; 0 = MSX1, 1 = MSX2, 2 = MSX2+, 3 = MSXturboR
103
BIOS_FORCLR: equ 0xF3E9
104
BIOS_BAKCLR: equ 0xF3EA
105
BIOS_BDRCLR: equ 0xF3EB
106
BIOS_ATRBYT: equ 0xF3F2
107
BIOS_INTFLG: equ 0xFC9B
108
BIOS_EXPTBL: equ 0xFCC1
109
BIOS_JIFFY: equ 0xFC9E
110
BIOS_BOTTOM: equ 0xFC48
111
BIOS_HIMEM: equ 0xFC4A
112
BIOS_SCRMOD: equ 0xFCAF ; 0=40x24 Text Mode, 1=32x24 Text Mode, 2=Graphics Mode, 3=Multicolour Mode.
113
BIOS_CLIKSW: equ 0xF3DB ; 0=keyboard click off, 1=keyboard click on
114
BIOS_GRPACX: equ 0xFCB7
115
BIOS_GRPACY: equ 0xFCB9
116
BIOS_DATLIN: equ 0xF6A3 ; 2 - line number of DATA statement read by READ statement
117
BIOS_DATPTR: equ 0xF6C8 ; 2 - address of data read by executing READ statement
118
BIOS_FLGINP: equ 0xF6A6 ; 1 - flag used in INPUT or READ
119
BIOS_TEMP: equ 0xF6A7 ; 2
120
BIOS_TEMP2: equ 0xF6BC ; 2
121
BIOS_TEMP3: equ 0xF69D ; 2
122
BIOS_TEMP8: equ 0xF69F ; 2
123
BIOS_TEMP9: equ 0xF7B8 ; 2
124
BIOS_OLDSCR: equ 0xFCB0 ; screen mode of the last text mode set
125
BIOS_LINL40: equ 0xF3AE ; width for 40 columns screen mode
126
BIOS_LINL32: equ 0xF3AF ; width for 32 columns screen mode
127
BIOS_LINLEN: equ 0xF3B0 ; current width for text screen mode
128
BIOS_CLMLST: equ 0xF3B2 ; minimum number of columns that must still be available on a line for a CRLF
129
BIOS_TXTNAM: equ 0xF3B3 ; characters table name
131
BIOS_VOICEN: equ 0xFB38 ; PSG voice number
132
BIOS_MCLTAB: equ 0xF956
133
BIOS_PRSCNT: equ 0xFB35
134
BIOS_SAVSP: equ 0xFB36
135
BIOS_QUEUEN: equ 0xFB3E
136
BIOS_MUSICF: equ 0xFB3F
137
BIOS_PLYCNT: equ 0xFB40
139
BIOS_DRWFLG: equ 0xFCBB
140
BIOS_MCLFLG: equ 0xF958
145
;--------------------------------------------------------
146
; MSX BASIC DATA/FUNCTION POINTERS
147
;--------------------------------------------------------
149
;---------------------------------------------------------------------------------------------------------
150
; MSX BASIC FUNCTIONS
151
;---------------------------------------------------------------------------------------------------------
153
BASIC_AUTO: equ 0x3973
154
BASIC_AND: equ 0x3A18
155
BASIC_ATTR: equ 0x39FE
156
BASIC_BASE: equ 0x39BE
157
BASIC_BSAVE: equ 0x39CC
158
BASIC_BLOAD: equ 0x39CA
159
BASIC_BEEP: equ 0x39AC
160
BASIC_CALL: equ 0x39C0
161
BASIC_CLOSE: equ 0x3994
162
BASIC_COPY: equ 0x39D8
163
BASIC_CONT: equ 0x395E
164
BASIC_CLEAR: equ 0x3950
165
BASIC_CLOAD: equ 0x3962
166
BASIC_CSAVE: equ 0x3960
167
BASIC_CSRLIN: equ 0x39FC
168
BASIC_CIRCLE: equ 0x39A4
169
BASIC_COLOR: equ 0x39A6
170
BASIC_CLS: equ 0x396A
171
BASIC_CMD: equ 0x39DA
172
BASIC_DELETE: equ 0x397C
173
BASIC_DATA: equ 0x3934
174
BASIC_DIM: equ 0x3938
175
BASIC_DEFSTR: equ 0x3982
176
BASIC_DEFINT: equ 0x3984
177
BASIC_DEFSNG: equ 0x3986
178
BASIC_DEFDBL: equ 0x3988
179
BASIC_DSKO: equ 0x39CE
180
BASIC_DEF: equ 0x395A
181
BASIC_DSKI: equ 0x3A00
182
BASIC_DRAW: equ 0x39A8
183
BASIC_ELSE: equ 0x396E
184
BASIC_END: equ 0x392E
185
BASIC_ERASE: equ 0x3976
186
BASIC_ERROR: equ 0x3978
187
BASIC_ERL: equ 0x39EE
188
BASIC_ERR: equ 0x39F0
189
BASIC_EQU: equ 0x3A1E
190
BASIC_FOR: equ 0x3920
191
BASIC_FIELD: equ 0x398E
192
BASIC_FILES: equ 0x39AA
194
BASIC_GOTO: equ 0x393E
195
BASIC_GOSUB: equ 0x3948
196
BASIC_GET: equ 0x3990
197
BASIC_INPUT: equ 0x3936
199
BASIC_INSTR: equ 0x39F6
200
BASIC_IMP: equ 0x3A20
201
BASIC_INKEY: equ 0x3A04
202
BASIC_IPL: equ 0x39D6
203
BASIC_KILL: equ 0x39D4
204
BASIC_KEY: equ 0x3964
205
BASIC_LPRINT: equ 0x394C
206
BASIC_LLIST: equ 0x3968
207
BASIC_LET: equ 0x393C
208
BASIC_LOCATE: equ 0x39DC
209
BASIC_LINE: equ 0x398A
210
BASIC_LOAD: equ 0x3996
211
BASIC_LSET: equ 0x399C
212
BASIC_LIST: equ 0x3952
213
BASIC_LFILES: equ 0x39A2
214
BASIC_MOTOR: equ 0x39C8
215
BASIC_MERGE: equ 0x3998
216
BASIC_MOD: equ 0x3A22
217
BASIC_MAX: equ 0x39C6
218
BASIC_NEXT: equ 0x3932
219
BASIC_NAME: equ 0x39D2
220
BASIC_NEW: equ 0x3954
221
BASIC_NOT: equ 0x39EC
222
BASIC_OPEN: equ 0x398C
223
BASIC_OUT: equ 0x3964
226
BASIC_OFF: equ 0x3A02
227
BASIC_PRINT: equ 0x394E
228
BASIC_PUT: equ 0x3992
229
BASIC_POKE: equ 0x395C
230
BASIC_PSET: equ 0x39B0
231
BASIC_PRESET: equ 0x39B2
232
BASIC_POINT: equ 0x3A06
233
BASIC_PAINT: equ 0x39AA
234
BASIC_PLAY: equ 0x39AE
235
BASIC_RETURN: equ 0x3948
236
BASIC_READ: equ 0x393A
237
BASIC_RUN: equ 0x3940
238
BASIC_RESTORE:equ 0x3944
239
BASIC_REM: equ 0x394A
240
BASIC_RESUME: equ 0x397A
241
BASIC_RSET: equ 0x399E
242
BASIC_RENUM: equ 0x3980
243
BASIC_SCREEN: equ 0x39B6
244
BASIC_SPRITE: equ 0x39BA
245
BASIC_STOP: equ 0x394C
246
BASIC_SWAP: equ 0x3974
247
BASIC_SET: equ 0x39D0
248
BASIC_SAVE: equ 0x39A0
249
BASIC_SPC: equ 0x39EA
250
BASIC_STEP: equ 0x39E4
251
BASIC_STRING: equ 0x39F2
252
BASIC_SPACE1: equ 0x397E
253
BASIC_SOUND: equ 0x39B4
254
BASIC_THEN: equ 0x39E0
255
BASIC_TRON: equ 0x3970
256
BASIC_TROFF: equ 0x3972
257
BASIC_TAB: equ 0x39E2
259
BASIC_TIME: equ 0x39C2
260
BASIC_USING: equ 0x39F4
261
BASIC_USR: equ 0x39E6
262
BASIC_VARPTR: equ 0x39FA
263
BASIC_VDP: equ 0x39BC
264
BASIC_VPOKE: equ 0x39B8
265
BASIC_WIDTH: equ 0x396C
266
BASIC_WAIT: equ 0x3958
267
BASIC_XOR: equ 0x3A1C
268
BASIC_ABS: equ 0x39E8
269
BASIC_ATN: equ 0x39F8
270
BASIC_ASC: equ 0x3A06
271
BASIC_BIN: equ 0x3A16
272
BASIC_CINT: equ 0x3A18
273
BASIC_CSNG: equ 0x3A1A
274
BASIC_CDBL: equ 0x3A1C
275
BASIC_CVI: equ 0x3A2C
276
BASIC_CVS: equ 0x3A2E
277
BASIC_CVD: equ 0x3A30
278
BASIC_COS: equ 0x39F4
279
BASIC_CHR: equ 0x3A08
280
BASIC_DSKF: equ 0x3A28
281
BASIC_EXP: equ 0x39F2
282
BASIC_EOF: equ 0x3A32
283
BASIC_FRE: equ 0x39FA
284
BASIC_FIX: equ 0x3A1E
285
BASIC_FPOS: equ 0x3A2A
286
BASIC_HEX: equ 0x3A12
287
BASIC_INT: equ 0x39E6
288
BASIC_INP: equ 0x39FC
289
BASIC_LPOS: equ 0x3A14
290
BASIC_LOG: equ 0x39F0
291
BASIC_LOC: equ 0x3A34
292
BASIC_LEN: equ 0x3A00
293
BASIC_LEFT: equ 0x39DE
294
BASIC_LOF: equ 0x3A36
295
BASIC_MKI: equ 0x3A38
296
BASIC_MKS: equ 0x3A3A
297
BASIC_MKD: equ 0x3A3C
298
BASIC_MID: equ 0x39E2
299
BASIC_OCT: equ 0x3A10
300
BASIC_POS: equ 0x39FE
301
BASIC_PEEK: equ 0x3A0A
302
BASIC_PDL: equ 0x3A24
303
BASIC_PAD: equ 0x3A26
304
BASIC_RIGHT: equ 0x39E0
305
BASIC_RND: equ 0x39EC
306
BASIC_SGN: equ 0x39E4
307
BASIC_SQR: equ 0x39EA
308
BASIC_SIN: equ 0x39EE
309
BASIC_STR: equ 0x3A02
310
BASIC_SPACE2: equ 0x3A0E
311
BASIC_STICK: equ 0x3A20
312
BASIC_STRIG: equ 0x3A22
313
BASIC_TAN: equ 0x39F6
314
BASIC_VAL: equ 0x3A04
315
BASIC_VPEEK: equ 0x3A0C
317
BASIC_TRAP_ENABLE: equ 0x631B ; ON INTERVAL/KEY/SPRITE/STOP/STRIG - hl = pointer to trap block
318
BASIC_TRAP_DISABLE: equ 0x632B ; hl = pointer to trap block
319
BASIC_TRAP_ACKNW: equ 0x6358 ; hl, acknowledge trap (handle trap: sts=5? has handler? ackn, pause, run trap, sts=1? unpause)
320
BASIC_TRAP_PAUSE: equ 0x6331 ; hl
321
BASIC_TRAP_UNPAUSE: equ 0x633E ; hl
322
BASIC_TRAP_CLEAR: equ 0x636E
324
BASIC_PLAY_DIRECT: equ 0x744C
325
BASIC_DRAW_DIRECT: equ 0x568C
327
BASIC_READYR: equ 0x409B
328
BASIC_READYC: equ 0x7D17
329
BASIC_FACEVAL: equ 0x4DC7
331
BASIC_ERROR_HANDLER:equ 0x406F
332
BASIC_ERROR_SYNTAX: equ 0x4055
333
BASIC_ERROR_DIVZER: equ 0x4058
334
BASIC_ERROR_OVRFLW: equ 0x4067
335
BASIC_ERROR_ARRAY: equ 0x405E
336
BASIC_ERROR_TYPMIS: equ 0x406D
338
; BASIC ERROR CODES TO BASIC_ERROR_HANDLER
339
; 01 NEXT without FOR 19 Device I/O error
340
; 02 Syntax error 20 Verify error
341
; 03 RETURN without GOSUB 21 No RESUME
342
; 04 Out of DATA 22 RESUME without error
343
; 05 Illegal function call 23 Unprintable error
344
; 06 Overflow 24 Missing operand
345
; 07 Out of memory 25 Line buffer overflow
346
; 08 Undefined line number 50 FIELD overflow
347
; 09 Subscript out of range 51 Internal error
348
; 10 Redimensioned array 52 Bad file number
349
; 11 Division by zero 53 File not found
350
; 12 Illegal direct 54 File already open
351
; 13 Type mismatch 55 Input past end
352
; 14 Out of string space 56 Bad file name
353
; 15 String too long 57 Direct statement in file
354
; 16 String formula too complex 58 Sequential I/O only
355
; 17 Can't CONTINUE 59 File not OPEN
356
; 18 Undefined user function
358
;---------------------------------------------------------------------------------------------------------
359
; MSX BASIC WORK AREAS
360
;---------------------------------------------------------------------------------------------------------
362
BASIC_DAC: equ 0xF7F6 ; 16
363
BASIC_ARG: equ 0xF847 ; 16
364
BASIC_VALTYP: equ 0xF663
365
BASIC_RNDX: equ 0xF857
366
BASIC_BUF: equ 0xF55E ; 259
367
BASIC_SWPTMP: equ 0xF7BC ; 8
368
BASIC_STRBUF: equ 0xF7C5 ; 43
369
BASIC_TXTTAB: equ 0xF676
370
BASIC_VARTAB: equ 0xF6C2
371
BASIC_ARYTAB: equ 0xF6C4
372
BASIC_STREND: equ 0xF6C6
373
BASIC_STKTOP: equ 0xF674
374
BASIC_FRETOP: equ 0xF69B
375
BASIC_MEMSIZ: equ 0xF672
377
BASIC_TEMPPT: equ 0xF678 ; 2 Starting address of unused area of temporary descriptor.
378
BASIC_TEMPST: equ 0xF67A ; 30 Temporary descriptors.
380
BASIC_DATPTR: equ 0xF6C8 ; 2 Pointer to next data to read from the instruction DATA. Modified by RESTORE.
381
BASIC_DATLIN: equ 0xF6A3 ; 2 Número de linha do comando DATA para o comando READ.
382
BASIC_DORES: equ 0xF664 ; 1 Usada pelo comando DATA para manter o texto no formato ASCII.
383
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).
385
BASIC_CURLIN: equ 0xF41C ; BASIC current line number
386
BASIC_INTVAL: equ 0xFCA0 ; interval value
387
BASIC_INTCNT: equ 0xFCA2 ; interval current count
389
BASIC_PRMPRV: equ 0xF74C ; Pointer to previous parameter block in PARM1
391
BASIC_TRPTBL: equ 0xFC4C ; 78 trap table - array of 3 bytes - state[1] (bit 0=on, bit 1=stop, bit 2=active) + address[2]
393
BASIC_TRPTBL_KEY: equ 0xFC4C ; 30 ON KEY GOSUB
394
BASIC_TRPTBL_STOP: equ 0xFC6A ; 3 ON STOP GOSUB
395
BASIC_TRPTBL_SPRITE: equ 0xFC6D ; 3 ON SPRITE GOSUB
396
BASIC_TRPTBL_STRIG: equ 0xFC70 ; 15 ON STRIG GOSUB
397
BASIC_TRPTBL_INTERVAL: equ 0xFC7F ; 3 ON INTERVAL GOSUB
398
BASIC_TRPTBL_OTHER: equ 0xFC82 ; 24 reserved for expansion
400
BASIC_ONGSBF: equ 0xFBD8 ; 1 trap occurred counter (0=not occurred)
404
;--------------------------------------------------------
406
;--------------------------------------------------------
408
;--------------------------------------------------------
410
;--------------------------------------------------------
411
MACRO __call_bios,CALL_PARM
415
MACRO __call_basic,CALL_PARM
421
push hl ; save parameter
425
pop iy ; restore PC of caller
426
pop hl ; get next parameter
427
push iy ; save PC of caller
431
pop iy ; restore PC of caller
432
push hl ; save return parameter
433
push iy ; save PC of caller
437
pop iy ; restore PC of caller
438
push hl ; save return parameter
439
push iy ; save PC of caller
443
MACRO set.line.number, line_number
444
ld bc, line_number ; current line number
445
ld (BASIC_CURLIN), bc
449
ld a, (BIOS_INTFLG) ; verify CTRL+BREAK
455
ld a, (BASIC_ONGSBF) ; trap occured counter
460
;--------------------------------------------------------
462
;--------------------------------------------------------
463
pgmArea: equ 0x8000 ; page 2 - program area
464
ramArea: equ 0xc000 ; page 3 - free RAM start area
466
org pgmArea ; program rom type start address
467
db 'AB' ; rom file ID
469
dw 0x0000 ; STATEMENT
474
;--------------------------------------------------------
476
;--------------------------------------------------------
478
start_pgm: ; start of the program
479
call BIOS_BASIC_SLOT_ENABLE ; enable bios and basic on page 0 and 1
480
__call_bios BIOS_ERAFNK ; turn off function keys display
481
__call_bios BIOS_GICINI ; initialize sound system
482
__call_bios BIOS_INITXT ; initialize text screen
484
ld (BIOS_CLIKSW), a ; disable keyboard click
486
ld (BASIC_CURLIN), bc ; interpreter in direct mode
487
call BASIC_TRAP_CLEAR ; clear traps work space
488
call memory.init ; initialize memory allocation
489
call INITIALIZE_VARIABLES ; initialize variables
502
ld hl, LIT_4 ; parameter
504
call SCREEN ; action call
505
ld hl, LIT_11 ; parameter
507
call COLOR_BORDER ; action call
508
ld hl, LIT_9 ; parameter
510
call COLOR_BACKGROUND ; action call
511
ld hl, LIT_7 ; parameter
513
call COLOR_FOREGROUND ; action call
514
call COLOR ; action call
515
ld hl, LIT_13 ; parameter
517
ld hl, IDF_12 ; parameter
519
call LET ; action call
520
ld hl, LIT_15 ; parameter
522
ld hl, IDF_14 ; parameter
524
call LET ; action call
527
ld hl, LIT_17 ; parameter
529
ld hl, IDF_16 ; parameter
531
call LET ; action call
532
ld hl, LIT_19 ; parameter
534
ld hl, IDF_18 ; parameter
536
call LET ; action call
537
ld hl, LIT_21 ; parameter
539
ld hl, IDF_20 ; parameter
541
call LET ; action call
542
ld hl, LIT_23 ; parameter
544
ld hl, IDF_22 ; parameter
546
call LET ; action call
549
ld hl, LIT_25 ; parameter
551
ld hl, IDF_24 ; parameter
553
call LET ; action call
554
ld hl, IDF_24 ; parameter
556
ld hl, IDF_24 ; parameter
558
call MATH.ADD ; action call
559
ld hl, IDF_24 ; parameter
561
call MATH.ADD ; action call
562
ld hl, IDF_24 ; parameter
564
call LET ; action call
565
call CLS ; action call
568
ld hl, LIT_31 ; parameter
570
ld hl, LIT_30 ; parameter
572
call LOCATE ; action call
573
ld hl, LIT_33 ; parameter
575
call PRINT ; action call
576
ld hl, PRINT.CRLF ; parameter
578
call PRINT ; action call
581
ld hl, LIT_35 ; parameter
583
ld hl, LIT_34 ; parameter
585
call LOCATE ; action call
586
ld hl, LIT_36 ; parameter
588
call PRINT ; action call
589
ld hl, PRINT.CRLF ; parameter
591
call PRINT ; action call
594
ld hl, LIT_38 ; parameter
596
ld hl, LIT_37 ; parameter
598
call LOCATE ; action call
599
ld hl, LIT_39 ; parameter
601
call PRINT ; action call
602
ld hl, PRINT.CRLF ; parameter
604
call PRINT ; action call
609
IF_1 : ; start of IF command
610
ld hl, LIT_42 ; parameter
612
call STRIG ; action call
613
call BOOLEAN.IF ; verify IF condition result, out in A
615
jp z, ELSE_1 ; if false, jump to ELSE actions
616
THEN_1 : ; THEN actions
617
call CLS ; action call
619
jp ENDIF_1 ; jump to END of IF command
620
ELSE_1 : ; ELSE actions
621
ENDIF_1 : ; end of IF command
627
call BEEP ; action call
628
ld hl, LIT_48 ; parameter
630
call SCREEN ; action call
631
ld hl, LIT_50 ; parameter
633
call SPRITEMODE ; action call
634
call RESTORE ; action call
644
FOR_1 : ; start of FOR command
645
ld hl, LIT_57 ; parameter
647
ld hl, IDF_56 ; parameter
649
call LET ; action call
650
jp FOR.WHILE_1 ; jump to test if end of FOR
651
FOR.STEP_1 : ; STEP action
652
ld hl, LIT_59 ; parameter
654
ld hl, IDF_56 ; parameter
656
call MATH.ADD ; action call
657
ld hl, IDF_56 ; parameter
659
call LET ; action call
660
FOR.WHILE_1 : ; test if end of FOR
661
ld hl, IDF_56 ; parameter
663
ld hl, LIT_62 ; parameter
665
call BOOLEAN.LE ; action call
666
call BOOLEAN.IF ; verify IF condition result, out in A
668
jp z, ENDFOR_1 ; end the loop if while condition is false
669
FOR.BODY_1 : ; start of FOR user code
670
ld hl, LIT_66 ; parameter
672
call RND ; action call
673
ld hl, LIT_67 ; parameter
675
call MATH.MULT ; action call
676
call INT ; action call
677
ld hl, IDF_63 ; parameter
679
call LET ; action call
680
ld hl, IDF_63 ; parameter
682
call PSET.COLOR ; action call
683
ld hl, LIT_73 ; parameter
685
call RND ; action call
686
ld hl, LIT_74 ; parameter
688
call MATH.MULT ; action call
689
call INT ; action call
690
ld hl, LIT_71 ; parameter
692
call RND ; action call
693
ld hl, LIT_72 ; parameter
695
call MATH.MULT ; action call
696
call INT ; action call
697
call PSET.XY ; action call
698
call PSET ; action call
699
jp FOR.STEP_1 ; repeat actions
700
ENDFOR_1 : ; END of FOR command
704
ld hl, LIT_80 ; parameter
706
call COLOR_BORDER ; action call
707
ld hl, LIT_79 ; parameter
709
call COLOR_BACKGROUND ; action call
710
ld hl, LIT_78 ; parameter
712
call COLOR_FOREGROUND ; action call
713
call COLOR ; action call
716
ld hl, LIT_82 ; parameter
718
call STICK ; action call
719
ld hl, IDF_63 ; parameter
721
call LET ; action call
724
IF_2 : ; start of IF command
725
ld hl, IDF_63 ; parameter
727
ld hl, LIT_83 ; parameter
729
call BOOLEAN.EQ ; action call
730
ld hl, IDF_16 ; parameter
732
ld hl, LIT_85 ; parameter
734
call BOOLEAN.LT ; action call
735
call BOOLEAN.AND ; action call
736
call BOOLEAN.IF ; verify IF condition result, out in A
738
jp z, ELSE_2 ; if false, jump to ELSE actions
739
THEN_2 : ; THEN actions
740
ld hl, IDF_16 ; parameter
742
ld hl, LIT_88 ; parameter
744
call MATH.ADD ; action call
745
ld hl, IDF_16 ; parameter
747
call LET ; action call
748
jp ENDIF_2 ; jump to END of IF command
749
ELSE_2 : ; ELSE actions
750
ENDIF_2 : ; end of IF command
753
IF_3 : ; start of IF command
754
ld hl, IDF_63 ; parameter
756
ld hl, LIT_89 ; parameter
758
call BOOLEAN.EQ ; action call
759
ld hl, IDF_16 ; parameter
761
ld hl, LIT_90 ; parameter
763
call BOOLEAN.GT ; action call
764
call BOOLEAN.AND ; action call
765
call BOOLEAN.IF ; verify IF condition result, out in A
767
jp z, ELSE_3 ; if false, jump to ELSE actions
768
THEN_3 : ; THEN actions
769
ld hl, IDF_16 ; parameter
771
ld hl, LIT_92 ; parameter
773
call MATH.SUB ; action call
774
ld hl, IDF_16 ; parameter
776
call LET ; action call
777
jp ENDIF_3 ; jump to END of IF command
778
ELSE_3 : ; ELSE actions
779
ENDIF_3 : ; end of IF command
782
ld hl, LIT_97 ; parameter
784
ld hl, LIT_96 ; parameter
786
ld hl, IDF_18 ; parameter
788
ld hl, IDF_16 ; parameter
790
ld hl, LIT_95 ; parameter
792
call PUT_SPRITE_COLOR ; action call
797
IF_4 : ; start of IF command
798
ld hl, IDF_14 ; parameter
800
ld hl, LIT_98 ; parameter
802
call BOOLEAN.EQ ; action call
803
call BOOLEAN.IF ; verify IF condition result, out in A
805
jp z, ELSE_4 ; if false, jump to ELSE actions
806
THEN_4 : ; THEN actions
808
jp ENDIF_4 ; jump to END of IF command
809
ELSE_4 : ; ELSE actions
810
ENDIF_4 : ; end of IF command
813
ld hl, LIT_103 ; parameter
815
ld hl, LIT_102 ; parameter
817
ld hl, IDF_20 ; parameter
819
ld hl, IDF_101 ; parameter
821
ld hl, LIT_100 ; parameter
823
call PUT_SPRITE_COLOR ; action call
826
IF_5 : ; start of IF command
827
ld hl, LIT_104 ; parameter
829
call STRIG ; action call
830
call BOOLEAN.IF ; verify IF condition result, out in A
832
jp z, ELSE_5 ; if false, jump to ELSE actions
833
THEN_5 : ; THEN actions
835
jp ENDIF_5 ; jump to END of IF command
836
ELSE_5 : ; ELSE actions
837
ENDIF_5 : ; end of IF command
847
ld hl, LIT_107 ; parameter
849
call COLOR_BORDER ; action call
850
call COLOR ; action call
851
ld hl, LIT_109 ; parameter
853
call SET_PLAY_VOICE_1 ; action call
854
call DO_PLAY ; action call
855
ld hl, IDF_14 ; parameter
857
ld hl, LIT_111 ; parameter
859
call MATH.ADD ; action call
860
ld hl, IDF_14 ; parameter
862
call LET ; action call
863
ld hl, IDF_12 ; parameter
865
ld hl, LIT_112 ; parameter
867
call MATH.ADD ; action call
868
ld hl, IDF_12 ; parameter
870
call LET ; action call
871
ld hl, LIT_113 ; parameter
873
call COLOR_BORDER ; action call
874
call COLOR ; action call
879
ld hl, LIT_118 ; parameter
881
ld hl, LIT_117 ; parameter
883
ld hl, IDF_20 ; parameter
885
ld hl, IDF_101 ; parameter
887
ld hl, LIT_116 ; parameter
889
call PUT_SPRITE_COLOR ; action call
890
ld hl, LIT_119 ; parameter
892
call SET_PLAY_VOICE_1 ; action call
893
call DO_PLAY ; action call
894
ld hl, IDF_14 ; parameter
896
ld hl, LIT_120 ; parameter
898
call MATH.SUB ; action call
899
ld hl, IDF_14 ; parameter
901
call LET ; action call
904
ld hl, LIT_121 ; parameter
906
ld hl, IDF_20 ; parameter
908
call LET ; action call
909
ld hl, LIT_122 ; parameter
911
call RND ; action call
912
ld hl, LIT_123 ; parameter
914
call MATH.MULT ; action call
915
ld hl, LIT_124 ; parameter
917
call MATH.ADD ; action call
918
call INT ; action call
919
ld hl, IDF_101 ; parameter
921
call LET ; action call
922
IF_6 : ; start of IF command
923
ld hl, IDF_101 ; parameter
925
ld hl, LIT_125 ; parameter
927
call MATH.MOD ; action call
928
ld hl, LIT_127 ; parameter
930
call BOOLEAN.EQ ; action call
931
call BOOLEAN.IF ; verify IF condition result, out in A
933
jp z, ELSE_6 ; if false, jump to ELSE actions
934
THEN_6 : ; THEN actions
935
ld hl, LIT_128 ; parameter
937
ld hl, IDF_22 ; parameter
939
call LET ; action call
940
jp ENDIF_6 ; jump to END of IF command
941
ELSE_6 : ; ELSE actions
942
ld hl, LIT_130 ; parameter
944
ld hl, IDF_22 ; parameter
946
call LET ; action call
947
ENDIF_6 : ; end of IF command
950
ld hl, LIT_136 ; parameter
952
call PSET.COLOR ; action call
953
ld hl, LIT_135 ; parameter
955
ld hl, LIT_134 ; parameter
957
ld hl, LIT_133 ; parameter
959
ld hl, LIT_132 ; parameter
961
call PSET.XY ; action call
962
call FBOX ; action call
965
ld hl, LIT_137 ; parameter
967
call COLOR_FOREGROUND ; action call
968
call COLOR ; action call
969
ld hl, LIT_139 ; parameter
971
ld hl, LIT_138 ; parameter
973
call LOCATE ; action call
974
ld hl, LIT_140 ; parameter
976
call PRINT ; action call
977
ld hl, IDF_12 ; parameter
979
call PRINT ; action call
980
ld hl, LIT_141 ; parameter
982
call PRINT ; action call
983
ld hl, IDF_14 ; parameter
985
call PRINT ; action call
986
ld hl, PRINT.CRLF ; parameter
988
call PRINT ; action call
993
ld hl, LIT_142 ; parameter
995
call SCREEN ; action call
996
ld hl, LIT_144 ; parameter
998
ld hl, LIT_143 ; parameter
1000
call LOCATE ; action call
1001
ld hl, LIT_145 ; parameter
1003
call PRINT ; action call
1004
ld hl, PRINT.CRLF ; parameter
1006
call PRINT ; action call
1009
ld hl, LIT_146 ; parameter
1011
call SET_PLAY_VOICE_1 ; action call
1012
call DO_PLAY ; action call
1015
IF_7 : ; start of IF command
1016
ld hl, LIT_147 ; parameter
1018
call STRIG ; action call
1019
call BOOLEAN.IF ; verify IF condition result, out in A
1021
jp z, ELSE_7 ; if false, jump to ELSE actions
1022
THEN_7 : ; THEN actions
1023
call CLS ; action call
1025
jp ENDIF_7 ; jump to END of IF command
1026
ELSE_7 : ; ELSE actions
1028
ENDIF_7 : ; end of IF command
1031
IF_8 : ; start of IF command
1032
ld hl, IDF_20 ; parameter
1034
ld hl, LIT_150 ; parameter
1036
call BOOLEAN.LT ; action call
1037
call BOOLEAN.IF ; verify IF condition result, out in A
1039
jp z, ELSE_8 ; if false, jump to ELSE actions
1040
THEN_8 : ; THEN actions
1041
ld hl, IDF_20 ; parameter
1043
ld hl, IDF_22 ; parameter
1045
call MATH.ADD ; action call
1046
ld hl, IDF_20 ; parameter
1048
call LET ; action call
1049
jp ENDIF_8 ; jump to END of IF command
1050
ELSE_8 : ; ELSE actions
1051
call TAG_185 ; gosub
1052
ENDIF_8 : ; end of IF command
1058
ld hl, LIT_153 ; parameter
1060
ld hl, IDF_152 ; parameter
1062
call LET ; action call
1063
FOR_2 : ; start of FOR command
1064
ld hl, LIT_154 ; parameter
1066
ld hl, IDF_56 ; parameter
1068
call LET ; action call
1069
jp FOR.WHILE_2 ; jump to test if end of FOR
1070
FOR.STEP_2 : ; STEP action
1071
ld hl, LIT_155 ; parameter
1073
ld hl, IDF_56 ; parameter
1075
call MATH.ADD ; action call
1076
ld hl, IDF_56 ; parameter
1078
call LET ; action call
1079
FOR.WHILE_2 : ; test if end of FOR
1080
ld hl, IDF_56 ; parameter
1082
ld hl, LIT_156 ; parameter
1084
call BOOLEAN.LE ; action call
1085
call BOOLEAN.IF ; verify IF condition result, out in A
1087
jp z, ENDFOR_2 ; end the loop if while condition is false
1088
FOR.BODY_2 : ; start of FOR user code
1089
ld hl, IDF_158 ; parameter
1091
call READ ; action call
1092
ld hl, IDF_152 ; parameter
1094
ld hl, IDF_158 ; parameter
1096
call CHR ; action call
1097
call MATH.ADD ; action call
1098
ld hl, IDF_152 ; parameter
1100
call LET ; action call
1101
jp FOR.STEP_2 ; repeat actions
1102
ENDFOR_2 : ; END of FOR command
1105
ld hl, LIT_161 ; parameter
1107
ld hl, IDF_160 ; parameter
1109
call LET ; action call
1110
FOR_3 : ; start of FOR command
1111
ld hl, LIT_162 ; parameter
1113
ld hl, IDF_56 ; parameter
1115
call LET ; action call
1116
jp FOR.WHILE_3 ; jump to test if end of FOR
1117
FOR.STEP_3 : ; STEP action
1118
ld hl, LIT_163 ; parameter
1120
ld hl, IDF_56 ; parameter
1122
call MATH.ADD ; action call
1123
ld hl, IDF_56 ; parameter
1125
call LET ; action call
1126
FOR.WHILE_3 : ; test if end of FOR
1127
ld hl, IDF_56 ; parameter
1129
ld hl, LIT_164 ; parameter
1131
call BOOLEAN.LE ; action call
1132
call BOOLEAN.IF ; verify IF condition result, out in A
1134
jp z, ENDFOR_3 ; end the loop if while condition is false
1135
FOR.BODY_3 : ; start of FOR user code
1136
ld hl, IDF_158 ; parameter
1138
call READ ; action call
1139
ld hl, IDF_160 ; parameter
1141
ld hl, IDF_158 ; parameter
1143
call CHR ; action call
1144
call MATH.ADD ; action call
1145
ld hl, IDF_160 ; parameter
1147
call LET ; action call
1148
jp FOR.STEP_3 ; repeat actions
1149
ENDFOR_3 : ; END of FOR command
1152
ld hl, IDF_152 ; parameter
1154
ld hl, LIT_166 ; parameter
1156
call SPRITE ; action call
1158
ld hl, IDF_160 ; parameter
1160
ld hl, LIT_167 ; parameter
1162
call SPRITE ; action call
1203
end_pgm: __call_bios BIOS_DSPFNK ; turn on function keys display
1205
ld (BIOS_CLIKSW), a ; enable keyboard click
1206
jp BASIC_READYR ; warm start Basic
1207
ret ; end of the program
1209
;--------------------------------------------------------
1210
; LITERALS / VARIABLES / CONFIGURATIONS
1211
;--------------------------------------------------------
1213
VAR_STACK.START: equ ramArea
1216
;VAR_STACK.END: equ VAR_STACK.START + 0x800 ; 2kb (~200 variables)
1219
VAR_STACK.POINTER: equ VAR_STACK.START
1221
PRINT.CRLF: db 3, 0, 0, 2
1222
dw PRINT.CRLF.DATA, 0, 0, 0
1223
PRINT.CRLF.DATA: db 13,10,0
1225
PRINT.TAB: db 3, 0, 0, 1
1226
dw PRINT.TAB.DATA, 0, 0, 0
1227
PRINT.TAB.DATA: db 09,0
1230
LIT_NULL_DBL: dw 0, 0, 0, 0
1236
LIT_QUOTE_CHAR: db '"'
1239
LIT_TRUE: db 2, 0, 0
1243
LIT_FALSE: db 2, 0, 0
1264
IDF_12: equ VAR_STACK.POINTER + 0
1271
IDF_14: equ VAR_STACK.POINTER + 11
1278
IDF_16: equ VAR_STACK.POINTER + 22
1285
IDF_18: equ VAR_STACK.POINTER + 33
1292
IDF_20: equ VAR_STACK.POINTER + 44
1299
IDF_22: equ VAR_STACK.POINTER + 55
1306
IDF_24: equ VAR_STACK.POINTER + 66
1309
LIT_25: db 3, 0, 0, 17
1310
dw LIT_25_DATA, 0, 0
1312
LIT_25_DATA: db "O4L8EBGBEAO5C#O4A", 0
1323
LIT_33: db 3, 0, 0, 12
1324
dw LIT_33_DATA, 0, 0
1326
LIT_33_DATA: db "CATA-METEORO", 0
1337
LIT_36: db 3, 0, 0, 12
1338
dw LIT_36_DATA, 0, 0
1340
LIT_36_DATA: db "************", 0
1351
LIT_39: db 3, 0, 0, 16
1352
dw LIT_39_DATA, 0, 0
1354
LIT_39_DATA: db "CLUBE MSX - 2019", 0
1381
IDF_56: equ VAR_STACK.POINTER + 77
1396
IDF_63: equ VAR_STACK.POINTER + 88
1491
IDF_101: equ VAR_STACK.POINTER + 99
1518
LIT_109: db 3, 0, 0, 5
1519
dw LIT_109_DATA, 0, 0
1521
LIT_109_DATA: db "L8DC-", 0
1552
LIT_119: db 3, 0, 0, 5
1553
dw LIT_119_DATA, 0, 0
1555
LIT_119_DATA: db "L8C+C", 0
1626
LIT_140: db 3, 0, 0, 7
1627
dw LIT_140_DATA, 0, 0
1629
LIT_140_DATA: db "PLACAR:", 0
1632
LIT_141: db 3, 0, 0, 14
1633
dw LIT_141_DATA, 0, 0
1635
LIT_141_DATA: db " ENERGIA:", 0
1650
LIT_145: db 3, 0, 0, 12
1651
dw LIT_145_DATA, 0, 0
1653
LIT_145_DATA: db "FIM DE JOGO!", 0
1656
LIT_146: db 3, 0, 0, 56
1657
dw LIT_146_DATA, 0, 0
1659
LIT_146_DATA: db "A3R15A4R15A8R15A3R15O5C5O4R15B8R15B5R15A8R15A5R15A8R15A1", 0
1682
IDF_152: equ VAR_STACK.POINTER + 110
1685
LIT_153: db 3, 0, 0, 0
1686
dw LIT_153_DATA, 0, 0
1688
LIT_153_DATA: db "", 0
1703
IDF_158: equ VAR_STACK.POINTER + 121
1706
IDF_160: equ VAR_STACK.POINTER + 132
1709
LIT_161: db 3, 0, 0, 0
1710
dw LIT_161_DATA, 0, 0
1712
LIT_161_DATA: db "", 0
1736
dw 0, &x00011000, 0, 0
1740
dw 0, &x00100100, 0, 0
1744
dw 0, &x01110110, 0, 0
1748
dw 0, &x11011111, 0, 0
1752
dw 0, &x11001111, 0, 0
1756
dw 0, &x01100110, 0, 0
1760
dw 0, &x00110100, 0, 0
1764
dw 0, &x00011000, 0, 0
1768
dw 0, &x10000001, 0, 0
1772
dw 0, &x10000001, 0, 0
1776
dw 0, &x10000001, 0, 0
1780
dw 0, &x11000011, 0, 0
1784
dw 0, &x11000011, 0, 0
1788
dw 0, &x11111111, 0, 0
1792
dw 0, &x11111111, 0, 0
1796
dw 0, &x11000011, 0, 0
1798
AFTER_LAST_VARIABLE: equ VAR_STACK.POINTER + 143
1799
VAR_DUMMY.START: equ AFTER_LAST_VARIABLE ; variable dummy circular queue area
1800
VAR_DUMMY.COUNTER: equ VAR_DUMMY.START ; variable dummy circular queue count
1801
VAR_DUMMY.POINTER: equ VAR_DUMMY.COUNTER + 1 ; pointer to next variable dummy
1802
VAR_DUMMY.DATA: equ VAR_DUMMY.POINTER + 2 ; first variable dummy
1805
VAR_DUMMY.SIZE: equ 8
1806
VAR_DUMMY.LENGTH: equ (11 * VAR_DUMMY.SIZE)
1807
VAR_DUMMY.END: equ VAR_DUMMY.DATA + VAR_DUMMY.LENGTH
1808
VAR_STACK.END: equ VAR_DUMMY.END + 1
1811
;--------------------------------------------------------
1813
;--------------------------------------------------------
1832
DATA_ITEMS_COUNT: equ 16
1835
;--------------------------------------------------------
1836
; MSX BASIC KEYWORDS
1837
;--------------------------------------------------------
1842
; out IX = variable assigned address
1843
pop.parm ; get variable address parameter
1844
push hl ; just to transfer hl to ix
1846
ld a, (ix) ; get variable type
1847
cp 3 ; test if string
1848
jr nz, LET.PARM ; if not a string, it isn't necessary to free memory
1849
ld a, (ix + 3) ; get variable string length
1851
jr z, LET.PARM ; if zero, it isn't necessary to free memory
1852
ld c, (ix + 4) ; get old string address low
1853
ld b, (ix + 5) ; get old string address high
1854
push ix ; save variable address
1855
push bc ; just to transfer bc (old string address) to ix
1857
call memory.free ; free memory
1858
pop ix ; restore variable address
1859
LET.PARM: pop.parm ; get data address parameter (out hl = data address)
1860
ld a, (ix + 2) ; get variable type flag
1861
or a ; cp 0 - test type flag (0=any, 255=fixed)
1862
jr nz, LET.FIXED ; if type flag is fixed, so casting is necessary
1863
LET.ANY: push ix ; just to transfer ix (variable address) to de
1865
ldi ; copy 1 byte from hl (data address) to de (variable address)
1866
inc de ; go to variable data area
1868
inc hl ; go to data data area
1870
ld bc, 8 ; data = 8 bytes
1871
ldir ; copy bc bytes from hl (data address) to de (variable address)
1872
ld a, (ix) ; get variable type
1873
cp 3 ; test if string
1874
ret nz ; if not string, return
1875
jp LET.STRING ; else do string treatment (in ix = variable address)
1876
LET.FIXED: push ix ; save variable destination address
1877
push hl ; save variable source address
1878
ld a, (ix) ; get variable fixed type, and hl has parameter data address
1879
call CAST_TO ; cast data to type (in hl = variable address, a = type to, out hl = casted data address)
1881
pop ix ; restore variable address
1882
ld a, (ix) ; get variable destination type again
1883
cp 3 ; test if string
1884
jr nz, LET.VALUE ; if not string, do value treatment
1885
ld a, (de) ; get variable source type again
1886
cp 3 ; test if string
1887
jr nz, LET.FIX1 ; if not string, get casted string size
1892
ld (ix + 3), a ; source string size
1895
call GET_STR.LENGTH ; get string length (in HL, out B)
1897
ld (ix + 3), b ; set variable length
1898
LET.FIX2: ld (ix + 4), l ; casted data address low
1899
ld (ix + 5), h ; casted data address high
1900
jp LET.STRING ; do string treatment (in ix = variable address)
1901
LET.VALUE: push ix ; just to transfer ix (variable address) to de
1903
inc de ; go to variable data area (and the data from its casted)
1906
ld bc, 8 ; data = 8 bytes
1907
ldir ; copy bc bytes from hl (data address) to de (variable address)
1909
LET.STRING: ld a, (ix + 3) ; string size
1910
or a ; cp 0 - test if null
1911
jr nz, LET.ALLOC ; if not null, allocate new string (in ix = variable address)
1912
ld bc, LIT_NULL_STR ; else, set to a null string literal
1913
ld (ix + 4), c ; variable address low
1914
ld (ix + 5), b ; variable address high
1916
LET.ALLOC: push ix ; save variable address
1917
ld l, (ix + 4) ; source string address low
1918
ld h, (ix + 5) ; source string address high
1919
push hl ; save copy from address
1920
ld c, (ix + 3) ; get variable length
1922
inc bc ; string length have one more byte from zero terminator
1923
push bc ; save variable lenght + 1
1924
call memory.alloc ; in bc = size, out ix = address, nz=OK
1926
push ix ; just to transfer memory address from ix to de
1928
pop bc ; restore bytes to be copied
1929
pop hl ; restore copy from string address
1930
push de ; save copy to address
1931
ldir ; copy bc bytes from hl (data address) to de (variable address)
1936
pop de ; restore copy to address
1937
pop ix ; restore variable address
1938
ld (ix + 4), e ; put memory address low into variable
1939
ld (ix + 5), d ; put memory address high into variable
1940
ret ; variable assigned
1945
pop.parm ; get parameter boolean result in hl
1948
ld a, (ix+5) ; put boolean integer result in a
1954
pop.parm ; get first parameter
1956
call GET_INT.VALUE ; output BC with integer value
1957
ld a, c ; A = screen number (0 to 3)
1959
jr c, SCREEN.1 ; if mode < 9, jump
1960
ld a, 8 ; else, fix to 8
1968
__call_bios BIOS_CHGCLR ; change VDP colors
1974
pop.parm ; get first parameter
1976
call GET_INT.VALUE ; output BC with integer value
1977
ld a, c ; A = pixel color
1978
;call gfxSetForeColor
1979
ld (BIOS_FORCLR), a ; foreground color
1986
pop.parm ; get first parameter
1988
call GET_INT.VALUE ; output BC with integer value
1989
ld a, c ; A = pixel color
1990
;call gfxSetBackColor
1991
ld (BIOS_BAKCLR), a ; foreground color
1997
pop.parm ; get first parameter
1999
call GET_INT.VALUE ; output BC with integer value
2000
ld a, c ; A = pixel color
2001
;call gfxSetBorderColor
2002
ld (BIOS_BDRCLR), a ; border color
2008
call MATH.PARM.POP ; get parameters into DAC/ARG
2009
ld a, (BASIC_VALTYP) ;
2010
cp 2 ; test if integer
2011
jp z, MATH.ADD.INT ;
2012
cp 3 ; test if string
2013
jp z, STRING.CONCAT ;
2014
cp 4 ; test if single
2015
jp z, MATH.ADD.SGL ;
2016
jp MATH.ADD.DBL ; it is a double
2021
xor a ; reset Z flag
2022
__call_bios BIOS_CLS ; clear screen
2028
pop.parm ; get first parameter
2030
call GET_INT.VALUE ; output BC with integer value
2031
pop.parm ; get second parameter
2032
push bc ; save first parameter as integer
2034
call GET_INT.VALUE ; output BC with integer value
2035
inc c ; BASIC has start position on 0,0 instead of 1,1 of BIOS
2036
ld l, c ; set second parameter (L = Y position)
2037
pop bc ; restore first parameter as integer
2038
inc c ; BASIC has start position on 0,0 instead of 1,1 of BIOS
2039
ld h, c ; set first parameter (H = X position)
2040
ld a, (BIOS_SCRMOD) ; 0=40x24 Text Mode, 1=32x24 Text Mode, 2=Graphics Mode, 3=Multicolour Mode
2042
jr nc, LOCATE.G ; jump if graphic screen mode (not a < 2)
2043
LOCATE.T: __call_bios BIOS_POSIT ; H = X, L = Y
2049
ld (BIOS_GRPACX), bc ;
2050
ld (BIOS_GRPACY), de ;
2051
__call_bios BIOS_SCALXY ; BC = X, DE = Y
2052
__call_bios BIOS_MAPXYC ; BC = X, DE = Y
2058
pop.parm ; get first parameter
2065
pop.parm ; get first parameter
2067
call GET_INT.VALUE ; output BC with integer value
2069
__call_bios BIOS_GTTRIG
2071
jp z, BOOLEAN.RET.FALSE ;
2076
; abstract virtual GOTO
2080
__call_basic BASIC_BEEP ; play a beep in the system speaker
2086
pop.parm ; get first parameter
2088
call GET_INT.VALUE ; output BC with integer value
2089
ld a, c ; A = sprite mode (0 to 3)
2096
ld (BASIC_DATPTR), hl ; data items pointer
2098
ld (BASIC_DATLIN), hl ; data items index
2103
; abstract virtual GOSUB
2106
; abstract virtual FOR
2110
call MATH.PARM.POP ; get parameters into DAC/ARG
2111
ld a, (BASIC_VALTYP) ;
2112
cp 2 ; test if integer
2113
jp z, BOOLEAN.LE.INT ;
2114
cp 3 ; test if string
2115
jp z, BOOLEAN.LE.STR ;
2116
cp 4 ; test if single
2117
jp z, BOOLEAN.LE.SGL ;
2118
jp BOOLEAN.LE.DBL ; it is a double
2123
pop.parm ; get first parameter in HL
2125
call GET_INT.VALUE ; put parameter into BC
2126
call COPY_TO.VAR_DUMMY.INT ; create a fake integer variable from BC in HL
2132
pop.parm ; get parameter
2133
call COPY_TO.DAC ; put in DAC
2134
and 12 ; test if single/double
2135
jr nz, RND.1 ; if already double
2136
__call_bios MATH_FRCDBL ; convert DAC to double
2137
RND.1: __call_bios MATH_RND ; put in DAC a new random number from previous DAC parameter
2138
jp MATH.PARM.PUSH ; return a dummy double variable from DAC
2143
call MATH.PARM.POP ; get parameters into DAC/ARG
2144
ld a, (BASIC_VALTYP) ;
2145
cp 2 ; test if integer
2146
jp z, MATH.MULT.INT ;
2147
cp 3 ; test if string
2149
cp 4 ; test if single
2150
jp z, MATH.MULT.SGL ;
2151
jp MATH.MULT.DBL ; it is a double
2161
pop.parm ; get first parameter
2163
call GET_INT.VALUE ; output BC with integer value
2164
ld (BIOS_GRPACX), bc ; X
2165
pop.parm ; get second parameter
2167
call GET_INT.VALUE ; output BC with integer value
2168
ld (BIOS_GRPACY), bc ; Y
2174
pop.parm ; get first parameter
2176
call GET_INT.VALUE ; output BC with integer value
2178
call gfxSetForeColor
2183
; abstract virtual NEXT
2187
pop.parm ; get first parameter
2189
call GET_INT.VALUE ; output BC with integer value
2191
__call_bios BIOS_GTSTCK
2194
call COPY_TO.VAR_DUMMY.INT ; create a fake integer variable from BC in HL
2200
call MATH.PARM.POP ; get parameters into DAC/ARG
2201
ld a, (BASIC_VALTYP) ;
2202
cp 2 ; test if integer
2203
jp z, BOOLEAN.EQ.INT ;
2204
cp 3 ; test if string
2205
jp z, BOOLEAN.EQ.STR ;
2206
cp 4 ; test if single
2207
jp z, BOOLEAN.EQ.SGL ;
2208
jp BOOLEAN.EQ.DBL ; it is a double
2213
call MATH.PARM.POP ; get parameters into DAC/ARG
2214
ld a, (BASIC_VALTYP) ;
2215
cp 2 ; test if integer
2216
jp z, BOOLEAN.LT.INT ;
2217
cp 3 ; test if string
2218
jp z, BOOLEAN.LT.STR ;
2219
cp 4 ; test if single
2220
jp z, BOOLEAN.LT.SGL ;
2221
jp BOOLEAN.LT.DBL ; it is a double
2226
call MATH.PARM.POP ; get parameters into DAC/ARG
2227
ld a, (BASIC_VALTYP) ;
2228
cp 2 ; test if integer
2229
jp z, BOOLEAN.AND.INT ;
2230
jp MATH.ERROR ; it is a double
2235
call MATH.PARM.POP ; get parameters into DAC/ARG
2236
ld a, (BASIC_VALTYP) ;
2237
cp 2 ; test if integer
2238
jp z, BOOLEAN.GT.INT ;
2239
cp 3 ; test if string
2240
jp z, BOOLEAN.GT.STR ;
2241
cp 4 ; test if single
2242
jp z, BOOLEAN.GT.SGL ;
2243
jp BOOLEAN.GT.DBL ; it is a double
2248
call MATH.PARM.POP ; get parameters into DAC/ARG
2249
ld a, (BASIC_VALTYP) ;
2250
cp 2 ; test if integer
2251
jp z, MATH.SUB.INT ;
2252
cp 3 ; test if string
2254
cp 4 ; test if single
2255
jp z, MATH.SUB.SGL ;
2256
jp MATH.SUB.DBL ; it is a double
2261
pop.parm ; get sprite number
2263
call GET_INT.VALUE ; output BC with integer value
2264
ld (GFX_TEMP), bc ; sprite number
2268
call GET_INT.VALUE ; output BC with integer value
2269
ld (GFX_TEMP1), bc ; X
2273
call GET_INT.VALUE ; output BC with integer value
2274
ld (GFX_TEMP2), bc ; Y
2276
pop.parm ; get color
2278
call GET_INT.VALUE ; output BC with integer value
2279
ld (GFX_TEMP3), bc ; color
2289
call gfxSetSpriteColorInt
2306
ld hl, BIOS_TEMP ; voice count
2320
jp BASIC_PLAY_DIRECT
2324
; abstract virtual RETURN
2328
call MATH.PARM.POP.INT ; get parameters as integer into DAC/ARG
2336
pop.parm ; get first parameter
2338
call GET_INT.VALUE ; output BC with integer value
2339
ld (GFX_TEMP1), bc ; dX
2340
pop.parm ; get second parameter
2342
call GET_INT.VALUE ; output BC with integer value
2345
ld bc, (GFX_TEMP1) ; dX
2346
or 1 ; a = 1 (filled box)
2352
pop.parm ; get first parameter (variable to be read)
2353
push hl ; save input variable...
2355
ld hl, (BASIC_DATLIN) ; index of data items
2356
ld de, DATA_ITEMS_COUNT ; count of data items
2357
sbc hl, de ; compare hl >= de
2358
jr z, READ.END ; jump if equal
2359
jr nc, READ.END ; jump if above
2360
pop de ; restore saved input variable to DE
2361
ld ix, (BASIC_DATPTR) ; data items pointer
2364
push.parm ; LET parameter 2 - data as right operand
2365
ex de, hl ; put DE into HL
2366
push.parm ; LET parameter 1 - input variable as left operand
2367
call LET ; put data into variable
2368
ld hl, (BASIC_DATLIN) ; old index of data items
2370
ld (BASIC_DATLIN), hl ; save new index of data items
2371
ld hl, (BASIC_DATPTR) ; old data items pointer
2375
ld (BASIC_DATPTR), hl ; save new data items pointer
2382
pop.parm ; get first parameter
2384
call GET_INT.VALUE ; output BC with integer value
2388
ld bc, 2 ; string size
2389
call memory.alloc ; in bc size, out ix new memory address, nz=OK
2390
jp z, memory.error ;
2401
call COPY_TO.VAR_DUMMY.STR ; create a fake string variable from HL in HL
2407
pop.parm ; get sprite number
2409
call GET_INT.VALUE ; output BC with integer value
2410
ld (GFX_TEMP), bc ; sprite number
2412
pop.parm ; get sprite data
2417
call GET_STR.ADDR ; put string address into hl
2420
ret z ; is string empty?
2423
ld c, a ; string size
2424
ld a, (GFX_TEMP) ; sprite number
2425
call gfxSetSpriteData
2429
ld c, a ; sprite number
2430
call gfxSetSpritePattern
2436
call gfxSetSpriteColorInt
2440
;call gfxSetSpriteXY
2446
; abstract virtual DATA
2449
;--------------------------------------------------------
2450
; INITIALIZE VARIABLES
2451
;--------------------------------------------------------
2456
ld (VAR_DUMMY.COUNTER), a ; max circular queue = 8 dummys
2457
ld hl, VAR_DUMMY.DATA ; start of variable dummy circular queue
2458
ld (VAR_DUMMY.POINTER), hl
2459
ld b, VAR_DUMMY.LENGTH
2464
djnz INITIALIZE_DUMMY.1
2468
ld (BASIC_DATPTR), hl ; next DATA pointer to use by READ command
2470
ld (BASIC_DATLIN), hl ; index of DATA item to use by READ command
2474
INITIALIZE_VARIABLES:
2476
call INITIALIZE_DATA
2477
call INITIALIZE_DUMMY
2481
ld d, 2 ; any = default integer
2482
ld c, 0 ; variable name 1 (variable number)
2483
ld b, 0 ; variable name 2 (type flag=any)
2484
call INIT_VAR ; variable initialize
2486
ld d, 2 ; any = default integer
2487
ld c, 1 ; variable name 1 (variable number)
2488
ld b, 0 ; variable name 2 (type flag=any)
2489
call INIT_VAR ; variable initialize
2491
ld d, 2 ; any = default integer
2492
ld c, 2 ; variable name 1 (variable number)
2493
ld b, 0 ; variable name 2 (type flag=any)
2494
call INIT_VAR ; variable initialize
2496
ld d, 2 ; any = default integer
2497
ld c, 3 ; variable name 1 (variable number)
2498
ld b, 0 ; variable name 2 (type flag=any)
2499
call INIT_VAR ; variable initialize
2501
ld d, 2 ; any = default integer
2502
ld c, 4 ; variable name 1 (variable number)
2503
ld b, 0 ; variable name 2 (type flag=any)
2504
call INIT_VAR ; variable initialize
2506
ld d, 2 ; any = default integer
2507
ld c, 5 ; variable name 1 (variable number)
2508
ld b, 0 ; variable name 2 (type flag=any)
2509
call INIT_VAR ; variable initialize
2512
ld c, 6 ; variable name 1 (variable number)
2513
ld b, 255 ; variable name 2 (type flag=fixed)
2514
call INIT_VAR ; variable initialize
2516
ld d, 2 ; any = default integer
2517
ld c, 7 ; variable name 1 (variable number)
2518
ld b, 0 ; variable name 2 (type flag=any)
2519
call INIT_VAR ; variable initialize
2522
ld c, 8 ; variable name 1 (variable number)
2523
ld b, 255 ; variable name 2 (type flag=fixed)
2524
call INIT_VAR ; variable initialize
2526
ld d, 2 ; any = default integer
2527
ld c, 9 ; variable name 1 (variable number)
2528
ld b, 0 ; variable name 2 (type flag=any)
2529
call INIT_VAR ; variable initialize
2532
ld c, 10 ; variable name 1 (variable number)
2533
ld b, 255 ; variable name 2 (type flag=fixed)
2534
call INIT_VAR ; variable initialize
2536
ld d, 2 ; any = default integer
2537
ld c, 11 ; variable name 1 (variable number)
2538
ld b, 0 ; variable name 2 (type flag=any)
2539
call INIT_VAR ; variable initialize
2542
ld c, 12 ; variable name 1 (variable number)
2543
ld b, 255 ; variable name 2 (type flag=fixed)
2544
call INIT_VAR ; variable initialize
2548
;---------------------------------------------------------------------------------------------------------
2550
;---------------------------------------------------------------------------------------------------------
2552
BIOS_BASIC_SLOT_ENABLE:
2555
__call_bios BIOS_ENASLT ; Select main ROM on page 0 (0000h~3FFFh)
2558
__call_bios BIOS_ENASLT ; Select main ROM on page 1 (4000h~7FFFh)
2561
BIOS_BASIC_SLOT_DISABLE:
2564
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
2568
RUN_TRAPS.1: push hl
2579
; in hl = trap block address (handle trap: sts=5? has handler? ackn, pause, run trap, sts=1? unpause)
2581
ld a, (hl) ; trap status
2582
cp 5 ; trap occured AND trap not paused AND trap enabled ?
2583
ret nz ; return if false
2585
ld e, (hl) ; get trap address
2592
ret z ; return if address zero
2594
call BASIC_TRAP_ACKNW
2595
call BASIC_TRAP_PAUSE
2596
ld hl, TRAP_HANDLER.1
2597
push hl ; next return will be to trap handler
2598
push de ; indirect jump to trap address
2600
TRAP_HANDLER.1: pop hl
2602
cp 1 ; trap enabled?
2604
jp BASIC_TRAP_UNPAUSE
2606
; hl = trap block, de = trap handler
2608
ld (hl), a ; trap block status
2610
ld (hl), e ; trap block handler (pointer)
2617
if defined SET_PLAY_VOICE_1 or defined SET_PLAY_VOICE_2 or defined SET_PLAY_VOICE_3 or defined DO_PLAY
2620
ld (BIOS_TEMP), a ; save voice number
2624
ret nz ; return if not string
2626
ld (BIOS_TEMP2), a ; save string size
2627
push hl ; string address
2628
ld a, (BIOS_TEMP) ; restore voice number
2629
call BIOS_GETVCP ; get PSG voice buffer address (in A = voice number, out HL = address of byte 2)
2631
ld a, (BIOS_TEMP2) ; restore string size
2632
ld (hl), a ; string size
2634
ld (hl), e ; string address
2638
ld D,H ; voice stack
2654
;---------------------------------------------------------------------------------------------------------
2655
; VARIABLES ROUTINES
2656
;---------------------------------------------------------------------------------------------------------
2658
; input hl = variable address
2659
; input bc = variable name
2660
; input d = variable type
2661
INIT_VAR: ld (hl), d ; variable type
2663
ld (hl), c ; variable name 1
2665
ld (hl), b ; variable name 2
2679
CLEAR.VAR.LOOP: inc hl
2680
ld (hl), 0 ; data address/value
2683
; input HL = variable address
2684
; input A = variable output type
2685
; output HL = casted data address
2695
; input HL = variable address
2696
; output HL = variable address
2697
CAST_TO.INT: ;push af
2702
jp z, CAST_STR_TO.INT
2704
jp z, CAST_SGL_TO.INT
2706
jp z, CAST_DBL_TO.INT
2709
; input HL = variable address
2710
; output HL = variable address
2711
CAST_TO.STR: ;push af
2714
jp z, CAST_INT_TO.STR
2718
jp z, CAST_SGL_TO.STR
2720
jp z, CAST_DBL_TO.STR
2723
; input HL = variable address
2724
; output HL = variable address
2725
CAST_TO.SGL: ;push af
2728
jp z, CAST_INT_TO.SGL
2730
jp z, CAST_STR_TO.SGL
2734
jp z, CAST_DBL_TO.SGL
2737
; input HL = variable address
2738
; output HL = variable address
2739
CAST_TO.DBL: ;push af
2742
jp z, CAST_INT_TO.DBL
2744
jp z, CAST_STR_TO.DBL
2746
jp z, CAST_SGL_TO.DBL
2751
CAST_SGL_TO.STR: ; same as CAST_INT_TO.STR
2752
CAST_DBL_TO.STR: ; same as CAST_INT_TO.STR
2753
CAST_INT_TO.STR: call COPY_TO.DAC
2755
__call_bios MATH_FOUT ; convert DAC to string
2758
CAST_INT_TO.SGL: call COPY_TO.DAC
2759
__call_bios MATH_FRCSGL
2762
CAST_INT_TO.DBL: call COPY_TO.DAC
2763
__call_bios MATH_FRCDBL
2766
CAST_SGL_TO.INT: ; same as CAST_DBL_TO.INT
2767
CAST_DBL_TO.INT: call COPY_TO.DAC
2768
__call_bios MATH_FRCINT
2771
CAST_STR_TO.INT: call CAST_STR_TO.VAL ;
2772
__call_bios MATH_FRCINT ;
2775
CAST_STR_TO.SGL: call CAST_STR_TO.VAL ;
2776
__call_bios MATH_FRCSGL ;
2779
CAST_STR_TO.DBL: call CAST_STR_TO.VAL ;
2780
__call_bios MATH_FRCDBL ;
2783
CAST_STR_TO.VAL: call GET_STR.ADDR ;
2785
__call_bios MATH_FIN ; convert string to a value type
2788
GET_INT.VALUE: inc hl ; output BC with integer value
2794
CAST_SGL_TO.DBL: ; same as GET_DBL.ADDR
2795
CAST_DBL_TO.SGL: ; same as GET_DBL.ADDR
2796
GET_INT.ADDR: ; same as GET_DBL.ADDR
2797
GET_SGL.ADDR: ; same as GET_DBL.ADDR
2798
GET_DBL.ADDR: inc hl
2803
GET_STR.ADDR: push hl
2809
; input hl = string address
2810
; output b = string length
2811
GET_STR.LENGTH: ld b, 0
2812
GET_STR.LEN.NEXT: ld a, (hl)
2819
jr z, GET_STR.LEN.ERR
2821
GET_STR.LEN.ERR: ld b, 0
2823
STRING.COMPARE: ld ix, (BASIC_DAC+1) ; string 1
2824
ld iy, (BASIC_ARG+1) ; string 2
2825
STRING.COMPARE.NX: ld a, (ix) ; next char from string 1
2826
cp (iy) ; char s1 = char s2?
2827
jr nz, STRING.COMPARE.NE ; if not equal...
2829
jr z, STRING.COMPARE.F1 ; if string 1 has finished...
2830
ld a, (iy) ; next char from string 2
2832
jr z, STRING.COMPARE.GT ; if s2 has finished, s1 has not finished yet, so s1 is greater than s2
2835
jr STRING.COMPARE.NX ; get next char pair
2836
STRING.COMPARE.F1: ld a, (iy) ; verify if string 2 has finished too
2838
jr z, STRING.COMPARE.EQ ; if s2 has finished, then they are equals
2839
jr STRING.COMPARE.LT ; else, result = s1 is less than s2
2840
STRING.COMPARE.NE: jr c, STRING.COMPARE.GT ; verify if s1 is greater than s2...
2841
STRING.COMPARE.LT: ld a, 1 ; ...else, result = s1 less than s2
2843
STRING.COMPARE.GT: ld a, 0xFF ; result = s1 is greater than s2
2845
STRING.COMPARE.EQ: xor a ; result = s1 is equal to s2
2847
STRING.CONCAT: ld ix, BASIC_DAC ; s1 size
2848
ld a, (BASIC_ARG) ; s2 size
2849
add a, (ix) ; s3 size = s1 size + s2 size
2852
call memory.get_free
2856
inc bc ; add 1 byte to size
2857
call memory.alloc ; in bc size, out ix new memory address, nz=OK
2858
jp z, memory.error ;
2862
ld a, (BASIC_DAC) ; s1 size
2863
ld hl, (BASIC_DAC + 1) ; string 1
2864
call COPY_TO.STR ; copy to new memory
2865
ld a, (BASIC_ARG) ; s2 size
2866
ld hl, (BASIC_ARG + 1) ; string 2
2867
call COPY_TO.STR ; copy to new memory
2869
ld (de), a ; null terminated
2872
call COPY_TO.VAR_DUMMY.STR ;
2873
ret.parm ; WARNING - VERIFY STRING MEMORY LEAKs
2874
STRING.PRINT: ld a, (BIOS_SCRMOD) ; 0=40x24 Text Mode, 1=32x24 Text Mode, 2=Graphics Mode, 3=Multicolour Mode
2876
jr nc, STRING.PRINT.G2 ; jump if graphic screen mode MSX2 (>=5)
2878
jr nc, STRING.PRINT.G1 ; jump if graphic screen mode MSX1 (>=2)
2879
STRING.PRINT.T: ld a, (hl) ; get a char from a string parameter
2880
or a ; cp 0 - is it the string end?
2882
__call_bios BIOS_CHPUT ; put the char (a) into text screen
2884
jr STRING.PRINT.T ; repeat
2885
STRING.PRINT.G1: ld a, (hl) ; get a char from a string parameter
2886
or a ; cp 0 - is it the string end?
2888
__call_bios BIOS_GRPPRT ; put the char (a) into graphical screen
2890
jr STRING.PRINT.G1 ; repeat
2891
STRING.PRINT.G2: ld a, (hl) ; get a char from a string parameter
2892
or a ; cp 0 - is it the string end?
2894
ld ix, BIOS_GRPPRT2 ; put the char (a) into graphical screen
2897
jr STRING.PRINT.G2 ; repeat
2899
; a = string size to copy
2900
; input hl = string from
2901
; input de = string to
2903
ret z ; avoid copy if size = zero
2905
ld c, a ; string size
2906
ldir ; copy bc bytes from hl to de
2908
COPY_TO.BASIC_BUF: ld bc, BASIC_BUF
2909
ld a, (LIT_QUOTE_CHAR)
2912
COPY_BAS_BUF.LOOP: ld a, (hl)
2914
jr z, COPY_BAS_BUF.EXIT
2918
jr COPY_BAS_BUF.LOOP
2919
COPY_BAS_BUF.EXIT: ld a, (LIT_QUOTE_CHAR)
2926
COPY_TO.VAR_DUMMY: ld a, (BASIC_VALTYP) ; create dummy variable from VALTYPE
2928
jr nz, COPY_TO.VAR_DUMMY.DBL
2931
call GET_STR.LENGTH ; get string length
2933
ld a, b ; string length
2935
COPY_TO.VAR_DUMMY.STR: call GET_VAR_DUMMY.ADDR ; create dummy string variable from HL
2936
ld (ix), 3 ; data type string
2938
ld (ix+2), 255 ; var type fixed
2939
ld (ix+3), a ; string length
2940
ld (ix+4), l ; data address low
2941
ld (ix+5), h ; data address high
2942
;call GET_STR.LENGTH ; get string length
2943
;ld (ix+3), b ; string length
2944
push ix ; output var address...
2947
COPY_TO.VAR_DUMMY.INT: call GET_VAR_DUMMY.ADDR ; create dummy integer variable from BC
2948
ld (ix), 2 ; data type string
2959
push ix ; output var address...
2962
COPY_TO.VAR_DUMMY.DBL: call GET_VAR_DUMMY.ADDR ; create dummy value variable from DAC
2963
ld (ix), a ; data type
2968
push ix ; just to copy ix to de
2973
ldir ; copy bc bytes from hl (data address) to de (variable address)
2974
push ix ; output var address...
2978
GET_VAR_DUMMY.ADDR: push af ;
2981
ld ix, (VAR_DUMMY.POINTER) ;
2982
ld a, (VAR_DUMMY.COUNTER) ;
2983
GET_VAR_DUMMY.NEXT: add ix, de ;
2986
jr nz, GET_VAR_DUMMY.EXIT ;
2988
ld ix, VAR_DUMMY.DATA ;
2989
GET_VAR_DUMMY.EXIT: ld (VAR_DUMMY.POINTER), ix ;
2990
ld (VAR_DUMMY.COUNTER), a ;
2991
ld a, (ix) ; get last var dummy type
2992
cp 3 ; is it string?
2993
call z, GET_VAR_DUMMY.FREE ; free string memory
3000
ld l, (ix+4) ; get string data address
3004
call memory.free ; free memory
3010
; input hl = variable address
3011
COPY_TO.DAC: ld de, BASIC_DAC
3012
COPY_TO.DAC.DATA: ld a, (hl)
3013
ld (BASIC_VALTYP), a
3017
ld bc, 8 ; data = 8 bytes
3018
ldir ; copy bc bytes from hl (data address) to de (variable address)
3020
COPY_TO.ARG: ld de, BASIC_ARG ;
3021
jr COPY_TO.DAC.DATA ;
3022
COPY_TO.DAC_ARG: ld hl, BASIC_DAC ;
3024
ld bc, 8 ; data = 8 bytes
3025
ldir ; copy bc bytes from hl (data address) to de (variable address)
3027
COPY_TO.ARG_DAC: ld hl, BASIC_ARG ;
3029
ld bc, 8 ; data = 8 bytes
3030
ldir ; copy bc bytes from hl (data address) to de (variable address)
3032
COPY_TO.DAC_TMP: ld hl, BASIC_DAC ;
3033
ld de, BASIC_SWPTMP ;
3034
ld bc, 8 ; data = 8 bytes
3035
ldir ; copy bc bytes from hl (data address) to de (variable address)
3037
COPY_TO.TMP_DAC: ld hl, BASIC_SWPTMP ;
3039
ld bc, 8 ; data = 8 bytes
3040
ldir ; copy bc bytes from hl (data address) to de (variable address)
3043
exx ; save registers
3046
ld de, BASIC_SWPTMP ;
3047
ldir ; copy bc bytes from hl to de
3051
ldir ; copy bc bytes from hl to de
3053
ld hl, BASIC_SWPTMP ;
3055
ldir ; copy bc bytes from hl to de
3056
exx ; restore registers
3059
CLEAR.DAC: ld de, BASIC_DAC
3060
CLEAR.DAC.DATA: ld hl, BASIC_VALTYP
3063
ld bc, 8 ; data = 8 bytes
3064
ldir ; copy bc bytes from hl (data address) to de (variable address)
3066
CLEAR.ARG: ld de, BASIC_ARG
3072
;---------------------------------------------------------------------------------------------------------
3073
; MATH 16 BITS ROUTINES
3074
;---------------------------------------------------------------------------------------------------------
3076
MATH.PARM.POP: pop af ; get PC from caller stack
3077
ex af, af' ; save PC to temp
3078
pop.parm ; get first parameter
3079
call COPY_TO.ARG ; put HL in ARG (return var type in A)
3080
pop.parm ; get second parameter
3081
ex af, af' ; restore PC from temp
3082
push af ; put again PC from caller in stack
3083
ex af, af' ; restore 1st data type
3084
push af ; save 1st data type
3085
call COPY_TO.DAC ; put HL in DAC (return var type in A)
3086
pop bc ; restore 1st data type (ARG) in B
3087
cp b ; test if data type in A (DAC) = data type in B (ARG)
3088
ret z ; return if is equal data types
3089
MATH.PARM.CAST: push bc ; else cast both to double
3090
and 12 ; test if single/double
3091
jr nz, MATH.PARM.CST1 ; avoid cast if already single/double
3092
__call_bios MATH_FRCDBL ; convert DAC to double
3093
MATH.PARM.CST1: pop af ;
3094
and 12 ; test if single/double
3095
jr nz, MATH.PARM.CST2 ; avoid cast if already single/double
3096
ld (BASIC_VALTYP), a ;
3097
call COPY_TO.DAC_TMP ;
3098
call COPY_TO.ARG_DAC ;
3099
__call_bios MATH_FRCDBL ; convert ARG to double
3100
call COPY_TO.DAC_ARG ;
3101
call COPY_TO.TMP_DAC ;
3102
MATH.PARM.CST2: ld a, 8 ;
3103
ld (BASIC_VALTYP), a ;
3105
MATH.PARM.POP.INT: ; return result in DAC/ARG as integer
3106
pop af ; get PC from caller stack
3107
ex af, af' ; save PC to temp
3108
pop.parm ; get first parameter
3109
ld a, (hl) ; get parameter type
3110
and 2 ; test if integer
3111
jr z, MATH.PARM.POP.I1 ; do cast if not integer
3112
call COPY_TO.ARG ; put HL in ARG (return var type in A)
3113
jr MATH.PARM.POP.I2 ; go to next parameter
3114
MATH.PARM.POP.I1: call COPY_TO.DAC ; put HL in DAC (return var type in A)
3115
__call_bios MATH_FRCINT ; convert DAC to int
3116
call COPY_TO.DAC_ARG ; copy DAC to ARG
3117
MATH.PARM.POP.I2: pop.parm ; get second parameter
3118
call COPY_TO.DAC ; put HL in DAC (return var type in A)
3119
and 2 ; test if integer
3120
jr nz, MATH.PARM.POP.I3 ; avoid cast if already integer
3121
__call_bios MATH_FRCINT ; convert DAC to int
3123
ld (BASIC_VALTYP), a ;
3125
ex af, af' ; restore PC from temp
3126
push af ; put again PC from caller in stack
3128
MATH.PARM.PUSH: call COPY_TO.VAR_DUMMY ;
3131
; output in parm stack
3132
; http://www.z80.info/zip/zaks_book.pdf - page 104
3133
MATH.ADD.INT: ld hl, (BASIC_DAC+2) ;
3134
ld bc, (BASIC_ARG+2) ;
3136
ld (BASIC_DAC+2), hl ;
3139
; output in parm stack
3140
; http://www.z80.info/zip/zaks_book.pdf - page 104
3141
MATH.SUB.INT: ld hl, (BASIC_DAC+2) ;
3142
ld de, (BASIC_ARG+2) ;
3145
ld (BASIC_DAC+2), hl ;
3148
; output in parm stack
3149
MATH.MULT.INT: ld hl, (BASIC_DAC+2) ;
3150
ld bc, (BASIC_ARG+2) ;
3152
ld (BASIC_DAC+2), hl ;
3154
; input HL = multiplicand
3155
; input BC = multiplier
3156
; output HL = result
3157
; http://www.z80.info/zip/zaks_book.pdf - page 131
3158
MATH.MULT.16: ld a, c ; low multiplier
3159
ld c, b ; high multiplier
3161
ld d, h ; multiplicand
3164
MULT16LOOP: srl c ; right shift multiplier high
3165
rra ; rotate right multiplier low
3166
jr nc, MULT16NOADD ; test carry
3167
add hl, de ; add multiplicand to result
3168
MULT16NOADD: ex de, hl
3169
add hl, hl ; double - shift multiplicand
3173
; input AC = dividend
3174
; input DE = divisor
3175
; output AC = quotient
3176
; output HL = remainder
3177
; http://www.z80.info/zip/zaks_book.pdf - page 140
3178
MATH.DIV.16: ld hl, 0 ; clear accumulator
3179
ld b, 16 ; set counter
3180
DIV16LOOP: rl c ; rotate accumulator result left
3182
adc hl, hl ; left shift
3183
sbc hl, de ; trial subtract divisor
3184
jr nc, $ + 3 ; subtract was OK ($ = current location)
3185
add hl, de ; restore accumulator
3186
ccf ; calculate result bit
3187
djnz DIV16LOOP ; counter not zero
3188
rl c ; shift in last result bit
3192
; compare two signed 16 bits integers
3193
; HL < DE: Carry flag
3194
; HL = DE: Zero flag
3195
; http://www.z80.info/zip/zaks_book.pdf - page 531
3196
MATH.COMP.S16: ld a, h ; test high order byte
3197
and 0x80 ; test sign, clear carry
3198
jr nz, MATH.COMP.S16.NEGM1 ; jump if hl is negative
3200
ret nz ; de is negative (and hl is positive)
3202
cp d ; signs are both positive, so normal compare
3204
ld a, l ; test low order byte
3207
MATH.COMP.S16.NEGM1:
3209
rla ; sign bit into carry
3210
ret c ; signs different
3212
cp d ; both signs negative
3218
MATH.ADD.SGL: ld a, 8 ;
3219
ld (BASIC_VALTYP), a ;
3220
MATH.ADD.DBL: __call_bios MATH_DECADD ;
3222
MATH.SUB.SGL: ld a, 8 ;
3223
ld (BASIC_VALTYP), a ;
3224
MATH.SUB.DBL: __call_bios MATH_DECSUB ;
3226
MATH.MULT.SGL: ld a, 8 ;
3227
ld (BASIC_VALTYP), a ;
3228
MATH.MULT.DBL: __call_bios MATH_DECMUL ;
3231
; output in parm stack
3232
MATH.DIV.INT: __call_bios MATH_FRCDBL ; convert DAC to double
3235
ld (BASIC_VALTYP), a ;
3236
__call_bios MATH_FRCDBL ; convert ARG to double
3238
MATH.DIV.SGL: ld a, 8 ;
3239
ld (BASIC_VALTYP), a ;
3240
MATH.DIV.DBL: __call_bios MATH_DECDIV ;
3243
; output in parm stack
3244
MATH.IDIV.SGL: ld a, 8 ;
3245
ld (BASIC_VALTYP), a ;
3246
MATH.IDIV.DBL: __call_bios MATH_FRCINT ; convert DAC to integer
3249
ld (BASIC_VALTYP), a ;
3250
__call_bios MATH_FRCINT ; convert ARG to integer
3252
MATH.IDIV.INT: ld hl, (BASIC_DAC+2) ;
3255
ld de, (BASIC_ARG+2) ;
3259
ld (BASIC_DAC+2), hl ; quotient
3262
MATH.POW.INT: ld (BASIC_VALTYP), a ;
3263
__call_bios MATH_FRCDBL ; convert DAC to double
3266
ld (BASIC_VALTYP), a ;
3267
__call_bios MATH_FRCDBL ; convert ARG to double
3269
MATH.POW.SGL: ld a, 8 ;
3270
ld (BASIC_VALTYP), a ;
3271
MATH.POW.DBL: __call_bios MATH_DBLEXP ;
3274
;MATH.MOD.SGL: ld a, 8 ;
3275
; ld (BASIC_VALTYP), a ;
3276
;MATH.MOD.DBL: __call_bios MATH_FRCINT ; convert DAC to integer
3277
; call SWAP.DAC.ARG ;
3279
; ld (BASIC_VALTYP), a ;
3280
; __call_bios MATH_FRCINT ; convert ARG to integer
3281
; call SWAP.DAC.ARG ;
3282
MATH.MOD.INT: ld hl, (BASIC_DAC+2) ;
3285
ld de, (BASIC_ARG+2) ;
3287
ld (BASIC_DAC+2), hl ; remainder
3290
; fast 16-bit integer square root
3291
; http://www.retroprogramming.com/2017/07/a-fast-z80-integer-square-root.html
3292
; 92 bytes, 344-379 cycles (average 362)
3293
; v2 - 3 t-state optimization spotted by Russ McNulty
3294
; call with hl = number to square root
3295
; returns a = square root
3370
MATH.RANDOMIZE: ld ix, BIOS_JIFFY ;
3375
MATH.SEED: push bc ; in bc = new integer seed
3379
ld (ix+2), c ; copy bc to dac
3381
ld a, 2 ; type integer
3382
ld (BASIC_VALTYP), a ;
3383
__call_bios MATH_FRCDBL ; convert DAC integer to DAC double
3384
__call_bios MATH_NEG ; DAC = -DAC
3385
__call_bios MATH_RND ; put in DAC a new random number from previous DAC parameter
3387
MATH.ERROR: ld e, 13 ; type mismatch
3388
jp BASIC_ERROR_HANDLER ;
3389
;__call_basic BASIC_END ;
3393
;---------------------------------------------------------------------------------------------------------
3395
;---------------------------------------------------------------------------------------------------------
3397
BOOLEAN.RET.TRUE: ld hl, LIT_TRUE ;
3399
BOOLEAN.RET.FALSE: ld hl, LIT_FALSE ;
3401
BOOLEAN.CMP.INT: ld hl, (BASIC_DAC+2) ;
3402
ld de, (BASIC_ARG+2) ;
3403
__call_bios MATH_ICOMP ;
3405
BOOLEAN.CMP.SGL: ld bc, (BASIC_ARG) ;
3406
ld de, (BASIC_ARG+2) ;
3407
__call_bios MATH_DCOMP ;
3409
BOOLEAN.CMP.DBL: __call_bios MATH_XDCOMP ;
3411
BOOLEAN.CMP.STR: call STRING.COMPARE ;
3413
BOOLEAN.GT.INT: call BOOLEAN.CMP.INT ;
3415
BOOLEAN.GT.STR: call BOOLEAN.CMP.STR ;
3417
BOOLEAN.GT.SGL: call BOOLEAN.CMP.SGL ;
3419
BOOLEAN.GT.DBL: call BOOLEAN.CMP.DBL ;
3421
BOOLEAN.GT.RET: cp 0x01 ;
3422
jp z, BOOLEAN.RET.TRUE ;
3423
jp BOOLEAN.RET.FALSE ;
3424
BOOLEAN.LT.INT: call BOOLEAN.CMP.INT ;
3426
BOOLEAN.LT.STR: call BOOLEAN.CMP.STR ;
3428
BOOLEAN.LT.SGL: call BOOLEAN.CMP.SGL ;
3430
BOOLEAN.LT.DBL: call BOOLEAN.CMP.DBL ;
3432
BOOLEAN.LT.RET: cp 0xFF ;
3433
jp z, BOOLEAN.RET.TRUE ;
3434
jp BOOLEAN.RET.FALSE ;
3435
BOOLEAN.GE.INT: call BOOLEAN.CMP.INT ;
3437
BOOLEAN.GE.STR: call BOOLEAN.CMP.STR ;
3439
BOOLEAN.GE.SGL: call BOOLEAN.CMP.SGL ;
3441
BOOLEAN.GE.DBL: call BOOLEAN.CMP.DBL ;
3443
BOOLEAN.GE.RET: cp 0x01 ;
3444
jp z, BOOLEAN.RET.TRUE ;
3446
jp z, BOOLEAN.RET.TRUE ;
3447
jp BOOLEAN.RET.FALSE ;
3448
BOOLEAN.LE.INT: call BOOLEAN.CMP.INT ;
3450
BOOLEAN.LE.STR: call BOOLEAN.CMP.STR ;
3452
BOOLEAN.LE.SGL: call BOOLEAN.CMP.SGL ;
3454
BOOLEAN.LE.DBL: call BOOLEAN.CMP.DBL ;
3456
BOOLEAN.LE.RET: cp 0xFF ;
3457
jp z, BOOLEAN.RET.TRUE ;
3459
jp z, BOOLEAN.RET.TRUE ;
3460
jp BOOLEAN.RET.FALSE ;
3461
BOOLEAN.NE.INT: call BOOLEAN.CMP.INT ;
3463
BOOLEAN.NE.STR: call BOOLEAN.CMP.STR ;
3465
BOOLEAN.NE.SGL: call BOOLEAN.CMP.SGL ;
3467
BOOLEAN.NE.DBL: call BOOLEAN.CMP.DBL ;
3469
BOOLEAN.NE.RET: or a ; cp 0
3470
jp nz, BOOLEAN.RET.TRUE ;
3471
jp BOOLEAN.RET.FALSE ;
3472
BOOLEAN.EQ.INT: call BOOLEAN.CMP.INT ;
3474
BOOLEAN.EQ.STR: call BOOLEAN.CMP.STR ;
3476
BOOLEAN.EQ.SGL: call BOOLEAN.CMP.SGL ;
3478
BOOLEAN.EQ.DBL: call BOOLEAN.CMP.DBL ;
3480
BOOLEAN.EQ.RET: or a ; cp 0
3481
jp z, BOOLEAN.RET.TRUE ;
3482
jp BOOLEAN.RET.FALSE ;
3483
BOOLEAN.AND.INT: ld a, (BASIC_DAC+2) ;
3484
ld hl, BASIC_ARG+2 ;
3486
ld (BASIC_DAC+2), a ;
3488
ld a, (BASIC_DAC+3) ;
3490
ld (BASIC_DAC+3), a ;
3493
BOOLEAN.OR.INT: ld a, (BASIC_DAC+2) ;
3494
ld hl, BASIC_ARG+2 ;
3496
ld (BASIC_DAC+2), a ;
3498
ld a, (BASIC_DAC+3) ;
3500
ld (BASIC_DAC+3), a ;
3503
BOOLEAN.XOR.INT: ld a, (BASIC_DAC+2) ;
3504
ld hl, BASIC_ARG+2 ;
3506
ld (BASIC_DAC+2), a ;
3508
ld a, (BASIC_DAC+3) ;
3510
ld (BASIC_DAC+3), a ;
3513
BOOLEAN.EQV.INT: ld a, (BASIC_DAC+2) ;
3514
ld hl, BASIC_ARG+2 ;
3517
ld (BASIC_DAC+2), a ;
3519
ld a, (BASIC_DAC+3) ;
3522
ld (BASIC_DAC+3), a ;
3525
BOOLEAN.IMP.INT: ld a, (BASIC_DAC+2) ;
3526
ld hl, BASIC_ARG+2 ;
3529
ld (BASIC_DAC+2), a ;
3531
ld a, (BASIC_DAC+3) ;
3534
ld (BASIC_DAC+3), a ;
3537
BOOLEAN.SHR.INT: ld ix, BASIC_DAC+2 ; shift DAC integer to right (bits 15...0-->)
3538
ld a, (BASIC_ARG+2) ;
3540
jp z, MATH.PARM.PUSH ; return if not shift
3541
ld b, a ; shift count
3542
BOOLEAN.SHR.INT.N: rr (ix+1) ;
3545
djnz BOOLEAN.SHR.INT.N ; next shift
3547
jp MATH.PARM.PUSH ; return DAC
3548
BOOLEAN.SHL.INT: ld ix, BASIC_DAC+2 ; shift DAC integer to left (<--bits 15...0)
3549
ld a, (BASIC_ARG+2) ;
3551
jp z, MATH.PARM.PUSH ; return if not shift
3552
ld b, a ; shift count
3553
BOOLEAN.SHL.INT.N: rl (ix) ;
3556
djnz BOOLEAN.SHL.INT.N ; next shift
3558
jp MATH.PARM.PUSH ; return DAC
3559
BOOLEAN.NOT.INT: ld a, (BASIC_DAC+2) ;
3561
ld (BASIC_DAC+2), a ;
3562
ld a, (BASIC_DAC+3) ;
3564
ld (BASIC_DAC+3), a ;
3571
;---------------------------------------------------------------------------------------------------------
3572
; MEMORY ALLOCATION ROUTINES
3573
;---------------------------------------------------------------------------------------------------------
3574
; Adapted from memory allocator code by SamSaga2, Spain, 2015
3575
; https://www.msx.org/forum/msx-talk/development/asm-memory-allocator
3576
; https://www.msx.org/users/samsaga2
3577
;---------------------------------------------------------------------------------------------------------
3579
memory.heap_start: equ VAR_STACK.END + 1 ; start at end of variable stack
3580
memory.heap_end: equ 0xF0A0 - 100 ; end at start of work area for stack (100 bytes reserved), BIOS and BASIC interpreter
3581
block.next: equ 0 ; next free block address
3582
block.size: equ 2 ; size of block including header
3583
block: equ 4 ; block.next + block.size
3587
ld ix,memory.heap_start ; first block
3588
ld hl,memory.heap_start+block ; second block
3589
;; first block NEXT=secondblock, SIZE=0
3590
;; with this block we have a fixed start location
3591
;; because never will be allocated
3592
ld (ix+block.next),l
3593
ld (ix+block.next+1),h
3594
ld (ix+block.size),0
3595
ld (ix+block.size+1),0
3596
;; second block NEXT=0, SIZE=all
3597
;; the first and only free block have all available memory
3598
ld (ix+block.next+block),0
3599
ld (ix+block.next+block+1),0
3601
;ld hl,memory.heap_end ; size = @heap_end (stack) - heap_start - block_header * 2 - 100 (buffer for stack)
3604
ld de, memory.heap_start + (block * 2) + 100
3606
;ld de, block * 2 + 100
3608
ld (ix+block.size+block),l
3609
ld (ix+block.size+block+1),h
3613
;; IN BC=size, OUT IX=memptr, NZ=ok
3619
ld ix,memory.heap_start ; this
3622
ld l,(ix+block.size)
3623
ld h,(ix+block.size+1)
3626
jp z, memory.alloc.exactfit
3627
jp c, memory.alloc.nextblock
3628
;; split found block
3629
memory.alloc.splitfit:
3630
;; free space must allow at least two blocks headers (current + next)
3632
jr nz, memory.alloc.splitfit.do ; if free space > 0xFF, do split
3635
jr c, memory.alloc.nextblock ; if free space < 4, skip to next block
3636
memory.alloc.splitfit.do:
3637
;; newfreeblock = this + BC
3641
;; prevblock->next = newfreeblock
3642
ld (iy+block.next),l
3643
ld (iy+block.next+1),h
3644
;; newfreeblock->next = this->next
3646
pop iy ; iy = newfreeblock
3647
ld l,(ix+block.next)
3648
ld h,(ix+block.next+1)
3649
ld (iy+block.next),l
3650
ld (iy+block.next+1),h
3651
;; newfreeblock->size = this->size - BC
3652
ld l,(ix+block.size)
3653
ld h,(ix+block.size+1)
3656
ld (iy+block.size),l
3657
ld (iy+block.size+1),h
3659
ld (ix+block.size),c
3660
ld (ix+block.size+1),b
3662
;; use whole found block
3663
memory.alloc.exactfit:
3664
;; prevblock->next = this->next - remove block from free list
3665
ld l,(ix+block.next)
3666
ld h,(ix+block.next+1)
3667
ld (iy+block.next),l
3668
ld (iy+block.next+1),h
3677
memory.alloc.nextblock:
3678
ld l,(ix+block.next)
3679
ld h,(ix+block.next+1)
3686
;; this = this->next
3689
jp memory.alloc.find
3694
;; HL = IX - block_header_size
3701
ld ix,memory.heap_start
3703
ld e,(ix+block.next)
3704
ld d,(ix+block.next+1)
3707
jp z, memory.free.passedend
3708
sbc hl,de ; test this (HL) against next (DE)
3709
jr c, memory.free.found ; if DE > HL
3710
add hl,de ; restore hl value
3712
pop ix ; current = next
3715
;; ix=prev, hl=this, de=next
3717
add hl,de ; restore hl value
3718
ld (ix+block.next), l
3719
ld (ix+block.next+1), h ; prev->next = this
3722
ld (iy+block.next), e
3723
ld (iy+block.next+1), d ; this->next = next
3724
push ix ; prev x this
3729
call memory.free.coalesce
3730
pop ix ; this x next
3731
jr memory.free.coalesce
3735
memory.free.coalesce:
3736
ld c, (iy+block.size)
3737
ld b, (iy+block.size+1) ; bc = this->size
3741
adc hl, bc ; hl = this + this->size
3745
sbc hl, de ; if this + this->size == next, then this->size += next->size, this->next = next->next
3746
jr z, memory.free.coalesce.do
3747
push ix ; else, new *this = *next
3750
memory.free.coalesce.do:
3751
ld l, (ix+block.size)
3752
ld h, (ix+block.size+1) ; hl = next->size
3754
adc hl, bc ; hl += this->size
3755
ld (iy+block.size), l
3756
ld (iy+block.size+1), h ; this->size = hl
3757
ld l, (ix+block.next)
3758
ld h, (ix+block.next+1) ; hl = next->next
3759
ld (iy+block.next), l
3760
ld (iy+block.next+1), h ; this->next = hl
3763
memory.free.passedend:
3764
;; append block at the end of the free list
3765
ld (ix+block.next),l
3766
ld (ix+block.next+1),h
3769
ld (iy+block.next),0
3770
ld (iy+block.next+1),0
3776
ld ix,memory.heap_start
3778
memory.get_free.count:
3780
add a,(ix+block.size)
3783
adc a,(ix+block.size+1)
3785
ld l,(ix+block.next)
3786
ld h,(ix+block.next+1)
3792
jr memory.get_free.count
3794
memory.error: ld e, 7 ; out of memory
3795
jp BASIC_ERROR_HANDLER ;
3800
;---------------------------------------------------------------------------------------------------------
3802
; By: Amaury Carvalho, 2019
3803
;---------------------------------------------------------------------------------------------------------
3805
; https://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm#Algorithm_for_integer_arithmetic
3806
; https://en.wikipedia.org/wiki/Midpoint_circle_algorithm
3807
; https://rosettacode.org/wiki/Bitmap/Midpoint_circle_algorithm#C
3808
; https://www.msx.org/wiki/MSX-BASIC_Instructions
3809
;---------------------------------------------------------------------------------------------------------
3811
;---------------------------------------------------------------------------------------------------------
3813
;---------------------------------------------------------------------------------------------------------
3815
BIOS_WRTVDP: EQU 0x0047
3816
BIOS_RDVRM: EQU 0x004A
3817
BIOS_WRTVRM: EQU 0x004D
3818
BIOS_LDIRVM: EQU 0x005C
3819
BIOS_PNTINI: EQU 0x18CF
3820
BIOS_RIGHTC: EQU 0x16C5 ; Move current pixel physical address right
3821
BIOS_TRIGHTC: EQU 0x16AC ; Test then RIGHTC if legal
3822
BIOS_LEFTC: EQU 0x16EE ; Move current pixel physical address left
3823
BIOS_TLEFTC: EQU 0x16D8 ; Test then LEFTC if legal
3824
BIOS_UPC: EQU 0x175D ; Move current pixel physical address up
3825
BIOS_TUPC: EQU 0x173C ; Test then UPC if legal
3826
BIOS_DOWNC: EQU 0x172A ; Move current pixel physical address down
3827
BIOS_TDOWNC: EQU 0x170A ; Test then DOWNC if legal
3828
BIOS_DCOMPR: EQU 0x146A ; compare HL and DE (Flag NC if HL>DE, Flag Z if HL=DE, Flag C if HL<DE)
3830
BIOS_FILVRM: EQU 0x0056 ; fill VRAM with value
3833
BIOS_BIGFIL: EQU 0x016B ; msx 2
3834
BIOS_NRDVRM: EQU 0x0174 ; msx 2
3835
BIOS_NWRVRM: EQU 0x0177 ; msx 2
3836
BIOS_NRDVDP: EQU 0x013E ; msx 2
3837
BIOS_VDPSTA: EQU 0x0131 ; msx 2
3838
BIOS_NWRVDP: EQU 0x012D ; msx 2 (0x0647)
3840
BASIC_SUB_LINE: equ 0x58fc
3841
BASIC_SUB_LINEBOX: equ 0x5912
3842
BASIC_SUB_LINEBOXFILLED: equ 0x58C1
3843
BASIC_SUB_CIRCLE: equ 0x5B19
3844
BASIC_SUB_PAINT1: equ 0x59DA ;0x59C8
3845
BASIC_SUB_PAINT2: equ 0x0069 ;0x2664 ;0x2651+3
3847
;---------------------------------------------------------------------------------------------------------
3849
;---------------------------------------------------------------------------------------------------------
3851
BIOS_RG0SAV: EQU 0xF3DF
3852
BIOS_RG1SAV: EQU 0xF3E0
3853
BIOS_RG8SAV: EQU 0xFFE7
3854
BIOS_BDRATR: EQU 0xFCB2
3855
BIOS_STATFL: EQU 0xF3E7 ; VDP status register
3857
BIOS_CXOFF: EQU 0xF945
3858
BIOS_CYOFF: EQU 0xF947
3859
BIOS_GXPOS: EQU 0xFCB3
3860
BIOS_GYPOS: EQU 0xFCB5
3862
BIOS_ASPECT: equ 0xF931 ;2 Aspect ratio of the circle; set by <ratio> of CIRCLE.
3863
BIOS_CENCNT: equ 0xF933 ;2 Counter used by CIRCLE.
3864
BIOS_CLINEF: equ 0xF935 ;1 Flag to draw line to centre, Used set by CIRCLE
3865
BIOS_CNPNTS: equ 0xF936 ;2 Point to be plottted in a 45° segment, Used set by CIRCLE
3866
BIOS_CPLOTF: equ 0xF938 ;1 Plot polarity flag, Used set by CIRCLE
3867
BIOS_CPCNT: equ 0xF939 ;2 Number of points in 1/8 of circle, Used set by CIRCLE.
3868
BIOS_CPCNT8: equ 0xF93B ;2 Number of points in the circle. Used by CIRCLE.
3869
BIOS_CRCSUM: equ 0xF93D ;2 Cyclic redundancy check sum of the circle. Used by CIRCLE.
3870
BIOS_CSTCNT: equ 0xF93F ;2 Variable to maintain the number of points of the starting angle. Used by the instruction CIRCLE
3871
BIOS_CSCLXY: equ 0xF941 ;1 Scale of X & Y. Used by the instruction CIRCLE
3872
BIOS_ASPCT1: equ 0xF40B ;2 256/aspect ratio for Basic instruction CIRCLE.
3873
BIOS_ASPCT2: equ 0xF40D ;2 256*aspect ratio for Basic instruction CIRCLE.
3874
BIOS_MAXUPD: equ 0xF3EC ;3 Work area used by the instruction CIRCLE, contains JP 0000h at start.
3875
BIOS_MINUPD: equ 0xF3EF ;3 Work area used by the instruction CIRCLE, contains JP 0000h at start.
3877
BIOS_PARM1: EQU 0xF6E8 ; 100
3878
BIOS_PARM2: EQU 0xF750 ; 100
3880
GFX_TEMP: EQU BIOS_PARM1 ; 2
3881
GFX_TEMP1: EQU GFX_TEMP + 2 ; 2
3882
GFX_TEMP2: EQU GFX_TEMP1 + 2 ; 2
3883
GFX_TEMP3: EQU GFX_TEMP2 + 2 ; 2
3884
GFX_TEMP4: EQU GFX_TEMP3 + 2 ; 2
3885
GFX_TEMP5: EQU GFX_TEMP4 + 2 ; 2
3886
GFX_TEMP6: EQU GFX_TEMP5 + 2 ; 2
3887
GFX_TEMP7: EQU GFX_TEMP6 + 2 ; 2
3888
GFX_TEMP8: EQU GFX_TEMP7 + 2 ; 2
3889
GFX_TEMP9: EQU GFX_TEMP8 + 2 ; 2
3891
BIOS_SCR_SIZE_X: dw 240, 256, 256, 64, 256, 256, 512, 512, 256, 512, 256, 256, 256
3892
BIOS_SCR_SIZE_Y: dw 192, 192, 192, 48, 192, 212, 212, 212, 212, 384, 212, 212, 212
3895
;---------------------------------------------------------------------------------------------------------
3896
; gfxIsScreenModeMSX2
3897
; return if screen mode is from MSX 2
3898
; out C is set, if MSX2 and screen mode above 3
3899
;---------------------------------------------------------------------------------------------------------
3901
gfxIsScreenModeMSX2:
3902
ld a, (BIOS_VERSION)
3904
jp nz, BIOS_CHKNEW ; if not MSX1, jump to CHKNEW
3908
;---------------------------------------------------------------------------------------------------------
3910
; set current screen mode
3911
; in A = screen number
3912
;---------------------------------------------------------------------------------------------------------
3916
ld a, (BIOS_VERSION)
3918
jr nz, gfxSetScreenMode.1 ; if not MSX1, jump
3921
call nc, gfxSetScreenMode.0 ; if screen mode >= 4, change to screen 2
3922
__call_bios BIOS_CHGMOD ; change the screen mode (msx1)
3923
jr gfxSetScreenMode.2
3931
ld ix, BIOS_CHGMOD2 ; change the screen mode (msx2)
3935
call gfxGetScreenHeight
3936
jp gfxGetScreenWidth
3938
;---------------------------------------------------------------------------------------------------------
3940
; return current screen mode
3941
; out A = screen number (0=40x24 Text Mode, 1=32x24 Text Mode, 2=Graphics Mode, 3=Multicolour Mode)
3942
;---------------------------------------------------------------------------------------------------------
3948
;---------------------------------------------------------------------------------------------------------
3950
; set current screen location
3953
;---------------------------------------------------------------------------------------------------------
3956
ld (BIOS_GRPACX), bc ; x
3957
;ld (BIOS_GXPOS), bc
3958
ld (BIOS_GRPACY), de ; y
3959
;ld (BIOS_GYPOS), de
3962
;---------------------------------------------------------------------------------------------------------
3964
; refresh current screen location
3965
;---------------------------------------------------------------------------------------------------------
3968
ld bc, (BIOS_GRPACX) ; x
3969
ld de, (BIOS_GRPACY) ; y
3971
call gfxIsScreenModeMSX2
3972
jr nc, gfxRefreshXY.2 ; if MSX2 and screen mode above 3
3973
__call_bios BIOS_SCALXY ; BC = X, DE = Y
3974
__call_bios BIOS_MAPXYC ; in BC = X, DE = Y
3977
ld ix, BIOS_SCALXY2 ; BC = X, DE = Y
3979
ld ix, BIOS_MAPXYC2 ; in BC = X, DE = Y
3982
;---------------------------------------------------------------------------------------------------------
3984
; get current screen location
3987
;---------------------------------------------------------------------------------------------------------
3990
ld bc, (BIOS_GRPACX) ; x
3991
ld de, (BIOS_GRPACY) ; y
3994
;---------------------------------------------------------------------------------------------------------
3995
; gfxGetScreenHeight
3997
; out hl = screen height
3998
;---------------------------------------------------------------------------------------------------------
4004
ld ix, BIOS_SCR_SIZE_Y
4018
;---------------------------------------------------------------------------------------------------------
4021
; out hl = screen width
4022
;---------------------------------------------------------------------------------------------------------
4028
ld ix, BIOS_SCR_SIZE_X
4042
if defined GFX_FAST and defined PAINT
4044
;---------------------------------------------------------------------------------------------------------
4046
; move screen current location up
4047
; out: carry if off screen
4048
;---------------------------------------------------------------------------------------------------------
4053
ld de, (BIOS_GRPACY)
4058
ld (BIOS_GRPACY), de
4069
;---------------------------------------------------------------------------------------------------------
4071
; move screen current location down
4072
; out: carry if off screen
4073
;---------------------------------------------------------------------------------------------------------
4078
ld de, (BIOS_GRPACY)
4083
ld (BIOS_GRPACY), de
4094
;---------------------------------------------------------------------------------------------------------
4096
; move screen current location left
4097
; out: carry if off screen
4098
;---------------------------------------------------------------------------------------------------------
4103
ld de, (BIOS_GRPACX)
4108
ld (BIOS_GRPACX), de
4119
;---------------------------------------------------------------------------------------------------------
4121
; move screen current location right
4122
; out: carry if off screen
4123
;---------------------------------------------------------------------------------------------------------
4128
ld de, (BIOS_GRPACX)
4133
ld (BIOS_GRPACX), de
4146
;---------------------------------------------------------------------------------------------------------
4148
; push current screen location
4149
;---------------------------------------------------------------------------------------------------------
4154
ld iy, (BIOS_GRPACX) ; x
4156
ld iy, (BIOS_GRPACY) ; y
4162
;---------------------------------------------------------------------------------------------------------
4164
; pop current screen location
4167
;---------------------------------------------------------------------------------------------------------
4176
;---------------------------------------------------------------------------------------------------------
4178
; set current foreground color
4180
;---------------------------------------------------------------------------------------------------------
4183
ld (BIOS_FORCLR), a ; foreground color
4187
;---------------------------------------------------------------------------------------------------------
4189
; get current foreground color
4191
;---------------------------------------------------------------------------------------------------------
4194
ld a, (BIOS_FORCLR) ; foreground color
4197
;---------------------------------------------------------------------------------------------------------
4199
; set current background color
4201
;---------------------------------------------------------------------------------------------------------
4204
ld (BIOS_BAKCLR), a ; foreground color
4207
;---------------------------------------------------------------------------------------------------------
4209
; get current background color
4211
;---------------------------------------------------------------------------------------------------------
4214
ld a, (BIOS_BAKCLR) ; foreground color
4217
;---------------------------------------------------------------------------------------------------------
4219
; set current border color
4221
;---------------------------------------------------------------------------------------------------------
4224
ld (BIOS_BDRCLR), a ; border color
4227
;---------------------------------------------------------------------------------------------------------
4229
; get current border color
4231
;---------------------------------------------------------------------------------------------------------
4234
ld a, (BIOS_BDRCLR) ; border color
4237
;---------------------------------------------------------------------------------------------------------
4239
; set fill border color
4241
;---------------------------------------------------------------------------------------------------------
4244
ld (BIOS_BDRATR), a ; border color
4247
;---------------------------------------------------------------------------------------------------------
4249
; get fill border color
4251
;---------------------------------------------------------------------------------------------------------
4254
ld a, (BIOS_BDRATR) ; border color
4257
;---------------------------------------------------------------------------------------------------------
4259
; set current color (foreground, background and border)
4260
;---------------------------------------------------------------------------------------------------------
4265
jp nz, BIOS_CHGCLR2 ; change VDP colors - msx2
4267
jp nz, BIOS_CHGCLR2 ; change VDP colors - msx2
4268
jp BIOS_CHGCLR ; change VDP colors
4269
; __call_bios BIOS_SETATR ; change the pixel color
4272
;---------------------------------------------------------------------------------------------------------
4274
; set pixel in current position to current foreground color
4275
;---------------------------------------------------------------------------------------------------------
4278
call gfxIsScreenModeMSX2
4279
jr nc, gfxSetPixel.1 ; if MSX2 and screen mode above 3
4280
__call_bios BIOS_SETC
4286
;---------------------------------------------------------------------------------------------------------
4288
; get pixel color in current position
4289
; out A = pixel color
4290
;---------------------------------------------------------------------------------------------------------
4293
call gfxIsScreenModeMSX2
4294
jr nc, gfxGetPixel.1 ; if MSX2 and screen mode above 3
4295
__call_bios BIOS_READC
4303
;---------------------------------------------------------------------------------------------------------
4305
; plot a line from current position to informed destination
4306
; in BC = destination x
4307
; DE = destination y
4308
; https://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm#Algorithm_for_integer_arithmetic
4309
; https://rosettacode.org/wiki/Bitmap/Bresenham%27s_line_algorithm#C
4310
;---------------------------------------------------------------------------------------------------------
4311
;void line(int x0, int y0, int x1, int y1) {
4312
; int dx = abs(x1-x0), sx = x0<x1 ? 1 : -1;
4313
; int dy = abs(y1-y0), sy = y0<y1 ? 1 : -1;
4314
; int err = (dx>dy ? dx : -dy)/2, e2;
4317
; if (x0==x1 && y0==y1) break;
4319
; if (e2 >-dx) { err -= dy; x0 += sx; }
4320
; if (e2 < dy) { err += dx; y0 += sy; }
4325
if not defined GFX_FAST
4326
ld hl, (BIOS_GRPACX)
4328
ld hl, (BIOS_GRPACY)
4334
ld (GFX_TEMP2), bc ; x
4335
ld (GFX_TEMP3), de ; y
4337
ld hl, (BIOS_GRPACX) ; x0
4338
ld de, (GFX_TEMP2) ; x
4341
;jp po, gfxLine.1 ; x0 >= x? else jump to endif
4343
jp c, gfxLine.1 ; x0 < x? jump
4346
ld (GFX_TEMP4), hl ; dx = x0 - x
4348
ld (GFX_TEMP5), hl ; sx = -1
4352
ld de, (BIOS_GRPACX) ; x0
4353
ld hl, (GFX_TEMP2) ; x
4356
ld (GFX_TEMP4), hl ; dx = x - x0
4358
ld (GFX_TEMP5), hl ; sx = 1
4361
ld hl, (BIOS_GRPACY) ; y0
4362
ld de, (GFX_TEMP3) ; y
4365
;jp po, gfxLine.3 ; y0 >= y? else, jump to endif
4367
jp c, gfxLine.3 ; y0 < y? jump
4370
ld (GFX_TEMP6), hl ; dy = y0 - y
4372
ld (GFX_TEMP7), hl ; sy = -1
4376
ld de, (BIOS_GRPACY) ; y0
4377
ld hl, (GFX_TEMP3) ; y
4380
ld (GFX_TEMP6), hl ; dy = y - y0
4382
ld (GFX_TEMP7), hl ; sy = 1
4385
ld hl, (GFX_TEMP6) ; dy
4388
jp z, gfxLine.h ; dy = 0?
4390
ld hl, (GFX_TEMP4) ; dx
4393
jp z, gfxLine.v ; dx = 0?
4395
ld de, (GFX_TEMP4) ; dx
4396
ld hl, (GFX_TEMP6) ; dy
4401
ld (GFX_TEMP9), hl ; dxy = dx + dy
4403
ld de, (GFX_TEMP4) ; dx
4404
ld hl, (GFX_TEMP6) ; dy
4407
;jp pe, gfxLine.5 ; dy < dx? else, jump to endif
4409
jp z, gfxLine.5 ; dy = dx? jump
4410
jp nc, gfxLine.5 ; dy > dx? jump
4412
ld de, (GFX_TEMP6) ; dy
4418
ld (GFX_TEMP8), de ; err = -dy / 2
4422
ld hl, (GFX_TEMP4) ; dx
4426
ld (GFX_TEMP8), hl ; err = dx/2
4431
ld hl, (GFX_TEMP9) ; dxy
4434
jp nc, gfxLine.loop.0 ; dxy > 0? jump
4435
;jp z, gfxLine.loop.0 ; dxy = 0? jump
4441
ld de, (GFX_TEMP4) ; dx
4444
ld de, (GFX_TEMP8) ; e2 = err
4448
;jp pe, gfxLine.loop.1 ; if -dx < e2, else jump to endif
4450
jp z, gfxLine.loop.1 ; -dx = e2? jump
4451
jp nc, gfxLine.loop.1 ; -dx > e2? jump
4452
ld hl, (GFX_TEMP8) ; err
4453
ld de, (GFX_TEMP6) ; dy
4456
ld (GFX_TEMP8), hl ; err -= dy
4458
ld hl, (GFX_TEMP9) ; dxy
4460
ld (GFX_TEMP9), hl ; dxy -= 1
4462
ld hl, (BIOS_GRPACX)
4466
ld (BIOS_GRPACX), hl ; x0 += sx
4470
ld de, (GFX_TEMP6) ; dy
4473
;jp pe, gfxLine.loop.2 ; if e2 < dy, else jump to endif
4475
jp z, gfxLine.loop.2 ; e2 = dy? jump
4476
jp nc, gfxLine.loop.2 ; e2 > dy? jump
4477
ld hl, (GFX_TEMP8) ; err
4478
ld de, (GFX_TEMP4) ; dx
4481
ld (GFX_TEMP8), hl ; err += dx
4483
ld hl, (GFX_TEMP9) ; dxy
4485
ld (GFX_TEMP9), hl ; dxy -= 1
4487
ld hl, (BIOS_GRPACY)
4491
ld (BIOS_GRPACY), hl ; y0 += sy
4498
ld a, (GFX_TEMP5) ; sx
4500
jr z, gfxLine.h.1 ; if a is positive
4501
ld hl, (BIOS_GRPACX)
4505
ld (BIOS_GRPACX), hl
4509
__call_bios BIOS_FETCHC
4510
ld hl, (GFX_TEMP4) ; dx
4512
call gfxDrawHorLine ; HL = pixel count
4516
ld a, (GFX_TEMP7) ; sy
4518
jr z, gfxLine.v.1 ; if a is positive
4519
ld hl, (BIOS_GRPACY)
4523
ld (BIOS_GRPACY), hl
4528
ld hl, (GFX_TEMP6) ; dy
4531
jp gfxBox.drawVerLine
4536
if defined BOX or defined FBOX or defined BOX_STEP or defined FBOX_STEP
4538
;---------------------------------------------------------------------------------------------------------
4540
; plot a box from current position to informed destination
4541
; in BC = destination x
4542
; DE = destination y
4543
; A = filled flag (0 = not filled, <>0 = filled)
4544
;---------------------------------------------------------------------------------------------------------
4548
if not defined GFX_FAST
4549
ld hl, (BIOS_GRPACX)
4551
ld hl, (BIOS_GRPACY)
4553
ld hl, BASIC_SUB_LINEBOX
4556
call gfxIsScreenModeMSX2
4558
ld hl, BASIC_SUB_LINEBOXFILLED
4571
call gfxAdjustDestXY
4573
jr nz, gfxBox.filled
4577
call gfxBox.drawHorLine
4579
ld de, (BIOS_GRPACX)
4583
ld (BIOS_GRPACX), hl
4585
call gfxBox.drawVerLine
4587
call gfxBox.drawVerLine
4588
call gfxBox.drawHorLine
4596
ld bc, (BIOS_GRPACX)
4598
call gfxBox.drawHorLine
4600
ld (BIOS_GRPACX), bc
4601
ld bc, (BIOS_GRPACY)
4603
ld (BIOS_GRPACY), bc
4609
jr nz, gfxBox.filled.loop
4621
gfxBox.drawVerLine.loop:
4629
jr nz, gfxBox.drawVerLine.loop
4632
;---------------------------------------------------------------------------------------------------------
4634
; draw a horizontal line
4636
;---------------------------------------------------------------------------------------------------------
4641
jr c, gfxDrawHorLine.2 ; if screen mode < 5 then jump
4643
ret nz ; return if negative
4646
jr nz, gfxDrawHorLine.1
4648
ret z ; return if hl = 0
4657
jr nz, gfxDrawHorLine.1
4661
__call_bios BIOS_NSETCX ; HL = fill count
4664
;---------------------------------------------------------------------------------------------------------
4666
; invert if dest XY is less than current XY position
4669
;---------------------------------------------------------------------------------------------------------
4673
ld (GFX_TEMP2), bc ; x
4674
ld (GFX_TEMP3), de ; y
4676
; verify x againt current position
4677
ld hl, (BIOS_GRPACX)
4680
sbc hl, de ; dx = x1 - x0
4681
bit 7, h ; result is negative?
4682
jr z, gfxAdjustDestXY.1
4684
ld (BIOS_GRPACX), hl
4692
; verify y againt current position
4693
ld hl, (BIOS_GRPACY)
4696
sbc hl, de ; dy = y1 - y0
4697
bit 7, h ; result is negative?
4698
jr z, gfxAdjustDestXY.2
4700
ld (BIOS_GRPACY), hl
4708
; refresh new position
4718
;---------------------------------------------------------------------------------------------------------
4720
; plot a circle centered in current position
4721
; BC = tracing end x
4722
; DE = tracing end y
4724
; A = filled flag (0 = not filled, <>0 = filled)
4725
; https://en.wikipedia.org/wiki/Midpoint_circle_algorithm
4726
; https://rosettacode.org/wiki/Bitmap/Midpoint_circle_algorithm#C
4727
;---------------------------------------------------------------------------------------------------------
4731
if not defined GFX_FAST
4733
ret nz ; return if negative radius
4734
ld (BIOS_GXPOS), hl ; circle ray
4736
ld bc, (BIOS_GRPACY)
4740
;jr nz, gfxDrawCircle.1
4749
ld (GFX_TEMP), hl ; radius
4752
ret z ; return if zero radius
4754
ret nz ; return if negative radius
4757
ld (GFX_TEMP1), bc ; x0
4758
ld (GFX_TEMP2), de ; y0
4761
jp nz, gfxCircle.filled
4763
gfxCircle.notFilled:
4765
ld de, (GFX_TEMP) ; radius
4768
ld (GFX_TEMP3), hl ; f = 1 - radius
4771
ld (GFX_TEMP4), hl ; ddF_x = 0
4780
ld (GFX_TEMP5), hl ; ddF_y = -2 * radius
4783
ld (GFX_TEMP6), hl ; x = 0
4786
ld (GFX_TEMP7), hl ; y = radius
4788
; plot(x0, y0 + radius)
4789
ld de, (GFX_TEMP) ; radius
4790
ld hl, (GFX_TEMP2) ; y0
4794
ld bc, (GFX_TEMP1) ; x0
4798
; plot(x0, y0 - radius)
4799
ld de, (GFX_TEMP) ; radius
4800
ld hl, (GFX_TEMP2) ; y0
4804
ld bc, (GFX_TEMP1) ; x0
4808
; plot(x0 + radius, y0)
4809
ld hl, (GFX_TEMP1) ; x0
4810
ld de, (GFX_TEMP) ; radius
4815
ld de, (GFX_TEMP2) ; y0
4819
; plot(x0 - radius, y0)
4820
ld hl, (GFX_TEMP1) ; x0
4821
ld de, (GFX_TEMP) ; radius
4826
ld de, (GFX_TEMP2) ; y0
4829
jp gfxCircle.notFilled.3
4831
gfxCircle.notFilled.1:
4832
ld hl, (GFX_TEMP3) ; f
4834
jr nz, gfxCircle.notFilled.2 ; if( f < 0 ), jump
4836
ld hl, (GFX_TEMP7) ; y -= 1
4840
ld hl, (GFX_TEMP5) ; ddF_y += 2
4845
ld hl, (GFX_TEMP3) ; f
4846
ld de, (GFX_TEMP5) ; ddF_y
4849
ld (GFX_TEMP3), hl ; f += ddF_y
4851
gfxCircle.notFilled.2:
4852
ld hl, (GFX_TEMP6) ; x
4854
ld (GFX_TEMP6), hl ; x++
4856
ld hl, (GFX_TEMP4) ; ddF_x += 2
4861
ld hl, (GFX_TEMP3) ; f
4862
ld de, (GFX_TEMP4) ; ddF_x
4866
ld (GFX_TEMP3), hl ; f += ddF_x + 1
4868
; plot(x0 + x, y0 + y)
4869
ld hl, (GFX_TEMP1) ; x0
4870
ld de, (GFX_TEMP6) ; x
4875
ld hl, (GFX_TEMP2) ; y0
4876
ld de, (GFX_TEMP7) ; y
4883
; plot(x0 - x, y0 + y)
4884
ld hl, (GFX_TEMP1) ; x0
4885
ld de, (GFX_TEMP6) ; x
4890
ld hl, (GFX_TEMP2) ; y0
4891
ld de, (GFX_TEMP7) ; y
4898
; plot(x0 + x, y0 - y)
4899
ld hl, (GFX_TEMP1) ; x0
4900
ld de, (GFX_TEMP6) ; x
4905
ld hl, (GFX_TEMP2) ; y0
4906
ld de, (GFX_TEMP7) ; y
4913
; plot(x0 - x, y0 - y)
4914
ld hl, (GFX_TEMP1) ; x0
4915
ld de, (GFX_TEMP6) ; x
4920
ld hl, (GFX_TEMP2) ; y0
4921
ld de, (GFX_TEMP7) ; y
4928
; plot(x0 + y, y0 + x)
4929
ld hl, (GFX_TEMP1) ; x0
4930
ld de, (GFX_TEMP7) ; y
4935
ld hl, (GFX_TEMP2) ; y0
4936
ld de, (GFX_TEMP6) ; x
4943
; plot(x0 - y, y0 + x)
4944
ld hl, (GFX_TEMP1) ; x0
4945
ld de, (GFX_TEMP7) ; y
4950
ld hl, (GFX_TEMP2) ; y0
4951
ld de, (GFX_TEMP6) ; x
4958
; plot(x0 + y, y0 - x)
4959
ld hl, (GFX_TEMP1) ; x0
4960
ld de, (GFX_TEMP7) ; y
4965
ld hl, (GFX_TEMP2) ; y0
4966
ld de, (GFX_TEMP6) ; x
4973
; plot(x0 - y, y0 - x)
4974
ld hl, (GFX_TEMP1) ; x0
4975
ld de, (GFX_TEMP7) ; y
4980
ld hl, (GFX_TEMP2) ; y0
4981
ld de, (GFX_TEMP6) ; x
4988
gfxCircle.notFilled.3:
4989
ld hl, (GFX_TEMP6) ; x
4990
ld de, (GFX_TEMP7) ; y
4993
jp c, gfxCircle.notFilled.1 ; while( x < y )
4994
ld bc, (GFX_TEMP1) ; x0
4995
ld de, (GFX_TEMP2) ; y0
5000
call gfxCircle.notFilled
5001
ld hl, (BIOS_BDRATR)
5003
ld hl, (BIOS_FORCLR)
5004
ld (BIOS_BDRATR), hl
5008
ld (BIOS_BDRATR), hl
5014
if defined PAINT or (defined CIRCLE and defined GFX_FAST)
5016
;---------------------------------------------------------------------------------------------------------
5018
; Fill current region delimited by border attribute color changing pixels to foreground color
5019
; in: a = fill type (0 = not symmetric, 1 = symmetric)
5020
;---------------------------------------------------------------------------------------------------------
5024
if not defined GFX_FAST
5026
ld bc, (BIOS_GRPACX)
5028
ld de, (BIOS_GRPACY)
5046
call gfxIsScreenModeMSX2
5047
jr nc, gfxBorderFill.1 ; if MSX2 and screen mode above 3, jump
5055
;ld ix, BASIC_SUB_PAINT2
5061
ld hl, (BIOS_GRPACY)
5063
call gfxBorderFill.down
5066
ld (BIOS_GRPACY), hl
5068
call gfxBorderFill.up
5070
ld (BIOS_GRPACY), hl
5075
call gfxBorderFill.line
5081
jr nz, gfxBorderFill.down
5085
call gfxBorderFill.line
5091
jr nz, gfxBorderFill.up
5095
ld de, (BIOS_GRPACX)
5098
ld de, 1 ; skip count
5099
__call_bios BIOS_SCANR
5101
;ld (GFX_TEMP2), hl ; pixel count transversed
5104
ld (BIOS_GRPACX), de
5107
;cp 0 ; 0 = not symmetric, 1 = symmetric
5108
;jr z, gfxBorderFill.line.1
5110
;__call_bios BIOS_NSETCX ; HL = fill count
5111
;jr gfxBorderFill.line.2
5112
gfxBorderFill.line.1:
5114
ld de, 0 ; skip count
5115
__call_bios BIOS_SCANL
5116
gfxBorderFill.line.2:
5118
ld (BIOS_GRPACX), de
5122
;---------------------------------------------------------------------------------------------------------
5124
; Fload fill current region changing current pixel color to foreground color
5125
; https://en.wikipedia.org/wiki/Flood_fill
5126
;---------------------------------------------------------------------------------------------------------
5130
ld (GFX_TEMP), a ; replacement-color
5131
call gfxFloadFill.recursive
5134
gfxFloadFill.recursive:
5135
; 1. If target-color is equal to replacement-color, return.
5141
; 2. ElseIf the color of node is not equal to target-color, return.
5147
; 3. Else Set the color of node to replacement-color.
5150
; 4. Perform Flood-fill (one step to the left of node, target-color, replacement-color).
5151
gfxFloadFill.recursive.left:
5153
jr c, gfxFloadFill.recursive.right
5154
call gfxFloadFill.recursive
5157
; Perform Flood-fill (one step to the right of node, target-color, replacement-color).
5158
gfxFloadFill.recursive.right:
5160
jr c, gfxFloadFill.recursive.up
5161
call gfxFloadFill.recursive
5164
; Perform Flood-fill (one step to the up of node, target-color, replacement-color).
5165
gfxFloadFill.recursive.up:
5167
jr c, gfxFloadFill.recursive.down
5168
call gfxFloadFill.recursive
5171
; Perform Flood-fill (one step to the down of node, target-color, replacement-color).
5172
gfxFloadFill.recursive.down:
5175
call gfxFloadFill.recursive
5183
if defined SPRITEMODE
5185
;---------------------------------------------------------------------------------------------------------
5187
; set current sprite mode
5189
; 0: Spritesize is 8 by 8 pixels - default value
5190
; 1: Spritesize is 8 by 8 pixels, magnified to 16 by 16 pixels
5191
; 2: Spritesize is 16 by 16 pixels
5192
; 3: Spritesize is 16 by 16 pixels, magnified to 32 by 32 pixels
5193
; RG1SAV bit 0 = magnify sprite (double size)
5194
; RG1SAV bit 1 = sprite size (0=8 pixels, 1=16 pixels)
5195
;---------------------------------------------------------------------------------------------------------
5199
and 3 ; keeps only bits 0 and 1 from A
5202
ld a, (BIOS_RG1SAV) ; get copy from register #1 of VDP
5203
and 0xFC ; clear bits 0 and 1 from A
5204
or b ; put parameter to A (bits 0 and 1)
5205
ld (BIOS_RG1SAV), a ; restore to register #1 of VDP
5206
ld b, a ; value to write
5207
ld c, 1 ; register number to write
5208
call gfxWRTVDP ; write register to VDP
5209
call gfxCLRSPR ; clear sprites
5218
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
5220
;---------------------------------------------------------------------------------------------------------
5221
; gfxSetSpriteColorInt
5224
;---------------------------------------------------------------------------------------------------------
5226
gfxSetSpriteColorInt:
5227
ld b, a ; save sprite number
5229
call gfxCALATR ; get sprite attribute table address
5239
ret c ; if screen mode < 3, do not adjust sprite multicolor
5241
ld a, b ; recover sprite number
5242
call gfxGetSpriteColorTable
5245
ld b, 16 ; array of 16 bytes
5247
gfxSetSpriteColorInt.1:
5254
djnz gfxSetSpriteColorInt.1
5257
;---------------------------------------------------------------------------------------------------------
5258
; gfxSetSpriteColorStr
5260
; DE = address to color byte array
5261
; BC = color byte array size
5262
;---------------------------------------------------------------------------------------------------------
5264
gfxSetSpriteColorStr:
5265
ld b, a ; save sprite number
5269
call gfxCALATR ; get sprite attribute table
5274
ld a, c ; byte array zero length?
5286
ret c ; if screen mode < 3, do not adjust sprite mode 2
5288
ld a, b ; recover sprite number
5289
call gfxGetSpriteColorTable
5291
ld b, 16 ; array of 16 bytes (color table)
5292
ld a, c ; size of color array
5294
pop iy ; save array start
5296
gfxSetSpriteColorStr.1:
5304
jr nz, gfxSetSpriteColorStr.2
5305
ld a, c ; recover array size
5307
pop de ; recover array start
5309
gfxSetSpriteColorStr.2:
5310
djnz gfxSetSpriteColorStr.1
5315
;---------------------------------------------------------------------------------------------------------
5316
; gfxGetSpriteColorTable
5318
; HL = address to color table
5319
;---------------------------------------------------------------------------------------------------------
5321
gfxGetSpriteColorTable:
5325
ld l, a ; recover sprite number
5329
add hl, hl ; multiply by 16 (shift left 4)
5333
call gfxCALATR ; get sprite attribute table address
5339
sbc hl, de ; address of color table from sprite multicolor
5346
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
5348
;---------------------------------------------------------------------------------------------------------
5352
;---------------------------------------------------------------------------------------------------------
5358
call gfxCALATR ; get sprite attribute table address
5371
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
5373
;---------------------------------------------------------------------------------------------------------
5374
; gfxSetSpritePattern
5376
; BC = pattern number
5377
;---------------------------------------------------------------------------------------------------------
5381
gfxSetSpritePattern:
5383
call gfxCALATR ; get sprite attribute table address
5387
ld a, c ; pattern number
5397
;---------------------------------------------------------------------------------------------------------
5399
; HL = point to sprite data as a string of 8 or 32 characters according the sprites size (8x8 or 16x16)
5401
;---------------------------------------------------------------------------------------------------------
5408
call gfxCALPAT ; get sprite pattern data address
5410
call gfxGSPSIZ ; return in 'a' sprite default size
5414
jr z, gfxSetSpriteData.1
5415
jr nc, gfxSetSpriteData.1
5431
if defined GFX_SPRITES
5433
;---------------------------------------------------------------------------------------------------------
5435
; initialises all sprites
5436
;---------------------------------------------------------------------------------------------------------
5444
;---------------------------------------------------------------------------------------------------------
5446
; set sprite default x, y, pattern and color
5448
;---------------------------------------------------------------------------------------------------------
5455
ld a, (BIOS_GRPACY) ; y
5458
ld a, (BIOS_GRPACX) ; x
5464
ld a, (BIOS_FORCLR) ; color
5470
;---------------------------------------------------------------------------------------------------------
5471
; VDP / VRAM support routines
5472
;---------------------------------------------------------------------------------------------------------
5476
; c = register number
5477
; a = register number
5480
ret nz ; is negative? read only
5482
ret z ; is register 8? then status register 0 (read only)
5483
jr nc, gfxWRTVDP.1 ; is > 8? then control registers numbers added 1
5498
;jp nz, BIOS_NWRVDP ; msx 2
5500
;jp nz, BIOS_NWRVDP ; msx 2
5501
jp BIOS_WRTVDP ; msx 1
5504
; in a = register number
5508
jr nz, gfxRDVDP.1 ; is negative? then status register 1 to 9
5510
jr z, gfxRDVDP.2 ; is register 8? then status register 0
5512
jr nc, gfxRDVDP.3 ; is >= 9? then control registers numbers added 1
5513
ld hl, BIOS_RG0SAV ; else is correct control registers numbers
5525
jp BIOS_NRDVDP ;BIOS_VDPSTA
5532
ld hl, BIOS_RG8SAV-9
5615
;---------------------------------------------------------------------------------------------------------
5617
;---------------------------------------------------------------------------------------------------------
5626
RET_MATH_LIB: call COPY_TO.TMP_DAC
5630
MATH_DECADD: ld ix, addSingle
5633
MATH_DECSUB: ld ix, subSingle
5636
MATH_DECMUL: ld ix, mulSingle
5639
MATH_DECDIV: ld ix, divSingle
5644
MATH_SNGEXP: ld ix, powSingle
5649
MATH_COS: ld ix, cosSingle
5654
MATH_SIN: ld ix, sinSingle
5659
MATH_TAN: ld ix, tanSingle
5664
MATH_ATN: ld ix, atanSingle
5669
MATH_SQR: ld ix, sqrtSingle
5674
MATH_LOG: ld ix, lnSingle
5679
MATH_EXP: ld ix, expSingle
5683
MATH_ABSFN: ld ix, absSingle
5686
MATH_NEG: ld ix, negSingle
5689
MATH_SGN: ld ix, sgnSingle
5692
MATH_RND: ld ix, randSingle
5695
MATH_FRCINT: ld hl, BASIC_DAC
5708
ld (BASIC_VALTYP), a
5711
MATH_FRCDBL: ; same as MATH_FRCSGL
5712
MATH_FRCSGL: ld hl, BASIC_DAC+2 ; input address
5713
ld bc, BASIC_DAC ; output address
5716
ld (BASIC_VALTYP), a
5719
MATH_ICOMP: ld a, h ; cp hl, de (or use bios DCOMPR)
5721
jr nz, MATH_ICOMP.NE
5724
jr nz, MATH_ICOMP.NE
5726
MATH_ICOMP.NE: jr c, MATH_DCOMP.GT
5729
MATH_XDCOMP: ; same as MATH_DCOMP
5730
MATH_DCOMP: ld ix, cmpSingle
5734
MATH_DCOMP.GT: ld a, 0xFF ; DAC > ARG
5736
MATH_DCOMP.EQ: ld a, 0 ; DAC = ARG
5738
MATH_DCOMP.LT: ld a, 1 ; DAC < ARG
5742
MATH_FIN: ; HL has the source string
5743
ld a, (BASIC_VALTYP)
5744
cp 2 ; test if integer
5746
ld hl, (BASIC_DAC+2)
5751
MATH_FIN.1: ld BC, BASIC_DAC
5755
MATH_FOUT: ld a, (BASIC_VALTYP)
5756
cp 2 ; test if integer
5758
ld hl, (BASIC_DAC+2)
5763
MATH_FOUT.1: ld hl, BASIC_DAC
5772
;---------------------------------------------------------------------------------------------------------
5774
; Copyright 2018 Zeda A.K. Thomas
5775
;---------------------------------------------------------------------------------------------------------
5777
; https://github.com/Zeda/z80float
5778
; https://www.omnimaga.org/asm-language/(z80)-floating-point-routines/
5779
; https://en.wikipedia.org/wiki/Single-precision_floating-point_format
5780
;---------------------------------------------------------------------------------------------------------
5782
; HL points to the first operand
5783
; DE points to the second operand (if needed)
5784
; IX points to the third operand (if needed, rare)
5785
; BC points to where the result should be output
5786
; Floats are stored by a little-endian 24-bit mantissa. However, the highest bit
5787
; is taken as implicitly 1, so we replace it as a sign bit. Next comes an 8-bit
5788
; exponent biased by +128.
5789
;---------------------------------------------------------------------------------------------------------
5790
; Adapted to MSXBas2Asm by Amaury Carvalho, 2019
5791
;---------------------------------------------------------------------------------------------------------
5793
;---------------------------------------------------------------------------------------------------------
5795
;---------------------------------------------------------------------------------------------------------
5797
BASIC_HOLD8: equ 0xF806 ; 48 Work area for decimal multiplications.
5798
BASIC_HOLD2: equ 0xF836 ; 8 Work area in the execution of numerical operators.
5799
BASIC_HOLD: equ 0xF83E ; 8 Work area in the execution of numerical operators.
5800
scrap: equ BASIC_HOLD8
5801
seed0: equ BASIC_RNDX
5802
seed1: equ seed0 + 4
5803
var48: equ scrap + 4
5806
addend2: equ scrap+7 ;4 bytes
5807
var_x: equ BASIC_HOLD8 + 4 ;4 bytes
5808
var_y: equ var_x + 4 ;4 bytes
5809
var_z: equ var_y + 4 ;4 bytes
5810
var_a: equ var_z + 4 ;4 bytes
5811
var_b: equ var_a + 4 ;4 bytes
5812
var_c: equ var_b + 4 ;4 bytes
5813
temp: equ var_c + 4 ;4 bytes
5814
temp1: equ temp + 4 ;4 bytes
5815
temp2: equ temp1 + 4 ;4 bytes
5816
temp3: equ temp2 + 4 ;4 bytes
5818
pow10exp_single: equ scrap+9
5819
strout_single: equ 0xF750 ; PARM2 - BASIC_BUF ;pow10exp_single+2
5821
;---------------------------------------------------------------------------------------------------------
5823
;---------------------------------------------------------------------------------------------------------
5825
;;Still need to tend to special cases
5893
pop hl ;bigger float
6025
;;Need to adjust sign flag
6048
;;How many push/pops are needed?
6056
;;How many push/pops are needed?
6062
;;How many push/pops are needed?
6063
;;Return bigger number
6070
;---------------------------------------------------------------------------------------------------------
6072
;---------------------------------------------------------------------------------------------------------
6095
jp addInject ;jumps in to the addSingle routine
6097
;---------------------------------------------------------------------------------------------------------
6099
;---------------------------------------------------------------------------------------------------------
6102
;Inputs: HL points to float1, DE points to float2, BC points to where the result is copied
6103
;Outputs: float1*float2 is stored to (BC)
6104
;573+mul24+{0,35}+{0,30}
6107
;avg: 2055.13839751681cc
6133
;;return float in CHLB
6143
jr z,mulSingle_case0
6155
;jr z,mulSingle_case1
6159
jp z,mulSingle_case1
6164
rra ; |Lots of help from Runer112 and
6165
adc a,a ; |calc84maniac for optimizing
6166
jp po,bad ; |this exponent check.
6175
call mul24 ;BDE*CHL->HLBCDE, returns sign info
6232
;special*x = special
6253
;basically, if b|c has bit 5 set, return NaN
6286
;;avg :1464.9033203125cc (1464+925/1024)
6289
;avg: 1449.63839751681cc
6330
;---------------------------------------------------------------------------------------------------------
6332
;---------------------------------------------------------------------------------------------------------
6335
;;HL points to numerator
6336
;;DE points to denominator
6337
;;BC points to where the quotient gets written
6339
divSingle_no_pushpop:
6345
xor (hl) ; |Get sign of output
6352
ex de,hl ; |Get exponent
6459
call divsub1 ;34 or 66
6477
;34cc or 66cc or 93cc
6492
;---------------------------------------------------------------------------------------------------------
6494
; https://www.geeksforgeeks.org/write-a-c-program-to-calculate-powxn/
6495
; https://stackoverflow.com/questions/3518973/floating-point-exponentiation-without-power-function
6496
;---------------------------------------------------------------------------------------------------------
6497
;double mypow( double base, double power, double precision )
6499
; if ( power < 0 ) return 1 / mypow( base, -power, precision );
6500
; else if ( power >= 1 ) return base * mypow( base, power-1, precision );
6501
; else if ( precision >= 1 ) {
6502
; if( base >= 0 ) return sqrt( base );
6503
; else return sqrt( -base );
6504
; } else return sqrt( mypow( base, power*2, precision*2 ) );
6507
if defined MATH.POW or defined MATH_EXP or defined MATH_LOG or defined MATH_LN
6513
;;BC points to output
6517
ld bc, var_y ; power
6522
ld hl, const_precision
6523
ld bc, var_a ; precision
6526
ld bc, var_z ; result
6535
; if ( power < 0 ) return 1 / mypow( base, -power, precision );
6541
; else if ( power >= 1 ) return base * mypow( base, power-1, precision );
6547
; else if ( precision >= 1 ) {
6548
; if( base >= 0 ) return sqrt( base );
6549
; else return sqrt( -base );
6555
; } else return sqrt( mypow( base, power*2, precision*2 ) );
6580
; return 1 / mypow( base, -power, precision );
6599
; return base * mypow( base, power-1, precision );
6618
; if( base >= 0 ) return sqrt( base );
6619
; else return sqrt( -base );
6645
; 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)))))
6646
;Please note that usually I like to reduce to [-.5,.5] as the extra overhead is usually worth it.
6647
;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.
6650
;x-=int(x) ;leaves x in [0,1)
6652
;;if x==inf -> out==inf
6653
;;if x==-inf -> out==0
6654
;;if x==NAN -> out==NAN
6661
push af ;keep track of sign
6671
jr c,_pow_1 ;int(x)=0
6684
jr nz,exp_normalized
6695
jr exp_normalized ;.db $11 ;start of `ld de,**`
6702
jr comp_exp ;.db $06 ;start of 'ld b,*` just to eat the next byte
6711
jp z,exp_underflow+1
6712
;perform 1-(var48+10)--> var48+10
6720
;our 'x' is at var48+10
6721
;our `temp` is at var48+6 so as not to cause issues with mulSingle)
6722
;uses 14 bytes of RAM
6764
;-inf -> +0 because lim approaches 0 from the right
6786
;-inf -> +0 because lim approaches 0 from the right
6788
sbc a,a ;FF if should be 0,
6803
;---------------------------------------------------------------------------------------------------------
6805
;---------------------------------------------------------------------------------------------------------
6807
if defined MATH_SQR or defined MATH_EXP
6809
;Uses 3 bytes at scrap
6811
;552+{0,19}+8{0,3+{0,3}}+pushpop+sqrtHLIX
6830
jp z,sqrtSingle_special
6833
push af ;new exponent
6843
;AHL is the new remainder
6844
;Need to divide by 2, then divide by the 16-bit (var_x+4)
6848
;We are just going to approximate it
6930
;Output: DE is the sqrt, AHL is the remainder
6931
;speed: 754+{0,1}+6{0,6}+{0,3+{0,18}}+{0,38}+sqrtHL
6955
jr _15a ;.db $FE ;start of `cp *`
6969
jr _16a ;.db $FE ;start of `cp *`
6983
jr _17a ;.db $FE ;start of `cp *`
6997
jr _18a ;.db $FE ;start of `cp *`
7001
;Now we have four more iterations
7002
;The first two are no problem
7014
jr _19a ;.db $FE ;start of `cp *`
7028
jr _20a ;.db $FE ;start of `cp *`
7033
;On the next iteration, HL might temporarily overflow by 1 bit
7035
rl d ;sla e \ rl d \ inc e
7039
adc hl,hl ;This might overflow!
7040
jr c,sqrt32_iter15_br0
7053
;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
7056
ld b,a ;either 0x00 or 0x80
7077
;returns A as the sqrt, HL as the remainder, D = 0
7091
jr _23a ;.db $01 ;start of ld bc,** which is 10cc to skip the next two bytes.
7102
jr _24a ;.db $01 ;start of ld bc,** which is 10cc to skip the next two bytes.
7113
dec d ;this resets the low bit of D, so `srl d` resets carry.
7114
jr _25a ;.db $06 ;start of ld b,* which is 7cc to skip the next byte.
7136
jr _27a ;.db $01 ;start of ld bc,** which is 10cc to skip the next two bytes.
7149
jr _28a ;.db $01 ;start of ld bc,** which is 10cc to skip the next two bytes.
7171
;---------------------------------------------------------------------------------------------------------
7173
;---------------------------------------------------------------------------------------------------------
7175
if defined MATH_LOG or defined MATH_LN
7178
; x / (1 + x/(2-x+4x/(3-2x+9x/(4-3x+16x/(5-4x)))))
7179
; a * x ^ (1/a) - a, where a = 100
7182
ld de, const_100_inv
7184
call powSingle ; temp = x ^ (1/100)
7188
call mulSingle ; temp1 = temp * 100
7191
call subSingle ; bc = temp1 - 100
7196
;---------------------------------------------------------------------------------------------------------
7198
;---------------------------------------------------------------------------------------------------------
7215
;---------------------------------------------------------------------------------------------------------
7217
;---------------------------------------------------------------------------------------------------------
7224
;;BC points to the output
7229
;;DE points to lg(y), HL points to x, BC points to output
7238
;---------------------------------------------------------------------------------------------------------
7240
; https://en.wikipedia.org/wiki/List_of_trigonometric_identities
7241
; https://en.wikipedia.org/wiki/Taylor_series#Trigonometric_functions
7242
; https://cs.stackexchange.com/questions/89245/how-approximate-sine-using-taylor-series
7243
; https://stackoverflow.com/questions/42217069/approximating-sinex-with-a-taylor-series-in-c-and-having-a-lot-of-problems
7244
;---------------------------------------------------------------------------------------------------------
7246
if defined MATH_SIN or defined MATH_TAN or defined MATH_COS
7249
; taylor: x - x^3/6 + x^5/120 - x^7/5040
7250
; x(1 - x^2(1/6 - x^2(1/120 - x^2/5040)) )
7252
; var_b = round( x / (2*PI), 0 )
7253
; var_c = x - var_b*2*PI
7254
; temp1 = if( var_c >= 0, var_c, var_c + 2*PI )
7255
; temp2 = if( temp1 > PI, temp1 - PI, temp1 )
7256
; var_a = if( temp2 > PI/2, PI - temp2, temp2 ) * if( temp1 > PI, -1, 1 )
7263
call copySingle ; return 0
7267
call trigRangeReductionSinCos
7272
call mulSingle ; var_b = var_a * var_a
7276
call mulSingle ; temp = x^2/5040
7280
call subSingle ; temp1 = 1/120 - temp
7284
call mulSingle ; temp = x^2 * temp1
7288
call subSingle ; temp1 = 1/6 - temp
7292
call mulSingle ; temp = x^2 * temp1
7296
call subSingle ; temp1 = 1 - temp
7300
call mulSingle ; return x * temp1
7303
trigRangeReductionSinCos:
7306
; var_b = round( x / (2*PI), 0 )
7314
; var_c = x - var_b*2*PI
7318
call mulSingle ; temp = var_b*2*PI
7322
call subSingle ; var_c = x - temp
7323
; temp1 = if( var_c >= 0, var_c, var_c + 2*PI )
7327
jr nc, trigRangeReductionSinCos.else.2
7330
call copySingle ; temp1 = var_c
7331
jr trigRangeReductionSinCos.endif.2
7332
trigRangeReductionSinCos.else.2:
7336
call addSingle ; temp1 = var_c + 2*PI
7337
trigRangeReductionSinCos.endif.2:
7338
; temp2 = if( temp1 > PI, temp1 - PI, temp1 )
7342
jr c, trigRangeReductionSinCos.else.3
7343
jr z, trigRangeReductionSinCos.else.3
7347
call subSingle ; temp2
7348
jr trigRangeReductionSinCos.endif.3
7349
trigRangeReductionSinCos.else.3:
7352
call copySingle ; temp2 = temp1
7353
trigRangeReductionSinCos.endif.3:
7354
; var_a = if( temp2 > PI/2, PI - temp2, temp2 ) * if( temp1 > PI, -1, 1 )
7355
ld hl, const_half_pi
7358
jr c, trigRangeReductionSinCos.else.4
7359
jr z, trigRangeReductionSinCos.else.4
7363
call subSingle ; var_a
7364
jr trigRangeReductionSinCos.endif.4
7365
trigRangeReductionSinCos.else.4:
7368
call copySingle ; var_a = temp2
7369
trigRangeReductionSinCos.endif.4:
7370
; if( temp > PI, -1, 1 )
7374
jr nc, trigRangeReductionSinCos.endif.5
7378
ld (ix+2), a ; turn var_a to negative
7379
trigRangeReductionSinCos.endif.5:
7385
;---------------------------------------------------------------------------------------------------------
7387
;---------------------------------------------------------------------------------------------------------
7389
if defined MATH_COS or defined MATH_TAN
7392
; taylor: 1 - x^2/2 + x^4/24 - x^6/720
7393
; 1 - x^2(1/2 - x^2(1/24 - x^2/720) )
7394
; reduction: same as sin
7403
call copySingle ; return 1
7407
; 1 - x^2(1/2 - x^2(1/24 - x^2/720) )
7408
call trigRangeReductionSinCos
7413
call mulSingle ; var_b = var_a * var_a
7417
call mulSingle ; temp = x^2/720
7421
call subSingle ; temp1 = 1/24 - temp
7425
call mulSingle ; temp = x^2 * temp1
7429
call subSingle ; temp1 = 1/2 - temp
7433
call mulSingle ; temp = x^2 * temp1
7437
call subSingle ; temp1 = 1 - temp
7439
; temp3 = abs(var_c)
7440
; temp1 = temp1 * if( temp3 >= PI/2, -1, 1 ) ==> cos sign
7447
ld (ix+2), a ; temp3 = abs(var_c)
7449
ld de, const_half_pi
7450
call cmpSingle ; if temp3 >= PI/2 then temp1 = -temp1
7451
jr nc, cosSingle.endif.1
7455
ld (ix+2), a ; temp1 = -temp1
7459
call copySingle ; return temp1
7464
;---------------------------------------------------------------------------------------------------------
7466
;---------------------------------------------------------------------------------------------------------
7487
;---------------------------------------------------------------------------------------------------------
7489
;---------------------------------------------------------------------------------------------------------
7494
;taylor: x/(1 + x^2/(3 + (2*x)^2/(5 + (3*x)^2/(7+(4*x)^2/9) ) ) )
7495
; x < -1: atan - PI/2
7496
; x >= 1: PI/2 - atan
7497
;reduction: abs(X) > 1 : Y = 1 / X
7498
; abs(X) <= 1: Y = X
7507
call copySingle ; return 0
7511
;x/(1 + x^2/(3 + (2*x)^2/(5 + (3*x)^2/(7+(4*x)^2/9) ) ) )
7512
call trigRangeReductionAtan
7518
call mulSingle ; var_b = var_a * var_a
7522
call mulSingle ; temp = (4*x)^2
7526
call divSingle ; temp1 = temp/9
7530
call addSingle ; temp = 7 + temp1
7534
call mulSingle ; temp1 = var_b * 9
7538
call divSingle ; temp2 = temp1 / temp
7542
call addSingle ; temp = 5 + temp2
7546
call mulSingle ; temp1 = var_b * 4
7550
call divSingle ; temp2 = temp1 / temp
7554
call addSingle ; temp = 3 + temp2
7558
call divSingle ; temp2 = var_b / temp
7562
call addSingle ; temp = 1 + temp2
7566
call divSingle ; temp2 = var_a / temp
7568
; x >= 1: PI/2 - atan
7572
ld hl, const_half_pi
7579
; x < -1: atan - PI/2
7590
ld de, const_half_pi
7599
call copySingle ; return temp2
7602
trigRangeReductionAtan:
7603
;reduction: abs(X) > 1 : Y = 1 / X
7604
; abs(X) <= 1: Y = X
7613
ld (ix+2), a ; abs(x)
7617
jr nc, trigRangeReductionAtan.1
7623
jr trigRangeReductionAtan.2
7624
trigRangeReductionAtan.1:
7629
trigRangeReductionAtan.2:
7633
jr c, trigRangeReductionAtan.3
7637
ld (ix+2), a ; y = -y
7638
trigRangeReductionAtan.3:
7643
;---------------------------------------------------------------------------------------------------------
7645
;---------------------------------------------------------------------------------------------------------
7657
;---------------------------------------------------------------------------------------------------------
7659
;---------------------------------------------------------------------------------------------------------
7714
;---------------------------------------------------------------------------------------------------------
7716
;---------------------------------------------------------------------------------------------------------
7719
;;HL points to the float
7720
;;BC points to where to output the result
7735
;---------------------------------------------------------------------------------------------------------
7737
;---------------------------------------------------------------------------------------------------------
7740
;;HL points to the float
7741
;;BC points to where to output the result
7747
jr nz, negSingle.test.sign
7750
jr nz, negSingle.test.sign
7753
jr nz, negSingle.test.sign
7756
jr nz, negSingle.test.sign
7765
negSingle.test.sign:
7768
jr z, negSingle.positive
7772
call negSingle.positive
7787
;---------------------------------------------------------------------------------------------------------
7789
;---------------------------------------------------------------------------------------------------------
7792
;;HL points to the float
7793
;;BC points to where to output the result
7796
;---------------------------------------------------------------------------------------------------------
7798
;---------------------------------------------------------------------------------------------------------
7801
;Input: HL points to float1, DE points to float2
7803
; float1 >= float2 : nc
7804
; float1 < float2 : c,nz
7805
; float1 == float2 : z
7806
; There is a margin of error allowed in the lower 2 bits of the mantissa.
7808
;Currently fails when both numbers have magnitude less than about 2^-106
7843
ld a,(scrap+3) ;new power
7844
pop bc ;B is old power
7854
or 1 ;not equal, so reset z flag
7855
rla ;if negative, float1<float2, setting c flag as wanted, else nc.
7861
;---------------------------------------------------------------------------------------------------------
7863
;---------------------------------------------------------------------------------------------------------
7866
;Stores a pseudo-random number on [0,1)
7867
;it won't produce values on (0,2^-23)
7876
;DEHL is the mantissa, B is the exponent
7892
;If we needed to shift more than 8 bits, we'll load in more random data
7897
jp nc,rand_no_more_rand_data
7905
rand_no_more_rand_data:
7924
;;Tested and passes all CAcert tests
7925
;;Uses a very simple 32-bit LCG and 32-bit LFSR
7926
;;it has a period of 18,446,744,069,414,584,320
7927
;;roughly 18.4 quintillion.
7928
;;LFSR taps: 0,2,6,7 = 11000101
7930
;;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.
7931
;Uses 64 bits of state
7965
;---------------------------------------------------------------------------------------------------------
7967
; HL = Single address
7968
; BC = String address
7969
; http://0x80.pl/notesen/2015-12-29-float-to-string.html
7970
; http://0x80.pl/articles/convert-float-to-integer.html
7971
;---------------------------------------------------------------------------------------------------------
7985
; Move the float to scrap
7989
; Make the float negative, write a '-' if already negative
7998
ld a,'-' ; write '-' simbol
8006
; Check if the exponent field is 0 (a special value)
8013
; We should write '0' next. When rounding 9.999999... for example, not padding with a 0 will return '.' instead of '1.'
8021
; Now we need to perform signed (A-128)*77 (approximation of exponent*log10(2))
8029
ld (pow10exp_single),a ;The base-10 exponent
8033
ld de,pow10LUT ;get the table of 10^-(2^k)
8035
ld hl, pow10exp_single
8037
call singletostr_mul
8038
call singletostr_mul
8039
call singletostr_mul
8040
call singletostr_mul
8041
call singletostr_mul
8042
call singletostr_mul
8043
;now the number is pretty close to a nice value
8045
; If it is less than 1, multiply by 10
8050
;ld hl,scrap ;Since singletostr_mul returns BC = scrap, can do this cheaper
8056
ld hl,pow10exp_single
8062
; Convert to a fixed-point number !
8076
;We need to get 7 digits
8078
pop hl ;Points to the string
8080
;The first digit can be as large as 20, so it'll actually be two digits
8084
;Increment the exponent :)
8085
ld de,(pow10exp_single-1)
8087
ld (pow10exp_single-1),de
8096
; Get the remaining digits.
8103
call singletostrmul10
8108
;Save the pointer to the end of the string
8115
jr c,rounding_done_single
8116
jr _40a ;.db $DA ;start of `jp c,*` in order to skip the next instruction
8125
rounding_done_single:
8128
;Strip the leading zero if it exists (rounding may have bumped this to `1`)
8140
;Now lets move HL-DE bytes at DE+1 to DE
8152
;If z flag is reset, this means that the exponent should be bumped up 1
8153
ld a,(pow10exp_single)
8156
ld (pow10exp_single),a
8159
;if -4<=A<=6, then need to insert the decimal place somewhere.
8164
;for this, we need to insert the decimal after the first digit
8165
;Then, we need to append the exponent string
8167
ld de,strout_single-1
8169
cp '-' ;negative sign
8177
;remove any stray zeroes at the end before appending the exponent
8181
; Write the exponent
8184
ld a,(pow10exp_single)
8187
ld (hl),'-' ;negative sign
8204
ld hl,strout_single-1
8207
ld a,(pow10exp_single)
8211
;need to put zeroes before everything
8214
cp '-' ;negative sign
8240
ld de,strout_single-1
8244
cp '-' ;negative sign
8255
ld hl,strout_single-1
8272
;multiply the 0.24 fixed point number at scrap by 10
8273
;overflow in A register
8308
;Check that the last digit isn't a decimal!
8358
;---------------------------------------------------------------------------------------------------------
8360
; https://www.ticalc.org/pub/86/asm/source/routines/atof.asm
8361
;---------------------------------------------------------------------------------------------------------
8366
ptr_sto: equ scrap+9
8368
;;#Routines/Single Precision
8370
;; HL points to the string
8371
;; BC points to where the float is output
8373
;; scrap+9 is the pointer to the end of the string
8375
;; 11 bytes at scrap ?
8378
;Check if there is a negative sign.
8387
;Skip all leading zeroes
8390
jr z,$-4 ;jumps back to the `inc hl`
8393
;Check if the next char is char_DEC
8395
or a ;to reset the carry flag
8397
jr _54a ;.db $FE ;start of cp *
8404
jr z,$-5 ;jumps back to the `dec b`
8407
;Now we read in the next 8 digits
8413
;Now `scrap` holds the 4-digit base-100 number.
8415
;if carry flag is set, just need to get rid of remaining digits
8416
;Otherwise, need to get rid of remaining digits, while incrementing the exponent
8427
jp z,strToSingle_inf
8430
;Now check for engineering `E` to modify the exponent
8434
;Gotta multiply the number at (scrap) by 2^24
8437
call scrap_times_256
8440
call scrap_times_256
8443
call scrap_times_256
8446
call scrap_times_256
8449
;Now scrap+3 is a 4-byte mantissa that needs to be normalized
8457
jp z,strToSingle_zero-1
8461
jp m,strToSingle_normed
8462
;Will need to iterate at most three times
8475
;Move the number to scrap
8484
;now (scrap) is our number, need to multiply by power of 10!
8485
;Power of 10 is stored in B, need to put in A first
8493
jp nc,strToSingle_inf+1
8496
jp nc,strToSingle_zero
8520
cp char_NEG ;negative exponent?
8572
call scrap_times_sub
8585
jr nz,strToSingle_inf
8601
;---------------------------------------------------------------------------------------------------------
8603
; http://wikiti.brandonw.net/index.php?title=Z80_Routines:Math:Division#24.2F8_division
8604
;---------------------------------------------------------------------------------------------------------
8611
ld l, (ix) ; convert integer parameter to single float
8613
ld bc, 0x1000 ; bynary digits count + sign
8615
int2Single.test.zero:
8617
or h ; test if hl is not zero
8618
jr nz, int2Single.test.negative
8620
jr nz, int2Single.test.negative
8625
int2Single.test.negative:
8626
bit 7, h ; test if hl is negative
8627
jr z, int2Single.normalize
8628
ld c, 0x80 ; sign negative
8637
int2Single.normalize:
8640
jr nz, int2Single.mount
8643
jr int2Single.normalize
8646
res 7, h ; turn off upper bit
8648
ld a, c ; restore sign
8650
ld h, a ; ...into upper mantissa
8652
ld e, h ; sign+mantissa
8653
ld h, l ; high mantissa
8654
ld l, 0 ; low mantissa
8656
ld a, b ; binary digits count
8657
or 0x80 ; exponent bias
8662
ld (ix), l ; low mantissa
8663
ld (ix+1), h ; high mantissa
8664
ld (ix+2), e ; sign + mantissa
8665
ld (ix+3), d ; expoent
8672
;---------------------------------------------------------------------------------------------------------
8674
; http://0x80.pl/articles/convert-float-to-integer.html
8675
;---------------------------------------------------------------------------------------------------------
8678
; HL points to the single-precision float
8680
; HL is the 16-bit signed integer part of the float
8681
; BC points to 16-bit signed integer
8698
jr c,no_shift_single_to_int16
8700
jr nc,no_shift_single_to_int16
8722
jr _67a ;.db $11 ;start of ld de,*
8734
no_shift_single_to_int16:
8755
;---------------------------------------------------------------------------------------------------------
8756
; Auxiliary routines
8757
;---------------------------------------------------------------------------------------------------------
8764
const_pi: db $DB,$0F,$49,$81
8765
const_e: db $54,$f8,$2d,$81
8766
const_lg_e: db $3b,$AA,$38,$80
8767
const_ln_2: db $18,$72,$31,$7f
8768
const_log2: db $9b,$20,$1a,$7e
8769
const_lg10: db $78,$9a,$54,$81
8770
const_0: db $00,$00,$00,$00
8771
const_1: db $00,$00,$00,$80
8772
const_2: dw 0, 33024
8773
const_3: dw 0, 33088
8774
const_4: dw 0, 33280
8775
const_5: dw 0, 33312
8776
const_7: dw 0, 33376
8777
const_9: dw 0, 33552
8778
const_16: dw 0, 33792
8779
const_100: db $00,$00,$48,$86
8780
const_100_inv: dw 55050, 31011
8781
const_precision: db $77,$CC,$2B,$65 ;10^-8
8782
const_half_1: dw 0, 32512
8783
const_inf: db $00,$00,$40,$00
8784
const_NegInf: db $00,$00,$C0,$00
8785
const_NaN: db $00,$00,$20,$00
8786
const_log10_e: db $D9,$5B,$5E,$7E
8787
const_2pi: db $DB,$0F,$49,$82
8788
const_2pi_inv: db $83,$F9,$22,$7D
8789
const_half_pi: dw 4059, 32841
8790
const_p25: db $00,$00,$00,$7E
8791
const_p5: db $00,$00,$00,$7F
8794
sin_a1: dw 43691, 32042
8795
sin_a2: dw 34952, 30984
8796
sin_a3: dw 3329, 29520
8797
cos_a1: equ const_half_1
8798
cos_a2: dw 43691, 31530
8799
cos_a3: dw 2914, 30262
8800
exp_a1: db $15,$72,$31,$7F ;.693146989552
8801
exp_a2: db $CE,$FE,$75,$7D ;.2402298085906
8802
exp_a3: db $7B,$42,$63,$7B ;.0554833215071
8803
exp_a4: db $FD,$94,$1E,$79 ;.00967907584392
8804
exp_a5: db $5E,$01,$23,$76 ;.001243632065103
8805
exp_a6: db $5F,$B7,$63,$73 ;.0002171671843714
8806
const_1p40625: db $00,$00,$34,$80 ;1.40625
8814
;A is the constant ID#
8815
;returns nc if failed, c otherwise
8816
;HL points to the constant
8817
cp (end_const-start_const)>>2
8824
;#if ((end_const-4)>>8)!=(start_const>>8)
8835
db $CD,$CC,$4C,$7C ;.1
8836
db $0A,$D7,$23,$79 ;.01
8837
db $17,$B7,$51,$72 ;.0001
8838
db $77,$CC,$2B,$65 ;10^-8
8839
db $95,$95,$66,$4A ;10^-16
8840
db $1F,$B1,$4F,$15 ;10^-32
8843
db $00,$00,$20,$83 ;10
8844
db $00,$00,$48,$86 ;100
8845
db $00,$40,$1C,$8D ;10000
8846
db $20,$BC,$3E,$9A ;10^8
8847
db $CA,$1B,$0E,$B5 ;10^16
8848
db $AE,$C5,$1D,$EA ;10^32
8855
;C>=128 135+6{0,33+{0,1}}+{0,20+{0,8}}
8856
;C>=64 115+5{0,33+{0,1}}+{0,20+{0,8}}
8857
;C>=32 95+4{0,33+{0,1}}+{0,20+{0,8}}
8858
;C>=16 75+3{0,33+{0,1}}+{0,20+{0,8}}
8859
;C>=8 55+2{0,33+{0,1}}+{0,20+{0,8}}
8860
;C>=4 35+{0,33+{0,1}}+{0,20+{0,8}}
8861
;C>=2 15+{0,20+{0,8}}
8864
;avg: 349.21279907227cc
8955
;26 bytes, adds 118cc to the traditional routine
8988
;c flag means don't increment the exponent
8991
jr c,ascii_to_uint8_noexp
8993
jr z,ascii_to_uint8_noexp-2
8997
jr nc,ascii_to_uint8_noexp_end
9009
jr z,ascii_to_uint8_noexp_2nd
9013
jr nc,ascii_to_uint8_noexp_end
9024
ascii_to_uint8_noexp:
9027
jr nc,ascii_to_uint8_noexp_end
9034
ascii_to_uint8_noexp_2nd:
9039
jr nc,ascii_to_uint8_noexp_end
9042
jr ascii_2 ;.db $FE ;start of `cp **`, saves 1cc
9043
ascii_to_uint8_noexp_end:
9070
jp addInject ;jumps in to the addSingle routine
9072
;This routine performs `x mod 1`, returning a non-negative value.
9095
jr z,mod1Single_special
9108
;If it is zero, need to set exponent to zero and return
9131
;make sure it isn't zero else we need to add 1
9143
;If INF, need to return NaN instead
9144
;For 0 and NaN, just return itself :)
9162
; --------------------------------------------------------------
9163
; Converts a signed integer value to a zero-terminated ASCII
9164
; string representative of that value (using radix 10).
9166
; Brandon Wilson WikiTI
9167
; http://wikiti.brandonw.net/index.php?title=Z80_Routines:Other:DispA#Decimal_Signed_Version
9168
; --------------------------------------------------------------
9170
; HL Value to convert (two's complement integer).
9171
; DE Base address of string destination. (pointer).
9172
; --------------------------------------------------------------
9175
; --------------------------------------------------------------
9176
; REGISTERS/MEMORY DESTROYED
9178
; --------------------------------------------------------------
9184
; Detect sign of HL.
9188
; HL is negative. Output '-' to string and negate HL.
9193
; Negate HL (using two's complement)
9197
ld a, 0 ; Note that XOR A or SUB A would disturb CF
9201
; Convert HL to digit characters
9203
ld b, 0 ; B will count character length of number
9206
call div_hl_c; HL = HL / A, A = remainder
9213
; Retrieve digits from stack
9221
; Terminate string with NULL
9229
;===============================================================
9230
; Convert a string of base-10 digits to a 16-bit value.
9231
; http://z80-heaven.wikidot.com/math#toc32
9233
; DE points to the base 10 number string in RAM.
9235
; HL is the 16-bit value of the number
9236
; DE points to the byte after the number
9241
; A (actually, add 30h and you get the ending token)
9244
; n is the number of digits
9246
; at most 595 cycles for any 16-bit decimal value
9247
;===============================================================
9250
ld hl,0 ; 10 : 210000
9267
jr nc,ConvLoop ;12|23: 30EE
9269
jr ConvLoop ; --- : 18EB
9272
; return remainder in a
9273
; http://wikiti.brandonw.net/index.php?title=Z80_Routines:Math:Division
9290
; http://wikiti.brandonw.net/index.php?title=Z80_Routines:Math:Division#24.2F8_division
9320
djnz div_dehl_c.loop
9328
;--------------------------------------------------------
9329
romSize: equ 0x4000 ; ROM size (16k)
9331
ds romSize-(romPad-pgmArea),0
9332
end_file: end start_pgm ; label start is the entry point