and alphabetic key combinations.
For example, rather than >
to activate the printer mode, simply type .
In addition, type to load a disk file or to save the workspace to disk.
LDOS's KSM facility issues the original instruction in response to the abbreviated
commands, and hence there is no need to alter the original VisiCalc program (except to
apply the appropriate patches designed to allow VisiCalc to run under LDOS). For
special matrix operations, VisiCalc commands continue to work as before.
VC/KSM is created by typing BUILD VC/KSM, and typing the responses noted in listing 1.
Plenty of blank responses are provided for your personal key combinations. For example,
a frequently used file may be designated to load and save with the responses
/SLfilename/VC; and /SSfilename/VC;.
I have included a "Help" feature which is selected by pressing . This command
saves the current workspace in TEXT/VC and loads the Visicalc file HELP/VC (listing 2).
To return to the original workspace, type (to clear the screen) and (to
load TEXT/VC). HELP/VC is a sample of the mnemonic keyboard responses in VisiCalc
format. It can be entered with a text editor or by typing BUILD HELP/VC from the LDOS
Ready prompt. More inventive users may prefer a machine language "Help" routine that
utilizes the /X- command provided by the LDOS patch to Visicalc (see Earl Terwilliger's
Z-Command from the Jan 83 Quarterly).
Finally, I include a Job Control Language (JCL) program - EASY/JCL. The previous
Quarterly missed the JCL program to initialize the Easy LScript configuration, so I have
rewritten it to select LScript or Visicalc. Simply type DO EASY (program), where
program is LSCRIPT or VC.
In summary, EASY VISICALC continues the trend to standardized and more memorable
mnemonic commands. Frequent and occasional users will prefer the faster command input
and more easily remembered commands. This "ease-of-use" can keep a program up-to-date
and prevent its fall into disuse.
.Easy LScript and VisiCalc JCL Initialization Program
//IF LSCRIPT
FILTER *KI KSM LSCRIPT
LSCRIPT
//KEYIN Type <1> to initiate spelling checker =>
//1
PROOFRDR
//STOP
///
//EXIT
//ELSE
//SET NOTLSCRIPT
//END
//IF VC&NOTLSCRIPT
FILTER *KI KSM VC
VC
//STOP
//ELSE
//SET NOTVC
//END
//IF NOTLSCRIPT&NOTVC
.Syntax error - proper form is => DO EASY (program)
where program is "LSCRIPT" or "VC"
//EXIT
//END
Page 24
VC/KSM Filter Data
A=> G=> /SLTEXT; M=> /M R=> /R X=> /X
B=> /B; H=> /SSTEXT;/SLHELP; S=> /SS Y=>
C=> /C I=> /I N=> T=> >Al; Z=>
D=> /D J=> O=> U=>
E=> /SQ K=> P=> /PP V=>
F=> /F L=> /SL Q=> W=>
Text for HELP/VC
>D8:"xt!
>C8:"eturn to tex
>B8:"CLR-G> to r
>A8:" & <
>D6:"X Command
>C6:"Replicate
>B6:"Load
>A6:"Format
>D5:"W
>C5:"Q
>B5:"K
>A5:"Exit
>D4:"V
>C4:"Print
>B4:"J
>A4:"Delete
>D3:"U
>C3:"O
>B3:"Insert
>A3:"Clear
>E2:"Z
>D2:"Top
>C2:"N
>B2:"Help
>A2:"Blank
>E1:"Y
>D1:"Save
>C1:"Move
>B1:"Get Text
>A1:"A
/W1
/GOC
/GRA
/GC11
/X>Al:>A9:
Review of Profile III+ for the LDOS Operating System
by Sam Goldberg
Laurelwood Products, Inc.
12520D Quicksilver Drive
Rancho Cordova, Ca. 95670
(916) 351-0607
CompuServe # 72265,416
Profile III+ Data Management Package was written by The small Computer Company. This
package is sold through Radio Shack Stores as the "hard disk version" or by ordering it
directly from them at 230 West 41st Street, Suite 1200, New York, NY 10036, (212) 398-
9290.
Page 25
Profile III+ is a Data Base Management program designed for the Radio Shack Model III
Micro-Computer. This package allows the user to define the initial structures, formats,
and will permit a wide range of manipulations to the data base.
Profile III+ has several powerful features that I will discuss in more detail later on,
but here are some highlights...
- Permits quick access to individual records or groups of related records
- 36 User Defined Search Fields
- Five User Defined Screen Formats
- Five User Defined Report Formats
- Five User Defined Label Formats
- Special Index Feature for High-Speed locating of a specific record or series of
records.
- Custom User Menus for Internal Profile Use or Overall System Applications
- Math Package allows Addition, Multiplication, Subtraction, and Division of data
within fields.
- Associated Fields can be 'Clustered' into search groups
- Password protection available for each screen, report, or label format
- Mass-Mode for Recalculation, Hardcopy, Deletion, and Purge features for specified
records
- Separate diskette to allow access for selected employees to creation functions of
Profile III+
- Can be used to pass information to Model III SuperScripsit for Form Letters
- Can pass information to Model III Visicalc for extended mathematical functions
The minimum equipment required for this package is a Model III Computer with 48k memory
and One disk drive. The manual states that a two drive Model III is required, but I
found that the program can be run with just a single disk drive or on the 5Meg Hard Disk
Unit. You will also need a printer with printer cable to produce Hardcopy of records.
You receive this program on two 5 1/4" diskettes. The first diskette is the Creation
Disk and the other is the Runtime Diskette.
Creation Diskette
This disk contains all the necessary programs to create your database system. This
includes the modules to define the fields, screens, reports, labels, mathematical
formulas, and selection formats.
In defining your file, you are prompted to name the file to contain your records. This
is an up-to-eight character name that identifies your file. You are then able to define
your fields. These fields are placed into one of four available segments. Each of
these four segments can hold a record length of from 1 to 255 characters, with these
characters being defined into field lengths with appropriate headings and field numbers.
In the first segment you can define related fields as being in the same logical group.
These fields are treated as a single field for searching, sorting, and selecting
records. I find this to be a very powerful feature.
You are also able to review and edit any segment in your fields, and can reserve
characters previously unused for future additions (this feature is a life saver when you
found out you forgot a heading ...)
Now you can define your screens (Yes, I said screens). Profile III+ allows up to five
screens for your files. You can even switch instantly between them while updating
or searching later on.
Page 26
Another nice feature of the screen formatting is the availability to use the Model III's
Special Character Set on the screen. However, these special characters are only for
screen displays, as the printer translates them into periods during any printing from
the screen (oh well, there goes the pointing finger...).
Field indicators define the type of entry you can make to each field. There are the
standard indicators for alphabetic and numeric characters as well as several special
feature indicators such as Must-Fill Alphabetic, Numeric, Decimal, and two forms of
Must-Fill Date fields, Protected fields to show information but not allow updating, add-
to and subtract-from fields, and three special date fields. These allow for limited
errors in the entry of information into your fields, and can format the information into
your records.
The Report section is an extremely flexible in its formation. For each of the five
report formats that are available, you can assign titles for the headings as well as
automatic page numbering, 'Date Printed', and Sort Field Information.
You have two lines for titles and the above information, two heading lines to head the
information to follow below, and two lines to present the information from your records.
These reports can be up to 132 characters in width, and will, if requested, space
between each line of the report. In printing the reports, the program will
automatically prompt you for a 'control break field' to divide your report if wanted.
If you are using information you want totaled, Profile III+ will give a grand total at
the bottom of-the report.
Creating Labels is just like creating a mini-report. All the features are available,
and you have up to eight lines in each of your five label formats. One special feature
I like is the "Move-Over" indicator. This will move the information to the left of
another field and line it up only one space away, this looks great when first and last
names are next to each other and not spaces away. I use a label format for one of my
Customer Reports, as eleven six line labels fit on a standard page with room in between.
I've found this format a dream when the record has more characters than will fit onto
two 132 character lines in a report format.
Another special feature is the Selection Formats to pass information from your records
to SuperScripsit and Visicalc. You can choose information to pass to these other
programs and put it into any sorted order you want. Form Letters are now a snap as you
can send a 'custom' looking letter to any or all of your clients. As a mailing list
package, Profile III+ functions very well. For performing complicated mathematical
functions, the power of Visicalc can be utilized just by sending the base information to
it in the form of a label or number. A simple analysis of your information can
sometimes show a hidden trend in costs, sales, or orders.
The math package that is included in Profile III+ can solve up to 16 formulas, each
using up to 20 fields! Addition, subtraction, multiplication, and division are
supported, and your answers can be automatically placed into the correct field. You can
also assign 'real' numbers, such as fixed percentages, to be used in your formulas, as
well as formatting the answer to integer or floating decimal place style. I found that
you can place a calculation into a dummy field number to allow more complex
calculations, and then move it back into the real field later.
Having the Runtime programs separate from the Creation programs will keep anyone from
changing passwords or gaining access to your sensitive information. The program will
note the password in upper and lower-case letters and WILL NOT substitute one for
another! The only way to bypass a password is to use the Creation Diskette to re-define
the format with a new password or none.
Killing a Data Base is easily done from either menu by pressing the 'K' key. This is
not a listed option on the menu as being a choice (good!) and will prompt you for the
file name of the file you wish to delete. Once you press the enter key after you
specify the file name, all portions of the file will be deleted! There is,
Page 27
unfortunately, no second prompt for verification of deletion, so you must be careful
that you really want to delete the file.
The manual for Profile III+ is very complete in presenting a lengthy sample use of the
package, with several examples and explanations. However, some of the more esoteric
functions, such as the extended selection mode are not explained to their fullest, and
the user must experiment to really understand the power of this feature. There are
several pages of instructions for backup and format of blank disks for use with program,
as well as hints and tips for usage.
This program is not a 'protected' package and allows for the user to make as many
backups as they feel comfortable with. It comes in a nice binder with the instructions
printed on good quality stock for long life.
I thoroughly recommend the package for anyone who has anything to keep in order. In our
company, we are using Profile III+ to track all of our business from the time we make
the bid, through receiving the order, manufacturing the products, through delivery, and
to track final billing. A complete business package designed around a single data base
management package - a clean, concise, and accurate solution. In combination with
SuperScripsit and Visicalc, these three packages make a powerful set of programs that
every business could use to promote computer use, save time, money, and put the time
back your day for coffee breaks.
I think I'll have a donut with this cup.......
Color Comes to the TRS-80's
by Scott A. Loomer
reviewed: CHROMAtrs Color Graphics System
$168 kit, $208 assembled and tested
Have you ever found yourself trying to convince a Apple owner that having a
sophisticated disk operating system was more important to you than color graphics? How
would you like to tell the next one you meet that you have the best microcomputer DOS
AND color graphics? If you feel inclined to turn the screw farther, you can also
explain that your color graphics are superior to an Apple's. Interested? Read on ....
At least two companies are now advertising color graphics add-on systems for the Model I
and III. This article will review the graphics capabilities, hardware and software of
the first of these companies to get its product on the market, specifically the
CHROMAtrs system from South Shore Computer Concepts, Inc., Hewlett, New York. The
second company that has recently started advertising a color board is Micromint, Inc.,
Cedarhurst, New York. My remarks that deal with the graphics capabilities would apply
to both systems since they employ the same color graphics processor (CGP), the Texas
Instruments 9918A. If you are interested in more background information, I suggest that
you read the article on sprite graphics in the August 1982 Byte magazine.
Graphics Capabilities
Enough of the background; what are we talking about here? The graphics capabilities are
provided and managed by the TI CGP chip. Sixteen colors are available (counting
transparent, black, white and 13 others) which also provide eight discrete luminance
values (gray levels) if viewed on a black and white TV. The graphics capabilities of
this system can be thought of as consisting of three layers: the background, the pattern
plane and the sprites. The background forms a top and bottom border to the actual
graphics area (the screen is clipped top and bottom to make it more orthogonal). The
background can be set to any color which will also show through any portions of the
pattern or sprite planes that are transparent. The pattern plane is visually in front
of the background plane and is where high resolution graphics images can be created.
Page 28
The resolution of this plane is 256 picture elements (pixels) horizontally by 192 pixels
vertically. This resolution is the same as the Apple's; the TI CGP, however, has fewer
restrictions on the placement of colors. All colors are available anywhere on the
screen with the restriction that in eight contiguous pixels horizontally (a sliver)
there can only be two different colors. In practice, this does not greatly hamper your
artistry.
The nearest visual plane is where the power of the TI chip really becomes apparent. The
system supports up to 32 prioritized sprites. A sprite is a pattern (either 8 x 8
pixels or 16 x 16 pixels) that can be defined and moved as a single entity anywhere on
the screen. The sprites will appear in front of the pattern plane and will block out
the pattern plane image except in areas of the sprite that have been left transparent.
Animation of games becomes extremely easy. Merely define the shape of your hyper-
megalon infinite-probability space ship and you can move the entire ship by passing one
address to the CGP. When the image of the ship is moved, there is no effort necessary
to restore the pattern plane image where it had been covered by the ship as the CGP
maintains the image continuously. The sprites are prioritized which means that a sprite
of higher priority will superimpose a lower priority sprite. There are some limitations
to all this magic. Each sprite can only have a foreground and background (usually
transparent) color. Since only one address is necessary to move a sprite, two or more
different colored sprites can be combined to form an object and they can be moved
apparently simultaneously even from a BASIC program. Sprites can also be moved off of
the edges of the screen and will disappear line by line.
The graphics capabilities described above represent the highest resolution of the TI CGP
and is termed Graphics Mode II. There are three other modes of operation available,
Graphics Mode I (a more restricted version of Graphics Mode II), Multicolor Mode (low
resolution, 64 x 48 pixels) and a text Mode (24 lines of 40 characters). The other
graphics modes use less of the CGP's RAM and can consequently be loaded into the RAM
somewhat faster than Graphics Mode II.
Hardware Description
The CHROMAtrs system from South Shore consists of a peripheral that attaches to a Mod I
or III with ribbon cable to the system bus connector. The CHROMAtrs is powered by its
own power supply. The video output from the CHROMAtrs is available as a composite video
signal (for use with a monitor) or a radio frequency signal (with the optional RF
modulator) for use with a color TV.
The system also contains the 16K RAM used by the CGP to build and store the graphics
image(s) . The unit is port mapped to ports 78H to 7FH, but can be changed via jumpers
if this conflicts with other peripherals. The South Shore unit consists of a circuit
board approximately 9 inches square. The board is high quality with components nicely
spaced, silk screened and solder masked. The board has both 40 and 50 pin edge
connectors so that the same unit can be used with either a Model I or III (and
presumably a MAX-80 via the 40 pin connector). South Shore has added two nice
embellishments to the graphics capabilities of the TI CGP -- sound and joysticks. The
sound capabilities are rudimentary, but a wide range of tones can be created that are
brought out on the board to an RCA connector or can be heard on the audio of the
attached TV set. The joystick capability supports two Atari style joysticks or four
game paddles. The joystick data is read by doing an input from a port.
Construction of the kit form of the CHROMAtrs will not be difficult for anyone who has
built projects with integrated circuits. I must confess to have had an atypical
experience as I built the CHROMAtrs from the bare circuit board and not the kit. I did
this only because I already had purchased the TI 9918 chip in anticipation of building a
graphics unit from scratch. I DON'T recommend buying the bare board. South Shore's kit
price is very reasonable and I doubt if you could save money by buying the components
yourself; I didn't if you exclude the previously purchased TI 9918.
My construction of the unit probably represents an acid test of the instructions since I
didn't have their parts assortment. There is an addenda sheet which should be posted
Page 29
to the instructions prior to starting. There was only one inconsistency that I found;
one value of resistor was missing from the parts list and necessitated another trip to
buy them when I got to the installation step. I would make one suggestion for kit
builders: socket all of the IC's. South Shore provides sockets for the high cost chips
(TI 9918, RAM) but not the others. It may not seem to make sense to spend 30 cents to
socket a 35 cent IC, but it will the first time you have to remove it (for whatever
reason). Socketing will also ensure that you don't damage an IC by overheating. It's
well worth the extra buck or two.
The caveat on kit building is, of course, that the darn thing may not work when you turn
it on. The troubleshooting instructions are minimal so it helps to:
1) have a lot of test equipment and the knowledge on how to use it or
2) have a good friend (Phil Docken in this case) who satisfies item 1.
I di d have some problems that Phil helped me fix, but all but one are attributable from
building the unit from the bare board and should not occur with the kit. The one
problem that you might encounter is that the unit as designed may be fussy about the TV
set that you use (symptom: black and white image, but no color). Phil talked with TI
about the problem and has designed a small circuit with trimming capacitor that replaces
one of the IC's and licked this problem for me. This is Phil's replacement circuit:
C1
8 7 8 ------|------)|-------|
9 6 | |
10 U 5 crystal |
11 2 4 | C2 |
12 1 3 9 ------|------)/|------|
13 2 | |
14 1 |------)|-------|
notch C3 |
7
Parts List
Cl & C3 - 47 pf capacitors, Radio Shack #272-121
C2 - 5-60 pf trimmer capacitor, Radio Shack #272-1340
Instructions
1. Remove IC U21.
2. Build the replacement circuit on a small scrap of perfboard.
3. Attach jumpers from the connections marked 7-9 to the respective holes in the socket
for IC U21.
4. With the CHROMAtrs on, adjust trimmer capacitor C2 for the best color.
Software
Software frequently determines the value of any peripheral. Well, as they say, I have
some good news and some bad news. First some good news. South Shore provides a machine
language driver that provides set, reset, test, line drawing, sprite definition,
joystick and sound routines. The best part of this is that they supply the assembler
source code for their driver as well.
Now the bad news. The driver is what I've come to think of as T**DOS standard. It is
non-relocatable and uses the top 18k of memory! Give South Shore 10 brownie points for
protecting the driver by setting HIGH$, but take away 20 points because they set both
the Model I and III HIGH$ locations! When I called South Shore about this they were
surprised to learn that this is not a good procedure. They said it hadn't caused them
any problems under whatever DOS they had been using (I find that unlikely, as stuffing
random data into any area of the resident DOS has got to mess something up). I
convinced them that they should change it. The LDOS symptom was an inability to save
programs from BASIC.
Page 30
As stated, the other major problem with the driver is the loss of 18k of memory. It
turns out that the driver code itself occupies less than 2k, but the top 16k of memory
is reserved as a buffer for moving images into the video RAM. South Shore moves images
(3 samples provided with the CHROMAtrs) into the video RAM by using the DOS LOAD command
to place the 16k image (saved as a load module) into the top 16k of memory. A PUT
command (supplied by South Shore) then merely moves the image into the external video
RAM. This negates the entire advantage in the CGP having its own dedicated RAM. The
balance of the software provided by South Shore consists of a BASIC program that has a
line drawing demo (the line function of the driver is fast) and a lunar lander game.
The game is primarily interesting as a demonstration of how sprites ease the programming
burden so much that you can write a real-time game in BASIC. My last comment about the
supplied software is to note that South Shore states that they will evaluate software
that supports their board and offer it on a commission basis to their users via a
newsletter.
Now let's look at what can and has been done to improve the state of the graphics
software. Writing (or rewriting) a peripheral driver definitely makes one appreciate
the myriad features of LDOS.
My first effort was to eliminate the image buffer. A new DISPLAY program was written
that reads an image in as 256 byte blocks and transfers it a block at a time. This
program takes about 4 seconds to access the 16k file on disk and output it to the
CHROMAtrs. Parameters were also provided to set screen background color and to control
the blanking of an image during the loading. New sprite tables could be loaded in
without disturbing the displayed image for instance. The Z-80 OTIR command (block
output) works perfectly as it is just slightly slower than the TI CGP data capture rate.
Of course, that's at a Z-80 clock rate of 2 MHz. A delay loop would be required on a
MAX-80 or any system using a faster clock. A program called FETCH was written to
accomplish the opposite function, to grab an image out of the video RAM and save it to
disk.
The second step was to make the driver relocatable. Would you believe 140+ relocated
addresses? The article by Chuck Jensen on relocating code in the January 1982 LDOS
Quarterly was a boon here. It ought to be noted here that there isn't a single relative
jump in the entire South Shore driver (it turns out that all but two can be relative,
however). The driver advises LBASIC of its entry points by passing a base address via
the USTOR$ location provided by LDOS.
The third step was to make the driver initialization SYSGENable as was described by Roy
Soltoff in the October 1982 LDOS Quarterly. I've since decided to rewrite the entire
driver to include other functions (circles, filling areas, etc.).
There are many other exciting possibilities of this piece of hardware that I've not yet
had time to pursue. The video RAM might have other non-graphic potentials. For
example, how about a new version of the LDOS SPOOL command that uses the 16k of video
RAM as its buffer? This would be nearly equivalent to buying one of the dedicated
printed spoolers that typically cost about $159 for a 16k buffer. This way you would
get color graphics for "free". A MEMDISK type program could also be developed that
would have little impact on your main system RAM but would provide a transfer rate equal
to a floppy.
If any of you now succumb to the urge to buy a CHROMAtrs and are interested in
cooperating on the development of supporting software, please drop me a line. I think
that the LDOS community is likely to take this peripheral far beyond the expectations of
its designers.
Final Impressions
I don't want to leave you with the impression that the South Shore software is no good.
With the exception of the HIGH$ problem, the software works as advertised. It just
doesn't meet the standards that we've come to expect under LDOS. The capabilities that
color graphics add to your system are tremendous. The dedicated TI CGP makes image
creation and manipulation quite simple and fast; for example, it is possible to do some
Page 31
very credible programming using LBASIC because of this speed. The South Shore unit is
well designed and reasonably priced (though you have to add some components up to get
the total costs):
Item Kit Built-Up
CHROMAtrs $99 $169
Case $18 included
Bus cable $14/15 $14/15 (Mod I/III)
RF Modulator $25 $25
Power Supply $12 included
Total $168 $208
All in all, the CHROMAtrs is an inexpensive peripheral that will add color to your
life.
If you have any questions or comments about this article, please address them to:
Scott A. Loomer
315 Palomino Lane
Madison, WI 53705
608-233-7739 or MNet [70075,0933]
Since the preceding article was written in February, a few items need updating. First,
the driver software now provided by South Shore Computer Concepts has the HIGH$ problem
fixed. The new software comes with a BASIC program called MLOGO which is a creditable
interpreter of a subset of the LOGO language. All of those fancy pinwheel designs that
you've seen can now be yours. South Shore is also advertising a color graphics BASIC
(appends to the DOS BASIC) for $30. I haven't had a chance to try this out yet, but it
is supposed to be compatible with LDOS.
An additional piece of advice if you decide to purchase the ChromaTRS board is to order
the Texas Instruments manual for the 9918A ($5) from South Shore at the same time. This
recently printed manual gives precise details about what the chip can do and will allow
you to utilize the unit to its capacity.
As a note to the MAXers in the crowd, the ChromaTRS board does work with the Lobo MAX-
80. Two things must be corrected, however. First, the ground on the MAX-80 expansion
BUS is only brought out on one line. You must jumper it to the two other ground lines
on the ChromaTRS board. Second, the MAX is TOO FAST. The driver software must have
delay loops added to slow the data transfer rate down to the 2 MHz that the color board
can handle. I will provide the details on both fixes if you send me a SASE.
Last, I was chastised about my article on Alcor Pascal for not providing the company's
address (and by trans-Atlantic call yet!) so here it is: South Shore Computer Concepts,
1590 Broadway, Hewlett, NY 11557 (516-569-4390).
.......... er..........
by Earle Robinson
300 Grenola
Pacific Palisades, CA 90272
So many peop1e called in to LSI for the name of the pub1isher of the Plum book on 'C'
programming which I mentioned in my last article, that I am putting it here for whomever
may require it.
Learning to program in C
Plum Hall,
1 Spruce Avenue
Cardiff, NJ 08232.
Telephone:(609)927-3770
Page 32
[Powersoft ad]
Page 33
Please excuse the plug, but I should like to announce that I can now provide
SuperScripsit printer drivers for the Comrex, Diablo 630, Gemini 10, Gemini 15 & others
will be added to the regular line, which includes the MX80/100, Prowriter, Nec l023a, C.
Itoh Fl0, Qume, Brother. All drivers will run on the Model I, III, and the MAX80.
(Editor's note: We have been getting some of these inquiries. Please contact Earle
Robinson directly.)
The Model 4 has finally made its appearance, and in spite of the excellent operating
system written by you know whom (LSI), I was very disappointed in it. First of all, in
spite of the market's eager acceptance of more ergonometrically designed microcomputers,
especially due to the detachable keyboard, as shown in the IBM PC, the Tandy Model 12
among others, the new Radio Shack's offering is one big box. It is painted 'computer
room' white, but is the same clumsy looking machine that the Model III was. The Model 4
looks like a 1980 computer, not a 1983 one!
Secondly, Tandy has introduced the machine over a month before I began writing this
article, but there is still no technical manual available! Since a large number of
early purchasers of a new computer model are software houses, OEM companies, and others
wishing to develop programs or systems, how can they effectively do anything without
technical specifications, listings and the like? IBM issued their very complete
Technical Reference Manual, containing not only references, but a complete listing of
the BIOS, at the same time as the PC. Since the Model 4 has no software yet, except the
new version of Microsoft Basic, to run in the 6.0 mode (other than Misosys' excellent
utilities), how can Tandy expect to maintain its already shrunken market share?
Finally, it seems to me that the price of the Model 4 is on the high side in the present
market environment. It is possible to get much more for the money with say the Kaypro
II which costs over $300 less and is bundled with an excellent package of word
processing, dictionary, spread sheet, and two Basics. And, the Max80, with a couple of
drives and a video monitor should cost somewhat less, too. Further, it is already
possible to run 80 columns on the Max under 5.1.x. In the Compuserve data base of the
LDOS board there is a driver which enables 80 columns. It works very nicely running
EDAS, Lmodem80, and even in Basic!
In an earlier article I bad-mouthed the Brother HR-1 because it was incapable of doing
anything else than print plain vanilla copy: no underlining, no bold, no superscript nor
subscript. Well, the Brother people have quietly replaced the original chip in the
printer so that it now does all those wonderful things. This means that if you are
attracted by this printer, you won't have to pay an extra $100 to get the Comrex, which
until now was the only way to have a Brother which would provide the underlining, etc.
For those of you who have an older version, I suggest you talk with your dealer about
getting the new chip installed.
Among the new products I have recently been able to try, I particularly liked two of the
programs on the LSI Utility disk #2. The first one is based on an old enhancement I did
for early versions of LDOS which permits re-defining keystrokes from within a KSM file.
For example, let us say that I am working on a program called 'Myfile'. By redefining a
key from within Basic or EDAS to output that name each time as required, I save time,
and avoid errors of misspelling which can occur. This program is called Ksmplus on the
disk. The other program is a very elegant filter for input or output to translate a
user defined key into a group of characters, up to 255 in length. This is a sort of
expanded KSM type filter which will permit translation of output of whatever you want
from the keyboard, a communications port, or any other device. Similarly, it can be
used for input translation into whatever you wish, to the video display, a printer, or
whatever device you wish. This program is called Maxlate. The concept is beautiful,
and its implementation ideally done.
I am enclosing a little program to change your prompt device from the 'LDOS Ready' which
we know so well. So, if you prefer a '%' or a '$' 1ike under Unix, or whatever, all you
have to do is type the command as you desire it. Use a '=' as the first
Page 34
character if you wish to suppress the 1ine feed which normally precedes the 'LDOS Ready'
prompt. And, if you wish to suppress the carriage return which normally follows the
prompt, use the '=' as the last character. So, if you wish to have a '%' without
linefeed and without a carriage return you would type 'Prompt =% =' then hit .
That will give you the prompt without a line feed and without a carriage return. Or,
you could type 'Function: ', if you wish that as your command and wish to have both the
linefeed and a carriage return. To get back the 'LDOS Ready' merely type 'Prompt'. For
those of you who may not wish to type the hex fi1e below and then convert it, you may
send me $10 and I'll send PR0MPT to you, together with primitive instructions. I hope
that I don't need to remind you that you should NOT use this program with the SYS1 file
on your Master diskette!
Until next quarter, when I hope to talk a little about UNIX, and what it may mean to all
of us. Perhaps, I shall have had the opportunity to meet some of you at the LSI open
house before you read this issue of the Quarterly.
05 06 50 52 4F 4D 50 54 01 02 00 52 22 68 53 11 99 53 21 D0 54 06 00 CD 24 44 C2 A2 52 01
03 00 CD 42 44 CD 36 44 CC 4D 53 11 6A 53 21 D0 53 06 00 CD 24 44 20 72 01 04 00 CD 42 44
CD 36 44 20 6D D5 16 0C 3A 67 53 B7 C2 53 53 06 FF 7E FE 4C 23 28 04 10 F8 18 63 7E 05 FE
44 23 20 EF 2B 2B 2B ED 4B 68 53 0A E5 03 FE 3D 28 03 23 0B 15 0A FE 3D 28 0C 77 23 03 FE
0D 28 08 15 28 42 18 EF 3E 03 77 E1 D1 01 04 00 CD 42 44 CD 3C 44 CD 28 44 20 21 11 99 53
22 D0 54 01 03 00 CD 42 44 CD 3C 44 CD 28 44 C3 2D 40 21 BA 52 C3 09 44 21 DA 52 C3 09 44
21 F1 52 C3 09 44 21 08 53 C3 09 44 21 21 53 C3 09 44 54 68 65 72 65 20 69 73 20 6E 6F 20
73 79 73 31 20 6F 6E 20 79 6F 75 72 20 73 79 73 74 65 6D 0D 52 65 61 64 20 65 72 72 6F 72
2E 20 20 41 62 6F 72 74 69 6E 67 21 0D 57 72 69 74 65 20 65 72 72 6F 72 2E 20 41 62 01 02
00 53 6F 72 74 69 6E 67 21 0D 54 68 65 72 65 20 69 73 20 6E 6F 20 6E 65 77 20 6D 65 73 73
61 67 65 21 0D 54 68 65 72 65 20 61 72 65 20 6F 76 65 72 20 31 30 20 63 68 61 72 61 63 74
65 72 73 20 69 6E 20 74 68 65 20 6D 65 73 73 61 67 65 0D 3E FF 32 67 53 C9 2A D0 54 ED 4B
68 53 E5 0A FE 0D C2 5B 52 01 C4 53 C3 63 52 00 00 00 53 59 53 31 2F 53 59 53 2E 45 5A 54
4F 3A 30 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 50 52 4F 4D 50 54 2F 43 4D 44 03 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0A 4C 44 4F 53 20 52 65 61 64 79 0D
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 D3 00 54 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 02 00 52
***** PARITY = ODD *****
(c) 1983 Tim Daneliuk, T&R Communications Associates
4927 N. Rockwell St., Chicago, IL 60625
This installment of PARITY = ODD marks one full year since I've been writing regularly
for the LDOS Quarterly. Since a good deal of my computer related work involves not only
program development, but technical writing ABOUT the industry, I decided to dedicate
this issue to a review of computer magazines!
A recent editorial in 80-U.S. Journal exhorted the readers to treat their magazines as
"peripherals". The writer had a point. A well conceived and produced magazine can
serve as a great teacher, and save you a lot of grief. On the other hand, magazine
subscriptions have been steadily increasing in cost. If you're like most microcomputer
users, you can ill afford to waste 20 or 30 bucks on something which doesn't meet your
needs.
I decided to evaluate the four magazines which are most likely to come to your attention
as a TRS-80 owner. Two are industry-wide journals, and two are specific to
Page 35
the TRS-80. In each case, I looked at three major areas in the evaluation: 1) Technical
Depth / Readability, 2) Timeliness of the magazine's contents, and 3) Quality of the
product reviews. The first point needs a little explanation. Merely because a magazine
has only tutorial material or deeply technical material doesn't necessarily make it bad.
There is a place in the magazine market for journals which are directed only to a very
narrow group of users. The real question is whether that magazine presents material
appropriate to their intended audience in a readable form.
I've also included the latest advertising rates for these magazines that I could find.
A magazine derives the lion's share of its income from advertising, not subscriptions.
In turn, these rates affect the cost of computer products we buy. I have quoted only
the "one time" rate for an ad, which is the most expensive rate there is. Keep in mind
that the more often a given ad is scheduled to appear, the lower the rate per
publication becomes. Finally, for those of you with an inclination to write, I've
included what payment for a typical article might be. This figure is based on my own
experience in working with these magazines.
BYTE
BYTE has been around longer than virtually every other microcomputer magazine. It
started out with a heavy emphasis on hardware "hacking", and some of this Emphasis still
remains. With the advent of "appliance" computers such as the TRS-80, Apple, and Pet,
BYTE's articles and reviews have changed to encompass these machines. Of all the
popular computing magazines, this one has the most technically thorough articles. If
you enjoy reading material dealing with abstract areas of computer design such as
searching and sorting algorithms, benchmark design, and interface standards, BYTE is for
you. The one objection I do have to these articles is that they tend to be very machine
specific. I would rather see a generalized article on writing efficient sorting
algorithms than a program listing of such a sort which only runs on a DEC 350, or a TRS-
80, or whatever. Articles which rely heavily on demonstrating a concept only by
programming example usually don't explain the concept itself very well. In general,
BYTE articles are not for the rank beginner. They assume some computer experience on
the reader's part. Apart from that, the writing is quite readable, and well edited.
In the area of timeliness BYTE falls flat on its face! I personally have had articles
submitted which took almost a year to get into print. I've also seen reviews published
in BYTE when the product in question was no longer being manufactured (i.e. the BASE 2
printer). The so-called "news" sections of this magazine are usually a minimum of 3-4
months behind what the industry is actually doing. In fact, I have NEVER read a news
item in BYTE's pages which had not already appeared in several other industry journals.
BYTE product reviews are probably the most comprehensive published. This does not
necessarily mean that they are good, they're just long! Time after time, I've seen
software reviews which contain a detailed description of every command in the product,
the command syntax, and a complete explanation of the product's installation procedure!
This is decidedly NOT what a review is supposed to be. These details are what the
instruction manual is for. A review should tell you what a product is supposed to do,
how well it does that task, the quality of the documentation, and whether value is being
delivered for the money. In my experience, reviews which go into endless detail usually
miss the point of a particular product completely.
In all fairness to BYTE, good reviews are hard to come by. For example, someone
reviewing a new 16 bit personal computer really should have experience with at least one
other similar machine so a basis for comparison exists. This is not usually the case,
so the review suffers somewhat. The only other choice the magazine editors have is to
get review samples of various machines and do the evaluation themselves. One thing that
BYTE could do to alleviate this problem would be to establish a set of uniform review
guidelines which all reviewers would have to follow. The one area in which BYTE reviews
DO excel is that of comparative reviews. Many magazines will not do a side-by-side
comparison of several similar products, perhaps in fear of losing advertisers. BYTE,
however, has no qualms about this, and several excellent comparisons of products have
been run in its pages in the past few years.
Page 36
BYTE Summary
============
TECHNICAL DEPTH: INTERMEDIATE TO ADVANCED
TIMELINESS: EXTREMELY POOR
REVIEW QUALITY: GOOD (But could be much better)
Full page ad, 1 time: $5950 (Oct. '82 Rate Card)
Typical Payment To Author: $50 per published typeset page
INFOWORLD
INFOWORLD is a relative newcomer to the world of computing magazines, but it already has
a prestigious reputation. This magazine is published every two weeks and makes no
attempt to be a "how to" magazine. You won't find articles on programming technique,
interface design, or the like here. Instead INFOWORLD concentrates on the news of the
industry. When new products are announced, you'll hear about them almost immediately in
INFOWORLD. There are also several columns which deal with trends in the industry as a
whole, as well as stories about people in the industry. The writing style is light and
eminently readable.
INFOWORLD seems to appeal primarily to people who USE their computers a lot, like
lawyers, accountants, and so on. It keeps them in touch with the latest products and
trends in the microcomputer industry. By its very nature INFOWORLD is an extremely
timely magazine. News items are right up to date, and you will often see things in
INFOWORLD which don't appear elsewhere for months. Their product reviews are generally
well chosen, and accurately reflect the present state of products available to the
consumer.
INFOWORLD is also THE leader in product reviews. All reviewers are given a set of
guidelines to which they must conform. Software is evaluated in the categories of
PERFORMANCE, EASE OF USE, DOCUMENTATION, and ERROR HANDLING. Hardware is categorized by
SETUP, EASE OF USE, PERFORMANCE, DOCUMENTATION, and SERVICEABILITY. Each review
concludes with a "Report Card" which rates each of these areas as Poor, Fair, Good, or
Excellent. No other magazine reviews have the consistency that INFOWORLD reviews have.
If you're considering a major hardware or software purchase, this is one resource you
shouldn't ignore.
INFOWORLD Summary
=================
TECHNICAL DEPTH - None - News Magazine
TIMELINESS - EXCELLENT
REVIEW QUALITY - EXCELLENT
Full page ad, 1 time: $3780 (Apr. 4, '83 rate card)
Typical payment to author (review): $85
80-MICROCOMPUTING
80-Micro is a TRS-80 specific magazine, though it does occasionally address other brands
of computers. This magazine tries to address all segments of the TRS-80 industry. The
material ranges from tutorials to such complex areas as microprocessor emulation. This
is almost all "how to" material though. 80-Micro makes little attempt to deal with the
design of software and hardware, but rather presents the finished results.
A majority of each issue's program listings are available on cassette or disk to save
you the drudgery of typing it in yourself. This is a great idea, and one which more
magazines ought to follow. The writing style varies, but is generally acceptable for
the magazine's intended audience. There is one major problem with this magazine,
however. It has an editorial policy which not only enjoys controversy, but manages to
create it as well . This is in no small measure due to the publisher and owner, Wayne
Green. Mr. Green's editorials are generally full of shots at Radio Shack, the computer
industry, and almost everyone except Wayne Green Inc.! Now, there's no question that
Radio Shack and others occasionally have deserved a slap on the hand for a bad
Page 37
decision, but I find it difficult to believe that nothing good EVER comes from Fort
Worth. I find these editorials pompous, unsubstantiated, and hypocritical. For
example, Mr. Green has on several occasions taken Radio Shack to task for not offering
enough value for the cost of their products. Yet, if you look at 80-Micro itself, the
value delivered is rapidly decreasing. The subscription rate is being increased, but
the number of pages per issue appears to be decreasing! There is little here that you
can't get in other magazines, so I cannot recommend you spend you money to read Mr.
Green's self-serving editorials.
Just like BYTE, 80-Micro gets a decided thumbs down in the timeliness department. The
"news" articles rarely are, and the main articles are often dated by the time they
appear in print. About the only up-to-date material you can rely on in 80-Micro are the
product reviews.
The reviews in 80-Micro are similar in form to those in BYTE. Each reviewer sets pretty
much their own approach to the product being reviewed so there is little correlation
between reviews written by different people. 80-Micro does publish comprehensive
listings of a given type of product from time to time, and these are quite good. For
example, reports on word-processing products and programming aids recently were
published. I found both of these articles informative, current, and truly useful.
80-MICROCOMPUTING Summary
=========================
TECHNICAL DEPTH - "How To" Primarily/ Little Design Material
TIMELINESS - POOR
REVIEW QUALITY - FAIR to GOOD
Full page ad, 1 time: $2395 (Jan. 15 183)
Typical Payment to Author: $50 per typeset printed page
80-U.S. JOURNAL
80-U.S. is also a TRS-80 only magazine. Its thrust is primarily for the novice
programmer and newcomer to the world of personal computing. There is little here for
the intermediate or advanced user, but there is a WEALTH of information for the rank
beginner. If you are new to all this, 80-U.S. is an absolute MUST. You can learn more
in one issue of this magazine than you'll learn in weeks of "hacking" by yourself. The
writing style is direct, and delightfully simple to understand. Though the majority of
the material in 80-U.S. is "how to", there is also usually an article or two on the
"why" behind a particular TRS-80 feature or command. Most examples are done in BASIC,
and 80-U.S. hasn't forgotten that cassette only systems are still in use.
Insofar as 80-U.S. presents newsy material, it is fairly current. The first published
reports on the TRS-80 Model 100 and Model 4 were in 80-U.S., as were a string of Tandy
product announcements.
The reviews are usually also reasonably current. 80-U.S. has two types of reviews.
There is a collection of "mini" reviews in each issue as well as one or two in-depth
reviews as feature articles. I generally find these to be too superficial to be of any
real help in determining the value of a product. Several times I have seen reviews of
products which I KNEW were poor, but got passable ratings in 80-U.S. Here again, a set
of uniform review guidelines would help enormously.
80-U.S. JOURNAL Summary
=======================
TECHNICAL DEPTH - NOVICE to INTERMEDIATE
TIMELINESS - GOOD to EXCELLENT
REVIEW QUALITY - POOR to FAIR
Full page ad, 1 time: $1000 (Feb. 1, '83 Rate Card)
Typical payment to author (article): $l00
SPENDING YOUR MONEY
In my estimation, everyone should get INFOWORLD. It is THE source for information about
the computer industry. If you're a beginner, you'll want to subscribe to 80-U.S. for a
Page 38
year or two, 'til1 you get your feet wet. There really is no good magazine for the
advanced TRS-80 programmer, so you're pretty much on your own if you're past the
beginner stage. Perhaps someone with a lot of cash would 1ike to start a new
magazine?.....
THE "C" LANGUAGE (Part III)
by Earl 'C' Terwilliger Jr.
647 N. Hawkins Ave.
Akron, Ohio 44313
WELCOME back for Part III! As promised, the main topic for this article is operators.
The C language is very rich in its capabilities of data manipulation. Operators perform
this data manipulation. In the C language, operators are usually grouped into
categories. These categories (or types) are shown in a chart below.
Operators specify what is to be done to variables and constants. Operators, when
combined with variables and constants, are called expressions. When an expression is
followed by a semicolon it becomes a statement. In the next article we will see more on
expressions, statements and the logic control and flow in the C language.
Before I go on, I would like to clarify a few things you will encounter in the C
programming language in dealing with expressions and operators. Basically, these points
involve the concepts of ]value, rvalue, "side effects" and type conversions.
An lvalue (left hand value) is an expression which references storage in the computer.
In C, an object is a manipulatable area of storage. An lvalue is an expression which
refers to that object. An lvalue is the only value which can be on the left side of an
assignment statement. An lvalue or an rvalue can be found on the right side of an
assignment statement. An expression which is not an Ivalue is sometimes called an
rvalue. An rvalue doesn't refer to an object (area of storage). An example? Consider
the following C statements:
int c;
c = 0;
For Z80 based machines, if the HL register pair was used to obtain the value of c from
the stack, you might see the following instruction (among others) generated as a result
of compiling the above C statements:
LD HL,O ;Load HL pair with 0
The 0 is contained in the instruction and doesn't take up any data storage. Side effects
come into play when there are no explicit C rules as to how an expression is to be
evaluated. In this article, a chart is used to summarize the rules of precedence and
associativity for the various operators.
If no rule of evaluation applies, the C compiler is free to evaluate an expression or
subexpressions as it sees fit. The results (expected or not) are called side-effects.
To overcome side-effects, break up larger expressions or statements and use explicit
"temporary" lvalues.
When expressions involve arithmetic with different data types, a conversion (or
promotion) to a common data type occurs. Since both data types are of a common type,
the result is also of that type. Since "lower" data types are converted to "higher"
types, the process is called promotion. Of course there is a set of rules for this
conversion or promotion. The "ladder of promotion" (if I can be allowed to invent a
phrase) is shown to illustrate this promotion:
Page 39
double
float
unsigned long
long
unsigned int, unsigned short
int, short
unsigned char
char
Besides arithmetic expressions, type conversions can take place when a function is
called. After all, a function argument is an expression. Conversions can also take
place across an assignment statement. When this happens the value on the right side is
converted to the type on the left side. The above promotions can occur or the reverse
process can also occur. (Demotion!) A word of caution! The C language guarantees any
character in the machines standard character set will never be negative when used in
arithmetic expressions. However, C does not specify whether variables of type char are
signed or unsigned. So, be careful when using various bit patterns (other than the
standard character set) because you may be dealing with negative values. Later, we will
see how to force a type conversion using the cast operator.
Now that these points have been mentioned, let's get back to more on expressions. As an
expression is evaluated , there is a precedence or order of evaluation. It is important
to know the order of evaluation when the different types of operators are combined in an
expression, especially if you want a correct result! Below is a chart of the operators
available in C. It shows the relative order (level) of precedence, and the associativity
of operators of equal precedence. The associativity is given to show how expressions
are evaluated if operators of an equal level of precedence are found side by side in the
same expression. (You saw the following chart in Part II.) It is repeated here with
examples of each operator and sample expressions.
Operators Level Type Associativity
---------------------------------------------------------------
() [] -> 15 Primary left to right
! ~ ++ -- - 14 monodactic right to left
(type) * & sizeof 14 monodactic right to left
* / % 13 arithmetic left to right
+ - 12 arithmetic left to right
<< >> 11 shift left to right
< <= > >= 10 relational left to right
== != 9 relational left to right
& 8 bitwise logical left to right
^ 7 bitwise logical left to right
| 6 bitwise logical left to right
&& 5 logical left to right
|| 4 logical left to right
?: 3 conditional right to left
= += -= *= /= %= 2 assignment right to left
|= ~= &= >>= <<= 2 assignment right to left
, 1 comma left to right
Since variables must be declared before they are used, I will declare a few so they can
be used in our sample expressions.
int a, b, c, d;
Variables can be initialized in their declaration statement. As you might guess, an
operator (the equals sign) is needed to accomplish this. For example:
int a = 10;
int b = 5;
int c = 2;
Page 40
An easier way to initialize the above variables is:
int a = 10, b = 5, c = 2;
(Well... anyway it takes less lines in your program.) To accomplish the initialization,
the variable name is followed by an equals sign and a constant. The constant's value
serves as an initializer. Multiple initializations can be performed in a single
statement (as is done above) when separated by a comma. The comma, used in this way as
a separator, is not an operator and does not mandate the rules of evaluation as does the
comma operator. Some variable types, external and static, are automatically initialized
to zero by default of the C compiler. However, as stated by K&R, it is better
programming practice to state their initialization anyway. If automatic variables are
not initialized, their values will be of an undefined value. (Garbage!) You should note
that for external or static variables, the initialization is done only once.
For automatic variables which are initialized in a function, they are re-initialized
each time the function is called.
I may need to declare a few more variables to illustrate all of the operators. However,
I will do so when each individual operator is introduced. Let's begin!
Operators Level Type Associativity
---------------------------------------------------------------
() [] -> 15 Primary left to right
printf("C is a very useful language to know!\n");
The () is called the function call operator. The left and right parentheses separate
any optional arguments passed to the called function.
char buffer[100]
The [] operator(s) is used for arrays. In this example, an array of characters, whose
name is buffer, is declared to have 100 elements. The [] is used to reference (index or
subscript) elements of the array. In this example, the elements are buffer[Ol thru
buffer[99]. In C the index starts at 0. Be careful about your use of these subscripts,
since the C compiler does not check to see if the subscript you use is within the bounds
of the array.
struct date { int month, day, year;} birth;
struct date *pdate;
pdate = &birth;
birth.month = 10;
pdate->day = 3;
The . and the -> (period and arrow) operators are used when dealing with structures.
The "." operator is called the structure member operator because it connects the
structure name and a member name. Pointers to structures are very frequently used, due
to the restrictions imposed by the C language. These limitations imply that structures
are not to be dealt with as a single unit. This limitation does not hold for pointers
to structures. Therefore a shorthand operator, ->, is used to make pointers to
structures and structure members easier to use. In the examples above, birth is a
structure of type date, month and day are members of the structure and pdate is a
pointer to a structure of type date. More later on structures! (As you can see, we
haven't yet discussed the * and & operators!)
Operators Level Type Associativity
---------------------------------------------------------------
! ~ ++ -- - 14 monodactic right to left
(type) * & sizeof 14 monodactic right to left
Page 41
All of these operators are unary or monodactic operators. This means they need only one
operand.
!a
The truth value of a is reversed. If a was TRUE (non-zero) it is now FALSE (zero). If
a was FALSE it is now TRUE. Since I declared a to be 10 earlier, after the !a, the
result returned will be FALSE (zero).
~a
The one's complement of the operand a is returned. Just invert each bit of the operand.
If a bit was a one switch it to a zero and if the bit was a zero switch it to a one.
++a --a a++ a--
These are the increment ++ or decrement -- operators. They may prefix or postfix the
operand. If the operator prefixes the operand, its value is taken after the increment
or decrement. If the operator postfixes the operand, its value is taken and returned by
the expression before it is incremented or decremented. These operators do not
necessarily mean to add 1 or subtract 1 from the operand. The increment or decrement
value is based upon the storage TYPE of the operand!
-a
This is the unary minus operator. It reverses the sign of a. After -a, since a was
declared to be 10, the result is now a -10. (There is no unary + operator.)
myfunc((double) c);
The variable c was defined as an integer above. If the function myfunc() needs to be
passed a double precision floating-point variable, c can be coerced into that type.
This construct of forcing a variable into another type is called a cast. In this
example, c is cast into type double.
char name[30];
name = "Earl C. Terwilliger Jr.";
char *ptr;
ptr = &name;
The & operator obtains the address of an object. (The & operator applies only to
variables and array elements.) The * operator precedes an operand containing an address.
This address is then used to fetch the data stored there. A lot more will be said about
these operators when pointers and arrays are discussed in greater detail!
sizeof(a)
This operator returns the size of any object. The value returned is determined by the
number of units contained in the object. Each "unit" or "byte" has the same relative
size as type char.
Operators Level Type Associativity
---------------------------------------------------------------
* / % 13 arithmetic left to right
+ - 12 arithmetic left to right
d = a * b; /* a multiplied by b */
d = a / b; /* a divided by b */
d = b % c; /* b modulus c */
d = a + b; /* a added to b */
d = a - b; /* b subtracted from a */
The *,/,+,- operators perform the arithmetic functions of multiplication, division,
addition and subtraction respectively. Since integer division in C truncates the
fractional part, use the % or modulus operator to obtain the remainder. (% can not be
applied to float or double operands.) (Note that parentheses are also used around
expressions to specify order of evaluation. Watch out! The C compiler can sometimes
Page 42
rearrange a parenthesized computation. For some associative and commutative operators
(remember your arithmetic for * and + ?) the C language does not specify the order of
evaluation. Use explicit temporary variables to overcome this, if in fact this re-
arrangement makes any difference.)
Operators Level Type Associativity
---------------------------------------------------------------
<< >> 11 shift left to right
a >> 2 /* a shifted right by 2 bits */
b << 4 /* b shifted left by 4 bits */
These shift operators perform left and right shifting of the bits in their operand. The
number of bits shifted is the right operand. When an operand is shifted left, vacated
bits are filled with a 0. Right shifting an unsigned operand causes the vacated bits to
be filled with zeros. Right shifting a signed operand may be an "arithmetic" or
"1ogical" depending on the machine and the C compiler.
Operators Level Type Associativity
---------------------------------------------------------------
< <= > >= 10 relational left to right
== != 9 relational left to right
a < c /* a less than c */
a <= c /* a less than or equal to c */
a > c /* a greater than c */
a >= c /* a greater than or equal to c */
a == c /* a equal to c */
a != c /* a not equal to c */
Each of these operators takes two operands and returns the result TRUE or FALSE (1 or
0). The result is based upon the relationship of the two operands. (Note: one of the
more frequent errors by new C programmers is the failure to differentiate the ==
operator from the = operator. The == operator tests for equality while the = always
sets equality.)
Operators Level Type Associativity
---------------------------------------------------------------
& 8 bitwise logical left to right
^ 7 bitwise logical left to right
| 6 bitwise logical left to right
a & Ox0f /* a bitwise ANDed with Ox0f */
a ^ OxfO /* a bitwise XORed with OxfO */
a | Ox01 /* a bitwise ORed with Ox01 */
These operators provide C the capabilities of bit manipulations. Bits of the left
operand can be ORed, ANDed or exclusively ORed by bits in the right operand.
Operators Level Type Associativity
---------------------------------------------------------------
&& 5 logical left to right
|| 4 logical left to right
&& and
|| or
Page 43
These operators logically connect their operands. (They should not be confused with the
& and | bitwise operators.) These operators can be used to connect expressions. For
examples:
(a == 2) || (a == 3)
(a != 0) && (c == 2)
Operators Level Type Associativity
---------------------------------------------------------------
?: 3 conditional right to left
(a == b) ? (c = 1) : (c = 2)
This ?: construct is a ternary (three) operator. It provides an alternative to the IF .
. . THEN ... ELSE . . . type logic. If the expression to the left of the ? is TRUE then
the expression immediately after the ? is evaluated. If it is false then the expression
after the : is evaluated.
Operators Level Type Associativity
---------------------------------------------------------------
= += -= *= /= %= 2 assignment right to left
|= ~= &= >>= <<= 2 assignment right to left
a += 1 /* Add 1 to a */
a -= 3 /* Subtract 3 from a */
a *= 5 /* Multiply a times 5 */
c /= 2 /* Divide c by 2 */
c %= 2 /* Store remainder of c/2 into c */
c |= Ox80 /* c is bitwise ORed with Ox80 */
c ^= OxO2 /* c is bitwise XORed with Ox02 */
c &= Oxf0 /* c is bitwise ANDed with OxfO */
c >>= 2 /* c is shifted right 2 bits */
c <<= 4 /* c is shifted left 4 bits */
These operators represent the assignment operators. They were seen before without the
equals sign. They make expressions such as: a = a + 1 much easier when written as: a +=
1 . Usually the resultant assembler (machine) code produced as a result of these
operators is more efficient too. They are especially helpful if a long complicated
expression is on the left of the = and needs to be used to the right of the =.
Operators Level Type Associativity
---------------------------------------------------------------
, 1 comma left to right
The comma is used in C as punctuation. It is seen separating expressions in
declarations and it is seen separating arguments passed to functions. The comma
separator is different from the comma operator. The comma operator is usually found
used in a for statement. An example of a 'for' expression? OK!
for (i = 1, j = 2, c = 3; i != 50; ++i)
In the next article, I will be discussing the logic of a C program (the control and flow
of how and in what order computations are done). Until then, read some more of K&R and
the rest of the LDOS QUARTERLY!
Page 44
ITEMS OF GENERAL INTEREST
There is a possibi1ity of misunderstanding the PDSHELP/FIX patch that was in the PDS
article in the January 1983 Quarterly. This patch is to be applied to a new PDS after
you have created it with the BUILD command. - Scott Loomer -
Since the January 1983 Quarterly article was written, Alcor has introduced version 2.0
of their Pascal system. The upgrade cost to current owners is $21 which includes new
disks. Briefly, these are the enhancements in version 2.0. The Pascal functions GET and
PUT have been added (the only Jensen and Wirth langauge standards that had been
missing). The flag register status is now returned in the machine language CALL. The
procedure to internally define file names has been simplified. Random access files are
now supported. The additional compiler options INCLUDE, LIST, PAGESIZE, WIDELIST
RANGECHK and PTRCHECK have been added. The LOCATION function will now work with
procedures as well as variables. The linking loader will now accept lower case. The
error in subrange variables has been corrected.
As is typical , just prior to getting the update announcement, I had just finished
patches to version 1.2 to allow 1ower case filespecs in all modules. After I've
examined 2.0, I wi11 submit any of the patches that are necessary to ensure complete
lower case compatibility. - Scott Loomer -
Patches, patches, patches ....
The following is a mandatory patch to FORMAT/CMD. This is for all versions of FORMAT
produced with file dates before 06/l0/83. This patch is the same for al1 5.1.3
releases, and is the same for Model 1, Model 3, and MAX-80.
. FORMATC/F3X - 06/08/83
.
. Corrects problem with setting "D" BEFORE calling
. SELECT so the FDC driver can properly deal with precomp
.
X'60DF'=8B 67
X'6OE5'=08 64
X'678B'=FD 56 05 C3 F4 63
.
. EOP
Optional Patches
. Patch to Enhanced VisiCalc to remove parallel printer ready check
. this is necessary if the *PR device is routed to a serial printer
.
. original contents was: 3A E8 37
.
. Patch for version VC-150Y0-T83
D55,2C=AF C9
.
. Patch for version VC-160Y0-T83
. D55,4D=AF C9
. Patch to extend the keyboard debounce time for 'problem' keyboards
. NOT for MAX-80
. file to patch is: KI/DVR original contents was: 03
.
. for Model 1
D01,A9=04
.
. for Model 3
. D01,AC=04
Page 45
. Patch to disable the Model 3 external I/O bus on boot, if non-standard
. peripherals are causing a problem. Do NOT use this patch on a
. hard disk system
.
. file to patch is: SYS0/SYS original contents was: 38
D0D,20=28
. Patch to use "." rather than "/" and ":" on bootup DATE and TIME prompts
. NOT for MAX-80
. file to patch is: SYS0/SYS original contents was: "/" and ":"
.
. Model 1
X'4EB8'="."
X'4FA5'="."
.
. Model 3
. X'4EB9'="."
. X'4FA6'="."
. Patch to allow LPRINT TAB past position 63 (up to 127)
. this patch is for MAX-80 ONLY!
.
. file to patch is: SYS0/SYS original contents was: 3F
.
X'213B'=7F
. Patch to force lower-case driver on boot. This is necessary on some
. non-RS type lower-case mods
. this patch is for Model 1 ONLY
.
. file to patch is: SYS0/SYS original contents was: 2V 06
X'4E36'=00 00
LET US ASSEMBLE
by Rich Hilliard
Welcome back. Last issue we listed several methods of working on your ego so that along
with assembly language expertise, you could become (as is normally the case) an
insufferable egomaniac at the same time. Several letters from Country & Western Fans
pointed out that C & W people may substitute the song "It's Hard to be Humble" rather
than "Nobody Does It Better". I agree that this is a fine substitution. Broadway buffs
may substitute "C'est Moi, C'est Moi" (It's me, It's me) from Camelot and classical
fans, the theme from Beethoven's "Eroica" (The Hero) symphony.
Lawrence Welk fans may simply pick up their Model III computer sideways (which then
looks like an accordion), and do a Myron Florn imitation. (Anyone thinking that more
than three minutes of accordion music is entertainment MUST be an egomaniac.)
By the way, if after reading this series of articles you still cannot grasp assembly but
you have participated in the ego exercises, you can always write reviews. If you cannot
do anything you can always become a computer salesperson, or if you are a complete
idiot, you already have sufficient background to be either a computer consultant or a
systems analyst. So fear not and forge ahead! The computing industry has a place for
everybody.
Page 46
If the computing industry is a "melting pot", just consider mother nature. The evidence
is overwhelming that nature looks upon all her children equally - - as a quick meal; or
why else is humanity nothing more than a protein bag stretched over many pounds of
obscene glop.
To those who find it hard to believe in mankind as a quick lunch, I point to the so
called loyalty of man's erstwhile "best friend", the family dog. If humanity is not a
tasty morsel, then why do they always try to lick us?
Well now that the fun is over let's get to work. In the last issue we wrote the
following:
00100 ORG 5200H ;define entry
00110 LD HL,HELLO ;point to message
00120 CALL 4467H ;print it
00130 JP 402DH ;return to system
00140 HELLO DB 1CH,lFH,'HELLO I AM YOUR TRS-80 COMPUTER',ODH
00150 END 5200H
To see it execute after assembly, at LDOS Ready merely type "PRINT" and the screen will
clear and print the message defined in line 00140.
Assembler, or for that matter, any compiled language, has a tremendous disadvantage in
not being capable of halting any run to examine for problems. For this reason, a class
of "monitor" program such as DEBUG is very handy. Let's examine PRINT/CMD under the
LDOS system DEBUGger. Switch on DEBUG by typing its name at LDOS Ready. Unlike most
programs, DEBUG will not execute immediately. To remove other memory clutter, do a
MEMORY (C), before entering DEBUG. After switching on DEBUG, it will activate mostly by
executing a user (non-system) program or by pressing the key. To DEBUG
PRINT/CMD, type "PRINT" at LDOS Ready. Do this before going farther (don't cheat
either; we have ways of making you DEBUG).
Down the left side of the video are the twelve paired/16-bit registers commonly used in
the Z-80. The next two columns after the equal sign display the contents of each eight
bit register separately. The four lowest registers are normally not addressable by less
than 16 bits at a time (but they can be "fooled", which we will get into a dozen or so
articles from now). Since our PRINT program has just started, our code has affected
only one register. Notice that the PC register contains 5200 which points to the next
instruction to fetch from memory and execute.
After the register contents is a "=>" followed by 16 bytes of information. This "=>"
symbol shows what each pair "points" at in memory. You can now see the difference
between the register contents and the pointed-to address. The PC register contains the
value 5200 and points to the value 21 in memory. All of these values are in hex, by the
way. If you look at the assembly listing from this program in the last issue, you will
note that the assembler's first columns read like this: 5200 210952, which you recall
means that there is a 21 at 5200, a 09 at 5201, and a 52 at 5202. Looking past the 21
that PC points to, you can see the remaining bytes of code in the same horizontal row.
Now I draw your attention to the last four rows of the video. These display any 64
bytes in memory. To see the rest of our program, type "D 5200". This points the
lower "D"isplay to 5200 through 523F. If you cleared memory before entering DEBUG, you
can readily see the entire PRINT program, all 43 bytes of it, ending with the OD at
522B. (If you did not clear memory, take out a flexible plastic object and smack
yourself repeatedly across the knuckles for not following instructions. This simulates
a quality education and tenderizes your hand for Rover.)
To proceed as if the code really were executing, DEBUG provides the "I" and the "C"
commands. The difference is that "I" executes one instruction at a time but "C" will
Page 47
perform a CALL instruction as a single step. This has an advantage. Recall that we
CALL @DSPLY (4467H) in this program. We know that the system call involves all the code
necessary to print our sentence to the video. We can bypass the tedium of this routine
with the "C" instruction since we are only interested in our own code. It should also
be noted that DEBUG will not single step through ROM, and that if a call to a ROM
routine is made by the system, a "C" must be used.
Press the once. (If pressed twice please revert to flexible plastic discipline
unless, of course, you enjoy it in which case cut yourself off for a month.) Notice that
the PC now contains 5203 which points to the next instruction, CD. Note that the HL
register now contains 5209. Our first instruction has been executed. The assembler
converted the label "HELLO" into the address 5209.
Press the key. This turns the right side of the screen to an "A"SCII display. Now
look at the HL register. The contents of HL points to the screen message. The two dots
preceding the message are non-ASCII characters. Pressing the , for hex, key will
convert the display back to hex, although you may run under either mode. Press
again and the video will flash, the PC contains 5206 and is pointing to C3. Our system
call to @DSPLY has been performed and control returned to DEBUG. The message cleared
the screen, printed, and re-printed the DEBUG display so quickly that we could barely
notice the effect. Using DEBUG to examine video results is, therefore, done on a
theoretical level.
The last command we will examine for now is the "G" or Go command. Leaving DEBUG is
accomplished by means of the Go command. We can exit by typing G 402D. This is a jump
to the @EXIT system vector which also happens to be line 00130 of our PRINT program.
Typing G alone wil1 cause the program to continue normal execution. In this case we
conveniently are a1ready returning to LDOS Ready, so simply do a "G" and turn off
the debugger by typing "DEBUG (N)" at LDOS Ready.
You can explore the rest of the debugger on your own. This cursory explanation was to
show you the most used features in order to assist you for the first time. Other system
monitors worthy of note which provide many features beyond DEBUG are: UltraMon and
Macro-Mon.
Sorts Illustrated.
Now for some real fun. Did you ever wonder (wonder should be a trademark of Creative
Use of Glue in Preposterous Bread Commercials, Inc.) why SORTS have such bizarre names
such as Ripple, Bubble, and Shell. It probably is do to the "action" caused by the code
in memory causing a ripple or bubble effect to occur. The shell effect is interesting
because if you put your ear on a RAM chip while the shell sort is running, you will hear
nothing and most likely burn your ear. Since the TRS-80 video is RAM memory mapped, the
effects can be observed by sorting ONE character arrays directly in video.
We will examine both the bubble and shell sorts in TBA source code as well as assembler.
Stay tuned for an announcement regarding the ripple sort.
The bubb1e sort takes a list of objects and compares them two at a time. If the order
is incorrect, the two objects are exchanged. The next pair of objects is then examined
and so on until the entire list has been examined. Obviously, it requires several
passes, before the list is entirely correct. A flag is reset prior to every pass and
set if any exchange occurs. The process is repeated until a pass is completed without
the flag being set. This indicates that no exchanges took place and, therefore, the
list is now ordered. The effect of this sort is that the "light" stuff drifts to the
top and the "heavy" stuff sinks like a rock. The TBA listing is : (for those of you who
do not have TBA, I will translate this one time that you may see the folly of not
possessing it.)
I think you wi11 find it easier to fo11ow the 1ogic of the TBA code rather than the old
fashioned straight BASIC. (and now a message from our sponsor ... TBA is available for
$69.00 in the 5.1 version ... and now back to our program).
Page 48
=FLAG%,LOOP%,TEMP%,LOOPl%
'Fill half screen with random data 33 to 127
CLS 3 CLS
FOR LOOP%=15360 TO 15872 4 FORLO%=15360T015872
POKE LOOP%, RND(95)+32 5 POKELO%,RND(95)+32
NEXT LOOP% 6 NEXTLO%
'Reset flag and scream through data
swapping as necessary
@ORDER.DATA
FLAG%=0 9 FL%=0
FOR LOOP%=15360 TO 15871 10 FORLO%=15360TO15871
LOOP1%= LOOP%+1 11 LP%=LO%+1
IF PEEK(LOOP%)<=PEEK(LOOP1%)
THEN @SKIP.IT 12 IFPEEK(LO%)<=PEEK(LP%)THEN18
TEMP%=PEEK(LOOP1%) 13 TE%=PEEK(LP%)
POKE LOOP1%,PEEK(LOOP%) 14 POKELP%,PEEK(LO%)
POKE LOOP%,TEMP% 15 POKELO%,TE%
FLAG%=1 16 FL%=1
@SKIP.IT
NEXT LOOP% 18 NEXTLO%
'Loop and try until no swaps occur
IF FLAG% THEN @ORDER.DATA 20 IFFL%THEN9
@LOOP: GOTO @LOOP 21 GOT021
This program sorts 512 items and takes more time than drinking hot coffee even with a
loose filling. Our assembler version will sort 1024 items in several seconds. First,
we need to know another pseudo-op. This is EQU or equate. We will start the program at
5200H and the first four lines are
00100 ORG 5200H
00ll0 VIDEO EQU 3C00H
00l20 @EXIT EQU 402DH
00130 @KEY EQU 0049H
The equate sets the symbol in the label zone equal to the value/expression specified.
This means that we can now substitute the term for the number as in CALL @KEY, etc.
Our first task is to get the "random" data to the screen. There are several
complicated algorithms for accomplishing this but they are not necessary here. Someday
if we write some stupid game it may be necessary to deal with it. The idea is to
scream through memory and locate characters in the range of ASCII 33 through 127 and
reject everything else. To do this we need the equivalent of IF ... THEN or a
conditional branch.
The Z-80's F register contains flags used to indicate conditions that occurred in the
last completed instruction. Some instructions do not affect flags at all. In the F
register, bits 7, 6, 4, 2, 1, and 0 are used for flags. (Bits 3 and 5 are not used.)
The conditions can be used in conjunction with CALL, RET (RETurn), JP, and JR (Jump
Relative) to either GOSUB, RETURN, GOTO, or "kind of goto", on a conditional basis.
CALL and JP were covered in the last session. RET is simply a RETURN from a
subroutine. JR has no exact analog in BASIC except it is another form of JP. The
advantage is that unlike a jump (JP 402DH), JR requires no address but the jump must
be in a range from -126 to +129 (effectively) from the instruction. In other words, it
must be close. As you will see from the code below, it is usually referenced by a
label which the assembler converts to the relative jump location. This is like saying
GOTO ten lines ago or GOTO fifteen lines ahead. It executes slower than a jump but
takes 1 byte less of code. Its primary advantage is that unlike a JP, it does not
need to have the modifying address changed if the code is relocated. However, it does
not have all of the branch conditions available to it.
A conditional branch in assembler means "Execute the instruction only if this
condition exists" to the Z-80. JP Z,402DH means GOTO address 402D if the Z flag is
set. The conditions can either be met or excluded in that every flag has its opposite
Page 49
conditional branch. JP NZ,402DH means GOTO address 402D if the Z flag is NOT set. We
will discuss the flags in detail as we need to.
Briefly, they are as follows:
C - NC = Carry Flag Set/Reset (bit 0)
PE - PO = Parity Set/Reset (bit 2)
Z - NZ = Zero Set/Reset (bit 6)
M - P = Sign Flag Set/Reset (bit 7)
Now let's fill the screen (memory) with characters,
00l40 LD HL,4000H ;start anyplace, actually
00150 LD DE,VIDEO ;point DE to video RAM
00l60 GETCAR LD A,(HL) ;get a byte into A from HL address
00l70 CP '!' ;char < !
The A register is used for most math functions. The CP (ComPare) instruction performs
a subtraction which throws away the result but leaves the flags affected as if the
subtraction took place. This is how A is tested for its contents. Let us assume a
value X for the following chart of comparisons utilizing the instruction CP X:
Relationship: Branch Flag When to go
if A < X C then go on C flag
if A <= X C or Z then go on C (if less) or Z flag (if equal)
if A = X Z then go on Z
if A <> X NZ then go on NZ
if A >= X NC then go on NC
if A > X NZ & NC then go on both NZ and NC (this is tricky)
X can be another eight bit register, a number (0-255), (HL) or (IX/Y +d). The last we
will discuss in the future. It can be seen that we want characters greater than or
equal to an '!' (ASCII 33) and that if A >= !, then we want that character, but only
if it is <= ASCII 127, so the remaining selection code is as follows:
00l80 JR NC,TEST ;if A >= ! then test further
00l90 INC HL ;point to next memory location (INC) functions
;like this : HL = HL + 1
00200 JR GETCAR ;Jump back to line 160 (GETCAR)
00210 TEST CP 7FH ;is char <= 127
00220 JR C,OK ;char < 127, go
00230 JR Z,OK ;char = 127, go
00240 INC HL ;as above
00250 JR GETCAR
00260 OK LD (DE),A ;put A into memory pointed to by DE
00270 INC DE ;point to next place to write
00280 BIT 6,D ;test for end of screen
00290 JR Z,SORT ;if D=40H we are at end of video plus 1
00300 INC HL ;as above
00310 JR GETCAR
It should be noted that when a LD A,(HL) is performed, that neither of the contents of
the H nor the L register are placed in A. Rather the one byte contents of the ADDRESS
pointed to in the HL pair is loaded into A. Similarly, the LD (DE),A does not affect D
or E but does write the contents of A to the memory location pointed to in the DE
pair. Note the use of conditional branches to hop around to the desired spots.
Another test which can be performed on a register is the BIT test in line 00280 above.
The video screen occupies memory from X'3C00' (15360) through X'3FFF' (16383). The
upper limit of video ram looks like this 0011 1111 in D, and 1111 1111 in E. Adding 1
to this number yields X'4000' (16384) or 0100 0000 in D, with E containing all zeros.
Therefore, when bit 6 of the D register is not zero (NZ) we no longer need to loop
because the screen is full.
Page 50
We can now sort the data as we did in lines 9 through 21 of the BASIC program.
00320 SORT LD HL,VIDEO ;point HL to screen start
00330 LD C,0 ;C register is our flag
00340 SORT1 LD D,H ;point DE at HL + 1
00350 LD E,L
00360 INC DE
00370 LD A,(DE) ;get DE's pointed character
00380 CP (HL) ;if (HL) <= A then skip it
00390 JR NC,SKIPIT
00400 LD B,A ;this starts the exchange A has (DE) value
00410 LD A,(HL) ;xfer A to B and get (HL)
00420 LD (DE),A ;swap characters
00430 LD (HL),B
00440 LD C,l ;a swap a swap, mark it!
00450 SKIPIT INC HL ;advance
00460 BIT 6,H ;check for finish
00470 JR Z,SORT1
00480 INC C ;passover I mean pass over check for C being a
;zero which means no swap occurred on last pass
00490 DEC C ;this sets Z flag if C was zero but not if C was 1
00500 JR NZ,SORT ;try another pass
00510 CALL @KEY ;entry point which waits for a keystroke
00520 JP @EXIT ;back to LDOS Ready
00530 END 5200H
DEC is the opposite of INC, so that in line 00490 C = C - 1. Why this manipulation? The
LD instructions do NOT affect the flags, but on single registers, if the result of a DEC
is a Zero, then the Z flag is set. At the end of a pass C contains either one or zero.
If a swap occurred, C is loaded with one. At the end of the pass, C is INCreased to two
and DECreased back to one which does not set Z. Therefore, a JR NZ executes and that
branches to the code which reloads C with zero and does another pass. If C was zero at
the end of a pass, it would be INCreased to one and DECreased to zero which does set Z,
and control falls through the JR NZ to the keyboard call.
BIT tests the argument (in this case the H register) to see whether or not a specific
bit is set (1) or reset (0). The flag Z is set if a zero is detected at the specified
bit (in this case 6). One CAUTION should be noted. The test for the end of a pass (BIT
6,H) is a little tacky. Since we point DE at HL + 1, when HL is 3FFFH, DE will already
BE 4000H or one byte past the end of VIDEO RAM. We get away with this because X'4000'
happens to contain a C3H which is above our upper limit so that it will never swap. If
the program were modified to use characters through byte FF then a SWAP would occur on a
vital system vector (a C3 is a jump) and an FF would end up there (an FF is a RST 38H)
which would positively blow your buns away. PART ONE of the ASSEMBLY contest is to
rewrite the assembly code so that this can never occur. Also in PART ONE, see if you
can rewrite lines 2l0-230 to do the same job with one less compare.
The Shell sort takes a list of elernents and divides them into zones of ever increasing
length. A list of l00 elements is divided by an arbitrary number. In advanced
languages, this is usually not two but in assembler it makes little difference due to
speed and is usually done to take advantage of the easy method of dividing by two in a
binary base numbering system. You merely shift the number one place to the right, which
is exactly what we do when dividing by ten in a decimal system.
The items in each shell are then placed in order and the list advances to each
successive shell until the list is exhausted. The control number is then divided again
which effectively increases the size of the shells and the process is repeated until the
shell length equals the number of objects in the list. Since this might be a bit vague,
let's look at some actual numbers. In a list of l00 we divide by 3 to get 32 shells of
3 items each and one of 4. The first shell is comprised of the first element plus all
elements offset by 33 or the elements 1, 34, 67, and l00. The second shell contains
elements 2, 35, and 68, shell three is composed of 3, 36, 69 etc. So that each
Page 51
of the shells has very few elements. Each shell is then ordered by comparing a pair of
elements within it. 1 is compared to 34 and if necessary they are swapped. Then 2 is
compared to 35 etc. until the list reaches 34. Now we are back to the first shell and
compare 34 to 67. If no swap is necessary we also know that since 1 < 34 < 67 that
shell 1 is in order within itself. If, however, item 67 is less than item 34 we swap
them, but we still have no idea if 1 is less than that item (now at 34) so we compare 1
and 34 again, and if necessary swap them also.
We divide the number 33 by two and get 16, now there are 16 shells of length 6 or 7.
These are already somewhat re-ordered by pass 1 and we are about 20% "zoned" at the end
of this pass. In 2 passes we have accomplished more than on l00 passes in the bubble
sort. As the sort progresses, you will note the migration of the elements toward their
final resting place. (Kind of like life, isn't it?) The TBA code for the shell screen
sort is as follows:
=OFFSET%,ELEMENTS%,LOOP%,TEST%,TEMP%
CLS
CLEAR100
FOR LOOP%= 15360 TO 15872
POKE LOOP%,RND(95)+32
NEXT LOOP%
ELEMENTS%=512
OFFSET%=INT(ELEMENTS%/3)
FOR LOOP% = 0 TO ELEMENTS%-OFFSET%
TEST%=LOOP%+15360
IF PEEK(TEST%) <= PEEK(TEST%+OFFSET%) THEN @ANOTHER
OFFSET%= INT(ELEMENTS%/2)
@GO: FOR LOOP% = 0 TO ELEMENTS% - OFFSET%
TEST%=LOOP%+15360
@AGAIN: IF PEEK(TEST%) <= PEEK(TEST%+OFFSET%) THEN @ANOTHER
TEMP%=PEEK(TEST%)
POKE TEST%,PEEK(TEST%+OFFSET%)
POKE TEST%+OFFSET%,TEMP%
TEST%=TEST%-OFFSET%
IF TEST%>15360 THEN @AGAIN
@ANOTHER: NEXT LOOP%
OFFSET%=INT(OFFSET%/2)
IF OFFSET%>0 THEN @GO
@DONE: GOTO @DONE
The assembler code is as follows
00090 TITLE <'SHELL/ASM shell sort of video contents'>
00100 ORG 05200H
00ll0 VIDEO EQU 03C00H
00120 @EXIT EQU 0402DH
00130 @KEY EQU 00049H
00140 START LD HL,4000H ;random selection
00l50 LD BC,l024 ;do l024 times
00160 LD DE,VIDEO ;point to screen
00180 SELECT LD A,(HL) ;stuff contents in A
00190 TESTLO CP '!' ;A >= !
00200 JR NC,TESTHI ;test upper limit
002l0 BUMP INC HL ;A < i go
00220 JR SELECT ;try again
00230 TESTHI CP 80H ;check for > 127
00240 JR C,OK ;if not, proceed
00250 JR BUMP ;else try again
00260 OK LD (DE),A ;put on screen
00270 DEC BC ;decrease count
00280 LD A,B ;test for end of loop
00290 OR C ;does C = B = 0?
Page 52
00300 JR Z, SORT ;BC is 0, goto sort
003l0 INC HL ;else point to next char
00320 INC DE ;point to next video
00330 JR SELECT ;goto select
With EDAS, the TITLE pseudo-op places the string between the <> at the top of every page
if you send the assembly listing to the printer. Rather than wait for DE to acquire a
value of 4000H, this time we set up a definite loop in the BC register which DECs every
time a character which meets our discriminating standards is selected. We test for BC =
0 in lines 280 and 290. OR performs a logical or operation of the argument (in this
case the C register) against the accumulator. The result of this operation will be zero
only when both B & C are zero. This must be done because DEC BC or the DEC of any 16
bit pair does not affect flags. Therefore, it is a way to determine when the 16 bit pair
is zero.
00340 SORT LD BC,512 ;initial offset is 512
00350 LD HL,VIDEO ;point to CRT
00360 SORT1 PUSH HL ;save pointer in case we need to go back
00370 POP IX ;loads 16 bit IX through SP
00380 PUSH HL ;save it one more time
00390 ADD HL,BC ;make DE the next Shell member
Note that we did not convert the BC load number into any other number base. We knew we
wanted 512 so the assembler will convert the number to hex for us. A PUSH instruction
places the contents of a 16 bit register or register pair into the memory stack. I will
not discuss the stack at all here. Suffice it to say that it places the contents in
memory and knows where they are. A POP does exactly the opposite, retrieving the
contents from the stack. The operation in lines 360-370 is the most common method of
transferring a 16 bit pair (HL) to an index register. Effectively, after execution of
line 370, IX = HL. HL may be used as a 16 bit "accumulator" for addition and
subtraction. In this case BC was set to 512 (and will be decreased later) which makes
HL = HL + 512 after execution of 390.
00400 LD E,L
00410 LD D,H
00420 BIT 6,H ;test for end of pass
00430 POP HL ;restore current shell element to HL
00440 JR NZ,DIVIDE ;if end of pass goto divide
00460 COMP LD A,(DE) ;compare HL to DE
00470 SUB (HL) ;if A < 0 swap
00480 JP P,NEXT ;if A >= 0 goto next
SUB takes the argument (in this case (HL)) and subtracts it from the accumulator and
stores the result back in A (A = A - (HL)). In this case, because the original
information is destroyed, it may be more desirable to use a CP, but we save one byte
this way and I wanted to show you different methods of de-dermitizing the feline.
Notice the JP P,NEXT. Although a JR would be in range, a JR on condition P is not
allowed, so a JP had to be used.
00490 LD A,(DE) ;restore A for swap
00500 PUSH AF ;save element 1
00510 LD A,(HL) ;get element 2
00520 LD (DE),A ;& put at position 1
00530 POP AF ;restore element 1
00540 LD (HL),A ;& put at position 2
00550 LD E,L ;since a swap occurred, we must look
00560 LD D,H ;backward in the shell
00570 XOR A ;this always clears the C flag
00580 SBC HL,BC ;point HL to -offset
XOR does an exclusive OR logical operation on A. We will discuss logical operators next
time. It is necessary in this case because the only 16 bit subtraction possible is an
Page 53
SBC which is SuBtract with Carry. This subtracts one from the result if the carry flag
is set, which is necessary for multiple precision math. In this case, we do not want
the carry bit set, so we make sure it is gone by blasting it with XOR.
00590 LD A,H ;we must be sure we are >= 3C00
00600 CP 03CH ;if H < 0 then proceed
00610 JR NC,COMP ;use same code to check negative shell
00620 NEXT PUSH IX ;restore HL to current element
00630 POP HL
00640 INC HL ;point to next shell
00650 BIT 6,H ;test for > 4000H
00660 JR Z,SORT1 ;if not go again
00670 DIVIDE SRL B ;divide BC offset by 2
00680 RR C
The SRL instruction (Shift Right Logical) takes all eight bits of a register and bumps
every one one space to the right. A zero is loaded into bit 7 and if there was a 1 at
bit zero the carry flag is set. In this case, the instruction is used to divide the BC
off set by two. The RR C instruction rotates all eight bits of register C to the right,
and will store any carry from the previous SRL B instruction into bit seven of C. Any
carry from C would be a fraction and we don't care about it. The effect is C = INT(C/2).
00690 NOCR LD A,B ;if BC = 0 we are done
00700 OR C
00710 LD HL,VIDEO
00720 JR NZ,SORT1 ;go back if BC <> 0
00730 CALL @KEY ;wait for keystroke
00740 JP 0402DH ;return to LDOS
00750 END START
Well that almost wraps it up. But wait, there's more. Announcing the first LET US
ASSEMBLE CONTEST. Below is a TBA source for a Ripple Sort. Write the assembler version
which works on the screen and answer part one described above. Submit both your answer
to part one and the code for the ripple sort by September 1, 1983 to LSI attn: Ripple
contest. All CORRECT replies will be placed in a hat and three winners will be drawn at
random. Each of the winners will receive A FREE YEAR of extended support.
No purchase is necessary to enter (or is probably possible). All entrants must be alive
at the time the code is written. Employees of cesspool cleaning firms are eiigible but
must wash your hands before handling the envelope.
Ripple Sort TBA listing :
=FLAG%,LOOP%,TEMP%,LOOPl%
CLS
FOR LOOP%=15360 TO 15872
POKE LOOP%, RND(95)+32
NEXT LOOP%
FOR LOOP%=15360 TO 15871
FOR LOOP1%= LOOP%+1 TO 15872
IF PEEK(LOOP%)<=PEEK(LOOP1%) THEN @SKIP.IT
TEMP%=PEEK(LOOP1%)
POKE LOOP1%,PEEK(LOOP%)
POKE LOOP%,TEMP%
@SKIP.IT
NEXT LOOP1%,LOOP%
@LOOP: GOTO @LOOP
Page 54
LDOS: HOW IT WORKS - Non-Radio Shack disk drives
Creating system disks, booting double-sided discussed
or--- How to make a directory sandwich.
by Joseph J. Kyle-DiPietropaolo
This quarter's topic is one of constant demand, mainly due to the proliferation of non -
standard hardware out there. Those of you with 80 track, or double-sided (DS) disk
drives wil1 find this in formation of tremendous interest. Anyone with "normal"
hardware out there? You should come along for the ride anyway. There wi11 be some
important information given that isn't available anywhere else.
First of all, anyone who doesn't have at least one forty track disk drive will be wacked
over the knuckles with this ruler I borrowed from Rich. Forty track is THE standard for
distribution, and not having a forty track drive will cause you no end of headaches
right up until the day you break down and buy one. For those unfortunate souls that
don't own a forty track drive, LSI can provide most of its products on eighty track
single-sided media for a modest additional charge. Also, on the LSI Utility Disk #1,
there is a program that will allow READING of a forty track disk on a eighty track
drive, within certain limits.
The first step in the use of double-sided disk drives is to get them communicating with
your computer/interface and LDOS. A good discussion of the hardware requirements is in
the LDOS Quarterly, Vol. 1 Number 2 (which has been reprinted in The Anthology, Volume
One). As a quick summary, the drive should be configured as a single physical drive,
with side select on pin 32. A continuous cable should be used, with each drive
programmed to its proper drive select. If you have any questions, contact your drive
vendor to get the information for your particular drive.
Now, to the heart of the matter. How do we create a optimized system disk in a 80 track
or double-sided configuration?
Step 1) Get a hardcopy directory of your system disk with all files and allocation
information (use the a,s,i,p parameters).
Step 2) Format a clean, new diskette with the appropriate density, number of sides, and
tracks. Now, consult this chart to determine the number of sectors per cylinder, and
granules per cylinder for your diskette.
Size Density Sides Sectors Granules Size Density Sides Sectors Granules
5" sgl 1 10 2 8" sgl 1 16 2
5" dbl 1 18 3 8" dbl 1 30 3
5" sgl 2 20 4 8" sgl 2 32 4
5" dbl 2 36 6 8" dbl 2 60 6
Now, we need to calculate how many full cylinders will be needed to hold SYS0 and SYS6.
To use the MAX-80 as an example, on that machine SYS0 requires 81 sectors. On a 5" Dden
2-sided disk, that would be 14 granules. SYS6 requires 53 sectors, or 9 granules.
Together that would be 25 granules, or almost five cylinders.
Step 3) Use the patch from the last Quarterly (to SYS8, by the way) to determine where
files will be allocated on the disk. For convenience, I have reprinted the patch at the
end of this article. We want to put SYS0 and SYS6 immediately below the directory, so
we patch SYS8 to place them there for us. In our example, we would patch SYS8 to start
allocation at cylinder 15, allowing five full cylinders. Now, backup SYS0 from your
system disk to your new diskette. A typical command would be:
backup sys0:0 :1 (s)
By following this procedure, SYS0 will be stored in one extent, starting at the
beginning of a cylinder, and starting on the 'front' of the diskette. This will ensure
that the resulting diskette will boot on your system, if your system will handle the
Page 55
density involved. Model I users with SOLE, use the diskette processed by SOLE1 starting
with Step 2, create the sysgen file after Step 7, and SOLE2 after Step 8.
Step 4) Now backup SYS6 to the new diskette. It will be placed immediately below the
directory. The remainder of the system files other than SYS7 will require 10 granules
Calculate how many cylinders will be necessary to hold these files, and patch SYS8 to
start allocating that far above the directory. For our example, that would be two
cylinders, and we would tell SYS8 to start allocating at cylinder 23 (17 hex), leaving
21 and 22 free for the other system files. You can also check the free space map of the
diskette, and see if there are any free granules immediately below the directory left
over after SYS6. If so, these can be used for the other system files, and can be
subtracted from the ten needed. Now, backup SYS7.
Step 5) We now have SYS7 above the directory, with enough blank space in-between to hold
all of the other system files. At this point, we're most of the way home. Re-patch
SYS8 with the cylinder number from Step 3, and backup the remainder of the system files.
A typical command would be:
backup /sys:0 :1 (new,s)
Step 6) Now backup everything else from your system disk. Use a command like:
backup :0 :1 (new)
Model I users will then want to transfer control to their new system disk (see the
'system (system=' command), and backup the files from their LDOSXTRA disk to their new
system disk.
Step 7) Re-patch SYS8 back to normal, or to the desired allocation on both your old and
new system disks.
That's it! Now, that wasn't so painful, was it?
For your convenience, here is the SYS8 patch information reprinted from the last
Quarterly:
. Optional patch to SYS8/SYS
. This patch allows for arbitrary allocation, as opposed to random
. The patch is the same for Model I, Model 3, and MAX-80, for LDOS 5.1.3 ONLY
.
D00,FE=2E 01 00 00 00 00
. This (the 01) is the cylinder number (hex) that allocation will start at
.
. To reverse the patch, the original code in SYS8 was:
. D00,FE=D5 CD 4E 44 D1 6C
.
. end of patch
As an example, here's the format of a patch to start allocation at cylinder 15:
PATCH SYS8/SYS.SYSTEM (D00,FE=2E 0F 00 00 00 00)
LES INFORMATION
by Les Mikesell
The differences between device and file access under the 5.1 version of LDOS have been
discussed in earlier issues. The status in the Z flag is different for requests through
@GET. A character will be input from a file with the Z flag set if there are no errors,
Page 56
while @GET returns with an NZ condition if the request goes to a device driver. If the
ROM keyboard driver is used instead of the LDOS KI/DVR, the status flag is unspecified,
and it is necessary to test for a non-null character.
Under LDOS 6.0 (alias TRSDOS 6.0) the status conditions returned by @GET and @PUT
requests are handled identically for files and devices. This simplifies the task of
dealing with I/O devices which may be ROUTED to files by the operating system, and
allows programs to use the same routines with either devices or files if a choice is
given at run-time. The routines using these functions should be written to handle the
error conditions that might be returned by either a device or file access.
For @PUT, the Z flag will be set after a successful completion. If the function returns
with NZ status, the error number will be in the A register. Possible errors from a @PUT
request might include "device not available" from a timeout on the printer ready test,
or any of the file access errors. If it is possible to recover from an output error, a
program should take the appropriate steps when the error is detected.
The status for @GET is similar: returning with the Z flag set indicates a successful
input, and the input character will be in the A register. If the Z flag is reset, the
value in the A register indicates the type of error. However, a very likely possibility
is that the error number will be 0, indicating "no error". This simply means that the
device did not have a character available to return at the time of the input request.
Thus, the indication is that since the Z flag is reset, the input request was not
successful, but there was actually no error involved. A program would normally loop
repeating the @GET request until a character is received, if the input is necessary
before further processing.
Examples of @GET and @PUT for 6.0
First a file or device must be OPENed using the defined FCB
FCB DS 32
.. then to output a character...
LD DE,FCB ;point to OPEN FCB
LD C,CHAR ;put character in C
LD A,4 ;@PUT SVC number
RST 40 ;do it
JP NZ,ERROR ;process error (or quit)
..continue..
.. to input a character...
LD DE,FCB
LOOP: LD A,3 ;@GET SVC number
RST 40 ;do it
JR Z,GOTCHR ;continue if char rcvld
OR A ;otherwise test for error
JR Z,LOOP ;wait for some input
CP 1CH ;End of file error?
JP Z,EOF ;to completion handler..
.. could test for other specific errors here..
.. depending on the program..
JP ERROR ;to fatal error exit..
GOTCHR .... normal continuation of program
-------------------------------------------------
One built-in function that is available on many other systems but not the TRS80's is a
simple method of temporarily linking the video output to the printer. The lack of this
function may stern from the incompatibility between the TRS80 video and printer control
codes. The following filters will provide this ability for both 5.1 and 6.0 versions.
The program actually filters both the *KI and *DO devices, using the presence of a
control-P (shift-down arrow P on the Model 1 & 3) detected during a keyboard input to
toggle the link between the video and printer on and off. When the toggle is on, each
Page 57
character sent to the video is also sent to the printer, except for those values that
are likely to cause strange effects. The SYSTEM (GRAPHIC)-bit is tested to determine if
the characters above X'7F' should be sent or converted to a period, as in the screen-
print function. A typical use of the function would be to obtain a listing of the
output from a program that normally displays only on the video. Just before pressing
on the command that invokes the listing, enter the control-P character. Enter
the control-P again to terminate the listing any time the system is requesting keyboard
input.
After assembling the program with the name CTLP/FLT, the 5.1 version of the filter would
be installed with the command: FILTER *KI CTLP
The 6.0 version requires two steps to install, since filters take their own device name
and DCB:
SET *CP CTLP
FILTER *KI CTLP
The 6.0 version filters the video by modifying the driver address in the DCB, like the
5.1 version instead of creating an additional DCB for the video portion of the filter
also. This method requires that no other filtering, routing, or linking be done to the
*DO device before loading CTLP/FLT.
The assembly language listings follow, starting on Page 59.
THE JCL CORNER - By Chuck
There will be no JCL Corner this issue, as the JCL Corner is currently undergoing a
change in format. Because all the basics for JCL have been covered, in the future, it
will be going to a question and answer format. Question and answer columns covering
advanced subjects will alternate with reprints of earlier introductory information.
Because of the late mailing of the last Quarterly, the winners of the JCL Corner
question competition will not be announced until the next Quarterly.
So, until next time......
//EXIT
Page 58
00100 ;Filter for LDOS 5.1.x to allow toggling a link 00530 JP NZ,ISNIL ;Go if so
00110 ; *DO *PR by typing CTL-P any time the 00540 BIT 4,A ;Routed?
00120 ; keyboard driver is called 00550 JP NZ,ROUTED ;Go if so (error)
00130 ; 00560 AND 1 ;dvr handle input?
00140 TGLCHR EQU 'P'-40H ;ctl-P 00570 CP 1
00150 ; 00580 JP NZ,DEVERR ;Go if not
00160 ; Hardware dependant EQUates.. Mod 1 addresses used 00590 POP HL ;rest buff pointer
00170 HIGH3 EQU 4411H 00600 LD DE,PRMTBL ;Scan parameters
00180 PARAM3 EQU 4454H 00610 CALL @PARAM
00190 HIGH$ EQU 4049H 00620 MMOD4 EQU $-2
00200 @PARAM EQU 4476H 00630 JP NZ,PRMERR ;quit if error
00210 @LOGOT EQU 447BH 00640 ;test parameter value and initialize filter
00220 LOGOT3 EQU 428AH 00650 LD BC,$-$ ;value set by @PARAM
00230 KIJCL$L EQU 43BEH 00660 CHARP EQU $-2 ;<=here
00240 KIJCL$3 EQU 42BEH 00670 LD A,C
00250 SFLAG$L EQU 430FH 00680 OR A ;set flag
00260 SFLAG$3 EQU 442BH 00690 JR Z,GETDVR ;go if not specified
00270 DFLAG$L EQU 441FH 00700 LD (TGL),A ;stuff byte if wanted
00280 DFLAG$3 EQU 4289H 00710 ;allow installation to *KI in JCL
00290 ; 00720 GETDVR PUSH IX ;If the DCB is for *KI,
00300 ; General EQUates... 00730 POP DE ; then use KIJCL saved
00310 KDCB$ EQU 4015H 00740 LD HL,KDCB$ ; vector for hooks
00320 DODCB$ EQU 401DH 00750 XOR A ;clear carry
00330 @EXIT EQU 402DH 00760 SBC HL,DE ;Zero if *KI
00340 @ABORT EQU 4030H 00770 LD L,(IX+l) ;P/u DCB vector address
00350 @DSPLY EQU 4467H 00780 LD H,(IX+2)
00360 @PRT EQU 3BH 00790 JR NZ,SETADD ;use if not *KI
00370 LF EQU l0 ;linefeed character 00800 LD A,(SFLAG$l) ;Is DO in effect?
00380 CR EQU 13 ;carriage return 00810 SFLAG EQU $-2
00390 ; 00820 AND 20H
00400 ; LDOS 'FILTER' command handler 00830 JR Z,SETADD ;Not KIJCL if no DO
00410 ; 00840 LD HL,(KIJCL$l) ;P/u JCL saved vector
00420 ORG 5200H 00850 KJCL EQU $-2
00430 LNTRY PUSH DE ;put DCB pointer 00860 LD (WASKI+l),A ;Note for later
00440 POP IX ;into IX register 00870 ; put previous driver addresses into filter
00450 PUSH HL ;save buff pointer 00880 SETADD LD (DVRADD),HL ;put in filter
00460 CALL MODEL 00890 LD (DVRl),HL
00470 LD A,(DE) ;Get DCB type byte 00900 LD HL,(DODCB$+l) ;get *DO dvr addr
00480 PUSH AF 00910 LD (DODVR),HL ;put in filter
00490 LD HL,SIGNON ;=>Signon message 00920 ; find available high memory
00500 CALL @DSPLY ;print it 00930 LD HL,(HIGH$) ;find top of memory
00510 POP AF ;restore type byte 00940 MMOD1 EQU $-2
00520 BIT 3,A ;Device routed NIL? 00950 LD (OLDMEM),HL ;save in flt header
00960 PUSH HL ;save 01390 ISNIL LD HL,ISNIL$
00970 ; relocate JP and CALL addresses 01400 JR ERROUT
00980 LD DE,LAST ;end of code now.. 01410 DEVERR LD HL,DEVER$
00990 OR A ;clr carry 01420 JR ERROUT
01000 SBC HL,DE ;offset of move 01430 ROUTED LD HL,ROUTD$
01010 EX DE,HL ;into DE 01440 JR ERROUT
01020 LD HL,(REL1) ;fix absolute memory 01450 PRMERR LD HL,PRMER$ ;'Parameter error'
01030 ADD HL,DE ;references 01460 ERROUT CALL @LOGOT ;Display and log
01040 LD (REL1),HL ;in filter 01470 MMOD3 EQU $-2
01050 LD HL,(REL2) 01480 JP @ABORT ;Quit
01060 ADD HL,DE 01490 ;*=*=*
01070 LD (REL2),HL 01500 MODEL LD A,(125H)
01080 LD HL,(REL3) 01510 CP 'I'
01090 ADD HL,DE 01520 RET NZ
01100 LD (REL3),HL 01530 LD HL,HIGH3
01110 ; move into high memory 01540 LD (MMOD1),HL
01120 LD HL,LAST ;end of relocated code 01550 LD (MMOD2),HL
01130 POP DE ;old HIGH$ 01560 LD HL,LOGOT3
01140 LD BC,LAST-FENTRY+l ;len of rel code 01570 LD (MM003),HL
01150 LDDR ;move it 01580 LD HL,PARAM3
01160 EX DE,HL 01590 LD (MMOD4),HL
01170 LD (HIGH$),HL ;set new HIGH$ 01600 LD HL,KIJCL$3
01180 MMOD2 EQU $-2 01610 LD (KJCL),HL
01190 INC HL ;pnt to flt entry 01620 LD (KJCL2),HL
01200 ; install new addresses in DCBs 01630 LD HL,SFLAG$3
01210 DI ;Off while DCB update 01640 LD (SFLAG),HL
01220 WASKI LD A,0 ;If DCB was for KI & 01650 LD HL,(DFLAG$3)
01230 OR A ; DO was in effect, 01660 LD (DFLAG),HL
01240 JR Z,WASKIL ; then update KIJCL 01670 RET
01250 LD (KIJCL$l),HL 01680 ;*=*=*
01260 KJCL2 EQU $-2 01690 ; Data area
01270 JR WASKI2 01700 ;*=*=*
01280 WASKI1 LD (IX+l),L ;set new addr in DCB 01710 SIGNON DB 'CTLP/FLT - LDOS printer control filter'
01290 LD (IX+2),H 01720 DB LF,CR
01300 LD DE,DOEPT-FENTRY ;offset to DO filter 01730 PRMER$ DB 'Parameter error!',CR
01310 ADD HL,DE ;calc new address 01740 ISNIL$ DB 'Device not active!',CR
01320 LD (DODCB$+l),HL ;for video DCB 01750 DEVER$ DB 'Incorrect device type!',CR
01330 WASKI2 EI 01760 ROUTD$ DB 'Device is routed!',CR
01340 ;*=*=* 01770 ;
01350 EXIT JP @EXIT ;Done 01780 PRMTBL DB 'CHAR '
01360 ;*=*=* 01790 DW CHARP
01370 ; Error handling 01800 DB 'C '
01380 ;*--*=* 01810 DW CHARP
01820 DW 0 ;end of list 02250 REL2 EQU $-2 ;relocate address
01830 ; 02260 OR A
01840 ;*=*=* 02270 JR Z,DOPUT ;go if toggle OFF
01850 ; Actual filter moved to high memory 02280 ;send to both *DO and *PR
01860 ; LDOS style header... 02290 ;but test first for video control codes...
01870 ;*=*=* 02300 ;that may do strange things to a printer...
01880 FENTRY JR START ;Branch over linkage 02310 LD A,C ;check char..
01890 DW $-$ ;Last byte used 02320 CP 20H ;for ctl range
01900 OLDMEM EQU $-2 ;prev HIGH$ value 02330 JR NC,DUAL ;go if printable
01910 ; 02340 CP 0DH+1 ;allow CR/LF/FF/BKSP
01920 DB 4,'CTLP' 02350 JR NC,DOOUT ;avoid 0EH -19H
01930 TOGGLE DB 0 ;on/off switch 02360 DUAL PUSH BC ;save char in C
01940 ; 02370 CALL DOOUT ;CALL video output
01950 ; actual filter routine 02380 REL3 EQU $-2
01960 START JP NC,$-$ ;go if not input request 02390 POP BC ;restore character
01970 DVRL EQU $-2 ;old driver address 02400 PUSH BC ;save again
01980 CALL $-$ ;otherwise ca]] old driver 02410 LD A,LF ;is character..
01990 DVRADD EQU $-2 ;stuff dvr addr here also 02420 CP C ;a line-feed?
02000 ; 02430 LD A,CR ;make carriage ret
02010 PUSH AF ;save char/status 02440 JR Z,PRCHAR ;if so.
02020 CP TGLCHR ;is it a toggle? 02450 BIT 7,C ;GRAPHIC char?
02030 TGL EQU $-1 02460 JR Z,NOTGRP ;go if not
02040 JR NZ,DONE ;go if not 02470 LD A,(DFLAG$l) ;graphics ok?
020S0 LD HL,TOGGLE ;get current state 02480 DFLAG EQU $-2
02060 REL1 EQU $-2 02490 RLCA ;quick bit 7 test
02070 LD A,(HL) 02500 LD A,'.' ;change to a period
02080 CPL ;reverse it 02510 JR NC,PRCHAR ;if GRAPHIC off
02090 LD (HL),A ;and save 02520 NOTGRP LD A,C ;get character in A
02100 POP AF ;dump toggle from 02530 PRCHAR CALL @PRT ;send to current *PR
02110 XOR A ;input stream 02540 POP BC ;then rest original
02120 RET 02550 LD A,C ;char in case calling
02130 ; 02560 CP A ;program needs it
02140 DONE POP AF ;restore char/status 02570 RET
02150 RET ;and return it 02580 ;
02160 ; 02590 LAST EQU $-1 ;used for length calculation
02170 ;This code is actually a filter for *DO 02600 ;
02180 DOEPT JR Z,ISOUT ;only affect output 02610 END ENTRY
02190 DOPUT JP $-$ ;previous *DO driver
02200 DODVR EQU $-2
02210 DOOUT XOR A ;Set Z for output
02220 JR DOPUT ;go to driver 00100 ;Filter for LDOS 6.x to allow toggling a link
02230 ;test if link wanted.. 00110 ; *DO *PR by typing CTL-P any time the
02240 ISOUT LD A,(TOGGLE) ;*PR active now? 00120 ; keyboard driver is called
00130 ; 00560 LD DE,PRMTBL ;Scan parameters
00140 TGLCHR EQU 'P'-40H ;ctl-P 00570 LD A,@PARAM
00150 ; 00580 RST 40
00160 ; SVC number equates 00590 JP NZ,PRMERR ;quit if error
00170 @HIGH$ EQU 100 00600 ;test parameter value and initialize filter
00180 @PARAM EQU 17 00610 LD BC,$-$ ;val set by @PARAM
00190 @LOGOT EQU 12 00620 CHARP EQU $-2 ;<=here
00200 @DSPLY EQU 10 00630 LD A,C
00210 @PRT EQU 6 00640 OR A ;set flag
00220 @CHNIO EQU 20 00650 JR Z,CHKDVR ;go if not specified
00230 @FLAGS EQU 101 00660 LD (TGL),A ;stuff byte if wanted
00240 @GTMOD EQU 83 00670 ; see if filter is already installed
00250 @GTDCB EQU 82 00680 CHKDVR LD DE,FLTNAM ;=>CTLP
00260 ;flag table offset values 00690 LD A,@GTMOD ;lk up module header
00270 DFLAG$ EQU 3 00700 RST 40
00280 ; 00710 JP Z,ISRES ;already loaded
00290 ; General EQUates... 00720 ; check if memory available
00300 LF EQU 10 ;linefeed character 00730 BIT 0,(IY+2) ;HIGH$ frozen?
00310 CR EQU 13 ;carriage return 00740 JP NZ,NOROOM ;quit if so
00320 ; 00750 ; hook into video driver directly but first check
00330 ; LDOS 'FILTER' command handler for 6.0 00760 ; that it is not linked or routed or filtered
00340 ; The filter is first installed with the 'SET' 00770 GETDVR LD E,'D'
00350 ; command and takes its own DCB 00780 LD D,'O' ;DO name to DE
00360 ; Then it is connected to the desired device with 00790 LD A,@GTDCB ;find the DCB
00370 ; the 'FILTER' command 00800 RST 40
00380 ; 00810 JP NZ,DOERR ;error if not found
00390 ORG 3000H 00820 LD A,(HL) ;check TYPE byte
00400 ENTRY PUSH DE ;put DCB pointer 00830 AND 01110000B ;filter/route/link??
00410 POP IX ;into IX register 00840 JP NZ,CANT ;all illegal
00420 PUSH HL ;save buff pointer 00850 INC HL ;=>driver LSB
00430 LD HL,SIGNON ;=>Signon message 00860 LD (DODCB),HL ;save addr of DCB+L
00440 LD A,@DSPLY 00870 LD E,(HL) ;get *DO driver
00450 RST 40 ;print it 00880 INC HL ;address
00460 LD A,@FLAGS ;pnt IY to flg table 00890 LD D,(HL) ;in DE
00470 RST 40 00900 LD (DODVR),DE ;put into filter
00480 PUSH IY 01000 ;
00490 POP HL ;base address to HL 00920 ; find available high memory
00500 LD DE,OFLAG$ ;ofst to DFLAG$ addr 00930 LD A,@HIGH$ ;get HIGH$ into HL
00510 ADD HL,DE ;point there 00940 LD HL,0
00520 LD (DFLAG),HL ;put addr in filter 00950 LD B,L ;B=0
00530 POP HL ;=>command line 00960 RST 40 ;get top of memory
00540 BIT 3,(IY+2) ;System request? 00970 LD (OLDMEM),HL ;save in flt header
00550 JP Z,NOTSET ;must inst] w/SET 00980 PUSH HL ;save HIGH$
00990 LD (DCBADD),IX ;put DCB addr in hdr 01420 ;*=*=*
01000 ; relocate JP, CALL and LD addresses in filter 01430 LD HL,0 ;indicate no error
01010 LD DE,LAST ;end of code now.. 01440 RET
01020 OR A ;clear carry flag 01450 ;*=*=*
01030 SBC HL,DE ;offset of move 01460 ; Error handling
01040 EX DE,HL ;into DE 01470 ;*=*=*
01050 LD HL,(REL1) ;fix absolute memory 01480 NOROOM LD HL,NOROOM$
01060 ADD HL,DE ;references 01490 JR ERROUT
01070 LD (REL1),HL ;in filter 01500 ISRES LD HL,ISRES$
01080 LD HL,(REL2) 01510 JR ERROUT
01090 ADD HL,DE 01520 NOTSET LD HL,NTSET$
01100 LD (REL2),HL 01530 JR ERROUT
01110 LD HL,(REL3) 01540 DOERR LD HL,DOERR$
01120 ADD HL,DE 01550 JR ERROUT
01130 LD (REL3),HL 01560 CANT LD HL,CANT$
01140 LD HL,(REL4) 01570 JR ERROUT
01150 ADD HL,DE 01580 PRMERR LD HL,PRMER$ ;'Parameter error'
01160 LD (REL4),HL 01590 ERROUT LD A,@LOGOT ;Display and log
01170 ; move into high memory 01600 RST 40
01180 LD HL,LAST ;end of rel code 01610 LD HL,0FFFFH ;indicate error
01190 POP DE ;old HIGH$=destination 01620 RET
01200 LD BC,LAST-FENTRY+l ;len of rel code 01630 ;*=*=*
01210 LDDR ;move it, leaving DE.. 01640 ;*=*=*
01220 EX DE,HL ;=>new HIGH$ 01650 ; Data area
01230 PUSH HL 01660 ;*=*=*
01240 LD A,@HIGH$ ;set new HIGH$ 01670 DODCB DW 0 ;store DCB ptr
01250 RST 40 ;note: B=0 01680 SIGNON DB 'CTLP/FLT - LDOS printer control filter'
01260 POP HL 01690 DB LF,CR
01270 INC HL ;pnt to flt entry 01700 PRMER$ DB 'Parameter error!',CR
01280 ; set up new in DCB 01710 DOERR$ DB 'Cannot find *DO DCB',CR
01290 LD (IX+0),01000111B ;filter/getputct] 01720 NTSET$ DB 'Must install with SET command',CR
01300 LD (IX+l),L ;set new addr in DCB 01730 CANT$ DB 'Display device is routed, linked,'
01310 LD (IX+2),H ;for new Device/flt 01740 DB ' or filtered.',CR
01320 ; hook into video driver 01750 ISRES$ DB 'Filter already resident',CR
01330 LD DE,DOEPT-FENTRY ;offset to DO filter 01760 NOROOM$ DB 'No memory available',CR
01340 ADD HL,DE ;calc new address 01770 ;
01350 EX DE,HL ;move to DE 01780 PRMTBL DB 'CHAR '
01360 DI 01790 DW CHARP
01370 LD HL,(DODCB) ;=>*DO DCB+L 01800 DB 'C '
01380 LD (HL),E 01810 DW CHARP
01390 INC HL 01820 DW 0 ;end of list
01400 LD (HL),D ;repl driver address 01830 ;
01410 EI 01840 FLTNAM DB 'CTLP',3 ;name terminated for @GTMOD
01850 ;*=*=* 02280 CP A
01860 ; Actual filter moved to high memory 02290 JR DOPUT ;go to driver
01870 ; LDOS style header... 02300 ;test if link wanted..
01880 ;*=*=* 02310 ISOUT LD A,(TOGGLE) ;*PR active now?
01890 FENTRY JR START ;Branch around linkage 02320 REL2 EQU $-2 ;relocate address
01990 DW $-$ ;Last byte used 02330 OR A
01910 OLDMEM EQU $-2 ;prev HIGH$ value 02340 JR Z,DOOUT ;go if toggle OFF
01920 ; 02350 ;send to both *DO and *PR
01930 DB 4,'CTLP' 02360 ;but test first for video control codes...
01940 DCBADD DW $-$ ;DCB using filter 02370 ;that may do strange things to a printer...
019S0 SPARE DW 0 02380 LD A,C ;check char..
01960 TOGGLE DB 0 ;on/off switch 02390 CP 20H ;for ctl range
01970 ; 02400 JR NC,DUAL ;go if printable
01980 ; actual filter routine (looks for toggle) 02410 CP 0DH+1 ;allow CR/LF/FF/BKSP
01990 START LD IX,(DCBADD) ;get DCB addr to IX 02420 JR NC,DOOUT ;avoid 0EH -19H
02000 REL4 EQU $-2 ;relocate address 02430 DUAL PUSH BC ;save char in C
02010 LD A,@CHNIO ;cont down dev chain 02440 CALL DOOUT ;CALL video output
02020 JP NC,40 ;dn't come back here 02450 REL3 EQU $-2 ;relocated address
02030 RST 40 ;unless input req 02460 POP BC ;restore character
02040 RET NZ ;back if no char 02470 PUSH BC ;save again
02050 ;check input character for toggle value 02480 LD A,LF ;is character..
02060 PUSH AF ;save char/status 02490 CP C ;a line-feed?
02070 CP TGLCHR ;is it a toggle? 02500 LD A,CR ;make carriage ret
02080 TGL EQU $-1 02510 JR Z,PRCHAR ;if so.
02090 JR NZ,DONE ;go if not 02520 BIT 7,C ;GRAPHIC char?
02100 LD HL,TOGGLE ;=> switch byte 02530 JR Z,NOTGRP ;go if not
02110 REL1 EQU $-2 02540 LD A,($-$) ;graphics ok?
02120 LD A,(HL) ;pick it up 02550 DFLAG EQU $-2 ;fnd from flg tbl indx
02130 CPL ;reverse it 02560 RLCA ;quick bit 7 test
02140 LD (HL),A ;and save 02570 LD A,'.' ;change to a period
02150 POP AF ;discard toggle from 02580 JR NC,PRCHAR ;go if GRAPHIC off
02160 OR 0FFH ;input stream 02590 NOTGRP LD A,C ;get character in A
02170 LD A,0 ;by ret 0 w/NZ stat 02600 PRCHAR LD C,A ;send to current *PR
02180 RET 02610 LD A,@PRT
02190 02620 RST 40 ;out to PR
02200 DONE POP AF ;restore char/status 02630 POP BC ;then rest original
02210 RET ;and return it 02640 LD A,C ;char if calling
02220 ; 02650 RET
02230 ;This code is actually a filter for *DO 02660 ;
02240 DOEPT JR Z,ISOUT ;only affect output 02670 LAST EQU $-1 ;used for length calculation
02250 DOPUT JP $-$ ;previous *DO driver 02680 ;
02260 DODVR EQU $-2 02690 END ENTRY
02270 DOOUT LD A,C ;Set Z for output