Closed larsbrinkhoff closed 8 years ago
Oh, and of course MOVE
needs two EAs.
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.
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.
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.
Pull request #135 implements a first version of an EA calculation API.
There are three different entry points.
ea_begin_read
- start a read operation.ea_begin_modify
- start a write operation to the same location as the previous read operation.ea_begin_write
- start a new write operation.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.
ea_step
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.
Unless someone has some more thoughts, ideas, suggestions, I think we can consider this closed.
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?
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.
Ok, this could probably be closed now. A new issue can be opened when dealing with future changes.
Right!
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:
I'll leave some details undefined. :-)