h5n1xp / Omega

Bare metal Amiga Emulator
Mozilla Public License 2.0
69 stars 7 forks source link

Interrupt Dispatcher #2

Closed h5n1xp closed 5 years ago

h5n1xp commented 5 years ago

Notice the current Interrupt dispatch code is both sub optimal and violates my dependency rules.

I will do a code refresh soon, to move the checkInterrupt() function out of the chipset.c file and into the CPU.c file. The only way for Omega to interact with the CPU Emulator should be via the CPU.c functions. This is to ensure Omega is not dependant upon any specific CPU Emulator.

h5n1xp commented 5 years ago

Moved the interrupt handler to CPU.c, still need to go though it and confirm it is optimal... also need to workout how to ensure interrupts will work on other 68k emulators.

dirkwhoffmann commented 5 years ago

Your new IRQ code only checks the master enable bit, but not the individual enable bits for the interrupt sources. Hence, you trigger an interrupt once the req bit is set, even if the enable bit for the specific IRQ source is 0. The old code seems to be correct in my opinion.

h5n1xp commented 5 years ago

I agree, the old code is better. I have spent the last hour looking over the code and think I can make it better.

The problem stems from the fact that in the original design (“Zorro”), the CPU interrupt level was raised actually in the chipset function write to intreq... but that didn’t feel right. So I just let the intreq function set/clear the bits then have the CPU periodically check the intreqr & intenar and raise the interrupt level if required... this seems cleaner, but is it better?

dirkwhoffmann commented 5 years ago

Don't use polling. It's too slow and unnecessary in this case. I think it's best to write a function checkInterrupt() that computes the IRQ level out of the current bits in INTREQ and INTENA. Simply call this function whenever INTREQ and INTENA changes.

h5n1xp commented 5 years ago

Don't use polling. It's too slow and unnecessary in this case. I think it's best to write a function checkInterrupt() that computes the IRQ level out of the current bits in INTREQ and INTENA. Simply call this function whenever INTREQ and INTENA changes.

I agree. I will test that now.

h5n1xp commented 5 years ago

Moving the check interrupt out of the main loop and to the intreq and intena functions didn't work... have reverted for now. Not going to worry too much about it, as interrupts work, need to focus on the blitter issue.

h5n1xp commented 5 years ago

Ok, so now the emulator works sufficiently to run a wide range of software, I need to focus on what is wrong with my interrupt dispatch, which should only have to be called when intreq and intena are called.

I worry that there might be some kind of "priority loop" going on with with the CIAs and Paula... Not sure, I made a big mess of the CIA code trying to get the floppy drives working.

It works, but perhaps @dirkwhoffmann we might be able to pick apart my code. It's is embarrassing to see how elegant vAmiga is compared with Omega (not being able to use C++ doesn't help).

dirkwhoffmann commented 5 years ago

I didn't look into the Amiga IRQ details yet, but I guess that Paula treats interrupts the following way (it's the most reasonable way from a hardware designers point of view):

INTENA and INTREQ are fed into AND gates (one for each bit). The result is fed into some combinatorial logic that computes the IRQ level. The IRQ level lines are directly connected to the CPU.

Hence, I guess something like this should do it:

checkIrq() {
    int level = computeIrqLevel(irqena & irqreq);
    cpu.setIrqLevel(level);
}

setIntEna(newValue) {
    intena = newValue;
    checkIrq();
}

  setIntReq(newValue) {
    intreq = newValue;
    checkIrq();
}

Don't forget to call setIreReq() when, e.g., the CIA releases the interrupt request.

vAmiga's Paula already has a function for computing the IRQ level (not tested yet, because all the other IRQ stuffing is still missing in vAmiga):

int
Paula::interruptLevel()
{
    uint16_t mask = intreq & intena;

    if (mask & 0b0110000000000000) return 6;
    if (mask & 0b0001100000000000) return 5;
    if (mask & 0b0000011110000000) return 4;
    if (mask & 0b0000000001110000) return 3;
    if (mask & 0b0000000000001000) return 2;
    if (mask & 0b0000000000000111) return 1;

    return 0;
}
dirkwhoffmann commented 5 years ago

Why can't you use C++? 🤔

