Jump to content

Photo

Cassette loader bypasing C: device - looking for sample source


25 replies to this topic

#1 baktra OFFLINE  

baktra

    Chopper Commander

  • 248 posts
  • Location:Czech republic

Posted Wed Apr 5, 2017 6:34 AM

Hello,

 

I am looking for a sample source code that demonstrates loading from cassette without using the C: device, just by calling SIO.

I would like to write a binary loader that uses 512 B - 1024 B blocks.

 

I could disassemble some existing code, but perhaps there is something ready that I can just take and customize a bit.

 

Thank you.



#2 Rybags OFFLINE  

Rybags

    Quadrunner

  • 14,720 posts
  • Location:Australia

Posted Wed Apr 5, 2017 10:13 AM

It's been a while, but... going mostly from memory, in a cassette boot situation:

 

Motor control should already be on so no need to worry about it.  Due to a bug in the OS, you should turn the motor off via PACTL once the tape boot is complete.

A call to SIOV $E459 should be made for each block to be read.

Prerequisite setup of the DCB:

DDEVIC $300 should be set to $60 for cassette, this only needs to be done once, in the case of a tape boot/continuation code it should already have been set.

DUNIT $301 unit number for cassette is ignored so don't worry about this one.

DCOMND $302 command, we want "R" for Read operation, set to $52

DSTATS $303 this is important.  On return this has the status code but before calling SIOV the top 2 bits are used to indicate whether an input or output operation is taking place.  So, we need $40 to indicate input, if we were writing a block it'd be $80.

DBUF $304-5 Points to our buffer address.

DTIMLO $306 and DUNUSE $307 Not used for tape.

DBYT $308-9 Byte count - this is the number of bytes for the operation - data payload only, this doesn't include sync leader bytes or checksum, SIO takes care of those things.

DAUX1/2 $30A-B DAUX1 ignored (?) DAUX2 should = $80 to force short inter-record gaps (in a boot situation should already be set as such)

 

For a multistage boot, a few things to note:

You can use a short leader between the EOF block of the booter and the remainder of the program, 4-5 seconds should be plenty.

Probably best to have a delay of about 1 second before attempting to start read operations, allows for pause between recording of the 1st/2nd stage of the boot and any unwanted noise that might be on that section of tape.

Note that if you have intro screen or any possible extra delay beyond a couple of seconds it's probably a good idea to stop the tape.  Note that when you restart the tape you should allow about 1.5-2 seconds before calling SIO, allow the tape to get up to speed.

 

Most important - a binary loader by tape can potentially be too slow such that the next block is played before the SIO call has a chance to start reading it. Efficient programming becomes a must.  In most cases it'd probably never happen but e.g. a section of binary file with a lot of 1-2 byte segments could potentially cause overrun.

 

And of course, INIT sections where title screens or user intervention is needed to continue loading - you'd need to cater for this by motor off, then extra long leader before the next block.


Edited by Rybags, Wed Apr 5, 2017 10:22 AM.


#3 baktra OFFLINE  

baktra

    Chopper Commander

  • Topic Starter
  • 248 posts
  • Location:Czech republic

Posted Wed Apr 5, 2017 10:22 AM

It's been a while, but... going mostly from memory, in a cassette boot situation:

 

Motor control should already be on so no need to worry about it.  Due to a bug in the OS, you should turn the motor off via PACTL once the tape boot is complete.

A call to SIOV $E459 should be made for each block to be read.

Prerequisite setup of the DCB:

DDEVIC $300 should be set to $60 for cassette, this only needs to be done once, in the case of a tape boot/continuation code it should already have been set.

DUNIT $301 unit number for cassette is ignored so don't worry about this one.

DCOMND $302 command, we want "R" for Read operation, set to $52

DSTATS $303 this is important.  On return this has the status code but before calling SIOV the top 2 bits are used to indicate whether an input or output operation is taking place.  So, we need $40 to indicate input, if we were writing a block it'd be $80.

DBUF $304-5 Points to our buffer address.

DTIMLO $306 and DUNUSE $307 Not used for tape.

