# Interrupciones del puerto paralelo



## MaMu (Nov 4, 2005)

Bueno, no se si será la hora o que, pero mi puerto paralelo ha cobrado vida propia . Estoy armando un pequeño proyecto al cual no tuve la mejor idea que decidir hacerlo usando las interrupciones del puerto paralelo, en version para MS-DOS (en el queridísimo Turbo Pascal 7).
Antes que nada, empecé analizando la forma de trabajo de las interrupciones en dicho puerto. Si bien, según el estado lógico del Bit C4 (Registro de Control -> Bit 4 : este no tiene conexión externa al DB25 que todos vemos en la pc, puesto que es Lógico, es decir conmutando entre 0 y 1, se activa o desactiva la IRQ). Una vez que activamos la IRQ, la interrupción se generara a partir del S6 (Registro de Estado -> Bit 6: de esta forma, funciona de forma Lógica. Para quienes no conocen cual es el Bit, es el pin #10 del conector DB25), es decir, que se ejecutará la interrupción al detectarse un flanco ascendente o descendente (según en que norma se encuentre el LPT).
Todo esto para que, mediante un pulsador entre S6 y GND, genere una interrupción cada ves que se activa. (nada de pullup, todo digital).
Ahora bien, diganme si estoy equivocado, pero el vector de interrupción (para IRQ7) no es la INT 15 ? (INT 13 para IRQ5). En port 0x0020 ingreso mi vector, en 0x0021 lo restablezco (asi como las máscaras con las que modifico el LPT).

Saludos.


----------



## Marcelo (Nov 4, 2005)

Oye MaMu, cuando vas a tomar vacaciones?...te vas a volver loco.

Lo que dices es cierto si y solo si estás manejando EPP. Así es que debes declara el puerto como EPP, sino en lugar de tomarte el IRQ utilizará la señal de ACK (estamos hablando del pin 10 que es el único que usa INT en el puerto paralelo) y según tengo entendido solo funciona con flanco ascendente o Rising Edge.

Los registros para EPP son:
Puerto de direcciones: Base + 3 y es lectura/escritura
Puerto de Datos: Base + 4 y es lectura/escritura

Ahora, ¿cual es la pregunta?, porque no entendí....

La tabla de vectores de interrupción y su uso común es la anexa y según dice, si es el 15 para comunicación paralela.

(¿Por cierto, el firmware del PIC medidor de temperatura no me lo vas a mandar nunca?)

Saludos,
Marcelo.


----------



## MaMu (Nov 5, 2005)

Marcelo dijo:
			
		

> (¿Por cierto, el firmware del PIC medidor de temperatura no me lo vas a mandar nunca?)
> 
> Saludos,
> Marcelo.



hahahahha, todavia lo estoy buscando, tengo una ensalada de hdd's y cd's



Saludos.


----------



## MaMu (Nov 5, 2005)

Parece ser tu dia de suerte, lo encontré en el 2º CD que tenía a mano.
En realidad la pregunta era si la INT 15 era para manejar la IRQ del puerto paralelo, queria saber si era correcto.

Saludos.


----------



## MaMu (Nov 6, 2005)

El diseño lógico.

*NOTA:* en windows XP no podrá tener acceso a las interrupciones por hardware sino dispone de algun driver (como el PortTalk), ya que estas funciones estan restringidas. 

*Programando la IRQ*

Lo que se quiere lograr, es reemplazar la IRQ del puerto (sólo cuando esta deba ser ejecutada) por otro procedimiento del tipo interrupt

*Pascal*


```
GetIntVec(vector_de_int,pointer_de_int);
```
Guardamos el viejo vector con la int original.

```
SetIntVec(vector_de_int,@mi_procedure_interrupt);
```
Asignamos nuestro procedure al vector como nueva interrupción.

Mis preguntas (nunca utilice la int del puerto paralelo):
(No quiero trabajar en modo EPP, ya que quiero que la interrupción se genere con la señal ACK  - ver diagrama - )

1) Para leer o setear el byte del vector de interrupciones debo utilizar la dirección (port) $21 ?

