assembly68hc11

Interrupts IQR and XIRQ - assembly


I've been struggling with a topic related to IRQ (interrupts itself); i'm using an old MC68HC11

Been practicing for a while; i decided to move on and check the hardest exercises showed in this chapter that's why i found an interesting one (and a little tricky tbh)

Take a look at this:

Problem

This is what i tried so far (This is just an outline):

Do NOTE:

FLAGNMI means XIRQ

FLAGIQR means IRQ

IRQ                 EQU     $FFF2
XIRQ                EQU     $FFF4
RESET               EQU     $FFFE
RWM                 EQU     $0000
ROM                 EQU     $C000
LEDS                EQU     $1004
VARIABLE            EQU     $1003
MECHANICAL_SEAL     EQU     $0080
CONFIG              EQU     $1039


                    CLR     VALUE
                    CLR     BALANCE
                    CLR     PRICE_SODA
                    TPA
                    ANDA    #(MASKNMI&MASKIRQ)
                    TAP
                    LDAA    CONFIG
                    ORAA    #MASKEDGE
                    STAA    CONFIG
                    CLR     FLAGIRQ
                    CLR     FLAGNMI
                    LDAA    #$00
                    STAA    REMAINING_MONEY
                    LDAA    #$FF
                    STAA    LEDS
                    
                    
Main                
                    LDAA    FLAGNMI
                    BNE     COINS   
                    CLR     FLAGNMI
                    LDAA    FLAGIRQ
                    BEQ     Main
                    CLR     FLAGIRQ 
                    JSR     DRINKS
                    BRA     Main

I got stuck right here; i can imagine a few ways to solve it using C but that's not gonna help me a lot (not in assembly).

Can help me?

EDIT:

;*******************************************************************************
; MCU specific
;*******************************************************************************

REGS                equ       $1000               ;register base
PORTB               equ       REGS+$04            ;port B (output only)
PORTC               equ       REGS+$03            ;port C
OPTION              equ       REGS+$39            ;System Configuration Options
STACKTOP            equ       $01FF               ;Top of Stack
RAM                 equ       $0040               ;beginning of RAM
ROM                 equ       $F800               ;beginning of ROM

Virq                equ       $FFF2               ;IRQ vector
Vxirq               equ       $FFF4               ;XIRQ vector
Vreset              equ       $FFFE               ;reset vector

X.                  equ       %01000000           ;XIRQ disable
IRQE.               equ       %00100000           ;IRQ Edge sensitive

;*******************************************************************************
; Application specific
;*******************************************************************************

LED                 equ       PORTB               ;bitmap of LED
COIN                equ       PORTC               ;coin value is here
SODA_CHOICE         equ       PORTC               ;drink choice as bitmap
SODA_PULSES         equ       $0080               ;bitmap of soda pulses

INITIAL_DRINKS      equ       4                   ;number of initial drinks
DRINK_COST          equ       20                  ;drink cost in dollars

NOT                 equ       $FF                 ;XOR value to invert bits
;*******************************************************************************
                    org       RAM
;*******************************************************************************

soda_counters       rmb       8                   ;array of soda counters
money_total         rmb       2                   ;keeps money in machine

;*******************************************************************************
                    org       ROM
;*******************************************************************************

Start               
                    lds       #STACKTOP
                    bsr       InitMachine

                    tpa
                    anda      #X.^NOT             ;enable XIRQ interrupts
                    tap

                    ldaa       OPTION
                    oraa       #IRQE.              ;make IRQ edge sensitive
                    staa       OPTION

Loop_a              cli                           ;enable interrupts
                    wai                           ;low power mode until interrupt
                    bra       Loop_a              ;endless loop (all work is done in interrupt handlers)

;*******************************************************************************

InitMachine         
          ;-------------------------------------- ;assume INITIAL_DRINKS of each type
                    ldx       #soda_counters      ;X -> drink counters
                    ldaa      #INITIAL_DRINKS     ;A = number of drinks initially