DBYT $308-9 Byte count - this is the number of bytes for the operation - data payload only, this doesn't include sync leader bytes or checksum, SIO takes care of those things.

DAUX1/2 $30A-B DAUX1 ignored (?) DAUX2 should = $80 to force short inter-record gaps (in a boot situation should already be set as such)

 

Thank you, Rybags.

 

This is a very good start. I cannot, however, presume cassette boot situation. The loader could be loaded from a disk, so I have to set everything from scratch - switch on the motor, baud rate, wait for leader tone.

Another question - How do I set the expected baud rate?  - POKEY registers?



#4 ijor OFFLINE  

ijor

    Stargunner

  • 1,782 posts

Posted Wed Apr 5, 2017 10:42 AM

Your best source for information is the Atari OS source itself. You have everything there.

 

If you call SIO, you don't mess directly with Pokey. Unless of course, you want to bypass SIO as well, and not just CIO. Anyway, again, check the OS source.



#5 baktra OFFLINE  

baktra

    Chopper Commander

  • Topic Starter
  • 248 posts
  • Location:Czech republic

Posted Wed Apr 5, 2017 11:20 AM

Your best source for information is the Atari OS source itself. You have everything there.

 

If you call SIO, you don't mess directly with Pokey. Unless of course, you want to bypass SIO as well, and not just CIO. Anyway, again, check the OS source.

Yes, now I understand. I will have to bypass also SIO, as I intend to use constant (and not measured) baud rate.



#6 Rybags OFFLINE  

Rybags

    Quadrunner

  • 14,720 posts
  • Location:Australia

Posted Wed Apr 5, 2017 11:25 AM

The bitrate for tape read is determined automatically by the SIO code counting how long it takes to read the timing bytes, each record.

This can compensate for tape stretch that's present or not in various parts of the tape... a standard 132 byte block + short IRG occupies about 5 inches of tape.

I once had an AsmEd cartridge copy as 2-stage tape load, it was recorded as booter + a large 8K single block of data recorded at higher bitrate, never had a problem with it.

 

For tape I/O straight after disk I think the only thing you'd need worry about is turning on the motor.

There's not really any logic that takes care of finding leader tone preceding a file, it's up to the user to position the tape properly.

Generally that means about 8 seconds worth of leeway in total.

 

For recording to tape, the bitrate isn't user selectable but I used a workaround method - have a VBlank Immediate routine which you enable just before calling SIOV - the VBI should plug your alternate bitrate values into the AUDF3/4 channels.  In doing so you can perform fast tape writes although most drives won't handle much over 800 bps.



#7 ijor OFFLINE  

ijor

    Stargunner

  • 1,782 posts

Posted Wed Apr 5, 2017 12:12 PM

Yes, now I understand. I will have to bypass also SIO, as I intend to use constant (and not measured) baud rate.

 

Again, I recommend to check the OS source. You can use the information there to code your own loader. Or, as sometimes was done back at the day, copy the OS to RAM under the ROM (assuming you can live without computers with less than 64k), and implement some patches. Some patches are rather trivial.

 

Not that I am lazy to answer questions. Just that I think this is the best way. And you can always come back if you still have questions after checking the source.



#8 baktra OFFLINE  

baktra

    Chopper Commander

  • Topic Starter
  • 248 posts
  • Location:Czech republic

Posted Wed Apr 5, 2017 12:37 PM

 

Again, I recommend to check the OS source. You can use the information there to code your own loader. Or, as sometimes was done back at the day, copy the OS to RAM under the ROM (assuming you can live without computers with less than 64k), and implement some patches. Some patches are rather trivial.

 

Not that I am lazy to answer questions. Just that I think this is the best way. And you can always come back if you still have questions after checking the source.

 

This is fair enough. The OS listing is a valuable resource. I am not going to patch OS, because the binary loader would fail to load games using RAM under ROM.

 

