Classic Computer Magazine Archive COMPUTE! ISSUE 64 / SEPTEMBER 1985 / PAGE 110

INSIGHT: Atari

Bill Wilkinson

Using Serial Input/Output

Last month, I introduced the structure of Atari's operating system (OS). My most important point was that the OS consists of several layers. When you type in a BASIC statement such as LPRINT "Hi There!", you cause a fairly complex chain of events. First, BASIC figures out that LPRINT means you want to use a printer, so it calls the OS to open a channel to the printer (always channel number 7, in this case). Then BASIC sends the bytes to be printed to a part of the OS called Central Input/Output (CIO), which in turn realizes that a file to the printer has been opened on that channel. CIO calls the printer driver, which collects bytes until it has a block of them (or until it gets a carriage-return character or a CLOSE command). Finally, the printer driver sends a block of bytes to the printer by calling Serial Input/ Output (SIO)-another subroutine inside the OS, and the subject of this month's discussion.
    I'd like to point out that this process stops at SIO only as far as the computer is concerned. The printer interface (for example, an 850 Interface Module) also contains a microprocessor which collects the block sent to it by SIO. Then the interface passes the block, a byte at a time, to the printer. Within the printer, yet another microprocessor is usually employed to control the various motors and hammers and wheels that actually place the characters on paper.
    Did you note that the process of printing even a single character most probably requires the use of three microprocessors? Did you stop to think that each of these processors requires software to make it work? Did you ever wonder why there are so many people making a living at programming? (Though barely, in the case of some of us.)
    Perhaps the most amazing thing is that, for the most part, the three microprocessors work reliably and efficiently together. (It is even more amazing when you consider that either the printer or interface module is often made by a company other than the one which made the computer!) The secret to success here is standardization. The usual printer connection is a fairly simple one, originally defined by a company named Centronics and now adopted by almost every manufacturer in the microcomputer market.
    The way your Atari computer "talks" to your interface module, though, is strictly an Atari invention-the SIO. There is a well-defined protocol associated with SIO. It includes such niceties as Command and Data Frames, Acknowledgment, Nonacknowledgment, Command and Bus Errors, and more. Luckily, 99 percent of all Atari programmers need never learn these gory details, since there really isn't anything you can do to change their workings.

