Menu

Show posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.

Show posts Menu

Topics - BigDumbDinosaur

#1
Herdware / VIDEO MONITOR ALTERNATIVES
September 25, 2024, 04:44 PM
My C-128D has been in storage since 2012 following the failure of the only compatible video monitor I had.  The flyback transformer in the monitor literally went up in smoke and with no working monitor, I could no longer mess with the C-128D.  So I packed it away.
 
Now that Lance has this site back in operation, I'd like to resume fooling around with the C-128D.  I need to do something about a monitor, and rather than scrounging around for another CBM display and taking a chance that it too will go up in smoke,, would like to somehow attach a VGA-compatible LCD monitor to the computer.  At one time, I thought someone had devised a way to do this, but I'm not finding anything.
 
Any suggestions?
#2
Herdware / DUAL PORT SERIAL INTERFACE ADAPTER
January 13, 2011, 04:36 PM
I have a C-128D and Lt. Kernal/Rear Admiral setup, for which I am going to develop some database code.  I do all my 6502 development on my trusty UNIX server, since it is able to assemble about 10,000 lines of code per second (just a tiny bit faster than DevPak running on a C-128).  The problem comes in getting working code onto the C-128D.  The method I have chosen is to use an EIA-232 data link between the UNIX box (which has a bunch of serial ports) and the C-128.  This method would ultimately be less involved than the hassle of having to run a program on a PC to get the code onto a floppy disk that the 128 can read.

Usually, serial interfacing to the C-128 is through the user port.  However, that means using the error-prone fake RS-232 routines in the kernel.  Also, those routines are terribly inefficient and needlessly limit the speed at which the link can be run.  So I decided to take a different tack.

Below are some pictures of the dual port serial interface adapter I made for the C-128.  This one uses an NXP SCC2692A dual ACIA, along with glue logic in a GAL and a ROM in the internal ROM socket to provide the driver code.  Also in the ROM will be conversion code that will accept Motorola S-records from the UNIX box and load the relevant areas of RAM with machine code that can be saved to disk.

The 2692 can run at up to 115.2 Kbps on each channel, a speed that is well beyond the capabilities of the C-128 (it would amount to some 23,000 IRQs per second, virtually saturating the 8502 with interrupts).  For my application, I'm going to limit the speed to 38,400 Kbps, which the C-128 can manage without too much difficulty.  Although the adapter has two serial ports, initially I'm only going to use one.  Eventually the driver code will take care of both ports, allowing, for example, two modems to be in simultaneous use on a single 128.

I've got the hardware completed and am banging away at the driver.  As I said above, it runs in a 32K x 8 ROM plugged into the internal socket.  To avoid a conflict with the boot ROM in the Lt. Kernal/Rear Admiral host adapter, I'm running my code in high ROM ($C000).  Doing so complicates things a bit, as I have to mirror some of the CBM kernel code to deal with interrupts when my ROM is in context.

I'll periodically add commentary as I work through this thing.  Due to the one megabyte file size limit per post several posts will follow with additional pictures.
#3
Herdware / C-128DCR COOLING
October 04, 2010, 08:54 AM
INSTALLING A FAN IN A C-128DCR

Ed.note: This article was authored by Ray Carlsen, who is well-known in electronic circles for his skill in bringing dead Commodore hardware back to life.  Don't hesitate to contact him if your C= machine goes belly-up on you, as his rates are quite reasonable.  I reformatted this article for easier reading, added some information about fan types and sources, and added some photos of a C-128D with a cooling fan installed.

Although there is a place cut and drilled for a fan on the inside rear panel of the metal-cased C128D, few (if any) were sold with the fan installed. The benefits of forced-air cooling should make it a priority for anyone who owns one of those models to install a fan.  Unlike the "flat" C128, the DCR doesn't have the metal shield that touches the chips to draw the heat away, so convection cooling is all there is. The box was designed for the fan to pull air through the front of the computer (vent holes in the lower front panel), over the chips and out through the rear panel opening.

Fans are usually marked with two arrows to indicate the directions of rotation and airflow.  If your fan is not marked, a temporary hookup to the fan will tell you "which way the wind blows".  You want it directed out the back of the computer. Since the case was designed that way, the effect of drawing air out of the computer case has a minimal effect of drawing dust into the internal disk drive.  Still, it's a good idea to check it at least every six months, and more often if you live in a very dusty area (
Ed.note: or if you keep pets in your home).  It's easy to blow the dust out with compressed air.  (Ed. note: by "compressed air," it is meant the stuff you buy in cans at the local computer store, not what comes out of an air compressor.)

Since the C128D's internal power supply puts out both +5 volts and +12 volts DC, either of those voltages could be used for a fan.  Although a 120VAC type would work as well as a low voltage one, I couldn't find any 120 volt fans that small, and the 5 volt versions are more expensive.  Connecting any of the three types of fans to the computer is easy.  You only need to know where to tap off the power.  I'll give you instructions for connecting a 12 volt fan since it's the most common type and is readily available.

The maximum size of the [fan] opening is 2.5" high by 2.5" wide by 1.5"deep.  The spacing of the four mounting holes is exactly 2" center to center.  A "standard" fan case size is 2.36" square by about an inch deep (
Ed. note: the fan being described is a 60 millimeter fan, similar to the types used on CPU coolers in modern PCs).  It makes sense to buy a fan that exactly fits, rather than trying to modify the opening for something else.

Mouser Electronics 1-800-346-6873) has three fans that will fit the opening: part numbers 432-31432, 432-31434, and 432-31436 at $12 each.  They are all 12 volt ball bearing models and differ only in the amount of air they move (called CFM, or cubic feet per minute).  The higher (part) number is the higher CFM rating, by the way.  Of course the faster the air flow, the noiser the fan, but because of where it's mounted, noise shouldn't be a problem.  You'll get used to a bit of noise if you know it's cooling those precious chips!  Mouser has a web page for those interested: www.mouser.com.  They are an industrial supplier and maintain a good stock of parts, so you shouldn't have to wait long for your order.

Allied Electronics Inc. @ 1-800-433-5700 is another outlet that has a good selection of suitable fans that range in price from $8.50 to $20. Their web page is: www.allied.avnet.com. They have more than a hundred outlets nationwide, so you might find one near you.  Some fan part numbers from their catalog: 592-0750, 592-0760, 592-0770 selling for $8.50 each.  Note that the -lower- numbers are for the higher CFM (and noise) rating.  Low cost fans are sleeve types rather than ball bearings, but even the "cheapies" will last for many years (
Ed. note: true to some extent, but they will get noisier as they age).  Ball bearing equivalents of the above numbers are: 592-0690, 592-0700, 592-0710 selling for $11 each.  Here again, the lower numbers are the higher CFM and noise rating fans.  Allied Electronics also has a pretty good selection of standard and mini DIN plugs used in Commodore computers.