Loop_1              staa      ,x                  ;update current counter
                    inx                           ;X -> next drink counter
                    cpx       #soda_counters+8
                    blo       Loop_1              ;repeat for all drink counters
                    bsr       AdjustLeds          ;adjust LED indicators
          ;--------------------------------------
                    clra
                    clrb
                    std       money_total         ;zero initial money balance
                    rts

;*******************************************************************************

AdjustLeds          
                    ldx       #soda_counters      ;X -> soda counters
                    clra                          ;bit mask of soda LED
Loop_2             tst       ,x                  ;test current soda counter
                    clc                           ;assume a zero
                    beq       Cont_1              ;if zero, go put a zero in the mask
                    sec                           ;else we'll put a one in the mask
Cont_1             rora                          ;shift in zero/one bit for this LED
                    inx                           ;X -> next soda counter
                    cpx       #soda_counters+8
                    blo       Loop_2              ;repeat for all counters
                    staa      LED                 ;update the LED accordingly
                    rts

;*******************************************************************************

AllowOneDrinkOnly   
                    pshx
                    pshb
                    psha

                    ldx       #8                  ;number of bits in a byte
                    clrb                          ;initialize bit counter
Loop_3              lsra                          ;drink choice into CCR[C]
                    bcc       Cont_2              ;skip zeros
                    incb                          ;count this choice
Cont_2              dex                           ;one less bit to ess
                    bne       Loop_3              ;repeat for all bits

                    cmpb      #1                  ;do we have only one drink?
                    bls       Done_1             ;if so, we're done

                    pula
                    clra                          ;else zero caller's RegA (drinks)
                    psha

Done_1              pula
                    pulb
                    pulx
                    rts

;*******************************************************************************

PulseDelay          
                    psha
                    clra
Loop_4              deca
                    bne       Loop_4
                    pula
                    rts

;*******************************************************************************

IRQ_Handler         
                    ldd       money_total         ;D = available money
                    cpd       #DRINK_COST         ;is it enough for a drink?
                    blo       Done_2             ;if less, ignore request

                    ldaa      SODA_CHOICE         ;A = drink choice
                    bsr       AllowOneDrinkOnly   ;A = validated drink choice (zero if more than one)
                    bita      LED                 ;is the drink available (LED on)?
                    beq       Done_2              ;if not, ignore request
          ;-------------------------------------- ;deliver drink
                    staa      SODA_PULSES         ;start selected drink pulse
                    bsr       PulseDelay          ;arbitrary delay for the pulse
                    clr       SODA_PULSES         ;stop all drink pulses
          ;-------------------------------------- ;count down the available drinks
                    ldx       #soda_counters
Loop_5             lsra                          ;move choice into CCR[C]
                    bcc       Cont_3             ;if not this one, continue
                    dec       ,x                  ;one less drink
                    ldd       money_total         ;D = previous money balance
                    subd      #DRINK_COST         ;less the drink value
                    std       money_total         ;update money balance
                    ldx       #soda_counters+8 ;will cause termination of loop (by making X too large)
Cont_3              inx
                    cpx       #soda_counters+8
                    blo       Loop_5
                    bsr       AdjustLeds          ;adjust LED indicators
          ;--------------------------------------
Done_2              rti

;*******************************************************************************

XIRQ_Handler        
                    ldab      COIN                ;B = value of inserted coin

                    cmpb      #1                  ;1 is allowed value
                    beq       Accept_1

                    cmpb      #2                  ;2 is allowed value
                    beq       Accept_1

                    cmpb      #5                  ;5 is allowed value
                    beq       Accept_1

                    cmpb      #10                 ;10 is allowed value
                    beq       Accept_1

          ; What do we do with all other coins?

                    bra       Done_3              ;get out of here
          ;-------------------------------------- ;update money in machine
