In my computer networks course we are supposed to learn parallel port programming by using the native registers (like using outportb like commands). I don't have a parallel port (because I live in 2011) but want to practice the programs (I installed the old turboc 3 IDE using dosbox). Is there a program which emulates parallel ports like this program emulates serial ports?
Since the environment is fake anyway, i.e. you don't have an actual port to play with, you could just as well emulate the port functionality in your program.
Here's how to do it in Windows using Structured Exception Handling (SEH):
// Filename: PortEmu.c
// Compiled with Open Watcom 1.9 as: wcl386 PortEmu.c
#include <windows.h>
#include <stdio.h>
#include <conio.h>
// Port state. Holds the last value written by OUT.
// IN reads from it.
volatile UINT32 PortState = 0;
UINT32 ReadPort(UINT16 PortNumber, UINT OperandSize)
{
UNREFERENCED_PARAMETER(PortNumber);
switch (OperandSize)
{
default:
case 8:
return PortState & 0xFF;
case 16:
return PortState & 0xFFFF;
case 32:
return PortState;
}
}
void WritePort(UINT16 PortNumber, UINT OperandSize, UINT32 Value)
{
UNREFERENCED_PARAMETER(PortNumber);
switch (OperandSize)
{
default:
case 8:
PortState = (PortState & ~0xFF) | (Value & 0xFF);
break;
case 16:
PortState = (PortState & ~0xFFFF) | (Value & 0xFFFF);
break;
case 32:
PortState = Value;
break;
}
}
// Exception filter to emulate x86 IN and OUT instructions
// in 32-bit Windows application.
int IoExceptionFilter(LPEXCEPTION_POINTERS ep)
{
CONTEXT* c = ep->ContextRecord;
UINT8* instr = (UINT8*)c->Eip;
int OperandSizeIs16Bit = 0;
switch (ep->ExceptionRecord->ExceptionCode)
{
case EXCEPTION_PRIV_INSTRUCTION:
if (instr[0] == 0x66)
{
OperandSizeIs16Bit = 1;
instr++;
}
switch (instr[0])
{
case 0xE4: // IN AL, imm8
*(UINT8*)&c->Eax = ReadPort(instr[1], 8);
c->Eip += 2 + OperandSizeIs16Bit;
return EXCEPTION_CONTINUE_EXECUTION;
case 0xE5: // IN (E)AX, imm8
if (OperandSizeIs16Bit)
*(UINT16*)&c->Eax = ReadPort(instr[1], 16);
else
c->Eax = ReadPort(instr[1], 32);
c->Eip += 2 + OperandSizeIs16Bit;
return EXCEPTION_CONTINUE_EXECUTION;
case 0xEC: // IN AL, DX
*(UINT8*)&c->Eax = ReadPort((UINT16)c->Edx, 8);
c->Eip += 1 + OperandSizeIs16Bit;
return EXCEPTION_CONTINUE_EXECUTION;
case 0xED: // IN (E)AX, DX
if (OperandSizeIs16Bit)
*(UINT16*)&c->Eax = ReadPort((UINT16)c->Edx, 16);
else
c->Eax = ReadPort((UINT16)c->Edx, 32);
c->Eip += 1 + OperandSizeIs16Bit;
return EXCEPTION_CONTINUE_EXECUTION;
case 0xE6: // OUT imm8, AL
WritePort(instr[1], 8, (UINT8)c->Eax);
c->Eip += 2 + OperandSizeIs16Bit;
return EXCEPTION_CONTINUE_EXECUTION;
case 0xE7: // OUT imm8, (E)AX
if (OperandSizeIs16Bit)
WritePort(instr[1], 16, (UINT16)c->Eax);
else
WritePort(instr[1], 32, c->Eax);
c->Eip += 2 + OperandSizeIs16Bit;
return EXCEPTION_CONTINUE_EXECUTION;
case 0xEE: // OUT DX, AL
WritePort((UINT16)c->Edx, 8, (UINT8)c->Eax);
c->Eip += 1 + OperandSizeIs16Bit;
return EXCEPTION_CONTINUE_EXECUTION;
case 0xEF: // OUT DX, (E)AX
if (OperandSizeIs16Bit)
WritePort((UINT16)c->Edx, 16, (UINT16)c->Eax);
else
WritePort((UINT16)c->Edx, 32, c->Eax);
c->Eip += 1 + OperandSizeIs16Bit;
return EXCEPTION_CONTINUE_EXECUTION;
default:
return EXCEPTION_CONTINUE_SEARCH;
}
default:
return EXCEPTION_CONTINUE_SEARCH;
}
}
int main(void)
{
__try
{
outp(0x278, 0x00);
printf("portb=0x%X\n", inp(0));
outp(0x278, 0x55);
printf("portb=0x%X\n", inp(0));
outp(0x278, 0xFF);
printf("portb=0x%X\n", inp(0));
outpw(0x278, 0xAAAA);
printf("portw=0x%X\n", inpw(0));
outpd(0x278, 0x12345678);
printf("portd=0x%X\n", inpd(0));
outpw(0x278, 0xAAAA);
outp(0x278, 0x55);
printf("portd=0x%X\n", inpd(0));
}
__except(IoExceptionFilter(GetExceptionInformation()))
{
}
return 0;
}
Output:
C:\>PortEmu.exe
portb=0x0
portb=0x55
portb=0xFF
portw=0xAAAA
portd=0x12345678
portd=0x1234AA55
Just alter the implementation of ReadPort()
and WritePort()
to do something more useful or more in line with the printer port operation.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With