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 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 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 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 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 #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 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 1713 DEAC 20 A7 DD jsr fst0r 1714 DEAF A2 E6 ldx #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 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 #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 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 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 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 #[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 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 ;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 #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 #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 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 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 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 # $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 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