Implementing Switch statements for the 8051

Jan 02, 2007 6 Replies

Hello Everyone, I am basically implementing the equivelent to a switch statement in C for my 8051 in assembly. There are multiple ways to implement a switch statement in assembly, however, I keep cornering myself into a statement like the following:



MOV A,CASE_LOCATION CJNE A,#CASE1_CONST,TRY_CASE2 LJMP CASE1



TRY_CASE2: CJNE A,#CASE2_CONST,TRY_CASE3 LJMP CASE2



and so on. The readability of this statement is bad, so I have devised a case statement of this nature



MOV A,CASE_LOCATION MOV R0,A ; Multiply A by 3 because LJMP is 3 bytes long RL A ADD A,R0 MOV DPTR,#CASE_TABLE JMP @A+DPTR



CASE_TABLE: LJMP CASE1 LJMP CASE2 LJMP CASE3



I am an not 100% sure this is correct, however, this thread is not to belabor the correctness of this switch statement syntax, but to discover the "best" way to implement a switch statement in 8051. I know finding the "best" switch statement is subjective but what are some ways people are doing implementing switch statements in 8051 assembly?



Thanks, Lloyd Rochester

formatting link



On 2 Jan 2007 15:26:40 -0800, "nfirtaps" wrote in comp.arch.embedded:

What you show above only works if the possible switch values are contiguous, with no gaps. This may not be entirely correct, because I am doing it from memory at home, and I've mostly avoided 8051 assembly language for 10 years or so, but something like this:

switch_table: db num_cases db first_case dw first_address db second_case dw second_address

; and so on..l

db last_case dw last_address dw default_address

Then I have a subroutine, called with dp pointing to switch_table, and the comparison value in another register, and it goes something like this in pseudo code, because I don't remember 8051 assembly mnemonics very well:

read first byte (case count) from code memory via dp into a move case count to another register increment dp (point to first case value)

loop: read byte from code memory into a via dp increment dp compare a with compare value register

go_go: if equal: read code memory @dp into a push a increment dp read code memory @dp into a push a return else: (compare not equal) increment dp increment dp decrement case count if case count not 0: jump to loop else: (case count is 0) jump to go_go

This was a modification of a routine I originally developed for the Z80 about a quarter century ago. There can be any number of cases, and a default. The cases don't have to be consecutive values, and don't have to be in any particular order, allowing you to put the most commonly used ones earlier in the table. It overcomes the inability of the 8051 to (easily) execute code out of RAM by pushing the address to jump to onto the stack, so a return instruction actually performs the jump.

Jack Klein Home: http://JK-Technology.Com FAQs for comp.lang.c http://c-faq.com/ comp.lang.c++ http://www.parashift.com/c++-faq-lite/alt.comp.lang.learn.c-c++ http://www.contrib.andrew.cmu.edu/~ajo/docs/FAQ-acllc.html

Using the SesAsm51 assembler you may do it this way:

MOV A, CASE_LOC CJE A, #CASE1_CNST, CASE1 CJE A, #CASE2_CNST, CASE2 CJE A, #CASE3_CNST, CASE3 ... JMP DEFAULT

Jorgen

... snip code ...

On the 8080/z80 I used to do roughly the following:

; call ath entry in table hl. ; a,f,h,l (disturbed)

execix: add a; double, word address add l mov l,a mvi a,0; don't disturb carry adc h mov h,a pchl; can be push h | ret. much slower.

main code fragment, a holds index needed: lxi h,tbl call execix ....

tbl: dw case0 dw case1 ... maxtbl equ ($ - tbl) / 2

Chuck F (cbfalconer at maineline dot net) Available for consulting/temporary embedded and systems.

[...] you mentioned the "sequence of tests", and the "jump table" approach. Some of the more important ones you didn't mention are the decision tree and the hash-mapped jump table.

There's no such thing. As with most, if not all, truly interesting questions the answer is: "It depends." Here it depends on the exact set of cases you want to switch() among. Short, tight sequences demand different strategies than a set of 200 numbers more-or-less randomly spread across the range of an unsigned 16-bit integers.

In other words the only answer you should remember is that no single answer is correct for this question. You have to know a selection of different answers to apply in different situations. It's called a "tool chest" because there's more than one tool in it.

This is pretty much the standard jump table method of doing a switch table. If you look at the output of most C compilers for the 8051 you will see they produce pretty much the same code as this for a switch statement.

ian

; carry for bad call

execix: cmp m rc; out of range. inx h

jc errorhandler; optional

; Maximum 128 entries. 0 through 127. tbl: db maxtbl

Minor correction to 8080 code to detect argument out of range. We could also detect excessive maxtbl value at assembly time with a pseudo op here. The code could nest cases.

Chuck F (cbfalconer at maineline dot net) Available for consulting/temporary embedded and systems.

Join the Discussion

Have something to add? Share your thoughts — no account required.

Didn't find your answer?

Ask the community — no account required