2) En el reemplazo de la int del puerto paralelo, debo tomarla de (port) $20? (de forma standard devuelve un 1 en el bit 5 cuando se produce la interrupción ACK pin 10 - "S6")


----------



## Marcelo (Nov 6, 2005)

MaMu, creo que esta página te podría aclarar algunas dudas.

http://www.beyondlogic.org/spp/parallel.htm#5

Sino, mandas un mensaje para ponerme a buscar en mis libros.

En Windows XP deberías progamar un DCOM para poder variar los permisos desde las "Herramientas Administrativas". Creo que allí puedes permitir el uso completo del hardware variando los defaults de permisología mediante "Directivas de seguridad" y "Servicios de componentes", pero eso es programación bien avanzada.

¿Pero no estabas haciendo el driver en DOS?

No entiendo algo; al decir:



> Lo que se quiere lograr, es reemplazar la IRQ del puerto (sólo cuando esta deba ser ejecutada) por otro procedimiento del tipo interrupt



¿Deseas simular una interrupción? es decir, físicamente ningún dispositivo genera la interrupción pulsando el pin 10 sino que la "seteas" por software.

Lo que dices parece lógico: Lees Base+0 = $20 o lo que es lo mismo, monitoreas el registro de estados del paralelo y cuando el bit ACK se va a 1, se produjo la interrupción.

Y para activar la interrupción por vía ACK debes colocar a 1 el bit 4 del registro de control (Base+2).

Cuando digo "Base" me refiero al DataPort o al Data Register que es lo mismo. Y lo que te digo es si el puerto es bidireccional, que es cuando puedes recibir datos de esa direccion Base pues en modo unidireccional solo puedes escribir en ella.

Bueno, lee la página que te digo a ver si estamos hablando de lo mismo.

Saludos.
Marcelo.


----------



## MaMu (Nov 6, 2005)

Si, mi idea es setear por software la interrupción. Con respecto a las funciones de privilegio, tan solo lo aclaré, ya que al trabajar en MS-DOS no le doy importancia. Lo que quiero hacer es algo sencillo, a modo de ejemplo te pongo esto:

- quiero que al accionarse el pulsador, imprima en pantalla "Pulsador Accionado" (interrumpiendo la tarea en curso). La idea es hacerlo utilizando la interrupción ACK habilitada por el C4. Si bien existen formas mucho más sencillas de realizar esta operación, la idea es generarla mediante la interrupción, ya que el programa correrá otras tareas simultaneamente (sin hacer un polling del estado). Lo que queria saber, como vos bien me aclaraste lo del DataPort, es si estoy utilizando bien los offsets, que son :

1) 0x0021h -> 021h -> $21 -> Para setear IRQ7
(bit 7 en 0=habilitado / 1=deshabilitado)
2) 0x0020h -> 020h -> $20 -> Acá se lee la interrupción que se produce, ya que cambia el estado del bit 5 a 1. (Y ésta es la que quiero reemplazar por mi "procedimiento").

Ej:


```
program irq_test;

uses dos,crt;

const DirIRQ=$21;
         DirBase=$20;
          DirLPT=$378;
var old_vector:pointer;

{Manejo del Vector de IRQs}
procedure irq7(estado:integer);
begin
   case estado of
    0 :      begin 
                   {código deshabilita DirIRQ=$21;}
              end;
    1 :      begin
                   {código habilita DirIRQ=$21;}
               end;
   eng;
end;

{mi procedure de interrupción}
{+M}
procedure estado_pulsador; interrupt;
begin
  writeln('Pulsador Accionado');
end;
{-M}      

{habilitador de interrupción ACK}
procedure ACK(estado:integer);
begin
   case estado of
    0 :      begin 
                   {código deshabilita DirLPT+2}
              end;
    1 :      begin
                   {código habilita DirLPT+2}
               end;
   eng;
end;


{Programa Principal}
Begin
    irq7(1);
    ACK(1); 
    GetIntVec(DirBase,old_vector);
    SetIntVec(DirBase,@estado_pulsador);
   {...........................}
   {sentencias}
   {...........................}
   keep(0); {sino hay error lo mantengo en memoria}
   {restablesco todo cuando sale de la aplicación}
   ACK(0);
   SetIntVec(DirBase,@old_vector);
   irq7(0);
end.
```

Ahi volque el ejemplo, he omitido las rutinas de comprobaciones y máscaras ya que es secundario.

Quizas con este ejemplo, se entienda más mi duda.

Saludos.


----------



## Marcelo (Nov 7, 2005)

Acuérdate que recién he empezado con el Pascal. Aunque entiendo el código, al no tener todas las rutinas me enredo un poco.

Lo que puedo hacer es decirte como lo veo en pseudo código. (Nota aparte: en el código que anexastes, ¿ _"eng"_ es una instrucción o un error ?)

Si me equivoco por favor me perdonas, pues la programación de interrupciones la hacía para el 6510 de una commodore 128 para manejar scrolling y sprites, así es que hace bastante que no refresco esto.
Lo que voy a tratar de hacer es escribirte un algoritmo (que va a ser largo), de como haría yo esto.

Aqui vamos:

*1)* La familia del 8086 tiene en total 256 interrupciones. El vector de interrupción que te interesa de la tabla de vectores que contiene las ISR (Interrupt Service Routines) es la INT (0F) que corresponde a la dirección de memoria que apuntará el vector cuando el IRQ 7 se habilita. Esto ya lo habíamos dicho.

*2)* Esta familia posee 2 PIC (Programmable Interrupt Controller) y c/u se encarga de 8 interrupciones. Estos 2 PIC están conectados en cascada.

*3)*PIC1 de 0 a 7 y PIC2 de 8 a 15 La interrupciones que podemos programar son 15, todas de hardware y enmascarables (que se pueden ocultar para que el  microprocesador no las "vea"). La tabla de vectores para estos 15 IRQ de los 256 existentes, te la anexé en un post más arriba.

*4)* Tenemos 2 "comandos" o registros principales para controlar las interrupciones: OCW1 (Operation Control Word 1) y OCW2.  OCW1 se utiliza para enmascarar o no los IRQ y el OCW2 sirve para seleccionar como FINALIZAR la interrupción (EOI). También existen las palabras OCW3, ICW1(Initialization Command Word), ICW2,  ICW3 , ICW4 pero creo que estas no las voy a tocar. Estas palabras son las que se envían a los PIC y eso se hace almacenándo el valor deseado en las direcciones de memoria o registros establecidos para cada una de estas palabras.

*5)*Primero se define la OCW1 para decirle al micro cual interupciones vamos a enmascarar y cuales no.

*6)* Debemos saber cual PIC tenemos que usar porque cada uno está en direcciones de memoria distintas. El PIC1 está en 0x20h y el segundo en 0x0Ah. 

*7)* Como te interesa el IRQ7 entonces tu base es 0x20h. Hasta aquí vamos bien. El byte a enviar al PIC1 pareciera ser 10000*0*00. Aquí hay algo importante. El bit 2 de este byte (el que está en negrita), es el que enlaza o conecta el PIC1 con el PIC2. Como lo estamos enmascarando, deberás desactivar también los IRQ 8 al 15 del PIC2.

*8)* OCW1 incide en  parejas de IRQ por bit. Por ejemplo el bit7 actúa sobre los IRQ 7 y 15. La diferencia radica en que si OCW1 la mandas a la dirección 0x21h (0x20h - PIC1) se actúa sobre el 7 y si la "pokeas" en la dirección 0x0Bh (0x0Ah - PIC2) sobre el IRQ15. El bit 0 de OCW1 va con los IRQ 0 y 8, el 1 con los IRQ 1 y 9  y así sucesivamente. Ahora te explico por qué en 0x21h y 0x0Bh.

