boeckmann / asm6502

Small but useful 6502 assembler in ~3K lines of ANSI C code.
MIT License
5 stars 2 forks source link

Port C64 KERNAL source as ultimate test case #19

Open boeckmann opened 1 year ago

boeckmann commented 1 year ago

The original source can be found at https://github.com/mist64/cbmsrc/tree/master/KERNAL_C64_03

Repository of the port: https://github.com/boeckmann/c64krnl

It does assemble but some adjustments still have to be made, because the original source jumps around in the output file via .org. ASM6502 does not support this. But the changes are minor.

boeckmann commented 1 year ago

I managed to produce a nearly exact replica of the ROM file kernal-901227-03.bin shipped with the Vice emulator. The BASIC code at $E000-$E4D3 is replaced by $AA.

There is one byte of difference at $FF7E. But this is not an assembler error. The code I assembled contains

FF7D  4C 85 EE        42:   JMP CLKHI       ;RELEASE THE CLOCK LINE***901227-03***

While the ROM code contains

FF7D  4C 8E EE        42:   JMP CLKLO

Seems some sort of error was fixed in the source code that is not reflected in the VICE ROM, despite being named 901227-03. In the KERNAL V2 source the line is

JMP CLKLO       ;RELEASE THE CLOCK LINE

So either the Vice ROM is not what it pretends to be or the source change did not make it into the original C64 machine ROMS.

boeckmann commented 1 year ago

Commodore C64 KERNAL v3 and Commodore BASIC v2 are fully ported. The ROMs are operational in the emulator VirtualC64. Apart from the check sum bytes, which I left at value zero, the ROMs are exact replicas of the original ROMs.

waltje commented 1 year ago

Hi:

My 8086 assembler (which I have used, and still use, for BIOS ROMs) has a .sum() function for this:

 the_rom:    .blob      "thebios.bin",8191                     .db        .checksum(the_rom, .)

to do this automatically.  Probably worth adding to this asm.

Fred

On Thursday, April 20, 2023 at 05:52:51 PM EDT, Bernd Böckmann @.***> wrote:

Commodore C64 KERNAL v3 and Commodore BASIC v2 are fully ported. The ROMs are operational in the emulator VirtualC64. Apart from the check sum bytes, which I left at value zero, the ROMs are exact replicas of the original ROMs.

— Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you are subscribed to this thread.Message ID: @.***>

boeckmann commented 1 year ago

Yes I am considering this but have not yet decided if I should implement it. The question is which checksum algorithms to implement, as there are many :-). It should be somewhat generic. And if I implement multiple algorithms it blows up the code.

Should ideally also be a function to be used within expressions to allow something like this:

sum .byte (0 - .chksum(ADD8, "file"...)) & $ff

At the moment a have no code to support calling functions within expressions. But that is another topic. 1k lines of code :-)

boeckmann commented 1 year ago

Kernal assembles in ~1 second on my Pentium MMX 166 machine running OS/2, which is not THAT bad I think. There are over thousend global symbols. Like expected, profiling reveals that the majority of time (75%) is spent searching the symbol table if not writing a listing. While this could be improved by changing the symbol table data structure, this test may be the worst case a) regarding the machine it is running on and b) the size of the symbol table. So for simplicity, I think I leave the symbol table structure as it is.

waltje commented 1 year ago

My code does that different - while inserting, I insert in ascending alphabetical order.  Searches are faster, because it can stop early if it hits a "bigger" symbol:

symbol_t sym_aquire(const char name, symbol_t *table) {     symbol_t ptr, *sym;

    if (table == NULL)         table = &symbols;

    sym = sym_lookup(name, table);

    if (sym == NULL) {         sym = sym_new(name);

        / Insert symbol in alphabetical order. /         if ((table == NULL) || (strcasecmp((table)->name, name) > 0)) {                 sym->next = table;                 table = sym;         } else {                 for (ptr = *table; ptr->next != NULL; ptr = ptr->next) {                         if (strcasecmp(ptr->next->name, name) > 0)                                 break;                 }

                sym->next = ptr->next;                 ptr->next = sym;         }     }

    return sym; }

A binary tree would be even better, but I was lazy :P

--Fred

On Friday, April 21, 2023 at 02:24:39 PM EDT, Bernd Böckmann @.***> wrote:

Kernal assembles in ~1 second on my Pentium MMX 166 machine running OS/2, which is not THAT bad I think. There are over thousend global symbols. Like expected, profiling reveals that the majority of time (75%) is spent searching the symbol table if not writing a listing. While this could be improved by changing the symbol table data structure, this test may be the worst case a) regarding the machine it is running on and b) the size of the symbol table. So for simplicity, I think I leave the symbol table structure as it is.

— Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you commented.Message ID: @.***>

boeckmann commented 1 year ago

Would be interesting to know how much of a performance improvement that is. Perhaps I will benchmark the two versions when I have time.

If I "enhance" my symtbl I think I will propably implement a hash tbl at the global level, with a fixed prime numbered bucket size of around 100-200. And on collisions do chaining with the current struct, and also for the local labels. Should reduce the strcmps for 1000 global symbols to around 10 for a lookup. Should not be that much code to implement this.

waltje commented 1 year ago

Yeah, that would probably be even better than a BT !

Still, I am close to 6,000 lines as it is..

--Fred

On Friday, April 21, 2023 at 04:13:10 PM EDT, Bernd Böckmann @.***> wrote:

Would be interesting to know how much of an performance improvement that is. Perhaps I will benchmark the two versions when I have time.

If I "enhance" my symtbl I think I will propably implement a hash tbl at the global level, with a fixed prime numbered bucket size of around 100-200. And on collisions do chaining with the current struct, and also for the local labels. Should reduce the strcmps for 1000 global symbols to around 10 for a lookup. Should not be that much code to implement this.

— Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you commented.Message ID: @.***>

waltje commented 1 year ago

Can you post "known good" images of the kernal.bin and basic.bin images in the repo, just so people can compare?

Fred

On Friday, April 21, 2023 at 04:13:10 PM EDT, Bernd Böckmann @.***> wrote:

Would be interesting to know how much of an performance improvement that is. Perhaps I will benchmark the two versions when I have time.

If I "enhance" my symtbl I think I will propably implement a hash tbl at the global level, with a fixed prime numbered bucket size of around 100-200. And on collisions do chaining with the current struct, and also for the local labels. Should reduce the strcmps for 1000 global symbols to around 10 for a lookup. Should not be that much code to implement this.

— Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you commented.Message ID: @.***>