虚拟并行端口仿真器

时间:2011-10-17 15:07:54

标签: c emulation virtualization device

在我的计算机网络课程中,我们应该通过使用本机寄存器来学习并行端口编程(比如使用outportb之类的命令)。我没有并行端口(因为我住在2011年)但想要练习程序(我使用dosbox安装了旧的turboc 3 IDE)。是否存在模拟并行端口的程序,如this程序模拟串口?

3 个答案:

答案 0 :(得分:2)

由于环境是假的,即你没有实际的端口可以使用,你也可以模拟程序中的端口功能。

以下是使用 Structured Exception Handling (SEH)在Windows中执行此操作的方法:

// 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()的实施,即可根据打印机端口操作执行更有用或更多功能。

答案 1 :(得分:0)

看起来dosbox可能不支持没有patches的并行端口。它还显示virtualboxdoesn't yet support个并行端口。但即使他们确实支持并行端口,你仍然需要另一端的东西 - 主机操作系统上的调试驱动程序,或USB转并行适配器(通常在零售商处可用)。

您能详细说明为什么要了解parallel port吗?正如你的建议,它在2011年是一个基本上死机的界面。如果您真的想要使用低级并行风格的I / O,您可能需要查看Arduino平台。

答案 2 :(得分:0)

我不知道有任何软件,但是如果Linux Wine在支持并行端口方面做得很好,我也不会感到惊讶,虽然我不知道它是否可以在缺少时完全虚拟化物理LPT。

当必须进行遗留兼容性测试时,我总是惊讶于找到一台便宜的旧PC是多么容易。

唉,这是一个高度区域性的,但访问当地的转售商店或电脑回收业务。例如,在波特兰,我会访问Free Geek和Goodwill,并且不会期望支付超过15美元。如果你的时间价值很高,这可能比搞乱仿真器更实惠,然后想知道它们有多好。