1

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

JustToKnow
  • 785
  • 6
  • 23
  • 1
    Please describe why you are stuck, what your thoughts were and what approaches you had in mind that you think won't help you – CherryDT Jun 30 '20 at 07:23
  • 2
    I'm going through this and the design description has flaws. For example, both the coins and the drink selection buttons update the same memory location ($1003). So if one puts a coin while pressing a button, confusion! Remember an XIRQ will interrupt an IRQ and there is no way for the IRQ handler to prevent that. Another is it does not mention what to do with invalid coin denominations which are not counted but are silently kept? Anyway, I will ignore those issues, and give you a possible solution within those flawed requirements. – tonypdmtr Jun 30 '20 at 21:04

1 Answers1

3

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 :)

tonypdmtr
  • 3,037
  • 2
  • 17
  • 29
  • 1
    I feel like i'm 5 years old and waiting for Christmas.. i'm reading everything – JustToKnow Jun 30 '20 at 23:24
  • You wrote *#soda_counters+::soda_counters* ; you used "+::" and that's ASM11 terminology. Is it the same to use *#soda_counters+soda_counters? – JustToKnow Jun 30 '20 at 23:44
  • 1
    @Student_new No, you need to add the size of that array, that would 8 in this case. So, make a constant with value 8 and use that, or (not recommended in general) hard code it like `#soda_counters+8`. – tonypdmtr Jun 30 '20 at 23:46
  • In my case i should delete *proc* and get rid of those "@@" otherwise my program wont run it. Also, right now i'm looking into "IRQ_Handler". What is this actually doing? – JustToKnow Jun 30 '20 at 23:50
  • What the description says. When a drink selection button is pressed IRQ is triggered and the value of the button(s) goes into the corresponding register (`SODA_CHOICE`). You use that and depending on money balance and drink availability, you dispense the drink. – tonypdmtr Jun 30 '20 at 23:52
  • Sorry, i'm thinking out loud and my hands are next to the keyboard :D. Probably this is a stupid question but why did you use "equ %01000000" and "equ %00100000"? – JustToKnow Jun 30 '20 at 23:56
  • These are the definitions of those bits from the datasheet. More tomorrow, I have to call it a day. – tonypdmtr Jun 30 '20 at 23:57
  • Tony, seriously. you're amazing: just another thing: i should replace lda -> ldaa and ora ->oraa and sta -> staa. Also "def" what is actually using? Can i use "ORG" instead of that? – JustToKnow Jul 01 '20 at 00:07
  • OK, `DEF` is the same as `EQU` provided the label is not already defined (defaults to the value if not already set). So, it's not `ORG`. `LDA` is the same as `LDAA` and `ORA` is the same as `ORAA`. – tonypdmtr Jul 01 '20 at 00:19
  • Sorry, i ment EQU – JustToKnow Jul 01 '20 at 00:20
  • Yes, `DEF` is in this case same as `EQU` – tonypdmtr Jul 01 '20 at 00:20
  • Tony, i have modified your code a little bit (i have updated my question); i replaced the different *loop@@* and used *loop_1*, *loop_2*.. it works now but i had an error message related to: *The program is writing to address $01fd where no memory is located* Why? – JustToKnow Jul 01 '20 at 04:34
  • Check where your stack is supposed to be for the simulated MCU, and adjust STACKTOP (and possibly other definitions in the 'MCU specific' section) accordingly. – tonypdmtr Jul 01 '20 at 08:09