1 ******************************** 2 * 3 * Apple][Sd Firmware 4 * Version 0.5 5 * 6 * (c) Florian Reitz, 2017 7 * 8 * X register usually contains SLOT16 9 * Y register is used for counting or SLOT 10 * 11 ******************************** 12 15-JUL-17 18:27 14 15 XC ; enable 65C02 code 16 ORG $C800 ; Expansion ROM 17 18 * Memory defines 19 20 SLOT16 = $2B ; $s0 -> slot * 16 21 WORK = $3C 22 SLOT = $3D ; $0s 23 CMDLO = $40 24 CMDHI = $41 25 26 CURSLOT = $07F8 ; $Cs 27 DATA = $C080 28 CTRL = DATA+1 29 DIV = DATA+2 30 SS = DATA+3 31 R30 = $0478 32 R31 = $04F8 33 R32 = $0578 34 R33 = $05F8 35 36 * Constants 37 38 SSNONE = $0F 39 SS0 = $0E 40 DUMMY = $FF 41 42 43 ******************************** 44 * 45 * Install SD card driver 46 * 47 ******************************** 48 49 * signature bytes 50 C800: A2 20 51 LDX #$20 C802: A0 00 52 LDY #$00 C804: A2 03 53 LDX #$03 C806: 86 3C 54 STX WORK 55 ===== Page 2 ===== 57 * find slot nr 58 C808: 20 58 FF 59 JSR $FF58 C80B: BA 60 TSX C80C: BD 00 01 61 LDA $0100,X C80F: 29 0F 62 AND #$0F C811: 85 3D 63 STA SLOT ; $0s C813: 09 C0 64 ORA #$C0 C815: 8D F8 07 65 STA CURSLOT ; $Cs C818: 0A 66 ASL A C819: 0A 67 ASL A C81A: 0A 68 ASL A C81B: 0A 69 ASL A C81C: 85 2B 70 STA SLOT16 ; $s0 71 C81E: 20 00 C9 72 JSR INIT C821: 2C FF CF 73 BIT $CFFF 74 75 * 76 * TODO: check for init error 77 * 78 79 * see if slot has a driver already 80 C824: AE 31 BF 81 LDX $BF31 ; get devcnt C827: BD 32 BF 82 INSLP LDA $BF32,X ; get a devnum C82A: 29 70 83 AND #$70 ; isolate slot C82C: C5 2B 84 CMP SLOT16 ; slot? C82E: F0 2E 85 BEQ INSOUT ; yes, skip it C830: CA 86 DEX C831: 10 F4 87 BPL INSLP ; keep up the search 88 89 * restore the devnum to the list 90 C833: AE 31 BF 91 LDX $BF31 ; get devcnt again C836: E0 0D 92 CPX #$0D device table full? C838: D0 03 93 BNE INSLP2 94 C83A: 4C 5E C8 95 JMP INSOUT ; do something! 96 C83D: BD 31 BF 97 INSLP2 LDA $BF32-1,X ; move all entries down C840: 9D 32 BF 98 STA $BF32,X ; to make room at front C843: CA 99 DEX ; for a new entry C844: D0 F7 100 BNE INSLP2 C846: A9 04 101 LDA #$04 ; ProFile type device C848: 05 2B 102 ORA SLOT16 C84A: 8D 32 BF 103 STA $BF32 ; slot, drive 1 at top of list C84D: EE 31 BF 104 INC $BF31 ; update devcnt 105 ===== Page 3 ===== 107 * now insert the device driver vector 108 C850: A5 3D 109 LDA SLOT C852: AA 110 TAX C853: A9 5F 111 LDA #CMD0 C92C: 85 41 204 STA CMDHI C92E: 20 D9 C9 205 JSR CMD C931: 20 ED C9 206 JSR GETR1 ; get response C934: C9 01 207 CMP #$01 C936: D0 39 208 BNE :ERROR1 ; error! 209 C938: A9 C6 210 LDA #CMD8 C93E: 85 41 213 STA CMDHI C940: 20 D9 C9 214 JSR CMD C943: 20 08 CA 215 JSR GETR3 C946: C9 01 216 CMP #$01 ===== Page 5 ===== C948: D0 2A 217 BNE :SDV1 ; may be SD Ver. 1 218 219 * check for $01aa match! C94A: A9 D2 220 :SDV2 LDA #CMD55 C950: 85 41 223 STA CMDHI C952: 20 D9 C9 224 JSR CMD C955: 20 ED C9 225 JSR GETR1 C958: A9 D8 226 LDA #ACMD4140 C95E: 85 41 229 STA CMDHI C960: 20 D9 C9 230 JSR CMD C963: 20 ED C9 231 JSR GETR1 C966: C9 01 232 CMP #$01 C968: F0 E0 233 BEQ :SDV2 ; wait for ready C96A: C9 00 234 CMP #$00 C96C: D0 03 235 BNE :ERROR1 ; error! 236 * send CMD58 237 * SD Ver. 2 initialized! C96E: 4C AE C9 238 JMP :BLOCKSZ 239 C971: 4C CA C9 240 :ERROR1 JMP :IOERROR ; needed for far jump 241 C974: A9 D2 242 :SDV1 LDA #CMD55 C97A: 85 41 245 STA CMDHI C97C: 20 D9 C9 246 JSR CMD ; ignore response C97F: A9 DE 247 LDA #ACMD410 C985: 85 41 250 STA CMDHI C987: 20 D9 C9 251 JSR CMD C98A: 20 ED C9 252 JSR GETR1 C98D: C9 01 253 CMP #$01 C98F: F0 E3 254 BEQ :SDV1 ; wait for ready C991: C9 00 255 CMP #$00 C993: D0 03 256 BNE :MMC ; may be MMC card 257 * SD Ver. 1 initialized! C995: 4C AE C9 258 JMP :BLOCKSZ 259 C998: A9 C0 260 :MMC LDA #CMD1 C99E: 85 41 263 STA CMDHI C9A0: 20 D9 C9 264 :LOOP1 JSR CMD C9A3: 20 ED C9 265 JSR GETR1 C9A6: C9 01 266 CMP #$01 C9A8: F0 F6 267 BEQ :LOOP1 ; wait for ready C9AA: C9 00 268 CMP #$00 C9AC: D0 1C 269 BNE :IOERROR ; error! 270 * MMC Ver. 3 initialized! 271 C9AE: A9 CC 272 :BLOCKSZ LDA #CMD16 C9B4: 85 41 275 STA CMDHI C9B6: 20 D9 C9 276 JSR CMD C9B9: 20 ED C9 277 JSR GETR1 C9BC: C9 00 278 CMP #$00 C9BE: D0 0A 279 BNE :IOERROR ; error! 280 C9C0: 18 281 :END CLC ; all ok C9C1: A2 00 282 LDX #0 C9C3: 90 08 283 BCC :END1 C9C5: 38 284 :CDERROR SEC C9C6: A2 28 285 LDX #$28 ; no card error C9C8: B0 03 286 BCS :END1 C9CA: 38 287 :IOERROR SEC C9CB: A2 27 288 LDX #$27 ; init error C9CD: A9 0F 289 :END1 LDA #SSNONE ; deselect card C9CF: 9D 83 C0 290 STA SS,X C9D2: A9 00 291 LDA #0 ; set div to 2 C9D4: 9D 82 C0 292 STA DIV,X C9D7: 8A 293 TXA ; retval in A C9D8: 60 294 RTS 295 296 297 ******************************** 298 * 299 * Send SD command 300 * Call with command in CMDHI and CMDLO 301 * 302 ******************************** 303 C9D9: 5A 304 CMD PHY C9DA: A0 00 305 LDY #0 C9DC: B1 40 306 :LOOP LDA (CMDLO),Y C9DE: 9D 80 C0 307 STA DATA,X C9E1: 3C 81 C0 308 :WAIT BIT CTRL,X ; TC is in N C9E4: 10 FB 309 BPL :WAIT C9E6: C8 310 INY C9E7: C0 06 311 CPY #6 C9E9: 90 F1 312 BCC :LOOP C9EB: 7A 313 PLY C9EC: 60 314 RTS 315 ===== Page 7 ===== 317 ******************************** 318 * 319 * Get R1 320 * R1 is in A 321 * 322 ******************************** 323 C9ED: A9 FF 324 GETR1 LDA #DUMMY C9EF: 9D 80 C0 325 STA DATA,X C9F2: 3C 81 C0 326 :WAIT BIT CTRL,X C9F5: 10 FB 327 BPL :WAIT C9F7: BD 80 C0 328 LDA DATA,X ; get response C9FA: 85 3C 329 STA WORK ; save R1 C9FC: 29 80 330 AND #$80 C9FE: D0 ED 331 BNE GETR1 ; wait for MSB=0 CA00: A9 FF 332 LDA #DUMMY CA02: 9D 80 C0 333 STA DATA,X ; send another dummy CA05: A5 3C 334 LDA WORK ; restore R1 CA07: 60 335 RTS 336 337 338 ******************************** 339 * 340 * Get R3 341 * R1 is in A 342 * R3 is in scratchpad ram 343 * 344 ******************************** 345 CA08: 20 ED C9 346 GETR3 JSR GETR1 ; get R1 first CA0B: 48 347 PHA ; save R1 CA0C: 5A 348 PHY ; save Y CA0D: A9 04 349 LDA #04 ; load counter CA0F: 85 3C 350 STA WORK CA11: A4 3D 351 LDY SLOT CA13: A9 FF 352 :LOOP LDA #DUMMY ; send dummy CA15: 9D 80 C0 353 STA DATA,X CA18: 3C 81 C0 354 :WAIT BIT CTRL,X CA1B: 10 FB 355 BPL :WAIT CA1D: BD 80 C0 356 LDA DATA,X CA20: 48 357 PHA CA21: C6 3C 358 DEC WORK CA23: D0 EE 359 BNE :LOOP ; do 4 times CA25: 68 360 PLA CA26: 99 F8 05 361 STA R33,Y ; save R3 CA29: 68 362 PLA CA2A: 99 78 05 363 STA R32,Y CA2D: 68 364 PLA CA2E: 99 F8 04 365 STA R31,Y CA31: 68 366 PLA CA32: 9D 78 04 367 STA R30,X CA35: 7A 368 PLY ; restore Y CA36: A9 FF 369 LDA #DUMMY CA38: 9D 80 C0 370 STA DATA,X ; send another dummy CA3B: 68 371 PLA ; restore R1 CA3C: 60 372 RTS 373 ===== Page 8 ===== 374 375 ******************************** 376 * 377 * Status request 378 * $43 Unt number DSSS000 379 * $44-45 Unused 380 * $46-47 Unused 381 * 382 * C Clear - No error 383 * Set - Error 384 * A $00 - No error 385 * $27 - I/O error 386 * $28 - No card inserted / no init 387 * $2B - Card write protected 388 * x - Blocks avail (low byte) 389 * y - Blocks avail (high byte) 390 * 391 ******************************** 392 CA3D: 18 393 STATUS CLC ; no error CA3E: A9 00 394 LDA #0 CA40: A2 FF 395 LDX #$FF ; 32 MB partition CA42: A0 FF 396 LDY #$FF CA44: 60 397 RTS 398 399 * TODO: check for card detect and write protect! 400 401 402 ******************************** 403 * 404 * Read 512 byte block 405 * $43 Unit number DSSS0000 406 * $44-45 Address (LO/HI) of buffer 407 * $46-47 Block number (LO/HI) 408 * 409 * C Clear - No error 410 * Set - Error 411 * A $00 - No error 412 * $27 - Bad block number 413 * $28 - No card inserted 414 * 415 ******************************** 416 417 * TODO: check for card detect! 418 CA45: A9 0E 419 READ LDA #SS0 ; enable /CS CA47: 9D 83 C0 420 STA SS,X 421 CA4A: 5A 422 PHY ; save Y CA4B: A4 3D 423 LDY SLOT CA4D: A5 46 424 LDA $46 ; store block num CA4F: 99 F8 05 425 STA R33,Y ; in R30-R33 CA52: A5 47 426 LDA $47 CA54: 99 78 05 427 STA R32,Y CA57: A9 00 428 LDA #0 CA59: 99 F8 04 429 STA R31,Y CA5C: 99 78 04 430 STA R30,Y ===== Page 9 ===== 431 CA5F: DA 432 PHX CA60: 5A 433 PHY CA61: A0 09 434 LDY #9 CA63: A6 3D 435 LDX SLOT ; ASL can't be done with Y CA65: 1E F8 05 436 :LOOP ASL R33,X ; mul block num CA68: 3E 78 05 437 ROL R32,X ; by 512 to get CA6B: 3E F8 04 438 ROL R31,X ; real address CA6E: 3E 78 04 439 ROL R30,X CA71: 88 440 DEY CA72: D0 F1 441 BNE :LOOP CA74: 7A 442 PLY CA75: FA 443 PLX 444 CA76: A9 51 445 LDA #$51 ; send CMD17 CA78: 9D 80 C0 446 STA DATA,X CA7B: 3C 81 C0 447 :WAIT BIT CTRL,X CA7E: 10 FB 448 BPL :WAIT CA80: B9 78 04 449 :ARG LDA R30,Y ; get arg from R30 on CA83: 9D 80 C0 450 STA DATA,X CA86: 3C 81 C0 451 :WAIT1 BIT CTRL,X CA89: 10 FB 452 BPL :WAIT1 CA8B: B9 F8 04 453 LDA R31,Y CA8E: 9D 80 C0 454 STA DATA,X CA91: 3C 81 C0 455 :WAIT11 BIT CTRL,X CA94: 10 FB 456 BPL :WAIT11 CA96: B9 78 05 457 LDA R32,Y CA99: 9D 80 C0 458 STA DATA,X CA9C: 3C 81 C0 459 :WAIT12 BIT CTRL,X CA9F: 10 FB 460 BPL :WAIT12 CAA1: B9 F8 05 461 LDA R33,Y CAA4: 9D 80 C0 462 STA DATA,X CAA7: 3C 81 C0 463 :WAIT13 BIT CTRL,X CAAA: 10 FB 464 BPL :WAIT13 CAAC: A9 FF 465 LDA #DUMMY CAAE: 9D 80 C0 466 STA DATA,X ; dummy crc CAB1: 3C 81 C0 467 :WAIT2 BIT CTRL,X CAB4: 10 FB 468 BPL :WAIT2 CAB6: A9 FF 469 :GETR1 LDA #DUMMY CAB8: 9D 80 C0 470 STA DATA,X ; get R1 CABB: 3C 81 C0 471 :WAIT3 BIT CTRL,X CABE: 10 FB 472 BPL :WAIT3 CAC0: BD 80 C0 473 LDA DATA,X ; get response 474 * 475 * TODO: check for error! 476 * CAC3: C9 FE 477 CMP #$FE CAC5: D0 EF 478 BNE :GETR1 ; wait for $FE 479 CAC7: 5A 480 PHY CAC8: A0 02 481 LDY #2 ; read data from card CACA: 64 3C 482 :LOOPY STZ WORK CACC: A9 FF 483 :LOOPW LDA #DUMMY CACE: 9D 80 C0 484 STA DATA,X CAD1: 3C 81 C0 485 :WAIT4 BIT CTRL,X CAD4: 10 FB 486 BPL :WAIT4 CAD6: BD 80 C0 487 LDA DATA,X ===== Page 10 ===== CAD9: 92 44 488 STA ($44) CADB: E6 44 489 INC $44 CADD: D0 02 490 BNE :INW CADF: E6 45 491 INC $45 ; inc msb on page boundary CAE1: E6 3C 492 :INW INC WORK CAE3: D0 E7 493 BNE :LOOPW CAE5: 88 494 DEY CAE6: D0 E2 495 BNE :LOOPY CAE8: 7A 496 PLY 497 CAE9: 20 08 CA 498 :OK JSR GETR3 ; read 2 bytes crc CAEC: A9 0F 499 LDA #SSNONE CAEE: 9D 83 C0 500 STA SS,X ; disable /CS CAF1: 18 501 CLC ; no error CAF2: A9 00 502 LDA #$00 CAF4: 7A 503 PLY ; restore Y CAF5: 60 504 RTS 505 CAF6: A9 0F 506 :ERROR LDA #SSNONE CAF8: 9D 83 C0 507 STA SS,X ; disable /CS CAFB: 38 508 SEC ; an error occured CAFC: A9 27 509 LDA #$27 CAFE: 7A 510 PLY ; restore Y CAFF: 60 511 RTS 512 513 514 ******************************** 515 * 516 * Write 512 byte block 517 * $43 Unit number DSSS000 518 * $44-45 Address (LO/HI) of buffer 519 * $46-47 Block number (LO/HI) 520 * 521 * C Clear - No error 522 * Set - Error 523 * A $00 - No error 524 * $27 - Bad block number 525 * $28 - No card inserted 526 * 527 ******************************** 528 529 * TODO: check for card detect and write protect! 530 CB00: A9 0E 531 WRITE LDA #SS0 ; enable /CS CB02: 9D 83 C0 532 STA SS,X 533 CB05: 5A 534 PHY CB06: A4 3D 535 LDY SLOT CB08: A5 46 536 LDA $46 ; store block num CB0A: 99 F8 05 537 STA R33,Y CB0D: A5 47 538 LDA $47 CB0F: 99 78 05 539 STA R32,Y CB12: A9 00 540 LDA #0 CB14: 99 F8 04 541 STA R31,Y CB17: 99 78 04 542 STA R30,Y 543 CB1A: DA 544 PHX ===== Page 11 ===== CB1B: 5A 545 PHY CB1C: A0 09 546 LDY #9 CB1E: A6 3D 547 LDX SLOT ; ASL can't be done with Y CB20: 1E F8 05 548 :LOOP ASL R33,X ; mul block num CB23: 3E 78 05 549 ROL R32,X ; by 512 to get CB26: 3E F8 04 550 ROL R31,X ; real address CB29: 3E 78 04 551 ROL R30,X CB2C: 88 552 DEY CB2D: D0 F1 553 BNE :LOOP CB2F: 7A 554 PLY CB30: FA 555 PLX 556 CB31: A9 58 557 LDA #$58 ; send CMD24 CB33: 9D 80 C0 558 STA DATA,X CB36: 3C 81 C0 559 :WAIT BIT CTRL,X CB39: 10 FB 560 BPL :WAIT CB3B: B9 78 04 561 :ARG LDA R30,Y ; get arg from R30 on CB3E: 9D 80 C0 562 STA DATA,X CB41: 3C 81 C0 563 :WAIT1 BIT CTRL,X CB44: 10 FB 564 BPL :WAIT1 CB46: B9 F8 04 565 LDA R31,Y CB49: 9D 80 C0 566 STA DATA,X CB4C: 3C 81 C0 567 :WAIT11 BIT CTRL,X CB4F: 10 FB 568 BPL :WAIT11 CB51: B9 78 05 569 LDA R32,Y CB54: 9D 80 C0 570 STA DATA,X CB57: 3C 81 C0 571 :WAIT12 BIT CTRL,X CB5A: 10 FB 572 BPL :WAIT12 CB5C: B9 F8 05 573 LDA R33,Y CB5F: 9D 80 C0 574 STA DATA,X CB62: 3C 81 C0 575 :WAIT13 BIT CTRL,X CB65: 10 FB 576 BPL :WAIT13 CB67: A9 FF 577 LDA #DUMMY CB69: 9D 80 C0 578 STA DATA,X ; dummy crc CB6C: 3C 81 C0 579 :WAIT2 BIT CTRL,X CB6F: 10 FB 580 BPL :WAIT2 CB71: A9 FF 581 :GETR1 LDA #DUMMY CB73: 9D 80 C0 582 STA DATA,X ; get R1 CB76: 3C 81 C0 583 :WAIT3 BIT CTRL,X CB79: 10 FB 584 BPL :WAIT3 CB7B: BD 80 C0 585 LDA DATA,X ; get response 586 * 587 * TODO: check for error! 588 * CB7E: C9 FE 589 CMP #$FE CB80: D0 EF 590 BNE :GETR1 ; wait for $FE 591 CB82: 5A 592 PHY CB83: A0 02 593 LDY #2 ; send data to card CB85: 64 3C 594 :LOOPY STZ WORK CB87: B2 44 595 :LOOPW LDA ($44) CB89: 9D 80 C0 596 STA DATA,X CB8C: 3C 81 C0 597 :WAIT4 BIT CTRL,X CB8F: 10 FB 598 BPL :WAIT4 CB91: E6 44 599 INC $44 CB93: D0 02 600 BNE :INW CB95: E6 45 601 INC $45 ; inc msb on page boundary ===== Page 12 ===== CB97: E6 3C 602 :INW INC WORK CB99: D0 EC 603 BNE :LOOPW CB9B: 88 604 DEY CB9C: D0 E7 605 BNE :LOOPY 606 CB9E: A0 02 607 LDY #2 ; send 2 dummy crc bytes CBA0: 9D 80 C0 608 :CRC STA DATA,X CBA3: 3C 81 C0 609 :WAIT5 BIT CTRL,X CBA6: 10 FB 610 BPL :WAIT5 CBA8: 88 611 DEY CBA9: D0 F5 612 BNE :CRC CBAB: 7A 613 PLY 614 CBAC: A9 0F 615 :OK LDA #SSNONE ; disable /CS CBAE: 9D 83 C0 616 STA SS,X CBB1: 18 617 CLC ; no error CBB2: A9 00 618 LDA #0 CBB4: 7A 619 PLY CBB5: 60 620 RTS 621 622 623 ******************************** 624 * 625 * Format 626 * not supported! 627 * 628 ******************************** 629 CBB6: 38 630 FORMAT SEC CBB7: A9 01 631 LDA #$01 ; invalid command CBB9: 60 632 RTS 633 634 635 CBBA: 40 00 00 636 CMD0 HEX 400000 CBBD: 00 00 95 637 HEX 000095 CBC0: 41 00 00 638 CMD1 HEX 410000 CBC3: 00 00 F9 639 HEX 0000F9 CBC6: 48 00 00 640 CMD8 HEX 480000 CBC9: 01 AA 87 641 HEX 01AA87 CBCC: 50 00 00 642 CMD16 HEX 500000 CBCF: 02 00 FF 643 HEX 0200FF CBD2: 77 00 00 644 CMD55 HEX 770000 CBD5: 00 00 65 645 HEX 000065 CBD8: 69 40 00 646 ACMD4140 HEX 694000 CBDB: 00 00 77 647 HEX 000077 CBDE: 69 00 00 648 ACMD410 HEX 690000 CBE1: 00 00 FF 649 HEX 0000FF ===== Page 13 ===== --End assembly, 900 bytes, Errors: 0 Symbol table - alphabetical order: ACMD410 =$CBDE ACMD4140=$CBD8 CMD =$C9D9 CMD0 =$CBBA CMD1 =$CBC0 CMD16 =$CBCC CMD55 =$CBD2 CMD8 =$CBC6 CMDHI =$41 CMDLO =$40 CTRL =$C081 CURSLOT =$07F8 DATA =$C080 DIV =$C082 DRIVER =$C85F DUMMY =$FF FORMAT =$CBB6 GETR1 =$C9ED GETR3 =$CA08 INIT =$C900 INSLP =$C827 INSLP2 =$C83D INSOUT =$C85E R30 =$0478 R31 =$04F8 R32 =$0578 R33 =$05F8 READ =$CA45 SLOT =$3D SLOT16 =$2B SS =$C083 SS0 =$0E SSNONE =$0F STATUS =$CA3D WORK =$3C WRITE =$CB00 Symbol table - numerical order: SS0 =$0E SSNONE =$0F SLOT16 =$2B WORK =$3C SLOT =$3D CMDLO =$40 CMDHI =$41 DUMMY =$FF R30 =$0478 R31 =$04F8 R32 =$0578 R33 =$05F8 CURSLOT =$07F8 DATA =$C080 CTRL =$C081 DIV =$C082 SS =$C083 INSLP =$C827 INSLP2 =$C83D INSOUT =$C85E DRIVER =$C85F INIT =$C900 CMD =$C9D9 GETR1 =$C9ED GETR3 =$CA08 STATUS =$CA3D READ =$CA45 WRITE =$CB00 FORMAT =$CBB6 CMD0 =$CBBA CMD1 =$CBC0 CMD8 =$CBC6 CMD16 =$CBCC CMD55 =$CBD2 ACMD4140=$CBD8 ACMD410 =$CBDE