How do exactly works the .CAS Format ?

By cesco

Champion (454)

cesco's picture

06-01-2008, 10:08

Does anybody here knows how the .CAS Format works? I'm talking about the file format used in the MSX emulators to store Tape images

From what I have understood doing a quick "reverse-engineering" with a Hex editor, there are eight characters at the beginning of each file stored in the tape that are always the same:

0x1F, 0xA6, 0xDE, 0xBA, 0xCC, 0x13, 0x7D, 0x74

Then there is a character that is repeated for ten times, and then the name of the file stored in six character, followed by a 0x1F character. The rest of the header is a mistery to me... it probably tells if the following file is a binary file, an ASCII file or a Basic file... how long it is and probably its checksum... but I really don't understand how I can read those values.

For example this appears to be a valid header for a .CAS File:

img142.imageshack.us/img142/2235/casheaderho8.gif

I'd like to try to make a small utility to manage .CAS files in my free time, like what DiskManager is for the .DSK format. I think it shouldn't be a difficult task...

Login or register to post comments

By Vincent van Dam

Hero (513)

Vincent van Dam's picture

06-01-2008, 10:36

I have send this to the msx mailinglist once (a few years ago);

The cas format is the result of bypassing the following BIOS calls:

00E1 - TAPION
00E4 - TAPIN
00EA - TAPOON
00ED - TAPOUT

If you call the TAPION function, the BIOS will read from tape untill it has
found a header, and all of the header is read. The TAPOUT function will
output a header. In the cas format the header is encoded to these 8 bytes:

1F A6 DE BA CC 13 7D 74

These bytes have to be at a position that can be divided by 8; e.g. 0000,
0008, 0010 etc. If not, the byte sequence is not recognised as a header.

When outputting data to tape with the BIOS calls TAPOUT the bytes are
written to the .cas file, nothing fancy is done with the bytes (unlike on a
real tape where the byte would be fsk encoded with 1 start bit and 2 stop
bits).

Because the cas file format is the product of some BIOS hooks not all tapes
can be converted to this format. For example, if you would take a gremlin
tape, the data on the tape is encoded entirely differently than the BIOS
would have done (you can hear the different modulation in the sound). The
loader included on the tape writes and reads directly from the tape without
using the bios, but using the IO ports.

You can take a look at the source castools package and example cas files at:
http://home.kabelfoon.nl/~vincentd

By cesco

Champion (454)

cesco's picture

06-01-2008, 10:56

Thank you very much.

How do you recognize if a file on a tape is a Binary or not?

By Vincent van Dam

Hero (513)

Vincent van Dam's picture

06-01-2008, 11:31

There are 4 types of data that can be stored on a tape;

* binary files (bload)
* basic files (cload)
* ascii files (load)
* custom data (to be loaded using the bios)

Data is stored on the tape in blocks, each block is preceeded by a header (the 1f a6 de .. block). The purpose of this header (the pieeeeeeeeep), is to sync for decoding the fsk data.

Binary files (bload) consist out of two blocks; a binary header block, and a binary data block. The binary header block is specified by 10 times 0xD0, followed by 6 characters defining its filename. The block following this header, is the datablock, which also defines the begin,end and start address (0xFE,begin,end,start).

Basic files (cload) also consist out of two blocks; a basic header block, and a basic data block. The basic header block is specified by 10 times 0xD3, followed by 6 characters defining its filename. The block folowing this header is the datablock (tokenized basic data).

Ascii files (load) can consist out of multiple blocks. The first block is always the ascii header block, which is specified by 10 times 0xea, followed again by 6 characters defining the filename. After this, an unlimited number of blocks can follow. The last block can be identified by the EOF (0x1a) character.

Custom blocks are all blocks that don't fit in the 3 specified above.

You might want to look at the casdir.c code, which implemented the above.

By cesco

Champion (454)

cesco's picture

06-01-2008, 12:02

Now I understand... Thank you very much for your help

By muffie

Paladin (933)

muffie's picture

15-06-2009, 04:47

1F A6 DE BA CC 13 7D 74

I have a .CAS with several of those strings.
First one is like you said:
1F A6 DE BA CC 13 7D 74 + 10*d0 + 6*(name) + data. Second one is:

1F A6 DE BA CC 13 7D 74 + 00 a0 + 00 a4 + 00 a0

