This is a wildly anachronistic project to give Apple Pascal running on an Apple II series computer the ability to read a hardware Real Time Clock (RTC) and update the current date as recorded by the Pascal Operating System.
If you're reading this, chances are you already know the background. But let me relate history just in case someone stumbles on this unwittingly.
Apple Pascal, based on UCSD Pascal, for the Apple II series of machines, was published in 1979. While UCSD had support for time, there was no RTC support. The only time support was access to a free running system clock to measure execution time. Apple Pascal didn't even have that since Apple II hardware had no clock hardware other then the 14 MHz system oscillator.
Add-on clock hardware was later provided by third party vendors. Mostly this was in the form of add-on cards, such as the popular Thunderclock Plus that was introduced in 1980. One remarkable solution was the No-Slot Clock installed in parallel with one of the standard system ROM chips. When the IIgs was introduced, it included its own built in clock hardware that shared hardware registers with the battery-back settings RAM that were accessed by memory-mapped I/O.
Which is all fine and good, but Apple Pascal, from the original 1.0 in 1979 to 1.3 released in 1984, never incorporated any standard support for reading clocks. Apple Pascal would update file directory entries with a last modified date stamp. But only if the user remembered to update the system date every day, which I was very bad at.
The ProDOS line of operating systems did have clock support. The original ProDOS support was basic. It also set the creation and/or modification time and date when a file was saved. But if there was a supported system clock available, the values would be read from that, automatically as necessary.
Nostalgia means I've been using Apple Pascal on Applewin and GSport. I still have a bad memory and I wanted clock support. Applewin emulates a No-Slot Clock. GSport emulates the IIgs clock.
I originally did something fancy. First I thought I might like applications that were portable without recompilation across the two emulators. So I came up with a solution that was based on having a user driver, like the Apple II Mouse driver for Apple Pascal (available as part of the MouseText Tool Kit). It proved to be unwieldy, so I changed it to a simple external assembly procedure that could be linked into a host program. There might be some use for a user driver version, so I've kept a copy of the code.
The other thing that changed as I went was access to the Pascal system global
variables. I was fairly certain that system programs could access them, but the
Apple documentation for the $U- compiler switch is very spartan:
Compilation at the system level will produce meaningful results only if the program was written with knowledge of the operating-system structure. Do not attempt system-level compilation unless you have this knowledge.
However the P-machine internals were documented, so I came up with an external assembly procedure that read the system registers, and walked the procedure call dynamic links back to the head of the call stack.
It was very interesting, and took a long time to get right. Then I discovered
a book that explained how to use the $U- compiler option (Advanced UCSD
Pascal Programming Techniques by Willner and Demchack, Prentice-Hall, 1985).
Doing things this way only took an hour or so to implement.
More information about the $U- compiler option can be found on Neil Parker's
page Undocumented Secrets of Apple Pascal.
THUNDER.TEXT-- A Thunderclock Plus clock card reading routine. Tests for the card in the same way that the ProDOS loader does, by looking for signature bytes in the ROM. The reading routine is based on code from the user manual that reads the time directly from the card IO space. This avoids interfering with the contents of $0200 onwards.IIGSCLK.TEXT-- An Apple IIgs built-in clock reading routine intended to be linked directly into a program. Works on a real IIgs ROM 03 and in GSport with ROM 03.NOSLOTCLK.TEXT-- A No Slot Clock reading routine. Does a search for the clock installation location the same way that version 1.4 of the ProDOS 8 driver does. Works on a real enhanced Apple //e with a Manilla Gear No-Slot clock inserted under the CF ROM. It also works just fine inside an Applewin emulator.MKYRTAB.TEXT-- Generates a year lookup table that is included in the assembly ofTHUNDER.TEXT. The Thunderclock Plus card does not report the year and the driver requires a lookup based on date, month, and day of week.MKYRTAB.DATA-- Reference data used during the execution ofMKYRTAB.CODE.CLOCK.TEXT-- A unit that defines the Pascal interface to call either driver.CALLRDTIME.TEXT-- A simple host program that links to eitherIIGSCLK.TEXTorNOSLOTCLK.TEXT, calls the ReadClock procedure and displays the current time and date.GLOBALS.TEXT--const,typeandvardeclarations for the Pascal system global variables. Originally based on the released code of UCSD Pascal I.5. Updated to match changes for Apple Pascal 1.3. For example, the core unit table is extended from 12 to 20 units.STARTUP.TEXT-- A startup program that will link to eitherIIGSCLK.TEXTorNOSLOTCLK.TEXTand set the system date to the current date. Compiled as a system program to access the system global variables. This technique is explained in Advanced UCSD Pascal Programming Techniques by Willner and Demchack (Prentice-Hall, 1985). It's described in section 5.0.12. The date is also written back to the system boot disk.
Building applications is a manual sequence of steps. Exec files would be able to automate some of this, but they would be opaque (figuring out file and build dependencies from an Exec file is hard) and unreliable (they are just blind sequences of canned user input that make no allowances for failure). Here is a rough guide.
Note, no file references (uses or includes) have a volume qualifier. All required files will need to be on the default volume defined by the Filer Prefix command.
The following instructions skip interim steps that are helpful such as getting and saving the system work files.
Does not depend on anything else.
- Compile
MKYRTAB.TEXT.
Depends on the table generator, and its data file MKYRTAB.DATA.
- Execute
MKYRTAB.CODE. It will use a date and day of week to generate the lookup table. When asked for the output file, you can useCONSOLE:to just send it to the screen. However, it needs to be written to a file in order to included in the assembly of the Thunderclock Plus clock driver. The driver code expects the year lookup table to be defined in a file calledYEARTAB.TEXT.
Depends on the year lookup table in YEARTAB.TEXT.
- Assemble
THUNDER.TEXT.
Does not depend on anything else.
- Assemble
IIGSCLK.TEXT.
Does not depend on anything else.
- Assemble
NOSLOTCLK.TEXT.
Does not depend on anything else.
- Compile
CLOCK.TEXT.
Depends on the clock unit, and on either the IIgs external procedure or the No-Slot Clock external procedure.
- Compile
CALLRDTIME.TEXT. - Link with
CLOCK.CODE, and eitherIIGSCLK.CODEorNOSLOTCLK.CODE.
Depends on either the Thunderclock Plus external procedure, the IIgs external
procedure, or the No-Slot Clock external procedure. Depends on GLOBALS.TEXT.
- Compile
STARTUP.TEXT. - Link with either
THUNDER.CODE,IIGSCLK.CODEorNOSLOTCLK.CODE. - Copy to the system disk as
SYSTEM.STARTUP.
This only describes the current model of clock driver, implemented in
THUNDER.TEXT, IIGSCLK.TEXT, and NOSLOTCLK.TEXT, and called by
CALLRDTIME.TEXT and STARTUP.TEXT. The interface into both drivers
is summarised by the following declarations.
type
daterec = packed record
month: 0..12;
day : 0..31;
year : 0..100
end {daterec};
timerec = packed record
hour : 0..23;
minute : 0..59;
filler1: 0..31;
second : 0..59;
filler2: 0..1023
end {timerec};
clockrec = record
date: daterec;
time: timerec
end {clockrec};
function InitClock:boolean;
external;
procedure ReadClock(var now:clockrec);
external;
procedure ClockName(var name:string);
external;InitClock must be called and return true before ReadClock and ClockName
will return meaningful values. InitClock can be safely called multiple times.
ReadClock and ClockName can be safely called if InitClock has not been
called or has returned false, but will return a zeroed out clock record and a
name indicating that there is no clock.
The declarations above can be copied into your application inline, which is then compiled and linked to either clock driver, or you can use the clock unit and then link to both it and one of the clock drivers.
START.THDR.CODE--STARTUP.TEXTcompiled and linked withTHUNDER.CODE. Ready to be transferred asSYSTEM.STARTUPto a startup disk for a system with a Thunderclock Plus card installed.START.IIGS.CODE--STARTUP.TEXTcompiled and linked withIIGSCLK.CODE. Ready to be transferred asSYSTEM.STARTUPto a IIgs startup disk. Works on GSport.START.NSC.CODE--STARTUP.TEXTcompiled and linked withNOSLOTCLK.CODE. Ready to be transferred asSYSTEM.STARTUPto a startup disk for a system with a NoSlotClock installed. Works on AppleWin.CLOCK.CODE-- The Clock interface unit compiled and ready to be linked with your application and a driver.THUNDER.CODEThe Thunderclock Plus clock driver assembled and ready to be linked with your application.IIGSCLK.CODEThe IIgs built-in clock driver assembled and ready to be linked with your application.NOSLOTCLK.CODEThe No-Slot Clock driver assembled and ready to be linked with your application.