Initial working PiDrive

This commit is contained in:
dschmenk 2014-02-09 16:37:46 -08:00
parent d8bf70b34d
commit bf07a8c365
31 changed files with 897 additions and 113 deletions

BIN
client/A2PI#069600 Executable file

Binary file not shown.

BIN
client/A2PLUSPI#069600 Executable file

Binary file not shown.

BIN
client/BASIC.SYSTEM#FF2000 Executable file

Binary file not shown.

1
client/BUILD/A2PI.S#040000 Executable file

File diff suppressed because one or more lines are too long

1
client/BUILD/A2PLUSPI.S#040000 Executable file

File diff suppressed because one or more lines are too long

BIN
client/BUILD/ED#069DB6 Executable file

Binary file not shown.

BIN
client/BUILD/MERLIN.SYSTEM#FF0000 Executable file

Binary file not shown.

BIN
client/BUILD/PARMS#068000 Executable file

Binary file not shown.

BIN
client/CONFIG#FC0801 Executable file

Binary file not shown.

1
client/DEFSLOT#060300 Executable file
View File

@ -0,0 +1 @@
 <20>L<>

2
client/LIST.CMD Executable file
View File

@ -0,0 +1,2 @@
LIST
]

BIN
client/PIDRIVE#062000 Executable file

Binary file not shown.

32
client/PIDRIVE.BAS Executable file
View File

@ -0,0 +1,32 @@
NEW
REM LOAD PIDRIVE AND APPLY FIXUPS
300 PRINT CHR$ (4);"BLOAD PIDRIVE.A2DRVR"
310 VE = 816 : FX = VE + 4 : SI = PEEK(768) : SN = SI / 8
REM CHECK IF PRODOS DEVICE VECTOR SET
320 IF PEEK(48913 + SN) = 222 THEN POKE 48912 + SN, PEEK(VE) : POKE 48913 + SN, PEEK (VE + 1)
330 IF PEEK(48929 + SN) = 222 THEN POKE 48928 + SN, PEEK(VE) : POKE 48929 + SN, PEEK (VE + 1)
340 FOR D = 48946 TO 48959
350 IF PEEK (D) = 0 THEN POKE D, SI + 1 : POKE 48945, PEEK (48945) + 1 : D = 48960
360 NEXT
370 FOR D = 48946 TO 48959
380 IF PEEK (D) = 0 THEN POKE D, SI + 1 : POKE 48945, PEEK (48945) + 129 : D = 48960
390 NEXT
395 PRINT "PIDRIVE CONNECTED ON SLOT #"; SN / 2
REM INSERT CLOCK DRIVER
400 POKE 48903, PEEK (VE + 2) : POKE 48904, PEEK (VE + 3)
405 PRINT "PICLOCK CONNECTED"
REM RUN THROUGH FIXUP TABLE
410 AA = PEEK (FX) : IF AA = 0 THEN NEW : END
420 AA = AA + PEEK (FX + 1) * 256 : FX = FX + 2
430 POKE AA, PEEK (AA) + SI
440 GOTO 410
]

BIN
client/PRODOS#FF0000 Executable file

Binary file not shown.

BIN
client/STARTUP#FC0801 Executable file

Binary file not shown.

66
client/STARTUP.BAS Executable file
View File

