在装配中使用中断

时间:2012-04-25 20:57:33

标签: assembly

我被要求用中断(full instructions)重写我的代码。我们还没有真正涵盖课堂上的中断,我不确定如何使用它们或如何实现它们。这是我在没有使用中断的情况下编写的代码,它基本上使键盘成为钢琴或可以播放为motorola 68hc11编写的歌曲(lamb,chromsc,hall):

PORTA      EQU  $1000  ;The speaker port
SPEAKER    EQU  PORTA
SPEAKERBIT   EQU  %00100000

SCSR    EQU  $6400    ; Serial communications status register
SCDR    EQU  $6401    ; Serial communcations data register
TDRE    EQU  %00000010    ; mask for TDRE flag in SCSR
RDRF    EQU  %00000001    ; mask for RDRF flag in SCSR


ORG     $8000;  Place data at 8000
LAMB    FCB  'trerttttrrrrtuuutrerttttrrtre',$00
CHROMSC FCB  'q2we4r5ty7u8i9op-[=]',$00
HALL    FCB  'qwertet5w5r2rqwertetiutetu',$00

KEYMAP  FDB  'q', 220, 758  ;  A    ;key, frequency, and 1/4 second "period"
        FDB  '2', 233, 715  ;  A#
        FDB  'w', 247, 675  ;  B
        FDB  'e', 262, 636  ;  C
        FDB  '4', 277, 602  ;  C#
        FDB  'r', 294, 567  ;  D
        FDB  '5', 311, 536  ;  D#
        FDB  't', 330, 505  ;  E
        FDB  'y', 349, 478  ;  F
        FDB  '7', 370, 450  ;  F#
        FDB  'u', 392, 425  ;  G
        FDB  '8', 415, 402  ;  G#
        FDB  'i', 440, 379  ;  A
        FDB  '9', 466, 358  ;  A#
        FDB  'o', 494, 337  ;  B
        FDB  'p', 523, 319  ;  C
        FDB  '-', 554, 301  ;  C#
        FDB  '[', 587, 284  ;  D
        FDB  '=', 622, 268  ;  D#
        FDB  ']', 659, 253  ;  E
        FDB  $00            ;  Null termination character

PROMPT  FCB  $0D, 'Piano program - use QWERTY row to play notes', $0D, $00  ;Prompt String

        ORG  $8800
        LDS  #$DFFF

;;;;;;;;;;  Main Start  ;;;;;;;;;;
        LDX    #PROMPT

        PSHX  ;Push the argument to the stack
        JSR    printString  ;Print the promp string
        PULX

ALWAYS  DES
        JSR    getChar  ;Get a character from the keyboard
        JSR    putChar
        PULA  ;put the character in A

        PSHA  ;Push character to the stack
        JSR    playTone  ;Play the tone
        PULA

        CMPA   #'a'
        BNE    SKIPLAMB

        LDX    #HALL
        PSHX
        JSR    playSong
        PULX

SKIPLAMB CMPA   #'s'
        BNE    BRAALW

        LDX    #LAMB
        PSHX
        JSR    playSong
        PULX

BRAALW  BRA    ALWAYS  ;Loop to the top and continue playing
;;;;;;;;;;  Main End  ;;;;;;;;;;

;;;;;;;;;;  playTone Start  ;;;;;;;;;; Passed an ascii character and a length on the stack
playTone    PSHB  ;for transparency
            PSHA
            PSHX
            PSHY

            TSY    ;make Y point to the top of the stack

            LDAA   8,Y  ;load A with the passed argument
            LDX    #KEYMAP  ;make Y point to the KEYMAP
CBAALWAYS   LDAB   1,X  ;load B with the ascii value
            BEQ    EXITPT  ;If current value is $00, end of table, no key match, exit routine
            CBA        ;Compare B to A
            BEQ    SKIPTESTS  ;If value are equal, skip rest of test to play tone
            XGDX
            ADDD   #6  ;Make X point to the next character to compare
            XGDX
            BRA    CBAALWAYS  ;Branch until the end of table is reached

SKIPTESTS   LDD     2,X  ;Load D with the frequency
            LSRD  ;Number of times to toggle the speaker in a 1/4 second
            LSRD    ;this shortens the tone to an 1/8 note
            ;LSRD    ;this plays a 1/16 note
            ;LSRD    ;this plays a 1/32 note
