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