*9)* Los bits de OCW1 funcionan en complemento, lo que quiere decir que cuando los bit están a 0, los IRQ están activados (a 1 se enmascaran). Por lo tanto si queremos activar el IRQ 7, deberemos definir OCW1 complementado. Habíamos dicho que el supuesto byte era 10000000 (128 = 0x80h) , entonces en OCW1 deberemos poner: 01111111 (127 = 0x7Fh) para dejar activo solo el IRQ7 (recuerda lo que te dije antes, en 0x0B deberas colocar 11111111=255=0xFFh).

*10)* Como no sabes en que estado se encuentran los bits de interrupción en la dirección donde hay que colocar OCW1, debemos hacer un AND con lo que hay allí de manera tal que no vayamos a "colgar" la computadora. LA DIRECCION O REGISTRO DONDE SE ALMACENA OCW1 ES EN *BASE+1* (0x21h para PIC1 y 0x0B para PIC2). Entonces, antes de establecer el Byte de enmascarados hacemos esto: Leemos OCW1  -- hacemos el AND de ese Byte con nuestro Byte de enmascaramiento -- Guardamos el resultado en BASE +1 estableciendo el nuevo valor de OCW1. (lo mismo desbes aplicar para PIC2 con 11111111 porque IRQ2 está enmascarado)

*Ahora estamos listo para capturar la interrupción y que la computadora haga lo que le hemos programado en nuestra rutina de servicios de interrupción. Según vi en el código en Pascal que anexastes, estás claro en como hacerlo.*

*11)* Para poner las cosas como estaban antes de haber actuado sobre estos registros y después de haber hecho lo que queríamos en nuestra rutina de servicios de interrupción, debemos resetear al estado inicial. Para esto hacemos lo siguiente: Leemos OCW1  -- hacemos el OR de ese Byte con nuestro Byte de enmascaramiento COMPLEMENTADO (es decir el que originalmente habíamos tomado: 10000000 = 128 = 0x80h) -- Guardamos el resultado en BASE +1 reestableciendo el valor de OCW1. (lo mismo desbes aplicar para PIC2 con 00000000 porque IRQ2 estaba enmascarado)

*12)* Para enviar la orden de finalización de interrupción al procesador (EOI), deberemos "pokear" el valor 0x20h en la dirección 0x20h para el PIC1 o en la 0x0Ah para el PIC2.

Recuerda que si IRQ2 no lo enmascaras, entonces no hace falta actuar sobre PIC2 a no ser que también desees enmascarar IRQs en ese bloque (PIC2 = IRQ 8 a 15).
Pero para este caso del IRQ 7 que te está sacando el sueño, si lo dejas sin enmascarar,  todos los IRQ desde el 8 hasta el 15 deberás tratarlos dentro de tu ISR (Interrupt Service Routine), pues alcanzarán al microporcesador y dispararán la solicitud de interrupción.

Para generar la interrupción del paralelo, debes colocar a 1 el ya famoso ACK.

Seguro que mucho de lo que te dije aquí ya lo sabías, pero tenía que explicarlo completo para hacerme entender. Me parece que con esto te indiqué más o menos como lo veo yo.

Espero que te ayude.

Saludos,
Marcelo.


----------



## MaMu (Nov 7, 2005)

Marcelo : lo del eng fue un error al tipear. Todo lo que explicaste, esta perfecto y es tal cual lo entiendo yo, pero el tema es el siguiente, a la IRQ7 le corresponde el vector 0Fh (INT 15), ahora bien, en todos los listados de interrupciones me aparece como la INT 17 y no la 15. Esto es importante, ya que justamente es el vector que yo debo reemplazar por mi interrupción.


```
SetIntVec($17,@mi_irq);
```

Saludos.


----------



## Marcelo (Nov 7, 2005)

Si, ya veo.

Eso se establece en el Bios y el paralelo que yo sepa siempre usa el IRQ7 y si tienes un LPT2 el IRQ5.



Déjame seguir buscando a ver de donde sale el 17 y el 15.


----------



## Marcelo (Nov 7, 2005)

Esto es lo que yo tengo.

Según la tabla: 

