TDOS3.WS4
---------

- "S-100 Computers & TurboDOS"
  Michael Winter
  "FOGHORN", Vol.VIII, No.3, December 1988, p.13

(Retyped by Emmanuel ROCHE.)


Introduction
------------

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
(ADC) multi-slave boards, each board supporting 3 users, each user with  128-K
bank-switched  RAM,  an 8-MHz Z-80 CPU, 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
ends.

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
additional boards.

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
clock.

TurboDOS  also  provides DO file operations, which is similar to  CP/M  SUBMIT
operations.

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
other bank.

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
directory.

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
called INVOICE.DBF.

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
inhibit productivity.

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
spreadsheet software.

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
described above:

      - Integrand Research Corp.
        8620 Roosevelt Avenue
        Visalia
        CA 93291

      - Advanced Digital Corporation
        5432 Production Drive
        Huntington Beach
        CA 92649

      - Intercontinental Micro Systems Corp. (I.C.M.)
        4020 Leaverton Court
        Anaheim
        CA 92807-1692

      - The TEAC streaming tape drive accepts cassette-style tapes, and  works
        fine,  but  I  have  no manual, and can  supply  no  address  for  the
        manufacturer.

      - 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"
  Michael Winter
  "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
own use.

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

Thus,

        POKE 62030,14,28,195,80,0
        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:
                                                        0=direct, 1=spooled,
                                                        2=console, -1=leave
                                                        unchanged.
LD      D,prnt/q        16,prnt/qH      22,prnt/q       1=A, 2=B, ..., 16=P,
                                                        Q0=leave unchanged,
                                                        P0=output discarded.
LD      B,drive         6,driveH        6,drive         0=A, 1=B, ..., 15=P,
                                                        -1=leave unchanged.
JP      0050            C3,50,0         195,80,0        TDOS

Thus,

        POKE 62123,14,27,30,0,22,0,6,255,195,80,0

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):

        IF $(TERMR,1,1)#$(TERMR,2,1)
           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-
SPOOLED.

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
wanted).

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
PRINT command.


* PRINTER.CMD

SET CALL TO 62123
POKE 62126,0,22,0
CALL
SET PRINT ON
EJECT
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.

IF VAL(NEWPR)=0
   STORE @(NEWPR,'0ABCDEF') TO METHOD
   IF METHOD=1
      STORE 10 TO NEWPRD
   ELSE
      STORE 10+METHOD TO NEWPRD
   ENDIF METHOD
ELSE
   STORE VAL(NEWPR) TO NEWPRD
ENDIF VAL(NEWPR)
IF NEWPRD#4
   STORE 1 TO METHOD
ELSE
   STORE 0 TO METHOD
ENDIF
POKE 62126,METHOD,22,NEWPRD
CALL
IF NEWPR#'4'
   USE PRINTER
   IF ##0
      LOCATE FOR NEWPR=WHPRINT
   ENDIF ##0
ELSE
   USE TERMPRNT
   IF ##0
      LOCATE FOR TERM=WHPRINT
   ENDIF ##0
ENDIF NEWPRD#4
IF EOF .OR. #=0
   ACCEPT 'Can't identify printer. Get ;
System Manager.' TO DUMWAIT
ELSE
   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
ENDIF EOF
USE

* 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 ;
TERMR
RELEASE METHOD,NEWPRD,NEWPR
RETURN

* 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
environment.

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.


EOF