@ -0,0 +1,66 @@
NEW
10 PRINT
11 PRINT "STARTING APPLE II PI CLIENT."
12 PRINT "PRESS ANY KEY TO CANCEL..."
REM ALLOCATE BASIC BUFFER SPACE
20 PRINT CHR$ (4);"BLOAD DEFSLOT"
30 CALL 769
REM LOAD APPROPRIATE CLIENT
40 A2$ = "A2PI" : IF PEEK (64435) < > 6 THEN A2$ = "A2PLUSPI"
50 PRINT CHR$ (4);"BLOAD ";A2$
REM IF DEFAULT SLOT NOT SET, SEARCH FOR SSC
60 IF PEEK (768) = 0 THEN GOSUB 100
65 POKE 769,0
REM INIT A2PI DRIVER
70 PRINT CHR$ (4);"PR# A$9600"
80 IF PEEK (769) < > 0 THEN PRINT "APPLE II PI CONNECTED." : PRINT "KEYBOARD ROUTED TO LINUX" : GOSUB 300
90 NEW : END
REM SEARCH FOR SSC
100 SC = 0 : PI = 0
110 FOR S = 1 TO 7
120 FW = 49152 + 256 * S
130 IF PEEK (FW + 5) = 56 AND PEEK (FW + 7) = 24 AND PEEK (FW + 12) = 49 THEN SC = S : PRINT "FOUND SERIAL CARD: SLOT #";S
150 NEXT
160 IF SC < > 0 THEN POKE 768,SC * 16: RETURN
REM NOTHING FOUND. LOW BUZZ TO SIGNIFY CONFIG NEEDED
200 FOR S = 1 TO 100 : SP = PEEK (49200): NEXT
210 POP : PRINT CHR$ (4);"RUN CONFIG"
220 END
REM LOAD PIDRIVE AND APPLY FIXUPS
300 PRINT CHR$ (4);"BLOAD PIDRIVE"
310 VE = 816 : FX = VE + 4 : SI = PEEK(768) : SN = SI / 8
REM CHECK IF PRODOS DEVICE VECTOR SET
320 IF PEEK(48913 + SN) = 222 THEN POKE 48912 + SN, PEEK(VE) : POKE 48913 + SN, PEEK (VE + 1)
330 IF PEEK(48929 + SN) = 222 THEN POKE 48928 + SN, PEEK(VE) : POKE 48929 + SN, PEEK (VE + 1)
335 PRINT "PIDRIVE CONNECTED ON SLOT #"; SN / 2
REM INSERT CLOCK DRIVER
340 POKE 48903 + SN, PEEK (VE + 2) : POKE 48904 + SN, PEEK (VE + 3)
345 PRINT "PICLOCK CONNECTED"
REM RUN THROUGH FIXUP TABLE
350 AA = PEEK (FX) + PEEK (FX + 1) * 256 : FX = FX + 2
360 IF AA = 0 THEN RETURN
370 POKE AA, PEEK (AA) + SI
380 GOTO 350
]

BIN
client/VSDRIVE#062000 Executable file

Binary file not shown.

BIN
pidrive/PIDRIVE#062000 Executable file

Binary file not shown.

BIN
pidrive/PROGROM#FC0801 Executable file

Binary file not shown.

BIN
pidrive/ROM#062000 Executable file

Binary file not shown.

10
pidrive/drvr.cfg Executable file
View File

@ -0,0 +1,10 @@
MEMORY {
RAM: start = $2000, size = $200, file = %O;
}
SEGMENTS {
CODE: load = RAM, type = rw;
DATA: load = RAM, type = rw;
BSS: load = RAM, type = rw;
}

21
pidrive/makefile Executable file
View File

@ -0,0 +1,21 @@
.SUFFIXES =
AFLAGS = -o $@
ROM = ROM\#062000
DRVR = PIDRIVE\#062000
#
# Image filetypes for CiderPress
#
PLATYPE = \#ed0000
BINTYPE = \#060000
SYSTYPE = \#ff0000
TXTTYPE = \#040000
all: $(ROM) $(DRVR)
$(ROM): rom.s
ca65 rom.s -o rom.o
ld65 -o $(ROM) -C rom.cfg rom.o
$(DRVR): pidrive.s
ca65 pidrive.s -o pidrive.o
ld65 -o $(DRVR) -C drvr.cfg pidrive.o

280
pidrive/pidrive.s Executable file
View File