PERIODLOOP  LDY     4,X  ;Load Y with the delay between toggles
FREQLOOP    DEY    ;Decrement Y until it's 0

            BNE   FREQLOOP    ;Branch until X is 0

            PSHB    ;preserve D
            PSHA

            LDAA  PORTA  ;Load A with the speaker
            EORA  #SPEAKERBIT  ;Toggle the speaker bit
            STAA  PORTA    ;Store back into the speaker

            PULA    ;restore D
            PULB

            SUBD  #1  ;Decrement D
            CPD    #0  ;Compare D to 0
            BNE    PERIODLOOP    ;Branch until D is 0

EXITPT      PULY
            PULX
            PULA
            PULB  ;return the stack to normal

            RTS    ;return to the main program
;;;;;;;;;;  playTone End  ;;;;;;;;;;

;;;;;;;;;;  playSong Start;;;;;;;;;;
playSong    PSHB    ;Reference is passed on the stack
            PSHA    ;Pushes for transparency
            PSHX
            PSHY

            TSX
            LDX     8,x     ;Load X with the passed value

LOOPSTRING  LDAA    0,X     ;Load A with the ith character of the string
            BEQ     ENDPSTRING          ;Skips to end of subroutine if current character is null character
            PSHA            ;Pass the argument in A to putChar
            JSR     playTone
            INS             ;Return the stack to normal
            INX             ;increments X to point to the next character
            BRA     LOOPSTRING

ENDPSTRING  PULY
            PULX
            PULA
            PULB

            RTS


;;;;;;;;;;  playSong End  ;;;;;;;;;;

;;;;;;;;;;  putChar start  ;;;;;;;;;; Passed argument should be an ascii value
putChar     PSHB    ;is passed an argument on the stack
            PSHA    ;for transparency
            PSHX
            PSHY
            TSY     ;stack frame

            LDX     #SCSR            ;Load in address of SCSR (Serial Communication Status Register)
GCWAIT      BRCLR   0,X TDRE GCWAIT    ;Loop
            LDAA    8,Y   ;Load A with the passed value
            STAA    SCDR  ;Write A to the SCDR

            PULY
            PULX
            PULA
            PULB

            RTS
;;;;;;;;;;  putChar end  ;;;;;;;;;;

;;;;;;;;;;  getChar start  ;;;;;;;;;; ascii value is returned
getChar     PSHB    ;No argument. Passes result back on the stack.
            PSHA    ;For transparency
            PSHX
            PSHY
            TSY

            LDX     #SCSR            ;Load in address of SCSR (Serial Communication Status Register)
PCWAIT      BRCLR   0,X RDRF PCWAIT    ;Loop when the
            LDAA    SCDR  ;Load A with what's in the SCDR (should be the pressed key)
            STAA    8,Y   ;Store it to the stack to be passed back

            PULY
            PULX
            PULA
            PULB

            RTS
;;;;;;;;;;  getChar  end  ;;;;;;;;;;

;;;;;;;;;;  printString start   ;;;;;;;;;;  argument passed on the stack in ascii
printString PSHB    ;Reference is passed on the stack
            PSHA    ;Pushes for transparency
            PSHX
            PSHY

            TSX
            LDX     8,x     ;Load X with the passed value

LOOPSTRING1 LDAA    0,X     ;Load A with the ith character of the string
            BEQ    ENDPSTRING1          ;Skips to end of subroutine if current character is null character
            PSHA            ;Pass the argument in A to putChar
            JSR     putChar
            INS             ;Return the stack to normal
            INX             ;increments X to point to the next character
            BRA    LOOPSTRING1

ENDPSTRING1 PULY
            PULX
            PULA
            PULB

            RTS
;;;;;;;;;;  printString end  ;;;;;;;;;;

有人可以给我一个例子,说明如何有效地实现或只是提示如何开始编写中断,以便我可以用它们重写我的代码。

2 个答案:

答案 0 :(得分:5)