Jameco Electronics @ 1-800-831-4242 (www.jameco.com) also sells fans, and has a small selection of Commodore IC chips available as well.  I counted seven fans in their latest catalog that would fit the 128D case that sell for under $10 each, such as: part number 75352 for $7.95.  If you want to order one, what you need to specify is: 2.36" square (
Ed. note: 60mm), 12 volts DC, the type of bearings (ball or sleeve), and the CFM rating.

I would go with the highest CFM rating to get the most cooling.  The noise only reminds me that it's working!  Most fans have 12" lead wires, but some will come with only 5" of wire, so you may have to "pigtail" extra wire to make it reach...no big deal.  Insulate any bare wires to keep them from shorting to each other or anything else.

The cover of the C128Dmust be removed to do the fan installation.  Remove two screws along the side bottom front edges and three more on the sides and top of the rear panel.  The top cover must then be slid back about 3/4" and lifted up and off.  (
Ed. note: it may be necessary to use a small blade screwdriver to pry the cover back enough to disengage it from the chassis.)

The fan and case mounting holes will accept four standard 6-32 by 1.25" long machine screws.  4-40 screws will work if you use washers on the smaller diameter hardware (
Ed. note: not recommended).  Don't overtighten the screws or it could damage the plastic fan housing.  A dab of glue on the screw threads will keep them from loosening up over time.

Mounting the fan with screws and nuts requires that you first remove the power supply from the 128D.  As an alternative, a thin bead of silicon rubber sealer can be used to"glue" the fan in place, and you will not need mounting hardware or need to remove the power supply (
Ed. note: again, not recommended). Silicon rubber takes about an hour to "set up" and is fully "cured" in about 24 hours.  Don't get any sealer on the blades or it may cause the fan to stall, or vibrate from the imbalance.

To connect the fan to the power supply 12 volt DC source: locate the short wire bundle that goes between the power supply and the motherboard.  There are six wires in that bundle.  The brown and white wires are the 9VAC, the red wire is +5 volts, the two black wires are ground, and lastly, the yellow wire is +12 volts DC...the one you want for the fan.

The polarity of the fan hookup is important.  Most fans come with two wires, one black (-) and one red (+).  Connect the red fan wire to the yellow wire of the C128D power supply, and the black fan wire to either of the black power supply wires.  You can pull back the insulation a bit on the power supply wires (or trim a little insulation away with a knife) and just wrap the bare ends of the fan wires around them if you want.  If you make a good electrical and mechanical connection, you don't need to solder it.

Ed.note: there are two holes in the power supply printed circuit board immediately adjacent to where the above-mentioned wires are connected.  These holes can be used to connect the fan wiring.  Use a solder sucker to clear solder from the holes, strip about a 1/4 inch of insulation from the fan wires, insert them into the holes and solder.  Examine the underside of the board to determine which hole goes to +and -.  Remember: the YELLOW wire is positive.

Make sure your added wires don't short to each other or any other wires or metal.  Wrap electrical tape around exposed wiring if necessary.  If you unplug the power supply from the motherboard for any reason, make sure you get it back in the right way.  If you reverse it, you will damage the computer.  Note that one black wire of the bundle goes to pin 1 of socket CN7 on the motherboard...pins 1 and 6 are marked on that board.

Ray Carlsen CET
Carlsen Electronics

Ed.note: I've attached two pictures taken of my C-128D after installing a cooling fan into the power supply.  The fan I used was an Antec 60mm case fan, UPC number 761345760065.  To attach the fan to the power supply subchassis, I enlarged the fan mounting holes with a 3/16 inch drill and used the self-tapping mounting screws provided with the fan.  Also note how I made the electrical connection, which arrangement allows the fan to be replaced without having to unsolder any leads.  Go to Antec's website for more information on this fan.
#4
Herdware / C-128D on the Way
June 23, 2010, 03:48 AM
Okay...I finally decided to get a real C-128D instead of making do with WinVICE (although 80CDM and CC128 were both tested and debugged in VICE).  The "D" should be here soon.  Only thing I'm missing right now is an RGBI monitor to go with it.

Also sitting on the shelf awaiting a call to duty is a Lt. Kernal hard disk unit.  With this hardware in hand I may suddenly get the urge to step back in time 20-or-so years and do some eight bit database software engineering.  Of course, this being 2010, no one would actually have a need for anything of the sort, eh?  And, if I did do it, I'd have to multiplex a second 128 to the Lt. Kernal to test file and record locking semantics, as well as inter-port communication.  Nevertheless, I've got far more powerful development tools than what existed in 1990â€"all editing and assembly will be done on my UNIX development system.  So whatever I decide to do will take less time and hopefully be more refined.  :)

One of the little "infrastructure" items I have to settle is how to transfer executable binaries to the 128.  I'm looking at creating a EIA-232 link between the "D" and my UNIX box, as the latter has lots of serial ports.  On the 128 side, a little machine code will drive the serial interface and stuff the incoming bytes into RAM.  However, I historically have avoided the fake RS-232 code in the kernel like the plague.  It's a prime example of crap software.  :D  Ergo, it appears I'll have to design and build a real serial interface.  I can assure you it won't be equipped with a 6551 UART.  The only problem will be that of getting the driver to the "D", since there initially won't be a working connection...problems, problems!
#5
128 programmers / To Merge or Not to Merge...
March 02, 2009, 04:23 AM
I've been thinking some of merging Clock-Calendar 128 and the 80 Column Display Manager into a general purpose software support utility.  If I did so, I would also consider adding a programmable keyboard input function, an easy-to-use cursor positioning subroutine and possibly a high speed method of printing to the 80 column screen that would support display control mnemonics, thus creating a big mish-mash that a software developer could use for various projects.  I have no idea how many here actually write software, but might there be an interest in such a utility?
#6
VDC Programming / MOVED: PEEKing Bitmap Color?
January 12, 2009, 02:53 PM
I moved this topic to the BASIC programming subforum, since it doesn't appear to have anything to do with the VDC. BASIC.

