Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | ;.lib "axm" |
| 2 | ; |
| 3 | ;begin |
| 4 | ;title "A2232 serial board driver" |
| 5 | ; |
| 6 | ;set modules "2232" |
| 7 | ;set executable "2232.bin" |
| 8 | ; |
| 9 | ;;;;set nolink |
| 10 | ; |
| 11 | ;set temporary directory "t:" |
| 12 | ; |
| 13 | ;set assembly options "-m6502 -l60:t:list" |
| 14 | ;set link options "bin"; loadadr" |
| 15 | ;;;bin2c 2232.bin msc6502.h msc6502code |
| 16 | ;end |
| 17 | ; |
| 18 | ; |
| 19 | ; ### Commodore A2232 serial board driver for NetBSD by JM v1.3 ### |
| 20 | ; |
| 21 | ; - Created 950501 by JM - |
| 22 | ; |
| 23 | ; |
| 24 | ; Serial board driver software. |
| 25 | ; |
| 26 | ; |
| 27 | % Copyright (c) 1995 Jukka Marin <jmarin@jmp.fi>. |
| 28 | % All rights reserved. |
| 29 | % |
| 30 | % Redistribution and use in source and binary forms, with or without |
| 31 | % modification, are permitted provided that the following conditions |
| 32 | % are met: |
| 33 | % 1. Redistributions of source code must retain the above copyright |
| 34 | % notice, and the entire permission notice in its entirety, |
| 35 | % including the disclaimer of warranties. |
| 36 | % 2. Redistributions in binary form must reproduce the above copyright |
| 37 | % notice, this list of conditions and the following disclaimer in the |
| 38 | % documentation and/or other materials provided with the distribution. |
| 39 | % 3. The name of the author may not be used to endorse or promote |
| 40 | % products derived from this software without specific prior |
| 41 | % written permission. |
| 42 | % |
| 43 | % ALTERNATIVELY, this product may be distributed under the terms of |
| 44 | % the GNU General Public License, in which case the provisions of the |
| 45 | % GPL are required INSTEAD OF the above restrictions. (This clause is |
| 46 | % necessary due to a potential bad interaction between the GPL and |
| 47 | % the restrictions contained in a BSD-style copyright.) |
| 48 | % |
| 49 | % THIS SOFTWARE IS PROVIDED `AS IS'' AND ANY EXPRESS OR IMPLIED |
| 50 | % WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
| 51 | % OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| 52 | % DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, |
| 53 | % INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
| 54 | % (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
| 55 | % SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
| 56 | % HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, |
| 57 | % STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| 58 | % ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED |
| 59 | % OF THE POSSIBILITY OF SUCH DAMAGE. |
| 60 | ; |
| 61 | ; |
| 62 | ; Bugs: |
| 63 | ; |
| 64 | ; - Can't send a break yet |
| 65 | ; |
| 66 | ; |
| 67 | ; |
| 68 | ; Edited: |
| 69 | ; |
| 70 | ; - 950501 by JM -> v0.1 - Created this file. |
| 71 | ; - 951029 by JM -> v1.3 - Carrier Detect events now queued in a separate |
| 72 | ; queue. |
| 73 | ; |
| 74 | ; |
| 75 | |
| 76 | |
| 77 | CODE equ $3800 ; start address for program code |
| 78 | |
| 79 | |
| 80 | CTL_CHAR equ $00 ; byte in ibuf is a character |
| 81 | CTL_EVENT equ $01 ; byte in ibuf is an event |
| 82 | |
| 83 | EVENT_BREAK equ $01 |
| 84 | EVENT_CDON equ $02 |
| 85 | EVENT_CDOFF equ $03 |
| 86 | EVENT_SYNC equ $04 |
| 87 | |
| 88 | XON equ $11 |
| 89 | XOFF equ $13 |
| 90 | |
| 91 | |
| 92 | VARBASE macro *starting_address ; was VARINIT |
| 93 | _varbase set \1 |
| 94 | endm |
| 95 | |
| 96 | VARDEF macro *name space_needs |
| 97 | \1 equ _varbase |
| 98 | _varbase set _varbase+\2 |
| 99 | endm |
| 100 | |
| 101 | |
| 102 | stz macro * address |
| 103 | db $64,\1 |
| 104 | endm |
| 105 | |
| 106 | stzax macro * address |
| 107 | db $9e,<\1,>\1 |
| 108 | endm |
| 109 | |
| 110 | |
| 111 | biti macro * immediate value |
| 112 | db $89,\1 |
| 113 | endm |
| 114 | |
| 115 | smb0 macro * address |
| 116 | db $87,\1 |
| 117 | endm |
| 118 | smb1 macro * address |
| 119 | db $97,\1 |
| 120 | endm |
| 121 | smb2 macro * address |
| 122 | db $a7,\1 |
| 123 | endm |
| 124 | smb3 macro * address |
| 125 | db $b7,\1 |
| 126 | endm |
| 127 | smb4 macro * address |
| 128 | db $c7,\1 |
| 129 | endm |
| 130 | smb5 macro * address |
| 131 | db $d7,\1 |
| 132 | endm |
| 133 | smb6 macro * address |
| 134 | db $e7,\1 |
| 135 | endm |
| 136 | smb7 macro * address |
| 137 | db $f7,\1 |
| 138 | endm |
| 139 | |
| 140 | |
| 141 | |
| 142 | ;-----------------------------------------------------------------------; |
| 143 | ; ; |
| 144 | ; stuff common for all ports, non-critical (run once / loop) ; |
| 145 | ; ; |
| 146 | DO_SLOW macro * port_number ; |
| 147 | .local ; ; |
| 148 | lda CIA+C_PA ; check all CD inputs ; |
| 149 | cmp CommonCDo ; changed from previous accptd? ; |
| 150 | beq =over ; nope, do nothing else here ; |
| 151 | ; ; |
| 152 | cmp CommonCDb ; bouncing? ; |
| 153 | beq =nobounce ; nope -> ; |
| 154 | ; ; |
| 155 | sta CommonCDb ; save current state ; |
| 156 | lda #64 ; reinitialize counter ; |
| 157 | sta CommonCDc ; ; |
| 158 | jmp =over ; skip CD save ; |
| 159 | ; ; |
| 160 | =nobounce dec CommonCDc ; no, decrement bounce counter ; |
| 161 | bpl =over ; not done yet, so skip CD save ; |
| 162 | ; ; |
| 163 | =saveCD ldx CDHead ; get write index ; |
| 164 | sta cdbuf,x ; save status in buffer ; |
| 165 | inx ; ; |
| 166 | cpx CDTail ; buffer full? ; |
| 167 | .if ne ; no: preserve status: ; |
| 168 | stx CDHead ; update index in RAM ; |
| 169 | sta CommonCDo ; save state for the next check ; |
| 170 | .end ; ; |
| 171 | =over .end local ; |
| 172 | endm ; |
| 173 | ; |
| 174 | ;-----------------------------------------------------------------------; |
| 175 | |
| 176 | |
| 177 | ; port specific stuff (no data transfer) |
| 178 | |
| 179 | DO_PORT macro * port_number |
| 180 | .local ; ; |
| 181 | lda SetUp\1 ; reconfiguration request? ; |
| 182 | .if ne ; yes: ; |
| 183 | lda SoftFlow\1 ; get XON/XOFF flag ; |
| 184 | sta XonOff\1 ; save it ; |
| 185 | lda Param\1 ; get parameter ; |
| 186 | ora #%00010000 ; use baud generator for Rx ; |
| 187 | sta ACIA\1+A_CTRL ; store in control register ; |
| 188 | stz OutDisable\1 ; enable transmit output ; |
| 189 | stz SetUp\1 ; no reconfiguration no more ; |
| 190 | .end ; ; |
| 191 | ; ; |
| 192 | lda InHead\1 ; get write index ; |
| 193 | sbc InTail\1 ; buffer full soon? ; |
| 194 | cmp #200 ; 200 chars or more in buffer? ; |
| 195 | lda Command\1 ; get Command reg value ; |
| 196 | and #%11110011 ; turn RTS OFF by default ; |
| 197 | .if cc ; still room in buffer: ; |
| 198 | ora #%00001000 ; turn RTS ON ; |
| 199 | .end ; ; |
| 200 | sta ACIA\1+A_CMD ; set/clear RTS ; |
| 201 | ; ; |
| 202 | lda OutFlush\1 ; request to flush output buffer; |
| 203 | .if ne ; yessh! ; |
| 204 | lda OutHead\1 ; get head ; |
| 205 | sta OutTail\1 ; save as tail ; |
| 206 | stz OutDisable\1 ; enable transmit output ; |
| 207 | stz OutFlush\1 ; clear request ; |
| 208 | .end |
| 209 | .end local |
| 210 | endm |
| 211 | |
| 212 | |
| 213 | DO_DATA macro * port number |
| 214 | .local |
| 215 | lda ACIA\1+A_SR ; read ACIA status register ; |
| 216 | biti [1<<3] ; something received? ; |
| 217 | .if ne ; yes: ; |
| 218 | biti [1<<1] ; framing error? ; |
| 219 | .if ne ; yes: ; |
| 220 | lda ACIA\1+A_DATA ; read received character ; |
| 221 | bne =SEND ; not break -> ignore it ; |
| 222 | ldx InHead\1 ; get write pointer ; |
| 223 | lda #CTL_EVENT ; get type of byte ; |
| 224 | sta ictl\1,x ; save it in InCtl buffer ; |
| 225 | lda #EVENT_BREAK ; event code ; |
| 226 | sta ibuf\1,x ; save it as well ; |
| 227 | inx ; ; |
| 228 | cpx InTail\1 ; still room in buffer? ; |
| 229 | .if ne ; absolutely: ; |
| 230 | stx InHead\1 ; update index in memory ; |
| 231 | .end ; ; |
| 232 | jmp =SEND ; go check if anything to send ; |
| 233 | .end ; ; |
| 234 | ; normal char received: ; |
| 235 | ldx InHead\1 ; get write index ; |
| 236 | lda ACIA\1+A_DATA ; read received character ; |
| 237 | sta ibuf\1,x ; save char in buffer ; |
| 238 | stzax ictl\1 ; set type to CTL_CHAR ; |
| 239 | inx ; ; |
| 240 | cpx InTail\1 ; buffer full? ; |
| 241 | .if ne ; no: preserve character: ; |
| 242 | stx InHead\1 ; update index in RAM ; |
| 243 | .end ; ; |
| 244 | and #$7f ; mask off parity if any ; |
| 245 | cmp #XOFF ; XOFF from remote host? ; |
| 246 | .if eq ; yes: ; |
| 247 | lda XonOff\1 ; if XON/XOFF handshaking.. ; |
| 248 | sta OutDisable\1 ; ..disable transmitter ; |
| 249 | .end ; ; |
| 250 | .end ; ; |
| 251 | ; ; |
| 252 | ; BUFFER FULL CHECK WAS HERE ; |
| 253 | ; ; |
| 254 | =SEND lda ACIA\1+A_SR ; transmit register empty? ; |
| 255 | and #[1<<4] ; ; |
| 256 | .if ne ; yes: ; |
| 257 | ldx OutCtrl\1 ; sending out XON/XOFF? ; |
| 258 | .if ne ; yes: ; |
| 259 | lda CIA+C_PB ; check CTS signal ; |
| 260 | and #[1<<\1] ; (for this port only) ; |
| 261 | bne =DONE ; not allowed to send -> done ; |
| 262 | stx ACIA\1+A_DATA ; transmit control char ; |
| 263 | stz OutCtrl\1 ; clear flag ; |
| 264 | jmp =DONE ; and we're done ; |
| 265 | .end ; ; |
| 266 | ; ; |
| 267 | ldx OutTail\1 ; anything to transmit? ; |
| 268 | cpx OutHead\1 ; ; |
| 269 | .if ne ; yes: ; |
| 270 | lda OutDisable\1 ; allowed to transmit? ; |
| 271 | .if eq ; yes: ; |
| 272 | lda CIA+C_PB ; check CTS signal ; |
| 273 | and #[1<<\1] ; (for this port only) ; |
| 274 | bne =DONE ; not allowed to send -> done ; |
| 275 | lda obuf\1,x ; get a char from buffer ; |
| 276 | sta ACIA\1+A_DATA ; send it away ; |
| 277 | inc OutTail\1 ; update read index ; |
| 278 | .end ; ; |
| 279 | .end ; ; |
| 280 | .end ; ; |
| 281 | =DONE .end local |
| 282 | endm |
| 283 | |
| 284 | |
| 285 | |
| 286 | PORTVAR macro * port number |
| 287 | VARDEF InHead\1 1 |
| 288 | VARDEF InTail\1 1 |
| 289 | VARDEF OutDisable\1 1 |
| 290 | VARDEF OutHead\1 1 |
| 291 | VARDEF OutTail\1 1 |
| 292 | VARDEF OutCtrl\1 1 |
| 293 | VARDEF OutFlush\1 1 |
| 294 | VARDEF SetUp\1 1 |
| 295 | VARDEF Param\1 1 |
| 296 | VARDEF Command\1 1 |
| 297 | VARDEF SoftFlow\1 1 |
| 298 | ; private: |
| 299 | VARDEF XonOff\1 1 |
| 300 | endm |
| 301 | |
| 302 | |
| 303 | VARBASE 0 ; start variables at address $0000 |
| 304 | PORTVAR 0 ; define variables for port 0 |
| 305 | PORTVAR 1 ; define variables for port 1 |
| 306 | PORTVAR 2 ; define variables for port 2 |
| 307 | PORTVAR 3 ; define variables for port 3 |
| 308 | PORTVAR 4 ; define variables for port 4 |
| 309 | PORTVAR 5 ; define variables for port 5 |
| 310 | PORTVAR 6 ; define variables for port 6 |
| 311 | |
| 312 | |
| 313 | |
| 314 | VARDEF Crystal 1 ; 0 = unknown, 1 = normal, 2 = turbo |
| 315 | VARDEF Pad_a 1 |
| 316 | VARDEF TimerH 1 |
| 317 | VARDEF TimerL 1 |
| 318 | VARDEF CDHead 1 |
| 319 | VARDEF CDTail 1 |
| 320 | VARDEF CDStatus 1 |
| 321 | VARDEF Pad_b 1 |
| 322 | |
| 323 | VARDEF CommonCDo 1 ; for carrier detect optimization |
| 324 | VARDEF CommonCDc 1 ; for carrier detect debouncing |
| 325 | VARDEF CommonCDb 1 ; for carrier detect debouncing |
| 326 | |
| 327 | |
| 328 | VARBASE $0200 |
| 329 | VARDEF obuf0 256 ; output data (characters only) |
| 330 | VARDEF obuf1 256 |
| 331 | VARDEF obuf2 256 |
| 332 | VARDEF obuf3 256 |
| 333 | VARDEF obuf4 256 |
| 334 | VARDEF obuf5 256 |
| 335 | VARDEF obuf6 256 |
| 336 | |
| 337 | VARDEF ibuf0 256 ; input data (characters, events etc - see ictl) |
| 338 | VARDEF ibuf1 256 |
| 339 | VARDEF ibuf2 256 |
| 340 | VARDEF ibuf3 256 |
| 341 | VARDEF ibuf4 256 |
| 342 | VARDEF ibuf5 256 |
| 343 | VARDEF ibuf6 256 |
| 344 | |
| 345 | VARDEF ictl0 256 ; input control information (type of data in ibuf) |
| 346 | VARDEF ictl1 256 |
| 347 | VARDEF ictl2 256 |
| 348 | VARDEF ictl3 256 |
| 349 | VARDEF ictl4 256 |
| 350 | VARDEF ictl5 256 |
| 351 | VARDEF ictl6 256 |
| 352 | |
| 353 | VARDEF cdbuf 256 ; CD event queue |
| 354 | |
| 355 | |
| 356 | ACIA0 equ $4400 |
| 357 | ACIA1 equ $4c00 |
| 358 | ACIA2 equ $5400 |
| 359 | ACIA3 equ $5c00 |
| 360 | ACIA4 equ $6400 |
| 361 | ACIA5 equ $6c00 |
| 362 | ACIA6 equ $7400 |
| 363 | |
| 364 | A_DATA equ $00 |
| 365 | A_SR equ $02 |
| 366 | A_CMD equ $04 |
| 367 | A_CTRL equ $06 |
| 368 | ; 00 write transmit data read received data |
| 369 | ; 02 reset ACIA read status register |
| 370 | ; 04 write command register read command register |
| 371 | ; 06 write control register read control register |
| 372 | |
| 373 | CIA equ $7c00 ; 8520 CIA |
| 374 | C_PA equ $00 ; port A data register |
| 375 | C_PB equ $02 ; port B data register |
| 376 | C_DDRA equ $04 ; data direction register for port A |
| 377 | C_DDRB equ $06 ; data direction register for port B |
| 378 | C_TAL equ $08 ; timer A |
| 379 | C_TAH equ $0a |
| 380 | C_TBL equ $0c ; timer B |
| 381 | C_TBH equ $0e |
| 382 | C_TODL equ $10 ; TOD LSB |
| 383 | C_TODM equ $12 ; TOD middle byte |
| 384 | C_TODH equ $14 ; TOD MSB |
| 385 | C_DATA equ $18 ; serial data register |
| 386 | C_INTCTRL equ $1a ; interrupt control register |
| 387 | C_CTRLA equ $1c ; control register A |
| 388 | C_CTRLB equ $1e ; control register B |
| 389 | |
| 390 | |
| 391 | |
| 392 | |
| 393 | |
| 394 | section main,code,CODE-2 |
| 395 | |
| 396 | db >CODE,<CODE |
| 397 | |
| 398 | ;-----------------------------------------------------------------------; |
| 399 | ; here's the initialization code: ; |
| 400 | ; ; |
| 401 | R_RESET ldx #$ff ; |
| 402 | txs ; initialize stack pointer ; |
| 403 | cld ; in case a 6502 is used... ; |
| 404 | ldx #0 ; ; |
| 405 | lda #0 ; ; |
| 406 | ldy #Crystal ; this many bytes to clear ; |
| 407 | clr_loop sta 0,x ; clear zero page variables ; |
| 408 | inx ; ; |
| 409 | dey ; ; |
| 410 | bne clr_loop ; ; |
| 411 | ; ; |
| 412 | stz CommonCDo ; force CD test at boot ; |
| 413 | stz CommonCDb ; ; |
| 414 | stz CDHead ; clear queue ; |
| 415 | stz CDTail ; ; |
| 416 | ; ; |
| 417 | lda #0 ; ; |
| 418 | sta Pad_a ; ; |
| 419 | lda #170 ; test cmp ; |
| 420 | cmp #100 ; ; |
| 421 | .if cs ; ; |
| 422 | inc Pad_a ; C was set ; |
| 423 | .end ; ; |
| 424 | ; |
| 425 | ;-----------------------------------------------------------------------; |
| 426 | ; Speed check ; |
| 427 | ;-----------------------------------------------------------------------; |
| 428 | ; |
| 429 | lda Crystal ; speed already set? ; |
| 430 | beq DoSpeedy ; ; |
| 431 | jmp LOOP ; yes, skip speed test ; |
| 432 | ; ; |
| 433 | DoSpeedy lda #%10011000 ; 8N1, 1200/2400 bps ; |
| 434 | sta ACIA0+A_CTRL ; ; |
| 435 | lda #%00001011 ; enable DTR ; |
| 436 | sta ACIA0+A_CMD ; ; |
| 437 | lda ACIA0+A_SR ; read status register ; |
| 438 | ; ; |
| 439 | lda #%10000000 ; disable all ints (unnecessary); |
| 440 | sta CIA+C_INTCTRL ; ; |
| 441 | lda #255 ; program the timer ; |
| 442 | sta CIA+C_TAL ; ; |
| 443 | sta CIA+C_TAH ; ; |
| 444 | ; ; |
| 445 | ldx #0 ; ; |
| 446 | stx ACIA0+A_DATA ; transmit a zero ; |
| 447 | nop ; ; |
| 448 | nop ; ; |
| 449 | lda ACIA0+A_SR ; read status ; |
| 450 | nop ; ; |
| 451 | nop ; ; |
| 452 | stx ACIA0+A_DATA ; transmit a zero ; |
| 453 | Speedy1 lda ACIA0+A_SR ; read status ; |
| 454 | and #[1<<4] ; transmit data reg empty? ; |
| 455 | beq Speedy1 ; not yet, wait more ; |
| 456 | ; ; |
| 457 | lda #%00010001 ; load & start the timer ; |
| 458 | stx ACIA0+A_DATA ; transmit one more zero ; |
| 459 | sta CIA+C_CTRLA ; ; |
| 460 | Speedy2 lda ACIA0+A_SR ; read status ; |
| 461 | and #[1<<4] ; transmit data reg empty? ; |
| 462 | beq Speedy2 ; not yet, wait more ; |
| 463 | stx CIA+C_CTRLA ; stop the timer ; |
| 464 | ; ; |
| 465 | lda CIA+C_TAL ; copy timer value for 68k ; |
| 466 | sta TimerL ; ; |
| 467 | lda CIA+C_TAH ; ; |
| 468 | sta TimerH ; ; |
| 469 | cmp #$d0 ; turbo or normal? ; |
| 470 | .if cs ; ; |
| 471 | lda #2 ; turbo! :-) ; |
| 472 | .else ; ; |
| 473 | lda #1 ; normal :-( ; |
| 474 | .end ; ; |
| 475 | sta Crystal ; ; |
| 476 | lda #0 ; ; |
| 477 | sta ACIA0+A_SR ; ; |
| 478 | sta ACIA0+A_CTRL ; reset UART ; |
| 479 | sta ACIA0+A_CMD ; ; |
| 480 | ; |
| 481 | jmp LOOP ; |
| 482 | ; |
| 483 | ; ; |
| 484 | ;-----------------------------------------------------------------------; |
| 485 | ; ; |
| 486 | ; The Real Thing: ; |
| 487 | ; ; |
| 488 | LOOP DO_SLOW ; do non-critical things ; |
| 489 | jsr do_input ; check for received data |
| 490 | DO_PORT 0 |
| 491 | jsr do_input |
| 492 | DO_PORT 1 |
| 493 | jsr do_input |
| 494 | DO_PORT 2 |
| 495 | jsr do_input |
| 496 | DO_PORT 3 |
| 497 | jsr do_input |
| 498 | DO_PORT 4 |
| 499 | jsr do_input |
| 500 | DO_PORT 5 |
| 501 | jsr do_input |
| 502 | DO_PORT 6 |
| 503 | jsr do_input |
| 504 | jmp LOOP |
| 505 | |
| 506 | |
| 507 | do_input DO_DATA 0 |
| 508 | DO_DATA 1 |
| 509 | DO_DATA 2 |
| 510 | DO_DATA 3 |
| 511 | DO_DATA 4 |
| 512 | DO_DATA 5 |
| 513 | DO_DATA 6 |
| 514 | rts |
| 515 | |
| 516 | |
| 517 | ;-----------------------------------------------------------------------; |
| 518 | section vectors,data,$3ffa |
| 519 | dw $d0d0 |
| 520 | dw R_RESET |
| 521 | dw $c0ce |
| 522 | ;-----------------------------------------------------------------------; |
| 523 | |
| 524 | |
| 525 | |
| 526 | end |
| 527 | |
| 528 | |
| 529 | |