What I think it means: start loading at a000, end at a400 and when it's done execute a000.

No FE, right?

BUT, last one on the cas is:

1F A6 DE BA CC 13 7D 74 + f9 2f + 80 01 + 0104
start loading at 2ff9, stop at 0180? and run 0401?

What's wrong with my assumptions?

By cesco

Champion (454)

cesco's picture

15-06-2009, 08:31

This sequence of bytes:

0x1F 0xA6 0xDE 0xBA 0xCC 0x13 0x7D 0x74

is the "header" of your file stored on tape: it tells the MSX that what follows on the tape is not garbage but a program (or at least some valuable data). This is followed by ten bytes that explain to the MSX which kind of file it is going to read. All these ten bytes must have the same value:

if the byte value is 0xD0, then it's a binary file
if the byte value is 0xD3, then it's a basic file
if the byte value is 0xEA, then it's an ASCII file
if the byte value is not one of these three, then the MSX knows that it is going to read a data block. A data block can be used to store data, for example if you'd like to create a turbo loader you could make a binary file first with the program that handles the turbo loading, then you could store the file you want to load in a data block.

you usually could have to handle one of these cases:

1) A BINARY FILE:

* When this byte value is 0xD0, 0xD3 or 0xEA (Binary, Basic or ASCII) this is followed by six bytes / six characters that contains the name of the file.

* After the name of the file you have six bytes that explains to MSX:

- the STARTING ADDRESS; From which RAM address the MSX will have to store data (2 bytes)
- the ENDING ADDRESS; that is equal to STARTING ADDRESS + FILE LENGTH - 1. Just remember that FILE LENGTH is the length of your file *WITHOUT* the header information, just the plain file you're going to load. (2 bytes)
- the EXECUTION ADDRESS; that tells the MSX on which memory address it will found an assembly routine to execute the file. (2 bytes)

REMEMBER: all these addresses (STARTING, ENDING and EXECUTION) takes two bytes *BUT* the byte values are stored "swapped"; this method does have a name and if I am not mistaken it was invented by Intel, but in this moment I cannot remember its name (big-endian and low-endian).
If I show you an example, maybe you'll understand this concept better:

let's say we want to store address 0x4000. In this case we'll have to put bytes 0x00 and 0x40. You swap 40 and 00.
Now let's say we want to store address 0x1234. In this case we'll have to put bytes 0x34 and then 0x12. You swap 12 and 34.

2) A BASIC FILE:

* When this byte value is 0xD0, 0xD3 or 0xEA (Binary, Basic or ASCII) this is followed by six bytes / six characters that contains the name of the file.
* Remember that what follows is a tokenized basic file.

3) AN ASCII FILE:

* When this byte value is 0xD0, 0xD3 or 0xEA (Binary, Basic or ASCII) this is followed by six bytes / six characters that contains the name of the file.
* Every 256 bytes you have a resynchronization (the long "BEEEEEEEEP" sound you hear when you try to listen a msx tape). resynchronization is (again) 0x1F 0xA6 0xDE 0xBA 0xCC 0x13 0x7D 0x74.
* If the length of your program is less than 256 bytes, you should fill it with the value 0x31. I don't know why or if you could use another value, but 0x31 worked for me.

If you want some weeks ago I have started to convert some portions of MSX Taper in PHP, you can read the sample code to read a tape file by visiting this web address:

http://code.google.com/p/msx-tape-tools/source/browse/trunk/msxtape.php

This simple PHP script will read the content of a .CAS file, put it into a XML file and then it will print it on the screen. The indentation of the code is not really good on the site, I probably forgot to use TABs instead of spaces on some lines because it's perfect on my IDE, and the comments are still written in Italian, but maybe you can have an idea about what it does.

By cesco

Champion (454)

cesco's picture

15-06-2009, 09:32

* If the length of your program is less than 256 bytes, you should fill it with the value 0x31. I don't know why or if you could use another value, but 0x31 worked for me.

Sorry, that wasn't correct:

you have to fill it with the value 0x1A. The very last byte (the 256th) should be 0x1F

By SadKen

Rookie (17)

SadKen's picture

01-10-2014, 16:01

Quick question (really old thread i know... but meh)

How do you handle the custom types? CAS2WAV doesn't like these, and it'd be good to put them in (as certain cas files don't work after converting)