Disk Access Via SIO
Some programmers, however, do want to send and receive blocks via SIO. And usually the blocks to be transferred are disk sectors. So let's look at how one reads or writes a specific disk sector.
    When SIO is called by a program, it expects to find certain information in a Device Control Block (DCB). There is only one DCB, located at $0300-$030B (768-779 decimal). It contains four one-byte values and four two-byte (word) values, all of which must be set up properly. The accompanying table briefly describes each location in the DCB. See COMPUTE! Books' Mapping the Atari for more details.
    Does all this look confusing? Not to worry. Program 1 below is a subroutine which does most of the work for you. Just type it in, LIST it to disk or cassette, and use it in your own programs whenever you wish. Program 2 demonstrates how to use the subroutine, though I hope the comments make it pretty much self-explanatory. (Perhaps I should note that a command of R reads a sector, P writes a sector without verifying it, and W both writes and verifies a sector.) To use Program 2, you must add the subroutine from Program 1. You can either type in the lines from Program 1, or ENTER them from disk or tape if you have LISTed out a copy of Program 1. Program 3 is the source code behind the DATA statements in line 9210 of Program 1.
    If you type in and use Program 2, you might like to remember that the volume table of contents (VTOC) of a DOS 2.0-compatible disk is in sector 360. The directory occupies sectors 361 to 368. Sectors 1, 2, and 3 are for booting only. All other sectors from 4 to 719 should be DOS file sectors. (See COMPUTE! Books' Inside Atari DOS for more info. Caution: The diagram of the sector link bytes is wrong.)
    Finally, I give you a hint and challenge for next month: Most drives not made by Atari allow the user to specify their configuration (for example, single or double density). You can read their configuration blocks with an SIO command of N (or write via O). But be careful! DSIZE must be given as 12 bytes. Can you modify our subroutine to read the configuration block? Good luck.


DCB Layout Table

 Location  
Name
 Size 
Purpose
Hex
Dec



300
768
DDEVIC 1
Name of device on SIO bus (all disk drives use "1," $31, as a name).
301
769
DUNIT 1
Unit number of device (to distinguish Dl: from D2:, for example).
302
770
DCOMND 1
Command, usually an ATASCII letter, such as "R" for read sector (but "1" will format a disk!).
303
771
DSTATS 1
Direction control before call to SIO; status of operation upon return.
304
772
DBUF 2
Address of buffer to read from or write to, as appropriate.
306
774
DTIME 2
Timeout value. SIO waits this many seconds before giving up.
308
776
DBYTE 2
Number of bytes to transfer (always 128 or 256 for disks).
308
778
DAUX
2
Purpose varies; always sector number when used with disks.


Program 1: SIO Subroutine
For instructions on entering this listing, please refer to "COMPUTE!'s Guide to Typing In Programs" published bimonthly in COMPUTE!.

LF 9000 REM ................
JG 9010 REM DISK SECTOR I/O
        ROUTINE
JF 9020 REM . ENTER:
JO 9030 REM .{3 SPACES}secto
        r number in SECTOR
ND 9040 REM .{3 SPACES}drive
        number in DRIVE
DC 9050 REM .{3 SPACES}buffe
        r address in ADDR
IP 9060 REM .{3 SPACES}comma
        nd in CMD$
MJ 9070 REM .{3 SPACES}densi
        ty in DENSITY
GM 9080 REM (only "R","W","P
        " are valid for CMD$
        )
EA 9090 REM (only 1=SGL and
        2=DBL are valid for
        DENSITY)
FA 9100 REM . EXIT:
CH 9110 REM .(3 SPACES)statu
        s in SIOSTATUS
LA 9120 REM
OI 9160 TRAP 9220:REM activa
        tad if SIOCALL$ alre
        ady DIM'd
IO 9170 DIM SIOCALL$(16)
MC 9180 RESTORE 9210
JP 9190 FOR CNT=1 TO 14:READ
        BYTE
EN 9200 SIOCALL$(CNT)=CHR$(B
        YTE):NEXT CNT
MC 9210 DATA 104,32,89,228,1
        73,3,3,133,212,169,0
        ,133,213,96
FB 9220 TRAP 40000:REM turn
        off TRAP
MO 9230 POKE 768,ASC("1"):RE
        M don't ask me why
GC 9240 POKE 769,DRIVE:REM m
        ust be 1 through 8
OJ 9250 POKE 770,ASC(CMD$)
DN 9260 POKE 771,128:REM ass
        ume write
LP 9270 IF CMD$="R" THEN POK
        E 771,64
NA 9280 POKE 773,INT(ADDR/25
        6):REM buffer addres
        s
PF 9290 POKE 772,ADDR-256*PE
        EK(773)
FB 9300 POKE 774,3:REM short
        timeout
JK 9310 POKE 775,0:REM (high
        byte of timeout)
AA 9320 POKE 776,128:POKE 77
        7,0:REM assume singl
        e density
LG 9330 IF DENSITY=2 THEN PO
        KE 776,0:POKE 777,1
KK 9340 POKE 779,INT(SECTOR/
        256)
LD 9350 POKE 778,SECTOR-256*
        PEEK(779)
HM 9360 SIOSTATUS=USR(ADR(SI
        OCALL$))
LD 9370 RETURN


Program 2: SIO Demo
For instructions on entering this listing, please refer to "COMPUTE!'s Guide to Typing In Programs" published bimonthly In COMPUTE!.

KC 1000 REM PROGRAM TO DEMON
        STRATE SECTOR READ S
        UBROUTINE
HJ 1010 REM NOTE: rather tha
        n ask questions, we
E3 1020 REM .{5 SPACES}assum
        e that we will work
        with drive
KP 1030 REM .{5 SPACES}numbe
        r 1 and that it is s
        ingle
HK 1040 REM .{5 SPACES}densi
        ty (128 byte sectors
KK 1050 REM
PA 1100 DIM BUFFER$(256):REM
         guaranteed adequate
ML 1110 ADDR-ADR(BUFFER$):RE
        M required by subrou
        tine
PI 1120 DRIVE=1:REM assumpti
        on ... easily changed
OC 1130 DENSITY=1:REM assump
        tion...ditto
JO 1140 DIM CMD$(1):CMD$="R"
        :REM always, for thi
        s demo
KL 1150 REM
NB 1160 PRINT "What sector t
        o display";
CJ 1170 INPUT SECTOR
BD 1180 GOSUB 9000
EM 1190 GRAPHICS 0
DL 1200 PRINT "Read Sector "
        ;SECTOR;" gave Statu
        s ";SIOSTATUS
OP 1210 SIZE-DENSITYf128:REM
         size is 128 or 256
CJ 1220 SECTOR-PEEK(ADDR+SIZ
        E-3)
JC 1230 FILE;INT(SECTOR/4)
EP 1240 SECTOR=SECTOR-4*FILE
DN 1250 SECTOR=SECTOR*256+PE
        EK(ADDR+SIZE-2)
EA 1260 CNT-PEEK(ADDR+SIZE-1
DO 1270 PRINT "If DOS file s
        ector, this is file
        #";FILE
MB 1280 PRINT " there are "
        ;CNT;" bytes in this
         sector"
NA 1290 PRINT " and the nex
        t sector is number "
        ;SECTOR
FB 1300 PRINT
JL 1310 FOR LINE=0 TO DENSIT
        Y*128-1 STEP 8
FP 1320 BYTE=LINE:GOSUB 1500
        :PRINT ":";
WK 1330 FOR CNT=0 TO 7
PD 1340 BYTE=PEEK(ADDR+LINE+
        CNT):GOSUB 15002PRIN
        T " ";
ON 1350 NEXT CNT
NN 1360 FOR CNT=0 TO 7
DA 1370 BYTE=PEEK(ADDR+LINE+
        CNT)
AD 1380 IF BYTE>127 THEN BYT
        E=BYTE-128
BB 1390 PRINT CHR$(27);CHR$(
        BYTE);
OJ 1400 NEXT CNT
FD 1410 PRINT
CO 1420 NEXT LINE
FF 1430 PRINT
MK 1440 GOTO 1160
LA 1450 REM ................
        ....................
        ...
PF 1460 REM A QUICKY DECIMAL
         TO HEX CONVERTER
NF 1500 TRAP 1520
DO 1510 DIM HX$(16):HX$="012
        3456789ABCDEF"
PO 1520 TRAP 40000
EK 1530 HX=INT(HYTE/16)+1:PR
        INT HX$(HX,HX);:HX=B
        YTE-16*HX+17:PRINT H
        X$(HX,HX);
KK 1540 RETURN


Program 3: Subroutine Source Code
Note: This listing is provided for informational purposes; it requires an assembler to enter into your computer.

     *= anyplace
CALLSIO
  PLA      ;throw away count
           ; of arguments
  JSR SIOV   ;(at $E459)
  LDA DSTATS ;SIO status
             ; (from DCB)
  STA FRO ;floating point
          ; register 0, $D4
  LDA #0
  STA FRO+1 ;(to get a two-
            ; byte value)
  RTS ;back to BASIC caller