Files
86Box/src/bugger.c

324 lines
8.5 KiB
C

/*
* 86Box A hypervisor and IBM PC system emulator that specializes in
* running old operating systems and software designed for IBM
* PC systems and compatibles from 1981 through fairly recent
* system designs based on the PCI bus.
*
* This file is part of the 86Box distribution.
*
* Implementation of the ISA Bus (de)Bugger expansion card
* sold as a DIY kit in the late 1980's in The Netherlands.
* This card was a assemble-yourself 8bit ISA addon card for
* PC and AT systems that had several tools to aid in low-
* level debugging (mostly for faulty BIOSes, bootloaders
* and system kernels...)
*
* The standard version had a total of 16 LEDs (8 RED, plus
* 8 GREEN), two 7-segment displays and one 8-position DIP
* switch block on board for use as debugging tools.
*
* The "Plus" version, added an extra 2 7-segment displays,
* as well as a very simple RS-232 serial interface that
* could be used as a mini-console terminal.
*
* Two I/O ports were used; one for control, at offset 0 in
* I/O space, and one for data, at offset 1 in I/O space.
* Both registers could be read from and written to. Although
* the author has a vague memory of a DIP switch to set the
* board's I/O address, comments in old software seems to
* indicate that it was actually fixed to 0x7A (and 0x7B.)
*
* A READ on the data register always returned the actual
* state of the DIP switch. Writing data to the LEDs was done
* in two steps.. first, the block number (RED or GREEN) was
* written to the CTRL register, and then the actual LED data
* was written to the DATA register. Likewise, data for the
* 7-segment displays was written.
*
* The serial port was a bit different, and its operation is
* not verified, but two extra bits in the control register
* were used to set up parameters, and also the actual data
* input and output.
*
* TODO: Still have to implement the RS232 Serial Port Parameters
* configuration register (CTRL_SPCFG bit set) but have to
* remember that stuff first...
*
* Version: @(#)bugger.c 1.0.4 2017/05/09
*
* Author: Fred N. van Kempen, <decwiz@yahoo.com>
* Copyright 1989-2017 Fred N. van Kempen.
*/
#include "ibm.h"
#include "io.h"
#include "bugger.h"
/* BugBugger registers. */
#define BUG_CTRL 0
# define CTRL_RLED 0x00 /* write to the RED LED block */
# define CTRL_GLED 0x01 /* write to the GREEN LED block */
# define CTRL_SEG1 0x02 /* write to the RIGHT 7SEG displays */
# define CTRL_SEG2 0x04 /* write to the LEFT 7SEG displays */
# define CTRL_SPORT 0x20 /* enable the serial port */
# define CTRL_SPCFG 0x40 /* set up the serial port */
# define CTRL_INIT 0x80 /* enable and reset the card */
# define CTRL_RESET 0xff /* this resets the board */
#define BUG_DATA 1
static uint8_t bug_ctrl, /* control register */
bug_data, /* data register */
bug_ledr, bug_ledg, /* RED and GREEN LEDs */
bug_seg1, bug_seg2, /* LEFT and RIGHT 7SEG displays */
bug_spcfg; /* serial port configuration */
# define FIFO_LEN 256
static uint8_t bug_buff[FIFO_LEN], /* serial port data buffer */
*bug_bptr;
# define UISTR_LEN 24
static char bug_str[UISTR_LEN]; /* UI output string */
extern void set_bugui(char *__str);
/* Update the system's UI with the actual Bugger status. */
static void
bug_setui(void)
{
/* Format all current info in a string. */
sprintf(bug_str, "%02X:%02X %c%c%c%c%c%c%c%c-%c%c%c%c%c%c%c%c",
bug_seg2, bug_seg1,
(bug_ledg&0x80)?'G':'g', (bug_ledg&0x40)?'G':'g',
(bug_ledg&0x20)?'G':'g', (bug_ledg&0x10)?'G':'g',
(bug_ledg&0x08)?'G':'g', (bug_ledg&0x04)?'G':'g',
(bug_ledg&0x02)?'G':'g', (bug_ledg&0x01)?'G':'g',
(bug_ledr&0x80)?'R':'r', (bug_ledr&0x40)?'R':'r',
(bug_ledr&0x20)?'R':'r', (bug_ledr&0x10)?'R':'r',
(bug_ledr&0x08)?'R':'r', (bug_ledr&0x04)?'R':'r',
(bug_ledr&0x02)?'R':'r', (bug_ledr&0x01)?'R':'r');
/* Send formatted string to the UI. */
status_settext(bug_str);
}
/* Flush the serial port. */
static void
bug_spflsh(void)
{
*bug_bptr = '\0';
pclog("BUGGER- serial port [%s]\n", bug_buff);
bug_bptr = bug_buff;
}
/* Handle a write to the Serial Port Data register. */
static void
bug_wsport(uint8_t val)
{
uint8_t old = bug_ctrl;
/* Clear the SPORT bit to indicate we are busy. */
bug_ctrl &= ~CTRL_SPORT;
/* Delay while processing byte.. */
if (bug_bptr == &bug_buff[FIFO_LEN-1]) {
/* Buffer full, gotta flush. */
bug_spflsh();
}
/* Write (store) the byte. */
*bug_bptr++ = val;
/* Restore the SPORT bit. */
bug_ctrl |= (old & CTRL_SPORT);
pclog("BUGGER- sport %02x\n", val);
}
/* Handle a write to the Serial Port Configuration register. */
static void
bug_wspcfg(uint8_t val)
{
bug_spcfg = val;
pclog("BUGGER- spcfg %02x\n", bug_spcfg);
}
/* Handle a write to the control register. */
static void
bug_wctrl(uint8_t val)
{
if (val == CTRL_RESET) {
/* User wants us to reset. */
bug_ctrl = CTRL_INIT;
bug_spcfg = 0x00;
bug_bptr = NULL;
} else {
/* If turning off the serial port, flush it. */
if ((bug_ctrl & CTRL_SPORT) && !(val & CTRL_SPORT))
bug_spflsh();
/* FIXME: did they do this using an XOR of operation bits? --FvK */
if (val & CTRL_SPCFG) {
/* User wants to configure the serial port. */
bug_ctrl &= ~(CTRL_SPORT|CTRL_SEG2|CTRL_SEG1|CTRL_GLED);
bug_ctrl |= CTRL_SPCFG;
} else if (val & CTRL_SPORT) {
/* User wants to talk to the serial port. */
bug_ctrl &= ~(CTRL_SPCFG|CTRL_SEG2|CTRL_SEG1|CTRL_GLED);
bug_ctrl |= CTRL_SPORT;
if (bug_bptr == NULL)
bug_bptr = bug_buff;
} else if (val & CTRL_SEG2) {
/* User selected SEG2 (LEFT, Plus only) for output. */
bug_ctrl &= ~(CTRL_SPCFG|CTRL_SPORT|CTRL_SEG1|CTRL_GLED);
bug_ctrl |= CTRL_SEG2;
} else if (val & CTRL_SEG1) {
/* User selected SEG1 (RIGHT) for output. */
bug_ctrl &= ~(CTRL_SPCFG|CTRL_SPORT|CTRL_SEG2|CTRL_GLED);
bug_ctrl |= CTRL_SEG1;
} else if (val & CTRL_GLED) {
/* User selected the GREEN LEDs for output. */
bug_ctrl &= ~(CTRL_SPCFG|CTRL_SPORT|CTRL_SEG2|CTRL_SEG1);
bug_ctrl |= CTRL_GLED;
} else {
/* User selected the RED LEDs for output. */
bug_ctrl &=
~(CTRL_SPCFG|CTRL_SPORT|CTRL_SEG2|CTRL_SEG1|CTRL_GLED);
}
}
/* Update the UI with active settings. */
pclog("BUGGER- ctrl %02x\n", bug_ctrl);
bug_setui();
}
/* Handle a write to the data register. */
static void
bug_wdata(uint8_t val)
{
bug_data = val;
if (bug_ctrl & CTRL_SPCFG)
bug_wspcfg(val);
else if (bug_ctrl & CTRL_SPORT)
bug_wsport(val);
else {
if (bug_ctrl & CTRL_SEG2)
bug_seg2 = val;
else if (bug_ctrl & CTRL_SEG1)
bug_seg1 = val;
else if (bug_ctrl & CTRL_GLED)
bug_ledg = val;
else
bug_ledr = val;
pclog("BUGGER- data %02x\n", bug_data);
}
/* Update the UI with active settings. */
bug_setui();
}
/* Reset the ISA BusBugger controller. */
static void
bug_reset(void)
{
/* Clear the data register. */
bug_data = 0x00;
/* Clear the RED and GREEN LEDs. */
bug_ledr = 0x00; bug_ledg = 0x00;
/* Clear both 7SEG displays. */
bug_seg1 = 0x00; bug_seg2 = 0x00;
/* Reset the control register (updates UI.) */
bug_wctrl(CTRL_RESET);
}
/* Handle a WRITE operation to one of our registers. */
static void
bug_write(uint16_t port, uint8_t val, void *priv)
{
switch (port-BUGGER_ADDR) {
case BUG_CTRL: /* control register */
if (val == CTRL_RESET) {
/* Perform a full reset. */
bug_reset();
} else if (bug_ctrl & CTRL_INIT) {
/* Only allow writes if initialized. */
bug_wctrl(val);
}
break;
case BUG_DATA: /* data register */
if (bug_ctrl & CTRL_INIT) {
bug_wdata(val);
}
break;
}
}
/* Handle a READ operation from one of our registers. */
static uint8_t
bug_read(uint16_t port, void *priv)
{
uint8_t ret = 0xff;
if (bug_ctrl & CTRL_INIT) switch (port-BUGGER_ADDR) {
case BUG_CTRL: /* control register */
ret = bug_ctrl;
break;
case BUG_DATA: /* data register */
if (bug_ctrl & CTRL_SPCFG) {
ret = bug_spcfg;
} else if (bug_ctrl & CTRL_SPORT) {
ret = 0x00; /* input not supported */
} else {
/* Just read the DIP switch. */
ret = bug_data;
}
break;
default:
break;
}
return(ret);
}
/* Initialize the ISA BusBugger emulator. */
void
bugger_init(void)
{
pclog("ISA Bus (de)Bugger, I/O=%04x\n", BUGGER_ADDR);
/* Initialize local registers. */
bug_reset();
io_sethandler(BUGGER_ADDR, BUGGER_ADDRLEN,
bug_read, NULL, NULL, bug_write, NULL, NULL, NULL);
}
/* Remove the ISA BusBugger emulator from the system. */
void
bugger_remove(void)
{
io_removehandler(BUGGER_ADDR, BUGGER_ADDRLEN,
bug_read, NULL, NULL, bug_write, NULL, NULL, NULL);
}