@ -0,0 +1,280 @@
.DEFINE EQU =
.DEFINE DB .BYTE
.DEFINE DW .WORD
.CODE
PISLOT EQU $00
;*
;* ACIA REGISTERS
;*
ACIADR EQU $C088+PISLOT*16
ACIASR EQU $C089+PISLOT*16
ACIACR EQU $C08A+PISLOT*16
ACIAMR EQU $C08B+PISLOT*16
;*
;* APPLE I/O LOCATIONS
;*
KEYBD EQU $C000
STROBE EQU $C010
;*
;* UTIL ROUTINES
;*
WAIT EQU $FCA8
COUT EQU $FDED
CROUT EQU $FD8E
PRBYTE EQU $FDDA
PRHEX EQU $FDE3
PRNTAX EQU $F941
RDKEY EQU $FD0C
RDCHAR EQU $FD35
GETLN EQU $FD6A
;*
;* ZERO PAGE PARAMETERS
;*
PDCMD EQU $42
PDUNIT EQU $43
PDBUFF EQU $44
PDBUFL EQU $44
PDBUFH EQU $45
PDBLKL EQU $46
PDBLKH EQU $47
;*
;* SLOT INDEX = SLOT # * 16
;*
SLOTIDX EQU $0300
;*
;* DRIVER SCRATCHPAD
;*
TMP EQU $0478+PISLOT
PAD0 EQU $0478+PISLOT
PAD1 EQU $04F8+PISLOT
PAD2 EQU $0578+PISLOT
PAD3 EQU $05F8+PISLOT
PAD4 EQU $0678+PISLOT
PAD5 EQU $06F8+PISLOT
PAD6 EQU $0778+PISLOT
PAD7 EQU $07F8+PISLOT
;*
;* PRODOS COMMANDS
;*
PDSTAT EQU 0
PDREAD EQU 1
PDWRITE EQU 2
PDFORMT EQU 3
;*
;* PRODOS ERRORS
;*
PDNOERR EQU $00
PDIOERR EQU $27
PDNODEV EQU $28
PDWRPRT EQU $2B
;*
;* PRODOS GLOBAL PAGE LOCATIONS
;*
CLKJSR EQU $BF06
DEV1L EQU $BF10
DEV1H EQU $BF11
DEV2L EQU $BF20
DEV2H EQU $BF21
DEVCNT EQU $BF31
DEVLST EQU $BF32
PDTIME EQU $BF90
;*
;* ZERO PAGE LOCATIONS FOR LOADER
;*
DSTPTR EQU $06
DSTL EQU $06
DSTH EQU $07
SRCPTR EQU $08
SRCL EQU $08
SRCH EQU $09
;*
;* DRIVER LOADER
;*
DRVRDST EQU $D742
DRVRLEN EQU 125
LDA #$60
STA CLKJSR ; UNHOOK CLOCK DRIVER (WITH RTS)
LDA #<DRVRELOC
STA SRCL
LDA #>DRVRELOC
STA SRCH
LDA #<DRVRDST
STA DSTL
LDA #>DRVRDST
STA DSTH
LDY #DRVRLEN-1
BIT $C08B ; ENABLE LCRAM & WRITE
BIT $C08B
CPYLP: LDA (SRCPTR),Y
STA (DSTPTR),Y
DEY
BPL CPYLP
INY
LDX #SFIXUPTBL-IFIXUPTBL-1
IFIXLP: LDA IFIXUPTBL,X
STA DSTH
DEX
LDA IFIXUPTBL,X
STA DSTL
LDA (DSTPTR),Y
ORA SLOTIDX
STA (DSTPTR),Y
DEX
BPL IFIXLP
LDX #DRVRELOC-SFIXUPTBL-1
SFIXLP: LDA SFIXUPTBL,X
STA DSTH
DEX
LDA SFIXUPTBL,X
STA DSTL
LDA SLOTIDX
LSR
LSR
LSR
LSR
CLC
ADC (DSTPTR),Y
STA (DSTPTR),Y
DEX
BPL SFIXLP
BIT $C08A ; EBABLE ROM
LDA SLOTIDX
LSR
LSR
LSR
TAX
LDA DEV1H,X
CMP #$DE ; GNODEV
BNE INSDEV2
LDA #<DRVRDST
STA DEV1L,X
LDA #>DRVRDST
STA DEV1H,X
INY
INSDEV2:
LDA DEV2H,X
CMP #$DE
BNE INCDEV1
LDA #<DRVRDST
STA DEV2L,X
LDA #>DRVRDST
STA DEV2H,X
INY
INCDEV1:
CPY #$00
BEQ EXIT ; NOTHING TO BE DONE HERE
LDX #$00
DEV1LP: LDA DEVLST,X
BNE NXTDEV1
LDA SLOTIDX
ORA #$01
STA DEVLST,X
INC DEVCNT
BNE INCDEV2
NXTDEV1:
INX
CPX #14
BNE DEV1LP
INCDEV2:
LDX #$00
DEV2LP: LDA DEVLST,X
BNE NXTDEV2
LDA SLOTIDX
ORA #$81
STA DEVLST,X
INC DEVCNT
BNE EXIT
NXTDEV2:
INX
CPX #14
BNE DEV2LP
EXIT: RTS
;*
;* FIXUP TABLE
;*
IFIXUPTBL:
DW FIXUP1+1
DW FIXUP2+1
DW FIXUP3+1
DW FIXUP4+1
SFIXUPTBL:
DW FIXUP5+1
DW FIXUP6+1
DRVRELOC:
;*
;* PRODOS INTELLIGENT DEVICE ENTRYPOINT (OVERWRITE CLOCK DRIVER)
;*
.ORG DRVRDST
DOCMD: LDA PDUNIT
ASL
LDA PDCMD
ROL
ASL
ORA #$A0
LDX PDBLKL
LDY PDBLKH
PHP
FIXUP5: STA PAD0
SEI
JSR SENDACC
TXA
JSR SENDACC
TYA
JSR SENDACC
CHKACK: JSR RECVACC
TAX
DEX
FIXUP6: CPX PAD0
BNE CHKACK
LDY PDCMD
BEQ STATUS
LDX #$02 ; # OF PAGES TO XFER
DEY ; CPY #PDREAD
BEQ RDBLK
DEY ; CMP #PDWRITE
BEQ WRBLK
IOERR: LDA #PDIOERR
CMDERR: PLP
SEC
DOCLK: RTS ; NO OP CLOCK ROUTINE
RDBLK: JSR RECVACC
STA (PDBUFF),Y
INY
BNE RDBLK
INC PDBUFH
DEX
BNE RDBLK
STATUS: LDX #$FF
DEY ; LDY #$FF
CMDEX: JSR RECVACC
BNE CMDERR
PLP
CLC
RTS
WRBLK: LDA (PDBUFF),Y
JSR SENDACC
INY
BNE WRBLK
INC PDBUFH
DEX
BNE WRBLK
BEQ CMDEX
;*
;* ACIA I/O ROUTINES
;*
SENDACC:
PHA
FIXUP1:
SENDWT: LDA ACIASR
AND #$10
BEQ SENDWT
PLA
FIXUP2: STA ACIADR
RTS
RECVACC:
FIXUP3:
RECVWT: LDA ACIASR
AND #$08
BEQ RECVWT
FIXUP4: LDA ACIADR
RTS

