3878 lines
168 KiB
Plaintext
3878 lines
168 KiB
Plaintext
#(@)top:
|
|
|
|
########
|
|
##################
|
|
###### ######
|
|
#####
|
|
##### #### #### ## ##### #### #### #### #### #### #####
|
|
##### ## ## #### ## ## ## ### ## #### ## ## ##
|
|
##### ######## ## ## ## ##### ## ## ## ## ##
|
|
##### ## ## ######## ## ## ## ### ## ## #### ## ##
|
|
##### #### #### #### #### ##### #### #### #### #### #### ######
|
|
##### ##
|
|
###### ###### Issue #11
|
|
################## Version 1.0
|
|
######## December 1995
|
|
|
|
-------------------------------------------------------------------------------
|
|
|
|
#(@)contents: Table of Contents
|
|
|
|
|
|
Features
|
|
6. Speed up RAMLink transfers with the Double-DMA Technique
|
|
(Reference: dbldma) by Doug Cotton and Mark Fellows
|
|
RAMLink Designer Mark Fellows and Technical Editor Doug Cotton of
|
|
CMD describe a way of using a Commodore REU to increase transfer
|
|
rates of the CMD RAMLink to one-half the speed of the REU transfer
|
|
rate.
|
|
8. The Graphics Toolbox by Stephen Judd
|
|
(Reference: toolbox)
|
|
To add another tool to our toolbox, Stephen details a new algorithm
|
|
for drawing ellipses. Some improvements to the circle routine in
|
|
a previous column that will enable it to draw perfect circles of any
|
|
radius is discussed, as well as details on using logarithms to
|
|
perform division.
|
|
10. Design and Implementation of an Advanced Text Editor by Craig Bruce
|
|
(Reference: zedace)
|
|
Peer into the internal organization and implementation of an
|
|
advanced text editor/word processor for the ACE environment.
|
|
Relevant data structure, global variables, display maintenance,
|
|
text "sloshing", and algorithms for many editing commands are
|
|
detailed.
|
|
|
|
Columns
|
|
4. Hi Tech Trickery by George Taylor
|
|
(Reference: trick)
|
|
Don't let anyone ever tell you the SID chip is only capable of 4 bit
|
|
sample playback. George Taylor explains using the digi dithering
|
|
technique to increase the SID's resolution.
|
|
12. Hacking Graphics by Rick Mosdell
|
|
(Reference: gfx)
|
|
Dig into this overview on how to set up the VIC-II to display Doodle
|
|
and KOALA format pictures. The two formats are detailed, and similar
|
|
formats are referenced.
|
|
|
|
Departments
|
|
1. The (cough,cough) Hacking Editor
|
|
(Reference: editor)
|
|
2. Input/Output
|
|
(Reference: io)
|
|
3. Newsfront
|
|
(Reference: news)
|
|
5. Hacking the Mags
|
|
(Reference: mags)
|
|
7. UseNuggets
|
|
(Reference: usenet)
|
|
9. Hack Surfing
|
|
(Reference: surf)
|
|
11. Commodore Trivia
|
|
(Reference: trivia)
|
|
13. ? DS, DS$: rem The Error Channel
|
|
(Reference: error)
|
|
14. The Next Hack
|
|
(Reference: next)
|
|
|
|
-------------------------------------------------------------------------------
|
|
|
|
#(@)legal: Commodore Hacking Legal Notice
|
|
|
|
Commodore and the respective Commodore product names are trademarks or
|
|
registered trademarks of ESCOM GmbH. Commodore hacking is in no way
|
|
affiliated with ESCOM GmbH, owners of said trademarks. Commodore Hacking is
|
|
published 4 times yearly by:
|
|
|
|
Brain Innovations Inc.
|
|
602 N. Lemen
|
|
Fenton MI 48430
|
|
|
|
The magazine is published on on-line networks free of charge, and a nominal
|
|
fee is charged for alternate mediums of transmission.
|
|
|
|
Permission is granted to re-distribute this "net-magazine" or "e-zine" in its
|
|
entirety for non-profit use. A charge of no more than US$5.00 may be
|
|
charged by redistribution parties to cover printed duplication and no more
|
|
than US$10.00 for other types of duplication to cover duplication and media
|
|
costs for this publication. If this publications is included in a for-profit
|
|
compilation, this publication must be alternately available separately or as
|
|
part of a non-profit compilation.
|
|
|
|
This publication, in regards to its specific ordering and compilations of
|
|
various elements, is copyright(c) 1995 by Brain Innovations, Incorporated,
|
|
unless otherwise noted. Each work in this publication retains any and all
|
|
copyrights pertaining to the individual work's contents. For
|
|
redistribution rights to individual works, please contact the author of said
|
|
work or Brain Innovations, Inc.
|
|
|
|
Brain Innovations, Inc. assumes no responsibility for errors or omissions in
|
|
editorial, article, or program listing content.
|
|
|
|
-------------------------------------------------------------------------------
|
|
|
|
#(@)info: Commodore Hacking Information
|
|
|
|
Commodore Hacking is published via the Internet 4 times yearly, and is
|
|
presented in both ISO-8859-1 and HTML versions. This and previous issues can
|
|
be found at the Commodore Hacking Home Page
|
|
(http://www.msen.com/~brain/chacking/), as well as via FTP
|
|
(ftp://ccnga.uwaterloo.ca/pub/cbm/hacking.mag/)
|
|
|
|
In addition, the Commodore Hacking mail server can be used to retrieve each
|
|
issue. To request a copy of an issue, please send the following electronic
|
|
mail message:
|
|
|
|
To: brain@mail.msen.com
|
|
Subject: MAILSERV
|
|
Body of Message:
|
|
|
|
help
|
|
catalog
|
|
send c=hacking11.txt
|
|
quit
|
|
|
|
To subscribe to the Commodore Hacking and receive new issues as
|
|
they are published, add the following command to you MAILSERV message
|
|
prior to the quit command:
|
|
|
|
subscribe c=hacking Firstname Lastname msglen
|
|
|
|
(msglen is largest size of file in kilobytes you can receive in an email
|
|
message. When in doubt, choose 64)
|
|
|
|
example:
|
|
|
|
subscribe c=hacking Jim Brain 100
|
|
|
|
Although no fee is charged for this magazine, donations are gladly accepted
|
|
from corporate and individual concerns. All monies will be used to defray
|
|
any administrative costs, subscribe to publications for review, and
|
|
compensate the individual authors contributing to this issue.
|
|
|
|
Any persons wishing to author articles for inclusion in Commodore Hacking are
|
|
encouraged to view the submission guidelines on the WWW
|
|
(http://www.msen.com/~brain/pub/c-hacking-submit.txt) or via the MAILSERV
|
|
server (send c-hacking-submit.txt).
|
|
|
|
============================================================================
|
|
|
|
#(@)rch: Reading C=Hacking
|
|
|
|
Starting with Issue 11 of Commodore Hacking, the new QuickFind indexing
|
|
system is utilized to aid readers of the text version in navigating the
|
|
magazine. At the top of each article or other important place in the
|
|
magazine, a word prefixed with a special string is present. (See the
|
|
title of this article for an example. Throughout the magazine, if an
|
|
article is mentioned, it will be followed by a reference string. For
|
|
example, if we mentioned this article, we would add (Reference: rch) after
|
|
the name. By using your favorite editor's search function and searching
|
|
for the string after the word "Reference:", prefixed by the magic prefix
|
|
string, will move you directly to the article of choice. To merely skip to
|
|
the next article in the magazine, search only for the magic prefix string.
|
|
|
|
Some handy indexing strings possibly not referenced anywhere are:
|
|
|
|
top top of issue
|
|
bottom bottom of issue
|
|
contents table of contents
|
|
legal legal notice
|
|
|
|
For those with access to a UNIX system, the command "what" can be
|
|
run on the issue, which will result in all the article titles being
|
|
printed.
|
|
|
|
A slightly different magic prefix string "#(A)" is used to delimit
|
|
sub-topics or main heading in articles. The text after the magic string
|
|
differs depending on article content. For the Input/Output column
|
|
(Reference: io), the text after the magic prefix will either be "c" for
|
|
comment, or "r" for response. In features and columns, a number after
|
|
the prefix indicates the ordinal of that heading or sub-topic in the
|
|
article. If a specific sub-topic is referenced elsewhere in the article,
|
|
a sub-topic reference will be indicated. A reference to "#(A)r" would
|
|
be written as "(SubRef: r)".
|
|
|
|
As time goes on, the role of this indexing system will be expanded and
|
|
changed to ease navigation of the text version, but minimize the clutter
|
|
added by these extra items.
|
|
|
|
============================================================================
|
|
|
|
#(@)editor: The Hacking Editor
|
|
by Jim Brain (brain@mail.msen.com)
|
|
|
|
Two new faces appear in this month's Commodore Hacking. One is its new editor,
|
|
while the other is its new look. I hope neither causes anyone to worry about
|
|
the content of the magazine. It's all still here. C=Hacking will continue
|
|
to provide leading edge technical information about the Commodore computers
|
|
we all know and love. The magazine will continue to cater to the Commodore
|
|
computer programmer, whether it be in the areas of sound, graphics, algorithms,
|
|
disk media access, or communications.
|
|
|
|
However, the role of the magazine continues to expand. It has been shown that
|
|
many people other than CBM programmers read the magazine, and programmers have
|
|
requested other information besides technical content be included in the
|
|
magazine. To this end, Issue 11 contains many new features, including:
|
|
|
|
o "Hacking the Mags" (Reference: mags), which will summarize the other
|
|
Commodore magazines in the market place. Not everyone can read or
|
|
subscribe to all the quality CBM publications out there, so this column
|
|
will alert readers to specific issues that may be of interest.
|
|
|
|
o "Newsfront" (Reference: news), which will bring the Commodore programmer
|
|
and user up to date on developments in the Commodore community. The
|
|
Commodore world doesn't stand still, and every programmer should be aware
|
|
of the newest technologies affecting the CBM line.
|
|
|
|
o "The Error Channel" (Reference: error), which will formalize the process
|
|
of fixing errors in earlier issues. Hopefully, this will be unnecessary
|
|
in most issues, but it will be here just in case.
|
|
|
|
o "Input/Output" (Reference: io), which will allow C=Hacking readers space
|
|
for comments and concerns. Many readers have sent me suggestions and
|
|
comments, some C=Hacking can implement, and some C=Hacking cannot.
|
|
This spot will detail which is which and why.
|
|
|
|
o Article separators. As you can see above, each article or column in the
|
|
magazine is delimited by the special key, followed by a short name
|
|
of the article. See "Reading C=Hacking" (Reference: rch) in this issue.
|
|
|
|
o Smaller size. The last issue was over 400kB in size, which generated
|
|
many complaints. There is no need to create such a long issue, when
|
|
more issues can be published. This issue should comfortably fit on
|
|
two sides of a 1541 disk, a 1571 disk, or a 1581 disk.
|
|
|
|
o Stable publication dates. Circumstances (college, job hunt), made it
|
|
hard for the previous editor to maintain a schedule, so no blame is laid,
|
|
but the magazine does need some stability. Although possibly unrealistic,
|
|
I am striving to publish C=Hacking quarterly, with the following schedule:
|
|
|
|
Publication Date Submission Deadline
|
|
March, 1996 February 10, 1996
|
|
June, 1996 May 10, 1996
|
|
September, 1996 Auguest 10, 1996
|
|
December 1996 November 10, 1996
|
|
|
|
If article submissions keep up, a switch to bi-monthly publication might
|
|
be warranted, but I won't get too far ahead.
|
|
|
|
o Fully HTML-ized version of the magazine. Issue 11 contains many
|
|
improvements designed to make the publication of an World Wide Web
|
|
readable version of the magazine easier. Look for the HTML version of
|
|
this and older issue at URL: http://www.msen.com/~brain/chacking/.
|
|
|
|
Many people have compared Commodore Hacking to the defunct _Transactor_
|
|
magazine, which is encouraging. The new format will hopefully add to the
|
|
appeal of Commodore Hacking.
|
|
|
|
Although many of you know me or of me through previous Commodore work, this
|
|
is my first editorship, so please comment on the changes I have made and what
|
|
your opinions on each are. As the magazine is for you, the reader, it is
|
|
always important to keep the reader happy.
|
|
|
|
Sadly, some things, like the WWW browser for C=Hacking, did not get done,
|
|
but there is always next time.
|
|
|
|
Enjoy YOUR magazine,
|
|
|
|
Jim Brain (brain@mail.msen.com)
|
|
editor
|
|
|
|
============================================================================
|
|
|
|
#(@)io: Input/Ouput
|
|
|
|
Obviously, Commodore Hacking depends on the comments and article submissions
|
|
from the Commodore community to flourish. Everyone sees the articles, but
|
|
let's not forget those comments. They are very helpful, and every attempt
|
|
is made to address concerns in them. Address any comments, concerns, or
|
|
suggestions to:
|
|
|
|
Commodore Hacking
|
|
602 N. Lemen
|
|
Fenton, MI 48430
|
|
brain@mail.msen.com (Internet)
|
|
|
|
#(A)c: Need Samples of Samples
|
|
|
|
From: "Clifford \"Paska\" Anderson" <andersoc@saturn.uaamath.alaska.edu>
|
|
|
|
Dear C=Hacking,
|
|
Hey. Just writing to mention something I'd like to see in C=Hacking, if
|
|
you can find someone to write about it. I am interested in knowing more
|
|
about how samples work on the 64, how to play, etc.
|
|
-----
|
|
_ _ _
|
|
Si vales, valeo
|
|
|
|
#(A)r:
|
|
Your wish is granted. Check out this issue's Hi Tech Trickery
|
|
(Reference: trick) by George Taylor for some insight into playing
|
|
samples.
|
|
|
|
#(A)c: You Index, I Index, We all Index
|
|
|
|
From: coyote@wakko.gil.net
|
|
|
|
Dear C=Hacking,
|
|
I would like to offer an idea for the Chacking mag. Every now and then
|
|
I'll come across a reference to an article in this or that Chacking Issue.
|
|
I run Zed and load that issue in (Thanks Mr Bruce) and start hunting for
|
|
the start of the article.
|
|
|
|
This process would be made a lot easier if Chacking used a method of
|
|
indexing I have seen used in several publications.
|
|
|
|
It involves the search function of most text editors. A 2/3/4 ? letter
|
|
code (with a delimiter char to prevent unintentional matches) that the
|
|
reader uses to find the beginning of the article.
|
|
|
|
(Outline of suggestion deleted)
|
|
|
|
I would like to add a personal thanks for all your efforts on behalf of
|
|
the C= community.
|
|
|
|
Al Anger
|
|
13841 SW 139 Ct.
|
|
Miami Fl. 33186
|
|
(305) 233-4689
|
|
|
|
#(A)r:
|
|
Fire up that search function in your favorite editor. Issue 11 now
|
|
contains the QuickFind indexing system that should fit your needs. See
|
|
"Reading C=Hacking" (Reference: rch) for information on how to utilize the
|
|
indexing system. We would like to add that C=Hacking appreciates your
|
|
personal thanks.
|
|
|
|
#(A)c: Are We Talking the Same Language?
|
|
From: Jack Vander White <ceejack@crl.com>
|
|
|
|
Dear C=Hacking,
|
|
Noticed something that may be a potential problem and thought I would
|
|
let you know.
|
|
|
|
Way back when hacking mag started I didn't have Internet access. the first
|
|
couple of issues were sent to me by fellows who had downloaded them and in
|
|
downloading had set their terms to translate them to PETSCII. This of
|
|
course changed the coding in the uuencoding parts of the magazine and made
|
|
them decode improperly.
|
|
|
|
Since then I have my own access and have re-downloaded them and posted
|
|
them on my BBS in the original straight ASCII so that those who download
|
|
them can uudecode the relevant parts and then translate the text for
|
|
reading.
|
|
|
|
Since different Terminal Programs are using different Translation tables
|
|
I can see all kinds of problems in this for the average user.
|
|
|
|
Any comment????
|
|
|
|
Jack VW
|
|
|
|
#(A)r:
|
|
The HTML version of Commodore Hacking utilizes the ISO-8859-1 text
|
|
encoding standard, while the text version utilizes its 7-bit subset,
|
|
commonly called ASCII. Normally, the encoding standard poses little
|
|
problem, as text uses but a nominal set of characters which can be
|
|
translated between PETSCII and ASCII. However, as you point out, the
|
|
uucode format uses more characters, which may or may not be
|
|
translated correctly. To circumvent this problem, which only occurs
|
|
in the text version, the files embedded in a Commodore Hacking issue
|
|
should be uudecoded prior to converting the file to anoy alternate
|
|
format.
|
|
|
|
============================================================================
|
|
|
|
#(@)news: Newsfront
|
|
|
|
* Although not new news, Some still may not know that Creative Micro Designs,
|
|
Inc., is currently designing the Super64CPU accelerator. This external
|
|
3" tall by 6" wide by 2" deep cartridge will allow Commodore computers
|
|
to execute programs at either 10MHz or 20MHz (actually, 9 and 18 MHz,
|
|
realistically). The unit uses the Western Design Center's 65C816S CPU,
|
|
which is object code compatible with the 6502/6510/8502. The CPU, used
|
|
in the Super Nintendo Entertainment System as well as other products, can
|
|
be switched between 6502 emulation mode and "native" mode, which allows
|
|
the following:
|
|
|
|
o access to 16 MB of RAM without bank switching.
|
|
o 64kB stack.
|
|
o 64kB zero page (now called "direct access").
|
|
o 16 bit registers.
|
|
o Support for virtual memory systems.
|
|
|
|
The unit is scheduled for production in February, 1996, and will cost
|
|
~US$149.00 for the 10MHz unit and US$199.00 for the 20MHz unit.
|
|
|
|
* The following information was relayed to the USENET newsgroup comp.sys.cbm
|
|
by Jack Vanderhite, editor and publisher of COMMODORE CEE disk magazine:
|
|
|
|
Rather than reply to all the messages asking about DIEHARD I will tell
|
|
all what has been happening over the last few days.
|
|
|
|
Brian Crosthwaite, Publisher of Diehard, contacted CMD, Loadstar, and
|
|
Commodore CEE this week with the following form letter faxed to each of
|
|
us:
|
|
-----------
|
|
|
|
Diehard, the Flyer for commodore 8bitters is planning to cease
|
|
publication and we are looking to transfer our subscription fulfillment.
|
|
Our number of outstanding subscribers is approximately 8,400 and I
|
|
would be willing to throw in the balance of the list, totaling
|
|
approximately 12,000.
|
|
|
|
Please call me at (xxx)xxx-xxxx if you are interested in acquiring these
|
|
readers and names.
|
|
|
|
Sincerely,
|
|
|
|
Brian L. Crosthwaite
|
|
Publisher
|
|
|
|
----------
|
|
|
|
Each of us did contact Brian for further details. They are bleak. The
|
|
total number of paper issues due to subscribers is approximately 64,000.
|
|
This does not count the approximately 1,200 spinner subscribers which
|
|
would make approximately 10,000 disks due.
|
|
|
|
The cost of publishing alone would amount to approximately $100,000 for
|
|
printing, layout, disks, ,mail cost, etc. Not taking into account the
|
|
cost of articles, etc.
|
|
|
|
when asked about money Brian's only comment was "There is none. It's
|
|
gone."
|
|
|
|
a further complication is that Tom Netsel told me last week that General
|
|
Media says that Brian has assumed the obligation to deliver the balance
|
|
of the Gazette subscriptions. I questioned Brian about this. Brian says
|
|
that general media faxed him the terms of transference of the
|
|
obligation and that he faxed back an acceptance of the terms. While I
|
|
have not seen the actual faxes involved it does sound like offer and
|
|
acceptance of a binding contract from here.
|
|
|
|
Obviously, all of us have rejected this offer. I have been told that
|
|
there is an issue of Diehard at the printers, probably printed.
|
|
However, the printing bill alone is over $8,000 plus the cost
|
|
of mailing. Since there is no money it sits there.
|
|
|
|
If anyone were willing to assume the total obligations they would have
|
|
to assume a liability of well over $100,000 over the next year before
|
|
any returns from renewals would even make a dent in this huge
|
|
obligation.
|
|
|
|
Please Note: I am putting this out as a public message. This is ALL I
|
|
know.
|
|
|
|
Please do not come back at me asking questions. I have nothing more I can
|
|
add to this.
|
|
|
|
Jack VW
|
|
|
|
So, if you have outstanding issues of dieHard due you, as the editor
|
|
does, the fears have been confirmed. However, for those who purchased
|
|
the dieHard "Spinner" disk, read on for the encouraging news.
|
|
|
|
* The LOADSTAR disk magazine has been recently purchased from Softdisk
|
|
Publishing by LOADSTAR principles Fender Tucker and Julie Mangham. Now
|
|
owned by J and F Publishing, a corporation founded by Mr. Tucker and Mrs.
|
|
Mangham, provide the magazine with even more flexibility Tucker
|
|
states that now LOADSTAR is "more solvent then ever before". Existing
|
|
subscribers will see no difference with this change, as Softdisk and
|
|
LOADSTAR will continue to maintain a close relationship, with Softdisk
|
|
continuing to handle subscriptions, in addition to other tasks.
|
|
|
|
In related news, J and F Publishing has agreed to fulfill the remainder
|
|
of the outstading dieHard "Spinner" subscriptions. Although
|
|
unfortunate that dieHard left its subscribers out in the cold, it
|
|
is commendable that these subscriptions will be fulfilled with
|
|
LOADSTAR issues. The agreement will provide one issue of LOADSTAR
|
|
for every two issues of the Spinner, as the Spinner was a single
|
|
disk, whereas LOADSTAR is double that. No word has been heard yet on
|
|
the fate of dieHard paper subscriptions. All 1200 Spinner
|
|
subscribers should be receiving information about the
|
|
subscription fulfillment soon.
|
|
|
|
* For those people wishing to use the Internet with their Commodore 64,
|
|
only to find out that the local Internet Service Provider (ISP) only
|
|
provides Serial Line Internet Protocol (SLIP) service with no shell
|
|
account service, help is coming. A prototype Transmissions Control
|
|
Protocol/Internet Protocol (TCP/IP) protocol stack with SLIP support has
|
|
been developed by Daniel Dallmann
|
|
(Daniel.Dallmann@studbox.rus.uni-stuttgart.de) of Germany. Available now
|
|
via the Internet (ftp://131.188.190.131:/pub/c64), the package is by no
|
|
means complete, but does include the basic TCP/IP stack, the SLIP driver,
|
|
and a rudimentary Telnet application.
|
|
|
|
* Another Commodore hardware/software supplier has announced its online
|
|
presence: Performance Peripherals Incorporated. Maker of the RAMDrive
|
|
and BB units (BBGRAM, BBRTC, and BBGRam), PPI published an online catalog
|
|
that users can retrieve via the C=Hacking WWW Site
|
|
(http://www.msen.com/~brain/pub/PPI_catalog.11.95.txt) and the
|
|
C=Hacking MAILSERV server. (send PPI_catalog.11.95.txt). In addition to
|
|
importing FLASH8 (the 8MHz accelerator cartridge from Germany), PPI
|
|
manufactures CommPort, which is a 6551 UART cartridge (ala Swiftlink)
|
|
which has the basic 6551 functionality with the addition of switch
|
|
selectable NMI or IRQ interrupt triggering and switch-selectable
|
|
$de00/$df00 addressing.
|
|
|
|
* PPI has one more trick up its sleeve. PPI will be carrying Novaterm 9.6,
|
|
the newest version of Nick Rossi's oft-used terminal program for the
|
|
C64. The blurb follows:
|
|
|
|
Novaterm 9.6 is a complete terminal emulation program on cartridge for
|
|
the C64. Novaterm has several features such as 80 column ANSI on a stock
|
|
C64, and compatibility with CommPort, RAMDrive, BBGRam, and many other
|
|
hardware devices. Just connect a BBGRam, and Novaterm can use it as a
|
|
"buffer" for storing text or as a "virtual disk" for quickly and easily
|
|
downloading files. Definately the perfect setup for Internet usage. And
|
|
since Novaterm is in cartridge form, the program loads in seconds, not
|
|
minutes. Novaterm 9.6 is the latest version programmed by NICK ROSSI.
|
|
Includes autoboot switch.
|
|
|
|
============================================================================
|
|
|
|
#(@)trick: Hi Tech Trickery: Sample Dither
|
|
by George Taylor (yurik@io.org)
|
|
|
|
#(A): Introduction
|
|
|
|
You may know of dithering in graphics. It is when a limited number of
|
|
colors are used to simulate more. This is done by randomly arranging the
|
|
pixels so they blend at a distance, creating an average of the shades.
|
|
Here, screen space is being averaged, and more shades are being produced.
|
|
In playing samples, time is being averaged, and more bits are being produced.
|
|
|
|
#(A): Dithering Sound
|
|
|
|
Let's say we do the following:
|
|
|
|
lda #8
|
|
sta $d418 This code toggles the low bit of the output.
|
|
lda #9
|
|
sta $d418
|
|
|
|
Over an average of time, this is the same as:
|
|
|
|
lda #8.5 But we can't really do this.
|
|
sta $d418
|
|
|
|
This idea can be used to easily do 5 bit sound. Basically, we take a
|
|
5 bit sample, shift right, then add 0. If bit 0 was high,
|
|
it will increment the 4 bit number. Then as this adding takes place,
|
|
toggling bit 0, it will average out to give half a bit.
|
|
|
|
#(A): Is There a Catch?
|
|
|
|
There is one drawback though. This toggling can be heard as the high
|
|
frequency square wave it resembles. You must use a high enough sample
|
|
rate so this can't be heard. Also it takes two bit toggles to create the
|
|
5th bit, so you must double the sample rate. In order to play 8.5, for
|
|
example, you must play 8 and then 9, so the 8 and 9 must take half the normal
|
|
time, or your sample will play too slow.
|
|
One other problem is that there is the possibility of overflow. In this
|
|
case you can use hard clipping on the signal. In other words, the 5 bit
|
|
sample 31 will be played at 16, so instead play 15.
|
|
|
|
This is actually called pulse width modulation. It is a good example for
|
|
illustrating sample dithering. For example, you can play TRUE 16 bit sound,
|
|
even with one bit. To do this, take the 16 bit sample, add a 12 bit random
|
|
number, then play the high 4 bits of this result. Also remember the clipping
|
|
problem as mentioned above.
|
|
|
|
@(A): How Is This Like Pulse Width Modulation?
|
|
|
|
The random number range is proportional to the 16 bit sample. If the 16 bit
|
|
number is high, then it is very likely the 0 bit (toggle bit) is high. It is
|
|
the random number which allows the toggle bit to change. So now we have 16
|
|
bit sound with 16db signal to noise ratio.
|
|
|
|
There are some more advanced technical issues to this. The kind of random
|
|
number you choose affects the results. You need a triangle density function
|
|
for perfect linearity (ie., for no distortion). This is the relationship
|
|
of random numbers in the sequence, and does not affect the probability
|
|
distribution, which should be equal. The choice of density function is a
|
|
tradeoff between added noise and linearity. I used pulse density function
|
|
in my demo, which is non-filtered random numbers, and it's ok but I can
|
|
still hear some noise pumping.
|
|
|
|
#(A): Conclusion
|
|
|
|
Enjoy the ditherdigi!
|
|
|
|
#(A)5bit: Listing One: 5 bit play routine
|
|
|
|
Memory map:
|
|
3: start page of sample
|
|
4: end page of sample
|
|
5: sample period (remmber to play twice normal speed)
|
|
fb,fc: pointer to sample
|
|
|
|
start lda 3
|
|
sta $fc
|
|
lda #0
|
|
sta $fb ; initialize sample pointer
|
|
lda #$b
|
|
sta $d011 ; blank screen for better timing
|
|
sei ; disable interrupts for better timing
|
|
play lda ($fb),y
|
|
lsr
|
|
sta $d418 ; push sample
|
|
ldx 5
|
|
d dex
|
|
bne d
|
|
pha
|
|
nop
|
|
adc #0
|
|
cmp #$10
|
|
beq s1
|
|
sta $d418
|
|
bpl s
|
|
s1 nop
|
|
nop
|
|
nop
|
|
s pla
|
|
ldx 5
|
|
d1 dex
|
|
bne d1
|
|
iny
|
|
bne play
|
|
inc fc
|
|
lda fc
|
|
cmp 4
|
|
bne play
|
|
lda #$1b
|
|
sta $d011
|
|
cli
|
|
end rts
|
|
|
|
#(A): References
|
|
|
|
Consult the proceedings of the ACM for further info on digi dithering.
|
|
|
|
============================================================================
|
|
|
|
#(@)mags: Hacking the Mags
|
|
|
|
Not everything good and/or technical comes from Commodore Hacking, which is
|
|
as it should be. (I still think we have the most, though...) Thus, let's
|
|
spotlight some good and/or technical reading from the other Commodore
|
|
publications.
|
|
|
|
If you know of a magazine that you would like to see summarized here, let
|
|
C=Hacking know about it. These summaries are only limited by Commodore
|
|
Hacking's inability to purchase subscriptions to all the Commodore
|
|
publications available. We are very grateful to those publications that send
|
|
complimentary copies of their publications for review.
|
|
|
|
#(A): COMMODORE CEE
|
|
Volume 1, Issues 1 and 2 came all packaged as one "mega-issue". This
|
|
particular double issue should be renamed the memory map issue, with
|
|
I/O and/or memory maps for the VIC, 64, 128, and PET computers.
|
|
Information on 6522 bugs and on the 6526 CIA chips that was cut from the
|
|
final compilation of the Commodore 64 Prorammer's Reference Guide is
|
|
of interest to Commodore Haking readers. Some of the information is
|
|
culled from the Internet: the 64 memory maps, the info on the 6522, and a
|
|
list of all the CSG produced IC numbers with descriptions. Of course, these
|
|
files are also available on the Internet, if you have access. Howver, for
|
|
those who don't know where to look or for those without access, the
|
|
information is welcome. Issue 3 has a PCX to GEOPaint converter, much like
|
|
_LOADSTAR_, and Issue 4 will begin a column on PAL to NTSC program
|
|
conversions. One thing we'd like to see at Commodore Hacking is a better
|
|
menu program, as the current one is somewhat hard to navigate.
|
|
|
|
#(A): Commodore World
|
|
Issue 10 just arrived at the computer room, with a snazzy front cover.
|
|
Slick paper aside, the picture of Al Anger's Tower 128 was a masterpiece.
|
|
Editor Doug Cotton spews about the hype of Windows 95, and the first ads
|
|
for the Super 64 CPU accelerator are present. If you're into hardware
|
|
mods, you can't miss page 4, which shows some other Al Anger hacked
|
|
Commodore creations. Jim Butterfield's 4 page 65XX ML reference is
|
|
useful for the newer programmers, and Doug Cotton's Assembly Line topic of
|
|
serial routines will help those disk I/O challenged in the crowd. This
|
|
issue details the high level routines, while #11 will tackle the low level
|
|
disk I/O. Maurice Randall goes over event handling in GEOS, while Al Anger
|
|
details how to disable the internal 1571D in the C128D. Gaelyne Moranec
|
|
touches on the Internet nitty-gritty of learning UNIX commands and
|
|
includes a table of UNIX-like commands found in ACE and LUnix. At the end,
|
|
though, C=Hacking's burning question is: What hangup does Doug have with
|
|
those abstract graphics sprinkled throughout the mag? There's nothing
|
|
wrong with them, but some look like those psycho-analyst inkblot test
|
|
cards.
|
|
|
|
#(A): Driven
|
|
Driven 9 contains a rundown on USENET (written by Jim Brain), which will
|
|
help those Internet "newbies". For those doing cross development, the
|
|
review of the PC<->C64/C128 networking system called 64NET by Paul Gardner-
|
|
Stephen might help some get object code from the PC to the 64/128. Eddie
|
|
Bourdon has some info on GEnie, including what Commodore support is
|
|
available.
|
|
|
|
Driven 10 presents some useful WWW addresses, while XMikeX and Pegasus
|
|
tackle the issues of apathy and pessimism in the Commodore community. Both
|
|
make for good reading, but the best (in our opinion) was the pessimism
|
|
piece. How many times have YOU been laughed out of CompUSA for mentioning
|
|
that modem or SCSI drive was for a Commodore?
|
|
|
|
#(A): LOADSTAR
|
|
Issue 138 just finished loading on the 1581 disk drive, and the disk is
|
|
packed with information. Fender Tucker goes into much detail on the
|
|
recent changes at LOADSTAR and its new Publishing company, J and F
|
|
Publishing. Of interest to programmers is the PCX to GEOPaint converter
|
|
program, written by Fender Tucker and Doreen Horne. Some details on Al
|
|
Angers machines that are shown in Commodore World are related. Jeff Jones
|
|
presents a simple program pause routine, which fiddles with the NMI
|
|
interrupt, and gives out source code as well. The Internet 101 series takes
|
|
a month off from the LOADSTAR letter in #28, but is expected back next
|
|
month. Lastly, Dave Moorman presents his fractal generator called FRACTAL
|
|
MOUNTAINS. C=Hacking couldn't get it to work, but we think it's user error.
|
|
|
|
#(A): LOADSTAR 128
|
|
In Issue 29, Fender apologizes for not paying enough attention to the 800
|
|
LOADSTAR 128 subscribers. Of interest to programmers is the program listing
|
|
pause program on the issue, but the rest is pretty light stuff, not to knock
|
|
LOADSTAR. Different audiences need different material.
|
|
|
|
#(A): Vision
|
|
|
|
In Issue 7, Rick Mosdell has an article on graphics formats, updated and
|
|
reproduced in this issue (Reference: gfx). There is some information from
|
|
USENET reproduced, and a list of FTP sites as posted to USENET is
|
|
also presented. Not much technical content in here, but C=Hacking was
|
|
impressed with the graphics, music, and stories in the mag. Besides,
|
|
everyone needs some time to enjoy the machine.
|
|
|
|
Other magazines not covered in this rundown include _The Underground_,
|
|
_Gatekeeper_, _Commodore Network_, _64'er_, _Atta Bitar_ (_8 bitter_), as well
|
|
as those C=Hacking is simply not aware of. As soon as we can snag a copy of
|
|
any of these, or get the foreign language ones in English :-), we will give
|
|
you the scoop on them.
|
|
|
|
============================================================================
|
|
|
|
#(@)dbldma: Speed up RAMLink transfers with the Double-DMA Technique
|
|
by Doug Cotton (cmd-doug@genie.com) and Mark Fellows
|
|
|
|
#(A): Introduction
|
|
|
|
When CMD designed the RAMLink, we tried to make the system as fast as possible,
|
|
but costs and complexity prohibited us from duplicating the operation of the
|
|
DMA operation found in the Commodore RAM Expansion Unit (REU), The 8726 DMA
|
|
controller found in the REU is a very complex item that allows the REU to
|
|
transfer one byte per 1 MHz CPU clock cycle (1 microsecond). On the other
|
|
hand, the RAMLink uses the 6510/8502 CPU load and store operations to transfer
|
|
memory from the RAMLink memory to main memory. For the user who uses RL-DOS
|
|
and RAMDOS, the difference is not noticeable, because although the RAMLink
|
|
transfer is slower, RAMDOS continually pages its code in and out of main
|
|
memory, effectively slowing its effective transfer speed down significantly.
|
|
|
|
But, what if the programmer isn't using RAMDOS? Then, the speed of the RAMLink
|
|
becomes an issue. The RAMLink takes about 8 cycles to perform a transfer
|
|
of a byte, while the REU does it in 1. This is significant. However, if a
|
|
user owns both a RAMLink and an REU, there is a way to boost the transfer rate
|
|
of the RAMLink via software. The method is called Double-DMA.
|
|
|
|
#(A): Double-DMA Description
|
|
|
|
Basically, the process is quite simple. Since the REU has the ability to
|
|
transfe memory at 1 byte/microsecond, you can use the REU DMA to transfer
|
|
memory from the RAMLink to main memory. To understand how we can do this,
|
|
remember that the normal RL-DOS transfer routines use the CPU to perform the
|
|
memory transfer. Well, to do that, at least some of the RAMLink RAM must be
|
|
mapped into main memory. To be exact, 256 bytes is mapped in. So, to
|
|
utilize the Double-DMA technique, the programmer simply makes the
|
|
appropriate 256 bytes of RAMLink memory to be transferred visible in the
|
|
main memory map, uses the REU to transfer that 256 bytes to the REU, and then
|
|
uses the REU to transfer the 256 bytes in the REU to its destination in the
|
|
main memory map. Thus, the Double-DMA technique will allow the RAMLink to
|
|
transfer data at rouyghly 1/2 the speed of the REU, or 3-4 times faster than
|
|
using the CPU to perform transfers.
|
|
|
|
#(A): The RAMLink memory map
|
|
|
|
To achieve this transfer speed gain, the programmer must forego RL-DOS
|
|
usage and write specialized transfer routines. To do that, we need to
|
|
discuss how the RAMLink maps itself into main memory and detail the various
|
|
RAMLink registers needed to make this feat possible:
|
|
|
|
Address Description
|
|
------- -----------
|
|
$de00 256 bytes of data (See $dfc0-$dfc3 for more information)
|
|
$df7e write to this location to activate the RAMLink hardware
|
|
$df7f write to this location to deactivate the RAMLink hardware.
|
|
$dfa0 lo byte of requested RAMCard memory page
|
|
$dfa1 hi byte of requested RAMCard memory page
|
|
$dfc0 write to this location to show RL variable RAM at $de00 (default)
|
|
$dfc1 write to this location to show RAMCard memory at $de00
|
|
$dfc2 write to this location to show the RAM Port device $de00 page at $de00
|
|
$dfc0 write to this location to show Pass-Thru Port dev. $de00 page at $de00
|
|
|
|
|
|
For all locations that have the description "write to this address...", the
|
|
program can safely write any byte to those locations, as the RAMLink hardware
|
|
simply waits for an access, not any particular byte to be written.
|
|
|
|
#(A): Order of Operations
|
|
|
|
Although the Double-DMA technique relies on use of the REU, it is beyond the
|
|
scope of this article to detail how to access the REU RAM under programmatic
|
|
control. For more information on transferring data from the Commodore 128/64
|
|
and the 17XX REU, refer to the back of a REU owner's manual.
|
|
|
|
The following steps will realize the Double-DMA method:
|
|
|
|
Notes: P = PAGE in RAMCard RAM to be transferred to/from
|
|
A = PAGE of RAM in main memory to be transferred to/from
|
|
X = single page of memory in REU used as temp RAM
|
|
|
|
|
|
1) if computer = 128, set up correct RAM bank
|
|
2) make I/O visible in main memory
|
|
3) sei
|
|
4) sta $df7e - activate RAMLink
|
|
5) lda #<P
|
|
6) sta $dfa0
|
|
7) lda #>P
|
|
8) sta $dfa1
|
|
9) sta $dfc1 - make $de00 show PAGE of RAM on RAMCard
|
|
|
|
Now, with the RAMLink hardware enabled in this way, the REU registers are
|
|
also visible, so one can do a double DMA transfer at this point. There
|
|
are two choices:
|
|
|
|
Transfer A->P:
|
|
|
|
10) set up REU for A->X transfer
|
|
11) initiate REU DMA transfer
|
|
12) set up REU for X->$de00 transfer
|
|
13) initiate REU DMA transfer
|
|
|
|
Transfer P->A
|
|
|
|
10) set up REU for X->$de00 transfer
|
|
11) initiate REU DMA transfer
|
|
12) set up REU for A->X transfer
|
|
13) initiate REU DMA transfer
|
|
|
|
Now, to go on:
|
|
|
|
14) If more byte need transferrring, A=A+1, P=P+1, goto 5
|
|
15) sta $dfc1 - restore contents of $de00
|
|
15) sta $df7f - deactivate RAMLink hardware
|
|
16) if computer = 128, restore bank
|
|
17) restore I/O visibility if needed
|
|
18) cli
|
|
|
|
#(A): Address Translation
|
|
|
|
To effectively use the Double-DMA technique, a programmer will want to
|
|
set up a DACC partition in the RAMLink for use as external RAM. The
|
|
programmer will need to determine the start address of the partition with the
|
|
RL-DOS G-P command (or its sister command, G-[shift]P) This command will
|
|
return the address of the DACC partition, or will it?
|
|
|
|
The answer is: Maybe. If a user has inserted an REU into the RAMLink RAM
|
|
port and has the Normal/Direct swittch set to Normal, RL-DOS uses REU memory
|
|
as the lowest RAM in the RAMLink memory map. However, when directly accessing
|
|
the RAMLink and bypassing RL-DOS, the REU is not mapped into the RAMLink
|
|
memory map. So, for such a condition, the code that determines the start of
|
|
the DACC partition must SUBTRACT the size of the REU from the address returned
|
|
by the G-P command. It's non-utopian, but the program need only do this once.
|
|
However, for such an REU configuration, one must take care to ensure that at
|
|
least 256 bytes of REU RAM is available and not already in use before
|
|
utilizing the Double-DMA technique.
|
|
|
|
#(A): Performance
|
|
|
|
Craig Bruce, who has implemented this technique in his ACE operating system,
|
|
provides the following performance figures for different access techniques:
|
|
|
|
Type Bandwidth Latency Notes
|
|
(bytes/sec) (~usec)
|
|
------------- --------- ------- -----
|
|
REU 1,007,641 65.8 REU in Direct mode
|
|
REU thru RL 1,007,641 77.8 REU in RAM Port in Normal mode
|
|
RAMLink 105,792 199.2 Regular RAMLink access
|
|
RL with REU 372,827 319.8 Double-DMA
|
|
Internal RAM0 120,181 44.2 Zero-page
|
|
Internal RAM1 80,283 56.3 All main memory except zero-page
|
|
|
|
So, using this technique in ACE results in a 3.7x increase in transfer speed.
|
|
For some applications, that is well worth the trouble.
|
|
|
|
#(A): Conclusion
|
|
|
|
Obviously, CMD recommends that the RL-DOS be used for most operations, but
|
|
we realize that some programmers simply need faster transfer rates. The
|
|
Double-DMA technique should provide the speed needed from the RAMLink.
|
|
Obviously, since this technique bypasses RL-DOS, code using it can
|
|
potentially corrupt RAMLink memory if errors occur or if the technique is
|
|
improperly used. When using the technique, we recommend extensive testing
|
|
using various DACC partitions and different REU configurations to ensure
|
|
proper operation.
|
|
|
|
#(A)ddcode: Double-DMA Code
|
|
|
|
Following is a set of functions that will perform transfers using Double-DMA.
|
|
They are copied from the routines used in Craig Bruce's ACE operating system,
|
|
Release 14, which incorporates the Double-DMA method. We thank Craig for
|
|
the code below:
|
|
|
|
; Name: Double-DMA memory transfer
|
|
; Author: Craig Bruce
|
|
; Date: 1995-12-4
|
|
; Description: The following routines use the Double-DMA technique to transfer
|
|
; memory to/from main RAM and the RAMLink. If no RL is present,
|
|
; normal CPU transfer methods are utilized.
|
|
;
|
|
; Variables: [mp] holds the address of RAMCard memory to transfer
|
|
; ramlinkNearPtr hold the address of main memory to transfer
|
|
; ramlinkLength is length of data to transfer
|
|
; ramlinkOpcode = $90: main memory -> RL
|
|
; = $91: RL -> main memory
|
|
|
|
reu = $df00
|
|
rlActivate = $df7e
|
|
rlDeactivate = $df7f
|
|
rlSram = $dfc0
|
|
rlPageSelect = $dfa0
|
|
rlPageActivate = $dfc1
|
|
rlPageData = $de00
|
|
|
|
ramlinkOpcode .buf 1
|
|
ramlinkLength .buf 2
|
|
ramlinkNearPtr .buf 2
|
|
ramlinkMpSave .buf 3
|
|
ramlinkZpSave .buf 2
|
|
|
|
ramlinkOp = * ;( [mp]=farPtr, ramlinkNearPtr, ramlinkLength, ramlinkOpcode )
|
|
lda mp+0
|
|
ldy mp+1
|
|
ldx mp+2
|
|
sta ramlinkMpSave+0
|
|
sty ramlinkMpSave+1
|
|
stx ramlinkMpSave+2
|
|
lda zp+0
|
|
ldy zp+1
|
|
sta ramlinkZpSave+0
|
|
sty ramlinkZpSave+1
|
|
lda ramlinkNearPtr+0
|
|
ldy ramlinkNearPtr+1
|
|
sta zp+0
|
|
sty zp+1
|
|
clc
|
|
lda mp+1
|
|
adc aceRamlinkStart+0
|
|
sta mp+1
|
|
lda mp+2
|
|
adc aceRamlinkStart+1
|
|
sta mp+2
|
|
- lda ramlinkLength+0
|
|
ora ramlinkLength+1
|
|
beq +
|
|
jsr rlTransferChunk
|
|
jmp -
|
|
+ lda ramlinkMpSave+0
|
|
ldy ramlinkMpSave+1
|
|
ldx ramlinkMpSave+2
|
|
sta mp+0
|
|
sty mp+1
|
|
stx mp+2
|
|
lda ramlinkZpSave+0
|
|
ldy ramlinkZpSave+1
|
|
sta zp+0
|
|
sty zp+1
|
|
clc
|
|
rts
|
|
|
|
rlTrSize .buf 1
|
|
|
|
rlTransferChunk = * ;( [mp]=rlmem, (zp)=nearmem, rlLength, rlOpcode )
|
|
;** figure maximum page operation
|
|
lda ramlinkLength+1
|
|
beq +
|
|
lda #0
|
|
ldx mp+0
|
|
beq rlTrDo
|
|
sec
|
|
sbc mp+0
|
|
jmp rlTrDo
|
|
+ lda mp+0
|
|
beq +
|
|
lda #0
|
|
sec
|
|
sbc mp+0
|
|
cmp ramlinkLength+0
|
|
bcc rlTrDo
|
|
+ lda ramlinkLength+0
|
|
|
|
;** do the transfer
|
|
rlTrDo = *
|
|
tay
|
|
sty rlTrSize
|
|
jsr rlPageOp
|
|
|
|
;** update the pointers and remaining length
|
|
clc
|
|
lda rlTrSize
|
|
bne +
|
|
inc mp+1
|
|
inc zp+1
|
|
dec ramlinkLength+1
|
|
rts
|
|
+ adc mp+0
|
|
sta mp+0
|
|
bcc +
|
|
inc mp+1
|
|
+ clc
|
|
lda zp+0
|
|
adc rlTrSize
|
|
sta zp+0
|
|
bcc +
|
|
inc zp+1
|
|
+ sec
|
|
lda ramlinkLength+0
|
|
sbc rlTrSize
|
|
sta ramlinkLength+0
|
|
bcs +
|
|
dec ramlinkLength+1
|
|
+ rts
|
|
|
|
rlPageOp = * ;( [mp]=rlmem, (zp)=nearmem, .Y=bytes, ramlinkOpcode )
|
|
php
|
|
sei
|
|
sta rlActivate
|
|
lda mp+1
|
|
sta rlPageSelect+0
|
|
lda mp+2
|
|
sta rlPageSelect+1
|
|
sta rlPageActivate
|
|
lda aceReuRlSpeedPage+3
|
|
bne rlPageOpReu ;xxx dependency on aceMemNull==0
|
|
rlPageOpNonReu = *
|
|
tya
|
|
clc
|
|
adc mp+0
|
|
tax
|
|
|
|
lda ramlinkOpcode
|
|
cmp #$91
|
|
bne rlPageOpWrite
|
|
dex
|
|
dey
|
|
beq +
|
|
- lda rlPageData,x
|
|
sta (zp),y
|
|
dex
|
|
dey
|
|
bne -
|
|
+ lda rlPageData,x
|
|
sta (zp),y
|
|
jmp rlPageOpContinue
|
|
|
|
rlPageOpWrite = *
|
|
dex
|
|
dey
|
|
beq +
|
|
- lda (zp),y
|
|
sta rlPageData,x
|
|
dex
|
|
dey
|
|
bne -
|
|
+ lda (zp),y
|
|
sta rlPageData,x
|
|
|
|
rlPageOpContinue = *
|
|
sta rlSram
|
|
sta rlDeactivate
|
|
plp
|
|
rts
|
|
|
|
rlPageOpReu = * ;( [mp]=rlmem, (zp)=nearmem, .Y=bytes, ramlinkOpcode )
|
|
;** ramlink hardware already switched in
|
|
ldx #1
|
|
tya
|
|
beq +
|
|
ldx #0
|
|
cmp #0 ;xx cut-off value
|
|
bcc rlPageOpNonReu
|
|
+ ldy ramlinkOpcode
|
|
cpy #$90
|
|
beq +
|
|
ldy #$90 ;rl->reu->intern
|
|
jsr rlPageOpReuRl
|
|
ldy #$91
|
|
jsr rlPageOpReuIntern
|
|
jmp ++
|
|
+ ldy #$90 ;intern->reu->rl
|
|
jsr rlPageOpReuIntern
|
|
ldy #$91
|
|
jsr rlPageOpReuRl
|
|
+ sta rlSram
|
|
sta rlDeactivate
|
|
plp
|
|
rts
|
|
|
|
rlPageOpReuIntern = * ;( .AX=bytes, .Y=op )
|
|
sta reu+7 ;len
|
|
stx reu+8
|
|
sty temp1
|
|
pha
|
|
lda zp+0
|
|
ldy zp+1
|
|
sta reu+2
|
|
sty reu+3
|
|
lda aceReuRlSpeedPage+0
|
|
ldy aceReuRlSpeedPage+1
|
|
sta reu+4
|
|
sty reu+5
|
|
lda aceReuRlSpeedPage+2
|
|
sta reu+6
|
|
.if computer-64
|
|
ldy vic+$30
|
|
lda #0
|
|
sta vic+$30
|
|
.ife
|
|
lda temp1
|
|
sta reu+1
|
|
.if computer-64
|
|
sty vic+$30
|
|
.ife
|
|
pla
|
|
rts
|
|
|
|
rlPageOpReuRl = * ;( .AX=bytes, .Y=op )
|
|
sta reu+7 ;len
|
|
stx reu+8
|
|
sty temp1
|
|
pha
|
|
lda mp+0
|
|
ldy #>rlPageData
|
|
sta reu+2
|
|
sty reu+3
|
|
lda aceReuRlSpeedPage+0
|
|
ldy aceReuRlSpeedPage+1
|
|
sta reu+4
|
|
sty reu+5
|
|
lda aceReuRlSpeedPage+2
|
|
sta reu+6
|
|
.if computer-64
|
|
ldy vic+$30
|
|
lda #0
|
|
sta vic+$30
|
|
.ife
|
|
lda temp1
|
|
sta reu+1
|
|
.if computer-64
|
|
sty vic+$30
|
|
.ife
|
|
pla
|
|
rts
|
|
|
|
============================================================================
|
|
|
|
#(@)usenet: UseNuggets
|
|
|
|
COMP.SYS.CBM: The breeding ground of programmers and users alike. Let's
|
|
see what topics are showing up this month:
|
|
|
|
#(A): We Want More Power!
|
|
CMD's announcement of the Super64 CPU accelerator got things stirred up
|
|
in the newsgroup. When it was announced that the initial product would run
|
|
on a C64 or on a C128 in 64 mode only, some angry C128 128 mode users
|
|
vented all over the place. Everything from people wondering aloud what
|
|
extra work the 128 version would require to threats of non-purchase of
|
|
the unit ensued. Then, just as the first wave of fighting subsided, the
|
|
next wave started, programmers worried about RAM transfer speed bottlenecks
|
|
questioned CMD's decision not to include a DMA device on the unit to
|
|
speed data transfers. CMD's response:
|
|
|
|
From: Doug Cotton <cmd-doug@genie.geis.com>
|
|
Newsgroups: comp.sys.cbm
|
|
Subject: Re: Power Users!
|
|
Date: 28 Nov 1995 00:59:26 GMT
|
|
Organization: Creative Micro Designs, Inc.
|
|
|
|
There were some earlier questions about how fast memory transfers
|
|
could be accomplished with the accelerator, and at least one
|
|
individual emailed me over the lack of a DMA controller. I obtained
|
|
some figures from Mark concerning this. Presently, the DMA transfers
|
|
using an REU transfers a byte in 1 microsecond. The accelerator can
|
|
achieve this same speed when transferring data from either
|
|
on-board static RAM, or from expansion memory (slower DRAM) to the
|
|
host computer RAM. Transfers internally (from static RAM to static
|
|
RAM) will take .35 microseconds per byte (350 nanoseconds).
|
|
Transfers from RAMLink RAMCard RAM (direct style) to the host
|
|
computer RAM will take about 2 microseconds per byte. The only figures
|
|
I don't have yet are for transfers between on-board static RAM
|
|
and expansion DRAM, but this will be governed by the speed of the
|
|
DRAM itself, and the number of wait-states required. It definately
|
|
will be faster than 1 byte per microsecond though. So the only
|
|
thing slower than a current DMA operation is transferring to and
|
|
from RAMLink RAMCard memory, which is still pretty impressive at
|
|
half the speed of present DMA transfers.
|
|
|
|
Given these speeds, the cost of high-speed DMA controllers ($$$$), and
|
|
a real lack of anywhere to put one on the main board, I think
|
|
going without a DMA controller is reasonable. If you really want
|
|
one, though, there's always the high-speed expansion port, and
|
|
a do-it-yourself project.
|
|
|
|
Doug Cotton
|
|
|
|
Notice the tiny "high speed expansion port" mention at the end. Reports
|
|
indicate that such a port or ports will definitely appear on the unit,
|
|
but it is still undetermined whether a single connector or a small
|
|
expansion bus will be utilized. Commodore Hacking recommends the latter,
|
|
as more options for hardware mods are available.
|
|
|
|
#(A): Let's all design the Commodore 64 Laptop!
|
|
|
|
Yes, the dreamers are at it once again. Starting in late October, the
|
|
net was abuzz with thoughts on what should be included on a Commodore
|
|
Laptop. The designs were flying fast and furious, with many different
|
|
features discussed. It was agreed that the laptop would need to be
|
|
a power sipper and have an LCD screen and a keyboard. However, that
|
|
was where agreement ended. Some of following items were bantered about:
|
|
|
|
CPU:
|
|
|
|
o "really fast" 6510
|
|
o 65C816S
|
|
|
|
Disk:
|
|
|
|
o FLASH RAM cards.
|
|
o built in hard drive
|
|
o low power 1581 or CMD FD2000/4000
|
|
|
|
RAM
|
|
|
|
o definitely more than 64kB, but disagreement as to how much more.
|
|
|
|
Video
|
|
|
|
o VIC-II compatibility with more modes.
|
|
o VIC-III as found in Commodore 65
|
|
|
|
Sound
|
|
|
|
o Built in stereo SIDs
|
|
o Quad SIDs
|
|
|
|
So, on and on it went. Some got down to the nitty gritty of planning
|
|
designs for chips. Some wanted to put the SIDs into one chip, while
|
|
others wanted a SID/VIC/CPU single chip solution.
|
|
|
|
It's December, and the thread is still going strong, but a few great
|
|
things have surfaced, which is why you can't just discount this type of
|
|
dreaming:
|
|
|
|
o Someone posted the procedure for modifying the C64 to run on
|
|
battery power.
|
|
|
|
o A few people started looking into how much money such designing would
|
|
require.
|
|
|
|
o Most people who thought disk media should be included agreed that the
|
|
CMD FD drive could/should be used.
|
|
|
|
o Everyone woke up and noticed that the NMOS CPU process used for the
|
|
fabbibng of the CBM chips was power hungry and ill-suited to battery
|
|
operation.
|
|
|
|
C=Hacking encourages users to answer the quetion: My dream Commodore
|
|
laptop computer would include.... Send you entries to Commodore
|
|
Hacking (brain@mail.msen.com) with the subject "LAPTOP". We'll print
|
|
the best entries next issue.
|
|
|
|
Everyone seems to think that CMD is going to have one in development
|
|
before long. Dunno. Commodore Hacking has heard rumors of what is going
|
|
on at CMD, but we haven't heard about the laptop project. Of course,
|
|
we're not SPECIAL or anything.... :-)
|
|
|
|
#(A): The Tower of Power
|
|
|
|
It seems Al Anger's (coyote@gil.net) Tower 128 picture on Commodore World's
|
|
Issue 10 cover got everyone excited. A couple of people were sending Al
|
|
email about it, Commodore Hacking asked some questions, and some USENETters
|
|
were deciding how to do it themselves. Al states that $2000 would just
|
|
about cover it, which turned a few enquiring minds away, we're sure.
|
|
Still, the reasons given for wanting a tower were solid. Commodore users
|
|
are getting tired of all the clutter and mess cables, power cords,
|
|
expansion extenders, Swiftlink cartridges, etc. make in the computer room.
|
|
C=Hacking notes that at least one manufacturer produces tower 64 systems,
|
|
but the cost is evidently more than what most folks are willing to fork
|
|
over (~US$300 - US$550). So, everyone is waiting for the cost to come
|
|
down....
|
|
|
|
#(A): Dave Letterman, Eat Your Heart Out!
|
|
|
|
The latest thread is the top ten list of games. Everyone is submitting
|
|
their 10 most favorite games for the CBM machines. (Is anyone compiling
|
|
these?) Anyway, it turns out this thread has a nice side effect. People
|
|
are reminiscing about the old games, and the Commodore users are noting
|
|
that the new games "just aren't as good". Here, here!
|
|
|
|
So, that wraps up the USENET this time. We try to keep an eye out for
|
|
stuff of interest, but drop us a line if you think we might miss an IMPORTANT
|
|
topic...
|
|
|
|
============================================================================
|
|
|
|
#(@)toolbox: The Graphics Toolbox: Ellipses
|
|
by Stephen L. Judd (sjudd@nwu.edu)
|
|
|
|
|
|
#(A): Introduction
|
|
|
|
After a much needed break from Commodore 64 programming, I thought it
|
|
would be nice to construct another algorithm for the 2D graphics toolbox.
|
|
Since we did circles last time, a natural successor would be an algorithm
|
|
to draw eclipses. We will first review the circle algorithm, and then build
|
|
upon it to draw eclipses. You may recall that the algorithm had problems
|
|
with small-radius circles. There is a very easy way to fix this, so we will
|
|
cover that issue as well.
|
|
|
|
#(A): Circles
|
|
|
|
Recall that the equation for a circle is
|
|
|
|
x^2 + y^2 = r^2
|
|
|
|
After taking differentials of both sides, we find that
|
|
|
|
dy = -x/y dx
|
|
|
|
That is, if we take a step of size dx in the x-direction, we in principle
|
|
want to take a step of size dy in the y-direction.
|
|
|
|
Next we start at the top of the circle, so that y=r and x=0. We
|
|
start increasing x in step sizes of one. We only care about step sizes
|
|
of one, since our basic unit is now a pixel. The y-coordinate is going to
|
|
start piling up these dy's, and at some point the integer part of y will
|
|
increase, and we get a new y-coordinate for the pixel. The idea, then, is to
|
|
keep adding the dy's together, and once their sum is greater than one, we
|
|
decrease y (remember that y starts at the top of the circle).
|
|
|
|
The sneaky way to do this is to treat y as an integer "constant". Then
|
|
it is very easy to add the dy's together, since they have a common denominator
|
|
equal to y. So really all we need to do is start adding x-coordinates together,
|
|
and once their sum is larger than y, we decrease y and hang on to the
|
|
remaining fractional part of dy. The algorithm then looks like:
|
|
|
|
y=r
|
|
x=0
|
|
a=r
|
|
loop: x=x+1
|
|
a=a-r
|
|
if a<=0 then a=a+y:y=y-1
|
|
plot (x,y)
|
|
if x<y then loop:
|
|
|
|
Now, Chris McBride pointed something out to me. As you may recall,
|
|
the algorithm breaks down for small r. Chris said that if a is initially
|
|
set to r/2 instead of r, the algorithm works perfectly. Why is that?
|
|
Recall that we add dy to itself until it is greater than one. Wouldn't
|
|
it make more sense to add dy to itself until it is greater than 0.5?
|
|
That would have the effect of rounding things up. Thus, starting at r/2
|
|
is like adding 0.5 to the fractional part of y -- it is the difference
|
|
between INT(y) and INT(y+0.5).
|
|
|
|
Thus, the above line
|
|
|
|
a=r
|
|
|
|
should be changed to
|
|
|
|
a=r/2
|
|
|
|
for a perfect circle every time. Thus, this corresponds to adding an LSR
|
|
to the machine code. Incidentally, this fix appeared in an earlier C=Hacking,
|
|
but it was placed in such a crazy place that you probably never saw it.
|
|
|
|
#(A): Ellipses, HO!
|
|
|
|
Now we can move on to eclipses. Since ellipses are simply a
|
|
squashed circle, it seems reasonable that we could modify the above circle
|
|
algorithm. So, let's get to it!
|
|
|
|
Everyone knows the equation of an eclipse:
|
|
|
|
x^2/a^2 + y^2/b^2 = 1
|
|
|
|
Upon taking differentials of both sides we have,
|
|
|
|
2*x*dx/a^2 + 2*y*dy/b^2 = 0
|
|
|
|
or, equivalently,
|
|
|
|
dy = -b^2/a^2 * x/y * dx
|
|
|
|
As you can see, life becomes suddenly becomes more complicated by a factor of
|
|
b^2/a^2. Furthermore, with an eclipse we only have reflection symmetries
|
|
through the x- and y-axis. In the circle algorithm we could get away with
|
|
just drawing an eighth of the circle, but now we have to draw a full quarter
|
|
of the eclipse.
|
|
|
|
We will start drawing the eclipse at x=0, y=b, so that initially x
|
|
will increase by one at each step, and y will wait a few steps to increase.
|
|
At some point, though, we will want y to increase by one at each step, and
|
|
x to wait a few steps before increasing; in the circle algorithm we just quit
|
|
once we reached this point, but now we are going to need an equation for dx:
|
|
|
|
dx = -a^2/b^2 * y/x * dy
|
|
|
|
In the circle algorithm, we used a single variable to count up and
|
|
tell us when it was time to increase y. Perhaps your intuition suggests
|
|
that we can do an eclipse with _two_ variables; mine said the same thing,
|
|
so that is exactly what we will do.
|
|
|
|
First, let us assume we have a way of calculating b^2/a^2:
|
|
|
|
E = b^2/a^2
|
|
|
|
I will suggest a way to perform this calculation later. Let's write out
|
|
the first few terms in the dy summation, starting at x=0, y=b:
|
|
|
|
dy1 + dy2 + ... = -E * (x0 + x1 + x2 + x3 + ...)/y
|
|
= -E * (0 + 1 + 2 + 3 + ...)/b
|
|
= - (0 + E + 2E + 3E + ...)/b
|
|
|
|
So, the basic structure of the algorithm is: add up 0, E, 2E, etc. until
|
|
the sum is larger than y. At that point, reset the counter, keeping the
|
|
remainder, and decrease y. This is where the two variables come in:
|
|
|
|
X=X+1
|
|
T2=T2+E
|
|
T1=T1+T2
|
|
IF T1>=Y THEN T1=T1-Y:Y=Y-1
|
|
|
|
Do you see how it works? T2 simply takes on the values 0, E, 2E, 3E, etc.,
|
|
and T1 is the counter. Furthermore, you can see that once T2 is larger
|
|
than Y, dy will be larger than one at each step. We need a new algorithm
|
|
to continue the calculation, and it turns out to be quite simple.
|
|
|
|
Look at the expression for dx above. We could calculate a^2/b^2,
|
|
but somehow that goes against the spirit of the calculation so far. Let's
|
|
instead rewrite dx slightly:
|
|
|
|
dx = - y/(E*x) * dy
|
|
|
|
Here we have simply written a^2/b^2 as 1/(b^2/a^2) = 1/E. But E*x is
|
|
exactly the variable T2 above, so we can continue the calcuation without
|
|
even stopping for breath:
|
|
|
|
Y=Y-1
|
|
T1=T1+Y
|
|
IF T1>=T2 THEN T1=T1-T2:X=X+1:T2=T2+E
|
|
|
|
(remember that T1 keeps track of the fractional part of y). So, we now
|
|
have a complete algorithm for drawing an eclipse:
|
|
|
|
0 REM ELLIPSE ATTEMPT #N SLJ 11/3/95
|
|
10 A=150:B=16:E=B*B/(A*A)
|
|
20 X=0:Y=B:T1=0:T2=0.5
|
|
30 GRAPHIC1,1:SLOW:X0=160:Y0=100:DRAW1,X0+A,Y0:DRAW1,X0,Y0-B
|
|
40 X=X+1:T2=T2+E
|
|
50 T1=T1+T2
|
|
60 IF T1>=Y THEN T1=T1-Y:Y=Y-1
|
|
70 DRAW1,X0+X,Y0-Y
|
|
80 IF T2<Y THEN 40
|
|
90 Y=Y-1
|
|
100 T1=T1+Y
|
|
110 IF T1>=T2 THEN T1=T1-T2:X=X+1:T2=T2+E
|
|
120 DRAW1,X0+X,Y0-Y
|
|
130 IF Y>0 THEN 90
|
|
|
|
Lines 40-80 are the top part of the eclipse, and lines 90-130 handle the
|
|
bottom part. Note that T2 starts at 0.5, to round off the calculation in the
|
|
same spirit as we did in the circle algorithm.
|
|
|
|
Naturally, this algorithm has a few limitations. In line 30 the start
|
|
and end points are plotted, so you can see how close the algorithm really is.
|
|
In my experiments it occasionally missed the endpoint by a pixel or two. As
|
|
usual, I was a little too lazy to investigate possible ways to get around this.
|
|
If you require a perfect eclipse, you need to start the calculation at x=0, y=b
|
|
and run it forwards (e.g. lines 40-80 above), and then do another, similar
|
|
calcuation, starting at x=a, y=0, and running backwards. That is, for the
|
|
second calculation, calculate E2=a^2/b^2, and then run the algorithm just like
|
|
lines 40-80, interchanging X and Y.
|
|
|
|
Now we need to translate this algorithm into assembly. I am going
|
|
to make a few assumptions: first, that everything fits in a byte. In
|
|
particular, I require that b^2/a < 256. This insures that b^2/a^2 < 256,
|
|
and also insures that T2 will not overflow (note that when x=a, T2=E*a,
|
|
e.g. T2=b^2/a). What this means is that eclipses can't be too squashed.
|
|
|
|
Next, we need to deal with the fraction E=b^2/a^2. Any number
|
|
like this consists of two parts, an integer part plus a fractional part
|
|
(e.g. a number and a decimal). So, let's split E into two parts, EL and EH,
|
|
where EL represents the decimal part and EH the integer. Now our addition
|
|
consists of adding together the fractional parts, and if there is an overflow,
|
|
increasing the integer part. For example, if E=1.62, then EH=1 and EL=0.62.
|
|
We add EL to our number, and if it is greater than one, we carry the one to
|
|
when we add EH to our number.
|
|
|
|
The best thing to do is to represent EL as a fractional part of 256.
|
|
That is, our EL above should really be 0.62*256. This way, carries and
|
|
overflows will be handled automatically (this will become clear in a moment).
|
|
|
|
Let me give some pseudo-assembly code and we'll push off the
|
|
explanation until later:
|
|
|
|
35 GOTO 200
|
|
190 REM ***********************
|
|
200 XM=0:YM=B:X=128:Y=0:EH%=INT(E):EL%=INT((E-EH%)*256+0.5)
|
|
210 XM=XM+1
|
|
220 C=0:A=X:A=A+EL%:IF A>255 THEN A=A-256:C=1
|
|
230 X=A:A=Y:A=A+EH%+C:Y=A
|
|
235 A=A+T1
|
|
240 IF A>=YM THEN A=A-YM:YM=YM-1
|
|
250 T1=A:DRAW1, X0+XM, Y0-YM
|
|
260 IF Y<=YM THEN 210
|
|
265 T2=Y:A=T1
|
|
270 YM=YM-1
|
|
280 A=A+YM:IF A<T2 THEN 300
|
|
290 A=A-T2:T1=A:XM=XM+1:A=X:C=0:A=A+EL%:IF A>255 THEN A=A-256:C=1
|
|
295 X=A:A=T2:A=A+EH%+C:T2=A:A=T1
|
|
300 DRAW1, X0+XM, Y0-YM
|
|
310 YM=YM-1:IF YM>=0 THEN 280
|
|
|
|
XM and YM are the x and y coordinates of the point to be plotted. Note
|
|
that in line 200 X starts at 128, and this again is to round up all our
|
|
calculations; compare to line 20, where we started T2 at 0.5. In the
|
|
above code I store T2 in the X and Y registers for the first part of the
|
|
code. Note that in lines 220 and 290 there is some extraneous code to
|
|
simulate things that in assembly are taken care of by the 6502. Note
|
|
also that the comparison in line 260 has been changed from < to <=. This
|
|
makes the branch easier, and I'm not sure how it affects the calculation
|
|
(I didn't notice any difference in the few runs I tried it on).
|
|
|
|
Moving through the code, we increase x, and then add the decimal
|
|
part of E to the counter. Then we add the integer part of E to the counter,
|
|
along with any carries. If the integer part of the counter is greater than
|
|
y, it is time to decrease y and reset the counter.
|
|
|
|
Moving to the second part of the code, we do a little rearranging
|
|
in line 265. Really a better thing to do would be to let A=T1-T2, so that
|
|
the compare in line 280 becomes simpler. Anyways, note that the Y register
|
|
becomes freed up at this point. From here on, it is pretty much the same
|
|
thing as before.
|
|
|
|
The full assembly code is then:
|
|
|
|
;Ellipse SLJ 11/3/95 Assumptions:
|
|
;0->XM B->YM, x- and y-coordinates
|
|
;0->T1
|
|
;EL and EH contain remainder and integer parts of E, resp.
|
|
|
|
LDX #128
|
|
LDY #00
|
|
CLC
|
|
L1 INC XM
|
|
TXA
|
|
ADC EL
|
|
TAX
|
|
TYA
|
|
ADC EH
|
|
TAY
|
|
ADC T1
|
|
CMP YM
|
|
BCC :CONT1
|
|
SBC YM
|
|
DEC YM
|
|
:CONT1 STA T1
|
|
JSR PLOT
|
|
CPY YM
|
|
BCC L1
|
|
|
|
STY T2
|
|
LDA T1
|
|
SBC T2
|
|
DEC YM
|
|
L2 ADC YM
|
|
BCC :CONT2
|
|
SBC T2
|
|
STA T1
|
|
INC XM
|
|
TXA
|
|
ADC EL
|
|
TAX
|
|
LDA T2
|
|
ADC EH
|
|
STA T2
|
|
LDA T1
|
|
:CONT2 JSR PLOT
|
|
DEC YM
|
|
BPL L2 ;Assuming y<128
|
|
|
|
|
|
#(A): Logarithms
|
|
|
|
Finally, we need a way of calculating b^2/a^2. I suggest using
|
|
logarithms for this. I do believe I discussed this concept in an earlier
|
|
issue of C=Hacking. Nevertheless, the idea is that if
|
|
|
|
x = b^2/a^2
|
|
|
|
then
|
|
|
|
log(x) = 2*log(b) - 2*log(a)
|
|
|
|
so that
|
|
|
|
x = exp(2*(log(b) - log(a))
|
|
|
|
Thus, three tables need to be created: one for log(x), and one each for
|
|
the integer and remainder parts of e^(2*x). Now, to improve accuracy,
|
|
the first table might be a table of f(x)=222/log(128) * log(x/2). This
|
|
constant is chosen so that f(255) is roughly 255. 222 was chosen because
|
|
the inversion (i.e. the e^x part) works best at that value. This pretty
|
|
much assumes that x is not zero or one, either. You can of course use
|
|
more tables for somewhat better accuracy.
|
|
|
|
One really nice thing about this is that you don't have to worry
|
|
about squaring things, since that part can be taken care of automatically
|
|
in logarithm space. On the downside, we are restricted even further by
|
|
the types of numbers we can divide (e.g. log(a)-log(b) can't be larger
|
|
than 127 or so).
|
|
|
|
Division then consists of a table lookup, subtraction of another
|
|
table lookup, and two more table lookups. Here is a short program to
|
|
demonstrate the use of logs in this sort of division, and a very rough
|
|
feel for the type of accuracy to expect -- note that it doesn't compare
|
|
decimal parts, or convert the decimal parts into fractions of 256, etc.:
|
|
|
|
1 FAST:PRINT"[CLR]"
|
|
10 DIM L(256),EI(256),ER(256):FC=222/LOG(128)
|
|
20 FOR I=1 TO 256
|
|
25 PRINT "[HOME]"I
|
|
30 L(I)= INT(FC*LOG(I/2)+0.5):IF I=1 THEN L(I)=0
|
|
40 S=I:IF I>127 THEN S=I-256
|
|
50 EX=EXP(2*S/FC):IF EX>256 THEN PRINT"WHOOPS! EX="EX"I="I
|
|
60 EI(I)=INT(EX+0.5)
|
|
70 ER(I)=EX-EI(I)
|
|
80 NEXT I
|
|
90 EI(0)=1:ER(0)=0
|
|
100 FOR A=2 TO 250
|
|
110 FOR B=2 TO 250
|
|
120 X=L(B)-L(A)
|
|
123 IF X>127 THEN PRINT"OOPS:A="A"B="B"X="X
|
|
126 IF X<0 THEN X=X+256
|
|
130 A1=EI(X)+ER(X):A2=B*B/(A*A):IF A2>255 THEN B=600
|
|
135 BL=INT(A2+0.5)-INT(A1+0.5)
|
|
140 PRINT A;B,A1;A2,"ERR="INT(A2+0.5)-INT(A1+0.5)
|
|
150 NEXT:NEXT
|
|
|
|
#(A): Conclusion
|
|
|
|
Sorry, no 3D graphics this time around. Watch for a full-screen, hires
|
|
bitmapped solid 3D virtual world sometime in the not too distant future.
|
|
Otherwise, may your ellipses never be square :).
|
|
|
|
|
|
============================================================================
|
|
|
|
#(@)surf: Hack Surfing
|
|
|
|
For those who can access that great expanse of area called the World Wide
|
|
Web, here is some new places to visit that are of interest to the Commodore
|
|
community. In early 1994, when the US Commodore WWW Site started, the number
|
|
of sites online that catered to Commodore numbered in the 10's. Now, the
|
|
number is in the 100's. What a change.
|
|
|
|
If you know of a site that is not listed here, please feel free to send it
|
|
to the magazine. The following links have been gleaned from those recently
|
|
changed or added to the US Commodore WWW Site Links page
|
|
(http://www.msen.com/~brain/cbmlinks.html).
|
|
|
|
To encourage these sites to strive to continually enhance their creations,
|
|
and because we like to gripe :-), we'll point out an improvements that
|
|
could be made at each site.
|
|
|
|
#(A): Companies
|
|
|
|
o http://www.escom.nl
|
|
ESCOM Interactive, Inc. The new home of Commodore has links to many of
|
|
its offices and some general information. The pages are still under
|
|
construction, but you should probably save this address. C=Hacking gripe:
|
|
No Commodore 8-bit inforation yet.
|
|
|
|
o http://www.msen.com/~brain/guest/cmd/
|
|
Creative Micro Designs. Stay tuned to this site for information on
|
|
the accelerator, and keep up to date on the latests prices on CMD
|
|
peripherals and software. C=Hacking gripe: For a comapny wanting having
|
|
just announced the Super64CPU, no mention of it is to found anywhere on
|
|
the WWW site. Bummer.
|
|
|
|
#(A): Publications
|
|
|
|
o http://www.softdisk.com/about/c64.html
|
|
LOADSTAR and LOADSTAR 128. If you are interested in LOADSTAR, check 'em
|
|
out here. Some Commodore links are included, and the and a few magazine
|
|
teasers are present. In addition, details on how to ordr LOADSTAR or any
|
|
of its related software titles is provided. C=Hacking gripe: the
|
|
background color. Yellow is hard on our eyes... Oh well.
|
|
|
|
o http://www.mds.mdh.se/~dat95pkn/8bitar/
|
|
Atta Bitar (8 Bitter) magazine. Full indexes for the past 3 years, as well
|
|
as information on how to subscribe. We'd tell you more, but none of us
|
|
read German (At least we THINK it's German), and the English transmation
|
|
page isn't done yet. Anyway, if you would like to subscribe or need to
|
|
search the index of the magazine, here's the place to go.
|
|
C=H gripe: Yes, we know this is English-centric, but we just wish we could
|
|
actually read all the great info on this site.
|
|
|
|
#(A): User's Groups
|
|
|
|
o http://www.cucug.org/
|
|
Champaign-Urbana Commodore User's Group. Home of the Universtity of
|
|
Illinois (the editor's alma mater!) Meeting dates and time, along with
|
|
newsletters and a user group listing are presented. C=H gripe: No
|
|
mention of what local CBM 8-bit users are doing. This site recently
|
|
changed addresses, so change all your links...
|
|
|
|
o http://www.psc.edu/~eberger/pcg/
|
|
Pittsburgh Commodore Group. Local news, meeting dates and time, and
|
|
some newsletters are present. This site has also recently relocated
|
|
to this new address. C=H gripe: Same as for CUCUG. We want to know
|
|
what the CBM 8-bitters are doing in Pittsburgh.
|
|
|
|
o http://www.slonet.org/~rtrissel/
|
|
The Central Coast Commodore User's Group. Those in the Santa Maria
|
|
CA area will be glad to know that CCCUG is there for them. Past
|
|
newsletter are available, and some links to other information of
|
|
interest is present. C=H gripe: Meeting dates and times need to be
|
|
present in some easy place. C=H plug: It sounds like this club might
|
|
need a little help, as it is down on members. If you are in the Santa
|
|
Maria area, consider joining...
|
|
|
|
#(A): Miscellaneous
|
|
|
|
o http://www.byte.com/art/9408/sec14/art1.htm
|
|
Byte Magazine's Commodore obituary, by Tom Halfhill. Tom spells out many
|
|
of the things that Commodore DID do right in its lifetime, and reflects
|
|
on the blunders CBM made. The article makes for very good reading, but
|
|
will depress some. C=H gripe: The pictures in the real article aren't
|
|
reproduced in the WWW page.
|
|
|
|
o http://stud1.tuwien.ac.at/~e9426444/geoswarp/index.html
|
|
GEOS Warp 1.0. For the Mac user who needs or wants to run GEOS, this
|
|
program, run on a Macintosh, will allow GEOS programs to operate on
|
|
the Mac. The system looks very impressive, to the point of us not asking,
|
|
Why? C=H gripe: Not really with the page, but the writer laments that
|
|
progress is slow owing to no agreement with GEOWorks. Such things may
|
|
doom the project to failure.
|
|
|
|
o http://vanbc.wimsey.com/~danf/cbm/
|
|
Dan Fandrich's WWW Site. For those who develop on alternate platforms or
|
|
use multiple programming languages with the C64/128, bookmark this page.
|
|
Very current info, and lots of it is presented. Some defunct Commodore
|
|
mags are indexed, and pointers are provided to many of the current crop of
|
|
magazines, including this one. C=H gripe: the page needs a little bit
|
|
more organization to make it easier to get at juicy info.
|
|
|
|
o http://www.aloha.net/~scatt/commodore.htm
|
|
Scatt's WWW Site. For those just moving into assembly language programming
|
|
from BASIC or something else, this page has a beginner's tutorial you
|
|
might find useful. C=H gripe: A little low on content, but we are glad
|
|
what there is is available.
|
|
|
|
o http://www.cs.wm.edu/~pbgonz/progc64.html
|
|
Pete Gonzalez's WWW Site. Small page, but worth viewing. Pete shows some
|
|
screen shots of a new game he is developing, and offers copies of his
|
|
in progress cross assembler for the PC. C=H gripe: When's the game coming
|
|
out again? :-)
|
|
|
|
o http://www.ts.umu.se/~yak/cccc/
|
|
The Commodore Computer Cult Corner. Some people play games, and then some
|
|
people PLAY games. Jonas Hulten has pictures of his game design,
|
|
implementation, and programming heoes. You can read about each one, and
|
|
even light a "candle" for them. This site has a CBM links page, which
|
|
anyone can add their link to automatically. C=H gripe: We can add our home
|
|
page automatically, but not our hero.
|
|
|
|
o http://www.slonet.org/~jwilbur/
|
|
John Wilbur's WWW Site. Basically, just a links page right now, but we'll
|
|
check back. C=H gripe: We'd like to see a little more about John as it
|
|
relates to Commodore.
|
|
|
|
o http://www.student.informatik.th-darmstadt.de/~supermjk/
|
|
Marc-Jano Knopp's WWW Site. Mainly a large links page for Commodore
|
|
information, this site does give a glimpse of the never produced Commodore
|
|
LCD laptop computer. C=H gripe: As above, we love to see a little more
|
|
about Marc-Jano as it relates to Commodore.
|
|
|
|
============================================================================
|
|
|
|
#(@)zedace: Design and Implementation of an Advanced Text Editor
|
|
by Craig Bruce (csbruce@ccnga.uwaterloo.ca)
|
|
|
|
Note: Due to the size of the article, no executable or source code
|
|
is included, but both will be included in ACE Release #15
|
|
(ftp://ccnga.uwaterloo.ca/pub/cbm/os/ace/).
|
|
|
|
#(A)1: 1. INTRODUCTION
|
|
|
|
This article discusses the design and implementation of the ZED text editor
|
|
for the ACE operating system (Release #15 and higher). The program and full
|
|
source code will be freely available when they are ready. ZED is written
|
|
entirely in assembly language (ACEassembler) and makes heavy use of the
|
|
full-screen control capabilities of ACE. However, part of the genius of the
|
|
design of the ACE interface is that its facilities could be replicated into
|
|
a standalone environment and a new ZED could be made into a one-part program
|
|
(for greater convenience, with less flexibility).
|
|
|
|
There was a previous version of ZED, which WAS a standalone program. It was
|
|
written entirely in _machine_ language (as opposed to assembly language;
|
|
y'know, hexadecimal and stuff, with a machine-language monitor). Needless
|
|
to say, upgrading and maintaining the program was a real problem, even
|
|
though it was only 17K in size. The program also had a couple of
|
|
limitations, the most serious of which being that all lines were limited to
|
|
a maximum of 80 characters (plus a carriage return), or they would be split
|
|
into two physical lines internally. It would also work only on the
|
|
80-column C128.
|
|
|
|
Still, the standalone version had a number of outstanding capabilities,
|
|
including the ability to edit EXTREMELY large files with an REU and dynamic
|
|
data structures, the ability to use "burst mode" on devices that supported
|
|
it, TAB and character-set translation on loading and saving, global search
|
|
and replace, range delete and recall, and a paragraph "juggling" feature.
|
|
It is truly an outstanding program (if I do say so myself), and it is my
|
|
pleasure to use it every day. (I also use Unix's "vi" every day, and I am
|
|
getting tired of its clumsy user interface... I may just have to port ZED to
|
|
the Unix environment one of these days).
|
|
|
|
The ACE version has/will have all of these features and then some. The ACE
|
|
version supports even larger files by using the ACE dynamic memory
|
|
management system (see C= Hacking #7 or a newer ACE Programmer's Reference
|
|
Guide) in addition to its own byte-oriented memory management (see C=
|
|
Hacking #2) with internal memory (up to 512K on a C128), REUs up to 16 Megs,
|
|
and RAMLink DACC memory up to 16 Megs. Burst-mode support isn't currently
|
|
available in ACE (see C= Hacking #3), nor does the ACE version of ZED
|
|
currently implement the other outstanding editing features of the original
|
|
ZED mentioned above. (For another C= Hacking reference, ACE does support a
|
|
three-key rollover for typing convenience (see C= Hacking #6)).
|
|
|
|
However, the ACE version supports extremely long physical lines (paragraphs)
|
|
by providing automatic word wrapping and "soft returns" with automatic "text
|
|
sloshing" (a dynamic form of "juggling"), and it therefore has/will have the
|
|
functionality of a word processor. The new version also works in all video
|
|
modes that ACE supports on both the C128 and C64.
|
|
|
|
#(A)2: 2. DATA STRUCTURES, FILE LOADING
|
|
|
|
Now we start talking about the implementation of ZED. What a text editor
|
|
is, basically, is a program that holds a text document in memory that allows
|
|
you to use certain commands to alter tiny pieces or large-scale chunks of
|
|
the document and then to save the changed document permanently back to
|
|
disk. The way in which the document is held in memory is the content of
|
|
this section.
|
|
|
|
#(A)2.1: 2.1. DOCUMENT DATA STRUCTURE
|
|
|
|
ZED uses a bi-directionally linked list to hold the text document in
|
|
memory. A special "trailer" line is used (which is displayed with a little
|
|
"house" character on it) to make modifications to the linked list and the
|
|
whole list is in the form of a big ring (the links run around in circles).
|
|
Here is an asciigram of a document with two data lines:
|
|
|
|
/-------------------\
|
|
| /----------\ |
|
|
| | V |
|
|
| | +-------------------------------------
|
|
| | |next|prev| data for line #1...
|
|
| | +-------------------------------------
|
|
| | | ^
|
|
| | V |
|
|
| | +-------------------------------------
|
|
| | |next|prev| data for line #2...
|
|
| | +-------------------------------------
|
|
| | | ^
|
|
| | V |
|
|
| | +-------------------------------------
|
|
| | |next|prev| special trailer line...
|
|
| | +-------------------------------------
|
|
| | | ^
|
|
| \----------/ |
|
|
\-------------------/
|
|
|
|
I should mention that all pointers are 32-bit values, so that they can point
|
|
to anywhere in ACE's "far" memory. (In fact, many of the control variables
|
|
for ZED are 32 bits in size, to avoid all arbitrary restrictions on the
|
|
magnitudes of various things). And, despite where the arrows point in the
|
|
diagram, the value that is stored for the pointer is the address of the
|
|
starting byte of the record that is being pointed to.
|
|
|
|
I should also mention that lines are stored as they are displayed. If one
|
|
physical line (terminated by a carriage return) has to be split (using "soft
|
|
returns") over multiple display lines, then each _display_ line takes up one
|
|
linked-record position in the document data structure.
|
|
|
|
Using a bi-directionally (doubly) linked list (instead of a uni-directionaly
|
|
(singly) linked list is a practical necessity in this environment for two
|
|
reasons. First, the linking represents the natural way that the user
|
|
accesses the document: he normally moves cursor up and down, page up and
|
|
down. It would take a lot of time to move the cursor up using a singly
|
|
linked list. Second, using a double linked list makes it easier to insert
|
|
or delete a line from the document. You need to modify the previous record
|
|
to point beyond the record being deleted, but the previous record is
|
|
difficult to locate in a singly linked list; you must keep and manage a
|
|
pointer to it (and if the user moves the cursor up, you lose what you've got
|
|
for it). I prefer doubly liked lists for any job anyway, even if the
|
|
ability to go backwards isn't needed, because they are easier to work with
|
|
(and to construct reusable library routines for).
|
|
|
|
Using a large block of memory for the data isn't really an option either.
|
|
Anyone who has used SpeedScript knows what happens when you try to insert
|
|
text near the beginning of a long document: it takes a lot of time to insert
|
|
one space in the document memory, and the delay is annoying. Imagine this
|
|
played out for a document that is N megabytes in size. (Some auxiliary data
|
|
structure would be needed in this case anyway, to break the 64K barrier).
|
|
I'm guessing that most other word processors/text editors for Commodore
|
|
computers use this data structure (a "large" block of memory).
|
|
|
|
The decision to store each display line in a single record is really one of
|
|
convenience and efficiency. Most of the time, the use will be positioning
|
|
the cursor and whizzing between display pages, so we don't want to be
|
|
wasting any time uselessly re-formatting the text while he (sic) is doing
|
|
this. We only want to re-format the text when an actual modification is
|
|
made to the document. This organization does have the ugly implication that
|
|
physical and logical line numbers may not always match up, but if the
|
|
"target" line length (the maximum length that a single display line can be)
|
|
is set to be longer than the maximum physical-line length of a file (often
|
|
80 characters), then the two will match up.
|
|
|
|
Accessing the document is fairly simple. All that we need to locate the
|
|
entire document is the address of the special trailer line. With this, we
|
|
know directly where the bottom line is, so we can instantly go to the bottom
|
|
of the document (Commodore-DOWN) and then follow the links backward to
|
|
access preceeding lines. Finding the top of the document is also quite easy
|
|
since the document is in a ring. We just locate the trailer line and then
|
|
follow the "next" link, and we arrive at the first line (Commodore-UP). It
|
|
should be no surprise that a pointer is kept to the trailer line in ZED in
|
|
order to locate a document. The design allows for many documents to be held
|
|
in memory at the same time, including the "kill buffer" (which is logically
|
|
a complete and independent document). To make management even simpler, it
|
|
should be noted that this trailer line never changes (therefore, we never
|
|
have to update the pointer to the trailer line of a document).
|
|
|
|
#(A)2.2: 2.2. LINE DATA STRUCTURE
|
|
|
|
The format of each individual display line within a document held in the
|
|
linked-list structure described above is as follows:
|
|
|
|
OFF SIZ DESC
|
|
--- --- -----
|
|
0 4 pointer to the next line
|
|
4 4 pointer to the previous line
|
|
8 1 flags for the line, including $80=hard-return, $40=trailer line
|
|
9 1 number of characters on the line
|
|
10 n the displayable characters of the line
|
|
n+10 - SIZE
|
|
|
|
The two 32-bit pointers have already been mentioned. The "flags" field
|
|
tells whether the line ends in a "hard return" or a "soft return". A hard
|
|
return (indicated by the $80 bit being set) is recorded for every place in
|
|
the text file where a carriage-return character is present. A soft return
|
|
(indicated by the $80 bit being clear) is formatted into the document every
|
|
place where a line must be broken in order to avoid it exceeding the target
|
|
line length. If you modify the document, then words can be wrapped and
|
|
pulled back around a soft return in order to insure that display lines are
|
|
as full as possible (whereas they cannot be wrapped around a hard return).
|
|
|
|
When a file is being written back to disk, lines that have a hard return
|
|
flag will be written with a trailing carriage-return character, whereas
|
|
lines ending with a soft return will be written with only the characters
|
|
displayed on the line (no CR), and, as such, they will be logically
|
|
concatenated together into the same physical line (again) in the output
|
|
file. The "trailer line" flag indicates whether the current line is the
|
|
special trailer line of the document or not. We need a convenient way to
|
|
check for running into the trailer line, and we cannot use null pointers
|
|
since the document is in a ring (note that there won't be any null pointers
|
|
even if the document contains zero data lines; the trailer line will point
|
|
to itself).
|
|
|
|
The lower six bits of the flags field are currently unused, but they could
|
|
be used, for example, to record the number of leading spaces that a
|
|
line has before the first non-blank character. This would allow us to
|
|
hold a file with a lot of indentation (a program, for example) using less
|
|
memory per line. This feature is not currently implemented.
|
|
|
|
The next field tells the number of displayable characters that are on the
|
|
line and then the next field stores the actual characters in a simple
|
|
string. If the line ends in a hard return, then the carriage-return
|
|
character is NOT stored in the line data, since its presence is already
|
|
indicated in the line header. When records are allocated in the
|
|
dynamic-memory space, only the number of bytes that are actually needed are
|
|
allocated. This is the number of bytes on the line plus ten bytes for the
|
|
line header. Actually, the number of bytes reserved for an allocation is
|
|
the number of bytes requested rounded up to the nearest multiple of eight
|
|
bytes, for technical reasons discussed in C= Hacking #2. A single display
|
|
line can contain up to 240 characters (not counting the CR).
|
|
|
|
Every time that a line needs to be accessed, it must be fetched from far
|
|
memory into a buffer in the program space. There is a slight efficiency
|
|
problem in accessing a line that there isn't when allocating and storing a
|
|
line. When going to read the line, you don't know how big it is, since you
|
|
know nothing about it other than its far location. The conservative thing
|
|
to do would be to read the first ten bytes of the line record (the header
|
|
information) and then use the value in the line-length field to figure out
|
|
how many more bytes you need to fetch. I kind of took a wild stab and made
|
|
it so that I read the first twenty bytes of a line and then see if the line
|
|
has ten or fewer displayable characters on it. If so, then I have
|
|
successfully fetched the whole line and I am done in one access. (Note that
|
|
there is no problem with fetching far memory beyond one record's allocation
|
|
(although there certainly would be a problem with stashing)). If not, then
|
|
I fetch the remaining characters and I am done in two fetches (actually, I
|
|
fetch all of the characters for simplicity).
|
|
|
|
However, often times I don't actually have to fetch the data of a line at
|
|
all and I only need to access its header information (to follow or change
|
|
its linkage, for example). In this case, I only have to access the header
|
|
of the line and I only need one access to get it since I already know how
|
|
long the header is (ten bytes). I can also write back a modified header in
|
|
place since it is of fixed length. If I were to, for example, add
|
|
characters to a line, then I would have to re-allocate a larger line record
|
|
for it, free the old line-record storage, and link the new line record in
|
|
with the rest of the document (by updating the previous record's "next"
|
|
pointer and updating the next record's "prev" pointer and by updating any
|
|
necessary global variables... quite a bit or work).
|
|
|
|
#(A)2.3: 2.3. GLOBAL VARIABLES
|
|
|
|
This section describes all of the global variables that ZED keeps in order
|
|
to edit a document. First, I have three separate temporary-storage work
|
|
areas:
|
|
|
|
work1 = $02 ;(16) ;used by malloc
|
|
work2 = $12 ;(16) ;used by file-load
|
|
work3 = $22 ;(14)
|
|
|
|
Each work area is used by successively higher levels of software in order to
|
|
avoid conflicts between layers. For example, "work1" is used by the
|
|
dynamic-memory routines and "work2" gets modified when loading a file. The
|
|
process of loading a file involves a lot of memory-allocation work, so it is
|
|
good that they use separate working storage and don't clobber each other.
|
|
|
|
The following variables are used for managing the screen and the current
|
|
cursor column:
|
|
|
|
scrTopAddr = $30 ;(2) ;screen address of the top line on the display
|
|
scrRow = $34 ;(1) ;row number of the current line on the display
|
|
scrCol = $35 ;(1) ;virtual screen column number of cursor position
|
|
scrRows = $36 ;(1) ;number of rows on the display
|
|
scrCols = $37 ;(1) ;number of columns on the display
|
|
scrStartRow: .buf 1 ;starting row on the display
|
|
scrStartCol: .buf 1 ;starting column on the display
|
|
scrRowInc = $38 ;(1) ;row increment for the display
|
|
scrLeftMargin = $39 ;(1) ;left margin for displaying lines
|
|
statusMargin: .buf 1 ;left margin of the status line on the display
|
|
conColor: .buf 8 ;color palette
|
|
|
|
Most of these fields are used for interfacing with ACE's direct-access
|
|
full-screen-control calls. The ones that are used most often are allocated
|
|
to zero-page locations (to reduce code size and to increase performance) and
|
|
the others are allocated to absolute memory. ACE allows application
|
|
programs to use zero-page locations $02 to $7F for their own purposes.
|
|
|
|
The current displayed cursor location is stored in "scrRow" and "scrCol".
|
|
"scrRow" is the current physical display row of the current document line
|
|
(where display rows start at 2 since the control and separator lines take up
|
|
rows 0 and 1), and "scrCol" tells the current position on the current line,
|
|
from 0 up to the length of the line. Since this version of ZED features
|
|
horizontal scrolling to handle really long display lines, "scrLeftMargin" is
|
|
also maintained to tell what the column number of the left margin of the
|
|
display is. When we refresh the screen, we will display all lines starting
|
|
from this character position. Note that internally, column numbers start
|
|
from 0 whereas they are numbered starting from 1 in all dialogue with the
|
|
ape at the keyboard. Every time that the cursor could possibly move off the
|
|
right or left edge of the screen, a check is made and if this happens, then
|
|
the "scrLeftMargin" is adjusted and the screen is re-painted (effectively
|
|
giving us horizontal scrolling).
|
|
|
|
The following variables are used to keep track of various parameters:
|
|
|
|
targetLen = $3a ;(1) ;length to display lines
|
|
wrapFlag = $3b ;(1) ;$80=wrap,$40=showCR
|
|
modified = $3c ;(1) ;$00=no, $ff=modified
|
|
modeFlags = $3d ;(1) ;$80=insert, $40=indent
|
|
statusUpdate = $3e ;(1) ;128=line,64=col,32=mod,16=ins,8=byt,4=fre,2=nm,1=msg
|
|
markedLinePtr: .buf 4 ;line that is marked, NULL of none
|
|
markedLineNum: .buf 4 ;line number that is marked
|
|
markedCol: .buf 1 ;column of marked logical line
|
|
|
|
"targetLen" is the length that ZED tries to keep wrappable lines as close to
|
|
without exceeding. By default, it will be set to the physical display width
|
|
of the screen, but it can be set to 240 characters by the "-l" option and it
|
|
will eventually be manually settable to any value you want (10<=l<=240).
|
|
The "wrapFlag" tells, first, whether word wrapping should be used ($80 set)
|
|
or whether lines should just be broken at the target length regardless of
|
|
whether it gets broken in the middle of a word or not ($80 clear), and
|
|
second, tells whether carriage-return characters should be displayed to the
|
|
user ($40 set) or not ($40 clear). (Actually, a suitable character to
|
|
represent the carriage return is displayed, taken from the graphical palette
|
|
of the current character set). You will normally want carriage returns
|
|
displayed when you are using ZED as a word processor, and you will normally
|
|
want them not displayed when using ZED as a text editor.
|
|
|
|
The "modeFlags" tell, first, whether auto-insert ($80 bit set) or over-type
|
|
($80 clear) mode is in effect, and second, whether auto-indent ($40 set) or
|
|
no-indent ($40 clear) mode is in effect. Insert/overtype is currently
|
|
supported and auto-indent is not. Auto-indent is intended to eventually
|
|
make programming easier by not requiring you to type a bunch of spaces to
|
|
indent a new line of a source file that should be at the same nesting level
|
|
as the previous line.
|
|
|
|
The "statusUpdate" variable is used to reduce the amount of work the needs
|
|
to be done in order to keep the status line at the top of the screen up to
|
|
date. If any of the variables that control the values displayed on the
|
|
status line change, then the corresponding bit in this variable should be
|
|
set. After processing a keystroke but before waiting for the next
|
|
keystroke, ZED will update all of the fields that have a '1' bit in this
|
|
variable. The "msg" bit is special, since it tells whether a dialogue
|
|
message is currently being displayed on the separator line (between the
|
|
status line and the first document line), and if there is, then the message
|
|
should be erased (overwritten by the separator characters) _after_ the user
|
|
presses the next key (since it wouldn't be much fun if the user had only a
|
|
couple of milliseconds to read the message).
|
|
|
|
The "marked*" fields tell where the "mark" is currently set for range
|
|
commands (like delete). Like in the stand-alone ZED, I will be making this
|
|
version clear the mark after every modification to the file. The main
|
|
reason for this is that it would be a pain in the but to keep track of the
|
|
mark in some cases like when the line that is marked gets deleted or
|
|
updated, and that having set-mark/do-operation clear the mark prevents the
|
|
ape at the keyboard from accidentally hitting a range-destroy key and wiping
|
|
out his document (he will get a "range not set" error message instead).
|
|
|
|
The following variables are used to keep track of the current position in
|
|
the document:
|
|
|
|
linePtr = $40 ;(4) ;pointer to current line
|
|
lineNum = $44 ;(4) ;number of current physical line
|
|
headLinePtr = $4c ;(4) ;pointer to the special header/trailer line
|
|
lineCount = $50 ;(4) ;number of display lines in buffer
|
|
byteCount = $54 ;(4) ;number of bytes in buffer
|
|
|
|
"linePtr" always points to the line record that the cursor is logically on.
|
|
This is probably the most important global variable. This variable is
|
|
needed so that we know what line to modify/etc. if the user enteres a
|
|
letter/etc. "lineNum" gives the line number of the "linePtr" line, where
|
|
line numbers start from 1. This needs to be maintained in order to tell the
|
|
ape at the keyboard where in the document he is. These two fields are
|
|
sequentially updated as the user moves from line to line in the document.
|
|
|
|
"headLinePtr" is a bit of a misnomer since it actually points to the special
|
|
trailer line. As explained above, it is used to find the top and the bottom
|
|
of the document. "lineCount" keeps track of the total number of display
|
|
lines in the current document, and "byteCount", the total number of bytes.
|
|
Each carriage-return character counts as one byte. Keeping track of line
|
|
and byte counts is for convenience rather than necessity.
|
|
|
|
The following variables manage the "kill buffer", where text goes after it's
|
|
been deleted but before it's completely discarded (a sort of purgatory):
|
|
|
|
killBufHeadPtr: .buf 4 ;pointer to special header/trailer line of kill buf
|
|
killLineCount: .buf 4 ;number of lines in kill buffer
|
|
killByteCount: .buf 4 ;number of bytes in the kill buffer
|
|
|
|
The kill buffer is maintained in exactly the same structure that the main
|
|
document is: a ring of doubly linked line records. The three fields shown
|
|
store the pointer to the special trailer line, the number of data lines in
|
|
the kill buffer, and the number of data bytes in the kill buffer,
|
|
respectively.
|
|
|
|
In addition to the kill buffer, there is also a "rub buffer":
|
|
|
|
RUB_BUFFER_SIZE = 50
|
|
rubBufPtr: .buf 1
|
|
rubBufSize: .buf 1
|
|
rubBuffer: .bss RUB_BUFFER_SIZE
|
|
|
|
It is used to hold the fifty single characters that have most recently been
|
|
deleted by using either the DEL or Commodore-DEL (Rub). I found that when
|
|
using the old version of ZED, I would sometimes unintentionally delete a
|
|
single character and then want it back, and I had to expend mental effort to
|
|
figure out what it was. This mechanism takes the effort out of that job by
|
|
maintaining a LIFO (Last In First Out) (circular) buffer controlled by the
|
|
variables given above (note that "RUB_BUFFER_SIZE" is a constant which can
|
|
be easily changed up to 255 in the source code). The "rubBuffer" is
|
|
actually contained in the uninitialized-storage section of the program
|
|
("bss" in Unix terminology). (The ".bss" directive is not currently
|
|
implemented in the ACEassembler, but I used it here as a shorthand for the
|
|
equates that replace it).
|
|
|
|
The Shift-Ctrl-R (rub recall) keystroke is used to recall the previous
|
|
character (as if you had typed it in) and has the effect of resetting the
|
|
"rubBufPtr". Then, each additional time that you type Shift-Ctrl-R in a
|
|
row, the "rubBufPtr" is advanced backward to the character previous to
|
|
the one just recalled. Pressing anything other than Shift-Ctrl-R resets
|
|
the "rubBufPtr", so that you could recall the characters again, if you want.
|
|
You can recall as few characters as you wish.
|
|
|
|
Interpreting command keys is done with the following global variables:
|
|
|
|
keychar = $58 ;(1)
|
|
keyshift = $59 ;(1)
|
|
sameKeyCount: .buf 1
|
|
sameKeyChar: .byte $00
|
|
sameKeyShift: .byte $ff
|
|
|
|
ACE returns both a shift pattern and a key character code, so both are
|
|
stored. The shift pattern allows us to take different actions for commands
|
|
like Ctrl-R and Shift-Ctrl-R. The "same*" fields store the previous
|
|
keystroke and the number of times that the exact keystroke has been made, so
|
|
that slightly different actions can be taken when the same keystroke is made
|
|
multiple times, such as with Shift-Ctrl-R (or maybe HOME).
|
|
|
|
The following global variables are also maintained for various purposes:
|
|
|
|
exitFlag: .buf 1
|
|
arg: .buf 2
|
|
temp: .buf 4
|
|
stringbuf: .bss 256
|
|
filebuf: .bss 256
|
|
tpaFreemap: .bss 256
|
|
linebuf: .bss 256
|
|
line = linebuf+headLength ;(241)
|
|
headBuffer = $70 ;(10) ;buffer for holding the head of the current line
|
|
headNext = $70 ;(4) ;pointer to the next line in a document
|
|
headPrev = $74 ;(4) ;pointer to the prev line in a document
|
|
headLineLe = $78 ;(1) ;length of the text line
|
|
headFlags = $79 ;(1) ;$80=CR-end, $40=headerLine, &$3F=indent
|
|
headLength = 10 ;length of the line header
|
|
documentBuf: .bss 256
|
|
docbufNext = documentBuf+0 ;(4)
|
|
docbufPrev = documentBuf+4 ;(4)
|
|
docbufInfo = documentBuf+8 ;(23)
|
|
docbufFilenameLen = documentBuf+31 ;(1)
|
|
docbufFilename= documentBuf+32 ;(224)
|
|
|
|
"exitFlag" is set to tell the main loop to bail out and exit back to the
|
|
calling program. "arg" is used for scanning the command-line arguments.
|
|
"temp" is used miscellaneously. "stringbuf" is used for miscellaneous
|
|
string processing, and "filebuf" is used for miscellaneous file/string
|
|
processing. "tpaFreemap" is used by the dynamic-memory-management code as a
|
|
free-memory-page map for making allocations out of the application program
|
|
area (or TPA, Transient Program Area). The ACE kernel doesn't dynamically
|
|
allocate pages in the application space (since this cannot normally be done
|
|
reliably), so a mechanism is needed inside of ZED to make use of this
|
|
memory.
|
|
|
|
"linebuf" is the place where the current line is fetched to/stashed from
|
|
when it is being accessed or modified. "line" is the sub-field of "linebuf"
|
|
where the actual line data is stored. The "head*" variables are allocated
|
|
in zeropage and the record-header information from "linebuf" is copied to
|
|
these variables whenever a line is fetched and copied from these variables
|
|
when a line is stashed to far memory. Zero page is used for these variables
|
|
since they are manipulated all of the time.
|
|
|
|
Finally, "documentBuf" stores all of the information about the current main
|
|
document. There is currently support for only one main document
|
|
implemented, but the design includes the concept of the user being able to
|
|
switch between an arbitrary number of documents held in memory at any time.
|
|
|
|
2.4. LOADING A FILE
|
|
|
|
When ZED is first started up, its usual first job is to load in the document
|
|
that was named on the command line (plus you can load a file at any time
|
|
with Ctrl-L). ZED uses the standard ACE "open", "read", and "close" system
|
|
calls to do this, although there is a bit of business that has to happen to
|
|
get the data into the internal form that ZED uses. The job is split into a
|
|
number of routines to make it easier to program.
|
|
|
|
The main routine opens the file for reading and initializes that variables
|
|
that the load routine uses. Among other things, the load routine counts up
|
|
the number of display lines and physical bytes in the file and must wrap
|
|
physical lines into display lines while reading. Later, this routine will
|
|
perform on-the-fly translation from other file formats to PETSCII and will
|
|
perform TAB expansion if requested.
|
|
|
|
The main routine repeatedly calls subroutines to read a line into the line
|
|
buffer, wrap it, and store it to memory. For the purpose of the following
|
|
discussion, we will assume that the "target" line length is 80 characters,
|
|
although it can be set to anything that you want. The Read routine copies
|
|
characters from the "filebuf" to the line buffer, with the filebuf being
|
|
re-filled with file-data characters as necessary in 254-byte chunks (the
|
|
natural size of Commodore data sectors, for efficiency). Data bytes are
|
|
copied until either a carriage-return (CR) character is encountered or we
|
|
reach the 81st character (target+1). We have to check the 81st character
|
|
because it may be a CR, and if we are in the normal text-editor mode, we can
|
|
store a full 80 data characters on a display line, even if it ends in a CR
|
|
(some editors, quite annoyingly, cannot do this). However, if the user
|
|
selects the mode where CRs are visibly displayed on the screen, then we stop
|
|
scanning the current display line at a maximum of 80 characters if a CR
|
|
isn't encountered.
|
|
|
|
After the characters of the display line have been put into the line buffer
|
|
in the above step, it may be the case that the word at the end of the line
|
|
has been abruptly broken in the middle. If the line ended in a CR, then
|
|
this doesn't need to be checked. If the line didn't end in a CR and if the
|
|
"wrap" mode is currently on, then an abruptly cut word will have to be
|
|
wrapped to the next line. To do this, we scan from the end of the line back
|
|
until we encounter the last space character on the line. Then, we cut the
|
|
line immediately after that space, and remember where we cut it so that we
|
|
can later process the overflown characters. If there is no space on the
|
|
line (i.e., the first and only word on the line is longer than the target
|
|
length), then we keep it as-is and end up breaking the word abruptly. Note
|
|
that we break the line with a "soft return", so there is no damage done to
|
|
the data by word wrapping.
|
|
|
|
After the fat (if any) has been trimmed off the current display line, we
|
|
want to store it into far memory, into the doubly linked ring structure
|
|
discussed above. To do this, we first, set the pointer to the previous line
|
|
to the address of the previous line record (we keep track of this) and set
|
|
the pointer to the next line to Null (for now). Then we we allocate memory
|
|
for the current line and Stash it out. But we're not done yet; we need to
|
|
set the "next" pointer on the previous line record to point to our newly
|
|
allocated line. This can be done by simply writing the 32-bit pointer value
|
|
to the start address of the previous line (there is no need to re-fetch the
|
|
previous-line contents or header).
|
|
|
|
And after stashing out the line, we recall where we wrapped it (if we did)
|
|
and copy the characters that were cut off to the beginning of the line
|
|
buffer and we pretend that we have fetched these from the file as if in the
|
|
Load Line step above. Then we go back to the Load Line step and continue.
|
|
|
|
When loading is finished (after we hit End-Of-File (EOF) on the file being
|
|
read), we flush the last incomplete line segment, if there was one (a file
|
|
is not required to end in a CR) and then we cap things off with the special
|
|
trailer line. This trailer line is allocated before we start loading the
|
|
file (although I didn't mention it above), and now we set up its links so
|
|
that our entire file is the nice doubly linked ring that we like so much.
|
|
Now we are finished, and we return the trailer-line pointer, the number of
|
|
display lines read in, and the number of physical bytes read in to whomever
|
|
called us (it could be the command-line parser, the Ctrl-L (Load) command,
|
|
or the Ctrl-I (Insert) command).
|
|
|
|
There are three reasons why I like having this special trailer line around.
|
|
(1) It allows us to not have to worry about Null pointers. For example, you
|
|
will notice that while stashing a loaded line, I allocated the trailer line
|
|
first so that we would always have a "previous" line to link with. (2) It
|
|
allows the user to move the cursor beyond the physical end of the document
|
|
to do operations like recall (Ctrl-R) a block of text. This was a problem
|
|
with the original ZED; you had to go the the end of the file, press RETURN
|
|
to open up a blank line, recall the text, and then delete the bogus blank
|
|
line. (3) It allows a document to have zero characters in it in a
|
|
consistent fashion.
|
|
|
|
There is also a subtle but complicated issue dealing with dynamic memory
|
|
allocation that I haven't discussed yet: what if it fails? (I.e., what if
|
|
we run out of memory?). In this case, we must handle the failure
|
|
gracefully, maintain the integrity of the document as best we can, and
|
|
inform the user. In some cases, maintaining the integrity will involve
|
|
un-doing committed changes to the document, which is a real pain in the
|
|
butt, but which is still very important. It would be kind of annoying if
|
|
you just made the last keystroke on five hours of editing work and the
|
|
program aborted on an "out of memory" error, sending all of your work to the
|
|
great bit bucket in the sky.
|
|
|
|
#(A)3: 3. SCREEN DISPLAY, MOVING AROUND
|
|
|
|
This section discusses the operations that have to do with maintaining the
|
|
current secion of the document on the display and moving the cursor around
|
|
within the document.
|
|
|
|
#(A)3.1: 3.1. PAINTING THE SCREEN
|
|
|
|
This is the essential operation that keeps the screen up to date with the
|
|
docment in memory. ZED has a single function that does this operation, and
|
|
it is called with the arguments: a pointer to the starting line to display,
|
|
the starting screen line number to start painting at, and the ending screen
|
|
line number to end painting at, plus one (lots of endings are 'plus one'
|
|
since this allows me to use the BCC instruction). Some implied arguments
|
|
include general information about the screen for use with the "aceWin*"
|
|
kernel functions and the left margin for displaying lines.
|
|
|
|
This subroutine simply goes through the display lines one by one, displays
|
|
the line contents, and advances the line pointer. To display a single line,
|
|
the line is fetched into the line buffer from far memory and the number of
|
|
displayable characters is calculated according to the line length and the
|
|
left-hand display margin. The displayable characters (possibly zero) are
|
|
written to the screen memory and if the line isn't completely full, then the
|
|
remainder of the line is filled in with space characters. The displaying is
|
|
completely performed by the "aceWinPut" system call. One oddity that needs
|
|
to be handled is running out of document lines before filling the screen
|
|
range. In this case, each remaining screen line is cleared.
|
|
|
|
Attributes (colors) are not used for this operation, since they are not
|
|
needed and using them would only slow us down. They display-area color
|
|
cells are initialized when ZED starts (as are the status-line and
|
|
separator-line color cells) and don't change during operation. The colors
|
|
come from the ACE palette (which the user can configure to his own liking).
|
|
|
|
This subroutine is used to both repaint the entire screen (when necessary)
|
|
and to repaint only one line or a few lines (when I can get away with
|
|
this). Repainting takes time, so we want to repaint only what has changed.
|
|
However, repainting isn't too slow, especially when compared to serial-line
|
|
speeds, since screen updates are written directly to screen memory, although
|
|
the C64's soft-80 screen is significantly slower than the other screen types
|
|
since so much more processor work needs to be done just to make a single
|
|
character appear.
|
|
|
|
In the future, it may be useful to allow this function to abort in the
|
|
middle of this operation if the user presses a key before the repainting is
|
|
finished, in order to allow the user to work faster. For example, if you
|
|
hold down the Page-Down keystroke, the speed that you go forward in the
|
|
document is limited by how fast the screen can be repainted. If the repaint
|
|
operation were abortable, then you could always go forward as fast as the
|
|
key repeates, and when you get to where you are going and release the
|
|
Page-Down key, the screen would repaint one final time and everything would
|
|
be consistent. A flag would need to be kept to tell whether the screen is
|
|
consistent or not, in order to make this work.
|
|
|
|
There is also a function that displays a message in the separator line on
|
|
the screen. It also needs to store the displayed message in order to allow
|
|
the user to scroll through it if the screen is not wide enough to display it
|
|
in its entirety. When the message is no longer needed, it is erased by
|
|
overwriting it with separator characters. And, there is also a function
|
|
that updates all of the fields that have changed on the status line.
|
|
|
|
#(A)3.2: 3.2. MAIN CONTROL
|
|
|
|
Before I start talking about the implementations of the individual commands,
|
|
I should say something about the main control for the program. After ZED
|
|
initializes and loads the initial document (even if you don't specify one,
|
|
ZED will default to the name "noname" and try to load it), control is passed
|
|
to a small main loop of simply displaying the cursor, waiting for a
|
|
keystroke, undisplaying the cursor, calling the subroutine associated with
|
|
the keystroke, and repeating.
|
|
|
|
#(A)3.3: 3.3. END UP, DOWN, LEFT, RIGHT
|
|
|
|
Moving the current line to the top and bottom of the document is straight
|
|
forward, because of the organization that was discussed in the data-
|
|
structure secion above. To go to the top of the document, copy the
|
|
trailer-line pointer to the current line pointer and then fetch the next
|
|
pointer from the trailer line's header; this will give a pointer to the top
|
|
line. Then we set the current line number to one and a couple of other
|
|
variables and call the subroutine discussed above to repaint the screen.
|
|
|
|
Going to the bottom of the document would be just as easy as going to the
|
|
top, except that we want the last line (the trailer line) to be displayed on
|
|
the bottom of the screen in order to present as much useful document content
|
|
to the user as possible. If there are fewer lines in the file than will
|
|
fill a screen, then we cannot, of course, display an entire screen.
|
|
|
|
To make this business easier, a subroutine is provided that, given a
|
|
starting line pointer and a count, will scan until it either hits the
|
|
count-th line previous to the given one or it hits the top line of the
|
|
document. It returns the number of lines that were actually scanned upwards
|
|
(possibly zero), the pointer to the line that it stopped scanning at, and a
|
|
flag indicating whether it stopped because it hit the top of the document or
|
|
not. This subroutine is quite generally useful. There is a similar
|
|
subroutine that scans downward.
|
|
|
|
So, after locating the bottom line of the document and setting the line
|
|
number, the scan-upwards subroutine is called to scan upwards the number of
|
|
displayable lines on the screen. The screen is then repainted in its
|
|
entirety from the line that was scanned up to, and the new cursor-display
|
|
location is computed from the count of the lines that were scanned over.
|
|
This works equally well for a long document, a document shorter than the
|
|
height of the screen, and an empty document.
|
|
|
|
The End-Left and End-Right commands are very simple in that they don't even
|
|
have to change the current line pointer, but they do have to check if the
|
|
cursor has moved off either the left or right edge (margin) of the screen.
|
|
The visible columns go from the column number of the left margin, up to that
|
|
plus the width of the screen. If the cursor goes off an edge of the screen,
|
|
then the new left margin will have to be computed and the entire display
|
|
will need to be repainted.
|
|
|
|
This repainting effectively achieves horizontal scrolling. Lines in ZED, of
|
|
course, can be up to 240 characters across (241 if you count the carriage-
|
|
return character), but the widest screen that ACE supports is 80 columns.
|
|
Arguably, the horizontal scrolling could be done more efficiently by moving
|
|
the contents of the display left or right by the requred number of columns
|
|
and then filling in the opened spaces with the data from the correct columns
|
|
of the display lines in memory. However, the additional complexity is
|
|
non-trivial and the speedup may not be all that great except for the soft-80
|
|
screen of the C64. A better approach might be to go with the interruptable-
|
|
repainting idea that I spoke of earlier, if the current line were updated
|
|
first (so that you can see what you're doing) and the rest of the lines
|
|
afterwards.
|
|
|
|
#(A)3.4: 3.4. PAGE UP, DOWN, CURSOR UP, DOWN, LEFT, RIGHT, WORD LEFT & RIGHT
|
|
|
|
All of these functions follow quite naturally from what is above. For Page-
|
|
Up and Down, the scan-up or scan-down subroutines already described are
|
|
called to find the new current line for the cursor and then the entire
|
|
screen is repainted, effectively paging up or down.
|
|
|
|
For cursor up and down, we just go up or down to the next line in the
|
|
document and adjust adjust the cursor location on the screen. If the cursor
|
|
goes off the top or bottom of the screen, then we scroll the screen up or
|
|
down as appropriate (ACE can scroll the screen up or down and will
|
|
eventually be able to scroll it left and right (although this will be a bit
|
|
painful for the soft-80 screen since it may mean scrolling left and right
|
|
nybbles)). Then, we display the current line at either the top or bottom of
|
|
the screen to fill in the blank line that we just opened up. Because we use
|
|
scrolling and painting only a single line, we can scroll the screen fairly
|
|
quickly, easily keeping up with the cursor repeat rate, except on the
|
|
soft-80 screen.
|
|
|
|
For cursor left and right, we advance the cursor one position on the line
|
|
and see if it has gone over the edge. If not, then we are done; nothing
|
|
needs to be redisplayed. If we have gone off the edge, then we call the
|
|
cursor-up or cursor-down routines to go to the previous/next line and we
|
|
position the cursor to either the end or start of the new line.
|
|
|
|
The word left/right functions are similar to the cursor left/right
|
|
functions, except that we keep scanning until we run into the start of the
|
|
next word. For word left, this is defined as running into a non-whitespace
|
|
character that is preceeded by a whitespace character. A whitespace
|
|
character is defined as either a space, a TAB, a hard return, or the
|
|
beginning or ending of the document. For word right, the start of the next
|
|
word is defined as a non-whitespace character that is preceeded by a
|
|
whitespace character, where we start searching from one position to the
|
|
right of the current cursor position. If we run into the beginning or end
|
|
of the document, then we stop there.
|
|
|
|
BTW, all of these moving-around functions check the cursor position against
|
|
the display bounds and "scroll" the display left or right if the cursor has
|
|
gone off the screen. Well, actually, there is one exception to this rule.
|
|
If the current line is the target-length number of characters long, and the
|
|
target length equals the screen width, and carriage returns are selected not
|
|
to be displayed, and the left margin of the display is column one
|
|
(external), and the cursor is in the target-length-plus-one position of the
|
|
line, then the screen is NOT scrolled right. Instead, the cursor is
|
|
displayed on the last position of the line and is made to blink fast (an ACE
|
|
feature). This is done to avoid the annoyance of having the screen scroll
|
|
right when you are editing a text file on, say, an 80-column screen that has
|
|
up to 80-character lines in it. The standalone ACE does this too, when you
|
|
logically hit the 81st column.
|
|
|
|
#(A)4: 4. TEXT INPUT AND "SLOSHING"
|
|
|
|
So far, we can load up a document and whiz around inside of it, but we can't
|
|
actually change anything. This section describes the single-character
|
|
modification operations of character input, rub, and delete, and the text
|
|
"sloshing" algorithm that is needed to make sure that lines are always as
|
|
full as they can be without going over the target length ("Come on down!").
|
|
|
|
#(A)4.1: 4.1. TEXT INPUT, DELETION
|
|
|
|
Adding a single character to a document isn't really very difficult. There
|
|
are two modes for single-character inputting: insert and overtype. Insert
|
|
mode is generally more useful and more often used, but overtyping can be
|
|
very useful when dealing with tabular or specially formatted text.
|
|
Therefore, we must support both modes. In some other text editors, overtype
|
|
mode is the natural mode because the cost of inserting a character can be
|
|
so high, but not here.
|
|
|
|
Actually, there isn't a whole lot of difference in the implementations of
|
|
the two modes. For overtype mode, you just fetch the current line, take the
|
|
inputted character and store it into the line buffer at the current
|
|
position, stash the line back into memory, and repaint the line. For insert
|
|
mode, we do the same thing, except that we copy the line from the cursor to
|
|
the end to one position beyond the cursor (backwards) and bump its length up
|
|
by one before storing the new character on the line.
|
|
|
|
Rubbing out a character (Commodore-DEL) is done in quite the same way,
|
|
except that we copy the rest of the line back one space and decrement the
|
|
length. Oh, and when the length of the new line is different from the
|
|
length of the old line, we have to deallocate the old line and allocate new
|
|
memory for the new line, and surgically link it in with the rest of the
|
|
document. I have a subroutine that does this.
|
|
|
|
The DEL key is handled as if you had typed Cursor Left then RUB, except when
|
|
you press DEL on the first column of a line and the previous line ends with
|
|
a hard return, the hard return of the previous line is removed instead. I
|
|
decided to make the RUB (Co-DEL) key return an error instead of joining
|
|
lines together like DEL, because sometimes it is convenient to just lean on
|
|
the RUB key to delete to the end of a line.
|
|
|
|
#(A)4.2: 4.2. TEXT SLOSHING
|
|
|
|
But, we're not done with text modifications yet. If we just left the
|
|
modifications as described in the previous sections, we would be end up with
|
|
lines that are longer than the target length, with ragged lines, and with
|
|
lines that don't join together like they should after pressing DEL in the
|
|
first column.
|
|
|
|
After each of the modifications, the text-sloshing routine is called to
|
|
straighten everything up and figure out how to redisplay the screen. Often,
|
|
only one line needs to change, but sometimes, many lines or even the whole
|
|
screen will have to be updated, as sloshing text can continue for many lines
|
|
as line overflows and underflows cascade forward from the line that has just
|
|
been modified. In fact, the text-sloshing routine is enormously complicated
|
|
and has many, many special cases. (Although, for all of its complexity, it
|
|
is only 400 lines long, although it still needs a few more features).
|
|
|
|
There are many more cases that could cause sloshing than you might think.
|
|
There are the obvious inserting/deleting one-too-many characters in the
|
|
current line, but there is also the case that an insertion or deletion
|
|
causes a space character to move to the right position on a line to allow
|
|
the line to be sloshed backward, or maybe you remove a space from the end of
|
|
a line that creates a word that would be too long to be contained on one
|
|
line and therefore needs to be sloshed forward.
|
|
|
|
The sloshing algorithm doesn't introduce or take away any characters from
|
|
the body of the document; it just reorganizes the existing characters. All
|
|
of the spaces are retained at the ends of wrapped lines. We don't want to
|
|
delete spaces, since it is difficult to reconstruct them, since two spaces
|
|
are normally between two sentences in text, but it is difficult for a
|
|
computer to figure out where a sentence ends. In fact, keeping these spaces
|
|
can sometimes cause an anomaly: if all of the spaces won't fit on the end of
|
|
one line, then they will be displayed at the beginning of the next line.
|
|
|
|
The variables that are maintained by the algorithm are as follows:
|
|
|
|
sloshLinesAltered = work2+0 ;(1) ;a simple count
|
|
sloshRedisplayAll = work2+1 ;(1) ;$80=redisplay to bottom, $ff=force all
|
|
sloshRedisplayPrev = work2+2 ;(1) ;whether previous line needs to be repainted
|
|
sloshMaxChars = work2+3 ;(1) ;number of chars that can be sloshed
|
|
sloshTailChar = work2+4 ;(1) ;the last char of prev line
|
|
sloshTheCr = work2+5 ;(1) ;whether a CR should be sloshed
|
|
sloshLinesInserted = work2+6 ;(1) ;number of new line records created
|
|
sloshLinesDeleted = work2+7 ;(1) ;number of existing line records deleted
|
|
sloshCurAltered = work2+8 ;(1) ;whether the current line has been altered
|
|
sloshTerminate = work2+9 ;(1) ;flag to terminate (hit a hard return)
|
|
sloshCurTailChar = work2+10 ;(1);last char of current line
|
|
|
|
The algorithm has a main loop that is repeated for each line that can be
|
|
sloshed. The loop exits when we either run into a hard return or we run
|
|
into a line that does not need to be sloshed. We start scanning from the
|
|
cursor line of the main document.
|
|
|
|
We first look at the previous line and see how many more characters it can
|
|
accommodate before being full. Then, we scan the current line from this
|
|
point (the number of characters that could potentially be sloshed backwards)
|
|
back to the start of the line searching for spaces. If there are no spaces,
|
|
then the current line cannot be sloshed back onto the previous line. If we
|
|
do run into a space, then we stop searching and know that we can (and must)
|
|
slosh back the current line. So, we remove the characters from the current
|
|
line and write it back (maintaining links as appropriate) and then go back
|
|
to the previous line and append these characters to it.
|
|
|
|
If the cursor happened to be on the line in a position that got sloshed
|
|
back, then we must adjust the cursor position and move it back to the
|
|
previous line. If the previous line is before the start of the screen,
|
|
we must set the flag to redisplay the entire screen later. If the current
|
|
line is the first line of the slosh area but the cursor didn't get moved
|
|
back to the previous line, then we must set the flag to indicate that
|
|
we must redisplay the previous line too when we repaint the screen.
|
|
|
|
If it turns out that we have sloshed back ALL of the characters on the
|
|
current line, then we must remove the empty line record of the current line
|
|
from the document and adjust the global line count. We also have to worry
|
|
about sloshing back a hard return, and if we do, then we bail out of the
|
|
algorithm since we are done. Oh, and we have to keep in mind whether we are
|
|
displaying carriage returns or not in calculating line lengths.
|
|
|
|
After shoshing backward, we check if the current line needs to be sloshed
|
|
forward. It needs to be sloshed forward if it is either longer than the
|
|
target length or it ends in a non-space character and the first
|
|
word on the next line cannot be sloshed back. The latter is a special case
|
|
and needs to be checked for specially, even thought the functionality
|
|
for doing so is redundant.
|
|
|
|
If we do need to slosh forward, we start scanning the current line at the
|
|
target-line-length point and scan backwards until we hit the first space.
|
|
If there is no space, then the current word is longer than the target length
|
|
and must remain abruptly broken over two (or more) lines. We wrap it at the
|
|
target length. If we do find a space earlier on the line, then we wrap the
|
|
line right after that space. Oh, I forgot to mention: we need to do
|
|
something special for lines that end with non-spaces for backward sloshing
|
|
too. If the previous line ends in a non-space (presumably because it
|
|
contains a single very long word), then we don't find any spaces to slosh
|
|
back to the end of the word, then we slosh back as many characters as will
|
|
fit, since the word is broken anyway, and we want it to have as many
|
|
characters as possible on a single line.
|
|
|
|
To wrap the line, we set the length of the current line to the new length
|
|
and replace the old version of the line in memory. Then, we create a new
|
|
line record and store the characters that were wrapped in it and link this
|
|
line record in with the rest of the document. And this is all that we do
|
|
here; we don't actually insert the wrapped characters into the next line,
|
|
since that would be more complicated, and since it might cause that line to
|
|
overflow. If we just leave the wrapped characters, they will be joined with
|
|
the next line (if necessary) on the next iteration of the main sloshing loop
|
|
in a slosh-back operation. We must adjust the cursor location, like before,
|
|
if the cursor was on the part of the line that got wrapped around.
|
|
|
|
At the end of a loop, we check to see if we have passed a hard return in
|
|
the document, in which case, we exit. Otherwise, if either the current
|
|
line has been modified or if the current line is the first line to
|
|
be sloshed, then we go on to the next line and repeat the above
|
|
procedure.
|
|
|
|
On our way out, we do a little fine tuning of the "sloshLinesAltered",
|
|
"sloshRedisplayAll", and "sloshRedisplayPrev" variables, which were
|
|
described earlier. These variables will be used to repaint the changed
|
|
portions of the screen display. Part of the fine adjustment includes
|
|
comparing the number of lines that have been inserted and deleted from the
|
|
document. If these two numbers match, then the bottom portion of the screen
|
|
doesn't have to be repainted, only the altered lines themselves; otherwise,
|
|
we need to repaint from the current line all the way to the bottom of the
|
|
screen.
|
|
|
|
The sloshing algorithm currently does not handle non-wrap mode; lines will
|
|
always be word wrapped. Later, all lines will be broken at the N-th column
|
|
if you are not in word-wrap mode. Also, the algorithm can produce an
|
|
anomalous wrapping in one case involving lines that end with non-spaces that
|
|
I can't seem to remember that this algorithm will fail in (but, the document
|
|
will still be interally consistent). And finally, if you change the target
|
|
line length while editing a document (which you can't currently do), then
|
|
the algorithm may not be able to give optimal word wrapping in all cases
|
|
(though, again, the document will always be interally consistent).
|
|
|
|
#(A)5: 5. OTHER FEATURES
|
|
|
|
This secion discusses the other features of the editor that have not been
|
|
described yet. In general, the operation of this version follows closely
|
|
from the standalone version, so you can read its documentation for more
|
|
details. First, I will give a summary of all of the implemented and planned
|
|
commands, and then I will discuss the operation of a few selected commands.
|
|
|
|
#(A)5.1: 5.1. COMMAND SUMMARY
|
|
|
|
Here is a command summary. The "I" column in this list tells whether the
|
|
feature is currently implemented or not. A blank means "no", and an
|
|
asterisk means "yes". Note that "currently" means "by the time that you
|
|
read this" (which will be a couple of weeks after I have written this). The
|
|
"CODE" column tells the internal ACE-PETSCII code for the key. A plus
|
|
symbol following it means that the shift status of the key is checked to
|
|
distinguish this key. The "KEY" column tells what keystroke you must make
|
|
("CT-" means Ctrl, "CO-" means Commodore, "SH-" means Shift, and "AL-" means
|
|
Alt). The "ACTION" column tells you what happens.
|
|
|
|
I CODE KEY ACTION
|
|
- ---- ------- -------
|
|
$e0 CT-@ Exchange cursor position with mark position
|
|
* $e1 CT-A Alter case of letter under cursor
|
|
$e2 CT-B Go on to next document buffer
|
|
$e2+ SH-CT-B Go on to previous document buffer
|
|
$e3 CT-C Copy range
|
|
* $e4 CT-D Delete range
|
|
* $e5 CT-E Exit with save
|
|
* $e6 CT-F Find next occurrence of hunt string
|
|
$e6+ SH-CT-F Find previous occurrence of hunt string
|
|
$e7 CT-G Go to given line number
|
|
$e7+ SH-CT-G Go to given _physical_ line number
|
|
* $e8 CT-H Set Hunt string
|
|
* $e9 CT-I Insert new file into current one
|
|
$ea CT-J Juggle the lines of paragraphs, keep separate
|
|
$eb CT-K Kill current line
|
|
* $ec CT-L Load file
|
|
$ed CT-M Set Mark for range operations
|
|
* $ee CT-N Set Name of current file
|
|
$ef CT-O Set Options: input/output translation/tab-expansion, etc.
|
|
$f0 CT-P Print current file
|
|
* $f1 CT-Q Quit without save
|
|
* $f2 CT-R Recall text from the Kill buffer
|
|
* $f2+ SH-CT-R Recall text from the Rub buffer
|
|
* $f3 CT-S Save file
|
|
$f4 CT-T Tie together multiple lines into one big line (paragraph)
|
|
$f5 CT-U Undo the last change made to the document
|
|
$f6 CT-V Verify file
|
|
$f7 CT-W Write range with new name
|
|
$f8 CT-X Extract the individual lines from a paragraph
|
|
$f9 CT-Y Replace (all the other letters were taken!)
|
|
* $fa CT-Z Goto bottom of screen
|
|
* $fb CT-[ Toggle insert mode
|
|
* $fc CT-\ Toggle modified flag
|
|
* $fd CT-] Toggle indent mode
|
|
$fe CT-^ Change the current working directory
|
|
$ff CT-_ Compose ISO-8859-1 character
|
|
|
|
I CODE KEY ACTION
|
|
- ---- --- ------
|
|
* $91 UP Cursor up
|
|
* $11 DOWN Cursor down
|
|
* $9d LEFT Cursor left
|
|
* $1d RIGHT Cursor right
|
|
* $06 SH-LEFT Word left
|
|
* $0b SH-RIGHT Word right
|
|
* $16 CT-UP Page up
|
|
* $17 CT-DOWN Page down
|
|
* $19 CT-LEFT Page left
|
|
* $1a CT-RIGHT Page right
|
|
* $0c CO-UP Goto top of document
|
|
* $0f CO-DOWN Goto bottom of document
|
|
* $10 CO-LEFT Goto beginning of line
|
|
* $15 CO-RIGHT Goto end of line
|
|
|
|
* $0d RETURN Split current line (indent not yet implemented)
|
|
$8d SH-RETURN Go to next paragraph
|
|
$01 CT-RETURN Go up one paragraph
|
|
$09 TAB Tab
|
|
$02 SH-TAB Backtab
|
|
$18 CT-TAB Insert to next tab stop
|
|
* $14 DEL Delete character
|
|
* $08 CO-DEL Rubout
|
|
* $94 INST Insert one space
|
|
* $13 HOME <nothing>
|
|
* $93 CLR Cursor home
|
|
$04 HELP Bring up help window
|
|
$84 SH-HELP Display help screen
|
|
* $0a LINEFEED <nothing>
|
|
* $07 SH-LINEFEED <nothing>
|
|
* $1b ESCAPE Redisplay screen
|
|
* $0e SH-ESCAPE <nothing>
|
|
* $03 STOP <stop some operations>
|
|
* $83 RUN <nothing>
|
|
|
|
$90 CT-1 Clear document
|
|
$05 CT-2 Clear buffer
|
|
$1c CT-3 Enter hexadecimal PETSCII character code
|
|
$9f CT-4 Display directory
|
|
$9c CT-5 Destroy current document buffer
|
|
$1e CT-6 Create new document buffer
|
|
$1f CT-7 Display PETSCII code of current character
|
|
* $9e CT-8 Scroll left margin of status line
|
|
* $12 CT-9 Reverse screen on
|
|
* $92 CT-0 Screen reverse off
|
|
|
|
$81 CO-1 Set display to show single buffer
|
|
$95 CO-2 Set display to show two buffers
|
|
$96 CO-3 Set display to show three buffers
|
|
$97 CO-4 Set display to 40 columns, default rows
|
|
$98 CO-5 Set display to take full screen
|
|
$99 CO-6 Set display to default number of rows
|
|
$9a CO-7 Set display to maximum number of rows
|
|
$9b CO-8 Set display to 80 columns, default rows
|
|
|
|
$85 F1 Function key 1 : user-defined string
|
|
$89 SH-F1 Function key 2 : user-defined string
|
|
$86 F3 Function key 3 : user-defined string
|
|
$8a SH-F3 Function key 4 : user-defined string
|
|
$87 F5 Function key 5 : user-defined string
|
|
$8b SH-F5 Function key 6 : user-defined string
|
|
$88 F7 Function key 7 : user-defined string
|
|
$8c SH-F7 Function key 8 : user-defined string
|
|
$80 CT-F1 Function key 9 : user-defined string
|
|
$82 CT-F3 Function key 10 : user-defined string
|
|
$8e CT-F5 Function key 11 : user-defined string
|
|
$8f CT-F7 Function key 12 : user-defined string
|
|
|
|
#(A)5.2: 5.2. TEXT SAVE
|
|
|
|
This function is, of course, implemented, since the text-modification
|
|
functions of the editor would be useless without it. It is really quite
|
|
simple, because of the data structure of the document. First, we try to
|
|
open the file for writing. If not successful and we get a "file exists"
|
|
error, then we scratch the old file. Then, we re-open for writing.
|
|
|
|
To save the file contents, we start at the top line, and fetch each line in
|
|
turn until we hit the trailer line of the document, at which point we are
|
|
finished. After fetching the line, we check if it ends with a hard return,
|
|
and if so, we append the line buffer with a carriage return character and
|
|
bump up the line length. We then call the ACE "write" primitive with the
|
|
line buffer as the argument to write out the line. Writing in this size of
|
|
chunk rather than in single bytes gives ACE the opportunity to carry out
|
|
this operation as efficiently as it can.
|
|
|
|
We then close the file and we are done. We display status information to
|
|
the user during all phases of this operation, and we certainly tell him if
|
|
anything goes wrong.
|
|
|
|
#(A)5.3: 5.3. RANGE DELETION & RECALL
|
|
|
|
Range delete and recall are implemented, since they are very useful for
|
|
general editing. What will normally happen is that the user will set the
|
|
mark with Ctrl-M (mark) to one end of the range to be deleted, and then move
|
|
the cursor to the other end of the range and press Ctrl-D (delete). The
|
|
text then disappears into the kill buffer and can be recalled any number of
|
|
times at any point in the document using the Ctrl-R (recall).
|
|
|
|
One difference between this ZED and the operations mentioned here are
|
|
"character oriented" rather than "line oriented". So, you can now delete
|
|
only portions of lines rather than entire lines. You just have to keep in
|
|
mind that the cursor is logically located "between" the previous character
|
|
and the character that the cursor is currently over. For example, if the
|
|
cursor was on the "y" in "xyz", then the mark would be set to between the
|
|
"x" and "y" if you pressed Ctrl-M at that point. This also means that if
|
|
you wanted to delete an entire line (that ended with a hard return), then
|
|
you would move the cursor to the first character of the line and press
|
|
Ctrl-M and then move the cursor to the first character of the NEXT line and
|
|
press Ctrl-D. (The Hard Return itself won't be included in the delete
|
|
operation if you move the cursor to the end of the line to be deleted--this
|
|
is one of the reasons for having a displayable trailer line).
|
|
|
|
To implement the delete operation, all of the lines in the operation are
|
|
unlinked from the main document and are linked into the kill buffer. If
|
|
there already was something in the kill buffer, then it is deallocated and
|
|
the kill buffer is cleared. A trailer line is permanently allocated to the
|
|
kill buffer, to make it work consistently with the main document. Partial
|
|
lines (potentially, the first and last lines of the range) are a bit of a
|
|
pain and have to be split into two lines at the point of the mark/cursor,
|
|
where one of the broken lines stays with the document and the other goes
|
|
into the kill buffer. After extracting the range, the lines around the
|
|
extracted region are sewn back together ("sponge, nurse!") and text is
|
|
"sloshed" about the stitch point (if necessary). The number of bytes and
|
|
lines involved are counted up and are subtracted from the global counts
|
|
for the main document.
|
|
|
|
Ctrl-C (copy) is very similar to the delete operation, except that the data
|
|
to be deleted is actually copied to the kill buffer and the document is left
|
|
unmodified. Range copy is not currently implemented, since its operation
|
|
can be emulated with a Ctrl-D followed immediately by a Ctrl-R.
|
|
|
|
To implement the recall operation, the kill buffer is replicated into a
|
|
temporary document and the current line of the main document is broken into
|
|
two lines at the recall point (if necessary). Then, the temporary document
|
|
is linked into the main document at the recall point and the text is
|
|
"sloshed" about the two stitch points. The line and byte counts are
|
|
adjusted, and we are done.
|
|
|
|
#(A)5.4: 5.4. TEXT SEARCHING
|
|
|
|
Forward text searching is implemented, since it is very useful for both
|
|
finding things and for moving quickly around in a document. (Reverse search
|
|
and Range search and replace are not currently implemented, since they are
|
|
less useful).
|
|
|
|
The implementation is quite straightforward. The user will first use Ctrl-H
|
|
(hunt-string) to set the string to search for. The user will input this on
|
|
the top line of the screen, and we don't have to do much work for inputting
|
|
the string, since ACE already provides a console-input routine complete with
|
|
left/right cursor movement and a scroll-back buffer (although it is a bit
|
|
hard to use if the input line is longer than the input window on the
|
|
screen).
|
|
|
|
After the search string is set, the user will press Ctrl-F (find) to find
|
|
the next occurrence of the string. So, we just search for that string,
|
|
starting at the cursor position to the right of the current position. A
|
|
simple algorithm of keeping a pointer to the current scan position in the
|
|
hunt string and pointers to both the current position in the document and to
|
|
the position in the document corresponding to the start of the string is
|
|
used.
|
|
|
|
If the current document character matches the current hunt-string character,
|
|
then both the document and hunt-string pointers are advanced. If the hunt
|
|
string is exhausted by this, then we have found a match and can stop
|
|
searching. We move the cursor to the saved document position of the start
|
|
of the hunt string and exit. If the characters don't match, then we move
|
|
the current document pointer back to the postition corresponding to the
|
|
start of the hunt string, advance it by one, save it, and start searching
|
|
again. Our algorithm needs to be able to wrap around soft returns in the
|
|
main document.
|
|
|
|
#(A)6: 6. CONCLUSION
|
|
|
|
So, here we finally have the basic ACE version of the ZED text editor that I
|
|
have been promising for a very long time. The new version doesn't contain
|
|
all of the features of the standalone version, but I am working on it. The
|
|
new version does, however, include a few features that the old version does
|
|
not, like long lines, horizontal scrolling, text "sloshing", the ability to
|
|
use additional memory types for storage, the ability to work on the C64,
|
|
integration with a command-line environment, and full assembler-code
|
|
availability (Real Soon Now(TM)).
|
|
|
|
In order to make ZED operational as a word processor, some means of giving
|
|
embedded commands and for formatting and printing these commands must be
|
|
provided. I was originally thinking that an EasyScript or SpeedScript kind
|
|
of embedded-command structure, and then I was thinking abouta LaTeX kind of
|
|
structure (the LaTeX structure is superior), but I am now thinking that an
|
|
HTML type of format-command structure might be rather apropos. Why then I
|
|
would need to create a print formatter and previewer that might be usable
|
|
for other purposes, too.
|
|
|
|
============================================================================
|
|
|
|
#(@)trivia: Commodore Trivia
|
|
by Jim Brain (brain@mail.msen.com)
|
|
|
|
#(A): Introduction
|
|
|
|
Well, the cold has moved in on us in Michigan, but the Commodore information
|
|
coming into the house is keeping us warm. Some orphan computers have showed
|
|
up, including a Commodore 65 and C116, as well as a couple of Commodore B-128
|
|
computers with all the fixin's. So, armed with the hardware, I have come up
|
|
with some brain ticklers for the Commodore know-it-all.
|
|
|
|
As some may know, these questions are part of a contest held each month on
|
|
the Internet, in which the winner receives a donated prize. I encourage
|
|
those who can received the newest editions of trivia to enter the contest.
|
|
|
|
This article contains the questions and answers for trivia editions #19-22,
|
|
with questions for the current contest, #23.
|
|
|
|
If you wish, you can subscribe to the trivia mailing list and receive the
|
|
newest editions of the trivia via Internet email. To add your name to the
|
|
list, please mail a message:
|
|
|
|
To: brain@mail.msen.com
|
|
Subject: MAILSERV
|
|
Body:
|
|
subscribe trivia Firstname Lastname
|
|
help
|
|
quit
|
|
|
|
#(A): Trivia Questions
|
|
|
|
Q $120) What is the model number of the assembler/monitor for the KIM-1?
|
|
|
|
A $120) The KIM-5 was the model number of the editor/assembler product.
|
|
|
|
Q $121) How many LEDs are on the KIM-1?
|
|
|
|
A $121) The basic unit contains 6 7-segment LED displays, or 42 LEDs if
|
|
you count each LED in a segment.
|
|
|
|
Q $122) What is the model number of the REC chip used in the REU?
|
|
|
|
A $122) MOS 8726.
|
|
|
|
Q $123) At least two versions of the above chip exist. What is the main
|
|
physical difference between the versions?
|
|
|
|
A $123) The eraly versio of the chip (8726-R1) exists in DIP form, while the
|
|
8726-r4-r8 exists as a "J-lead" square surface mount unit.
|
|
|
|
Q $124) Why couldn't regular Atari(tm) style joystcks be used with the
|
|
Commodore Plus/4 series?
|
|
|
|
A $124) Instead of using the de-facto 9 pin D-subminuture connector for the
|
|
joysticks, the Plus/4 series used small mini-DIN connectors. Some
|
|
sources claim the older connectors were leaking a fair bit of
|
|
radio interference and were preventing the units from attaining
|
|
FCC approval, so the connectors were changed to the better-shielded
|
|
mini-DIN types.
|
|
|
|
Q $125) What was the first joystick model Commodore produced that would
|
|
function with the Plus/4 computer line?
|
|
|
|
A $125) The Commodore T-1341 Joystick, which had the special mini-DIN
|
|
connector
|
|
|
|
Q $126) How many computer models are included in the Plus/4 line?
|
|
|
|
A $126) At last count, 3 models in the Plus/4 series were produced:
|
|
|
|
The Commodore Plus/4
|
|
The Commodore 16
|
|
The Commodore 116
|
|
|
|
Some Commodore 264 models are known to exist, but are not counted,
|
|
since the 264 was the prototype model of the Plus/4. Also, a V364
|
|
model was planned, but only one unit is known to exist.
|
|
|
|
Q $127) In a normal Commodore disk drive Directory Entry, what relative
|
|
offset denotes the start of the program name?
|
|
|
|
A $127) The filename starts at the 4th byte in the directory entry.
|
|
|
|
Q $128) How many tracks in a 1541 or 4040 are normally available for use as
|
|
storage?
|
|
|
|
A $128) 35 tracks.
|
|
|
|
Q $129) How many bytes comprise a single disk drive directory entry?
|
|
|
|
A $129) 30 bytes.
|
|
|
|
Q $12A) What is the model number of the Commodore dual drive with a total
|
|
capacity per unit of 2.12MB?
|
|
|
|
A $12A) The Commodore 8250 or 8250LP dual disk drive.
|
|
|
|
Q $12B) On the drive denoted in $12A, how large could a single sequential
|
|
file be?
|
|
|
|
A $12B) 1.025 megabytes.
|
|
|
|
Q $12C) At least two version of the Commodore 64C keyboard exist. What is
|
|
the difference between them? Extra Credit: Why?
|
|
|
|
A $12C) One one keyboard style, the Commodore graphics are printed on the
|
|
front of the keys, while they appear above the letters on the keys
|
|
in the second type of keyboard. I can't answer the extra credit
|
|
part except to say that Commodore was always seeking the best deal.
|
|
aybe a new keyboard manufacturer got the bid and changed the layout.
|
|
|
|
Q $12D) On the Commodore 64, what area of memory is swapped out when using an
|
|
REU with RamDos?
|
|
|
|
A $12D) $6000 - $7fff is swapped out when a RAMDOS command is executing.
|
|
|
|
Q $12E) Commodore manufactured two different versions of the 1541-II drive.
|
|
What is the difference between them?
|
|
|
|
A $12E) The drive mechanisms differ in the two drives. You can tell which you
|
|
have by the appearance of the front of the drive. If the lever hits
|
|
a rest in the release position, you have the direct drive model. If
|
|
the lever has no such rest visible, the drive cotains the belt drive
|
|
mechanism.
|
|
|
|
Q $12F) How many colors could the Commodore 1520 plotter plot in?
|
|
|
|
A $12F) 4. red, black, blue, and green.
|
|
|
|
Q $130) The Commodore Plus/4 was referred to as the "___________ Machine".
|
|
|
|
A $130) Productivity.
|
|
|
|
Q $131) Although the Commodore 16 and 116 were functionally equivalent, what
|
|
two physical characteristics distinguished one from another?
|
|
|
|
A $131) Case style and keyboard. The C16 is enclosed in a VIC20/C64 style
|
|
case with keyboard, while the C116 sports a scaled down Plus/4
|
|
style case and "chicklet" keyboard.
|
|
|
|
Q $132) How many pins are there on the Commodore plus/4 expansion port
|
|
connector?
|
|
|
|
A $132) 50 pins.
|
|
|
|
Q $133) On which side of the Commodore 65 (as it is facing you) did Commodore
|
|
place the power switch on?
|
|
|
|
A $133) The left side. Since the disk drive fills the entire right side, the
|
|
left side is an obvious choice, as the swith would require cabling if
|
|
installed on the right side.
|
|
|
|
Q $134) How many keys are on a standard Commodore 128 keyboard?
|
|
|
|
A $134) 92 keys.
|
|
|
|
Q $135) What color are the drive LEDs on the SX64 drive?
|
|
|
|
A $135) There is only one LED, a red in-use LED.
|
|
|
|
Q $136) True or False? The Commodore 64 and VIC-20 keyboards are
|
|
interchangeable.
|
|
|
|
A $136) True.
|
|
|
|
Q $137) On a 1526/MPS 802 printer, how many redefinable characters
|
|
were available for use per line of text?
|
|
|
|
A $137) 1. True fact: In order to print a line of graphics, one must
|
|
print a GFX char, do a returb without linefeed (resets the graphic
|
|
character, evidently), the tab over and repeat the cycle until 80
|
|
characters were printed. I had one, and it took me 7 hours to
|
|
print 21 pages of GEOWrite text!
|
|
|
|
Q $138) To set up a redefinable character on the MPS 802/1526 printer, what
|
|
secondary address must be opened?
|
|
|
|
A $138) Secondary address #5.
|
|
|
|
Q $139) How many pins are in each Euro-DIN plug used on the Plus/4-C16
|
|
joysticks?
|
|
|
|
A $139) 8 pins.
|
|
|
|
Q $13A) How many pins are on a regular Commodore VIC-20/C64 joystick
|
|
connector?
|
|
|
|
A $13A) 9 pins.
|
|
|
|
Q $13B) What BASIC command is used to change from C128 mode to C64 mode on a
|
|
C128?
|
|
|
|
A $13B) go 64. It will ask for confirmation.
|
|
|
|
Q $13C) What were the four integrated programs included in the infamous
|
|
"3+1" software in the Plus/4?
|
|
|
|
A $13C) A word processor, spreadsheet, graphics software, and a data management
|
|
program.
|
|
|
|
Q $13D) Which Commodore serial printer(s) had a small switch that allowed it
|
|
to be addressed as either device 4 or device 5?
|
|
|
|
A $13D) The 1525, MPS 801, and MPS 803 had such a switch. Although I cannot
|
|
confirm this, I believe the 1515, the precursor to the 1525, also
|
|
had the 4/5 switch.
|
|
|
|
Q $13E) How many addressable registers does the Commodore VIC-II IC have?
|
|
|
|
A $13E) There are 47 control registers in the Commodore VIC-II chip.
|
|
|
|
Q $13F) On a Commodore PET machine, what output appears on the screen after
|
|
typing in SAVE "",2?
|
|
|
|
A $13F) PRESS PLAY AND RECORD ON TAPE #2
|
|
|
|
Q $140) What was the model number of the microprocessor used in the
|
|
first of the Commodore 264 Series?
|
|
|
|
A $140) The early Plus/4 units contained a 7501 microprocessor, and the
|
|
later units featured a 8501 microprocessor. The only differences
|
|
between the two units is the manufacturing process and die size.
|
|
|
|
Q $141) How fast could the microprocessor in the Commodore 264 Series
|
|
theoretically run at?
|
|
|
|
A $141) 1.76 MHz.
|
|
|
|
Q $142) How many colors can a Commodore Plus/4 display at once?
|
|
|
|
A $142) 8 shades each of 16 colors, but the 8 shades of black are still
|
|
still black, so a total of 121 colors are possible.
|
|
|
|
Q $143) What anomaly exists in the numbering of the BASIC interpreter
|
|
in the Plus/4 as 3.5?
|
|
|
|
A $143) This version contained almost all of the commands in Version 4.0,
|
|
plus some new commands for graphics and sound.
|
|
|
|
Q $144) After the very first 1581 disk drives were introduced, Commodore
|
|
found that the WD1770 disk controller chip in the drive could corrupt
|
|
the disk in some situations. So, Commodore offered a replacement
|
|
IC to fix the problem. What was the number of the replacement IC?
|
|
|
|
A $144) The Western Digital WD1772 IC.
|
|
|
|
Q $145) On some very early CBM 1541 drives, what would happen if the serial
|
|
bus CLOCK and DATA lines were high upon startup?
|
|
|
|
A $145) On the very first 1541 drives (I suspect the feature was also on the
|
|
1540 as well), On power-up, the drive would jump to a subroutine at
|
|
$E780 after performing the reset routine. The code there would check
|
|
for the high state of CLOCK and DATA. If found, the code would wait
|
|
until both go low and then store '*' into the filename buffer, sets the
|
|
filename length to 1, and then jumps to the & command, which loads
|
|
a USR file and executes it.
|
|
|
|
Since the Commodore computer never used this feature, and some machines
|
|
would boot with these lines randomly high, Commodore removed the
|
|
feature.
|
|
|
|
Q $146) In question $0F8, we learned that one must DIMension an array in
|
|
BASIC if it will have more than 11 elements. Which Commodore
|
|
produced reference book ncorrectly claims the need to DIMension
|
|
arrays for more than 10 elements.
|
|
|
|
A $146) The Commodore 128 Programmer's Reference Guide. Page 17.
|
|
|
|
Q $147) Why should serial device number 31 not be used?
|
|
|
|
A $147) While it is specified as a valid serial bus address, when "or"ed with
|
|
certain commands, it results in a bad command, hanging the bus and
|
|
the serial drivers.
|
|
|
|
Q $148) On most VIC game cartridges from VIC-1910 up, toggling interlaced
|
|
screen display can be done with a keypress. Which key?
|
|
|
|
A $148) Press the F7 function key.
|
|
|
|
Q $149) Which cartidge fitting the criteria in $148 does not toggle interlace
|
|
display with the same keypress as the others? How is it toggled
|
|
on this cartridge?
|
|
|
|
A $149) Gorf, VIC-1923. Pushing the joystick up toggles interlace mode.
|
|
|
|
Q $14A) The Commodore 64 KERNAL and BASIC code use every opcode in the 6510
|
|
CPU except three. Which three?
|
|
|
|
A $14A) BRK, CLV, and SED.
|
|
|
|
Q $14B) For what purpose does the BASIC interpreter in a Commodore 64
|
|
require the Complex Interface Adaptor (CIA) IC?
|
|
|
|
A $14B) In order to calculate random values for the BASIC function RND(0),
|
|
the first 4 registers of the CIA whose address is provided by the
|
|
IOBASE KERNAL routine are read.
|
|
|
|
Q $14C) On the Commodore 128, the 80 column output is output by the VDC
|
|
chip. What does VDC stand for?
|
|
|
|
A $14C) Video Display Controller.
|
|
|
|
Q $14D) By now, most people know about the ill-fated Commodore 65. What
|
|
were the specifications on the original Commodore 65 idea?
|
|
|
|
A $14D) A Commodore C64C with a built-in 1581.
|
|
|
|
Q $14E) When referring to the Commodore 4032, one usually states that
|
|
one has a "thin 40" or a "fat 40". What does "thin" and "fat"
|
|
signify?
|
|
|
|
A $14E) A "thin 40" had a 9" screen and could not be upgraded. The
|
|
"fat 40" had a 12" screen, and could be upgraded to a 8000 series
|
|
machine with some upgrade chips.
|
|
|
|
Q $14F) If you own a Commodore 4032, how can you tell which kind (thin
|
|
or fat) you have?
|
|
|
|
A $14F) If you hold down the cursor key and it repeats, you have a "fat 40".
|
|
(Of course, inspection could also be used, as the "thin" unit had a
|
|
smaller screen)
|
|
|
|
Q $150) How nmany keys are on a standard Commodore B-128 keyboard?
|
|
|
|
A $150) 94 keys.
|
|
|
|
Q $151) How many revisions of the 1541 printed circuit board are
|
|
known to exist?
|
|
|
|
A $151) For the 1541:
|
|
|
|
PCB# 1540001 The "long board", as used in the 1540.
|
|
PCB# 1540008-01 Minor revisions to the 1540001 board.
|
|
PCB# 1540048 The "short board".
|
|
PCB# 1540050 Minor revisions to the 1540048 board.
|
|
-01 ALPS mechanism
|
|
-03 Newtronics mechanism
|
|
PCB# 250442-01 A revision of the short board. 1541 A board
|
|
PCB# 250446-01 Minor revisions to the #250442 board, 1541 A-2 board
|
|
PCB# 250446-03 Cost reduced 250442-03 board. the 1541A C/R.
|
|
|
|
For the 1541C:
|
|
|
|
PCB# 250448-01 Contains the track 1 sensor logic. the 1541B board.
|
|
|
|
For the 1541-II:
|
|
|
|
PCB# 340503 Cost reduced board. Termed the 1541-II board.
|
|
|
|
There might be others, but these we can confirm. There are 9
|
|
if you count the 1541-II board as a 1541 board, 8 if not.
|
|
|
|
Q $152) The Commodore 6510 CPU has two internal I/O registers. Where in the
|
|
Commodore 64 are these two registers located at?
|
|
|
|
A $152) Location $0000 and $0001
|
|
|
|
Q $153) The Commodore 64 cotains 64kB of memory. How many bytes is in
|
|
64kB?
|
|
|
|
A $153) 65536 bytes
|
|
|
|
Q $154) What is the name of the Commodore employee responsible for much of
|
|
the Commodore 128 and 65 software development, among other
|
|
accomplishments? (hint: initials are FB)
|
|
|
|
A $154) Fred Bowen.
|
|
|
|
Q $155) In question $13F, we found out the message that was displayed after
|
|
typing SAVE "",2. Why did Commodore change that message on the
|
|
VIC-20?
|
|
|
|
A $155) The original message, as detailed in Q $13F was:
|
|
|
|
PRESS PLAY AND RECORD ON TAPE #2
|
|
|
|
Commodore found that people were pressing the play buttopn BEFORE the
|
|
record button, which would prevent the record button from functioning
|
|
in some cases. So, Commodore changed the message to:
|
|
|
|
PRESS RECORD AND PLAY ON TAPE
|
|
|
|
To circumvent the problem. Note that the VIC did not have 2 tape
|
|
interfaces, so no cassette number was needed.
|
|
|
|
Q $156) What was the number of Commodore 64 machines sold, within 4 million?
|
|
|
|
A $156) 17 million (This information came from Dave Haynie)
|
|
|
|
Q $157) What was the number of Commodore 128 machines sold, within 1 million?
|
|
|
|
A $157) 4.5 million (This information came from Dave Haynie)
|
|
|
|
Q $158) In 1985, Commodore previewed the Commodore LCD Laptop computer at the
|
|
January CES show. How many software packages were to be built-in?
|
|
|
|
A $158) 8:
|
|
|
|
Word Processor
|
|
File Manager
|
|
Spreadsheet
|
|
Address Book
|
|
Scheduler
|
|
Calculator
|
|
Memo Pad
|
|
Telecommunications Package
|
|
|
|
Q $159) In the Commodore LCD unit, what were the text screen dimensions?
|
|
|
|
A $159) 80 coumns by 16 rows. 1200 characters on screen.
|
|
|
|
Q $15A) What is the version number of the only known "bug-free" VIC-II
|
|
IC?
|
|
|
|
A $15A) 6569-R5. What's funny is that this chip was manufactured after
|
|
the Commodore 128 was introduced, so they used the 6569-R3 for the
|
|
development of the Vic-IIe chip (8563 series), which is buggy.
|
|
So, the newest PAL 64s have a better VIC than the C128.
|
|
|
|
Q $15B) Machine language programmer typically use the .X register to index
|
|
into small arrays. What is the largest byte-array size that can be
|
|
handled in this way?
|
|
|
|
A $15B) 256 bytes.
|
|
|
|
Q $15C) In the mid-1980's, Commodore started manufacturing IBM clone PCs.
|
|
One of the models had a name which was a type of horse. Name the term.
|
|
|
|
A $15C) The Commodore "Colt" PC.
|
|
|
|
Q $15D) What is the model number of the first mouse introduced for the
|
|
Commodore 64?
|
|
|
|
A $15D) The 1350.
|
|
|
|
Q $15E) What was the problem with the mouse in question $15D?
|
|
|
|
A $15E) As Commodore was either still developing the (now more
|
|
popular) 1351 mouse or the 1350 was designed as a lower cost
|
|
alternative, this mouse could only emulate a joystick. When you
|
|
rolled it up, the joystick "UP" pin was triggered. Likewise for the
|
|
other directions.
|
|
|
|
Q $15F) If you hold down the cursor key on the CBM 4000 series machine and it
|
|
does not repeat, what fact about the machine do you now know?
|
|
(other than the key doesn't repeat)
|
|
|
|
A $15F) It is a thin 40XX machine, meaning it could not be upgraded to an
|
|
80XX machine via chip swaps.
|
|
|
|
------- A publication describing BASIC on the Commodore makes the claim that
|
|
BASIC variables are limited to 5 characters, with the first two being
|
|
significant. The example to prove this point in the book is given as:
|
|
|
|
ABCDE=5 works, while
|
|
ABCDEF=6 does not.
|
|
|
|
The following questions refer to this claim:
|
|
|
|
Q $160) What is wrong with the above statement?
|
|
|
|
Q $161) What causes the variable ABCDEF to fail?
|
|
|
|
Q $162) How long can variable names really be?
|
|
|
|
Extra Credit: Who was the book publisher?
|
|
|
|
------- The Commodore LCD Computer system, much like the Commodore 65,
|
|
was a product that never reached the market. Do you remember this
|
|
pint-size CBM machine?
|
|
|
|
Q $163) How many keys were on the CLCD keyboard?
|
|
|
|
Q $164) What does LCD in the Commodore LCD stand for?
|
|
|
|
Q $165) Was an internal modem to be includes?
|
|
|
|
Q $166) Like the Plus/4 the CLCD unit had integrated software. What programs
|
|
were included?
|
|
|
|
Q $167) How many batteries of what type did the CLCD use for power?
|
|
|
|
Q $168) Approximately how much did the CLCD unit weigh?
|
|
|
|
Q $169) What version of BASIC was to be included with the CLCD computer?
|
|
|
|
Q $16A) The CLCD unit contained a port that could be used with a
|
|
Hewlett-Packard device. What did the device do?
|
|
|
|
Q $16B) What microprocessor did the CLCD unit utilize?
|
|
|
|
Q $16C) In addition to the usual inclusion of standard Commodore ports,
|
|
what two industry standard ports were included on the CLCD?
|
|
|
|
Q $16D) How much RAM did the CLCD computer include?
|
|
|
|
Q $16E) How many pixels are on the LCD screen on the CLCD machine?
|
|
|
|
Q $16F) How much ROM did the CLCD computer contain?
|
|
|
|
============================================================================
|
|
|
|
#(@)gfx: Hacking Graphics: Let's Get Graphical
|
|
by Rick Mosdell (rick.mosdell@canrem.com)
|
|
|
|
(c) September 1995 (used by permission)
|
|
|
|
#(A): Introduction
|
|
|
|
High resolution graphics on the C64 is not all that complicated. How to set
|
|
up the VIC-chip to see your bitmap and colors IS, so this will not become
|
|
a discussion on which bits to flip or where to put your blocks of data
|
|
inside a computer already renowned for its lack of space. Instead, I
|
|
am interested in the internal data formats of the only two graphics formats.
|
|
|
|
#(A): Definitions
|
|
|
|
nybble the first (lowest) or last(highest) group of 4 bits found in a:
|
|
|
|
byte the fundamental 8 bit unit of our C64: an 8-bit computer.
|
|
|
|
word two bytes side by side and related, ie. 16 bits. c64 pointers
|
|
into RAM are lo/hi byte style.
|
|
|
|
bitmap a contiguous block of data where a shape is defined when some
|
|
bits or bit-pairs take a fore-ground color and others take on
|
|
a background color.
|
|
|
|
color-ram a block of data which defines the colors for the bitmap,
|
|
thus completing the picture.
|
|
|
|
color nybble since the C64 has a maximum of nybble 16 colors, to conserve
|
|
space 2 colors fit into 1 byte.
|
|
|
|
LORES important! This would refer to pictures created by using the
|
|
normal 256-byte character set. Extensive use of the graphics
|
|
characters in lowercase plus RVSon/RVSoff here. These are NOT
|
|
graphic files and are text files stored in SEQ format.
|
|
|
|
MEDRES this refers to Koala Paint files and related formats.
|
|
|
|
HIRES this refers to Doodle files and their derivatives.
|
|
|
|
#(A): Doodle!
|
|
|
|
This graphics format is the simplest of all! Here the screen is
|
|
divided into 64000 pixels of light (320x200) and is truly HIRES. Neither
|
|
the text color-ram at $D800 nor the 4 background colors at $D021 apply at
|
|
all. The downside is that only 2 colors can be displayed at one time in an
|
|
8x8 pixel block. This is the format geoPaint uses (but allows for a whole
|
|
page displayed a screenful at a time). These files are prefixed with
|
|
"dd..." that when compressed become "jj...". They are PRG files that load
|
|
at $5C00. Internally, the 1K of color (1024 bytes) is first followed by 8K
|
|
of bitmap (8192 bytes). The "dd..." files are invariably 37 blocks long,
|
|
which makes sense since they are 9K long (36+ disk sectors each 254
|
|
bytes). The "1" bit of the bitmap uses the low nybble value of the
|
|
color-ram while the "0" bit displays the high nybble color.
|
|
Simple, straight-forward and direct! Some artists might find this
|
|
color restriction too hazardous to their health. Since our screen is
|
|
320x200 pixels (64000 total remember?) dividing by 8 will give us only
|
|
8000 bytes needed for the bitmap and only 1000 bytes necessary for
|
|
the color-ram. So this format actually wastes 216 bytes! Careful placement
|
|
of colors can result in spectacular HIRES pictures though: look for
|
|
the "Lobster" pic in geoPaint and the Doodle files "Middle Earth"
|
|
and "Pagoda". Other related formats are (refer to the program "Autograph+"
|
|
by Fuzzy Fox):
|
|
|
|
* OCP Art Studio
|
|
* RUN Paint HIRES
|
|
* SID/PIC HIRES
|
|
* (geoPaint)
|
|
|
|
#(A): Koala Paint
|
|
|
|
Koala is certainly the most colorful and interesting format. Here
|
|
the screen is MEDRES, resulting in dots double pixel width for a resolution
|
|
of 32000 elements (160x200). The loss of resol- ution is compensated by
|
|
the ability to display 4 colors at once in each 8x8 pixel block. Here you
|
|
have 2 blocks of color-ram, one wherever you put it AND the normal
|
|
color-ram at $D800. Your picture is also effected screen-wide by
|
|
the background color at $D021. These files, prefixed by "[cbm-1]pic...", are
|
|
PRG files that load at $6000. The same files, when compressed, are prefixed
|
|
by "gg...". That first character in the filename of the raw format means that
|
|
you cannot delete these files normally. It is made by pressing CBM-1
|
|
(orange) and is hex $81 (decimal 129). The only way I know to scratch
|
|
these files is by typing:
|
|
|
|
OPEN15,DV,15,"s0:[cbm-1]pic...":close15
|
|
|
|
Where DV is your current device. Here the creators of Koala were smart
|
|
and wasted NO space. Internally the file contains 8000 bytes for the
|
|
bitmap(not 8192 bytes), 1000 bytes (not 1024) for the movable color-ram,
|
|
1000 bytes for the color-ram at $D800, and (this IS important) ONE more
|
|
byte for the background color. The length ends up at 41 blocks which is
|
|
ok considering it is about 10K long. These double width dots are called
|
|
bit-pairs and they draw their colors from various sources:
|
|
|
|
%00 from the background color at $D021
|
|
%01 from the high nybble of the movable color-ram
|
|
%10 from the low nybble of the movable color-ram
|
|
%11 from the low nybble of the normal color-ram at $D800.
|
|
|
|
Interesting eh? There's your 4 colors and where they come from! Related
|
|
formats would be:
|
|
|
|
* Advanced OCP Art Studio
|
|
* Artist64
|
|
* Blazing Paddles
|
|
* RUN Paint MEDRES
|
|
* SID/PIC multi-color
|
|
|
|
#(A): Conclusion
|
|
|
|
Although I am not an expert on graphics screens (not am I claiming to be),
|
|
I think programmers should be aware of these two poular formats for
|
|
storing and displaying graphics on the Commodore 64/128.
|
|
|
|
============================================================================
|
|
|
|
#(@)error: ? DS, DS$: rem The Error Channel
|
|
|
|
In Commodore Hacking Issue #10, the end of the "Second SID Chip Installation"
|
|
article was omitted. The omitted section is included below. (SubRef: sid)
|
|
|
|
Certain early revisions of C=Hacking #10 are missing the end of the article
|
|
by Alan Jones entitled "Solving Large Systems of Linear Equations on a
|
|
C64 Without Memory". The omitted text is included below. (SubRef: linear)
|
|
|
|
#(A)sid: Second SID Chip Installation (Line 137 on)
|
|
(c) 1987 Mark A. Dickenson
|
|
|
|
Here comes the difficult part to explain. This is the coupling
|
|
circuit for the audio output. Here is a rough schematic.
|
|
|
|
|
|
|
|
Pin 27 on 12volts dc
|
|
SID chip resistor !
|
|
--. 10k ohm !collector
|
|
27!----.--/!/!/--.-----O 2n2222
|
|
--' ! ! !emitter
|
|
! ! !
|
|
<resistor ! !
|
|
>1k ! ! +
|
|
<ohm ! :--!]---to RCA
|
|
! ! ! 10 uf
|
|
! ! !electrol cap
|
|
! ! !
|
|
ground--- ! !
|
|
- ! <resistor
|
|
! >1k
|
|
! <ohm
|
|
! !
|
|
! !
|
|
! !
|
|
! ---ground
|
|
! -
|
|
!
|
|
=== 1000 pf (.001mf)
|
|
! capacitor
|
|
!
|
|
---ground
|
|
-
|
|
|
|
|
|
You can get the 12 volts you need for the transistor directly from pin #28 of
|
|
the SID chip.
|
|
|
|
If you need any help on constructing this circuit check out any of the
|
|
many books that have schematics on the C-64. This is similar to the one
|
|
already inside the C-64.
|
|
|
|
The ground wire from the RCA plug can be soldered to the main grounding
|
|
strip between the serial and video ports. The center wire will be
|
|
connected to the negative side of the 10uf electrolitic capacitor.
|
|
|
|
I still think you should have someone familier with electronics install
|
|
this circuit for you.
|
|
|
|
If you have a problem with some cartridges, you will have to install
|
|
a switch between pin #25 of BOTH SID chips. This will CUT the power to the
|
|
extra SID chip, effectivly turning it off. I would suggest that you turn
|
|
OFF the computer before you turn the extra SID chip ON or OFF with this
|
|
switch.
|
|
|
|
A good place to mount the switch and RCA plug is on the back of the
|
|
computer and above the monitor jack on the 64. I still haven't found a GOOD
|
|
place on the 128. A suggestion was made that if you are not going to use
|
|
the RF output on the computer, you can cut the wire going to that RCA plug.
|
|
Then connect your audio output wire to the center connector of the plug. This
|
|
does work but BE CAREFUL!
|
|
|
|
Good luck on the construction.
|
|
|
|
|
|
Mark A. Dickenson
|
|
|
|
#(A)linear: SOLVING LARGE SYSTEMS OF LINEAR EQUATIONS ON A C64
|
|
by Alan Jones (alan.jones@qcs.org) WITHOUT MEMORY (Line 239 on)
|
|
|
|
PROC slv(n#,nr#,i#,REF a(),REF c(),REF b(,),sdb#,REF sw#(),REF fail#) CL
|
|
OSED
|
|
// This routine solves a system of equations using the quartersolve
|
|
// algorithm with partial pivoting.
|
|
// It is called a "line at a time" and uses only
|
|
// 0.25*nn memory locations which enables larger problems to be solved
|
|
|
|
Slv calls the swap'real and swap'integer proocedures from the strings
|
|
package. The strings package is a ROMMED package on the Super Chip ROM.
|
|
|
|
It does exactly what it says, e.g. swap'real(a,b) is the same as:
|
|
t:=a; a:=b; b:=t.
|
|
|
|
Slv calls the sdot, isamax#, sswap, sscal, saxpy, and scopy routines
|
|
from the blas package. The blas package is LINKed to the program, but
|
|
it could, and should, be placed on EPROM.
|
|
|
|
Basic Linear Algebra Subroutines, BLAS
|
|
|
|
The BLAS were originally written for the Fortran language to speed
|
|
execution and streamline code used for solving linear algebra and other
|
|
matrix problems. The LINPACK routines, Ref. 3, use the BLAS and are
|
|
perhaps the best known. The idea is that the BLAS routines will be
|
|
highly optimized for a particular computer, coded in ML or a High Order
|
|
Language. Some operating systems even include BLAS like routines.
|
|
Writing fast efficient programs is then a simple matter of selecting the
|
|
best solution algorithm and coding it in a manner that makes best use of
|
|
the blas routines. There are blas routines for single precision, double
|
|
precision, and complex numbers. The level 1 BLAS perform operations on
|
|
rows or columns of an array and typicaly do n scalar operations
|
|
replacing the inner most loop of code. There are also level 2 BLAS that
|
|
perform n*n operations and Level 3 BLAS that perform n*n*n operations.
|
|
Nicholas Higham has coded most of the single precision level 1 blas
|
|
routines and put them in a Comal 2.0 package. The Comal blas package is
|
|
included on the Packages Library Volume 2 disk. I am not aware of ML
|
|
blas routines coded for any other C64/128 languages although this is
|
|
certainly possible and recommended.
|
|
|
|
The Comal blas routines behave exactly the same way that the Fortran
|
|
blas routines do except that Fortran can pass the starting address of an
|
|
array with just "a", while Comal requires "a(1)". The Comal blas will
|
|
allow you pass an array, by reference, of single or multiple dimensions
|
|
and start from any position in the array. If you code the blas routines
|
|
as ordinary Comal routines you have to pass additional parameters and
|
|
have separate routines for single dimensioned arrays and two dimensional
|
|
arrays. Note also that Fortran stores two dimensional arrays by
|
|
columns, and Comal (like many other languages) stores two dimensional
|
|
arrays by rows. If you translate code between Fortran and Comal using
|
|
blas routines you will have to change the increment variables.
|
|
|
|
Fortran Comal
|
|
dimension c(n), a(ilda,isda) DIM c(n#), a(lda#,sda#)
|
|
scopy(n,c,1,a(i,1),ilda) scopy(n#,c(1),1,a(i#,1),1)
|
|
scopy(n,c,1,a(1,j),1) scopy(n#,c(1),1,a(1,j#),sda#)
|
|
|
|
The first scopy copies array c into the ith row of array a. The second
|
|
scopy copies array c into the jth column of array a.
|
|
|
|
This is what scopy does in Fortran:
|
|
|
|
subroutine scopy(n,sx,incx,sy,incy)
|
|
real sx(1),sy(1)
|
|
ix=1
|
|
iy=1
|
|
do 10 i = 1,n
|
|
sy(iy) = sx(ix)
|
|
ix = ix + incx
|
|
iy = iy + incy
|
|
10 continue
|
|
return
|
|
end
|
|
|
|
The Comal BLAS does exactly the same thing. If coded entirely in COMAL
|
|
rather than as a package it would have to be different. The call would
|
|
change.
|
|
|
|
scopy(n#,c(1),1,a(1,j#),sda#) would have to become,
|
|
scopy(n#,c(),1,1,a(,),1,j#,sda#,sda#) and the Comal procedure might be:
|
|
|
|
PROC scopy(n#, REF x(), ix#, incx#, REF y(,), iy#, jy#, sdy#, incy#) CLOSED
|
|
iyinc#:=incy# DIV sdy# //assuming y is dimensioned y(?,sdy#)
|
|
jyinc#:=incy# MOD sdy#
|
|
FOR i#=1 TO n# DO
|
|
y(iy#,jy#):=x(ix#)
|
|
ix#:+incx#; iy#:+iyinc#; jy#:+jyinc#
|
|
ENDFOR
|
|
ENDPROC scopy
|
|
|
|
Note that more information has to be passed to the procedure and used
|
|
that the ML blas picks up automatically. Also we would need separate
|
|
procedures to handle every combination of single and multi dimensional
|
|
arrays. The Comal ML blas are indeed wonderful. For speed
|
|
considerations this should also be left as an open procedure or better
|
|
yet just use in line code.
|
|
|
|
Here is a very simplified description of what each of the routines in
|
|
the Comal BLAS package does.
|
|
|
|
sum:=sasum(n#,x(1),1) Returns sum of absolute values in x().
|
|
sum:=0
|
|
FOR i#:=1 TO n# DO sum:+ABS(x(i#))
|
|
|
|
saxpy(n#,sa,x(1),1,y(1),1) Add a multiple of x() to y().
|
|
FOR i#:=1 TO n# DO y(i#):+sa*x(i#)
|
|
|
|
prod:=sdot(n#,x(1),1,y(1),1) Returns dot product of x() and y().
|
|
prod:=0
|
|
FOR i#:=1 TO n# DO prod:+x(i#)*y(i#)
|
|
|
|
sswap(n#,x(1),1,y(1),1) Swaps x() and y().
|
|
FOR i#:=1 TO n# DO t:=x(i#); x(i#):=y(i#); y(i#):=t
|
|
|
|
scopy(n#,x(1),1,y(1),1) Copy x() to y().
|
|
For i#:=1 TO n# DO y(i#):=x(i#)
|
|
|
|
max#:=isamax#(n,x(1),1) Returns index of the element of x() with the
|
|
largest absolute value.
|
|
t:=0; max#:=1
|
|
FOR i#:=1 TO n#
|
|
IF ABS(x(i#))>t THEN t:=ABS(x(i#)); max#:=i#
|
|
ENDFOR i#
|
|
|
|
sscal(n#,sa,x(1),1) Scale x() by a constant sa.
|
|
FOR i#:=1 TO n# DO x(i#):=sa*x(i#)
|
|
|
|
snrm2(n#,x(1),1) Returns the 2 norm of x().
|
|
norm2:=0
|
|
FOR i#:=1 TO n# DO norm2:+x(i#)*x(i#)
|
|
norm2:=SQR(norm2)
|
|
|
|
srot(n#,x(1),1,y(1),1,c,s) Apply Givens rotation.
|
|
FOR i#:=1 TO n# DO
|
|
t:=c*x(i#) + s*y(i#)
|
|
y(i#):=s*x(i#) + c*y(i#)
|
|
x(i#):=t
|
|
ENDFOR i#
|
|
|
|
|
|
Bear in mind that each of these simple examples can be more complex as
|
|
was given for scopy. You now have enough information to write your own
|
|
BLAS routines in ML or the programming language of your choice, or to
|
|
expand the BLAS routine calls in slv to ordinary in line code.
|
|
|
|
You can also apply the BLAS routines in creative ways besides just
|
|
operating on rows or columns. For example you could create the identity
|
|
matrix with:
|
|
|
|
DIM a(n#,n#)
|
|
a(1,1):=1; a(1,2):=0
|
|
scopy(n#*n#-2,a(1,2),0,a(1,3),1) // zero the rest of the matrix
|
|
scopy(n#-1,a(1,1),0,a(2,2),n#+1) // copy ones to the diagonal.
|
|
|
|
References
|
|
|
|
1. Zambardino, R. A., "Solutions of Systems of Linear Equations with
|
|
Partial Pivoting and Reduced Storage Requirements", The Computer Journal
|
|
Vol. 17, No. 4, 1974, pp. 377-378.
|
|
|
|
2. Orden A., "Matrix Inversion and Related Topics by Direct Methods",
|
|
in Mathematical Methods for Digital Computers, Vol. 1, Edited by A.
|
|
Ralston and H. Wilf, John Wiley and Sons Inc., 1960.
|
|
|
|
3. Dongarra, J. J., Moeler, C. B., Bunch, J. R., Stewart, G. W.,
|
|
Linpack Users' Guide, SIAM Press, Philadelphia, 1979.
|
|
|
|
============================================================================
|
|
|
|
#(@)next: The Next Hack
|
|
|
|
"But wait, there's more!" Actually, there is, but you'll have to wait
|
|
until next issue for it. Here's a little appetizer of what's ahead in
|
|
Commodore Hacking issue #12
|
|
|
|
o All you cross-development folks, listen up! Issue #12 will enter the
|
|
realm of cross-compilers with Craig Bruce as he details the construction
|
|
of a high level language cross compiler. It'll be written in C and will
|
|
compile a a simplified but structured custom language including concepts
|
|
from BASIC, C, and Pascal. Concepts like declaration handling, expression
|
|
interpretion and optimization, and structure control definitions will be
|
|
discussed
|
|
|
|
o Gearing up for the 65C816S. C=Hacking will detail the new opcodes
|
|
available to programmers, show how to detect CPU clock speed on any
|
|
C64, accelerated or not, discuss pitfalls in code migration, and
|
|
possibly give a rundown on a prototype accelerator unit from CMD.
|
|
|
|
o SLIP, Sliding away.... C=Hacking will take an in-depth look at Daniel
|
|
Dallmann's SLIP-DEMO program and go over the SLIP and TCP/IP
|
|
protocols in detail as they relate to the Commodore.
|
|
|
|
o Here Boy, here Boy! Good Dog. The "FIDO's Nuggets" column will bring
|
|
readers up to date on the discussions in the FIDO CBM echo.
|
|
|
|
o The RumorMonger. The best rumors we've heard so far. Your mileage
|
|
may vary...
|
|
|
|
o All that and C=Hacking's regular columns.
|
|
|
|
So, set aside a place on that disk drive for the next issue now, because you
|
|
won't want to miss it...
|
|
|
|
============================================================================
|
|
#(@)bottom
|
|
|