Jump to content

kenjennings' Blog - Part 11 -- Simple Assembly for Atari BASIC (The End


Recommended Posts

Binary File I/O (Part 2 of 2)

New XIO in Mac/65 Assembler Code

Many articles on this subject go by a simple route – use BASIC code to set up all the IOCB values for the 7/Get Bytes or 11/Put Bytes commands, and then provide a minimal assembly routine that simply calls the CIO vector. While BASIC mangles the binary read/write functions, XIO itself also is sufficiently broken to justify a complete machine language USR() routine that exercises CIO commands the way they were intended. For example, ICAX values are not always needed or even wanted, but XIO requires the values. In fact, ICAX values are rarely needed outside of the 3/Open command. Similarly, the filespec/buffer is often not necessary.

This routine will perform the same purpose of XIO, but allow a variable number of arguments, adding more arguments only as needed:

Always required (2 arguments):

1) Channel Number – Only low byte values 0 to 7 accepted. The high byte is ignored.

2) CIO Command – Only the low byte of the argument will be used.

Optional (4 arguments):

3) Filespec/Buffer address – 16-bit value

4) Filespec/Buffer length – 16-bit value

Additionally optional when the Filespec/Buffer is provided (5 arguments):

5) ICAX1 – the low byte of this argument is used. High byte is ignored.

Additionally optional when the Filespec/Buffer and ICAX1 are provided (6 arguments):

6) ICAX2 – the low byte of this argument is used. High byte is ignored.

Since the routine accepts 2, 4, 5, or 6 arguments it can support any of the following:



2) USR(NEWXIO,6,18) – Perform command 18/Fill for screen device (assuming channel 6)

4) USR(NEWXIO,1,254,ADR(F$),LEN(F$)) - Use channel 1 to format (254) the disk drive described by F$. This would also be the format/number of arguments needed for performing CIO Commands 7/Get Bytes and 11/Put Bytes.

5) USR(NEWXIO,5,3,ADR(F$),LEN(F$),6) - Use channel 5 to open (3) the disk directory (read/4 + directory/2 = 6) described by F$

6) USR(NEWXIO,6,3,ADR(F$),LEN(F$),28,7) – Use channel 6 to open (3) as graphics mode 7 with a text window (read/4 + write/8 + window/16 = 28) assuming F$ describes “S:”

Variable number of arguments means this program is organized differently from the prior utilities that copy stack arguments to Page Zero. Since this is just an interface for putting values into the IOCB it doesn't make use of Page Zero beyond returning a status value to BASIC.
The initialization is similar to prior utilities. It begins by setting the return value to a known value ($FFFF) that cannot be returned by a successful exit. Then it pulls the argument count and does a series of value checks to identify any invalid number of arguments. If the code identifies an issue here it branches to cleaning the stack and then exits. One difference in the stack argument management is that this utility does not double the argument count to derive the number of bytes on the stack, because it will not be looping to copy the stack values into Page Zero.

The channel handling is more involved than other arguments:
0525 DO_ICCMD ;      Arg 2 = Command0530     PLA         ; discard high byte0535     PLA         ; command byte0540     STA ICCMD,X ; Store Command in IOCB0545     DEY         ; subtract one arg0550     BEQ DO_CIO
The values are pulled from the stack and stored in the corresponding IOCB field. Then the argument counter is decremented. At the end of processing the arguments for command, buffer length, and ICAX1 (arguments 2, 4, and 5) the argument count is tested if it has reached zero. If this occurs then the program skips over the work for processing any subsequent arguments.

Finally, it gets down to business:
1. The function accepts an absolute address and a length allowing access to any part of memory. While this is much more flexible than XIO it also means that this routine cannot directly accept a BASIC string. This routine can use a string passed by its address via ADR(). It is also up to the BASIC program to pass the correct length. LEN() is correct only when the string has defined content, so a BASIC program must fill or pad out the string to its expected length.

2. Since this is a USR() routine it is not integrated in BASIC's error handling. Therefore TRAP cannot trap any Input/Output errors. The BASIC program must check the return value of the NXIO routine or use the STATUS command to identify problems.

