marhel / r68k

A m68k emulator in rust - let r68k = musashi.clone();
MIT License
72 stars 7 forks source link

Implement JMP #12

Closed marhel closed 8 years ago

marhel commented 8 years ago

Please implement the instruction for Jump. For more information, please read the instruction contribution guidelines

marhel commented 8 years ago

I can take this.

marhel commented 8 years ago

It seems there's another cycle count bug in Musashi, JMP IX should take 14 cycles, not 12.

But even stranger is the fact that all JMP-instructions sometimes seems to consume one extra cycle, giving an odd number (in more ways than one). There's special handling for when the JMP jumps back to itself, which then immediately consumes the rest of the remaining cycles (within a single JMP).

However I cannot see how that would cause this seemingly random behaviour. Even if I messed up the opmasks, mistakenly call the wrong instruction, it would not consume odd nunber of cycles, would it?

marhel commented 8 years ago

I think this happens: when the JMP happens to jump back on itself, Musashi sets m68ki_remaining_cycles to zero. Then the instruction finishes, and Musashi deducts the instruction cycles (say 8), giving -8 cycles remaining. Then the execute-loop ends returning the number of consumed cycles via the expression initial_cycles - remaining_cycles. As I start each instruction by giving a timeslice of 1 cycle, this ends up as 1 initial - (-8 remaining) = 9, instead of the normal case of 1 initial - (-7 remaining) = 8

emoon commented 8 years ago

I see.

Does Mame do this different? Seems there are quite a number of issues in even proven code :)

marhel commented 8 years ago

Yes, they are also special casing jumps back to itself the same way.

I assume it can be explained by the fact that when executing a "time slice" of tens of thusands of cycles, a slight error in reporting of consumed cycles has very very little effect, at most we're overconsuming 1 JMP instruction worth of cycles (given N cycles, and a self-jump, it will report N + J (the cost of the particular JMP) which I think overconsumes N % J cycles at most, which in the whole is a very small error. We notice it when we are measuring a single instruction.

Executing more than the given slice happens all the time, we give it 1 cycle, and it has "more than 0" and then executes one instruction, but most of the time it reports actual consumption, but here it overconsumes.

emoon commented 8 years ago

Yeah I guess that is correct and I rather have some slight over consume than under.

marhel commented 8 years ago

Also, when emulating a game, say, I don't think a few cycles here and there are noticable. An incorrect condition code, or the stack pointer at the wrong offset, will eventually crash the system, but cycle consumption are external and invisible to the emulated code, it's only in the context of a whole-system emulation that it might cause some very minor timing issue, I guess.

marhel commented 8 years ago

As a side note, I quite like the fact that our QC-tests found this, by randomly arranging registers so that the calculated effective address was in fact pointing back to the instruction itself. Randomized testing FTW!

emoon commented 8 years ago

That really depends on the system.

This is true on Amiga for example where not much (from what I know at least) programs need exact timing. On the C64 on the other hand esp demos are written in a way where they "race the beam" and cycle timing there needs to be highly accurate with the real hardware.

That being said 6510 that is in C64 is a much simpler CPU than the 68000 and given here that it's not exactly easy to calculate the correct number of cycles even on the real hardware (if you use instructions that give exact numbers all the time (as we know divs for example isn't always the same on 000)

So I think we are fine but we should of course. Also there is trade-off being accurate and performance of the emulator. Has to find a balance there also.

emoon commented 8 years ago

Yeah the QC tests has been awesome :) I had to go several rounds on SBCD to get it right :)

marhel commented 8 years ago

Note that QC checks do not pass for self-jumps (due to the above issue) or JMP IX, due to a cycle count bug in Musashi (M68000UM says 14 cycles, Musashi uses 12).

We'll have to look into a variant of the QC-tests that allows for differences in cycle consumption, I think, unless we keep doing Cycle-PRs to Musashi.

emoon commented 8 years ago

Yeah I think we should have a macro that allows you to skip cycle count if needed.

marhel commented 8 years ago

Note that I sent a few PRs Musashi's way yesterday, now merged, fixing this issue, plus jmp ix, scc true/false and the instruction-mode reset. Running the tests now towards the official version to see if there are any remaining differences.

emoon commented 8 years ago

Yeah I noticed. Great work on those :)

marhel commented 8 years ago

Running all 1098 qc-tests took about 18 mins in the background while I was working with other things, and only found issues with andi_16_tos, eori_16_tos, ext_bw and lsr_32_r. Don't think it has anything to do with the new Musashi-version, but rather better qc-tests now uncovers additional mistakes in our implementation.

emoon commented 8 years ago

nice :)

marhel commented 8 years ago

Now pushed a version including libmusashi.a built from the official Musashi sources. Feel free to look at the above issues, if you beat me to it.

marhel commented 8 years ago

I've now fixed andi_16_tos, eori_16_tos, ext_bw and will look into lsr_32_r shortly.

emoon commented 8 years ago

:+1: Sorry for the lack of updates from my part. Been busy with other things :/

marhel commented 8 years ago

So basically I get what I pay for, right? ;) No worries!

emoon commented 8 years ago

Pretty much :) Next week I will be in SF on a conference and some time off after that so I hope to be able to do some more things then :)