nocrew / ostis

Atari ST Emulator
GNU Lesser General Public License v2.1
20 stars 4 forks source link

EA calculation state machine #122

Closed larsbrinkhoff closed 8 years ago

larsbrinkhoff commented 8 years ago

It would be very tedious to implement EA calculation in every individual instruction. EA calculation normally happens at the start of an instruction, takes 0-18 cycles, fetches 0-2 program words, and reads 0-2 operand words.

Is there a plan to alleviate this? If not, I suggest creating a helper state machine.

This state machine would keep its own state. The instruction can call it from any instruction state to advance execution of the instruction and EA calculation in parallel, if necessary. In practice, I expect most instructions to just do a complete EA calculation in the beginning and process the rest of the instruction after that.

I imagine an API like this:

void ea_begin(struct cpu *, WORD mode); // Initiate EA calculation.
int ea_step(struct cpu *); // Return status: in progress, or complete.

I'll leave some details undefined. :-)

larsbrinkhoff commented 8 years ago

Oh, and of course MOVE needs two EAs.

stefanberndtsson commented 8 years ago

I'm thinking this should actually be six (or possibly four) reentrant points instead of ea_step().

ea_(read|write)_(byte|word|long)(struct cpu *cpu, WORD mode)

My reasoning here is that read/write isn't actually part of EA (the actual choice is set in the instruction op-code, not in the mode flags). The same goes for the size. Word and byte are technically pretty much the same thing, and long should be two steps of word of course.

So the instruction does its state-bits first, then sets itself in an EA-state relevant to the instruction.

So a MOVE.L (A0),D0 could setEA_READ_LONG, but ROXL (A1) might only use EA_READ, and EA_WRITE because it's always a word. That state would be one of the instruction states.

Within EA then it would have its own states including prefetching new words and returning something relevant when the instruction should move on to the next state.

Care needs to be taken during the EA states should. One cannot rely on EA to always finish. If a BUS ERROR occurs during an EA, the instruction is aborted midway through its execution and both the instruction state and EA state needs to be cleared.

larsbrinkhoff commented 8 years ago

I was vaguely thinking that the calculation of the EA may be separated from doing a memory access to that address. Maybe it's convenient to combine them, as you describe.

I see in the Yacht table that most instruction seem to do the address calculation and accessing the first operand in an identical manner.

stefanberndtsson commented 8 years ago

Yes, I think MOVEM.L reg,-(Ax) as destination is the main exception, where it's done "nw nW" instead of "nW nw", and that one isn't using the normal EA writes anyway.

larsbrinkhoff commented 8 years ago

Pull request #135 implements a first version of an EA calculation API.

There are three different entry points.

After this, this function should be called to advance the state machine. It returns 1 when the calculation has finished. May return immediately for i.e. register accesses which takes 0 cycles.

larsbrinkhoff commented 8 years ago

The entry points take an instruction words as input. This is used to extract the addressing mode, and also operand size. (Some instructions don't conform to the standard format, so bits have to be shuffled around.)

The ea_begin_modify function takes four additional arguments to specify how many more cycles are needed to write a word/byte, or long to a data or address register. This isn't particularly pretty, so we'll see how this plays out.

larsbrinkhoff commented 8 years ago

Unless someone has some more thoughts, ideas, suggestions, I think we can consider this closed.

stefanberndtsson commented 8 years ago

Ahh, saw this one too late (about ea_begin_modify). No that's not pretty. What possible options for c1-c4 can there be? Could this be a bitmask and OR:ed flags instead?

larsbrinkhoff commented 8 years ago

It could be extracted right out of the instruction bits. But the idea is that the caller, i.e. the instruction, already knows about the timing for writing registers.

It's all about what's convenient and makes for nice code. I don't know yet, but I'm sure we'll have a better understanding when we implement a few more instructions.

stefanberndtsson commented 8 years ago

Ok, this could probably be closed now. A new issue can be opened when dealing with future changes.

larsbrinkhoff commented 8 years ago

Right!