13

I was recently interested in how to 'bload' some data on my commodore 64. For the sake of discussion the data isn't really relevant (it could be any blob of bytes).

Generally you can load a file into the memory address specified in the file itself by using the well known

LOAD "filename",8,1 

where the value 8 represents the disk drive device id, and the 1 signals the file should be loaded into it's specified target address.

But I was curious if you could load data into a specific address (different from the one specified in the saved file) and stumbled on this snippet of code:

10 SYS 57812"NAME",8     : REM SET FILENAME AND DEVICE
20 POKE781,LO:POKE782,HI : REM SET TARGET ADDRESS
30 POKE780,0             : REM FORCE "LOAD"
40 SYS65439              : REM LOAD THE FILE

It seems reasonable to assume the pokes are setting up the input values for the SYS on line 40, which calls the kernel SCNKEY routine at $EA87 (via the jump table address $FF9F). (According to Mapping the Commodore 64, 780-783 are loaded into .A .X .Y and status registers when SYS is invoked.)

But I can't make sense out of syntax of the first SYS on line 10, nor do I understand why the code would want to call SCNKEY to load a file into memory. Obviously this is exploiting some trick on the 64, but I'm not savvy enough to grok the magic here.

My actual goal is to find a small ML snippet that will load any filename into a given memory address. So this example (being close) is really just a starting point, I might be barking up the wrong tree entirely. But I would still like to understand how this code works.

Full disclosure: I am not in a position to actually try this for another week - so this entire process is a thought experiment right now. I am assuming the code above actually works.

EDIT

My question above was motivated by my desire to learn how to load a file into any target address from assembly or ML. I thought if I understood how the BASIC routine worked, I could translate it to assembly - but that thought process turned out to be a red herring. For those interested, I eventually worked out the following snippet in CBM prg Studio v3.14:

*=$C000

SETLFS = $FFBA    ; set logical file parameters
SETNAM = $FFBD    ; set filename parameters
LOAD   = $FFD5    ; load from a device

loader   lda #$01      ; logical file number
         ldx #$08      ; device number
         ldy #$00      ; secondary address
         jsr SETLFS
         lda #$08      ; length of filename in characters
         ldx #<FNAME   ; address of filename (lo)
         ldy #>FNAME   ; address of filename (hi)
         jsr SETNAM
         lda #$00      ; 0 = load, non-zero = verify
         ldx #$00      ; target load address (lo) 
         ldy #$C0      ; target load address (hi)
         jsr LOAD
         rts

FNAME text “filename”

2 Answers 2

22

Line 40 looks like a typo. It should be SYS 65493 instead of SYS 65439. SYS 65493 ($FFD5) maps to the internal LOAD routine at $F49E

Line 10 calls the filename parsing routine PLSV at $E1D4. PLSV is used by the LOAD and SAVE BASIC commands to parse filenames from the command line input.

At the point SYS 57812 is executed, the PLSV routine will parse the text immediately following ("NAME",8) in preparation for an upcoming LOAD or SAVE. When PLSV returns, BASIC will continue parsing/executing at line 20.

Lines 20 and 30 set the load address. Line 40 calls LOAD.

1
  • 3
    Indeed, going back to the source material I transposed the digits. Calling the LOAD routine at $F49E makes way more sense. Many thanks for pointing that out - I thought there was some seriously dark voodoo going on. :-)
    – Geo...
    Sep 27, 2023 at 10:54
12

Three related concepts one should understand when trying to understand Commodore BASIC programs (or other Microsoft-derived BASIC interpreters for that matter) are the CHRPTR address, and the CHRGET and CHRGOT routines.

The CHRPTR address indicates what part of the program "text" has just been examined. CHRGET adds 1 to CHRPTR and calls CHRGOT. CHRGOT examines the character at CHRPTR, reruns CHRGET if that character is a blank, and otherwise sets CPU flags based upon which of several categories it is.

If one uses a LOAD or SAVE command, the interpreter will call a routine which uses CHRGET to fetch the file name, device, and mode arguments and then passes to the KERNAL. If one performs a SYS command, it will use CHRGET to fetch the address and leave CHRPTR pointing to the first byte after the address. If the address points to the routine that's used by LOAD and SAVE to fetch arguments, it will treat whatever follows the SYS address as the arguments for LOAD or SAVE, leaving leave CHRPTR pointing after those arguments. Once the code returns from the SYS call, the BASIC interpreter will use CHRGOT/CHRGET to for and skip the zero byte or colon that follows the end of a statement and proceed to the next statement.

0

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .