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