Ejemplo n.º 1
0
/*! \brief reset the ACIA */
void myacia_reset(void)
{
    DEBUG_LOG_MESSAGE((acia.log, "reset_myacia"));

    acia.rs232_status_lines = 0;
    rs232drv_set_status(acia.fd, acia.rs232_status_lines);

    acia.cmd = ACIA_CMD_DEFAULT_AFTER_HW_RESET;
    acia.ctrl = ACIA_CTRL_DEFAULT_AFTER_HW_RESET;
    acia.ectrl = T232_ECTRL_DEFAULT_AFTER_HW_RESET;

    set_acia_ticks();

    acia.status = ACIA_SR_DEFAULT_AFTER_HW_RESET;
    acia.in_tx = ACIA_TX_STATE_NO_TRANSMIT;

    if (acia.fd >= 0) {
        rs232drv_close(acia.fd);
    }
    acia.fd = -1;

    if (acia.alarm_tx) {
        alarm_unset(acia.alarm_tx);
    }
    if (acia.alarm_rx) {
        alarm_unset(acia.alarm_rx);
    }
    acia.alarm_active_tx = 0;
    acia.alarm_active_rx = 0;

    acia_set_int(acia.irq_type, acia.int_num, IK_NONE);
    acia.irq = 0;
}
Ejemplo n.º 2
0
/* gets a byte to the RS232 line, returns !=0 if byte received, byte in *b. */
int rs232dev_getc(int fd, BYTE * b)
{
    DWORD number_of_bytes = 1;

#if DEBUG_FAKE_INPUT_OUTPUT

    if (fds[fd].rts && fds[fd].dtr && rs232_debug_fake_input_available) {
        if (rs232_debug_fake_input_available > 0) {
            --rs232_debug_fake_input_available;
        }
        *b = rs232_debug_fake_input;
    } else {
        number_of_bytes = 0;
    }

#else
    if (fds[fd].rts && fds[fd].dtr) {
        if (ReadFile(fds[fd].fd, b, number_of_bytes, &number_of_bytes, NULL) == 0) {
            return -1;
        }
    } else {
        number_of_bytes = 0;
    }

#endif

    if (number_of_bytes) {
        DEBUG_LOG_MESSAGE((rs232dev_log, "rs232dev: Input %u = `%c'.", (unsigned)*b, *b));
        return 1;
    }

    return 0;
}
Ejemplo n.º 3
0
/* closes the rs232 window again */
void rs232dev_close(int fd)
{
    DEBUG_LOG_MESSAGE((rs232dev_log, "rs232dev: close(fd=%d).", fd));

    if (fd < 0 || fd >= RS232_NUM_DEVICES) {
        log_error(rs232dev_log, "Attempt to close invalid fd %d.", fd);
        return;
    }
    if (!fds[fd].inuse) {
        log_error(rs232dev_log, "Attempt to close non-open fd %d.", fd);
        return;
    }

    if (!SetCommState(fds[fd].fd, &fds[fd].restore_dcb)) {
        DEBUG_LOG_MESSAGE((rs232dev_log, "rs232dev: SetCommState '%s' on close failed: %d.\n", rs232_devfile[fd], GetLastError()));
    }

    CloseHandle(fds[fd].fd);
    fds[fd].inuse = 0;
}
Ejemplo n.º 4
0
/*! \brief read the ACIA register values

  This function is used to read the ACIA values from the computer.
  All side-effects are executed.

  \param addr
    The address of the ACIA register to read

  \return
    The value the register has
*/
BYTE myacia_read(WORD addr)
{
#if 0 /* def DEBUG */
    static BYTE myacia_read_(WORD);
    BYTE byte = myacia_read_(addr);
    static WORD last_addr = 0;
    static BYTE last_byte = 0;

    if ((addr != last_addr) || (byte != last_byte)) {
        DEBUG_LOG_MESSAGE((acia.log, "read_myacia(%04x) -> %02x", addr, byte));
    }
    last_addr = addr; last_byte = byte;
    return byte;
}
Ejemplo n.º 5
0
/*! \internal \brief Receive (RX) alarm function

 This function is called when the receive alarm fires.
 It checks if there is any data received. If there is some,
 this data is made available in the ACIA data register (DR)

 \param offset
   The clock offset this alarm is executed at.

   The current implementation of the emulation core does
   not allow to guarantee that the alarm will fire exactly
   at the time it was scheduled at. The offset tells the
   alarm function how many cycles have passed since the
   time the alarm was scheduled to fire. Thus, (myclk - offset)
   yiels the clock count which the alarm was scheduled to.

 \param data
   Additional data defined in the call to alarm_new().
   For the acia implementation, this is always NULL.

 \remark
   The alarm is re-scheduled for the time when the reception
   has completed.
*/
static void int_acia_rx(CLOCK offset, void *data)
{
    DEBUG_VERBOSE_LOG_MESSAGE((acia.log, "int_acia_rx(offset=%ld, myclk=%d", offset, myclk));

    assert(data == NULL);

    do {
        BYTE received_byte;

        if (acia.fd < 0) {
            break;
        }

        if (!rs232drv_getc(acia.fd, &received_byte)) {
            break;
        }

        DEBUG_LOG_MESSAGE((acia.log, "received byte: %u = '%c'.",
                           (unsigned) received_byte, received_byte));

        /*! \todo: What happens on the real 6551? Is the old value overwritten in
         * case of an overrun, or is it not?
         */
        acia.rxdata = received_byte;

        /* generate an interrupt if the ACIA was configured to generate one */
        if (!(acia.cmd & ACIA_CMD_BITS_IRQ_DISABLED)) {
            acia_set_int(acia.irq_type, acia.int_num, acia.irq_type);
            acia.irq = 1;
        }

        if (acia.status & ACIA_SR_BITS_RECEIVE_DR_FULL) {
            acia.status |= ACIA_SR_BITS_OVERRUN_ERROR;
            break;
        }

        acia.status |= ACIA_SR_BITS_RECEIVE_DR_FULL;
    } while (0);


    acia.alarm_clk_rx = myclk + acia.ticks_rx;
    alarm_set(acia.alarm_rx, acia.alarm_clk_rx);
    acia.alarm_active_rx = 1;
}
Ejemplo n.º 6
0
/* get the status lines of the RS232 device */
enum rs232handshake_in rs232dev_get_status(int fd)
{
    enum rs232handshake_in modem_status = 0;