Accept_1            clra
                    addd      money_total         ;add inserted money to total
                    bcs       Done_3              ;on (unlikely) overflow, ignore
                    std       money_total
          ;--------------------------------------
Done_3              rti

;*******************************************************************************
                    org       Virq
                    dw        IRQ_Handler

                    org       Vxirq
                    dw        XIRQ_Handler

                    org       Vreset
                    dw        Start
;*******************************************************************************

Errors:

errors


Solution

  • OK, here it is, TOTALLY UNTESTED but should give you the idea!

    Assumptions: IRQ input is debounced, IRQ is edge triggered (so it won't repeat for the same key press), and XIRQ pulse will be shorter than the time it takes to execute the corresponding handler to avoid counting the same money twice or more.

    Like I said in the comment, the design is somewhat flawed as given, but if we ignore this and assume corner cases won't happen, here's one possibility:

        ;*******************************************************************************
    ; MCU specific
    ;*******************************************************************************
    
    REGS                equ       $1000               ;register base
    PORTB               equ       REGS+$04            ;port B (output only)
    PORTC               equ       REGS+$03            ;port C
    OPTION              equ       REGS+$39            ;System Configuration Options
    STACKTOP            equ       $01FF               ;Top of Stack
    RAM                 equ       $0040               ;beginning of RAM
    ROM                 equ       $F800               ;beginning of ROM
    
    Virq                def       $FFF2               ;IRQ vector
    Vxirq               def       $FFF4               ;XIRQ vector
    Vreset              equ       $FFFE               ;reset vector
    
    X.                  equ       %01000000           ;XIRQ disable
    IRQE.               equ       %00100000           ;IRQ Edge sensitive
    
    ;*******************************************************************************
    ; Application specific
    ;*******************************************************************************
    
    LED                 equ       PORTB               ;bitmap of LED
    COIN                equ       PORTC               ;coin value is here
    SODA_CHOICE         equ       PORTC               ;drink choice as bitmap
    SODA_PULSES         equ       $0080               ;bitmap of soda pulses
    
    INITIAL_DRINKS      equ       4                   ;number of initial drinks
    DRINK_COST          equ       20                  ;drink cost in dollars
    
    NOT                 equ       $FF                 ;XOR value to invert bits
    ;*******************************************************************************
                        org       RAM
    ;*******************************************************************************
    
    soda_counters       rmb       8                   ;array of soda counters
    money_total         rmb       2                   ;keeps money in machine
    
    ;*******************************************************************************
                        org       ROM
    ;*******************************************************************************
    
    Start               proc
                        lds       #STACKTOP
                        bsr       InitMachine
    
                        tpa
                        anda      #X.^NOT             ;enable XIRQ interrupts
                        tap
    
                        lda       OPTION
                        ora       #IRQE.              ;make IRQ edge sensitive
                        sta       OPTION
    
    Loop@@              cli                           ;enable interrupts
                        wai                           ;low power mode until interrupt
                        bra       Loop@@              ;endless loop (all work is done in interrupt handlers)
    
    ;*******************************************************************************
    
    InitMachine         proc
              ;-------------------------------------- ;assume INITIAL_DRINKS of each type
                        ldx       #soda_counters      ;X -> drink counters
                        ldaa      #INITIAL_DRINKS     ;A = number of drinks initially
    Loop@@              staa      ,x                  ;update current counter
                        inx                           ;X -> next drink counter
                        cpx       #soda_counters+::soda_counters
                        blo       Loop@@              ;repeat for all drink counters
                        bsr       AdjustLeds          ;adjust LED indicators
              ;--------------------------------------
                        clra
                        clrb
                        std       money_total         ;zero initial money balance
                        rts
    
    ;*******************************************************************************
    
    AdjustLeds          proc
                        ldx       #soda_counters      ;X -> soda counters
                        clra                          ;bit mask of soda LED
    Loop@@              tst       ,x                  ;test current soda counter
                        clc                           ;assume a zero
                        beq       Cont@@              ;if zero, go put a zero in the mask
                        sec                           ;else we'll put a one in the mask
    Cont@@              rora                          ;shift in zero/one bit for this LED
                        inx                           ;X -> next soda counter
                        cpx       #soda_counters+::soda_counters
                        blo       Loop@@              ;repeat for all counters
                        staa      LED                 ;update the LED accordingly
                        rts
    
    ;*******************************************************************************
    
    AllowOneDrinkOnly   proc
                        pshx
                        pshb
                        psha
    
                        ldx       #8                  ;number of bits in a byte
                        clrb                          ;initialize bit counter
    Loop@@              lsra                          ;drink choice into CCR[C]
                        bcc       Cont@@              ;skip zeros
                        incb                          ;count this choice
    Cont@@              dex                           ;one less bit to process
                        bne       Loop@@              ;repeat for all bits
    
                        cmpb      #1                  ;do we have only one drink?
                        bls       Done@@              ;if so, we're done
    
                        pula
                        clra                          ;else zero caller's RegA (drinks)
                        psha
    
    Done@@              pula
                        pulb
                        pulx
                        rts
    
    ;*******************************************************************************
    
    PulseDelay          proc
                        psha
                        clra
    Loop@@              deca
                        bne       Loop@@
                        pula
                        rts
    
    ;*******************************************************************************
    
    IRQ_Handler         proc
                        ldd       money_total         ;D = available money
                        cpd       #DRINK_COST         ;is it enough for a drink?
                        blo       Done@@              ;if less, ignore request
    
                        ldaa      SODA_CHOICE         ;A = drink choice
                        bsr       AllowOneDrinkOnly   ;A = validated drink choice (zero if more than one)
                        bita      LED                 ;is the drink available (LED on)?
                        beq       Done@@              ;if not, ignore request
              ;-------------------------------------- ;deliver drink
                        staa      SODA_PULSES         ;start selected drink pulse
                        bsr       PulseDelay          ;arbitrary delay for the pulse
                        clr       SODA_PULSES         ;stop all drink pulses
              ;-------------------------------------- ;count down the available drinks
                        ldx       #soda_counters
    Loop@@              lsra                          ;move choice into CCR[C]
                        bcc       Cont@@              ;if not this one, continue
                        dec       ,x                  ;one less drink
                        ldd       money_total         ;D = previous money balance
                        subd      #DRINK_COST         ;less the drink value
                        std       money_total         ;update money balance
                        ldx       #soda_counters+::soda_counters ;will cause termination of loop (by making X too large)
    Cont@@              inx
                        cpx       #soda_counters+::soda_counters
                        blo       Loop@@
                        bsr       AdjustLeds          ;adjust LED indicators
              ;--------------------------------------
    Done@@              rti
    
    ;*******************************************************************************
    
    XIRQ_Handler        proc
                        ldab      COIN                ;B = value of inserted coin
    
                        cmpb      #1                  ;1 is allowed value
                        beq       Accept@@
    
                        cmpb      #2                  ;2 is allowed value
                        beq       Accept@@
    
                        cmpb      #5                  ;5 is allowed value
                        beq       Accept@@
    
                        cmpb      #10                 ;10 is allowed value
                        beq       Accept@@
    
              ; What do we do with all other coins?
    
                        bra       Done@@              ;get out of here
              ;-------------------------------------- ;update money in machine
    Accept@@            clra
                        addd      money_total         ;add inserted money to total
                        bcs       Done@@              ;on (unlikely) overflow, ignore
                        std       money_total
              ;--------------------------------------
    Done@@              rti
    
    ;*******************************************************************************
                        org       Virq
                        dw        IRQ_Handler
    
                        org       Vxirq
                        dw        XIRQ_Handler
    
                        org       Vreset
                        dw        Start
    ;*******************************************************************************
    

    Now, I want a free soda for my work :)