• Please review our updated Terms and Rules here

Would a "true" PET emulator be possible for the c64/+4?

orac81

Experienced Member
Joined
Mar 21, 2024
Messages
200
I was thinking, would a "true" PET emulator be possible for the c64/+4? I wrote a simple Basic one back when i got the 64, that sets the screen to $8000 and Basic to $0401, etc, so most old PET programs could run with just the odd mod.


But what I mean is switching to 64k Ram mode, then loading an adapted Pet Kernal+Basic 2.0 ROM at $C000 up, with the code altered to run with the 64. The USR vector at 0,1,2 would clash with the c64 mem control regs, you could trap peek/poke for that. Some emulation of PET hardware at $E800, via the IRQ would be needed for the common pokes for sound, keyboard, lower case. The original char set can be put at $8800, and A000-BFFF would be available for extra support code. I would guess the IEEE and tape would be a lot of work, but a simple hack to just get Basic running might not be too hard.

Thinking about it, it might be possible to "swap" kernel mem below 1k between the 64 and Pet mode, so that the 64 routines are called for loading files etc.

This is my "simple" emulator..
Code:
100 rem pet simulator for c64, (c)1983 orac81,freeware.
110 rem make sure bits 0&1 are output
120 poke56578,peek(56578)or3
130 rem change banks:-
140 rem 0 -> $0000 to $3fff, default
150 rem 1 -> $4000 to $7fff
160 rem 2 -> $8000 to $bfff, new val.
170 rem 3 -> $c000 to $ffff
175 poke56576,(peek(56576)and 252)or1
177 poke53272,peek(53272)and15
180 rem tell kernal where screen is
182 poke648,128
185 rem move top & bot pointer1s
190 poke55,0:poke56,128
200 poke1024,0:poke43,1:poke44,4
300 rem reset
310 poke53280,0:poke53281,0
320 print chr$(147)chr$(30)"### commodore basic ###"
330 print:print" 31743 bytes free"
340 new

The ultimate aim of a "true" emulator would be to run at least some Pet asm apps without alterations.

I wonder if its possible to do? Has anyone tried?
 
Last edited:
Some emulation of PET hardware at $E800, via the IRQ would be needed for the common pokes for sound, keyboard, lower case.

I’m confused, does the C64 have a mechanism to fire an IRQ when a random page of memory it accessed? I guess I see where you’re going here, for simple writes to the PIA ports you could use the vertical blank interrupt to periodically read the port addresses and change settings based on their current values, but that’s not going to help with anything that hammers on the IO ports regularly. (Like, for instance, you had an ML program that had its own keyboard scan routine.)
 
No, it doesn't. That's why my KIM-1 emulator on the C64 essentially does a full software emulation of the 6502 on the 6510. It's the only reliable way to trap and remap memory accesses, undocumented instructions, etc.

It should be possible to do this for the PET, too. The problem is of course it's about 35-50 times slower than a real KIM-1, even though this is enough to run real software like Tiny BASIC and FOCAL.

 
Yes, if you intend to closely emulate Pet3032 that hammers the VIAs etc, it won't work. But you could conceivably pick up changes in values from Ram at E800 via the 1/60th sec IRQ, say setting the sound, gfx mode. It probably won't be sufficient for keyboard scanning, I guess..

Ok thinking some more..

Suppose you have a "full speed" and an "emulate 6502" mode, toggled with F7 key. If the emulator finds an instruction that directly accesses the keyboard port, it substitutes the LDA PORT or STA PORT with a JSR to a patch with c64 keyboard code, then flashes the border. So if the user has a problem program, they hit F7, and wait until it stops flashing the border. Then they hit F7 to run the program at full speed!
How does that sound?

(mem $9000-BFFF is available for the emulator)
 
Last edited:
No, it doesn't. That's why my KIM-1 emulator on the C64 essentially does a full software emulation of the 6502 on the 6510. It's the only reliable way to trap and remap memory accesses, undocumented instructions, etc.

There was a technique used by some oddball 8086/8088 PC compatibles where they would use a hardware shim to capture accesses targeting a missing piece of hardware and trigger a Non-Maskable Interrupt to call a software routine to suss out what was being attempted and translate it to what the machine actually had. (A common case was the machine didn’t have a real 6845 CRTC, and the NMI would trap calls to change video modes, update the cursor location, whatever.)

Maybe you could build a hardware cartridge that snooped the bus and did something like that, but I’m not sure the interrupt structure of the 6502 would make that feasible?
 
You can sniff the bus, but the 6502 won't look at an interrupt until the current instruction finishes, as per the design. If you can fit yourself into the CPU socket, you could halt the CPU clock and potentially do something (like switch to an alternate RAM, save the address, latch an IRQ, and then unhalt the CPU clock, with the IRQ going to a routine in the new RAM that would read the address impacted, use the data (if it was a write) or load some alternate data (if it was a read), set the flags on the stack, the RTI, and the HW would switch the RAM back on completion of the RTI. But, that's a heavy lift.

