; Chapter 4 9S12C32 assembly language programs ; Jonathan W. Valvano, 2/07/07 ; This software accompanies the book, ; Embedded Microcomputer Systems: Real Time Interfacing, Second Edition ; published by Thomson Engineering, 2006 ; Second rmb 2 Temporary global variable ; Input parameters: Reg X,Y contain 2 16 bit numbers ; Output parameter: Reg X is returned with the average AVE sty Second ;Save the second number in memory xgdx ;Reg D contains first number addd Second ;Reg D=First+Second lsrd ;(First+Second)/2 adcb #0 ;round up? adca #0 xgdx rts ; Program 4.1. This subroutine is nonreentrant because of the read-modify-write access to a global. Money rmb 2 ;bank balance implemented as a global ; add $100 to the account more ldd Money ;where Money is a global variable addd #100 std Money ;Money=Money+100 rts ; Program 4.2. This subroutine is also nonreentrant because of the read-modify-write access to a global. temp rmb 2 ;temporary result implemented as a global ; calculate RegX=RegX+2*RegD mac stx temp ;Save X so that it can be added lsld ;RegD=2*RegD addd temp ;RegD=RegX+2*RegD xgdx ;RegX=RegX+2*RegD rts ; Program 4.4. This assembly subroutine is nonreentrant because of the write-read access to a global. Info rmb 4 ;32-bit data implemented as a global ; set the variable using RegX and RegY set stx Info ;Info is a 32 bit global variable sty Info+2 rts ; Program 4.6. This assembly subroutine is nonreentrant because of the multi-step write access to a global. ; Input parameters: Reg X,Y contain 2 16 bit numbers ; Output parameter: Reg X is returned with the average AVE pshy ;Save the second number on the stack tsy ;Reg Y points the Second number xgdx ;Reg D contains first number addd 0,Y ;Reg D=First+Second lsrd ;(First+Second)/2 adcb #0 ;round up? adca #0 xgdx puly rts ; Program 4.8. This assembly subroutine is reentrant because it does not write to any globals. Status rmb 1 ;0 means empty, -1 means it contains something Message rmb 1 ;data to be communicated ; Input parameter: Reg B contains an 8 bit message ; Output parameter: Reg CC (C bit) is 1 for OK, 0 for busy error SEND tst Status ;check if mailbox is empty bmi Busy ;full, can't store, so return with C=0 stab Message ;store dec Status ;signify it is now contains a message sec ;stored OK, so return with C=1 Busy rts ; Program 4.9. This assembly subroutine is nonreentrant because of the read-modify-write access to a global. Status rmb 1 ;0 means empty, -1 means it contains something Message rmb 1 ;data to be communicated ; Input parameter: Reg B contains an 8 bit message ; Output parameter: Reg CC (C bit) is 1 for OK, 0 for busy error SEND clc ;Initialize carry=0 tpa ;save current interrupt state psha sei ;disable interrupts during vulnerable window tst Status ;check if mailbox is empty bmi Busy ;full, so return with C=0 staa Message ;store dec Status ;signify it is now contains a message pula oraa #1 ;OK, so return with C=1 psha Busy pula ;restore interrupt status tap rts ; Program 4.10. This assembly subroutine is reentrant because it disables interrupts during the critical section. ; Global parameter: Semi4 is the memory location to test and set ; If the location is zero, it will set it (make it -1) ; and return Reg CC (Z bit) is 1 for OK ; If the location is nonzero, it will return Reg CC (Z bit) = 0 Semi4 fcb 0 ;Semaphore is initially free Tas tst Semi4 ;check if already set bne Out ;busy, operation failed, so return with Z=0 dec Semi4 ;signify it is now busy bita #0 ;operation successful, so return with Z=1 Out rts ; Program 4.12. This assembly subroutine can be used as part of a binary semaphore. GetPt rmb 2 ;Pointer to oldest data PutPt rmb 2 ;Pointer to free memory ; Call by value with RegA Fifo_Put ldx PutPt ;place to put next staa 1,x+ ;Store data into FIFO stx PutPt ;Update pointer ldaa #-1 ;success rts ; Call by reference with RegX Fifo_Get ldy GetPt ;place to remove next ldaa 1,y+ ;Read data from FIFO staa 0,x ;return by reference sty GetPt ;Update pointer ldaa #-1 ;success rts ; Program 4.13. Code fragments showing the basic idea of a FIFO. ;Two–pointer implementation of the FIFO FIFOSIZE equ 10 ;can hold 9 elements PutPt rmb 2 ;where to put next GetPt rmb 2 ;where to get next Fifo rmb FIFOSIZE Fifo_Init ldx #Fifo tpa ;make atomic sei ;critical section stx PutPt stx GetPt ;Empty tap ;end critical section rts ;******Put a byte into the FIFO****** ;Input RegA is 8-bit data to put ;Output RegA is -1 if ok, 0 if full Fifo_Put ldx PutPt ;Temporary staa 1,x+ ;Try to put data cpx #Fifo+FIFOSIZE bne PutNoWrap ldx #Fifo ;Wrap PutNoWrap clra cpx GetPt ;Full if same beq PutDone coma ;-1 means OK stx PutPt PutDone rts ;*******Get a byte from the FIFO******* ; Input RegX place for 8-bit data ; Output RegA is -1 if ok, 0 if empty Fifo_Get clra ;assume it will fail ldy GetPt cpy PutPt ;Empty if the same beq GetDone coma ;RegA=-1 means OK ldab 1,y+ ;Data from FIFO stab 0,x ;Return by reference cpy #Fifo+FIFOSIZE bne GetNoWrap ldy #Fifo ;Wrap GetNoWrap sty GetPt GetDone rts ; Program 4.14. Two pointer implementation of a FIFO. ; Pointer, counter implementation FIFOSIZE equ 10 ;can hold 10 PutPt rmb 2 ;where to put next GetPt rmb 2 ;where to get next Size rmb 1 ;empty if Size=0 Fifo rmb FIFOSIZE Fifo_Init ldx #Fifo tpa ;make atomic sei ;critical section stx PutPt stx GetPt ;Empty clr Size tap ;end critical section rts ********Put a byte into the FIFO******* * Input RegA contains 8-bit data to put * Output RegA is -1 if ok, 0 if full Fifo_Put pshc ;save old CCR sei ;make atomic ldab Size cmpb #FIFOSIZE ;Full ? bne PNotFull clra bra PutDone PNotFull inc Size ;one more element ldx PutPt staa 1,x+ ;Put data into fifo cpx #Fifo+FIFOSIZE bne PutNoWrap ldx #Fifo ;Wrap PutNoWrap ldaa #-1 ;success means OK stx PutPt PutDone pulc ;end critical section rts *****Get a byte from the FIFO******** * Input RegX points to place for data * Output RegA is -1 if ok, 0 if empty Fifo_Get pshc ;save old CCR sei ;critical section clra ;assume it will fail tst Size beq GetDone dec Size ;one less element ldy GetPt coma ;RegA=-1 means OK ldab 1,y+ ;Data from FIFO stab 0,x ;Return by reference cpy #Fifo+FIFOSIZE bne GetNoWrap ldy #Fifo ;Wrap GetNoWrap sty GetPt GetDone pulc ;end critical section rts ; Program 4.15 Implementation of a two-pointer with counter FIFO. ; Index,counter implementation of the FIFO FifoSize equ 10 ;Number of 8 bit data in the Fifo PutI rmb 1 ;Index of where to put next GetI rmb 1 ;Index of where to get next Size rmb 1 ; FIFO is empty if Size=0 ; FIFO is full if Size=FifoSize Fifo rmb FifoSize ;The statically allocated fifo data ;**********Initialize FIFO****************** ; No parameters InitFifo tpa sei ;make atomic, entering critical section clr PutI clr GetI clr Size ;Empty when Size == 0 tap ;end critical section rts ; ;***********Put a byte into the FIFO****************** ; Input RegA contains 8 bit data to put ; Output RegA is -1 if successful, 0 if data not stored PutFifo psha tpa tab pula pshb ;save old CCR sei ;make atomic, entering critical section ldab Size cmpb #FifoSize ;Full if Size==FifoSize beq PutNotFull clra bra PutDone PutNotFull incb stab Size ;Size++ ldx #Fifo ldab PutI abx staa 0,x ;Put data into fifo incb cmpb #FifoSize bne PutNoWrap ;skip if no wrapping needed clrb ;Wrap PutNoWrap clra ;sucess coma ;RegA=-1 means OK stab PutI PutDone tab ;end critical section pula tpa ;restore CCR to previous value tba rts ;**********Get a byte from the FIFO****************** ; Input RegX points to place for 8 bit data from Get ; Output RegA is -1 if successful, 0 if Fifo was empty when called GetFifo tpa psha ;save old CCR sei ;make atomic, entering critical section clra ;assume it will fail tst Size beq GetDone ldy #Fifo ldab GetI aby coma ;RegA=-1 means OK ldab 0,y ;Data from FIFO stab 0,x ;Return by reference ldab GetI incb cmpb #FifoSize bne GetNoWrap ;skip if no wrapping needed clrb ;Wrap GetNoWrap stab GetI GetDone tab ;end critical section pula tpa ;restore CCR to previous value tba rts ; Program 4.xx. A two index with counter FIFO. ;MC9S12C32 TimeHan movb #$80,TFLG2 ;clear TOF ;*Timer interrupt calculations* rti ExtHan movb #$80,PIFJ ;clear flag7 ;*External interrupt calculations* rti org $FFDE ;timer overflow fdb TimeHan org $FFD0 ;Key wakeup J fdb ExtHan ; Program 4.17 Example of a vectored interrupt. ;MC9S12C32 ExtHan brset PIFJ,$80,KJ7Han brset PIFJ,$40,KJ6Han swi ;error KJ7Han movb #$80,PIFJ ;clear flag7 ;*KJ7 interrupt calculations* rti KJ6Han movb #$40,PIFJ ;clear flag6 ;*KJ6 interrupt calculations* rti org $FFCE ;Key wakeup J fdb ExtHan ; Program 4.18 Example of a polled interrupt. ; MC9S12C32 ; PT6-PT0 inputs = keyboard DATA ; PJ7=STROBE interrupt on rise Key_Init sei ; make atomic movb #$80,DDRT ;PT7 unused output bclr DDRJ,#$80 ;PJ7 input bset PPSJ,#$80 ;rise on PJ7 bset PIEJ,#$80 ;arm PJ7 movb #$80,PIFJ ;clear flag7 clr PTT ;PT7=0 jsr Fifo_Init cli ;Enable IRQ rts ExtHan brset PIFJ,$80,KeyHan swi ;error KeyHan movb #$80,PIFJ ;ack, clear flag7 ldaa PTT ;read key jsr Fifo_Put rti org $FFCE ;Key wakeup J fdb ExtHan ; Program 4.19 Interrupting keyboard software. ; MC9S12C32 ;*****goes in RAM************** OK rmb 1 ;0=busy, 1=done Line rmb 20 ;ASCII, end with 0 Pt rmb 2 ;pointer to Line ;*****goes in ROM************** ;Input RegX=>string Fill ldy #Line ;RegX=>string sty Pt ;initialize pointer Floop ldaa 1,x+ ; copy data staa 1,y+ tsta ;end? bne Floop clr OK rts ;Return RegA=data Get ldx Pt ldaa 1,x+ ;read data stx Pt rts ; Program 4.21 Helper routines for the printer interface. ; MC9S12C32 ; PT6-PT0 outputs = printer DATA ; PJ7=READY interrupt on rise ;Input RegX=>string Print_Init sei ; make atomic bsr Fill ;Init global movb #$FF,DDRT ;PT6-0 outputs movb #$40,DDRJ ;PJ6=START, PJ7=READY bset PPSJ,#$80 ;rise on PJ7 bset PIEJ,#$80 ;arm PJ7 movb #$80,PIFJ ;clear flag7 bsr Get bsr Out ;start first cli ;Enable IRQ rts ;RegA is data to print Out bclr PTJ,#$40 ;START=0 staa PTT ;write DATA bset PTJ,#$40 ;START=1 rts ; Program 4.22 Initialization routines for the printer interface. ; MC9S12C32 ExtHan brset PIFJ,$02,PrtHan swi ;error PrtHan movb #$80,PIFJ ;Ack, clear flag7 bsr Get tsta beq Disarm bsr Out ;start next bra Done Disarm bclr PIEJ,#$80 ;disarm PJ7 inc OK ;line complete Done rti org $FFCE ;Key wakeup J fdb ExtHan ;Program 4.23 ISR routines for the printer interface. ; Called to initialize the power system RITUAL ldaa #$FF staa DDRB ;Port B outputs (6812 only) ldaa #0 ;Backup power initially off staa PORTB ;Set the flip flop, make XIRQ=1 ldaa #1 staa PORTB ;Flip flop ready to receive rising edge of TooLow ldaa #$10 ;Enable XIRQ, Disable IRQ tap rts ;Back to main, foreground thread ;Note that the software can only enable XIRQ and can not disable XIRQ. ; In this way, XIRQ is non-maskable. XIRQHAN ldaa #2 staa PORTB ;Enable BackUp power, acknowledge XIRQ ldaa #3 staa PORTB ;Will thread another rising edge of TooLow rti org $FFF4 fdb XIRQHAN ;XIRQ interrupt vector ;Program 4.25. Assembly software for the XIRQ interrupt. start fdb llPJ2 ;place to start polling Mask equ 0 ; and mask DevHan equ 1 ; device handler NextPt equ 3 ; next pointer num fcb 3 ;number of devices llPJ2 fcb $04 ;look at bit 2 fdb PJ2han ;device handler fdb llPJ1 ;pointer to next device to poll llPJ1 fcb $02 ;look at bit 1 fdb PJ1han ;device handler fdb llPJ0 ;pointer to next device to poll llPJ0 fcb $01 ;look at bit 0 fdb PJ0han ;device handler fdb 0 ;end of list ;Program 4.30. 6812 assembly structure for interrupt polling using linked lists. IrqHan ldx start ;Reg X points to linked list place to start ldab num ;number of possible devices next ldaa KWIFJ ;read status anda Mask,x ;check if proper bit is set beq Notyet ;skip if this device not requesting jsr [DevHan,x] ;call device handler, will return here Notyet ldx NextPt,x ;Reg X points to next entry decb ;device counter bne next ;check next device rti ;Program 4.31. 6812 assembly implementation of interrupt polling using linked lists. ; MC9S12C32 assembly org $3800 ;RAM Time rmb 2 org $4000 RTI_Init sei ;make atomic movb #$73,RTICTL ;32.768ms movb #$80,CRGINT ;arm RTI movw #0,Time cli ;enable IRQ rts RTIHan movb #$80,CRGFLG ;ack ldd Time addd #1 std Time rti org $FFF0 fdb RTIHan ;vector ;Program 4.41. Implementation of a periodic interrupt using the real time clock feature. ; MC9S12C32 assembly org $3800 ;RAM Time rmb 2 org $4000 TOF_Init sei ;make atomic movb #$80,TSCR1 ;enable TCNT movb #$81,TSCR2 ;arm, 32.768ms movw #0,Time cli ;enable IRQ rts TOFHan movb #$80,TFLG2 ;acknowledge ldd Time addd #1 std Time rti org $FFDE fdb TOFHan ;vector ;Program 4.42. Implementation of a periodic interrupt using timer overflow. ; MC9S12C32 assembly PERIOD equ 1000 ;in usec org $3800 ;RAM Time rmb 2 org $4000 OC6_Init sei ;make atomic movb #$80,TSCR1 ;enable TCNT movb #$02,TSCR2 ;1us bset TIOS,#$40 ;activate OC6 bset TIE,#$40 ;arm OC6 movw #0,Time ldd TCNT ;time now addd #50 ;first in 50us std TC6 cli ;enable IRQ rts OC6Han movb #$40,TFLG1 ;acknowledge ldd TC6 addd #PERIOD std TC6 ;next in 1 ms ldd Time addd #1 std Time rti org $FFE2 fdb OC6Han ;vector ;Program 4.43. Implementation of a periodic interrupt using output compare. ;************************************** ; programs from the first edition ; MC68HC812A4 assembly org $0800 ;RAM Time rmb 2 org $F000 RTI_Init sei ;make atomic movb #$86,RTICTL ;32.768ms arm movw #0,Time cli ;enable IRQ rts RTIHan movb #$80,RTIFLG ;ack ldd Time addd #1 std Time rti org $FFF0 fdb RTIHan ;vector ;Program 4.38. Implementation of a periodic interrupt using the real time clock feature. ; MC68HC812A4 assembly org $0800 ;RAM Time rmb 2 org $F000 TOF_Init sei ;make atomic movb #$82,TMSK2 ;arm, 32.768ms movb #$80,TSCR ;enable TCNT movw #0,Time cli ;enable IRQ rts TOFHan movb #$80,TFLG2 ;acknowledge ldd Time addd #1 std Time rti org $FFDE fdb TOFHan ;vector ;Program 4.39. Implementation of a periodic interrupt using timer overflow. ; MC68HC812A4 assembly PERIOD equ 1000 ;in usec org $0800 ;RAM Time rmb 2 org $F000 OC6_Init sei ;make atomic movb #$03,TMSK2 ;1us movb #$80,TSCR ;enable TCNT bset TIOS,#$40 ;activate OC6 bset TMSK1,#$40 ;arm OC6 movw #0,Time ldd TCNT ;time now addd #50 ;first in 50us std TC6 cli ;enable IRQ rts OC6Han movb #$40,TFLG1 ;acknowledge ldd TC6 addd #PERIOD std TC6 ;next in 1 ms ldd Time addd #1 std Time rti org $FFE2 fdb OC6Han ;vector ;Program 4.40. Implementation of a periodic interrupt using output compare. ; Program 4.27. Example of a vectored interrupt. ; MC68HC812A4 TimeHan ldaa #$80 ;TOF is bit 7 staa TFLG2 ;clear TOF ;*Timer interrupt calculations* rti ExtHan ldaa #$01 ;Ack staa KWIFJ ;clear flag ;*External interrupt calculations* rti org $FFDE ;timer overflow fdb TimeHan org $FFD0 ;Key wakeup J fdb ExtHan ; Program 4.28. Example of a polled interrupt. ; MC68HC812A4 ExtHan brset KWIFJ,$01,KJ0Han brset KWIFJ,$02,KJ1Han swi ;error KJ0Han ldaa #$01 ;Ack flag0 staa KWIFJ ;clear flag0 ;*KJ0 interrupt calculations* rti KJ1Han ldaa #$02 ;Ack flag1 staa KWIFJ ;clear flag1 ;*KJ1 interrupt calculations* rti org $FFD0 ;Key wakeup J fdb ExtHan ; Program 4.29. Interrupting keyboard software. ; MC68HC812A4 ; PJ6-PJ0 inputs = keyboard DATA ; PJ7=STROBE interrupt on rise Init sei ; make atomic clr DDRJ ;all inputs ldaa #$80 staa KPOLJ ;rising edge PJ7 staa KWIEJ ;arm PJ7 staa KWIFJ ;clear flag7 jsr InitFifo cli ;Enable IRQ rts ExtHan brset KWIFJ,$80,KeyHan swi ;error KeyHan ldaa #$80 ;Ack flag7 staa KWIFJ ;clear flag7 ldaa PORTJ anda #$7F jsr PutFifo rti org $FFD0 ;Key wakeup J fdb ExtHan ; Program 4.31. Helper routines for the printer interface. ; MC68HC812A4 ;*****goes in RAM************** OK rmb 1 ;0=busy, 1=done Line rmb 20 ;ASCII, end with 0 Pt rmb 2 ;pointer to Line ;*****goes in ROM************** ;Input RegX=>string Fill ldy #Line ;RegX=>string sty Pt ;initialize pointer Floop ldaa 1,X+ ;copy data staa 1,Y+ tsta ;end? bne Floop clr OK rts ;Return RegA=data Get ldx Pt ldaa 1,X+ ;read data stx Pt rts ; Program 4.32. Initialization routines for the printer interface. ; MC68HC812A4 ; PH6-PH0 outputs = printer DATA ; PJ1=READY interrupt on rise ;Input RegX=>string Init sei ; make atomic bsr Fill ;Init global ldaa #$FF staa DDRH ;PH6-0 outputs ldaa #$01 ;PJ0 output START staa DDRJ ;PJ1 input ldaa #$02 staa KPOLJ ;rising edge PJ1 staa KWIEJ ;arm PJ1 staa KWIFJ ;clear flag1 bsr Get bsr Out ;start first cli ;Enable IRQ rts Out clr PORTJ ;START=0 staa PORTH ;write DATA inc PORTJ ;START=1 rts ; Program 4.33. ISR routines for the printer interface. ; MC68HC812A4 ExtHan brset KWIFJ,$02,PrtHan swi ;error PrtHan ldaa #$02 ;Ack flag1 staa KWIFJ ;clear flag1 bsr Get tsta beq Disarm bsr Out ;start next bra Done Disarm clr KWIEJ ;disarm PJ1 inc OK ;line complete Done rti org $FFD0 ;Key wakeup J fdb ExtHan ; Program 4.35. Assembly software for the XIRQ interrupt. * Called to initialize the power system RITUAL ldaa #$FF staa DDRB Port B outputs (6812 only) ldaa #0 Backup power initially off staa PORTB Set the flip flop, make XIRQ=1 ldaa #1 staa PORTB Flip flop ready to receive rising edge of TooLow ldaa #$10 Enable XIRQ, Disable IRQ tap rts Back to main, foreground thread *Note that the software can only enable XIRQ and can not disable XIRQ. * In this way, XIRQ is non-maskable. XIRQHAN ldaa #2 staa PORTB Enable BackUp power, acknowledge XIRQ ldaa #3 staa PORTB Will thread another rising edge of TooLow rti org $FFF4 fdb XIRQHAN XIRQ interrupt vector ; Program 4.40. 6812 assembly structure for interrupt polling using linked lists. start fdb llPJ2 place to start polling Mask equ 0 and mask DevHan equ 1 device handler NextPt equ 3 next pointer num fcb 3 number of devices llPJ2 fcb $04 look at bit 2 fdb PJ2han device handler fdb llPJ1 pointer to next device to poll llPJ1 fcb $02 look at bit 1 fdb PJ1han device handler fdb llPJ0 pointer to next device to poll llPJ0 fcb $01 look at bit 0 fdb PJ0han device handler fdb 0 end of list ; Program 4.41. 6812 assembly implementation of interrupt polling using linked lists. IrqHan ldx start Reg X points to linked list place to start ldab num number of possible devices next ldaa KWIFJ read status anda Mask,x check if proper bit is set beq Notyet skip if this device not requesting jsr [DevHan,x] call device handler, will return here Notyet ldx NextPt,x Reg X points to next entry decb device counter bne next check next device rti ; Program 4.48. 6812 assembly implementation of a periodic interrupt using real time interrupt. RITUAL sei disable interrupts during RITUAL ldaa #$86 Set RTR2-0 = 110 Interrupt period = 32.768ms staa RTICTL Set RTIE=1 arm RTI interrupts cli Enable IRQ interrupts rts RTIHAN ldaa RTIFLG Polling for zeros and ones expect=10000000 cmpa #$80 RTIF should equal 1 beq OK swi Error OK ldaa #$80 RTIF is cleared by writing to RTIFLG staa RTIFLG with bit 7 set * service occurs every 32.768ms or about 30.517Hz rti ; Program 4.50. 6812 assembly implementation of a periodic interrupt using timer overflow. RITUAL sei disable interrupts during RITUAL ldaa #$B2 Set PR2-0 = 010 Interrupt period = 32.768ms staa TMSK2 Set TOI=1 arm TOF interrupts ldaa #$80 TEN=1 staa TSCR enable TCNT cli Enable IRQ interrupts rts TOFHAN ldaa TFLG2 Polling for zeros and ones expect=10000000 cmpa #$80 RTIF should equal 1 beq OK swi Error OK ldaa #$80 TOF is cleared by writing to TFLG2 staa TFLG2 with bit 7 set * service occurs every 32.768ms or about 30.517Hz rti