http://landover.no-ip.com/forums/index.php?topic=2588.0
#7
The link to download version 1.2 of the C-128 80 Column Display Manager (80CDM) is at the end of this post.

Included in the ZIP distribution is the 80CDM binary, a status line writer BASIC interface binary (with source code) and an Adobe PDF containing full documentation.  Please peruse the README.1ST file and PDF documentation before trying to integrate the display manager with your software.  If you have been using version 1.0 or 1.1 of 80CDM please note that 80CDM's load address and access table structure have been changed.  Versions 1.0 and 1.1 cannot be integrated with Clock-Calendar 128.




The C-128 80 Column Display Manager adds some display management functions that should have been part of the original C-128 kernel but were not included for a variety of reasons.  The main feature is the ability to buffer screens for later recall, thus enhancing the basic "window" functions that are part of the display kernel (screen editor ROM).  The display manager implements the following functions, the availability of which depends on whether the computer has 16K or 64K of video RAM (VRAM):


  • Screen Save: copy the visible display to any of 10 hidden screen buffers.  Such copying includes all related display variables that define window margins, cursor location and mode (e.g., static, flashing, etc.), current character attributes, etc.  It is also possible to copy one hidden screen to another.  Only one hidden screen is available on a 16K machine.


  • Screen Restore: copy any hidden screen to the visible display and establish the associated display parameters that define the window margins, cursor location and mode, etc., that existed when the screen was previously saved.


  • Display Redirection: redirect display output to any of the hidden screens, as well as the visible screen, permitting the build-up of a screen "behind the scenes."  Later, the resulting hidden screen can be copied to visible space, resulting in a display that pops into view at lightning speed.


  • Screen Exchange: swap the visible display with a temporary buffer, allowing rapid flipping between two screens (e.g., presenting a help screen from within a running application).  As with save and restore, the associated display parameters are copied.  The temporary buffer is independent of any of the 10 hidden screen buffers but is accessible for display redirection.  Not available on a 16K machine.


  • Status Line: generate a static, reverse video status line that is unaffected by any other screen activity.  Included is a function to write text into the status line, starting at any desired column, and a function to make small adjustments to vertically center the display on the screen to compensate for the added display row.  A separate assembly language program (included in the ZIP download) may be used to drive the status line from BASIC.  Not available on a 16K machine.


  • Display Blanker: turn off the visible display to reduce static image burn-in on the video monitor screen.


  • Video RAM Sizing: automatic detection and reporting of the amount of VRAM attached to the 8563/8568 video display controller (VDC), with appropriate reconfiguration if 64K is detected on a C-128 with 1985 ROMs.


  • Export/Import: export a screen to system RAM (which can be saved to a file) or import a screen from system RAM.  Exported screens include all relevant display parameters.  This feature can be used on a 16K machine to make up for the lack of multiple buffers.


  • In-Use Semaphore: a feature that allows both foreground and interrupt-driven programs to access certain manager features on a non-interference basis.


  • Presence Signature: a test feature to determine if the display manager has been loaded into RAM.

The C-128 80 Column Display Manager loads into RAM-0 under the kernel ROM, and when initialized, adjusts the top-of-BASIC pointers to protect itself from a large BASIC program.  This has minimal effect on the size of BASIC program text space, reducing it by less than 8K total, leaving approximately 50K in which to load a BASIC program.

If you have any questions about the use of the display manager please peruse the documentation.  If that doesn't help then feel free to post questions and comments here.  If you are reporting what you think may be a bug, please be as specific as possible as to the nature of the problem.  Posts that lack adequate information or aren't germane to the topic will be ignored.
#8
This forum is a support area for Clock-Calendar 128 and related code that manipulates dates and time.  If you have any reasonable feature requests for CC128 you can post them here.
#9
General chat / Health (or lack thereof)
July 05, 2008, 03:26 PM
My ITP condition has gone into full relapse despite the surgery I underwent last January, and I am now living on steroids again.  The drugs that used to be able to rescue me when the platelet counts crashed can no longer be used, so now it's a tricky balancing act between using enough steroids to keep my immune system from gobbling up all my platelets but not too many steroids, which would gobble up my liver.  Life can suck sometimes...the surgery was technically a success (I lived to tell about it) but ultimately accomplished nothing, unless you call transferring close to 100,000 dollars (the U.S. kind) from the insurance company to the hospital and doctors an accomplishment.

Corticosteroids tend to break down bone and muscle mass and when used at the high doses required to have the desired effect in my case, will ultimately result in permanent liver damage, cardiac problems—possibly an early death.  A more immediate and annoying side-effect is a loss of motor coordination and the development of what I call the "steroid shakes," most noticeable when lifting a can of beer to one's mouth.  The latter condition has made the use of a computer more difficult for me, as my typing has significantly deteriorated.  Since programming is largely an exercise in thinking and typing, I'm in big trouble, especially in the thinking department.  Hence projects like Clock-Calendar 128 have been languishing as I try to deal with this little mess.

Ultimately, my survival is going to hinge of the development of a drug that will cause my body to generate platelets faster than my immune system can destroy them.  One such drug, AMG 531, shows some promise but is still in clinical trials.  I had attempted to get into the trials late last year but my condition was considered a bit too precarious at the time for me to become a lab experiment.  Now that I've gone through a triple splenectomy, yet relapsed soon after the surgery, I'm considered a viable candidate for AMG 531.  However, they're not taking any more test subjects right now, so I'll have to wait and see.

Meantime, I'm trying to keep a positive attitude about this thing, even when the platelets go into the toilet, the bruising and bleeding start, and the nice folks at the hospital ER infuse more steroids to try to get things out of the danger zone.  A normal person has a platelet count of 150,000 to 450,000 per microliter of blood.  My count has been below 2000 at times.  Anything below 20,000 is dangerous—a trivial cut can become life-threatening—and at less than 5000, a bump to the head can start intracerebral hemorrhaging, which is often fatal.  Needless to say, when my counts are low I don't get into any situations where a whack to the noggin is a possibility.  That includes riding in an automobile.  At least I can save on gas that way...
#10
The attached program is an enhanced version of a VDC RAM detection program I published a while ago.  This one includes code that will correctly configure the VDC in a flat 128 that has been upgraded to 64K of video RAM (VRAM)

After loading this program, run it from BASIC as follows:

    BANK 15 : SYS DEC("0B00") : RREG VS
    PRINT "This C-128 has";VS;"K video RAM."


VS will equal 16 for a C-128 with 16K of VRAM or 64 for a machine with 64K of VRAM.

