Эмулятор виртуального параллельного порта - PullRequest
9 голосов
/ 17 октября 2011

В моем курсе по компьютерным сетям мы должны изучать программирование параллельных портов, используя собственные регистры (например, используя команды, подобные outportb). У меня нет параллельного порта (потому что я живу в 2011 году), но я хочу попрактиковаться в программах (я установил старую TurboC 3 IDE с помощью DOSBox). Есть ли программа, которая эмулирует параллельные порты, такие как , эта программа эмулирует последовательные порты?

Ответы [ 3 ]

2 голосов
/ 19 октября 2011

Поскольку среда в любом случае фальшивая, т. Е. У вас нет действительного порта для игры, вы также можете эмулировать функциональность порта в вашей программе.

Вот как это сделать в Windows, используя Структурная обработка исключений (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;
}

Вывод:

C:\>PortEmu.exe
portb=0x0
portb=0x55
portb=0xFF
portw=0xAAAA
portd=0x12345678
portd=0x1234AA55

Просто измените реализацию ReadPort() и WritePort() сделать что-то более полезное или более подходящее для работы с портом принтера.

0 голосов
/ 17 октября 2011

Я не знаю ни о каком программном обеспечении, хотя я не удивлюсь, если Linux Wine хорошо справится с поддержкой параллельного порта, хотя я не знаю, можно ли его полностью виртуализировать при недостатке физического LPT.

Когда мне приходится тестировать совместимость с устаревшими версиями, я всегда удивляюсь, как легко найти дешевый старый ПК.

Увы, это в значительной степени регионально-ориентированный, но посещение местного магазина перепродажи или операции по переработке компьютера. Например, в Портленде я бы посетил Free Geek и Goodwill и не ожидал, что заплатит больше 15 долларов. Если ваше время стоит многого, это, вероятно, более доступно, чем возиться с эмуляторами, а потом удивляться, насколько они хороши.

0 голосов
/ 17 октября 2011

Похоже, что dosbox может не поддерживать параллельные порты без патчей . Также представляется, что virtualbox также еще не поддерживает параллельные порты. Но даже если бы они поддерживали параллельные порты, вам все равно понадобилось бы что-то на другом конце - либо драйвер отладки в операционной системе вашего хоста, либо что-то вроде адаптера USB-Parallel (доступно в обычных магазинах).

Не могли бы вы рассказать подробнее о том, почему вы хотите узнать о параллельном порту ? Как вы и предполагаете, это в основном мертвый интерфейс в 2011 году. Если вы действительно хотите играть с низкоуровневым параллельным вводом / выводом, вы можете обратиться к платформе Arduino .

...