My goal is to write an alternative to the STDBLOAD 2a binary loader skeleton. The alternative is to be slightly faster and more reliable.  Fixed baud rate ranging from 600-820 bd (utility that will generate the .CAS or .WAV files will patch the loader to set the baud rate), 512 B blocks, XOR checksum, program name displayed, adjustable text and background colors, optional silent I/O, stopping the motor when INIT segments are executed.


Edited by baktra, Wed Apr 5, 2017 12:41 PM.


#9 ijor OFFLINE  

ijor

    Stargunner

  • 1,782 posts

Posted Wed Apr 5, 2017 3:06 PM

 

My goal is to write an alternative to the STDBLOAD 2a binary loader skeleton. The alternative is to be slightly faster and more reliable.  Fixed baud rate ranging from 600-820 bd (utility that will generate the .CAS or .WAV files will patch the loader to set the baud rate), 512 B blocks, XOR checksum, program name displayed, adjustable text and background colors, optional silent I/O, stopping the motor when INIT segments are executed.

 

Just out of curiosity. Why you want a fixed bit rate? And in which way it will be more reliable?



#10 baktra OFFLINE  

baktra

    Chopper Commander

  • Topic Starter
  • 248 posts
  • Location:Czech republic

Posted Wed Apr 5, 2017 3:17 PM

Just want to circumnavigate the baud rate automatic determination routine in the Atari OS. It has a problem that can result in boot errors. I know it occurs rarely and can be patched easily.

#11 Rybags OFFLINE  

Rybags

    Quadrunner

  • 14,720 posts
  • Location:Australia

Posted Wed Apr 5, 2017 6:31 PM

IMO using a forced baud rate for reads would cause more problems than it solves.  The OS bug which causes periodic read errors would probably still be more reliable.



#12 phaeron OFFLINE  

phaeron

    River Patroller

  • 2,135 posts
  • Location:USA

Posted Wed Apr 5, 2017 9:34 PM

Besides the clock sampling bugs, the other funny thing about the standard OS baud rate routine is that it has a lot of code to do a table-based piecewise linear interpolation to compute the POKEY divisor from 10 bit cell times. All they had to do was measure 19 bits instead and the calculation would have simply been multiply the line pair count by six and subtract seven.



#13 ijor OFFLINE  

ijor

    Stargunner

  • 1,782 posts

Posted Wed Apr 5, 2017 10:02 PM

Besides the clock sampling bugs, the other funny thing about the standard OS baud rate routine is that it has a lot of code to do a table-based piecewise linear interpolation to compute the POKEY divisor from 10 bit cell times. All they had to do was measure 19 bits instead and the calculation would have simply been multiply the line pair count by six and subtract seven.

 

Interesting, and possibly they were not aware about that optimization. But if I had to choose, and being so slow, I still prefer to save one additional byte per block.



#14 Rybags OFFLINE  

Rybags

    Quadrunner

  • 14,720 posts
  • Location:Australia

Posted Thu Apr 6, 2017 1:20 AM

Possibly you could just do the baud rate determination once every 8th frame or so, then just use that value as a forced bitrate for the following ones.

But really, it'd probably be a break-even odds tradeoff where you sacrifice reliability to reduce the random chance of the bug popping up.



#15 baktra OFFLINE  

baktra

    Chopper Commander

  • Topic Starter
  • 248 posts
  • Location:Czech republic

Posted Thu Apr 6, 2017 1:28 AM

I am also considering disabling DMA and all unnecessary interrupts when reading a block.

That way, i can try to measure baud rate by counting loop passes when polling the DATA IN pin for just one $55 byte.

 

Anyway, I will have to do some experimentation to determine what works the best.


Edited by baktra, Thu Apr 6, 2017 1:29 AM.


#16 Rybags OFFLINE  

Rybags

    Quadrunner

  • 14,720 posts
  • Location:Australia

Posted Thu Apr 6, 2017 5:44 AM

I think the existing method is probably more than sufficient so long as it's done using bug-free code.

One timing byte or two... really it's less than 1% difference but I guess in terms of a long program load that can be several seconds.

 

Really, without going crazy the biggest savings to be had are by a moderate bitrate increase combined with a larger record size.



