Actually.... an online friend of mine had a very efficient use of goto in his NES emulator:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
switch (cpu.opcode)
{
case lda_imm:
get_imm();
goto lda;
case lda_zp:
get_zp():
goto lda;
case adc_imm:
get_imm();
goto adc;
lda: /* do stuff */
break;
adc: /* do stuff */
break;
}
|
The first time I looked at this I was like "wtf, goto?", but as I thought about it, it started to make more and more sense.
*) There are 256 opcodes (256 cases in that switch) but most of them are different addressing modes of the same instruction. IE: ADC immediate vs. ADC absolute.
*) As this is a CPU emulator, it will run this switch statement hundreds of thousands of times per second, so it needs to be quick.
*) ADC/LDA/etc instructions all have the same code in them, so repeating the same code multiple times is no good.
*) Putting ADC/LDA/etc code in separate (non-inline) functions has a lot of unnecessary overhead.
*) Putting ADC/LDA/etc code in inline functions inflates code size, potentially slowing it down (remember that this switch is going to have 256 cases -- if you're inlining both the addressing mode code as well as the instruction code it'll be huge)
*) Goto allows you to share code while keeping the switch size minimal, and without adding the overhead of function calls.
So it just goes to show you. Don't write off a language feature just because it's "evil". Here, it's actually not that bad of an idea.
Although now I wonder if another switch statement would be better....
oh well that's a topic for another forum!