flat assembler
Message board for the users of flat assembler.

Index > OS Construction > IRQ only fires once?

Author
Thread Post new topic Reply to topic
newport



Joined: 08 Jun 2012
Posts: 86
Location: Kentucky, USA
newport 23 Nov 2014, 00:45
First, let me say that I did my research and have read every pertaining thread within this board and searched extensively on the net for an answer before posting...

After achieving a working IDT thanks to everyone who commented on my last thread, I've got the keyboard interrupt working. However, it will only fire once.. I have no idea what is wrong.. There's way too much code to paste within here, so I am including a re-organized copy of my working OS for download to examine the code... I would appreciate any help I could get on this one.. Thanks in advance!


Description:
Download
Filename: MyOS.zip
Filesize: 8.35 KB
Downloaded: 567 Time(s)


_________________
It's the desire to learn that leads to success...

http://www.webicomp.com
Post 23 Nov 2014, 00:45
View user's profile Send private message Visit poster's website Reply with quote
BAiC



Joined: 22 Mar 2011
Posts: 272
Location: California
BAiC 23 Nov 2014, 05:14
as I told you in the previous post you have to respond to the interrupt once your done processing it (technically the interrupt controller can be notified before hand in a certain case)..

this is the ISR code that's wrong (line 167 in isr.asm):

Code:
        isr33:
             pusha
             push ds
             push es
             push fs
             push gs
             mov edi, 0xB8000
             mov byte[es:edi], 'a'
             inc edi
             mov byte[es:edi], 10
             inc edi
             pop gs
             pop fs
             pop es
             pop ds
             popa
        iret    

use this instead:
Code:
        isr33:
                
                push eax
                mov al, 0x60+1
                out 0x20, al
                mov[0xB8000], word 10 shl 8 + 'a'
                pop eax
                
        iret    

refer to my previous post for the details.

- Stefan

_________________
byte me.
Post 23 Nov 2014, 05:14
View user's profile Send private message Visit poster's website Reply with quote
BAiC



Joined: 22 Mar 2011
Posts: 272
Location: California
BAiC 23 Nov 2014, 09:44
I forgot to mention you also need to read the keyboard data.
Code:
in al, 0x60;keyboard controller data port.    

so the code should look like this:
Code:
        isr33:
                
                push eax
                in  al, 0x60;read the keyboard controller data port
                mov al, 0x60+1
                out 0x20, al
                mov[0xB8000], word 10 shl 8 + 'a'
                pop eax
                
        iret    
Post 23 Nov 2014, 09:44
View user's profile Send private message Visit poster's website Reply with quote
BAiC



Joined: 22 Mar 2011
Posts: 272
Location: California
BAiC 23 Nov 2014, 14:32
the following will show the code works by printing the character to the screen:
Code:
    isr33:
        
        push eax edi
            
            in  al, 0x60;read the keyboard controller data port to get the scancode.
            test al, al
            js  @f
                
                ;convert the scancode to ASCII.
              movzx eax, byte [eax+normal_keymap]
                add eax, 10 shl 8
                
                ;calculate the pointer in memory.
                mov edi, 2
               xadd[.idx],edi
                
                ;write the ASCII character to memory.
                mov[edi],ax
                
            @@:
            
            ;respond to the interrupt controller.
            mov al, 0x60+1
            out 0x20, al
            
        pop edi eax
        
    iret
    align 4
   .idx dd 0xB8000+ 160*3    

_________________
byte me.
Post 23 Nov 2014, 14:32
View user's profile Send private message Visit poster's website Reply with quote
newport



Joined: 08 Jun 2012
Posts: 86
Location: Kentucky, USA
newport 23 Nov 2014, 20:28
I do appreciate your help very much BAiC, but I tried your suggestions and I can't get them to work either. In fact I receive an invalid opcode error. My updated code reflects the following... the string "Keyboard Interrupt Handled" appears on the screen upon striking a key, however, it's only executed once...

Code:
align 4
;int33
        irq1:
          pushad
          push ds
          push es
          push fs
          push gs
           call newLine
           mov esi, imsg
           call printString
          pop gs
          pop fs
          pop es
          pop ds
          in  al, 0x60;read the keyboard controller data port
          mov al, 0x60+1
          out 0x20, al
          popad
        iret  

    


thanks again for your help

CORRECTION: ok... i got it working.. the pushad and popad was affecting the outcome.. I replaced this with push eax ebx ecx edx edi and was still having issues. It was not until I did not push or pop esi and edi that it worked... thanks.. so you were right all along!!! my apologies... the corrected working code is as follows...

Code:
align 4
;int33
        irq1:
          ;pushad
          push eax ebx ecx edx
          push ds
          push es
          push fs
          push gs
           call newLine
           mov esi, imsg
           call printString
          pop gs
          pop fs
          pop es
          pop ds
          in  al, 0x60;read the keyboard controller data port
          mov al, 0x60+1
          out 0x20, al
          ;popad
          pop edx ecx ebx eax
        iret                      

_________________
It's the desire to learn that leads to success...

http://www.webicomp.com
Post 23 Nov 2014, 20:28
View user's profile Send private message Visit poster's website Reply with quote
smiddy



