Hello, Guest the thread was called10k times and contains 158 replays

last post from FeralChild at the

Work is underway to make open-source replacement ROMs for the C64

  • Yes, at 1MHz the 4510 of the C65 (and the 4502 of the MEGA65) use exactly the same number of cycles per instruction as the 6510. The only difference is when in the instruction certain memory accesses occur, which is only likely to affect a very few situations.

    We can already boot GEOS from an IEC drive on the MEGA65, as an indication of how satisfactory how this is.


  • Thanks for the clarification. That's great news. I was always worried for this kind of compatibility issues. Then probably all of the original C64 fastloaders and such things will work.

    :: @rosettif added on 20 May ’19 · 03:11

    Now I have partly re-read that ominous "Preliminary" about the original C65 again, and yeah it indeed speaks about some "dummy cycles" emulated by the processor. Strange I have never recognized it before... However, I have never seen it in the emulations yet, either.

    At least it is emulated at a nearly 1.18 MHz effective speed in both existing emulators (MESS and XEMU) as it was even so on MEGA65 two years ago as well (see my topic about MemTest64 here) as opposed to the 6510 which is about 0.98 MHz. Thanks again.

  • Hello,

    Well, it has only stalled in so far as I am not an octopus with as many eyes as tentacles to be able to type on 8 keyboards at a time. I'll very likely attack the next stage when I get a moment, but it is also at a stage that is suitable for the community to join in, and make the whole thing go much faster than if it stays just me alone. There are a bunch of tasks that people could work on, if they have interest:

    1. Implement floating-point functions.
    2. Implement expression parser (with a nice little cache to speed up frequently referred to constant expressions).
    3. Implement variables (with a nice little variable cache to speed up use of frequently referred to variables).
    4. Implement missing BASIC commands.
    5. Implement missing KERNAL functions.
    6. Write lots of tests, and test lots of things!


  • No idea about MESS, but in XEMU the problem about the CPU speed, that it emulates 65CE02 CPU core with its timing ... more or less. A true C65 would (according to the existing partial documents on this ...) insert "dead cycles" in "slow mode" to more or less match the speed of the 6502 timing. Eg 65CE02 has 1 cycle to execute to NOP, but 6502 requires 2, and so on, regardless of the CPU clock. So I guess what C65 designers wanted is to insert extra cycles in "slow" mode to match the timing of the 6502. For Xemu it didn't worked yet ... For mega65 itself, I have no idea, I guess it works there, and even more work expected (ie giving more 6502 compatibility in "C64 mode" like illegal opcodes). Surely, these can be done in Xemu too, hopefully I get the point some time to do all of these ...

  • Hi, I'm a programmer interested in computers in so much as I can understand them. So older systems are much more likely to interest me than new ones, which are just really to overblown to get a handle on.

    As such I would like to help develop the Free BASIC and Kernal ROMs! For a description of my level of expertise, read on!

    I had always wondered how the old 8 bit machines implemented BASIC and have interested in assembly language programming on them as well since the 1980s. But an assembler seemed to be some expensive semi magical piece of technology that was just unaffordable and unapproachable to my younger self. But after studying computer science at university, it's now something that I should be able to do. Theoretically at least.

    Once thing I always wanted to implement an assembler on an 8 bit micro back in the day and maybe a high level language. I've studied compiler construction, and did that Nand2Tetris course on Coursera as well

    I had been trying to get my dad to dig out ye olde TRS-80 Color Computer II for years without much success, so I started to look into systems that maybe I could buy.

    So in the last 6 months or so I started to settle on the Commodore 8 bit micros, looking for a system and typing in a lot of assembler from old books into the VICE emulator running various assemblers I could get my hands on, both in C=64 and C=128 emulation, and also reading and watching all I can to find out how they worked. Including how BASIC was interpreted, tokenised, stored, and ran.

    This eventually lead me to actually drop $520AUD on a C=128, 1541 Disc Drive, 1084s monitor and a data set. Which all works great, although the 80 column display doesn't seem to want to sync, though it does display, just the picture keeps rolling and won't lock on, although I'm not sure if that's a problem with the machine or lack of a suitable cable I've tried several stop gap solutions.

    However back when it was looking like I might not be able to afford original hardware, I was looking into getting a cheap LatticeXO2 or XO3 FPGA/CPLD board or something like that and developing one bit by bit, no pun intended, starting with say the 6501, then the I/O port to make it a 6510, clocking and PAL, VIC-II, CIAs, SID, etc., etc. until I had something that could run the original ROMs and games. So I poured over all the relevant data sheets and started learning VHDL...

    I think I have a pretty reasonable understanding of how the Commodore 64 actually works now, Commodore 128 a bit less.

    After I got the Commodore 128, I was still a bit interested in the FPGA stuff, and thought probably the best thing to do was try to create something simple like an REU, then say a SuperCPU, then a C=64, then a C=128.

    But then I saw the talk Paul gave about the FPGA phone in Christchurch in January <https://youtu.be/KuNB4ocZDXA> and saw what I wanted to do had essentially be done, and so I want to contribute! It seems a better use of my time that writing yet another assembler for the C=64 or C=128, and I'm fresh out of ideas for games, etc...

  • The 'cmd_load.s' contains:

    ;; XXX - C64 BASIC apparently doesn't clear variables after a LOAD in the
    ;; middle of a program. For safety, we do.
    jsr basic_do_clr

    This will break some BASIC software, like:

    100 DN = 8: REM set device number
    110 LOAD "SPRITE DATA 1", DN, 1
    120 LOAD "SPRITE DATA 2", DN, 1: REM <- this will try to load from device #0

  • Howdy,

    It would be great for you to help out on the open-roms, if you are willing. Also glad you enjoyed the talk at LCA :)

    Anyway, the source is at https://github.com/mega65/open-roms, if you haven't already found it.

    If you were willing to start with implementing floating point format handling, that would be great, as together with the expression parser it is the key to getting the BASIC really useful. It's important that we don't copy the C= code, but implement everything fresh, so I would even recommend not reading up on the algorithm that they used, but do it from scratch how you think best. I'd begin with floating point number parsing, and then move onto displaying floating point numbers, and performing calculations on them. There are a bunch of good academic papers on parsing floating point numbers in recent times, because floating point is the default data type for many modern scripting languages, so a lot of work has been done on improving the algorithms for working with them.


  • The 'LICENSE' contains:

    This software is Copyright Paul Gardner-Stephen (2019). All rights reserved.
    It must not be used or distributed without prior written permission of the author.
    NOTE: This is a placeholder statement until a final license is selected.


    Somehow, I don't feel comfortable trying to use this...

  • First, thanks for the heads up on the behaviour of the LOAD command. Can you please create an issue on github for it?

    Now, for the license, I think I have a pretty good record of putting things under appropriate open-source licenses, so I wouldn't worry. The reason I hadn't chosen one, is that I wanted to talk with the community about what the preferred license would be. My gut feeling is LGPL, but I would like to hear what other people think. Then I'm totally happy to change the license file to indicate what we settle on.


  • Hey, thanks was thinking of starting there anyway, floating point parsing, manipulation and representation, probably working backwards so representation and manipulation followed by parsing.

    But I was a bit taken aback by your reply and what I read when I read your more of your blog. I see that you aren't following the same tokeniser scheme that the C=64 did.

    Fair enough I guess, would be easier to implement a better symbol table that way. For instance say keeping the identifiers heap sorted so lookup of any symbol is O(log n) where n is the number of symbols.

    I guess I'll see when I look at the code. I'm guessing you've got something working anyway, considering you can do LOAD, etc.

    But I'm curious as to whether you want to keep the same Microsoft floating point format that the C=64 uses and all the memory addresses in the zero page the same way that the C=64 does as documented in _Mapping the Commodore 64,_ etc. As far as I'm aware doing so would be crucial to getting binary compatibility with existing software that used the KERNAL. I'm guessing the tokeniser format not so much.

    How to do the transcendental functions is a bit of a vexed question. There's basically two ways to do it I know of. The first is polynomial evaluation of something close to the Taylor series but with the constants of the polynomial finagled slightly to give more accurate results than using only the first few terms of the Taylor series and ignoring the rest.

    Terms which grow increasingly smaller, but increase in order and are infinite in number. And which unfortunately don't settle down to "negligible" for quite some number of terms. So (empirically derived?) correction is added to the first few terms to compensate.

    This is how the C=64 did it, and in fact if you are keeping binary compatibility with the BASIC and KERNAL ROMs you actually have to implement this polynomial evaluator because it's exposed and documented so presumably anyone could have used it.

    Then you might as well use it to evaluate your transcendentals, but then you are in the position where the table of constants of your polynomials would be the same as the copyrighted Microsoft floating point implementation.

    Now I doubt this would be copyright-able, given that to get the same results on the same data (achieve binary compatibility), you are basically stuck with using these constants. So presumably they would be more "facts" than "inventions" or other protectable works, but I'm not a lawyer. And it generally seems against the approach that you want to take.

    The other approach would be to use a CORDIC algorithm to do transcendentals. This might even be faster and would not be based on anything Microsoft or CBM did. Unfortunately I don't understand CORDIC yet :P

  • Yes, my feeling is that keeping binary format compatibility will be important. One of the nice things about building the ROMs progressively, is that we can change our design decisions as we go along.

    My view is that we should always minimise risk of copyright infringement first, and then improve compatibility after. In particular, any forced convergence with the original ROM should be supported by an issue that demontrates a program that cannot run without the convergence, e.g., in this case find a program that relies on the data format of the floating point numbers to work, and in the meantime, implement it however we think is best practice. What is certain, is that the most of the implementation will be re-usable, even if we started with a different format.

    But otherwise, it is really encouraging to see the interest from yourselves in helping out with this project :)


  • Ok, I think I have warped my tiny brain enough so CORDIC can fit in :D At least for computing sine and cosine...

    By the way, I cloned the repo, but Paul do you have a link to any documentation about what the work flow is? What assemblers, etc.

    Also I think we probably need to start noting down what volatile memory addresses are used and where. Because obviously we can't use locations that are available to the programmer, because then they aren't available to the programmer anymore! Not a huge deal with functions that don't call any other, so long as certain memory addresses are reserved for these leaf functions, but even there we still have to worry about what locations might be trampled by an interrupt handler.

    _Mapping the Commodore 64,_ _Mapping the Commodore 128,_ and the _Commodore 64 Programmer's Reference Guide,_ etc., can help but only so much. We can use it to know what locations are used by BASIC and KERNAL but not really to stop one part of the OS rofl stomping another part, written by someone else.

    The stack isn't as helpful as it could be 1. because stack relative addressing isn't directly supported on a 6502, although it can be arranged by getting the stack pointer into X with TSX and then using relative addressing eg. LDA

    That doesn't help much though because the stack is only 256 bytes! So facilities for recursion would seem to be quite limited, so every bit of data will have to be a global pretty much, and pretty much either located by prior agreement or doled out by central mechanism in the KERNAL..

    This could be simple as a free list but even still, it's still a pain because were do you keep that address you receive. Putting a couple of them on the stack isn't likely to be catastrophic, but otherwise you're back to the chicken and egg problem of you have to store it somewhere, and that requires an agreed upon location...

  • “I'm guessing you've got something working anyway, considering you can do LOAD”

    I can't get this to work - it's probably incomplete, as even CIOUT is clearly not implemented. I'm going to take a look into this.

    “What assemblers, etc.”

    It uses Ophis assembler, it's in the submodule. Under Linux typing 'make' in the 'open-rom' directory did the trick for me (just one REALLY nasty thing: I had to switch Python to version 2 :/)