diff --git a/Makefile b/Makefile old mode 100755 new mode 100644 index 5e4d6636..f1da873d --- a/Makefile +++ b/Makefile @@ -17,7 +17,7 @@ else D64_TEMPLATE = GEOS64.D64 endif -ASFLAGS = -I inc -I . +ASFLAGS = -I inc -I . --cpu 6502X # code that is in front bank of all variants KERNAL_SOURCES= \ @@ -233,6 +233,7 @@ endif DRIVER_SOURCES= \ drv/drv1541.bin \ + drv/drv1541parallel.bin \ drv/drv1571.bin \ drv/drv1581.bin \ input/joydrv.bin \ @@ -269,6 +270,7 @@ PREFIXED_RELOCATOR_OBJS = $(addprefix $(BUILD_DIR)/, $(RELOCATOR_OBJS)) ALL_BINS= \ $(BUILD_DIR)/kernal/kernal.bin \ $(BUILD_DIR)/drv/drv1541.bin \ + $(BUILD_DIR)/drv/drv1541parallel.bin \ $(BUILD_DIR)/drv/drv1571.bin \ $(BUILD_DIR)/drv/drv1581.bin \ $(BUILD_DIR)/input/joydrv.bin \ @@ -379,6 +381,9 @@ endif $(BUILD_DIR)/drv/drv1541.bin: $(BUILD_DIR)/drv/drv1541.o drv/drv1541.cfg $(DEPS) $(LD) -C drv/drv1541.cfg $(BUILD_DIR)/drv/drv1541.o -o $@ +$(BUILD_DIR)/drv/drv1541parallel.bin: $(BUILD_DIR)/drv/drv1541parallel.o drv/drv1541parallel.cfg $(DEPS) + $(LD) -C drv/drv1541parallel.cfg -m $(BUILD_DIR)/drv/drv1541parallel.map $(BUILD_DIR)/drv/drv1541parallel.o -o $@ + $(BUILD_DIR)/drv/drv1571.bin: $(BUILD_DIR)/drv/drv1571.o drv/drv1571.cfg $(DEPS) $(LD) -C drv/drv1571.cfg $(BUILD_DIR)/drv/drv1571.o -o $@ diff --git a/README.md b/README.md index 6536e78f..e3fd1455 100755 --- a/README.md +++ b/README.md @@ -81,7 +81,7 @@ Without pucrunch/c1541, you can still build an uncompressed KERNAL binary image. Run `make` to build the original "BSW" GEOS for C64. This will create the following files in directory `build/bsw`: * raw KERNAL components: `kernal.bin`, `lokernal.bin`, `init.bin` -* disk drive drivers: `drv1541.bin`, `drv1571.bin`, `drv1581.bin` +* disk drive drivers: `drv1541.bin`, `drv1541parallel.bin`, `drv1571.bin`, `drv1581.bin` * input drivers: `amigamse.bin`, `joydrv.bin`, `lightpen.bin`, `mse1351.bin`, `koalapad.bin`, `pcanalog.bin` * combined KERNAL image (`SYS 49155`): `kernal_combined.prg` * compressed KERNAL image (`RUN`): `kernal_compressed.prg` @@ -112,7 +112,7 @@ By default, the KERNAL image will contain the Commodore 1541 disk driver (`drv15 make DRIVE= INPUT= -Supported drives are `drv1541`, `drv1571` and `drv1581`. Supported input devices are `amigamse`, `joydrv`, `koalapad`, `lightpen`, `mse1351` and `pcanalog`. +Supported drives are `drv1541`, `drv1541parallel`, `drv1571` and `drv1581`. Supported input devices are `amigamse`, `joydrv`, `koalapad`, `lightpen`, `mse1351` and `pcanalog`. ## Customization diff --git a/config.inc b/config.inc index eca79b6a..b028f71f 100755 --- a/config.inc +++ b/config.inc @@ -168,6 +168,8 @@ REUPresent = 1 .if .defined(drv1541) DRV_TYPE = 1 ; DRV_1541 +.elseif .defined(drv1541parallel) +DRV_TYPE = 1; DRV_1541 .elseif .defined(drv1571) DRV_TYPE = 2; DRV_1571 .elseif .defined(drv1581) diff --git a/drv/drv1541.s b/drv/drv1541.s index 378f303b..b26cd8f7 100644 --- a/drv/drv1541.s +++ b/drv/drv1541.s @@ -1298,7 +1298,7 @@ Drv_ExitTurbo: jsr D_DUNK4_1 LoadB $33, 0 sta $1800 - jsr $f98f + jsr $f98f ; turn drive motor off LoadB $1c0c, $ec pla pla @@ -1435,7 +1435,7 @@ Drv_NewDisk_4: Drv_NewDisk_5: txa Drv_NewDisk_6: - jsr $f24b + jsr $f24b ; Establish number of sectors per track (in: A=track, out: A=number of sectors on that track) sta $43 Drv_NewDisk_7: lda $1c00 @@ -1528,11 +1528,11 @@ D_DUNK11_1: beq D_DUNK11_3 cmp #$30 beq D_DUNK11_2 - jmp $f4ca + jmp $f4ca ; Test command code further ($00=read, $10=write, $20=verify, other=read block header) D_DUNK11_2: - jmp $f3b1 + jmp $f3b1 ; Read block header, verify ID D_DUNK11_3: - jsr $f5e9 + jsr $f5e9 ; Calculate parity for data buffer ($30) sta $3a lda $1c00 and #$10 @@ -1540,11 +1540,11 @@ D_DUNK11_3: lda #$08 bne D_DUNK11_9 D_DUNK11_4: - jsr $f78f - jsr $f510 + jsr $f78f ; Convert 260 bytes (256+4) to 325 bytes group code buffer $01BB-$01FF and ($30) + jsr $f510 ; Read block header (wait until needed block header arrives) ldx #9 D_DUNK11_5: - bvc D_DUNK11_5 + bvc D_DUNK11_5 ; skip over sync clv dex bne D_DUNK11_5 @@ -1565,14 +1565,14 @@ D_DUNK11_6: bne D_DUNK11_6 ldy #$bb D_DUNK11_7: - lda $0100,y + lda $0100,y ; write data bvc * clv sta $1c01 iny bne D_DUNK11_7 D_DUNK11_8: - lda ($30),y + lda ($30),y ; write data, continued bvc * clv sta $1c01 @@ -1593,9 +1593,9 @@ D_DUNK12: lda $20 and #$20 bne D_DUNK12_3 - jsr $f97e + jsr $f97e ; Turn drive motor on D_DUNK12_1: - ldy #$80 + ldy #$80 ; delay until it spins up D_DUNK12_2: dex bne D_DUNK12_2 diff --git a/drv/drv1541parallel.cfg b/drv/drv1541parallel.cfg new file mode 100644 index 00000000..d24cfb28 --- /dev/null +++ b/drv/drv1541parallel.cfg @@ -0,0 +1,13 @@ +MEMORY { + DISK_BASE: start = $9000, size = $0D80, file = %O; + + DRIVE0300: start = $0300, size = $0500, define = yes; + DRIVE0060: start = $0086, size = $70; +} + +SEGMENTS { + drv1541: load = DISK_BASE, type = ro; + drv1541_drivecode: load = DISK_BASE, run = DRIVE0300, type = ro, define = yes; + drv1541_zp: load = DISK_BASE, run = DRIVE0060, type = ro, define = yes; + drv1541_b: load = DISK_BASE, type = ro; +} diff --git a/drv/drv1541parallel.s b/drv/drv1541parallel.s new file mode 100755 index 00000000..66adeb2c --- /dev/null +++ b/drv/drv1541parallel.s @@ -0,0 +1,1720 @@ +; GEOS by Berkeley Softworks +; reverse engineered by Maciej Witkowiak, Michael Steil +; +; On the fly sector read and GCR decoding code from Spindle 3.1 by lft, linusakesson.net/software/spindle/ +; +; Commodore 1541 disk driver with parallel cable by Maciej Witkowiak + +.include "const.inc" +.include "geossym.inc" +.include "geosmac.inc" +.include "config.inc" +.include "kernal.inc" +.include "jumptab.inc" +.include "c64.inc" + +.import __DRIVE0300_START__ +.import __DRIVE0300_LAST__ + +.import __drv1541_drivecode_RUN__ +.import __drv1541_drivecode_SIZE__ +.import __drv1541_zp_RUN__ +.import __drv1541_zp_LOAD__ +.import __drv1541_zp_SIZE__ + +; interleave testing in VICE (load DESK TOP saved with that interleave, count cycles between c326 and c3a8) +; interleave start end diff diff% +;1 124188392 138549570 14361178 226% +;2 206544077 221469179 14925102 235% +;3 323246805 326144363 2897558 46% +;4 377406197 380848405 3442208 54% +;5 444598875 448993889 4395014 69% +;6 503908689 508692309 4783620 75% +;7 567056391 572631055 5574664 88% +;8 630004373 636087138 6082765 96% +;9 717602340 724270720 6668380 105% +;10 779826865 787041178 7214313 113% +;11 873107683 881082247 7974564 125% +;12 924738595 933295187 8556592 135% +;13 1014288120 1023780169 9492049 149% +;14 1076008138 1085921087 9912949 156% +;15 1154807307 1165244853 10437546 164% + + +OPTIMAL_INTERLEAVE = 3 + +DExeProc = $80 +DTrkSec = $82 +DTrkSecH = $83 + +.segment "drv1541" + +_InitForIO: + .word __InitForIO +_DoneWithIO: + .word __DoneWithIO +_ExitTurbo: + .word __ExitTurbo +_PurgeTurbo: + .word __PurgeTurbo +_EnterTurbo: + .word __EnterTurbo +_ChangeDiskDevice: + .word __ChangeDiskDevice +_NewDisk: + .word __NewDisk +_ReadBlock: + .word __ReadBlock +_WriteBlock: + .word __WriteBlock +_VerWriteBlock: + .word __VerWriteBlock +_OpenDisk: + .word __OpenDisk +_GetBlock: + .word __GetBlock +_PutBlock: + .word __PutBlock +_GetDirHead: + .word __GetDirHead +_PutDirHead: + .word __PutDirHead +_GetFreeDirBlk: + .word __GetFreeDirBlk +_CalcBlksFree: + .word __CalcBlksFree +_FreeBlock: + .word __FreeBlock +_SetNextFree: + .word __SetNextFree +_FindBAMBit: + .word __FindBAMBit +_NxtBlkAlloc: + .word __NxtBlkAlloc +_BlkAlloc: + .word __BlkAlloc +_ChkDkGEOS: + .word __ChkDkGEOS +_SetGEOSDisk: + .word __SetGEOSDisk + +Get1stDirEntry: + jmp _Get1stDirEntry +GetNxtDirEntry: + jmp _GetNxtDirEntry +GetBorder: + jmp _GetBorder +AddDirBlock: + jmp _AddDirBlock +ReadBuff: + jmp _ReadBuff +WriteBuff: + jmp _WriteBuff + jmp DUNK4_1 + jmp GetDOSError +AllocateBlock: + jmp _AllocateBlock +ReadLink: + jmp _ReadLink + +__GetDirHead: + jsr SetDirHead + bne __GetBlock +_ReadBuff: + LoadW r4, diskBlkBuf +__GetBlock: + jsr EnterTurbo + bnex GetBlk0 + jsr InitForIO + jsr ReadBlock + jsr DoneWithIO +GetBlk0: + rts + +__PutDirHead: + jsr SetDirHead + bne __PutBlock +_WriteBuff: + LoadW r4, diskBlkBuf +__PutBlock: + jsr EnterTurbo + bnex PutBlk1 + jsr InitForIO + jsr WriteBlock + bnex PutBlk0 + jsr VerWriteBlock +PutBlk0: + jsr DoneWithIO +PutBlk1: + rts + +SetDirHead: + LoadB r1L, DIR_TRACK + LoadB r1H, 0 + sta r4L + LoadB r4H, (>curDirHead) + rts + +CheckParams: +CheckParams_1: + lda #0 + sta errCount + ldx #INV_TRACK + lda r1L + beq CheckParams_2 + cmp #N_TRACKS+1 + bcs CheckParams_2 + sec + rts +CheckParams_2: + clc + rts + +__OpenDisk: + ldy curDrive + lda _driveType,y + sta tmpDriveType + and #%10111111 + sta _driveType,y + jsr NewDisk + bnex OpenDsk1 + jsr GetDirHead + bnex OpenDsk1 + jsr SetDirHead +OpenDsk0: + LoadW r5, curDirHead + jsr ChkDkGEOS + LoadW r4, curDirHead+OFF_DISK_NAME + ldx #r5 + jsr GetPtrCurDkNm + ldx #r4 + ldy #r5 + lda #18 + jsr CopyFString + ldx #0 +OpenDsk1: + lda tmpDriveType + ldy curDrive + sta _driveType,y + rts +tmpDriveType: + .byte 0 + +__BlkAlloc: + ldy #1 + sty r3L + dey + sty r3H +__NxtBlkAlloc: + PushW r9 + PushW r3 + LoadW r3, $00fe + ldx #r2 + ldy #r3 + jsr Ddiv + lda r8L + beq BlkAlc0 + inc r2L + bne BlkAlc0 + inc r2H +BlkAlc0: + LoadW r5, curDirHead + jsr CalcBlksFree + PopW r3 + ldx #INSUFF_SPACE + CmpW r2, r4 + beq BlkAlc1 + bcs BlkAlc4 +BlkAlc1: + MoveW r6, r4 + MoveW r2, r5 +BlkAlc2: + jsr SetNextFree + bnex BlkAlc4 + ldy #0 + lda r3L + sta (r4),y + iny + lda r3H + sta (r4),y + AddVW 2, r4 + lda r5L + bne @X + dec r5H +@X: dec r5L + lda r5L + ora r5H + bne BlkAlc2 + ldy #0 + tya + sta (r4),y + iny + lda r8L + bne BlkAlc3 + lda #$fe +BlkAlc3: + clc + adc #1 + sta (r4),y + ldx #0 +BlkAlc4: + PopW r9 + rts + +_Get1stDirEntry: + LoadB r1L, DIR_TRACK + LoadB r1H, 1 + jsr ReadBuff + LoadW r5, diskBlkBuf+FRST_FILE_ENTRY + lda #0 + sta borderFlag + rts + +_GetNxtDirEntry: + ldx #0 + ldy #0 + AddVW $20, r5 + CmpWI r5, diskBlkBuf+$ff + bcc GNDirEntry1 + ldy #$ff + MoveW diskBlkBuf, r1 + bne GNDirEntry0 + lda borderFlag + bne GNDirEntry1 + lda #$ff + sta borderFlag + jsr GetBorder + bnex GNDirEntry1 + tya + bne GNDirEntry1 +GNDirEntry0: + jsr ReadBuff + ldy #0 + LoadW r5, diskBlkBuf+FRST_FILE_ENTRY +GNDirEntry1: + rts + +_GetBorder: + jsr GetDirHead + bnex GetBord2 + LoadW r5, curDirHead + jsr ChkDkGEOS + bne GetBord0 + ldy #$ff + bne GetBord1 +GetBord0: + MoveW curDirHead+OFF_OP_TR_SC, r1 + ldy #0 +GetBord1: + ldx #0 +GetBord2: + rts + +__ChkDkGEOS: + ldy #OFF_GS_ID + ldx #0 + LoadB isGEOS, 0 +ChkDkG0: + lda (r5),y + cmp GEOSDiskID,x + bne ChkDkG1 + iny + inx + cpx #11 + bne ChkDkG0 + LoadB isGEOS, $ff +ChkDkG1: + lda isGEOS + rts + +GEOSDiskID: + .byte "GEOS format V1.0",NULL + +__GetFreeDirBlk: + php + sei + PushB r6L + PushW r2 + ldx r10L + inx + stx r6L + LoadB r1L, DIR_TRACK + LoadB r1H, 1 +GFDirBlk0: + jsr ReadBuff +GFDirBlk1: + bnex GFDirBlk5 + dec r6L + beq GFDirBlk3 +GFDirBlk11: + lda diskBlkBuf + bne GFDirBlk2 + jsr AddDirBlock + bra GFDirBlk1 +GFDirBlk2: + sta r1L + MoveB diskBlkBuf+1, r1H + bra GFDirBlk0 +GFDirBlk3: + ldy #FRST_FILE_ENTRY + ldx #0 +GFDirBlk4: + lda diskBlkBuf,y + beq GFDirBlk5 + tya + addv $20 + tay + bcc GFDirBlk4 + LoadB r6L, 1 + ldx #FULL_DIRECTORY + ldy r10L + iny + sty r10L + cpy #$12 + bcc GFDirBlk11 +GFDirBlk5: + PopW r2 + PopB r6L + plp + rts + +_AddDirBlock: + PushW r6 + ldy #$48 + ldx #FULL_DIRECTORY + lda curDirHead,y + beq ADirBlk0 + MoveW r1, r3 + jsr SetNextFree + MoveW r3, diskBlkBuf + jsr WriteBuff + bnex ADirBlk0 + MoveW r3, r1 + jsr ClearAndWrite +ADirBlk0: + PopW r6 + rts + +ClearAndWrite: + lda #0 + tay +CAndWr0: + sta diskBlkBuf,y + iny + bne CAndWr0 + dey + sty diskBlkBuf+1 + jmp WriteBuff + +__SetNextFree: + lda r3H + add interleave + sta r6H + MoveB r3L, r6L + cmp #25 + bcc SNxtFree0 + dec r6H +SNxtFree0: + cmp #DIR_TRACK + beq SNxtFree1 +SNxtFree00: + lda r6L + cmp #DIR_TRACK + beq SNxtFree3 +SNxtFree1: + asl + asl + tax + lda curDirHead,x + beq SNxtFree3 + lda r6L + jsr SNxtFreeHelp + lda SecScTab,x + sta r7L + tay +SNxtFree2: + jsr SNxtFreeHelp2 + beq SNxtFree4 + inc r6H + dey + bne SNxtFree2 +SNxtFree3: + inc r6L + CmpBI r6L, N_TRACKS+1 + bcs SNxtFree5 + sub r3L + sta r6H + asl + adc #4 + adc interleave + sta r6H + bra SNxtFree00 +SNxtFree4: + MoveW_ r6, r3 + ldx #0 + rts +SNxtFree5: + ldx #INSUFF_SPACE + rts + +SNxtFreeHelp: + ldx #0 +SNFHlp0: + cmp SecTrTab,x + bcc SNFHlp1 + inx + bne SNFHlp0 +SNFHlp1: + rts + +SecTrTab: + .byte 18, 25, 31, 36 +SecScTab: + .byte 21, 19, 18, 17 + +SNxtFreeHelp2: + lda r6H +SNFHlp2_1: + cmp r7L + bcc SNFHlp2_2 + sub r7L + bra SNFHlp2_1 +SNFHlp2_2: + sta r6H + +_AllocateBlock: + jsr FindBAMBit + beq SNFHlp2_3 + lda r8H + eor #$ff + and curDirHead,x + sta curDirHead,x + ldx r7H + dec curDirHead,x + ldx #0 + rts +SNFHlp2_3: + ldx #BAD_BAM + rts + +__FindBAMBit: + lda r6L + asl + asl + sta r7H + lda r6H + and #%00000111 + tax + lda FBBBitTab,x + sta r8H + lda r6H + lsr + lsr + lsr + sec + adc r7H + tax + lda curDirHead,x + and r8H + rts + +FBBBitTab: + .byte $01, $02, $04, $08 + .byte $10, $20, $40, $80 + +__FreeBlock: + jsr FindBAMBit + bne FreeBlk0 + lda r8H + eor curDirHead,x + sta curDirHead,x + ldx r7H + inc curDirHead,x + ldx #0 + rts +FreeBlk0: + ldx #BAD_BAM + rts + +__CalcBlksFree: + LoadW_ r4, 0 + ldy #OFF_TO_BAM +CBlksFre0: + lda (r5),y + add r4L + sta r4L + bcc CBlksFre1 + inc r4H +CBlksFre1: + tya + clc + adc #4 + tay + cpy #$48 + beq CBlksFre1 + cpy #$90 + bne CBlksFre0 + LoadW r3, $0298 + rts + +__SetGEOSDisk: + jsr GetDirHead + bnex SetGDisk2 + LoadW r5, curDirHead + jsr CalcBlksFree + ldx #INSUFF_SPACE + lda r4L + ora r4H + beq SetGDisk2 + LoadB r3L, DIR_TRACK+1 + LoadB r3H, 0 + jsr SetNextFree + beqx SetGDisk0 + LoadB r3L, 1 + jsr SetNextFree + bnex SetGDisk2 +SetGDisk0: + MoveW r3, r1 + jsr ClearAndWrite + bnex SetGDisk2 + MoveW r1, curDirHead+OFF_OP_TR_SC + ldy #OFF_GS_ID+15 + ldx #15 +SetGDisk1: + lda GEOSDiskID,x + sta curDirHead,y + dey + dex + bpl SetGDisk1 + jsr PutDirHead +SetGDisk2: + rts + +__InitForIO: + php + PopB tmpPS + sei + MoveB CPU_DATA, tmpCPU_DATA +.ifndef bsw128 + LoadB CPU_DATA, KRNL_IO_IN +.endif + MoveB grirqen, tmpgrirqen + MoveB clkreg, tmpclkreg + ldy #0 + sty clkreg + sty grirqen + lda #%01111111 + sta grirq + sta cia1base+13 + sta cia2base+13 + lda #>D_IRQHandler + sta irqvec+1 +.ifdef bsw128 + sta nmivec+1 +.endif + lda #D_NMIHandler + sta nmivec+1 + lda #EnterCommand + lda #DriveCode + LoadW DTrkSec, __DRIVE0300_START__ ; target address +EntTur1: + ldx #>Drv_RecvZP ; recieve data + lda #DriveCode + sta z8c + ldy #0 + jsr Hst_SendByte + inc DTrkSecH + inc EntTH+1 + CmpBI DTrkSecH, >(__DRIVE0300_LAST__) + bne EntTur1 + ; send page 7 data to page 2 + LoadB DTrkSecH, $02 + ldx #>Drv_RecvZP + lda #Drv_ExitTurbo + lda #WriteCommand + lda #Drv_NewDisk + lda #Drv_ChngDskDev + lda #Drv_RecvZP ; recieve data + lda #Drv_ReadSec ; read sector and status + lda #Drv_WriteSec + lda #Drv_SendByte_0 + lda #(DriveLoop-1) ; return address + pha + lda #<(DriveLoop-1) + pha + jmp (DExecAddy) + +Drv_LedOFF: + lda #$f7 + and $1c00 +Drv_LedDo: + sta $1c00 + rts +Drv_LedON: + lda #$08 + ora $1c00 + bne Drv_LedDo + +Drv_RecvZP: + MoveW DDatas, $73 + jmp Drv_RecvWord + +Drv_END_MW_CODE: ; marker for end of code that has to be sent via M-W command + +Drv_SendByte_0: + LoadB $1803, $ff ; send length (1) and status byte from $00 +Drv_SendStatus: + LoadB $1801, $01 ; send length + lda #$10 +: bit $180d ; wait for handshake + beq :- + bit $1800 ; clear flag + ldy $00 + sty $1801 ; send status +: bit $180d ; wait for handshake + beq :- + bit $1800 ; clear flag + LoadB $1803, $00 ; port A input + rts + + +Drv_ExitTurbo: + jsr Drv_RestorePage7 + jmp Drv_DoExitTurbo + +Drv_ChngDskDev: + lda DDatas + sta $77 + eor #$60 + sta $78 + rts + +D_DUNK4: + dec $48 + bne D_DUNK4_1 + jsr D_DUNK8_2 +D_DUNK4_1: + LoadB $1800, 0 + rts + +D_DUNK5: + jsr D_DUNK12 + lda $22 + beq D_DUNK5_1 + ldx $00 + dex + beq D_DUNK5_2 +D_DUNK5_1: + lda $12 ; was disk logged in? + ora $13 + beq :+ ; no, just read the ID + + PushB $12 ; preserve current disk ID + PushB $13 + jsr Drv_NewDisk_1 + PopB $13 + tax + PopB $12 + ldy $00 + cpy #$01 ; any error? + bne D_DUNK5_41 ; yes, error + cpx $17 ; different ID? + bne D_DUNK5_5 ; yes, error + cmp $16 + bne D_DUNK5_5 + beq :++ + +: jsr Drv_NewDisk_1 ; login disk +: lda #0 ; ID the same +D_DUNK5_2: + pha + lda $22 + ldx #$ff + sec + sbc DDatas + beq D_DUNK5_4 + bcs D_DUNK5_3 + eor #$ff + adc #1 + ldx #1 +D_DUNK5_3: + jsr D_DUNK6 + lda DDatas + sta $22 + jsr Drv_NewDisk_6 +D_DUNK5_4: + pla +D_DUNK5_41: + rts +D_DUNK5_5: + LoadB $00, $0b ; ID mismatch + rts + +D_DUNK6: + stx $4a + asl + tay + lda $1c00 + and #$fe + sta $70 + lda #$1e + sta $71 +D_DUNK6_1: + lda $70 + add $4a + eor $70 + and #%00000011 + eor $70 + sta $70 + sta $1c00 + lda $71 + jsr D_DUNK6_4 + lda $71 + cpy #5 + bcc D_DUNK6_2 + cmp #$11 + bcc D_DUNK6_3 + sbc #2 + bne D_DUNK6_3 +D_DUNK6_2: + cmp #$1c + bcs D_DUNK6_3 + adc #4 +D_DUNK6_3: + sta $71 + dey + bne D_DUNK6_1 + lda #$4b +D_DUNK6_4: + sta $1805 + lda $1805 + bne *-3 + rts + +Drv_NewDisk: + jsr D_DUNK12 +Drv_NewDisk_1: + ldx $00 + dex + beq Drv_NewDisk_2 + ldx #$ff + lda #$01 + jsr D_DUNK6 + lax #$01 + jsr D_DUNK6 + lda #$ff + jsr D_DUNK6_4 +Drv_NewDisk_2: + LoadB $70, $04 +Drv_NewDisk_3: + jsr D_DUNK11 + ldx $18 + stx $22 + ldy $00 + dey + beq Drv_NewDisk_5 + dec $70 + bmi Drv_NewDisk_4 + ldx $70 + jsr Drv_NewDisk_7 + sec + bcs Drv_NewDisk_3 +Drv_NewDisk_4: + LoadB $22, 0 + rts +Drv_NewDisk_5: + txa +Drv_NewDisk_6: + jsr $f24b ; Establish number of sectors per track (in: A=track, out: A=number of sectors on that track, X=speed zone number) + sta $43 +Drv_NewDisk_7: + lda $1c00 ; set speedzone + and #$9f + ora DTrackTab,x +Drv_NewDisk_8: + sta $1c00 + rts + +D_DUNK8_2: + LoadB $20, 0 + LoadB $3e, $ff + lda #$fb + and $1c00 + jmp Drv_NewDisk_8 + +DTrackTab: ; speedzone (bitrate) bits for $1c00 + .byte $00, $20, $40, $60 + +D_DUNK9: + tax + bbrf 7, $20, D_DUNK9_0 + jsr D_DUNK12_1 + LoadB $20, $20 + ldx #0 +D_DUNK9_0: + cpx $22 + beq D_DUNK9_1 + jsr Drv_NewDisk_2 + cmp #1 + bne D_DUNK9_1 + ldy $19 + iny + cpy $43 + bcc @X + ldy #0 +@X: sty $19 + LoadB $45, 0 ; job READ + LoadW $32, $0018 ; sector 18,0 + jsr D_DUNK11_1 +D_DUNK9_1: + rts + +Drv_WriteSec: + LoadB DLastOper, 1 ; mark that $07xx will be destroyed + jsr D_DUNK5 + ldx $00 + dex + bne D_DUNK10_1 + jsr D_DUNK9 +D_DUNK10_1: + jsr Drv_RecvWord + lda #$10 + bne D_DUNK10_2 + +Drv_RestorePage7: + lda DLastOper ; last operation was READ? + beq :++ + ldx #0 ; no, restore that code after write + stx DLastOper +: lda $0200,x + sta $0700,x + inx + cpx #<(__DRIVE0300_LAST__-__DRIVE0300_START__) + bne :- +: rts + +Drv_ReadSec: + jsr Drv_RestorePage7 + jsr D_DUNK5 + lda #0 +D_DUNK10_2: + ldx $00 + dex + beq D_DUNK11_0 + rts + +D_DUNK11: + lda #$30 ; job $B0 = SEEK +D_DUNK11_0: + sta $45 + lda #>DDatas + sta $33 + lda # carry + sta first_mod3+1 + + bvc * + lax $1c01 ; 0 1 2 3 ddddeeee + .byt $6b,$f0 ; 4 5 arr imm, ddddd000 + clv ; 6 7 + tay ; 8 9 +first_mod3: lda gcrdecode ; 10 11 12 13 lsb = 000ccccc + ora gcrdecode+1,y ; 14 15 16 17 y = ddddd000, lsb = 00000001 + pha ; 18 19 20 first byte to $100 + + ; get sector number from the lowest 5 bits of the first byte + + and #$1f ; 21 22 + tay ; 23 24 + nop ; lda interested,y ; 25 26 + nop ; lda interested,y ; 27 28 + nop ; beq notint (not taken) ; 29 30 + ;lda interested,y ; 25 26 27 28 +;mod_safety: + ;beq notint ; 29 30 + + jmp zpc_entry ; 31 32 33 x = ----eeee +zp_return: + .byt $6b,$f0 ; arr imm, ddddd000 + tay + lda gcrdecode,x ; x = 000ccccc + ora gcrdecode+1,y ; y = ddddd000, lsb = 00000001 + + sta $24 ; checksum + +Drv_ReadSec_DataOut: + ; send out data, compute checksum + ldy #$ff + sty $1803 ; port B output + iny + sty $25 ; clear computed checksum +: pla + sta $1801 ; send next byte (reversed order, as host expects) + eor $25 + sta $25 ; update checksum + lda #$10 ; handshake test bit pattern +: bit $180d ; wait for handshake + beq :- + bit $1800 ; clear CB1 flag + dey + cpy #0 + bne :-- + + CmpBI $00, 1 ; if there is error already + bne :+ ; return it + CmpB $24, $25 ; otherwise compare checksums + beq :+ + LoadB $00, 5 ; checksum error + ; if header was found in time and checksum is OK then send status byte==1 + ; if header not found, send error $04 +: jsr Drv_SendStatus + + ; restore stack pointer (must be below $01bb) + ldx #$45 + txs + + ; return to main loop (XXX ExitTurbo must warm reset drive somehow because we have destroyed stack contents) + jmp DriveLoop + +Drv_DoExitTurbo: + jsr Drv_LedOFF + ldy $78 ; preserve device number + lax #0 +: sta $00,x + sta $0200,x + inx + bne :- + bit $1801 ; final sync + LoadB $180c, $01 ; CA1 (ATN IN) trigger on positive edge + lda #$82 + sta $180d ; interrupt possible through ATN IN + sta $180e + ldx #$45 + txs + tya ; restore device number ($78) + jmp $eb45 ; reset routine, after RAM/ROM test when device number is set + + +.segment "drv1541_zp" : zeropage + +prof_zp: +zpc_loop: + ; This nop is needed for the slow bitrates (at least for 00), + ; because apparently the third byte after a bvc sync might not be + ; ready at cycle 65 after all. + + ; However, with the nop, the best case time for the entire loop + ; is 128 cycles, which leaves too little slack for motor speed + ; variance at bitrate 11. + + ; Thus, we modify the bne instruction at the end of the loop to + ; either include or skip the nop depending on the current + ; bitrate. + + nop + + lax $1c01 ; 62 63 64 65 ddddeeee + .byte $6b,$f0 ; 66 67 arr imm, ddddd000 + clv ; 68 69 + tay ; 70 71 +zpc_mod3: lda gcrdecode ; 72 73 74 75 lsb = 000ccccc + ora gcrdecode+1,y ; 76 77 78 79 y = ddddd000, lsb = 00000001 + + ; first read in [0..25] + ; second read in [32..51] + ; third read in [64..77] + ; clv in [64..77] + ; in total, 80 cycles from bvc + + bvc * ; 0 1 + + pha ; 2 3 4 second complete byte (nybbles c, d) +zpc_entry: + lda #$0f ; 5 6 + sax z:zpc_mod5+1 ; 7 8 9 + + lda $1c01 ; 10 11 12 13 efffffgg + ldx #$03 ; 14 15 + sax z:zpc_mod7+1 ; 16 17 18 + .byte $4b,$fc ; 19 20 asr imm, 0efffff0 + tay ; 21 22 + ldx #$79 ; 23 24 +zpc_mod5: lda gcrdecode,x ; 25 26 27 28 lsb = 0000eeee, x = 01111001 + eor gcrdecode+$40,y ; 29 30 31 32 y = 0efffff0, lsb = 01000000 + pha ; 33 34 35 third complete byte (nybbles e, f) + + lax $1c01 ; 36 37 38 39 ggghhhhh + clv ; 40 41 + and #$1f ; 42 43 + tay ; 44 45 + + ; first read in [0..25] + ; second read in [32..51] + ; clv in [32..51] + ; in total, 46 cycles from bvc + + bvc * ; 0 1 + + lda #$e0 ; 2 3 + .byte $cb, $00 ; sbx #0 ; 4 5 +zpc_mod7: lda gcrdecode,x ; 6 7 8 9 x = ggg00000, lsb = 000000gg + ora gcrdecode+$20,y ; 10 11 12 13 y = 000hhhhh, lsb = 00100000 + pha ; 14 15 16 fourth complete byte (nybbles g, h) + + ; start of a new 5-byte chunk + + lda $1c01 ; 17 18 19 20 aaaaabbb + ldx #$f8 ; 21 22 + sax z:zpc_mod1+1 ; 23 24 25 + and #$07 ; 26 27 + ora #$08 ; 28 29 + tay ; 30 31 + + lda $1c01 ; 32 33 34 35 bbcccccd + ldx #$c0 ; 36 37 + sax z:zpc_mod2+1 ; 38 39 40 + .byt $4b,$3f ; 41 42 asr imm, 000ccccc, d -> carry + sta z:zpc_mod3+1 ; 43 44 45 + +zpc_mod1: lda gcrdecode ; 46 47 48 49 lsb = aaaaa000 +zpc_mod2: eor gcrdecode,y ; 50 51 52 53 lsb = bb000000, y = 00001bbb + pha ; 54 55 56 first complete byte (nybbles a, b) + + tsx ; 57 58 +BNE_WITH_NOP = (zpc_loop - (* + 2)) & $ff +BNE_WITHOUT_NOP = (zpc_loop + 1 - (* + 2)) & $ff +zpc_bne: .byt $d0,BNE_WITHOUT_NOP ; 59 60 61 bne zpc_loop + + ldx z:zpc_mod3+1 ; 61 62 63 + lda $1c01 ; 64 65 66 67 ddddeeee + jmp zp_return + +.segment "drv1541_b" + +tmpclkreg: + .byte 0 +tmpPS: + .byte 0 +tmpgrirqen: + .byte 0 +tmpCPU_DATA: + .byte 0 +tmpmobenble: + .byte 0 +errCount: + .byte 0 +errStore: + .byte 0 +borderFlag: + .byte 0 +LastOper: + .byte $ff + diff --git a/kernal/start/start64.s b/kernal/start/start64.s index b8725583..700e9f28 100644 --- a/kernal/start/start64.s +++ b/kernal/start/start64.s @@ -68,6 +68,9 @@ ; _ResetHandle: +.ifdef drv1541parallel + jsr detect_1541s +.endif sei cld ldx #$FF @@ -130,6 +133,20 @@ ASSERT_NOT_BELOW_IO ; jsr FirstInit jsr MouseInit +.ifdef drv1541parallel + LoadB NUMDRV, 0 + ldy #8 +: lda drives,y + cmp #DRV_1541 + bne :+ + sta _driveType,y + inc NUMDRV +: iny + cpy #12 + bne :-- + LoadB curType, DRV_1541 + MoveB curDevice, curDrive +.else lda #currentInterleave sta interleave @@ -140,6 +157,7 @@ ASSERT_NOT_BELOW_IO lda #DRV_TYPE ; see config.inc sta curType sta _driveType,y +.endif ; This is the original code the cbmfiles version ; has at $5000. @@ -209,3 +227,208 @@ bootSec2: .byte 0 bootOffs: .byte 0 + +.ifdef drv1541parallel + +; ------------------------------------------ + +k_second = $ff93 +k_unlstn = $ffae +k_listen = $ffb1 +k_setlfs = $ffba +k_setnam = $ffbd +k_open = $ffc0 +k_close = $ffc3 +k_chkin = $ffc6 +k_clrchn = $ffcc +k_chrin = $ffcf +k_chrout = $ffd2 +k_getin = $ffe4 + +drives = *-8 + .byte 0, 0, 0, 0 + +; multiple daisy-chained parallel port connections work with 1541 (see DualDriveBurstBackup) +; but 1541 ROM will set port A to output upon boot ($FF10) - not clear why +; so we have to scan for all attached 1541s and run M-W,$1803,1,0 to set port A as input + +detect_1541s: + PushB CPU_DATA + PushB curDevice +ASSERT_NOT_BELOW_IO + LoadB CPU_DATA, KRNL_IO_IN + jsr drive_poll + ; copy discovered drive types + ldy #8 +: lda drives,y + cmp #DRV_1541 + bne :+ + jsr set1541PortAInput +: iny + cpy #12 + bne :-- + PopB curDevice + sta curDrive + PopB CPU_DATA + rts + +set1541PortAInput: + tya + pha + tax + lda #15 + tay + jsr k_setlfs + lda #7 + ldx #<@write1803 + ldy #>@write1803 + jsr k_setnam + jsr k_open + lda #15 + jsr k_close + pla + tay + rts + +@write1803: + .byte "M-W" + .word $1803 + .byte 1 + .byte 0 + +; drive detection code based on codebase64 solution https://codebase64.org/doku.php?id=base:detect_drives_on_iec_bus +; by Todd S. Elliott + +drive_poll: + + LoadB curDevice, 8 ; start at #8 + tay + lda #DRV_NULL ; that is actually 0 +: sta drives,y ; zero out the drive buffer + iny + cpy #12 + bne :- + + ; scan IEC bus, if devices exist +@iecloop: + ldy #0 + sty STATUS ; clear status + lda curDevice + jsr k_listen ; opens the device for listening + lda #$ff ; Secondary address - $0f OR'ed with $f0 to open + jsr k_second ; opens the channel with sa of 15 + + + bbsf 7, STATUS, @close ; branch if there is no device present + + ldy curDevice + tya + sta drives,y ; store non-zero in successful device number + +@close: jsr k_unlstn ; severs the serial bus control + + LoadB STATUS, 0 ; clear status + lda curDevice + jsr k_listen + lda #$ef ; sa - $0f and OR'ed with $e0 to close file + jsr k_second ; closes the channel with sa of 15 + jsr k_unlstn ; finally closes it + + inc curDevice ; next device + CmpBI curDevice, 12 ; last device to check? + bne @iecloop + + ldy #8 + sty curDevice ; restart at #8 + +@scanloop: + lda drives,y + bne @scandevice + iny + cpy #12 ; are we done? (acceptable range of 8 to 30) + bne @scanloop + rts ; exits the whole drive polling routine + +@scandevice: + sty curDevice + + jsr @open_cmd_channel + ldx #cbminfo + jsr @open_cmd_two + + jsr k_chrin ; gets the drive info + cmp #'5' ; is it '5' for the 15xx drives? + bne @not4171 + jsr k_chrin ; gets the next number + cmp #'4' ; is it '4' for the 1541? + bne @not41 + + lda #DRV_1541 ; indicates a 1541 at that device number + bne @get_next_drive + +@not41: cmp #'7' ; is it '7' for the 1571? + bne @not4171 + + lda #DRV_1571 ; indicates a 1571 at that device number + bne @get_next_drive + +@not4171: ; check for 1581 + jsr @close_cmd_channel + jsr @open_cmd_channel + ldx #info1581 + jsr @open_cmd_two + + jsr k_chrin ; gets the drive info + cmp #'5' ; is it a '5' for a 15xx drive? + bne @not81 + jsr k_chrin ; gets the next drive number + cmp #'8' ; is it a '8' for a 1581? + bne @not81 + + lda #DRV_1581 ; indicates a 1581 at that device number + bne @get_next_drive + +@not81: ; foreign drive exists, but mark it as a missing device (no built-in drivers) + lda #DRV_NULL + +@get_next_drive: + ldy curDevice + sta drives,y + jsr @close_cmd_channel + ldy curDevice + iny ; increment table offset + jmp @scanloop + +@close_cmd_channel: + jsr k_clrchn + lda #15 ; lfn + jmp k_close + +@open_cmd_channel: + lda #15 ; lfn + tay ; sa for command channel + ldx curDevice + jsr k_setlfs ; set up the open sequence + lda #6 ; length of command (m-r command) + rts + +@open_cmd_two: + jsr k_setnam ; sends the command + jsr k_open ; opens the file + ldx #15 ; lfn + jmp k_chkin ; redirect input + +cbminfo: ; gets CBM drive info at $e5c5 in drive ROM + .byte "M-R" + .word $e5c5 + .byte 2 + +info1581: ; gets 1581 drive info at $a6e8 in drive ROM + .byte "M-R" + .word $a6e8 + .byte 2 + +.endif +