    do {
        DWORD modemstat = 0;
        if (GetCommModemStatus(fds[fd].fd, &modemstat) == 0) {
            DEBUG_LOG_MESSAGE((rs232dev_log, "Could not get modem status for device %d.", device));
            break;
        }

        if (modemstat & MS_CTS_ON) {
            modem_status |= RS232_HSI_CTS;
        }

        if (modemstat & MS_DSR_ON) {
            modem_status |= RS232_HSI_DSR;
        }
    } while (0);

    return modem_status;
}
Ejemplo n.º 7
0
/* sends a byte to the RS232 line */
int rs232dev_putc(int fd, BYTE b)
{
    DWORD number_of_bytes = 1;

    DEBUG_LOG_MESSAGE((rs232dev_log, "rs232dev: Output %u = `%c'.", (unsigned)b, b));

#if DEBUG_FAKE_INPUT_OUTPUT

    rs232_debug_fake_input_available = DEBUG_FAKE_INPUT_OUTPUT;
    rs232_debug_fake_input = b;

#else
    if ( WriteFile(fds[fd].fd, &b, number_of_bytes, &number_of_bytes, NULL) == 0) {
        return -1;
    }

    if (number_of_bytes != 1) {
        return -1;
    }
#endif

    return 0;
}
Ejemplo n.º 8
0
/* set the bps rate of the physical device */
void rs232dev_set_bps(int fd, unsigned int bps)
{
    /*! \todo set the physical bps rate */
    DEBUG_LOG_MESSAGE((rs232dev_log, "Setting bps to %u", bps));
}
Ejemplo n.º 9
0
/* opens a rs232 window, returns handle to give to functions below. */
int rs232dev_open(int device)
{
    HANDLE serial_port;
    int ret = -1;
    int i;

    for (i = 0; i < RS232_NUM_DEVICES; i++) {
        if (!fds[i].inuse) {
            break;
        }
    }
    if (i >= RS232_NUM_DEVICES) {
        log_error(rs232dev_log, "No more devices available.");
        return -1;
    }

    DEBUG_LOG_MESSAGE((rs232dev_log, "rs232dev_open(device=%d).", device));

    do {
        DCB dcb;
        COMMTIMEOUTS comm_timeouts;
        char *mode_string = strchr(rs232_devfile[device], ':');

        if (mode_string != NULL) {
            *mode_string = 0;
        }

        serial_port = CreateFile(rs232_devfile[device], GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);

        if (mode_string != NULL) {
            *mode_string = ':';
        }


        if (serial_port == INVALID_HANDLE_VALUE) {
            DEBUG_LOG_MESSAGE((rs232dev_log, "rs232dev: CreateFile '%s' failed: %d.\n", rs232_devfile[device], GetLastError()));
            break;
        }

        memset(&dcb, 0, sizeof dcb);
        dcb.DCBlength = sizeof dcb;

        if (!GetCommState(serial_port, &dcb)) {
            DEBUG_LOG_MESSAGE((rs232dev_log, "rs232dev: GetCommState '%s' failed: %d.\n", rs232_devfile[device], GetLastError()));
            break;
        }

        fds[i].restore_dcb = dcb;

        if (mode_string != NULL) {
            ++mode_string;

            while (*mode_string == ' ') {
                ++mode_string;
            }

            if ( ! BuildCommDCB(mode_string, &dcb) ) {
                DEBUG_LOG_MESSAGE((rs232dev_log, "rs232dev: BuildCommDCB '%s' for device '%s' failed: %d.\n", mode_string + 1, rs232_devfile[device], GetLastError()));
                break;
            }
        }

        if (! SetCommState(serial_port, &dcb)) {
            DEBUG_LOG_MESSAGE((rs232dev_log, "rs232dev: SetCommState '%s' failed: %d.\n", rs232_devfile[device], GetLastError()));
            break;
        }

        memset(&comm_timeouts, 0, sizeof comm_timeouts);

        /*
         * ensure that a read will always terminate and only return
         * what is already in the buffers
         */
        comm_timeouts.ReadIntervalTimeout = MAXDWORD;
        comm_timeouts.ReadTotalTimeoutMultiplier = 0;
        comm_timeouts.ReadTotalTimeoutConstant = 0;

        /*
         * Do not use total timeouts for write operations
         */
        comm_timeouts.WriteTotalTimeoutConstant = 0;
        comm_timeouts.WriteTotalTimeoutMultiplier = 0;

        if (!SetCommTimeouts(serial_port, &comm_timeouts)) {
            DEBUG_LOG_MESSAGE((rs232dev_log, "rs232dev: SetCommTimeouts '%s' failed: %d.\n", rs232_devfile[device], GetLastError()));
            break;
        }

        fds[i].inuse = 1;
        fds[i].fd = serial_port;
        fds[i].file = rs232_devfile[device];
        ret = i;
        serial_port = INVALID_HANDLE_VALUE;

    } while (0);

    if (serial_port != INVALID_HANDLE_VALUE) {
        CloseHandle(serial_port);
    }

    return ret;
}
Ejemplo n.º 10
0
/*! \brief write the ACIA register values
  This function is used to write the ACIA values from the computer.

  \param addr
    The address of the ACIA register to write

  \param byte
    The value to set the register to
*/
void myacia_store(WORD addr, BYTE byte)
{
    int acia_register_size;

    DEBUG_LOG_MESSAGE((acia.log, "store_myacia(%04x,%02x)", addr, byte));

    if (mycpu_rmw_flag) {
        myclk--;
        mycpu_rmw_flag = 0;
        myacia_store(addr, acia.last_read);
        myclk++;
    }

    if (acia.mode == ACIA_MODE_TURBO232) {
        acia_register_size = 7;
    } else {
        acia_register_size = 3;
    }

    switch (addr & acia_register_size) {
    case ACIA_DR:
        acia.txdata = byte;
        if (acia.cmd & ACIA_CMD_BITS_DTR_ENABLE_RECV_AND_IRQ) {
            if (acia.in_tx == ACIA_TX_STATE_DR_WRITTEN) {
                log_message(acia.log, "ACIA: data register written "
                            "although data has not been sent yet.");
            }
            acia.in_tx = ACIA_TX_STATE_DR_WRITTEN;
            if (acia.alarm_active_tx == 0) {
                acia.alarm_clk_tx = myclk + 1;
                alarm_set(acia.alarm_tx, acia.alarm_clk_tx);
                acia.alarm_active_tx = 1;
            }
            acia.status &= ~ACIA_SR_BITS_TRANSMIT_DR_EMPTY; /* clr TDRE */
        }
        break;
    case ACIA_SR:
        /* According the CSG and WDC data sheets, this is a programmed reset! */

        if (acia.fd >= 0) {
            rs232drv_close(acia.fd);
        }
        acia.fd = -1;

        acia.status &= ~ACIA_SR_BITS_OVERRUN_ERROR;
        acia.cmd &= ACIA_CMD_BITS_PARITY_TYPE_MASK | ACIA_CMD_BITS_PARITY_ENABLED;
        acia.in_tx = ACIA_TX_STATE_NO_TRANSMIT;
        acia_set_int(acia.irq_type, acia.int_num, IK_NONE);
        acia.irq = 0;
        if (acia.alarm_tx) {
            alarm_unset(acia.alarm_tx);
        }
        acia.alarm_active_tx = 0;
        acia_set_handshake_lines();
        break;
    case ACIA_CTRL:
        acia.ctrl = byte;
        set_acia_ticks();
        break;
    case ACIA_CMD:
        acia.cmd = byte;
        acia_set_handshake_lines();
        if ((acia.cmd & ACIA_CMD_BITS_DTR_ENABLE_RECV_AND_IRQ) && (acia.fd < 0)) {
            acia.fd = rs232drv_open(acia.device);
            /* enable RX alarm */
            acia.alarm_active_rx = 1;
            set_acia_ticks();
        } else if ((acia.fd >= 0) && !(acia.cmd & ACIA_CMD_BITS_DTR_ENABLE_RECV_AND_IRQ)) {
            rs232drv_close(acia.fd);
            alarm_unset(acia.alarm_tx);
            acia.alarm_active_tx = 0;
            acia.fd = -1;
        }
        break;
    case T232_ECTRL:
        if ((acia.ctrl & ACIA_CTRL_BITS_BPS_MASK) == ACIA_CTRL_BITS_BPS_16X_EXT_CLK) {
            acia.ectrl = byte;
            set_acia_ticks();
        }
    }
}
Ejemplo n.º 11
0
/*! \internal \brief set the ticks between characters of the ACIA according to the bps rate

 Set the ticks that will pass for one character to be transferred
 according to the current ACIA settings.
*/
static void set_acia_ticks(void)
{
    unsigned int bits;

    DEBUG_LOG_MESSAGE((acia.log, "Setting ACIA to %u bps",
                       (unsigned int) get_acia_bps()));

    switch (acia.ctrl & ACIA_CTRL_BITS_WORD_LENGTH_MASK) {
    case ACIA_CTRL_BITS_WORD_LENGTH_8:
        bits = 8;
        break;
    case ACIA_CTRL_BITS_WORD_LENGTH_7:
        bits = 7;
        break;
    case ACIA_CTRL_BITS_WORD_LENGTH_6:
        bits = 6;
        break;
    default:
    /*
     * this case is only for gcc to calm down, as it wants to warn that
     * bits is used uninitialised - which it is not.
     */
    /* FALL THROUGH */
    case ACIA_CTRL_BITS_WORD_LENGTH_5:
        bits = 5;
        break;
    }

    /*
     * we neglect the fact that we might have 1.5 stop bits instead of 2
     */
    bits += 1 /* the start bit */
            + ((acia.cmd & ACIA_CMD_BITS_PARITY_ENABLED) ? 1 : 0) /* parity or not */
            + ((acia.ctrl & ACIA_CTRL_BITS_2_STOP) ? 2 : 1);   /* 1 or 2 stop bits */

    /*
     * calculate time in ticks for the data bits
     * including start, stop and parity bits.
     */
    acia.ticks = (int) (machine_get_cycles_per_second() / get_acia_bps() * bits);

    /*
     * Note: With 10 bit, the timing is very hard to NovaTerm 9.6c with 57600 bps
     * on reception. It cannot cope and behaves erroneously, at least when configured
     * for NMI interrupts. This is because the interrupt routine needs too much
     * time to execute, leaving not more than 20 cycles for the non-NMI routine.
     * Thus, it was decided to add 25% "safety margin" to allow NovaTerm to react
     * appropriately. This gives the main program 50 extra cycles.
     * This way, NovaTerm can cope with the transmission at 57600 bps.
     */
    acia.ticks_rx = acia.ticks * 5 / 4;

    /* adjust the alarm rate for reception */
    if (acia.alarm_active_rx) {
        acia.alarm_clk_rx = myclk + acia.ticks_rx;
        alarm_set(acia.alarm_rx, acia.alarm_clk_rx);
        acia.alarm_active_rx = 1;
    }

    /*
     * set the baud rate of the physical device
     */
    rs232drv_set_bps(acia.fd, (unsigned int)get_acia_bps());
}