📄 io.c
字号:
/* * io.c -- * * This file implements a couple of simple memory-mapped I/O * devices for the MIPS DLX simulator. * * This file is part of DISC. It came from the file "io.c" * in the distribution of "dlxsim" available at: * ftp://max.stanford.edu/pub/hennessy-patterson.software/dlx.tar.Z * * The original source code is copyright as follows: * * Copyright 1989 Regents of the University of California * Permission to use, copy, modify, and distribute this * software and its documentation for any purpose and without * fee is hereby granted, provided that the above copyright * notice appear in all copies. The University of California * makes no representations about the suitability of this * software for any purpose. It is provided "as is" without * express or implied warranty. */#include <ctype.h>#include <stdio.h>#include <fcntl.h>#include <unistd.h>#include "dlx.h"/* * Terminal input is handled by polling the terminal for input every * once-in-a-while during simulation (the simulator is already busy- * waiting during input so this doesn't make things any worse). For * terminal output, the character gets output to the terminal * immediately, but the terminal output device doesn't get marked as * ready until many instructions later. *//* * How many instructions to wait between checks for terminal input: */#define INPUT_WAIT 5000/* * How many instructions must elapse between a character is received * for output and its transmission is considered complete. */#define OUTPUT_DELAY 500/* * Forward declarations for procedures defined in this file: */static void CheckInput(DLX *);static void InputTimerProc(DLX *);static void MarkOutput(DLX *);/* *---------------------------------------------------------------------- * * Io_Init -- * * This procedure is called whenever a new machine is created. * Its job is to initialize the part of the machine structure * related to I/O. * * Results: * None. * * Side effects: * Depends on the I/O devices (caller need not know about this). * *---------------------------------------------------------------------- */voidIo_Init(machPtr) register DLX *machPtr; /* New machine. */{ machPtr->ioState.flags = IO_TERM_OUTPUT_READY; /* * Arrange for periodic callbacks to check for terminal input. */ Sim_CallBack(machPtr, INPUT_WAIT, InputTimerProc, (ClientData) machPtr);}/* *---------------------------------------------------------------------- * * Io_Read -- * * Read an I/O device register, if one exists at the given * address. * * Results: * The return value is non-zero if there is an I/O register at * address; otherwise the return value is zero. If the register * exists, its contents are stored at *valuePtr. * * Side effects: * None. * *---------------------------------------------------------------------- */intIo_Read(machPtr, address, valuePtr) register DLX *machPtr; /* Machine whose memory is being read. */ unsigned int address; /* Desired address of I/O register. */ int *valuePtr; /* Store contents of I/O register here. */{ int result = 0; switch (address) { case IO_RECV_CONTROL: if (machPtr->ioState.flags & IO_TERM_INPUT_READY) { result |= IO_READY; } if (machPtr->ioState.flags & IO_TERM_INPUT_IE) { result |= IO_IE; } break; case IO_RECV_DATA: result = machPtr->ioState.input & 0xff; if (machPtr->ioState.flags & IO_TERM_INPUT_READY) { machPtr->ioState.flags &= ~IO_TERM_INPUT_READY; if (machPtr->ioState.flags & IO_TERM_INPUT_IE) { Cop0_IntPending(machPtr, 0, -1); } CheckInput(machPtr); } break; case IO_TRANS_CONTROL: if (machPtr->ioState.flags & IO_TERM_OUTPUT_READY) { result |= IO_READY; } if (machPtr->ioState.flags & IO_TERM_OUTPUT_IE) { result |= IO_IE; } break; case IO_TRANS_DATA: break; default: return 0; } *valuePtr = result; return 1;}/* *---------------------------------------------------------------------- * * Io_Write -- * * Write an I/O device register, if one exists at the given * address. * * Results: * The return value is non-zero if there is an I/O register at * address; otherwise the return value is zero. If the register * exists, its contents are overwritten with value. * * Side effects: * The given memory location get modified, which may start an * I/O device or do any of several other things. * *---------------------------------------------------------------------- */intIo_Write(machPtr, address, value, size) register DLX *machPtr; /* Machine whose memory is being written. */ unsigned int address; /* Desired address of I/O register. */ int value; /* New value for I/O register. */ int size; /* Size of value in bytes (1, 2, or 4). */{ switch (address & ~0x3) { case IO_RECV_CONTROL: if (((address & 0x3) + size) < 4) { break; } if (value & IO_IE) { if (!(machPtr->ioState.flags & IO_TERM_INPUT_IE)) { machPtr->ioState.flags |= IO_TERM_INPUT_IE; if (machPtr->ioState.flags & IO_TERM_INPUT_READY) { Cop0_IntPending(machPtr, 0, 1); } } } else { if ((machPtr->ioState.flags & (IO_TERM_INPUT_IE|IO_TERM_INPUT_READY)) == (IO_TERM_INPUT_IE|IO_TERM_INPUT_READY)) { Cop0_IntPending(machPtr, 0, -1); } machPtr->ioState.flags &= ~IO_TERM_INPUT_IE; } break; case IO_RECV_DATA: break; case IO_TRANS_CONTROL: if (((address & 0x3) + size) < 4) { break; } if (value & IO_IE) { if (!(machPtr->ioState.flags & IO_TERM_OUTPUT_IE)) { if (machPtr->ioState.flags & IO_TERM_OUTPUT_READY) { Cop0_IntPending(machPtr, 0, 1); } machPtr->ioState.flags |= IO_TERM_OUTPUT_IE; } } else { if ((machPtr->ioState.flags & (IO_TERM_OUTPUT_IE|IO_TERM_OUTPUT_READY)) == (IO_TERM_OUTPUT_IE|IO_TERM_OUTPUT_READY)) { Cop0_IntPending(machPtr, 0, -1); } machPtr->ioState.flags &= ~IO_TERM_OUTPUT_IE; } break; case IO_TRANS_DATA: if (((address & 0x3) + size) < 4) { break; } if (machPtr->ioState.flags & IO_TERM_OUTPUT_READY) { char c; /* * Start transmitting data, mark transmitter not ready, and * arrange for transmitter to be marked ready again later. */ c = value; if (write(1, &c, 1) != 1) { fprintf(stderr, "Internal error writing to stdout!\n"); exit(1); } machPtr->ioState.flags &= ~IO_TERM_OUTPUT_READY; if (machPtr->ioState.flags & IO_TERM_OUTPUT_IE) { Cop0_IntPending(machPtr, 0, -1); } Sim_CallBack(machPtr, OUTPUT_DELAY, MarkOutput, (ClientData) machPtr); } break; default: return 0; } return 1;}/* *---------------------------------------------------------------------- * * Io_BeginSim -- * * This procedure is invoked just before a simulation begins, * so that anything I/O-related (such as resetting terminal * characteristics) may be done. * * Results: * None. * * Side effects: * I/O-related stuff is set up (e.g. terminal characteristics * are reset). * *---------------------------------------------------------------------- */voidIo_BeginSim(machPtr) register DLX *machPtr; /* Machine being simulated. */{ struct termios term; /* * Save terminal state, and put it into a raw-er mode during * the simulation. */ tcgetattr(0, &term); machPtr->ioState.savedState = term; term.c_lflag &= ~ECHO; tcsetattr(0, TCSANOW, &term); }/* *---------------------------------------------------------------------- * * Io_EndSim -- * * This procedure is invoked just after a simulation command * completes, so that anything I/O-related (such as resetting * terminal characteristics for Disc command processing) may * be done. * * Results: * None. * * Side effects: * I/O-related stuff is reset (e.g. terminal characteristics). * *---------------------------------------------------------------------- */voidIo_EndSim(machPtr) register DLX *machPtr; /* Machine being simulated. */{ /* * Read a pending input character, if any, and restore terminal * state. */ CheckInput(machPtr); tcsetattr(0, TCSANOW, &(machPtr->ioState.savedState));}/* *---------------------------------------------------------------------- * * CheckInput -- * * Check to see if an input character has arrived; if so, read it * in and update the I/O control registers. * * Results: * None. * * Side effects: * I/O device state may change, and interrupts may occur. * *---------------------------------------------------------------------- */static voidCheckInput(machPtr) register DLX *machPtr; /* Machine to check for I/O. */{ /* * See if there is an input character on the terminal. *//* char c; int count; if (!(machPtr->ioState.flags & IO_TERM_INPUT_READY)) { ioctl(0, FIONREAD, (char *) &count); if (count > 0) { if (read(0, &c, 1) != 1) { fprintf(stderr, "Internal error reading stdin!\n"); exit(1); } machPtr->ioState.input = c; machPtr->ioState.flags |= IO_TERM_INPUT_READY; if (machPtr->ioState.flags & IO_TERM_INPUT_IE) { Cop0_IntPending(machPtr, 0, 1); } } } */}/* *---------------------------------------------------------------------- * * InputTimerProc -- * * This procedure is invoked periodically during input to see * if any I/O has completed. * * Results: * None. * * Side effects: * I/O device state may change, and interrupts may occur. * *---------------------------------------------------------------------- */static voidInputTimerProc(machPtr) register DLX *machPtr; /* Machine to check for I/O. */{ CheckInput(machPtr); /* * Re-register ourselves to get called again later. */ Sim_CallBack(machPtr, INPUT_WAIT, InputTimerProc, (ClientData) machPtr);}/* *---------------------------------------------------------------------- * * MarkOutput -- * * This procedure is called back by the simulator after a number * of instructions have been executed since starting an output * operation. * * Results: * None. * * Side effects: * The transmitter unit is marked as "ready" again. * *---------------------------------------------------------------------- */static voidMarkOutput(machPtr) DLX *machPtr; /* Machine whose transmitter should be * marked ready again. */{ machPtr->ioState.flags |= IO_TERM_OUTPUT_READY; if (machPtr->ioState.flags & IO_TERM_OUTPUT_IE) { Cop0_IntPending(machPtr, 0, 1); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -