Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Assembly 为什么不是';这首歌不是一直在集合中播放吗?_Assembly_16 Bit - Fatal编程技术网

Assembly 为什么不是';这首歌不是一直在集合中播放吗?

Assembly 为什么不是';这首歌不是一直在集合中播放吗?,assembly,16-bit,Assembly,16 Bit,我正在上一堂组装入门课,在最后一个项目中,我们必须制作一个播放“生日快乐”的程序 问题是,程序将歌曲播放到一半(到第13个音符),然后停止播放。我已经尽了一切努力来修复它,但我不知道为什么它不应该工作。我试着改变代码,改变循环的工作方式,改变哪些寄存器持有不同的值,但似乎没有任何效果。我查看了调试,没有发现任何异常。这是程序的代码: ;data segment dseg segment para 'data' ;hex value for each note to send

我正在上一堂组装入门课,在最后一个项目中,我们必须制作一个播放“生日快乐”的程序

问题是,程序将歌曲播放到一半(到第13个音符),然后停止播放。我已经尽了一切努力来修复它,但我不知道为什么它不应该工作。我试着改变代码,改变循环的工作方式,改变哪些寄存器持有不同的值,但似乎没有任何效果。我查看了调试,没有发现任何异常。这是程序的代码:

;data segment

dseg      segment para 'data'
    ;hex value for each note to send to port 42
    NOTES DW 11CAh,11CAh,0FDAh,11CAh,0D5Ah,0E1Fh,11CAh,11CAh
          DW 0FDAh,11CAh,0BE3h,0D5Ah,11CAh,11CAh,08E9h,0A97h
          DW 0D5Ah,0E1Fh,0FDAh,0A00h,0A00h,0A97h,0D5Ah,0BE3h,0D5Ah,"$"

    ;duration for each note
    DUR DB 1d,1d,2d,2d,2d,4d,1d,1d,2d,2d,2d
        DB 4d,1d,1d,2d,2d,2d,2d,6d,1d,1d,2d,2d,2d,4d    

dseg      ends

;----------------------------------------------------------------------
;code segment
cseg      segment para 'code'

main    proc far               ;this is the program entry point
    assume cs:cseg, ds:dseg, ss:sseg 
    mov  ax,dseg           ;load the data segment value
    mov  ds,ax             ;assign value to ds

    MOV AL, 0B6h
    OUT 43h, AL     ;output whats in AL to port 43h
    MOV SI, OFFSET NOTES    ;moves the address of the first note into SI
    MOV DI, OFFSET DUR  ;moves the address of the first duration into DI
    SUB BX, BX      ;clears BX
    SUB DX, DX      ;clears DX
    SUB CX, CX      ;cleasr CX
PLAY:   NOP
    MOV DX, [SI]        ;moves the frequency and divider for the note into DX
    CMP DX, "$"     
    JE EXIT         ;if at end of notes jump to exit
    MOV BL, [DI]        ;moves the number of times delay is called into BL
    CALL TONE       ;plays the note for the duration
    INC SI          ;move to next note
    INC DI          ;moves to next duration
    JMP PLAY        ;loop back to PLAY if there are still notes
EXIT:   NOP


      mov  ah,4Ch            ;set up interupt
      int  21h               ;Interupt to return to DOS

main      endp


TONE PROC 

    SUB AX, AX      ;clears ax
    MOV AL, DL      ;sets up the frequency for the tone
    OUT 42h, AL     ;output whats in AL to port 42h
    MOV DL, 0       ;use to compare to BL
    MOV AL, DH      ;divider for the tone smaller value = higher pitch
    OUT 42h, AL
    IN AL, 61h      ;input the contents of port 61h into AL
    MOV AH, AL      ;preserve contents of AL
    OR AL, 00000011b    ;uses mask to change the bits that we need
    OUT 61h, AL     ;outputs the changed bits back into the port to start tone
AGAIN:  NOP         ;loops 1/2 second delay for times needed
    CALL DELAY
    DEC BL
    CMP BL, DL      ;compares value in bl to 0
    JNE AGAIN       ;loops delay until bl is 0
    MOV AL, AH
    OUT 61h, AL     ;turns off tone with preserved contents from port 61h
    CALL DELAY_TWO      ;adds delay between notes
    RET

TONE ENDP

DELAY PROC NEAR     ;half second delay

    PUSH AX     ;preserve value in ax in stack
    MOV CX, 33156   ;delays for half second
WAITF:  NOP
    IN AL, 61h  ;read port 61
    AND AL, 10h ;gives 0001 0000 check PB4
    CMP AL, AH
    JE WAITF    ;jump to WAITF if AL is equal to AH
    MOV AH, AL  ;makes both AL and AH contain same number
    LOOP WAITF  ;continue until CX is 0
    POP AX  
    RET

DELAY ENDP

DELAY_TWO PROC NEAR ;small delay between notes

    PUSH AX     ;need value in ax for TONE so save it
    MOV CX, 331
WAITO:  NOP
    IN AL, 61h
    AND AL, 10h
    CMP AL, AH
    JE WAITO
    MOV AH, AL
    LOOP WAITO
    POP AX      ;get back ax value once delay is done
    RET

DELAY_TWO ENDP


cseg      ends
      end     main           ;Program exit point
我们只使用16位汇编。可能还有其他的定时器和铃声制作方法,但我们必须这样做,程序中使用的端口。另外,我正在使用DOSBox来运行.exe,当它播放时听起来有点不对劲


任何帮助都将不胜感激。

您需要为每个音符增加两次SI,因为它指向一个16位值的数组。非常感谢!我忘了我需要对16位值执行此操作。现在它工作得很好。寄存器归零的标准习惯用法是
xor same,same
。IIRC,在一些CPU上,
次相同、相同的
没有。