If your C-128 is a flat unit with 1985 ROMs but has been upgraded to 64K of VRAM, it will not automatically recognize the extra RAM.  The 1985 ROMs always tell the VDC that it has 16K.  This program will detect such a situation and change the VDC settings so it does recognize the full extent of VRAM.  This reconfiguration process will disrupt the 80 column display, which can be corrected by clearing the screen afterward.

As a side note, the 80 Column Display Manager includes this enhanced detection process.
#11
Clock-Calendar 128 / DAY of the WEEK
May 21, 2008, 02:40 AM
Here's an assembly language program that computes the day of the week for any Gregorian date from February 24, 1582 to December 31, 9999 inclusive.  Please read the comments to see how to pass a date into this program and what to expect as output.  Dates earlier than 1582/02/24 can be passed but will produce erroneous output, as the calendar system in general use prior to that date was the (less accurate) Julian system.  Note that the British Empire didn't switch to the Gregorian calendar until September 14, 1752.

You can also download the source file via the link below.

;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
;*                                                                             *
;*                        CALCULATE THE DAY OF THE WEEK                        *
;*                                                                             *
;*                       by BigDumbDinosaur,  March 1997                       *
;*                                                                             *
;* This 6502 assembly language program calculates the day of the week for  any *
;* calendar date from February 24, 1582 to December 31, 9999 inclusive.        *
;*                                                                             *
;* --------------------------------------------------------------------------- *
;*                                                                             *
;* Copyright (C)1997 by BigDumbDinosaur.  All rights reserved.                 *
;*                                                                             *
;* Permission is granted to copy and redistribute this software, provided this *
;* copyright notice is retained and proper attribution is given.               *
;*                                                                             *
;* THERE IS NO WARRANTY OF ANY KIND WITH THIS SOFTWARE.  It's free,  so  don't *
;* look a gift horse in the mouth.                                             *
;*                                                                             *
;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
;
;
; Calling Syntax:
;
; ldx #<date            ;starting address of..,
; ldy #>date            ;date data
; jsr cdow              ;this subroutine
; sta dow               ;day of week returned in .A
;
; .X and .Y are preserved.
;
; The information at DATE must be in the following format:
;
; Offset   Data
; --------------------------------------------------------------
;   $00    Year MSB.  For example, if the year is 1997 then this
;          value would be $07.
;
;   $01    Year LSB.  For example, if the year is 1997 then this
;          value would be $CD.
;
;   $02    Month, ranging from $01 to $0C.
;
;   $03    Date, ranging from $01 to $1F.
; --------------------------------------------------------------
;
; Upon return, .A will contain the day of the week in the range $01-$07,
; with $01 being Sunday. 
;
; Execution time will typically be 4150 clock cycles, depending  on  the
; supplied values.  No range checking is performed.  A bogus  date  will
; produce a bogus result.
;
;===============================================================================
;
;DECLARATIONS
;
_origin_ =$02000               ;assembly address
;
zpptr    =$FA                  ;working ZP pointer...
;
; --------------------------------------------------------
; Redefine the above assignments to suit your application.
; --------------------------------------------------------
;
dayswk   =7                    ;days in a week
march    =$03                  ;March in binary
s_bits   =8                    ;number of bits in a byte
s_byte   =1                    ;size of a byte or char
s_date   =4                    ;size of the input date
s_dword  =4                    ;size of a double word
s_word   =2                    ;size of a word
y2fac    =4                    ;Y2 computation factor
y3fac    =100                  ;Y3 computation factor
y4fac    =400                  ;Y4 computation factor
;
;===============================================================================
;
;COMPUTE DAY OF WEEK
;
         *=_origin_            ;set program counter
;
cdow     stx zpptr             ;save pointer to...
         sty zpptr+1           ;date info
         ldy #s_date-1         ;bytes in date -1
;
cdow01   lda (zpptr),y         ;copy user's date...
         sta userdate,y        ;into our storage
         dey
         bpl cdow01
;
         lda month             ;month
         ldx yearlo            ;year LSB
         ldy yearhi            ;year MSB
         pha                   ;save month
;
; ------------------------
; evaluate Y -= M < 3 (Y1)
; ------------------------
;
         cmp #march            ;month March or later?
         bcs cdow03            ;yes, no year adjustment
;
         txa                   ;year LSB
         sec
         sbc #1                ;move back a year
         bcs cdow02
;
         dey                   ;adjust MSB
;
cdow02   tax                   ;hold LSB
;
cdow03   stx y1                ;save Y1
         sty y1+1
;
; -----------------
; compute Y2 (Y1/4)
; -----------------
;
         jsr stafaca           ;store Y1 in accummulator #1
         ldx #<y2fac           ;4
         ldy #>y2fac
         jsr stafacb           ;copy to accummulator #2
         jsr dpdiv             ;Y2=Y1/4
         stx y2                ;store
         sty y2+1
;
; -------------------
; compute Y3 (Y1/100)
; -------------------
;
         jsr stay1fac          ;copy Y1 to accummulator #1
         ldx #<y3fac
         ldy #>y3fac
         jsr stafacb           ;copy to accummulator #2
         jsr dpdiv             ;Y3=Y1/100
         stx y3                ;store
         sty y3+1
;
; -------------------
; compute Y4 (Y1/400)
; -------------------
;
         jsr stay1fac
         ldx #<y4fac
         ldy #>y4fac
         jsr stafacb           ;copy to accummulator #2
         jsr dpdiv             ;Y4=Y1/400
         stx y4                ;store
         sty y4+1
;
; -------------
; combine terms
; -------------
;
         clc
         lda y1                ;Y1
         adc y2                ;Y2
         sta acm1
         lda y1+1
         adc y2+1
         sta acm1+1
         sec
         lda acm1
         sbc y3                ;Y3
         sta acm1
         lda acm1+1
         sbc y3+1
         sta acm1+1
         clc
         lda acm1
         adc y4                ;Y4
         sta acm1
         lda acm1+1
         adc y4+1
         sta acm1+1
         pla                   ;get month
         tax                   ;change 1-12 to...
         dex                   ;0-11
         clc
         lda acm1              ;combined terms
         adc dowmctab,x        ;month comp factor
         bcc cdow04
;
         inc acm1+1
;
cdow04   sta acm1
         clc
         lda date              ;date
         adc acm1              ;last term
         bcc cdow05
;
         inc acm1+1
