Jump to content
IGNORED

Write and Load blocks of memory to Tape/Disk


peteym5

Recommended Posts

Now this is a major question I had been researching. Does the Commodore Vic-20, 64, 128, or other 8-bit computer Basic have a way to write and re-load blocks of memory from tape or disk. I know this is common practice with the Atari 800/XL/XE systems where Fonts, ML routines, Sprite Data, and Music are written to disk and retrieved by a program as it runs. Usually done instead of setting up a font with read and data statements and saves room inside the program. I seem not to be getting a direct answer by google searching the information. I know Commodore Basic can like input# and poke stuff one byte at a time, but can it do large blocks directly from disk to memory?

 

 

Link to comment
Share on other sites

BASIC 7 in the 128 has BLOAD and BSAVE which I believe can do this. On BASIC 2 machines you can INPUT#/POKE and PEEK/OUTPUT# in BASIC for as much memory as you want, provided you observe reserved memory and I/O space. The fastest way would be in assembly where you can have custom routines to read data from disk and put it in ANY RAM you want (even RAM under I/O space -- hey, is it possible to swap out color RAM?) but if you want to return to BASIC you still have to honor reserved memory and vectors. In all cases you need to watch the CPU stack.

 

I have not poked around in the KERNAL in a while, but ISTR you can set up a few memory locations and call a ROM routine to load data into memory. Ugh... now I want to look but I have no time! :)

Link to comment
Share on other sites

Thankyou. I have a Vic-20 and found all my old tapes with games I made. I set up fonts by read/data statements and after I moved onto the Atari I wonder if I could had done it different with loading files from disk into Memory. Turbo Basic and Basic XE have a similar function. Atari Basic I believe can do it with a function call to the OS. There should be a call in the kernel on the Vic-20 or 64 that will do it.

Link to comment
Share on other sites

Indeed there are such routines. Here is a list of addresses that apply both to the VIC and C64, I think also the PET series use the same calls while the Plus/4 may not.

http://zimmers.net/anonftp/pub/cbm/maps/kernel.lib

 

You would do it something like this:

LDA #length of file name
LDX #low byte pointing to the file name
LDY #high byte pointing to the file name
JSR $FFBD ; SETNAM
LDA #logical file ; any number 1-255 IIRC
LDX #8 ; floppy drive
LDY #1 ; secondary address, e.g. 15 to read the error channel
JSR $FFBA ; SETLFS
LDA #0 ; LOAD = 0, VERIFY = 1
LDX #low byte ; only used if secondary address above = 0
LDY #high byte
JSR $FFD5 ; LOAD

If you want to SAVE you do as above, but you store the starting address of the program somewhere at zeropage. Recommended is to use TXTTAB, address $2B/$2C:

LDA #low byte start
STA $2B
LDA #high byte start
STA $2C
LDA #$2B ; zero-page index to the pointer
LDX #low byte end (possibly +1)
LDY #high byte end
JSR $FFD8

There are routines closer inside BASIC ROM that you can set up and call with less hassle too, but this is the system friendly way to do it.

 

Don't forget to CLOSE the channel afterwards! I'll leave that as an exercise to the reader, it is perhaps the easiest thing.

Edited by carlsson
  • Like 1
Link to comment
Share on other sites

If you use LOAD inside a program, the interpreter tends to restart the program after the file is loaded. It can be solved with setting variables or POKE a certain value to use as a flag, and then branch at the start of the program. Many programs use this technique, so it is doable. If you call the KERNAL routines above, the program supposedly should keep running after RTS.

 

An alternative is of course to try to pack your data as closely in memory as possible and perhaps add small routines to move memory blocks to desired positions. Once you're finished, you can run a cruncher on the single filed executable to reduce it in size. It makes it much harder to modify an individual memory chunk, but easier to copy and distribute and no need to rewrite the program to make it run from tape or disk.

Link to comment
Share on other sites

Back in the day I used a machine language monitor to save chunks of memory to disk. Afterwards a normal load"file",8,1 could be used in BASIC to load it back into the same memory location.

 

 

 