Joined: 31 Oct 2004
Posts: 557
smiddy 23 Nov 2014, 21:02
Check this page out, it may provide more details into why things are not working as expected: http://www.brokenthorn.com/Resources/OSDevPic.html

In reviewing my own code I don't do this:
Code:
    mov al,0x60+1
    out 0x20, al
    


I do this:
Code:
.FinishUp:

        mov al,20h                                                              ; Load EOI into AL
        out 20h,al                                                              ; Send to first PIC port
    

Looking around, I have no idea why you would do 0x60+1.
The page link I just sent wrote:
Sending End of Interrupt (EOI)

As you know, when a hardware interrupt triggers, all other interrupts are masked off inside of the Interrupt Mask Register until an EOI signal is sent to the primary controller. This means, we must send an EOI to insure all hardware interrupts are enabled at the end of our Interrupt Routine (IR).


Based on this set of information, 0x61 (effectively) is not an option...maybe I'm missing something.


Last edited by smiddy on 23 Nov 2014, 21:04; edited 1 time in total
Post 23 Nov 2014, 21:02
View user's profile Send private message Reply with quote
newport



Joined: 08 Jun 2012
Posts: 86
Location: Kentucky, USA
newport 23 Nov 2014, 21:04
For all those entering into the world of x86 Assembly OS programming, I have included my working example for anyone who wishes to study the code. It has taken me nearly 2 years of on/off studying of assembly and the help of the wonderful people in these forums just to get to the point I am at now. Please make sure you understand how and why the code works the way it does, and not simply just copy it to use in your own OS. The zip file includes a two-stage bootloader with a very minimilistic kernel and a working keyboard interrupt. All organized in 4 simple and easy to read files. While it is not perfect and very far from being a complete OS, it does provide useful studying information nonetheless. Enjoy!


Description:
Download
Filename: NewportOS.zip
Filesize: 8.32 KB
Downloaded: 537 Time(s)


_________________
It's the desire to learn that leads to success...

http://www.webicomp.com
Post 23 Nov 2014, 21:04
View user's profile Send private message Visit poster's website Reply with quote
newport



Joined: 08 Jun 2012
Posts: 86
Location: Kentucky, USA
newport 23 Nov 2014, 21:18
smiddy wrote:
Check this page out, it may provide more details into why things are not working as expected: http://www.brokenthorn.com/Resources/OSDevPic.html

In reviewing my own code I don't do this:
Code:
    mov al,0x60+1
    out 0x20, al
    


I do this:
Code:
.FinishUp:

        mov al,20h                                                              ; Load EOI into AL
        out 20h,al                                                              ; Send to first PIC port
    

Looking around, I have no idea why you would do 0x60+1.
The page link I just sent wrote:
Sending End of Interrupt (EOI)

As you know, when a hardware interrupt triggers, all other interrupts are masked off inside of the Interrupt Mask Register until an EOI signal is sent to the primary controller. This means, we must send an EOI to insure all hardware interrupts are enabled at the end of our Interrupt Routine (IR).


Based on this set of information, 0x61 (effectively) is not an option...maybe I'm missing something.



I have read the same thing you did smiddy and tried your example yet it doesn't work the way I(we) think it would.. but, doing it BAiC's way works.. this is something I'm still trying to research and grasp the concept for myself...back to the intel docs... lol

_________________
It's the desire to learn that leads to success...

http://www.webicomp.com
Post 23 Nov 2014, 21:18
View user's profile Send private message Visit poster's website Reply with quote
BAiC



Joined: 22 Mar 2011
Posts: 272
Location: California
BAiC 24 Nov 2014, 03:32
smiddy wrote:
Check this page out, it may provide more details into why things are not working as expected: http://www.brokenthorn.com/Resources/OSDevPic.html

In reviewing my own code I don't do this:
Code:
    mov al,0x60+1
    out 0x20, al
    


I do this:
Code:
.FinishUp:

        mov al,20h                                                              ; Load EOI into AL
        out 20h,al                                                              ; Send to first PIC port
    

Looking around, I have no idea why you would do 0x60+1.
The page link I just sent wrote:
Sending End of Interrupt (EOI)

As you know, when a hardware interrupt triggers, all other interrupts are masked off inside of the Interrupt Mask Register until an EOI signal is sent to the primary controller. This means, we must send an EOI to insure all hardware interrupts are enabled at the end of our Interrupt Routine (IR).


Based on this set of information, 0x61 (effectively) is not an option...maybe I'm missing something.


there are two options to issuing an interrupt response:

1) tell the PIC which interrupt you're responding to directly (in the low 3 bits, corresponding to ints 0-7). this is the 0x60+INT message.
2) tell the PIC to respond to the highest priority interrupt that is currently running. this is the 0x20 message.

just imagine multiple (at least two) higher priority interrupts occurring while the current interrupt is running: you'll end up responding to the highest priority interrupt (not the current) and cause the middle one to begin executing. the fact that it's only the controller being responded to means the device will likely just issue another interrupt (this is usually true for 'line' interrupts and usually false for 'edge' interrupts).