;
cdow05   sta acm1
         ldx #<dayswk          ;number of days in a week
         ldy #>dayswk
         jsr stafacb           ;copy to accummulator #2
         jsr dpdiv             ;ACM1=ACM1 mod 7
         adc #1                ;0-6 --> 1-7...
;
; -------------------------------------------------
; remove the ADC #1 instruction for a 0-6 DOW range
; -------------------------------------------------
;
         ldx zpptr             ;restore
         ldy zpptr+1           ;likewise
         rts                   ;return day of week in .A
;
;================================================================================
;
;DOUBLE-PRECISION DIVISION
;
; -----------------------------------------
; acm1 = 16 bit dividend
; acm2 = 16 bit divisor
; -----------------------------------------
; acm1 = 16 bit quotient
; .A   = remainder
; .X   = quotient LSB
; .Y   = quotient MSB
;
; The remainder is also available in acm1+2.
;
; No check is made for division by zero.
; ------------------------------------------
;
dpdiv    lda #0
         sta acm1+s_word       ;clear dividend hi bits
         sta acm1+s_word+s_byte
         ldx #s_bits*s_word    ;bits to process
         clc
;
dpdiv01  rol acm1              ;rotate dividend
         rol acm1+s_byte
         rol acm1+s_word
         rol acm1+s_word+s_byte
         sec
         lda acm1+s_word
         sbc acm2              ;subtract divisor
         tay
         lda acm1+s_word+s_byte
         sbc acm2+s_byte
         bcc dpdiv02
;
         sty acm1+s_word       ;save partial quotient
         sta acm1+s_word+s_byte
;
dpdiv02  dex
         bne dpdiv01           ;next
;
         rol acm1              ;rotate in last carry to...
         rol acm1+s_byte       ;finish quotient
         lda acm1+s_word       ;get remainder LSB
         ldx acm1              ;get quotient LSB
         ldy acm1+s_byte       ;get quotient MSB
         rts
;
;================================================================================
;
;STORE Y1 INTO ACCUMMULATOR #1
;
stay1fac ldx y1
         ldy y1+1
;
;================================================================================
;
;STORE INTO ACCUMMULATOR #1
;
stafaca  stx acm1
         sty acm1+1
         rts
;
;================================================================================
;
;STORE INTO ACCUMMULATOR #2
;
stafacb  stx acm2
         sty acm2+1
         rts
;
;===============================================================================
;
;COMPENSATION TABLE
;
dowmctab .byte 0,3,2,5,0,3,5,1,4,6,2,4
;
;===============================================================================
;
;WORKING STORAGE
;
acm1     *=*+s_dword           ;accummulator #1
acm2     *=*+s_word            ;accummulator #2
y1       *=*+s_word            ;adjusted year (Y1)
y2       *=*+s_word            ;Y1/4
y3       *=*+s_word            ;Y1/100
y4       *=*+s_word            ;Y1/400
;
; ---------------------------------------------------------------------
; The above locations can be defined on page zero if room is available.
; Execution time will be reduced about 20 percent.
; ---------------------------------------------------------------------
;
userdate *=*+s_date            ;input date storage...
;
yearhi   =userdate             ;year MSB
yearlo   =yearhi+s_byte        ;year LSB
month    =yearlo+s_byte        ;month
date     =month+s_byte         ;date
;
;===============================================================================
#12
Clock-Calendar 128 / CLOCK-CALENDAR 128 DOWNLOAD
April 25, 2008, 03:51 PM
Clock-Calendar 128 (CC128) is now available for downloading.  See the link at the end of this post and be sure to read the documentation before trying it out.  Also, if you wish to integrate CC128 with the C-128 80 Column Display Manager (80CDM) be sure the version of 80CDM on your system is 1.2 or later.


Clock-Calendar 128 is a utility for the C-128 that provides date and time services that may be used by other programs on an ad hoc basis.  When started, CC128 is linked into the C-128's interrupt request (IRQ) processing subsystem, causing the utility to run in the background until its services are needed.  There are any number of uses to which CC128 can be put, such as providing date and time services to BBS software, date and time stamping of records in a database, date and time stamping of entries into a log, etc.

CC128's basic features are:


  • 12 hour, AM/PM continuous time-of-day function.  All CC128 timing functions are derived from the hardware TOD clock in CIA #2.  Unlike the TI$ software jiffy "clock" available in BASIC, the CIA's TOD clock is unaffected by operating system activities and maintains excellent accuracy over long periods.


  • Full range calendar with year, month, date and day of week.  CC128 can maintain dates from January 1, 1753 to December 31, 9999, inclusive, with full leap year compensation.


  • Audible alarm.  At the alarm time, your C-128 will alert you with a pleasant gong tone.  The alarm has the software equivalent of a "snooze bar."


  • Continuously updated date and time values.  CC128 can export date and time data into any desired location in RAM-0 for use by your software.


  • Automatic detection of NTSC and PAL systems.  Upon startup, CC128 will determine which video system is in use and will program the TOD clock for the correct power line (mains) frequency.


  • Presence signature.  CC128 includes a "presence signature" that can be tested by other programs to determine if CC128 has been loaded into memory and is intact..

CC128 can interface with the C-128 80 Column Display Manager (80CDM) version 1.2 or  later and offer the following extra services:


  • Timed "screen saver" function.  CC128 can be configured to monitor the C-128's keyboard and turn off the 80 column display after a programmable period of inactivity.  Pressing almost any key will turn on the display.  The inactivity period can range from one to 32,767 seconds (more than nine hours).


  • Continuous date and time display.  If 80CDM's status line has been enabled, CC128 can be told to generate a constantly-updating date and time display on the right-hand end of the status line (leaving plenty of room for user-generated status line text).

CC128 runs in RAM-0 underneath the kernel ROM and consumes less that 2 KB of memory.  Data is stored in normally unused memory at the very top of RAM-0.  When loaded and started, CC128 will adjust the top-of-BASIC pointers to protect itself from outsized programs.

CC128 is a low level operating system enhancement, and thus natively operates at the machine language level.  Access is through a jump table similar to the kernel ROM jump table, and date and time inputs and outputs are given in compressed binary-coded decimal (BCD) format for easy manipulation and conversion in the M/L environment.  However, BASIC programmers have not been left out in the cold!  I have also developed CC128CTL (CC128 control, included in the CC128 distribution) to allow CC128 functions to be called from BASIC, using a simple SYS calling syntax that even a trained monkey can understand.   ::)

