Assembly 在不带OUT指令的传统PC扬声器上发声
我目前正在尝试在汇编代码中生成声音。以下是我找到的一些代码:Assembly 在不带OUT指令的传统PC扬声器上发声,assembly,audio,x86,segmentation-fault,pc,Assembly,Audio,X86,Segmentation Fault,Pc,我目前正在尝试在汇编代码中生成声音。以下是我找到的一些代码: section .text global sound sound: mov al, 182 ; meaning that we're about to load mov ax, 182 out 43h, al ; a new countdown value ret mov ax, 2153 ; count
section .text
global sound
sound:
mov al, 182 ; meaning that we're about to load
mov ax, 182
out 43h, al ; a new countdown value
ret
mov ax, 2153 ; countdown value is stored in ax. It is calculated by
out 42h, al ; Output low byte.
mov al, ah ; Output high byte.
out 42h, al
in al, 61h
or al, 00000011b
out 61h, al ; Send the new value
ret
根据这段代码的所有者的说法,它应该可以工作,但是当我用C main运行它时,它被一个分段错误杀死了
通过进一步的研究,我发现在现代操作系统中,由于权限的原因,很难访问说话者。如果有人知道如何使用扬声器并播放声音,我很乐意学习
注意:当我以超级用户的身份运行代码时,不会出现分段错误,但不会产生声音。[在阅读NASM编译器的工作原理之前,我不确定是否有其他编译器] 您的代码很好,但问题是:
mov ax,182
和ret
,因为此处的返回将跳出代码,跳转到您调用的位置,不再运行代码生成:
mov ax, 2153 ; countdown value is stored in ax. It is calculated by
out 42h, al ; Output low byte.
mov al, ah ; Output high byte.
out 42h, al
in al, 61h
or al, 00000011b
out 61h, al ; Send the new value
ret
过时的。对于mov-ax,182
当我使用扬声器时,我的工作原理是没有这个,所以我猜你不需要它,所以如果必要的话,我会说移除它
因此,修改后的代码版本将是:
bits 16
start:
mov ax, 0x07c0 ; Setup the stack past where we are loaded
add ax, 544
cli ; Disable interrupts
mov ss, ax
mov sp, 4096
sti ; Restore interrupts
mov ax, 0x07c0 ; Set the data segment to where we are
mov ds, ax
sound:
mov al, 182 ; Were about to load
out 0x43, al
mov ax, 15000 ; 15000(Pitch) = 1,193,180 / 79.5453333(Repeating)
out 0x42, al ; Give the port the lower value
mov al, ah
out 0x42, al ; Now give it the higher
in al, 0x61
or al, 00000011b ; Connect the speaker to Timer 2
out 0x61, al
jmp $ ; hang
times 510-($-$$) db 0 ; Pad the rest of the file with 0's
dw 0xaa55 ; Little Endian MBR Signature
若要运行此操作以查看其是否工作,请确保您的计算机具有车载扬声器。我的看起来像这样:
如果您没有它,您的可能与我的不一样,如果没有,您可以在代码之后显示或执行某些操作以确保它运行
我使用这些命令来运行它
nasm -f bin <YOURFILENAME>.asm -o boot.bin
dd if=boot.bin of=\\.\<DRIVENUMBER>: bs=512
若要查看是否正在引导,请将其添加到文件顶部的位16之后:
jmp short start
nop
OEMLabel db "Contoso" ; OEM Label
BytesPerSector dw 512 ; There are 512b per sector
SectorsPerCluster db 1 ; Sectors per cluster
ReservedForBoot dw 1 ; # of sectors reserved for boot
NumberOfFats db 2 ; # of fats
RootDirEntries dw 224 ; # of root directory entries
LogicalSectors dw 2880 ; # of sectors
MediumByte db 0x0f0 ; Medium descriptor byte
SectorsPerFat dw 9 ; # of sectors per fat
SectorsPerTrack dw 18 ; # of sectors per track
Sides dw 2 ; # of sides
HiddenSectors dd 0 ; # of hidden sectors
LargeSectors dd 0 ; # of large sectors
DriveNo dw 0 ; The drive number
Signature db 41 ; The drive signature
VolumeID dd 0xdeadbeef ; The volume id
VolumeLabel db "Windows9 "; This can be any 11 characters
FileSystem db "FAT12 " ; File system of the floppy DONT CHANGE
如果出于任何原因,代码无法工作,请检查是否存在任何错误,并确保主板上有内置扬声器
如需了解更多信息,请参见上文所述。
源代码的基础。
关于汇编的一些技巧,这是一个非常有文档记录的开源操作系统,可以帮助初学者学习汇编
希望这有帮助
编辑:Peter Cordes的一些打字错误和帮助(在评论中)找到一个在您想要的目标操作系统上工作的库(例如FMOD、BASS),然后在您的程序中使用该库。out
指令具有特权。它还针对不再存在的硬件。您应该在DOSBox中运行这个程序,或者获得一个在Linux下运行的库?对不起,我是个有汇编代码的新手。我将搜索类似的内容,感谢你们两位的回答,因为root允许Linux系统调用成功运行,但如果您不这样做,这仍然会导致root失败。也许你以root用户身份运行的方式隐藏了segfault消息?超级用户仍然独立于内核模式,尽管ioperm/iopl可以允许在用户空间中执行I/O指令(通常具有特权)。准确模拟传统IBM-PC的虚拟机将拥有该虚拟硬件。e、 g.可能是BOCHS或DOSBox。当你说“振荡器”时,我想你实际上是指“PC扬声器”。在您的照片中,它是mobo上的压电元件;在其他情况下,它可以是电路板上的一个标题,您需要连接到线圈扬声器。如果你有一个旧的电脑机箱,你可以把扬声器拿出来,放进一个现代化的机箱里,连接到mobo上。当然,您也可以在模拟器中运行,该模拟器使用常规声音I/O功能通过主机的声卡产生蜂鸣音。顺便说一句,我认为您在512字节引导扇区(例如)的末尾遗漏了0xAA55
MBR引导签名。您的测试之所以成功,可能是因为您写入的字节数少于512字节,因此保留了现有签名?或者,在加载引导扇区之前,BIOS没有检查该签名。顺便说一句,问题是他们试图在Linux或MacOS下的用户空间中运行此代码!!(短语“分段错误”是一个线索)。这是一个showtupper,与早期的ret
(可能是为了查看是否只有第一部分仍然存在故障)等bug分开。如果您进行ioperm
系统调用以启用这些I/O端口以便从用户空间使用,则可能会起作用。或者是的,当然,编写一个引导加载程序可以让你对整个机器进行真正的模式控制。或者这是他的代码中的一个bug。嗯,是的,这个bug很天真地在Linux下的用户空间中运行这个代码,没有使用ioperm
或任何东西,并且惊讶地发现out
出现了故障:P许多初学者没有意识到汇编语言是多么不可移植,他们想知道为什么在复制/粘贴他们找到的一些代码后,int 21h
在Windows(非DOS)可执行文件和类似的东西中不起作用,例如在x86汇编中打印一个数字
mov ah, 0x0e
mov al, 'X'
int 0x10
jmp short start
nop
OEMLabel db "Contoso" ; OEM Label
BytesPerSector dw 512 ; There are 512b per sector
SectorsPerCluster db 1 ; Sectors per cluster
ReservedForBoot dw 1 ; # of sectors reserved for boot
NumberOfFats db 2 ; # of fats
RootDirEntries dw 224 ; # of root directory entries
LogicalSectors dw 2880 ; # of sectors
MediumByte db 0x0f0 ; Medium descriptor byte
SectorsPerFat dw 9 ; # of sectors per fat
SectorsPerTrack dw 18 ; # of sectors per track
Sides dw 2 ; # of sides
HiddenSectors dd 0 ; # of hidden sectors
LargeSectors dd 0 ; # of large sectors
DriveNo dw 0 ; The drive number
Signature db 41 ; The drive signature
VolumeID dd 0xdeadbeef ; The volume id
VolumeLabel db "Windows9 "; This can be any 11 characters
FileSystem db "FAT12 " ; File system of the floppy DONT CHANGE