IRQ7 --> INT 0F o INT 15

IRQ5 --> INT 0D o INT 13

INT 17 (23 en decimal) es para interrupción por software 

Pero según esta página, el Bios extiende el servicio de printer hasta el 17h

http://webpages.charter.net/danrollins/techhelp/0027.HTM

En DOS la cosa no es igual que en Windows y es lógico. Windows no maneja los IRQ como el DOS- Por ejemplo, los COM en Windows son compartidos y puedes tener tantos puertos virtuales como quieras hasta 256 compartiendo IRQs. Esto no lo puede hacer DOS.

Aquí hay unos documentos que te pueden servir:

http://www.csupomona.edu/~myin/ece342/Spring2003/BIOS&DOSProgramming.pdf#search='programming DOS interrupt'

http://zone.ni.com/devzone/conceptd...75a30b35f95bcb8286256865004f8ad6?OpenDocument


----------



## MaMu (Nov 7, 2005)

Marcelo dijo:
			
		

> Si, ya veo.
> 
> Eso se establece en el Bios y el paralelo que yo sepa siempre usa el IRQ7 y si tienes un LPT2 el IRQ5.



El IRQ5 se ejecuta tambien con cada pulsación de la tecla "PrintScreen".

Saludos.


----------



## Marcelo (Nov 7, 2005)

Si MaMu, pero el PrintScreen es una interrupción del DOS (del teclado, luego de que DOS cargó el driver) y no del BIOS. 

En el caso de los LPT, la asignación la hace el BIOS y no el DOS, por lo que la tabla de vectores puede ser redireccionada por el sistema operativo. De ahí la "extensión" del Bios que maneja DOS.

También si ves la tabla anexa, verás que el IRQ5 se lo asignan a la trajeta de sonido, pero en este caso es el Windows quien lo hace.

Es más, si en el Bios del computador haces un cambio a mano de las interrupciones de los puertos COM1 y COM2 es decir que los permutas y además, tienes establecida la opción de que los IRQ son asignados por el OS, verás como en el administrador de programas de Windows aparecen al revés nuevamente, como deberían de estar antes de haber hecho el cambo a mano.

Lo que te quiero decir es que el SO prevalece en lo que respecta a los IRQ y direcciones E/S, sobre el Bios.

No dejes de ver los dos documentos que te linkeé antes.

Saludos.


----------



## MaMu (Nov 7, 2005)

Excelente todo Marcelo, mil gracias.

PD: jeje, podrias darme un sinónimo de "pokear", entiendo que significa ASIGNAR, pero nunca lo habia escuchado.

Otra cosa, 0x0Bh ? no deberia ser Base+1 (del Pic 2) 0x0A0h+1 = 0x0A1h ?

Perdón pero a esta hora ya tengo una ensalada!!! .

Saludos.


----------



## Marcelo (Nov 7, 2005)

_Primero lo de la suma:_

La dirección es 0x0Ah y no 0x0A0h.

0x0Ah + 1 = 0x0Bh  y no 0x0A1h 

esto mismo en decimal sería: 10 +1 = 11; 11 en hexa es 0B.  
A1h en decimal es 161.

El otro caso 20h + 1 = 21h

en decimal: 32 + 1 = 33 que en hexa es 21h, este está correcto.

_Lo del Poke:_

Esa es una "degeneración" de los inicios de la programación cuando las computadoras empezaron a hacerse del dominio público. Hoy casi ya no se usa el modismo.

Las primeras máquinas tenían un Basic incluido que estaba preprogramado y era lo que permitía a los usarios, hacer algo con ellas. 

Como esos lenguaje no tenían todo el potencial de alto nivel que poseen los de ahora, tenían instrucciones para actuar directamente sobre el microporcesador y la memoria, así que en realidad eran una mezcla entre Basic y Assembler. 
Esto era básico en las commodore, synclair, tandy y atari por ejemplo.

Dos de esas instrucciones eran "PEEK" y "POKE"; con una leías y con otra escribías en memoria.