If you have any questions about the use of CC128 please peruse the documentation.  If that doesn't help then feel free to post your question here.  If you are reporting what you think may be a bug, please be as specific as possible as to the problem.  Posts that lack adequate information or aren't germane to the topic will be ignored.
#13
General chat / QUIET AS A MORGUE
February 29, 2008, 03:28 PM
Lately this place seems to have hit the doldrums.  Hardly any posting going on.  Did everyone go on vacation to somewhere that doesn't have Internet access?  ???
#14
General chat / FORUM CHANGES
February 18, 2008, 10:45 AM
The description says it all.  The display is back to that putrid pastel that I can't read.  Whatever it is that is supposed to change it to something more pleasant has apparently disappeared, leaving me with what is basically an unreadable screen.  Lemme know when it's fixed and I'll come back.
#15
Assembly / ASSEMBLER STANDARDS
February 12, 2008, 11:42 AM
MOS TECHNOLOGY ASSEMBLER SYNTAX STANDARDS

Scattered about the Internet landscape are a number of homegrown 6502/65C02 assemblers free for the downloading.  Unfortunately, many of them don't conform to the original MOS Technology standard developed with the 6502 microprocessor (MPU), which drives us old-time 6502 programmers to drink (we have to blame something for our bad habits).  Variances or outright errors are typically found in instruction mnemonic representation, number radices, operand representation, label/symbol representation, comment delimiters, whitespace rules or assembler pseudo-ops.

For this who are reading this and are contemplating the scratch-development of a 6502 assembler, perhaps the following might be of interest to you.

Mnemonics and Operands
MOS Technology defined a complete set of mnemonics to describe every legal instruction that the MPU can execute, and also defined how to represent the operand with any instruction that can operate on either memory or an MPU register.  For example:

        ASL FLAG        ;Memory is the operand.

        ASL A           ;The MPU accumulator is the operand.

        ASL             ;WRONG!  Any questions?

Any instruction that can operate on memory or an MPU register MUST be followed by an operand to avoid ambiguity.

Number Radices
A radix (plural radices) is a symbol for the base representation of a number.  In almost all assembly language programs, the programmer may freely mix binary, octal, decimal and hexadecimal. 

The correct MOS Technology radices for representing the decimal number 165 would be as follows:

        %10100101       Base 2 or bitwise binary.

        @245            Base 8 or octal.

        165             Base 10 or decimal.

        $A5             Base 16 or hexadecimal.

The MOS Technology standard designated base 10 as the assembler default, which is nearly universal.  However, the C-128's machine language monitor uses hexadecimal as the default base (e.g., LDA #A5 is actually LDA #$A5) and symbolizes decimal numbers with a plus sign (e.g., +165 = $A5 = @245 = %10100101).  The other MOS Technology radices are supported as described above.

Operand Representation
The operand to any MPU instruction or assembler directive (see labels and symbols below) must be in a format that clearly delineates between different addressing modes.  Also, the operand must be in a form that the assembler can evaluate in an unambiguous fashion.  Examples of proper operands are as follows:

        165             165, an eight bit value.

        $3FFF           16383, a 16 bit value.

        165+21          186.

        5+4*2/3         6.

        'A              65, the ASCII value for the uppercase letter A.

        *               The program counter (assembly address).

        *=$2000         Sets the program counter to decimal location 8192.

        *=*+10          Advances the program counter ten locations.

Assignments in all cases are evaluated from left to right with no algebraic precedence.

The assembler should also support the entry of character strings and other data into a static data storage area, which will be discussed below.

Label and Symbol Notation
A label refers to a memory location within a program and is automatically assigned the value of the program counter when assembled.  A symbol (symbolic constant), on the other hand, refers to the explicit assignment of a value by program code.  The difference between a label and a symbol, aside from the manner in which the assignment is made, is that some assemblers allow the value of a symbol to be changed later in the program (reassigned).  On the other hand, a label cannot be changed, and an attempt to do so will cause assembly to halt with an error.

The MOS Technology standard for label and symbol naming states that the name must begin with an alphabetic character, may be followed by up to five alphanumeric characters, and may not be any MPU instruction mnemonic, such as CLC or LDA.  A single character label or symbol cannot be A, X or Y, as those are reserved for representing the MPU registers—the use of single character names is not recommended.  Labels and symbols are not supposed to be case-sensitive, which in practice is seldom observed anymore.  Although I will be using uppercase examples below, I never use uppercase names in any assembly language programs that I develop, as it is too easy to get mixed up.

The size limitation of six characters was due to the modest capabilities of the systems in use at the time of the 6502's development, and is an unnecessary restriction in modern implementations.  Contemporary assemblers (such as the HCD65 C-128 assembler) generally permit much longer names and also allow the use of the underscore character as part of the name.  Hence a symbol such as THE_SIZE_OF_AN_INVENTORY_RECORD is acceptable (although ridiculous).  This could also be done as TheSizeOfAnInventoryRecord, as is often found in Windows software development (and also ridiculous), as a standards-compliant assembler would ignore case.

Some label and symbol examples:

        S_CMMAS   =721            ;customer record master record size

The above creates the symbol S_CMMAS, representing the size of a customer master record, and assigns the value 721 to it.  Following this assignment, any other instruction in the program can (and should) use S_CMMAS when referring to the size of a customer master record, instead of using the hard coded number 721.  It is bad practice to bury "magic numbers" like 721 in code.  Always symbolically represent them in a separate "include" file, where changes can be quickly and easily made if needed.

        A_NUL     =0              ;ASCII <NUL>
        A_LF      =10             ;ASCII <LF>
        A_CR      =13             ;ASCII <CR>

The above creates the symbolic constants A_NUL (ASCII null), A_LF (ASCII linefeed) and A_CR (ASCII carriage return) with the values 0, 10 and 13, respectively.  Again, it is bad practice to hard code such values into programs.

        OPCMMAS *=*+S_CMMAS     ;customer master record image

The above code assigns the location in memory where a customer record will be buffered and reserves S_CMMAS bytes for storage, where S_CMMAS was previously defined as 721.  The expression *=*+S_CMMAS advances the program counter S_CMMAS bytes.  The rest of the program can refer to the record image location with OPCMMAS, such as in the following example:

        LDX #<OPCMMAS
        LDY #>OPCMMAS
        JSR PUTREC

The above example illustrates the MOS Technology standard notation for taking the least significant byte (LSB, represented by <) and most significant byte (MSB, represented by >) of the 16 bit value of OPCMMAS, which we defined in the previous example, and passing the address to a function for processing.

