Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

ASM - if_then routine - any better way of doing?

Status
Not open for further replies.

augustinetez

Active Member
Just curious as to whether there might be a better way of doing IF_THEN routines in ASM as opposed to below code.

Background:

Processor is 16F628A - already set from an old project so not changeable (at this stage).

The routine is to select a group of 4 bytes from a table of 16 bytes depending in the inputs RA6 & 7 (switches), 4 options available.

The code below is only performed once on power-up to set a selected value.

There is a bit of jiggery-pokery (not shown) to shift what are bits 6 & 7 of PORTA to bits 0 & 1 of the IF_index register (so I don't have to count higher than 3 :D )

The code within the ////////////////////////// marks are what I have used before in other projects and am asking about.

Once this routine has been performed, it drops through to more set-up code for other variables.

Code:
; Using RA6 & 7 input data, obtain the if_table entry and
; copy IF offset from table and store in ioff_3..0
;
        clrf    temp              ; Clear the temp variable
        movlw   FREQ_COUNT        ; There are four bytes to copy
        movwf   count             ; Set up count variable
        movlw   ioff_0            ; Get target address
        movwf   FSR               ; Store in pointer register

;////////////////////////////////////////////////////////////////////////////////

    movf    IF_index,f
    btfsc    STATUS,Z
    goto    get_if_loop       ; If IF_index is '0' get values from table starting at index 0

    movfw    IF_index    ;
    xorlw    1
    btfsc    STATUS,Z
    goto    index_1              ; If IF_index is '1' get values from table starting at index 4

    movfw    IF_index    ;
    xorlw    2
    btfsc    STATUS,Z
    goto    index_2             ; If IF_index is '2' get values from table starting at index 8

    movfw    IF_index    ;
    xorlw    3
    btfsc    STATUS,Z
    goto    index_3             ; If IF_index is '3' get values from table starting at index 12
    clrf    temp                    ; Error checking - if index value is other than 0->3
    goto    get_if_loop        ; set index to 0

index_1
    movlw    d'4'
    movwf   temp
    goto    get_if_loop    ;

index_2
    movlw    d'8'
    movwf   temp
    goto    get_if_loop    ;

index_3
    movlw    d'12'
    movwf   temp

;////////////////////////////////////////////////////////////////////////////////

get_if_loop
        movf    temp,w            ; Get the if_table index into W
        call    if_table          ; Get a if_table byte
        movwf   INDF              ; Store it into ioff_3..0
        incf    FSR,f             ; Point to next higher offset byte, ioff_0..3
        incf    temp,f            ; Increment table index
        decfsz  count,f           ; Decrement loop count
        goto    get_if_loop       ; loop while more bytes remain
 
Mapping the value of IF_index to the value that is in temp gives,
0 = 0
1 = 4
2 = 8
3 = 12

Can't you just shift left twice? I.E. multiply by 4. Or the original value (bits 6 & 7) right three times?

Mike.
 
Mapping the value of IF_index to the value that is in temp gives,
0 = 0
1 = 4
2 = 8
3 = 12

Can't you just shift left twice? I.E. multiply by 4. Or the original value (bits 6 & 7) right three times?

Mike.

I would have done something like that, or just this:-
Code:
        clrf     temp
        btfsc    PORTA, 6
        bsf      temp, 2
        btfsc    PORTA, 7
        bsf      temp, 3
 
Last edited:
I would have done something like that, or just this:-
Code:
        clrf     temp
        btfsc    PORTA, 6
        bsf      temp, 2
        btfsc    PORTA, 7
        bsf      temp, 3

I've just realised that there is a considerably more concise option:-
Code:
       swapf    PORTA, w
       andlw    0b1100 
       movwf    temp
I realise that this is very specific to this situation. Any change of port pins or need for any other type of lookup spacing would not work.
 
Found the bug - was me :eek: - the program has so many defines included for various functions to be enabled or not, I kept following the wrong line.

Because the program is being used by and possibly the table modified by someone else, I stayed with my original code.

It will be easier for any remote fault finding if needed.
 
This version of the code loads the index value into the W register and uses it to calculate the address of the appropriate entry in the lookup table. The lookup table consists of 16 consecutive entries, each containing the appropriate offset value for the corresponding switch settings. The table is defined as a series of retlw instructions, which return the appropriate value to the W register.

By using a lookup table, we eliminate the need for conditional jumps, making the code simpler and easier to follow. Additionally, the use of the PCLATH and PCL registers to jump to the appropriate entry in the table allows us to perform the lookup operation in just a few instructions, rather than using a separate conditional jump for each possible index value.


; Using RA6 & 7 input data, obtain the if_table entry and
; copy IF offset from table and store in ioff_3..0

clrf temp ; Clear the temp variable
movlw FREQ_COUNT ; There are four bytes to copy
movwf count ; Set up count variable
movlw ioff_0 ; Get target address
movwf FSR ; Store in pointer register

movf IF_index, w ; Load the index value into W
movlw HIGH if_table ; Load the upper byte of the table address into W
movwf PCLATH ; Store it in the program counter latch
addwf IF_index, f ; Add the index value to the upper byte
movlw LOW if_table ; Load the lower byte of the table address into W
movwf PCL ; Jump to the table entry

if_table
retlw ioff_0 ; Entry 0
retlw ioff_1 ; Entry 1
retlw ioff_2 ; Entry 2
retlw ioff_3 ; Entry 3
retlw ioff_0 ; Entry 4
retlw ioff_1 ; Entry 5
retlw ioff_2 ; Entry 6
retlw ioff_3 ; Entry 7
retlw ioff_0 ; Entry 8
retlw ioff_1 ; Entry 9
retlw ioff_2 ; Entry 10
retlw ioff_3 ; Entry 11
retlw ioff_0 ; Entry 12
retlw ioff_1 ; Entry 13
retlw ioff_2 ; Entry 14
retlw ioff_3 ; Entry 15

; Copy values from the lookup table into ioff_3..0
get_if_loop
movf INDF, w ; Get the value from the lookup table
movwf INDF ; Store it into ioff_3..0
incf FSR, f ; Point to the next offset byte, ioff_0..3
incf temp, f ; Increment the table index
decfsz count, f ; Decrement the loop count
goto get_if_loop ; Loop while more bytes remain
 
I do much the same but the table is near the start of the program, it is in the same page as the code that calls it so no need for the PCLATH command.

I didn't include it in my code above as it wasn't relative to my query.

Here it is for completeness - laying it out as 'dt' commands makes it easier to understand each group of offsets and takes up less space on the screen. It assembles as a series 'retlw' commands, same as your code.

The 0-3 etc are the entries into the table while the '00' '01' etc are the values of RA6 & 7 that need to be translated into the index value at the start of each line.

Code:
if_table
    addwf   PCL,f
    dt    0x00, 0X12, 0x7A, 0x00    ; + 8MHz    0-3    00
    dt    0xD0, 0X59, 0x99, 0x00    ; + 10.050MHz    4-7    01
    dt    0xC0, 0X60, 0xBB, 0x00    ; + 12.28MHz    8-11    10
    dt    0x40, 0x54, 0x89, 0x00    ; + 9.00MHz    12-15    11
 
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top