1 REM MAKENXIO.BAS5 REM CREATE NXIO.BIN FILE10 OPEN #1,8,0,"H1:NXIO.BIN"15 FOR I=1 TO 9420 READ D:PUT #1,D25 NEXT I30 FOR I=95 TO 25535 PUT #1,040 NEXT I45 CLOSE #150 END21996 REM H1:NXIO.OBJ21997 REM SIZE = 9421998 REM START = 3686421999 REM END = 3695722000 DATA 160,255,132,212,132,213,104,24022001 DATA 84,168,201,1,240,8,201,322002 DATA 240,4,201,7,144,6,104,10422003 DATA 136,208,251,96,136,104,104,20122004 DATA 8,176,243,10,10,10,10,17022005 DATA 104,104,157,66,3,136,240,3422006 DATA 104,157,69,3,104,157,68,322007 DATA 136,104,157,73,3,104,157,7222008 DATA 3,136,240,14,104,104,157,7422009 DATA 3,136,240,6,104,104,157,7522010 DATA 3,136,132,212,132,213,32,8622011 DATA 228,16,2,132,212,9622012 DATA 67,3,133,212,96
This will make managing the utility easier, allowing the test program (and any other BASIC program) to load the utility directly from the file without reading DATA statements. Note that the program purposely pads the output to 255 bytes, so that a BASIC program can use the (broken) XIO. This is acceptable for the tightly confined usage here – the program does only one operation to read a file of 255 bytes. The remaining CIO activity in the program is run by the shiny, new NXIO routine:
$="!!!!!!!!"345 ? "LOADING 8 BYTE MEMORY.BIN..."350 OPEN #1,4,0,"H1:MEMORYT0.BIN"355 XREAD8=USR(NXIO,1,7,ADR(D$),8)360 CLOSE #1365 FOR I=1 TO 8370 ? ASC(D$(I,I)),375 NEXT I380 ?  "XREAD8 = ";XREAD8385 GOSUB 595390 REM395 REM SAVE THE ROM CHARACTER SET400 CR=57344:REM ROM SET $E000405 ? "SAVING ROM CHARACTER SET..."410 OPEN #1,8,0,"H1:CSET.BIN"415 XSAVE=USR(NXIO,1,11,CR,1024)420 CLOSE #1425 ? "XSAVE = ";XSAVE430 GOSUB 595435 REM440 REM GAMES WITH THE BINARY LOAD445 REM SETUP SCREEN FIRST...450 GRAPHICS 0:POSITION 0,12455 SC=PEEK(88)+256*PEEK(89)460 FOR Y=0 TO 7465 FOR X=0 TO 31470 POKE SC+Y*40+X,Y*32+X475 NEXT X480 NEXT Y485 ? "NORMAL CSET DISPLAYED"490 ? "TO LOAD SOFT SET"495 GOSUB 595500 REM505 REM LOAD THE SOFT SET IN510 REM FLIPPED HALF SETS515 CH=36864:REM SOFT SET $9000520 POKE 756,144525 OPEN #1,4,0,"H1:CSET.BIN"530 CSLOAD1=USR(NXIO,1,7,CH+512,512)535 CSLOAD2=USR(NXIO,1,7,CH,512)540 CLOSE #1545 ? "SWAPPED, SOFT CSET CSET DISPLAYED"550 GOSUB 595555 REM560 REM THE END565 GRAPHICS 0570 ? "CSLOAD1 = ";CSLOAD1575 ? "CSLOAD2 = ";CSLOAD2580 END585 REM590 REM WAIT FOR A KEY595 ? "PRESS A KEY"600 OPEN #1,4,0,"K:"605 POKE 764,255610 GET #1,A615 CLOSE #1620 RETURN 

The program begins by reading the machine language routine via XIO into a string 255 characters long. Yes, the routine is actually only 94 bytes long, so it wastes a bit of space. Such is life when using XIO.

The first round of tests validates the argument management. There is a separate test for each bad argument possibility – 0, 1, 3, and 7 (or greater). Each failure to start results in error code 65535 from NXIO:

The next round of tests uses NXIO with all the supported arguments to open a graphics mode 5 display with no text window. Then it draws a shape and uses NXIO to execute the 18/Fill command:

After the fill completes press a key to continue and then the program prints the NXIO exit codes for the Graphics Open and the Fill:

Press a key again and the program runs the next test which uses 7/Get Characters to read the 8-byte MEMORYT0.BIN file created earlier. After loading the file the program prints the ATASCII codes for the bytes in the string. It should report the values below, and then print the exit code from NXIO for the 8-byte read.:

Press a key after this to run the next test. This will use the 11/Put Characters to save the entire 1,024 bytes of the Atari's ROM character set to a file. Then it will print the exit code from the NXIO routine for the operation:

