~amaurycarvalho/msxbas2asm/trunk

« back to all changes in this revision

Viewing changes to test/test25.asm

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

Show diffs side-by-side

added added

removed removed

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