Menu

#210 Two inline assembly issues.

open
nobody
None
5
22 hours ago
22 hours ago
RvD
No

I am writing timer0 interrupt code to reprogram the timer0 for accurate timekeeping.
But the 8051 inside a network-switch SOC is running at high frequency of 125 MHz.

I encounter two issues.

Issue 1: Calculation is wrong inside the inline-assembly when using large numbers.

Defines and C functions.

// System frequency which is also CPU frequency
#define CLOCK_HZ 125000000
// Timer0 is divided by 12
#define TIMER0_CLK_DIV 12
// Number of Timer0 Interrupts per second.
// Minimum must be 158 because of the high clock frequency and 16-bit timer resolution.
#define SYS_TICK_HZ 200
// Number of timer0 counts needed to get SYS_TICK_HZ
#define SYSTICK_TIMER0_VALUE (CLOCK_HZ / TIMER0_CLK_DIV / SYS_TICK_HZ)

// Number of Timer0 ticks missed while reprogramming.
#define TIMER0_REPROGRAM_TIMER_TICK_COUNT (12 * 4 / TIMER0_CLK_DIV)

// Value programmed into TIMER0.
#define TIMER0_REPROGRAM_VALUE  (0x10000 - SYSTICK_TIMER0_VALUE + TIMER0_REPROGRAM_TIMER_TICK_COUNT)

// C-code
inline void update_timer0(void) __naked {
    __asm
    ; Turn off global interrupts, to ensure code below is not interrupted.
    clr _EA
    ; Store ACC, PSW both are overwritten.
    push a
    push psw
    mov a, #(TIMER0_REPROGRAM_VALUE & 0xFF)
    clr _TR0
    ; Timer0 is disables, every instruction below this line is counted as delay
    ; what the TIMER0 could advance while reprogramming.
    add a, _TL0
    mov _TL0, a
    mov a, _TH0
    addc a, #((TIMER0_REPROGRAM_VALUE >> 8) & 0xFF)
    mov _TH0, a
    setb _TR0
    ; Timer 0 is enabled again, every instruction above this line is counted as delay.
    ; Restore PSW, ACC
    pop psw
    pop a
    ; Turn on global interrupts.
    setb _EA
    __endasm;
}

// Interrupt handler
void isr_timer0(void) __interrupt(1)
{
    update_timer0();

    ticks++;
    if (sleep_ticks > 0)
        sleep_ticks--;
    sec_counter++;

}

SYSTICK_TIMER0_VALUE should be 52083.
TIMER0_REPROGRAM_VALUE is 13457 or 0x3491

But assembly below shows that 0xF3B7 is programmed into TIMER0.

    000019 74 B7            [12]  783   mov a, #(((0x10000 - (125000000 / 12 / 200)) + (12 * 4 / 12)) & 0xFF)
      00001B C2 8C            [12]  784     clr _TR0
                                    785 ;   Timer0 is disables, every instruction below this line is counted as delay
                                    786 ;   what the TIMER0 could advance while reprogramming.
      00001D 25 8A            [12]  787     add a, _TL0
      00001F F5 8A            [12]  788     mov _TL0, a
      000021 E5 8C            [12]  789     mov a, _TH0
      000023 34 F3            [12]  790     addc    a, #((((0x10000 - (125000000 / 12 / 200)) + (12 * 4 / 12)) >> 8) & 0xFF)

When replacing TIMER0_REPROGRAM_VALUE with (0x10000 - 52083 + TIMER0_REPROGRAM_TIMER_TICK_COUNT) the values are fine.

  000019 74 91            [12]  783     mov a, #((0x10000 - 52083 + (12 * 4 / 12)) & 0xFF)
      00001B C2 8C            [12]  784     clr _TR0
                                    785 ;   Timer0 is disables, every instruction below this line is counted as delay
                                    786 ;   what the TIMER0 could advance while reprogramming.
      00001D 25 8A            [12]  787     add a, _TL0
      00001F F5 8A            [12]  788     mov _TL0, a
      000021 E5 8C            [12]  789     mov a, _TH0
      000023 34 34            [12]  790     addc    a, #(((0x10000 - 52083 + (12 * 4 / 12)) >> 8) & 0xFF)

Do I something wrong?

Issue 2: When use any inline assembly, SDCC wants sdcc_atomic_exchange_rollback_start.

Why is this needed because I can't find any documentation and can I disable this?
Because I don't want extra code inside my interrupt function.

I added this to crtstart.asm as a workaround.

sdcc_atomic_exchange_rollback_start::
    ret

sdcc_atomic_exchange_rollback_end::
    ret

I am no problem moving inline-assembly update_timer0() to crtstart.asm.
But I am struggling how to use defines from C into asm-files.

I am using SDCC : mcs51/z80/z180/r2k/r2ka/r3ka/sm83/tlcs90/ez80_z80/z80n/r800/ds390/TININative/ds400/hc08/s08/stm8/pdk13/pdk14/pdk15/mos6502/mos65c02/f8 TD- 4.5.0 #15242 (Linux) from debian 13.

Discussion


Log in to post a comment.