Open davejduke opened 10 months ago
ok so you know which code to compile in,
targets pet2001 - Just use basic 2 in case it was upgraded to basic2 pet3008 -basic 2 pet3016, -basic 2 pet3032 -basic 2, pet4016 -basic 4, pet4032 - basic 4 pet8032 - basic 4
Hope this helps!
Thanks to Ken Mclveen from canda, we now have a working routines, this code saves and saves from $4000 to end of screen, and loads it again. Just an example of 16k ish save and load.
if peek(57016)=52 then print "basic 4" end if
rem ================================================= rem SAVEMEM rem ================================================= SUB savemem (name$ AS STRING * 10) dim c as BYTE c=1 rem TBUFFR 027A-0329 634-825 Tape I/O Buffer #1 DIM a(22) AS BYTE dim flen as byte flen=len(name$) FOR x as byte = 0 to flen poke 634+x , ASC(MID$(name$, x, c)) NEXT poke 1,len(name$)
rem save screen asm
lda #$7a
STA $DA
LDA #$02
STA $DB
LDA #$00 ; SPECIFY SAVE START ADDRESS
STA $FB ; IN THIS SAMPLE SAVE DIRECTLY FROM THE SCREEN ($8000)
LDA #$40
STA $FC
LDA #$D0 ; SPECIFY SAVE END ADDRESS +1 (BOTTOM RIGHT OF SCREEN)
STA $C9 ; IN THIS SAMPLE SAVE DIRECTLY FROM THE SCREEN ($83E8)
LDA #$87
STA $CA
LDA $01 ; SET FILENAME LENGTH (5 IN THIS CASE)
STA $D1
LDA #$08 ; SET DEVICE ADDRESS (8 IS DISK DRIVE)
STA $D4
LDA #$00
STA $96 ; CLEAR THE STATUS BYTE
LDA #$61 ; SET SECONDARY ADDRESS TO 1 (OR'ED WITH #60)
STA $D3
JSR $F6E3 ; PREFORM "SAVE" (F6A4 IN BASIC 2)
RTS
end asm end sub
sub loadmem(name$ as string*10) rem ========================================== rem load screen rem ========================================== dim c as BYTE c=1 rem TBUFFR 027A-0329 634-825 Tape I/O Buffer #1 DIM a(22) AS BYTE dim flen as byte flen=len(name$) FOR x as byte = 0 to flen poke 634+x , ASC(MID$(name$, x, c)) NEXT poke 1,len(name$)
asm
lda #$7a
STA $DA
LDA #$02
STA $DB
LDA #$00 ; load to address
STA $FB
LDA #$40
STA $FC
LDA $01 ; file len
STA $D1
LDA #$08 ;device name
STA $D4
LDA #$00
STA $9D
STA $96
LDA #$60
STA $D3
JSR $F4A5
JSR $F0D2
LDA $D3
JSR $F193
JSR $F1C0
JSR $F1C0
JSR $F391
rts
end asm print "saved" end sub call savemem("screenshot") print "{clr}" call loadmem("screenshot") print "loaded"
What would be good is a command that does this
Savemem("filename",$source,$dest_or_length) loadmem("filename",destination address of where to load into)
use this code to detect if basic 4 or 2
if peek(57016)=52 then print "basic 4" else print "basic2"
end if
Does the above work in XC=BASIC now? I haven't yet had the time to test it out.
Will get you the latest one over soon , I have file delete now also, just got the flu at the moment On 4 Feb 2024, at 14:49, Csaba Fekete @.***> wrote: Does the above work in XC=BASIC now? I haven't yet had the time to test it out.
—Reply to this email directly, view it on GitHub, or unsubscribe.You are receiving this because you authored the thread.Message ID: @.***>
Any update on this? Does it mean we can expect READ#
and WRITE#
to work on PETs any time soon? :smiley:
Any update on this? Does it mean we can expect
READ#
andWRITE#
to work on PETs any time soon? 😃
Due to the lack of unified KERNAL API in the PET, file I/O would need to be implemented differently for each PET versions. I cannot undertake this work for now.
The community accepted a trade-off when XC=BASIC was made compatible with the PET, and this trade-off was that file I/O could not be implemented.
"SAVE" sample
LDA #FNTABLE.LO ; PLACE POINTER TO FILE NAME IN ($DA) STA $DA LDA #FNTABLE.HI STA $DB LDA #$00 ; SPECIFY SAVE START ADDRESS STA $FB ; IN THIS SAMPLE SAVE DIRECTLY FROM THE SCREEN ($8000) LDA #$80 STA $FC LDA #$E9 ; SPECIFY SAVE END ADDRESS +1 (BOTTOM RIGHT OF SCREEN) STA $C9 ; IN THIS SAMPLE SAVE DIRECTLY FROM THE SCREEN ($83E8) LDA #$83 STA $CA LDA #FNTABLE.LENGTH ; SET FILENAME LENGTH (5 IN THIS CASE) STA $D1 LDA #$08 ; SET DEVICE ADDRESS (8 IS DISK DRIVE) STA $D4 LDA #$00 STA $96 ; CLEAR THE STATUS BYTE LDA #$61 ; SET SECONDARY ADDRESS TO 1 (OR'ED WITH #60) STA $D3 JSR $F6E3 ; PERFORM "SAVE" (F6A4 IN BASIC 2) RTS
.FNTABLE "FILE1" ($46 $49 $4C $45 $31)
I just tested this code and can confirm it works fine for BASIC 4.
It's important to note, that FNTABLE.HI
and FNTABLE.LO
have to point to the first character of the filename string, i.e. skipping the preceding string length byte!
Adding relevant addresses for BASIC 1 (taken from "Programming the PET/CBM" by Raeto Collin West):
BASIC 1 | BASIC 2 | BASIC 4 | Description |
---|---|---|---|
($F9) |
($DA) |
($DA) |
Pointer to filename |
$EE |
$D1 |
$D1 |
Filename length |
$F1 |
$D4 |
$D4 |
Device number |
$F0 |
$D3 |
$D3 |
Secondary address |
($F7) |
($FB) |
($FB) |
Pointer to save start address |
($E5) |
($C9) |
($C9) |
Pointer to save end address |
$020C |
$96 |
$96 |
Status byte ST |
$F6B1 |
$F6A4 |
$F6E3 |
MLM ROM routine SAVE |
I tested all BASIC variants of the SAVE
example in VICE:
BASIC 1 did mess up the filename though. Turns out "Programming the PET/CBM" contains an error in the zero-page listing on page 395: The correct address for the filename length is $EE
instead of $ED
as in the book! (Although it is listed correctly in a footnote on page 420.)
I fixed this in my comment above now. Using $EE
for the filename length my test for BASIC 1 was successful as well.
Sweet glad I could help.Dave On 4 Aug 2024, at 20:42, Tobias @.***> wrote: I tested all variants in VICE:
PET 2001: BASIC 1 PET 3008: BASIC 2 PET 8032: BASIC 4
BASIC 1 did mess up the filename though. Turns out "Programming the PET/CBM" contains an error in the zero-page listing on page 395: The correct address for the filename length is $EE instead of $ED as in the book! (Although it is listed correctly in a footnote on page 420.) I fixed this in my comment above now. Using $EE for the filename length my test for BASIC 1 was successful as well.
—Reply to this email directly, view it on GitHub, or unsubscribe.You are receiving this because you authored the thread.Message ID: @.***>
Thank you both for your work on investigating this. I scheduled implementing LOAD/SAVE for PET in version V3.2.0.
"LOAD" sample
LDA #FNTABLE.LO ; PLACE POINTER TO FILE NAME IN ($DA) STA $DA LDA #FNTABLE.HI STA $DB LDA #$00 ; SPECIFY ADDRESS TO LOAD TO (IGNORE ADDRESS IN FILE) STA $FB ; IN THIS SAMPLE LOAD DIRECTLY TO THE SCREEN ($8000) LDA #$80 STA $FC LDA #FNTABLE.LENGTH ; SET FILENAME LENGTH (5 IN THIS CASE) STA $D1 LDA #$08 ; SET DEVICE ADDRESS (8 IS DISK DRIVE) STA $D4 LDA #$00 STA $9D ; SPECIFY LOAD (AS OPPOSED TO LOAD/VERIFY) STA $96 ; CLEAR THE STATUS BYTE LDA #$60 ; SET SECONDARY ADDRESS TO 0 (OR'ED WITH #60) STA $D3 JSR $F4A5 ; SEND NAME TO IEEE (F466 IN BASIC 2) JSR $F0D2 ; SEND 'TALK' (F0B6 IN BASIC 2) LDA $D3 JSR $F193 ; SEND SECONDARY ADDRESS (F128 IN BASIC 2) JSR $F1C0 ; GET LOW BYTE OF ADDRESS (F18C IN BASIC 2) - USE IT IF YOU WANT, GOES INTO $FB LDA $96 ; CHECK STATUS BIT (2ND FROM RIGHT) LSR A LSR A BCC CNT ; STATUS OK, SKIP ERROR OUT JMP $F3C1 ; ABORT FILES, PRINT ?FILE NOT FOUND ERROR AND EXIT (F56E IN BASIC 2) CNT JSR $F1C0 ; GET HIGH BYTE OF ADDRESS ;JSR $F1C0 ; READ 1 MORE BYTE TO SETUP FOR LOAD ROUTINE JSR $F391 ; REJOIN LOAD (WITHOUT PRINTING 'LOADING ...'). (F355 IN BASIC 2) RTS
.FNTABLE "FILE1" ($46 $49 $4C $45 $31)
I tested the code for the LOAD
example as well and there were some minor difficulties. (It would have been nice to know that these code samples are based on the code in chapter 6.6 "Machine-code programming with CBM disk drives" of "Programming the PET/CBM" for all the additional explanations given there…)
I had to remove the second JSR $F1C0
after jump label CNT
(cp. code in quote above). I couldn't figure out why this would help to "setup for LOAD
routine" and the byte is obviously not available for the LOAD
routine then.
It was a bit trickier to find out that the given BASIC 4 ROM routine addresses aren't exactly spot-on and the book is similarly contradictory as with the BASIC 1 filename length zero-page address (referring to my comment above).
Here are the differences I implemented for BASIC 4: | address | replaced by | reason |
---|---|---|---|
$F193 |
$F143 |
additionally checks for time-out | |
$F3C1 |
$F5AD |
simply wrong, I think; $F3C1 is at the of the LOAD routine $F356 in BASIC 4, not part of the error handling |
|
$F391 |
$F38F |
include required LDA #$FD |
I also tried to find the equivalent BASIC 1 routines and found all but the routine that reads data to memory ($F355
/$F38F
in BASIC 2/BASIC 4). "Programming the PET/CBM" lists $F37E
for this, but it's implemented completely different from BASIC 2 & 4 and seems to be part of the direct mode LOAD
BASIC command which expects to drop back to BASIC in the end and thus jumps to $C581
to clear the stack! Took me about two days to find out what went wrong there and I don't want to touch it again with a 10-foot pole… :laughing:
After all these are the addresses and ROM routines I managed to find for LOAD : |
BASIC 1 | BASIC 2 | BASIC 4 | Description |
---|---|---|---|---|
($F9) |
($DA) |
($DA) |
Pointer to filename | |
$EE |
$D1 |
$D1 |
Filename length | |
$F1 |
$D4 |
$D4 |
Device number | |
$F0 |
$D3 |
$D3 |
Secondary address | |
$020B |
$9D |
$9D |
LOAD (#$00 ) or VERIFY (#$01 ) |
|
$020C |
$96 |
$96 |
Status byte ST |
|
($F7) |
($FB) |
($FB) |
Pointer to memory address to load file contents to | |
$F462 |
$F466 |
$F4A5 |
Send filename string to IEEE-488 bus | |
$F0B6 |
$F0B6 |
$F0D2 |
Send "Talk" to IEEE-488 bus | |
$F12C |
$F128 |
$F143 |
Send command to IEEE-488 (and clear ATN line) |
|
$F187 |
$F18C |
$F1C0 |
Read single byte from IEEE-488 bus into accumulator | |
$F579 |
$F56E |
$F5AD |
Print "?FILE NOT FOUND" error and exit to BASIC (!) | |
$F355 |
$F38F |
Read data to memory until EOI (end of input) as indicated by ST value #$40 |
And finally I came up with some code to replace the missing/inadequate BASIC 1 routine to read data to memory until EOI is encountered.
This is based on the ROM routine at $F37E
, but stripped of the parts that are used for VERIFY
and returning to BASIC afterwards:
iF37E jsr $F339 ; check stop key
ldx $020C ; read status byte
; bvs iF3CC ; (used in ROM; overflow is set when reading after EOI & accumulator holds #$0D; used for INPUT#?)
bne iF3CC ; do not wait for overflow (set when reading after EOI), but exit as soon as status != 0
jsr $F187 ; read byte from IEEE-488 bus (NB: Will return $0D when reading after EOI!)
; skip usual LOAD/VERIFY check here
ldy #$00 ; make sure Y register is 0 before using it for indirect STA
; TBD: use X register [holding status byte] instead?!
sta ($F7),Y ; write byte to store address
inc $F7 ; increment store address
bne iF37E
inc $F7+1
jmp iF37E
iF3CC jsr $EF18 ; UNTALK & UNLISTEN, CLOSE IEEE-488
I used the BASIC 1 ROM addresses as labels [iF37E
and iF3CC
] so you can find the original code in disassembled ROMs if you want to compare (or in case I missed something).
The assembler code and all ROM routines are tested in VICE for BASIC 1, BASIC 2 and BASIC 4.
I haven't tested the FILE NOT FOUND
error in depth though. Currently this should drop back to BASIC for all versions. I guess, this is not expected behavior in XC=BASIC?
Great job, thanks.
I haven't tested the FILE NOT FOUND error in depth though. Currently this should drop back to BASIC for all versions. I guess, this is not expected behavior in XC=BASIC?
No, XC=BASIC will execute its own error trapping mechanism.
The code is for basic 4, the comments shows calls for basic 2.
working code is
"LOAD" sample
CNT JSR $F1C0 ; GET HIGH BYTE OF ADDRESS JSR $F1C0 ; READ 1 MORE BYTE TO SETUP FOR LOAD ROUTINE JSR $F391 ; REJOIN LOAD (WITHOUT PRINTING 'LOADING ...'). (F355 IN BASIC 2) RTS
.FNTABLE "FILE1" ($46 $49 $4C $45 $31)
"SAVE" sample
.FNTABLE "FILE1" ($46 $49 $4C $45 $31)