Podías hacer cosas como POKE 0x020h, 0xFFh para colocar FF en 20h, o leer PEEk 0x020h lo que había en 20h.

Entonces, "Pokear" se usaba para decir "escribir en la dirección o registro" y "Peekear" era "leer el registro".  En esos tiempos (los 80) si programabas, era común tener en el escritorio al menos 4 cosas: 
1) El manual del Basic 
2) El mapa de memoria de la computadora
3) La tabla de interrupciones
4) El manual de assembler del micro (6502, 6510 y otros)

Esas computadoras eran increibles y de hecho lo siguen siendo.

http://en.wikipedia.org/wiki/PEEK_and_POKE

(pareciera que lo que escribí aquí, me lo copié de este link de wikipedia  pero es de mi creación, ojo)

Saludos,
Marcelo


----------



## MaMu (Nov 7, 2005)

Gracias Marcelo por la aclaración y por la tan interesante literatura acerca de la Jurassica era de las PC. (Te imaginas si uno pudiese viajar en el tiempo? de seguro no se llamarían Transistor, se llamarían MaMustor!!! o la Ley de MaMohm!!!! jejeje )

PD : seguro que fue la hora de la madrugada la que no me dejo sumar.

Saludos.


----------



## Marcelo (Nov 8, 2005)

De nada MaMu,

Si, y también hubieras podido "inventar" y sacar al mercado la MaMudore 256 para competir con las Commodore 64 y 128 y llenarte de guita. 

Una cosa que me olvidé decirte es que cuando te digo en los posts que "Pokees" quiere decir que uses el método en Pascal para hacer eso, escribir en una dirección de memoria.

¿Ya aclaraste como usar lo de los IRQ y los Registros en DOS?. ¿Me lo explicas cuando lo tengas?.

Saludos.
Marcelo.


----------



## MaMu (Nov 9, 2005)

Si, ya he probado los procedimientos con resultados óptimos, y con la mínima inclusión de assembler posible (ya que la idea es explotar el pascal), los procedimientos que apliqué son :


```
PROCEDURE HabilitaIRQ(Num:Byte);
VAR Mask:Byte;
BEGIN
   IF Num<=7 THEN 
     BEGIN
           Mask:=NOT(1 SHL Num);
           ASM CLI END;
           Port[$21]:=Port[$21] AND Mask;
           ASM STI END;
     END
   ELSE 
     BEGIN
          { IRQ>7}
          Num:=Num-8;
          Mask:=NOT(1 SHL Num);
          ASM CLI END;
          Port[$A1]:=Port[$A1] AND Mask;
          ASM STI END;
          HabilitaIRQ(Num);
     END;
END;
```

Este primero, es para habilitar el número de IRQ que deseo. Nota que ha aparecido una nueva función de Pascal : SHL (tambien esta SHR), la cual realiza un corrimiento hacia izquierda (su contraparte la hace hacia derecha).


```
PROCEDURE DeshabilitaIRQ(Num:Byte);
VAR Mask:Byte;
BEGIN
      IF Num<=7 THEN
        BEGIN
             Mask:=1 SHL Num;
             ASM CLI END;
             Port[$21]:=Port[$21] OR Mask;
             ASM STI END;
        END
      ELSE 
        BEGIN
             {IRQ>7}
             Num:=Num-8;
             Mask:=1 SHL Num;
             ASM CLI END;
             Port[$A1]:=Port[$A1] OR Mask;
             ASM STI END;
             DeshabilitaIRQ(Num);
        END;
END;
```
Este segundo procedimiento es para deshabilitar la IRQ que deseo. Nota ademas que he incluido la menor cantidad de ASM posible (para ganar tiempo...) y que tranquilamente se puede usar la sentencia "inline".

Al principio se tildaba la pc, pero leyendo un poco en la web, he notado que Turbo Pascal tiene algunos problemas para manejar variables Assembler de 32 bits en interrupciones, por lo que casi todo programador Pascal se vuelca al uso de la librería TrapInt. 