There is, if anyone cares, an official PET emulator app on one of the C64 disks:

 
Also, what PET would you emulate? Remember that there are three different generations of classic PET computers.
 
I think the best target would be Pet3032/2001 upgrade, that was the system at the PETs peak popularity for home use, the 40xx/80xx was mostly Business use after that time. (although a true 8032 emu for a c128 could be interesting!)

I think Ive seen that emulator (linked above), its ok but Basic only. By actually modding the original ROMs you get (nearly) the same low 1k memory map, and a lot of m/c programs should run. For example Tape buf#1 would be in the same place, peek(151) would be the key down code, etc.

To take real cases, my 1981 PET Orac game should run. The original Microchess should run. If asm game uses peek(151) or kernel for keyboard, it may run.
If you allow switching back to 64 mode, by swapping kernel low 1k mem, you could implement disc access, and serious asm programs like wordpro, compilers etc may run..

Everyone seems to be thinking of things like running modern chase-the-raster demos, but most old stuff never did that.
 
Last edited:
So someone supplied this link to an emulator called "Basil".


This looks close to what I mean, but I was thinking of directly modding the original ROMs. Still interesting.
 
Yes, if you intend to closely emulate Pet3032 that hammers the VIAs etc, it won't work. But you could conceivably pick up changes in values from Ram at E800 via the 1/60th sec IRQ, say setting the sound, gfx mode. It probably won't be sufficient for keyboard scanning, I guess..

Ok thinking some more..

Suppose you have a "full speed" and an "emulate 6502" mode, toggled with F7 key. If the emulator finds an instruction that directly accesses the keyboard port, it substitutes the LDA PORT or STA PORT with a JSR to a patch with c64 keyboard code, then flashes the border. So if the user has a problem program, they hit F7, and wait until it stops flashing the border. Then they hit F7 to run the program at full speed!
How does that sound?

(mem $9000-BFFF is available for the emulator)
I think this could be done even more simply: run a patched BASIC natively, because you can intercept WAIT, PEEK and POKE that way, but when you do a SYS or USR() switch to the emulated core.

The problem with the substitution trick is that you need to know the virtual address you're intercepting in advance (it's virtual because you want to remap it to a physical 64 address), at the time the instruction is being run, but before the instruction actually is. This isn't possible on the 6502 without hardware: you'd have to look ahead in the instruction stream to find them, and at that point you're pretty much emulating the CPU anyway. Also, even if you scanned the code AOT to find all absolute references, this wouldn't trigger on indexed indirect accesses where the values may not yet be known.

Plus, there are programs that jump into the middle of instructions (BIT is a good choice for this), and the patch approach would break them. They are a minority but it could generate some very hard to trace bugs.
 
I think this could be done even more simply: run a patched BASIC natively, because you can intercept WAIT, PEEK and POKE that way, but when you do a SYS or USR() switch to the emulated core.

The problem with the substitution trick is that you need to know the virtual address you're intercepting in advance (it's virtual because you want to remap it to a physical 64 address), at the time the instruction is being run, but before the instruction actually is. This isn't possible on the 6502 without hardware: you'd have to look ahead in the instruction stream to find them, and at that point you're pretty much emulating the CPU anyway. Also, even if you scanned the code AOT to find all absolute references, this wouldn't trigger on indexed indirect accesses where the values may not yet be known.

Plus, there are programs that jump into the middle of instructions (BIT is a good choice for this), and the patch approach would break them. They are a minority but it could generate some very hard to trace bugs.

I did have an idea on this. You can run an asm prog as normal, but use the IRQ to watch certain writes to $E8xx. if a program writes to the keyboard row select, switch to emulation, then trap the "STA rowsel " instruction, and change the code to a JSR to a routine that maps that to the c64 keyboard, and puts the answer back in the right place at $E8xx. After some fixed amount of time, go back to full speed mode.

You could even try to trap read/write to 6510 MMU at $00/01 this way, substituting all zp call with two byte 00 0x using BRK + code trap to emulate different possible options.

There you go, automatic on the fly code patching!
 
Last edited:
Ingenious but not quite that easy :) Without hardware, you can't trigger an IRQ directly on a write to that port, and since the value is stateful you're reduced to constantly watching the value stored to ensure you don't miss any changes. Your IRQ would have to run every few cycles or so as a result, and even then it's a big can of race condition.

The second approach you suggest is the general case of pre-patching code to turn loads and stores into BRK software interrupts. This should work in many cases, and I think there's even prior art that did something like this, except that there are so many instructions that access memory that you would be forced to trap and emulate a substantial part of the ISA. That's not a lot less work than just emulating the ISA entirely to begin with, and it still doesn't cover the (infrequent, to be sure, but not unheard-of) case of a program jumping back into the middle of a prior instruction, or indirect indexing of any type.
 
Back
Top