COMMENTS and CODE LINE STRUCTURE
All programs should be sufficiently commented to allow a third party to read and understand what the program is supposed to accomplish.  Uncommented code is a sign of laziness and (in my opinion) programmer ignorance, especially when complex routines are involved.  Nobody's memory is that good that s/he can write a program this year and expect several years hence to recall all the details of what was supposed to happen.

The MOS Technology standard for comments require that they begin with a semicolon (;).  Any text following the semicolon up to the end of the line will be ignored by the assembler, although it will usually be regurgitated in a printed listing as the assembler runs.  Here's a simple example, which also illustrates how a fully formed line of code should appear:

PUTREC  STX IMGPTR              ;store image pointer LSB
        STY IMGPTR+1            ;store image pointer MSB

Note that a fully formed code line (the STX IMGPTR line above) consists of four fields: label, instruction, operand and comment.  The MOS Technology standard requires that the label always start at the left end of the line, followed by whitespace, followed by the instruction mnemonic, followed by whitespace, followed by the operand (if required), followed by whitespace again, followed by the comment, if any.

Whitespace is defined as at least one blank (ASCII 32) or horizontal tab (ASCII 9) character that is not bounded by quotes.  If no label is to be used (e.g., the STY IMGPTR+1 line above), whitespace should start the line as shown above.  Incidentally, MOS Technology never stated how the assembler should behave when it encounters a blank line or one consisting only of whitespace characters.  The logical thing to do would be to discard the line without complaining about it, or add a semicolon to its beginning so it appears on a printed listing as a blank comment line.

PSEUDO-OPS
A pseudo-op (pseudo-operation) is an instruction to which the assembler itself responds, as opposed to one that is assembled into code.  The distinguishing characteristic of a pseudo-op is that it always starts with a period (.).  The standard pseudo-ops required by MOS Technology are:

        .BYTE           Assembles one eight bit value

        .DBYTE          Assembles one big-endian 16 bit value.

        .END            Terminates assembly, even if not at end-of-file.

        .TEXT           Assembles a null-terminated character string.

        .WORD           Assembles one little-endian 16 bit value.

As with symbols and labels, pseudo-ops are not supposed to be case-sensitive.  Here are some
syntactically correct examples:

        FLAG    .byte $00

The label FLAG is defined at the current address in the program counter and zero is assembled into that location.

        INPBFR  =$0200
        IPBADR  .WORD INPBFR

The symbol INPBFR refers to a fixed location in memory (an input buffer, in this case, at decimal 512 in RAM).  The label IPBADR is set to the current address in the program counter and the little-endian address of the input buffer INPBFR is assembled at that location.

        DSPTCH  .DBYTE DPADD-1,DPSUB-1,DPMUL-1,DBDIV-1

The above assembles a comma-delimited table of big-endian addresses at location DSPTCH, each address being one location before the actual location to which it refers.  If the following are true:

        DPADD   =$2000
        DPSUB   =$2140
        DPMUL   =$22FF
        DPDIV   =$2368

and the program counter is $1000 when assembly of the table occurs, RAM will appear as follows:

        >1000 1F FF 21 3F 22 FE 23 67

A typical use for the above table would be as follows:

        LDX #INDEX              ;table index
        LDA DSPTCH,X            ;routine-1 MSB
        PHA                     ;setting up a return address
        LDA DSPTCH+1,X          ;routine-1 LSB
        PHA
        RTS                     ;goto routine

The above is an example of the 6502 machine code equivalent of an ON GOTO statement in BASIC.  By the way, this unorthodox technique works because RTS, in pulling the "return address" from the stack, will increment it before loading it into the MPU's program counter.  Hence the MPU will go to the selected routine's real address, not the address minus one. 

        TITLE   .TEXT 'C-128 80 Column Display Manager'

The above assembles the null-terminated character string C-128 80 Column Display Manager and stores the string starting at memory location TITLE, which will be whatever the program counter happens to be when the code is encountered.  An alternate way of accomplishing the above would be:

        TITLE   .BYTE 'C-128 80 Column Display Manager',A_CR,A_LF,A_NUL

which allows characters that can't be entered from the keyboard to be included in the string.  Each character bounded by the single quites ('') is assembled with its ASCII value into memory.  Values defined by symbols (e.g., A_CR) are assembled in the order shown.  Commas are used to delimit values, as the entire series of bytes is treated as a single operand by the assembler.  Note the use of the symbolic representation for the carriage return, linefeed and null characters, rather than hard-coded numbers.

Incidentally, to get a single quote into the string you would code as follows:

        TITLE   .BYTE 'BigDumbDinosaur''s Software',A_CR,A_LF,A_NUL

Note the BigDumbDinosaur''s construct, which will assemble as BigDumbDinosaur's.

In addition to the above pseudo-ops, others may be supported to control assembly.  This would include macro-instructions (macros were not part of the original MOS Technology-supplied assembler), listing controls, conditional assembly, and so forth.  The implementation of any of these features would depend on the inclination of the assembler's developer.

The Commodore MADS assembler package only looked at the first, second and third characters of pseudo-ops, which meant that the pseudo-ops .WORD and .WOR were functionally identical.  This, of course, was not in keeping with the MOS Technology standard.
#16
Links / Xetec Lt. Kernal
January 25, 2008, 03:44 AM
The Lt. Kernal archive website has been updated.  Check it out at http://www.floodgap.com/retrobits/ckb/ltk.
#17
Elsewhere on this site, I've seen various code examples for programming the VDC from BASIC using POKEs and PEEKs.  This method of programming the VDC is incorrect and may cause all sorts of strange and hard-to-fix errors.  Below is an edited statement that was originally found in the VDC technical documentation provided to early 128 developers:

Commodore's specifications for this chip state that when accessing the VDC, you should avoid machine language instructions that use the indirect addressing mode.  That is, you should avoid using instructions like LDA ($CC),Y to read this register because the VDC apparently responds improperly to such instructions.  This imposes no particular hardship on machine language programmers, but has highly unfortunate consequences for BASIC programmers.  The 128's PEEK, POKE, and WAIT instructions are implemented using the Kernal INDFET, INDSTA, and INDCMP routines, all of which use indirect-Y addressing to read or store values.  As a result, you should not use PEEK, POKE, or WAIT statements to read or change the contents of the VDC registers.


The correct way to control the VDC from BASIC is by using two screen editor ROM primitives located at $CDCC and $CDDA.  The former, officially referred to as WRITEREG, writes to a selected register in the VDC.  The other location, READREG, reads from a selected VDC register.