Yup yup. WarpSpeed has a great MLM. I want to code something similar for the TI.

Link to comment
Share on other sites

Why not just save a series of values to a sequential file? That way, you're not loading up a new program that will overtake the RAM or restart anything.

 

Writing to a sequential file: OPEN 1, 8, 8, "[FILE NAME], SEQ, W"

 

Reading from one: OPEN 1, 8, 8, "[FILE NAME], SEQ, R"

After either of those commands, use PRINT# or GET# to read / write one character at a time. Don't forget to CLOSE the opened file at the end of the routine.

 

This is all from memory, and it's been a while, so I highly recommend searching online for tutelage about sequential C64 files if you'd like to experiment with this method.

Link to comment
Share on other sites

You're correct but it will be rather slow. Also you will want to POKE into memory each value you GET# and vice versa PEEK every value to PRINT# to file, since you can't really store graphical definitions or machine code inside BASIC variables. For program data that you might as well keep as variables instead of memory addresses, the method using GET# or INPUT# is pretty fine.

 

Actually you can open your file as "FILE NAME,P,W" instead of sequential file. This will generate a PRG file. By PRINT# the desired load address represented as CHR$ codes, you could in theory prepare your binary files from a BASIC program using regular file processing, and then LOAD them into the desired position without going through the GET# motions later on. I've used that method many times when dumping ROM or other memory blocks and not had the time or motivation to look up more efficient ways to save a memory block to file.

Edited by carlsson
  • Like 1
Link to comment
Share on other sites

You're correct but it will be rather slow. Also you will want to POKE into memory each value you GET# and vice versa PEEK every value to PRINT# to file, since you can't really store graphical definitions or machine code inside BASIC variables. For program data that you might as well keep as variables instead of memory addresses, the method using GET# or INPUT# is pretty fine.

 

Actually you can open your file as "FILE NAME,P,W" instead of sequential file. This will generate a PRG file. By PRINT# the desired load address represented as CHR$ codes, you could in theory prepare your binary files from a BASIC program using regular file processing, and then LOAD them into the desired position without going through the GET# motions later on. I've used that method many times when dumping ROM or other memory blocks and not had the time or motivation to look up more efficient ways to save a memory block to file.

 

Excellent points. I didn't think of the potential speed issue.

Link to comment
Share on other sites

By the way, here is a thread on how to use direct ROM calls to save a memory block, instead of going through the KERNEL calls I posted above:

http://www.lemon64.com/forum/viewtopic.php?t=51284

 

Notice the SYS addresses on the Lemon64 post relate to the C64, this is why I give them both for C64 and VIC-20 below:

 

 

SH% = startadr/256:SL = startadr-SH%*256
EH% = endadr/256:EL = endadr-EH%*256
SYS 57812("filename"),8,1 : REM SYS 57809 ON VIC-20
POKE 193,SL:POKE 194,SH%:POKE 174,EL:POKE 175,EH%
SYS 62957 : REM SYS 63109 ON VIC-20

 

Compared with the calls I posted above, the routine at 57812 / 57809 actually calls SETNAM and SETLFS, plus a bunch of other things.

However the KERNEL routine SAVE at $FFD8 jumps to a position that predates 62957 / 63109 by 16 bytes.

 

There is a corresponding LOAD routine at $F49E (C64) and $F542 (VIC), but I don't know if it is easier to call directly than through the KERNEL library.

  • Like 1
Link to comment
Share on other sites

JamesD - good thing to know at least the jump table is the same. The lower 1K is a bit different on TED machines compared to VIC/C64 if I recall correctly, but then again the lower 1K on PET isn't identical either so perhaps one shouldn't assume total compatibility there.

 

USR, SEQ are good for generic data, however if you intend to load executable code you might as well make those files PRG even if they are not meant to be loaded standalone. You can open a non-PRG file as ,P,R and set load address as well, so yes it might be possible to store your fonts, sprite data etc in either of these formats and set up loading, preventing the user from loading the files themselves.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...