h5n1xp commented 5 years ago

Don't forget to call setIreReq() when, e.g., the CIA releases the interrupt request.

:thinking: You might be onto something here!

My CIA will call intreq() if the appropriate bit is set in it's icr register. This will raise the CPU IRQ level to (whichever CIA int is called), the CPU will then service the Interrupt. In the AmigaOS ISR it will read the CIA icr register. Now my CIA clears it's IRQ bits upon read of the icr, But my CIA can only service interrupts using it's execution cycle... once every 5 chipset cycles... I'm probably getting a race condition here... I'll need to investigate... i have a lot of strange latches in my CIA, who's purpose is now lost in time.

h5n1xp commented 5 years ago

Why can't you use C++?

I decided for this project I wanted to use plain C, with no support libraries. Remember the initial goal was to be able to use this on a baremetal RaspberryPi and AFAIK C++ can become tricky without a runtime library. Where as I have a pretty good idea whats going on "under the hood" with C and can compile to baremetal relatively easily.

I also have a nice little Cortex M4 microcontroller here, with just enough Flash to hold a project of this size... A man can dream :wink:

mithrendal commented 5 years ago

I think this is really the aspect where Omega stands out of the other emulators, which all need a certain host OS. I wish Omega had this bare metall aspect in its name. ;-) Like bareMetallOmega .... but the name would be too way long wouldn't it ? I have two Raspi's already waiting for being turned into Amigas ...

dirkwhoffmann commented 5 years ago

Yes, you're right. Right now, there is no Amiga emulator around that runs everywhere (except the Browser variants, but they're completely different in their own way and don't run on Raspis for example).

I personally dislike C++ very much and I'm mainly using it for encapsulating stuff in objects. You can fake that of course in C by using structs instead of classes and provide a struct pointer as the first parameter to a function.

h5n1xp commented 5 years ago

I think this is really the aspect where Omega stands out of the other emulators, which all need a certain host OS. I wish Omega had this bare metall aspect in its name. ;-) Like bareMetallOmega .... but the name would be too way long wouldn't it ? I have two Raspi's already waiting for being turned into Amigas ...

I think UAE is probably pretty cleanly separated from the host, but my assessment of the code base is that it has become very complex, and trying to extract what I needed from WinUAE, become too difficult and far less interesting a task than building from the ground up. Which has been a lot of fun!

h5n1xp commented 5 years ago

Yes, you're right. Right now, there is no Amiga emulator around that runs everywhere (except the Browser variants, but they're completely different in their own way and don't run on Raspis for example).

I personally dislike C++ very much and I'm mainly using it for encapsulating stuff in objects. You can fake that of course in C by using structs instead of classes and provide a struct pointer as the first parameter to a function.

If you look at some of Omega's code it still has vestiges of an OOP design pattern*, which my Zorro code used. But doing OOP in plain C is just a headache which I didn't need.

*Some functions still take a "this" parameter, but I will be removing any of this as I update the design... my CIA code will probably keep some of that since there are two nearly identical units, and it avoids duplication in this case.

mithrendal commented 5 years ago

Just a nerdy question: When you look at emulators like WinUAE or FSUAE, they are clearly some sort of virtual machines, right?

Then I have the question, do you think Omega is also still a VM ? Or does it already cross the boundary and fall into some sort of "hardware specific driver" for AmigaDOS ??

h5n1xp commented 5 years ago

Just a nerdy question: When you look at emulators like WinUAE or FSUAE, they are clearly some sort of virtual machines, right?

Then I have the question, do you think Omega is also still a VM ? Or does it already cross the boundary and fall into some sort of "hardware specific driver" for AmigaDOS ??

Currently it falls very much into the VM category (possibly it might be more a simulator, as I'm running the system steps together in time, a proper emulator would be scheduling and prioritising events for efficiency). But hopefully once the bugs have been workout sufficiently to make it run usefully, it hopefully be more of a "missing hardware driver"... if that make sense?

dirkwhoffmann commented 5 years ago

Clearly a virtual machine for me.

h5n1xp commented 5 years ago

Floppy rewrite appears to have removed the need to poll interrupts, they are now just tested and set upon intreq/intena as they should be.