If I ever want to create a finite state machine in 8051 assembly, I'll need an efficient equivalent of C switch()
expression.
[for this question, let us disregard the fall-through behavior, both retaining and dropping it is acceptable].
There are a few ways to achieve that in 8051 assembly, but each of them has their downsides. The ones for short switches of 5-10 cases are simple enough, and clear enough, but if I want a switch of >128, or even >256 cases, things get complicated.
The first one is simple, a chain of CJNE
comparing the operand to values and jumping to next case if not equal; equivalent to if(){...}else if(){....} else if(){...}
. The upside is simplicity, the downside is obvious: in case of a long switch this will create a very long string of choices.
This can be reduced through building a binary tree, using JB
for consecutive bits of the control variable. This is still not quite efficient, very hard to maintain and makes sparse keys set difficult to implement (`case 1:...; case 5:...; case 23:...; case 118:...)
Next approach is to multiply, then jump offset. Multiply the control variable by 2, load the result into DPTR, load the accumulator with an offset, then perform a JMP @A+DPTR
into a zone preloaded with multitude of AJMP
. (or multiply by 3 and jump into zone preloaded with multitude of LJMP
. ).
I did that once. Adjusting locations of the jump instruction to the bytes was a puzzle I don't really want to repeat, plus the jump table is unnecessarily large (repeating ajmp
each other byte). Maybe I don't know some trick that would make it easy...
And there's the approach to pull an address from a dedicated table, preload the stack and perform RET
. It sounds very neat except pulling an address from a dedicated table needs to be done with the horrendous MOVC A, @A+DPTR
or MOV A, @A+PC
- these addressing modes make me wince so hard I never tried implementing it. If you know a neat way of doing this, please post that as an answer.
In general, I'd like to know if there's a more elegant, efficient way to perform a switch() style jump - one without creating too much overhead, not wasting too much memory and giving freedom of jumping at least AJMP
distance, with number of case
s going into hundreds.