- "S-100 Computers & TurboDOS"
"FOGHORN", Vol.VIII, No.3, December 1988, p.13
(Retyped by Emmanuel ROCHE.)
I am the system manager and programmer for a business that repairs electric
tools, and sells and repairs electric motors and pumps. We generate 20,000
sales invoices, 10,000 repair tags, 3,600 checks, and 5,000 purchase orders
each year. We also process 6,000 payable invoices, and payroll for up to 20
employees paid on a weekly basis. We maintain a 40,000 record parts inventory
database. All systems are integrated into general ledger, and a complete
financial statement is generated by 9 a.m. on the first of every month,
summarizing the just completed month.
It is all done with dBASE II ver. 2.43 operating on an S-100 Bus 17-user
system running a TurboDOS ver. 1.43 operating system.
There are 5 system printers. Printing is automatically routed to the printer
having the correct form loaded -- invoice, job tag, check, bookkeeping
reports, and all other reports/plain paper forms. All printing is
automatically spooled and despooled, so there are never any conflicts.
The software is designed so that all users can be simultaneously generating
any particular form, i.e., an invoice, and, if they all send it to the printer
at the same moment, TurboDOS will despool each invoice, one at a time. The
system accommodates both open account invoicing and point-of-sale invoicing.
TurboDOS runs on the Zilog Z-80 and Intel 8086 families of processors. It is
distinguished by its networking capability, and its ability to run virtually
any CP/M program without modification. Our business has relied on it
continually for the last 4 years, and we have never been "down" on a business
day for more than an hour or two.
A separate microcomputer supports each user's video console, and an additional
microcomputer manages the disks and the bus.
Growth forced hardware upgrade
Up until October 1987, we operated an 8-user NorthStar Horizon (S-100 Bus)
system running an earlier version of TurboDOS. Although it had given us good
service, we had outgrown it. The 8-bit 4-MHz 64-K RAM slave boards, combined
with an 8-bit 64-K RAM master, just was not fast enough.
All the slots on the bus were filled, and we had maxed out at 8 users. We
implemented a massive hardware upgrade, purchasing a new chassis, S-100 Bus
boards, hard disk controller, floppy drives, and a tape drive. We retained our
existing hard disks, printers, and CRTs.
Since the floppies and tapes used on the NorthStar system were completely
incompatible with the floppies and tapes for the new system (ROCHE> NorthStar
used "hard-sectored" floppies, because this simplified the disk controller.
Unfortunately, "soft-sector" floppies became the standard...), all of the DBF
and CMD files had to be ported to the new system by cabling slave serial ports
together, and making the transfer with the MEX communications software. Two
sets of slaves were used, and the transfer was completed overnight. No serious
problems were encountered.
Our system now includes the following hardware: a CPZ-186 single-board central
processor (the master), manufactured by Intercontinental Micro System Corp.
(I.C.M.) with a megabyte of memory managed by an Intel 80186 8-MHz processor,
a floppy disk controller for up to 4 floppy drives, 2 serial ports, and 2
parallel I/O channels.
The parallel channels are connected thru a SCSI port to an ICM Omti Disk
Controller, which manages 2 Maxtor XT2085 85-megabyte hard disks and a half-
height TEAC streaming tape drive. There are 4 Advanced Digital Corporation
(AD) multi-slave boards, each board supporting 3 users, each user with 128-K
bank-switched RAM, an 8-MHz Z-80, and 2 serial ports, one used for the
console, and another available for a printer, modem, or other RS-232C device.
There is one ICM CPS-BMX board which is similar to the multi-slave, except
that it is a 6-MHz single-user board, utilizing direct memory addressing and,
in addition to the 2 serial ports, it has a parallel port which is connected
to a battery-powered real-time clock board. Each time the system boots up, it
goes out to this clock, and brings in the correct system time, even if the
power has been off. We never have to key in the correct time, except in Spring
and Fall, when the clock must be reset when Daylight Savings Time begins and
The final board plugged in our S-100 Bus is an ICM Q6A board, which is similar
to the multi-slave, except that there are 4 6-MHz Z-80 CPUs on it, supporting
4 users, each with 128-K of bank-switched RAM.
All the hardware is mounted in a single "box" about the size of an egg crate.
This is an Integrand 3015T chassis which includes a 15-slot bus, 4 cooling
fans, and the power supply. We have 2 8" double-sided, double-density floppy
drives, mounted in a separate cabinet.
TurboDOS formats 8" floppies to 1024-K. We use floppies only to back up the
day's work at day's end. The system boots directly from hard disk.
Surprisingly, the 6-MHz ICM CPS-BMX slave completes typical tasks that we run
on the system up to 30 percent faster than any of the AD 8-MHz slaves.
Technical people have tried to explain this to me, referring to the direct
memory addressing feature of the CPS-BMX, and mentioning that the
implementation of the AD multi-slave results in bus wait states.
The logical setup
I read an article in the "FOGHORN" expressing interest in systems with CP/M
compatibility and a multi-user capability.
S-100 Bus systems operating TurboDOS are the logical step.
The performance is excellent.
The price is reasonable -- we have approximately $26,000 in the equipment and
purchased software, including 14 consoles, an external 500 VA uninterruptible
power supply, 6 printers, 2 hard disks, the S-100 Bus boards, the chassis, 2
floppy drives, modem, external IBM PC, and cabling.
The system is flexible and expandable. We are using fewer than half the slots
in the chassis, and could easily double our number of users by purchasing
Beyond that, TurboDOS supports multiple box networks, up to 65,534 nodes. Each
master, slave, or LAN board occupies 1 node. Boxes with both 8-bit and 16-bit
slaves on the same bus are feasible, too.
The IBM PC is interfaced to the system for the singular purpose of importing
data files from 5-1/4" MS-DOS floppies, which our suppliers periodically
provide to maintain current parts/motor pricing information.
One slave on the S-100 Bus runs MEX to operate a serial port which is cabled
(with a "Null-Modem Cable") to the IBM PC serial port.
We run CROSSTALK XVI on the IBM PC, and are able to quickly import data files
off of the submitted floppies.
That same slave has its other serial port cabled to the RS-232C interface on
the uninterruptible power supply, which periodically reports technical
information such as load, accumulated operating hours, projected back-up time
remaining, operating temperature, number of previous outages, battery voltage,
AC volts in, and AC volts out. This slave has no console cabled to it. System
software enables any user, at any console, to ATTACH to its remote console
driver, and operate it, as if cabled to it.
All of the system users use it with enthusiasm, but are uninterested in
operating systems or applications programming, so all needed operations are
directly accessible from our dBASE II main menu.
All of our staff, including the non-keyboard oriented people, have been able
to assimilate at least enough know-how to do routine things on the system,
such as looking up parts pricing, or punching in/out on our payroll time
TurboDOS also provides DO file operations, which is similar to CP/M SUBMIT
Although dBASE II runs on TurboDOS without modification, if you wish to change
printers or auto-trigger despooling from within CMD files (on the fly), PEEK
and POKE routines are needed.
TurboDOS responds to virtually all C-function calls just as CP/M would, and
adds additional T-function calls for managing network activities, that are
easily implemented in POKE routines. All of the Z-80 slaves on our system use
128-K bank-switched memory. This means that your application program may
utilize almost all of 64-K memory, because the operating system is in the
Although TurboDOS supports file locking and record locking, these T-functions
are not automatically implemented by dBASE II, as they did not exist in the
CP/M world. (ROCHE> ??? They were available in MP/M-II... And network system
calls in CP/NET!)
Permissive multi-user file sharing is offered, which permits all users to read
in any file at any time, but, as soon as any user writes to a file by changing
or extending it, he has achieved an explicit lock.
Should any other user try writing to that file, before the first user has
closed it, the second user will crash to the dBASE dot prompt after receiving
the oblique error message "Disk is Full".
To avoid this problem, I write pseudo-file locking routines into any dBASE
program where conflicts can be anticipated.
The primary hard disk is partitioned into 2 logical drives: A and B. Drive B
has only one track assigned to it, for the sole purpose of maintaining a 64-
entry directory. All pseudo-file locks are then, actually, 0-K files on this
This makes wild-card file searches extremely fast, when an application checks
for a file lock. For example, if the file to be locked is PARTS.DBF, and user
F is the requester, the application will first check to see if there is a file
named B:PARTS.LK0 ?
If user A already has locked that file, there will be B:PARTS.LKA.
The small file locking procedure then identifies that the final character of
the name is A, and reports to the user trying to perfect his file lock that
terminal A has the file, and suggests a later attempt.
Any user is still permitted reading access for look-ups and reports; he just
cannot write to the file.
If user F's application found no files B:PARTS.LK?, then B:PARTS.LKF would be
immediately created, and User F would then proceed with his change.
If user F is posting a multiple transaction then, of course, the application
must achieve file locks on all of the files before starting any posting.
Care in implementing this scheme must be taken, to avoid the "Fatal Embrace",
about which much has already been written. Essentially, if 4 file locks are
needed, and the routine successfully locks the first 3, and finds it cannot
perfect the 4th, then it must display its error message, and immediately
release the first 3 which have already been created.
You may be wondering why I just did not write the PEEK/POKE routine necessary
to latch the TurboDOS T-functions needed to implement actual operating system
file and record locking.
Like CP/M, at the operating system level, TurboDOS uses File Control Blocks
(FCB) for any function that references a file.
Simply put, the ASCII file name is poked into memory first, and then that
memory address is loaded into a register, the function number (open file,
close file, make file, lock file, etc.) to be implemented is loaded into
another register, and then a call is issued.
dBASE, of course, does this every time with the USE "filespec" command.
However, I have found no way to predictably determine where, in memory, dBASE
will have the particular FCB in question. I was able to see the general area
in memory where all of the up to 16 FCBs are maintained by dBASE, but found no
way in an application program to quickly determine which of the 16 represents
the FCB that I need at that moment.
I would be pleased to hear from anyone out there, who has nailed this down.
The other multi-user work-around that a programmer must face for a system like
ours, copes with several users needing to generate, for example, a sale
invoice at the same time. All invoices are retained in a master (core) file
If there was only this one file then, obviously, only one user could be
creating (adding) an invoice at any time, and this limitation would severely
Therefore, we have sets of daily files for each possible user -- AINVOICE.DBF,
AJOB.DBF, ACHECKS.DBF for user A, -- BINVOICE.DBF, BJOB.DBF, BCHECKS.DBF for
user B, etc.
At the close of business, each day, the night program is run. Among the
responsibilities of this program is appending to the core files all the
records from the daily files, and then emptying the daily files.
It then dumps routine reports into the spooler, to be printed the following
day, such as the daily aged receivable and payable reports, the final sales
report from the previous day, and other daily transaction reports.
The second part of the night time procedure checks the date, and performs
additional reporting activity for end of month, end of quarter, and end of
year. The date is also tested during this part of the night procedure, to
determine if it is a week-end.
The second week-end of the month, housekeeping procedures (drop off the
records closed out in excess of specified time period, and then re-index as
appropriate) are run on the sales invoice and job tag files.
The third week-end of the month, receivable and payable housekeeping occurs.
On the fourth week-end of the month, core files such as the phone book and
parts database are packed and re-indexed.
These procedures sometimes take 12-18 hours and, if they were run during the
business day, performance would be degraded somewhat but, more importantly,
key files would not be available for needed look-ups.
Finally, the last part of the night time procedure copies all data files and
indexes from our primary hard disk to our backup hard disk.
With the second hard disk functioning as a dynamic back up in this way, should
we have a catastrophic failure on the primary hard disk, during the business
day, we could immediately begin functioning on the back up hard disk, having
lost only the transactions posted since 8 a.m. that morning, all of which can
be quickly re-entered from control hard-copies routinely accumulated in trays
on various desks.
We also maintain routine daily off-site backup by copying all the data and
index files off of the backup hard disk to tape, every morning. The employee
responsible for this process arrives at 6 a.m. and runs a streaming tape that
is completed in 3 hours. About 300 files, totaling 45 megabytes, are copied
onto the tape. The tape program is run on a slave, and does not require system
dedication, but does degrade responses to user requests for file accesses
about 10-20 percent while running.
Hard disk file organization is very similar to CP/M systems. Directory
libraries are organized into user areas 0 to 31. Maximum file size is 134
megabytes. Disk drives up to a gigabyte are supported without partitioning.
Drives, printers, and print queues are identified in each slave's operating
systems by assignment tables, each table up to 16 entries long.
For example, an individual slave could access 16 different logical drives, and
16 different network printers located anywhere on the network. All of our
system printers are on slave serial ports, operated remotely across the
network. We found that system performance was enhanced by not connecting
printers to the serial ports on the master, allowing the master to focus 100%
of its time functioning as a file server, and bus master.
WordStar 3.0 is used to write all the dBASE CMD files. We are not running any
TurboDOS comes with a well-organized manual (2-1/2" thick, usually presented
in a 3" ring binder) that is logically divided into 5 sections -- User's
Guide, Z-80 Programmer's Guide, Z-80 Implementer's Guide, 8086 Programmer's
Guide, and 8086 Implementer's Guide. The documentation is very complete.
I think Gene Davis, at Productive Data Systems, Inc., 303 North Indian Avenue,
Palm Springs, CA 92262, is the best source of supply and support for S-100 Bus
hardware and TurboDOS.
Here are names and addresses of the manufacturers of the S-100 Bus hardware
- Integrand Research Corp.
8620 Roosevelt Avenue
- Advanced Digital Corporation
5432 Production Drive
- Intercontinental Micro Systems Corp. (I.C.M.)
4020 Leaverton Court
- The TEAC streaming tape drive accepts cassette-style tapes, and works
fine, but I have no manual, and can supply no address for the
- TurboDOS is a registered trademark of Software 2000, Inc., dBASE II is
a registered trademark of Ashton-Tate. MEX is a trademark of NightOwl
Software, Inc. IBM PC and MS-DOS are registered trademarks of
International Business Machines. CP/M is a trademark of Digital
Research. CROSSTALK XVI is a trademark of Microstuff, Inc.
I hope that this overview of our S-100 Bus system running TurboDOS 1.43
excites some interest out there. I am really enthused because it offers us a
truly integrated business solution, at a reasonable cost, using many of the
system and programming techniques learned on an Osborne 1.
- "dBASE II Machine Language Interface for TurboDOS Printer/Queue changes"
"FOGHORN", Vol.VIII, No.3, December 1988, p.48
(Retyped by Emmanuel ROCHE.)
The following routines are essential for switching printers on the fly, and
signaling end of print (tripping the spooler) from within dBASE II ver. 2.43
running on a TurboDOS operating system ver. 1.43.
They are stored in high memory, assuming that the slave hardware provides 128K
bank-switched memory, and that dBASE has available almost all of 64K for its
I have shown the decimal derivation of each set of instructions just before
the actual POKE command. They would not be included in the program itself, but
are here to demonstrate the procedure that you would follow to write a POKE
sequence to accomplish any other special function, not otherwise directly
supported by dBASE. The POKE commands would be first implemented at the
beginning of the Main Menu program.
Signal end of print (Trip Spooler), TurboDOS T-function 28.
Called by any CMD file requiring spooler trip.
Mnemonics Hex Decimal Comments
--------- --- ------- --------
LD C,1C 0E,1C 14,28 T-func.28
JP 0050 C3,50,0 195,80,0 TDOS
SET CALL TO 62030
Change Queue/Printer Assignment, TurboDOS T-function 27 (62123 -> 62133).
Insert instructions at 62126 = METHOD, 62128 = QUEUE/PRINTER.
Called by PRINTER.CMD.
Mnemonics Hex Decimal Comments
--------- --- ------- --------
LD C,1B 0E,1B 14,27 T-func.27
LD E,method 1E,methodH 30,method Print mode:
LD D,prnt/q 16,prnt/qH 22,prnt/q 1=A, 2=B, ..., 16=P,
LD B,drive 6,driveH 6,drive 0=A, 1=B, ..., 15=P,
JP 0050 C3,50,0 195,80,0 TDOS
PRINTER.CMD is implemented by any other dBASE command file, when it determines
that a printer, other than the current printer, is needed. Data file area may
be primary or secondary, depending on considerations of the calling file. If a
file is open, it must be reopened and repointed as necessary -- those
responsibilities must be handled by the calling file. The calling file passes
its newly-selected printer in memvar NEWPR (i.e., NEWPR='1', the character is
the printer name). Ever present memory variable TERMR identifies all available
system printers as follows:
$(TERMR,1,1) Current printer
$(TERMR,2,1) Report printer
$(TERMR,3,1) Invoice printer
$(TERMR,4,1) Job tag printer
$(TERMR,5,1) Bookkeeping report printer
$(TERMR,6,1) Check printer
An example from REPORTMN.CMD (report printer will be needed):
STORE $(TERMR,2,1) TO NEWPR
DO PRINTER ENDIF $(TERMR,1,1)
TERMR is initialized at sign-on in the beginning of MENU.CMD from the PRTR
field of SYSPAR.DBF.
All files assume that all printers are spooled and available system wide,
except printer "4" is defined throughout this software as being LOCAL and NON-
All command files include a CALL to automatically Signal End of Print when a
report or form is complete, if the current designated printer is *NOT* "4".
To implement single-form printing (i.e., point of sale invoicing) effectively,
all procedures that route print output to a special form printer, such as an
invoice, job tag, or check, must assume that a form has just been torn off
and, therefore, the form is already lined up and ready to go (no Form-Feed
Output for a special form always ends with an eject.
All other printers (plain paper) assume eject required before print output
begins. Sounds simple, but there is a hitch. If you use dBASE's report command
to generate a printout, then have TurboDOS switch printers to a special form
printer, and then output printing @ 0,0, dBASE assumes a Form Feed is
required, and automatically issues an eject (Form Feed) command to the
printer. The following poke sequence sets printer 0, direct (TurboDOS traps
print output, and discards it), so that the eject command can be issued to re-
initialize dBASE, and avoid that extra eject upon any subsequent SET FORMAT TO
SET CALL TO 62123
SET PRINT ON
SET PRINT OFF
* Note: Our system assumes TurboDOS operation,
* allowing up to 16 printers/queues per processor.
* '1'=A '2'=B ... '0'=J 'A'=K ... 'F'=P
* (pseudo Hex). The @ sequence converts that
* convention to decimal for the poke sequence.
STORE @(NEWPR,'0ABCDEF') TO METHOD
STORE 10 TO NEWPRD
STORE 10+METHOD TO NEWPRD
STORE VAL(NEWPR) TO NEWPRD
STORE 1 TO METHOD
STORE 0 TO METHOD
LOCATE FOR NEWPR=WHPRINT
LOCATE FOR TERM=WHPRINT
IF EOF .OR. #=0
ACCEPT 'Can't identify printer. Get ;
System Manager.' TO DUMWAIT
STORE TRIM(HOW80) TO TERM80
STORE TRIM(HOW96) TO TERM96
STORE TRIM(HOW136) TO TERM136
STORE TRIM(HOWLONG) TO TERMLONG
STORE TRIM(HOWSTAN) TO TERMSTAN
* Reset the default call, for signaling end of print condition.
SET CALL TO 62030
* Make $(TERMR,1,1) equal to the current printer.
STORE NEWPR+$(TERMR,2,LEN(TERMR)-1) TO ;
* EOF PRINTER.CMD
PRINTER.DBF contains the CONTROL SEQUENCES for PITCH CHANGES, etc. for all
system-wide printers -- one record for each printer.
TERMPRNT.DBF contains the CONTROL SEQUENCES for the LOCAL PRINTERS, one record
for each dedicated printer (identified by memvar TERM).
Ever present memory variables, TERM80, TERM96, TERM136, TERMLONG, and TERMSTAN
permit dBASE II to change print pitches while outputting any form or report,
without executing any additional look-ups.
One other note about implementing machine language commands in the dBASE II
I had the idea that, at a Main Menu sign-on, I would initialize all of my
machine language routines in an area of memory not otherwise used by dBASE,
and then simply adjust the ad hoc call address during the various procedures
that would need these routines, without having to repoke the whole routine
each time it was needed.
My manual shows that, with the exception of the SORT command, dBASE never
invades memory above A400 (41984 decimal).
Although none of my dBASE program ever uses the SORT command, I found that the
area between 45000 and 46000 was intermittently overwritten. That's why these
procedures were put in the 62000 area.