Right! I'm disappointed at the low views , 'cause he's a warranty of oddities and deep knowledge in every video. But hey, maybe that's the reason. We're becoming a rarity.😢
Hurray for shoutouts. Glad you found my blog post about the 6510 Processor Port useful. The best part of the 2 low-bits of $01 being the ones that control the 4 dependency levels is that, if you know that BASIC and the KERNAL are currently patched in, and you want to patch them both out but leave in I/O, you can simply DEC $01 twice. All the other higher bits are left untouched by this too. 👍
There are four “levels” 1) RAM only 2) I/O 3) KERNAL+I/O 4) BASIC+KERNAL+I/O INC $01 steps up a level. DEC $01 steps down a level. The default level when you power on is 4.
Great video. Longer than your usual but it's good to see a detailed explanation of something relatively complex like borrowing routines from BASIC. Thanks!
This was a great feature.The Dan Heeb book was the first chance.I had to understand how to use the floating point Basic routines. If they are described any in other resource I certainly never found it. I went back and looked at your review of his two books (now two years old) I see that his son is apparently one of your viewers. How great is that!
Wow! Such a cool video, an your such a cool creator! I learned so much, thanks so much :-) I can’t wait to delve into your videos. Super happy new subscriber 🎉
well that solves the issue I was having whenever I LOADed anything at $C000. Before now, I'd get ?OUT OF MEMORY if I tried LOADing any BASIC program after my binary was loaded. So yes, this old Apple II guy DID learn something about his C64 today!
Thanks for compiling all of that great information and experience into such a handy program. And for providing a great explanation. I need to revisit the Machine Code Master book and included basic extender and compare the patching in of additional functionality.
Another interesting bug? Based on one of your other videos, I thought you might find this interesting: My first computer was the TRS-80 Model 1 Level 1 and that version of basic was very limited. But I found a glitch one day that gave me special access and nullified some of it's limitations. First let me explain that this version of BASIC only allowed 2 string variables and then didn't allow simple comparisons like IF A$ = "Rob" THEN... You could only assign a string and print a string; nothing more. This version of basic did not include any advanced string functions or peek and poke type commands. So you had no direct access to the memory either. However, it had one array variable A( ) that overlaid all of available memory. ** I discovered that if you jogged that available memory pointer, you could then access all the memory, not just what it considered available. I discovered 2 ways to do that. One method: I used the TRS-80 assembler program to save one byte at the very end of memory. For some reason, loading that caused this pointer to think all memory was available. Then I could examine memory by copying A(x) to screen memory (once I figured out where that was). Well, maybe you cant compare A$ with B$ but you can compare A(927) with A(931) once you know where those variables are stored. So that knowledge allowed me to do a lot of advanced things most people could not do with Model 1 Level 1 BASIC. Now to the glitch! Before I discovered the Assembler tape method of resetting the end of memory pointer, I found another way to do the same thing. All I had to do was type and run the following 3 line program: 10 For X = 1 to 10 15 Let X = 15 20 Next X Run. This essentially did the same thing. It reset the available memory pointer to the end of memory making all memory available via the subscript variable A(x). I don't know why it works but it only seems to work on real hardware Level 1 Model 1. I have tried it on the java script / browser based emulators and it doesn't seem to work there. Somehow by changing the value of the loop variable to a value outside the range, that also caused this glitch. As I say, this gave you "access" to the memory but it was a bit less straight forward. All numeric variables on the level 1 model 1 were 32 bit floating point. Which means you could assess the memory but only 4 bytes at a time. So the second thing I did (after mapping out the memory) was to figure out how to take one 32 bit value and reinterpret it as 4 bytes. That was about as far as I got when I gave up on it. I was only 14 at the time and didn't realize this could have potentially allowed me to write programs for the Level 1 that nobody else could write.
Maybe you can think of it as SEI equals SET INTERRUPTION (I want to do stuff without interrupts) and CLI meaning CLEAR INTERRUPTION (return control back to interrupts)? This is interesting, a great example of how the Kernal can be used. I remember learning a few tricks about that from Loadstar, particularly the way they used the built-in Kernal routines for loading/saving an updated program. Great resources too, I haven't explored the pagetable site before. An obvious source of possible confusion there is that you use X/Y registers for an address at one point, but a different Kernal routine needs you to use A (accumulator) and Y. Floating point numbers have always seemed tricky to handle for me.
German speaking viewers may also have a look at "Das Maschinensprachenbuch für Fortgeschrittene zum Commondore 64" (yes, German book titles are fun!) by Lothar Englisch (who is also known for his contributions to "64 Intern"), published in the Data Becker series.
The teenage me got very frustrated by the PRG description of LORAM and HIRAM and I definitely fell afoul of HIRAM takes LORAM with it and say-bye-bye to I/O "rules". The diagrams on pages 262-267 convey the information correctly (*) - and I think they saved my sanity once I realized the proper implication of the bit patterns. (*) My fourth printing (UK) version and sixth printing (US/Canada) differ on page 265: In the bottom diagram the 4th printing suggests "GAME = 1", whereas the 6th suggests "GAME = 0". Whoever originally owned the 6th printing copy I have pencilled in various corrections and is clearly a legend.
Regarding the NEW command, my first thought would be looking at BASIC, identify the token used and the jump table vector used. A cursory search of a ROM disassembly suggests that the entry point is $A642. Hah! The pagetable site was where I sourced that information.
Yes, that's one of the first six things I tried, shown at 12:12. Unfortunately, I wasn't able to get any of those direct calls to work, but there may be a way. Fortunately, resetting the end-of-program pointer at locations 45 and 46 did the trick.
Great video! Not that it matters, but I believe an inc should set the Z flag, so no need to load $fc into the accumulator before the beq during the rom copy
Nothing to do with this topic, but if you are interested in a bug (if you may call it so) in the CCS64 emulator , let me know. I realy like this channel, still learning.
Ran a lot of type-in utilities in 49152, but only 1 at a time. The self modifying code made it impossible to relocate anything. Maybe you could sniff out variables 1 by 1. Atmega used the same interrupt opcodes.
At 53:23 this works if you are benchmarking in Basic only? What if you were benching a compiled program or wanted a universal benchmark routine that would also work for assembly language programs? Would this still work? I'm guessing no- that you would instead write 0 to three CIA registers on the $Dxxxx region?
Make a comment in the instruction manuals so future generations know the exact addresses? Write your name too, so they will know it comes from a veritable source. (Patching run: 21:36 && 25:32)
12:12 That's a nice looking table. Is it a Chippendale? My project in 2025 is to learn ARM Assembly for Embedded Systems. Apparently even electric toothbrushes use it. ⚛ 🤖
Object code doesn't contain headers and other links. I don't know what's involved in linking for a C64, but for some others it's about any number of OS related things in order to get it loaded into memory properly before it is ready to run. If you take an object file (on disk) and copy it byte by byte to the correct memory location and then SYS call that address, it should work fine. But without the linking part, the OS (ROM) wouldn't know where to load it.
@@saganandroid4175 That may well be the case. "A Commodore 64 binary executable is intended to be run on a Commodore 64 or on another machine that is emulating one. These files are often stored with the extension .prg when kept in filesystems that distinguish types by extension. (In the original Commodore environment, they generally didn't have an extension but had file type "PRG" in the directory structure.) Files of this type might be binary executables, tokenized BASIC, or other sorts of data files; even text files are sometimes stored in PRG format instead of TXT, so the file type doesn't give much information about what sort of data it is. The first two bytes in a PRG file are the memory address that the file should be loaded into (in little-endian format). For a C64 Commodore BASIC tokenized file, intended to be loaded into $801, these bytes are $01,$08. Note that these bytes will be ignored (i.e. a PRG file will be loaded into $801) UNLESS the LOAD command had a non-zero parameter after the device number. i.e. LOAD "*",8 will load a file from device 8 (the typical device number for a disk drive) into $801, while LOAD "*",8,1 will load a file into whatever memory address is specified by the first 2 bytes of the PRG. " So yes, that appears to be correct. I would have expected something more sophisticated.
Yes, the two terms end up being nearly synonymous on the C64 and many other 6502 systems. When Turbo Macro Pro saves the object code, it does so as a PRG file which has the 16-bit load address at the beginning. Then when the file is LOADed, it's put in the correct location in memory for execution with RUN or SYS. CPUs and operating systems with better code relocation abilities, or a true "executable file" concept make much more of a distinction.
33:08 If you wanted to be even more accurate, you could also set the CIA timer to its full count and clear any pending interrupt. Or, you could chain two CIA timers together for microsecond-level accuracy for up to 70 minutes. 39:16 Using any Kernal routine in an interrupt can clobber variables that the main program is using, especially if it's concurrently calling the same Kernal routine.
@@saganandroid4175: If you set the 16-bit CIA timer to the full count for a jiffy, about 17045 for NTSC, the first jiffy counted off in the timed period will be a full jiffy. Otherwise, it will be some random amount of time between 0 and 1 jiffy.
@@csbruce "full count for a jiffy" does not compute. A jiffy should be in increment of 1 for the 60ths of a sec? I heard PAL machine still use 1/60th of a sec for system timing. VICII is 50Hz of course. Not really sure what you are trying to say. Maybe pick a CIA chip and specific register/address and explain from there?
@@saganandroid4175: The IRQ interrupts run independently from the Benchmark program. Just setting the jiffy zero-page value to $000000 doesn't reset the CIA timer, so if there's only 100 1-MHz clock ticks left in the CIA timer before the next interrupt, the first "jiffy" will be ticked off after only 100 microseconds instead of the proper 16667 microseconds.
I know you love tinyest code Robin, but mentally, that copy routine is seriously tortured logic from a human perspective. I wonder if a decrement approach (from FFFF) would be any more human-brain-friendly.
#SepTandy came early this year with my 3.17 cm diskette video. I don't think I'll have time to do another this month. The scroll routine always scrolls logical lines which on the C-64 are two 40 column physical lines. On the VIC-20 it'll scroll four lines at a time! This logical line concept, of combining physical lines together, is to allow user input (such as a program line) to go past the 40 character limit it would otherwise have on the C-64, and the 22 column limit on the VIC-20!
@@8_Bit I guess that makes some sort of rational sense. This distinction between physical lines and logical is interesting. Are these physical lines based on hardware? Otherwise if they are implemented in software I'm not sure how that makes complete sense. But this rationale does have some obvious merit insofar as the line editing is concerned.
@@anjinmiura6708 Yes, "physical lines" just means the number of text columns the video chip displays by default. There may be a better term for it, but that's the one I've seen in descriptions of the concept. The KERNAL maintains a "link list" that combines the physical lines into these logical lines. It's somewhat complicated, but is part of Commodore's screen editor that I still find to be a better solution than maybe any other 8-bit computer I've used.
@@8_Bit The VIC2? en.wikipedia.org/wiki/MOS_Technology_VIC-II This says it's 40x25. 80 Columns in the VIC2e exists but it's a different though related chip. The idea that the KERNAL tracks it this way does make some sense. It would definitely make sense as it relates to outputting to printers which are almost always 80 columns minimum. I'm not doubting you in the least. You probably have the KERNAL source code memorized. I'd love it if you did a walk-through on the "two line scroll" behavior because to me, it's the one thing that ruins the 10 PRINT thing. I actually created a kind of screensaver built around the 10print thing but for that last character, I ended up either not printing that last one or poking it into screen memory just to keep it from scrolling twice.
Sunday 6:05 in the morning and I'm watching "Softpatching a C64 Rom..." - should I consider a doctors-visit or try to heal it by buying another C64??? Hard decision... (Don't ask my wife...)
It’s always a good day when we get a new video from Robin 👍
+1!
Hear, hear 👍
100% agree
Right! I'm disappointed at the low views , 'cause he's a warranty of oddities and deep knowledge in every video. But hey, maybe that's the reason. We're becoming a rarity.😢
Hurray for shoutouts. Glad you found my blog post about the 6510 Processor Port useful. The best part of the 2 low-bits of $01 being the ones that control the 4 dependency levels is that, if you know that BASIC and the KERNAL are currently patched in, and you want to patch them both out but leave in I/O, you can simply DEC $01 twice. All the other higher bits are left untouched by this too. 👍
@@c64os what if you want to switch out Basic but leave kernel Rom running intact?
There are four “levels”
1) RAM only
2) I/O
3) KERNAL+I/O
4) BASIC+KERNAL+I/O
INC $01 steps up a level.
DEC $01 steps down a level.
The default level when you power on is 4.
@@c64os oh that is easy to follow now. Thanks!
Great video. Longer than your usual but it's good to see a detailed explanation of something relatively complex like borrowing routines from BASIC. Thanks!
This was a great feature.The Dan Heeb book was the first chance.I had to understand how to use the floating point Basic routines. If they are described any in other resource I certainly never found it.
I went back and looked at your review of his two books (now two years old) I see that his son is apparently one of your viewers. How great is that!
@@vcv6560 what are the names of his books?
Wow! Such a cool video, an your such a cool creator! I learned so much, thanks so much :-) I can’t wait to delve into your videos. Super happy new subscriber 🎉
Love the deep dives, keep 'em comin'.
There's only one King of Commodore Kernal Coding, and he lives here.
well that solves the issue I was having whenever I LOADed anything at $C000. Before now, I'd get ?OUT OF MEMORY if I tried LOADing any BASIC program after my binary was loaded.
So yes, this old Apple II guy DID learn something about his C64 today!
Thanks for compiling all of that great information and experience into such a handy program. And for providing a great explanation. I need to revisit the Machine Code Master book and included basic extender and compare the patching in of additional functionality.
Another interesting bug? Based on one of your other videos, I thought you might find this interesting: My first computer was the TRS-80 Model 1 Level 1 and that version of basic was very limited. But I found a glitch one day that gave me special access and nullified some of it's limitations. First let me explain that this version of BASIC only allowed 2 string variables and then didn't allow simple comparisons like IF A$ = "Rob" THEN... You could only assign a string and print a string; nothing more. This version of basic did not include any advanced string functions or peek and poke type commands. So you had no direct access to the memory either. However, it had one array variable A( ) that overlaid all of available memory. ** I discovered that if you jogged that available memory pointer, you could then access all the memory, not just what it considered available. I discovered 2 ways to do that. One method: I used the TRS-80 assembler program to save one byte at the very end of memory. For some reason, loading that caused this pointer to think all memory was available. Then I could examine memory by copying A(x) to screen memory (once I figured out where that was). Well, maybe you cant compare A$ with B$ but you can compare A(927) with A(931) once you know where those variables are stored. So that knowledge allowed me to do a lot of advanced things most people could not do with Model 1 Level 1 BASIC. Now to the glitch! Before I discovered the Assembler tape method of resetting the end of memory pointer, I found another way to do the same thing. All I had to do was type and run the following 3 line program:
10 For X = 1 to 10
15 Let X = 15
20 Next X
Run.
This essentially did the same thing. It reset the available memory pointer to the end of memory making all memory available via the subscript variable A(x). I don't know why it works but it only seems to work on real hardware Level 1 Model 1. I have tried it on the java script / browser based emulators and it doesn't seem to work there. Somehow by changing the value of the loop variable to a value outside the range, that also caused this glitch.
As I say, this gave you "access" to the memory but it was a bit less straight forward. All numeric variables on the level 1 model 1 were 32 bit floating point. Which means you could assess the memory but only 4 bytes at a time. So the second thing I did (after mapping out the memory) was to figure out how to take one 32 bit value and reinterpret it as 4 bytes. That was about as far as I got when I gave up on it. I was only 14 at the time and didn't realize this could have potentially allowed me to write programs for the Level 1 that nobody else could write.
9:37 you are so right about how backward the SEI mnemonic is. And then it hit me! Henceforth l will think of SEI as "Stop Executing Interrupts ".
So how you want to explain CLI ;)
@@cactuslist Continue Launching Interrupts
@@cactuslist Continue Looking for Interrupts? 😄
@@AndyG-_- SEt Interrupt mask, Clear Interrupt mask
For finns, SEI makes perfect sense, as the finnish word "SEIS" means STOP.
I really love these videos, super interesting! Thanks Robin :) 👌
Always a good day when Robin uploads a new video. Thanks for your dedication 👍 Greetings from France.
Nice video Robin. I was hoping you were making a 10 print maze in assembly… very fast and very smooth 😅
Maybe you can think of it as SEI equals SET INTERRUPTION (I want to do stuff without interrupts) and CLI meaning CLEAR INTERRUPTION (return control back to interrupts)?
This is interesting, a great example of how the Kernal can be used. I remember learning a few tricks about that from Loadstar, particularly the way they used the built-in Kernal routines for loading/saving an updated program. Great resources too, I haven't explored the pagetable site before.
An obvious source of possible confusion there is that you use X/Y registers for an address at one point, but a different Kernal routine needs you to use A (accumulator) and Y. Floating point numbers have always seemed tricky to handle for me.
@@merman1974 Stop Executing Interrupts makes more sense to me
German speaking viewers may also have a look at "Das Maschinensprachenbuch für Fortgeschrittene zum Commondore 64" (yes, German book titles are fun!) by Lothar Englisch (who is also known for his contributions to "64 Intern"), published in the Data Becker series.
The Data Becker books were pretty good, they set the standard for German language publications.
The teenage me got very frustrated by the PRG description of LORAM and HIRAM and I definitely fell afoul of HIRAM takes LORAM with it and say-bye-bye to I/O "rules". The diagrams on pages 262-267 convey the information correctly (*) - and I think they saved my sanity once I realized the proper implication of the bit patterns.
(*) My fourth printing (UK) version and sixth printing (US/Canada) differ on page 265: In the bottom diagram the 4th printing suggests "GAME = 1", whereas the 6th suggests "GAME = 0". Whoever originally owned the 6th printing copy I have pencilled in various corrections and is clearly a legend.
Regarding the NEW command, my first thought would be looking at BASIC, identify the token used and the jump table vector used.
A cursory search of a ROM disassembly suggests that the entry point is $A642. Hah! The pagetable site was where I sourced that information.
Yes, that's one of the first six things I tried, shown at 12:12. Unfortunately, I wasn't able to get any of those direct calls to work, but there may be a way. Fortunately, resetting the end-of-program pointer at locations 45 and 46 did the trick.
I think sei was meant to mean set interrupt mask which is why we also have non-maskable interrupts
According to the MOS references, it's "Set Interrupt Disable Status" which is about as clear as mud :)
Great video!
Not that it matters, but I believe an inc should set the Z flag, so no need to load $fc into the accumulator before the beq during the rom copy
Thanks, I think that's exactly the one optimization that David Youd told me I missed on that, when I saw him at VCFMW a couple weekends ago.
Nothing to do with this topic, but if you are interested in a bug (if you may call it so) in the CCS64 emulator , let me know.
I realy like this channel, still learning.
Pedantic, but at the very end, can't jsr $a831 be replaced with jmp $a831, and eliminate the rts? Great video!
Ran a lot of type-in utilities in 49152, but only 1 at a time. The self modifying code made it impossible to relocate anything. Maybe you could sniff out variables 1 by 1. Atmega used the same interrupt opcodes.
Commodores IEEE 488 cartridge also uses c000, I'm not sure why as it has a ROM and it copies from ROM to RAM at startup and then banks out the ROM.
@@phill6859 does it copy itself to $C000 Ram?
I guess because of the different paged plus 4 memory mentioned that this wouldn't work like for like on a plus 4?
I love the C64 but I can't imagine coding directly on it anymore.
I’d bet most modern c64 game developers agree with you.
At 53:23 this works if you are benchmarking in Basic only? What if you were benching a compiled program or wanted a universal benchmark routine that would also work for assembly language programs? Would this still work? I'm guessing no- that you would instead write 0 to three CIA registers on the $Dxxxx region?
Yeah, this is all only for benchmarking BASIC, and yes, using an otherwise unused CIA timer would probably be the best way to benchmark assembly.
Make a comment in the instruction manuals so future generations know the exact addresses? Write your name too, so they will know it comes from a veritable source.
(Patching run: 21:36 && 25:32)
What enclosure is that?
12:12 That's a nice looking table. Is it a Chippendale? My project in 2025 is to learn ARM Assembly for Embedded Systems. Apparently even electric toothbrushes use it. ⚛ 🤖
Make video about "micro adventure" books from texas instruments
I would love any video related to Texas Instrument. I grew up with a TI99
@@thenorseguy2495 It's #SepTandy you insensitive clod! We Trash-80 users are always left behind!
7:55 Object code? How is this different from an executable? I thought there was some difference, requiring something called a "Linker"?
Object code doesn't contain headers and other links. I don't know what's involved in linking for a C64, but for some others it's about any number of OS related things in order to get it loaded into memory properly before it is ready to run. If you take an object file (on disk) and copy it byte by byte to the correct memory location and then SYS call that address, it should work fine. But without the linking part, the OS (ROM) wouldn't know where to load it.
@@anjinmiura6708 sounds like on the C64 you prepend the 16 bit load address to the object file and you are done.
@@saganandroid4175 That may well be the case.
"A Commodore 64 binary executable is intended to be run on a Commodore 64 or on another machine that is emulating one. These files are often stored with the extension .prg when kept in filesystems that distinguish types by extension. (In the original Commodore environment, they generally didn't have an extension but had file type "PRG" in the directory structure.) Files of this type might be binary executables, tokenized BASIC, or other sorts of data files; even text files are sometimes stored in PRG format instead of TXT, so the file type doesn't give much information about what sort of data it is.
The first two bytes in a PRG file are the memory address that the file should be loaded into (in little-endian format). For a C64 Commodore BASIC tokenized file, intended to be loaded into $801, these bytes are $01,$08. Note that these bytes will be ignored (i.e. a PRG file will be loaded into $801) UNLESS the LOAD command had a non-zero parameter after the device number. i.e. LOAD "*",8 will load a file from device 8 (the typical device number for a disk drive) into $801, while LOAD "*",8,1 will load a file into whatever memory address is specified by the first 2 bytes of the PRG. "
So yes, that appears to be correct. I would have expected something more sophisticated.
Yes, the two terms end up being nearly synonymous on the C64 and many other 6502 systems. When Turbo Macro Pro saves the object code, it does so as a PRG file which has the 16-bit load address at the beginning. Then when the file is LOADed, it's put in the correct location in memory for execution with RUN or SYS. CPUs and operating systems with better code relocation abilities, or a true "executable file" concept make much more of a distinction.
33:08 If you wanted to be even more accurate, you could also set the CIA timer to its full count and clear any pending interrupt. Or, you could chain two CIA timers together for microsecond-level accuracy for up to 70 minutes.
39:16 Using any Kernal routine in an interrupt can clobber variables that the main program is using, especially if it's concurrently calling the same Kernal routine.
Set the CIA timer to $FF? How does that improve accuracy?
@@saganandroid4175: If you set the 16-bit CIA timer to the full count for a jiffy, about 17045 for NTSC, the first jiffy counted off in the timed period will be a full jiffy. Otherwise, it will be some random amount of time between 0 and 1 jiffy.
@@csbruce "full count for a jiffy" does not compute. A jiffy should be in increment of 1 for the 60ths of a sec? I heard PAL machine still use 1/60th of a sec for system timing. VICII is 50Hz of course. Not really sure what you are trying to say. Maybe pick a CIA chip and specific register/address and explain from there?
@@saganandroid4175: The IRQ interrupts run independently from the Benchmark program. Just setting the jiffy zero-page value to $000000 doesn't reset the CIA timer, so if there's only 100 1-MHz clock ticks left in the CIA timer before the next interrupt, the first "jiffy" will be ticked off after only 100 microseconds instead of the proper 16667 microseconds.
@@csbruce 0 and 1 what? What units? 17045 what? Clock cycles?
I know you love tinyest code Robin, but mentally, that copy routine is seriously tortured logic from a human perspective. I wonder if a decrement approach (from FFFF) would be any more human-brain-friendly.
This video lacks turtles.,
HEY! This is #SEPTANDY! Do something Tandy!!!
Also, why when the scroll routine does its thing does it scroll two lines?
#SepTandy came early this year with my 3.17 cm diskette video. I don't think I'll have time to do another this month.
The scroll routine always scrolls logical lines which on the C-64 are two 40 column physical lines. On the VIC-20 it'll scroll four lines at a time! This logical line concept, of combining physical lines together, is to allow user input (such as a program line) to go past the 40 character limit it would otherwise have on the C-64, and the 22 column limit on the VIC-20!
@@8_Bit I guess that makes some sort of rational sense. This distinction between physical lines and logical is interesting. Are these physical lines based on hardware? Otherwise if they are implemented in software I'm not sure how that makes complete sense. But this rationale does have some obvious merit insofar as the line editing is concerned.
@@anjinmiura6708 Yes, "physical lines" just means the number of text columns the video chip displays by default. There may be a better term for it, but that's the one I've seen in descriptions of the concept. The KERNAL maintains a "link list" that combines the physical lines into these logical lines. It's somewhat complicated, but is part of Commodore's screen editor that I still find to be a better solution than maybe any other 8-bit computer I've used.
@@8_Bit The VIC2? en.wikipedia.org/wiki/MOS_Technology_VIC-II This says it's 40x25. 80 Columns in the VIC2e exists but it's a different though related chip. The idea that the KERNAL tracks it this way does make some sense. It would definitely make sense as it relates to outputting to printers which are almost always 80 columns minimum.
I'm not doubting you in the least. You probably have the KERNAL source code memorized. I'd love it if you did a walk-through on the "two line scroll" behavior because to me, it's the one thing that ruins the 10 PRINT thing. I actually created a kind of screensaver built around the 10print thing but for that last character, I ended up either not printing that last one or poking it into screen memory just to keep it from scrolling twice.
435
That is nowhere near as efficient as you can make the memory copy.
I'm looking forward to seeing your code.
5327
Sunday 6:05 in the morning and I'm watching "Softpatching a C64 Rom..." - should I consider a doctors-visit or try to heal it by buying another C64??? Hard decision... (Don't ask my wife...)