Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Virtual parallel port emulator

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?

like image 270
Rick_2047 Avatar asked Oct 17 '11 15:10

Rick_2047


1 Answers

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.

like image 57
Alexey Frunze Avatar answered Oct 24 '22 22:10

Alexey Frunze