8bitworkshop/res/altirra/kernel.lst

10525 lines
364 KiB
Plaintext

mads 2.1.0
Source: source/main.xasm
1 ; Altirra - Atari 800/800XL emulator
2 ; Kernel ROM replacement
3 ; Copyright (C) 2008-2016 Avery Lee
4 ;
5 ; Copying and distribution of this file, with or without modification,
6 ; are permitted in any medium without royalty provided the copyright
7 ; notice and this notice are preserved. This file is offered as-is,
8 ; without any warranty.
9
10 ;==========================================================================
11
12 .if _KERNEL_XLXE
13 _KERNEL_PBI_SUPPORT = 1
14 _KERNEL_USE_BOOT_SCREEN = 1
15 .macro _KERNELSTR_BIOS_NAME_INTERNAL
16 .ifdef _KERNEL_816
17 dta d" for 65C816"
18 .else
19 dta d" for XL/XE/XEGS"
20 .endif
21 .endm
22 .else
23 = 0000 _KERNEL_PBI_SUPPORT = 0
24 = 0000 _KERNEL_USE_BOOT_SCREEN = 0
25 .endif
26
27 = 0001 _KERNEL_PRINTER_SUPPORT = 1
28
29 ;==========================================================================
30
31 icl 'version.inc'
Source: source/Shared/version.inc
1 ; Altirra - Atari 800/800XL emulator
2 ; Kernel ROM replacement - version info
3 ; Copyright (C) 2008-2020 Avery Lee
4 ;
5 ; Copying and distribution of this file, with or without modification,
6 ; are permitted in any medium without royalty provided the copyright
7 ; notice and this notice are preserved. This file is offered as-is,
8 ; without any warranty.
9
10 .macro _KERNELSTR_VERSION
11 dta '3.26'
12 .endm
13
14 .macro _KERNELSTR_VERSION_INTERNAL
15 dta "3.26"
16 .endm
32 icl 'hardware.inc'
Source: source/Shared/hardware.inc
1 ; Altirra - Atari 800/800XL/5200 emulator
2 ; Modular Kernel ROM - Hardware register definitions
3 ; Copyright (C) 2008-2016 Avery Lee
4 ;
5 ; Copying and distribution of this file, with or without modification,
6 ; are permitted in any medium without royalty provided the copyright
7 ; notice and this notice are preserved. This file is offered as-is,
8 ; without any warranty.
9
10 .ifndef f_HARDWARE_INC
11 .def f_HARDWARE_INC
12
13 ;==========================================================================
14 ; GTIA
15 ;
16 m0pf equ $d000
17 m1pf equ $d001
18 m2pf equ $d002
19 m3pf equ $d003
20 p0pf equ $d004
21 p1pf equ $d005
22 p2pf equ $d006
23 p3pf equ $d007
24 m0pl equ $d008
25 m1pl equ $d009
26 m2pl equ $d00a
27 m3pl equ $d00b
28 p0pl equ $d00c
29 p1pl equ $d00d
30 p2pl equ $d00e
31 p3pl equ $d00f
32
33 hposp0 equ $d000
34 hposp1 equ $d001
35 hposp2 equ $d002
36 hposp3 equ $d003
37 hposm0 equ $d004
38 hposm1 equ $d005
39 hposm2 equ $d006
40 hposm3 equ $d007
41 sizep0 equ $d008
42 sizep1 equ $d009
43 sizep2 equ $d00a
44 sizep3 equ $d00b
45 sizem equ $d00c
46 grafp0 equ $d00d
47 grafp1 equ $d00e
48 grafp2 equ $d00f
49 grafp3 equ $d010
50 grafm equ $d011
51 trig0 equ $d010
52 trig1 equ $d011
53 trig2 equ $d012
54 colpm0 equ $d012
55 trig3 equ $d013
56 colpm1 equ $d013
57 pal equ $d014
58 colpm2 equ $d014
59 colpm3 equ $d015
60 colpf0 equ $d016
61 colpf1 equ $d017
62 colpf2 equ $d018
63 colpf3 equ $d019
64 colbk equ $d01a
65 prior equ $d01b
66 vdelay equ $d01c
67 gractl equ $d01d
68 hitclr equ $d01e
69 consol equ $d01f
70
71 ;==========================================================================
72 ; POKEY
73 ;
74 pot0 equ $d200
75 audf1 equ $d200
76 pot1 equ $d201
77 audc1 equ $d201
78 pot2 equ $d202
79 audf2 equ $d202
80 pot3 equ $d203
81 audc2 equ $d203
82 pot4 equ $d204
83 audf3 equ $d204
84 pot5 equ $d205
85 audc3 equ $d205
86 pot6 equ $d206
87 audf4 equ $d206
88 pot7 equ $d207
89 audc4 equ $d207
90 audctl equ $d208
91 kbcode equ $d209
92 skres equ $d20a
93 potgo equ $d20b
94 serin equ $d20d
95 serout equ $d20d
96 irqen equ $d20e
97 irqst equ $d20e
98 skctl equ $d20f
99 skstat equ $d20f
100
101 ;==========================================================================
102 ; PIA
103 ;
104 porta equ $d300
105 portb equ $d301
106 pactl equ $d302
107 pbctl equ $d303
108
109 ;==========================================================================
110 ; ANTIC
111 ;
112 dmactl equ $d400
113 chactl equ $d401
114 dlistl equ $d402
115 dlisth equ $d403
116 hscrol equ $d404
117 vscrol equ $d405
118 pmbase equ $d407
119 chbase equ $d409
120 wsync equ $d40a
121 vcount equ $d40b
122 penh equ $d40c
123 penv equ $d40d
124 nmien equ $d40e
125 nmist equ $d40f
126 nmires equ $d40f
127
128 ;==========================================================================
129 ; 6502
130 ;
131 nmivec equ $fffa
132 resvec equ $fffc
133 irqvec equ $fffe
134
135 .endif
33 icl 'kerneldb.inc'
Source: source/Shared/kerneldb.inc
1 ; Altirra - Atari 800/800XL/5200 emulator
2 ; Modular Kernel ROM - Kernel Database Definitions
3 ; Copyright (C) 2008-2016 Avery Lee
4 ;
5 ; Copying and distribution of this file, with or without modification,
6 ; are permitted in any medium without royalty provided the copyright
7 ; notice and this notice are preserved. This file is offered as-is,
8 ; without any warranty.
9
10 .ifndef f_KERNELDB_INC
11 .def f_KERNELDB_INC
12
13 casini = $0002 ;cassette initialization vector
14 ramlo = $0004 ;
15 tramsz = $0006 ;temporary ram size / cart A flag
16 tstdat = $0007 ;RAM test data register / cart B flag
17 ;(also CMCMD for T:)
18 warmst = $0008 ;warmstart flag
19 boot? = $0009 ;boot flag; 0 if none, 1 for disk, 2 for cassette
20 dosvec = $000a
21 dosini = $000c
22 appmhi = $000e
23 pokmsk = $0010
24 brkkey = $0011 ;set on [BREAK]
25 rtclok = $0012
26 bufadr = $0015 ;indirect buffer address pointer (temp for disk buffer)
27 ; $0016
28 iccomt = $0017 ;CIO: command byte
29 ziocb = $0020 ;zero-page IOCB
30 ichidz = $0020 ;Zero page IOCB: device index ($FF = not open)
31 icdnoz = $0021 ;Zero page IOCB: device number
32 iccomz = $0022 ;Zero page IOCB: command byte
33 icstaz = $0023 ;Zero page IOCB: status byte
34 icbalz = $0024 ;Zero page IOCB: address of device/filename spec lo
35 icbahz = $0025 ;Zero page IOCB: address of device/filename spec hi
36 icptlz = $0026 ;Zero page IOCB: put byte address lo (-1)
37 icpthz = $0027 ;Zero page IOCB: put byte address hi (-1)
38 icbllz = $0028 ;Zero page IOCB: buffer length/byte count lo (-1)
39 icblhz = $0029 ;Zero page IOCB: buffer length/byte count hi (-1)
40 icax1z = $002a ;Zero page IOCB: device-specific information 1
41 icax2z = $002b ;Zero page IOCB: device-specific information 2
42 icax3z = $002c ;Zero page IOCB: device-specific information 3
43 icax4z = $002d ;Zero page IOCB: device-specific information 4
44 icax5z = $002e ;Zero page IOCB: device-specific information 5
45 icidno = $002e ;CIO: call X register save/restore
46 icax6z = $002f ;Zero page IOCB: device-specific information 6
47 ciochr = $002f ;CIO: call A register save/restore
48 status = $0030 ;SIO: temporay status byte
49 chksum = $0031 ;SIO: temporary checksum byte (used by IRQ routines)
50 bufrlo = $0032 ;SIO: buffer pointer lo (incremented by IRQ routines)
51 bufrhi = $0033 ;SIO: buffer pointer hi (incremented by IRQ routines)
52 bfenlo = $0034 ;SIO: buffer end lo
53 bfenhi = $0035 ;SIO: buffer end hi
54 ltemp = $0036 ;Relocating loader: loader temp address (XL/XE)
55 ; $0037
56 bufrfl = $0038 ;SIO: buffer full flag
57 recvdn = $0039 ;SIO: receive completed flag
58 xmtdon = $003a ;SIO: transmit completed flag
59 chksnt = $003b ;SIO: checksum sent flag
60 nocksm = $003c ;SIO: no-checksum flag
61 bptr = $003d ;Cassette: Buffer pointer
62 ftype = $003e ;Cassette: Interrecord gap (IRG) type; bit7=1 means continuous mode
63 feof = $003f ;Cassette: EOF flag
64 soundr = $0041 ;SIO: noisy audio flag
65 critic = $0042 ;critical flag for vbi
66 zchain = $004a ;Peripheral Handler: zero-page chain address
67 ; $004b
68 atract = $004d ;screen attract counter
69 drkmsk = $004e ;screen attract mask
70 colrsh = $004f ;screen attract color shift
71 tmpchr = $0050 ;Screen Editor
72 hold1 = $0051 ;Display/Editor: temporary storage
73 lmargn = $0052 ;left margin column
74 rmargn = $0053 ;right margin column
75 rowcrs = $0054 ;cursor row
76 colcrs = $0055 ;cursor column
77 ; $0056
78 dindex = $0057 ;display mode index
79 savmsc = $0058 ;lowest address of screen region
80 oldrow = $005a ;
81 oldcol = $005b ;
82 oldchr = $005d ;cursor character save/restore
83 oldadr = $005e ;cursor memory address
84 ; $005f
85 palnts = $0062 ;PAL/NTSC flag
86 logcol = $0063 ;Display/Editor: Logical column (0-119)
87 adress = $0064 ;temporary storage (display code)
88 ; $0065
89 toadr = $0066 ;temporary storage (display code)
90 a1 = toadr
91 ; $0067
92 frmadr = $0068 ;temporary storage (display code)
93 ; $0069
94 ramtop = $006a ;ram size
95 bufcnt = $006b
96 bufstr = $006c ;row/column of start of logical line
97 bitmsk = $006e ;Screen Editor
98 shfamt = $006f ;Screen Editor
99 rowac = $0070 ;Screen Editor: line drawing
100 ; $0071 ;
101 colac = $0072 ;Screen Editor: line drawing
102 ; $0073 ;
103 endpt = $0074 ;Screen Editor: line drawing
104 ; $0075 ;
105 deltar = $0076 ;Screen Editor: delta row (line drawing)
106 deltac = $0077 ;Screen Editor: delta column (line drawing)
107 ; $0078 ;
108 keydef = $0079 ;XL/XE: Keyboard definition table
109 ; $007a
110 swpflg = $007b ;current display var state ($00 = main, $FF = split screen)
111 holdch = $007c ;temporary key hold area prior to shift/control lock logic
112 countr = $007e ;Screen Editor: line length
113 ; $007f
114 fr0 = $00d4 ;FP: Accumulator 0
115 _fr3 = $00da ;FP: Accumulator 3 (officially FRE)
116 fr1 = $00e0 ;FP: Accumulator 1
117 fr2 = $00e6 ;FP: Accumulator 2
118 _fpcocnt= $00ec ;FP: temporary storage - polynomial coefficient counter
119 _fptemp0= $00ed ;FP: temporary storage - transcendental temporary (officially EEXP)
120 _fptemp1= $00ee ;FP: temporary storage - transcendental temporary (officially NSIGN)
121 ;esign $00ef ;BASIC: Used in sqr() routine -- must not be touched by FP elementary functions
122 ;fchrflg $00f0 ;BASIC: Used in sin() routine -- must not be touched by any FP functions
123 cix = $00f2 ;FP: Character index
124 inbuff = $00f3 ;FP: ASCII conversion buffer
125 ; $00f4
126 ; $00f5 ;FP: temporary storage -- also temporarily used by BASIC power routine
127 ; $00f6 ;FP: temporary storage
128 ztemp4 = $00f7 ;FP: temporary storage -- also temporarily used by BASIC power routine
129 ; $00f8 ;FP: temporary storage
130 ; $00f9 ;FP: temporary storage
131 ; $00fa ;FP: temporary storage
132 degflg = $00fb ;FP: degree/radian flag (0=radians, 6=degrees)
133 flptr = $00fc ;FP: pointer for floating-point loads and stores
134 fptr2 = $00fe ;FP: pointer for polynomial evaluation
135
136 vdslst = $0200 ;display list interrupt vector
137 vprced = $0202 ;serial bus proceed interrupt vector
138 vinter = $0204 ;serial bus interrupt vector
139 vbreak = $0206 ;BRK instruction vector
140 vkeybd = $0208 ;keyboard interrupt vector
141 vserin = $020a ;serial input ready interrupt vector
142 vseror = $020c ;serial output ready interrupt vector
143 vseroc = $020e ;serial output completed interrupt vector
144 vtimr1 = $0210 ;pokey timer 1 interrupt vector
145 vtimr2 = $0212 ;pokey timer 2 interrupt vector
146 vtimr4 = $0214 ;pokey timer 4 interrupt vector
147 vimirq = $0216 ;immediate IRQ vector
148 cdtmv1 = $0218 ;countdown timer 1
149 cdtmv2 = $021a ;countdown timer 2
150 cdtmv3 = $021c ;countdown timer 3
151 cdtmv4 = $021e ;countdown timer 4
152 cdtmv5 = $0220 ;countdown timer 5
153 vvblki = $0222 ;vertical blank immediate vector
154 vvblkd = $0224 ;vertical blank deferred vector
155 cdtma1 = $0226 ;timer 1 vector
156 cdtma2 = $0228 ;timer 2 vector
157 cdtmf3 = $022a ;timer 3 flag
158 srtimr = $022b ;autorepeat timer
159 cdtmf4 = $022c ;timer 4 flag
160 intemp = $022d ;temp value used by SETVBV
161 cdtmf5 = $022e ;timer 5 flag
162 sdmctl = $022f ;shadow for DMACTL ($D400)
163 sdlstl = $0230 ;shadow for DLISTL ($D402)
164 sdlsth = $0231 ;shadow for DLISTH ($D403)
165 sskctl = $0232 ;shadow for SKCTL ($D20F)
166 lcount = $0233 ;Relocating loader: (XL/XE)
167 lpenh = $0234 ;light pen horizontal pos
168 lpenv = $0235 ;light pen vertical pos
169 brkky = $0236 ;break key interrupt vector (OS B+ only)
170 vpirq = $0238 ;PBI device interrupt vector (XL/XE)
171 ; $0239
172 cdevic = $023a ;SIO: command frame device ID
173 ccomnd = $023b ;SIO: command frame command ID
174 caux1 = $023c ;SIO: command aux byte 1
175 caux2 = $023d ;SIO: command aux byte 2
176 temp = $023e ;SIO: temp space
177 errflg = $023f ;SIO: error flag
178 dflags = $0240 ;disk boot flags
179 dbsect = $0241 ;disk boot sector count
180 bootad = $0242 ;disk boot address
181 coldst = $0244 ;cold start flag
182 reclen = $0245 ;Relocating loader: record length (XL/XE)
183 dsktim = $0246 ;Disk Handler: Disk operation timeout
184 pdvmsk = $0247 ;PBI device mask (XL/XE)
185 shpdvs = $0248 ;PBI device selection register shadow ($D1FF) (XL/XE)
186 pdmsk = $0249 ;PBI device interrupt mask (XL/XE)
187 reladr = $024a ;Relocating loader: temp address (XL/XE)
188 ; $024b
189
190 .if _KERNEL_816
191 vabte = $024f ;(816) Emulation ABORT vector
192 ; $0250
193 vcope = $0251 ;(816) Emulation COP vector
194 ; $0252
195 vabtn = $0253 ;(816) Native ABORT vector
196 ; $0254
197 ; $0255
198 vcopn = $0256 ;(816) Native COP vector
199 ; $0257
200 ; $0258
201 vnmin = $0259 ;(816) Native NMI vector
202 ; $025a
203 ; $025b
204 virqn = $025c ;(816) Native IRQ vector
205 ; $025d
206 ; $025e
207 vbrkn = $025f ;(816) Native BREAK vector
208 ; $0260
209 ; $0261
210 vcop0 = $0262 ;(816) Native COP #0 vector
211 ; $0263
212 ; $0264
213 vcopu = $0265 ;(816) Native COP #1-127 vector
214 ; $0266
215 ; $0267
216 vcopc = $0268 ;(816) Native COP #128-255 vector
217 ; $0269
218 ; $026a
219 .endif
220
221 fine = $026e ;fine scrolling flag (XL/XE)
222 gprior = $026f ;shadow for PRIOR ($D01B)
223 paddl0 = $0270 ;shadow for POT0 ($D200)
224 paddl1 = $0271 ;shadow for POT1 ($D201)
225 paddl2 = $0272 ;shadow for POT2 ($D202)
226 paddl3 = $0273 ;shadow for POT3 ($D203)
227 paddl4 = $0274 ;shadow for POT4 ($D204)
228 paddl5 = $0275 ;shadow for POT5 ($D205)
229 paddl6 = $0276 ;shadow for POT6 ($D206)
230 paddl7 = $0277 ;shadow for POT7 ($D207)
231 stick0 = $0278 ;shadow for PORTA lo ($D300)
232 stick1 = $0279 ;shadow for PORTA hi ($D300)
233 stick2 = $027A ;shadow for PORTB lo ($D302)
234 stick3 = $027B ;shadow for PORTB hih ($D302)
235 ptrig0 = $027c ;paddle trigger 0
236 ptrig1 = $027d ;paddle trigger 1
237 ptrig2 = $027e ;paddle trigger 2
238 ptrig3 = $027f ;paddle trigger 3
239 ptrig4 = $0280 ;paddle trigger 4
240 ptrig5 = $0281 ;paddle trigger 5
241 ptrig6 = $0282 ;paddle trigger 6
242 ptrig7 = $0283 ;paddle trigger 7
243 strig0 = $0284 ;shadow for TRIG0 ($D001)
244 strig1 = $0285 ;shadow for TRIG1 ($D002)
245 strig2 = $0286 ;shadow for TRIG2 ($D003)
246 strig3 = $0287 ;shadow for TRIG3 ($D004)
247 hibyte = $0288 ;Relocating loader (XL/XE)
248 wmode = $0289 ;Cassette: Write mode (00 = read, 80 = write)
249 blim = $028a ;Cassette: Buffer limit
250 jveck = $028c ;XL/XE: IRQ jump vector
251 newadr = $028e ;Relocating loader (XL/XE)
252 txtrow = $0290
253 txtcol = $0291
254 ; $0292
255 tindex = $0293 ;text mode index
256 txtmsc = $0294 ;text window pointer
257 ; $0295
258 cretry = $029c ;SIO: command retries (XL/XE)
259 hold3 = $029d ;Screen Editor
260 hold2 = $029f ;Screen Editor
261 dmask = $02a0 ;Display/Editor: Graphics merge mask
262 tmplbt = $02a1
263 escflg = $02a2 ;Display/Editor: Escape next character
264 tabmap = $02a3 ;Display/Editor: Bitfield indicating tabs (note reversed bit positions)
265 logmap = $02b2 ;Display/Editor: Logical line start map (4 bytes)
266 invflg = $02b6 ;Keyboard Handler: inverse flag ($00/$80)
267 tmprow = $02b8 ;Screen Editor
268 tmpcol = $02b9 ;Screen Editor
269 ; $02ba
270 scrflg = $02bb ;Display/Editor: Scroll counter
271 hold4 = $02bc ;Screen Editor
272 dretry = $02bd ;SIO: device retries (XL/XE)
273 shflok = $02be ;shift/control lock flags
274 botscr = $02bf ;number of text rows in text window
275 pcolr0 = $02c0 ;shadow for COLPM0 ($D012)
276 pcolr1 = $02c1 ;shadow for COLPM1 ($D013)
277 pcolr2 = $02c2 ;shadow for COLPM2 ($D014)
278 pcolr3 = $02c3 ;shadow for COLPM3 ($D015)
279 color0 = $02c4 ;shadow for COLPF0 ($D016)
280 color1 = $02c5 ;shadow for COLPF1 ($D017)
281 color2 = $02c6 ;shadow for COLPF2 ($D018)
282 color3 = $02c7 ;shadow for COLPF3 ($D019)
283 color4 = $02c8 ;shadow for COLBK ($D01A)
284 runadr = $02c9 ;Relocating loader: run address (XL/XE)
285 ; $02ca
286 hiused = $02cb ;Relocating loader: Next available memory location (out) (XL/XE)
287 ; $02cc
288 zhiuse = $02cd ;Relocating loader: Next available zero-page address (out) (XL/XE)
289 ; $02ce
290 gbytea = $02cf ;Relocating loader: GET BYTE address (XL/XE)
291 ; $02d0
292 loadad = $02d1 ;Relocating loader: Load address (XL/XE)
293 ; $02d2
294 zloada = $02d3 ;Relocating loader: Zero-page load address (XL/XE)
295 ; $02d4
296 dsctln = $02d5 ;Disk sector size (XL/XE)
297 krpdel = $02d9 ;Keyboard repeat delay (XL/XE)
298 keyrep = $02da ;Keyboard repeat rate (XL/XE)
299 helpfg = $02dc ;Help flag (XL/XE)
300 pbpnt = $02de ;Printer: Buffer index (XL/XE location)
301 pbufsz = $02df ;Printer: Record size (XL/XE location)
302 ramsiz = $02e4 ;ram size in pages
303 memtop = $02e5 ;highest location for programs and data
304 memlo = $02e7 ;base of application memory
305 hndlod = $02e9 ;CIO: Handler load flag (XL/XE)
306 dvstat = $02ea ;DISK: Status request buffer area (4 bytes)
307 ; $02eb
308 ; $02ec
309 ; $02ed
310 cbaudl = $02ee ;Cassette baud rate as POKEY divisor. Set to nominal ($05CC) by C: init.
311 cbaudh = $02ef ;
312 crsinh = $02f0 ;Display/Editor: cursor inhibit flag
313 keydel = $02f1 ;keyboard debounce delay (set to 3 vblanks per key)
314 ch1 = $02f2 ;last keyboard code read
315 chact = $02f3 ;shadow for CHACTL ($D401)
316 chbas = $02f4 ;shadow for CHBASE ($D409)
317 rowinc = $02f8 ;Screen Editor: row direction (XL/XE location)
318 colinc = $02f9 ;Screen Editor: col direction (XL/XE location)
319 atachr = $02fb ;Screen Editor
320 ch = $02fc ;keyboard FIFO byte
321 fildat = $02fd ;Screen Editor: fill color
322 dspflg = $02fe ;enable/disable of control codes by screen editor (E:)
323 ssflag = $02ff ;display/screen editor suspend flag
324 ddevic = $0300 ;serial bus ID
325 dunit = $0301 ;device number
326 dcomnd = $0302 ;command byte
327 dstats = $0303 ;status byte
328 dbuflo = $0304 ;buffer address lo
329 dbufhi = $0305 ;buffer address hi
330 dtimlo = $0306 ;disk timeout value
331 dbytlo = $0308 ;byte count lo
332 dbythi = $0309 ;byte count hi
333 daux1 = $030a ;sector number lo
334 daux2 = $030b ;sector number hi
335 timer1 = $030c ;SIO: baud rate determination - first timer value
336 addcor = $030e ;SIO: baud rate determination - correction value
337 casflg = $030f ;SIO: cassette I/O flag (0=normal, nonzero=cassette)
338 timer2 = $0310 ;SIO: baud rate determination - second timer value
339 temp1 = $0312 ;SIO: baud rate determination - temp
340 ; $0313
341 ptimot = $0314 ;Printer: Timeout (XL/XE location)
342 temp3 = $0315 ;SIO: baud rate determination - temp
343 timflg = $0317 ;SIO: operation timeout flag (set by countdown timer 1 IRQ)
344 stackp = $0318 ;SIO: stack pointer save
345 hatabs = $031a ;handler table
346 pupbt1 = $033d ;(XL/XE) Power-up boot flag #1 - $5C
347 pupbt2 = $033e ;(XL/XE) Power-up boot flag #2 - $93
348 pupbt3 = $033f ;(XL/XE) Power-up boot flag #3 - $25
349 ichid = $0340 ;IOCB #0 handler ID
350 icdno = $0341 ;IOCB #0 device number
351 iccmd = $0342 ;IOCB #0 command byte
352 icsta = $0343 ;IOCB #0 status
353 icbal = $0344 ;IOCB #0 buffer address lo
354 icbah = $0345 ;IOCB #0 buffer address hi
355 icptl = $0346 ;IOCB #0 PUT address lo
356 icpth = $0347 ;IOCB #0 PUT address hi
357 icbll = $0348 ;IOCB #0 buffer length/byte count lo
358 icblh = $0349 ;IOCB #0 buffer length/byte count hi
359 icax1 = $034a ;IOCB #0 auxiliary information lo
360 icax2 = $034b ;IOCB #0 auxiliary information hi
361 icax3 = $034c ;
362 icax4 = $034d ;
363 icax5 = $034e ;
364 icax6 = $034f ;
365 prnbuf = $03c0 ;printer buffer
366 ckey = $03e9 ;cassette boot key
367 basicf = $03f8 ;XL/XE: ROM BASIC flag. 0 = enabled
368 gintlk = $03fa ;XL/XE: Cartridge interlock (clone of TRIG3).
369 chlink = $03fb ;XL/XE: Relocated loader chain
370 casbuf = $03fd ;Cassette buffer (03FD-047F)
371 lbuff = $0580 ;
372 plyarg = $05e0 ;FP: Polynomial evaluation temp register
373 fpscr = $05e6 ;FP: Temp evaluation register (used by LOG/LOG10)
374
375 .endif
34
35 opt h-o+f+
36
37 .ifdef _KERNEL_816
38 opt c+
39 .endif
40
41 .if _KERNEL_XLXE
42 org $c000
43
44 ;==============================================================================
45 ; lower ROM identification block (XL/XE)
46 ;==============================================================================
47
48 dta a(0)
49 dta $01,$01,$13
50 dta $02
51 dta 'CX',$00,$00,$00
52 dta $00
53
54 _KERNEL_REPORT_MODULE_MARK
55
56 .ifdef _KERNEL_816
57 icl 'vbi816.s'
58 .else
59 icl 'vbi.s'
60 .endif
61
62 _KERNEL_REPORT_MODULE_SIZE 'VBI routines', 0
63
64 .ifdef _KERNEL_816
65 icl 'interrupt816.s'
66 .else
67 icl 'interrupt.s'
68 .endif
69
70 _KERNEL_REPORT_MODULE_SIZE 'Base interrupt routines', 0
71
72 .ifdef _KERNEL_816
73 icl 'irq816.s'
74 .else
75 icl 'irq.s'
76 .endif
77
78 _KERNEL_REPORT_MODULE_SIZE 'IRQ routines', 0
79
80 icl 'pbi.s'
81 _KERNEL_REPORT_MODULE_SIZE 'PBI routines', 0
82 icl 'phandler.s'
83 _KERNEL_REPORT_MODULE_SIZE 'Peripheral Handler routines', 0
84
85 .ifdef _KERNEL_816
86 icl 'syscall816.s'
87 icl 'sysdev816.s'
88 .endif
89
90 org $cc00
91 icl 'atariifont.inc'
92
93 org $d000
94 icl 'bootscreen.s'
95
96 opt f+
97 .endif
98
99 org $d800
100
101 icl 'mathpack.s'
Source: source/Shared/mathpack.s
1 ; Altirra - Atari 800/800XL/5200 emulator
2 ; Modular Kernel ROM - Decimal Floating-Point Math Pack
3 ; Copyright (C) 2008-2016 Avery Lee
4 ;
5 ; Copying and distribution of this file, with or without modification,
6 ; are permitted in any medium without royalty provided the copyright
7 ; notice and this notice are preserved. This file is offered as-is,
8 ; without any warranty.
9
10 ;==========================================================================
11 ;
12 ; Known problems:
13 ; Currently incompatible with BASIC XE due to it relying on $DE-DF not
14 ; being modified by FADD/FSUB.
15 ;
16 ;==========================================================================
17 ;
18 ; Notes
19 ;
20 ; AFP FMUL
21 ; |FASC.FDIV
22 ; |.IPF.|PLYEVL
23 ; |.|FPI|.EXP
24 ; |.|.FADD|REDRNG
25 ; |.|.|.|.|.LOG
26 ; vvvvvvvvvvv
27 ; $D4 FR0 M MMM.
28 ; $D5 | M MMM.
29 ; $D6 | M MMM.
30 ; $D7 | M MMM.
31 ; $D8 | M MMM.
32 ; $D9 v M MMM.
33 ; $DA FR2 {FRE} TTTTTTT.
34 ; $DB | TT TTTT.
35 ; $DC | TT TTTT.
36 ; $DD | TT TTTT.
37 ; $DE | T TTT. [1,2]
38 ; $DF v TTT. [1,2]
39 ; $E0 FR1 MM . [3]
40 ; $E1 | MM . [3]
41 ; $E2 | MM . [3]
42 ; $E3 | MM . [3]
43 ; $E4 | MM . [3]
44 ; $E5 v MM . [3]
45 ; $E6 FR3 {FR2} . .
46 ; $E7 . .
47 ; $E8 . .
48 ; $E9 . .
49 ; $EA . .
50 ; $EB . .
51 ; $EC {FRX} . .
52 ; $ED {EEXP} . .
53 ; $EE {NSIGN} . .
54 ; $EF {ESIGN} . .
55 ; $F0 {FCHRFLG} . .
56 ; $F1 {DIGRT} . .
57 ; $F2 CIX . .
58 ; $F3 INBUFF . .
59 ; $F4 v . .
60 ; $F5 {ZTEMP1} . .
61 ; $F6 v . .
62 ; $F7 {ZTEMP4} . .
63 ; $F8 v . .
64 ; $F9 {ZTEMP3} . .
65 ; $FA v . .
66 ; $FB DEGFLG/RADFLG . .
67 ; $FC FLPTR . .
68 ; $FD v . .
69 ; $FE FPTR2 . .
70 ; $FF v . .
71 ; $05E0 PLYARG T T
72 ; $05E1 | T T
73 ; $05E2 | T T
74 ; $05E3 | T T
75 ; $05E4 | T T
76 ; $05E5 v T T
77 ; $05E6 FPSCR TT
78 ; $05E7 | TT
79 ; $05E8 | TT
80 ; $05E9 | TT
81 ; $05EA | TT
82 ; $05EB v TT
83 ; $05EC FPSCR1
84 ; $05ED |
85 ; $05EE |
86 ; $05EF |
87 ; $05F0 |
88 ; $05F1 v
89 ;
90 ; Notes:
91 ; [1] BASIC XE relies on $DE/DF not being touched by FADD, or FOR/NEXT
92 ; breaks.
93 ; [2] MAC/65 relies on $DE/DF not being touched by IPF.
94 ; [3] DARG relies on FPI not touching FR1.
95 ; [4] ACTris 1.2 relies on FASC not touching lower parts of FR2.
96 ;
97
98 .macro ckaddr
99 .if * <> %%1
100 .error 'Incorrect address: ',*,' != ',%%1
101 .endif
102 .endm
103
104 .macro fixadr
105 .if * < %%1
106 .print (%%1-*),' bytes free before ',%%1
107 org %%1
108 .elif * > %%1
109 .error 'Out of space: ',*,' > ',%%1,' (',*-%%1,' bytes over)'
110 .endif
111 .endm
112
113 ;==========================================================================
114 ; AFP [D800] Convert ASCII string at INBUFF[CIX] to FR0
115 ;
116 org $d800
117 = D800 _afp = afp
118 .proc afp
119 = 00E6 dotflag = fr2
120 = 00E7 xinvert = fr2+1
121 = 00E8 cix0 = fr2+2
122 = 00E9 sign = fr2+3
123 = 00EA digit2 = fr2+4
124
125 ;skip initial spaces
126 D800 20 A1 DB jsr skpspc
127
128 ;init FR0 and one extra mantissa byte
129 D803 A9 7F lda #$7f
130 D805 85 D4 sta fr0
131 D807 85 EA sta digit2
132
133 D809 A2 D5 ldx #fr0+1
134 D80B 20 46 DA jsr zf1
135
136 ;clear decimal flag
137 D80E 85 E6 sta dotflag
138 D810 85 E9 sta sign
139
140 ;check for sign
141 D812 A4 F2 ldy cix
142 D814 B1 F3 lda (inbuff),y
143 D816 C9 2B cmp #'+'
144 D818 F0 06 beq isplus
145 D81A C9 2D cmp #'-'
146 D81C D0 03 bne postsign
147 D81E 66 E9 ror sign
148 D820 isplus:
149 D820 C8 iny
150 D821 postsign:
151 D821 84 E8 sty cix0
152
153 ;skip leading zeroes
154 D823 A9 30 lda #'0'
155 D825 20 A5 DB jsr fp_skipchar
156
157 ;check if next char is a dot, indicating mantissa <1
158 D828 B1 F3 lda (inbuff),y
159 D82A C9 2E cmp #'.'
160 D82C D0 10 bne not_tiny
161 D82E C8 iny
162
163 ;set dot flag
164 D82F 66 E6 ror dotflag
165
166 ;increment anchor so we don't count the dot as a digit for purposes
167 ;of seeing if we got any digits
168 D831 E6 E8 inc cix0
169
170 ;skip zeroes and adjust exponent
171 D833 A9 30 lda #'0'
172 D835 tiny_denorm_loop:
173 D835 D1 F3 cmp (inbuff),y
174 D837 D0 05 bne tiny_denorm_loop_exit
175 D839 C6 D4 dec fr0
176 D83B C8 iny
177 D83C D0 F7 bne tiny_denorm_loop
178 D83E tiny_denorm_loop_exit:
179
180 D83E not_tiny:
181
182 ;grab digits left of decimal point
183 D83E A2 01 ldx #1
184 D840 nextdigit:
185 D840 B1 F3 lda (inbuff),y
186 D842 C9 45 cmp #'E'
187 D844 F0 55 beq isexp
188 D846 C8 iny
189 D847 C9 2E cmp #'.'
190 D849 F0 28 beq isdot
191 D84B 49 30 eor #'0'
192 D84D C9 0A cmp #10
193 D84F B0 2A bcs termcheck
194
195 ;write digit if we haven't exceeded digit count
196 D851 E0 06 cpx #6
197 D853 B0 15 bcs afterwrite
198
199 D855 24 EA bit digit2
200 D857 10 09 bpl writehi
201
202 ;clear second digit flag
203 D859 C6 EA dec digit2
204
205 ;merge in low digit
206 D85B 15 D4 ora fr0,x
207 D85D 95 D4 sta fr0,x
208
209 ;advance to next byte
210 D85F E8 inx
211 D860 D0 08 bne afterwrite
212
213 D862 writehi:
214 ;set second digit flag
215 D862 E6 EA inc digit2
216
217 ;shift digit to high nibble and write
218 D864 0A asl
219 D865 0A asl
220 D866 0A asl
221 D867 0A asl
222 D868 95 D4 sta fr0,x
223
224 D86A afterwrite:
225 ;adjust digit exponent if we haven't seen a dot yet
226 D86A 24 E6 bit dotflag
227 D86C 30 02 E6 D4 smi:inc fr0
228
229 ;go back for more
230 D870 4C 40 D8 jmp nextdigit
231
232 D873 isdot:
233 D873 A5 E6 lda dotflag
234 D875 D0 04 bne termcheck
235
236 ;set the dot flag and loop back for more
237 D877 66 E6 ror dotflag
238 D879 D0 C5 bne nextdigit
239
240 D87B termcheck:
241 D87B 88 dey
242 D87C C4 E8 cpy cix0
243 D87E F0 1A beq err_carryset
244 D880 term:
245 ;stash offset
246 D880 84 F2 sty cix
247
248 D882 term_rollback_exp:
249 ;divide digit exponent by two and merge in sign
250 D882 26 E9 rol sign
251 D884 66 D4 ror fr0
252
253 ;check if we need a one digit shift
254 D886 B0 0F bcs nodigitshift
255
256 ;shift right one digit
257 D888 A2 04 ldx #4
258 D88A digitshift:
259 D88A 46 D5 lsr fr0+1
260 D88C 66 D6 ror fr0+2
261 D88E 66 D7 ror fr0+3
262 D890 66 D8 ror fr0+4
263 D892 66 D9 ror fr0+5
264 D894 CA dex
265 D895 D0 F3 bne digitshift
266
267 D897 nodigitshift:
268 D897 4C 00 DC jmp fp_normalize
269
270 D89A err_carryset:
271 D89A 60 rts
272
273 D89B isexp:
274 D89B C4 E8 cpy cix0
275 D89D F0 FB beq err_carryset
276
277 ;save off this point as a fallback in case we don't actually have
278 ;exponential notation
279 D89F 84 F2 sty cix
280
281 ;check for sign
282 D8A1 A2 00 ldx #0
283 D8A3 C8 iny
284 D8A4 B1 F3 lda (inbuff),y
285 D8A6 C9 2B cmp #'+'
286 D8A8 F0 05 beq isexpplus
287 D8AA C9 2D cmp #'-'
288 D8AC D0 02 bne postexpsign
289 D8AE CA dex ;x=$ff
290 D8AF isexpplus:
291 D8AF C8 iny
292 D8B0 postexpsign:
293 D8B0 86 E7 stx xinvert
294
295 ;pull up to two exponent digits -- check first digit
296 D8B2 20 B1 DB jsr fp_isdigit_y
297 D8B5 C8 iny
298 D8B6 B0 CA bcs term_rollback_exp
299
300 ;stash first digit
301 D8B8 AA tax
302
303 ;check for another digit
304 D8B9 20 B1 DB jsr fp_isdigit_y
305 D8BC B0 05 bcs notexpzero2
306 D8BE C8 iny
307
308 D8BF 7D 39 DA adc fp_mul10,x
309 D8C2 AA tax
310 D8C3 notexpzero2:
311 D8C3 8A txa
312
313 ;zero is not a valid exponent
314 D8C4 F0 BC beq term_rollback_exp
315
316 ;check if mantissa is zero -- if so, don't bias
317 ; ldx fr0+1
318 ; beq term
319
320 ;apply sign to exponent
321 D8C6 45 E7 eor xinvert
322 D8C8 26 E7 rol xinvert
323
324 ;bias digit exponent
325 D8CA 65 D4 adc fr0
326 D8CC 85 D4 sta fr0
327 D8CE expterm:
328 D8CE 4C 80 D8 jmp term
329
330 .endp
331
332 ;==========================================================================
333 D8D1 .proc fp_fmul_carryup
334 D8D1 round_loop:
335 D8D1 75 D4 adc fr0,x
336 D8D3 95 D4 sta fr0,x
337 D8D5 dec_entry:
338 D8D5 CA dex
339 D8D6 A9 00 lda #0
340 D8D8 B0 F7 bcs round_loop
341 D8DA 60 rts
342 .endp
343
344 ;==========================================================================
345 D8DB .proc fp_tab_lo_100
346 D8DB 00 64 C8 2C 90 F4 + :10 dta <[100*#]
347 .endp
348
349 ;==========================================================================
350 D8E5 fixadr $d8e6
Macro: FIXADR [Source: source/Shared/mathpack.s]
2 .print ($D8E6-*),' bytes free before ',$D8E6
2 $0001 bytes free before $D8E6
3 D8E5 org $D8E6
Source: source/Shared/mathpack.s
351 = D8E6 _fasc = fasc
352 D8E6 .proc fasc
353 = 00F7 dotcntr = ztemp4
354 = 00F8 expval = ztemp4+1
355 = 00F9 trimbase = ztemp4+2
356 D8E6 20 51 DA jsr ldbufa
357 D8E9 A0 00 ldy #0
358
359 ;read exponent and check if number is zero
360 D8EB A5 D4 lda fr0
361 D8ED D0 05 bne notzero
362
363 D8EF A9 B0 lda #$b0
364 D8F1 91 F3 sta (inbuff),y
365 D8F3 60 rts
366
367 D8F4 notzero:
368 D8F4 84 F8 sty expval
369 D8F6 84 F9 sty trimbase
370
371 ;insert sixth mantissa byte
372 D8F8 84 D4 sty fr0
373
374 ;check if number is negative
375 D8FA 10 0A bpl ispos
376 D8FC A2 2D ldx #'-'
377 D8FE C6 F3 dec inbuff
378 D900 8E 7F 05 stx lbuff-1
379 D903 E6 F9 inc trimbase
380 D905 C8 iny
381 D906 ispos:
382
383 ;set up for 5 mantissa bytes
384 D906 A2 FB ldx #-5
385
386 ;compute digit offset to place dot
387 ; 0.001 (10.0E-04) = 3E 10 00 00 00 00 -> -1
388 ; 0.01 ( 1.0E-02) = 3F 01 00 00 00 00 -> 1
389 ; 0.1 (10.0E-02) = 3F 10 00 00 00 00 -> 1
390 ; 1.0 ( 1.0E+00) = 40 01 00 00 00 00 -> 3
391 ; 10.0 (10.0E+00) = 40 10 00 00 00 00 -> 3
392 ; 100.0 ( 1.0E+02) = 40 01 00 00 00 00 -> 5
393 ; 1000.0 (10.0E+02) = 40 10 00 00 00 00 -> 5
394
395 D908 0A asl
396 D909 38 sec
397 D90A E9 7D sbc #125
398
399 ;check if we should go to exponential form (exp >= 10 or <=-3)
400 D90C C9 0C cmp #12
401 D90E 90 0A bcc noexp
402
403 ;yes - compute and stash explicit exponent
404 D910 E9 02 sbc #2 ;!! - carry set from BCC fail
405 D912 85 F8 sta expval ;$0A <= expval < $FE
406
407 ;reset dot counter
408 D914 A9 02 lda #2
409
410 ;exclude first two digits from zero trim
411 D916 E6 F9 inc trimbase
412 D918 E6 F9 inc trimbase
413
414 D91A noexp:
415 ;check if number is less than 1.0 and init dot counter
416 D91A C9 02 cmp #2
417 D91C B0 03 bcs not_tiny
418
419 ;use sixth mantissa byte
420 D91E 69 02 adc #2
421 D920 CA dex
422 D921 not_tiny:
423 D921 85 F7 sta dotcntr ;$02 <= dotcntr < $0C
424
425 ;check if number begins with a leading zero
426 D923 B5 DA lda fr0+6,x
427 D925 C9 10 cmp #$10
428 D927 B0 0C bcs digitloop
429
430 D929 C6 F9 dec trimbase
431
432 ;yes - skip the high digit
433 D92B 46 F8 lsr expval
434 D92D 06 F8 asl expval
435 D92F D0 18 bne writelow
436 D931 C6 F7 dec dotcntr
437 D933 90 14 bcc writelow
438
439 ;write out mantissa digits
440 D935 digitloop:
441 D935 C6 F7 dec dotcntr
442 D937 D0 05 bne no_hidot
443 D939 A9 2E lda #'.'
444 D93B 91 F3 sta (inbuff),y
445 D93D C8 iny
446 D93E no_hidot:
447
448 ;write out high digit
449 D93E B5 DA lda fr0+6,x
450 D940 4A lsr
451 D941 4A lsr
452 D942 4A lsr
453 D943 4A lsr
454 D944 09 30 ora #$30
455 D946 91 F3 sta (inbuff),y
456 D948 C8 iny
457
458 D949 writelow:
459 ;write out low digit
460 D949 C6 F7 dec dotcntr
461 D94B D0 05 bne no_lodot
462 D94D A9 2E lda #'.'
463 D94F 91 F3 sta (inbuff),y
464 D951 C8 iny
465 D952 no_lodot:
466
467 D952 B5 DA lda fr0+6,x
468 D954 29 0F and #$0f
469 D956 09 30 ora #$30
470 D958 91 F3 sta (inbuff),y
471 D95A C8 iny
472
473 ;next digit
474 D95B E8 inx
475 D95C D0 D7 bne digitloop
476
477 ;skip trim if dot hasn't been written
478 D95E A5 F7 lda dotcntr
479 D960 10 11 bpl skip_zero_trim
480
481 ;trim off leading zeroes
482 D962 A9 30 lda #'0'
483 D964 lzloop:
484 D964 C4 F9 cpy trimbase
485 D966 F0 05 beq stop_zero_trim
486 D968 88 dey
487 D969 D1 F3 cmp (inbuff),y
488 D96B F0 F7 beq lzloop
489
490 ;trim off dot
491 D96D stop_zero_trim:
492 D96D B1 F3 lda (inbuff),y
493 D96F C9 2E cmp #'.'
494 D971 D0 03 bne no_trailing_dot
495
496 D973 skip_zero_trim:
497 D973 88 dey
498 D974 B1 F3 lda (inbuff),y
499 D976 no_trailing_dot:
500
501 ;check if we have an exponent to deal with
502 D976 A6 F8 ldx expval
503 D978 F0 26 beq noexp2
504
505 ;print an 'E'
506 D97A A9 45 lda #'E'
507 D97C C8 iny
508 D97D 91 F3 sta (inbuff),y
509
510 ;check for a negative exponent
511 D97F 8A txa
512 D980 10 07 bpl exppos
513 D982 49 FF eor #$ff
514 D984 AA tax
515 D985 E8 inx
516 D986 A9 2D lda #'-'
517 D988 2C dta {bit $0100}
518 D989 exppos:
519 D989 A9 2B lda #'+'
520 D98B expneg:
521 D98B C8 iny
522 D98C 91 F3 sta (inbuff),y
523
524 ;print tens digit, if any
525 D98E 8A txa
526 D98F 38 sec
527 D990 A2 2F ldx #$2f
528 D992 tensloop:
529 D992 E8 inx
530 D993 E9 0A sbc #10
531 D995 B0 FB bcs tensloop
532 D997 48 pha
533 D998 8A txa
534 D999 C8 iny
535 D99A 91 F3 sta (inbuff),y
536 D99C 68 pla
537 D99D 69 3A adc #$3a
538 D99F C8 iny
539 D9A0 noexp2:
540 ;set high bit on last char
541 D9A0 09 80 ora #$80
542 D9A2 91 F3 sta (inbuff),y
543 D9A4 60 rts
544 .endp
545
546 ;==========================================================================
547 ; IPF [D9AA] Convert 16-bit integer at FR0 to FP
548 ;
549 ; !NOTE! Cannot use FR2/FR3 -- MAC/65 requires that $DE-DF be preserved.
550 ;
551 D9A5 fixadr $d9aa
Macro: FIXADR [Source: source/Shared/mathpack.s]
2 .print ($D9AA-*),' bytes free before ',$D9AA
2 $0005 bytes free before $D9AA
3 D9A5 org $D9AA
Source: source/Shared/mathpack.s
552 D9AA .proc ipf
553 D9AA F8 sed
554
555 D9AB A2 D6 ldx #fr0+2
556 D9AD A0 05 ldy #5
557 D9AF 20 48 DA jsr zfl
558
559 D9B2 A0 10 ldy #16
560 D9B4 byteloop:
561 ;shift out binary bit
562 D9B4 06 D4 asl fr0
563 D9B6 26 D5 rol fr0+1
564
565 ;shift in BCD bit
566 D9B8 A5 D8 lda fr0+4
567 D9BA 65 D8 adc fr0+4
568 D9BC 85 D8 sta fr0+4
569 D9BE A5 D7 lda fr0+3
570 D9C0 65 D7 adc fr0+3
571 D9C2 85 D7 sta fr0+3
572 D9C4 26 D6 rol fr0+2
573
574 D9C6 88 dey
575 D9C7 D0 EB bne byteloop
576
577 D9C9 A9 43 lda #$43
578 D9CB 85 D4 sta fr0
579
580 D9CD 4C FF DB jmp fp_normalize_cld
581 .endp
582
583 ;==========================================================================
584 ; FPI [D9D2] Convert FR0 to 16-bit integer at FR0 with rounding
585 ;
586 ; This cannot overwrite FR1. Darg relies on being able to stash a value
587 ; there across a call to FPI in its startup.
588 ;
589 D9D0 fixadr $d9d2
Macro: FIXADR [Source: source/Shared/mathpack.s]
2 .print ($D9D2-*),' bytes free before ',$D9D2
2 $0002 bytes free before $D9D2
3 D9D0 org $D9D2
Source: source/Shared/mathpack.s
590 D9D2 .nowarn .proc fpi
591 = 00E6 _acc0 = fr2
592 = 00E7 _acc1 = fr2+1
593
594 ;error out if it's guaranteed to be too big or negative (>999999)
595 D9D2 A5 D4 lda fr0
596 D9D4 C9 43 cmp #$43
597 D9D6 B0 60 bcs err
598
599 ;zero number if it's guaranteed to be too small (<0.01)
600 D9D8 E9 3E sbc #$3f-1 ;!!- carry is clear
601 D9DA 90 68 bcc zfr0
602
603 D9DC AA tax
604
605 ;clear temp accum and set up rounding
606 D9DD A9 00 lda #0
607 D9DF B4 D5 ldy fr0+1,x
608 D9E1 C0 50 cpy #$50
609 D9E3 2A rol ;!! - clears carry too
610 D9E4 85 D4 sta fr0
611 D9E6 A9 00 lda #0
612
613 ;check for [0.01, 1)
614 D9E8 CA dex
615 D9E9 30 4B bmi done
616
617 ;convert ones/tens digit pair to binary (one result byte: 0-100)
618 D9EB B5 D5 lda fr0+1,x
619 D9ED 20 CD DA jsr fp_dectobin
620 D9F0 65 D4 adc fr0
621 D9F2 79 F6 DF adc fp_dectobin_tab,y
622 D9F5 18 clc
623 D9F6 85 D4 sta fr0
624 D9F8 A9 00 lda #0
625
626 ;check if we're done
627 D9FA CA dex
628 D9FB 30 39 bmi done
629
630 ;convert hundreds/thousands digit pair to binary (two result bytes: 0-10000)
631 D9FD B5 D5 lda fr0+1,x
632 D9FF 20 CD DA jsr fp_dectobin
633 DA02 A5 D4 lda fr0
634 DA04 79 48 DF adc fp_tab_lo_1000,y
635 DA07 85 D4 sta fr0
636 DA09 B9 52 DF lda fp_tab_hi_1000,y
637 DA0C 69 00 adc #0
638 DA0E 48 pha
639 DA0F B5 D5 lda fr0+1,x
640 DA11 29 0F and #$0f
641 DA13 A8 tay
642 DA14 A5 D4 lda fr0
643 DA16 79 DB D8 adc fp_tab_lo_100,y
644 DA19 85 D4 sta fr0
645 DA1B 68 pla
646 DA1C 79 5C DF adc fp_tab_hi_100,y
647
648 ;check if we're done
649 DA1F CA dex
650 DA20 30 14 bmi done
651
652 ;convert ten thousands digit pair to binary (two result bytes: 0-100000, overflow possible)
653 DA22 B4 D5 ldy fr0+1,x
654 DA24 C0 07 cpy #$07
655 DA26 B0 10 bcs err
656 DA28 AA tax
657 DA29 98 tya
658 DA2A 0A asl
659 DA2B 0A asl
660 DA2C 0A asl
661 DA2D 0A asl
662 DA2E 65 D4 adc fr0
663 DA30 85 D4 sta fr0
664 DA32 8A txa
665 DA33 79 65 DF adc fp_tab_hi_10000-1,y
666
667 DA36 done:
668 ;move result back to FR0, with rounding
669 DA36 85 D5 sta fr0+1
670 DA38 err:
671 DA38 60 rts
672 .endp
673
674 ;==========================================================================
675 DA39 fp_mul10:
676 DA39 00 0A 14 1E 28 32 + dta 0,10,20,30,40,50,60,70,80,90
677
678 ;==========================================================================
679 ; ZFR0 [DA44] Zero FR0
680 ; ZF1 [DA46] Zero float at (X)
681 ; ZFL [DA48] Zero float at (X) with length Y (UNDOCUMENTED)
682 ;
683 DA43 fixadr $da44
Macro: FIXADR [Source: source/Shared/mathpack.s]
2 .print ($DA44-*),' bytes free before ',$DA44
2 $0001 bytes free before $DA44
3 DA43 org $DA44
Source: source/Shared/mathpack.s
684 DA44 zfr0:
685 DA44 A2 D4 ldx #fr0
686 DA46 ckaddr $da46
Macro: CKADDR [Source: source/Shared/mathpack.s]
Source: source/Shared/mathpack.s
687 DA46 zf1:
688 DA46 A0 06 ldy #6
689 DA48 ckaddr $da48
Macro: CKADDR [Source: source/Shared/mathpack.s]
Source: source/Shared/mathpack.s
690 DA48 zfl:
691 DA48 A9 00 lda #0
692 DA4A zflloop:
693 DA4A 95 00 sta 0,x
694 DA4C E8 inx
695 DA4D 88 dey
696 DA4E D0 FA bne zflloop
697 DA50 60 rts
698
699 ;==========================================================================
700 ; LDBUFA [DA51] Set LBUFF to #INBUFF (UNDOCUMENTED)
701 ;
702 DA51 fixadr $da51
Macro: FIXADR [Source: source/Shared/mathpack.s]
Source: source/Shared/mathpack.s
703 DA51 ldbufa:
704 DA51 A9 80 85 F3 A9 05 + mwa #lbuff inbuff
705 DA59 60 rts
706
707 ;==========================================================================
708 ; FPILL_SHL16 [DA5A] Shift left 16-bit word at $F7:F8 (UNDOCUMENTED)
709 ;
710 ; Illegal entry point used by MAC/65 when doing hex conversion.
711 ;
712 ; Yes, even the byte ordering is wrong.
713 ;
714 DA5A fixadr $da5a
Macro: FIXADR [Source: source/Shared/mathpack.s]
Source: source/Shared/mathpack.s
715
716 DA5A .nowarn .proc fpill_shl16
717 DA5A 06 F8 asl $f8
718 DA5C 26 F7 rol $f7
719 DA5E 60 rts
720 .endp
721
722 ;** 1 byte free**
723
724 ;==========================================================================
725 ; FSUB [DA60] Subtract FR1 from FR0; FR1 is altered
726 ; FADD [DA66] Add FR1 to FR0; FR1 is altered
727 DA5F fixadr $da60
Macro: FIXADR [Source: source/Shared/mathpack.s]
2 .print ($DA60-*),' bytes free before ',$DA60
2 $0001 bytes free before $DA60
3 DA5F org $DA60
Source: source/Shared/mathpack.s
728 = DA66 fadd = fsub._fadd
729 DA60 .proc fsub
730
731 = 00E0 _diffmode = fr1
732
733 ;toggle sign on FR1
734 DA60 A5 E0 lda fr1
735 DA62 49 80 eor #$80
736 DA64 85 E0 sta fr1
737
738 ;fall through to FADD
739
740 DA66 ckaddr $da66
Macro: CKADDR [Source: source/Shared/mathpack.s]
Source: source/Shared/mathpack.s
741 DA66 _fadd:
742 ;if fr1 is zero, we're done
743 DA66 A5 E0 lda fr1
744 DA68 F0 4E beq sum_xit
745
746 ;if fr0 is zero, swap
747 DA6A A5 D4 lda fr0
748 DA6C F0 0E beq swap
749
750 ;compute difference in exponents, ignoring sign
751 DA6E A5 E0 lda fr1 ;load fr1 sign
752 DA70 45 D4 eor fr0 ;compute fr0 ^ fr1 signs
753 DA72 29 80 and #$80 ;mask to just sign
754 DA74 AA tax
755 DA75 45 E0 eor fr1 ;flip fr1 sign to match fr0
756 DA77 18 clc
757 DA78 E5 D4 sbc fr0 ;compute difference in exponents - 1
758 DA7A 90 05 bcc noswap
759
760 ;swap FR0 and FR1
761 DA7C swap:
762 DA7C 20 74 DD jsr fp_swap
763
764 ;loop back and retry
765 DA7F 30 E5 bmi _fadd
766
767 DA81 noswap:
768 ;A = FR1 - FR0 - 1
769 ;X = add/sub flag
770
771 ;compute positions for add/subtract
772 DA81 69 06 adc #6 ;A = (FR1) - (FR0) + 6 !! carry is clear coming in
773 DA83 A8 tay
774
775 ;check if FR1 is too small in magnitude to matter
776 DA84 30 32 bmi sum_xit
777
778 ;jump to decimal mode and prepare for add/sub loops
779 DA86 F8 sed
780
781 ;check if we are doing a sum or a difference
782 DA87 E0 80 cpx #$80
783 DA89 A2 05 ldx #5
784 DA8B B0 2E bcs do_subtract
785
786 ;set up rounding
787 DA8D A9 00 lda #0
788 DA8F C0 05 cpy #5
789 DA91 B0 03 bcs add_no_round
790 DA93 B9 E1 00 lda fr1+1,y
791 DA96 add_no_round:
792 DA96 C9 50 cmp #$50
793
794 ;add mantissas
795 DA98 98 tya
796 DA99 F0 0B beq post_add_loop
797 DA9B add_loop:
798 DA9B B9 E0 00 lda fr1,y
799 DA9E 75 D4 adc fr0,x
800 DAA0 95 D4 sta fr0,x
801 DAA2 CA dex
802 DAA3 88 dey
803 DAA4 D0 F5 bne add_loop
804 DAA6 post_add_loop:
805
806 ;check if we had a carry out
807 DAA6 90 10 bcc sum_xit
808
809 ;carry it up
810 DAA8 B0 08 bcs sum_carryloop_start
811 DAAA sum_carryloop:
812 DAAA B5 D5 lda fr0+1,x
813 DAAC 69 00 adc #0
814 DAAE 95 D5 sta fr0+1,x
815 DAB0 90 06 bcc sum_xit
816 DAB2 sum_carryloop_start:
817 DAB2 CA dex
818 DAB3 10 F5 bpl sum_carryloop
819
820 DAB5 20 6A DE jsr fp_carry_expup
821
822 DAB8 sum_xit:
823 ;exit decimal mode
824 ;normalize if necessary and exit (needed for borrow, as well to check over/underflow)
825 DAB8 4C FF DB jmp fp_normalize_cld
826
827 DABB do_subtract:
828 ;subtract FR0 and FR1 mantissas (!! carry is set coming in)
829 DABB 84 E0 sty fr1
830 DABD B0 08 bcs sub_loop_entry
831 DABF sub_loop:
832 DABF B5 D4 lda fr0,x
833 DAC1 F9 E1 00 sbc fr1+1,y
834 DAC4 95 D4 sta fr0,x
835 DAC6 CA dex
836 DAC7 sub_loop_entry:
837 DAC7 88 dey
838 DAC8 10 F5 bpl sub_loop
839 DACA 4C 5E DC jmp fp_fsub_cont
840 .endp
841
842 ;==========================================================================
843 ; Entry:
844 ; A = BCD value
845 ; P.D = clear
846 ;
847 ; Exit:
848 ; A = binary value
849 ; Y = modified
850 ;
851 DACD .proc fp_dectobin
852 DACD 48 pha
853 DACE 4A lsr
854 DACF 4A lsr
855 DAD0 4A lsr
856 DAD1 4A lsr
857 DAD2 A8 tay
858 DAD3 68 pla
859 = DAD4 .def :fp_exit_success
860 DAD4 18 clc
861 DAD5 60 rts
862 .endp
863
864 ;==========================================================================
865 ; FMUL [DADB]: Multiply FR0 * FR1 -> FR0
866 ;
867 DAD6 fixadr $dad6
Macro: FIXADR [Source: source/Shared/mathpack.s]
Source: source/Shared/mathpack.s
868 DAD6 fp_fld1r_const_fmul:
869 DAD6 A0 DB ldy #>fpconst_ten
870 DAD8 fp_fld1r_fmul:
871 DAD8 20 98 DD jsr fld1r
872 DADB ckaddr $dadb
Macro: CKADDR [Source: source/Shared/mathpack.s]
Source: source/Shared/mathpack.s
873 DADB .proc fmul
874
875 ;We use FR0:FR3 as a double-precision accumulator, and copy the
876 ;original multiplicand value in FR0 to FR1. The multiplier in
877 ;FR1 is converted to binary digit pairs into FR2.
878
879 = 00DF _offset = _fr3+5
880 = 00E6 _offset2 = fr2
881
882 ;if FR0 is zero, we're done
883 DADB A5 D4 lda fr0
884 DADD F0 F5 beq fp_exit_success
885
886 ;if FR1 is zero, zero FR0 and exit
887 DADF A5 E0 lda fr1
888 DAE1 18 clc
889 DAE2 F0 17 beq fp_exit_zero
890
891 ;move fr0 to fr2
892 DAE4 20 79 DE jsr fp_fmul_fr0_to_binfr2
893
894 ;compute new exponent and stash
895 DAE7 A5 E0 lda fr1
896 DAE9 18 clc
897 DAEA 20 03 DB jsr fp_adjust_exponent.fmul_entry
898
899 DAED 85 D4 sta fr0
900 DAEF E6 D4 inc fr0
901
902 ;clear accumulator through to exponent byte of fr1
903 DAF1 A2 D5 ldx #fr0+1
904 DAF3 A0 0C ldy #12
905 DAF5 F8 sed
906
907 DAF6 4C C3 DC jmp fp_fmul_innerloop
908 .endp
909
910 DAF9 underflow_overflow:
911 DAF9 68 pla
912 DAFA 68 pla
913 DAFB fp_exit_zero:
914 DAFB 4C 44 DA jmp zfr0
915
916 DAFE .proc fp_adjust_exponent
917 DAFE fdiv_entry:
918 DAFE A5 E0 lda fr1
919 DB00 49 7F eor #$7f
920 DB02 38 sec
921 DB03 fmul_entry:
922 ;stash modified exp1
923 DB03 AA tax
924
925 ;compute new sign
926 DB04 45 D4 eor fr0
927 DB06 29 80 and #$80
928 DB08 85 E0 sta fr1
929
930 ;merge exponents
931 DB0A 8A txa
932 DB0B 65 D4 adc fr0
933 DB0D AA tax
934 DB0E 45 E0 eor fr1
935
936 ;check for underflow/overflow
937 DB10 C9 4F cmp #128-49
938 DB12 90 E5 bcc underflow_overflow
939
940 DB14 C9 B1 cmp #128+49
941 DB16 B0 E1 bcs underflow_overflow
942
943 ;rebias exponent
944 DB18 8A txa
945 DB19 E9 3F sbc #$40-1 ;!! - C=0 from bcs fail
946 DB1B 60 rts
947 .endp
948
949 ;==========================================================================
950 DB1C .pages 1 ;optimized by fp_fld1r_const_fmul
951
952 DB1C fpconst_ten:
953 DB1C 40 10 00 00 00 00 .fl 10
954
955 DB22 fpconst_ln10:
956 DB22 40 02 30 25 85 09 .fl 2.3025850929940456840179914546844
957
958 DB28 .endpg
959 ;==========================================================================
960 ; FDIV [DB28] Divide FR0 / FR1 -> FR0
961 ;
962 ; Compatibility:
963 ; - It is important that FDIV rounds if FADD/FMUL do. Otherwise, some
964 ; forms of square root computation can have a slight error on integers,
965 ; which breaks TICKTOCK.BAS.
966 ;
967 DB28 fixadr $db28
Macro: FIXADR [Source: source/Shared/mathpack.s]
Source: source/Shared/mathpack.s
968 DB28 .proc fdiv
969 = 00DB _digit = _fr3+1
970 = 00DC _index = _fr3+2
971 ;check if divisor is zero
972 DB28 A5 E0 lda fr1
973 DB2A F0 72 beq err
974
975 ;check if dividend is zero
976 DB2C A5 D4 lda fr0
977 DB2E F0 6C beq ok
978
979 ;compute new exponent
980 DB30 20 FE DA jsr fp_adjust_exponent.fdiv_entry
981
982 DB33 20 2D DC jsr fp_fdiv_init
983
984 DB36 digitloop:
985 ;just keep going if we're accurate
986 DB36 A5 D4 lda fr0
987 DB38 05 D5 ora fr0+1
988 DB3A F0 3D beq nextdigit
989
990 ;check if we should either divide or add based on current sign (stored in carry)
991 DB3C 90 05 bcc incloop
992
993 DB3E 20 B9 DB jsr fp_fdiv_decloop
994 DB41 90 36 bcc nextdigit
995
996 DB43 incloop:
997 ;decrement quotient mantissa byte
998 DB43 A9 00 lda #0
999 DB45 E5 DB sbc _digit
1000 DB47 A6 DC ldx _index
1001 DB49 downloop:
1002 DB49 75 ED adc fr2+7,x
1003 DB4B 95 ED sta fr2+7,x
1004 DB4D A9 99 lda #$99
1005 DB4F CA dex
1006 DB50 90 F7 bcc downloop
1007
1008 ;add mantissas
1009 DB52 18 clc
1010 .rept 6
1011 LDA FR0+(5-#)
1012 ADC FR1+(5-#)
1013 STA FR0+(5-#)
1014 .ENDR
1014 .endr
Source: REPT
1011 DB53 A5 D9 LDA FR0+(5-#)
1011 DB55 65 E5 ADC FR1+(5-#)
1011 DB57 85 D9 STA FR0+(5-#)
1011 DB59 A5 D8 LDA FR0+(5-#)
1011 DB5B 65 E4 ADC FR1+(5-#)
1011 DB5D 85 D8 STA FR0+(5-#)
1011 DB5F A5 D7 LDA FR0+(5-#)
1011 DB61 65 E3 ADC FR1+(5-#)
1011 DB63 85 D7 STA FR0+(5-#)
1011 DB65 A5 D6 LDA FR0+(5-#)
1011 DB67 65 E2 ADC FR1+(5-#)
1011 DB69 85 D6 STA FR0+(5-#)
1011 DB6B A5 D5 LDA FR0+(5-#)
1011 DB6D 65 E1 ADC FR1+(5-#)
1011 DB6F 85 D5 STA FR0+(5-#)
1011 DB71 A5 D4 LDA FR0+(5-#)
1011 DB73 65 E0 ADC FR1+(5-#)
1011 DB75 85 D4 STA FR0+(5-#)
Source: source/Shared/mathpack.s
1015
1016 ;keep going until we overflow
1017 DB77 90 CA bcc incloop
1018
1019 DB79 nextdigit:
1020 ;shift dividend (make sure to save carry state)
1021 DB79 08 php
1022 DB7A A2 04 ldx #4
1023 DB7C bitloop:
1024 DB7C 06 D9 asl fr0+5
1025 DB7E 26 D8 rol fr0+4
1026 DB80 26 D7 rol fr0+3
1027 DB82 26 D6 rol fr0+2
1028 DB84 26 D5 rol fr0+1
1029 DB86 26 D4 rol fr0
1030 DB88 CA dex
1031 DB89 D0 F1 bne bitloop
1032 DB8B 28 plp
1033
1034 ;next digit
1035 DB8C A5 DB lda _digit
1036 DB8E 49 09 eor #$09
1037 DB90 85 DB sta _digit
1038 DB92 F0 A2 beq digitloop
1039
1040 ;next quo byte
1041 DB94 E6 DC inc _index
1042 DB96 D0 9E bne digitloop
1043
1044 ;move back to fr0
1045 DB98 20 EE DB jsr fp_fdiv_complete
1046 DB9B D8 cld
1047 DB9C ok:
1048 DB9C 18 clc
1049 DB9D 60 rts
1050 DB9E err:
1051 DB9E 38 sec
1052 DB9F 60 rts
1053 .endp
1054
1055 ;==========================================================================
1056 ; SKPSPC [DBA1] Increment CIX while INBUFF[CIX] is a space
1057 DBA0 fixadr $dba1
Macro: FIXADR [Source: source/Shared/mathpack.s]
2 .print ($DBA1-*),' bytes free before ',$DBA1
2 $0001 bytes free before $DBA1
3 DBA0 org $DBA1
Source: source/Shared/mathpack.s
1058 DBA1 skpspc:
1059 DBA1 A9 20 lda #' '
1060 DBA3 A4 F2 ldy cix
1061 DBA5 fp_skipchar:
1062 DBA5 skpspc_loop:
1063 DBA5 D1 F3 cmp (inbuff),y
1064 DBA7 D0 03 bne skpspc_xit
1065 DBA9 C8 iny
1066 DBAA D0 F9 bne skpspc_loop
1067 DBAC skpspc_xit:
1068 DBAC 84 F2 sty cix
1069 DBAE 60 rts
1070
1071 ;==========================================================================
1072 ; ISDIGT [DBAF] Check if INBUFF[CIX] is a digit (UNDOCUMENTED)
1073 DBAF fixadr $dbaf
Macro: FIXADR [Source: source/Shared/mathpack.s]
Source: source/Shared/mathpack.s
1074 = DBAF isdigt = _isdigt
1075 DBAF .proc _isdigt
1076 DBAF A4 F2 ldy cix
1077 = DBB1 .def :fp_isdigit_y = *
1078 DBB1 B1 F3 lda (inbuff),y
1079 DBB3 38 sec
1080 DBB4 E9 30 sbc #'0'
1081 DBB6 C9 0A cmp #10
1082 DBB8 60 rts
1083 .endp
1084
1085 ;==========================================================================
1086 DBB9 .proc fp_fdiv_decloop
1087 DBB9 decloop:
1088 ;increment quotient mantissa byte
1089 DBB9 A5 DB lda fdiv._digit
1090 DBBB A6 DC ldx fdiv._index
1091 DBBD uploop:
1092 DBBD 75 ED adc fr2+7,x
1093 DBBF 95 ED sta fr2+7,x
1094 DBC1 A9 00 lda #0
1095 DBC3 CA dex
1096 DBC4 B0 F7 bcs uploop
1097
1098 ;subtract mantissas
1099 DBC6 38 sec
1100 DBC7 A5 D9 lda fr0+5
1101 DBC9 E5 E5 sbc fr1+5
1102 DBCB 85 D9 sta fr0+5
1103 DBCD A5 D8 lda fr0+4
1104 DBCF E5 E4 sbc fr1+4
1105 DBD1 85 D8 sta fr0+4
1106 DBD3 A5 D7 lda fr0+3
1107 DBD5 E5 E3 sbc fr1+3
1108 DBD7 85 D7 sta fr0+3
1109 DBD9 A5 D6 lda fr0+2
1110 DBDB E5 E2 sbc fr1+2
1111 DBDD 85 D6 sta fr0+2
1112 DBDF A5 D5 lda fr0+1
1113 DBE1 E5 E1 sbc fr1+1
1114 DBE3 85 D5 sta fr0+1
1115 DBE5 A5 D4 lda fr0
1116 DBE7 E9 00 sbc #0
1117 DBE9 85 D4 sta fr0
1118
1119 ;keep going until we underflow
1120 DBEB B0 CC bcs decloop
1121 DBED 60 rts
1122 .endp
1123
1124 DBEE .proc fp_fdiv_complete
1125 DBEE A2 E5 ldx #fr2-1
1126 DBF0 A4 DA ldy _fr3
1127 DBF2 A5 E6 lda fr2
1128 DBF4 D0 02 bne no_normstep
1129 DBF6 E8 inx
1130 DBF7 88 dey
1131 DBF8 no_normstep:
1132 DBF8 94 00 sty 0,x
1133 DBFA 4C 87 DD jmp fld0r_zp
1134 .endp
1135
1136 ;==========================================================================
1137 ; NORMALIZE [DC00] Normalize FR0 (UNDOCUMENTED)
1138 DBFD fixadr $dc00-1
Macro: FIXADR [Source: source/Shared/mathpack.s]
2 .print ($DC00-1-*),' bytes free before ',$DC00-1
2 $0002 bytes free before $DBFF
3 DBFD org $DC00-1
Source: source/Shared/mathpack.s
1139 DBFF fp_normalize_cld:
1140 DBFF D8 cld
1141 DC00 ckaddr $dc00
Macro: CKADDR [Source: source/Shared/mathpack.s]
Source: source/Shared/mathpack.s
1142 DC00 fp_normalize:
1143 DC00 .nowarn .proc normalize
1144 DC00 A0 05 ldy #5
1145 DC02 normloop:
1146 DC02 A5 D4 lda fr0
1147 DC04 29 7F and #$7f
1148 DC06 F0 21 beq underflow2
1149
1150 DC08 A6 D5 ldx fr0+1
1151 DC0A F0 07 beq need_norm
1152
1153 ;Okay, we're done normalizing... check if the exponent is in bounds.
1154 ;It needs to be within +/-48 to be valid. If the exponent is <-49,
1155 ;we set it to zero; otherwise, we mark overflow.
1156
1157 DC0C C9 0F cmp #64-49
1158 DC0E 90 1A bcc underflow
1159 DC10 C9 71 cmp #64+49
1160 DC12 60 rts
1161
1162 DC13 need_norm:
1163 DC13 C6 D4 dec fr0
1164 DC15 A2 FB ldx #-5
1165 DC17 normloop2:
1166 DC17 B5 DB 95 DA mva fr0+7,x fr0+6,x
1167 DC1B E8 inx
1168 DC1C D0 F9 bne normloop2
1169 DC1E 86 DA stx fr0+6
1170 DC20 88 dey
1171 DC21 D0 DF bne normloop
1172
1173 ;Hmm, we shifted out everything... must be zero; reset exponent. This
1174 ;is critical since Atari Basic depends on the exponent being zero for
1175 ;a zero result.
1176 DC23 84 D4 sty fr0
1177 DC25 84 D5 sty fr0+1
1178 DC27 xit:
1179 DC27 18 clc
1180 DC28 60 rts
1181
1182 DC29 underflow2:
1183 DC29 18 clc
1184 DC2A underflow:
1185 DC2A 4C 44 DA jmp zfr0
1186
1187 .endp
1188
1189 ;==========================================================================
1190 ; HELPER ROUTINES
1191 ;==========================================================================
1192
1193 DC2D .proc fp_fdiv_init
1194 DC2D 85 DA sta _fr3
1195
1196 DC2F A2 E6 ldx #fr2
1197 DC31 20 46 DA jsr zf1
1198 DC34 A9 50 lda #$50
1199 DC36 85 EC sta fr2+6
1200
1201 DC38 A2 00 ldx #0
1202 DC3A 86 D4 stx fr0
1203 DC3C 86 E0 stx fr1
1204
1205 ;check if dividend begins with a leading zero digit -- if so, shift it left 4
1206 ;and begin with the tens digit
1207 DC3E A5 E1 lda fr1+1
1208 DC40 C9 10 cmp #$10
1209 DC42 B0 11 bcs start_with_ones
1210
1211 DC44 A0 04 ldy #4
1212 DC46 bitloop:
1213 DC46 06 E5 asl fr1+5
1214 DC48 26 E4 rol fr1+4
1215 DC4A 26 E3 rol fr1+3
1216 DC4C 26 E2 rol fr1+2
1217 DC4E 26 E1 rol fr1+1
1218 DC50 88 dey
1219 DC51 D0 F3 bne bitloop
1220
1221 DC53 A2 09 ldx #$09
1222
1223 DC55 start_with_ones:
1224
1225 DC55 86 DB stx fdiv._digit
1226 DC57 F8 sed
1227
1228 DC58 A2 F9 ldx #0-7
1229 DC5A 86 DC stx fdiv._index
1230 DC5C 38 sec
1231 DC5D 60 rts
1232 .endp
1233
1234 ;--------------------------------------------------------------------------
1235 DC5E .proc fp_fsub_cont
1236 ;check if we had a borrow
1237 DC5E B0 1F bcs sub_xit
1238 DC60 90 08 bcc borrow_loop_start
1239
1240 ;propagate borrow up
1241 DC62 borrow_loop:
1242 DC62 B5 D5 lda fr0+1,x
1243 DC64 E9 00 sbc #0
1244 DC66 95 D5 sta fr0+1,x
1245 DC68 B0 15 bcs sub_xit
1246 DC6A borrow_loop_start:
1247 DC6A CA dex
1248 DC6B 10 F5 bpl borrow_loop
1249
1250 DC6D A2 05 ldx #5
1251 DC6F 38 sec
1252 DC70 diff_borrow:
1253 DC70 A9 00 lda #0
1254 DC72 F5 D4 sbc fr0,x
1255 DC74 95 D4 sta fr0,x
1256 DC76 CA dex
1257 DC77 D0 F7 bne diff_borrow
1258 DC79 A9 80 lda #$80
1259 DC7B 45 D4 eor fr0
1260 DC7D 85 D4 sta fr0
1261 DC7F sub_xit:
1262
1263 DC7F norm_loop:
1264 ;Check if the exponent is in bounds.
1265 ;It needs to be within +/-48 to be valid. If the exponent is <-49,
1266 ;we set it to zero. Overflow isn't possible as this is the mantissa
1267 ;subtraction path.
1268 DC7F A5 D4 lda fr0
1269 DC81 29 7F and #$7f
1270 DC83 C9 0F cmp #64-49
1271 DC85 90 1F bcc underflow
1272
1273 DC87 A6 D5 ldx fr0+1
1274 DC89 F0 0F beq need_norm
1275
1276 ;check if we need to round, i.e.:
1277 ; 2.00000000
1278 ;-0.000000005
1279 ;load rounding byte offset
1280 DC8B A6 E0 ldx fr1
1281 DC8D E0 04 cpx #4
1282 DC8F B0 06 bcs no_round
1283 DC91 B5 E2 lda fr1+2,x
1284 DC93 C9 50 cmp #$50
1285 DC95 B0 27 bcs round_up
1286 DC97 no_round:
1287
1288 DC97 18 clc
1289 DC98 D8 cld
1290 DC99 60 rts
1291
1292 DC9A need_norm:
1293 DC9A A2 FC ldx #-4
1294 DC9C scan_loop:
1295 DC9C C6 D4 dec fr0
1296 DC9E B4 DA ldy fr0+6,x
1297 DCA0 D0 08 bne found_pos
1298 DCA2 E8 inx
1299 DCA3 D0 F7 bne scan_loop
1300
1301 ;hmm... mantissa is all zero.
1302 DCA5 underflow2:
1303 DCA5 18 clc
1304 DCA6 underflow:
1305 DCA6 D8 cld
1306 DCA7 4C 44 DA jmp zfr0
1307
1308 DCAA found_pos:
1309 ;shift up mantissa
1310 DCAA A0 00 ldy #0
1311 DCAC shift_loop:
1312 DCAC B5 DA 99 D5 00 mva fr0+6,x fr0+1,y
1313 DCB1 C8 iny
1314 DCB2 E8 inx
1315 DCB3 D0 F7 bne shift_loop
1316
1317 ;clear remaining mantissa bytes
1318 DCB5 clear_loop:
1319 DCB5 96 D5 C8 stx fr0+1,y+
1320 DCB8 C0 06 cpy #6
1321 DCBA D0 F9 bne clear_loop
1322
1323 ;check if we need to round
1324
1325
1326 ;if not, loop back to check the exponent and exit
1327 ; bcc norm_loop
1328 DCBC F0 C1 beq norm_loop
1329
1330 DCBE round_up:
1331 ;jump back into fadd code to carry up and exit
1332 DCBE A2 05 ldx #5
1333 DCC0 4C AA DA jmp fsub.sum_carryloop
1334 .endp
1335
1336 ;--------------------------------------------------------------------------
1337 DCC3 .proc fp_fmul_innerloop
1338 = 00DF _offset = _fr3+5
1339 = 00E6 _offset2 = fr2
1340
1341 DCC3 20 48 DA jsr zfl
1342
1343 ;set up for 7 bits per digit pair (0-99 in 0-127)
1344 DCC6 A0 07 ldy #7
1345
1346 ;set rounding byte, assuming renormalize needed (fr0+2 through fr0+6)
1347 DCC8 A9 50 lda #$50
1348 DCCA 85 DB sta fr0+7
1349
1350 ;begin outer loop -- this is where we process one _bit_ out of each
1351 ;multiplier byte in FR2's mantissa (note that this is inverted in that
1352 ;it is bytes-in-bits instead of bits-in-bytes)
1353 DCCC offloop:
1354
1355 ;begin inner loop -- here we process the same bit in each multiplier
1356 ;byte, going from byte 5 down to byte 1
1357 DCCC A2 05 ldx #5
1358 DCCE offloop2:
1359 ;shift an inverted bit out of fr1 mantissa
1360 DCCE 56 E6 lsr fr2,x
1361 DCD0 B0 2D bcs noadd
1362
1363 ;add fr1 to fr0 at offset
1364 .rept 6
1365 LDA FR0+(5-#),X
1366 ADC FR1+(5-#)
1367 STA FR0+(5-#),X
1368 .ENDR
1368 .endr
Source: REPT
1365 DCD2 B5 D9 LDA FR0+(5-#),X
1365 DCD4 65 E5 ADC FR1+(5-#)
1365 DCD6 95 D9 STA FR0+(5-#),X
1365 DCD8 B5 D8 LDA FR0+(5-#),X
1365 DCDA 65 E4 ADC FR1+(5-#)
1365 DCDC 95 D8 STA FR0+(5-#),X
1365 DCDE B5 D7 LDA FR0+(5-#),X
1365 DCE0 65 E3 ADC FR1+(5-#)
1365 DCE2 95 D7 STA FR0+(5-#),X
1365 DCE4 B5 D6 LDA FR0+(5-#),X
1365 DCE6 65 E2 ADC FR1+(5-#)
1365 DCE8 95 D6 STA FR0+(5-#),X
1365 DCEA B5 D5 LDA FR0+(5-#),X
1365 DCEC 65 E1 ADC FR1+(5-#)
1365 DCEE 95 D5 STA FR0+(5-#),X
1365 DCF0 B5 D4 LDA FR0+(5-#),X
1365 DCF2 65 E0 ADC FR1+(5-#)
1365 DCF4 95 D4 STA FR0+(5-#),X
Source: source/Shared/mathpack.s
1369
1370 ;check if we have a carry out to the upper bytes
1371 DCF6 90 07 bcc no_carry
1372 DCF8 86 E6 stx _offset2
1373 DCFA 20 D5 D8 jsr fp_fmul_carryup.dec_entry
1374 DCFD A6 E6 ldx _offset2
1375 DCFF no_carry:
1376
1377 DCFF noadd:
1378 ;go back for next byte
1379 DCFF CA dex
1380 DD00 D0 CC bne offloop2
1381
1382 ;double fr1
1383 DD02 18 clc
1384 DD03 A5 E5 lda fr1+5
1385 DD05 65 E5 adc fr1+5
1386 DD07 85 E5 sta fr1+5
1387 DD09 A5 E4 lda fr1+4
1388 DD0B 65 E4 adc fr1+4
1389 DD0D 85 E4 sta fr1+4
1390 DD0F A5 E3 lda fr1+3
1391 DD11 65 E3 adc fr1+3
1392 DD13 85 E3 sta fr1+3
1393 DD15 A5 E2 lda fr1+2
1394 DD17 65 E2 adc fr1+2
1395 DD19 85 E2 sta fr1+2
1396 DD1B A5 E1 lda fr1+1
1397 DD1D 65 E1 adc fr1+1
1398 DD1F 85 E1 sta fr1+1
1399 DD21 A5 E0 lda fr1+0
1400 DD23 65 E0 adc fr1+0
1401 DD25 85 E0 sta fr1+0
1402
1403 ;loop back until all mantissa bytes finished
1404 DD27 88 dey
1405 DD28 D0 A2 bne offloop
1406
1407 ;check if no renormalize is needed, and if so, re-add new rounding
1408 DD2A A5 D5 lda fr0+1
1409 DD2C F0 07 beq renorm_needed
1410
1411 DD2E A9 50 lda #$50
1412 DD30 A2 06 ldx #6
1413 DD32 20 D1 D8 jsr fp_fmul_carryup
1414
1415 DD35 renorm_needed:
1416 ;all done
1417 DD35 4C FF DB jmp fp_normalize_cld
1418 .endp
1419
1420 ;==========================================================================
1421 ; PLYEVL [DD40] Eval polynomial at (X:Y) with A coefficients using FR0
1422 ;
1423 DD38 fixadr $dd3e
Macro: FIXADR [Source: source/Shared/mathpack.s]
2 .print ($DD3E-*),' bytes free before ',$DD3E
2 $0006 bytes free before $DD3E
3 DD38 org $DD3E
Source: source/Shared/mathpack.s
1424 DD3E fp_plyevl_10:
1425 DD3E A9 0A lda #10
1426 DD40 .nowarn .proc plyevl
1427 ;stash arguments
1428 DD40 86 FE stx fptr2
1429 DD42 84 FF sty fptr2+1
1430 DD44 85 EC sta _fpcocnt
1431
1432 ;copy FR0 -> PLYARG
1433 DD46 A2 E0 ldx #<plyarg
1434 DD48 A0 05 ldy #>plyarg
1435 DD4A 20 A7 DD jsr fst0r
1436
1437 DD4D 20 44 DA jsr zfr0
1438
1439 DD50 loop:
1440 ;load next coefficient and increment coptr
1441 DD50 A5 FE lda fptr2
1442 DD52 AA tax
1443 DD53 18 clc
1444 DD54 69 06 adc #6
1445 DD56 85 FE sta fptr2
1446 DD58 A4 FF ldy fptr2+1
1447 DD5A 90 02 E6 FF scc:inc fptr2+1
1448 DD5E 20 98 DD jsr fld1r
1449
1450 ;add coefficient to acc
1451 DD61 20 66 DA jsr fadd
1452 DD64 B0 0D bcs xit
1453
1454 DD66 C6 EC dec _fpcocnt
1455 DD68 F0 09 beq xit
1456
1457 ;copy PLYARG -> FR1
1458 ;multiply accumulator by Z and continue
1459 DD6A A2 E0 ldx #<plyarg
1460 DD6C A0 05 ldy #>plyarg
1461 DD6E 20 D8 DA jsr fp_fld1r_fmul
1462 DD71 90 DD bcc loop
1463 DD73 xit:
1464 DD73 60 rts
1465 .endp
1466
1467 ;==========================================================================
1468 DD74 .proc fp_swap
1469 DD74 A2 05 ldx #5
1470 DD76 swaploop:
1471 DD76 B5 D4 lda fr0,x
1472 DD78 B4 E0 ldy fr1,x
1473 DD7A 95 E0 sta fr1,x
1474 DD7C 94 D4 sty fr0,x
1475 DD7E CA dex
1476 DD7F 10 F5 bpl swaploop
1477 DD81 60 rts
1478 .endp
1479
1480 ;==========================================================================
1481 ; FLD0R [DD89] Load FR0 from (X:Y)
1482 ; FLD0P [DD8D] Load FR0 from (FLPTR)
1483 ;
1484 DD82 fixadr $dd87
Macro: FIXADR [Source: source/Shared/mathpack.s]
2 .print ($DD87-*),' bytes free before ',$DD87
2 $0005 bytes free before $DD87
3 DD82 org $DD87
Source: source/Shared/mathpack.s
1485 DD87 fld0r_zp:
1486 DD87 A0 00 ldy #0
1487 DD89 ckaddr $dd89
Macro: CKADDR [Source: source/Shared/mathpack.s]
Source: source/Shared/mathpack.s
1488 DD89 fld0r:
1489 DD89 86 FC stx flptr
1490 DD8B 84 FD sty flptr+1
1491 DD8D ckaddr $dd8d
Macro: CKADDR [Source: source/Shared/mathpack.s]
Source: source/Shared/mathpack.s
1492 DD8D fld0p:
1493 DD8D A0 05 ldy #5
1494 DD8F fld0ploop:
1495 DD8F B1 FC lda (flptr),y
1496 DD91 99 D4 00 sta fr0,y
1497 DD94 88 dey
1498 DD95 10 F8 bpl fld0ploop
1499 DD97 60 rts
1500
1501 ;==========================================================================
1502 ; FLD1R [DD98] Load FR1 from (X:Y)
1503 ; FLD1P [DD9C] Load FR1 from (FLPTR)
1504 ;
1505 DD98 fixadr $dd98
Macro: FIXADR [Source: source/Shared/mathpack.s]
Source: source/Shared/mathpack.s
1506 DD98 fld1r:
1507 DD98 86 FC stx flptr
1508 DD9A 84 FD sty flptr+1
1509 DD9C ckaddr $dd9c
Macro: CKADDR [Source: source/Shared/mathpack.s]
Source: source/Shared/mathpack.s
1510 DD9C fld1p:
1511 DD9C A0 05 ldy #5
1512 DD9E fld1ploop:
1513 DD9E B1 FC lda (flptr),y
1514 DDA0 99 E0 00 sta fr1,y
1515 DDA3 88 dey
1516 DDA4 10 F8 bpl fld1ploop
1517 DDA6 60 rts
1518
1519 ;==========================================================================
1520 ; FST0R [DDA7] Store FR0 to (X:Y)
1521 ; FST0P [DDAB] Store FR0 to (FLPTR)
1522 ;
1523 DDA7 fixadr $dda7
Macro: FIXADR [Source: source/Shared/mathpack.s]
Source: source/Shared/mathpack.s
1524 DDA7 fst0r:
1525 DDA7 86 FC stx flptr
1526 DDA9 84 FD sty flptr+1
1527 DDAB ckaddr $ddab
Macro: CKADDR [Source: source/Shared/mathpack.s]
Source: source/Shared/mathpack.s
1528 DDAB fst0p:
1529 DDAB A0 05 ldy #5
1530 DDAD fst0ploop:
1531 DDAD B9 D4 00 lda fr0,y
1532 DDB0 91 FC sta (flptr),y
1533 DDB2 88 dey
1534 DDB3 10 F8 bpl fst0ploop
1535 DDB5 60 rts
1536
1537 ;==========================================================================
1538 ; FMOVE [DDB6] Move FR0 to FR1
1539 ;
1540 DDB6 fixadr $ddb6
Macro: FIXADR [Source: source/Shared/mathpack.s]
Source: source/Shared/mathpack.s
1541 DDB6 fmove:
1542 DDB6 A2 05 ldx #5
1543 DDB8 fmoveloop:
1544 DDB8 B5 D4 lda fr0,x
1545 DDBA 95 E0 sta fr1,x
1546 DDBC CA dex
1547 DDBD 10 F9 bpl fmoveloop
1548 DDBF 60 rts
1549
1550 ;==========================================================================
1551 ; EXP [DDC0] Compute e^x
1552 ; EXP10 [DDCC] Compute 10^x
1553 ;
1554 DDC0 fixadr $ddc0
Macro: FIXADR [Source: source/Shared/mathpack.s]
Source: source/Shared/mathpack.s
1555 = DDCC exp10 = exp._exp10
1556 DDC0 .proc exp
1557 DDC0 A2 64 ldx #<fpconst_log10_e
1558 DDC2 A0 DE ldy #>fpconst_log10_e
1559 DDC4 20 98 DD jsr fld1r ;we could use fp_fld1r_fmul, but then we have a hole :(
1560 DDC7 20 DB DA jsr fmul
1561 DDCA B0 5B bcs err2
1562
1563 DDCC ckaddr $ddcc
Macro: CKADDR [Source: source/Shared/mathpack.s]
Source: source/Shared/mathpack.s
1564 DDCC _exp10:
1565 ;stash sign and compute abs
1566 DDCC A5 D4 lda fr0
1567 DDCE 85 EE sta _fptemp1
1568 DDD0 29 7F and #$7f
1569 DDD2 85 D4 sta fr0
1570
1571 DDD4 A0 00 ldy #0
1572
1573 ;check for |exp| >= 100 which would guarantee over/underflow
1574 DDD6 C9 40 cmp #$40
1575 DDD8 90 1E bcc abs_ok
1576 DDDA F0 08 beq abs_large
1577
1578 DDDC abs_too_big:
1579 ;okay, the |x| is too big... check if the original was negative.
1580 ;if so, zero and exit, otherwise error.
1581 DDDC A5 EE lda _fptemp1
1582 DDDE 10 47 bpl err2
1583 DDE0 18 clc
1584 DDE1 4C 44 DA jmp zfr0
1585
1586 DDE4 abs_large:
1587 ;|exp|>=1, so split it into integer/fraction
1588 DDE4 A5 D5 lda fr0+1
1589 DDE6 20 CD DA jsr fp_dectobin
1590 DDE9 79 F6 DF adc fp_dectobin_tab,y
1591 DDEC 48 pha
1592 DDED A9 00 lda #0
1593 DDEF 85 D5 sta fr0+1
1594 DDF1 85 DA sta fr0+6
1595 DDF3 20 00 DC jsr fp_normalize
1596 DDF6 68 pla
1597 DDF7 A8 tay
1598
1599 DDF8 abs_ok:
1600 ;stash integer portion of exponent
1601 DDF8 84 ED sty _fptemp0
1602
1603 ;compute approximation z = 10^y
1604 DDFA A2 28 ldx #<coeff
1605 DDFC A0 DE ldy #>coeff
1606 DDFE 20 3E DD jsr fp_plyevl_10
1607
1608 ;tweak exponent
1609 DE01 46 ED lsr _fptemp0
1610
1611 ;scale by 10 if necessary
1612 DE03 90 07 bcc even
1613 DE05 A2 1C ldx #<fpconst_ten
1614 DE07 20 D6 DA jsr fp_fld1r_const_fmul
1615 DE0A B0 D0 bcs abs_too_big
1616 DE0C even:
1617
1618 ;bias exponent
1619 DE0C A5 ED lda _fptemp0
1620 DE0E 65 D4 adc fr0
1621 DE10 C9 71 cmp #64+49
1622 DE12 B0 C8 bcs abs_too_big
1623 DE14 85 D4 sta fr0
1624
1625 ;check if we should invert
1626 DE16 26 EE rol _fptemp1
1627 DE18 90 0D bcc xit2
1628
1629 DE1A 20 B6 DD jsr fmove
1630 DE1D A2 EA ldx #<fp_one
1631 DE1F A0 DF ldy #>fp_one
1632 DE21 20 89 DD jsr fld0r
1633 DE24 4C 28 DB jmp fdiv
1634
1635 DE27 err2:
1636 DE27 xit2:
1637 DE27 60 rts
1638
1639 DE28 coeff: ;Minimax polynomial for 10^x over 0 <= x < 1
1640 DE28 3F 01 46 90 83 08 .fl 0.0146908308
1641 DE2E BE 20 05 33 11 71 .fl -0.002005331171
1642 DE34 3F 09 19 45 20 45 .fl 0.0919452045
1643 DE3A 3F 19 21 38 38 84 .fl 0.1921383884
1644 DE40 3F 54 47 32 51 97 .fl 0.5447325197
1645 DE46 40 01 17 01 82 49 .fl 1.17018250
1646 DE4C 40 02 03 47 85 80 .fl 2.03478581
1647 DE52 40 02 65 09 44 94 .fl 2.65094494
1648 DE58 40 02 30 25 85 11 .fl 2.30258512
1649 DE5E 40 01 00 00 00 00 .fl 1
1650 .endp
1651
1652 ;==========================================================================
1653 DE64 fpconst_log10_e:
1654 DE64 3F 43 42 94 48 18 .fl 0.43429448190325182765112891891661
1655
1656 DE6A .proc fp_carry_expup
1657 ;adjust exponent
1658 DE6A E6 D4 inc fr0
1659
1660 ;shift down FR0
1661 DE6C A2 04 ldx #4
1662 DE6E sum_shiftloop:
1663 DE6E B5 D4 lda fr0,x
1664 DE70 95 D5 sta fr0+1,x
1665 DE72 CA dex
1666 DE73 D0 F9 bne sum_shiftloop
1667
1668 ;add a $01 at the top
1669 DE75 E8 inx
1670 DE76 86 D5 stx fr0+1
1671 DE78 60 rts
1672 .endp
1673
1674 ;==========================================================================
1675 DE79 .proc fp_fmul_fr0_to_binfr2 ;$15 bytes
1676 DE79 A2 04 ldx #4
1677 DE7B loop:
1678 DE7B B5 D5 lda fr0+1,x
1679 DE7D 4A lsr
1680 DE7E 4A lsr
1681 DE7F 4A lsr
1682 DE80 4A lsr
1683 DE81 A8 tay
1684 DE82 18 clc
1685 DE83 B5 D5 lda fr0+1,x
1686 DE85 79 F6 DF adc fp_dectobin_tab,y
1687 DE88 49 FF eor #$ff
1688 DE8A 95 E7 sta fr2+1,x
1689 DE8C CA dex
1690 DE8D 10 EC bpl loop
1691 = DE8F .def :fp_rts1
1692 DE8F 60 rts
1693 .endp
1694
1695 ;==========================================================================
1696 ; REDRNG [DE95] Reduce range via y = (x-C)/(x+C) (undocumented)
1697 ;
1698 ; X:Y = pointer to C argument
1699 ;
1700 DE90 fixadr $de95
Macro: FIXADR [Source: source/Shared/mathpack.s]
2 .print ($DE95-*),' bytes free before ',$DE95
2 $0005 bytes free before $DE95
3 DE90 org $DE95
Source: source/Shared/mathpack.s
1701 = DE95 redrng = _redrng
1702 DE95 .proc _redrng
1703 DE95 86 FE stx fptr2
1704 DE97 84 FF sty fptr2+1
1705 DE99 20 98 DD jsr fld1r
1706 DE9C A2 E6 ldx #<fpscr
1707 DE9E A0 05 ldy #>fpscr
1708 DEA0 20 A7 DD jsr fst0r
1709 DEA3 20 66 DA jsr fadd
1710 DEA6 B0 E7 bcs fail
1711 DEA8 A2 E0 ldx #<plyarg
1712 DEAA A0 05 ldy #>plyarg
1713 DEAC 20 A7 DD jsr fst0r
1714 DEAF A2 E6 ldx #<fpscr
1715 DEB1 A0 05 ldy #>fpscr
1716 DEB3 20 89 DD jsr fld0r
1717 DEB6 A6 FE ldx fptr2
1718 DEB8 A4 FF ldy fptr2+1
1719 DEBA 20 98 DD jsr fld1r
1720 DEBD 20 60 DA jsr fsub
1721 DEC0 B0 CD bcs fail
1722 DEC2 A2 E0 ldx #<plyarg
1723 DEC4 A0 05 ldy #>plyarg
1724 DEC6 20 98 DD jsr fld1r
1725 DEC9 4C 28 DB jmp fdiv
1726
1727 = DE8F fail = fp_rts1
1728 .endp
1729
1730 ;==========================================================================
1731 ; LOG [DECD] Compute ln x
1732 ; LOG10 [DED1] Compute log10 x
1733 ;
1734 DECC fixadr $decd
Macro: FIXADR [Source: source/Shared/mathpack.s]
2 .print ($DECD-*),' bytes free before ',$DECD
2 $0001 bytes free before $DECD
3 DECC org $DECD
Source: source/Shared/mathpack.s
1735 = DED1 log10 = log._log10
1736 DECD .proc log
1737 DECD 46 EE lsr _fptemp1
1738 DECF 10 03 bpl entry
1739 DED1 ckaddr $ded1
Macro: CKADDR [Source: source/Shared/mathpack.s]
Source: source/Shared/mathpack.s
1740 DED1 _log10:
1741 DED1 38 sec
1742 DED2 66 EE ror _fptemp1
1743 DED4 entry:
1744 ;throw error on negative number
1745 DED4 A5 D4 lda fr0
1746 DED6 30 6E bmi err
1747
1748 ;stash exponentx2 - 128
1749 DED8 0A asl
1750 DED9 49 80 eor #$80
1751 DEDB 85 ED sta _fptemp0
1752
1753 ;raise error if argument is zero
1754 DEDD A5 D5 lda fr0+1
1755 DEDF F0 65 beq err
1756
1757 ;reset exponent so we are in 1 <= z < 100
1758 DEE1 A2 40 ldx #$40
1759 DEE3 86 D4 stx fr0
1760
1761 ;split into three ranges based on mantissa:
1762 ; 1/sqrt(10) <= x < 1: [31, 99] divide by 100
1763 ; sqrt(10)/100 <= x < 1/sqrt(10): [ 3, 30] divide by 10
1764 ; 0 < x < sqrt(10)/100: [ 1, 2] leave as-is
1765
1766 DEE5 C9 03 cmp #$03
1767 DEE7 90 13 bcc post_range_adjust
1768 DEE9 C9 31 cmp #$31
1769 DEEB 90 04 bcc mid_range
1770
1771 ;increase result by 1 (equivalent to *10 input)
1772 DEED E6 ED inc _fptemp0
1773 DEEF D0 07 bne adjust_exponent
1774
1775 DEF1 mid_range:
1776 ;multiply by 10
1777 DEF1 A2 1C ldx #<fpconst_ten
1778 DEF3 20 D6 DA jsr fp_fld1r_const_fmul
1779 DEF6 B0 4F bcs err2
1780
1781 DEF8 adjust_exponent:
1782 ;increase result by 1 (equivalent to *10 input)
1783 DEF8 E6 ED inc _fptemp0
1784
1785 ;divide fraction by 100
1786 DEFA C6 D4 dec fr0
1787
1788 DEFC post_range_adjust:
1789 ;at this point, we have 0.30 <= z <= 3; apply y = (z-1)/(z+1) transform
1790 ;so we can use a faster converging series... this reduces y to
1791 ;0 <= y < 0.81
1792 DEFC A2 EA ldx #<fp_one
1793 DEFE A0 DF ldy #>fp_one
1794 DF00 20 95 DE jsr redrng
1795
1796 ;stash y so we can later multiply it back in
1797 DF03 A2 E6 ldx #<fpscr
1798 DF05 A0 05 ldy #>fpscr
1799 DF07 20 A7 DD jsr fst0r
1800
1801 ;square the value so we compute a series on y^2n
1802 DF0A 20 B6 DD jsr fmove
1803 DF0D 20 DB DA jsr fmul
1804
1805 ;do polynomial expansion
1806 DF10 A2 72 ldx #<fpconst_log10coeff
1807 DF12 A0 DF ldy #>fpconst_log10coeff
1808 DF14 20 3E DD jsr fp_plyevl_10
1809 DF17 B0 2E bcs err2
1810
1811 ;multiply back in so we have series on y^(2n+1)
1812 DF19 A2 E6 ldx #<fpscr
1813 DF1B A0 05 ldy #>fpscr
1814 DF1D 20 D8 DA jsr fp_fld1r_fmul
1815
1816 ;stash
1817 DF20 20 B6 DD jsr fmove
1818
1819 ;convert exponent adjustment back to float (signed)
1820 DF23 A9 00 lda #0
1821 DF25 85 D5 sta fr0+1
1822 DF27 A6 ED ldx _fptemp0
1823 DF29 10 04 bpl expadj_positive
1824 DF2B 38 sec
1825 DF2C E5 ED sbc _fptemp0
1826 DF2E AA tax
1827 DF2F expadj_positive:
1828 DF2F 86 D4 stx fr0
1829 DF31 20 AA D9 jsr ipf
1830
1831 ;merge (cannot fail)
1832 DF34 06 D4 asl fr0
1833 DF36 06 ED asl _fptemp0
1834 DF38 66 D4 ror fr0
1835 DF3A 20 66 DA jsr fadd
1836
1837 ;scale if doing log
1838 DF3D 24 EE bit _fptemp1
1839 DF3F 30 06 bmi xit2
1840
1841 DF41 A2 22 ldx #<fpconst_ln10
1842 DF43 4C D6 DA jmp fp_fld1r_const_fmul
1843
1844 DF46 err:
1845 DF46 38 sec
1846 DF47 xit2:
1847 DF47 err2:
1848 DF47 60 rts
1849 .endp
1850
1851 ;==========================================================================
1852 DF48 .proc fp_tab_lo_1000
1853 DF48 00 E8 D0 B8 A0 88 + :10 dta <[1000*#]
1854 .endp
1855
1856 DF52 .proc fp_tab_hi_1000
1857 DF52 00 03 07 0B 0F 13 + :10 dta >[1000*#]
1858 .endp
1859
1860 DF5C .proc fp_tab_hi_100
1861 DF5C 00 00 00 01 01 01 + :10 dta >[100*#]
1862 .endp
1863
1864 DF66 .proc fp_tab_hi_10000
1865 DF66 27 4E 75 9C C3 EA :6 dta >[10000*[#+1]]
1866 .endp
1867
1868 ;==========================================================================
1869 ; HALF (used by Atari BASIC)
1870 ;
1871 DF6C fixadr $df6c
Macro: FIXADR [Source: source/Shared/mathpack.s]
Source: source/Shared/mathpack.s
1872 DF6C fpconst_half:
1873 DF6C 3F 50 00 00 00 00 .fl 0.5
1874
1875 ;==========================================================================
1876 ; log10(x) coefficients
1877 ;
1878 ; LOG10 computes:
1879 ; -0.30 <= z <= 3.0
1880 ; y = (z-1)/(z+1) -0.54 <= y <= 0.5
1881 ; x = y^2 0 <= x <= 0.29
1882 ; log10(z) = f(x)*y
1883 ;
1884 ; Therefore:
1885 ; f(x) = log10((1+y)/(1-y))/y
1886 ;
1887 DF72 fpconst_log10coeff: ;Maclaurin series expansion for log10((z-1)/(z+1))
1888 DF72 3F 20 26 22 71 53 .fl 0.2026227154
1889 DF78 BF 07 32 04 49 21 .fl -0.0732044921
1890 DF7E 3F 10 60 98 35 64 .fl 0.1060983564
1891 DF84 3F 05 60 41 73 29 .fl 0.0560417329
1892 DF8A 3F 08 04 18 84 06 .fl 0.0804188407
1893 DF90 3F 09 63 91 60 14 .fl 0.0963916015
1894 DF96 3F 12 40 89 61 35 .fl 0.1240896135
1895 DF9C 3F 17 37 17 66 45 .fl 0.1737176646
1896 DFA2 3F 28 95 29 65 58 .fl 0.2895296558
1897 DFA8 3F 86 85 88 96 37 .fl 0.8685889638
1898
1899 ;==========================================================================
1900 ; Arctangent coefficients
1901 ;
1902 ; The 11 coefficients here form a power series approximation
1903 ; f(x^2) ~= atn(x)/x. This is not an official feature of the math pack but
1904 ; is relied upon by BASIC.
1905 ;
1906 ; We used to use the coefficients from Abramowitz & Stegun 4.4.49 here, but
1907 ; there seems to be an error there such that the result falls far short
1908 ; of the specified 2x10^-8 accuracy over 0<=x<=1 at x=1. Instead, we now
1909 ; use a custom minimax polynomial for f(y)=atn(sqrt(y))/sqrt(y) where y=x^2.
1910 ;
1911 DFAE fixadr $dfae
Macro: FIXADR [Source: source/Shared/mathpack.s]
Source: source/Shared/mathpack.s
1912 DFAE atncoef: ;coefficients for atn(x)/x ~= f(x^2)
1913 ;see Abramowitz & Stegun 4.4.49
1914
1915 DFAE 3E 11 12 07 58 81 .fl 0.001112075881 ;x**10*1.11207588057982e-3
1916 DFB4 BE 73 04 08 75 20 .fl -0.007304087520 ;x**9*-7.30408751951452e-3
1917 DFBA 3F 02 24 96 55 73 .fl 0.0224965573 ;x**8*2.24965572957342e-2
1918 DFC0 BF 04 46 18 51 71 .fl -0.0446185172 ;x**7*-4.46185172165888e-2
1919 DFC6 3F 06 73 46 32 44 .fl 0.0673463245 ;x**6*6.73463245104305e-2
1920 DFCC BF 08 80 69 06 64 .fl -0.0880690664 ;x**5*-8.80690663570546e-2
1921 DFD2 3F 11 05 66 74 99 .fl 0.1105667499 ;x**4*1.10566749879313e-1
1922 DFD8 BF 14 27 94 93 12 .fl -0.1427949312 ;x**3*-1.42794931245212e-1
1923 DFDE 3F 19 99 96 30 60 .fl 0.1999963060 ;x**2*1.99996306023439e-1
1924 DFE4 BF 33 33 33 24 72 .fl -0.3333332472 ;x**1*-3.33333247188074e-1
1925 ;x**0*9.99999999667198e-1
1926 DFEA fp_one:
1927 DFEA 40 01 00 00 00 00 .fl 1.0 ;also an arctan coeff
1928 DFF0 fixadr $dff0
Macro: FIXADR [Source: source/Shared/mathpack.s]
Source: source/Shared/mathpack.s
1929 DFF0 fp_pi4: ;pi/4 - needed by Atari Basic ATN()
1930 DFF0 3F 78 53 98 16 34 .fl 0.78539816339744830961566084581988
1931
1932 DFF6 fp_dectobin_tab:
1933 DFF6 00 FA F4 EE E8 E2 + :10 dta <[-6*#]
1934
1935 E000 ckaddr $e000
Macro: CKADDR [Source: source/Shared/mathpack.s]
Source: source/Shared/mathpack.s
102
103 E000 org $e000
104 E000 icl 'atarifont.inc'
Source: source/Shared/atarifont.inc
1 ; Altirra - Atari 800/800XL/5200 emulator
2 ; Modular Kernel ROM - Character Font
3 ; Copyright (C) 2008-2016 Avery Lee
4 ;
5 ; Copying and distribution of this file, with or without modification,
6 ; are permitted in any medium without royalty provided the copyright
7 ; notice and this notice are preserved. This file is offered as-is,
8 ; without any warranty.
9
10 E000 00 00 00 00 00 00 + ins 'atarifont.bin',$0,$400
105
106 E400 org $e400
107 E400 E9 F9 editrv dta a(EditorOpen-1)
108 E402 C8 E4 dta a(EditorClose-1)
109 E404 F5 F9 dta a(EditorGetByte-1)
110 E406 A7 FA dta a(EditorPutByte-1)
111 E408 C8 E4 dta a(EditorGetStatus-1)
112 E40A CA E4 dta a(EditorSpecial-1)
113 E40C 4C CB E4 jmp EditorInit
114 E40F 00 dta $00
115
116 E410 F5 F3 screnv dta a(ScreenOpen-1)
117 E412 C8 E4 dta a(ScreenClose-1)
118 E414 9E F5 dta a(ScreenGetByte-1)
119 E416 DE F5 dta a(ScreenPutByte-1)
120 E418 C8 E4 dta a(ScreenGetStatus-1)
121 E41A C2 F6 dta a(ScreenSpecial-1)
122 E41C 20 91 F5 jsr ScreenInit
123 E41F 00 dta $00
124
125 E420 C8 E4 keybdv dta a(KeyboardOpen-1)
126 E422 C8 E4 dta a(KeyboardClose-1)
127 E424 65 FE dta a(KeyboardGetByte-1)
128 E426 CA E4 dta a(KeyboardPutByte-1)
129 E428 C8 E4 dta a(KeyboardGetStatus-1)
130 E42A CA E4 dta a(KeyboardSpecial-1)
131 E42C 4C 4B FE jmp KeyboardInit
132 E42F 00 dta $00
133
134 E430 C5 ED printv dta a(PrinterOpen-1)
135 E432 DA ED dta a(PrinterClose-1)
136 E434 CA E4 dta a(PrinterGetByte-1)
137 E436 E1 ED dta a(PrinterPutByte-1)
138 E438 2F EE dta a(PrinterGetStatus-1)
139 E43A CA E4 dta a(PrinterSpecial-1)
140 E43C 20 C0 ED jsr PrinterInit
141 E43F 00 dta $00
142
143 E440 5B EE casetv dta a(CassetteOpen-1)
144 E442 B0 EE dta a(CassetteClose-1)
145 E444 D1 EE dta a(CassetteGetByte-1)
146 E446 11 EF dta a(CassettePutByte-1)
147 E448 C8 E4 dta a(CassetteGetStatus-1)
148 E44A CA E4 dta a(CassetteSpecial-1)
149 E44C 4C 51 EE jmp CassetteInit
150 E44F 00 dta $00
151
152 ;vector table
153 E450 org $e450
154 E450 4C 60 ED diskiv jmp DiskInit ;$E450
155 E453 4C 61 ED dskinv jmp DiskHandler ;$E453
156 E456 4C FC E4 ciov jmp CIO ;$E456
157 E459 4C 50 E9 siov jmp SIO ;$E459
158 E45C 4C 69 E8 setvbv jmp VBISetVector ;$E45C
159 E45F 4C 1D E7 sysvbv jmp VBIStage1 ;$E45F
160 E462 4C 61 E7 xitvbv jmp VBIExit ;$E462
161 E465 4C 45 E9 sioinv jmp SIOInit ;$E465
162 E468 4C 99 EA sendev jmp SIOSendEnable ;$E468
163 E46B 4C 7F E8 intinv jmp IntInitInterrupts ;$E46B
164 E46E 4C EA E4 cioinv jmp CIOInit ;$E46E
165
166 .if _KERNEL_XLXE
167 blkbdv jmp SelfTestEntry ;$E471
168 .else
169 E471 4C 80 E4 blkbdv jmp Blackboard ;$E471
170 .endif
171
172 E474 4C 49 F0 warmsv jmp InitWarmStart ;$E474
173 E477 4C FD EF coldsv jmp InitColdStart ;$E477
174 E47A 4C 52 EF rblokv jmp CassetteReadBlock ;$E47A
175 E47D 4C 6F EE csopiv jmp CassetteOpenRead ;$E47D
176
177 .if _KERNEL_XLXE
178 pupdiv jmp SelfTestEntry ;$E480 XL/XE: power-up display
179 slftsv jmp $5000 ;$E483 XL/XE: self-test entry
180 pentv jmp PHAddHandler ;$E486 XL/XE: peripheral handler add
181 phunlv jmp PHRemoveHandler ;$E489 XL/XE: peripheral handler remove
182 phiniv jmp PHInitHandler ;$E48C XL/XE: peripheral handler init
183 gpdvv PBI_VECTOR_TABLE ;$E48F XL/XE: Generic device vector
184 .endif
185
186 .if _KERNEL_XLXE
187 icl 'selftestentry.s'
188 .else
189 E480 icl 'blackboard.s'
Source: source/Shared/blackboard.s
1 ; Altirra - Atari 800/800XL emulator
2 ; Kernel ROM replacement - Blackboard
3 ; Copyright (C) 2008-2016 Avery Lee
4 ;
5 ; Copying and distribution of this file, with or without modification,
6 ; are permitted in any medium without royalty provided the copyright
7 ; notice and this notice are preserved. This file is offered as-is,
8 ; without any warranty.
9
10 E480 .proc Blackboard
11 ;print banner
12 E480 A9 A6 8D 44 03 mva #<blackboard_banner icbal
13 E485 A9 E4 8D 45 03 mva #>blackboard_banner icbah
14 E48A 8D 48 03 sta icbll
15 E48D A2 00 ldx #0
16 E48F 8E 49 03 stx icblh
17 E492 A9 09 lda #CIOCmdPutRecord
18 E494 echoloop:
19 E494 8D 42 03 sta iccmd
20 E497 20 56 E4 jsr ciov
21
22 E49A 8E 48 03 stx icbll
23 E49D A9 07 lda #CIOCmdGetChars
24 E49F D0 F3 bne echoloop
25 .endp
26
27 .if *>$e480 && *<$e4c0
28 ;anchor version for emulator purposes
29 E4A1 org $e4a6
30 .endif
31 E4A6 blackboard_banner:
32 E4A6 41 6C 74 69 72 72 + dta 'AltirraOS '
33 E4B0 _KERNELSTR_VERSION
Macro: _KERNELSTR_VERSION [Source: source/Shared/version.inc]
1 E4B0 33 2E 32 36 dta '3.26'
Source: source/Shared/blackboard.s
34 E4B4 20 6D 65 6D 6F 20 + dta ' memo pad',$9B
190 .endif
191
192 ;==============================================================================
193 ; $E4C0 Known RTS instruction
194 ;
195 ; The Atari 850 handler uses this as a "known RTS" instruction, as does
196 ; Altirra's internal R: handler emulation.
197 ;
198 E4BE org $e4c0
199
200 E4C0 .nowarn .proc KnownRTS
201 E4C0 60 rts
202 .endp
203
204 ;==============================================================================
205 ; Main modules.
206 ;
207 ; We report the sizes here as well as reference sizes. The reference sizes for
208 ; OS-B come from Mapping the Atari.
209 ;
210
211 .echo 'Module sizes:'
211 Module sizes:
212
213 .macro _KERNEL_REPORT_MODULE_MARK
214 .def ?@_kernel_lastpt = *
215 .endm
216
217 .macro _KERNEL_REPORT_MODULE_PAD_ADJUST
218 .def ?@_kernel_lastpt = ?@_kernel_lastpt + :1
219 .endm
220
221 .macro _KERNEL_REPORT_MODULE_SIZE
222 .echo ' ', *, ' -> ', *-?@_kernel_lastpt, '(', :2, ')', ' ', :1
223
224 .def ?@_kernel_lastpt = *
225 .endm
226
227 E4C1 icl 'misc.s'
Source: source/Shared/misc.s
1 ; Altirra - Atari 800/800XL/5200 emulator
2 ; Modular Kernel ROM - Miscellaneous data
3 ; Copyright (C) 2008-2016 Avery Lee
4 ;
5 ; Copying and distribution of this file, with or without modification,
6 ; are permitted in any medium without royalty provided the copyright
7 ; notice and this notice are preserved. This file is offered as-is,
8 ; without any warranty.
9
10 ;==========================================================================
11 ;Used by PBI and display/editor.
12 ;
13 E4C1 .proc ReversedBitMasks
14 E4C1 80 40 20 10 08 04 + dta $80,$40,$20,$10,$08,$04,$02,$01
15 .endp
16
17 ;==========================================================================
18 ;Used by CIO devices
19 E4C9 .proc CIOExitSuccess
20 E4C9 A0 01 ldy #1
21 E4CB exit_not_supported:
22 E4CB 60 rts
23 .endp
24
25 = E4CB CIOExitNotSupported = CIOExitSuccess.exit_not_supported
26
27 ;==========================================================================
28 ; Sound a bell using the console speaker.
29 ;
30 ; Entry:
31 ; Y = duration
32 ;
33 ; Modified:
34 ; X
35 ;
36 ; Preserved:
37 ; A
38 ;
39 E4CC .proc Bell
40 E4CC 48 pha
41 E4CD A9 08 lda #$08
42 E4CF soundloop:
43 E4CF A2 04 ldx #4
44 E4D1 48 pha
45 E4D2 delay:
46 E4D2 AD 0B D4 lda vcount
47 E4D5 CD 0B D4 F0 FB cmp:req vcount
48 E4DA CA dex
49 E4DB D0 F5 bne delay
50 E4DD 68 pla
51 E4DE 49 08 eor #$08
52 E4E0 8D 1F D0 sta consol
53 E4E3 D0 EA bne soundloop
54 E4E5 88 dey
55 E4E6 D0 E7 bne soundloop
56 E4E8 68 pla
57 E4E9 60 rts
58 .endp
228 E4EA _KERNEL_REPORT_MODULE_MARK
Macro: _KERNEL_REPORT_MODULE_MARK [Source: source/main.xasm]
1 = E4EA .def ?@_kernel_lastpt = *
Source: source/main.xasm
229
230 E4EA icl 'cio.inc'
Source: source/Shared/cio.inc
1 ; Altirra - Atari 800/800XL/5200 emulator
2 ; Modular Kernel ROM - Character Input/Output Definitions
3 ; Copyright (C) 2008-2016 Avery Lee
4 ;
5 ; Copying and distribution of this file, with or without modification,
6 ; are permitted in any medium without royalty provided the copyright
7 ; notice and this notice are preserved. This file is offered as-is,
8 ; without any warranty.
9
10 .ifndef f_CIO_INC
11 .def f_CIO_INC
12
13 CIOStatBreak = $80 ;break key abort
14 CIOStatIOCBInUse = $81 ;IOCB in use
15 CIOStatUnkDevice = $82 ;unknown device
16 CIOStatWriteOnly = $83 ;opened for write only
17 CIOStatInvalidCmd = $84 ;invalid command
18 CIOStatNotOpen = $85 ;device or file not open
19 CIOStatInvalidIOCB = $86 ;invalid IOCB number
20 CIOStatReadOnly = $87 ;opened for read only
21 CIOStatEndOfFile = $88 ;end of file reached
22 CIOStatTruncRecord = $89 ;record truncated
23 CIOStatTimeout = $8A ;device timeout
24 CIOStatNAK = $8B ;device NAK
25 CIOStatSerFrameErr = $8C ;serial bus framing error
26 CIOStatCursorRange = $8D ;cursor out of range
27 CIOStatSerOverrun = $8E ;serial frame overrun error
28 CIOStatSerChecksum = $8F ;serial checksum error
29 CIOStatDeviceDone = $90 ;device done error
30 CIOStatBadScrnMode = $91 ;bad screen mode
31 CIOStatNotSupported = $92 ;function not supported by handler
32 CIOStatOutOfMemory = $93 ;not enough memory
33 CIOStatDriveNumErr = $A0 ;disk drive # error
34 CIOStatTooManyFiles = $A1 ;too many open disk files
35 CIOStatDiskFull = $A2 ;disk full
36 CIOStatFatalDiskIO = $A3 ;fatal disk I/O error
37 CIOStatFileNumDiff = $A4 ;internal file # mismatch
38 CIOStatFileNameErr = $A5 ;filename error
39 CIOStatPointDLen = $A6 ;point data length error
40 CIOStatFileLocked = $A7 ;file locked
41 CIOStatInvDiskCmd = $A8 ;invalid command for disk
42 CIOStatDirFull = $A9 ;directory full (64 files)
43 CIOStatFileNotFound = $AA ;file not found
44 CIOStatInvPoint = $AB ;invalid point
45
46 CIOCmdOpen = $03
47 CIOCmdGetRecord = $05
48 CIOCmdGetChars = $07
49 CIOCmdPutRecord = $09
50 ; $0A ;PUT CHARS alias (required by K-Razy Shoot Out)
51 CIOCmdPutChars = $0B
52 CIOCmdClose = $0C
53 CIOCmdGetStatus = $0D
54 CIOCmdSpecial = $0E ;$0E and up is escape
55
56 .endif
231
232 .ifdef _KERNEL_816
233 icl 'cio816.s'
234 .else
235 E4EA icl 'cio.s'
Source: source/Shared/cio.s
1 ; Altirra - Atari 800/800XL/5200 emulator
2 ; Modular Kernel ROM - Character Input/Output Facility
3 ; Copyright (C) 2008-2016 Avery Lee
4 ;
5 ; Copying and distribution of this file, with or without modification,
6 ; are permitted in any medium without royalty provided the copyright
7 ; notice and this notice are preserved. This file is offered as-is,
8 ; without any warranty.
9
10 E4EA .proc CIOInit
11 E4EA 38 sec
12 E4EB A2 70 ldx #$70
13 E4ED iocb_loop:
14 E4ED A9 FF lda #$ff
15 E4EF 9D 40 03 sta ichid,x
16 E4F2 20 01 E7 jsr CIOSetPutByteClosed
17 E4F5 8A txa
18 E4F6 E9 10 sbc #$10
19 E4F8 AA tax
20 E4F9 10 F2 bpl iocb_loop
21 E4FB 60 rts
22 .endp
23
24 ;==============================================================================
25 ; Character I/O entry vector
26 ;
27 ; On entry:
28 ; X = IOCB offset (# x 16)
29 ;
30 ; Returns:
31 ; A = depends on operation
32 ; X = IOCB offset (# x 16)
33 ; Y = status (reflected in P)
34 ;
35 ; Notes:
36 ; BUFADR must not be touched from CIO. DOS XE relies on this for
37 ; temporary storage and breaks if it is modified.
38 ;
39 ; XL/XE mode notes:
40 ; HNDLOD is always set to $00 afterward, per Sweet 16 supplement 3.
41 ;
42 ; CIO can optionally attempt a provisional open by doing a type 4 poll
43 ; over the SIO bus. This happens unconditionally if HNDLOD is non-zero
44 ; and only after the device is not found in HATABS if HNDLOD is zero.
45 ; If this succeeds, the IOCB is provisionally opened. Type 4 polling
46 ; ONLY happens for direct opens -- it does not happen for a soft open.
47 ;
48 E4FC .proc CIO
49 ;stash IOCB offset (X) and acc (A)
50 E4FC 85 2F sta ciochr
51 E4FE 86 2E stx icidno
52 E500 20 0E E5 jsr process
53 E503 xit:
54 ;copy status back to IOCB
55 E503 A6 2E ldx icidno
56 E505 98 tya
57 E506 9D 43 03 sta icsta,x
58 E509 08 php
59
60 .if _KERNEL_XLXE
61 mva #0 hndlod
62 .endif
63
64 E50A A5 2F lda ciochr
65 E50C 28 plp
66 E50D 60 rts
67
68 E50E process:
69 ;validate IOCB offset
70 E50E 8A txa
71 E50F 29 8F and #$8f
72 E511 F0 06 beq validIOCB
73
74 ;return invalid IOCB error
75 E513 A0 86 ldy #CIOStatInvalidIOCB
76 E515 60 rts
77
78 E516 cmdInvalid:
79 ;invalid command <$03
80 E516 A0 84 ldy #CIOStatInvalidCmd
81 E518 60 rts
82
83 E519 validIOCB:
84 E519 20 D1 E6 jsr CIOLoadZIOCB
85
86 ;check if we're handling the OPEN command
87 E51C A5 22 lda iccomz
88 E51E C9 03 cmp #CIOCmdOpen
89 E520 F0 66 beq cmdOpen
90 E522 90 F2 bcc cmdInvalid
91
92 ;check if the IOCB is open
93 E524 A4 20 ldy ichidz
94
95 .if !_KERNEL_XLXE
96 E526 10 1C bpl isOpen
97 .else
98 bmi not_open
99
100 ;check for a provisionally open IOCB
101 iny
102 bpl isOpen
103
104 ;okay, it's provisionally open... check if it's a close
105 cmp #CIOCmdClose
106 sne:jmp cmdCloseProvisional
107
108 ;check if we're allowed to load a handler
109 lda hndlod
110 beq not_open
111
112 ;try to load the handler
113 jsr CIOLoadHandler
114 bpl isOpen
115 rts
116 .endif
117
118 E528 not_open:
119 ;IOCB isn't open - issue error
120 ;
121 ;Special cases;
122 ; - No error issued for close ($0C). This is needed so that extra CLOSE
123 ; commands from BASIC don't trip errors.
124 ; - Get status ($0D) and special ($0E+) do soft open and close if needed.
125 ; $0D case is required for Top Dos 1.5a to boot; $0E+ case is encountered
126 ; with R: device XIO commands.
127 ;
128 E528 A0 01 ldy #1
129 E52A A5 22 lda iccomz
130 E52C C9 0C cmp #CIOCmdClose
131 E52E F0 06 beq ignoreOpen
132 E530 C9 0D cmp #CIOCmdGetStatus
133 E532 B0 03 bcs preOpen ;closed IOCB is OK for get status and special
134 E534 not_open_handler:
135 E534 A0 85 ldy #CIOStatNotOpen
136 E536 ignoreOpen:
137 E536 60 rts
138
139 E537 preOpen:
140 ;If the device is not open when a SPECIAL command is issued, parse the path
141 ;and soft-open the device in the zero page IOCB.
142 E537 20 E0 E6 jsr CIOParsePath
143
144 ;check for special command
145 E53A A5 22 lda iccomz
146 E53C C9 0D cmp #CIOCmdGetStatus
147 E53E F0 40 beq cmdGetStatusSoftOpen
148 E540 C9 0E cmp #CIOCmdSpecial
149 E542 B0 3F bcs cmdSpecialSoftOpen
150
151 E544 isOpen:
152 E544 A6 22 ldx iccomz
153 E546 E0 0E cpx #CIOCmdSpecial
154 E548 90 02 A2 0E scc:ldx #$0e
155
156 ;do permissions check
157 E54C BD 8F E6 lda perm_check_table-4,x
158 E54F 30 04 bmi skip_perm_check
159 E551 24 2A bit icax1z
160 E553 F0 26 beq perm_check_fail
161 E555 skip_perm_check:
162
163 ;load command table vector
164 E555 BD B0 E6 lda command_table_hi-4,x
165 E558 48 pha
166 E559 BD A5 E6 lda command_table_lo-4,x
167 E55C 48 pha
168
169 ;preload dispatch vector and dispatch to command
170 E55D BC 9A E6 ldy vector_preload_table-4,x
171 E560 load_vector:
172 E560 A6 20 ldx ichidz
173 E562 BD 1B 03 85 2C BD + mwa hatabs+1,x icax3z
174 E56C B1 2C lda (icax3z),y
175 E56E AA tax
176 E56F 88 dey
177 E570 B1 2C lda (icax3z),y
178 E572 85 2C sta icax3z
179 E574 86 2D stx icax3z+1
180
181 ;many commands want to check length=0 on entry
182 E576 A5 28 lda icbllz
183 E578 05 29 ora icblhz
184 E57A 60 rts
185
186 E57B perm_check_fail:
187 ;at this point we have A=$04 if we failed a get perm check, and A=$08
188 ;if we failed a put perm check -- these need to be translated to Y=$83
189 ;and Y=$87.
190 E57B 18 clc
191 E57C 69 7F adc #$7f
192 E57E A8 tay
193 E57F 60 rts
194
195 ;--------------------------------------------------------------------------
196 E580 cmdGetStatusSoftOpen:
197 E580 A0 09 ldy #9
198 E582 2C dta {bit $0100}
199 E583 cmdSpecialSoftOpen:
200 E583 A0 0B ldy #11
201 E585 invoke_and_soft_close_xit:
202 E585 4C BF E6 jmp CIOInvoke
203
204 ;--------------------------------------------------------------------------
205 ; Open command ($03).
206 ;
207 E588 cmdOpen:
208 ;check if the IOCB is already open
209 E588 A4 20 ldy ichidz
210 E58A C8 iny
211 E58B F0 03 beq notAlreadyOpen
212
213 ;IOCB is already open - error
214 E58D A0 81 ldy #CIOStatIOCBInUse
215 E58F 60 rts
216
217 E590 notAlreadyOpen:
218 ;attempt to parse and open -- note that this will fail out directly
219 ;on an unknown device or provisional open
220 E590 20 E0 E6 jsr CIOParsePath
221
222 E593 open_entry:
223 ;request open
224 E593 A0 01 ldy #1
225 E595 20 BF E6 jsr CIOInvoke
226
227 ;move handler ID and device number to IOCB
228 E598 A6 2E ldx icidno
229 E59A A5 20 9D 40 03 mva ichidz ichid,x
230 E59F A5 21 9D 41 03 mva icdnoz icdno,x
231
232 E5A4 98 tya
233 E5A5 10 01 bpl openOK
234 E5A7 60 rts
235
236 E5A8 openOK:
237
238 ;copy PUT BYTE vector for Atari Basic
239 E5A8 A6 20 ldx ichidz
240 E5AA BD 1B 03 85 2C BD + mwa hatabs+1,x icax3z
241 E5B4 A0 06 ldy #6
242 E5B6 B1 2C lda (icax3z),y
243 E5B8 A6 2E ldx icidno
244 E5BA 9D 46 03 sta icptl,x
245 E5BD C8 iny
246 E5BE B1 2C lda (icax3z),y
247 E5C0 9D 47 03 sta icpth,x
248 E5C3 A0 01 ldy #1
249 E5C5 60 rts
250
251 = E6C2 cmdGetStatus = CIOInvoke.invoke_vector
252 E5C6 cmdSpecial:
253 E5C6 20 C2 E6 jsr CIOInvoke.invoke_vector
254
255 ;need to copy AUX1/2 back for R:
256 E5C9 A6 2E ldx icidno
257 E5CB A5 2A 9D 4A 03 mva icax1z icax1,x
258 E5D0 A5 2B 9D 4B 03 mva icax2z icax2,x
259 E5D5 60 rts
260
261 ;--------------------------------------------------------------------------
262 E5D6 cmdGetRecord:
263 ;check if buffer is full on entry
264 E5D6 F0 16 beq cmdGetRecordBufferFull
265 E5D8 cmdGetRecordLoop:
266 E5D8 cmdGetRecordGetByte:
267 ;fetch byte
268 E5D8 20 C2 E6 jsr CIOInvoke.invoke_vector
269 E5DB C0 00 cpy #0
270 E5DD 30 1C bmi cmdGetRecordXit
271
272 ;store byte (even if EOL)
273 E5DF A2 00 ldx #0
274 E5E1 81 24 sta (icbalz,x)
275
276 ;check for EOL
277 E5E3 49 9B eor #$9b
278 E5E5 C9 01 cmp #1
279
280 ;increment buffer pointer and decrement length
281 E5E7 20 72 E6 jsr advance_pointers
282
283 ;skip buffer full check if we had an EOL
284 E5EA 90 0F bcc cmdGetRecordXit
285
286 ;loop back for more bytes if buffer not full
287 E5EC D0 EA bne cmdGetRecordLoop
288
289 E5EE cmdGetRecordBufferFull:
290 ;read byte to discard
291 E5EE 20 C2 E6 jsr CIOInvoke.invoke_vector
292 E5F1 C0 00 cpy #0
293 E5F3 30 06 bmi cmdGetRecordXit
294
295 ;continue if not EOL
296 E5F5 C9 9B cmp #$9b
297 E5F7 D0 F5 bne cmdGetRecordBufferFull
298
299 ;return truncated record
300 E5F9 A0 89 ldy #CIOStatTruncRecord
301
302 E5FB cmdGetRecordXit:
303 E5FB cmdGetPutDone:
304 ;update byte count in IOCB
305 E5FB A6 2E ldx icidno
306 E5FD 38 sec
307 E5FE BD 48 03 lda icbll,x
308 E601 E5 28 sbc icbllz
309 E603 85 28 sta icbllz ;required by Lightspeed DOS
310 E605 9D 48 03 sta icbll,x
311 E608 BD 49 03 lda icblh,x
312 E60B E5 29 sbc icblhz
313 E60D 85 29 sta icblhz
314 E60F 9D 49 03 sta icblh,x
315
316 ;NOMAM 2013 BASIC Ten-Liners disk requires ICBALZ to be untouched :P
317 E612 BD 44 03 85 24 BD + mwa icbal,x icbalz
318
319 ;Pacem in Terris requires Y=1 exit.
320 ;DOS 3.0 with 128K/XE mode requires Y=3 for EOF imminent.
321 E61C 60 rts
322
323 ;--------------------------------------------------------------------------
324 E61D cmdGetChars:
325 E61D F0 15 beq cmdGetCharsSingle
326 E61F cmdGetCharsLoop:
327 E61F 20 C2 E6 jsr CIOInvoke.invoke_vector
328 E622 C0 00 cpy #0
329 E624 30 0B bmi cmdGetCharsError
330 E626 A2 00 ldx #0
331 E628 85 2F sta ciochr ;required by HOTEL title screen
332 E62A 81 24 sta (icbalz,x)
333 E62C 20 72 E6 jsr advance_pointers
334 E62F D0 EE bne cmdGetCharsLoop
335 E631 cmdGetCharsError:
336 E631 4C FB E5 jmp cmdGetPutDone
337
338 E634 cmdGetCharsSingle:
339 E634 20 C2 E6 jsr CIOInvoke.invoke_vector
340 E637 85 2F sta ciochr
341 E639 60 rts
342
343 ;--------------------------------------------------------------------------
344 ; PUT RECORD handler ($09)
345 ;
346 ; Exit:
347 ; ICBAL/ICBAH: Not changed
348 ; ICBLL/ICBLH: Number of bytes processed
349 ;
350 ; If the string does not contain an EOL character, one is printed at the
351 ; end. Also, in this case CIOCHR must reflect the last character in the
352 ; buffer and not the EOL. (Required by Atari DOS 2.5 RAMDISK banner)
353 ;
354 ; If length=0, the character in the A register is output without an EOL.
355 ; This behavior is required by the graphics library for Mad Pascal.
356 ;
357 E63A cmdPutRecord:
358 E63A F0 33 beq cmdPutCharsSingle
359 E63C cmdPutRecordLoop:
360 E63C A0 00 ldy #0
361 E63E B1 24 lda (icbalz),y
362 E640 20 C2 E6 jsr CIOInvoke.invoke_vector
363 E643 98 tya
364 E644 30 12 bmi cmdPutRecordError
365 E646 20 72 E6 jsr advance_pointers
366 E649 F0 08 beq cmdPutRecordEOL
367 E64B A9 9B lda #$9b
368 E64D C5 2F cmp ciochr
369 E64F F0 07 beq cmdPutRecordDone
370 E651 D0 E7 bne cmdPutRecord
371
372 E653 cmdPutRecordEOL:
373 E653 A9 9B lda #$9b
374 E655 20 C2 E6 jsr CIOInvoke.invoke_vector
375 E658 cmdPutRecordError:
376 E658 cmdPutRecordDone:
377 E658 4C FB E5 jmp cmdGetPutDone
378
379 ;--------------------------------------------------------------------------
380 E65B cmdPutChars:
381 E65B F0 12 beq cmdPutCharsSingle
382 E65D cmdPutCharsLoop:
383 E65D A0 00 ldy #0
384 E65F B1 24 lda (icbalz),y
385 E661 20 C2 E6 jsr CIOInvoke.invoke_vector
386 E664 98 tya
387 E665 30 F1 bmi cmdPutRecordError
388 E667 20 72 E6 jsr advance_pointers
389 E66A D0 F1 bne cmdPutCharsLoop
390 E66C 4C FB E5 jmp cmdGetPutDone
391 E66F cmdPutCharsSingle:
392 E66F 4C C4 E6 jmp CIOInvoke.invoke_vector_ciochr
393
394 ;--------------------------------------------------------------------------
395
396 E672 advance_pointers:
397 E672 E6 24 D0 02 E6 25 inw icbalz
398 E678 A5 28 D0 02 C6 29 + dew icbllz
399 E680 D0 02 A5 29 sne:lda icblhz
400 E684 60 rts
401
402 ;--------------------------------------------------------------------------
403 E685 cmdClose:
404 E685 20 C2 E6 jsr CIOInvoke.invoke_vector
405 E688 cmdCloseProvisional:
406 E688 A6 2E ldx icidno
407 E68A 20 01 E7 jsr CIOSetPutByteClosed
408 E68D A9 FF 9D 40 03 mva #$ff ichid,x
409 E692 60 rts
410
411 E693 perm_check_table:
412 E693 04 dta $04 ;$04 (get record)
413 E694 04 dta $04 ;$05 (get record)
414 E695 04 dta $04 ;$06 (get chars)
415 E696 04 dta $04 ;$07 (get chars)
416 E697 08 dta $08 ;$08 (put record)
417 E698 08 dta $08 ;$09 (put record)
418 E699 08 dta $08 ;$0A (put chars)
419 E69A 08 dta $08 ;$0B (put chars)
420 E69B FF dta $ff ;$0C (close)
421 E69C FF dta $ff ;$0D (get status)
422 E69D FF dta $ff ;$0E (special)
423
424 E69E vector_preload_table:
425 E69E 05 dta $05 ;$04 (get record)
426 E69F 05 dta $05 ;$05 (get record)
427 E6A0 05 dta $05 ;$06 (get chars)
428 E6A1 05 dta $05 ;$07 (get chars)
429 E6A2 07 dta $07 ;$08 (put record)
430 E6A3 07 dta $07 ;$09 (put record)
431 E6A4 07 dta $07 ;$0A (put chars)
432 E6A5 07 dta $07 ;$0B (put chars)
433 E6A6 03 dta $03 ;$0C (close)
434 E6A7 09 dta $09 ;$0D (get status)
435 E6A8 0B dta $0b ;$0E (special)
436
437 E6A9 command_table_lo:
438 E6A9 D5 dta <(cmdGetRecord-1) ;$04
439 E6AA D5 dta <(cmdGetRecord-1) ;$05
440 E6AB 1C dta <(cmdGetChars-1) ;$06
441 E6AC 1C dta <(cmdGetChars-1) ;$07
442 E6AD 39 dta <(cmdPutRecord-1) ;$08
443 E6AE 39 dta <(cmdPutRecord-1) ;$09
444 E6AF 5A dta <(cmdPutChars-1) ;$0A
445 E6B0 5A dta <(cmdPutChars-1) ;$0B
446 E6B1 84 dta <(cmdClose-1) ;$0C
447 E6B2 C1 dta <(cmdGetStatus-1) ;$0D
448 E6B3 C5 dta <(cmdSpecial-1) ;$0E
449
450 E6B4 command_table_hi:
451 E6B4 E5 dta >(cmdGetRecord-1) ;$04
452 E6B5 E5 dta >(cmdGetRecord-1) ;$05
453 E6B6 E6 dta >(cmdGetChars-1) ;$06
454 E6B7 E6 dta >(cmdGetChars-1) ;$07
455 E6B8 E6 dta >(cmdPutRecord-1) ;$08
456 E6B9 E6 dta >(cmdPutRecord-1) ;$09
457 E6BA E6 dta >(cmdPutChars-1) ;$0A
458 E6BB E6 dta >(cmdPutChars-1) ;$0B
459 E6BC E6 dta >(cmdClose-1) ;$0C
460 E6BD E6 dta >(cmdGetStatus-1) ;$0D
461 E6BE E5 dta >(cmdSpecial-1) ;$0E
462 .endp
463
464 ;==========================================================================
465 ; Invoke device vector.
466 ;
467 ; Entry (standard):
468 ; A, X = ignored
469 ; Y = offset to high vector byte in device table
470 ;
471 ; Entry (invoke_vector):
472 ; A = byte to pass to PUT CHAR vector
473 ; X, Y = ignored
474 ;
475 ; Exit:
476 ; A = byte returned from GET CHAR vector
477 ; Y = status
478 ;
479 E6BF .proc CIOInvoke
480 E6BF 20 60 E5 jsr CIO.load_vector
481 E6C2 invoke_vector:
482 E6C2 85 2F sta ciochr
483 E6C4 invoke_vector_ciochr:
484 E6C4 A5 2D lda icax3z+1
485 E6C6 48 pha
486 E6C7 A5 2C lda icax3z
487 E6C9 48 pha
488 E6CA A0 92 ldy #CIOStatNotSupported
489 E6CC A6 2E ldx icidno
490 E6CE A5 2F lda ciochr
491 E6D0 60 rts
492 .endp
493
494 ;==========================================================================
495 ; Copy IOCB to ZIOCB.
496 ;
497 ; Entry:
498 ; X = IOCB
499 ;
500 ; [OSManual p236] "Although both the outer level IOCB and the Zero-page
501 ; IOCB are defined to be 16 bytes in size, only the first 12 bytes are
502 ; moved by CIO."
503 ;
504 E6D1 .proc CIOLoadZIOCB
505 ;We used to do a trick here where we would count Y from $F4 to $00...
506 ;but we can't do that because the 65C816 doesn't wrap abs,Y within
507 ;bank 0 even in emulation mode. Argh!
508
509 E6D1 A0 00 ldy #0
510 E6D3 copyToZIOCB:
511 E6D3 BD 40 03 lda ichid,x
512 E6D6 99 20 00 sta ziocb,y
513 E6D9 E8 inx
514 E6DA C8 iny
515 E6DB C0 0C cpy #12
516 E6DD D0 F4 bne copyToZIOCB
517 E6DF 60 rts
518 .endp
519
520 ;==========================================================================
521 E6E0 .proc CIOParsePath
522 ;default to device #1
523 E6E0 A2 01 ldx #1
524
525 ;pull first character of filename and stash it
526 E6E2 A1 23 lda (icbalz-1,x)
527 E6E4 85 2D sta icax4z
528
529 ;Check for a device number.
530 ;
531 ; - D1:-D9: is supported. D0: also gives unit 1, and any digits beyond
532 ; the first are ignored.
533 ;
534 ; We don't validate the colon anymore -- Atari OS allows opening just "C" to get
535 ; to the cassette.
536 ;
537 E6E6 A0 01 ldy #1
538 E6E8 B1 24 lda (icbalz),y
539 E6EA 38 sec
540 E6EB E9 30 sbc #'0'
541 E6ED F0 06 beq nodevnum
542 E6EF C9 0A cmp #10
543 E6F1 B0 02 bcs nodevnum
544 E6F3 AA tax
545
546 E6F4 C8 iny
547
548 E6F5 nodevnum:
549 E6F5 86 21 stx icdnoz
550
551 .if _KERNEL_XLXE
552 ;check if we are doing a true open and if we should do a type 4 poll
553 lda iccomz
554 cmp #CIOCmdOpen
555 bne skip_poll
556
557 ;clear DVSTAT+0/+1 to indicate no poll
558 lda #0
559 sta dvstat
560 sta dvstat+1
561
562 ;check if we should do an unconditional poll (HNDLOD nonzero).
563 lda hndlod
564 bne unconditional_poll
565
566 ;search handler table
567 jsr CIOFindHandler
568 beq found
569
570 unconditional_poll:
571 ;do type 4 poll
572 jsr CIOPollForDevice
573 bmi unknown_device
574
575 ;mark provisionally open
576 ldx icidno
577 mva #$7f ichid,x
578 mva icax4z icax3,x
579 mva dvstat+2 icax4,x
580 mwa #CIOPutByteLoadHandler-1 icptl,x
581 mva icdnoz icdno,x
582
583 ;do direct exit, bypassing regular open path
584 pla
585 pla
586 ldy #1
587 rts
588
589 skip_poll:
590 .endif
591
592 ;search handler table
593 E6F7 20 0C E7 jsr CIOFindHandler
594 E6FA F0 04 beq found
595
596 E6FC unknown_device:
597 ;return unknown device error
598 E6FC A0 82 ldy #CIOStatUnkDevice
599 E6FE 68 pla
600 E6FF 68 pla
601 E700 found:
602 E700 60 rts
603 .endp
604
605 ;==========================================================================
606 E701 .proc CIOSetPutByteClosed
607 E701 A9 33 lda #<[CIO.not_open_handler-1]
608 E703 9D 46 03 sta icptl,x
609 E706 A9 E5 lda #>[CIO.not_open_handler-1]
610 E708 9D 47 03 sta icpth,x
611 E70B 60 rts
612 .endp
613
614 ;==========================================================================
615 ; Attempt to find a handler entry in HATABS.
616 ;
617 E70C .proc CIOFindHandler
618 ;search for handler
619 E70C A5 2D lda icax4z
620 E70E A2 21 ldx #11*3
621 E710 findHandler:
622 E710 DD 1A 03 cmp hatabs,x
623 E713 F0 05 beq foundHandler
624 E715 CA dex
625 E716 CA dex
626 E717 CA dex
627 E718 10 F6 bpl findHandler
628 E71A foundHandler:
629 ;store handler ID
630 E71A 86 20 stx ichidz
631 E71C 60 rts
632 .endp
633
634 ;==========================================================================
635 ; Poll SIO bus for CIO device
636 ;
637 ; Issues a type 4 poll ($4F/$40/devname/devnumber).
638 ;
639 .if _KERNEL_XLXE
640 .proc CIOPollForDevice
641 lda icax4z
642 sta daux1
643 lda icdnoz
644 sta daux2
645
646 ldx #9
647 mva:rpl cmd_tab,x ddevic,x-
648
649 jmp siov
650
651 cmd_tab:
652 dta $4f ;device
653 dta $01 ;unit
654 dta $40 ;command
655 dta $40 ;status (transfer flags)
656 dta <dvstat ;dbuflo
657 dta >dvstat ;dbufhi
658 dta $40 ;dtimlo
659 dta $00 ;unused
660 dta $04 ;dbytlo
661 dta $00 ;dbythi
662 .endp
663 .endif
664
665 ;==========================================================================
666 ; Load handler for a provisionally open IOCB.
667 ;
668 .if _KERNEL_XLXE
669 .proc CIOLoadHandler
670 ;load handler over SIO bus
671 mwa dvstat+2 loadad
672 ldx icidno
673 mva icax4,x ddevic
674 jsr PHLoadHandler
675 bcs fail
676
677 ;let's see if we can look up the handler now
678 ldx icidno
679 mva icax3,x icax4z
680 jsr CIOFindHandler
681 bne fail
682
683 ;follow through with open
684 jsr CIO.open_entry
685 bpl ok
686 fail:
687 ldy #CIOStatUnkDevice
688 ok:
689 rts
690 .endp
691 .endif
692
693 ;==========================================================================
694 ; PUT BYTE handler for provisionally open IOCBs.
695 ;
696 ; This handler is used when an IOCB has been provisionally opened pending
697 ; a handler load over the SIO bus. It is used when a direct call is made
698 ; through ICPTL/ICPTH. If HNDLOD=0, the call fails as handler loading is
699 ; not set up; if it is nonzero, the handler is loaded over the SIO bus and
700 ; then the PUT BYTE call continues if everything is good.
701 ;
702 .if _KERNEL_XLXE
703 .proc CIOPutByteLoadHandler
704 ;save off A/X
705 sta ciochr
706 stx icidno
707
708 ;check if we're allowed to load a handler and bail if not
709 lda hndlod
710 beq load_error
711
712 ;copy IOCB to ZIOCB
713 jsr CIOLoadZIOCB
714
715 ;try to load the handler
716 jsr CIOLoadHandler
717 bmi load_error
718
719 ;all good... let's invoke the standard handler
720 ldy #7
721 jsr CIOInvoke
722 jmp xit
723
724 load_error:
725 ldy #CIOStatUnkDevice
726 xit:
727 php
728 lda ciochr
729 ldx icidno
730 plp
731 rts
732 .endp
733 .endif
236 .endif
237
238 E71D _KERNEL_REPORT_MODULE_SIZE 'Central Input/Output (CIO)', $E6D5-$E4A6
Macro: _KERNEL_REPORT_MODULE_SIZE [Source: source/main.xasm]
1 .echo ' ', *, ' -> ', *-?@_kernel_lastpt, '(', $E6D5-$E4A6, ')', ' ', 'Central Input/Output (CIO)'
1 $E71D -> $0233($022F) Central Input/Output (CIO)
3 = E71D .def ?@_kernel_lastpt = *
Source: source/main.xasm
239
240 .if !_KERNEL_XLXE
241 E71D icl 'vbi.s'
Source: source/Shared/vbi.s
1 ; Altirra - Atari 800/800XL/5200 emulator
2 ; Modular Kernel ROM - Vertical Blank Interrupt Services
3 ; Copyright (C) 2008-2016 Avery Lee
4 ;
5 ; Copying and distribution of this file, with or without modification,
6 ; are permitted in any medium without royalty provided the copyright
7 ; notice and this notice are preserved. This file is offered as-is,
8 ; without any warranty.
9
10 ;==========================================================================
11 ; VBIExit - Vertical Blank Interrupt Exit Routine
12 ;
13 ; This is a drop-in replacement for XITVBV.
14 ;
15 = E761 VBIExit = VBIProcess.xit
16
17 ;==========================================================================
18 ; VBIProcess - Vertical Blank Processor
19 ;
20 = E71D VBIStage1 = VBIProcess.stage_1
21 = E772 VBIStage2 = VBIProcess.stage_2
22 E71D .proc VBIProcess
23 E71D stage_1:
24 ;increment real-time clock and do attract processing
25 E71D E6 14 inc rtclok+2
26 E71F D0 08 bne clock_done
27 E721 E6 4D inc atract
28 E723 E6 13 inc rtclok+1
29 E725 D0 02 bne clock_done
30 E727 E6 12 inc rtclok
31 E729 clock_done:
32
33 ;Pole Position depends on DRKMSK and COLRSH being reset from VBI as it
34 ;clears kernel vars after startup.
35 E729 A2 FE ldx #$fe ;default to no mask
36 E72B A9 00 lda #$00 ;default to no color alteration
37 E72D A4 4D ldy atract ;check attract counter
38 E72F 10 06 bpl attract_off ;skip if attract is off
39 E731 86 4D stx atract ;lock the attract counter
40 E733 A2 F6 ldx #$f6 ;set mask to dim colors
41 E735 A5 13 lda rtclok+1 ;use clock to randomize colors
42 E737 attract_off:
43 E737 86 4E stx drkmsk ;set color mask
44 E739 85 4F sta colrsh ;set color modifier
45
46 ;atract color 1 only
47 E73B 4D C5 02 eor color1
48 E73E 25 4E and drkmsk
49 E740 8D 17 D0 sta colpf1
50
51 ;decrement timer 1 and check for underflow
52 E743 AD 18 02 lda cdtmv1 ;check low byte
53 E746 D0 08 bne timer1_lobytezero ;if non-zero, decrement and check for fire
54 E748 AD 19 02 lda cdtmv1+1 ;check high byte
55 E74B F0 10 beq timer1_done ;if clear, timer's not running
56 E74D CE 19 02 dec cdtmv1+1 ;decrement high byte
57 E750 timer1_lobytezero:
58 E750 CE 18 02 dec cdtmv1 ;decrement low byte
59 E753 D0 08 bne timer1_done ;no underflow if non-zero
60 E755 AD 19 02 lda cdtmv1+1 ;low byte is zero... check if high byte is too
61 E758 D0 03 bne timer1_done ;if it's not, we're not done yet ($xx00 > 0)
62 E75A 20 67 E7 jsr timer1_dispatch ;jump through timer vector
63 E75D timer1_done:
64
65 ;check for critical operation
66 E75D A5 42 lda critic
67 E75F F0 09 beq no_critic
68 E761 xit:
69 E761 68 pla
70 E762 A8 tay
71 E763 68 pla
72 E764 AA tax
73 E765 exit_a:
74 E765 68 pla
75 E766 exit_none:
76 E766 40 rti
77
78 E767 timer1_dispatch:
79 E767 6C 26 02 jmp (cdtma1)
80
81 E76A no_critic:
82 E76A A9 04 lda #$04 ;I flag
83 E76C BA tsx
84 E76D 3D 04 01 and $0104,x ;I flag set on pushed stack?
85 E770 D0 EF bne xit ;exit if so
86
87 ;======== stage 2 processing
88
89 E772 stage_2:
90 ;re-enable interrupts
91 E772 58 cli
92
93 ;update shadow registers
94 E773 AD 31 02 8D 03 D4 mva sdlsth dlisth
95 E779 AD 30 02 8D 02 D4 mva sdlstl dlistl
96 E77F AD 2F 02 8D 00 D4 mva sdmctl dmactl
97 E785 AD F4 02 8D 09 D4 mva chbas chbase
98 E78B AD F3 02 8D 01 D4 mva chact chactl
99 E791 AD 6F 02 8D 1B D0 mva gprior prior
100
101 E797 A2 08 ldx #8
102 E799 8E 1F D0 stx consol ;sneak in speaker reset while we have an 8
103 E79C ColorLoop
104 E79C BD C0 02 lda pcolr0,x
105 E79F 45 4F eor colrsh
106 E7A1 25 4E and drkmsk
107 E7A3 9D 12 D0 sta colpm0,x
108 E7A6 CA dex
109 E7A7 10 F3 bpl ColorLoop
110
111 ;decrement timer 2 and check for underflow
112 E7A9 A2 03 ldx #3
113 E7AB 20 51 E8 jsr VBIDecrementTimer
114 E7AE D0 03 20 2F E8 sne:jsr Timer2Dispatch
115
116 ;Decrement timers 3-5 and set flags
117 ;
118 ;[OS Manual] Appendix L, page 254 says that the OS never modifies CDTMF3-5
119 ;except to set them to zero on timeout at init. This is a LIE. It also sets
120 ;the flags to $FF when they are running. It does not write the flags when
121 ;the timer is idle. Spider Quake depends on this.
122 ;
123 E7B3 A2 09 ldx #9
124 E7B5 timer_n_loop:
125 E7B5 18 clc
126 E7B6 20 51 E8 jsr VBIDecrementTimer
127 E7B9 B0 07 bcs timer_n_not_running
128 E7BB F0 02 A9 FF seq:lda #$ff
129 E7BF timer_n_not_expired:
130 E7BF 9D 25 02 sta cdtmf3-5,x
131 E7C2 timer_n_not_running:
132 E7C2 CA dex
133 E7C3 CA dex
134 E7C4 E0 05 cpx #5
135 E7C6 B0 ED bcs timer_n_loop
136
137 ;Read POKEY keyboard register and handle auto-repeat
138 E7C8 AD 0F D2 lda skstat ;get key status
139 E7CB 29 04 and #$04 ;check if key is down
140 E7CD D0 12 bne no_repeat_key ;skip if not
141 E7CF CE 2B 02 dec srtimr ;decrement repeat timer
142 E7D2 D0 12 bne no_repeat ;skip if not time to repeat yet
143 E7D4 AD 09 D2 8D FC 02 mva kbcode ch ;repeat last key
144
145 .if _KERNEL_XLXE
146 mva keyrep srtimr ;reset repeat timer
147 .else
148 E7DA A9 06 8D 2B 02 mva #$06 srtimr ;reset repeat timer
149 .endif
150
151 E7DF D0 0D bne no_keydel ;skip debounce counter decrement
152
153 E7E1 no_repeat_key:
154 E7E1 A9 00 lda #0
155 E7E3 8D 2B 02 sta srtimr
156 E7E6 no_repeat:
157 ;decrement keyboard debounce counter
158 E7E6 AD F1 02 lda keydel
159 E7E9 F0 03 CE F1 02 seq:dec keydel
160 E7EE no_keydel:
161
162 ;Update controller shadows.
163 ;
164 ;The PORTA/PORTB decoding is a bit complex:
165 ;
166 ; bits 0-3 -> STICK0/4 (and no, we cannot leave junk in the high bits)
167 ; bits 4-7 -> STICK1/5
168 ; bit 2 -> PTRIG0/4
169 ; bit 3 -> PTRIG1/5
170 ; bit 6 -> PTRIG2/6
171 ; bit 7 -> PTRIG3/7
172 ;
173 ;XL/XE machines only have two joystick ports, so the results of ports 0-1
174 ;are mapped onto ports 2-3.
175 ;
176
177 .if _KERNEL_XLXE
178 lda porta
179 tax
180 and #$0f
181 sta stick0
182 sta stick2
183 txa
184 lsr ;shr1
185 lsr ;shr2
186 tax
187 lsr ;shr3
188 lsr ;shr4
189 sta stick1
190 sta stick3
191 lsr ;shr5
192 lsr ;shr6
193 tay
194 and #$01
195 sta ptrig2
196 tya
197 lsr
198 sta ptrig3
199 txa
200 and #$01
201 sta ptrig0
202 txa
203 lsr
204 and #$01
205 sta ptrig1
206
207 ldx #3
208 pot_loop:
209 lda pot0,x
210 sta paddl0,x
211 sta paddl4,x
212 lda ptrig0,x
213 sta ptrig4,x
214 dex
215 bpl pot_loop
216
217 ldx #1
218 port_loop:
219 lda trig0,x
220 sta strig0,x
221 sta strig2,x
222 dex
223 bpl port_loop
224
225 .else
226 E7EE A2 07 ldx #7
227 E7F0 pot_loop:
228 E7F0 BD 00 D2 lda pot0,x
229 E7F3 9D 70 02 sta paddl0,x
230 E7F6 A9 00 lda #0
231 E7F8 9D 7C 02 sta ptrig0,x
232 E7FB CA dex
233 E7FC 10 F2 bpl pot_loop
234
235 E7FE A2 03 ldx #3
236 E800 trig_loop:
237 E800 BD 10 D0 lda trig0,x
238 E803 9D 84 02 sta strig0,x
239 E806 CA dex
240 E807 10 F7 bpl trig_loop
241
242 E809 AD 00 D3 lda porta
243 E80C A2 00 ldx #0
244 E80E A0 00 ldy #0
245 E810 20 32 E8 jsr do_stick_ptrigs
246 E813 AD 01 D3 lda portb
247 E816 A2 04 ldx #4
248 E818 A0 02 ldy #2
249 E81A 20 32 E8 jsr do_stick_ptrigs
250 .endif
251
252 ;restart pots (required for SysInfo)
253 E81D 8D 0B D2 sta potgo
254
255 ;update light pen
256 E820 AD 0C D4 8D 34 02 mva penh lpenh
257 E826 AD 0D D4 8D 35 02 mva penv lpenv
258
259 E82C 6C 24 02 jmp (vvblkd) ;jump through vblank deferred vector
260
261 E82F Timer2Dispatch
262 E82F 6C 28 02 jmp (cdtma2)
263
264 .if !_KERNEL_XLXE
265 E832 do_stick_ptrigs:
266 E832 48 pha
267 E833 29 0F and #$0f
268 E835 99 78 02 sta stick0,y
269 E838 68 pla
270 E839 4A lsr
271 E83A 4A lsr
272 E83B 4A lsr
273 E83C 3E 7C 02 rol ptrig0,x
274 E83F 4A lsr
275 E840 3E 7D 02 rol ptrig1,x
276 E843 99 79 02 sta stick1,y
277 E846 4A lsr
278 E847 4A lsr
279 E848 4A lsr
280 E849 3E 7E 02 rol ptrig2,x
281 E84C 4A lsr
282 E84D 3E 7F 02 rol ptrig3,x
283 E850 60 rts
284 .endif
285
286 .endp
287
288 ;==========================================================================
289 ; VBIDecrementTimer
290 ;
291 ; Entry:
292 ; X = timer index *2+1 (1-9)
293 ;
294 ; Exit:
295 ; C=1, Z=0, A!0 timer not running
296 ; C=0/same, Z=1, A=0 timer just expired
297 ; C=0/same, Z=0, A=? timer still running
298 ;
299 E851 .proc VBIDecrementTimer
300 ;check low byte
301 E851 BD 17 02 lda cdtmv1-1,x
302 E854 D0 0A bne lononzero
303
304 ;check high byte; set C=1/Z=1 if zero, C=0/Z=0 otherwise
305 E856 DD 18 02 cmp cdtmv1,x
306 E859 D0 02 bne lozero_hinonzero
307
308 ;both bytes are zero, so timer's not running
309 E85B 8A txa
310 E85C 60 rts
311
312 E85D lozero_hinonzero:
313 ;decrement high byte
314 E85D DE 18 02 dec cdtmv1,x
315
316 E860 lononzero:
317 ;decrement low byte
318 E860 DE 17 02 dec cdtmv1-1,x
319 E863 D0 03 bne still_running
320
321 ;return high byte to set Z appropriately
322 E865 BD 18 02 lda cdtmv1,x
323 E868 still_running:
324 E868 60 rts
325 .endp
326
327 ;==========================================================================
328 ; VBISetVector - set vertical blank vector or counter
329 ;
330 ; This is a drop-in replacement for SETVBV.
331 ;
332 ; A = item to update
333 ; 1-5 timer 1-5 counter value
334 ; 6 VVBLKI
335 ; 7 VVBLKD
336 ; X = MSB
337 ; Y = LSB
338 ;
339 E869 .proc VBISetVector
340 ;A = item to update
341 ; 1-5 timer 1-5 counter value
342 ; 6 VVBLKI
343 ; 7 VVBLKD
344 ;X = MSB
345 ;Y = LSB
346 ;
347 ;NOTE:
348 ;The Atari OS Manual says that DLIs will be disabled after SETVBV is called.
349 ;This is a lie -- neither the OS-B nor XL kernels do this, and the Bewesoft
350 ;8-players demo depends on it being left enabled.
351 ;
352 ;IRQ mask state must be saved across this proc. DOSDISKA.ATR breaks if IRQs
353 ;are unmasked.
354
355 E869 0A asl
356 E86A 8D 2D 02 sta intemp
357 E86D 08 php
358 E86E 78 sei
359 E86F 98 tya
360 E870 AC 2D 02 ldy intemp
361
362 ;We're relying on a rather tight window here. We can't touch NMIEN, so we have
363 ;to wing it with DLIs enabled. Problem is, in certain conditions we can be under
364 ;very tight timing constraints. In order to do this safely we have to finish
365 ;before a DLI can execute. The worst case is a wide mode 2 line at the end of
366 ;a vertically scrolled region with P/M graphics enabled and an LMS on the next
367 ;mode line. In that case we only have 7 cycles before we hit the P/M graphics
368 ;and another two cycles after that until the DLI fires. The exact cycle timing
369 ;looks like this:
370 ;
371 ;* inc wsync
372 ;ANTIC halts CPU until cycle 105
373 ;105 playfield DMA
374 ;106 refresh DMA
375 ;107 sta abs,y (1/5)
376 ;108 sta abs,y (2/5)
377 ;109 sta abs,y (3/5)
378 ;110 sta abs,y (4/5)
379 ;111 sta abs,y (5/5)
380 ;112 txa (1/2)
381 ;113 txa (2/2)
382 ;0 missiles
383 ;1 display list
384 ;2 player 0
385 ;3 player 1
386 ;4 player 2
387 ;5 player 3
388 ;6 display list address low
389 ;7 display list address high
390 ;8 sta abs,y (1/5)
391 ;9 sta abs,y (2/5)
392 ;10 sta abs,y (3/5)
393 ;11 sta abs,y (4/5)
394 ;12 sta abs,y (5/5)
395 ;
396 ;We rely on the 6502 not being able to service interrupts until the end of an
397 ;instruction for this to work. The INC WSYNC is necessary to combat the case
398 ;where the NMI is triggered across the WSYNC wait; without it, the VBI could
399 ;fire immediately after the first STA.
400
401 E873 EE 0A D4 inc wsync
402 E876 99 16 02 sta cdtmv1-2,y
403 E879 8A txa
404 E87A 99 17 02 sta cdtmv1-1,y
405 E87D 28 plp
406 E87E 60 rts
407 .endp
242 E87F icl 'interrupt.s'
Source: source/Shared/interrupt.s
1 ; Altirra - Atari 800/800XL/5200 emulator
2 ; Modular Kernel ROM - Interrupt Handlers
3 ; Copyright (C) 2008-2016 Avery Lee
4 ;
5 ; Copying and distribution of this file, with or without modification,
6 ; are permitted in any medium without royalty provided the copyright
7 ; notice and this notice are preserved. This file is offered as-is,
8 ; without any warranty.
9
10 ;==========================================================================
11 ; Dispatched from INTINV. Used by SpartaDOS X.
12 ;
13 E87F .proc IntInitInterrupts
14 E87F A9 40 8D 0E D4 mva #$40 nmien
15
16 .if _KERNEL_XLXE
17 ;Required by XEGS carts to run since they have a clone of the XL/XE
18 ;OS in them.
19 mva trig3 gintlk
20 .endif
21
22 E884 60 rts
23 .endp
24
25 ;==========================================================================
26 E885 .proc IntDispatchNMI
27 E885 2C 0F D4 bit nmist ;check nmi status
28 E888 10 06 bpl not_dli ;skip if not a DLI
29 E88A 6C 00 02 jmp (vdslst) ;jump to display list vector
30
31 .if !_KERNEL_XLXE
32 E88D is_system_reset:
33 E88D 4C 74 E4 jmp warmsv
34 .endif
35
36 E890 not_dli:
37 E890 48 pha
38
39 .if _KERNEL_XLXE
40 ;Only XL/XE OSes cleared the decimal bit.
41 cld
42 .else
43 ;The stock OS treats 'not RNMI' as VBI. We'd best follow its example.
44 E891 A9 20 lda #$20
45 E893 2C 0F D4 bit nmist
46 E896 D0 F5 bne is_system_reset
47 .endif
48
49 E898 8A txa
50 E899 48 pha
51 E89A 98 tya
52 E89B 48 pha
53 E89C 8D 0F D4 sta nmires ;reset VBI interrupt
54 E89F 6C 22 02 jmp (vvblki) ;jump through vblank immediate vector
55 .endp
56
57 E8A2 .proc IntDispatchIRQ
58 .if _KERNEL_XLXE
59 cld
60 .endif
61 E8A2 6C 16 02 jmp (vimirq)
62 .endp
63
64 ;==============================================================================
65 = E765 IntExitHandler_A = VBIProcess.exit_a
66 = E766 IntExitHandler_None = VBIProcess.exit_none
243 E8A5 icl 'irq.s'
Source: source/Shared/irq.s
1 ; Altirra - Atari 800/800XL/5200 emulator
2 ; Modular Kernel ROM - IRQ routines
3 ; Copyright (C) 2008-2016 Avery Lee
4 ;
5 ; Copying and distribution of this file, with or without modification,
6 ; are permitted in any medium without royalty provided the copyright
7 ; notice and this notice are preserved. This file is offered as-is,
8 ; without any warranty.
9
10 ;==========================================================================
11 ; _KERNEL_FAST_IRQ
12 ;
13 ; If set, expands the IRQ module slightly to save 12 cycles when ack'ing
14 ; POKEY IRQs. This is still faster than the stock XL/XE OS. If cleared,
15 ; an additional subroutine call is used to reduce code size.
16 ;
17 .ifndef _KERNEL_FAST_IRQ
18 _KERNEL_FAST_IRQ = 0
19 .endif
20
21 ;==========================================================================
22 .if _KERNEL_FAST_IRQ
23 _ACK_IRQ .macro
24 sta irqen
25 lda pokmsk
26 sta irqen
27 .endm
28 .else
29 _ACK_IRQ .macro
30 jsr IrqAcknowledge
31 .endm
32 .endif
33
34 ;==========================================================================
35 ; The canonical IRQ priority order for the XL/XE is:
36 ; - Serial input ready ($20)
37 ; - PBI devices
38 ; - Serial output ready ($10)
39 ; - Serial output complete ($08)
40 ; - Timer 1 ($01)
41 ; - Timer 2 ($02)
42 ; - Timer 4 ($04)
43 ; - Keyboard ($80)
44 ; - Break ($40)
45 ; - PIA proceed
46 ; - PIA interrupt
47 ; - BRK instruction
48 ;
49 = E8CD IRQHandler = _IRQHandler._entry
50 E8A5 .proc _IRQHandler
51 .if _KERNEL_PBI_SUPPORT
52 check_pbi:
53 ;check if a device interrupt is active
54 and $d1ff
55 beq no_pbi_interrupt
56
57 ;save X
58 sta jveck
59 txa
60 pha
61
62 ;jump through PBI interrupt vector
63 lda jveck
64 jmp (vpirq)
65 .endif
66
67 E8A5 dispatch_serout:
68 E8A5 A9 EF lda #$ef
69 E8A7 _ACK_IRQ
Macro: _ACK_IRQ [Source: source/Shared/irq.s]
1 E8A7 20 3C E9 jsr IrqAcknowledge
Source: source/Shared/irq.s
70 E8AA 6C 0C 02 jmp (vseror)
71
72 E8AD check_seroc:
73 E8AD 2C 0E D2 bit irqst
74 E8B0 D0 3C bne not_seroc
75 E8B2 dispatch_seroc:
76 E8B2 6C 0E 02 jmp (vseroc)
77
78 E8B5 dispatch_timer1:
79 E8B5 A9 FE lda #$fe
80 E8B7 _ACK_IRQ
Macro: _ACK_IRQ [Source: source/Shared/irq.s]
1 E8B7 20 3C E9 jsr IrqAcknowledge
Source: source/Shared/irq.s
81 E8BA 6C 10 02 jmp (vtimr1)
82
83 E8BD dispatch_timer2:
84 E8BD A9 FD lda #$fd
85 E8BF _ACK_IRQ
Macro: _ACK_IRQ [Source: source/Shared/irq.s]
1 E8BF 20 3C E9 jsr IrqAcknowledge
Source: source/Shared/irq.s
86 E8C2 6C 12 02 jmp (vtimr2)
87
88 E8C5 dispatch_timer4:
89 E8C5 A9 FB lda #$fb
90 E8C7 _ACK_IRQ
Macro: _ACK_IRQ [Source: source/Shared/irq.s]
1 E8C7 20 3C E9 jsr IrqAcknowledge
Source: source/Shared/irq.s
91 E8CA 6C 14 02 jmp (vtimr4)
92
93 E8CD _entry:
94 E8CD 48 pha
95
96 ;check for serial input ready IRQ
97 E8CE A9 20 lda #$20
98 E8D0 2C 0E D2 bit irqst
99 E8D3 D0 0D bne not_serin
100 E8D5 A9 DF lda #$df
101 E8D7 8D 0E D2 sta irqen
102 E8DA A5 10 lda pokmsk
103 E8DC 8D 0E D2 sta irqen
104 E8DF 6C 0A 02 jmp (vserin)
105 E8E2 not_serin:
106
107 .if _KERNEL_PBI_SUPPORT
108 ;check for PBI devices requiring interrupt handling
109 lda pdmsk
110 bne check_pbi
111 no_pbi_interrupt:
112 .endif
113
114 ;check for serial output ready IRQ
115 E8E2 A9 10 lda #$10
116 E8E4 2C 0E D2 bit irqst
117 E8E7 F0 BC beq dispatch_serout
118
119 ;check for serial output complete (not a latch, so must mask)
120 E8E9 4A lsr
121 E8EA 24 10 bit pokmsk
122 E8EC D0 BF bne check_seroc
123 E8EE not_seroc:
124
125 E8EE AD 0E D2 lda irqst
126 E8F1 4A lsr
127 E8F2 90 C1 bcc dispatch_timer1
128 E8F4 4A lsr
129 E8F5 90 C6 bcc dispatch_timer2
130 E8F7 4A lsr
131 E8F8 90 CB bcc dispatch_timer4
132 E8FA 2C 0E D2 bit irqst
133 E8FD 50 21 bvc dispatch_keyboard
134 E8FF 10 27 bpl dispatch_break
135
136 ;check for serial bus proceed line
137 E901 2C 02 D3 bit pactl
138 E904 30 2A bmi dispatch_pia_irqa
139
140 ;check for serial bus interrupt line
141 E906 2C 03 D3 bit pbctl
142 E909 30 2B bmi dispatch_pia_irqb
143
144 ;check for break instruction
145 ;
146 ;we used to use TSX here, but this takes too many insns to
147 ;handle stack wrapping properly
148 E90B 68 pla
149 E90C 8D 8C 02 sta jveck
150 E90F 68 pla
151 E910 48 pha
152 E911 29 10 and #$10
153 E913 F0 07 beq not_brk
154 E915 AD 8C 02 lda jveck
155 E918 48 pha
156 E919 6C 06 02 jmp (vbreak)
157 E91C not_brk:
158 E91C AD 8C 02 lda jveck
159 E91F 40 rti
160
161
162 E920 dispatch_keyboard:
163 E920 A9 BF lda #$bf
164 E922 _ACK_IRQ
Macro: _ACK_IRQ [Source: source/Shared/irq.s]
1 E922 20 3C E9 jsr IrqAcknowledge
Source: source/Shared/irq.s
165 E925 6C 08 02 jmp (vkeybd)
166
167 E928 dispatch_break:
168 E928 A9 7F lda #$7f
169 E92A _ACK_IRQ
Macro: _ACK_IRQ [Source: source/Shared/irq.s]
1 E92A 20 3C E9 jsr IrqAcknowledge
Source: source/Shared/irq.s
170 E92D 6C 36 02 jmp (brkky)
171
172 E930 dispatch_pia_irqa:
173 ;clear serial bus proceed interrupt
174 E930 AD 00 D3 lda porta
175 E933 6C 02 02 jmp (vprced)
176
177 E936 dispatch_pia_irqb:
178 ;clear serial bus interrupt interrupt
179 E936 AD 01 D3 lda portb
180 E939 6C 04 02 jmp (vinter)
181
182 .endp
183
184 ;==========================================================================
185 .if !_KERNEL_FAST_IRQ
186 E93C .proc IrqAcknowledge
187 E93C 8D 0E D2 sta irqen
188 E93F A5 10 lda pokmsk
189 E941 8D 0E D2 sta irqen
190 E944 60 rts
191 .endp
192 .endif
244 .endif
245 E945 _KERNEL_REPORT_MODULE_SIZE 'Interrupt routines', $E944-$E6D5
Macro: _KERNEL_REPORT_MODULE_SIZE [Source: source/main.xasm]
1 .echo ' ', *, ' -> ', *-?@_kernel_lastpt, '(', $E944-$E6D5, ')', ' ', 'Interrupt routines'
1 $E945 -> $0228($026F) Interrupt routines
3 = E945 .def ?@_kernel_lastpt = *
Source: source/main.xasm
246
247 E945 icl 'sio.inc'
Source: source/Shared/sio.inc
1 ; Altirra - Atari 800/800XL/5200 emulator
2 ; Modular Kernel ROM - SIO definitions
3 ; Copyright (C) 2008-2016 Avery Lee
4 ;
5 ; Copying and distribution of this file, with or without modification,
6 ; are permitted in any medium without royalty provided the copyright
7 ; notice and this notice are preserved. This file is offered as-is,
8 ; without any warranty.
9
10 .ifndef f_SIO_INC
11 .def f_SIO_INC
12
13 SIOSuccess = $01
14 SIOErrorTimeout = $8A
15 SIOErrorNAK = $8B
16 SIOErrorBadFrame = $8C
17 SIOErrorOverrun = $8E
18 SIOErrorChecksum = $8F
19 SIOErrorDeviceError = $90
20
21 .endif
248 E945 icl 'sio.s'
Source: source/Shared/sio.s
1 ; Altirra - Atari 800/800XL/5200 emulator
2 ; AltirraOS modular Kernel ROM - Serial Input/Output (SIO) routines
3 ; Copyright (C) 2008-2019 Avery Lee
4 ;
5 ; Copying and distribution of this file, with or without modification,
6 ; are permitted in any medium without royalty provided the copyright
7 ; notice and this notice are preserved. This file is offered as-is,
8 ; without any warranty.
9
10 E945 .proc SIOInit
11 ;turn off POKEY init mode so polynomial counters and audio run
12 E945 A9 03 8D 0F D2 mva #3 skctl
13 E94A 8D 32 02 sta sskctl
14
15 ;enable noisy sound (yes, this is actually documented as being inited to
16 ;3)
17 E94D 85 41 sta soundr
18 E94F 60 rts
19 .endp
20
21 ;==============================================================================
22 E950 .proc SIO
23 ;set retry counters
24 E950 A9 01 8D BD 02 mva #$01 dretry
25
26 ;enter critical section
27 E955 85 42 sta critic
28
29 .if _KERNEL_PBI_SUPPORT
30 ;attempt PBI transfer
31 jsr PBIAttemptSIO
32 scc:jmp xit_pbi
33 .endif
34
35 ;we must not save STACKP until after PBI devices are polled -- the
36 ;BlackBox PBI routines depend on being able to reuse this location
37 E957 BA tsx
38 E958 8E 18 03 stx stackp
39
40 ;Set timeout timer address -- MUST be done on each call to SIO, or
41 ;Cross-Town Crazy Eight hangs on load due to taking over this vector
42 ;previously. This is guaranteed by the OS Manual in Appendix L, H27.
43 E95B 20 65 EA jsr SIOSetTimeoutVector
44
45 ;check for cassette -- needs to match $60 or else Prisma: Alien Ambush
46 ;fails to load.
47 E95E A2 00 ldx #0
48 E960 AD 00 03 lda ddevic
49 E963 C9 60 cmp #$60
50 E965 D0 01 CA sne:dex
51 E968 8E 0F 03 stx casflg
52
53 ;init POKEY hardware
54 E96B 20 B8 EA jsr SIOInitHardware
55
56 ;go do cassette now
57 E96E 2C 0F 03 bit casflg
58 E971 10 03 bpl retry_command
59 E973 4C 2E EC jmp SIOCassette
60
61 E976 retry_command:
62 ;We try 13 times to get a command accepted by a device; after that it
63 ;counts as a device failure and we try one more round of 13 tries.
64 E976 A9 0D 8D 9C 02 mva #$0d cretry
65
66 E97B retry_command_2:
67 ;init command buffer
68 E97B AD 00 03 lda ddevic
69 E97E 18 clc
70 E97F 6D 01 03 adc dunit
71 E982 38 sec
72 E983 E9 01 sbc #1
73 E985 8D 3A 02 sta cdevic
74
75 E988 AD 02 03 8D 3B 02 mva dcomnd ccomnd
76 E98E AD 0A 03 8D 3C 02 mva daux1 caux1
77 E994 AD 0B 03 8D 3D 02 mva daux2 caux2
78
79 ;assert command line
80 E99A A9 34 8D 03 D3 mva #$34 pbctl
81
82 ;wait ~600us to ensure 750us minimum delay (~1k cycles or ~10 scanlines)
83 E99F A2 05 ldx #5
84 E9A1 AC 0B D4 ldy vcount
85 E9A4 cmddelay:
86 E9A4 CC 0B D4 F0 FB cpy:req vcount
87 E9A9 C8 iny
88 E9AA CA dex
89 E9AB D0 F7 bne cmddelay
90
91 ;send command frame
92 E9AD A9 00 85 3C mva #0 nocksm
93 E9B1 A9 02 lda #>cdevic
94 E9B3 85 33 sta bufrhi
95 E9B5 85 35 sta bfenhi
96 E9B7 A9 3A 85 32 mva #<cdevic bufrlo
97 E9BB A9 3E 85 34 mva #<caux2+1 bfenlo
98 E9BF 20 1D EB jsr SIOSend
99 E9C2 30 65 bmi xit
100
101 ;wait for the ACK
102 E9C4 20 70 EA jsr SIOWaitForACK
103 E9C7 10 0A bpl ackOK
104
105 E9C9 command_error:
106 E9C9 20 8A EB jsr SIOReceiveStop
107 E9CC CE 9C 02 dec cretry
108 E9CF 10 AA bpl retry_command_2
109 E9D1 30 4B bmi transfer_error
110
111 E9D3 ackOK:
112
113 ;check if we should send a data frame
114 E9D3 2C 03 03 bit dstats
115 E9D6 10 0D bpl no_send_frame
116
117 ;setup buffer pointers
118 E9D8 20 07 EB jsr SIOSetupBufferPointers
119
120 ;send data frame
121 E9DB 20 1D EB jsr SIOSend
122 E9DE 30 49 bmi xit
123
124 ;wait for ACK
125 E9E0 20 70 EA jsr SIOWaitForACK
126 E9E3 30 E4 bmi command_error
127
128 E9E5 no_send_frame:
129
130 ;setup for receiving complete
131 E9E5 A2 FF ldx #$ff
132 E9E7 8E 17 03 stx timflg
133 E9EA 86 3C stx nocksm
134
135 ;setup frame delay for complete
136 E9EC AD 06 03 lda dtimlo
137 E9EF 6A ror
138 E9F0 6A ror
139 E9F1 48 pha
140 E9F2 6A ror
141 E9F3 29 C0 and #$c0
142 E9F5 A8 tay
143 E9F6 68 pla
144 E9F7 29 3F and #$3f
145 E9F9 AA tax
146
147 E9FA A9 01 lda #1
148 E9FC 20 5C E4 jsr setvbv
149
150 E9FF A2 3E ldx #<temp
151 EA01 86 32 stx bufrlo
152 EA03 E8 inx
153 EA04 86 34 stx bfenlo
154 EA06 A2 02 ldx #>temp
155 EA08 86 33 stx bufrhi
156 EA0A 86 35 stx bfenhi
157 EA0C 20 4C EB jsr SIOReceive
158 EA0F 30 0D bmi transfer_error
159
160 ;Check if we received a C ($43) or E ($45) -- we must NOT abort immediately
161 ;on a device error, as the device still sends back data we need to read, and
162 ;Music Studio relies on the data coming back from a CRC error.
163 EA11 AD 3E 02 lda temp
164 EA14 C9 43 cmp #$43
165 EA16 F0 32 beq completeOK
166 EA18 C9 45 cmp #$45
167 EA1A F0 2E beq completeOK
168
169 ;we received crap... fail it now
170 EA1C device_error:
171 EA1C A0 90 ldy #SIOErrorDeviceError
172
173 EA1E transfer_error:
174 EA1E 20 8A EB jsr SIOReceiveStop
175
176 EA21 CE BD 02 dec dretry
177 EA24 30 03 bmi device_retries_exhausted
178 EA26 4C 76 E9 jmp retry_command
179
180 EA29 device_retries_exhausted:
181 EA29 xit:
182 EA29 AE 0F 03 ldx casflg
183 EA2C D0 0C bne leave_cassette_audio_on
184 EA2E 8E 01 D2 stx audc1
185 EA31 8E 03 D2 stx audc2
186 EA34 8E 05 D2 stx audc3
187 EA37 8E 07 D2 stx audc4
188 EA3A leave_cassette_audio_on:
189
190 .ifdef _KERNEL_816
191 ;we may be in native mode, so we can't f-up the high byte of the stack pointer
192 lda #1
193 xba
194 lda stackp
195 tcs
196 .else
197 EA3A AE 18 03 ldx stackp
198 EA3D 9A txs
199 .endif
200
201 EA3E xit_pbi:
202 EA3E A9 00 lda #0
203 EA40 85 42 sta critic
204
205 EA42 C0 00 cpy #0 ;!! - A=0 must be preserved for LiteDOS
206 EA44 8C 03 03 sty dstats
207 EA47 84 30 sty status
208 EA49 60 rts
209
210 EA4A completeOK:
211 ;check if we should read a data frame
212 EA4A 2C 03 03 bit dstats
213 EA4D 50 08 bvc no_receive_frame
214
215 ;setup buffer pointers
216 EA4F 20 07 EB jsr SIOSetupBufferPointers
217
218 ;receive the rest of the frame
219 EA52 20 4C EB jsr SIOReceive
220 EA55 30 C7 bmi transfer_error
221
222 EA57 no_receive_frame:
223 ;now we can finally shut off the receive IRQ
224 EA57 20 8A EB jsr SIOReceiveStop
225
226 ;Now check whether we got a device error earlier. If we did, return
227 ;that instead of success.
228 EA5A AD 3E 02 lda temp
229 EA5D C9 43 cmp #'C'
230 EA5F D0 BB bne device_error
231
232 ;nope, we're good... exit OK.
233 EA61 A0 01 ldy #SIOSuccess
234 EA63 D0 C4 bne xit
235 .endp
236
237 ;==============================================================================
238 EA65 .proc SIOSetTimeoutVector
239 EA65 A9 28 8D 26 02 A9 + mwa #SIOCountdown1Handler cdtma1
240 EA6F 60 rts
241 .endp
242
243 ;==============================================================================
244 EA70 .proc SIOWaitForACK
245 ;setup 2 frame delay for ack
246 EA70 A2 FF ldx #$ff
247 EA72 8E 17 03 stx timflg
248 EA75 86 3C stx nocksm
249 EA77 E8 inx ;X=0
250 EA78 A9 01 lda #1
251 EA7A A0 02 ldy #2
252 EA7C 84 33 sty bufrhi ;>temp = 2
253 EA7E 84 35 sty bfenhi ;>temp+1 = 2
254 EA80 20 5C E4 jsr setvbv
255
256 ;setup for receiving ACK
257 EA83 A2 3E ldx #<temp
258 EA85 86 32 stx bufrlo
259 EA87 E8 inx
260 EA88 86 34 stx bfenlo ;#<[temp+1]
261
262 EA8A 20 4C EB jsr SIOReceive
263
264 ;check if we had a receive error
265 EA8D 30 09 bmi xit
266
267 ;check if we got an ACK
268 EA8F AD 3E 02 lda temp
269 EA92 C9 41 cmp #'A'
270 EA94 F0 02 beq xit
271
272 ;doh
273 EA96 A0 8B ldy #SIOErrorNAK
274 EA98 xit:
275 EA98 60 rts
276 .endp
277
278 ;==============================================================================
279 ;SIO send enable routine
280 ;
281 ; This is one of those routines that Atari inadvisably exposed in the OS jump
282 ; table even though they shouldn't. Responsibilities of this routine are:
283 ;
284 ; - Hit SKCTL to reset serial hardware and init for sending
285 ; - Hit SKRES to clear status
286 ; - Enable send interrupts
287 ; - Configure AUDF3/AUDF4 frequency (19200 baud or 600 baud)
288 ; - Set AUDC3/AUDC4 for noisy or non-noisy audio
289 ; - Set AUDCTL
290 ;
291 ; It does not init any of the SIO variables, only hardware/shadow state.
292 ;
293 = EAB8 SIOInitHardware = SIOSendEnable.init_hardware
294 EA99 .proc SIOSendEnable
295 ;enable serial output ready IRQ and suppress serial output complete IRQ
296 EA99 A5 10 lda pokmsk
297 EA9B 09 10 ora #$10
298 EA9D 29 F7 and #$f7
299 EA9F 85 10 sta pokmsk
300 EAA1 8D 0E D2 sta irqen
301
302 EAA4 no_irq_setup:
303 ;clear forced break mode and reset serial clocking mode to timer 4
304 ;synchronous; also enable two-tone mode if in cassette mode
305 EAA4 AD 32 02 lda sskctl
306 EAA7 29 0F and #$0f
307 EAA9 09 20 ora #$20
308 EAAB AE 0F 03 ldx casflg
309 EAAE F0 02 09 08 seq:ora #$08
310 EAB2 8D 32 02 sta sskctl
311 EAB5 8D 0F D2 sta skctl
312
313 EAB8 init_hardware:
314 ;clock channel 3 and 4 together at 1.79MHz
315 ;configure pokey timers 3 and 4 for 19200 baud (1789773/(2*40+7) = 19040)
316 EAB8 A2 08 ldx #8
317
318 ;check if we are doing a cassette transfer; if so, use the cassette
319 ;register table instead
320 EABA AD 0F 03 lda casflg
321 EABD F0 02 beq not_cassette
322
323 EABF A2 11 ldx #17
324
325 EAC1 not_cassette:
326
327 = EAC1 .def :SIOInitPOKEYWithRegOffsetX
328 ;load POKEY audio registers
329 EAC1 A0 08 ldy #8
330 EAC3 BD EC EA CA 99 00 + mva:rpl regdata_normal,x- audf1,y-
331
332 ;go noisy audio if requested
333 EACD A5 41 lda soundr
334 EACF F0 17 beq no_noise
335
336 EAD1 A9 A8 lda #$a8
337 EAD3 8D 07 D2 sta audc4
338 EAD6 AE 0F 03 ldx casflg
339 EAD9 F0 0D beq no_noise
340 EADB A9 10 lda #$10
341 EADD 2C 32 02 bit sskctl
342 EAE0 D0 06 bne no_noise
343 EAE2 8D 01 D2 sta audc1
344 EAE5 8D 03 D2 sta audc2
345
346 EAE8 no_noise:
347
348 ;reset serial status
349 EAE8 8D 0A D2 sta skres
350 EAEB 60 rts
351
352 EAEC regdata:
353 EAEC regdata_normal:
354 EAEC 00 dta $00 ;audf1
355 EAED A0 dta $a0 ;audc1
356 EAEE 00 dta $00 ;audf2
357 EAEF A0 dta $a0 ;audc2
358 EAF0 28 dta $28 ;audf3
359 EAF1 A0 dta $a0 ;audc3
360 EAF2 00 dta $00 ;audf4
361 EAF3 A0 dta $a0 ;audc4
362 EAF4 28 dta $28 ;audctl
363
364 EAF5 regdata_cassette_write:
365 EAF5 05 dta $05 ;audf1
366 EAF6 A0 dta $a0 ;audc1
367 EAF7 07 dta $07 ;audf2
368 EAF8 A0 dta $a0 ;audc2
369 EAF9 CC dta $cc ;audf3
370 EAFA A0 dta $a0 ;audc3
371 EAFB 05 dta $05 ;audf4
372 EAFC A0 dta $a0 ;audc4
373 EAFD 28 dta $28 ;audctl
374
375 EAFE regdata_cassette_read:
376 EAFE 00 dta $00 ;audf1
377 EAFF A0 dta $a0 ;audc1
378 EB00 00 dta $00 ;audf2
379 EB01 A0 dta $a0 ;audc2
380 EB02 CC dta $cc ;audf3
381 EB03 A0 dta $a0 ;audc3
382 EB04 05 dta $05 ;audf4
383 EB05 A0 dta $a0 ;audc4
384 EB06 28 dta $28 ;audctl
385 .endp
386
387 ;==============================================================================
388 EB07 .proc SIOSetupBufferPointers
389 EB07 18 clc
390 EB08 AD 04 03 lda dbuflo
391 EB0B 85 32 sta bufrlo
392 EB0D 6D 08 03 adc dbytlo
393 EB10 85 34 sta bfenlo
394 EB12 AD 05 03 lda dbufhi
395 EB15 85 33 sta bufrhi
396 EB17 6D 09 03 adc dbythi
397 EB1A 85 35 sta bfenhi
398 EB1C 60 rts
399 .endp
400
401 ;==============================================================================
402 ;SIO send routine
403 ;
404 EB1D .proc SIOSend
405 ;configure serial port for synchronous transmission
406 ;enable transmission IRQs
407 EB1D 78 sei
408 EB1E 20 99 EA jsr SIOSendEnable
409
410 EB21 A0 00 ldy #0
411 EB23 84 3A sty xmtdon
412 EB25 84 30 sty status
413 EB27 84 3B sty chksnt
414
415 ;send first byte and set checksum (must be atomic)
416 EB29 B1 32 lda (bufrlo),y
417 EB2B 8D 0D D2 sta serout
418 EB2E 85 31 sta chksum
419
420 ;unmask IRQs
421 EB30 58 cli
422
423 ;wait for transmit to complete or Break to be pressed
424 EB31 wait:
425 EB31 A5 11 lda brkkey
426 EB33 F0 06 beq break_detected
427 EB35 A5 3A lda xmtdon
428 EB37 F0 F8 beq wait
429 EB39 D0 04 bne send_completed
430
431 EB3B break_detected:
432 EB3B A0 80 ldy #$80
433 EB3D 84 30 sty status
434
435 EB3F send_completed:
436 ;shut off transmission IRQs
437 EB3F 78 sei
438 EB40 A5 10 lda pokmsk
439 EB42 29 E7 and #$e7
440 EB44 85 10 sta pokmsk
441 EB46 8D 0E D2 sta irqen
442 EB49 58 cli
443
444 ;we're done
445 EB4A 98 tya
446 EB4B 60 rts
447 .endp
448
449 ;==============================================================================
450 ; SIO receive routine
451 ;
452 ; The exit and entry paths of this routine are time critical when receiving
453 ; the Complete/Error byte and data frame since there may be no delay at all
454 ; in between. The exit path needs to exit with the receive IRQ hot but IRQs
455 ; masked; the entry path in turn needs to keep the IRQ enabled but not unmask
456 ; IRQs until ready to receive.
457 ;
458 EB4C .proc SIOReceive
459 EB4C A9 00 lda #0
460 EB4E use_checksum:
461 EB4E 85 31 sta chksum
462 EB50 A2 00 ldx #0
463 EB52 86 39 stx recvdn ;receive done flag = false
464 EB54 86 38 stx bufrfl ;buffer full flag = false
465 EB56 E8 inx
466 EB57 86 30 stx status ;set status to success (1)
467
468 ;configure serial port for asynchronous receive
469 ;enable receive IRQ
470 EB59 78 sei
471 EB5A AD 32 02 lda sskctl
472 EB5D 29 8F and #$8f
473 EB5F 09 10 ora #$10
474 EB61 8D 32 02 sta sskctl
475 EB64 8D 0F D2 sta skctl
476 EB67 A5 10 lda pokmsk
477 EB69 09 20 ora #$20
478 EB6B 85 10 sta pokmsk
479 EB6D 8D 0E D2 sta irqen
480 EB70 58 cli
481
482 ;Negate command line (if it isn't already negated).
483 ;
484 ;Note that we DON'T do this until we are entirely ready to receive,
485 ;because as soon as we do this we can get data.
486 EB71 A9 3C 8D 03 D3 mva #$3c pbctl
487
488 ;wait for receive to complete
489 EB76 wait:
490 EB76 AD 17 03 lda timflg ;check for timeout
491 EB79 F0 0B beq timeout ;bail if so
492 EB7B A4 30 ldy status ;check for another error code
493 EB7D 30 05 bmi error ;bail if so
494 EB7F A5 39 lda recvdn ;check for receive complete
495 EB81 F0 F3 beq wait ;keep waiting if not
496 EB83 98 tya ;set flags from status
497
498 EB84 error:
499 ;Mask interrupts, but exit with them masked. We do this in order to
500 ;handle the transition from Complete to data frame during receive. There
501 ;is no guaranteed device delay in between these and some disk drives
502 ;send back-to-back bytes. In addition, there are demos that have DLIs
503 ;active during SIO loads. Therefore, we avoid turning off the receive
504 ;interrupt and instead hold it off to give us the best chance of snagging
505 ;the first and second bytes successfully, even if delayed.
506 EB84 78 sei
507 EB85 60 rts
508
509 EB86 timeout:
510 EB86 A0 8A ldy #SIOErrorTimeout
511 EB88 78 sei
512 EB89 60 rts
513 .endp
514
515 ;==============================================================================
516 EB8A .proc SIOReceiveStop
517 ;shut off receive IRQs
518 EB8A A5 10 lda pokmsk
519 EB8C 29 D7 and #$d7
520 EB8E 85 10 sta pokmsk
521 EB90 8D 0E D2 sta irqen
522 EB93 58 cli
523 EB94 60 rts
524 .endp
525
526 ;==============================================================================
527 ; SIO serial input routine
528 ;
529 ; DOS 2.0S replaces (VSERIN), so it's critical that this routine follow the
530 ; rules compatible with DOS. The rules are as follows:
531 ;
532 ; BUFRLO/BUFRHI: Points to next byte to read. Note that this is different
533 ; from (VSEROR)!
534 ; BFENLO/BFENHI: Points one after last byte in buffer.
535 ; BUFRFL: Set when all data bytes have been read.
536 ; NOCKSM: Set if no checksum byte is expected. Cleared after checked.
537 ; RECVDN: Set when receive is complete, including any checksum.
538 ;
539 EB95 .proc SIOInputReadyHandler
540 EB95 A5 38 lda bufrfl
541 EB97 D0 2A bne receiveChecksum
542
543 ;receive data byte
544 EB99 98 tya
545 EB9A 48 pha
546 EB9B AD 0D D2 lda serin
547 EB9E A0 00 ldy #$00
548 EBA0 91 32 sta (bufrlo),y
549 EBA2 18 clc
550 EBA3 65 31 adc chksum
551 EBA5 69 00 adc #$00
552 EBA7 85 31 sta chksum
553
554 ;restore Y now
555 EBA9 68 pla
556 EBAA A8 tay
557
558 ;bump buffer pointer
559 EBAB E6 32 D0 02 E6 33 inw bufrlo
560
561 ;check for EOB
562 EBB1 A5 32 lda bufrlo
563 EBB3 C5 34 cmp bfenlo
564 EBB5 A5 33 lda bufrhi
565 EBB7 E5 35 sbc bfenhi
566 EBB9 90 06 bcc xit
567
568 EBBB C6 38 dec bufrfl ;!! - this was $00 coming in
569
570 ;should there be a checksum?
571 EBBD A5 3C lda nocksm
572 EBBF D0 15 bne skipChecksum
573 EBC1 xit:
574 EBC1 68 pla
575 EBC2 40 rti
576
577 EBC3 receiveChecksum:
578 ;read and compare checksum
579 EBC3 AD 0D D2 lda serin
580 EBC6 C5 31 cmp chksum
581 EBC8 D0 06 bne checksum_fail
582
583 EBCA signal_end:
584 ;set receive done flag
585 EBCA A9 FF 85 39 mva #$ff recvdn
586
587 ;exit
588 EBCE 68 pla
589 EBCF 40 rti
590
591 EBD0 checksum_fail:
592 EBD0 A9 8F lda #SIOErrorChecksum
593 EBD2 85 30 sta status
594 EBD4 D0 F4 bne signal_end ;!! - unconditional
595
596 EBD6 skipChecksum:
597 ;set receive done flag
598 EBD6 85 39 sta recvdn
599
600 ;clear no checksum flag
601 EBD8 A9 00 lda #0
602 EBDA 85 3C sta nocksm
603 EBDC 68 pla
604 EBDD 40 rti
605 .endp
606
607 ;==============================================================================
608 ; SIO serial output ready routine
609 ;
610 ; DOS 2.0S replaces (VSEROR), so it's critical that this routine follow the
611 ; rules compatible with DOS. The rules are as follows:
612 ;
613 ; BUFRLO/BUFRHI: On entry, points to one LESS than the next byte to write.
614 ; BFENLO/BFENHI: Points to byte immediately after buffer.
615 ; CHKSUM: Holds running checksum as bytes are output.
616 ; CHKSNT: $00 if checksum not yet sent, $FF if checksum sent.
617 ; POKMSK: Used to enable the serial output complete IRQ after sending
618 ; checksum.
619 ;
620 EBDE .proc SIOOutputReadyHandler
621 ;increment buffer pointer
622 EBDE E6 32 inc bufrlo
623 EBE0 D0 02 bne addrcc
624 EBE2 E6 33 inc bufrhi
625 EBE4 addrcc:
626
627 ;compare against buffer end
628 EBE4 A5 32 lda bufrlo
629 EBE6 C5 34 cmp bfenlo
630 EBE8 A5 33 lda bufrhi
631 EBEA E5 35 sbc bfenhi ;set flags according to (dst - end)
632 EBEC B0 13 bcs doChecksum
633
634 ;save Y
635 EBEE 98 tya
636 EBEF 48 pha
637
638 ;send out next byte
639 EBF0 A0 00 ldy #0
640 EBF2 B1 32 lda (bufrlo),y
641 EBF4 8D 0D D2 sta serout
642
643 ;update checksum
644 EBF7 65 31 adc chksum
645 EBF9 69 00 adc #0
646 EBFB 85 31 sta chksum
647
648 ;restore registers and exit
649 EBFD 68 pla
650 EBFE A8 tay
651 EBFF 68 pla
652 EC00 40 rti
653
654 EC01 doChecksum:
655 ;send checksum
656 EC01 A5 31 lda chksum
657 EC03 8D 0D D2 sta serout
658
659 ;set checksum sent flag
660 EC06 A9 FF 85 3B mva #$ff chksnt
661
662 ;enable output complete IRQ and disable serial output IRQ
663 EC0A A5 10 lda pokmsk
664 EC0C 09 08 ora #$08
665 EC0E 29 EF and #$ef
666 EC10 85 10 sta pokmsk
667 EC12 8D 0E D2 sta irqen
668
669 EC15 68 pla
670 EC16 40 rti
671 .endp
672
673 ;==============================================================================
674 EC17 .proc SIOOutputCompleteHandler
675 ;check that we've sent the checksum
676 EC17 A5 3B lda chksnt
677 EC19 F0 0B beq xit
678
679 ;we're done sending the checksum
680 EC1B 85 3A sta xmtdon
681
682 ;need to shut off this interrupt as it is not latched
683 EC1D A5 10 lda pokmsk
684 EC1F 29 F7 and #$f7
685 EC21 85 10 sta pokmsk
686 EC23 8D 0E D2 sta irqen
687
688 EC26 xit:
689 EC26 68 pla
690 EC27 40 rti
691 .endp
692
693 ;==============================================================================
694 EC28 .proc SIOCountdown1Handler
695 ;signal operation timeout
696 EC28 A9 00 8D 17 03 mva #0 timflg
697 EC2D 60 rts
698 .endp
699
700 ;==============================================================================
701 EC2E .proc SIOCassette
702 ;check if it's read sector
703 EC2E AD 02 03 lda dcomnd
704 EC31 C9 52 cmp #$52
705 EC33 F0 0F beq isread
706
707 ;check if it's put sector
708 EC35 C9 50 cmp #$50
709 EC37 F0 05 beq iswrite
710
711 ;nope, bail
712 EC39 A0 8B ldy #SIOErrorNAK
713 EC3B 4C 29 EA jmp SIO.xit
714
715 EC3E iswrite:
716 EC3E 20 4A EC jsr SIOCassetteWriteFrame
717 EC41 4C 29 EA jmp SIO.xit
718
719 EC44 isread:
720 EC44 20 5B EC jsr SIOCassetteReadFrame
721 EC47 4C 29 EA jmp SIO.xit
722 .endp
723
724 ;==============================================================================
725 EC4A .proc SIOCassetteWriteFrame
726 ;wait for pre-record write tone or IRG read delay
727 EC4A A2 02 ldx #2
728 EC4C 20 9D EF jsr CassetteWaitLongShortCheck
729
730 ;set up to transmit
731 EC4F 20 99 EA jsr SIOSendEnable
732
733 ;setup buffer pointers
734 EC52 20 07 EB jsr SIOSetupBufferPointers
735
736 ;send data frame
737 EC55 20 1D EB jsr SIOSend
738
739 ;all done
740 EC58 4C 29 EA jmp SIO.xit
741 .endp
742
743 ;==============================================================================
744 ; Read cassette frame
745 ;
746 ; Wait for long/short IRG, measure baud rate from sync mark, and read frame.
747 ;
748 ; When reading a cassette frame, the audio configuration is expected to be
749 ; as follows:
750 ;
751 ; Channel 1: Inaudible (31.5KHz)
752 ; Channel 2: Inaudible (31.5KHz)
753 ; Channel 3: Silent
754 ; Channel 4: Audible if enabled in SOUNDR (600Hz modulated by async read)
755 ;
756 ; This is necessary for proper tape loading sounds.
757 ;
758 EC5B .proc SIOCassetteReadFrame
759 ;wait for pre-record write tone or IRG read delay
760 EC5B A2 04 ldx #4
761 EC5D 20 9D EF jsr CassetteWaitLongShortCheck
762
763 ;set to 600 baud, turn on async read to shut off annoying tone
764 EC60 A2 1A ldx #SIOSendEnable.regdata_cassette_read-SIOSendEnable.regdata+8
765 EC62 20 C1 EA jsr SIOInitPOKEYWithRegOffsetX
766
767 EC65 AD 32 02 lda sskctl
768 EC68 29 8F and #$8f
769 EC6A 09 10 ora #$10
770 EC6C 8D 32 02 sta sskctl
771
772 ;set timeout (approx; no NTSC/PAL switching yet)
773 EC6F A9 FF 8D 17 03 mva #$ff timflg
774 EC74 A9 01 lda #1
775 EC76 A2 0E ldx #>3600
776 EC78 A0 10 ldy #<3600
777 EC7A 20 69 E8 jsr VBISetVector
778
779 ;wait for beginning of frame
780 EC7D A9 10 lda #$10 ;test bit 4 of SKSTAT
781 EC7F waitzerostart:
782 EC7F 2C 17 03 bit timflg
783 EC82 10 2B bpl timeout
784 EC84 2C 0F D2 bit skstat
785 EC87 D0 F6 bne waitzerostart
786
787 ;take first time measurement
788 EC89 20 49 ED jsr readtimer
789 EC8C 8C 0D 03 sty timer1+1
790 EC8F 8D 0C 03 sta timer1
791
792 ;wait for 19 bit transitions
793 EC92 A9 10 lda #$10 ;test bit 4 of SKSTAT
794 EC94 A2 0A ldx #10 ;test 10 pairs of bits
795 EC96 waitone:
796 EC96 2C 17 03 bit timflg
797 EC99 10 14 bpl timeout
798 EC9B 2C 0F D2 bit skstat
799 EC9E F0 F6 beq waitone
800 ECA0 CA dex
801 ECA1 F0 11 beq waitdone
802 ECA3 waitzero:
803 ECA3 2C 17 03 bit timflg
804 ECA6 10 07 bpl timeout
805 ECA8 2C 0F D2 bit skstat
806 ECAB D0 F6 bne waitzero
807 ECAD F0 E7 beq waitone
808
809 ECAF timeout:
810 ECAF A0 8A ldy #SIOErrorTimeout
811 ECB1 4C 29 EA jmp SIO.xit
812
813 ECB4 waitdone:
814
815 ;take second time measurement
816 ECB4 20 49 ED jsr readtimer
817 ECB7 8D 10 03 sta timer2
818 ECBA 8C 11 03 sty timer2+1
819
820 ;compute baud rate and adjust pokey divisor
821 ;
822 ; counts = (pal ? 156 : 131)*rtdelta + vdelta;
823 ; lines = counts * 2
824 ; lines_per_bit = lines / 19
825 ; cycles_per_bit = lines_per_bit * 114
826 ; pokey_divisor = cycles_per_bit / 2 - 7
827 ;
828 ; -or-
829 ;
830 ; pokey_divisor = counts * 2 * 114 / 19 / 2 - 7
831 ; = counts * 6 - 7
832 ;
833 ;16 bits at 600 baud is nominally 209 scanline pairs. This means that we
834 ;don't have to worry about more than two frames, which is at least 262
835 ;scanline pairs or less than 480 baud.
836
837 ;set frame height - 262 scanlines for NTSC, 312 for PAL
838 ECBD A2 83 ldx #131
839 ECBF AD 14 D0 lda pal
840 ECC2 4A lsr
841 ECC3 D0 02 A2 9C sne:ldx #156
842 ECC7 8E 15 03 stx temp3
843
844 ;compute line difference
845 ECCA AD 0C 03 lda timer1
846 ECCD 20 57 ED jsr correct_time
847 ECD0 85 34 sta bfenlo
848
849 ECD2 AD 10 03 lda timer2
850 ECD5 20 57 ED jsr correct_time
851 ECD8 18 clc ;!! this decrements one line from the line delta
852 ECD9 E5 34 sbc bfenlo
853 ECDB 85 34 sta bfenlo
854 ECDD A0 00 ldy #0
855 ECDF B0 01 88 scs:dey
856
857 ;compute frame difference
858 ECE2 AD 11 03 lda timer2+1
859 ECE5 38 ED 0D 03 sub timer1+1
860 ECE9 AA tax
861
862 ;accumulate frame difference
863 ECEA F0 0C beq no_frames
864 ECEC A5 34 lda bfenlo
865 ECEE add_frame_loop:
866 ECEE 18 clc
867 ECEF 6D 15 03 adc temp3
868 ECF2 90 01 C8 scc:iny
869 ECF5 CA dex
870 ECF6 D0 F6 bne add_frame_loop
871 ECF8 no_frames:
872 ECF8 84 35 sty bfenhi
873
874 ;compute lines*6 - 7 = (lines-1)*6 - 1
875 ECFA 0A asl ;(lines-1)*2 (lo)
876 ECFB 26 35 rol bfenhi ;(lines-1)*2 (hi)
877 ECFD 85 34 sta bfenlo
878 ECFF A4 35 ldy bfenhi ;
879 ED01 06 34 asl bfenlo ;(lines-1)*4 (lo)
880 ED03 26 35 rol bfenhi ;(lines-1)*4 (hi)
881 ED05 65 34 adc bfenlo ;(lines-1)*6 (lo)
882 ED07 AA tax ;
883 ED08 98 tya ;
884 ED09 65 35 adc bfenhi ;(lines-1)*6 (hi) (and c=0)
885 ED0B CA dex ;-1 line, bringing us to -7
886 ED0C 8E 04 D2 stx audf3
887 ED0F 8E EE 02 stx cbaudl
888 ED12 E8 inx
889 ED13 D0 02 E9 00 sne:sbc #0
890 ED17 8D 06 D2 sta audf4
891 ED1A 8D EF 02 sta cbaudh
892
893 ;kick pokey into init mode to reset serial input shift hw
894 ED1D AE 32 02 ldx sskctl
895 ED20 8A txa
896 ED21 29 FC and #$fc
897 ED23 8D 0F D2 sta skctl
898
899 ;reset serial port status
900 ED26 8D 0A D2 sta skres
901
902 ;re-enable serial input hw
903 ED29 8E 0F D2 stx skctl
904
905 ED2C 20 07 EB jsr SIOSetupBufferPointers
906
907 ;stuff two $55 bytes into the buffer, which we "read" above
908 ED2F A9 55 lda #$55
909 ED31 A0 00 ldy #0
910 ED33 A2 02 ldx #2
911 ED35 aaloop:
912 ED35 91 32 sta (bufrlo),y
913 ED37 E6 32 D0 02 E6 33 inw bufrlo
914 ED3D CA D0 F5 dex:bne aaloop
915
916 ;reset checksum for two $55 bytes and receive frame
917 ED40 0A asl
918 ED41 85 31 sta chksum
919
920 ED43 20 4E EB jsr SIOReceive.use_checksum
921 ED46 4C 8A EB jmp SIOReceiveStop
922
923 ;-------------------------------------------------------------------------
924 ; We have to be VERY careful when reading (RTCLOK+2, VCOUNT), because
925 ; the VBI can strike in between. First, we double-check RTCLOK+2 to see
926 ; if it has changed. If so, we retry the read. Second, we check if
927 ; VCOUNT=124, which corresponds to lines 248/249. This can correspond to
928 ; either before or after the VBI -- with CRITIC off the VBI ends around
929 ; (249, 20-50) -- so we don't know which side of the frame boundary we're
930 ; on.
931 ;
932 ED49 readtimer:
933 ED49 A4 14 ldy rtclok+2
934 ED4B AD 0B D4 lda vcount
935 ED4E C4 14 cpy rtclok+2
936 ED50 D0 F7 bne readtimer
937 ED52 C9 7C cmp #124
938 ED54 F0 F3 beq readtimer
939 ED56 60 rts
940
941 ED57 correct_time:
942 ED57 38 sec
943 ED58 E9 7C sbc #124
944 ED5A B0 03 bcs time_ok
945 ED5C 6D 15 03 adc temp3
946 ED5F time_ok:
947 ED5F 60 rts
948
949 .endp
950
249 ED60 _KERNEL_REPORT_MODULE_SIZE 'Serial Input/Output (SIO)', $EDEA-$E944
Macro: _KERNEL_REPORT_MODULE_SIZE [Source: source/main.xasm]
1 .echo ' ', *, ' -> ', *-?@_kernel_lastpt, '(', $EDEA-$E944, ')', ' ', 'Serial Input/Output (SIO)'
1 $ED60 -> $041B($04A6) Serial Input/Output (SIO)
3 = ED60 .def ?@_kernel_lastpt = *
Source: source/main.xasm
250
251 ED60 icl 'disk.s'
Source: source/Shared/disk.s
1 ; Altirra - Atari 800/800XL/5200 emulator
2 ; Modular Kernel ROM - Disk Routines
3 ; Copyright (C) 2008-2016 Avery Lee
4 ;
5 ; Copying and distribution of this file, with or without modification,
6 ; are permitted in any medium without royalty provided the copyright
7 ; notice and this notice are preserved. This file is offered as-is,
8 ; without any warranty.
9
10 ED60 .proc DiskInit
11 .if _KERNEL_XLXE
12 ;set disk sector size to 128 bytes
13 mwa #$80 dsctln
14 .endif
15 ED60 60 rts
16 .endp
17
18 ;==========================================================================
19 ; Disk handler routine (pointed to by DSKINV)
20 ;
21 ; Exit:
22 ; A = command byte (undocumented; required by Pooyan)
23 ; Y = status
24 ; N = 1 if error, 0 if success (high bit of Y)
25 ; C = 1 if command is >=$21 (undocumented; required by Arcade Machine)
26 ;
27 ED61 .proc DiskHandler
28 ED61 A9 31 8D 00 03 mva #$31 ddevic
29 ED66 A9 0F 8D 06 03 mva #$0f dtimlo
30
31 ;check for status command
32 ED6B AD 02 03 lda dcomnd
33 ED6E 8D 3B 02 sta ccomnd
34 ED71 C9 53 cmp #$53
35 ED73 D0 20 bne notStatus
36
37 ED75 A9 EA lda #<dvstat
38 ED77 8D 04 03 sta dbuflo
39 ED7A A9 02 lda #>dvstat
40 ED7C 8D 05 03 sta dbufhi
41 ED7F 0A asl ;hack to save a byte to get $04 since >dvstat is $02
42 ED80 8D 08 03 sta dbytlo
43 ED83 A9 00 lda #0
44 ED85 8D 09 03 sta dbythi
45
46 ED88 20 AD ED jsr do_read
47 ED8B 30 07 bmi xit
48
49 ;update format timeout
50 ED8D AE EC 02 8E 46 02 mvx dvstat+2 dsktim
51 ED93 AA tax
52 ED94 xit:
53 ED94 60 rts
54
55 ED95 notStatus:
56
57 ;set disk sector length
58 .if _KERNEL_XLXE
59 mwy dsctln dbytlo
60 .else
61 ED95 A0 80 8C 08 03 A0 + mwy #$80 dbytlo
62 .endif
63
64 ;check for put/write
65 .if _KERNEL_XLXE
66 cmp #$50
67 beq do_write
68 .endif
69 ED9F C9 57 cmp #$57
70 EDA1 F0 19 beq do_write
71
72 ;check for format, or else assume it's a read command ($52) or similar
73 EDA3 C9 21 cmp #$21
74 EDA5 D0 06 bne do_read
75
76 ;it's format... use the format timeout
77 EDA7 AD 46 02 8D 06 03 mva dsktim dtimlo
78
79 EDAD do_read:
80 EDAD A9 40 lda #$40
81 EDAF do_io:
82 EDAF 8D 03 03 sta dstats
83 EDB2 20 59 E4 jsr siov
84
85 ;load disk command back into A (required by Pooyan)
86 ;emulate compare against format command (required by Arcade Machine)
87 ;sort-of emulate compare against status (required by Micropainter)
88 EDB5 AD 02 03 lda dcomnd
89 EDB8 C0 00 cpy #0 ;!! Atari800WinPlus's SIO patch doesn't set STATUS
90 EDBA 38 sec
91 EDBB 60 rts
92
93 EDBC do_write:
94 EDBC A9 80 lda #$80
95 EDBE D0 EF bne do_io
96 .endp
252 EDC0 _KERNEL_REPORT_MODULE_SIZE 'Disk Handler', $EE78-$EDEA
Macro: _KERNEL_REPORT_MODULE_SIZE [Source: source/main.xasm]
1 .echo ' ', *, ' -> ', *-?@_kernel_lastpt, '(', $EE78-$EDEA, ')', ' ', 'Disk Handler'
1 $EDC0 -> $0060($008E) Disk Handler
3 = EDC0 .def ?@_kernel_lastpt = *
Source: source/main.xasm
253
254 EDC0 icl 'printer.s'
Source: source/Shared/printer.s
1 ; Altirra - Atari 800/800XL/5200 emulator
2 ; Modular Kernel ROM - Printer Handler
3 ; Copyright (C) 2008-2016 Avery Lee
4 ;
5 ; Copying and distribution of this file, with or without modification,
6 ; are permitted in any medium without royalty provided the copyright
7 ; notice and this notice are preserved. This file is offered as-is,
8 ; without any warranty.
9
10 ;==========================================================================
11 EDC0 .proc PrinterInit
12 ;set printer timeout to default
13 EDC0 A9 1E 8D 14 03 mva #30 ptimot
14 EDC5 60 rts
15 .endp
16
17 ;==========================================================================
18 EDC6 .proc PrinterOpen
19 ;check for sideways mode and compute line size
20 EDC6 A2 28 ldx #40
21 EDC8 A5 2B lda icax2z
22 EDCA C9 53 cmp #$53
23 EDCC D0 02 A2 1D sne:ldx #29
24 EDD0 8E DF 02 stx pbufsz
25
26 EDD3 A9 00 lda #0
27 EDD5 8D DE 02 sta pbpnt
28
29 EDD8 xit:
30 EDD8 A0 01 ldy #1
31 EDDA 60 rts
32 .endp
33
34 ;==========================================================================
35 = EDDB PrinterClose = _PrinterPutByte.close_entry
36 = EDE2 PrinterPutByte = _PrinterPutByte.put_entry
37
38 EDDB .proc _PrinterPutByte
39 EDDB close_entry:
40 ;check if we have anything in the buffer
41 EDDB AD DE 02 lda pbpnt
42
43 ;exit if buffer is empty
44 EDDE F0 F8 beq PrinterOpen.xit
45
46 ;fall through to put with EOL
47 EDE0 A9 9B lda #$9b
48
49 EDE2 put_entry:
50 ;preload buffer index (useful later)
51 EDE2 AE DE 02 ldx pbpnt
52
53 ;check for EOL
54 EDE5 C9 9B cmp #$9b
55 EDE7 F0 0E beq do_eol
56
57 ;mask off MSB
58 EDE9 29 7F and #$7f
59
60 ;put char and advance
61 EDEB 9D C0 03 sta prnbuf,x
62 EDEE E8 inx
63 EDEF 8E DE 02 stx pbpnt
64
65 ;check for end of line and exit if not
66 EDF2 EC DF 02 cpx pbufsz
67 EDF5 90 E1 bcc PrinterOpen.xit
68
69 ;fall through to EOL
70
71 EDF7 do_eol:
72 ;fill remainder of buffer with spaces
73 EDF7 A9 20 lda #$20
74 EDF9 fill_loop:
75 EDF9 EC DF 02 cpx pbufsz
76 EDFC B0 06 bcs fill_done
77 EDFE 9D C0 03 sta prnbuf,x
78 EE01 E8 inx
79 EE02 90 F5 bcc fill_loop
80 EE04 fill_done:
81
82 ;send line to printer
83 EE04 A0 0A ldy #10
84 EE06 B9 25 EE 99 FF 02 + mva:rne iocbdat-1,y ddevic-1,y-
85
86 ;empty buffer
87 EE0F 8C DE 02 sty pbpnt
88
89 ;set line length
90 EE12 8E 08 03 stx dbytlo
91
92 ;Compute AUX1 byte from length.
93 ;
94 ;Note that the OS manual is wrong -- this byte needs to go into AUX1 and
95 ;not AUX2 as the manual says.
96 ;
97 ; normal (40): 00101000 -> 01001110 ($4E 'N')
98 ; sideways (29): 00011101 -> 01010011 ($53 'S')
99 ; 010_1I1_
100 EE15 8A txa
101 EE16 29 15 and #%00010101
102 EE18 49 4E eor #%01001110
103 EE1A 8D 0A 03 sta daux1 ;set AUX1 to indicate width to device
104
105 ;send to printer and exit
106 EE1D do_io:
107 EE1D AD 14 03 8D 06 03 mva ptimot dtimlo
108 EE23 4C 59 E4 jmp siov
109
110 EE26 iocbdat:
111 EE26 40 dta $40 ;device
112 EE27 01 dta $01 ;unit
113 EE28 57 dta $57 ;command 'W'
114 EE29 80 dta $80 ;input/output mode (write)
115 EE2A C0 03 dta a(prnbuf) ;buffer address
116 EE2C 00 00 dta a(0) ;timeout
117 EE2E 00 00 dta a(0) ;buffer length
118 .endp
119
120 ;==============================================================================
121 EE30 .proc PrinterGetStatus
122 ;setup parameter block
123 EE30 A2 09 ldx #9
124 EE32 BD 47 EE 9D 00 03 + mva:rpl iocbdat,x ddevic,x-
125
126 ;issue status call
127 EE3B 20 1D EE jsr _PrinterPutByte.do_io
128 EE3E 30 06 bmi error
129
130 ;update timeout
131 EE40 AD EC 02 8D 14 03 mva dvstat+2 ptimot
132
133 EE46 error:
134 EE46 60 rts
135
136 EE47 iocbdat:
137 EE47 40 dta $40 ;device
138 EE48 01 dta $01 ;unit
139 EE49 53 dta $53 ;command 'S'
140 EE4A 40 dta $40 ;input/output mode (read)
141 EE4B EA 02 dta a(dvstat) ;buffer address
142 EE4D 00 00 dta a(0) ;timeout
143 EE4F 04 00 dta a(4) ;buffer length
144 .endp
145
146 ;==============================================================================
147 = E4CB PrinterGetByte = CIOExitNotSupported
148 = E4CB PrinterSpecial = CIOExitNotSupported
255 EE51 _KERNEL_REPORT_MODULE_SIZE 'Printer Handler', $EF41-$EE78
Macro: _KERNEL_REPORT_MODULE_SIZE [Source: source/main.xasm]
1 .echo ' ', *, ' -> ', *-?@_kernel_lastpt, '(', $EF41-$EE78, ')', ' ', 'Printer Handler'
1 $EE51 -> $0091($00C9) Printer Handler
3 = EE51 .def ?@_kernel_lastpt = *
Source: source/main.xasm
256
257 EE51 icl 'cassette.s'
Source: source/Shared/cassette.s
1 ; Altirra - Atari 800/800XL/5200 emulator
2 ; Modular Kernel ROM - Cassette tape support
3 ; Copyright (C) 2008-2016 Avery Lee
4 ;
5 ; Copying and distribution of this file, with or without modification,
6 ; are permitted in any medium without royalty provided the copyright
7 ; notice and this notice are preserved. This file is offered as-is,
8 ; without any warranty.
9
10 ;==========================================================================
11 EE51 .proc CassetteInit
12 ;Set CBAUDL/CBAUDH to $05CC, the nominal POKEY divisor for 600
13 ;baud. We don't care about this, but it's documented in the OS
14 ;Manual.
15 EE51 A9 CC 8D EE 02 A9 + mwa #$05CC cbaudl
16 EE5B 60 rts
17 .endp
18
19 ;==========================================================================
20 ; Cassette open routine.
21 ;
22 ; XL/XE OS behavior notes:
23 ; - Attempting to open for none (AUX1=$00) or read/write (AUX1=$0C)
24 ; results in a Not Supported error (146).
25 ; - Open for read gives one beep, while open for write gives two beeps.
26 ; - Break will break out of the wait.
27 ; - Ctrl+3 during the keypress causes an EOF error (!). This is a side
28 ; effect of reusing the keyboard handler.
29 ;
30 ; CSOPIV behavior:
31 ; - Does NOT set FTYPE (continuous mode flag).
32 ; - Sets read mode (WMODE).
33 ; - Does NOT require ICAX1Z or ICAX2Z to be set.
34 ;
35 = EE6F CassetteOpenRead = CassetteOpen.do_open_read
36 EE5C .proc CassetteOpen
37 ;stash continuous mode flag
38 EE5C A5 2B lda icax2z ;!! FIRST TWO BYTES CHECKED BY ARCHON
39 EE5E 85 3E sta ftype
40
41 ;check mode byte for read/write modes
42 EE60 A2 80 ldx #$80
43 EE62 A5 2A lda icax1z
44 EE64 29 0C and #$0c
45 EE66 C9 04 cmp #$04 ;read?
46 EE68 F0 05 beq found_read_mode
47 EE6A C9 08 cmp #$08 ;write?
48 EE6C F0 03 beq found_write_mode
49
50 ;invalid mode -- return not supported
51 EE6E 60 rts
52
53 EE6F do_open_read:
54 EE6F found_read_mode:
55 EE6F A2 00 ldx #$00
56 EE71 found_write_mode:
57 EE71 8E 89 02 stx wmode
58
59 ;set cassette buffer size to 128 bytes and mark it empty
60 EE74 A9 80 lda #$80
61 EE76 85 3D sta bptr
62 EE78 8D 8A 02 sta blim
63
64 ;clear EOF flag
65 EE7B 0A asl
66 EE7C 85 3F sta feof
67
68 ;request one beep for read, or two for write
69 EE7E 2C 89 02 bit wmode
70 EE81 10 05 bpl one_ping_only
71
72 EE83 06 3D asl bptr ;!! - set bptr=0 when starting write
73
74 EE85 20 C9 EF jsr CassetteBell
75
76 EE88 one_ping_only:
77 EE88 20 C9 EF jsr CassetteBell
78
79 ;wait for a key press
80 EE8B 20 66 FE jsr KeyboardGetByte
81 EE8E 30 20 bmi aborted
82
83 ;need to set up POKEY for writes now to write leader
84 EE90 2C 89 02 bit wmode
85 EE93 10 08 bpl no_write_init
86 EE95 A9 FF lda #$ff
87 EE97 8D 0F 03 sta casflg
88 EE9A 20 A4 EA jsr SIOSendEnable.no_irq_setup
89 EE9D no_write_init:
90
91 ;turn on motor (continuous mode or not)
92 EE9D A9 34 lda #$34
93 EE9F 8D 02 D3 sta pactl
94
95 ;wait for leader (9.6 seconds read, 19.2s write)
96 EEA2 A2 00 ldx #0
97 EEA4 2C 89 02 bit wmode
98 EEA7 30 02 A2 01 smi:ldx #1
99 EEAB 20 A3 EF jsr CassetteWait
100
101 ;all done
102 EEAE A0 01 ldy #1
103 EEB0 aborted:
104 EEB0 60 rts
105 .endp
106
107 ;==========================================================================
108 EEB1 .proc CassetteClose
109 ;check if we are in write mode
110 EEB1 AD 89 02 lda wmode ;!! FIRST TWO BYTES CHECKED BY ARCHON
111 EEB4 10 0A bpl notwrite
112
113 ;check if we have data to write
114 EEB6 A5 3D lda bptr
115 EEB8 F0 03 beq nopartial
116
117 ;flush partial record ($FA)
118 EEBA 20 22 EF jsr CassetteFlush
119
120 EEBD nopartial:
121 ;write EOF record ($FE)
122 EEBD 20 22 EF jsr CassetteFlush
123
124 EEC0 notwrite:
125 ;stop the motor
126 EEC0 A9 3C lda #$3c
127 EEC2 8D 02 D3 sta pactl
128
129 ;kill audio
130 EEC5 A0 00 ldy #0
131 EEC7 8C 01 D2 sty audc1
132 EECA 8C 03 D2 sty audc2
133 EECD 8C 07 D2 sty audc4
134
135 ;all done
136 EED0 C8 iny
137 EED1 60 rts
138 .endp
139
140 ;==========================================================================
141 EED2 .proc CassetteGetByte
142 ;check if we have an EOF condition
143 EED2 A5 3F lda feof ;!! FIRST TWO BYTES CHECKED BY ARCHON
144 EED4 D0 1D bne xit_eof
145
146 EED6 fetchbyte:
147 ;check if we can still fetch a byte
148 EED6 A6 3D ldx bptr
149 EED8 EC 8A 02 cpx blim
150 EEDB F0 08 beq nobytes
151
152 EEDD BD 00 04 lda casbuf+3,x
153 EEE0 E6 3D inc bptr
154 EEE2 A0 01 ldy #1
155 EEE4 60 rts
156
157 EEE5 nobytes:
158 ;fetch more bytes
159 EEE5 20 52 EF jsr CassetteReadBlock
160 EEE8 30 0B bmi error
161
162 ;check control byte
163 EEEA AD FF 03 lda casbuf+2
164 EEED C9 FE cmp #$fe
165 EEEF D0 05 bne noteofbyte
166
167 ;found $FE (EOF) - set flag and return EOF
168 EEF1 85 3F sta feof
169 EEF3 xit_eof:
170 EEF3 A0 88 ldy #CIOStatEndOfFile
171 EEF5 error:
172 EEF5 60 rts
173
174 EEF6 noteofbyte:
175 ;reset buffer ptr
176 EEF6 A2 00 86 3D mvx #0 bptr
177
178 ;assume full block first (128 bytes)
179 EEFA A2 80 ldx #$80
180
181 ;check if it actually is one
182 EEFC C9 FC cmp #$fc
183 EEFE D0 06 bne not_full_block
184
185 EF00 init_new_block:
186 ;reset block length and loop back
187 EF00 8E 8A 02 stx blim
188 EF03 4C D6 EE jmp fetchbyte
189
190 EF06 not_full_block:
191 ;check if we have a partial block
192 EF06 C9 FA cmp #$fa
193 EF08 D0 05 bne not_partial_block
194
195 ;set length of partial block and the jump to init+loop
196 EF0A AE 7F 04 ldx casbuf+130
197 EF0D B0 F1 bcs init_new_block
198
199 EF0F not_partial_block:
200 ;uh oh... bad control byte.
201 EF0F A0 A3 ldy #CIOStatFatalDiskIO
202 EF11 60 rts
203 .endp
204
205 ;==========================================================================
206 EF12 .proc CassettePutByte
207 ;put a byte into the buffer
208 EF12 A6 3D ldx bptr ;!! FIRST TWO BYTES CHECKED BY ARCHON
209 EF14 9D 00 04 sta casbuf+3,x
210
211 ;bump and check if it's time to write
212 EF17 E8 inx
213 EF18 86 3D stx bptr
214 EF1A EC 8A 02 cpx blim
215 EF1D B0 03 bcs CassetteFlush
216
217 ;all done
218 EF1F A0 01 ldy #1
219 EF21 60 rts
220 .endp
221
222 ;==========================================================================
223 EF22 .proc CassetteFlush
224 EF22 A9 00 lda #0
225
226 ;set control byte based on buffer level
227 EF24 A2 FE ldx #$fe ;empty -> EOF
228 EF26 A4 3D ldy bptr ;get buffer level
229 EF28 D0 08 bne not_empty ;skip not empty
230
231 ;clear buffer for EOF
232 EF2A 99 00 04 C8 10 FA sta:rpl casbuf+3,y+
233 EF30 30 0C bmi is_empty ;!! - unconditional
234
235 EF32 not_empty:
236 EF32 A2 FC ldx #$fc ;load complete code
237 EF34 CC 8A 02 cpy blim ;check if buffer is full
238 EF37 B0 05 bcs is_complete ;skip if so
239 EF39 A2 FA ldx #$fa ;load partial code
240 EF3B 8C 7F 04 sty casbuf+130 ;store level in last byte
241 EF3E is_complete:
242 EF3E is_empty:
243
244 ;store code
245 EF3E 8E FF 03 stx casbuf+2
246
247 ;reset buffer level
248 EF41 85 3D sta bptr
249
250 ;setup sync bytes
251 EF43 A9 55 lda #$55
252 EF45 8D FD 03 sta casbuf
253 EF48 8D FE 03 sta casbuf+1
254
255 ;issue write request and exit
256 EF4B A2 80 ldx #$80
257 EF4D A0 50 ldy #'P'
258 EF4F 4C 56 EF jmp CassetteDoIO
259 .endp
260
261 ;==========================================================================
262 = E4C9 CassetteGetStatus = CIOExitSuccess
263 = E4CB CassetteSpecial = CIOExitNotSupported
264
265 ;==========================================================================
266 ; CassetteDoIO
267 ;
268 ; X = DSTATS value
269 ; Y = SIO command byte
270 ;
271 ; Note that SOUNDR must take effect each time a cassette I/O operation
272 ; occurs.
273 ;
274 = EF56 CassetteDoIO = _CassetteDoIO.do_io
275 = EF52 CassetteReadBlock = _CassetteDoIO.read_block
276
277 EF52 .proc _CassetteDoIO
278 EF52 read_block:
279 EF52 A2 40 ldx #$40
280 EF54 A0 52 ldy #'R'
281 EF56 do_io:
282 ;start the motor if not already running
283 EF56 A9 34 lda #$34
284 EF58 8D 02 D3 sta pactl
285
286 ;set up SIO read/write
287 EF5B 8E 03 03 stx dstats
288 EF5E 8C 02 03 sty dcomnd
289 EF61 A9 FD 8D 04 03 A9 + mwa #casbuf dbuflo
290 EF6B A9 83 8D 08 03 A9 + mwa #131 dbytlo
291 EF75 A9 60 8D 00 03 mva #$60 ddevic
292 EF7A A9 00 8D 01 03 mva #0 dunit
293 EF7F A5 3E 8D 0B 03 mva ftype daux2
294
295 ;do it
296 EF84 20 59 E4 jsr siov
297
298 ;check if we are in continuous mode (again)
299 EF87 A5 3E lda ftype
300 EF89 30 0F bmi rolling_stop
301
302 ;not in continuous mode -- wait for post-write tone if writing
303 EF8B 2C 89 02 bit wmode
304 EF8E 10 05 bpl no_pwt
305 EF90 A2 06 ldx #6
306 EF92 20 A3 EF jsr CassetteWait
307 EF95 no_pwt:
308
309 ;stop the motor
310 EF95 A9 3C lda #$3c
311 EF97 8D 02 D3 sta pactl
312
313 EF9A rolling_stop:
314 EF9A A4 30 ldy status
315 EF9C 60 rts
316 .endp
317
318 ;==========================================================================
319 ;Entry:
320 ; X = delay type
321 ;
322 = EFA3 CassetteWait = CassetteWaitLongShortCheck.normal_entry
323 EF9D .proc CassetteWaitLongShortCheck
324 EF9D 2C 0B 03 bit daux2
325 EFA0 10 01 E8 spl:inx
326 EFA3 normal_entry:
327 EFA3 20 65 EA jsr SIOSetTimeoutVector
328 EFA6 BC BB EF ldy wait_table_lo,x
329 EFA9 BD C2 EF lda wait_table_hi,x
330 EFAC AA tax
331 EFAD A9 01 lda #1
332 EFAF 8D 17 03 sta timflg
333 EFB2 20 69 E8 jsr VBISetVector
334 EFB5 AD 17 03 D0 FB lda:rne timflg
335 EFBA 60 rts
336
337 EFBB wait_table_lo:
338 EFBB 80 dta <$0480 ;$00 - write file leader (19.2 seconds NTSC)
339 EFBC 40 dta <$0240 ;$01 - read leader delay (9.6 seconds NTSC)
340 EFBD B4 dta <$00B4 ;$02 - long pre-record write tone (3.0s NTSC)
341 EFBE 0F dta <$000F ;$03 - short pre-record write tone (0.25s NTSC)
342 EFBF 78 dta <$0078 ;$04 - long read IRG (2.0s NTSC)
343 EFC0 0A dta <$000A ;$05 - short read IRG (0.16s NTSC)
344 EFC1 3C dta <$003C ;$06 - post record gap (1s NTSC)
345
346 EFC2 wait_table_hi:
347 EFC2 04 dta >$0480 ;$00 - write file leader (19.2 seconds NTSC)
348 EFC3 02 dta >$0240 ;$01 - read leader delay (9.6 seconds NTSC)
349 EFC4 00 dta >$00B4 ;$02 - long pre-record write tone (3.0s NTSC)
350 EFC5 00 dta >$000F ;$03 - short pre-record write tone (0.25s NTSC)
351 EFC6 00 dta >$0078 ;$04 - long read IRG (2.0s NTSC)
352 EFC7 00 dta >$000A ;$05 - short read IRG (0.16s NTSC)
353 EFC8 00 dta >$003C ;$06 - post record gap (1s NTSC)
354 .endp
355
356 ;==========================================================================
357 ; Sound a bell using the console speaker (cassette version)
358 ;
359 ; Modified:
360 ; A, X, Y
361 ;
362 EFC9 .proc CassetteBell
363 EFC9 A0 00 ldy #0
364 EFCB 98 tya
365 EFCC soundloop:
366 EFCC A2 0A ldx #10
367 EFCE 48 pha
368 EFCF delay:
369 EFCF AD 0B D4 lda vcount
370 EFD2 CD 0B D4 F0 FB cmp:req vcount
371 EFD7 CA dex
372 EFD8 D0 F5 bne delay
373 EFDA 68 pla
374 EFDB 49 08 eor #$08
375 EFDD 8D 1F D0 sta consol
376 EFE0 D0 EA bne soundloop
377 EFE2 88 dey
378 EFE3 D0 E7 bne soundloop
379 EFE5 60 rts
380 .endp
258 EFE6 _KERNEL_REPORT_MODULE_SIZE 'Cassette Handler', $F0E3-$EF41
Macro: _KERNEL_REPORT_MODULE_SIZE [Source: source/main.xasm]
1 .echo ' ', *, ' -> ', *-?@_kernel_lastpt, '(', $F0E3-$EF41, ')', ' ', 'Cassette Handler'
1 $EFE6 -> $0195($01A2) Cassette Handler
3 = EFE6 .def ?@_kernel_lastpt = *
Source: source/main.xasm
259
260 .ifdef _KERNEL_816
261 icl 'init816.s'
262 .else
263 EFE6 icl 'init.s'
Source: source/Shared/init.s
1 ; Altirra - Atari 800/800XL emulator
2 ; Kernel ROM replacement - Initialization
3 ; Copyright (C) 2008-2019 Avery Lee
4 ;
5 ; Copying and distribution of this file, with or without modification,
6 ; are permitted in any medium without royalty provided the copyright
7 ; notice and this notice are preserved. This file is offered as-is,
8 ; without any warranty.
9
10 .if _KERNEL_XLXE
11 .proc InitBootSignature
12 dta $5C,$93,$25
13 .endp
14 .endif
15
16 EFE6 .proc InitHandlerTable
17 EFE6 50 30 E4 dta c'P',a(printv)
18 EFE9 43 40 E4 dta c'C',a(casetv)
19 EFEC 45 00 E4 dta c'E',a(editrv)
20 EFEF 53 10 E4 dta c'S',a(screnv)
21 EFF2 4B 20 E4 dta c'K',a(keybdv)
22 .endp
23
24 EFF5 .nowarn .proc _InitReset
25 EFF5 run_diag:
26 ; start diagnostic cartridge
27 EFF5 6C FE BF jmp ($bffe)
28
29 = EFF8 .def :InitReset
30 ;mask interrupts and initialize CPU
31 EFF8 78 sei
32 EFF9 D8 cld
33 EFFA A2 FF ldx #$ff
34 EFFC 9A txs
35
36 .if _KERNEL_XLXE
37 ;wait for everything to stabilize (0.1s) (XL/XE only)
38 ldy #140
39 stabilize_loop:
40 dex:rne
41 dey
42 bne stabilize_loop
43
44 ;check for warmstart signature (XL/XE)
45 ldx #2
46 warm_check:
47 lda pupbt1,x
48 cmp InitBootSignature,x
49 bne cold_boot
50 dex
51 bpl warm_check
52
53 jmp InitWarmStart
54 .endif
55
56 = EFFD .def :InitColdStart
57 EFFD cold_boot:
58 ; 1. initialize CPU
59 EFFD 78 sei
60 EFFE D8 cld
61 EFFF A2 FF ldx #$ff
62 F001 9A txs
63
64 ; 2. clear warmstart flag
65 F002 E8 inx
66 F003 86 08 stx warmst
67
68 ; 3. test for diagnostic cartridge
69 F005 AD FC BF lda $bffc
70 F008 D0 17 bne not_diag
71 F00A A2 FF ldx #$ff
72 F00C EC FF BF cpx $bfff ;prevent diagnostic cart from activating if addr is $FFxx
73 F00F F0 10 beq not_diag
74 F011 8E FC BF stx $bffc
75 F014 CD FC BF cmp $bffc
76 F017 8D FC BF sta $bffc
77 F01A D0 05 bne not_diag
78
79 ; is it enabled?
80 F01C 2C FD BF bit $bffd
81 F01F 30 D4 bmi run_diag
82
83 F021 not_diag:
84
85 F021 20 70 F0 jsr InitHardwareReset
86
87 .if _KERNEL_XLXE
88 ;check for OPTION and enable BASIC (note that we do NOT set BASICF just yet)
89 lda #4
90 bit consol
91 beq no_basic
92
93 .ifdef _KERNEL_SOFTKICK
94 ldx #$fc
95 .else
96 ldx #$fd
97 .endif
98
99 ;check for keyboard present + SELECT or no keyboard + no SELECT and enable game if so
100 lda trig2 ;check keyboard present (1 = present)
101 asl
102 eor consol ;XOR against select (0 = pressed)
103 and #$02
104
105 .ifdef _KERNEL_SOFTKICK
106 seq:ldx #$be
107 .else
108 seq:ldx #$bf
109 .endif
110
111 stx portb ;enable GAME or BASIC
112
113 no_basic:
114 .endif
115
116 ; 4. measure memory -> tramsz
117 F024 20 9C F0 jsr InitMemory
118
119 ; 6. clear memory from $0008 up to [tramsz,0]
120 .ifdef _KERNEL_SOFTKICK
121 ldx #$50
122 .else
123 F027 A6 06 ldx tramsz
124 .endif
125 F029 A0 08 ldy #8
126 F02B A9 00 85 66 mva #0 a1
127 F02F 85 67 sta a1+1
128 F031 clearloop:
129 F031 91 66 C8 D0 FB sta:rne (a1),y+
130 F036 E6 67 inc a1+1
131 F038 CA dex
132 F039 D0 F6 bne clearloop
133
134 .if _KERNEL_XLXE
135 ;Blip the self test ROM for a second -- this is one way that Altirra detects
136 ;that Option has been used by the OS. The XL/XE OS does this as part of its
137 ;ROM checksum routine (which we don't bother with).
138 ldx portb
139 txa
140 and #$7f
141 sta portb
142 stx portb
143 .endif
144
145 ; 7. set dosvec to blackboard routine
146 .if _KERNEL_USE_BOOT_SCREEN
147 mwa #SelfTestEntry dosvec
148 .else
149 F03B A9 80 85 0A A9 E4 + mwa #Blackboard dosvec
150 .endif
151
152 ; 8. set coldstart flag
153 F043 CE 44 02 dec coldst ;!! coldst=0 from clear loop above, now $ff
154
155 .if _KERNEL_XLXE
156 ; set BASIC flag
157 lda portb
158 and #$02
159 sta basicf
160 .endif
161
162 ; 9. set screen margins
163 ; 10. initialize RAM vectors
164 ; 11. set misc database values
165 ; 12. enable IRQ interrupts
166 ; 13. initialize device table
167 ; 14. initialize cartridges
168 ; 15. use IOCB #0 to open screen editor (E)
169 ; 16. wait for VBLANK so screen is initialized
170 ; 17. do cassette boot, if it was requested
171 ; 18. do disk boot
172 ; 19. reset coldstart flag
173 ; 20. run cartridges or blackboard
174 F046 4C DA F0 jmp InitEnvironment
175 .endp
176
177 ;==============================================================================
178 F049 .proc InitWarmStart
179 ; A. initialize CPU
180 ;
181 ; Undocumented: Check if cold start completed (COLDST=0); if not, force
182 ; a cold start. ACTris 2.1 relies on this since its boot doesn't reset
183 ; COLDST. This is also required to work on Atari800WinPLus, which doesn't
184 ; clear memory on a cold start.
185 ;
186 F049 78 sei ;!! FIRST TWO BYTES CHECKED BY ARCHON
187 F04A AD 44 02 lda coldst
188 F04D D0 AE bne InitColdStart
189 F04F D8 cld
190 F050 A2 FF ldx #$ff
191 F052 9A txs
192
193 ; B. set warmstart flag
194 F053 86 08 stx warmst
195
196 ; reinitialize hardware without doing a full clear
197 F055 20 70 F0 jsr InitHardwareReset
198
199 .if _KERNEL_XLXE
200 ; reinitialize BASIC
201 lda basicf
202 sne:mva #$fd portb
203 .endif
204
205 ; C. check for diag, measure memory, clear hw registers
206 F058 20 9C F0 jsr InitMemory
207
208 ; D. zero 0010-007F and 0200-03EC (must not clear BASICF).
209 F05B A2 60 ldx #$60
210 F05D A9 00 lda #0
211 F05F 95 0F CA D0 FB sta:rne $0f,x-
212
213 F064 dbclear:
214 F064 9D 00 02 sta $0200,x
215 F067 9D ED 02 sta $02ed,x
216 F06A E8 inx
217 F06B D0 F7 bne dbclear
218
219 ; E. steps 9-16 above
220 ; F. if cassette boot was successful on cold boot, execute cassette init
221 ; G. if disk boot was successful on cold boot, execute disk init
222 ; H. same as steps 19 and 20
223 F06D 4C DA F0 jmp InitEnvironment
224 .endp
225
226 ;==============================================================================
227 F070 .proc InitHardwareReset
228 ; clear all hardware registers
229 F070 A0 00 ldy #0
230 F072 98 tya
231 F073 hwclear:
232 F073 99 00 D0 sta $d000,y
233 F076 99 00 D2 sta $d200,y
234 F079 99 00 D4 sta $d400,y
235 F07C C8 iny
236 F07D D0 F4 bne hwclear
237
238 ;initialize PIA
239 F07F A9 3C lda #$3c
240 F081 A2 38 ldx #$38
241
242 .ifdef _KERNEL_SOFTKICK
243 stx pactl ;switch to DDRA
244 sty porta ;portA -> input
245 sta pactl ;switch to IORA
246 sty porta ;portA -> $00
247 sta pbctl ;switch to IORB
248 dey
249 dey
250 sty portb ;portB -> $FE
251 stx pbctl ;switch to DDRB
252 iny
253 sty portb ;portB -> all output
254 sta pbctl ;switch to IORB
255 .elseif _KERNEL_XLXE
256 stx pactl ;switch to DDRA
257 sty porta ;portA -> input
258 sta pactl ;switch to IORA
259 sty porta ;portA -> $00
260 sta pbctl ;switch to IORB
261 dey
262 sty portb ;portB -> $FF
263 stx pbctl ;switch to DDRB
264 sty portb ;portB -> all output
265 sta pbctl ;switch to IORB
266 .else
267 F083 8E 02 D3 stx pactl ;switch to DDRA
268 F086 8E 03 D3 stx pbctl ;switch to DDRB
269 F089 8C 00 D3 sty porta ;portA -> input
270 F08C 8C 01 D3 sty portb ;portB -> input
271 F08F 8D 02 D3 sta pactl ;switch to IORA
272 F092 8D 03 D3 sta pbctl ;switch to IORB
273 F095 8C 00 D3 sty porta ;portA -> $00
274 F098 8C 01 D3 sty portb ;portB -> $00
275 .endif
276 F09B 60 rts
277 .endp
278
279 ;==============================================================================
280 F09C .proc InitMemory
281 ; 4. measure memory -> tramsz
282 F09C A0 00 ldy #$00
283 F09E 84 64 sty adress
284 F0A0 A2 02 ldx #$02
285 F0A2 pageloop:
286 F0A2 86 65 stx adress+1
287 F0A4 B1 64 lda (adress),y
288 F0A6 49 FF eor #$ff
289 F0A8 91 64 sta (adress),y
290 F0AA D1 64 cmp (adress),y
291 F0AC D0 09 bne notRAM
292 F0AE 49 FF eor #$ff
293 F0B0 91 64 sta (adress),y
294 F0B2 E8 inx
295
296 .if _KERNEL_XLXE
297 cpx #$c0
298 .else
299 F0B3 E0 D0 cpx #$d0
300 .endif
301
302 F0B5 D0 EB bne pageloop
303 F0B7 notRAM:
304 F0B7 86 06 stx tramsz
305
306 F0B9 60 rts
307 .endp
308
309 ;==============================================================================
310 F0BA .proc InitVectorTable1
311 F0BA 66 E7 dta a(IntExitHandler_None) ;$0200 VDSLST
312 F0BC 65 E7 dta a(IntExitHandler_A) ;$0202 VPRCED
313 F0BE 65 E7 dta a(IntExitHandler_A) ;$0204 VINTER
314 F0C0 65 E7 dta a(IntExitHandler_A) ;$0206 VBREAK
315 F0C2 CC FE dta a(KeyboardIRQ) ;$0208 VKEYBD
316 F0C4 95 EB dta a(SIOInputReadyHandler) ;$020A VSERIN
317 F0C6 DE EB dta a(SIOOutputReadyHandler) ;$020C VSEROR
318 F0C8 17 EC dta a(SIOOutputCompleteHandler) ;$020E VSEROC
319 F0CA 65 E7 dta a(IntExitHandler_A) ;$0210 VTIMR1
320 F0CC 65 E7 dta a(IntExitHandler_A) ;$0212 VTIMR2
321 F0CE 65 E7 dta a(IntExitHandler_A) ;$0214 VTIMR4
322 F0D0 CD E8 dta a(IrqHandler) ;$0216 VIMIRQ
323 F0D2 end:
324 .endp
325
326 F0D2 .proc InitVectorTable2
327 F0D2 1D E7 dta a(VBIStage1) ;$0222 VVBLKI
328 F0D4 61 E7 dta a(VBIExit) ;$0224 VVBLKD
329 F0D6 00 00 dta a(0) ;$0226 CDTMA1
330 .endp
331
332 F0D8 krpdel_table:
333 F0D8 30 28 dta 48,40
334
335 ;==============================================================================
336 F0DA .proc InitEnvironment
337 F0DA A5 06 8D E4 02 mva tramsz ramsiz
338
339 .if _KERNEL_XLXE
340 ; set warmstart signature -- must be done before cart init, because
341 ; SDX doesn't return.
342 ldx #3
343 mva:rne InitBootSignature-1,x pupbt1-1,x-
344 .endif
345
346 ; 9. set screen margins
347 F0DF A9 02 85 52 mva #2 lmargn
348 F0E3 A9 27 85 53 mva #39 rmargn
349
350 ;set PAL/NTSC flag (XL/XE only)
351 .if _KERNEL_XLXE
352 ldx #0
353 lda pal
354 ldy #6
355 and #$0e
356 bne is_ntsc
357 sne:inx
358 dey
359 is_ntsc:
360 stx palnts
361 sty keyrep
362 mva krpdel_table,x krpdel
363 .endif
364
365 ; 10. initialize RAM vectors
366
367 ;VDSLST-VIMIRQ
368 F0E7 A2 17 ldx #[.len InitVectorTable1]-1
369 F0E9 BD BA F0 9D 00 02 + mva:rpl InitVectorTable1,x vdslst,x-
370
371 ;VVBLKI-CDTMA1
372 F0F2 A2 05 ldx #[.len InitVectorTable2]-1
373 F0F4 BD D2 F0 9D 22 02 + mva:rpl InitVectorTable2,x vvblki,x-
374
375 F0FD A9 00 8D 36 02 A9 + mwa #KeyboardBreakIRQ brkky
376
377 ; 11. set misc database values
378 F107 A2 FF ldx #$ff
379 F109 86 11 stx brkkey
380 F10B E8 inx
381 F10C 8E E5 02 stx memtop
382 F10F 8E E7 02 stx memlo
383 F112 A5 06 8D E6 02 mva tramsz memtop+1
384 F117 A2 07 8E E8 02 mvx #$07 memlo+1
385
386 F11C 20 60 ED jsr DiskInit
387 F11F 20 91 F5 jsr ScreenInit
388 ;jsr DisplayInit
389 F122 20 4B FE jsr KeyboardInit
390
391 .if _KERNEL_PRINTER_SUPPORT
392 F125 20 C0 ED jsr PrinterInit
393 .endif
394
395 ; 13. initialize device table (HATABS has already been cleared)
396 ; NOTE: The R: emulation relies on this being before CIOINV is invoked.
397 F128 A2 0E ldx #14
398 F12A BD E6 EF 9D 1A 03 + mva:rpl InitHandlerTable,x hatabs,x-
399
400 ;jsr CassetteInit
401 F133 20 6E E4 jsr cioinv
402 F136 20 45 E9 jsr SIOInit
403 F139 20 7F E8 jsr IntInitInterrupts
404
405 ; check for START key, and if so, set cassette boot flag
406 F13C AD 1F D0 lda consol
407 F13F 29 01 and #1
408 F141 49 01 eor #1
409 F143 8D E9 03 sta ckey
410
411 .if _KERNEL_PBI_SUPPORT
412 jsr PBIScan
413 .endif
414
415 ; 12. enable IRQ interrupts
416 ;
417 ; We do this later than the original OS specification because the PBI scan needs
418 ; to happen with IRQs disabled (a PBI device with interrupts may not have been
419 ; inited yet) and that PBI scan in turn needs to happen after HATABS has been
420 ; set up. There's no harm in initing HATABS with interrupts masked, so we do so.
421
422 F146 58 cli
423
424 ; 14. initialize cartridges
425 F147 A9 00 85 07 mva #0 tstdat
426
427 .if !_KERNEL_XLXE
428 F14B AD FC 9F lda $9ffc
429 F14E D0 18 bne skipCartBInit
430 F150 AD FB 9F lda $9ffb
431 F153 AA tax
432 F154 49 FF eor #$ff
433 F156 8D FB 9F sta $9ffb
434 F159 CD FB 9F cmp $9ffb
435 F15C 8E FB 9F stx $9ffb
436 F15F F0 07 beq skipCartBInit
437 F161 20 11 F2 jsr InitCartB
438 F164 A9 01 85 07 mva #1 tstdat
439 F168 skipCartBInit:
440 .endif
441
442 F168 A9 00 85 06 mva #0 tramsz
443 F16C AD FC BF lda $bffc
444 F16F D0 18 bne skipCartAInit
445 F171 AD FB BF lda $bffb
446 F174 AA tax
447 F175 49 FF eor #$ff
448 F177 8D FB BF sta $bffb
449 F17A CD FB BF cmp $bffb
450 F17D 8E FB BF stx $bffb
451 F180 F0 07 beq skipCartAInit
452 F182 20 0E F2 jsr InitCartA
453 F185 A9 01 85 06 mva #1 tramsz
454 F189 skipCartAInit:
455
456 ; 15. use IOCB #0 ($0340) to open screen editor (E)
457 ;
458 ; NOTE: We _must_ leave $0C in the A register when invoking CIO. Pooyan
459 ; relies on $0C being left in CIOCHR after the last call to CIO before
460 ; disk boot!
461
462 F189 A9 03 8D 42 03 mva #$03 iccmd ;OPEN
463 F18E A9 14 8D 44 03 A9 + mwa #ScreenEditorName icbal
464 F198 A9 0C 8D 4A 03 mva #$0c icax1 ;read/write, no forced read
465 F19D A2 00 ldx #0
466 F19F 8E 4B 03 stx icax2 ;mode 0
467 F1A2 20 56 E4 jsr ciov
468
469 ; 16. wait for VBLANK so screen is initialized
470 F1A5 A5 14 lda rtclok+2
471 F1A7 waitvbl:
472 F1A7 C5 14 cmp rtclok+2
473 F1A9 F0 FC beq waitvbl
474
475 ;-------------------------------------------------------------------------
476 ; Pre-boot hook (AltirraOS-specific)
477 ;
478
479 .ifdef _KERNEL_PRE_BOOT_HOOK
480 jsr InitPreBootHook
481 .endif
482
483 ;-------------------------------------------------------------------------
484 ; Run cartridge/cassette/disk
485 ;
486
487 ; 17. do cassette boot, if it was requested
488 ; F. if cassette boot was successful on cold boot, execute cassette init
489
490 ; The cold boot path must check the warm start flag and switch paths if
491 ; necessary. SpartaDOS X relies on being able to set the warm start
492 ; flag from its cart init handler.
493 ;
494 ; Disk boot must be attempted after cassette boot. Besides support for
495 ; using DOS from tape-based software, this is also required by the tape
496 ; version of Fun With Spelling (featuring Heathcliff), which depends on
497 ; the SIO request causing the tape start vector to be invoked shortly
498 ; after VBI so it can do an unsafe screen swap.
499 ;
500
501 F1AB A5 08 lda warmst
502 F1AD D0 0B bne reinitcas
503
504 F1AF AD E9 03 lda ckey
505 F1B2 F0 0F beq postcasboot
506 F1B4 20 7B F2 jsr BootCassette
507 F1B7 4C C3 F1 jmp postcasboot
508
509 F1BA reinitcas:
510 F1BA A9 02 lda #2
511 F1BC 24 09 bit boot?
512 F1BE F0 03 beq postcasboot
513 F1C0 20 18 F2 jsr InitCassetteBoot
514 F1C3 postcasboot:
515
516 ;-------------------------------------------------------------------------
517 ; 18. do disk boot
518 ; G. if disk boot was successful on cold boot, execute disk init
519 ;
520 ; For 800 mode, we must check if either cart A or cart B is present,
521 ; doing a disk boot if either there are no carts or one of the carts
522 ; requests disk boot. For the XL/XE case, cart B doesn't exist and we
523 ; can simplify the logic.
524 ;
525
526 F1C3 A5 08 lda warmst
527 F1C5 D0 1D bne reinitDisk
528
529 .if !_KERNEL_XLXE
530
531 ;check if we have cart B
532 F1C7 A5 07 lda tstdat
533 F1C9 D0 06 bne have_cart_b
534
535 ;no cart B -- if no cart A either, do disk boot
536 F1CB A6 06 ldx tramsz ;cart A
537 F1CD F0 0F beq boot_disk
538 F1CF D0 07 bne have_cart_a
539
540 F1D1 have_cart_b:
541 ;have cart B - grab boot disk flag (bit 0)
542 F1D1 AD FD 9F lda $9ffd
543
544 ;merge cart A's flags if it is present
545 F1D4 A6 06 ldx tramsz
546 F1D6 F0 03 beq no_cart_a
547
548 F1D8 have_cart_a:
549 F1D8 0D FD BF ora $bffd
550
551 F1DB no_cart_a:
552 ;skip disk boot if neither cart requested it
553 F1DB 4A lsr
554 F1DC 90 0E bcc skip_disk_boot
555
556 .else
557
558 ;check for cart A requesting boot
559 lda tramsz
560 beq boot_disk
561
562 ;have cart A - boot disk if requested
563 lda $bffd
564 lsr
565 bcc skip_disk_boot
566
567 .endif
568
569 F1DE boot_disk:
570 F1DE 20 1C F2 jsr BootDisk
571 F1E1 4C EC F1 jmp post_disk_boot
572
573 F1E4 reinitDisk:
574 F1E4 A5 09 lda boot?
575 F1E6 4A lsr
576 F1E7 90 03 bcc skip_disk_boot
577 F1E9 20 15 F2 jsr InitDiskBoot
578
579 F1EC post_disk_boot:
580 .if _KERNEL_XLXE
581 ; (XL/XE only) do type 3 poll or reinit handlers
582 ; !! - must only do this if a disk boot occurs; Pole Position audio breaks if
583 ; we do this and hit SKCTL before booting the cart
584 lda warmst
585 bne reinit_handlers
586 jsr PHStartupPoll
587 jmp post_reinit
588 reinit_handlers:
589 jsr PHReinitHandlers
590 post_reinit:
591 .endif
592
593 F1EC skip_disk_boot:
594
595 ;-------------------------------------------------------------------------
596 ; H. same as steps 19 and 20
597 ; 19. reset coldstart flag
598
599 F1EC A2 00 ldx #0
600 F1EE 8E 44 02 stx coldst
601
602 ;-------------------------------------------------------------------------
603 ; 20. run cartridges or blackboard
604 ;
605 ; Weird quirk here: if the left cart is absent or doesn't request
606 ; cart start, and the right cart is present and also doesn't request
607 ; cart start, OS-B endlessly does disk boots instead of running (DOSVEC).
608 ; We don't emulate this behavior for now since in practice it just seems
609 ; useless, boot looping until DOS crashes. It is moot starting with the
610 ; 1200XL DOS due to support for cart B being dropped.
611 ;
612
613 ; try to boot cart A
614 F1F1 A9 04 lda #$04
615 F1F3 A6 06 ldx tramsz
616 F1F5 F0 08 beq NoBootCartA
617 F1F7 2C FD BF bit $bffd
618 F1FA F0 03 6C FA BF seq:jmp ($bffa)
619 F1FF NoBootCartA:
620
621 ; try to boot cart B
622 F1FF A6 07 ldx tstdat
623 F201 F0 08 beq NoBootCartB
624 F203 2C FD 9F bit $9ffd
625 F206 F0 03 6C FA 9F seq:jmp ($9ffa)
626 F20B NoBootCartB:
627
628 ; run blackboard
629 F20B 6C 0A 00 jmp (dosvec)
630
631 F20E InitCartA:
632 F20E 6C FE BF jmp ($bffe)
633
634 F211 InitCartB:
635 F211 6C FE 9F jmp ($9ffe)
636
637 F214 ScreenEditorName:
638 F214 45 dta c"E"
639
640 .endp
641
642 ;==============================================================================
643 F215 .proc InitDiskBoot
644 F215 6C 0C 00 jmp (dosini)
645 .endp
646
647 F218 .proc InitCassetteBoot
648 .endp
649 F218 6C 02 00 jmp (casini)
650
651 ;==============================================================================
652
653 F21B EA nop
264 .endif
265
266 F21C icl 'boot.s'
Source: source/Shared/boot.s
1 ; Altirra - Atari 800/800XL/5200 emulator
2 ; Modular Kernel ROM - Boot Code
3 ; Copyright (C) 2008-2016 Avery Lee
4 ;
5 ; Copying and distribution of this file, with or without modification,
6 ; are permitted in any medium without royalty provided the copyright
7 ; notice and this notice are preserved. This file is offered as-is,
8 ; without any warranty.
9
10 ;==========================================================================
11 ; Disk boot routine.
12 ;
13 ; Exit:
14 ; DBUFLO/DBUFHI = $0400 (Undoc; required by Ankh and the 1.atr SMB demo)
15 ; Last sector in $0400 (Undoc; required by Ankh)
16 ;
17 F21C .proc BootDisk
18 ;issue a status request first to see if the disk is active; if this
19 ;doesn't come back, don't bother trying to read
20 F21C A9 53 lda #$53
21 F21E 8D 02 03 sta dcomnd
22 F221 A2 01 ldx #1
23 F223 8E 01 03 stx dunit
24 F226 20 53 E4 jsr dskinv
25 F229 30 3C bmi xit
26
27 ;read first sector to $0400
28 F22B A2 01 ldx #1
29 F22D 8E 01 03 stx dunit
30 F230 8E 0A 03 stx daux1
31 F233 CA dex
32 F234 8E 04 03 stx dbuflo
33 F237 8E 0B 03 stx daux2
34 F23A A9 52 8D 02 03 mva #$52 dcomnd
35 F23F A9 04 8D 05 03 mva #$04 dbufhi
36 F244 20 53 E4 jsr dskinv
37 F247 30 1A bmi fail
38
39 F249 sector1_ok:
40 F249 A2 0C ldx #dosini
41 F24B 20 B6 F2 jsr BootInitHeaders
42
43 ;load remaining sectors
44 F24E sectorloop:
45 ;copy sector from $0400 to destination (required by Ankh; see above)
46 ;bump destination address for next sector copy
47 F24E 20 E3 F2 jsr BootCopyBlock
48
49 ;exit if this was the last sector (note that 0 means to load 256 sectors!)
50 F251 CE 41 02 dec dbsect
51 F254 F0 18 beq loaddone
52
53 ;increment sector (yes, this can overflow to 256)
54 F256 EE 0A 03 D0 03 EE + inw daux1
55
56 ;read next sector
57 F25E 20 53 E4 jsr dskinv
58
59 ;keep going if we succeeded
60 F261 10 EB bpl sectorloop
61
62 ;read failed
63 F263 fail:
64 F263 C0 8A cpy #SIOErrorTimeout
65 F265 D0 01 bne failmsg
66 F267 xit:
67 F267 60 rts
68
69 F268 failmsg:
70 .if _KERNEL_USE_BOOT_SCREEN
71 st_loop:
72 lda portb
73 eor #$80
74 sta portb
75 bmi sector1_ok
76 jsr BootScreen.boot_entry
77 jmp st_loop
78 .else
79 F268 20 F8 F2 jsr BootShowError
80 F26B 4C 1C F2 jmp BootDisk
81 .endif
82
83 F26E loaddone:
84 F26E 20 D3 F2 jsr BootRunLoader
85 F271 B0 F5 bcs failmsg
86
87 ;Diskette Boot Process, step 7 (p.161 of the OS Manual) is misleading. It
88 ;says that DOSVEC is invoked after DOSINI, but actually that should NOT
89 ;happen here -- it happens AFTER cartridges have had a chance to run.
90 ;This is necessary for BASIC to gain control before DOS goes to load
91 ;DUP.SYS.
92 F273 20 15 F2 jsr InitDiskBoot
93
94 ;Must not occur until after init routine is called -- SpartaDOS 3.2 does
95 ;an INC on this flag and never exits.
96 F276 A9 01 85 09 mva #1 boot?
97 F27A 60 rts
98 .endp
99
100
101 ;============================================================================
102
103 F27B .proc BootCassette
104 ;set continuous mode -- must do this as CSOPIV doesn't
105 F27B A9 80 lda #$80
106 F27D 85 3E sta ftype
107
108 ;open cassette device
109 F27F 20 7D E4 jsr csopiv
110
111 ;read first block
112 F282 20 7A E4 jsr rblokv
113 F285 30 24 bmi load_failure
114
115 F287 A2 02 ldx #casini
116 F289 20 B6 F2 jsr BootInitHeaders
117
118 F28C block_loop:
119 ;copy 128 bytes from CASBUF+3 ($0400) to destination
120 ;update destination pointer
121 F28C 20 E3 F2 jsr BootCopyBlock
122
123 ;read next block
124 ;we always need to do one more to catch the EOF block, which is
125 ;required by STDBLOAD2
126 F28F 20 7A E4 jsr rblokv
127 F292 30 17 bmi load_failure
128
129 F294 CE 41 02 dec dbsect
130 F297 D0 F3 bne block_loop
131
132 ;run loader
133 F299 20 D3 F2 jsr BootRunLoader
134
135 ;run cassette init routine
136 F29C 20 18 F2 jsr InitCassetteBoot
137
138 ;clear cassette boot key flag
139 F29F A9 00 lda #0
140 F2A1 8D E9 03 sta ckey
141
142 ;set cassette boot flag
143 F2A4 A9 02 85 09 mva #2 boot?
144
145 ;run application
146 F2A8 6C 0A 00 jmp (dosvec)
147
148 F2AB load_failure:
149 F2AB A9 00 lda #0
150 F2AD 8D E9 03 sta ckey
151 F2B0 20 B1 EE jsr CassetteClose
152 F2B3 4C F8 F2 jmp BootShowError
153 .endp
154
155 ;============================================================================
156 F2B6 .proc BootInitHeaders
157 ;copy the first four bytes to DFLAGS, DBSECT, and BOOTAD
158 F2B6 A0 FC ldy #$fc
159 F2B8 B9 04 03 99 44 01 + mva:rne $0400-$fc,y dflags-$fc,y+
160
161 ;copy boot address in BOOTAD to BUFADR
162 F2C1 85 16 sta bufadr+1
163 F2C3 AD 42 02 lda bootad
164 F2C6 85 15 sta bufadr
165
166 ;copy init vector
167 F2C8 AD 04 04 95 00 AD + mwa $0404 0,x
168 F2D2 60 rts
169 .endp
170
171 ;============================================================================
172 F2D3 .proc BootRunLoader
173 ;loader is at load address + 6
174 F2D3 AD 42 02 lda bootad
175 F2D6 18 69 05 add #$05
176 F2D9 AA tax
177 F2DA AD 43 02 lda bootad+1
178 F2DD 69 00 adc #0
179 F2DF 48 pha
180 F2E0 8A txa
181 F2E1 48 pha
182 F2E2 60 rts
183 .endp
184
185 ;============================================================================
186 F2E3 .proc BootCopyBlock
187 F2E3 A0 7F ldy #$7f
188 F2E5 B9 00 04 91 15 88 + mva:rpl $0400,y (bufadr),y-
189
190 F2ED A5 15 lda bufadr
191 F2EF 49 80 eor #$80
192 F2F1 85 15 sta bufadr
193 F2F3 30 02 E6 16 smi:inc bufadr+1
194 F2F7 60 rts
195 .endp
196
197 ;============================================================================
198
199 F2F8 .proc BootShowError
200 F2F8 A2 F5 ldx #$f5
201 F2FA msgloop:
202 F2FA 8A txa
203 F2FB 48 pha
204 F2FC BD 13 F2 lda errormsg-$f5,x
205 F2FF 20 A8 FA jsr EditorPutByte
206 F302 68 pla
207 F303 AA tax
208 F304 E8 inx
209 F305 D0 F3 bne msgloop
210 F307 60 rts
211
212 F308 errormsg:
213 F308 42 4F 4F 54 20 45 + dta 'BOOT ERROR',$9B
214 .endp
267 F313 _KERNEL_REPORT_MODULE_SIZE 'Monitor routines', $F3E4-$F0E3
Macro: _KERNEL_REPORT_MODULE_SIZE [Source: source/main.xasm]
1 .echo ' ', *, ' -> ', *-?@_kernel_lastpt, '(', $F3E4-$F0E3, ')', ' ', 'Monitor routines'
1 $F313 -> $032D($0301) Monitor routines
3 = F313 .def ?@_kernel_lastpt = *
Source: source/main.xasm
268
269 F313 icl 'screen.s'
Source: source/Shared/screen.s
1 ; Altirra - Atari 800/800XL/5200 emulator
2 ; Modular Kernel ROM - Screen Handler
3 ; Copyright (C) 2008-2016 Avery Lee
4 ;
5 ; Copying and distribution of this file, with or without modification,
6 ; are permitted in any medium without royalty provided the copyright
7 ; notice and this notice are preserved. This file is offered as-is,
8 ; without any warranty.
9
10 ;Display list:
11 ; 24 blank lines (3 bytes)
12 ; initial mode line with LMS (3 bytes)
13 ; mode lines
14 ; LMS for modes >4 pages
15 ; wait VBL (3 bytes)
16 ;
17 ; total is 8-10 bytes + mode lines
18
19 ; These are the addresses produced by the normal XL/XE OS:
20 ;
21 ; Normal Split, coarse Split, fine
22 ; Mode DL PF TX DL PF TX DL PF TX
23 ; 0 9C20 9C40 9F60 9C20 9C40 9F60 9C1F 9C40 9F60
24 ; 1 9D60 9D80 9F60 9D5E 9D80 9F60 9D5D 9D80 9F60
25 ; 2 9E5C 9E70 9F60 9E58 9E70 9F60 9E57 9E70 9F60
26 ; 3 9E50 9E70 9F60 9E4E 9E70 9F60 9E4D 9E70 9F60
27 ; 4 9D48 9D80 9F60 9D4A 9D80 9F60 9D49 9D80 9F60
28 ; 5 9B68 9BA0 9F60 9B6A 9BA0 9F60 9B69 9BA0 9F60
29 ; 6 9778 97E0 9F60 9782 97E0 9F60 9781 97E0 9F60
30 ; 7 8F98 9060 9F60 8FA2 9060 9F60 8FA1 9060 9F60
31 ; 8 8036 8150 9F60 8050 8150 9F60 804F 8150 9F60
32 ; 9 8036 8150 9F60 8036 8150 9F60 8036 8150 9F60
33 ; 10 8036 8150 9F60 8036 8150 9F60 8036 8150 9F60
34 ; 11 8036 8150 9F60 8036 8150 9F60 8036 8150 9F60
35 ; 12 9B80 9BA0 9F60 9B7E 9BA0 9F60 9B7D 9BA0 9F60
36 ; 13 9D6C 9D80 9F60 9D68 9D80 9F60 9D67 9D80 9F60
37 ; 14 8F38 9060 9F60 8F52 9060 9F60 8F51 9060 9F60
38 ; 15 8036 8150 9F60 8050 8150 9F60 804F 8150 9F60
39 ;
40 ; *DL = display list (SDLSTL/SDLSTH)
41 ; *PF = playfield (SAVMSC)
42 ; *TX = text window (TXTMSC)
43 ;
44 ; From this, we can derive a few things:
45 ; - The text window is always 160 ($A0) bytes below the ceiling.
46 ; - The playfield is always positioned to have enough room for
47 ; the text window, even though this wastes a little bit of
48 ; memory for modes 1, 2, 3, 4, and 13. This means that the
49 ; PF address does not have to be adjusted for split mode.
50 ; - The display list and playfield addresses are sometimes
51 ; adjusted in order to avoid crossing 1K boundaries for the
52 ; display list (gr.7) and 4K boundaries for the playfield (gr.8).
53 ; However, these are fixed offsets -- adjusting RAMTOP to $9F
54 ; does not remove the DL padding in GR.7 and breaks GR.7/8.
55 ; - Fine-scrolled modes take one additional byte for the extra
56 ; mode 2 line. In fact, it displays garbage that is masked by
57 ; a DLI that sets COLPF1 equal to COLPF2. (!)
58 ;
59 ; You might ask, why bother replicating these? Well, there are a
60 ; number of programs that rely on the layout of the default screen
61 ; and break if the memory addressing is different, such as ForemXEP.
62
63 .macro _SCREEN_TABLES_2
64
65 ;Mode Type Res Colors ANTIC Mem(unsplit) Mem(split)
66 ; 0 Text 40x24 1.5 2 960+32 (4) 960+32 (4)
67 ; 1 Text 20x24 5 6 480+32 (2) 560+32 (3)
68 ; 2 Text 20x12 5 7 240+20 (2) 360+22 (2)
69 ; 3 Bitmap 40x24 4 8 240+32 (2) 360+32 (2)
70 ; 4 Bitmap 80x48 2 9 480+56 (3) 560+52 (3)
71 ; 5 Bitmap 80x48 4 A 960+56 (4) 960+52 (4)
72 ; 6 Bitmap 160x96 2 B 1920+104 (8) 1760+92 (8)
73 ; 7 Bitmap 160x96 4 D 3840+104 (16) 3360+92 (14)
74 ; 8 Bitmap 320x192 1.5 F 7680+202 (32) 6560+174 (27)
75 ; 9 Bitmap 80x192 16 F 7680+202 (32) 6560+174 (27)
76 ; 10 Bitmap 80x192 9 F 7680+202 (32) 6560+174 (27)
77 ; 11 Bitmap 80x192 16 F 7680+202 (32) 6560+174 (27)
78 ; 12 Text 40x24 5 4 960+32 (4) 960+32 (4)
79 ; 13 Text 40x12 5 5 480+20 (2) 560+24 (3)
80 ; 14 Bitmap 160x192 2 C 3840+200 (16) 3360+172 (14)
81 ; 15 Bitmap 160x192 4 E 7680+202 (32) 6560+172 (27)
82
83 ;==========================================================================
84 ;
85 .proc ScreenPlayfieldSizesLo
86 dta <($10000-$03C0) ;gr.0 960 bytes = 40*24 = 40*24
87 dta <($10000-$0280) ;gr.1 640 bytes = 20*24 + 40*4 = 40*12 + 40*4
88 dta <($10000-$0190) ;gr.2 400 bytes = 10*24 + 40*4 = 40*6 + 40*4
89 dta <($10000-$0190) ;gr.3 400 bytes = 10*24 + 40*4 = 40*6 + 40*4
90 dta <($10000-$0280) ;gr.4 640 bytes = 10*48 + 40*4 = 40*12 + 40*4
91 dta <($10000-$0460) ;gr.5 1120 bytes = 20*48 + 40*4 = 40*24 + 40*4
92 dta <($10000-$0820) ;gr.6 2080 bytes = 20*96 + 40*4 = 40*48 + 40*4
93 dta <($10000-$0FA0) ;gr.7 4000 bytes = 40*96 + 40*4 = 40*96 + 40*4
94 dta <($10000-$1EB0) ;gr.8 7856 bytes = 40*192 + 40*4 + 16 = 40*192 + 40*4 + 16
95 dta <($10000-$1EB0) ;gr.9 7856 bytes = 40*192 + 40*4 + 16 = 40*192 + 40*4 + 16
96 dta <($10000-$1EB0) ;gr.10 7856 bytes = 40*192 + 40*4 + 16 = 40*192 + 40*4 + 16
97 dta <($10000-$1EB0) ;gr.11 7856 bytes = 40*192 + 40*4 + 16 = 40*192 + 40*4 + 16
98 dta <($10000-$0460) ;gr.12 1120 bytes = 40*24 + 40*4 = 40*24 + 40*4
99 dta <($10000-$0280) ;gr.13 640 bytes = 40*12 + 40*4 = 40*12 + 40*4
100 dta <($10000-$0FA0) ;gr.14 4000 bytes = 20*192 + 40*4 = 40*96 + 40*4
101 dta <($10000-$1EB0) ;gr.15 7856 bytes = 40*192 + 40*4 + 16 = 40*192 + 40*4 + 16
102 .endp
103
104 .proc ScreenPlayfieldSizesHi
105 dta >($10000-$03C0) ;gr.0
106 dta >($10000-$0280) ;gr.1
107 dta >($10000-$0190) ;gr.2
108 dta >($10000-$0190) ;gr.3
109 dta >($10000-$0280) ;gr.4
110 dta >($10000-$0460) ;gr.5
111 dta >($10000-$0820) ;gr.6
112 dta >($10000-$0FA0) ;gr.7
113 dta >($10000-$1EB0) ;gr.8
114 dta >($10000-$1EB0) ;gr.9
115 dta >($10000-$1EB0) ;gr.10
116 dta >($10000-$1EB0) ;gr.11
117 dta >($10000-$0460) ;gr.12
118 dta >($10000-$0280) ;gr.13
119 dta >($10000-$0FA0) ;gr.14
120 dta >($10000-$1EB0) ;gr.15
121 .endp
122
123 ;==========================================================================
124 ; ANTIC mode is in bits 0-3, PRIOR bits in 6-7.
125 ; DL 1K hop: bit 4
126 ; playfield 4K hop: bit 5
127 ;
128 .proc ScreenModeTable
129 dta $02,$06,$07,$08,$09,$0A,$0B,$1D,$3F,$7F,$BF,$FF,$04,$05,$1C,$3E
130 .endp
131
132 ;==========================================================================
133 ;
134 .proc ScreenHeightShifts
135 dta 1
136 dta 1
137 dta 0
138 dta 1
139 dta 2
140 dta 2
141 dta 3
142 dta 3
143 dta 4
144 dta 4
145 dta 4
146 dta 4
147 dta 1
148 dta 0
149 dta 4
150 dta 4
151 .endp
152
153 .proc ScreenHeights
154 dta 12, 24, 48, 96, 192
155 .endp
156
157 .proc ScreenPixelWidthIds
158 dta 1 ;gr.0 40 pixels
159 dta 0 ;gr.1 20 pixels
160 dta 0 ;gr.2 20 pixels
161 dta 1 ;gr.3 40 pixels
162 dta 2 ;gr.4 80 pixels
163 dta 2 ;gr.5 80 pixels
164 dta 3 ;gr.6 160 pixels
165 dta 3 ;gr.7 160 pixels
166 dta 4 ;gr.8 320 pixels
167 dta 2 ;gr.9 80 pixels
168 dta 2 ;gr.10 80 pixels
169 dta 2 ;gr.11 80 pixels
170 dta 1 ;gr.12 40 pixels
171 dta 1 ;gr.13 40 pixels
172 dta 3 ;gr.14 160 pixels
173 dta 3 ;gr.15 160 pixels
174 .endp
175 .endm
176
177 = F9C7 ScreenHeightsSplit = ScreenWidths
178 ; dta 10, 20, 40, 80, 160
179
180 = F9C8 ScreenPixelWidthsLo = ScreenWidths + 1
181
182 .macro _SCREEN_TABLES_1
183
184 .proc ScreenWidths
185 dta <10
186 dta <20
187 dta <40
188 dta <80
189 dta <160
190 dta <320
191 .endp
192
193 .proc ScreenPixelWidthsHi
194 dta >20
195 dta >40
196 dta >80
197 dta >160
198 dta >320
199 .endp
200
201 .proc ScreenEncodingTab
202 dta 0 ;gr.0 direct bytes
203 dta 0 ;gr.1 direct bytes
204 dta 0 ;gr.2 direct bytes
205 dta 2 ;gr.3 two bits per pixel
206 dta 3 ;gr.4 one bit per pixel
207 dta 2 ;gr.5 two bits per pixel
208 dta 3 ;gr.6 one bit per pixel
209 dta 2 ;gr.7 two bits per pixel
210 dta 3 ;gr.8 one bit per pixel
211 dta 1 ;gr.9 four bits per pixel
212 dta 1 ;gr.10 four bits per pixel
213 dta 1 ;gr.11 four bits per pixel
214 dta 0 ;gr.12 direct bytes
215 dta 0 ;gr.13 direct bytes
216 dta 3 ;gr.14 one bit per pixel
217 dta 2 ;gr.15 two bits per pixel
218 .endp
219
220 .proc ScreenPixelMasks
221 dta $ff, $0f, $03, $01, $ff, $f0, $c0, $80
222 .endp
223 .endm
224
225 .macro _SCREEN_TABLES_3
226 .proc ScreenEncodingTable
227 dta $00,$11,$22,$33,$44,$55,$66,$77,$88,$99,$aa,$bb,$cc,$dd,$ee,$ff
228 dta $00,$55,$aa,$ff
229 dta $00,$ff
230 .endp
231 .endm
232
233 .if _KERNEL_XLXE
234 _SCREEN_TABLES_3
235 _SCREEN_TABLES_2
236 _SCREEN_TABLES_1
237 .endif
238
239 ;==========================================================================
240 ;==========================================================================
241
242 ;Many compilation disks rely on ScreenOpen being at $F3F6.
243
244 .if *>$f3f6-8
245 .error 'ROM overflow into Screen Handler region: ',*,' > $F3EE.'
246 .endif
247
248 .ifdef _KERNEL_REPORT_MODULE_PAD_ADJUST
249 F313 _KERNEL_REPORT_MODULE_PAD_ADJUST [$f3f6-8]-*
Macro: _KERNEL_REPORT_MODULE_PAD_ADJUST [Source: source/main.xasm]
1 = F3EE .def ?@_kernel_lastpt = ?@_kernel_lastpt + [$F3F6-8]-*
Source: source/Shared/screen.s
250 .endif
251
252 F313 org $f3f6-8
253
254 ;==========================================================================
255 ;==========================================================================
256
257 ;==========================================================================
258 ;
259 ; Return:
260 ; MEMTOP = first byte used by display
261 ;
262 ; Errors:
263 ; - If there is not enough memory (MEMTOP > APPMHI), GR.0 is reopened
264 ; automatically and an error is returned.
265 ;
266 ; Notes:
267 ; - Resets character base (CHBAS).
268 ; - Resets character attributes (CHACT).
269 ; - Resets playfield colors (COLOR0-COLOR4).
270 ; - Resets tab map, even if the mode does not have a text window.
271 ; - Resets logical line map, even if the mode does not have a text window.
272 ; - Does NOT reset P/M colors (PCOLR0-PCOLR3).
273 ; - Does NOT reset margins (LMARGN/RMARGN).
274 ; - Sets up fine scrolling if FINE bit 7 is set. Note that this is
275 ; different than the scroll logic itself, which tests the whole byte.
276 ; - Returns error $80 if BREAK has been pressed.
277 ; - If clear is bypassed, ROWCRS and COLCRS are preserved.
278 ;
279 ; Modified:
280 ; - FRMADR: used for bitflags
281 ; bit 7 = skip clear
282 ; bit 6 = split screen
283 ; bit 0 = fine scrolling (XL/XE only)
284 ; - ADRESS: temporary addressing
285 ;
286 = F3F6 ScreenOpen = ScreenOpenGr0.use_iocb
287 = F3F2 ScreenOpenMode0 = ScreenOpenGr0.use_mode0
288 F3EE .proc ScreenOpenGr0
289 F3EE A9 0C 85 2A mva #12 icax1z
290 F3F2 use_mode0:
291 F3F2 A9 00 85 2B mva #0 icax2z
292 F3F6 use_iocb:
293 ;shut off ANTIC playfield and instruction DMA
294 F3F6 AD 2F 02 lda sdmctl
295 F3F9 29 DC and #$dc
296 F3FB 8D 2F 02 sta sdmctl
297 F3FE 8D 00 D4 sta dmactl
298
299 ;reset cursor parameters
300 F401 A2 0B ldx #11
301 F403 A9 00 lda #0
302 F405 clear_parms:
303 F405 95 54 sta rowcrs,x
304 F407 9D 90 02 sta txtrow,x
305 F40A CA dex
306 F40B D0 F8 bne clear_parms
307
308 ;mark us as being in main screen context
309 F40D 86 7B stx swpflg
310
311 ;copy mode value to dindex
312 F40F A5 2B lda icax2z
313 F411 29 0F and #15
314 F413 85 57 sta dindex
315 F415 AA tax
316
317 ;poke PRIOR value (saves us some time to do it now)
318 ;note that we must preserve bits 0-5 of GPRIOR or else Wayout shows logo artifacts
319 F416 BD 16 FE lda ScreenModeTable,x
320 F419 4D 6F 02 eor gprior
321 F41C 29 C0 and #$c0
322 F41E 4D 6F 02 eor gprior
323 F421 8D 6F 02 sta gprior
324
325 ;if a GTIA mode is active or we're in mode 0, force off split mode
326 F424 C9 40 cmp #$40
327 F426 A5 2A lda icax1z
328 F428 B0 04 bcs kill_split
329 F42A E0 00 cpx #0
330 F42C D0 02 bne not_gtia_mode_or_gr0
331 F42E kill_split:
332 F42E 29 EF and #$ef
333 F430 not_gtia_mode_or_gr0:
334
335 ;save off the split screen and clear flags in a more convenient form
336 F430 0A asl
337 F431 0A asl
338 F432 85 68 sta frmadr
339
340 ;compute number of mode lines that we're going to have and save it off
341 F434 BC 26 FE ldy ScreenHeightShifts,x
342 F437 BE 36 FE ldx ScreenHeights,y
343 F43A 0A asl
344 F43B 10 03 BE C7 F9 spl:ldx ScreenHeightsSplit,y
345 F440 86 69 stx frmadr+1
346
347 ;attempt to allocate playfield memory
348 F442 A5 6A lda ramtop
349 F444 A6 57 ldx dindex
350 F446 18 clc
351 F447 7D 06 FE adc ScreenPlayfieldSizesHi,x
352 F44A B0 09 bcs pf_alloc_ok
353
354 F44C alloc_fail:
355 ;we ran out of memory -- attempt to reopen with gr.0 if we aren't
356 ;already (to prevent recursion), and exit with an error
357 F44C 8A txa
358 F44D F0 03 beq cant_reopen_gr0
359
360 F44F 20 EE F3 jsr ScreenOpenGr0
361 F452 cant_reopen_gr0:
362 F452 A0 93 ldy #CIOStatOutOfMemory
363 F454 60 rts
364
365 F455 pf_alloc_ok:
366 F455 85 59 sta savmsc+1
367 F457 BC F6 FD ldy ScreenPlayfieldSizesLo,x
368 F45A 84 58 sty savmsc
369
370 ;Gr. modes 7 and 14 consume enough space for the playfield that there
371 ;is not enough space left between the playfield and the next 1K
372 ;boundary to contain the display list. In these cases, we preallocate
373 ;to the 1K boundary to prevent a DL crossing error. Gr.8-11 and 15
374 ;do this too -- I have no idea why, as it's not like the OS correctly
375 ;handles moving the 4K page split for those modes if RAMTOP is
376 ;misaligned.
377 F45C BD 16 FE lda ScreenModeTable,x
378 F45F A6 59 ldx savmsc+1
379 F461 29 30 and #$30
380 F463 F0 03 beq no_dlist_page_crossing
381 F465 A0 00 ldy #0
382 F467 CA dex
383 F468 no_dlist_page_crossing:
384 F468 84 70 sty rowac
385 F46A 8E E6 02 stx memtop+1
386 F46D 86 71 stx rowac+1
387 F46F 8E 31 02 stx sdlsth
388
389 ;Compute display list size.
390 ;
391 ; We need:
392 ; - 8 fixed bytes (24 blank lines, LMS address, JVB)
393 ; - N bytes for mode lines
394 ; - 2 bytes for LMS split address (ANTIC modes E-F only)
395 ; - 6 bytes for split
396 ;
397 ;Note that the display list never crosses a page boundary. This is
398 ;conservative, as the display list only can't cross 1K boundaries.
399
400 F472 C9 20 cmp #$20 ;test 4K hop bit (bit 5)
401 F474 A9 F8 lda #$f8 ;start with -8 (if carry is clear after test)
402 F476 90 02 A9 F5 scc:lda #$f5 ;use -11 if so (carry is set)
403 F47A E5 69 sbc frmadr+1 ;subtract mode line count
404 F47C 24 68 bit frmadr
405 F47E 50 02 E9 06 svc:sbc #6 ;subtract 6 bytes for a split
406
407 .if _KERNEL_XLXE
408 ldy #1
409 cpy fine ;clear carry to alloc +1 byte if fine scrolling is enabled
410 .endif
411
412 F482 65 70 adc rowac ;allocate dl bytes (note that carry is set!)
413 F484 8D E5 02 sta memtop
414 F487 85 70 sta rowac
415 F489 8D 30 02 sta sdlstl
416
417 ;check if we're below APPMHI
418 F48C E4 0F cpx appmhi+1
419 F48E 90 BC bcc alloc_fail
420 F490 D0 04 bne alloc_ok
421 F492 C5 0E cmp appmhi
422 F494 90 B6 bcc alloc_fail
423
424 F496 alloc_ok:
425 ;MEMTOP is -1 from first used byte; we cheat here with the knowledge that
426 ;the low byte of MEMTOP is never $00
427 F496 CE E5 02 dec memtop
428
429 ;set up text window address (-160 from top)
430 F499 A6 6A ldx ramtop
431 F49B CA dex
432 F49C 8E 95 02 stx txtmsc+1
433 F49F A9 60 8D 94 02 mva #$60 txtmsc
434
435 ;Turn on keyboard and break interrupts; note that this is done both for S:
436 ;and E: opens. Close does not do this.
437 F4A4 08 php
438 F4A5 78 sei
439 F4A6 0A asl ;!! - A = $C0
440 F4A7 05 10 ora pokmsk
441 F4A9 85 10 sta pokmsk
442 F4AB 8D 0E D2 sta irqen
443 F4AE 28 plp
444
445 ;Set row count: 24 for full-screen. We will fix up the split case to 4 later
446 ;while we are writing the display list. Mapping the Atari incorrectly states
447 ;that this value is set to 0 when no text window is present; this is wrong
448 ;and in fact BAYPILOT.BAS relies on this being set to 24 for a GR.7+16
449 ;screen since it later aliases it to GR.0.
450 F4AF A0 18 ldy #24
451 F4B1 8C BF 02 sty botscr
452
453 ;init colors -- note that we do NOT overwrite pcolr0-3!
454 F4B4 A0 05 ldy #5
455 F4B6 B9 88 F5 99 C3 02 + mva:rne standard_colors-1,y color0-1,y-
456
457 F4BF 8C F0 02 sty crsinh ;!! - Y=0 for this and for write index
458
459 ;add 24 blank lines
460 F4C2 A9 70 lda #$70
461 F4C4 A2 03 ldx #3
462 F4C6 20 6D F5 jsr write_repeat
463
464 ;override COLOR4 (background) to $06 for GR.11 so it isn't dark
465 F4C9 A5 57 lda dindex
466 F4CB C9 0B cmp #11
467 F4CD D0 05 bne not_gr11
468 F4CF A9 06 lda #$06
469 F4D1 8D C8 02 sta color4
470 F4D4 not_gr11:
471
472 ;add in the main screen
473 F4D4 20 32 F5 jsr setup_display
474
475 ;save off the DL ptr
476 F4D7 84 7E sty countr
477
478 ;clear it if necessary
479 F4D9 20 82 F5 jsr try_clear
480
481 ;check if we are doing a split
482 F4DC 24 68 bit frmadr
483 F4DE 50 12 bvc nosplit
484
485 ;change text screen height to four lines
486 F4E0 A2 04 ldx #4
487 F4E2 8E BF 02 stx botscr
488
489 ;swap to the text screen
490 F4E5 20 0A F9 jsr EditorSwapToText
491
492 ;add text screen dlist
493 F4E8 A4 7E ldy countr
494 F4EA 20 32 F5 jsr setup_display
495 F4ED 84 7E sty countr
496
497 ;clear the split screen
498 F4EF 20 82 F5 jsr try_clear
499
500 F4F2 nosplit:
501 F4F2 A9 02 8D F3 02 mva #2 chact
502
503 ;init tab map to every 8 columns
504 F4F7 A2 0F ldx #15
505 F4F9 4A lsr ;!! A=1
506 F4FA 9D A2 02 CA D0 FA sta:rne tabmap-1,x-
507
508 ;reset line status
509 F500 86 6B stx bufcnt
510
511 ;init character set
512 F502 A2 E0 8E F4 02 mvx #$e0 chbas ;!! - also used for NMIEN
513
514 ;enable VBI; note that we have not yet enabled display DMA
515 .if _KERNEL_XLXE
516 bit frmadr
517 sne:ldx #$40
518 .else
519 F507 A2 40 ldx #$40
520 .endif
521 F509 8E 0E D4 stx nmien
522
523 ;terminate display list with jvb
524 F50C A4 7E ldy countr
525 F50E A2 70 ldx #rowac
526 F510 A9 41 lda #$41
527 F512 20 74 F5 jsr write_with_zp_address
528
529 ;init display list and playfield dma
530 F515 AD 2F 02 lda sdmctl
531 F518 09 22 ora #$22
532 F51A 8D 2F 02 sta sdmctl
533
534 ;wait for screen to establish (necessary for Timewise splash screen to render)
535 F51D A5 14 lda rtclok+2
536 F51F C5 14 F0 FC cmp:req rtclok+2
537
538 ;If we're in screen mode 0, show the cursor; otherwise, skip it and wait for
539 ;E: to do so. We need to skip this even if a split screen is present, or else
540 ;ACTris 2.1 displays a bogus cursor. Unfortunately we may have swapped to the
541 ;split screen, so the mode we need may be in either DINDEX or TINDEX; it's
542 ;easier for us just to re-check AUX2 bits 0-3.
543 F523 A5 2B lda icax2z
544 F525 29 0F and #$0f
545 F527 D0 03 bne no_cursor
546
547 ;show cursor
548 F529 20 82 F6 jsr ScreenPutByte.recompute_show_cursor_exit
549 F52C no_cursor:
550 ;swap back to main context
551 F52C 20 61 FD jsr EditorSwapToScreen_Y1
552
553 ;exit
554 F52F A2 00 ldx #0 ;required by Qix (v3)
555 F531 60 rts
556
557
558 ;--------------------------------------------------------
559 F532 setup_display:
560 ;Add initial mode line with LMS, and check if we need to do an LMS
561 ;split (playfield exceeds 4K). As it turns out, this only happens if
562 ;we're using ANTIC mode E or F.
563 F532 A6 57 ldx dindex
564 F534 BD 16 FE lda ScreenModeTable,x
565 F537 29 0F and #$0f
566
567 .if _KERNEL_XLXE
568 ;check if we are doing fine scrolling and set the vscrol bit if so
569 ldx dindex
570 bne nofine
571 ldx fine
572 beq nofine
573 ora #$20
574 nofine:
575 .endif
576
577 F539 48 pha
578 F53A 09 40 ora #$40
579 F53C A2 58 ldx #savmsc
580 F53E 20 74 F5 jsr write_with_zp_address
581
582 ;retrieve row count
583 F541 A6 69 ldx frmadr+1
584 F543 A5 57 lda dindex
585 F545 D0 03 AE BF 02 sne:ldx botscr
586
587 ;dec row count since we already did the LMS
588 F54A CA dex
589 F54B 68 pla
590
591 .if _KERNEL_XLXE
592 ;subtract two rows if we are fine scrolling, as we need to do DLI
593 ;and non-vscrolled row
594 cmp #$22
595 beq dofine
596 .endif
597
598 ;check if this is a split mode
599 F54C C9 0E cmp #$0e
600 F54E 90 1D bcc no_lms_split
601
602 ;yes it is -- write 93 lines
603 F550 A2 5D ldx #93
604 F552 20 6D F5 jsr write_repeat
605
606 ;write LMS to jump over 4K boundary
607 F555 48 pha
608 F556 09 40 ora #$40
609 F558 91 70 C8 sta (rowac),y+
610 F55B A9 00 lda #0
611 F55D 91 70 C8 sta (rowac),y+
612 F560 A5 59 lda savmsc+1
613 F562 69 0E adc #$0f-1 ;!! - C=1 from bcc above
614 F564 91 70 C8 sta (rowac),y+
615
616 ;set up to write 95 fewer lines (note that carry is cleared)
617 F567 A5 69 lda frmadr+1
618 F569 E9 5E sbc #94
619 F56B AA tax
620 F56C 68 pla
621
622 ;write mode lines and return
623 F56D no_lms_split:
624 F56D write_repeat:
625 F56D 91 70 C8 sta (rowac),y+
626 F570 CA dex
627 F571 D0 FA bne write_repeat
628 F573 no_clear:
629 F573 60 rts
630
631 .if _KERNEL_XLXE
632 dofine:
633 ;write the regular lines (22 or 2)
634 dex
635 jsr write_repeat
636
637 ;write DLI line
638 ora #$80
639 sta (rowac),y+
640
641 ;write non-scrolled line
642 and #$5f
643 sta (rowac),y+
644
645 ;indicate to mainline that DLIs should be turned on
646 inc frmadr
647
648 ;set up DLI routine
649 ldx #<ScreenFineScrollDLI
650 lda #>ScreenFineScrollDLI
651 write_vdslst:
652 stx vdslst
653 sta vdslst+1
654 rts
655 .endif
656
657 ;--------------------------------------------------------
658 F574 write_with_zp_address:
659 F574 91 70 C8 sta (rowac),y+
660 F577 B5 00 lda 0,x
661 F579 91 70 C8 sta (rowac),y+
662 F57C B5 01 lda 1,x
663 F57E A2 01 ldx #1
664 F580 D0 EB bne write_repeat ;!! - unconditional
665
666 F582 try_clear:
667 F582 24 68 bit frmadr
668 F584 30 ED bmi no_clear
669 F586 4C 17 F8 jmp ScreenClear
670
671 ;--------------------------------------------------------
672 F589 standard_colors:
673 F589 28 dta $28
674 F58A CA dta $ca
675 F58B 94 dta $94
676 F58C 46 dta $46
677 = F58D .def :ScreenBitposFlipTab
678 F58D 00 dta $00 ;!! - shared value between tables
679 F58E 01 dta $01
680 F58F 03 dta $03
681 F590 07 dta $07
682
683 .endp
684
685 ;==========================================================================
686 F591 .proc ScreenInit
687 F591 AD E6 02 85 6A mva memtop+1 ramtop
688
689 .ifdef _KERNEL_816
690 stz colrsh
691 .else
692 F596 A9 00 85 4F mva #0 colrsh
693 .endif
694
695 F59A A9 FE 85 4E mva #$FE drkmsk
696 F59E 60 rts
697 .endp
698
699 ;==========================================================================
700 ; Behavior in gr.0:
701 ; - Reading char advances to next position, but cursor is not moved
702 ; - Cursor is picked up ($A0)
703 ; - Wrapping from end goes to left margin on next row
704 ; - Cursor may be outside of horizontal margins
705 ; - Error 141 (cursor out of range) if out of range
706 ; - Cursor will wrap to out of range if at end of screen (no automatic
707 ; vertical wrap)
708 ; - Does NOT update OLDROW/OLDCOL
709 ;
710 F59F .proc ScreenGetByte
711 F59F 20 C7 F8 jsr ScreenCheckPosition
712 F5A2 30 3A bmi xit
713
714 ;compute addressing
715 F5A4 A4 54 ldy rowcrs
716 F5A6 20 42 F9 jsr ScreenComputeToAddrX0
717 F5A9 A5 55 lda colcrs
718 F5AB A6 57 ldx dindex
719 F5AD BC D2 F9 ldy ScreenEncodingTab,x
720 F5B0 59 8D F5 eor ScreenBitposFlipTab,y
721 F5B3 AA tax
722 F5B4 A5 56 lda colcrs+1
723 F5B6 20 8B F9 jsr ScreenSetupPixelAddr.phase2
724
725 ;retrieve byte containing pixel
726 F5B9 A4 6F ldy shfamt
727 F5BB B1 66 lda (toadr),y
728
729 ;shift down
730 F5BD 20 78 F9 jsr ScreenAlignPixel
731
732 ;convert from Internal to ATASCII - must be done before we mask
733 ;Internal ATASCII
734 ;00-1F 20-3F
735 ;20-3F 40-5F
736 ;40-5F 00-1F
737 ;60-7F 60-7F
738 F5C0 0A asl
739 F5C1 08 php
740 F5C2 10 02 49 40 spl:eor #$40 ;00>20, 20>40, 40>60, 60>40
741 F5C6 69 40 adc #$40 ;00>20, 20>40, 40>00, 60>60
742 F5C8 28 plp
743 F5C9 6A ror
744
745 ;mask using right-justified pixel mask for mode
746 F5CA A6 57 ldx dindex
747 F5CC BC D2 F9 ldy ScreenEncodingTab,x
748 F5CF 39 E2 F9 and ScreenPixelMasks,y
749
750 ;advance to next position
751 F5D2 A6 57 ldx dindex
752 F5D4 F0 03 beq mode0
753 F5D6 4C A3 F9 jmp ScreenAdvancePosNonMode0
754 F5D9 mode0:
755 F5D9 20 D6 FD jsr ScreenAdvancePosMode0
756 F5DC A0 01 ldy #1
757 F5DE xit:
758 F5DE 60 rts
759 .endp
760
761 ;==========================================================================
762 ; Common behavior:
763 ; - Output is suspended if SSFLAG is set for non-clear and non-EOL chars
764 ; - Clear screen ($7D) and EOL ($9B) are always handled
765 ; - ESCFLG and DSPFLG are ignored (they are E: features)
766 ;
767 ; Behavior in gr.0:
768 ; - Logical lines are extended
769 ; - Scrolling occurs if bottom is hit
770 ; - Control chars other than clear and EOL are NOT handled by S:
771 ; - ROWCRS or COLCRS out of range results in an error.
772 ; - COLCRS in left margin is ignored and prints within margin.
773 ; - COLCRS in right margin prints one char and then does EOL.
774 ; - Previous cursor is not erased by S:, regardless of CRSINH state
775 ; - New cursor is drawn if CRSINH=0
776 ;
777 ; Behavior in gr.1+:
778 ; - No cursor is displayed
779 ; - LMARGN/RMARGN are ignored
780 ; - Cursor wraps from right side to next line
781 ; - ROWCRS may be below split screen boundary as long as it is within the
782 ; full screen size.
783 ;
784 F5DF .proc ScreenPutByte
785 F5DF 8D FB 02 sta atachr
786 F5E2 20 C7 F8 jsr ScreenCheckPosition
787 F5E5 30 0C bmi error
788
789 ;check for screen clear
790 F5E7 AD FB 02 lda atachr
791 F5EA C9 7D cmp #$7d
792 F5EC D0 0E bne not_clear_2
793 F5EE 20 17 F8 jsr ScreenClear
794 F5F1 A0 01 ldy #1
795 F5F3 error:
796 F5F3 60 rts
797
798 F5F4 graphics_eol:
799 F5F4 4C BC F9 jmp ScreenAdvancePosNonMode0.graphics_eol
800
801 ;*** ENTRY POINT FROM EDITOR FOR ESC HANDLING ***
802 F5F7 not_clear:
803 F5F7 20 C7 F8 jsr ScreenCheckPosition
804 F5FA 30 F7 bmi error
805
806 F5FC not_clear_2:
807 ;set old position now (used by setup code for plot pixel)
808 F5FC 20 CC FD jsr ScreenSetLastPosition
809
810 ;restore char
811 F5FF AD FB 02 lda atachr
812
813 ;check if we're in gr.0
814 F602 A6 57 ldx dindex
815 F604 F0 1E beq mode_0
816
817 ;nope, we're in a graphics mode... that makes this easier.
818 ;check if it's an EOL
819 F606 C9 9B cmp #$9b
820 F608 F0 EA beq graphics_eol
821
822 ;check for display suspend (ctrl+1) and wait until it is cleared
823 F60A AE FF 02 D0 FB ldx:rne ssflag
824
825 ;fold the pixel, compute masks, and convert ATASCII to Internal
826 F60F 20 9B F6 jsr ScreenFoldColor
827 F612 48 pha
828
829 ;compute addressing and shift mask
830 F613 20 73 F9 jsr ScreenSetupPlotPixel
831
832 F616 68 pla
833 F617 A4 6F ldy shfamt
834 F619 51 66 eor (toadr),y
835 F61B 25 6E and bitmsk
836 F61D 51 66 eor (toadr),y
837 F61F 91 66 sta (toadr),y
838
839 ;advance cursor position and exit
840 F621 4C A3 F9 jmp ScreenAdvancePosNonMode0
841
842 F624 mode_0:
843 ;check for EOL, which bypasses the ESC check
844 F624 C9 9B cmp #$9b
845 F626 D0 18 bne not_eol
846
847 ;it's an EOL
848 F628 A5 52 lda lmargn
849 F62A 85 55 sta colcrs
850 F62C E6 54 inc rowcrs
851 F62E A5 54 lda rowcrs
852 F630 CD BF 02 cmp botscr
853 F633 90 08 bcc noywrap
854
855 ;We've gone over -- delete logical line 0 to make room.
856 ;Note that we need to set ROWCRS here first because the scroll may
857 ;delete more than one physical line.
858 F635 AE BF 02 ldx botscr
859 F638 86 54 stx rowcrs
860
861 F63A 20 BC FC jsr EditorDeleteLine0
862 F63D noywrap:
863 F63D 4C 82 F6 jmp recompute_show_cursor_exit
864
865 F640 not_eol:
866 ;check for display suspend (ctrl+1) and wait until it is cleared
867 F640 AE FF 02 D0 FB ldx:rne ssflag
868
869 F645 48 pha
870 F646 20 B0 FC jsr EditorRecomputeCursorAddr
871 F649 68 pla
872 F64A 20 B8 F6 jsr ScreenConvertATASCIIToInternal
873
874 ;plot character
875 F64D A0 00 ldy #0
876 F64F 91 5E sta (oldadr),y
877
878 ;inc pos
879 F651 E6 5E D0 02 E6 5F inw oldadr
880 F657 20 D6 FD jsr ScreenAdvancePosMode0
881
882 ;check if we've gone beyond the right margin
883 F65A B0 29 bcs nowrap
884
885 ;check if we're beyond the bottom of the screen
886 F65C A5 54 lda rowcrs
887 F65E CD BF 02 cmp botscr
888 F661 90 12 bcc no_scroll
889
890 ;yes -- scroll up
891 F663 20 BC FC jsr EditorDeleteLine0
892
893 ;check if we can extend the current logical line -- 3 rows max.
894 F666 20 88 F6 jsr check_extend
895
896 ;Mark the current physical line as part of the last logical line.
897 ;
898 ;NOTE: There is a subtlety here in that we may delete multiple physical
899 ; lines if the top logical line is more than one line long, but we
900 ; only want to add one physical line onto our current logical line.
901 F669 20 34 FD jsr EditorGetCurLogicalLineInfo
902 F66C 59 B2 02 eor logmap,y
903 F66F 99 B2 02 sta logmap,y
904
905 F672 4C 82 F6 jmp post_scroll
906
907 F675 no_scroll:
908 ;check if we can extend the current logical line -- 3 rows max.
909 F675 20 88 F6 jsr check_extend
910
911 ;okay, here's the fun part -- we didn't scroll beyond, but we might
912 ;be on another logical line, in which case we need to scroll everything
913 ;down to extend it.
914 F678 A5 54 lda rowcrs
915 F67A 20 43 FD jsr EditorTestLogicalLineBit
916 F67D F0 03 beq post_scroll
917
918 ;yup, insert a physical line
919 F67F 20 5A F8 jsr ScreenInsertPhysLine
920
921 F682 recompute_show_cursor_exit:
922 F682 post_scroll:
923 F682 20 B0 FC jsr EditorRecomputeCursorAddr
924 F685 nowrap:
925 F685 4C E5 FD jmp ScreenShowCursorAndXitOK
926
927 F688 check_extend:
928 F688 A6 54 ldx rowcrs
929 F68A CA dex
930 F68B 8A txa
931 F68C 20 4C FD jsr EditorPhysToLogicalRow
932
933 .ifdef _KERNEL_816
934 inc
935 inc
936 .else
937 F68F 18 clc
938 F690 69 02 adc #2
939 .endif
940
941 F692 C5 54 cmp rowcrs
942 F694 90 01 60 scc:rts
943 F697 68 pla
944 F698 68 pla
945 F699 90 E7 bcc post_scroll
946 .endp
947
948 ;==========================================================================
949 = E4C9 ScreenGetStatus = CIOExitSuccess
950
951 ;==========================================================================
952 ; Given a color byte, mask it off to the pertinent bits and reflect it
953 ; throughout a byte. The byte is converted from ATASCII to Internal
954 ; if the mode uses byte encoding.
955 ;
956 ; Entry:
957 ; A = color value
958 ;
959 ; Exit:
960 ; A = folded color byte
961 ; Y = encoding mode
962 ; DMASK = right-justified bit mask
963 ; DELTAC = left-justified bit mask
964 ;
965 ; Modified:
966 ; HOLD1, ADRESS
967 ;
968 F69B .proc ScreenFoldColor
969 F69B A6 57 ldx dindex
970 F69D BC D2 F9 ldy ScreenEncodingTab,x ;0 = 8-bit, 1 = 4-bit, 2 = 2-bit, 3 = 1-bit
971 F6A0 BE E6 F9 86 77 mvx ScreenPixelMasks+4,y deltac
972 F6A5 BE E2 F9 8E A0 02 mvx ScreenPixelMasks,y dmask
973 F6AB 30 0B bmi fold_byte
974 F6AD 2D A0 02 and dmask
975 F6B0 19 9F FD ora ScreenEncodingOffsetTable-1,y
976 F6B3 AA tax
977 F6B4 BD A3 FD lda ScreenEncodingTable,x
978 F6B7 60 rts
979
980 F6B8 fold_byte:
981 ;convert byte from ATASCII to Internal -- this is required for gr.1
982 ;and gr.2 to work correctly, and harmless for other modes
983
984 ;==========================================================================
985 ; Convert an ATASCII character to displayable INTERNAL format.
986 ;
987 ; Entry:
988 ; A = ATASCII char
989 ;
990 ; Exit:
991 ; A = INTERNAL char
992 ;
993 = F6B8 .def :ScreenConvertATASCIIToInternal
994 ;ATASCII Internal
995 ;00-1F 40-5F
996 ;20-3F 00-1F
997 ;40-5F 20-3F
998 ;60-7F 60-7F
999
1000 F6B8 0A asl
1001 F6B9 08 php
1002 F6BA E9 3F sbc #$3f ;00>60, 20>00, 40>20, 60>40
1003 F6BC 10 02 49 40 spl:eor #$40 ;00>40, 20>00, 40>20, 60>60
1004 F6C0 28 plp
1005 F6C1 6A ror
1006 F6C2 60 rts
1007 .endp
1008
1009
1010 ;==========================================================================
1011 F6C3 .proc ScreenSpecial
1012 F6C3 A5 22 lda iccomz
1013 F6C5 C9 11 cmp #$11
1014 F6C7 F0 05 beq ScreenDrawLineFill ;draw line
1015 F6C9 C9 12 cmp #$12
1016 F6CB F0 01 beq ScreenDrawLineFill ;fill
1017 F6CD 60 rts
1018 .endp
1019
1020 ;==========================================================================
1021 ;
1022 ; Inputs:
1023 ; COLCRS,ROWCRS = next point
1024 ; OLDCOL,OLDROW = previous point
1025 ; ATACHR = color/character to use
1026 ;
1027 ; Outputs:
1028 ; OLDCOL,OLDROW = next point
1029 ;
1030 ; Behavior:
1031 ; - In GR.0:
1032 ; - Cursor is not drawn, even with CRSINH=0
1033 ; - OLDADR is updated to ending location, but not OLDCHR. If CRSINH=0,
1034 ; this can lead to a subsequent E: write stomping the last line draw
1035 ; cell with the under-cursor char from the last time the cursor was
1036 ; drawn elsewhere.
1037 ;
1038 ; Some test cases:
1039 ; - Ryba Pila
1040 ; - SPACEWAY.BAS
1041 ; - Worm of Bemer
1042 ;
1043 ; The Bresenham algorithm we use (from Wikipedia):
1044 ; dx = |x2 - x1|
1045 ; dy = |y2 - y1|
1046 ; e = dx - dy
1047 ;
1048 ; loop
1049 ; plot(x1, y1)
1050 ; if x1 == x2 and y1 == y2 then exit
1051 ; e2 = 2*e
1052 ; if e2 + dy > 0 then
1053 ; err = err - dy
1054 ; x0 = x0 + sign(dx)
1055 ; endif
1056 ; if e2 < dx then
1057 ; err = err + dx
1058 ; y0 = y0 + sign(dy)
1059 ; endif
1060 ; end
1061 ;
1062 F6CE .proc ScreenDrawLineFill
1063 ;;##TRACE "Drawing line (%d,%d)-(%d,%d) in mode %d" dw(oldcol) db(oldrow) dw(colcrs) db(rowcrs) db(dindex)
1064
1065 ;initialize bit mask and repeat pertinent pixel bits throughout byte
1066 F6CE AD FD 02 lda fildat
1067 F6D1 20 9B F6 jsr ScreenFoldColor
1068 F6D4 8D BC 02 sta hold4
1069 F6D7 AD FB 02 lda atachr
1070 F6DA 20 9B F6 jsr ScreenFoldColor
1071 F6DD 85 51 sta hold1
1072
1073 F6DF 20 73 F9 jsr ScreenSetupPlotPixel
1074
1075 ;compute screen pitch
1076 F6E2 A0 01 ldy #1
1077 F6E4 20 4C F9 jsr ScreenComputeRangeSize
1078 F6E7 85 78 sta deltac+1
1079 F6E9 AA tax
1080 F6EA A0 00 ldy #0
1081
1082 ;compute abs(dy) and sign(dy)
1083 F6EC A5 54 lda rowcrs
1084 F6EE 38 E5 5A sub oldrow
1085 F6F1 B0 0C bcs going_down
1086 F6F3 49 FF eor #$ff ;take abs(dy)
1087 F6F5 69 01 adc #1 ;
1088 ;negate screen pitch
1089 F6F7 48 pha
1090 F6F8 8A txa
1091 F6F9 49 FF eor #$ff
1092 F6FB AA tax
1093 F6FC E8 inx
1094 F6FD 88 dey
1095 F6FE 68 pla
1096 F6FF going_down:
1097 F6FF 86 70 stx rowac
1098 F701 85 76 sta deltar
1099 F703 84 71 sty rowac+1
1100
1101 ;;##TRACE "dy = %d" db(deltar)
1102
1103 ;compute abs(dx) and sign(dx)
1104 F705 A2 00 ldx #0
1105 F707 A5 55 lda colcrs
1106 F709 38 E5 5B sub oldcol
1107 F70C 85 72 sta colac
1108 F70E A5 56 lda colcrs+1
1109 F710 E5 5C sbc oldcol+1
1110 F712 B0 10 bcs going_right
1111 F714 49 FF eor #$ff
1112 F716 A8 tay
1113 F717 A5 72 lda colac
1114 F719 49 FF eor #$ff
1115 F71B 69 01 adc #1
1116 F71D 85 72 sta colac
1117 F71F 98 tya
1118 F720 69 00 adc #0
1119 F722 A2 CC ldx #left_shift_8-right_shift_8
1120 F724 going_right:
1121 F724 85 73 sta colac+1
1122
1123 ;;##TRACE "dx = %d" dw(colac)
1124
1125 ;set up x shift routine
1126 F726 8A txa
1127 F727 A6 57 ldx dindex
1128 F729 BC D2 F9 ldy ScreenEncodingTab,x
1129 F72C 18 clc
1130 F72D 79 7A F7 adc shift_lo_tab,y
1131 F730 85 64 sta adress
1132 F732 A9 F7 lda #>left_shift_8
1133 F734 85 65 sta adress+1
1134 F736 85 75 sta endpt+1
1135
1136 ;set up x fill shift routine
1137 F738 B9 7A F7 lda shift_lo_tab,y
1138 F73B 18 clc
1139 F73C 69 D9 adc #fill_right_8-right_shift_8
1140 F73E 85 74 sta endpt
1141
1142 ;compute initial error accumulator in frmadr (dx-dy)
1143 F740 A6 72 ldx colac
1144 F742 8A txa
1145 F743 38 E5 76 sub deltar
1146 F746 85 68 sta frmadr
1147 F748 A4 73 ldy colac+1 ;leave dx in y:x for max() below
1148 F74A 98 tya
1149 F74B E9 00 sbc #0
1150 F74D 85 69 sta frmadr+1
1151
1152 ;compute max(dx, dy) based on sign of (dx - dy)
1153 F74F B0 04 bcs dx_larger
1154 F751 A0 00 ldy #0
1155 F753 A6 76 ldx deltar
1156 F755 dx_larger:
1157 F755 86 7E stx countr
1158 F757 84 7F sty countr+1
1159
1160 F759 98 tya
1161 F75A D0 03 bne not_empty
1162 F75C 8A txa
1163 F75D F0 0D beq skip_showcursor
1164 F75F not_empty:
1165
1166 ;;##TRACE "Pixel count = %d" dw(countr)
1167
1168 ;enter pixel loop (this will do a decrement for us)
1169 F75F 4C CF F7 jmp next_pixel
1170
1171 ;----------------------------------------------
1172 F762 done:
1173 F762 20 CC FD jsr ScreenSetLastPosition
1174
1175 ;RYBA PILA requires the quirky behavior of the last character of a non-zero length
1176 ;DRAWTO being stomped by the character saved from the cursor draw of the last PLOT
1177 ;(write to S:). Note that we must NOT do this for length 0 or it breaks SPACEWAY.
1178 F765 A4 57 ldy dindex
1179 F767 D0 03 bne skip_showcursor
1180 F769 20 B0 FC jsr EditorRecomputeCursorAddr
1181 F76C skip_showcursor:
1182 F76C A0 01 ldy #1
1183 F76E 60 rts
1184
1185 ;----------------------------------------------
1186 F76F fill_done:
1187 F76F 86 6E stx bitmsk
1188 F771 4C CF F7 jmp next_pixel
1189
1190 ;----------------------------------------------
1191 F774 do_fill:
1192 F774 A4 6F ldy shfamt ;load current byte offset
1193 F776 A6 6E ldx bitmsk ;save current bitmask
1194 F778 D0 33 bne fill_start ;!! - unconditional
1195
1196 ;----------------------------------------------
1197 F77A shift_lo_tab:
1198 F77A B8 dta <right_shift_8
1199 F77B B2 dta <right_shift_4
1200 F77C B4 dta <right_shift_2
1201 F77D B5 dta <right_shift_1
1202
1203 ;----------------------------------------------
1204 F77E left_shift_4:
1205 F77E 0A asl
1206 F77F 0A asl
1207 F780 left_shift_2:
1208 F780 0A asl
1209 F781 left_shift_1:
1210 F781 0A asl
1211 F782 90 05 bcc left_shift_ok
1212 F784 left_shift_8:
1213 F784 C6 6F dec shfamt
1214 F786 AD A0 02 lda dmask
1215 F789 left_shift_ok:
1216 F789 D0 31 bne post_xinc ;!! - unconditional
1217
1218 ;----------------------------------------------
1219 F78B fill_right_4:
1220 F78B 4A lsr
1221 F78C 4A lsr
1222 F78D fill_right_2:
1223 F78D 4A lsr
1224 F78E fill_right_1:
1225 F78E 4A lsr
1226 F78F 90 09 bcc fill_right_ok
1227 F791 fill_right_8:
1228 F791 A5 77 lda deltac
1229 F793 C8 iny
1230 F794 C4 78 cpy deltac+1
1231 F796 90 02 A0 00 scc:ldy #0
1232 F79A fill_right_ok:
1233 F79A 85 6E sta bitmsk
1234 F79C F0 D1 beq fill_done
1235 F79E fill_loop:
1236 F79E B1 66 lda (toadr),y ;load screen byte
1237 F7A0 24 6E bit bitmsk ;mask to current pixel
1238 F7A2 D0 CB bne fill_done ;exit loop if non-zero
1239 F7A4 4D BC 02 eor hold4 ;XOR with fill color
1240 F7A7 25 6E and bitmsk ;mask change bits to current pixel
1241 F7A9 51 66 eor (toadr),y ;merge with screen byte
1242 F7AB 91 66 sta (toadr),y ;save screen byte
1243 F7AD fill_start:
1244 F7AD A5 6E lda bitmsk
1245 F7AF 6C 74 00 jmp (endpt)
1246
1247 ;----------------------------------------------
1248 F7B2 right_shift_4:
1249 F7B2 4A lsr
1250 F7B3 4A lsr
1251 F7B4 right_shift_2:
1252 F7B4 4A lsr
1253 F7B5 right_shift_1:
1254 F7B5 4A lsr
1255 F7B6 90 04 bcc right_shift_ok
1256 F7B8 right_shift_8:
1257 F7B8 E6 6F inc shfamt
1258 F7BA A5 77 lda deltac
1259 F7BC right_shift_ok:
1260 ;fall through to post_xinc
1261 F7BC post_xinc:
1262 F7BC 85 6E sta bitmsk
1263 F7BE no_xinc:
1264
1265 ;plot pixel
1266 ;;##TRACE "Plotting at $%04X+%d with mask $%02X" dw(toadr) db(shfamt) db(bitmsk)
1267 F7BE A4 6F ldy shfamt
1268 F7C0 A5 51 lda hold1
1269 F7C2 51 66 eor (toadr),y
1270 F7C4 25 6E and bitmsk
1271 F7C6 51 66 eor (toadr),y
1272 F7C8 91 66 sta (toadr),y
1273
1274 ;do fill if needed
1275 F7CA A5 22 lda iccomz
1276 F7CC 4A lsr
1277 F7CD 90 A5 bcc do_fill
1278
1279 F7CF next_pixel:
1280 ;loop back for next pixel
1281 F7CF A5 7E lda countr
1282 F7D1 D0 04 bne next_pixel_2
1283 F7D3 C6 7F dec countr+1
1284 F7D5 30 8B bmi done
1285 F7D7 next_pixel_2:
1286 F7D7 C6 7E dec countr
1287
1288 ;!! - fall through to pixel loop
1289
1290 ;------- pixel loop state -------
1291 ; (zp) frmadr error accumulator
1292 ; (zp) toadr current row address
1293 ; (abs) dmask right-justified bit mask
1294 ; (zp) deltac left-justified bit mask
1295 ; (zp) bitmsk current bit mask
1296 ; (zp) shfamt current byte offset within row
1297 ; (zp) rowac y step address increment/decrement (note different from Atari OS)
1298 ; (zp) adress left/right shift routine
1299 ; (zp) deltac+1 screen pitch, in bytes (for fill)
1300 ; (zp) endpt right shift routine
1301 ; (zp) colac dy
1302 F7D9 pixel_loop:
1303 ;compute 2*err
1304 ;;##TRACE "Error accum = %d (dx=%d, dy=%d(%d))" dsw(frmadr) dw(colac) db(deltar) dsw(rowac)
1305 F7D9 A5 68 lda frmadr
1306 F7DB 0A asl
1307 F7DC A8 tay
1308 F7DD A5 69 lda frmadr+1
1309 F7DF 2A rol
1310 F7E0 AA tax
1311
1312 ;check for y increment (2*e < dx, or A:Y < colac)
1313 F7E1 98 tya
1314 F7E2 18 clc
1315 F7E3 E5 72 sbc colac
1316 F7E5 8A txa
1317 F7E6 48 pha
1318 F7E7 E5 73 sbc colac+1
1319 F7E9 10 13 bpl no_yinc
1320
1321 F7EB do_yinc:
1322 ;bump y (add/subtract pitch, e += dx)
1323 F7EB A2 02 ldx #2
1324 F7ED yinc_loop:
1325 F7ED B5 70 lda rowac,x
1326 F7EF 18 clc
1327 F7F0 75 66 adc toadr,x
1328 F7F2 95 66 sta toadr,x
1329 F7F4 B5 71 lda rowac+1,x
1330 F7F6 75 67 adc toadr+1,x
1331 F7F8 95 67 sta toadr+1,x
1332 F7FA CA dex
1333 F7FB CA dex
1334 F7FC 10 EF bpl yinc_loop
1335 F7FE no_yinc:
1336
1337 ;check for x increment (2*e + dy > 0, or Y:[S] + deltar > 0)
1338 F7FE 98 tya
1339 F7FF 18 clc
1340 F800 65 76 adc deltar
1341 F802 68 pla
1342 F803 69 00 adc #0
1343 F805 30 B7 bmi no_xinc
1344
1345 ;update error accumulator
1346 F807 A5 68 lda frmadr
1347 F809 38 E5 76 sub deltar
1348 F80C 85 68 sta frmadr
1349 F80E B0 02 C6 69 scs:dec frmadr+1
1350
1351 ;bump x
1352 F812 A5 6E lda bitmsk
1353 F814 6C 64 00 jmp (adress)
1354
1355 .if [right_shift_4 ^ right_shift_8]&$ff00
1356 .error "Right draw routines cross page: ",right_shift_4,"-",right_shift_8
1357 .endif
1358 .if [left_shift_4 ^ left_shift_8]&$ff00
1359 .error "Left draw routines cross page: ",left_shift_4,"-",left_shift_8
1360 .endif
1361 .if [fill_right_4 ^ fill_right_8]&$ff00
1362 .error "Fill routines cross page: ",fill_right_4,"-",fill_right_8
1363 .endif
1364 .if [[right_shift_4^left_shift_4]|[left_shift_4^fill_right_4]]&$ff00
1365 .error "Line/fill routines cross page: ",left_shift_4,',',right_shift_4,',',fill_right_4
1366 .endif
1367
1368 .endp
1369
1370 ;==========================================================================
1371 ; Clear the screen.
1372 ;
1373 ; Used:
1374 ; ADRESS
1375 ; TOADR
1376 ;
1377 ; Quirks:
1378 ; Clears the split-screen text area even if the main screen (S:) receives
1379 ; the clear. The In-Store Demonstration Cart depends on this. The cursor
1380 ; state of the split screen is NOT reset, so if the cursor was over a
1381 ; non-blank character, that character will be restored when the cursor
1382 ; moves.
1383 ;
1384 ; The logical line map is always reset.
1385 ;
1386 F817 .proc ScreenClear
1387 ;first, set up for clearing the split-screen window (4*40 bytes main)
1388 F817 A0 04 ldy #4
1389
1390 ;check if we are in the split screen text window
1391 F819 A6 7B ldx swpflg
1392 F81B D0 08 bne is_text_window
1393
1394 ;nope, it's the main screen... compute size
1395 F81D A4 57 ldy dindex
1396 F81F BE 26 FE ldx ScreenHeightShifts,y
1397 F822 BC 36 FE ldy ScreenHeights,x
1398 F825 is_text_window:
1399 F825 20 4C F9 jsr ScreenComputeRangeSize
1400
1401 ;add 160 bytes to size if not GR.0 -- important to avoid clearing
1402 ;beyond GR.0 screen (the font breaks in BIKERDAV.BAS otherwise!)
1403 F828 18 clc
1404 F829 A6 57 ldx dindex
1405 F82B F0 02 beq is_gr0
1406 F82D 69 A0 adc #160
1407 F82F is_gr0:
1408 F82F A8 tay
1409 F830 A5 65 lda adress+1
1410 F832 69 00 adc #0
1411
1412 F834 AA tax
1413 F835 65 59 adc savmsc+1
1414 F837 85 67 sta toadr+1
1415 F839 A5 58 85 66 mva savmsc toadr
1416
1417 ;As it turns out, there are no cases where the main screen
1418 ;is an exact number of pages... so we can simply plow into
1419 ;the clear loop.
1420 F83D A9 00 lda #0
1421 F83F loop:
1422 F83F 88 dey
1423 F840 91 66 sta (toadr),y
1424 F842 D0 FB bne loop
1425 F844 C6 67 dec toadr+1
1426 F846 CA dex
1427 F847 10 F6 bpl loop
1428
1429 ;reset coordinates and cursor (we're going to wipe the cursor)
1430 F849 85 56 sta colcrs+1
1431 F84B 85 54 sta rowcrs
1432 F84D 85 5D sta oldchr
1433
1434 ;always reset the logical line map
1435 F84F A6 57 ldx dindex
1436 F851 D0 02 bne is_graphic_screen
1437 F853 A5 52 lda lmargn
1438 F855 is_graphic_screen:
1439 F855 85 55 sta colcrs
1440
1441 ;always reset the logical line map and exit
1442 F857 4C B9 FD jmp ScreenResetLogicalLineMap
1443 .endp
1444
1445 ;==========================================================================
1446 ; Insert a physical line at the current location.
1447 ;
1448 ; Entry:
1449 ; ROWCRS = row before which to insert new line
1450 ; C = 0 if physical line only, C = 1 if should start new logical line
1451 ;
1452 ; Modified:
1453 ; HOLD1, ADRESS
1454 ;
1455 = F85B ScreenInsertLine = ScreenInsertPhysLine.use_c
1456 F85A .proc ScreenInsertPhysLine
1457 F85A 18 clc
1458 F85B use_c:
1459 ;save new logline flag
1460 F85B 08 php
1461
1462 ;compute addresses
1463 F85C AC BF 02 ldy botscr
1464 F85F 88 dey
1465 F860 20 42 F9 jsr ScreenComputeToAddrX0
1466 F863 20 8A FD jsr EditorNextLineAddr
1467
1468 ;copy lines
1469 F866 AE BF 02 ldx botscr
1470 F869 D0 09 bne line_loop_start
1471 F86B line_loop:
1472 F86B A0 27 ldy #39
1473 F86D char_loop:
1474 F86D B1 68 lda (frmadr),y
1475 F86F 91 66 sta (toadr),y
1476 F871 88 dey
1477 F872 10 F9 bpl char_loop
1478 F874 line_loop_start:
1479 F874 A5 68 lda frmadr
1480 F876 85 66 sta toadr
1481 F878 38 sec
1482 F879 E9 28 sbc #40
1483 F87B 85 68 sta frmadr
1484 F87D A5 69 lda frmadr+1
1485 F87F 85 67 sta toadr+1
1486 F881 E9 00 sbc #0
1487 F883 85 69 sta frmadr+1
1488
1489 F885 CA dex
1490 F886 E4 54 cpx rowcrs
1491 F888 D0 E1 bne line_loop
1492
1493 F88A no_copy:
1494 ;clear the current line
1495 F88A A0 27 ldy #39
1496 F88C A9 00 lda #0
1497 F88E clear_loop:
1498 F88E 91 66 sta (toadr),y
1499 F890 88 dey
1500 F891 10 FB bpl clear_loop
1501
1502 ;insert bit into logical line mask
1503 F893 20 34 FD jsr EditorGetCurLogicalLineInfo
1504
1505 F896 28 plp
1506 F897 B0 02 A9 00 scs:lda #0
1507 F89B 85 51 sta hold1
1508
1509 F89D A9 00 lda #0
1510 F89F 38 sec
1511 F8A0 FD C1 E4 sbc ReversedBitMasks,x ;-bit
1512 F8A3 0A asl
1513 F8A4 39 B2 02 and logmap,y
1514 F8A7 18 clc
1515 F8A8 79 B2 02 adc logmap,y
1516 F8AB 6A ror
1517 F8AC 05 51 ora hold1
1518 F8AE 99 B2 02 sta logmap,y
1519
1520 F8B1 88 dey
1521 F8B2 10 03 6E B3 02 spl:ror logmap+1
1522 F8B7 88 dey
1523 F8B8 10 03 6E B4 02 spl:ror logmap+2
1524 F8BD 60 rts
1525 .endp
1526
1527 ;==========================================================================
1528 ; Hide the screen cursor, if it is present.
1529 ;
1530 ; Modified:
1531 ; Y
1532 ;
1533 ; Preserved:
1534 ; A
1535 ;
1536 F8BE .proc ScreenHideCursor
1537 ;erase the cursor
1538 F8BE 48 pha
1539 F8BF A0 00 ldy #0
1540 F8C1 A5 5D lda oldchr
1541 F8C3 91 5E sta (oldadr),y
1542 F8C5 68 pla
1543 F8C6 no_cursor:
1544 F8C6 60 rts
1545 .endp
1546
1547 ;==========================================================================
1548 F8C7 .proc ScreenCheckPosition
1549 ;Check for ROWCRS out of range. Note that for split screen modes we still
1550 ;check against the full height!
1551 F8C7 AD BF 02 lda botscr
1552 F8CA A6 57 ldx dindex
1553 F8CC F0 06 beq rowcheck_gr0
1554 F8CE BC 26 FE ldy ScreenHeightShifts,x
1555 F8D1 B9 36 FE lda ScreenHeights,y
1556 F8D4 rowcheck_gr0:
1557 ;while we know it's GR.0, clamp RMARGN to 39 (required for ARTILLERY.BAS)
1558 F8D4 A0 27 ldy #39
1559 F8D6 C4 53 cpy rmargn
1560 F8D8 B0 02 bcs rmargn_ok
1561 F8DA 84 53 sty rmargn
1562 F8DC rmargn_ok:
1563 F8DC 18 clc
1564 F8DD E5 54 sbc rowcrs
1565 F8DF B0 0E bcs rowcheck_pass
1566 F8E1 invalid_position:
1567
1568 ;If the cursor is out of range, reset it within bounds.
1569 F8E1 A0 00 ldy #0
1570 F8E3 84 56 sty colcrs+1 ;X high = 0
1571 F8E5 8A txa
1572 F8E6 D0 02 A4 52 sne:ldy lmargn
1573 F8EA 84 55 sty colcrs ;X low = X origin
1574
1575 F8EC A0 8D ldy #CIOStatCursorRange
1576 F8EE 60 rts
1577
1578 F8EF rowcheck_pass:
1579 ;check width
1580 F8EF BC 3B FE ldy ScreenPixelWidthIds,x
1581 F8F2 A5 55 lda colcrs
1582 F8F4 D9 C8 F9 cmp ScreenPixelWidthsLo,y
1583 F8F7 A5 56 lda colcrs+1
1584 F8F9 F9 CD F9 sbc ScreenPixelWidthsHi,y
1585 F8FC B0 E3 bcs invalid_position
1586
1587 ;check for BREAK
1588 F8FE A0 FF ldy #$ff
1589 F900 A5 11 lda brkkey
1590 F902 D0 04 bne no_break
1591 F904 84 11 sty brkkey
1592 F906 A0 7F ldy #CIOStatBreak-1
1593 F908 no_break:
1594 F908 C8 iny
1595 F909 60 rts
1596 .endp
1597
1598 ;==========================================================================
1599 ; Swap between the main screen and the split screen.
1600 ;
1601 ; Conventionally, the main screen is left as the selected context when
1602 ; the display handler is not active.
1603 ;
1604 ; Inputs:
1605 ; C = 0 for main screen
1606 ; C = 1 for split screen
1607 ;
1608 ; Modified:
1609 ; X
1610 ;
1611 ; Preserved:
1612 ; A
1613 ;
1614 ;==========================================================================
1615 ; Swap in the text screen (main if gr.0, split otherwise).
1616 ;
1617 F90A .proc EditorSwapToText
1618 ;set C=0 (main) if gr.0, C=1 (split) otherwise
1619 F90A A0 17 ldy #23
1620 F90C CC BF 02 cpy botscr
1621
1622 = F90F .def :ScreenSwap = *
1623 ;check if the correct set is in place
1624 F90F 48 pha
1625 F910 A9 00 lda #0
1626 F912 65 7B adc swpflg
1627 F914 F0 14 beq already_there
1628
1629 ;Nope, we need to swap. Conveniently, the data to be swapped
1630 ;is in a 12 byte block:
1631 ;
1632 ; ROWCRS ($0054) TXTROW ($0290)
1633 ; COLCRS ($0055) TXTCOL ($0291)
1634 ; DINDEX ($0057) TINDEX ($0293)
1635 ; SAVMSC ($0058) TXTMSC ($0294)
1636 ; OLDROW ($005A) TXTOLD ($0296)
1637 ; OLDCOL ($005B) TXTOLD ($0297)
1638 ; OLDCHR ($005D) TXTOLD ($0299)
1639 ; OLDADR ($005E) TXTOLD ($029A)
1640
1641 F916 A2 0B ldx #11
1642 F918 swap_loop:
1643 F918 B5 54 lda rowcrs,x
1644 F91A BC 90 02 ldy txtrow,x
1645 F91D 94 54 sty rowcrs,x
1646 F91F 9D 90 02 sta txtrow,x
1647 F922 CA dex
1648 F923 10 F3 bpl swap_loop
1649
1650 ;invert swap flag
1651 F925 8A txa
1652 F926 45 7B eor swpflg
1653 F928 85 7B sta swpflg
1654
1655 F92A already_there:
1656 F92A 68 pla
1657 F92B 60 rts
1658 .endp
1659
1660 ;==========================================================================
1661 ; Compute character address.
1662 ;
1663 ; Entry:
1664 ; X = byte index
1665 ; Y = line index
1666 ;
1667 ; Exit:
1668 ; A:X = address
1669 ;
1670 ; Used:
1671 ; ADRESS
1672 ;
1673 F92C .proc ScreenComputeAddr
1674 F92C 20 4C F9 jsr ScreenComputeRangeSize
1675 F92F 85 64 sta adress
1676 F931 8A txa
1677 F932 18 clc
1678 F933 65 64 adc adress ;row*10,20,40+col
1679 F935 90 02 E6 65 scc:inc adress+1
1680 F939 18 clc
1681 F93A 65 58 adc savmsc
1682 F93C AA tax
1683 F93D A5 65 lda adress+1
1684 F93F 65 59 adc savmsc+1
1685 F941 60 rts
1686 .endp
1687
1688 ;==========================================================================
1689 = F944 ScreenComputeToAddr = ScreenComputeToAddrX0.with_x
1690 F942 .proc ScreenComputeToAddrX0
1691 F942 A2 00 ldx #0
1692 F944 with_x:
1693 F944 20 2C F9 jsr ScreenComputeAddr
1694 F947 86 66 stx toadr
1695 F949 85 67 sta toadr+1
1696 F94B 60 rts
1697 .endp
1698
1699 ;==========================================================================
1700 ; Compute size, in bytes, of a series of lines.
1701 ;
1702 ; Entry:
1703 ; Y = line count
1704 ;
1705 ; Exit:
1706 ; ADRESS+1 High byte of size
1707 ; A Low byte of size
1708 ;
1709 ; Preserved:
1710 ; X
1711 ;
1712 ; Modified:
1713 ; Y
1714 ;
1715 F94C .proc ScreenComputeRangeSize
1716 F94C A9 00 85 65 mva #0 adress+1
1717 F950 84 64 sty adress
1718 F952 A4 57 ldy dindex
1719 F954 B9 3B FE lda ScreenPixelWidthIds,y
1720 F957 38 sec
1721 F958 F9 D2 F9 sbc ScreenEncodingTab,y
1722 F95B A8 tay
1723 F95C C8 iny
1724 F95D A5 64 lda adress
1725 F95F 0A asl
1726 F960 26 65 rol adress+1 ;row*2
1727 F962 0A asl
1728 F963 26 65 rol adress+1 ;row*4
1729 F965 18 clc
1730 F966 65 64 adc adress ;row*5
1731 F968 90 02 E6 65 scc:inc adress+1
1732 F96C shift_loop:
1733 F96C 0A asl
1734 F96D 26 65 rol adress+1 ;row*10,20,40
1735 F96F 88 dey
1736 F970 10 FA bpl shift_loop
1737 F972 60 rts
1738 .endp
1739
1740 ;==========================================================================
1741 ; Setup for pixel plot.
1742 ;
1743 ; Entry:
1744 ; OLDCOL, OLDROW = position
1745 ; DELTAC = left-justified pixel mask
1746 ;
1747 ; Exit:
1748 ; TOADR = screen row
1749 ; SHFAMT = byte offset within row
1750 ; BITMSK = shifted bit mask for pixel
1751 ;
1752 ; Modified:
1753 ; ADRESS
1754 ;
1755 = F978 ScreenAlignPixel = ScreenSetupPlotPixel.rshift_mask
1756 F973 .proc ScreenSetupPlotPixel
1757 ;;##TRACE "Folded pixel = $%02X" db(hold1)
1758 F973 20 82 F9 jsr ScreenSetupPixelAddr
1759
1760 ;preshift bit mask
1761 F976 A5 77 lda deltac
1762 F978 rshift_mask:
1763 F978 CA dex
1764 F979 30 04 bmi xmaskshift_done
1765 F97B xmaskshift_loop:
1766 F97B 4A lsr
1767 F97C CA dex
1768 F97D 10 FC bpl xmaskshift_loop
1769 F97F xmaskshift_done:
1770 F97F 85 6E sta bitmsk
1771
1772 ;;##TRACE "Initial bitmasks = $%02X $%02X" db(bitmsk) db(dmask)
1773 F981 60 rts
1774 .endp
1775
1776 ;==========================================================================
1777 ; Setup for pixel addressing.
1778 ;
1779 ; Entry:
1780 ; COLCRS, ROWCRS = position (ScreenSetupPixelAddr)
1781 ; OLDCOL, OLDROW = position (ScreenSetupPixelAddrOld)
1782 ;
1783 ; Exit:
1784 ; TOADR = screen row
1785 ; SHFAMT = byte offset within row
1786 ; X = number of bits from left side of byte to left side of pixel
1787 ;
1788 F982 .proc ScreenSetupPixelAddr
1789 ;compute initial address
1790 F982 A4 5A ldy oldrow
1791 F984 20 42 F9 jsr ScreenComputeToAddrX0
1792
1793 ;;##TRACE "Initial row address = $%04X" dw(toadr)
1794
1795 ;compute initial byte offset
1796 F987 A5 5C lda oldcol+1
1797 F989 A6 5B ldx oldcol
1798 F98B phase2:
1799 F98B 6A ror
1800 F98C 86 6F stx shfamt
1801 F98E A9 00 lda #0
1802 F990 A6 57 ldx dindex
1803 F992 BC D2 F9 ldy ScreenEncodingTab,x
1804 F995 F0 06 beq no_xshift
1805 F997 xshift_loop:
1806 F997 66 6F ror shfamt
1807 F999 6A ror
1808 F99A 88 dey
1809 F99B D0 FA bne xshift_loop
1810 F99D no_xshift:
1811 F99D 2A rol
1812 F99E 2A rol
1813 F99F 2A rol
1814 F9A0 2A rol
1815 F9A1 AA tax
1816
1817 ;;##TRACE "Initial row offset = $%02X" db(shfamt)
1818 F9A2 60 rts
1819 .endp
1820
1821 ;==========================================================================
1822 ; ScreenAdvancePosNonMode0
1823 ;
1824 F9A3 .proc ScreenAdvancePosNonMode0
1825 ;advance position
1826 F9A3 E6 55 inc colcrs
1827 F9A5 D0 02 E6 56 sne:inc colcrs+1
1828 F9A9 A6 57 ldx dindex
1829 F9AB BC 3B FE ldy ScreenPixelWidthIds,x
1830 F9AE BE CD F9 ldx ScreenPixelWidthsHi,y
1831 F9B1 E4 56 cpx colcrs+1
1832 F9B3 D0 0F bne graphics_no_wrap
1833 F9B5 BE C8 F9 ldx ScreenPixelWidthsLo,y
1834 F9B8 E4 55 cpx colcrs
1835 F9BA D0 08 bne graphics_no_wrap
1836
1837 F9BC graphics_eol:
1838 ;move to left side and then one row down -- note that this may
1839 ;push us into an invalid coordinate, which will result on an error
1840 ;on the next call if not corrected
1841 F9BC A0 00 ldy #0
1842 F9BE 84 55 sty colcrs
1843 F9C0 84 56 sty colcrs+1
1844 F9C2 E6 54 inc rowcrs
1845 F9C4 graphics_no_wrap:
1846 F9C4 A0 01 ldy #1
1847 F9C6 60 rts
1848 .endp
1849
1850 ;==========================================================================
1851 .if !_KERNEL_XLXE
1852 F9C7 _SCREEN_TABLES_1
Macro: _SCREEN_TABLES_1 [Source: source/Shared/screen.s]
3 F9C7 0A dta <10
4 F9C8 14 dta <20
5 F9C9 28 dta <40
6 F9CA 50 dta <80
7 F9CB A0 dta <160
8 F9CC 40 dta <320
12 F9CD 00 dta >20
13 F9CE 00 dta >40
14 F9CF 00 dta >80
15 F9D0 00 dta >160
16 F9D1 01 dta >320
20 F9D2 00 dta 0 ;gr.0 direct bytes
21 F9D3 00 dta 0 ;gr.1 direct bytes
22 F9D4 00 dta 0 ;gr.2 direct bytes
23 F9D5 02 dta 2 ;gr.3 two bits per pixel
24 F9D6 03 dta 3 ;gr.4 one bit per pixel
25 F9D7 02 dta 2 ;gr.5 two bits per pixel
26 F9D8 03 dta 3 ;gr.6 one bit per pixel
27 F9D9 02 dta 2 ;gr.7 two bits per pixel
28 F9DA 03 dta 3 ;gr.8 one bit per pixel
29 F9DB 01 dta 1 ;gr.9 four bits per pixel
30 F9DC 01 dta 1 ;gr.10 four bits per pixel
31 F9DD 01 dta 1 ;gr.11 four bits per pixel
32 F9DE 00 dta 0 ;gr.12 direct bytes
33 F9DF 00 dta 0 ;gr.13 direct bytes
34 F9E0 03 dta 3 ;gr.14 one bit per pixel
35 F9E1 02 dta 2 ;gr.15 two bits per pixel
39 F9E2 FF 0F 03 01 FF F0 + dta $ff, $0f, $03, $01, $ff, $f0, $c0, $80
Source: source/Shared/screen.s
1853 .endif
270 F9EA icl 'editor.s'
Source: source/Shared/editor.s
1 ; Altirra - Atari 800/800XL/5200 emulator
2 ; Modular Kernel ROM - Editor Handler
3 ; Copyright (C) 2008-2016 Avery Lee
4 ;
5 ; Copying and distribution of this file, with or without modification,
6 ; are permitted in any medium without royalty provided the copyright
7 ; notice and this notice are preserved. This file is offered as-is,
8 ; without any warranty.
9
10 ;==========================================================================
11 F9EA .proc EditorOpen
12 F9EA 20 B9 FD jsr ScreenResetLogicalLineMap
13 F9ED 8E FE 02 stx dspflg ;!! relies on X=0 from ScreenResetLogicalLineMap
14 F9F0 8E A2 02 stx escflg
15
16 ;we must force mode 0 here -- ACTION calls this with $0C in AUX2 and
17 ;expects mode 0 to be set
18 F9F3 4C F2 F3 jmp ScreenOpenMode0
19 .endp
20
21 ;==========================================================================
22 = E4C9 EditorClose = ScreenClose
23
24 ;==========================================================================
25 ;
26 ; === Forced read mode ===
27 ;
28 ; If bit 0 if AUX1 is set on the IOCB, it means to read in forced read
29 ; mode. In forced read mode, no keyboard input is fetched and instead
30 ; line read immediately commences, as if ENTER were pressed.
31 ;
32 ; Note that since AUX1 is tested on the IOCB used, it is possible to have
33 ; E: open on more than one IOCB with different forced read modes.
34 ;
35 F9F6 .proc EditorGetByte
36 ;check if we have anything left in the current line
37 F9F6 A5 6B lda bufcnt
38 F9F8 D0 06 bne have_line
39
40 ;nope, fetch a line
41 F9FA 20 16 FA jsr EditorGetLine
42 F9FD 10 01 bpl have_line
43 F9FF 60 rts
44
45 FA00 have_line:
46 ;swap to text context
47 FA00 20 0A F9 jsr EditorSwapToText
48
49 ;subtract off a char
50 FA03 C6 6B dec bufcnt
51
52 ;check if we're at the EOL
53 FA05 D0 09 bne have_char
54
55 ;yes, we're at the EOL -- print it and return it (this will re-enable
56 ;the cursor, too)
57 FA07 A9 9B lda #$9b
58 FA09 20 DF F5 jsr ScreenPutByte
59
60 FA0C A9 9B lda #$9b
61 FA0E D0 03 bne done
62
63 FA10 have_char:
64 ;read a char from the screen
65 FA10 20 9F F5 jsr ScreenGetByte
66 FA13 done:
67 FA13 4C 63 FD jmp EditorSwapToScreen
68 .endp
69
70 ;==========================================================================
71 ; This behavior is quite complex:
72 ; - The editor remembers the cursor position within the initial logical
73 ; line. Only contents beyond the initial position are returned. This
74 ; is true even if the cursor is moved out of the logical line and back
75 ; in again.
76 ; - Margins are not included.
77 ; - Trailing spaces at the end of a logical line are not returned even
78 ; if the cursor is after them.
79 ; - If the cursor is moved to another logical line, that logical line is
80 ; read instead. There is no memory of the line start for previous
81 ; logical lines, so if there was a prompt on that line it will be
82 ; picked up too.
83 ; - If the logical line length is exceeded, a beep sounds near the end
84 ; and after three lines (120ch) the logical line is terminated and a
85 ; new logical line is started. However, the previous logical line that
86 ; was overflowed is still returned. This still happens if the new
87 ; logical line extends to more than one physical line or even if
88 ; itself overflows (!). If the physical line is changed with up/down,
89 ; this memory is lost, but left/right don't do this.
90 ; - If a logical line extends exactly to the end of a physical line, an
91 ; extra blank line is printed on EOL.
92 ; - If a logical line extends exactly to the end of the screen, a cursor
93 ; out of bounds error results. (We currently do not implement this...
94 ; feature.)
95 ;
96 ; === The BUFSTR variable ===
97 ;
98 ; The BUFSTR variable is critical to the way that the get line algorithm
99 ; works. It actually consists of two bytes, the row followed by the column
100 ; of the origin of the line to be read. This is updated whenever a read
101 ; request arrives that starts a new line or whenever the cursor is moved
102 ; to a different logical line. This is how the screen editor knows to
103 ; read at the end of a prompt or from a different line that you have moved
104 ; to, and how it tracks that when scrolling occurs. It does not, however,
105 ; get updated when regular characters are typed, even when spilling to a
106 ; new logical line.
107 ;
108 ; === BUFCNT ===
109 ;
110 ; BUFCNT contains the number of characters left to return before we have
111 ; to get a new line: $00 means we will wait for keys, $01 is the EOL, and
112 ; >$01 returns a typed character. We need to follow this convention or
113 ; else the combination of S_VBXE.SYS + CON.SYS /E from SDX 4.46 acts
114 ; strangely on launch.
115 ;
116 FA16 .proc EditorGetLine
117 = 006D _start_x equ bufstr+1
118 = 006C _start_y equ bufstr
119
120 ;Set line buffer start to current position (NOT the start of the logical
121 ;line -- this is a special case).
122 FA16 20 0A F9 jsr EditorSwapToText
123 FA19 A5 55 85 6D mva colcrs _start_x
124 FA1D A5 54 85 6C mva rowcrs _start_y
125 FA21 20 63 FD jsr EditorSwapToScreen
126
127 ;check if forced read is enabled on the IOCB -- if so, assume we've gotten
128 ;an EOL
129 FA24 A5 2A lda icax1z
130 FA26 4A lsr
131 FA27 B0 25 bcs do_eol
132
133 FA29 read_loop:
134 ;get a character
135 FA29 20 66 FE jsr KeyboardGetByte
136 FA2C 10 01 bpl read_ok
137 FA2E read_error:
138 FA2E 60 rts
139
140 FA2F read_ok:
141 FA2F C9 9B cmp #$9b
142 FA31 F0 1D beq is_eol
143
144 ;echo the character
145 FA33 20 A8 FA jsr EditorPutByte
146 FA36 30 F6 bmi read_error
147
148 ;check if we've hit the warning point (logical pos 113)
149 FA38 A5 55 lda colcrs
150 FA3A C9 21 cmp #33
151 FA3C D0 EB bne read_loop
152
153 ;convert current row to logical start row
154 FA3E 20 4A FD jsr EditorGetCurLogicalRow
155
156 ;check if we're on the third row
157 FA41 18 clc
158 FA42 69 02 adc #2
159 FA44 C5 54 cmp rowcrs
160
161 ;if so, sound the bell
162 FA46 D0 E1 bne read_loop
163 FA48 20 5C FD jsr EditorBell
164
165 FA4B 4C 29 FA jmp read_loop
166
167 FA4E do_eol:
168 FA4E A9 9B lda #$9b
169 FA50 is_eol:
170 ;echo the character
171 FA50 20 A8 FA jsr EditorPutByte
172 FA53 30 D9 bmi read_error
173
174 ;swap to text screen context
175 FA55 20 0A F9 jsr EditorSwapToText
176
177 ;hide the cursor so we can scan text properly
178 FA58 20 BE F8 jsr ScreenHideCursor
179
180 ;compute address
181 FA5B A2 00 ldx #0
182 FA5D 86 63 stx logcol
183 FA5F A4 6C ldy _start_y
184 FA61 84 54 sty rowcrs
185 FA63 20 44 F9 jsr ScreenComputeToAddr
186
187 FA66 A4 6D ldy _start_x
188 FA68 char_loop:
189 FA68 E6 63 inc logcol
190 FA6A B1 66 lda (toadr),y
191 FA6C F0 04 beq blank
192 FA6E A5 63 85 6B mva logcol bufcnt
193 FA72 blank:
194 FA72 C4 53 cpy rmargn
195 FA74 C8 iny
196 FA75 90 F1 bcc char_loop
197 FA77 20 8A FD jsr EditorNextLineAddr
198
199 ;check if we're at the bottom of the screen
200 FA7A E6 54 inc rowcrs
201 FA7C A5 54 lda rowcrs
202 FA7E CD BF 02 cmp botscr
203 FA81 B0 0A bcs scan_scroll
204
205 ;check if we're at the end of the logical line
206 FA83 20 43 FD jsr EditorTestLogicalLineBit
207 FA86 D0 08 bne scan_done
208
209 FA88 A4 52 ldy lmargn
210 FA8A 4C 68 FA jmp char_loop
211
212 FA8D scan_scroll:
213 ;we're below the screen... need to scroll up
214 FA8D 20 BC FC jsr EditorDeleteLine0
215
216 FA90 scan_done:
217 ;adjust BUFCNT so it is the number of chars to read (scanned + EOL)
218 FA90 E6 6B inc bufcnt
219
220 ;mark this as the start of a new logical line, trimming off any extra
221 ;blank lines
222 FA92 A5 54 lda rowcrs
223 FA94 20 36 FD jsr EditorGetLogicalLineInfo
224 FA97 19 B2 02 ora logmap,y
225 FA9A 99 B2 02 sta logmap,y
226
227 ;reset cursor to line start, but leave the cursor off
228 FA9D A6 6D 86 55 mvx _start_x colcrs
229 FAA1 A4 6C 84 54 mvy _start_y rowcrs
230
231 ;swap back to main context and exit successfully
232 FAA5 4C 61 FD jmp EditorSwapToScreen_Y1
233 .endp
234
235 ;==========================================================================
236 ; This routine must NOT write BUFADR -- doing so breaks the DLT flasher.
237 ;
238 ; Behavior notes:
239 ; - Ctrl+1 (suspend display) does not affect control codes handled only
240 ; by E:. In particular, EOL, move up/down/left/right, ESC, insert, and
241 ; delete are not affected by it. CLEAR on the other hand, is, because
242 ; it's handled by S:.
243 ;
244 FAA8 .proc EditorPutByte
245 ;open the text screen if it is not open already
246 FAA8 A4 57 ldy dindex
247 FAAA F0 0C beq screenok
248 FAAC AC BF 02 ldy botscr
249 FAAF C0 04 cpy #4
250 FAB1 F0 05 beq screenok
251
252 FAB3 48 pha
253 FAB4 20 EE F3 jsr ScreenOpenGr0
254 FAB7 68 pla
255 FAB8 screenok:
256
257 ;swap to text context
258 FAB8 20 0A F9 jsr EditorSwapToText
259
260 ;hide the cursor -- this must be done before we suspend display on
261 ;Ctrl+1.
262 FABB 20 BE F8 jsr ScreenHideCursor
263
264 ;save off character to free up acc
265 FABE A8 tay
266
267 ;Check if [esc] is active
268 ;
269 ;Note that the ASL trick relies on ESCFLG being $80 when set; this
270 ;is in fact guaranteed by the spec in the OS Manual, Appendix L, B26.
271 ;
272 FABF 0E A2 02 asl escflg ;test and clear escape flag
273 FAC2 B0 1E bcs not_special
274
275 ;check if this might be a special character
276 FAC4 29 1F and #$1f
277 FAC6 C9 1B cmp #$1b
278 FAC8 90 18 bcc not_special
279
280 ;might be special, but not EOL... search the special char table
281 FACA A2 0E ldx #special_code_tab_end-special_code_tab-1
282 FACC 98 tya
283 FACD 20 A7 FC jsr EditorIsSpecial
284 FAD0 D0 10 bne not_special
285
286 FAD2 special_found:
287 ;check if display of control codes is desired; if so, we need to ignore this
288 FAD2 AD FE 02 lda dspflg
289 FAD5 D0 0B bne not_special
290
291 ;jump to routine
292 FAD7 20 53 FC jsr dispatch
293 FADA 20 B0 FC jsr EditorRecomputeCursorAddr
294 FADD 20 E5 FD jsr ScreenShowCursorAndXitOK
295 FAE0 10 06 bpl xit2 ;!! - unconditional jump
296
297 FAE2 not_special:
298 ;ok, just put the char to the screen
299 FAE2 8C FB 02 sty atachr
300 FAE5 20 F7 F5 jsr ScreenPutByte.not_clear
301 FAE8 xit2:
302 ;swap back to main context and exit
303 FAE8 4C 63 FD jmp EditorSwapToScreen
304
305 ;---------------
306 FAEB special_code_tab:
307 FAEB 1B dta $1b
308 FAEC 1C dta $1c
309 FAED 1D dta $1d
310 FAEE 1E dta $1e
311 FAEF 1F dta $1f
312 FAF0 7D dta $7d
313 FAF1 7E dta $7e
314 FAF2 7F dta $7f
315 FAF3 9C dta $9c
316 FAF4 9D dta $9d
317 FAF5 9E dta $9e
318 FAF6 9F dta $9f
319 FAF7 FD dta $fd
320 FAF8 FE dta $fe
321 FAF9 FF dta $ff
322 FAFA special_code_tab_end:
323 FAFA 9B dta $9b ;these are only for the K: check
324 FAFB 7C dta $7c
325 FAFC special_code_tab_end_2:
326
327 ;----------------
328
329 FAFC special_dispatch_lo_tab:
330 FAFC 0A dta <(special_escape-1)
331 FAFD 13 dta <(special_up-1)
332 FAFE 1D dta <(special_down-1)
333 FAFF B1 dta <(special_left-1)
334 FB00 BE dta <(special_right-1)
335 FB01 10 dta <(special_clear-1)
336 FB02 38 dta <(special_backspace-1)
337 FB03 77 dta <(special_tab-1)
338 FB04 C7 dta <(special_delete_line-1)
339 FB05 CD dta <(special_insert_line-1)
340 FB06 64 dta <(special_clear_tab-1)
341 FB07 5C dta <(special_set_tab-1)
342 FB08 59 dta <(special_bell-1)
343 FB09 D4 dta <(special_delete_char-1)
344 FB0A E0 dta <(special_insert_char-1)
345
346 .if [((special_escape-1)^(special_insert_char-1))&$ff00]
347 .error 'Special character routines cross a page boundary: ',special_escape,'-',special_insert_char
348 .endif
349
350 ;---------------
351 FB0B special_escape:
352 FB0B A9 80 8D A2 02 mva #$80 escflg
353 FB10 60 rts
354
355 ;---------------
356 FB11 special_clear:
357 FB11 4C 17 F8 jmp ScreenClear
358
359 ;---------------
360 FB14 special_up:
361 FB14 A6 54 ldx rowcrs
362 FB16 D0 03 bne isup2
363 FB18 AE BF 02 ldx botscr
364 FB1B isup2:
365 FB1B CA dex
366 FB1C 10 0A bpl vmoveexit
367
368 ;---------------
369 FB1E special_down:
370 FB1E A6 54 ldx rowcrs
371 FB20 E8 inx
372 FB21 EC BF 02 cpx botscr
373 FB24 90 02 A2 00 scc:ldx #0
374
375 FB28 vmoveexit:
376 FB28 86 54 stx rowcrs
377
378 ;check if we have moved into a different logical line -- if so,
379 ;we need to reset the read row
380 FB2A 8A txa
381 FB2B 20 4C FD jsr EditorPhysToLogicalRow
382 FB2E C5 6C cmp bufstr
383 FB30 F0 06 beq moveexit
384
385 ;we switched rows -- reset read row
386 FB32 85 6C sta bufstr
387 FB34 A5 52 85 6D mva lmargn bufstr+1
388
389 FB38 moveexit:
390 FB38 60 rts
391
392 ;---------------
393 FB39 special_backspace:
394 ;check if we are at the left column
395 FB39 A5 52 lda lmargn
396 FB3B C5 55 cmp colcrs
397 FB3D B0 0B bcs sbks_wrap
398
399 ;nope, we can just back up
400 FB3F C6 55 dec colcrs
401
402 ;recompute pos and clear character
403 FB41 sbks_recomp:
404 FB41 20 B0 FC jsr EditorRecomputeCursorAddr
405 FB44 A0 00 ldy #0
406 FB46 98 tya
407 FB47 91 5E sta (oldadr),y
408 FB49 sbks_xit:
409 FB49 60 rts
410
411 FB4A sbks_wrap:
412 ;check if we're at the start of the logical line
413 FB4A A5 54 lda rowcrs
414 FB4C 20 43 FD jsr EditorTestLogicalLineBit
415 FB4F D0 F8 bne sbks_xit
416
417 ;no, so we need to wrap to the right column of the prev line...
418 FB51 C6 54 dec rowcrs
419 FB53 A5 53 lda rmargn
420 FB55 85 55 sta colcrs
421
422 ;recompute everything and exit
423 FB57 4C 41 FB jmp sbks_recomp
424
425 ;----------------
426 FB5A special_bell:
427 FB5A 4C 5C FD jmp EditorBell
428
429 ;----------------
430 FB5D special_set_tab:
431 FB5D 20 71 FB jsr special_common_tab
432 FB60 1D A3 02 ora tabmap,x
433 FB63 D0 08 bne special_common_exit_tab
434
435 FB65 special_clear_tab:
436 FB65 20 71 FB jsr special_common_tab
437 FB68 49 FF eor #$ff
438 FB6A 3D A3 02 and tabmap,x
439 FB6D special_common_exit_tab:
440 FB6D 9D A3 02 sta tabmap,x
441 FB70 60 rts
442
443 FB71 special_common_tab:
444 FB71 20 6C FD jsr EditorGetLogicalColumn
445 FB74 A8 tay
446 FB75 4C 7B FD jmp EditorSetupTabIndex
447
448 ;--------------------------------------------------------------------------
449 ; Tab behavior:
450 ; - Moves cursor to the next tab position within the logical line.
451 ; - If there are no more tabs, moves cursor to beginning of next line.
452 ; This may cause a scroll.
453 ; - Tab does NOT adjust the read row.
454 ;
455 FB78 special_tab:
456 FB78 20 6C FD jsr EditorGetLogicalColumn
457 FB7B A8 tay
458 FB7C 8A txa
459 FB7D 38 sec
460 FB7E 65 54 adc rowcrs
461 FB80 85 54 sta rowcrs
462
463 ;scan forward until we find the next bit set, or we hit position 120
464 FB82 tab_scan_loop:
465 FB82 C8 iny
466 FB83 C0 78 cpy #120
467 FB85 B0 08 bcs tab_found
468 FB87 20 7B FD jsr EditorSetupTabIndex
469 FB8A 3D A3 02 and tabmap,x
470 FB8D F0 F3 beq tab_scan_loop
471 FB8F tab_found:
472 FB8F 84 55 sty colcrs
473 FB91 tab_adjust_row:
474 FB91 A5 55 lda colcrs
475 FB93 38 sec
476 FB94 E9 28 sbc #40 ;subtract a row worth of columns
477 FB96 90 19 bcc tab_adjust_done ;exit if <40
478 FB98 85 55 sta colcrs
479 FB9A E6 54 inc rowcrs ;next row
480 FB9C A5 54 lda rowcrs ;
481 FB9E CD BF 02 cmp botscr ;check if we're below the screen
482 FBA1 B0 07 bcs tab_adjust_scroll ;if so, do a scroll
483 FBA3 20 43 FD jsr EditorTestLogicalLineBit ;check if we're on a new log line
484 FBA6 F0 E9 beq tab_adjust_row ;if not, keep adjusting
485 FBA8 10 03 bpl tab_adjust_left ;position at beginning of new line
486
487 FBAA tab_adjust_scroll:
488 FBAA 20 BC FC jsr EditorDeleteLine0
489 FBAD tab_adjust_left:
490 FBAD hmove_to_lmargn:
491 ;move to left margin
492 FBAD A6 52 ldx lmargn
493 FBAF hmove_to_x:
494 FBAF 86 55 stx colcrs
495 FBB1 tab_adjust_done:
496 FBB1 60 rts
497
498 ;--------------------------------------------------------------------------
499 FBB2 special_left:
500 FBB2 A6 55 ldx colcrs
501 FBB4 F0 05 beq slft_to_right
502 FBB6 CA dex
503 FBB7 E4 52 cpx lmargn
504 FBB9 B0 F4 bcs hmove_to_x
505
506 ;move to right margin
507 FBBB slft_to_right:
508 FBBB A6 53 ldx rmargn
509 FBBD 90 F0 bcc hmove_to_x
510
511 ;--------------------------------------------------------------------------
512 FBBF special_right:
513 FBBF A6 55 ldx colcrs
514 FBC1 E4 53 cpx rmargn
515 FBC3 B0 E8 bcs hmove_to_lmargn
516
517 ;right one char
518 FBC5 E6 55 inc colcrs
519 FBC7 60 rts
520
521 ;--------------------------------------------------------------------------
522 ; Delete line behavior:
523 ; - The entire logical line that the cursor is in is deleted.
524 ; - The cursor is positioned at the beginning of the next logical line.
525 ;
526 FBC8 special_delete_line:
527 ;delete current logical line
528 FBC8 20 4A FD jsr EditorGetCurLogicalRow
529 FBCB 4C BE FC jmp EditorDeleteLine
530
531 ;----------------
532 FBCE special_insert_line:
533 ;insert a new logical line at this point; note that this may split
534 ;the current line
535 FBCE 38 sec
536 FBCF 20 5B F8 jsr ScreenInsertLine
537 FBD2 4C AD FB jmp tab_adjust_left
538
539 ;--------------------------------------------------------------------------
540 ; Delete character behavior:
541 ; - Erases the current character and drags in characters from the
542 ; remainder of the logical line, excluding the margins.
543 ; - If the last physical line is blank and not the only physical line in
544 ; the logical line, it is deleted and the logical line is shortened.
545 ; Only one line is removed even if the last two lines are blank. The
546 ; cursor does not move when this happens and may be shifted into the
547 ; next logical line. This also does not change the input line!
548 ;
549 FBD5 special_delete_char:
550 ;compute base address of current row (not char)
551 FBD5 A4 54 ldy rowcrs
552 FBD7 84 51 sty hold1
553 FBD9 20 42 F9 jsr ScreenComputeToAddrX0
554
555 ;begin shifting in the first column at the current pos
556 FBDC A4 55 ldy colcrs
557
558 ;delete chars to end
559 FBDE 4C 6C FC jmp delete_shift_loop_entry
560
561 ;--------------------------------------------------------------------------
562 ; Insert character behavior:
563 ; - Inserts a blank at the current position and shifts characters forward
564 ; within the margins.
565 ; - If the character shifted out of the end of the logical line is non-
566 ; blank, the logical line will be extended if possible. This can cause
567 ; a scroll. If the logical line is already three rows, the last
568 ; character is lost.
569 ;
570 FBE1 special_insert_char:
571 ;get logical line start
572 FBE1 20 4A FD jsr EditorGetCurLogicalRow
573
574 ;compute line at which we cannot add another physical line
575 FBE4 18 69 03 add #3
576 FBE7 85 76 sta deltar
577
578 ;compute address of row
579 FBE9 A4 54 ldy rowcrs
580 FBEB 84 51 sty hold1
581 FBED 20 42 F9 jsr ScreenComputeToAddrX0
582
583 FBF0 A4 55 ldy colcrs ;end shift at current column
584 FBF2 A2 00 ldx #0 ;insert blank character at start
585 FBF4 F0 04 beq insert_line_loop_entry
586
587 FBF6 insert_line_loop:
588 FBF6 A4 52 ldy lmargn ;end shift at left column
589 FBF8 A6 50 ldx tmpchr ;character to shift in (from last line)
590
591 FBFA insert_line_loop_entry:
592 FBFA 84 65 sty adress+1 ;stash shift origin
593 FBFC A4 53 ldy rmargn ;begin shift at right column
594 FBFE B1 66 lda (toadr),y ;get character being shifted out
595 FC00 85 50 sta tmpchr ;save it off to later shift in on the next row
596 FC02 insert_shift_loop:
597 FC02 88 dey
598 FC03 B1 66 lda (toadr),y
599 FC05 C8 iny
600 FC06 91 66 sta (toadr),y
601 FC08 88 dey
602 FC09 C4 65 cpy adress+1
603 FC0B D0 F5 bne insert_shift_loop
604
605 ;put character shifted out from previous line into beginning of this one
606 FC0D 8A txa
607 FC0E 91 66 sta (toadr),y
608
609 ;next row
610 FC10 E6 51 inc hold1
611
612 FC12 20 8A FD jsr EditorNextLineAddr
613
614 ;check if we're at the end of the logical line
615 FC15 A5 51 lda hold1
616 FC17 CD BF 02 cmp botscr
617 FC1A B0 05 bcs insert_crossed_lline
618 FC1C 20 43 FD jsr EditorTestLogicalLineBit
619 FC1F F0 D5 beq insert_line_loop
620 FC21 insert_crossed_lline:
621
622 ;check if we shifted out a non-blank character
623 FC21 A5 50 lda tmpchr
624 FC23 F0 2D beq insert_done
625
626 ;save current row
627 FC25 A5 54 lda rowcrs
628 FC27 48 pha
629
630 ;check if the logical line is already 3 rows -- if so, we cannot extend and
631 ;the last char goes into the bit bucket, but we still must scroll (!)
632 FC28 A6 51 ldx hold1
633 FC2A E4 76 cpx deltar
634 FC2C 08 php
635
636 ;move to the bottom line +1; we use ROWCRS so it stays updated with the scrolling
637 FC2D 86 54 stx rowcrs
638
639 ;check if we are at the bottom of the screen; if so we must scroll
640 FC2F A9 00 lda #0
641 FC31 85 76 sta deltar
642
643 FC33 EC BF 02 cpx botscr
644 FC36 90 03 bcc insert_no_scroll
645
646 ;scroll the screen
647 FC38 20 BC FC jsr EditorDeleteLine0
648
649 FC3B insert_no_scroll:
650 ;if we can't extend, we are done
651 FC3B 28 plp
652 FC3C B0 0E bcs insert_cant_extend
653
654 ;just insert a blank line at the end of this logical row to extend it
655 FC3E 20 5A F8 jsr ScreenInsertPhysLine
656
657 ;restore shifted character and put it in place
658 FC41 A4 54 ldy rowcrs
659 FC43 20 42 F9 jsr ScreenComputeToAddrX0
660 FC46 A5 50 lda tmpchr
661 FC48 A4 52 ldy lmargn
662 FC4A 91 66 sta (toadr),y
663 FC4C insert_cant_extend:
664
665 ;restore cursor row, adjusting for any scroll
666 FC4C 68 pla
667 FC4D 38 sec
668 FC4E E5 76 sbc deltar
669 FC50 85 54 sta rowcrs
670
671 FC52 insert_done:
672 FC52 60 rts
673
674 ;---------------------------------
675 FC53 dispatch:
676 FC53 A9 FB lda #>special_escape
677 FC55 48 pha
678 FC56 BD FC FA lda special_dispatch_lo_tab,x
679 FC59 48 pha
680 FC5A 60 rts
681
682 ;---------------------------------
683 FC5B delete_line_loop:
684 ;copy first character into right margin of previous row
685 FC5B A4 52 ldy lmargn
686 FC5D B1 66 lda (toadr),y
687 FC5F A4 53 ldy rmargn
688 FC61 91 68 sta (frmadr),y
689
690 ;start shifting new row at left margin
691 FC63 A4 52 ldy lmargn
692 FC65 delete_shift_loop:
693 FC65 C8 iny
694 FC66 B1 66 lda (toadr),y
695 FC68 88 dey
696 FC69 91 66 sta (toadr),y
697 FC6B C8 iny
698 FC6C delete_shift_loop_entry:
699 FC6C C4 53 cpy rmargn
700 FC6E D0 F5 bne delete_shift_loop
701
702 ;next line
703 FC70 20 8A FD jsr EditorNextLineAddr
704
705 ;check if the next row is a logical line start
706 FC73 A6 51 ldx hold1
707 FC75 E8 inx
708 FC76 EC BF 02 cpx botscr
709 FC79 B0 08 bcs delete_stop_shifting
710 FC7B 86 51 stx hold1
711 FC7D 8A txa
712 FC7E 20 43 FD jsr EditorTestLogicalLineBit
713
714 ;keep going if not
715 FC81 F0 D8 beq delete_line_loop
716
717 FC83 delete_stop_shifting:
718 ;blank the last character of the last line
719 FC83 A4 53 ldy rmargn
720 FC85 A9 00 lda #0
721 FC87 91 68 sta (frmadr),y
722
723 ;check if the last line is blank
724 FC89 delete_blank_test_loop:
725 FC89 B1 68 lda (frmadr),y
726 FC8B D0 19 bne delete_not_blank
727 FC8D 88 dey
728 FC8E C4 52 cpy lmargn
729 FC90 B0 F7 bcs delete_blank_test_loop
730
731 ;the last line is blank... check if it is a logical line start
732 FC92 C6 51 dec hold1
733 FC94 A5 51 lda hold1
734 FC96 20 43 FD jsr EditorTestLogicalLineBit
735
736 ;skip if so -- we can't delete the entire logical line
737 FC99 D0 0B bne delete_not_blank
738
739 ;delete this physical line... however, do not move the cursor and
740 ;do not change the read line even if the cursor hops to a new one
741 FC9B A5 55 lda colcrs
742 FC9D 48 pha
743 FC9E A5 51 lda hold1
744 FCA0 20 BE FC jsr EditorDeleteLine
745 FCA3 68 pla
746 FCA4 85 55 sta colcrs
747
748 FCA6 delete_not_blank:
749 ;re-show cursor and exit
750 FCA6 60 rts
751
752 .endp
753
754 ;==========================================================================
755 FCA7 .proc EditorIsSpecial
756 FCA7 special_binsearch:
757 FCA7 DD EB FA cmp EditorPutByte.special_code_tab,x
758 FCAA F0 03 beq special_found
759 FCAC CA dex
760 FCAD 10 F8 bpl special_binsearch
761 FCAF special_found:
762 FCAF 60 rts
763 .endp
764
765 ;==========================================================================
766 FCB0 .proc EditorRecomputeCursorAddr
767 FCB0 A6 55 ldx colcrs
768 FCB2 A4 54 ldy rowcrs
769 FCB4 20 2C F9 jsr ScreenComputeAddr
770 FCB7 86 5E stx oldadr
771 FCB9 85 5F sta oldadr+1
772 FCBB 60 rts
773 .endp
774
775 ;==========================================================================
776 ; Delete a logical line on screen, and scroll the remainder of the screen
777 ; upward.
778 ;
779 ; Inputs:
780 ; A = physical line row to delete
781 ;
782 ; Outputs:
783 ; DELTAR = number of lines scrolled
784 ;
785 = FCBE EditorDeleteLine = EditorDeleteLine0.use_line
786 FCBC .proc EditorDeleteLine0
787 FCBC A9 00 lda #0
788 FCBE use_line:
789 FCBE 85 51 sta hold1
790 FCC0 A2 00 ldx #0
791 FCC2 86 76 stx deltar
792
793 FCC4 scroll_loop:
794 ;compute base address and set that as destination
795 FCC4 A4 51 ldy hold1
796
797 .if _KERNEL_XLXE
798 sec
799 bne nofine
800 ldx fine
801 beq nofine
802 ldx #0
803 xloop:
804 lda rtclok+2
805 cmp:req rtclok+2
806 inx
807 stx vscrol
808 cpx #7
809 bne xloop
810 lda #32/2
811 cmp:rcc vcount
812 cmp:rcs vcount
813 nofine:
814 php ;C=0 for fine scroll, C=1 for coarse scroll
815 .endif
816
817 ;set TOADR to the line to be deleted
818 FCC6 20 42 F9 jsr ScreenComputeToAddrX0
819
820 FCC9 A6 51 ldx hold1
821 FCCB 10 0C bpl line_loop_start
822
823 FCCD line_loop:
824 ;bump line: FRMADR <- TOADR, TOADR += 40
825 FCCD 20 8A FD jsr EditorNextLineAddr
826
827 ;move line -- note that we are copying backwards (TOADR to FRMADR)!
828 FCD0 A0 27 ldy #39
829 FCD2 B1 66 91 68 88 10 + mva:rpl (toadr),y (frmadr),y-
830
831 FCD9 line_loop_start:
832 FCD9 E8 inx
833 FCDA EC BF 02 cpx botscr
834 FCDD D0 EE bne line_loop
835
836 ;clear the last line
837 FCDF A0 27 ldy #39
838 FCE1 A9 00 lda #0
839 FCE3 91 66 88 10 FB sta:rpl (toadr),y-
840
841 .if _KERNEL_XLXE
842 plp
843 bcs nofinescroll2
844 sta vscrol
845 nofinescroll2:
846 .endif
847
848 FCE8 20 1D FD jsr adjust_lines
849
850 ;delete bits out of the logical mask until we get to the next
851 ;logical line, computing the number of lines to scroll
852 FCEB A5 51 lda hold1
853 FCED 20 36 FD jsr EditorGetLogicalLineInfo
854 FCF0 BE 1A FD ldx update_table,y ;get number of masks to shift
855 FCF3 38 sec ;setup to add a new logical line at the end
856 FCF4 F0 09 beq do_mask ;jump to masking if we're on byte 2
857 FCF6 2E B4 02 rol logmap+2 ;shift byte 2
858 FCF9 CA dex ;
859 FCFA F0 03 beq do_mask ;jump to masking if we're on byte 1
860 FCFC 2E B3 02 rol logmap+1 ;shift byte 1
861 FCFF do_mask:
862 FCFF 85 64 sta adress ;stash mask
863 FD01 49 FF eor #$ff ;invert mask
864 FD03 39 B2 02 and logmap,y ;kill target bit
865 FD06 85 65 sta adress+1 ;stash modified mask
866 FD08 C6 64 dec adress ;form mask for LSBs below bit
867 FD0A 25 64 and adress ;isolate those bits
868 FD0C 65 65 adc adress+1 ;shift those up and the bit from the next byte in
869 FD0E 99 B2 02 sta logmap,y ;write to logmap
870
871 FD11 E6 76 inc deltar ;increment line count
872 FD13 E6 64 inc adress ;revert mask
873 FD15 24 64 bit adress ;test if we still have a logical line
874
875 ;loop back if we need to delete more physical lines
876 FD17 F0 AB beq scroll_loop
877
878 ;all done
879 FD19 60 rts
880
881 FD1A update_table:
882 FD1A 02 01 00 dta 2,1,0
883
884 FD1D adjust_lines:
885 FD1D A5 52 lda lmargn ;prep for line adjustments
886
887 ;adjust the read row if it is affected by the deletion
888 FD1F A2 6C ldx #<bufstr
889 FD21 20 26 FD jsr adjust_line
890
891 ;adjust the cursor row if it is affected by the deletion
892 FD24 A2 54 ldx #<rowcrs
893 FD26 adjust_line:
894 FD26 B4 00 ldy 0,x ;get row
895 FD28 C4 51 cpy hold1 ;compare against deletion pos
896 FD2A 90 07 bcc adjust_line_above ;nothing to do if it's above del range
897 FD2C D0 03 bne adjust_line_below ;skip col adjust if it's below del range
898 FD2E 95 01 sta 1,x ;within range - move cursor to left mgn
899 FD30 60 rts
900 FD31 adjust_line_below:
901 FD31 D6 00 dec 0,x
902 FD33 adjust_line_above:
903 FD33 60 rts
904 .endp
905
906 ;==========================================================================
907 = E4C9 EditorGetStatus = CIOExitSuccess
908 = E4CB EditorSpecial = CIOExitNotSupported
909 = E4CB EditorInit = CIOExitNotSupported
910
911 ;==========================================================================
912 ; Entry:
913 ; A = line
914 ;
915 ; Exit:
916 ; P = bit test status
917 ; A = bit mask
918 ; X = bit index
919 ; Y = mask index
920 ;
921 = FD34 EditorGetCurLogicalLineInfo = _EditorGetLogicalLineInfo
922 = FD36 EditorGetLogicalLineInfo = _EditorGetLogicalLineInfo.use_a
923 FD34 .proc _EditorGetLogicalLineInfo
924 FD34 A5 54 lda rowcrs
925 FD36 use_a:
926 FD36 48 pha
927 FD37 4A lsr
928 FD38 4A lsr
929 FD39 4A lsr
930 FD3A A8 tay
931 FD3B 68 pla
932 FD3C 29 07 and #7
933 FD3E AA tax
934 FD3F BD C1 E4 lda ReversedBitMasks,x
935 FD42 60 rts
936 .endp
937
938 ;==========================================================================
939 ; Test whether a physical line is the start of a logical line.
940 ;
941 ; Entry:
942 ; A = line
943 ;
944 ; Exit:
945 ; Z = 1 if so, 0 if not
946 ;
947 ; Modified:
948 ; all registers
949 ;
950 FD43 .proc EditorTestLogicalLineBit
951 FD43 20 36 FD jsr EditorGetLogicalLineInfo
952 FD46 39 B2 02 and logmap,y
953 FD49 60 rts
954 .endp
955
956 ;==========================================================================
957 ; Get the starting physical line for a logical line.
958 ;
959 ; Entry:
960 ; A = physical line
961 ;
962 ; Exit:
963 ; A = logical line start
964 ;
965 ; Modified:
966 ; ADRESS
967 ;
968 = FD4C EditorPhysToLogicalRow = EditorGetCurLogicalRow.use_line
969 FD4A .proc EditorGetCurLogicalRow
970 FD4A A5 54 lda rowcrs
971 FD4C use_line:
972 FD4C 85 64 sta adress
973 FD4E test_loop:
974 FD4E A5 64 lda adress
975 FD50 20 43 FD jsr EditorTestLogicalLineBit
976 FD53 D0 04 bne found
977 FD55 C6 64 dec adress
978 FD57 D0 F5 bne test_loop
979 FD59 found:
980 FD59 A5 64 lda adress
981 FD5B 60 rts
982 .endp
983
984 ;==========================================================================
985 FD5C .proc EditorBell
986 FD5C A0 00 ldy #0
987 FD5E 4C CC E4 jmp Bell
988 .endp
989
990 ;==========================================================================
991 FD61 .proc EditorSwapToScreen_Y1
992 FD61 A0 01 ldy #1
993 = FD63 .def :EditorSwapToScreen = *
994 FD63 84 64 sty adress
995 FD65 18 clc
996 FD66 20 0F F9 jsr ScreenSwap
997 FD69 A4 64 ldy adress
998 FD6B 60 rts
999 .endp
1000
1001 ;==========================================================================
1002 ; Compute the current logical column.
1003 ;
1004 ; Exit:
1005 ; A = column
1006 ; X = inverted row index (0-2 => $ff-$fd)
1007 ;
1008 FD6C .proc EditorGetLogicalColumn
1009 ;get starting row of logical line
1010 FD6C A5 54 lda rowcrs
1011 FD6E 20 4C FD jsr EditorPhysToLogicalRow
1012
1013 ;subtract off current row
1014 FD71 18 clc
1015 FD72 E5 54 sbc rowcrs
1016 FD74 AA tax
1017
1018 ;multiply negated difference by 40
1019 FD75 BD A0 FC lda EditorLineLengthTab-$fc,x
1020
1021 ;add in physical column
1022 FD78 65 55 adc colcrs
1023 FD7A 60 rts
1024 .endp
1025
1026 ;==========================================================================
1027 FD7B .proc EditorSetupTabIndex
1028 FD7B 98 tya
1029 FD7C 29 07 and #7
1030 FD7E AA tax
1031 FD7F BD C1 E4 lda ReversedBitMasks,x
1032 FD82 48 pha
1033 FD83 98 tya
1034 FD84 4A lsr
1035 FD85 4A lsr
1036 FD86 4A lsr
1037 FD87 AA tax
1038 FD88 68 pla
1039 FD89 60 rts
1040 .endp
1041
1042 ;==========================================================================
1043 ; Copy TOADR to FRMADR and add 40 to TOADR.
1044 ;
1045 FD8A .proc EditorNextLineAddr
1046 FD8A A5 66 lda toadr
1047 FD8C 85 68 sta frmadr
1048 FD8E 18 69 28 add #40
1049 FD91 85 66 sta toadr
1050 FD93 A5 67 lda toadr+1
1051 FD95 85 69 sta frmadr+1
1052 FD97 69 00 adc #0
1053 FD99 85 67 sta toadr+1
1054 FD9B 60 rts
1055 .endp
1056
1057 ;==========================================================================
1058 FD9C .proc EditorLineLengthTab
1059 FD9C 78 50 28 00 dta 120, 80, 40, 0
1060 .endp
1061
271
272 .ifdef _KERNEL_816
273 icl 'screenext816.s'
274 .else
275 FDA0 icl 'screenext.s'
Source: source/Shared/screenext.s
1 ; Altirra - Atari 800/800XL/5200 emulator
2 ; Modular Kernel ROM - Screen Handler extension routines
3 ; Copyright (C) 2008-2016 Avery Lee
4 ;
5 ; Copying and distribution of this file, with or without modification,
6 ; are permitted in any medium without royalty provided the copyright
7 ; notice and this notice are preserved. This file is offered as-is,
8 ; without any warranty.
9
10 ;==========================================================================
11 FDA0 ScreenEncodingOffsetTable:
12 FDA0 00 dta $00 ;4-bit
13 FDA1 10 dta $10 ;2-bit
14 FDA2 14 dta $14 ;1-bit
15
16 .if !_KERNEL_XLXE
17 FDA3 _SCREEN_TABLES_3
Macro: _SCREEN_TABLES_3 [Source: source/Shared/screen.s]
2 FDA3 00 11 22 33 44 55 + dta $00,$11,$22,$33,$44,$55,$66,$77,$88,$99,$aa,$bb,$cc,$dd,$ee,$ff
3 FDB3 00 55 AA FF dta $00,$55,$aa,$ff
4 FDB7 00 FF dta $00,$ff
Source: source/Shared/screenext.s
18 .endif
19
20 ;==========================================================================
21 ; ScreenFineScrollDLI
22 ;
23 ; This DLI routine is used to set the PF1 color to PF2 to kill junk that
24 ; would appear on the extra line added with vertical scrolling.
25 ;
26 .if _KERNEL_XLXE
27 .proc ScreenFineScrollDLI
28 pha
29 lda color2
30 eor colrsh
31 and drkmsk
32 sta colpf1
33 pla
34 rti
35 .endp
36 .endif
37
38 ;==========================================================================
39 ; ScreenResetLogicalLineMap
40 ;
41 ; Marks all lines as the start of logical lines.
42 ;
43 ; Exit:
44 ; X = 0
45 ;
46 FDB9 .proc ScreenResetLogicalLineMap
47 FDB9 A2 FF ldx #$ff
48 FDBB 8E B2 02 stx logmap
49 FDBE 8E B3 02 stx logmap+1
50 FDC1 8E B4 02 stx logmap+2
51
52 ;reset line read position
53 FDC4 E8 inx
54 FDC5 86 6C stx bufstr
55 FDC7 A5 52 lda lmargn
56 FDC9 85 6D sta bufstr+1
57
58 ;note - X=0 relied on here by EditorOpen
59 FDCB 60 rts
60 .endp
61
62 ;==========================================================================
63 ; ScreenSetLastPosition
64 ;
65 ; Copies COLCRS/ROWCRS to OLDCOL/OLDROW.
66 ;
67 FDCC .proc ScreenSetLastPosition
68 FDCC A2 02 ldx #2
69 FDCE loop:
70 FDCE B5 54 lda rowcrs,x
71 FDD0 95 5A sta oldrow,x
72 FDD2 CA dex
73 FDD3 10 F9 bpl loop
74 FDD5 60 rts
75 .endp
76
77 ;==========================================================================
78 ; ScreenAdvancePosMode0
79 ;
80 ; Advance to the next cursor position in reading order, for mode 0.
81 ;
82 ; Exit:
83 ; C = 1 if no wrap, 0 if wrapped
84 ;
85 ; Modified:
86 ; X
87 ;
88 ; Preserved:
89 ; A
90 ;
91 FDD6 .proc ScreenAdvancePosMode0
92 FDD6 E6 55 inc colcrs
93 FDD8 A6 53 ldx rmargn
94 FDDA E4 55 cpx colcrs
95 FDDC B0 06 bcs post_wrap
96 FDDE A6 52 ldx lmargn
97 FDE0 86 55 stx colcrs
98 FDE2 E6 54 inc rowcrs
99 FDE4 post_wrap:
100 FDE4 60 rts
101 .endp
102
103
104 ;==========================================================================
105 ; Output:
106 ; Y=1 for convenience
107 ;
108 ; (OLDADR) must point to the cursor location with OLDCHR even if the cursor
109 ; is hidden. This is required by SDX QUICKED.SYS, which always restores the
110 ; cursor.
111 ;
112 FDE5 .proc ScreenShowCursorAndXitOK
113 ;;##ASSERT dw(oldadr) >= dw(savmsc)
114 ;check if the cursor is enabled
115 FDE5 A0 00 ldy #0
116 FDE7 B1 5E lda (oldadr),y
117 FDE9 85 5D sta oldchr
118 FDEB AC F0 02 ldy crsinh
119 FDEE D0 04 bne cursor_inhibited
120 FDF0 49 80 eor #$80
121 FDF2 91 5E sta (oldadr),y
122 FDF4 cursor_inhibited:
123 FDF4 C8 iny
124 FDF5 60 rts
125 .endp
126
127 ;==========================================================================
128 ; Close screen (S:).
129 ;
130 ; This is a no-op in OS-B mode. In XL/XE mode, it reopens the device in
131 ; Gr.0 if fine scrolling is on, since this is necessary to clear the DLI.
132 ; This happens even if S: doesn't correspond to the text window. Only
133 ; the high bit of FINE is checked.
134 ;
135 .if !_KERNEL_XLXE
136 = E4C9 ScreenClose = CIOExitSuccess
137 .else
138 .proc ScreenClose
139 bit fine
140 bmi disable_fine_scrolling
141
142 ldy #1
143 rts
144
145 disable_fine_scrolling:
146 ;turn off DLI
147 mva #$40 nmien
148
149 ;restore vdslst
150 ldx #<IntExitHandler_None
151 lda #>IntExitHandler_None
152 jsr ScreenOpenGr0.write_vdslst
153
154 jmp ScreenOpenGr0
155 .endp
156 .endif
157
158 ;==========================================================================
159 .if !_KERNEL_XLXE
160 FDF6 _SCREEN_TABLES_2
Macro: _SCREEN_TABLES_2 [Source: source/Shared/screen.s]
23 FDF6 40 dta <($10000-$03C0) ;gr.0 960 bytes = 40*24 = 40*24
24 FDF7 80 dta <($10000-$0280) ;gr.1 640 bytes = 20*24 + 40*4 = 40*12 + 40*4
25 FDF8 70 dta <($10000-$0190) ;gr.2 400 bytes = 10*24 + 40*4 = 40*6 + 40*4
26 FDF9 70 dta <($10000-$0190) ;gr.3 400 bytes = 10*24 + 40*4 = 40*6 + 40*4
27 FDFA 80 dta <($10000-$0280) ;gr.4 640 bytes = 10*48 + 40*4 = 40*12 + 40*4
28 FDFB A0 dta <($10000-$0460) ;gr.5 1120 bytes = 20*48 + 40*4 = 40*24 + 40*4
29 FDFC E0 dta <($10000-$0820) ;gr.6 2080 bytes = 20*96 + 40*4 = 40*48 + 40*4
30 FDFD 60 dta <($10000-$0FA0) ;gr.7 4000 bytes = 40*96 + 40*4 = 40*96 + 40*4
31 FDFE 50 dta <($10000-$1EB0) ;gr.8 7856 bytes = 40*192 + 40*4 + 16 = 40*192 + 40*4 + 16
32 FDFF 50 dta <($10000-$1EB0) ;gr.9 7856 bytes = 40*192 + 40*4 + 16 = 40*192 + 40*4 + 16
33 FE00 50 dta <($10000-$1EB0) ;gr.10 7856 bytes = 40*192 + 40*4 + 16 = 40*192 + 40*4 + 16
34 FE01 50 dta <($10000-$1EB0) ;gr.11 7856 bytes = 40*192 + 40*4 + 16 = 40*192 + 40*4 + 16
35 FE02 A0 dta <($10000-$0460) ;gr.12 1120 bytes = 40*24 + 40*4 = 40*24 + 40*4
36 FE03 80 dta <($10000-$0280) ;gr.13 640 bytes = 40*12 + 40*4 = 40*12 + 40*4
37 FE04 60 dta <($10000-$0FA0) ;gr.14 4000 bytes = 20*192 + 40*4 = 40*96 + 40*4
38 FE05 50 dta <($10000-$1EB0) ;gr.15 7856 bytes = 40*192 + 40*4 + 16 = 40*192 + 40*4 + 16
42 FE06 FC dta >($10000-$03C0) ;gr.0
43 FE07 FD dta >($10000-$0280) ;gr.1
44 FE08 FE dta >($10000-$0190) ;gr.2
45 FE09 FE dta >($10000-$0190) ;gr.3
46 FE0A FD dta >($10000-$0280) ;gr.4
47 FE0B FB dta >($10000-$0460) ;gr.5
48 FE0C F7 dta >($10000-$0820) ;gr.6
49 FE0D F0 dta >($10000-$0FA0) ;gr.7
50 FE0E E1 dta >($10000-$1EB0) ;gr.8
51 FE0F E1 dta >($10000-$1EB0) ;gr.9
52 FE10 E1 dta >($10000-$1EB0) ;gr.10
53 FE11 E1 dta >($10000-$1EB0) ;gr.11
54 FE12 FB dta >($10000-$0460) ;gr.12
55 FE13 FD dta >($10000-$0280) ;gr.13
56 FE14 F0 dta >($10000-$0FA0) ;gr.14
57 FE15 E1 dta >($10000-$1EB0) ;gr.15
66 FE16 02 06 07 08 09 0A + dta $02,$06,$07,$08,$09,$0A,$0B,$1D,$3F,$7F,$BF,$FF,$04,$05,$1C,$3E
72 FE26 01 dta 1
73 FE27 01 dta 1
74 FE28 00 dta 0
75 FE29 01 dta 1
76 FE2A 02 dta 2
77 FE2B 02 dta 2
78 FE2C 03 dta 3
79 FE2D 03 dta 3
80 FE2E 04 dta 4
81 FE2F 04 dta 4
82 FE30 04 dta 4
83 FE31 04 dta 4
84 FE32 01 dta 1
85 FE33 00 dta 0
86 FE34 04 dta 4
87 FE35 04 dta 4
91 FE36 0C 18 30 60 C0 dta 12, 24, 48, 96, 192
95 FE3B 01 dta 1 ;gr.0 40 pixels
96 FE3C 00 dta 0 ;gr.1 20 pixels
97 FE3D 00 dta 0 ;gr.2 20 pixels
98 FE3E 01 dta 1 ;gr.3 40 pixels
99 FE3F 02 dta 2 ;gr.4 80 pixels
100 FE40 02 dta 2 ;gr.5 80 pixels
101 FE41 03 dta 3 ;gr.6 160 pixels
102 FE42 03 dta 3 ;gr.7 160 pixels
103 FE43 04 dta 4 ;gr.8 320 pixels
104 FE44 02 dta 2 ;gr.9 80 pixels
105 FE45 02 dta 2 ;gr.10 80 pixels
106 FE46 02 dta 2 ;gr.11 80 pixels
107 FE47 01 dta 1 ;gr.12 40 pixels
108 FE48 01 dta 1 ;gr.13 40 pixels
109 FE49 03 dta 3 ;gr.14 160 pixels
110 FE4A 03 dta 3 ;gr.15 160 pixels
Source: source/Shared/screenext.s
161 .endif
276 .endif
277
278 FE4B _KERNEL_REPORT_MODULE_SIZE 'Display routines', 0
Macro: _KERNEL_REPORT_MODULE_SIZE [Source: source/main.xasm]
1 .echo ' ', *, ' -> ', *-?@_kernel_lastpt, '(', 0, ')', ' ', 'Display routines'
1 $FE4B -> $0A5D($0000) Display routines
3 = FE4B .def ?@_kernel_lastpt = *
Source: source/main.xasm
279
280 .ifdef _KERNEL_816
281 icl 'keyboard816.s'
282 .else
283 FE4B icl 'keyboard.s'
Source: source/Shared/keyboard.s
1 ; Altirra - Atari 800/800XL/5200 emulator
2 ; Modular Kernel ROM - Keyboard Handler
3 ; Copyright (C) 2008-2016 Avery Lee
4 ;
5 ; Copying and distribution of this file, with or without modification,
6 ; are permitted in any medium without royalty provided the copyright
7 ; notice and this notice are preserved. This file is offered as-is,
8 ; without any warranty.
9
10 ;==========================================================================
11 ; Oddly, the keyboard IRQs are not enabled from the keyboard init
12 ; routine. It's done by the Display Handler instead on open.
13 ;
14 FE4B .proc KeyboardInit
15 FE4B A2 FF ldx #$ff
16 FE4D 8E FC 02 stx ch
17 FE50 8E F2 02 stx ch1
18 FE53 E8 inx
19 FE54 8E F1 02 stx keydel
20 FE57 8E B6 02 stx invflg
21
22 ;turn on shift lock
23 FE5A A9 40 8D BE 02 mva #$40 shflok
24
25 ;set keyboard definition table pointer
26 .if _KERNEL_XLXE
27 mwa #KeyCodeToATASCIITable keydef
28 .endif
29 FE5F 60 rts
30 .endp
31
32 = E4C9 KeyboardOpen = CIOExitSuccess
33 = E4C9 KeyboardClose = CIOExitSuccess
34
35 ;==========================================================================
36 ; K: GET BYTE handler.
37 ;
38 ; Behavior:
39 ; - Exits with a Break error when break key is pressed.
40 ; - Ctrl-1 does not suspend input here (it is handled by S:/E:).
41 ; - Ctrl-3 returns an EOF error.
42 ; - Caps Lock sets caps mode on OS-A/B depending on Ctrl and Shift key
43 ; state. On the XL/XE OS, pressing Caps Lock alone will enable shift
44 ; lock if no lock is enabled and disable it otherwise.
45 ; - Shift/Control lock is applied by K:, but only on alpha keys.
46 ; - Inverse mode is also applied by K:. Control characters are excluded:
47 ; 1B-1F/7C-7F/9B-9F/FD-FF.
48 ; - Any Ctrl+Shift key code (>=$C0) produces a key click but is otherwise
49 ; ignored.
50 ;
51 FE60 .nowarn .proc _KeyboardGetByte
52 FE60 toggle_shift:
53 .if _KERNEL_XLXE
54 ;Caps Lock without Shift or Control is a toggle on the XL/XE line:
55 ; None -> Shifted
56 ; Shifted, Control -> None
57 ldx shflok
58 bne caps_off
59 ldy #$40
60 .endif
61 FE60 shift_ctrl_on:
62 FE60 caps_off:
63 FE60 98 tya
64 FE61 29 C0 and #$c0
65 FE63 write_shflok:
66 FE63 8D BE 02 sta shflok
67
68 = FE66 .def :KeyboardGetByte
69 FE66 waitForChar:
70 FE66 A2 FF ldx #$ff
71 FE68 waitForChar2:
72 FE68 A5 11 lda brkkey
73 FE6A F0 58 beq isBreak
74 FE6C AD FC 02 lda ch
75 FE6F C9 FF cmp #$ff
76 FE71 F0 F5 beq waitForChar2
77
78 ;invalidate char
79 FE73 8E FC 02 stx ch
80
81 ;do keyboard click (we do this even for ignored ctrl+shift+keys)
82 FE76 A0 0C ldy #12
83 FE78 20 CC E4 jsr Bell
84
85 ;ignore char if both ctrl and shift are pressed
86 FE7B C9 C0 cmp #$c0
87 FE7D B0 E7 bcs waitForChar
88
89 ;trap Ctrl-3 and return EOF
90 FE7F C9 9A cmp #$9a
91 FE81 F0 46 beq isCtrl3
92
93 ;translate char
94 FE83 A8 tay
95
96 .if _KERNEL_XLXE
97 lda (keydef),y
98 .else
99 FE84 B9 0C FF lda KeyCodeToATASCIITable,y
100 .endif
101
102 ;handle special keys (see keytable.s)
103 FE87 10 0E bpl valid_key
104 FE89 C9 81 cmp #$81
105 FE8B 90 D9 bcc waitForChar ;$80 - invalid
106 FE8D F0 2B beq isInverse ;$81 - inverse video
107 FE8F C9 83 cmp #$83
108 FE91 90 CD bcc toggle_shift ;$82 - caps lock
109 FE93 C9 85 cmp #$85
110 FE95 90 C9 bcc shift_ctrl_on ;$83 - shift caps lock / $84 - ctrl caps lock
111
112 FE97 valid_key:
113 ;check for alpha key
114 FE97 C9 61 cmp #'a'
115 FE99 90 0F bcc notAlpha
116 FE9B C9 7B cmp #'z'+1
117 FE9D B0 0B bcs notAlpha
118
119 ;check for shift/control lock
120 FE9F 2C BE 02 bit shflok
121 FEA2 70 04 bvs doShiftLock
122 FEA4 10 04 bpl notAlpha
123
124 ;do control lock logic
125 FEA6 29 1F and #$1f
126
127 FEA8 doShiftLock:
128 FEA8 29 DF and #$df
129
130 FEAA notAlpha:
131 ;check if we should apply inverse flag -- special characters are excluded
132 FEAA A2 10 ldx #EditorPutByte.special_code_tab_end_2-EditorPutByte.special_code_tab-1
133 FEAC 20 A7 FC jsr EditorIsSpecial
134 FEAF F0 03 beq skip_inverse
135
136 ;apply inverse flag
137 FEB1 4D B6 02 eor invflg
138 FEB4 skip_inverse:
139
140 ;return char
141 FEB4 8D FB 02 sta atachr ;required or CON.SYS (SDX 4.46) breaks
142 FEB7 A0 01 ldy #1
143 FEB9 60 rts
144
145 FEBA isInverse:
146 FEBA AD B6 02 lda invflg
147 FEBD 49 80 eor #$80
148 FEBF 8D B6 02 sta invflg
149 FEC2 B0 A2 bcs waitForChar ;!! - unconditional
150
151 FEC4 isBreak:
152 FEC4 86 11 stx brkkey
153 FEC6 A0 80 ldy #CIOStatBreak
154 FEC8 60 rts
155
156 FEC9 isCtrl3:
157 FEC9 A0 88 ldy #CIOStatEndOfFile
158 FECB 60 rts
159 .endp
160
161 ;==============================================================================
162 = E4CB KeyboardPutByte = CIOExitNotSupported
163 = E4C9 KeyboardGetStatus = CIOExitSuccess
164 = E4CB KeyboardSpecial = CIOExitNotSupported
165
166 ;==============================================================================
167 ; Keyboard IRQ
168 ;
169 ; HELP button ($11, $51, and $91):
170 ; - Affects SRTIMR, ATRACT, KEYDEL, and HELPFG
171 ; - Does NOT affect CH, CH1
172 ;
173 FECC .proc KeyboardIRQ
174 ;reset software repeat timer
175 .if _KERNEL_XLXE
176 mva krpdel srtimr
177 .else
178 FECC A9 30 8D 2B 02 mva #$30 srtimr
179 .endif
180
181 ;read new key
182 FED1 AD 09 D2 lda kbcode
183
184 .if _KERNEL_XLXE
185 ;check for HELP
186 and #$3f
187 cmp #$11
188 bne not_help
189 sta helpfg
190 beq xit2
191
192 not_help:
193 lda kbcode
194 .endif
195
196 ;check if it is the same as the prev key
197 FED4 CD F2 02 cmp ch1
198 FED7 D0 08 bne debounced
199
200 ;reject key if debounce timer is still running
201 FED9 AD F1 02 lda keydel
202 FEDC D0 16 bne xit
203 FEDE AD F2 02 lda ch1
204 FEE1 debounced:
205
206 ;check for Ctrl+1 to toggle display activity
207 FEE1 C9 9F cmp #$9f
208 FEE3 F0 11 beq is_suspend
209
210 ;store key
211 FEE5 8D FC 02 sta ch
212 FEE8 8D F2 02 sta ch1
213
214 ;reset attract
215 FEEB A9 00 85 4D mva #0 atract
216
217 FEEF xit2:
218 ;reset key delay
219 FEEF A9 03 8D F1 02 mva #3 keydel
220
221 FEF4 xit:
222 ;all done
223 FEF4 68 pla
224 FEF5 40 rti
225
226 FEF6 is_suspend:
227 ;toggle stop/start flag
228 FEF6 AD FF 02 lda ssflag
229 FEF9 49 FF eor #$ff
230 FEFB 8D FF 02 sta ssflag
231 FEFE B0 EF bcs xit2 ;!! carry set from cmp #$9f!
232 .endp
233
234 ;==============================================================================
235 FF00 .proc KeyboardBreakIRQ
236 FF00 A9 00 85 11 mva #0 brkkey
237
238 ;need to clear the suspend flag as BREAK automatically nukes a pending Ctrl+1
239 FF04 8D FF 02 sta ssflag
240
241 ;interestingly, the default break handler forces the cursor back on.
242 FF07 8D F0 02 sta crsinh
243
244 FF0A 68 pla
245 FF0B 40 rti
246 .endp
284 .endif
285
286 FF0C icl 'keytable.s'
Source: source/Shared/keytable.s
1 ; Altirra - Atari 800/800XL/5200 emulator
2 ; Modular Kernel ROM - Keyboard Scan Code Table
3 ; Copyright (C) 2008-2016 Avery Lee
4 ;
5 ; Copying and distribution of this file, with or without modification,
6 ; are permitted in any medium without royalty provided the copyright
7 ; notice and this notice are preserved. This file is offered as-is,
8 ; without any warranty.
9
10 FF0C KeyCodeToATASCIITable:
11 ;Special codes in this table (values important for compat):
12 ; $80 - invalid key
13 ; $81 - inverse video
14 ; $82 - caps lock
15 ; $83 - shift caps lock
16 ; $84 - control caps lock
17
18 ;lowercase
19 FF0C 6C 6A 3B 80 80 6B + dta $6C, $6A, $3B, $80, $80, $6B, $2B, $2A
20 FF14 6F 80 70 75 9B 69 + dta $6F, $80, $70, $75, $9B, $69, $2D, $3D
21 FF1C 76 80 63 80 80 62 + dta $76, $80, $63, $80, $80, $62, $78, $7A
22 FF24 34 80 33 36 1B 35 + dta $34, $80, $33, $36, $1B, $35, $32, $31
23 FF2C 2C 20 2E 6E 80 6D + dta $2C, $20, $2E, $6E, $80, $6D, $2F, $81
24 FF34 72 80 65 79 7F 74 + dta $72, $80, $65, $79, $7F, $74, $77, $71
25 FF3C 39 80 30 37 7E 38 + dta $39, $80, $30, $37, $7E, $38, $3C, $3E
26 FF44 66 68 64 80 82 67 + dta $66, $68, $64, $80, $82, $67, $73, $61
27
28 ;SHIFT
29 FF4C 4C 4A 3A 80 80 4B + dta $4C, $4A, $3A, $80, $80, $4B, $5C, $5E
30 FF54 4F 80 50 55 9B 49 + dta $4F, $80, $50, $55, $9B, $49, $5F, $7C
31 FF5C 56 80 43 80 80 42 + dta $56, $80, $43, $80, $80, $42, $58, $5A
32 FF64 24 80 23 26 1B 25 + dta $24, $80, $23, $26, $1B, $25, $22, $21
33 FF6C 5B 20 5D 4E 80 4D + dta $5B, $20, $5D, $4E, $80, $4D, $3F, $80
34 FF74 52 80 45 59 9F 54 + dta $52, $80, $45, $59, $9F, $54, $57, $51
35 FF7C 28 80 29 27 9C 40 + dta $28, $80, $29, $27, $9C, $40, $7D, $9D
36 FF84 46 48 44 80 83 47 + dta $46, $48, $44, $80, $83, $47, $53, $41
37
38 ;CTRL
39 FF8C 0C 0A 7B 80 80 0B + dta $0C, $0A, $7B, $80, $80, $0B, $1E, $1F
40 FF94 0F 80 10 15 9B 09 + dta $0F, $80, $10, $15, $9B, $09, $1C, $1D
41 FF9C 16 80 03 80 80 02 + dta $16, $80, $03, $80, $80, $02, $18, $1A
42 FFA4 80 80 9B 80 1B 80 + dta $80, $80, $9B, $80, $1B, $80, $FD, $80
43 FFAC 00 20 60 0E 80 0D + dta $00, $20, $60, $0E, $80, $0D, $80, $80
44 FFB4 12 80 05 19 9E 14 + dta $12, $80, $05, $19, $9E, $14, $17, $11
45 FFBC 80 80 80 80 FE 80 + dta $80, $80, $80, $80, $FE, $80, $7D, $FF
46 FFC4 06 08 04 80 84 07 + dta $06, $08, $04, $80, $84, $07, $13, $01
287 FFCC _KERNEL_REPORT_MODULE_SIZE 'Keyboard routines', 0
Macro: _KERNEL_REPORT_MODULE_SIZE [Source: source/main.xasm]
1 .echo ' ', *, ' -> ', *-?@_kernel_lastpt, '(', 0, ')', ' ', 'Keyboard routines'
1 $FFCC -> $0181($0000) Keyboard routines
3 = FFCC .def ?@_kernel_lastpt = *
Source: source/main.xasm
288
289 .if _KERNEL_XLXE
290 .echo 'Free space: ', $FFEE-*, ' bytes'
291 .else
292 .echo 'Free space: ', $FFFA-*, ' bytes'
292 Free space: $002E bytes
293 .endif
294
295 ;==============================================================================
296 ; version block (XL/XE)
297 ;==============================================================================
298
299 .ifdef _KERNEL_816
300 org $ffe4
301 dta a(IntDispatchNativeCop) ;$FFE4
302 dta a(IntDispatchNativeBreak) ;$FFE6
303 dta a(IntDispatchNativeAbort) ;$FFE8
304 dta a(IntDispatchNativeNmi) ;$FFEA
305 dta a(0) ;$FFEC
306 dta a(IntDispatchNativeIrq) ;$FFEE
307 dta $13 ;$FFF0
308 dta $02 ;$FFF1 option byte - !!CHECKED BY ARCHON
309 dta 'CX' ;$FFF2
310 dta a(IntDispatchCop) ;$FFF4
311 dta a(0) ;$FFF6
312 dta a(IntDispatchAbort) ;$FFF8
313 .elif _KERNEL_XLXE
314 org $ffee
315 dta $01,$01,$13
316 dta $02 ;option byte - !!CHECKED BY ARCHON
317 dta 'CX',$00,$00,$00
318 dta $00
319 dta a(0)
320 .endif
321
322 ;==============================================================================
323 ; reset vectors
324 ;==============================================================================
325 FFCC org $fffa
326 FFFA 85 E8 dta a(IntDispatchNMI)
327 FFFC F8 EF dta a(InitReset)
328 FFFE A2 E8 dta a(IntDispatchIRQ)
329
330 end