;//--------------------------------------------------------------- ;// reporter.s ;// ;// This example reprogramms the 8259A Interrupt Controllers, ;// then shows a real-time display for any device-interrupts. ;// ;// assemble with: $ as86 reporter.s -b reporter.b ;// install using: $ dd if=reporter.b of=/dev/fd0 seek=1 ;// ;// NOTE: This code begins executing with CS:IP = 1000:0002. ;// ;// programmer: ALLAN CRUSE ;// written on: 08 MAR 2004 ;//--------------------------------------------------------------- .WORD 0xABCD ; programming signature ;----------------------------------------------------------------- main: mov ax, cs ; address this segment mov ds, ax ; with DS register pop dword return_address ; store return-address mov ss, ax ; adjust SS register lea esp, tos0 ; and set new stacktop call create_statusline call setup_new_vectors call program_both_PICs call do_keyboard_input call program_both_PICs call remove_statusline push dword return_address ; recover our exit-address retf ; exit to program launcher ;----------------------------------------------------------------- MACRO isr pushf ; push FLAGS register push #?1 ; push interrupt-ID call action ; goto common handler MEND ;----------------------------------------------------------------- myisrs: isr(0x08) isr(0x09) isr(0x0A) isr(0x0B) isr(0x0C) isr(0x0D) isr(0x0E) isr(0x0F) isr(0x70) isr(0x71) isr(0x72) isr(0x73) isr(0x74) isr(0x75) isr(0x76) isr(0x77) ISRLEN EQU ( * - myisrs )/16 ;----------------------------------------------------------------- ;----------------------------------------------------------------- return_address: .LONG 0 ; to store exit-address ;----------------------------------------------------------------- legend: .ASCII "TICK KYBD CASC COM2 COM1 LPT2 FDRV LPT1 " .ASCII "CMOS ---- ---- ---- PS/2 MATH HDRV ---- " .ASCII " 0 0 0 0 0 0 0 0 " .ASCII " 0 0 0 0 0 0 0 0 " ;----------------------------------------------------------------- create_statusline: ; setup video display for 28-lines of text mov ax, #0x0003 ; reset text display-mode int 0x10 ; request BIOS service mov ax, #0x1111 ; load 8x14 character-set mov bl, #0 ; in character-table zero int 0x10 ; request BIOS service ; reduce active number of display-lines to 25 push ds ; preserve DS register mov ax, #0x40 ; address ROM-BIOS data mov ds, ax ; using DS register mov word [0x84], #24 ; set last display-line pop ds ; restore DS register ; draw the display-legend and initial counts mov ax, #0xB800 ; address video memory mov es, ax ; with ES register mov ax, #26 ; output line-number imul di, ax, #160 ; offset to the line cld ; forward processing lea si, legend ; point to text string mov ah, #0x07 ; load color attribute mov cx, #160 ; number of characters .L1: lodsb ; fetch next character stosw ; store char and color loop .L1 ; again for more chars ret ;----------------------------------------------------------------- counter: .SPACE 32 ; 16 counters (word-size) ;----------------------------------------------------------------- INTAORG EQU 0x08 ; default base for INTA INTBORG EQU 0x70 ; default base for INTB IRQBASE EQU 0x90 ; revised base for PICs ;----------------------------------------------------------------- base1: .BYTE IRQBASE+0 ; holds baseID of PIC #1 base2: .BYTE IRQBASE+8 ; holds baseID of PIC #2 mask1: .BYTE -1 ; holds mask from PIC #1 mask2: .BYTE -1 ; holds mask from PIC #2 ;----------------------------------------------------------------- ;----------------------------------------------------------------- setup_new_vectors: push ds ; preserve registers push es xor ax, ax ; address vector table mov es, ax ; with ES register mov ax, #IRQBASE ; initial vector-number imul di, ax, #4 ; times vector-width cld ; do forward processing mov ax, cs ; code segment-address shl eax, #16 ; is vector hiword lea ax, myisrs ; point to first isr mov cx, #16 ; number of vectors .L3: stosd ; store next vector add ax, #ISRLEN ; point to next isr loop .L3 ; store next vector pop es ; restore registers pop ds ret ;----------------------------------------------------------------- do_keyboard_input: mov bh, #0 ; output display-page again: mov ah, #1 ; peek_keyboard_input int 0x16 ; request BIOS service jz again ; none? keep trying mov ah, #0 ; read_keyboard_input int 0x16 ; request BIOS service cmp ax, #0x011B ; was -key? je finis ; yes, exit this loop cmp al, #0x0D ; was -key? jne ahead ; no, output ascii push ax mov ax, #0x0E0A ; else output linefeed int 0x10 ; request BIOS service pop ax ahead: mov ah, #0x0E ; write_TTY int 0x10 ; request BIOS service jmp again finis: mov ax, #0x0E0A ; output linefeed int 0x10 ; request BIOS service mov ax, #0x0E0D ; output carriage-return int 0x10 ; request BIOS service mov al, #INTAORG ; original ID for PIC #1 mov base1, al ; use when reprogramming mov al, #INTBORG ; original ID for PIC #2 mov base2, al ; use when reprogramming ret ;----------------------------------------------------------------- ;----------------------------------------------------------------- program_both_PICs: cli ; no device interrupts mov ax, #0x1000 ; address this segment mov ds, ax ; with DS register in al, #0x21 ; get mask for PIC #1 xchg al, mask1 ; swap with memory out #0x21, al ; set mask for PIC #1 in al, #0xA1 ; get mask for PIC #2 xchg al, mask2 ; swap with memory out #0xA1, al ; set mask for PIC #2 mov al, #0x11 ; write ICW1 out #0x20, al ; to PIC #1 mov al, base1 ; write ICW2 out #0x21, al ; to PIC #1 mov al, #0x04 ; write ICW3 out #0x21, al ; to PIC #1 mov al, #0x01 ; write ICW4 out #0x21, al ; to PIC #1 mov al, #0x11 ; write ICW1 out #0xA0, al ; to PIC #2 mov al, base2 ; write ICW2 out #0xA1, al ; to PIC #2 mov al, #0x02 ; write ICW3 out #0xA1, al ; to PIC #2 mov al, #0x01 ; write ICW4 out #0xA1, al ; to PIC #3 in al, #0x21 ; get mask for PIC #1 xchg al, mask1 ; swap with memory out #0x21, al ; set mask for PIC #1 in al, #0xA1 ; get mask for PIC #2 xchg al, mask2 ; swap with memory out #0xA1, al ; set mask for PIC #2 sti ; allow interrupts again ret ;----------------------------------------------------------------- remove_statusline: mov ax, #0x0003 ; reset text display-mode int 0x10 ; request BIOS service ret ;----------------------------------------------------------------- ;----------------------------------------------------------------- ;=== Common Interrupt Service Routine (and Helper-Functions) === ;----------------------------------------------------------------- find_the_counter_number: mov ax, 4[bp] ; get interrupt-number xor dx, dx ; extend for division mov cx, #8 ; setup the divisor div cx ; perform a division and ax, #0x0080 ; bit 7 of quotient is or ax, dx ; merged with remainder mov -2[bp], ax ; save counter-number ret ;----------------------------------------------------------------- increment_counter_value: mov ax, #0x1000 ; address this segment mov ds, ax ; with DS register imul bx, -2[bp], #2 ; offset to the counter inc word counter[bx] ; update counter value ret ;----------------------------------------------------------------- write_counter_to_screen: mov ax, #0xB800 ; address video memory mov es, ax ; with ES register mov ax, #27 ; output line-number imul di, ax, #160 ; offset to the line imul ax, -2[bp], #10 ; indent for counter add di, ax ; offset on screen add di, #6 ; last digit position mov ax, counter[bx] ; get the counter-value mov bx, #10 ; setup decimal radix mov cx, #3 ; maximum digit-count .L2: xor dx, dx ; extend AX for divide div bx ; divide by the radix or dx, #0x0730 ; remainder into ascii ESEG ; write digit to screen mov [di], dx ; character and color sub di, #2 ; update screen pointer or ax, ax ; quotient was zero? loopnz .L2 ; no, show next digit ret ;----------------------------------------------------------------- setup_stack_to_transfer: xor ax, ax ; address vector table mov ds, ax ; with DS register mov ax, 4[bp] ; get vector ID-number imul si, ax, #4 ; get vector's offset mov ax, 0[si] ; fetch vector loword mov 2[bp], ax ; store vector loword mov ax, 2[si] ; fetch vector hiword mov 4[bp], ax ; store vector hiword ret ;----------------------------------------------------------------- ;----------------------------------------------------------------- action: push bp ; save current frame mov bp, sp ; setup new stackframe sub sp, #2 ; allocate word storage pusha push ds push es call find_the_counter_number call increment_counter_value call write_counter_to_screen call setup_stack_to_transfer pop es pop ds popa mov sp, bp ; discard temporary word pop bp ; recover frame-pointer iret ; resume suspended code ;----------------------------------------------------------------- .ALIGN 16 ; alignment at paragraph .SPACE 512 ; reserved for stack use tos0: ; label fop top-of-stack ;----------------------------------------------------------------- END