172
pidrive/pidriveclock.s Executable file
View File

@ -0,0 +1,172 @@
.DEFINE EQU =
.DEFINE DB .BYTE
.DEFINE DW .WORD
.CODE
PISLOT EQU $00
;*
;* ACIA REGISTERS
;*
ACIADR EQU $C088+PISLOT*16
ACIASR EQU $C089+PISLOT*16
ACIACR EQU $C08A+PISLOT*16
ACIAMR EQU $C08B+PISLOT*16
;*
;* APPLE I/O LOCATIONS
;*
KEYBD EQU $C000
STROBE EQU $C010
;*
;* UTIL ROUTINES
;*
WAIT EQU $FCA8
COUT EQU $FDED
CROUT EQU $FD8E
PRBYTE EQU $FDDA
PRHEX EQU $FDE3
PRNTAX EQU $F941
RDKEY EQU $FD0C
RDCHAR EQU $FD35
GETLN EQU $FD6A
;*
;* ZERO PAGE PARAMETERS
;*
PDCMD EQU $42
PDUNIT EQU $43
PDBUFF EQU $44
PDBUFL EQU $44
PDBUFH EQU $45
PDBLKL EQU $46
PDBLKH EQU $47
;*
;* DRIVER SCRATCHPAD
;*
TMP EQU $0478+PISLOT
PAD0 EQU $0478+PISLOT
PAD1 EQU $04F8+PISLOT
PAD2 EQU $0578+PISLOT
PAD3 EQU $05F8+PISLOT
PAD4 EQU $0678+PISLOT
PAD5 EQU $06F8+PISLOT
PAD6 EQU $0778+PISLOT
PAD7 EQU $07F8+PISLOT
;*
;* PRODOS COMMANDS
;*
PDSTAT EQU 0
PDREAD EQU 1
PDWRITE EQU 2
PDFORMT EQU 3
;*
;* PRODOS ERRORS
;*
PDNOERR EQU $00
PDIOERR EQU $27
PDNODEV EQU $28
PDWRPRT EQU $2B
;*
;* PRODOS GLOBAL PAGE LOCATIONS
;*
PDTIME EQU $BF90
;*
;* VECTORS
;*
;VECTBL: DB >DOCMD
; DB >DOCLK
; DB >FIXUP1+1
; DB >FIXUP2+1
; DB >FIXUP3+1
; DB >FIXUP4+1
;TMP: DB 0
;*
;* PRODOS INTELLIGENT DEVICE ENTRYPOINT
;*
DOCMD: LDA PDUNIT
ASL
LDA PDCMD
ROL
ASL
ORA #$A0
LDX PDBLKL
LDY PDBLKH
PHP
JSR SENDCMD
LDY PDCMD
BEQ STATUS
LDX #$02 ; # OF PAGES TO XFER
DEY ; CPY #PDREAD
BEQ RDBLK
DEY ; CMP #PDWRITE
BEQ WRBLK
IOERR: LDA #PDIOERR
CMDERR: PLP
SEC
RTS
RDBLK: JSR RECVACC
STA (PDBUFF),Y
INY
BNE RDBLK
INC PDBUFH
DEX
BNE RDBLK
STATUS: LDX #$FF
DEY ; LDY #$FF
CMDEX: JSR RECVACC
BNE CMDERR
PLP
CLC
RTS
WRBLK: LDA (PDBUFF),Y
JSR SENDACC
INY
BNE WRBLK
INC PDBUFH
DEX
BNE WRBLK
BEQ CMDEX
;*
;* PRODOS CLOCK ROUTINE
;*
;DOCLK: LDA #$AC
; PHP
; JSR SENDCMD
; LDY #$00
;CLKLP: JSR RECVACC
; STA PDTIME,Y
; INY
; CPY #$04
; BNE CLKLP
; PLP
; RTS
;*
;* ACIA I/O ROUTINES
;*
SENDCMD:
STA TMP
SEI
JSR SENDACC
TXA
JSR SENDACC
TYA
JSR SENDACC
CHKACK: JSR RECVACC
TAX
DEX
CPX TMP
BNE CHKACK
GOTACK: RTS
SENDACC:
PHA
FIXUP1:
SENDWT: LDA ACIASR
AND #$10
BEQ SENDWT
PLA
FIXUP2: STA ACIADR
RTS
RECVACC:
FIXUP3:
RECVWT: LDA ACIASR
AND #$08
BEQ RECVWT
FIXUP4: LDA ACIADR
RTS

