Revision 1.1 - 7.4.2002
Guess what happens when the original vectors are restored... The call to this routine can be NOPed in most cases, but if the program destroys the vectors, use VECTOR to backup at the beginning and than restore vectors.
Not really forbidden, until the original vector content is preserved. If C flag is high, it backups the vectors to (X,Y), if C=0 it loads the new vectors from (X,Y). Here's an example for replacing RESTOR:
ldx #<temp ;32 bytes unused memory ldy #>temp ;for backup sec jsr Vector jmp startme ;start program ... jsr restor ;RESTOR replaced ... restor ldx #<temp ldy #>temp clc jmp Vector
LISTEN and SECOND is used to select output serial device, like CHKOUT does. Backup register X if needed for CHKOUT.
lda $ba ;device number jsr Listen lda #15+$60 ;channel 15 jsr Second
TALK and TKSA is used to select input serial device, like CHKIN does. Backup register X if needed for CHKIN.
lda $ba ;device number jsr Talk lda #15+$60 ;channel 15 jsr Tksa
Don't forget to replace serial open to OPEN, and TALK+TKSA to CHKIN.
Don't forget to replace serial open to OPEN, and LISTEN+SECOND to CHKOUT.
Backup register X if needed.
Backup register X if needed.
jsr ChrIn ; read data from file sta Data,y jsr ReadSt ; test status and #$40 ; End of File flag bne EndOfFile
BIT | MEANING |
---|---|
7 | Device not present |
6 | End of File |
5 | (Tape CRC error) |
4 | Verify/read error (Tape read error) |
3 | (Tape long block) |
2 | (Tape short block) |
1 | No more bytes |
0 | Timeout |
lda #$00 jsr Setmsg ;turn off messages
BIT | MEANING |
---|---|
7 | Full error messages (LOADING, etc.) |
6 | Kernal error messages (I/O ERROR#x) |
5..0 | Undefined |
Returns Z=1 and calls CLRCHN if stop was pressed
jsr Stop beq stop ;Stop was pressed
Also known as the first three parameters of BASIC OPEN command.
lda #filenumber ; file number (1-255) ldx $ba ; actual device number ldy #secaddy ; secondary address jsr SetLfs
DEVICE NUMBER | DEVICE |
---|---|
0 | Keyboard |
1 | Datassette(TM) |
2 | RS-232C device |
3 | CRT display |
4..5 | Serial bus printer |
6..7 | Serial bus plotter |
8..11 | CBM serial bus disk drive |
12 | Primary IDE controller, Master |
13 | Primary IDE controller, Slave |
14 | PC-link (serial or parallel) |
15..30 | Other |
31..255 | Illegal |
SECONDARY ADDRESS | |
---|---|
0 | Read access (load) |
1 | Write access (save) |
2..14 | Data channel |
15 | Status/command channel |
16..127 | Illegal |
BIT 7 set | No command string(?) |
lda #8 ; filename length ldx #<Name ; pointer to filename, low byte ldy #>Name ; pointer to filename, high byte jsr SetNam ... Name .text "filename"
lda #FileNumber ; opened file number jsr Close
ldx #FileNumber ; opened file number jsr ChkIn
ldx #FileNumber ; opened file number jsr ChkOut
ldy #0 jsr ChrIn sta Data,y iny
ldy #0 jsr Getin sta Data,y iny
lda #$00 jsr ChrOut
jsr ClAll ; close all files, set default I/O jmp Run ; run program
lda #1 jsr Close jsr ClrChn ; set default I/O
Note: It's possible to load from $0400 to $FFFF (IDE64 switch $01 memory configuration register automatically).
lda #1 ; filename length ldx #<dirnam ldy #>dirnam ; filename pointer jsr SetNam lda #1 ; file number ldx $ba ; actual device number ldy #0 ; sec.address 0=new location, 1=original location jsr SetLfs lda #$00 ; load flag (1=verify) ldx #<dirbuff ldy #>dirbuff ; new start address jsr load bcc LoadOk ... rts LoadOk stx $ae ; new end after load/verify sty $af ... rts dirnam .text "$"
Note: It's possible to save RAM from $0400 to $9FFF and $C000-$CFFF
DataBegin = $fb lda #1 ; file number ldx $ba ; actual device number ldy #0 ; sec.address jsr SetLfs lda #8 ; filename length ldx #<Name ldy #>Name ; filename pointer jsr SetNam lda #<$1000 sta DataBegin ; begin lda #>$1000 sta DataBegin+1 lda #DataBegin ldx #<$8000 ldy #>$8000 ; end jsr Save Name .text "filename"
Note: Not possible to save under I/O. (eg. saveing from $D800 will save color ram) To access RAM under the BASIC and KERNAL ROM, set $01 correctly.
If you want your application using READ/WRITE make runnable on a not IDE64 equiped machine, check for IDE64 presence before calling these two calls, and use standard routines instead of, as described for serial drives. (Imagine what happens at JSR $DEF1 if there's open I/O space at $DE00-$DEFF...)
lda $de60 ;Check IDE64 cmp #$49 bne old lda $de61 cmp #$44 bne old lda $de62 cmp #$45 bne old lda #zp jsr $def1 bcc ok cmp #9 ;illegal device beq old2 ;tried to use call on non-IDE64 device ok ... rts old2 ldx #channel jsr Chkout old ... ;old byte by byte routine rts
Note: This routine does not load under I/O. (e.g. reading to $D800 will overwrite color ram)
lda #1 ; Source filenumber ldx $ba ; Actual device number ldy #0 ; Secondary address for read jsr SetLfs lda #outputname-inputname ldx #<inputname ldy #>inputname jsr SetNam jsr Open ; Open input file lda #2 ; Destination filenumber ldx $ba ; Actual device number ldy #1 ; Secondary address for write jsr SetLfs lda #status-outputname ldx #<outputname ldy #>outputname jsr SetNam jsr Open ; Open output file lda #<StartAdd sta $fb lda #>StartAdd ; Buffer start address sta $fc ldx #1 ; Set input to source file jsr ChkIn ldx #2 jsr ChkOut ; Set output to destination file loop lda #$fb ; Pointer to zeropage with start address ldx #<BlockSize ldy #>BlockSize ; Block size jsr Read ; READ bit $90 ; READST php ; Status to stack lda #$fb jsr Write ; WRITE plp ; Status bvc loop ; test End Of File lda #2 jsr Close ; Close output file lda #1 jsr Close ; Close input file jsr ClAll ; Set default I/O device rts inputname .text "/BIN/INPUT-FILE" outputname .text "/TMP/OUTPUT-FILE" status .byte 0
CODE | MEANING |
---|---|
0 | Routine terminated by the <STOP> key |
1 | Too many open files |
2 | File already open |
3 | File not open |
4 | File not found |
5 | Device not present |
6 | File is not an input file |
7 | File is not an output file |
8 | File name is missing |
9 | Illegal device number |
16 | Out of memory |
240 | Top-of-memory change RS-232 buffer allocation/deallocation |
IDE64 has four configurations of external memory. STND, 8kB, 16kB and OPEN. External RAM is available only in OPEN configuration. External RAM is not intended for users! Please DO NOT change any information in External RAM!
Switching is made by WRITE instruction on following addresses in I/O area:
sta $deff ; switch to STND configuration sta $defe ; switch to OPEN configuration sta $defd ; switch to 8kB configuration sta $defc ; switch to 16kB configuration
Normally, the system is in the STND configuration, only additional code is located between $DE60-$DEFF. Most of the system vectors are redirected to this area. If you call I/O routines in the kernal table between $FFC0 and $FFE7 you use IDE DOS extended routines. The memory configuration is changed, External ROM is turned on (and external RAM sometimes too). System checkes, if you access IDE device or standard device. If you access standard device, External ROM is disabled and system calls standard routines in C64/C128 ROM.
IDE64 extended routines uses all hardware memory configurations: STND, 8kB, 16kB and OPEN.
CONFIGURATION | $1000-$7FFF | $8000-$9FFF | $A000-$BFFF | $D000-$DFFF | $E000-$FFFF | |
---|---|---|---|---|---|---|
0 | STND | RAM | RAM | RAM | RAM | RAM |
8kB | RAM | RAM | RAM | RAM | RAM | |
16kB | RAM | RAM | RAM | RAM | RAM | |
OPEN | IDE RAM | IDE ROM LOW | IDE ROM HIGH | I/O | IDE ROM HIGH | |
1 | STND | RAM | RAM | RAM | CHAR ROM | RAM |
8kB | RAM | RAM | RAM | CHAR ROM | RAM | |
16kB | RAM | RAM | RAM | RAM | KERNAL ROM | |
OPEN | IDE RAM | IDE ROM LOW | IDE ROM HIGH | I/O | IDE ROM HIGH | |
2 | STND | RAM | RAM | BASIC ROM | CHAR ROM | KERNAL ROM |
8kB | RAM | RAM | RAM | CHAR ROM | KERNAL ROM | |
16kB | RAM | RAM | IDE ROM HIGH | CHAR ROM | KERNAL ROM | |
OPEN | IDE RAM | IDE ROM LOW | IDE ROM HIGH | I/O | IDE ROM HIGH | |
3 | STND | RAM | RAM | BASIC ROM | CHAR ROM | KERNAL ROM |
8kB | RAM | IDE ROM LOW | BASIC ROM | CHAR ROM | KERNAL ROM | |
16kB | RAM | IDE ROM LOW | IDE ROM HIGH | CHAR ROM | KERNAL ROM | |
OPEN | IDE RAM | IDE ROM LOW | IDE ROM HIGH | I/O | IDE ROM HIGH | |
4 | STND | RAM | RAM | RAM | RAM | RAM |
8kB | RAM | RAM | RAM | RAM | RAM | |
16kB | RAM | RAM | RAM | RAM | RAM | |
OPEN | IDE RAM | IDE ROM LOW | IDE ROM HIGH | I/O | IDE ROM HIGH | |
5 | STND | RAM | RAM | RAM | I/O | RAM |
8kB | RAM | RAM | RAM | I/O | RAM | |
16kB | RAM | RAM | RAM | I/O | RAM | |
OPEN | IDE RAM | IDE ROM LOW | IDE ROM HIGH | I/O | IDE ROM HIGH | |
6 | STND | RAM | RAM | RAM | I/O | KERNAL ROM |
8kB | RAM | RAM | RAM | I/O | KERNAL ROM | |
16kB | RAM | RAM | IDE ROM HIGH | I/O | KERNAL ROM | |
OPEN | IDE RAM | IDE ROM LOW | IDE ROM HIGH | I/O | IDE ROM HIGH | |
7 | STND | RAM | RAM | BASIC ROM | I/O | KERNAL ROM |
8kB | RAM | IDE ROM LOW | BASIC ROM | I/O | KERNAL ROM | |
16kB | RAM | IDE ROM LOW | IDE ROM HIGH | I/O | KERNAL ROM | |
OPEN | IDE RAM | IDE ROM LOW | IDE ROM HIGH | I/O | IDE ROM HIGH |
Original IRQ vector points at routine on $8000.
($0314/$0315 = $8000) $8000 ... ; original IRQ routine ... ... rti
Now you must change IRQ vector to special serving routine which is out of $8000-$9FFF.
sei lda $0314 sta OldIrq lda $0315 sta OldIrq+1 ; Store old irq vector lda #>NewIrq sta $0314 lda #<NewIrq sta $0315 ; Set new irq vector cli rts
O.K. IRQ vector is redirected to the new location. Now you can use IDE DOS extended routines for I/O access do IDE device. Please note, that longer call IRQ routine adds some delay which can cause 'raster bugs'.
* = $1000 ; out of $8000-$9fff NewIrq ; now actual A,X,Y, return address and status are in STACK lda $01 pha ; store original memory configuration to STACK lda #$34 sta $01 ; set new memory configuration, disable rom $8000-$9FFF lda #<EndOfIrq ; return address after RTI pha lda #>EndOfIrq ; return address after RTI pha lda #$24 ; statusword after RTI (disabled IRQ) pha jmp (OldIrq) ; Call original IRQ routine under ROM ; It will end with RTI instruction, 3 bytes are taken out ; from STACK, statusword and return address. Program will ; continue at return address. EndOfIrq ; this is called by RTI from original IRQ with disabled IRQ pla sta $01 ; restore original memory configuration rti ; 3 bytes are taken out from STACK, original return ; address and status. Program will continue at ; original return adress.
After finishing IDE DOS extended routines you can return back original IRQ.
sei lda OldIrq ; original IRQ sta $0314 lda OldIrq+1 sta $0315 cli rts
Note that code have to be located at $02-$7FFF and $C000-$CFFF.
bank_port0 = $de32 cfg_8 = $defd lda #$37 sta $01 ; set memory configuration sta bank_port0 ; set page 0 IDE ROM sta cfg_8 ; set 8kB configuration jmp ($fffc) ; call normal RESET routine
lda #1 ldx $ba ; actual device number ldy #15 ; secondary address = command jsr SetLfs lda #2 ; filename length ldx #>init_cmd ldy #<init_cmd jsr SetNam jsr Open php lda #$01 jsr Close plp bcs init_err ; error during OPEN rts ; initialized OK init_err ... ... rts init_cmd .text "I:" ; init command
lda #1 ldx $ba ; actual device number ldy #15 ; status/command channel jsr SetLfs lda #$00 jsr SetNam ; no filename jsr Open ; open status channel bcc OpenOk lda #1 ; error during open jsr Close sec rts OpenOk ldx #1 jsr ChkIn ; set status channel as input jsr ChrIn ; read first status character asl asl asl asl sta Hlp ; store jsr ChrIn ; read second status character and #$0f ora Hlp pha ; converted value Look4Comma jsr ChrIn ; get next status character cmp #"," bne Look4Comma ldy #0 GetStatusChar jsr ChrIn cmp #"," beq EndOfStatus sta DiskStatus,y iny jmp GetStatusChar EndOfStatus lda #$00 sta DiskStatus,y; make NULL terminated string jsr ChrIn cmp #13 bne EndOfStatus lda #1 jsr Close jsr ClrChn pla ; status number cmp #1 ; C=0 if status ok rts
lda $de60 ;Check IDE64 cmp #$49 ;I bne no lda $de61 cmp #$44 ;D bne no lda $de62 cmp #$45 ;E bne no ... ;present no ... ;not present