skiselev / 8088_bios

BIOS for Intel 8088 based computers
GNU General Public License v3.0
513 stars 61 forks source link

PC Speaker Compatibility #47

Closed oblende closed 11 months ago

oblende commented 11 months ago

Seems like a silly thing to ask about, but I couldn't figure out where else to ask as it seems hardware and BIOS related.

So I had decided to learn assembly language in DOS using the Book 8088 with the help of the book "Assembly Language Primer for the IBM PC & XT." Things were going good until I got to the section involving sound using the PC speaker, then everything stopped working. I then tried as many examples from the internet on using the PC speaker, including the beep code from your BIOS and all failed. The frustrating part is that other applications including the beep command seem to work fine. In desperation I then figured out how to get Virtualbox to passthrough the PC speaker, and the programs I was having troubble with worked. It still does not explain how your bios and various applications is able to make sound. Could you explain how I'm screwing my code up, please? Also I'm using the msa2 assembler, so I commented out all the MASM specific parts of the code. I may still end up using MASM so I figure writing the MASM parts in the comments was the best way to learn even if I wasn't using that assembler. Sorry if it makes the code harder to read.

` ;SIREN--Uses Timer2 to run speaker ; features siren effect ; ;** ;prognam segment ;define code segment

;--------------------------------------------------
;main:  ;proc far   ;main part of program

;assume cs:prognam

;org 0x100  ;first address

start:      ;starting execution address

;start 1/pitch at FFFFh
    mov bx,0x0ffff  ;set 1/pitch in BX

;sound the tone
    mov al,0xb6     ;put magic number
    out 0x43,al     ;  into timer2
tone:   mov ax,bx       ;move 1/pitch into AX
    out 0x42,al     ;LSB into timer2
   mov  al,ah       ;MSB to AL, then
    out 0x42,al     ;  to timer2
    in  al,0x61     ;read port B into AL
    or  al,0x03     ;turn on bits 0 and 1
   out  0x61,al     ;to turn on speaker

;increase the pitch and wait a bit
    dec bx      ;increase the pitch
    mov cx,100      ;set up wait loop
wait:   loop    wait        ;wait
    jmp tone        ;go do new tone

;main   endp    ;end of main part of program
;---------------------------------------------------
;
;prognam ends   ;end of code segment
;***************************************************
;
    ;end    start   ;end assembly

`

skiselev commented 11 months ago

This is obviously not a bug or an issue in the BIOS, and has nothing to do you the PC speaker compatibility :)

Anyhow, let me try to help you.

There is one document that you'd want to take a look at. It is the 8254 Programmable Interval Timer (PIT) datasheet. Particularly, check page number 6 there.

There are two components that are used for sound generation in the IBM PC:

A bit about 8254 PIT and its addressing in IBM PC:

How to program sound using PIT?

  1. Inhibit PIT channel 2, disable sound:
    • Read the current value from port 0x61
    • Reset bits 0 & 1, e.g. AND the current value with 0xFC
    • Write the result back to port 0x61
  2. Load 0xB6 to port 0x43 - this configures PIT channel 2 to generate square wave, and the PIT to expect a 16-bit long initial count value
  3. Load low byte of the initial count value to port 0x42
  4. Load high byte of the initial count value to port 0x42
  5. Enable PIT channel 2, enable sound:
    • Read the current value from port 0x61
    • Set bits 0 & 1 to 1, e.g. OR the current value with 0x03 To change the frequency, repeat all the steps above

Why my code doesn't work?

I suspect it happens because of this: "For each Counter, the Control Word must be written before the initial count is written." Try moving your "tone:" label two lines up, before you write the "magic number". Also, it might be a good idea to disable speaker before you reprogram the PIT. Add something like:

in al,0x61 and al,0xFC out 0x61,al

Of course, you can take the sound.inc from this BIOS, and just modify it a bit.

oblende commented 11 months ago

I thank you for your patience in answering my question. In a strange turn of events we were both wrong. I tried out your suggested modifications and it was still not working. So I looked at what was happening in debug and noticed when I unassembled the program that or al,0x03 was assembled by msa2 as or al,[bp+di], which would have been fine if it had worked. Instead bits 0 and 1 on port 0x61 were never both set. Putting 0x03 into the dl register and ORing that with al suddenly made my code work.

Again thank you for your patience and now I think I need to submit a bug report to a different project.

skiselev commented 11 months ago

I still don't understand what happened with your assembler ;) How come or al,0x03 got assembled as or al,[bp+di]? Either that assembler is trash or you're not doing something right ;)

oblende commented 11 months ago

As much as I'm willing to accept that I'm doing something wrong I really can't see how that can be. It seems to be a bug in the assembler, but only with OR reg,constant combinations. I'd submit a bug report to the author, but he doesn't seem to allow people to submit reports as the ability to do so has been disabled on his repositories. It's a shame as I appreciate a no nonsense assembler like this.

or al,0x03
or bl,0x02
or cl,0x05
or dl,0x04
or ah,0x03
or bh,0x08
or ch,0x07
or dh,0x03
or ax,0xAAAA
or bx,0xAAAA
or CX,0xAAAA
or dx,0xAAAA
int 0x20

debug

Edit I assembled over the areas with debug of the OR al,0x03 instruction and the OR AX,0xAAAA instruction, and everything fell back in line. So everything is fine except those two instructions. debug2