10
pidrive/rom.cfg Executable file
View File

@ -0,0 +1,10 @@
MEMORY {
ROM: start = $c700, size = $100, file = %O;
}
SEGMENTS {
CODE: load = ROM, type = ro;
DATA: load = ROM, type = ro;
BSS: load = ROM, type = ro;
}

173
pidrive/rom.s Executable file
View File

@ -0,0 +1,173 @@
.DEFINE EQU =
.CODE
PISLOT EQU $05
;*
;* ACIA REGISTERS
;*
ACIADR EQU $C088+PISLOT*16
ACIASR EQU $C089+PISLOT*16
ACIACR EQU $C08A+PISLOT*16
ACIAMR EQU $C08B+PISLOT*16
;*
;* APPLE I/O LOCATIONS
;*
KEYBD EQU $C000
STROBE EQU $C010
;*
;* UTIL ROUTINES
;*
WAIT EQU $FCA8
COUT EQU $FDED
CROUT EQU $FD8E
PRBYTE EQU $FDDA
PRHEX EQU $FDE3
PRNTAX EQU $F941
RDKEY EQU $FD0C
RDCHAR EQU $FD35
GETLN EQU $FD6A
;*
;* ZERO PAGE PARAMETERS
;*
PDCMD EQU $42
PDUNIT EQU $43
PDBUFF EQU $44
PDBUFL EQU $44
PDBUFH EQU $45
PDBLKL EQU $46
PDBLKH EQU $47
;*
;* PRODOS COMMANDS
;*
PDSTAT EQU 0
PDREAD EQU 1
PDWRITE EQU 2
PDFORMT EQU 3
;*
;* PRODOS ERRORS
;*
PDNOERR EQU $00
PDIOERR EQU $27
PDNODEV EQU $28
PDWRPRT EQU $2B
;*
;* AUTOSTART BOOT SIGNATURE
;*
LDX #$20
LDY #$00
LDX #$03
STX $3C
;*
;* INIT ACIA
;*
STY ACIASR ; RESET STATUS REGISTER
LDY #$0B
STY ACIACR ; SET CONTROL REGISTER
LDY #$10
STY ACIAMR ; SET COMMAND REGISTER (115K BAUD)
;*
;* SYNC WITH HOST
;*
SYNC: LDA #$80
STA ACIADR
LDA #$FF
JSR WAIT
LDA KEYBD
BMI SKIPBOOT
LDA ACIASR
AND #$08
BEQ SYNC
LDA ACIADR
CMP #$81
BNE SYNC
BEQ BOOT
SKIPBOOT: STA STROBE
JMP $FABA ; JUMP BACK TO BOOT SCANNER ROM ROUTINE
;*
;* CREATE COMMAND BUFFER FOR BOOT BLOCK
;*
BOOT: LDA #PDREAD
STA PDCMD
LDA #$00
STA PDUNIT
STA PDBUFL
STA PDBLKL
STA PDBLKH
PHA
LDA #$08
STA PDBUFH
PHA
;*
;* PRODOS INTELLIGENT DEVICE ENTRYPOINT
;*
DOCMD: PHP
SEI
LDA PDUNIT
ASL
LDA PDCMD
ROL
ASL
JSR SENDACC
LDA PDBLKL
JSR SENDACC
LDA PDBLKH
JSR SENDACC
CHKACK: JSR RECVACC
TAX
DEX
CPX PDCMD
BNE CHKACK
LDY #$00
CPX #PDREAD
BEQ RDBLK
CPX #PDWRITE
BEQ WRBLK
CPX #PDSTAT
BEQ STATDEV
LDA #PDIOERR
CMDERR: PLP
SEC
RTS
STATDEV:
LDX #$FF
LDY #$FF
CMDEX: JSR RECVACC
BNE CMDERR
PLP
CLC
RTS
RDBLK:
RD1BLK: JSR RECVACC
STA (PDBUFF),Y
INY
BNE RD1BLK
INC PDBUFH
RD2BLK: JSR RECVACC
STA (PDBUFF),Y
INY
BNE RD2BLK
BEQ CMDEX
WRBLK:
WR1BLK: LDA (PDBUFF),Y
JSR SENDACC
INY
BNE WR1BLK
INC PDBUFH
WR2BLK: LDA (PDBUFF),Y
JSR SENDACC
INY
BNE WR1BLK
BEQ CMDEX
SENDACC:
PHA
SENDWT: LDA ACIASR
AND #$10
BEQ SENDWT
PLA
STA ACIADR
RTS
RECVACC:
RECVWT: LDA ACIASR
AND #$08
BEQ RECVWT
LDA ACIADR
RTS

