A little historical time trivia: the division of units into 60s came originally from the Sumerians at about 2500 to 2000 BC. Instead of individual digits, they marked units and tens, and then after 5 tens and 9 units (and all these were in the same "place"), there was a great unit, representing 60. There only problem is that there was no 0 as a place holder then, so 1 and 60 looked like exactly the same number! Also, they could subdivide units into 60 pieces, and have a kind of "sexigesimal point," except for one other major problem: you guessed it! no symbol for it. So, a unit on a tablet could represent one, or sixty, or one-sixtieth, or 3600, or 1/3600, etc. lol Anyway, this system was passed on to the Akkadians, the Babylonians, and the Egyptians. It seemed, it was the Egyptians who perfected using sexigesimal units for parts of the 12 hours of the day, which back then were just the duration of daylight each day divided evenly by twelve. Later, the Greeks decided to also account for the hours without daylight and to make all the hours of the full day (more or less) even by dividing the whole thing into 24 hours. AM and PM are designations given to us by the Romans meaning "Before Noon" (Ante Meridian) and "After Noon" (Post Meridian). From there, the 24+ time zones came in the late 19th Century, and now we have atomic clocks that send out time signals on the Internet and beam them to satelites, and GPS that, in part, uses these signals to set their internal clocks by in order to precisely locate every vehicle and device using it.
Base 12 is convenient because it's evenly divided by 2,3,4, and 6 as well as 12. 60 is the smallest base that adds 5 to the mix. So those were logical choices. And today we have 60 seconds in the minute and 60 minutes in the hour or angular degree. 360 degrees in a circle is a nice round number in base 60 and close to the number of days in the year. A largely unappreciated side effect of the 24-hour day is the order of the days in our week. Originally, the seven Greek "planets" (everything visible to the naked eye that moved against the stars: Saturn, Jupiter, Mars, the Sun, Venus, Mercury, and the Moon) were assigned to hours instead of days. The assignment ran in the above order, from slowest to fastest motion through the night sky. When ancient timekeepers switched from hours to days, they named each day after the planet governing its first hour, and since 24 mod 7 is 3, successive days had names separated by 3 in the above list: the Sun, the Moon, Mars, Mercury, Jupiter, Venus, and Saturn. The associations between the planets and day names are more obvious in the Romance languages; in English, only Sun=Sunday, Moon=Monday, and Saturn=Saturday make sense directly. But that's because Old English timekeepers mapped the Roman gods to their own pantheon instead of adopting the rest of the names directly. So Mars, the Roman god of war, was taken to be Tiw (Norse Tyr), whence Tiw's Day->Tuesday, and likewise down the line: Mercury->Woden(Odin)->Wednesday, Jupiter->Thor->Thursday, and Venus->Frigg(Freya)->Friday.
The 6/5 fix is even more convoluted. If you start with the value 5 from the last call, until the BPL at $f62f actually triggers, you have 6 values: 5,4,3,2,1,0. The BPL at $f62f only falls through on the transition from zero to minus 1. So, I first thought this would be a 7/6 fix - but, as the Jiffy increment is repeated, so is the DEC of the fix counter at f631. I.e. even the fix counter, that has 6 values, is decremented twice in one interrupt. Therefore it indeed is a 6/5 fix for the Jiffies.
Hi, love the videos takes me back ;-) Also NTSC is not 60 image per second (actually it's 1 image for the impair lines and one with the pair lines so it's 29.97 complete image per second composed of two half of the image interlaced), it is 59.94 because the color burst was interfering with the audio on old TV when they added colour to the black and white signal they just reduced the images per second to be out of the harmonics of the audio sub carrier. Also timecode to be accurate for each image had to be compensated for by dropping 1 frame every minute except on minute 10, 20, 30, 40 and 50 it's called dropframe timecode and even audio recordings had to have those "drop frames" in their timecode so that they can stay in sync with the video. And even today you still have 59.94 images per second in HD even if it's not a problem anymore for over the air broadcast since it's now in digital form and there are no need for it.
Thanks, yes, the true NTSC spec is as you say. However, most/all 8-bit computers and games consoles were not exactly to spec. They neither ran at exactly 59.94 (or 29.97 depending on how you're counting) Hz, and most did not generate proper odd/even interlacing video either. So I find it's both easier *and* more accurate to just talk about 60 fps video output.
@@8_Bit Yes exactly, coming from a TV background, those missing frames in the timecode was something to really check for or else for example the commercial brakes were not at the correct time and you saw bumpers coming in out off commercial brakes in the middle of the show and you got commercial brakes in the middle of a sentence... Or the a show of 1 hour was short by 108 frames and you got black on air during that time. And it was easy as flipping a switch on a VTR to be in non-drop frame mode...
I heard the field rate is exactly 60*1000/1001. Would they really have needed drop frames every so often when they could just play video back a tiny bit slower? ua-cam.com/video/3GJUM6pCpew/v-deo.html
@@csbruce They actually dropped the frequency from 60 to 59.94 but timecode is a number attached (either in an audio extra track (LTC) or embedded in the vertical interval of an image (VITC)) so to be accurate so that an hour long show it's timecode will also be an hour long, you have to skip the numbering of frames going from 10:01:59:29 for example to 10:02:00:01 skipping 10:02:00:00 to compensate so that the timecode stays in sync with the actual duration.
how to quickly calculate in machine language: x2 = shift 1 bit left (1clock cycle only) x3 = shift 1 bit left + add itself ( 2 clock cycle) x4 = shift 2 bit left ( 2 clock cycle) x5 = shift 2 bit left + add itself ( 3 clock cycle) x6 = do x2 and x3 ( 3 clock cycle) x7 = do x2 and x3 + add itself ( 4 clock cycle) x10 = do x5 and x2 ( 4 clock cycle)
Very nice. And I also love that you finally also show some C128 internals, not just C64 :) I would love to see that much more often... By the way I never understood why they didn't implement a query on the CIAs timers instead, which will work even with interrupts disabled ("SEI" command in Assembler) and is more exact. Very very strange design decision if you ask me. GEOS clock does it right IIRC.
The CIA's TOD clock is specifically designed for accurate time keeping, and should be more accurate than CIA timer. But I don't think there is a PAL CIA, so I don't think the TOD is accurate on PAL. I don't have PAL machine to check...
Jiffies remain jiffies in Europe and North America unlike feet and ounces :) I guess the confusion comes from the difference of CPU frequencies. The CIA will wait freq/60s CPU cycles to perform an IRQ. That's 16,421 (=985,248/60) CPU cycles on a PAL but 17,045 (=1,022,730/60) CPU cycles on an NTSC.
2:23 Here's an obscure little bug. If you move the BASIC memory area to anywhere in the 4kB block between $C000 and $CFFF, then accessing either TI$ or TI with array indices will actually return the system time as if you accessed the TI$ or TI "variables" themselves. For example, PRINT TI$(5) will be treated as the same as PRINT TI$. 13:12 Minor quibble - the way the KERNAL sets the CIA system timer is not quite "independent" of the video display. Rather, the KERNAL must first determine whether the C64 is PAL or NTSC in order to determine the processor speed so that it can set the CIA timer to 60 Hz (and theoretically, in certain very unlikely circumstances, this determination by the KERNAL can be wrong).
4:10 It's not a dummy parameter on the C128. 5:39 Reading a multi-byte value without protection can give an inconsistent result. Here, you could read a high byte right before it increments and then read the low byte right after it rolls over. It's odd that the jiffy clock is big-endian. 10:00 There's another potential bug here: the IRQ handler doesn't execute a CLD, so if Decimal mode is active in a user program when an interrupt happens, the time comparison with SBC will be done in BCD and will be wrong. Also, SEC : LDA $A2 : SBC #$01 code could be shortened to LDA $A2 : CMP #$01. 11:42 You could avoid the race condition by printing the TI figure first every time. 14:43 Making the number of jiffies per second different between regions would produce a lot of broken BASIC programs. 15:44 C128 BASIC is so sluggish that you pretty much can only use it in FAST mode. 16:13 One minor issue is that the NTSC field rate isn't exactly 60 Hz, while PAL is supposed to be exactly 50 Hz.
Good point about the FRE() parameter. In C128 mode it refers to the RAM bank, and it's an ILLEGAL QUANTITY to pass anything other than 0 or 1. FRE(0) is space available for the BASIC program, while FRE(1) is space available for variables.
And if I remember correctly, on the B128 (80-column CBM-II machine) the 128K is split up into four 32K banks. FRE(0) returns free code space, while a parameter of 1, 2, or 3 returns free variable space for each different type: string, scalar, or array, or something similar to that.
@@8_Bit: According to the Anthology (p.43), this corresponds to how the B-series RAM banks were used, though they seem to skip bank 0. Sounds like they fill each of the four RAM banks only half-way for the B128.
POS(x) has a dummy parameter. Even on the C128 where it could conceivably use different values for the 40 and 80 column displays... Even though TI and ST are weird functions, it saves typing and bytes to omit the parentheses...
Great analysis Robin. I never really thought about how those might have been implemented since they are special. You should make a consolidated list of all your bug fixes. It is super easy to use a patched kernel with an EasyFlash 3. BASIC is slightly harder but still doable without opening up the C64 with the right cartridge. (Or just use emulators of course) At least the Commander X16 ROM could have these bug fixes easily! I would be happy to file issues / pull requests. I’m amateur at best but happy to help.
It'd be a neat idea to make an unofficial "KERNAL V4" ROM that incorporates the best fixes/patches people have come up with. I'd be happy if some of my ideas made it in there, but I don't have full confidence that these patches don't have some side effect I haven't noticed. I'm happiest exploring and raising awareness about these strange quirks and if you and/or others want to pull it together with other contributions into a project that produces an alternate ROM that'd be really cool.
I assumed TI was just a variable with a fixed pointer to a location that is constantly updated and not treated any differently. Also you're the only reason I'm even aware of TI in the first place. When I was a kid I never heard of it. But my programs were always super super super simple.
If Commodore BASIC supported 24-bit integer values it would make sense to just have TI be a permanent entry in the variable table pointing to the jiffy clock. But it has to be converted to floating-point, which is a pretty expensive operation to be doing 60 times a second, every second. Much more efficient to only do that when the program accesses the variable.
@@markjreed makes sense. I always thought of BASIC as this magic box that just works (especially as a kid). I never thought that much about what was in it. Especially now that I use much more modern languages these days.
14:25 The following will perform an exact one-second time delay on an NTSC or PAL C64 and confirms that there are 60 Jiffies per second on either system: 10 ti$="000000" 20 ifti$"000001"then20 30 printti
I will have to dig out my old C64. In the USA you have 60Hz AC, in Australia and UK we have 50Hz AC. When coding split screen on the C64 it was from memory 50Hz to be in sync with the TV otherwise it would not work. Clock speed was also adjusted to be in sync with video refresh. Eg: “6510 CPU is clocked at 1.023 MHz (NTSC) and 0.985 MHz (PAL)”
I think they accepted the 1/60th of a second off time, because if you have a look, it makes the code easier. You can do SBC 01 to force the carry flag to ripple through the other two subtractions, otherwise you'd need to check if the first byte is 00 and branch out manually. Either speed or memory size constraint. Plus, if you think about it: the clock is not from the more stable TV signal oscillator, but the "roughly 60 Hz" timer. That one is most def. far less accurate than 1/60th of a second in a day.
No. The wrap-around code will work just fine if the first constant is zero. Using 1 instead is definitely a bug. However, if you reverse the order of subtraction then the correct first constant would be 1 (because of the way CPU carry flag works. You can test this yourself by copy ROM to RAM and modify like Robin did. I guess maybe they had the order of subtraction reversed at sometime, then reversed the order, but the constant was not updated. Who knows? What is surprising is it wasn't fixed on C128.
Excellent video Robin. Very interesting indeed. Until recently I always thought that TI and TI$ came from the TOD clocks in the CIA chips. Do you know of any software that uses the CIA TOD clocks for timekeeping rather than the KERNAL derived time functions? Do you know how the KERNAL sets the CIA's 50/60Hz flag, how it determines if it's operating in a 50Hz or 60Hz AC area? What about the SX-64 where it has a built in 60Hz oscillator for the CIA chips? Interesting to know your thoughts.
Love this, Robin. Interestingly, the MEGA65, which I know is a modern device, includes a battery backed RTC. Wonder how this hardware addition might modify your TI and TI$ (they are reserved for BASIC 65) tips and tricks, if at all.
On the Mega65's BASIC 10, TI$ and TI are independent variables. TI$ has the current clock time (complete with colons now), while TI is the number of seconds (with fraction) since boot. Neither of them is resettable, either, which makes timing things a little more work.
TI and TI$ are almost a cross between a variable and a function. Vartion? Functable? I remember using TI and TI$ in some of my early BASIC programmes but haven't used them in years. I guess they left that jiffy number the same in the C128 Kernal/BASIC to avoid breaking backwards compatibility. It's amazing how dense and interconnected the BASIC ROM is, with routines calling other routines. I wonder how many jiffies this video lasted?
Question: does copying the basic (and Kernal?) ROMs to RAM increase the speed of BASIC programmes (since RAM is typically faster than ROM) - IBM clones used to mirror (AKA shadow) ROMs to RAM for a speed increase.
On a stock C64, RAM and ROM are the same speed. On my SuperCPU accelerator for the C64 (which is unfortunately quite rare) then the RAM is a lot faster and it does copy/shadow the ROMs into RAM like the IBM clones did.
I always wondered why they did not use TOD from any CIAs for printing TIme now I know, that by using US supply on PAL Commodore would give us wrong TIme, As when you use US power supply you will get 60Hz signal on TOD (pin 19 on both CIAs) while EU power supply gives 50Hz signal, so your test would not be valid in case when TOD is used. So IRQ runs 60 times per second and that is independent of PAL or NTSC C64 /128, source of IRQ is CIA1 and your test is valid only because crystal for PAL/NTSC is different. I found this funny and interesting at the same time :)
No, that would be a much more elaborate patch and the original authors didn't appear to even attempt that level of error checking. They did seem to want a numeric digit check and as it was easy to implement, I tried it :)
7:19: 5183974 does not equal exactly one second before midnight (5183940). I suspect the discrepancy/delay might be accounted for by the time it takes to interpreted code to run.
The error is actually worse because the actual field rate of NTSC is 60/1.001 ~ 59.94 So the actual count should be from 0 to 5 178 820 Actually because of the quartz used in the C64 or slow C128 it's actually 1 022 700×7÷2÷227,5÷525 =29,96923 images per second. So a good count should be from 0 to 5 178 682
I'm sorry but I don't follow. The TI variable is counting jiffies which are approximately 1/60th of a second but have nothing to do with the NTSC or PAL video standards. Jiffies are counted each system IRQ which is driven by the CIA timer interrupt which counts cpu/system cycles.
I think you're under the impression that the Time of Day source is the video crystal, but it actually comes directly from the A/C line from the power supply. Only the interrupt routine on the C128 runs from vsync, not the TOD timer itself. There should be some error involved since the interrupt and timer updates don't sync, but the error is still pretty small. The system timers make a lot of sense on the C64 and C128. The Amiga is what has me all confused, since most of those systems *DO* get the TOD source from vsync. I haven't figured out yet how AmigaOS determines whether the hardware uses a 59.94 Hz or 60 Hz timer.
I had to turn on my PAL C128 running on 50Hz AC to check if this was true. I was pretty surprised they went with 60Hz timer on all machines. I thought they simply used AC input as source for a clock counter.
Yes, I think there's a lot of uncertainty surrounding this topic; I wasn't sure about several things until I really dug into it for this video. Though now that you mention it, I didn't even talk about the AC input! Or how the system IRQ timer is set in the first place.
@@8_Bit: Also, the bulk of the C64 ROM content was just copied in a hurry from the VIC-20. The VIC used a timer configured for a 60 Hz IRQ, so that just got copied into the C64.
The TOD in the CIAs is indeed clocked by the mains frequency in most C64 variants but the CPU interrupt is timer driver. TOD tick is derived from the 9VAC supply. If you want a less drifty time of day read the CIA registers instead of relying on TI etc. There's gotchas such as ensuring the CIA is configured for the mains frequency in your area. This isn't necessarily correct. Apparently different ROM versions didn't work it out properly, and of course you could be using a C64 intended for an NTSC country in a PAL country and vice-versa.
Hmmm. Code that patches the kernal like that should probably check to see if the RAM version is already in use due to another patch, so that multiple patches can be compatible, instead of wiping each other out.
I wonder if 1/60s jiffy is a remnant of old unix time system when they probably used 60Hz counter instead of counting every second since 1 january 1970 in utc. At least wikipedia says so.
The 1/60th of a second bug assumes that a Jiffy really is 1/60th of a second. I had computers in the 90's where the clocks were not that accurate. I had to reset the clock monthly to get the time in the right ballpark. They would lose or gain 5 minutes a month or so. So the real question is how accurate is the 1/60 second timer. I used to have an internet based alarm clock that was even less accurate than that. So every week I would just unplug it and when restarting it would update the time automatically. Eventually they issued an update that it would check the clock at least once per day. But it was nice because I got pandora radio as my wakeup call instead of a CD starting on the same track every day or the stupid radio with some jerk that I don't care about making horrible jokes that just makes me mad at 7 am. lol (and no they aren't anymore funny at 5 pm either)
I read somewhere, don't remember where though, that on the C128 a jiffy is a 100th of a second instead of a 60th. Interesting to see that proven wrong, as I assumed that to be so.
That's not the C128, but the term "jiffy" has been used for other subsecond intervals. The 0.01-second version shows up mostly in Linux. Microsoft file and directory timestamps count from 1601-01-01T00:00:00Z the number of 100-nanosecond periods (= one ten-millionth of a second), which are also sometimes called "jiffies".
Thanks for this interesting video! The CBM machines are new to me (grew up with MSX), and with my new MEGA65 I'm now working my way through the C64 User Guide and the C64 Programmers Reference Guide. Can you please explain to me how/where to find the keys corresponding to the graphical characters? Like in your program TIME WRAP, line 1, you have the inverted heart. I know it is CLR HOME after trial and error, but could I have find it somewhere in the manuals?
Hi, congratulations on getting a MEGA65! Yes, all these special symbols are shown in the C64 Programmer's Reference Guide on pages 72-74, when describing the various special Quote Mode, Insert Mode, etc. They're a bit quirky, but also quite powerful and efficient.
@@8_Bit Ahhhhh....yes, I see them now! Thanks a lot!! I was searching for them in the appendix etc. ps, the C64 core for the MEGA65 is amazing, but also the C64 mode ("GO64") in MEGA65/C65 is already quite compatible.
To add to that, on the schematic of both C64 and C128 there is pin 19 (TOD Time Of Day) on the CIAs that is connected to the AC 9 Volts input and that is where it gets it's time reference, and in most countries the 60 Hz is really precise and is compensated by the utility company so that it is accurate overtime. Bwak on UA-cam has interesting videos of reverse engineering the CIAs from pictures of the die and we see those counters of the Time Of Day pin 19 ua-cam.com/users/bwackvideos
The CIA does get 50 or 60 Hz from AC for the TOD but to be clear (I'm not sure if you're implying otherwise or not) that's not used by the C64 for the TI or TI$ functions at all; they're driven by the system IRQ which is driven by a CIA timer interrupt set to roughly 1,000,000 / 60 microseconds. The TOD functions are an interesting and under-utilized feature of the C64 I think.
Were you on a PAL machine? I used an NTSC C128 as my main computer for years and only very rarely noticed any flickering in the split-screen graphics modes.
@@alexmcd378 Ah, emulators. I know VICE x128 in NTSC mode simply does not handle split-screen graphics; the entire text portion of the screen flashes, rendering it completely unusable. In PAL mode there's a much more minor flicker of just a scan-line or so. Which was also on the PAL machine in this video, so maybe that's accurate to the real hardware!
@@markjreed that's it exactly. If you use draw routines to cover the bottom couple rows of pixels of the graphics area, it reduces the flicker to a single row of pixels. Not ideal, but much less distracting
I wonder if there is any difference with TI or TI$ in the C128 1986 rom revision? Nothing is mentioned in the Rom Announcement! palnts $02A6 ;pal =1 or ntsc =0 set during init using video These values are used to set timers depending on palnts so 60 hertz will be correct sixty = 17045 ;ntsc sixtyp = 16421 ;pal
I probably missed something, but does the "hack" of looking for _TI_ not preclude using variable names beginning with TI? Meaning that TIMOTHY for example can't be used as a name for a variable?
@@8_Bit Oh... well, I suppose not having touched a C64 in a... never-mind-how-long time, can excuse me for forgetting that little detail. No? Thx for replying.
I'm in the process of compiling a pretty comprehensive list of bugs in the kernal and basic roms. More comprehensive than any I have ever seen, really. I may publish it some day when it's complete.
Hi, its Magnus. Me and my nephew are playing last update VERMEER in C64 and saving isnt working proper. neither in cas mode than in disk mode. My promis was to be able to save it but I cant. May you help me?
Hi Magnus. Sorry I don't know anything about that game, especially since it's in German, but here's a good website with info and links to another website with a manual. You can see if it even supports a save feature: www.c64-wiki.de/wiki/Vermeer Are you playing on a C64 with a real disk? You might need to insert a blank, formatted disk to get the save to work. I'm just guessing though; let me know more of the symptoms and maybe I'll have other ideas.
Is there a way for a program to find out whether it runs on a 50 Hz AC or 60 Hz AC machine? Or does it have to ask the user? I am thinking of a program that uses a TOD clock and wants to set that accordingly.
I was looking into this a week or two ago. Some programs just check if they're running on PAL/NTSC and assume 50/60 AC based on that. A large % of the time that is an okay assumption. However it's wrong for some edge cases, such as the SX-64 which has a 60 Hz TOD no matter whether PAL or NTSC as it has an internal 60 Hz crystal generating the signal instead of using AC. A better solution is to start a CIA timer (cycle counter) and set the TOD to 60 Hz and count the cycles it takes for the TOD to reach a certain amount of time (like a 10th of a second or whatever). Then that cycle count can be used to see if the TOD is really running at 60 Hz, or if it's too far out, 50 Hz must be right.
How does the C64 get it's 60Hz clock? I read on the internet that it's from a free-running CIA hardware timer, which reminds me of an AVR328-based clock project of mine that needed a 60Hz clock. I discovered that at the usual 16Mhz, there was no way to get a proper value in the 16-bit hardware timer to get exactly 60Hz so I ran the AVR at 12Mhz where there was a proper division (and I had to re-work the WS2812 assembly to get it to bit-bang at that speed). It makes me wonder if this leap-jiffy "bug" might be covering up for a pretty-darn-close-but-not-quite 60Hz clock - or maybe it just makes it worse ;^) Can any CIA gurus verify the precision of the CIA timer interrupt to give exactly 60Hz?
@@ImYourProblem I've done some reading since my comment and it seems that the jiffy clock comes from a CIA hardware timer and the CIA TOD real-time clock comes from the mains.
At 47.30 I am not so sure this is a valid test. Maybe both pal and ntsc 128 computers solve it differently on pcb level. How these 'rumours' started is that for C64, for the 250407 assy for example, the schematics clearly show that the TOD pins from the CIA's are connected to a little circuit that basically generates clock pulses based on the 9V ac input. So taking the 'pal' or 'ntsc' version would not matter as it is the line voltage alternation that is the driving factor.
Even in the C128 schematics the TOD pins from CIA1 and 2 are hooked up to the 9V AC. Through a Smitt Trigger and Zener and some timing circuitry. I don't have any own tools or something to do any measurements but it could well be this indeed is always 60 because you are just not changing your line phase.
Well, even though this doesn't have to do directly with the video standard, most PAL regions use 50 Hz AC power, while most NTSC regions use 60 Hz. I guess this is where the thought comes from. But you are correct, even on a PAL C64, a Jiffy is a 60th of a second. (Or close to at least, it seems to be kinda inaccurate)
@@paulkoopmans4620 There seems to be an assumption that the TOD in the CIA has something - anything to do with TI and TI$, but it doesn't. TI is incremented as part of the main system IRQ which is driven by a looping CIA timer (cycle counter) set to approximately 1 000 000 / 60 cycles. TOD is driven by AC, but it's not used by the TI functions at all.
Well that 1/60th of a second within a day is hardly relevant considering the JiffyClock is not very accurate at all. I think even after one hour you will see considerable drift from the actual time.
@14:30 you are running a PAL version on a power supply that is fed with 60Hz AC. PAL was designed for 50Hz. This could affect the results of your experiment.
All CPU and video timings on the C64 and C128 are derived from a crystal oscillator of 14.31818 MHz for NTSC and 17.734475 MHz for PAL, and have nothing to do with the AC frequency. The only thing the 50 or 60 Hz AC does is drives the Time Of Day (TOD) clock on the CIA chip, but that is not the source of the system IRQ. The system IRQ is driven by a CIA system cycle counter / timer in C64 mode at approximately 60 Hz, or by the video refresh on a C128 (at 50 Hz in PAL or 60 Hz in NTSC), but none of those 50 or 60 Hz for video or system interrupts have anything to do with the AC power frequency.
TI$ is not stored in RAM, but TI is. It is at addresses $00A0..$00A2. It is big-endian, in units of 1/60 seconds. Evaluation of the TI$ variable reads the TI value and converts it to the more human-readable HHMMSS form.
@@madmartigan1498 As for TI, I'm not sure what you mean by converting $00A0..$00A2 to TI, since for all intents and purposes $00A0..$00A2 **is** TI. You can get this value in an interrupt-safe manner by calling the kernal's RDTIM function at $FFDE. It returns the three bytes in the Y, X, and A registers in order from high to low. As for TI$, this is done by the routine that evaluates a BASIC variable within a BASIC expression. This routine is located at $AF28 in ROM. This routine calls another routine at $BE68 which does the actual work of the numeric conversion (incidentally, this function is also used by the routine that converts a floating point value to a decimal string). The resulting 6-character string is stored in BASIC String RAM at a location chosen by the BASIC interpreter. A 3-byte descriptor for this string is pushed to BASIC's temporary string stack (located at $19..$21) and a pointer to that descriptor is returned in memory locations $64/$65. Additionally, an interim working copy of the string will be found at $00FF..$0104, but this will be overwritten by any subsequent conversion of a numeric value to a string. I'm not sure if you are asking purely for curiosity's sake, but if you're thinking about writing code to use this built-in feature, there are a number of things you must consider. First, the routine at $AF28 starts by reading a variable name from the BASIC command buffer. This means that there MUST be a valid active BASIC command buffer pointer that currently points to the first character of the TI$ variable name. If you simply want to get the TI$ value "on the fly", I suppose you could bypass the command buffer read by instead calling into the routine at $AF48. Remember, though, that this routine is part of the BASIC interpreter, and it expects and requires a fully operational BASIC environment. Additionally, you would need to make sure that you properly deregister the temporary result string from BASIC's string stack by loading the the pointer at $64/$65 into the Y and A registers (low byte in A, high byte in Y) and calling the routine at $B6AA. This will return a pointer to the string data in memory locations $22/$23. This string should be used for your intended purpose before invoking any additional functions in the BASIC interpreter, as there is a good chance that pointer will be overwritten by the interpreter. If you DON'T want to have a full BASIC environment active (e.g. String RAM, Variable RAM, program memory, temporary string stack, garbage collector, etc.), you could just use the conversion routine at $BE68. Here's how you would do it: 1. Call the routine at $AF84 to convert TI to a 32-bit big-endian integer at $0062..$0065. 2. Store the value 0 in memory location $5E. 3. Store the value #$FF in memory location $71. 4. Store the value 6 in memory location $5D. 5. Load the Y register with the value #$24. 6. Call the conversion routine at $BE68. 7. The resulting 6-character string can then be read from memory at $00FF..$0104. Note that this method requires the use of the following memory locations, so you would have to be sure they aren't in use by other parts of your code: $0047, $005D, $005E, $0062..$0065, $0071, $00FF..$0105.
It's amazing how many errors / bugs etc. there are in a 40 year old 8k kernal rom, it's easy to see how windows would have so many unforeseen errors / backdoors / bugs etc. as software is based on older software which is based on older software etc.etc.etc. The C64 maybe flawed but it plays Bruce Lee so I'm happy.
These can be hardly called errors / bugs because under all practical circumstances, it all works. No one sets the time to 99:99:99 (and even then nothing explodes), or cares if TI$ is off a second when running for months.
Honestly though, a lot of the bugs are CAUSED by the need to cram everything into such a small space. Add to that the fact that it was all programmed in handmade assembly... lots of very ugly hacks are used to get the job done. In a modern O/S, many of these kind of bugs would be avoided by adherence to proper coding standards and the use of MUCH better development tools.
Your “extremely unimportant fix” is fascinating! 😉
I love these extra-nerdy deep dives! I bet this episode took a long time to make. Thanks!
A little historical time trivia: the division of units into 60s came originally from the Sumerians at about 2500 to 2000 BC. Instead of individual digits, they marked units and tens, and then after 5 tens and 9 units (and all these were in the same "place"), there was a great unit, representing 60. There only problem is that there was no 0 as a place holder then, so 1 and 60 looked like exactly the same number! Also, they could subdivide units into 60 pieces, and have a kind of "sexigesimal point," except for one other major problem: you guessed it! no symbol for it. So, a unit on a tablet could represent one, or sixty, or one-sixtieth, or 3600, or 1/3600, etc. lol Anyway, this system was passed on to the Akkadians, the Babylonians, and the Egyptians. It seemed, it was the Egyptians who perfected using sexigesimal units for parts of the 12 hours of the day, which back then were just the duration of daylight each day divided evenly by twelve. Later, the Greeks decided to also account for the hours without daylight and to make all the hours of the full day (more or less) even by dividing the whole thing into 24 hours. AM and PM are designations given to us by the Romans meaning "Before Noon" (Ante Meridian) and "After Noon" (Post Meridian). From there, the 24+ time zones came in the late 19th Century, and now we have atomic clocks that send out time signals on the Internet and beam them to satelites, and GPS that, in part, uses these signals to set their internal clocks by in order to precisely locate every vehicle and device using it.
Base 12 is convenient because it's evenly divided by 2,3,4, and 6 as well as 12. 60 is the smallest base that adds 5 to the mix. So those were logical choices. And today we have 60 seconds in the minute and 60 minutes in the hour or angular degree. 360 degrees in a circle is a nice round number in base 60 and close to the number of days in the year.
A largely unappreciated side effect of the 24-hour day is the order of the days in our week. Originally, the seven Greek "planets" (everything visible to the naked eye that moved against the stars: Saturn, Jupiter, Mars, the Sun, Venus, Mercury, and the Moon) were assigned to hours instead of days. The assignment ran in the above order, from slowest to fastest motion through the night sky. When ancient timekeepers switched from hours to days, they named each day after the planet governing its first hour, and since 24 mod 7 is 3, successive days had names separated by 3 in the above list: the Sun, the Moon, Mars, Mercury, Jupiter, Venus, and Saturn. The associations between the planets and day names are more obvious in the Romance languages; in English, only Sun=Sunday, Moon=Monday, and Saturn=Saturday make sense directly. But that's because Old English timekeepers mapped the Roman gods to their own pantheon instead of adopting the rest of the names directly. So Mars, the Roman god of war, was taken to be Tiw (Norse Tyr), whence Tiw's Day->Tuesday, and likewise down the line: Mercury->Woden(Odin)->Wednesday, Jupiter->Thor->Thursday, and Venus->Frigg(Freya)->Friday.
Most excellent! Off By One: The error so common that it earned its own name. I love the one byte fix.
The 6/5 fix is even more convoluted. If you start with the value 5 from the last call, until the BPL at $f62f actually triggers, you have 6 values: 5,4,3,2,1,0. The BPL at $f62f only falls through on the transition from zero to minus 1. So, I first thought this would be a 7/6 fix - but, as the Jiffy increment is repeated, so is the DEC of the fix counter at f631. I.e. even the fix counter, that has 6 values, is decremented twice in one interrupt. Therefore it indeed is a 6/5 fix for the Jiffies.
Hi, love the videos takes me back ;-) Also NTSC is not 60 image per second (actually it's 1 image for the impair lines and one with the pair lines so it's 29.97 complete image per second composed of two half of the image interlaced), it is 59.94 because the color burst was interfering with the audio on old TV when they added colour to the black and white signal they just reduced the images per second to be out of the harmonics of the audio sub carrier. Also timecode to be accurate for each image had to be compensated for by dropping 1 frame every minute except on minute 10, 20, 30, 40 and 50 it's called dropframe timecode and even audio recordings had to have those "drop frames" in their timecode so that they can stay in sync with the video. And even today you still have 59.94 images per second in HD even if it's not a problem anymore for over the air broadcast since it's now in digital form and there are no need for it.
Thanks, yes, the true NTSC spec is as you say. However, most/all 8-bit computers and games consoles were not exactly to spec. They neither ran at exactly 59.94 (or 29.97 depending on how you're counting) Hz, and most did not generate proper odd/even interlacing video either. So I find it's both easier *and* more accurate to just talk about 60 fps video output.
@@8_Bit Yes exactly, coming from a TV background, those missing frames in the timecode was something to really check for or else for example the commercial brakes were not at the correct time and you saw bumpers coming in out off commercial brakes in the middle of the show and you got commercial brakes in the middle of a sentence... Or the a show of 1 hour was short by 108 frames and you got black on air during that time. And it was easy as flipping a switch on a VTR to be in non-drop frame mode...
@@TheBookaroo Ah, the days when commercials interrupting mid-sentence was a bug, not a feature.
I heard the field rate is exactly 60*1000/1001. Would they really have needed drop frames every so often when they could just play video back a tiny bit slower? ua-cam.com/video/3GJUM6pCpew/v-deo.html
@@csbruce They actually dropped the frequency from 60 to 59.94 but timecode is a number attached (either in an audio extra track (LTC) or embedded in the vertical interval of an image (VITC)) so to be accurate so that an hour long show it's timecode will also be an hour long, you have to skip the numbering of frames going from 10:01:59:29 for example to 10:02:00:01 skipping 10:02:00:00 to compensate so that the timecode stays in sync with the actual duration.
Excellent! Had to refresh our memory of TI and TI$ when we did the Smokerdore 64 program so it was a good case of how to use them.
how to quickly calculate in machine language:
x2 = shift 1 bit left (1clock cycle only)
x3 = shift 1 bit left + add itself ( 2 clock cycle)
x4 = shift 2 bit left ( 2 clock cycle)
x5 = shift 2 bit left + add itself ( 3 clock cycle)
x6 = do x2 and x3 ( 3 clock cycle)
x7 = do x2 and x3 + add itself ( 4 clock cycle)
x10 = do x5 and x2 ( 4 clock cycle)
It was really interesting to understand all these TI connected things. Thanks for another great video.
Very nice. And I also love that you finally also show some C128 internals, not just C64 :) I would love to see that much more often...
By the way I never understood why they didn't implement a query on the CIAs timers instead, which will work even with interrupts disabled ("SEI" command in Assembler) and is more exact. Very very strange design decision if you ask me.
GEOS clock does it right IIRC.
The CIA's TOD clock is specifically designed for accurate time keeping, and should be more accurate than CIA timer. But I don't think there is a PAL CIA, so I don't think the TOD is accurate on PAL. I don't have PAL machine to check...
@@H2Obsession the pal version does have the cash going on at 60hz, it is used by goes for example 🙃
Jiffies remain jiffies in Europe and North America unlike feet and ounces :) I guess the confusion comes from the difference of CPU frequencies. The CIA will wait freq/60s CPU cycles to perform an IRQ. That's 16,421 (=985,248/60) CPU cycles on a PAL but 17,045 (=1,022,730/60) CPU cycles on an NTSC.
Remember how hard it was to use a time value in strange fractional second units. Most high level languages have time in milliseconds.
2:23 Here's an obscure little bug. If you move the BASIC memory area to anywhere in the 4kB block between $C000 and $CFFF, then accessing either TI$ or TI with array indices will actually return the system time as if you accessed the TI$ or TI "variables" themselves. For example, PRINT TI$(5) will be treated as the same as PRINT TI$.
13:12 Minor quibble - the way the KERNAL sets the CIA system timer is not quite "independent" of the video display. Rather, the KERNAL must first determine whether the C64 is PAL or NTSC in order to determine the processor speed so that it can set the CIA timer to 60 Hz (and theoretically, in certain very unlikely circumstances, this determination by the KERNAL can be wrong).
4:10 It's not a dummy parameter on the C128.
5:39 Reading a multi-byte value without protection can give an inconsistent result. Here, you could read a high byte right before it increments and then read the low byte right after it rolls over. It's odd that the jiffy clock is big-endian.
10:00 There's another potential bug here: the IRQ handler doesn't execute a CLD, so if Decimal mode is active in a user program when an interrupt happens, the time comparison with SBC will be done in BCD and will be wrong.
Also, SEC : LDA $A2 : SBC #$01 code could be shortened to LDA $A2 : CMP #$01.
11:42 You could avoid the race condition by printing the TI figure first every time.
14:43 Making the number of jiffies per second different between regions would produce a lot of broken BASIC programs.
15:44 C128 BASIC is so sluggish that you pretty much can only use it in FAST mode.
16:13 One minor issue is that the NTSC field rate isn't exactly 60 Hz, while PAL is supposed to be exactly 50 Hz.
Good point about the FRE() parameter. In C128 mode it refers to the RAM bank, and it's an ILLEGAL QUANTITY to pass anything other than 0 or 1. FRE(0) is space available for the BASIC program, while FRE(1) is space available for variables.
And if I remember correctly, on the B128 (80-column CBM-II machine) the 128K is split up into four 32K banks. FRE(0) returns free code space, while a parameter of 1, 2, or 3 returns free variable space for each different type: string, scalar, or array, or something similar to that.
@@8_Bit: According to the Anthology (p.43), this corresponds to how the B-series RAM banks were used, though they seem to skip bank 0. Sounds like they fill each of the four RAM banks only half-way for the B128.
POS(x) has a dummy parameter. Even on the C128 where it could conceivably use different values for the 40 and 80 column displays... Even though TI and ST are weird functions, it saves typing and bytes to omit the parentheses...
@@H2Obsession: At 4:10, Robin is talking about the FRE(x) function. On the C128, the FRE() parameter is the RAM bank.
Great analysis Robin. I never really thought about how those might have been implemented since they are special.
You should make a consolidated list of all your bug fixes. It is super easy to use a patched kernel with an EasyFlash 3. BASIC is slightly harder but still doable without opening up the C64 with the right cartridge. (Or just use emulators of course)
At least the Commander X16 ROM could have these bug fixes easily!
I would be happy to file issues / pull requests. I’m amateur at best but happy to help.
It'd be a neat idea to make an unofficial "KERNAL V4" ROM that incorporates the best fixes/patches people have come up with. I'd be happy if some of my ideas made it in there, but I don't have full confidence that these patches don't have some side effect I haven't noticed. I'm happiest exploring and raising awareness about these strange quirks and if you and/or others want to pull it together with other contributions into a project that produces an alternate ROM that'd be really cool.
I assumed TI was just a variable with a fixed pointer to a location that is constantly updated and not treated any differently. Also you're the only reason I'm even aware of TI in the first place. When I was a kid I never heard of it. But my programs were always super super super simple.
If Commodore BASIC supported 24-bit integer values it would make sense to just have TI be a permanent entry in the variable table pointing to the jiffy clock. But it has to be converted to floating-point, which is a pretty expensive operation to be doing 60 times a second, every second. Much more efficient to only do that when the program accesses the variable.
@@markjreed makes sense. I always thought of BASIC as this magic box that just works (especially as a kid). I never thought that much about what was in it. Especially now that I use much more modern languages these days.
☺Love the "remember when" songs. Brilliant production. Thank you.
I love how you fixed something that was useless to fix. That’s why I love these videos.
Loved the end!
Loved "Remember When"
Good work! I love how in depth these videos are.
14:25 The following will perform an exact one-second time delay on an NTSC or PAL C64 and confirms that there are 60 Jiffies per second on either system:
10 ti$="000000"
20 ifti$"000001"then20
30 printti
I will have to dig out my old C64. In the USA you have 60Hz AC, in Australia and UK we have 50Hz AC. When coding split screen on the C64 it was from memory 50Hz to be in sync with the TV otherwise it would not work. Clock speed was also adjusted to be in sync with video refresh. Eg: “6510 CPU is clocked at 1.023 MHz (NTSC) and 0.985 MHz (PAL)”
Fantastic work, Robin, super interesting! Excellent video!
Brilliant explaining as always. I'm sad this series is over.. now what's next...
I actually learned a fair bit there.
Really love these deep dive videos!
I think they accepted the 1/60th of a second off time, because if you have a look, it makes the code easier. You can do SBC 01 to force the carry flag to ripple through the other two subtractions, otherwise you'd need to check if the first byte is 00 and branch out manually. Either speed or memory size constraint. Plus, if you think about it: the clock is not from the more stable TV signal oscillator, but the "roughly 60 Hz" timer. That one is most def. far less accurate than 1/60th of a second in a day.
No. The wrap-around code will work just fine if the first constant is zero. Using 1 instead is definitely a bug. However, if you reverse the order of subtraction then the correct first constant would be 1 (because of the way CPU carry flag works. You can test this yourself by copy ROM to RAM and modify like Robin did.
I guess maybe they had the order of subtraction reversed at sometime, then reversed the order, but the constant was not updated. Who knows? What is surprising is it wasn't fixed on C128.
Excellent video Robin. Very interesting indeed.
Until recently I always thought that TI and TI$ came from the TOD clocks in the CIA chips. Do you know of any software that uses the CIA TOD clocks for timekeeping rather than the KERNAL derived time functions?
Do you know how the KERNAL sets the CIA's 50/60Hz flag, how it determines if it's operating in a 50Hz or 60Hz AC area?
What about the SX-64 where it has a built in 60Hz oscillator for the CIA chips?
Interesting to know your thoughts.
Oh.. you also have a 'flat' c128!.. I knew about your 128DCR.. nice video again.
dude, your songs are great - little added bonus imho
Love this, Robin. Interestingly, the MEGA65, which I know is a modern device, includes a battery backed RTC. Wonder how this hardware addition might modify your TI and TI$ (they are reserved for BASIC 65) tips and tricks, if at all.
On the Mega65's BASIC 10, TI$ and TI are independent variables. TI$ has the current clock time (complete with colons now), while TI is the number of seconds (with fraction) since boot. Neither of them is resettable, either, which makes timing things a little more work.
TI and TI$ are almost a cross between a variable and a function. Vartion? Functable? I remember using TI and TI$ in some of my early BASIC programmes but haven't used them in years. I guess they left that jiffy number the same in the C128 Kernal/BASIC to avoid breaking backwards compatibility. It's amazing how dense and interconnected the BASIC ROM is, with routines calling other routines. I wonder how many jiffies this video lasted?
How about fartion :-)
Fun fact: 1/60th of a second used to be known as thirds, and 1/60th of a third as fourths, etc.
Question: does copying the basic (and Kernal?) ROMs to RAM increase the speed of BASIC programmes (since RAM is typically faster than ROM) - IBM clones used to mirror (AKA shadow) ROMs to RAM for a speed increase.
On a stock C64, RAM and ROM are the same speed. On my SuperCPU accelerator for the C64 (which is unfortunately quite rare) then the RAM is a lot faster and it does copy/shadow the ROMs into RAM like the IBM clones did.
I always wondered why they did not use TOD from any CIAs for printing TIme now I know, that by using US supply on PAL Commodore would give us wrong TIme,
As when you use US power supply you will get 60Hz signal on TOD (pin 19 on both CIAs) while EU power supply gives 50Hz signal, so your test would not be valid in case when TOD is used.
So IRQ runs 60 times per second and that is independent of PAL or NTSC C64 /128, source of IRQ is CIA1 and your test is valid only because crystal for PAL/NTSC is different.
I found this funny and interesting at the same time :)
Hey, but did you fix the type of TI$ error where it's assigned a numerical string, but not one that represents a valid time, such as: TI$ = "999999"?
No, that would be a much more elaborate patch and the original authors didn't appear to even attempt that level of error checking. They did seem to want a numeric digit check and as it was easy to implement, I tried it :)
7:19: 5183974 does not equal exactly one second before midnight (5183940). I suspect the discrepancy/delay might be accounted for by the time it takes to interpreted code to run.
The error is actually worse because the actual field rate of NTSC is 60/1.001 ~ 59.94
So the actual count should be from 0 to 5 178 820
Actually because of the quartz used in the C64 or slow C128 it's actually
1 022 700×7÷2÷227,5÷525
=29,96923 images per second.
So a good count should be from 0 to 5 178 682
I'm sorry but I don't follow. The TI variable is counting jiffies which are approximately 1/60th of a second but have nothing to do with the NTSC or PAL video standards. Jiffies are counted each system IRQ which is driven by the CIA timer interrupt which counts cpu/system cycles.
I think you're under the impression that the Time of Day source is the video crystal, but it actually comes directly from the A/C line from the power supply. Only the interrupt routine on the C128 runs from vsync, not the TOD timer itself. There should be some error involved since the interrupt and timer updates don't sync, but the error is still pretty small. The system timers make a lot of sense on the C64 and C128.
The Amiga is what has me all confused, since most of those systems *DO* get the TOD source from vsync. I haven't figured out yet how AmigaOS determines whether the hardware uses a 59.94 Hz or 60 Hz timer.
I had to turn on my PAL C128 running on 50Hz AC to check if this was true. I was pretty surprised they went with 60Hz timer on all machines. I thought they simply used AC input as source for a clock counter.
Yes, I think there's a lot of uncertainty surrounding this topic; I wasn't sure about several things until I really dug into it for this video. Though now that you mention it, I didn't even talk about the AC input! Or how the system IRQ timer is set in the first place.
@@8_Bit: Also, the bulk of the C64 ROM content was just copied in a hurry from the VIC-20. The VIC used a timer configured for a 60 Hz IRQ, so that just got copied into the C64.
@@csbruce Sure, but the VIC-20 also had a PAL version. Weren't those the same other than the VIC chip itself?
@@markjreed CPU in the C64 was different too, controlled the bank switching.
The TOD in the CIAs is indeed clocked by the mains frequency in most C64 variants but the CPU interrupt is timer driver. TOD tick is derived from the 9VAC supply. If you want a less drifty time of day read the CIA registers instead of relying on TI etc. There's gotchas such as ensuring the CIA is configured for the mains frequency in your area. This isn't necessarily correct. Apparently different ROM versions didn't work it out properly, and of course you could be using a C64 intended for an NTSC country in a PAL country and vice-versa.
Hmmm. Code that patches the kernal like that should probably check to see if the RAM version is already in use due to another patch, so that multiple patches can be compatible, instead of wiping each other out.
Robin be like : 👉👆👈👎☝👍🤞🤏🤌🖐🖖
😅
I wonder if 1/60s jiffy is a remnant of old unix time system when they probably used 60Hz counter instead of counting every second since 1 january 1970 in utc. At least wikipedia says so.
The 1/60th of a second bug assumes that a Jiffy really is 1/60th of a second. I had computers in the 90's where the clocks were not that accurate. I had to reset the clock monthly to get the time in the right ballpark. They would lose or gain 5 minutes a month or so. So the real question is how accurate is the 1/60 second timer. I used to have an internet based alarm clock that was even less accurate than that. So every week I would just unplug it and when restarting it would update the time automatically. Eventually they issued an update that it would check the clock at least once per day. But it was nice because I got pandora radio as my wakeup call instead of a CD starting on the same track every day or the stupid radio with some jerk that I don't care about making horrible jokes that just makes me mad at 7 am. lol (and no they aren't anymore funny at 5 pm either)
I read somewhere, don't remember where though, that on the C128 a jiffy is a 100th of a second instead of a 60th. Interesting to see that proven wrong, as I assumed that to be so.
That's not the C128, but the term "jiffy" has been used for other subsecond intervals. The 0.01-second version shows up mostly in Linux. Microsoft file and directory timestamps count from 1601-01-01T00:00:00Z the number of 100-nanosecond periods (= one ten-millionth of a second), which are also sometimes called "jiffies".
Just in TIME$ for my machine code subroutine, yay
2:30: Does defining TI(0)=1 have any bearing on the output of TI or TI$?
Thanks for this interesting video!
The CBM machines are new to me (grew up with MSX), and with my new MEGA65 I'm now working my way through the C64 User Guide and the C64 Programmers Reference Guide.
Can you please explain to me how/where to find the keys corresponding to the graphical characters? Like in your program TIME WRAP, line 1, you have the inverted heart. I know it is CLR HOME after trial and error, but could I have find it somewhere in the manuals?
Hi, congratulations on getting a MEGA65! Yes, all these special symbols are shown in the C64 Programmer's Reference Guide on pages 72-74, when describing the various special Quote Mode, Insert Mode, etc. They're a bit quirky, but also quite powerful and efficient.
@@8_Bit Ahhhhh....yes, I see them now! Thanks a lot!!
I was searching for them in the appendix etc.
ps, the C64 core for the MEGA65 is amazing, but also the C64 mode ("GO64") in MEGA65/C65 is already quite compatible.
To add to that, on the schematic of both C64 and C128 there is pin 19 (TOD Time Of Day) on the CIAs that is connected to the AC 9 Volts input and that is where it gets it's time reference, and in most countries the 60 Hz is really precise and is compensated by the utility company so that it is accurate overtime. Bwak on UA-cam has interesting videos of reverse engineering the CIAs from pictures of the die and we see those counters of the Time Of Day pin 19 ua-cam.com/users/bwackvideos
The CIA does get 50 or 60 Hz from AC for the TOD but to be clear (I'm not sure if you're implying otherwise or not) that's not used by the C64 for the TI or TI$ functions at all; they're driven by the system IRQ which is driven by a CIA timer interrupt set to roughly 1,000,000 / 60 microseconds. The TOD functions are an interesting and under-utilized feature of the C64 I think.
@@8_Bit I see, I did not remember that, makes sense since disabling interrupts makes TI skip counts.
TWO Commodore Security badges. This must be serious.
Something was definitely goin' down there.
Ah! Commodore and their JIFFIES!
Hey look, it's the split screen flicker that drove me nuts. 😂
Were you on a PAL machine? I used an NTSC C128 as my main computer for years and only very rarely noticed any flickering in the split-screen graphics modes.
@@markjreed it's fine on my ntsc machine. I was having the issue on my emulator setup. Got Robin's help with a workaround.
@@alexmcd378 Ah, emulators. I know VICE x128 in NTSC mode simply does not handle split-screen graphics; the entire text portion of the screen flashes, rendering it completely unusable. In PAL mode there's a much more minor flicker of just a scan-line or so. Which was also on the PAL machine in this video, so maybe that's accurate to the real hardware!
@@markjreed that's it exactly. If you use draw routines to cover the bottom couple rows of pixels of the graphics area, it reduces the flicker to a single row of pixels. Not ideal, but much less distracting
@@alexmcd378 Hm, adding lines to he bottom of the graphics area doesn't seem to help. I must be misunderstanding.
Your info the sx64 pal has a 60hz clock for CIA and 50hz vic chip
Yes, apparently the Time Of Day on the SX-64 is driven by a crystal at 60 Hz on both PAL & NTSC models instead of AC mains power at 50 or 60 Hz.
I wonder if there is any difference with TI or TI$ in the C128 1986 rom revision? Nothing is mentioned in the Rom Announcement!
palnts $02A6 ;pal =1 or ntsc =0 set during init using video
These values are used to set timers depending on palnts so 60 hertz will be correct
sixty = 17045 ;ntsc
sixtyp = 16421 ;pal
I probably missed something, but does the "hack" of looking for _TI_ not preclude using variable names beginning with TI?
Meaning that TIMOTHY for example can't be used as a name for a variable?
These Commodore BASICs all have a 2 character limit on variable names anyway, so TIMOTHY gets treated the same as TI; extra letters are just ignored.
@@8_Bit Oh... well, I suppose not having touched a C64 in a... never-mind-how-long time, can excuse me for forgetting that little detail. No?
Thx for replying.
Interestingly, TI% and ST% are valid true variable names.
Is there a kind of database including all the bugs that could be fixed? Or even a bugfix file? - Thx for the extra nerdy content! :-)
I'm in the process of compiling a pretty comprehensive list of bugs in the kernal and basic roms. More comprehensive than any I have ever seen, really. I may publish it some day when it's complete.
@@ge97aa Great, looking forward to reading it!
Hi, its Magnus. Me and my nephew are playing last update VERMEER in C64 and saving isnt working proper. neither in cas mode than in disk mode. My promis was to be able to save it but I cant. May you help me?
Hi Magnus. Sorry I don't know anything about that game, especially since it's in German, but here's a good website with info and links to another website with a manual. You can see if it even supports a save feature: www.c64-wiki.de/wiki/Vermeer
Are you playing on a C64 with a real disk? You might need to insert a blank, formatted disk to get the save to work. I'm just guessing though; let me know more of the symptoms and maybe I'll have other ideas.
Is there a way for a program to find out whether it runs on a 50 Hz AC or 60 Hz AC machine? Or does it have to ask the user? I am thinking of a program that uses a TOD clock and wants to set that accordingly.
I was looking into this a week or two ago. Some programs just check if they're running on PAL/NTSC and assume 50/60 AC based on that. A large % of the time that is an okay assumption. However it's wrong for some edge cases, such as the SX-64 which has a 60 Hz TOD no matter whether PAL or NTSC as it has an internal 60 Hz crystal generating the signal instead of using AC. A better solution is to start a CIA timer (cycle counter) and set the TOD to 60 Hz and count the cycles it takes for the TOD to reach a certain amount of time (like a 10th of a second or whatever). Then that cycle count can be used to see if the TOD is really running at 60 Hz, or if it's too far out, 50 Hz must be right.
@@8_Bit Great, thank you!
How does the C64 get it's 60Hz clock? I read on the internet that it's from a free-running CIA hardware timer, which reminds me of an AVR328-based clock project of mine that needed a 60Hz clock. I discovered that at the usual 16Mhz, there was no way to get a proper value in the 16-bit hardware timer to get exactly 60Hz so I ran the AVR at 12Mhz where there was a proper division (and I had to re-work the WS2812 assembly to get it to bit-bang at that speed).
It makes me wonder if this leap-jiffy "bug" might be covering up for a pretty-darn-close-but-not-quite 60Hz clock - or maybe it just makes it worse ;^) Can any CIA gurus verify the precision of the CIA timer interrupt to give exactly 60Hz?
It comes directly from the 60hz AC power supply signal.
@@ImYourProblem I've done some reading since my comment and it seems that the jiffy clock comes from a CIA hardware timer and the CIA TOD real-time clock comes from the mains.
At 47.30 I am not so sure this is a valid test. Maybe both pal and ntsc 128 computers solve it differently on pcb level. How these 'rumours' started is that for C64, for the 250407 assy for example, the schematics clearly show that the TOD pins from the CIA's are connected to a little circuit that basically generates clock pulses based on the 9V ac input.
So taking the 'pal' or 'ntsc' version would not matter as it is the line voltage alternation that is the driving factor.
Even in the C128 schematics the TOD pins from CIA1 and 2 are hooked up to the 9V AC. Through a Smitt Trigger and Zener and some timing circuitry. I don't have any own tools or something to do any measurements but it could well be this indeed is always 60 because you are just not changing your line phase.
Well, even though this doesn't have to do directly with the video standard, most PAL regions use 50 Hz AC power, while most NTSC regions use 60 Hz. I guess this is where the thought comes from. But you are correct, even on a PAL C64, a Jiffy is a 60th of a second. (Or close to at least, it seems to be kinda inaccurate)
@@paulkoopmans4620 There seems to be an assumption that the TOD in the CIA has something - anything to do with TI and TI$, but it doesn't. TI is incremented as part of the main system IRQ which is driven by a looping CIA timer (cycle counter) set to approximately 1 000 000 / 60 cycles. TOD is driven by AC, but it's not used by the TI functions at all.
Well that 1/60th of a second within a day is hardly relevant considering the JiffyClock is not very accurate at all. I think even after one hour you will see considerable drift from the actual time.
@14:30 you are running a PAL version on a power supply that is fed with 60Hz AC. PAL was designed for 50Hz. This could affect the results of your experiment.
All CPU and video timings on the C64 and C128 are derived from a crystal oscillator of 14.31818 MHz for NTSC and 17.734475 MHz for PAL, and have nothing to do with the AC frequency. The only thing the 50 or 60 Hz AC does is drives the Time Of Day (TOD) clock on the CIA chip, but that is not the source of the system IRQ. The system IRQ is driven by a CIA system cycle counter / timer in C64 mode at approximately 60 Hz, or by the video refresh on a C128 (at 50 Hz in PAL or 60 Hz in NTSC), but none of those 50 or 60 Hz for video or system interrupts have anything to do with the AC power frequency.
Is TI$ stored in the RAM? If so, where can I find the address of the bytes?
TI$ is not stored in RAM, but TI is. It is at addresses $00A0..$00A2. It is big-endian, in units of 1/60 seconds. Evaluation of the TI$ variable reads the TI value and converts it to the more human-readable HHMMSS form.
@@ge97aa Thank you for your answer! But: Which routine(s) does (do) converts $00A0..$A00A2 into TI / TI$ and where can it be found in the RAM?
@@madmartigan1498 As for TI, I'm not sure what you mean by converting $00A0..$00A2 to TI, since for all intents and purposes $00A0..$00A2 **is** TI. You can get this value in an interrupt-safe manner by calling the kernal's RDTIM function at $FFDE. It returns the three bytes in the Y, X, and A registers in order from high to low.
As for TI$, this is done by the routine that evaluates a BASIC variable within a BASIC expression. This routine is located at $AF28 in ROM. This routine calls another routine at $BE68 which does the actual work of the numeric conversion (incidentally, this function is also used by the routine that converts a floating point value to a decimal string). The resulting 6-character string is stored in BASIC String RAM at a location chosen by the BASIC interpreter. A 3-byte descriptor for this string is pushed to BASIC's temporary string stack (located at $19..$21) and a pointer to that descriptor is returned in memory locations $64/$65. Additionally, an interim working copy of the string will be found at $00FF..$0104, but this will be overwritten by any subsequent conversion of a numeric value to a string.
I'm not sure if you are asking purely for curiosity's sake, but if you're thinking about writing code to use this built-in feature, there are a number of things you must consider. First, the routine at $AF28 starts by reading a variable name from the BASIC command buffer. This means that there MUST be a valid active BASIC command buffer pointer that currently points to the first character of the TI$ variable name.
If you simply want to get the TI$ value "on the fly", I suppose you could bypass the command buffer read by instead calling into the routine at $AF48. Remember, though, that this routine is part of the BASIC interpreter, and it expects and requires a fully operational BASIC environment. Additionally, you would need to make sure that you properly deregister the temporary result string from BASIC's string stack by loading the the pointer at $64/$65 into the Y and A registers (low byte in A, high byte in Y) and calling the routine at $B6AA. This will return a pointer to the string data in memory locations $22/$23. This string should be used for your intended purpose before invoking any additional functions in the BASIC interpreter, as there is a good chance that pointer will be overwritten by the interpreter.
If you DON'T want to have a full BASIC environment active (e.g. String RAM, Variable RAM, program memory, temporary string stack, garbage collector, etc.), you could just use the conversion routine at $BE68. Here's how you would do it:
1. Call the routine at $AF84 to convert TI to a 32-bit big-endian integer at $0062..$0065.
2. Store the value 0 in memory location $5E.
3. Store the value #$FF in memory location $71.
4. Store the value 6 in memory location $5D.
5. Load the Y register with the value #$24.
6. Call the conversion routine at $BE68.
7. The resulting 6-character string can then be read from memory at $00FF..$0104.
Note that this method requires the use of the following memory locations, so you would have to be sure they aren't in use by other parts of your code: $0047, $005D, $005E, $0062..$0065, $0071, $00FF..$0105.
DOOD!
It's amazing how many errors / bugs etc. there are in a 40 year old 8k kernal rom, it's easy to see how windows would have so many unforeseen errors / backdoors / bugs etc. as software is based on older software which is based on older software etc.etc.etc. The C64 maybe flawed but it plays Bruce Lee so I'm happy.
These can be hardly called errors / bugs because under all practical circumstances, it all works. No one sets the time to 99:99:99 (and even then nothing explodes), or cares if TI$ is off a second when running for months.
@@NuntiusLegis Appart from hackers.
Honestly though, a lot of the bugs are CAUSED by the need to cram everything into such a small space. Add to that the fact that it was all programmed in handmade assembly... lots of very ugly hacks are used to get the job done. In a modern O/S, many of these kind of bugs would be avoided by adherence to proper coding standards and the use of MUCH better development tools.
Also, the kernal ROM is only about 6.5 kB. The BASIC interpreter is around 9.5 kB.
Random number seed
Today I learned:
If I type "SYS 44808" I get:
? SYNTAX ERROR
But is it really?
It is not.