#17 ijor OFFLINE  

ijor

    Stargunner

  • 1,782 posts

Posted Thu Apr 6, 2017 9:52 AM

Larger block sizes can perform a significant saving. But the chances of checksum collision (good checksum with bad data) also increase. And unlike smart devices that compute the checksum, here checksum errors are more frequent because they come directly from the media.



#18 Rybags OFFLINE  

Rybags

    Quadrunner

  • 14,720 posts
  • Location:Australia

Posted Thu Apr 6, 2017 10:18 AM

Given a custom record size would need a loader which does the block level handling, it wouldn't be too much extra effort to do a 16-bit checksum or maybe a CRC.



#19 pirx OFFLINE  

pirx

    Moonsweeper

  • 323 posts
  • Location:Poland

Posted Fri Apr 7, 2017 1:23 AM

Such a system has been implemented by Jakub Husak in his games, he also did it for my Bank! Bang!. The goal was to be able to rewind tape and retry reading a single record.

 

With regards to baud rate - I had quite a success in reading 1200baud tapes, but 900 was the reasonable and standard in my primary school for keeping data :)))))))) 



#20 ijor OFFLINE  

ijor

    Stargunner

  • 1,782 posts

Posted Fri Apr 7, 2017 9:41 PM

Such a system has been implemented by Jakub Husak in his games, he also did it for my Bank! Bang!. The goal was to be able to rewind tape and retry reading a single record.

 

There are several custom loaders. But I think we implemented tape retry logic earlier than your friend. At least we did it a few years before those games.
 



#21 baktra OFFLINE  

baktra

    Chopper Commander

  • Topic Starter
  • 248 posts
  • Location:Czech republic

Posted Wed Apr 19, 2017 1:24 AM

All things considered, I will create a binary loader that works with 512 B blocks and will call SIOV. Bypassing SIO doesn't appear to be a brilliant idea anymore.
I will try to make the processing of the segment headers fast, so the IRGs won't have to be elongated by much or at all.


Edited by baktra, Wed Apr 19, 2017 6:12 AM.


#22 CharlieChaplin OFFLINE  

CharlieChaplin

    River Patroller

  • 2,411 posts

Posted Wed Apr 19, 2017 5:07 AM

It will be hard to load 512KB blocks on a 64k / 6502 machine. ;-)

512byte blocks might be better, even though they are non-standard...

(I still prefer the standard 128byte blocks that can be easily copied to disk/bootdisk.)


Edited by CharlieChaplin, Wed Apr 19, 2017 5:08 AM.


#23 baktra OFFLINE  

baktra

    Chopper Commander

  • Topic Starter
  • 248 posts
  • Location:Czech republic

Posted Wed Apr 19, 2017 6:14 AM

It will be hard to load 512KB blocks on a 64k / 6502 machine. ;-)

512byte blocks might be better, even though they are non-standard...

(I still prefer the standard 128byte blocks that can be easily copied to disk/bootdisk.)

 

You are right, but with U1MB, it might be possible :-)

For 128byte blocks, there is the C: device. 



#24 Rybags OFFLINE  

Rybags

    Quadrunner

  • 14,720 posts
  • Location:Australia

Posted Wed Apr 19, 2017 6:41 AM

You might get away with using slightly longer gaps when you know the record just written has lots of segments.

But really, it's not common to have more than several in a 512 byte section. 



#25 baktra OFFLINE  

baktra

    Chopper Commander

  • Topic Starter
  • 248 posts
  • Location:Czech republic

Posted Wed Apr 19, 2017 7:28 AM

You might get away with using slightly longer gaps when you know the record just written has lots of segments.

But really, it's not common to have more than several in a 512 byte section. 

 

Perhaps switching off screen DMA will give me some cycles. As the loader will be embedded in Turgen System, some preprocessing of the binary file can help - e.g. ensuring that no segment except the first one has optional $FF, $FF header. And yes, I will know how many INIT vectors are in a block, so the IRG can be elongated accordingly.






0 user(s) are browsing this forum

0 members, 0 guests, 0 anonymous users