Binary file not shown.

View File

@ -12,8 +12,8 @@
struct timespec tv;
struct input_event evkey, evabsx, evabsy, evsync;
#define BTTN_IO 0xC061
#define READGP0 0x380
#define READGP1 0x388
#define READGP0 0x320
#define READGP1 0x328
char readgp[] = {
0xA2, 0x00, // LDX #PADDLE
0x78, // SEI

View File

@ -12,8 +12,8 @@
struct timespec tv;
struct input_event evkey, evrelx, evrely, evsync;
#define BTTN_IO 0xC061
#define READGP0 0x380
#define READGP1 0x388
#define READGP0 0x320
#define READGP1 0x328
char readgp[] = {
0xA2, 0x00, // LDX #PADDLE
0x78, // SEI

View File

@ -14,8 +14,8 @@ struct input_event evkey, evrelx, evrely, evsync;
#define PEN_UP 0
#define PEN_DOWN 1
#define BTTN_IO 0xC061
#define READGP0 0x380
#define READGP1 0x388
#define READGP0 0x320
#define READGP1 0x328
char readgp[] = {
0xA2, 0x00, // LDX #PADDLE
0x78, // SEI

View File

@ -58,7 +58,7 @@ struct {
/*
* Virtual drive info
*/
int vdrivefd[2];
int vdrvfd[2];
/*
* ASCII to scancode conversion
*/
@ -353,100 +353,89 @@ static void sig_bye(int signo)
}
/*****************************************************************\
* *
* VDRIVE commands *
* vdrv commands *
* *
\*****************************************************************/
int vdriveopen(char *path)
int vdrvopen(char *path)
{
char filename[256];
strcpy(filename, path);
strcat(filename, "A2VD1.PO");
//printf("vdrive: open %s\n", filename);
if ((vdrivefd[0] = open(filename, O_RDWR, 0)) < 0)
vdrivefd[0] = 0;
//printf("vdrv: open %s\n", filename);
if ((vdrvfd[0] = open(filename, O_RDWR, 0)) < 0)
vdrvfd[0] = 0;
strcpy(filename, path);
strcat(filename, "A2VD2.PO");
//printf("vdrive: open %s\n", filename);
if ((vdrivefd[1] = open(filename, O_RDWR, 0)) < 0)
vdrivefd[1] = 0;
return vdrivefd[0] + vdrivefd[1];
//printf("vdrv: open %s\n", filename);
if ((vdrvfd[1] = open(filename, O_RDWR, 0)) < 0)
vdrvfd[1] = 0;
return vdrvfd[0] + vdrvfd[1];
}
void vdriveclose(void)
void vdrvclose(void)
{
if (vdrivefd[0]) close(vdrivefd[0]);
if (vdrivefd[1]) close(vdrivefd[1]);
vdrivefd[0] = vdrivefd[1] = 0;
if (vdrvfd[0]) close(vdrvfd[0]);
if (vdrvfd[1]) close(vdrvfd[1]);
vdrvfd[0] = vdrvfd[1] = 0;
}
void vdrivecmd(int afd, int command, int block, unsigned char crc_in)
unsigned char *prodos_time(void)
{
int i, vfd = vdrivefd[command >> 2];
unsigned char block_buff[512], crc_out = 0xC5 ^ command ^ block ^ (block >> 8);
static unsigned char time_buff[4];
/*
* Get ProDOS time.
*/
time_t now = time(NULL);
struct tm *tm = localtime(&now);
int ptime = (tm->tm_mday & 0x1F)
| (((tm->tm_mon + 1) & 0x0F) << 5)
| (((tm->tm_year - 100) & 0x7F) << 9)
| ((tm->tm_min & 0x3F) << 16)
| ((tm->tm_hour & 0x1F) << 24);
time_buff[0] = (unsigned char) ptime;
time_buff[1] = (unsigned char) (ptime >> 8);
time_buff[2] = (unsigned char) (ptime >> 16);
time_buff[3] = (unsigned char) (ptime >> 24);
return time_buff;
}
int vdrvtime(int afd)
{
return write(afd, prodos_time(), 4);
}
int vdrvstatus(int drive)
{
return vdrvfd[drive] == 0 ? 0x28 : 0x00;
}
int vdrvread(int afd, int drive, int block)
{
int err = 0, vfd = vdrvfd[drive];
unsigned char block_buff[512];
if (crc_in != crc_out)
prlog("vdrive: CRC mismatch!\n");
if (command == 0x01 || command == 0x03 || command == 0x05)
if (vfd)
{
//printf("vdrive: read block=%d from unit:%d\n", block, command >> 2);
block_buff[0] = 0xC5;
block_buff[1] = command;
block_buff[2] = block;
block_buff[3] = block >> 8;
write(afd, block_buff, 4);
if (command > 0x01)
{
unsigned char time_buff[4];
/*
* Get ProDOS time.
*/
time_t now = time(NULL);
struct tm *tm = localtime(&now);
int ptime = (tm->tm_mday & 0x1F)
| (((tm->tm_mon + 1) & 0x0F) << 5)
| (((tm->tm_year - 100) & 0x7F) << 9)
| ((tm->tm_min & 0x3F) << 16)
| ((tm->tm_hour & 0x1F) << 24);
time_buff[0] = (unsigned char) ptime;
time_buff[1] = (unsigned char) (ptime >> 8);
time_buff[2] = (unsigned char) (ptime >> 16);
time_buff[3] = (unsigned char) (ptime >> 24);
write(afd, time_buff, 4);
crc_out ^= time_buff[0] ^ time_buff[1] ^ time_buff[2] ^ time_buff[3];
}
write(afd, &crc_out, 1);
if (vfd)
{
lseek(vfd, block * 512, 0);
read(vfd, block_buff, 512);
}
write(afd, block_buff, 512);
for (crc_out = i = 0; i < 512; i++)
crc_out ^= block_buff[i];
write(afd, &crc_out, 1);
}
else if (command == 0x02 || command == 0x04)
{
//printf("vdrive: write block=%d to unit:%d\n", block, command >> 2);
for (crc_out = i = 0; i < 512; i++)
{
read(afd, &block_buff[i], 1);
crc_out ^= block_buff[i];
}
if (vfd)
{
lseek(vfd, block * 512, 0);
read(afd, &crc_in, 1);
}
if (crc_in == crc_out)
write(vfd, block_buff, 512);
block_buff[0] = 0xC5;
block_buff[1] = command;
block_buff[2] = block;
block_buff[3] = block >> 8;
block_buff[4] = crc_out;
write(afd, block_buff, 5);
lseek(vfd, block * 512, 0);
if (read(vfd, block_buff, 512) != 512)
err = 0x27; /* ProDOS I/O error */
}
else
state = RESET; // ??? What else to do ???
err = 0x28; /* ProDOS No device connected error */
write(afd, block_buff, 512);
return err;
}
int vdrvwrite(int afd, int drive, int block)
{
int i, err = 0, vfd = vdrvfd[drive];
unsigned char block_buff[512];
for (i = 0; i < 512; i++)
read(afd, &block_buff[i], 1);
if (vfd)
{
lseek(vfd, block * 512, 0);
if (write(vfd, block_buff, 512) != 512)
err = 0x27; /* ProDOS I/O error */
}
else
err = 0x28; /* ProDOS No device connected error */
return err;
}
/*****************************************************************\
* *
@ -722,12 +711,12 @@ void main(int argc, char **argv)
struct uinput_user_dev uidev;
struct termios oldtio,newtio;
unsigned char iopkt[16];
int i, c, rdycnt, vdriveactive;
int i, c, rdycnt, vdrvactive;
int a2fd, kbdfd, moufd, srvfd, maxfd;
struct sockaddr_in servaddr;
fd_set readset, openset;
char *devtty = "/dev/ttyAMA0"; /* default for Raspberry Pi */
char *vdrivedir = "/usr/share/a2pi/"; /* default VDRIVE image directory */
char *vdrvdir = "/usr/share/a2pi/"; /* default vdrv image directory */
/*
* Parse arguments
@ -851,9 +840,16 @@ void main(int argc, char **argv)
evrely.code = REL_Y;
evsync.type = EV_SYN;
/*
* Get VDRIVE images.
* Get vdrv images.
*/
vdriveactive = vdriveopen(vdrivedir);
vdrvactive = vdrvopen(vdrvdir);
#if defined(SETSERCLK) && defined(__ARMEL__)
/*
* Initialize ACIA clock for Apple II Pi card
*/
gpclk(271); /* divisor for ~1.8 MHz => (500/271) MHz */
sleep(1); /* give clock chance to settle down */
#endif
/*
* Open socket.
*/
@ -869,13 +865,6 @@ void main(int argc, char **argv)
die("error: bind socket");
if (listen(srvfd, MAX_CLIENT - 1) < 0)
die("error: listen socket");
#if defined(SETSERCLK) && defined(__ARMEL__)
/*
* Initialize ACIA clock for Apple II Pi card
*/
gpclk(271); /* divisor for ~1.8 MHz => (500/271) MHz */
sleep(1); /* give clock chance to settle down */
#endif
/*
* Open serial port.
*/
@ -1092,22 +1081,48 @@ reset:
else
state = RESET;
break;
case 0xC5: /* virtual drive request */
//printf("a2pid: vdrive request\n");
case 0xA0: /* virtual drive 1 STATUS call */
case 0xA2: /* virtual drive 2 STATUS call */
//printf("vdrive: STATUS unit:%d\n", (iopkt[0] >> 1) & 0x01);
iopkt[3] = iopkt[0] + 1; /* ack */
write(a2fd, &iopkt[3], 1);
iopkt[0] = vdrvstatus((iopkt[0] >> 1) & 0x01);
write(a2fd, iopkt, 1);
if (a2reqlist) /* resend last request */
write(a2fd, &(a2reqlist->type), 1);
break;
case 0xA4: /* virtual drive 1 READ call */
case 0xA6: /* virtual drive 2 READ call */
//printf("vdrive: READ unit:%d block:%d\n", (iopkt[0] >> 1) & 0x01, iopkt[1] | (iopkt[2] << 8));
iopkt[3] = iopkt[0] + 1; /* ack */
write(a2fd, &iopkt[3], 1);
iopkt[0] = vdrvread(a2fd, (iopkt[0] >> 1) & 0x01, iopkt[1] | (iopkt[2] << 8));
write(a2fd, iopkt, 1);
if (a2reqlist) /* resend last request */
write(a2fd, &(a2reqlist->type), 1);
break;
case 0xA8: /* virtual drive 1 WRITE call */
case 0xAA: /* virtual drive 2 WRITE call */
//printf("vdrive: WRITE unit:%d block:%d\n", (iopkt[0] >> 1) & 0x01, iopkt[1] | (iopkt[2] << 8));
iopkt[3] = iopkt[0] + 1; /* ack */
write(a2fd, &iopkt[3], 1);
newtio.c_cc[VMIN] = 1; /* blocking read until command packet received */
tcsetattr(a2fd, TCSANOW, &newtio);
if (read(a2fd, &iopkt[3], 1) + read(a2fd, &iopkt[4], 1) == 2)
{
//printf("vdrive cmd:%02X blk:%d crc:%02X\n", iopkt[1], iopkt[2] | (iopkt[3] << 8), iopkt[4]);
vdrivecmd(a2fd, iopkt[1], iopkt[2] | (iopkt[3] << 8), iopkt[4]);
}
else
state = RESET;
iopkt[0] = vdrvwrite(a2fd, (iopkt[0] >> 1) & 0x01, iopkt[1] | (iopkt[2] << 8));
write(a2fd, iopkt, 1);
newtio.c_cc[VMIN] = 3; /* blocking read until 3 chars received */
tcsetattr(a2fd, TCSANOW, &newtio);
if (a2reqlist) /* resend last request */
write(a2fd, &a2reqlist->type, 1);
write(a2fd, &(a2reqlist->type), 1);
break;
case 0xAC: /* virtual clock TIME call */
//printf("vclock: TIME\n");
iopkt[3] = 0xAD; /* ack */
write(a2fd, &iopkt[3], 1);
write(a2fd, prodos_time(), 4);
if (a2reqlist) /* resend last request */
write(a2fd, &(a2reqlist->type), 1);
break;
default:
prlog("a2pid: Unknown Event\n");
tcflush(a2fd, TCIFLUSH);
@ -1217,15 +1232,15 @@ reset:
case 0x98: /* get output chars from Apple II */
a2client[i].flags |= CLIENT_COUT;
break;
case 0xC0: /* reconnect VDRIVEs */
vdriveclose();
vdriveactive = vdriveopen(vdrivedir);
case 0xC0: /* reconnect vdrvs */
vdrvclose();
vdrvactive = vdrvopen(vdrvdir);
iopkt[0]++; /* ack */
write(a2client[i].fd, iopkt, 1);
break;
case 0xC2: /* disconnect VDRIVEs */
vdriveclose();
vdriveactive = 0;
case 0xC2: /* disconnect vdrvs */
vdrvclose();
vdrvactive = 0;
iopkt[0]++; /* ack */
write(a2client[i].fd, iopkt, 1);
break;
@ -1259,7 +1274,7 @@ reset:
close(a2client[i].fd);
if (state == RESET)
goto reset;
vdriveclose();
vdrvclose();
shutdown(srvfd, SHUT_RDWR);
close(srvfd);
tcsetattr(a2fd, TCSANOW, &oldtio);