This net-magazine is still alive after over two years suprising even myself. There should be more to come also!! And it's been late everytime it's been released. :-) I dunno - I'm trying not to make that a tradition but next time I don't think I'm going to set any firm dates so it can't possibly be late.
Lesee, first to address some questions and queries that have been going on over the network:
The articles in this issue of C=Hacking I'm especially pleased with. There are two articles concerning the VIC chip and its operations that detail how certain "magical" techniques are performed. Also, Marko Mäkelä has written a very detailed, interesting article on various memory techniques for the C-64. We also have a summary of the ACE programming / operating system and a referance guide on how to write applications for it. I've also included an InterNet guide that I've started writing to show individuals how to use the InterNet to get Commodore-64 / 128 / Vic-20 related material. Included within that is a list of FTP sites containing numerous programs.
Everyone who reads this article has had, or presently owns a Commodore computer of some kind. I own more than one, which is not uncommon among Commodore enthusiasts. Well, I bought my first Commodore computer in 1982, a brand new Vic-20 with some game cartridges. I had wanted an Atari, but father knew best and he told the then 11 year old son that computers would shape my life more than any game machine. Well, it is 11 years later and a Computer Engineering Degree earned, and I have spent many a night during that time playing on many models of Commdore equipment. Now, I would like to share the knowledge I have with you in an interesting way.
As you now know a little about me, let us see how much you know about the machines and company that binds us all together. The following is an installment of Commodore Trivia. These questions have been gleaned from books, magazines, persoanl knowledge, work on the machines in questions, and other fellow commodore users happy to share interesting bits of semi- useless knowledge concerning the CBM systems.
This installment consists of two parts, the December 1993 edition complete with answers and the January 1994 edition without answers. Each new issue of Commodore Hacking Magazine will contain more questions, as well as answers to the previous issue's questions. Each new edition is also posted every month on the 12th of the month on the Usenet newsgroup comp.sys.cbm. Winners will be announced on the newsgroup, and prizes may be awarded. For anyone wishing to submit answers from this article, please email your responses with question numbers preceeding each answer to :
brain@msen.com
The answers to this edition will be posted on the 12th of February in comp.sys.cbm with the next edition of questions. Have fun trying to answer the questions and feel free to send me a note with new questions. I can always use them.
[Ed's Note: In addition, the mailserver that I have setup for C=Hacking will make provisions to allow individuals to retrieve the newest set of questions and last month's answers. Currently not implemented, it should be available soon. Details in the next issue.
Also due to C= Hacking being published fairly irregularly and not every month the column here will contain answers to the last issue of C=Hacking's questions and have new questions for the month that it's released in.]
Jim Brain brain@msen.com
[This article is placed into public domain by the author. Copying encouraged]
This is the basic system of the Internet. Computers connected to other computers that are connected to others. In the above paragrph communication was limited because of geography - how close individuals were. The InterNet system; while geography does play a factor, relies more on how the sites grew up and were established as to how messages will get passed back and forth.
There are also other networks hooked up to the InterNet that provide auxilary services to their local group of computers. One large one is BITNET and UUCP. Various bbs's also carry items from the InterNet such as the BitNet news. In addition, online services such as Genie, Compuserve, and others offer "gate-ways" or ways of getting access to the resources of the InterNet.
Once you've gotten access to the InterNet you may be asking "Okay, I know what the InterNet _can_ give me - how do I do it?" Unfortunately, because the InterNet is run on differant computer systems this will vary from system to system. Your best bet would be to examine the documentation and help screens associated with the online service or college's facilities. Study them over until you can quote them backwards (well, not quite that much) - Study them over until you understand what they are saying. Also, having someone who is already experienced with the InterNet aid you in your explorations is a great help.
To send a message to me you'd use your mail program (the actual procedure varies depending on what type of machine you use) and tell it to send the message to my user name, "duck" at my site that I login at - (currently going to Pembroke State University) hence "pembvax1.pembroke.edu". So the full address with an "@" sign the computer needs to use to know how to seperate the computer name and the user name is "duck@pembvax1.pembroke.edu".
It's easy to talk to somebody in Mexico, Germany, Australia with this method and it's quicker than the U.S. Postal system (which, on the InterNet you'll see referred to as Snail Mail (or s-mail) due to it's slow delivery time compared to e-mail). Projects, Questions, Answers, Ideas and general chit-chat on how the family is doing, etc can be relayed over the InterNet.
There are also numerous abbreviations and notations that are used in
E-Mail. Some of them are:
You may also hear the phrase "my e-mail bounced". What this means is
that your message, much like a bounced check, did not work right and it
was returned to your account. Typically this happens because of
incorrect addresses, or an incorrect user name.
The only Email Server specifically designed for the Commodore computers
is one ran by the author. It major intent is that of distributing the
Commodore Hacking magazine as well as programs that are in the
magazine. To get help on how to use it send a message to the author in
the following format:
If anyone knows of any other Email Servers existing for the Commodore
computers please let the author know.
Two of these for the Commodore 64/128 line of computers are:
The newsgroup, Comp.Sys.Cbm supports discussion about anything under the
sun involving the Commodore 8 bit line of computers (and lately, even
talking about the old old ancient calculators that Commodore mae that
might not have even been 8 bit). Comp.Binaries.Cbm allows programs to be
"posted" or made available to everyone who wishes them. There are
programs available that will let you take the "encrypted" text-only
version of the program that you see on the screen and convert them into
the correct binary p rogram.
Basically the rules for newsgroups are: 1) Enjoy yourself, 2) Don't
harass others and 3) Try to stay on topic. Newsgroups are read by many
many people - typically you'll get a response to an inquiry within only
an hour or so - sometimes even sooner. But because they're read by so
many people chatter or "babble" as it's known, is also discouraged.
Don't hesitate to post any questions, concerns or comments but make sure
in each message that you post that you have a reason to post.
The major benefit of the Internet as I see it consists of the continued
support for the Commodore computers. Because all these differant means
of obtaining information are not sponsored by any one specific company
or individual the Commodore 8-bit line of computers are guranteed
continued support over the Internet. In addition, because the Internet
strongly frowns upon Commercial advertising you won't find numerous ads
or any other material urging you to "buy this, buy that" like you will
on some other serv ices.
[ The following is a list of FTP sites for the Commodore 64 and 128
computes and is currenty maintained by Howard Herman
(h.herman@GEnie.geis.com) and is used with his permission. He usually
posts an updated list to comp.sys.cbm newsgroup every month or so.]
I will try to keep this list as current and accurate as possible, so
that it can be a useful resource for users of the newsgroup.
PLEASE cooperate and send E-mail to me with any corrections and
updates. If a site has closed or no longer carries CBM software, let
me know and it will be deleted. If you uncover a site not listed,
tell me so that it can be added.
-----
To use this list on a UNIX system, just type 'ftp -----
In addition to the sites listed below there are hundreds of other
FTP sites on INet with interesting files covering every topic
imaginable. Take some time to seek out and explore these too.
Enjoy!
Most Commodore 64 programs do not utilize even nearly all of the 64 kB
random access memory space. By default, there are only 44 kilobytes of
accessible RAM. This article describes how you can take the hiding 20
kilobytes to use.
The 6510 MPU has an integrated I/O port with six I/O lines. This
port is accessed through the memory locations 0 and 1. The location 0
is the Data Direction Register for the Peripheral data Register, which
is mapped to the other location. When a bit in the DDR is set, the
corresponding PR bit controls the state of a corresponding Peripheral
line as an output. When it is clear, the state of the Peripheral line
is reflected by the Peripheral register. The Peripheral lines are
numbered from 0 to 5, and they are mapped to the DDR and PR bits 0 - 5,
respectively. The 8502 processor, which is used in the Commodore 128,
has seven Peripheral lines in its I/O port. The seventh line is connected
to the Caps lock or ASC/CC key.
Like most chips in the Commodore 64, the 6510 MPU uses the NMOS
(N-channel metal oxide semiconductor) technology. The NMOS switches
produce strong logical '0' levels, but weak '1' levels. The opposite
is the PMOS (P-channel metal oxide semiconductor) technology, which
cannot pull strong signals low, but is able to drive them high. The CMOS
technology (complementary metal oxide semiconductor), which combines
these two technologies, is able to drive both logical levels.
Because most integrated circuits in the C64 use the NMOS technology,
all hardware lines that are not outputs are driven to +5 volts with a
weak current. This is usually accomplished by pull-up resistors, large
resistances between the hardware lines and the +5 volt power supply
line. The resistors can be inside a chip or on the printed circuit
board. This allows any NMOS or CMOS chip to drive the line to the
desired state (low or high voltage level).
The difference between an input and an output is that an output uses
more current to drive the signal to the desired level. An input and an
output outputting logical '1' are equivalent for any other inputting
chip. But if a chip is trying to drive a signal to ground level, it
needs more current to sink an output than an input. You can even use
outputs as inputs, i.e. read them in your program.
You can use this feature to distinquish between the left
shift and the shift lock keys, although they are connected
to same hardware lines. The shift lock key has smaller
resistance than the left shift. If you make both CIA 1
ports to outputs (write $FF to $DC03 and $DC01) prior
reading the left shift key, only shift lock can change the
values you read from CIA 1 port B ($DC01).)
So, if you turn any memory management line to input, the external
pull-up resistors will make it look like it is outputting logical
'1'. This is actually why the computer always switches the ROMs in
upon startup: Pulling the -RESET line low resets all Peripheral lines
to inputs, thus driving all three processor-driven memory management
lines high.
The two remaining memory management lines are -EXROM and -GAME on
the cartridge port. Each line has a pull-up resistor, so the lines are
'1' by default. (In the Commodore 128, you can set the state of these
two lines prior to selecting the C64 mode, provided that you write the
mode switch routine yourself.)
Even though the memory banking has been implemented with a 82S100
Programmable _Logic_ Array, there is only one control line that seems
to behave logically at first sight, the -CHAREN line. It is mostly
used to choose between I/O address space and the character generator
ROM. The following memory map introduces the oddities of -CHAREN and
the other memory management lines. It is based on the memory maps in
the Commodore 64 Programmer's Reference Guide, pp. 263 - 267, and some
errors and inaccuracies have been corrected.
The leftmost column of the table contains addresses in hexadecimal
notation. The columns aside it introduce all possible memory
configurations. The default mode is on the left, and the absolutely
most rarely used Ultimax game console configuration is on the right.
(There have been at least two Ultimax cartridges on the market.) Each
memory configuration column has one or more four-digit binary numbers
as a title. The bits, from left to right, represent the state of the
-LORAM, -HIRAM, -GAME and -EXROM lines, respectively. The bits whose
state does not matter are marked with "x". For instance, when the
Ultimax video game configuration is active (the -GAME line is shorted
to ground, -EXROM kept high), the -LORAM and -HIRAM lines have no effect.
However, you should not use other addresses than those specified by
Commodore. For instance, the Commodore 128 mapped its additional I/O
chips to this same memory area, and the SID responds only to the
addresses D400-D4FF, also when in C64 mode. And the Commodore 65,
which unfortunately did not make its way to the market, could narrow
the memory window reserved for the MOS 6569/6567 VIC-II (or CSG 4567
VIC-III in that machine).
Note that the VIC-II always fetches its information from the
internal RAM, totally ignoring the memory configuration lines. There
is only one exception to this rule: The character generator ROM.
Unless the Ultimax mode is selected, VIC-II "sees" character generator
ROM in the memory areas 1000-1FFF and 9000-9FFF. If the Ultimax
configuration is active, the VIC-II will fetch all data from the
internal RAM.
But what if your program needs to use I/O? And how can you write the
return instruction to an I/O register while the I/O area is switched
off? You need a swap area for your program in normally visible memory.
The first thing your routine at $D000-$DFFF does is copying the I/O
routines (or the whole program) to normally visible memory, swapping
the bytes. For instance, if your I/O routines are initially being
stored at $D200-$D3FF, exchange the bytes in $D200-$D3FF with the
contents of $C000-$C1FF. Now you can call the I/O routines from your
routine at $D000-$DFFF, and the I/O routines can switch the I/O area
temporarily on to access the I/O chips. And right before exiting your
program at $D000-$DFFF swaps the old contents of that I/O routine area
in, e.g. exchanges the memory areas $D200-$D3FF and $C000-$C1FF
again.
What I/O registers can you use for the return instruction? There are
basically two alternatives: 8-bit VIC sprite registers or either CIA's
serial port register. The VIC registers are easiest to use, as they
act precisely like memory places: you can easily write the desired
value to a register. But the CIA register is usually better, as
changing the VIC registers might change the screen layout.
However, also the SP register has some drawbacks: If the machine's
CNT1 and CNT2 lines are connected to a frequency source, you must stop
either CIA's Timer A to use the SP register method. Normally the 1st
CIA's Timer A is the main hardware interrupt source. And if you use
the Kernal's RS232, you cannot stop the 2nd CIA's Timer A either. Also,
if you don't want to lose any CIA interrupts, you might want to know
that executing the RTS or RTI at SP register has the side effect of
reading the Interrupt Control Register, thus acknowledging an interrupt
that might have been waiting.
If you can't use either method, you can use either CIA's ToD seconds
or minutes or ToD alarm time for storing an RTI. Or, if you don't want
to alter any registers, use the VIC-II's light pen register. Before
exiting, wait for appropriate raster line and trig the light pen latch
with CIA1's PB4 bit. However, this method assumes that the control
port 1's button/light pen line remains up for that frame. After
trigging the light pen, causing the light pen Y co-ordinate register
($D014) to be $40 or $60, you have more than half a frame time to
restore the state of the I/O chips and return through the register.
You can also use the SID to store an RTI or RTS command. How is this
possible, you might ask. After all, the chip consists of read only or
write only registers. However, there are two registers that can be
controlled by program, the envelope generator and oscillator outputs
of the third voice. This method requires you to change the frequency
of voice 3 and to select a waveform for it. This will affect on the
voice output by turning the voice 3 off, but who would keep the voice
3 producing a tone while calling an operating system routine?
Also keep in mind that the user could press RESTORE while the Kernal
ROM and I/O areas are disabled. You could write your own non-maskable
interrupt (NMI) handler (using the NMI vector at $FFFA), but a fast
loader that uses very tight timing would still stop working if the
user pressed RESTORE in the middle of a data block transfer. So, to
make a robust program, you have to disable NMI interrupts. But how is
this possible? They are Non-Maskable after all. The NMI interrupt is
edge-sensitive, the processor jumps to NMI handler only when the -NMI
line drops from +5V to ground. To disable the interrupt, simply cause
an NMI with CIA2's timer, but don't read the Interrupt Control
register. If you need to read $DD0D in your program, you must add a
NMI handler just in case the user presses RESTORE. And don't forget to
raise the -NMI line upon exiting the program. Otherwise the RESTORE
key does not work until the user issues a -RESET or reads the ICR
register explicitly. (The Kernal does not read $DD0D, unless it is
handling an interrupt.) This can be done automatically by the two
following SP register examples due to one of the 6510's undocumented
features (refer to the descriptions of RTS and RTI below).
This stack routine will jump to your routine at $D000-$DFFF, as
described above. For performance's sake, copy the whole byte transfer
loop to the swap area, e.g. $C000-$C1FF, and call that subroutine
after doing the preliminary work. But what about files that load over
$C000-$C1FF? Wouldn't that destroy the transfer loop and jam the
machine? Not necessarily. If you copy those bytes to your swap area at
$D000-$DFFF, they will be loaded properly, as your program restores
the original $C000-$C1FF area.
If you want to make your program user-friendly, put a vector
initialization routine to the stack area as well, so that the user can
restore the fast loader by issuing a SYS command, rather than loading
it each time he has pressed RESET.
In order to fully understand the operation of this program, you need
to know how the instructions RTI, RTS and PHA work. There is some work
going on to reverse engineer the NMOS 6502 microprocessor to large
extent, and it is now known for most instructions what memory places
they access during their execution and for what purpose. The internal
procedures haven't been described in detail yet, but these
descriptions should be easier to read anyway.
For curiosity, I quote here the description of all instructions that
use the stack. The descriptions of internal operations are yet
inaccurate, but the memory accesses have been verified with an
oscilloscope. I will mail copies the whole document upon request. When
finished, the document will be put on an FTP site.
If the -NMI line is not asserted (the NMI interrupts are enabled), all
freezer cartridges should be able to halt any program. When the user
presses the "freeze" button, the cartridges halt the processor by
dropping the BA line low. Then they switch some of their own ROM to
the $E000 - $FFFF block by selecting the UltiMax configuration with
the -EXROM and -GAME lines. After this, they assert the -NMI line and
release the BA line. After completing the current instruction, the
processor will take the NMI interrupt and load the program counter
from the vector at $FFFA, provided that the NMI line was not asserted
already.
This approach is prone to many flaws. Firstly, if the processor is
executing a write instruction when the program is being halted, and if
the write occurred outside the area $0000 - $0FFF, the data would get
lost, if the UltiMax configuration was asserted too early. This can be
corrected to some extent by waiting at least two cycles after
asserting the BA line, as the processor will not stop during write
cycles. However, this is of no help if the processor has not gotten to
the write stage yet.
Secondly, if the instruction being executed is outside the area
$0000 - $0FFF, or if it accesses any data outside that area, the
processor will fetch either wrong parameters or incorrect data, or
both. If the instruction does not write anything, will only corrupt
one processor register.
Thirdly, if the NMI interrupts are disabled, pressing the "freeze"
button does not have any other immediate effect than leaving the
UltiMax mode asserted, which makes any system RAM outside the area
$0000 - $0FFF unavailable. It also forces the I/O area ($D000 - $DFFF)
on. If the program has any instructions or data outside the lowmost
four kilobytes, it will eventually jam, as that data will be something
else than the program expects.
One might except that reading from open address space should return
random bytes. But, in at least two C64's, the bytes read are mostly
$BD, which is the opcode for LDA absolute,X. So, if the processor has
a "good luck", it will happily execute only LDA $BDBD,X commands, and
it might survive to the cartridge ROM area without jamming. Or it
could eventually fetch a BRK and jump to the cartridge ROM via the
IRQ/BRK vector at $FFFE. The Action Replay VI has the familiar
autostart data in the beginning of both the ROML and ROMH blocks by
default, and that data could be interpreted as sensible commands. The
Action Replay VI was indeed able to freeze my test program, even
though I had covered its -RESET, -IRQ and -NMI lines with a piece of
tape, until I relocated the program to the first 4 kilobyte block.
However, it is possible to make some internal modifications to a C64,
so that it can freeze literally any program. You need to expand your
machine to 256 kilobytes following the documents on ftp.funet.fi in
the /pub/cbm/hardware/256kB directory. It will let you to reset the
computer so that all of the 64 kilobytes the previous program used,
will remain intact. If you add a switch to one of the memory expansion
controller's chip selection lines, the program being examined will
have no way to screw the machine up, as the additional memory management
registers will not be available.
A few enhancements to this circuit are required so that you can freeze
the programs without losing the state of the I/O chips. You will also
need to replace the Kernal ROM chip with your own code, if you do not
want to lose the state of the A, X, P and S registers. Unfortunately
this circuit will not preserve the state of the processor's Peripheral
lines (its built-in I/O port mapped to the memory addresses 0 and 1),
nor does it record the program counter (PC). I have a partial solution
to the PC problem, though.
If you are interested in this project, contact me. I will design the
additional hardware, and I will program the startup routines, but I
certainly do not have the time to program all of the freezer software.
Most of the freezer software could be in RAM, so it would be very easy
to develop it, and you could even use existing tools by patching them
slightly.
When we don't have to worry about bad lines, we have enough time to
open the borders and do some other effects too. It is not necassary to
change the vertical scroll on every line to get rid of the bad lines,
just make sure that it never matches the line counter (or actually the
least significant 3 bits).
You can even scroll the bad lines independently and you have FLD -
Flexible Line Distance. You just allow a bad line when it is time to
display the next character row. With this you can bounce the lines or
scroll a hires picture very fast down the screen.
(*** end of Albert's paragraph ***)
Horizontal scroll register can move the screen by eight pixels. This
isn't even nearly enough to produce a really stunning effect. You have
to move the graphics itself, fortunately with a resolution of one
character position (one byte) only, the rest can be done with the scroll
register. During one scan line there is no time to move the actual data,
you can only move a pointer. Changing the video matrix pointer won't
help, because VIC (video interface controller) will fetch the character
codes only at certain times, called bad lines. You can change the
character set pointer instead, because VIC reads the data it displays
directly from the character set memory.
The shift is done so that on each scan line we update the horizontal
scroll register ($D016) with the three lowest bits of the shift value.
We use the other bits to select the right character set ($D018). In a
tech-tech the shift value changes during the display of the whole
picture, and the values are stored in a table. In addition to that, the
shift values should be put into two tables, one for the horizontal
scroll register and another for the character set select. This is
necessary, because there is no time for extra calculations on a bad
line.
Because we have to change the character set and x-scroll dynamically, we
also need a raster routine to show a tech-tech. A raster routine is a
routine which is synchronized to the electron beam. This eats up the
processor time: the bigger the picture, the less time is left over for
other activities. On other than bad lines you can do other funny things,
like change the color of the background or border.
You can use a joystick to control the movement of the tech-tech. The
stick decreases or increases the shift add value in a resolution of a
half pixel. When the shift reaches its highest/lowest value, the
direction of the add is reversed. Just experiment with it.
However, there is one trick you can use to get all of the sprites on the
screen, with variable movements and color bars etc. You do not change
the x-coordinates, but the data itself on each scan line. In fact you
change the sprite image pointers. There is multiple sprite pictures,
where the graphics is shifted horizontally, just like the normal
tech-tech charsets. Because of this, the sprites have to be placed side
by side. No gaps are allowed. By changing the image pointers you can get
the graphics to move horizontally on each line as you wish. With
multicolor sprites you have to remember that one pixel corresponds to
two bits - the movement is not so smooth.
Wait ! How come there is enough time to change the sprite pointers, when
there is not time to change the coordinates ? This is another pointer
trick. VIC reads the sprite image pointers from the end of the current
video matrix, normally $07f8. You just have to change the video matrix
pointer ($D018) to change all of the image pointers. This takes only
eight cycles and there is plenty of time left for other effects on each
scan line. If you use only one video bank, you can get the sprite
picture to 16 different places. This allows also another kind of
effects, just use your imagination.
So what is ACE all about? Well, originally I tried a very ambitious
project of writing a multitasking operating system for the 128. It got
it partially working, but it was much too fragile and incomplete to be
released. It was a white-elephant project. So, then then it came to me
that I was aiming much too high. What I needed was a much simpler
system, one that would give the type of programming interface and
built-in features that I wanted, but one that was close enough to the
Commodore Kernal that it would not require much of a programming effort
to hack together a minimal implementation. And thus, there was ACE-128
Release #1. And I saw it was good.
What I wanted was a system that would be easier to program than the
Commodore Kernal with all its weird and wonderful device types,
non-existent memory management, and single-application design. The
first important feature of this environment was to be able to pass
arguments from a command line to an application program by typing them
on the command line of the shell. It is so annoying to load up a
program in BASIC, run it, and have it ask you for filenames in some
highly inconvenient way.
Another important system feature is to make near and far memory
management part of the system, and to make far memory convenient to use
for storing massively bulky data. And so it was. Also, we want to use
custom device drivers. Commodore didn't really come through with the
device drivers it provided. They are all REALLY SLOW. And so that was,
also, although more custom device drivers are needed. We want to have
the capability of making programs work together, rather than having
programs that are totally incompatible. This functionality is still
under construction. Programs will work together in this uni-tasking
environment by allowing a program to execute another program as a
sub-task, and then having control return to the calling program upon
exit. Finally, we want some good quality applications and a powerful
command shell. This is still being worked on and progress is coming
slowly. Oh, almost forgot; we also want all programs to work on both
the C64 and C128, and they do.
This documentation refers to ACE release #10, which has not been
released yet (or even programmed). In fact, the current release is #9.
Release #10 will be spruced up from the inside out to support the system
interface described in this document. The current release is not being
described, because some of its features are not the best they could
possibly be. Note, however, that the basic features, like "open",
"read", "dirread", and argv are not going to change. Note also that the
version number of this "P.R.G." is 0.9. This is because this is the
first incarnation of this document and, considering its nature, is bound
to hold a large number of small errors.
ID: "aceID" is a two-byte variable. Its purpose is to allow user
programs to be sure that they are executing on top of ACE. The low byte
(i.e., the first byte) must be equal to the symbolic constant "aceID1",
and the high, "aceID2". This will allow ACE applications to inform idiot
users that they cannot simply BOOT the program from BASIC, but rather
they must run ACE first.
ARGC: "aceArgc" is a two-byte unsigned number. It gives the number of
arguments passed to the application by the program (usually the command
shell) that called the application. The first argument is always the
name of the application program, so the count will always be at least
one. Other arguments are optional.
ARGV: "aceArgv" is a two-byte RAM0 pointer. Pay attention. This
pointer points to the first entry of an array of two-byte pointers which
point to the null-terminated strings that are the arguments passed to
the application program by the caller. (A null-terminated string is one
that ends with a zero byte). To find the address of the N-th argument
to an application, multiply N by two, add the "aceArgv" contents to
that, and fetch the pointer from that address. In this scheme, the
ever-present application name is the 0-th argument. The argv[argc]
element of the argument vector will always contain a value of $0000, a
null pointer.
MEM-TOP: "aceMemTop" is a two-byte RAM0 pointer. This points to one
byte past the highest byte that the application program is allowed to
use. All application programs are loaded into memory at address
"aceAppAddress" (next section), and all memory between the end of the
progam code and "aceMemTop" can be used for temporary variables, file
buffers, etc. The main problem with this approach is that there are no
guarantees about how much memory your application will get to play with.
Many applications, such as simple file utilities, can simply use all
available memory for a file buffer, but other programs, such as a file
compressor, may have much greater demand for "near" memory. [Note: this
variable has a different name in Release #9].
SHELL-PATH: "aceShellPath" is a two-byte RAM0 pointer. This points to
the page of memory that stores the pathnames of directories to search
through in order to find executable files. Each pathname is stored as a
null-terminated string, and the list is terminated by an empty string
(containing only the zero character). This is intended to be used by
the shell program, or any other program that is so inclined, to examine
or alter the search path. The search paths specified in the path page
are global variables and are used by all programs that make the "exec"
system call. This mechanism for reading/altering the executable search
path may be changed in the future.
SHELL-ALIAS: "aceShellAlias" is a two-byte RAM0 pointer. This points to
the page of memory that stores the aliases to be used with the command
shell. An alias is a string that is substituted in the place of a
command name on a shell command line whenever a certain command name
comes up. For example, you might specify if the user enters the command
"list a:" that the command name "list" be string-replaced with "cls;xls
-l". Each alias is stored with the command name first, followed by an
equals character ("="), followed by the string to substitute, followed
by a zero. The alias list is terminated by an empty string. This
mechanism may be extended in the future to allow multiple pages of
aliases, or may be changed completely.
CUR-DIR-NAME: "aceCurDirName" is a two-byte RAM0 pointer. It points to
the null-terminated string indicating the current directory. The user
is not supposed to modify this value, and the value will not always give
a full pathname. The implementation of this feature may need to change
in future versions of ACE.
ACE-EXIT-DATA: "aceExitData" is a two-byte RAM0 pointer. It points to
the 256-byte buffer allocated for user programs to give detailed return
information upon exiting back to their parent program. See the "exit"
system call. User programs are allowed to read and write this storage.
An example use of this feature would be a compiler program returning the
line number and character position, and description of a compilation
error to a text editor, so the editor can position the cursor and
display the error message for user convenience. The implementation of
this feature may need to change in future versions of ACE.
DIRENT-BUFFER: "aceDirentBuffer" is a buffer used for storing directory
information read with the "dirread" system call, and is
"aceDirentLength" bytes long. Only a single directory entry is
(logically) read from disk at a time. The individual fields of a read
directory entry are accessed by the fields described next. This field
is also used for returning disk name information and the number of bytes
free on a disk drive (see the "dirread" system call).
DIRENT-BYTES: "aceDirentBytes" is a four-byte (32-bit) unsigned field.
As always, the bytes are addressed from least significant to most
significant. This field gives the number of bytes in the file. Note
that this value may not be exact, since Commodore decided to store sizes
in disk blocks rather than bytes. For devices that report only block
counts (i.e., every disk device currently supported), the number of
bytes returned is the number of blocks multiplied by 254. This field,
as well and the other dirent fields are absolute addresses, not offsets
from aceDirentBuffer.
DIRENT-DATE: "aceDirentDate" is an eight-byte array of binary coded
decimal values, stored from most significant digits to least
significant. The first byte contains the BCD century, the second the
year, and so on, and the last byte contains the number of tenths of
seconds in its most significant nybble and a code for the day-of-week in
its least significant nybble. Sunday has code 1, Monday 2, etc.,
Saturday 7, and a code of 0 means "unknown". This is the standard
format for all dates used in ACE. This format is abstracted as
"YY:YY:MM:DD:HH:MM:SS:TW". For disk devices that don't support dates,
this field will be set to all zeroes, which can be conveniently
interpreted as the NULL date, negative infinity, or as the time that
J.C. was a seven-year-old boy.
DIRENT-TYPE: "aceDirentType" is a three-character (four-byte)
null-terminated string. It indicates what type the file is, in
lowercase PETSCII. Standard types such as "SEQ" and "PRG" will be
returned, as well and other possibilities for custom device drivers.
DIRENT-FLAGS: "aceDirentFlags" is a one-byte field that is interpreted
as consisting of eight independent one-bit fields. The abstract view of
the fields is "drwx*-et". "d" means that the item is a subdirectory
(otherwise it is a regular file), "r" means the item is readable, "w"
means the item is writable, and "x" means the item is executable. The
"x" option is really not supported currently. "*" means the item is
improperly closed (a "splat" file in Commodore-DOS terminology). The
"-" field is currently undefined. "e" means that the value given in the
"aceDirentBytes" field is actually exact, and "t" means the file should
be interpreted as being a "text" file (otherwise, its type is either
binary or unknown). The bit fields are all booleans; a value of "1"
means true, "0", false. The "d" bit occupies the 128-bit position, etc.
DIRENT-NAME-LEN: "aceDirentNameLen" is a one-byte number. It gives the
number of characters in the filename. It is present for convenience.
DIRENT-NAME: "aceDirentName" is a 16-character (17-byte) null-terminated
character string field. It gives the name of the file or directory or
disk. Filenames used with ACE are limited to 16 characters.
The "aceMem" group of constants are for use with the "pagealloc" system
call, except for "aceMemNull", which may be used by application programs
for indicating null far pointers. The "pagealloc" call allows you to
specify what types of memory you are willing to accept. This is
important because the difference types of memory have different
performance characteristics. ACE will try to give you the fastest
memory that is available. Ram Expansion Unit memory has startup and
byte-transfer times of about 60 us (microseconds) and 1 us,
respectively. This is the fastest type of far memory. Internal memory
has a startup time of 24 us and a byte-transfer time of between 7 and 14
us (depending on whether accessing RAM0 or RAM1+). REU memory accessed
through a RAMLink has a terrible startup time of 1000 us and a
byte-transfer time of 2 us. Direct-access RAMLink memory has a startup
time of 1000 us and a byte-transfer time of 16 us. All these times are
for the C128 in 2 MHz mode.
The "aceErr" group gives the error codes returned by system calls. The
error codes are returned in the "errno" variable. Not all possible
error codes from Commodore disk drives are covered, but the important
ones are. Finally, the "std" files group give the symbolic file
descriptor identifiers of the default input, output, and error output
file streams.
The function returns a file descriptor number, which is a small unsigned
integer that is used with other file calls to specify the file that has
been opened. File descriptors numbered 0, 1, and 2 are used for stdin,
stdout, and stderr, respectively. The file descriptor returned will be
the minimum number that is not currently in use. These numbers are
system-wide (rather than local to a process as in Unix), and this has
some implications for I/O redirection (see the "fdswap" call below).
Restrictions: only so many Kernal files allowed to be open on a disk
device, and there is a system maximum of open files. You will get a
"too many files" error if you ever exceed this limit. Also, because of
the nature of Commodore-DOS, there may be even tighter restrictions on
the number of files that can be simultaneously open on a single disk
device, resulting in a "no channel" error. Note that this call checks
the status channel of Commodore disk drives on each open, so you don't
have to (and should not anyway).
If the current program exits either by calling "exit" or simply by doing
the last RTS, all files that were opened by the program and are still
open will be automatically closed by the system before returning to the
parent program.
The call returns the number of bytes read in both the .AY register pair
and in (zw), for added convenience. [Note: in ACE Release #9, the
number of bytes read are returned only in the .AY registers, not in
(zw).] A return of zero bytes read means that the end of the file has
been reached. An attempt to read beyond the end of file will simply
give another EOF return. End of file is also returned in the .Z flag of
the processor.
Each subsequent call to this routine will return the next directory
entry in the directory. All of the "dirent" fields will be valid for
these.
Then, after all directory entries have been read through, the last call
will return a directory entry with a null (zero-length) name. This
corresponds to the "blocks free" line in a Commodore disk directory
listing. The "aceDirentBytes" field for this last entry will be set to
the number of bytes available for storage on the disk. On a Commodore
disk drive, this will be the number of blocks free multiplied by 254.
After reading this last entry, you should close the directory.
At any time, if something bizarre happens to the listing from the disk
that is not considered an error (I don't actually know if this is
possible or not), then the .Z flag will be set, indicating the abrupt
ending of the directory listing.
All of these calls use a 32-bit pointer that is stored in the zero-page
argument field "mp" (memory pointer). This field is to be interpreted
as consisting of low and high words. The low word, which of course come
first, is the offset into the memory "bank" that is contained in the
high word. Users may assume that offsets within a bank are continuous,
so operations like addition may be performed without fear on offsets, to
access subfields of a structure, for example. You may not, however,
make any interpretation of the bank word. An application should only
access far memory that it has allocated for itself via the "pagealloc"
call.
The X and Y registers contain the start and end "types" of far memory to
search for the required allocation. The possible types are mentioned in
the System Constants section. The numeric values for the "aceMem"
constants are arranged in order of accessing speed. So, if your
application has speed requirements that dictate, for example, that
RAMLink memory should not be used, then you would call "pagealloc" with
a search range of .X=0 to .Y=aceMemInternal. If you wanted to say you
are willing to accept any memory the system can give to you, you would
specify .X=0 to .Y=255. The values of 0 and 255 will be converted to
the fastest and slowest memory available. ACE will give you the fastest
type of memory, from what you specify as acceptable, that it can. If
you had an application that you didn't want to waste the high-speed
memory on, you could first call "pagealloc" asking for slow memory, such
as .X=aceMemRLREU to .Y=255, and if there is none of that type of memory
left, make another call with .X=0 to .Y=aceMemRLREU-1.
This routine will then search its available free memory for a chunk
fitting your specifications. If it cannot find one, the routine will
return a "insufficient memory" error and a null pointer. Note that this
error may occur if there is actually the correct amount of memory free
but just not in a big enough contiguous chunk. If successful, this
routine will return in "mp" a pointer to the first byte of the first
page of the allocated memory.
If you call a subprogram with the "exec" call while the current program
is holding far memory, that far memory will be kept allocated to your
program and will be safe while the child program is executing. If you
don't deallocate the memory with "pagefree" before exiting back to your
parent program, then the system will automatically deallocate all memory
allocated to you. So, have no fear about calling "exit" if you are in
the middle of complicated far memory manipulation when a fatal error
condition is discovered and you don't feel like figuring out what memory
your program owns and deallocating it.
Some applications will want to have the most amount of memory to work
with, and if there is free space in the application program area that
the program is not using directly, then you may want to use that as
"far" memory. To do this, you will need to write your own stub routines
that manage page allocation and deallocation requests to the near
memory, and calls the "pagealloc" and "pagefree" routines to manage the
far memory. The "sort" program distributed with ACE does this. Please
note that you CANNOT simply free the unused memory of the application
program area and expect the system to manage it. Bad stuff would
happen.
Some applications will want to have a byte-oriented memory allocation
service rather than a page-oriented service. You can build a
byte-oriented service on top of the page-oriented service in your
application programs that manage memory for the application and ask the
system for pages whenever more memory is required by the application.
Note that this still means that allocated memory will be freed
automatically when an application exits. The "sort" program implements
this byte-oriented service, so you can check its source code to see how
this is done (or to simply cut and paste the code into your own
program).
The calls are designed around the C-128/PET concept of a window. There
is only one active window on the display at a time, which may be is
large as the entire screen or as small as 1x1 character cells. This
window is very cheap to setup and tear down. An application can have
multiple windows on the screen by switching the active window around.
In the calls below, all mention of "sw" in the arguments and return
values refer to the "syswork" array. For many calls, there is a
"char/color/ high-attribute" argument. This argument determines which
parts of a screen location will be modified. There are three components
to each screen location: the character code, the color code, and the
high-attributes. The character code is exactly the same as the PETSCII
code for the character that you want to display (unlike the screen-code
arrangement that Commodore chose). There are 128 individual characters
in the normal PETSCII positions, and 128 reversed images of the
characters in the most sensible other positions. The codes are as
follows:
The screen-control system calls are as follows:
The color of the total field length will be filled in with "color". You
can use the "char/color/hi-attr" modification flags to specify what is
to be changed. If you were to, for example, specify that the colors of
the field are not to be changed, then the call would execute faster.
The first thing that a process that wants to call another program must
do is set up the arguments to be passed in. All arguments must be
null-terminated strings. These arguments are to be put into high
memory, starting from one less than the location pointed to by
"aceMemTop" and working downward. It does not matter in which order the
strings are placed, as long as they are all grouped together. Then,
immediately below the strings comes the vector of two-byte RAM0 pointers
that point to the strings. This array must be in order, with the lowest
entry pointing to the first (zero subscript) string, etc., the second
highest entry pointing to the last string, and the highest entry
containing the value $0000. An asciigram follows:
After setting up the arguments, you'll want to set up any redirections
of stdin, stdout, or stderr you'll be needing. Because there is only
one open file table in the whole uni-tasking system, you'll have to
manipulate existing entries using the "fdswap" system call described
earlier. The open file table is inherited by the child process. Note
that if it closes any of the open files it inherited, then they are also
closed to your use also. If the child accidentally leaves open any
files it opened, they will be closed by the system before you are
reactivated.
Finally, before the call is made, you have to save any volatile local
information into "far" memory. All application zeropage and application
area memory will be modified by the called program, so you must save
whatever you will need to continue after the return to be able to
continue. As mentioned earlier, all of the "far" memory that a parent
program owns will be safe, so you can save your volatile information
there, in any format you wish. All you have to do is save the pointer
to the far memory into the [mp] pointer. Upon return of the child
process, the value you put into [mp] will be restored, and you can then
restore your volatile information out of far storage. If you wish to
save no volatile information, then you can just leave garbage in the
[mp] value, since it will not be interpreted by the system.
Alright, so now you call the "exec" primitive, the child program is
loaded, executed, and it returns.
At this time, the parent program (that's you) is reloaded from wherever
it was loaded originally and you are returned to the instruction
immediately following the "jsr exec", with your processor stack intact
but the rest of your volatile storage invalid. Even if there is an
error return (carry flag set), your volatile storage will still need to
be restored, since the application area may have been overwritten before
the error was discovered. In the case of an error return, the child
process will not have been executed. If the system is unable to reload
the parent program (you), then an error return is given to your parent,
and so on, as far back as necessary. (This is a minor exception to the
rule that an error return indicates that a child didn't execute; in this
case, the child didn't complete).
You are also returned an "exit code", which will have
application-specific meaning, although standard programs (e.g., shell
script) interpret the value as: 0==normal exit, anything else==error
exit. The X register is also set to indicate the amount of
"aceExitData" that is used, to allow for more complicated return values.
[Note: This call is different in Release #9].
You may set up a return data in "aceExitData", up to 255 bytes worth,
and load the number of bytes used into .X if you wish. It is
recommended that the first field of this data be a special identifier
code so programs that cannot interpret your data will not try. You
cannot give any far pointers in your return data, since all far memory
allocated to you will be freed by the system before returning to your
parent.
The next six bytes of object code (which are the first six bytes of a
program) describe the header required by ACE programs. The first three
bytes must be a JMP to the main routine of the program. The next three
bytes must have the values "aceID1", "aceID2", and "aceID3",
respectively. And that's all there is to it. The rest of the program
can be organized however you want it to be.
In this example, we set up the arguments for the "write" system call to
print the string "Hello, cruel world." plus a carriage return to
standard output. Note that this string does not need a terminating null
($00) character since the write call takes a buffer length. The program
then returns to its calling environment via an RTS. This will cause an
implied "exit(0)" to be performed by the system, returning to the parent
program.
Although this program does not take advantage of this, an application
program may use zero-page locations $0002 through $007f for storage
without fear of having the storage trodden upon by the system. Also,
the processor stack may be used from the point it was at upon entry to
your program all the way down to the bottom. I will be doing something
about ensuring there is always enough processor space for an application
to use in the future, but for now, all applications have to share the
single page of processor stack storage.
Finally, an application program starts at location "aceAppAddress" (plus
six) and is allowed to use memory all the way up to one byte less than
the address pointed to by "aceMemTop" for its own purposes. Currently,
this amount of space is on the order of magnitude of about 24K. This
will be increased in the future.
Application programs are not to access I/O features or even change the
current memory configuration during execution. All I/O and unusual
contortions must be performed by ACE system calls; otherwise, we could
end up in as bad a shape as MESS-DOS.
Email Servers
Another large way of getting information is from individuals running
what are E-Mail servers from their accounts or from specific accounts.
From Email servers you may request certain files; catalogs of programs
that are availble for request; send messages to be distributed to other
individuals and automatically subscribe yourself to the mailing list for
new items.
To: duck@pembvax1.pembroke.edu
Subj: MAILSERV
Body of message: HELP
This specific mailserver is ran twice a day so you should get your reply
within approximately 12 hours. Please be sure to have a subject line of
"MAILSERV".
NewsGroups
One of the primary purposes of the InterNet is for educational research
and discussion. For this purpose, there are currently over 2000
newsgroups established dealing with a wide range of social, politicial,
science, computer and educational topics. Some of these range to inane,
whimsical, to practical and useful.
comp.sys.cbm
comp.binaries.cbm
The names for the newsgroups start with a short abbreviation such as
"comp" for computers, "sci" for science, "bio" for biology, etc... The
second group of letters stand for the type of newsgroup "sys for system,
binaries for binaries etc..." while the third describes it better -
"cbm" in this case for Commodore Business Machines.
So What's Out There?
So why should you be interested in the Internet? Imagine, if you will,
being able to ask questions to numerous individuals, download the latest
in shareware and public-domain software, know the "rumours" and topics
before they exist all for free? (Or at least, only for what your
"hookup" method charges - see Gaining Access to the InterNet latter).
That's what's out on the Internet. Any question you have - there is sure
to be an answer for - any software you're looking for you stand an
extremely good chance of finding something along the lines of your
needs.
FTP Sites
FTP stands for File Transfer Protocols and is a method of obtaining
programs that are stored on another system's computers. There are
numerous FTP sites out there in InterNet land - one of the best
currently available for the Commodore computers is that of R.Knop's site
at ccosun.caltech.edu.
This is the list of FTP sites containing software and programs
specific to the Commodore 64 and 128 computers.
Hiding kilobytes
by Marko Mäkelä Memory management
The Commodore 64 has access to more memory than its processor can
directly handle. This is possible by banking the memory. There are
five user configurable inputs that affect the banking. Three of them
can be controlled by program, and the rest two serve as control lines
on the memory expansion port.
A note concerning the I/O area
The I/O area is divided as follows:
The video chip
The MOS 6567/6569 VIC-II Video Interface Controller has access to
only 16 kilobytes at a time. To enable the VIC-II to access the whole
64 kB memory space, the main memory is divided to four banks of 16 kB
each. The lines PA0 and PA1 of the second CIA are the inverse of the
virtual VIC-II address lines VA14 and VA15, respectively. To select a
VIC-II bank other than the default, you must program the CIA lines to
output the desired bit pair. For instance, the following code selects
the memory area $4000-$7FFF (bank 1) for the video controller:
An application: Making an operating system extension
If you are making a memory resident program and want to make it as
invisible to the system as possible, probably the best method is
keeping most of your code under the I/O area (in the RAM at
$D000-$DFFF). This area is very safe, since programs utilizing it are
rare, since they are very difficult to implement and to debug. You
need only a short routine in the normally visible RAM that pushes the
current value of the processor's I/O register $01 on stack, switches
RAM on to $D000-$DFFF and jumps to this area. Returning from the
$D000-$DFFF area is possible even without any routine in the normally
visible RAM area. Just write an RTS or an RTI to an I/O register and
return through it.
An example: A "hello world" program
To help you in getting started, I have written a small
example program that echoes the famous message "hello, world!" to
standard output (normally screen) using the Kernal's CHROUT subroutine.
After the initialization routine has been run, the program can be started
by commanding SYS 300. I used the Commodore 128's machine language
monitor to put it up, but it was still pretty difficult to debug the
program.
Freezer cartridges
There are many cartridges that let you to stop almost any program for
"back-up" purposes. One of the most popular of these freezer
cartridges is the Action Replay VI made by Datel Electronics back in
1989. The cartridge has 8 kilobytes RAM and 32 kilobytes ROM on board,
and it has a custom chip for fiddling with the C64 cartridge port
lines -EXROM, -GAME, -IRQ, -NMI and BA.
Building an unbeatable freezer circuit
As you can see, it is totally impossible to design a freezer cartridge
that freezes any program. If the program to be freezed has disabled
the NMI interrupts, and if its code runs mostly at $0000 - $0FFF or
$D000 - $DFFF, the computer will more probably hang than succeed in
freezing the program.
FLD - Scrolling the screen
by Marek Klampar (klampar@elf.stuba.sk)
Scrolling the screen
VIC begins to draw the screen from the first bad line. VIC will know
what line is a bad line by comparing its scan line counter to the
vertical scroll register : when they match, the next line is a bad
line. If we change the vertical scroll register ($d011), the first bad
line will move also. If we do this on every line, the line counter in
VIC will never match with it and the drawing never starts (until it is
allowed to do so).
Tech-tech - more resolution to vertical shift.
by Pasi 'Albert' Ojala (po87553@cs.tut.fi _or_ albert@cc.tut.fi)
Written on 16-May-91 Translation 02-Jun-92
(All timings are in PAL, principles will apply to NTSC too)
One time half of the demos had pictures waving horizontally on the
width of the whole screen. This effect is named tech-tech, and the
audience was puzzled. You can move the screen only eight pixels using
the horizontal scroll register. This effect was done using character
graphics. How exactly and is the same possible with sprites ?
Character set-implementation has its restrictions
Because horizontal movement is done by changing the character sets, the
picture or text must be pure graphic and the character codes in the
video matrix must be in a numerical order. The normal picture is in the
first character memory and in the next one it is shifted one character
position to the right. One video bank can hold only seven full character
memories besides the video matrix. This limits the movement of the
picture to 56 pixels. It is possible to get more movement if you use
smaller picture or another video bank.
An example program
The demo program uses video bank 2, memory addesses $4000-7fff. The
video matrix is in the beginning of the bank. Only inverted chars are
used for the graphics, this way we have all eight character memories
available and the maximum shift is 64 pixels. The area for the tech-tech
in the video matrix is eight character rows high, but it has identical
graphics on every line. This is why we use only 320 bytes from each
character set.
You can do it on the screen, how about borders ?
Because you cannot get characters to the border, you might think that it
is impossible to make a tech-tech effect in the borders. It takes so
much time to change sprite x-coordinates, that you can change only some
of them. There is time for five sprite moves, if you do not need to
change the most significant (9th) bit of the x-coordinate. On the other
hand, you could design the movements directly to the sprites and then
just change the images, but then the movements would be constant.
C64 executable version of the demo program (PAL)
ACE-128/64 PROGRAMMER'S REFERENCE GUIDE (version 0.9, for Release #10)
by Craig Bruce 1. INTRODUCTION
ACE is a program for the Commodore 128 and Commodore 64 that provides a
command shell environment that is similar to that of Unix. It is still
in the development stage, but enough of it is complete to be useful.
BTW, "ACE" means "Advanced Computing Environment" (well, advanced for
the 128/64).
2. SYSTEM INTERFACE
This section describes the interface between user programs and the ACE
kernel. I am very careful throughout this interface specification about
revealing any internal details that you do not strictly need to know.
The interface with ACE is not specified in terms of absolute addresses;
to aid in portability and extensibility, all interfaces are specified in
terms of symbolic assembler labels. All of the ACE code is currently
written for the Buddy-128 assembler. Also, because these interface
absolute addresses are subject to change from version to version of the
kernel, executables compiled for use with an old version of ACE may not
work with a new version.
2.1. ZERO-PAGE VARIABLES
There are four zero-page variables used for passing arguments in most
system calls. They are as follows:
2.2. SYSTEM VARIABLES
There are several non-zeropage variables for storing system status and
return values:
2.3. SYSTEM CONSTANTS
There are several symbolic constants that are used with the ACE system
interface:
2.4. SYSTEM CALLS
All system calls are called by setting up arguments in specified
processor registers and memory locations, executing a JSR to the system
call address, and pulling the return values out of processor registers
and memory locations.
2.1. FILE CALLS
2.2. DIRECTORY CALLS
2.3. MEMORY CALLS
The calls given in this section are to be used for accessing "far"
memory in ACE, which includes all REU, RAMLink, RAM1 and above, and
sections of RAM0 that are not in the application program area.
Applications are not allowed to access "far" memory directly, because
the practice of bypassing the operating system would undoubtedly lead to
problems (can you say "MS-DOS"?).
2.4. SCREEN CONTROL CALLS
This section describes the system calls that are available to
application programmers for full-screen applications. These calls are
intended to be general enough to handle different screen hardware (the
VIC and VDC chips and a VIC soft-80-column bitmap screen, and possibly
others). These calls are also designed to be efficient as possible, to
discourage progammers from attempting to bypass using them. Bypassing
these calls would be a bad thing.
2.5. CONSOLE CALLS
The calls in this section refer to the system "console", which includes
the screen and keyboard. The screen-related calls are at a higher level
than the calls in the previous section.
2.6. PROCESS CONTROL CALLS
This section describes calls that are used to control the execution of
processes (active programs). From within one program, you can call for
the execution of another program, have it execute, and then return to
the calling program. Since only one program is allowed in memory at a
time, some special problems arise. Also, only rudimentary versions of
these system calls are implemented in Release #9 and I haven't decided
completely how they should work. So, this section is a bit tentative.
2.7. MISCELLANEOUS CALLS
3. USER PROGRAM ORGANIZATION
The ACE system itself is written using the Buddy-128 assembler, so it is
recommended that applications be written in this also. User programs
for ACE have a very simple structure. Here is the standard "hello,
world" example program written in Buddy assembler for ACE:
4. CONCLUSION
Cool, eh?
Looking Ahead: (Learned my lesson about "In The Next Issue" :-) (re: the
mouse article etc....) )
Either a Multi-Tasking article or a look at the Internals of Ace.
More graphics techniques.
Answers to the Trivia in this issue.
More articles and other information.
(Sorry that this is a little bit more vague than last time - Just have some
authors actually finding real jobs, and others that forgot to include what
they were going to do for the next issue.)