El finalizado de la interrupción se realiza con la instrucción Port:

```
Port[$20]:= $20 {para PIC1}
```
Si la IRQ >= 8, entonces tambien tenes que hacer 

```
Port[$A0]:= $20; {para PIC2}
```

Pero en fin, la idea era explotar al máximo el amado Pascal para DOS. 


*Inline*:Inline es una sentencia de Turbo Pascal que hace que sus argumentos del tipo byte,sean volcados directamente en el momento de la compilación,de este modo las órdenes 


```
a:=a+1; 
Inline($CO,$31); 
write(A);
```

Produce unas instrucciones máquina tal que así: 
[ como se traduzca a:=a+1] 
$CO,$31 
[ como se traduce write(A)] 

Importante: Para usar Inline es necesario conocer  los códigos de cada instrucción 
lo que dificulta de manera inpensable la programación .En realidad el sistema de Usar Inline era el usado en Compiladores anteriores al 6.0, pero ahora es inútil e incómodo. 

Inclusiones de Assembler :Es la mejor manera para  incorporar assembler  a  los programas en Pascal. Cuando quiera hacer una inclusión en Assembler, puede poner algo de código ensamblador por la palabra reservada *asm*, y seguido de esta todo el código que se quiera y para finalizar se pone un END y un punto y coma (Ojo!!! este método sólo funciona con Turbo Pascal 6.0 o superior ya que el 5.5 no contempla como palabra reservada a "asm") 

Estructura de la inclusión en assembler 

```
asm 
{ 

código assembler 

} 
end;
```



PD : te adjunto el source de TrapInt.

Saludos.


----------



## Marcelo (Nov 9, 2005)

Ahora si sigue lo que hablamos.
Gracias por la explicación y el código. Ya lo corté y lo pegué en un archivo Word para guardarlo.
Me imagino que si lo quieres usar en Delphi7, es la misma cosa.

¿Por qué usas la dirección A0h y A1h para PIC2? entonces era OxOA0h para PIC2 y no 0x0Ah, ¿no? (¿PIC2 está en Decimal 160 y no en Dec. 10  ????).

Aclárame esto porque me enredó la dirección.

Saludos,
Marcelo.


----------



## MaMu (Nov 10, 2005)

Marcelo dijo:
			
		

> ¿Por qué usas la dirección A0h y A1h para PIC2? entonces era OxOA0h para PIC2 y no 0x0Ah, ¿no? (¿PIC2 está en Decimal 160 y no en Dec. 10  ????).



Efectivamente, la dirección del PIC2 era el offset 0x0A0h (resolve) 0x0A1h (set). Después de leer algunos apuntes, no me quedaba todavia muy claro, ya que en algunos tenía 0x0Ah y 0x0Bh como vos lo mencionaste, pero... ante la duda, se me ocurrió averiguarlo mediante el uso de GetIntVec y SetIntVec, a nivel de Assembler, tomando como INT 21h, donde Ah=35h -> GetIntVec y Ah=25h -> SetIntVec. En la función Ah=35h, donde Al=Nº de IRQ , devuelve en CS:BS el puntero de la interrupción (segmento y corrieminto), dándome como dirección del PIC1 (para cualquier IRQ de 0 a 7) la dirección 0x020h / 0x021h, y para el PIC2 (para cualquier IRQ de 8 a 15) la dirección 0x0A0h / 0x0A1h. Luego de obtener las 2 direcciones, probé un "Pokeeo" sin enmascarar para producir un cuelgue intensiónal de la pc, utilizando simplemente la rutina Port[$21] y Port[$A1]. De todas maneras y más aún que implementé estas rutinas en un 80486DX (procesador Ciryx - MS-DOS 6.22 Win 3.11), recomendaría verificar bien, cual es la dirección del PIC2.

Saludos.


----------



## Marcelo (Nov 10, 2005)

Ok, copiado.

Bueno, pero si te funciona y chequeastes en caliente entonces definitivamente debe ser esa, A0h.

Gracias por aclararlo.

Marcelo.


----------