- Stefan

_________________
byte me.
Post 24 Nov 2014, 03:32
View user's profile Send private message Visit poster's website Reply with quote
smiddy



Joined: 31 Oct 2004
Posts: 557
smiddy 24 Nov 2014, 11:25
BAiC wrote:
smiddy wrote:
Check this page out, it may provide more details into why things are not working as expected: http://www.brokenthorn.com/Resources/OSDevPic.html

In reviewing my own code I don't do this:
Code:
    mov al,0x60+1
    out 0x20, al
    


I do this:
Code:
.FinishUp:

        mov al,20h                                                              ; Load EOI into AL
        out 20h,al                                                              ; Send to first PIC port
    

Looking around, I have no idea why you would do 0x60+1.
The page link I just sent wrote:
Sending End of Interrupt (EOI)

As you know, when a hardware interrupt triggers, all other interrupts are masked off inside of the Interrupt Mask Register until an EOI signal is sent to the primary controller. This means, we must send an EOI to insure all hardware interrupts are enabled at the end of our Interrupt Routine (IR).


Based on this set of information, 0x61 (effectively) is not an option...maybe I'm missing something.


there are two options to issuing an interrupt response:

1) tell the PIC which interrupt you're responding to directly (in the low 3 bits, corresponding to ints 0-7). this is the 0x60+INT message.
2) tell the PIC to respond to the highest priority interrupt that is currently running. this is the 0x20 message.

just imagine multiple (at least two) higher priority interrupts occurring while the current interrupt is running: you'll end up responding to the highest priority interrupt (not the current) and cause the middle one to begin executing. the fact that it's only the controller being responded to means the device will likely just issue another interrupt (this is usually true for 'line' interrupts and usually false for 'edge' interrupts).

- Stefan


Now I am even more confused. Although, I think I get what you're saying. So, no matter what bit 5 has to be set on the Operation Command Word (OCW) (ala 0x20 or 0x60, etcetera). The fact that you use 0x60 says you're wishing to end a specific interrupt. Bit 0, of the OCW says which interrupt level in which to react to, in this case an L0, which I'm not sure of, because 'line' triggered doesn't make sense to me. Where 'level' triggered would, being that there are three bits, L0 thru L2, that correspond to 0 to 7 levels, depending on the bits used. This is what must be confusing me. You're saying that since the keyboard ISR is 1, you set L0 = 1, and the bits 5 and 6 being set says, only react to the end of this L0. The L0 thru L2 correspond to the ISRs, in this case should be set for each ISR's number (for each PIC). The jargon used is confusing, since I get "line" now, where level is being used in the data sheet.

So, the fact that mine works is only likely because I only have it and the timer running, it gets much more complicated if I have more items running, and I would run into collisions as you must be saying. Is that correct?
Post 24 Nov 2014, 11:25
View user's profile Send private message Reply with quote
BAiC



Joined: 22 Mar 2011
Posts: 272
Location: California
BAiC 24 Nov 2014, 16:38
first of all: using the term "line" was an error on my part. the term "Level" is what I meant. I haven't used the term in awhile so I honestly forgot.

secondly for the edge/level thing:

the hardware may use either but it doesn't change the response to the interrupt controller: you always need to send an End of Interrupt. you configure the Edge/Level when you initialize the controller for a specific interrupt pin. btw: the configuration ports for Edge/Level are at 0x4D0 (master) and 0x4D1 (slave). the ports are readable so you might get some insight into the current BIOS configuration of your computer by looking at it.

as for the EOI:

I've seen the 0x20 on every example I've ever read concerning the PIC as well as the documentation. I only learned about the Specific EOI by reading the documentation. I made a judgment call to ignore the non-specific EOI to avoid the race condition. I have interrupts for keyboard(int1),soundblaster(int5, not used any more), floppy(int6), rtc(int8), mouse(int12), ATA HardDrive/Optical(int14 and int15). all of them work as expected using the Specific Interrupt method so I have no reason to use the non-specific mode.

Quote:
So, no matter what bit 5 has to be set on the Operation Command Word (OCW)


bit 5 is set for both methods but I think it's a coincidence. this is what I understand of the OCW situation: when you write to port 0x20 the device looks at bit 4 first. if bit 4 is 1 then it's an Initialize Command Word. if it's a 0 then bit 3 specifies which OCW it is (2 or 3, OCW1 is the Interrupt Mask which is at address 0x21 rather than 0x20).

- Stefan

_________________
byte me.
Post 24 Nov 2014, 16:38
View user's profile Send private message Visit poster's website Reply with quote
smiddy



Joined: 31 Oct 2004
Posts: 557
smiddy 24 Nov 2014, 18:13
Thanks, I like the specific EOI.

I'm a "hardware guy" learning to code, for fun, which is what confused me on the edge/level. I do a lot of analysis in that realm developing systems.

I hope to have timer, keyboard, and HDDs setup by years end, if I can find time to ring out my memory mapping, and usage. But that's another topic for another time.

I appreciate your insight, thanks!

Smiddy
Post 24 Nov 2014, 18:13
View user's profile Send private message Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  


< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2024, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.