要在hc11上使用中断,您需要做四件事:

  1. 首先确定您要使用哪种中断。 hc11有许多不同的类型,所以你必须参考手册,找到一个适合你想要做的事情。
  2. 对于接下来的步骤,我假设您正在使用IRQ中断。它只是hc11上的一个简单中断引脚,当电压降至低电平时会中断系统。但是,任何其他中断的步骤都非常相似。

    1. 您需要初始化中断服务程序的起始位置。当触发中断时,处理器将检查向量表以确定它需要去的位置。因此,例如当IRQ被触发时,它将转到对应于IRQ($ FFF2)的表条目,然后跳转到存储在那里的地址。我们将标记中断服务例程IRQ_INT并将其存储在与IRQ相对应的表条目中,以便在触发IRQ时它将开始执行标签IRQ_INT处的代码。

      ORG   $FFF2
      FDB   IRQ_INT
      
    2. 接下来,您需要启用中断,以便处理器在触发时识别它。您需要再次检查手册中的值以及存储该值的寄存器以启用它。要使能IRQ,必须在中断控制寄存器(INTCR)中将IRQ使能位(IRQEN)设置为1。然后可以使用CLI命令启用它。

      INTCR    EQU   $001E   ;address of interrupt control register
      INTCR_IN EQU   $60     ;sets IRQEN bits
      
               LDAA  #INTCR_IN
               STAA  INTCR
               CLI
      
    3. 最后,您需要编写中断服务程序。这是每次触发中断时将执行的代码。它将从我们之前在向量表中设置的标签开始,并在它到达指令RTI时结束。从中断返回指令告诉处理器服务程序已完成,它应该返回到触发中断之前执行的任何操作。

      IRQ_INT
             <instructions go here>
             RTI
      
    4. 我的猜测是你会想要键盘上的某种中断,当键被击中时会触发。一旦键被击中,中断将触发处理器进入中断服务程序。在那里,你必须编写代码来确定哪个键被击中并播放正确的音符。

答案 1 :(得分:2)

你必须编写两个ISR,基本上是子程序。每个似乎都是由定时器触发的硬件中断。

一个isr是切换扬声器音调并自动触发(开/关)的一个因此产生N个周期的音调。首先要熟悉如何编程定时器TOC3

另一个是定时器int循环,每隔1 ms寻找输入并监视RDRF标志并通过之前执行的某个项目读取数据。熟悉TOC2的编程

您需要初始化ISR,这意味着您必须设置CPU以告知它ISR例程所在的位置。你的指示已经说明了如何为TOC3做这个,并且应该与TOC2相似,阅读你的讲义以查看jmp表对于toc2的位置,他给你了toc3的位置。

 Memory $FFE4 contains 
 $00D9, so insert a JMP XXXX instruction at $00D9 (where XXXX is the 
 address of your TOC3 service routine.  Note: the opcode for JMP is $7E. 

所以做这样的事情:

 org $00d9 
 jmp YourTOC3ISR

;;;;;;;;;;;;;主要程序

 initialize timer registers ie setup toc2 and toc3
 initialize interrupt registers

 2) Read the current Timer Count from TCNT (pg. 374), add your DELAY to it, 
 and store the result in TOC3 (pg. 409).  This defines when you want the 
 first interrupt to occur.
 3) Set OC3I bit in TMSK1 to enable TOC3 interrupts (pg. 410).
 4) Clear the OC3F bit in TFLG1 to clear any previous interrupt condition.
 (pg. 410).  IMPORTANT!!!  Note that you must write a 1 to this bit to 
 clear it!  Do not use BSET!  See the discussion on page 387.
 5) Optional: Write to OM3 and OL3 bits in TCTL1 register to define how the 
 OC3 output pin will behave when the interrupt occurs (pg. 412).
 6) Enable interrupts globally. (See SEI and CLI instructions.)


 do lab 7 code

;;;;;;;;;;;;;;;;; toc3 isr例程YourTOC3Isr,playtone?

  save the regs and flags

 1) Define when the next interrupt should occur by adding your DELAY to TOC3.
 2) Do whatever it is you want done in the service routine ie speaker togggle stuff
 3) Clear the OC3F bit in TFLG1 to clear the interrupt condition (SEE ABOVE).
4) Return from interrupt when done (pg. 181).
unsave reg and flags
rti

;;;;;;;;;;;;;;; toc2 isr例程

保存reg和标志

然后它会检查RDRF标志,如果不是   然后返回。如果已设置,它将从接收中读取字符   注册,将其写入传输寄存器(您可以使用旧的putchar例程),   然后调用playtone并从中断返回。

这部分听起来好像他要你调用另一个中断例程toc3,    所以只需写入启动定时器和中断的TOC3控制寄存器    应该小心自己。

unsave reg和flags    器R

希望这有帮助, 中号