Press a key to run the next test. This will prepare the screen to demonstrate loading the character set from the file into memory. The characters are displayed in the internal order. Note the order of the characters.

Press a key to continue the test. The program will use 7/Get Characters to load the first 512 bytes from the file into the second 512 bytes of the soft character set in memory, and then it loads the second set of 512 bytes from the file into the first 512 bytes of the soft character set in memory. This effectively swaps the images of the first half of the character set with the second half. Observe the “changed” order of the characters:

Finally, press a key to return the display to the normal character set and the program will display the return codes from NXIO for the loading activities and then it ends:

The tests all work as expected, especially all the uses of 7/Get Characters and 11/Put Characters. So, there is no problem with CIO. The problem really is that BASIC's XIO command unnecessarily manages the interface to CIO commands. Correct use of the CIO commands is so simple and the behavior XIO implements is so involved and complicated that it is difficult to consider it simply an accident.

What could be the reason for XIO's bizarrely over-engineered behavior? Perhaps at the time Atari BASIC was designed there was an expectation that these I/O operations must work in increments no less and no more than 255 bytes. Perhaps a misunderstanding between OS design and BASIC design? Perhaps design requirements were in motion and it was too late to fix the behavior. Truly weird.

Below is a list of the source files and test examples from the New XIO discussion available in the disk image and archive. The files are listed in the order presented during the discussion. The BASIC programs come in the tokenized BASIC format ending in .BAS. Two listings in text format are also provided: Atari ATASCII format as .LIS and unix/linux text format ending in .TLS.

New XIO File List:

MSAVEDAT BASIC program to PRINT eight values to a file.
MSAVEDT0 BASIC program to PUT eight bytes to a file.
MLOADDT0 BASIC program to GET eight bytes from a file.
XIOFILL BASIC program performing the XIO fill command using device “Q:”
MSAVEDT2 BASIC program using XIO for 11/Put Bytes to write a file.
MSAVEDT3 BASIC program using XIO for 11/Put Bytes to write data to a file with a trailing string to identify the source of excess file data.
MLOADDT BASIC program using XIO for 7/Get Bytes.
MLOADDTX BASIC program using XIO for 7/Get Bytes with a trailing string to detect excess data read from the file.
MSAVE512 BASIC program to generate a file containing 512 bytes.
MLOAD512 BASIC program using XIO for 7/Get Bytes attempting to load 512 bytes from a file.
MLOAD8 BASIC program using XIO for 7/Get Bytes attempting to load bytes from a file containing 8 bytes.

NXIO.M65 Saved Mac/65 source
NXIO.L65 Mac/65 source listing
NXIO.T65 Mac/65 source listed to H6: (linux)
NXIO.ASM Mac/65 assembly listing
NXIO.TSM Mac/65 assembly listing to H6: (linux)
NXIO.OBJ Mac/65 assembled machine language program (with load segments)
NXIO.BIN Assembled machine language program without load segments with additional data padded to the end of the file to make it 255 bytes long.
NXIO.DAT LISTed DATA statements for NXIO machine language routine.

MAKENXIO BASIC program to create the BIN file with padding to 255 bytes so the file can be loaded using XIO to read the binary data.
TSTNXIO1 BASIC program testing the NXIO USR() routines for various CIO commands.

ZIP archive of files:

Tar archive of files (remove the .zip after download)

Game Over

The movie really is over this time. Thanks for playing. Enjoy the new toys. Finally, welcome to the new world of assembly language. Try to think of new ways to accelerate and improve BASIC programs.

- End -

Blessed is the man who walks not in the counsel of the wicked, nor stands in the way of sinners, nor sits in the seat of scoffers;
Psalm 1:1

Attached thumbnail(s)
  • blogentry-32235-0-20102000-1469762998.pn
  • blogentry-32235-0-72393900-1469763042.pn
  • blogentry-32235-0-53449900-1469763075.pn
  • blogentry-32235-0-96204000-1469763118.pn
  • blogentry-32235-0-25823200-1469763143.pn
  • blogentry-32235-0-72205300-1469763175.pn
  • blogentry-32235-0-67317700-1469763214.pn
  • blogentry-32235-0-82500200-1469763255.pn
Attached File(s)

Link to comment
Share on other sites

This topic is now closed to further replies.

  • Recently Browsing   0 members

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