To use WRITEREG from BASIC, you would code:

BANK 15:SYS("CDCC"),D,R

where D is the byte to be written and R is the desired register number.

To use READREG from BASIC, you would code:

BANK 15:SYS("CDDA"),,R:RREG D

where R is the desired register number.  The value in the register will be returned in D.

This quirk in the C-128's hardware was apparently discovered during the prototyping phase, but was never fixed.  The story I was told by Fred Bowen was that everyone was rushing to complete a working machine in time for demonstration at the January 1985 Consumer Electronics Show.  When this little gotcha was discovered, there wasn't enough time to do a new mask for the 8563, which had experienced all sorts of teething problems from the get go.  So the problem has persisted to this day.

Please!  Let's get it right for the noobies who are learning how to make their C-128s do what they want.  Perpetuating the PEEK/POKE method simply complicates things for them.
#18
Herdware / Blown CIAs
January 03, 2008, 04:14 PM
Earlier, there was a query of sorts as to why CIA chips fail.  Most people who have used a C-64 or C-128 have undoubtably encountered at least one instance where a CIA chip partially or completely failed.  Symptoms include a partially or completely dead keyboard, no fake RS-232 output at the user port and no tape functions.  In the case of the 128, CIA #1's serial data port is the fast serial driver, and if CIA#1 goes south, that function will go with it.

CIA #1 is charged with scanning the keyboard and joystick ports.  Failure of any of CIA #1's data lines will cause loss of operation.  Damage to the CIA can also affect the 16 bit interval timers and/or the TOD clock.  Timer A in CIA #1 of a C-64 is critical, as without that timer, there will be no timer A interrupt, which means the jiffy IRQ responsible for scanning the keyboard will not be present.  Applying a logic probe to CIA #1's /IRQ line will quickly indicate if the jiffy IRQ is present, as the required CIA #1 setup is performed early on during system boot.

The majority of CIA #1 failures are caused by static discharge into one of the joystick ports due to the user touching one or more pins.  Most often, the process is one of attrition rather than outright failure.  Each discharge slightly weakens the chip's core until the CIA converts itself from a semiconductor to a full-time conductor.

It is also possible for a serial bus device connected to the 128 to take out CIA #1 by damaging the SP connection inside the chip.  Although SP is used only when a so-called fast serial device is present (e.g, a 1581), a failure in any serial device can be the culprit, since SP is linked to the serial bus' data line.  In the early days of the 128, it was discovered that some of the less well-engineered serial to parallel printer interfaces caused damage.

CIA #2 is susceptible to damage from transients off the serial bus, and at the user port, since many of the data lines, as well as /FLAG and PC, are brought out there.  Some of the early Commodore modems were reputed to backfeed telephone line transients into the user port, taking out the entire computer.  This was apparently the result of using very cheap components in the modem.  The lack of line driver buffers exposes CIA #2 to damage.  Also, accidentally applying an input voltage to a data line set for output and currently holding a zero bit can cause failure in some cases, as the CIA will futilely attempt to sink a line that is delivering too much current.

In the 128, a CIA #2 failure can disrupt the 40 column video, since that CIA is responsible for determining the current RAM video bank being seen by the VIC-II.

Bottom line is that if a CIA goes south in your 64 or 128, look very carefully at what is connected and where your fingers go when you are reaching for the power switch or reset button.  Also, watch out for crud coming in off the power line.  None of the Commodore power supplies do a particulary good job of filter line transients -- the C-64's power supply is almost useless in that regard.  Using a small UPS to power your system is a good idea, if not to avoid data loss when the power fails, to avoid damage when the power goes flaky.

:-)
#19
Auctions et al / Keyboard Wanted
December 19, 2007, 11:27 AM
Looking for a 128DCR keyboard to attach to a North American machine.

Thanks for any help you can provide!
#20
Tips & tricks / Hey, buddy! Ya got the time?
December 11, 2007, 04:09 PM
In most operating environments, the kernel (kernal for you Commodorians) implements a way to generate an arbitrary time delay.  For example, in UNIX or Linux the sleep(x) kernel call will suspend program execution for approximately X seconds.  Unfortunately, Commodore didn't see fit to implement a sleep() function in their kernal.  Yes, it's possible to use the jiffy "clock" but it's about as stable as a three-legged elephant with epilepsy, especially when frequent serial bus activity occurs.

Fortunately, the hardware resources needed to set up a stable and repeatable sleep() function are already available.  All that is needed is a little assembly language code.  There are two parts to the following program: a setup function that is run only once and the delay function itself.


       *=$0B00                ;assembles into cassette buffer
;
cia2   =$dd00                 ;CIA #2 base address
d2tod  =cia2+8                ;time of day (TOD) clock
d2todt =d2tod+0               ;TOD seconds/10 (BCD)
d2icr  =cia2+13               ;interrupt control/source
d2cra  =cia2+14               ;control register A
d2crb  =cia2+15               ;control register B
;
;=======================================
;
;function jump table
;
sleep  jmp tdl                ;delay function $0B00
;
;=======================================
;
setup  lda #%00000100         ;setup function $0B03
       sta d2icr              ;no TOD interrupts
;
;execute next 3 lines on PAL machines only
;
       lda d2cra              ;control register A
       ora #%10000000         ;50 Hz power only!!!
       sta d2cra              ;set frequency
;
       lda d2crb              ;control register B
       and #%01111111         ;setting time, not alarm
       sta d2crb
       lda d2todt             ;nudge the clock
       sta d2todt
       rts
;
;=======================================
;
;time delay function -- load .X with delay in seconds.
;
tdl    ldy #10                ;0.1 sec delay counter
;
tdl01  lda d2todt             ;TOD tenths
;
tdl02  cmp d2todt             ;wait until...
       beq tdl02              ;it changes
;
       dey                    ;step 0.1 sec counter
       bne tdl01              ;repeat
;
       dex                    ;step 1.0 sec counter
       bne tdl                ;repeat
;
       rts
;
;


To perform the setup from BASIC, code as follows:

BANK 15;SYS DEC("0B03")

To call sleep() from BASIC:

BANK 15;SYS DEC("0B00"),,TD

where TD is the delay period in seconds (0=256 seconds).

This code can be ported to the C-64.  Simply find a new home for it, such as the 64's cassette buffer at $033C (828) and change the SYS addresses accordingly.  To pass the time delay in 64 mode POKE it into location 781.