diff --git a/AltairZ80/altairz80_sys.c b/AltairZ80/altairz80_sys.c
index 5b834732..2c239175 100644
--- a/AltairZ80/altairz80_sys.c
+++ b/AltairZ80/altairz80_sys.c
@@ -77,6 +77,12 @@ extern DEVICE pmmi_dev;
extern DEVICE hayes_dev;
extern DEVICE mmd_dev;
extern DEVICE mmdm_dev;
+extern DEVICE sol20_dev;
+extern DEVICE sol20k_dev;
+extern DEVICE sol20t_dev;
+extern DEVICE sol20s_dev;
+extern DEVICE sol20p_dev;
+extern DEVICE vdm1_dev;
extern DEVICE cromfdc_dev;
extern DEVICE wd179x_dev;
@@ -141,6 +147,13 @@ DEVICE *sim_devices[] = {
&djhdc_dev,
&mmd_dev,
&mmdm_dev,
+ /* Processor Technology Devices */
+ &sol20_dev,
+ &sol20k_dev,
+ &sol20t_dev,
+ &sol20s_dev,
+ &sol20p_dev,
+ &vdm1_dev,
/* MITS 88-2SIO */
&m2sio0_dev,
&m2sio1_dev,
diff --git a/AltairZ80/s100_vdm1.c b/AltairZ80/s100_vdm1.c
new file mode 100644
index 00000000..c824d249
--- /dev/null
+++ b/AltairZ80/s100_vdm1.c
@@ -0,0 +1,708 @@
+/* s100_vdm1.c: Processor Technology VDM-1
+
+ Copyright (c) 2023, Patrick Linstruth
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ Except as contained in this notice, the name of the author shall not be
+ used in advertising or otherwise to promote the sale, use or other dealings
+ in this Software without prior written authorization from the author.
+
+ VDM1 - Processor Technology VDM-1
+*/
+
+#include "altairz80_defs.h"
+#include "sim_video.h"
+
+#define VDM1_MARGIN (5)
+#define VDM1_CHAR_XSIZE (9) /* character x size */
+#define VDM1_CHAR_YSIZE (13) /* character y size */
+#define VDM1_COLS (64) /* number of colums */
+#define VDM1_LINES (16) /* number of rows */
+#define VDM1_XSIZE (VDM1_COLS * VDM1_CHAR_XSIZE + VDM1_MARGIN * 2) /* visible width */
+#define VDM1_YSIZE (VDM1_LINES * VDM1_CHAR_YSIZE + VDM1_MARGIN * 2) /* visible height */
+#define VDM1_PIXELS (VDM1_XSIZE * VDM1_YSIZE) /* total number of pixels */
+
+#define VDM1_MEM_BASE 0xcc00
+#define VDM1_MEM_SIZE 1024
+#define VDM1_MEM_MASK (1024 - 1)
+
+#define VDM1_IO_BASE 0xfe
+#define VDM1_IO_SIZE 1
+
+/*
+** PORT ASSIGNMENTS
+*/
+#define VDM1_DSTAT 0xfe /* VDM DISPLAY PARAMETER PORT */
+#define VDM1_DSTAT_RMSK 0xf0 /* START ROW MASK */
+#define VDM1_DSTAT_CMSK 0x0f /* START COL MASK */
+
+/*
+** Public VID_DISPLAY for other devices that may want
+** to access the video display directly, such as keyboard
+** events.
+*/
+VID_DISPLAY *vdm1_vptr = NULL;
+t_stat (*vdm1_kb_callback)(SIM_KEY_EVENT *kev) = NULL;
+
+static uint8 vdm1_ram[VDM1_MEM_SIZE];
+static uint8 vdm1_dstat = 0x00;
+static t_bool vdm1_dirty = FALSE;
+static t_bool vdm1_reverse = FALSE;
+static t_bool vdm1_blink = FALSE;
+static uint16 vdm1_counter = 0;
+static t_bool vdm1_active = FALSE;
+static uint32 vdm1_surface[VDM1_PIXELS];
+static uint32 vdm1_palette[2];
+
+enum vdm1_switch {VDM1_NONE,
+ VDM1_NORMAL, VDM1_REVERSE, VDM1_BLINK, VDM1_NOBLINK,
+ VDM1_MODE1, VDM1_MODE2, VDM1_MODE3, VDM1_MODE4
+};
+
+static enum vdm1_switch vdm1_ctrl = VDM1_MODE4;
+static enum vdm1_switch vdm1_cursor = VDM1_NOBLINK;
+static enum vdm1_switch vdm1_display = VDM1_NORMAL;
+
+const uint8 charset[128][VDM1_CHAR_YSIZE] =
+ {{0x00,0x7f,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x7f,0x00,0x00,0x00},
+ {0x00,0x7f,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x00,0x00,0x00},
+ {0x00,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x7f,0x00,0x00,0x00},
+ {0x00,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x7f,0x00,0x00,0x00},
+ {0x00,0x20,0x10,0x08,0x04,0x3e,0x10,0x08,0x04,0x02,0x00,0x00,0x00},
+ {0x00,0x7f,0x41,0x63,0x55,0x49,0x55,0x63,0x41,0x7f,0x00,0x00,0x00},
+ {0x00,0x00,0x01,0x02,0x04,0x48,0x50,0x60,0x40,0x00,0x00,0x00,0x00},
+ {0x00,0x1c,0x22,0x41,0x41,0x41,0x7f,0x14,0x14,0x77,0x00,0x00,0x00},
+ {0x00,0x10,0x20,0x7c,0x22,0x11,0x01,0x01,0x01,0x01,0x00,0x00,0x00},
+ {0x00,0x00,0x08,0x04,0x02,0x7f,0x02,0x04,0x08,0x00,0x00,0x00,0x00},
+ {0x00,0x7f,0x00,0x00,0x00,0x7f,0x00,0x00,0x00,0x7f,0x00,0x00,0x00},
+ {0x00,0x00,0x08,0x08,0x08,0x49,0x2a,0x1c,0x08,0x00,0x00,0x00,0x00},
+ {0x00,0x08,0x08,0x2a,0x1c,0x08,0x49,0x2a,0x1c,0x08,0x00,0x00,0x00},
+ {0x00,0x00,0x08,0x10,0x20,0x7f,0x20,0x10,0x08,0x00,0x00,0x00,0x00},
+ {0x00,0x1c,0x22,0x63,0x55,0x49,0x55,0x63,0x22,0x1c,0x00,0x00,0x00},
+ {0x00,0x1c,0x22,0x41,0x41,0x49,0x41,0x41,0x22,0x1c,0x00,0x00,0x00},
+ {0x00,0x7f,0x41,0x41,0x41,0x7f,0x41,0x41,0x41,0x7f,0x00,0x00,0x00},
+ {0x00,0x1c,0x2a,0x49,0x49,0x4f,0x41,0x41,0x22,0x1c,0x00,0x00,0x00},
+ {0x00,0x1c,0x22,0x41,0x41,0x4f,0x49,0x49,0x2a,0x1c,0x00,0x00,0x00},
+ {0x00,0x1c,0x22,0x41,0x41,0x79,0x49,0x49,0x2a,0x1c,0x00,0x00,0x00},
+ {0x00,0x1c,0x2a,0x49,0x49,0x79,0x41,0x41,0x22,0x1c,0x00,0x00,0x00},
+ {0x00,0x00,0x11,0x0a,0x04,0x4a,0x51,0x60,0x40,0x00,0x00,0x00,0x00},
+ {0x00,0x3e,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x63,0x00,0x00,0x00},
+ {0x00,0x01,0x01,0x01,0x01,0x7f,0x01,0x01,0x01,0x01,0x00,0x00,0x00},
+ {0x00,0x7f,0x41,0x22,0x14,0x08,0x14,0x22,0x41,0x7f,0x00,0x00,0x00},
+ {0x00,0x08,0x08,0x08,0x1c,0x1c,0x08,0x08,0x08,0x08,0x00,0x00,0x00},
+ {0x00,0x3c,0x42,0x42,0x40,0x30,0x08,0x08,0x00,0x08,0x00,0x00,0x00},
+ {0x00,0x1c,0x22,0x41,0x41,0x7f,0x41,0x41,0x22,0x1c,0x00,0x00,0x00},
+ {0x00,0x7f,0x49,0x49,0x49,0x79,0x41,0x41,0x41,0x7f,0x00,0x00,0x00},
+ {0x00,0x7f,0x41,0x41,0x41,0x79,0x49,0x49,0x49,0x7f,0x00,0x00,0x00},
+ {0x00,0x7f,0x41,0x41,0x41,0x4f,0x49,0x49,0x49,0x7f,0x00,0x00,0x00},
+ {0x00,0x7f,0x49,0x49,0x49,0x4f,0x41,0x41,0x41,0x7f,0x00,0x00,0x00},
+ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
+ {0x00,0x08,0x08,0x08,0x08,0x08,0x00,0x00,0x08,0x08,0x00,0x00,0x00},
+ {0x00,0x24,0x24,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
+ {0x00,0x14,0x14,0x14,0x7f,0x14,0x7f,0x14,0x14,0x14,0x00,0x00,0x00},
+ {0x00,0x08,0x3f,0x48,0x48,0x3e,0x09,0x09,0x7e,0x08,0x00,0x00,0x00},
+ {0x00,0x20,0x51,0x22,0x04,0x08,0x10,0x22,0x45,0x02,0x00,0x00,0x00},
+ {0x00,0x38,0x44,0x44,0x28,0x10,0x29,0x46,0x46,0x39,0x00,0x00,0x00},
+ {0x00,0x0c,0x0c,0x08,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
+ {0x00,0x04,0x08,0x10,0x10,0x10,0x10,0x10,0x08,0x04,0x00,0x00,0x00},
+ {0x00,0x10,0x08,0x04,0x04,0x04,0x04,0x04,0x08,0x10,0x00,0x00,0x00},
+ {0x00,0x00,0x08,0x49,0x2a,0x1c,0x2a,0x49,0x08,0x00,0x00,0x00,0x00},
+ {0x00,0x00,0x08,0x08,0x08,0x7f,0x08,0x08,0x08,0x00,0x00,0x00,0x00},
+ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x10,0x20,0x00},
+ {0x00,0x00,0x00,0x00,0x00,0x7f,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
+ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00},
+ {0x00,0x00,0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x00,0x00,0x00,0x00},
+ {0x00,0x3e,0x41,0x43,0x45,0x49,0x51,0x61,0x41,0x3e,0x00,0x00,0x00},
+ {0x00,0x08,0x18,0x28,0x08,0x08,0x08,0x08,0x08,0x3e,0x00,0x00,0x00},
+ {0x00,0x3e,0x41,0x01,0x02,0x1c,0x20,0x40,0x40,0x7f,0x00,0x00,0x00},
+ {0x00,0x3e,0x41,0x01,0x01,0x1e,0x01,0x01,0x41,0x3e,0x00,0x00,0x00},
+ {0x00,0x02,0x06,0x0a,0x12,0x22,0x42,0x7f,0x02,0x02,0x00,0x00,0x00},
+ {0x00,0x7f,0x40,0x40,0x7c,0x02,0x01,0x01,0x42,0x3c,0x00,0x00,0x00},
+ {0x00,0x1e,0x20,0x40,0x40,0x7e,0x41,0x41,0x41,0x3e,0x00,0x00,0x00},
+ {0x00,0x7f,0x41,0x02,0x04,0x08,0x10,0x10,0x10,0x10,0x00,0x00,0x00},
+ {0x00,0x3e,0x41,0x41,0x41,0x3e,0x41,0x41,0x41,0x3e,0x00,0x00,0x00},
+ {0x00,0x3e,0x41,0x41,0x41,0x3f,0x01,0x01,0x02,0x3c,0x00,0x00,0x00},
+ {0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x18,0x18,0x00,0x00,0x00},
+ {0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x18,0x18,0x10,0x20,0x00},
+ {0x00,0x04,0x08,0x10,0x20,0x40,0x20,0x10,0x08,0x04,0x00,0x00,0x00},
+ {0x00,0x00,0x00,0x00,0x3e,0x00,0x3e,0x00,0x00,0x00,0x00,0x00,0x00},
+ {0x00,0x10,0x08,0x04,0x02,0x01,0x02,0x04,0x08,0x10,0x00,0x00,0x00},
+ {0x00,0x1e,0x21,0x21,0x01,0x06,0x08,0x08,0x00,0x08,0x00,0x00,0x00},
+ {0x00,0x1e,0x21,0x4d,0x55,0x55,0x5e,0x40,0x20,0x1e,0x00,0x00,0x00},
+ {0x00,0x1c,0x22,0x41,0x41,0x41,0x7f,0x41,0x41,0x41,0x00,0x00,0x00},
+ {0x00,0x7e,0x21,0x21,0x21,0x3e,0x21,0x21,0x21,0x7e,0x00,0x00,0x00},
+ {0x00,0x1e,0x21,0x40,0x40,0x40,0x40,0x40,0x21,0x1e,0x00,0x00,0x00},
+ {0x00,0x7c,0x22,0x21,0x21,0x21,0x21,0x21,0x22,0x7c,0x00,0x00,0x00},
+ {0x00,0x7f,0x40,0x40,0x40,0x78,0x40,0x40,0x40,0x7f,0x00,0x00,0x00},
+ {0x00,0x7f,0x40,0x40,0x40,0x78,0x40,0x40,0x40,0x40,0x00,0x00,0x00},
+ {0x00,0x1e,0x21,0x40,0x40,0x40,0x4f,0x41,0x21,0x1e,0x00,0x00,0x00},
+ {0x00,0x41,0x41,0x41,0x41,0x7f,0x41,0x41,0x41,0x41,0x00,0x00,0x00},
+ {0x00,0x3e,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x3e,0x00,0x00,0x00},
+ {0x00,0x1f,0x04,0x04,0x04,0x04,0x04,0x04,0x44,0x38,0x00,0x00,0x00},
+ {0x00,0x41,0x42,0x44,0x48,0x50,0x68,0x44,0x42,0x41,0x00,0x00,0x00},
+ {0x00,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x7f,0x00,0x00,0x00},
+ {0x00,0x41,0x63,0x55,0x49,0x49,0x41,0x41,0x41,0x41,0x00,0x00,0x00},
+ {0x00,0x41,0x61,0x51,0x49,0x45,0x43,0x41,0x41,0x41,0x00,0x00,0x00},
+ {0x00,0x1c,0x22,0x41,0x41,0x41,0x41,0x41,0x22,0x1c,0x00,0x00,0x00},
+ {0x00,0x7e,0x41,0x41,0x41,0x7e,0x40,0x40,0x40,0x40,0x00,0x00,0x00},
+ {0x00,0x1c,0x22,0x41,0x41,0x41,0x49,0x45,0x22,0x1d,0x00,0x00,0x00},
+ {0x00,0x7e,0x41,0x41,0x41,0x7e,0x48,0x44,0x42,0x41,0x00,0x00,0x00},
+ {0x00,0x3e,0x41,0x40,0x40,0x3e,0x01,0x01,0x41,0x3e,0x00,0x00,0x00},
+ {0x00,0x7f,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x00,0x00,0x00},
+ {0x00,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x3e,0x00,0x00,0x00},
+ {0x00,0x41,0x41,0x41,0x22,0x22,0x14,0x14,0x08,0x08,0x00,0x00,0x00},
+ {0x00,0x41,0x41,0x41,0x41,0x49,0x49,0x55,0x63,0x41,0x00,0x00,0x00},
+ {0x00,0x41,0x41,0x22,0x14,0x08,0x14,0x22,0x41,0x41,0x00,0x00,0x00},
+ {0x00,0x41,0x41,0x22,0x14,0x08,0x08,0x08,0x08,0x08,0x00,0x00,0x00},
+ {0x00,0x7f,0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x7f,0x00,0x00,0x00},
+ {0x00,0x3c,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x3c,0x00,0x00,0x00},
+ {0x00,0x00,0x40,0x20,0x10,0x08,0x04,0x02,0x01,0x00,0x00,0x00,0x00},
+ {0x00,0x3c,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x3c,0x00,0x00,0x00},
+ {0x00,0x08,0x14,0x22,0x41,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
+ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7f,0x00,0x00,0x00},
+ {0x00,0x18,0x18,0x08,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
+ {0x00,0x00,0x00,0x00,0x3c,0x02,0x3e,0x42,0x42,0x3d,0x00,0x00,0x00},
+ {0x00,0x40,0x40,0x40,0x5c,0x62,0x42,0x42,0x62,0x5c,0x00,0x00,0x00},
+ {0x00,0x00,0x00,0x00,0x3c,0x42,0x40,0x40,0x42,0x3c,0x00,0x00,0x00},
+ {0x00,0x02,0x02,0x02,0x3a,0x46,0x42,0x42,0x46,0x3a,0x00,0x00,0x00},
+ {0x00,0x00,0x00,0x00,0x3c,0x42,0x7e,0x40,0x40,0x3c,0x00,0x00,0x00},
+ {0x00,0x0c,0x12,0x10,0x10,0x7c,0x10,0x10,0x10,0x10,0x00,0x00,0x00},
+ {0x00,0x00,0x00,0x00,0x3a,0x46,0x42,0x46,0x3a,0x02,0x02,0x42,0x3c},
+ {0x00,0x40,0x40,0x40,0x5c,0x62,0x42,0x42,0x42,0x42,0x00,0x00,0x00},
+ {0x00,0x00,0x08,0x00,0x18,0x08,0x08,0x08,0x08,0x1c,0x00,0x00,0x00},
+ {0x00,0x00,0x00,0x00,0x06,0x02,0x02,0x02,0x02,0x02,0x02,0x22,0x1c},
+ {0x00,0x40,0x40,0x40,0x44,0x48,0x50,0x68,0x44,0x42,0x00,0x00,0x00},
+ {0x00,0x18,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x1c,0x00,0x00,0x00},
+ {0x00,0x00,0x00,0x00,0x76,0x49,0x49,0x49,0x49,0x49,0x00,0x00,0x00},
+ {0x00,0x00,0x00,0x00,0x5c,0x62,0x42,0x42,0x42,0x42,0x00,0x00,0x00},
+ {0x00,0x00,0x00,0x00,0x3c,0x42,0x42,0x42,0x42,0x3c,0x00,0x00,0x00},
+ {0x00,0x00,0x00,0x00,0x5c,0x62,0x42,0x42,0x62,0x5c,0x40,0x40,0x40},
+ {0x00,0x00,0x00,0x00,0x3a,0x46,0x42,0x42,0x46,0x3a,0x02,0x02,0x02},
+ {0x00,0x00,0x00,0x00,0x5c,0x62,0x40,0x40,0x40,0x40,0x00,0x00,0x00},
+ {0x00,0x00,0x00,0x00,0x3c,0x42,0x30,0x0c,0x42,0x3c,0x00,0x00,0x00},
+ {0x00,0x00,0x10,0x10,0x7c,0x10,0x10,0x10,0x12,0x0c,0x00,0x00,0x00},
+ {0x00,0x00,0x00,0x00,0x42,0x42,0x42,0x42,0x46,0x3a,0x00,0x00,0x00},
+ {0x00,0x00,0x00,0x00,0x41,0x41,0x41,0x22,0x14,0x08,0x00,0x00,0x00},
+ {0x00,0x00,0x00,0x00,0x41,0x49,0x49,0x49,0x49,0x36,0x00,0x00,0x00},
+ {0x00,0x00,0x00,0x00,0x42,0x24,0x18,0x18,0x24,0x42,0x00,0x00,0x00},
+ {0x00,0x00,0x00,0x00,0x42,0x42,0x42,0x42,0x46,0x3a,0x02,0x42,0x3c},
+ {0x00,0x00,0x00,0x00,0x7e,0x04,0x08,0x10,0x20,0x7e,0x00,0x00,0x00},
+ {0x00,0x0e,0x10,0x10,0x10,0x20,0x10,0x10,0x10,0x0e,0x00,0x00,0x00},
+ {0x00,0x08,0x08,0x08,0x00,0x00,0x08,0x08,0x08,0x00,0x00,0x00,0x00},
+ {0x00,0x18,0x04,0x04,0x04,0x02,0x04,0x04,0x04,0x18,0x00,0x00,0x00},
+ {0x00,0x30,0x49,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
+ {0x00,0x24,0x49,0x12,0x24,0x49,0x12,0x24,0x49,0x12,0x00,0x00,0x00}};
+
+/* Debugging Bitmaps */
+
+#define DBG_REG 0x0001 /* registers */
+
+extern uint32 sim_map_resource(uint32 baseaddr, uint32 size, uint32 resource_type,
+ int32 (*routine)(const int32, const int32, const int32), const char* name, uint8 unmap);
+extern t_stat set_membase(UNIT *uptr, int32 val, CONST char *cptr, void *desc);
+extern t_stat show_membase(FILE *st, UNIT *uptr, int32 val, CONST void *desc);
+extern t_stat set_iobase(UNIT *uptr, int32 val, CONST char *cptr, void *desc);
+extern t_stat show_iobase(FILE *st, UNIT *uptr, int32 val, CONST void *desc);
+extern t_stat exdep_cmd(int32 flag, CONST char *cptr);
+
+static t_stat vdm1_svc(UNIT *uptr);
+static t_stat vdm1_reset(DEVICE *dptr);
+static t_stat vdm1_boot(int32 unitno, DEVICE *dptr);
+static t_stat vdm1_help(FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr);
+static int32 vdm1_io(const int32 port, const int32 io, const int32 data);
+static int32 vdm1_mem(int32 addr, int32 rw, int32 data);
+static const char *vdm1_description(DEVICE *dptr);
+static void vdm1_refresh(void);
+static void vdm1_render(void);
+static void vdm1_render_char(uint8 byte, uint8 x, uint8 y);
+static t_stat vdm1_set_ctrl(UNIT *uptr, int32 val, CONST char *cptr, void *desc);
+static t_stat vdm1_show_ctrl(FILE *st, UNIT *uptr, int32 val, CONST void *desc);
+static t_stat vdm1_set_cursor(UNIT *uptr, int32 val, CONST char *cptr, void *desc);
+static t_stat vdm1_show_cursor(FILE *st, UNIT *uptr, int32 val, CONST void *desc);
+static t_stat vdm1_set_display(UNIT *uptr, int32 val, CONST char *cptr, void *desc);
+static t_stat vdm1_show_display(FILE *st, UNIT *uptr, int32 val, CONST void *desc);
+
+/* VDM1 data structures
+
+ vdm1_dev VDM1 device descriptor
+ vdm1_unit VDM1 unit descriptor
+ vdm1_reg VDM1 register list
+*/
+
+typedef struct {
+ PNP_INFO pnp; /* Must be first */
+} VDM1_CTX;
+
+static VDM1_CTX vdm1_ctx = {{VDM1_MEM_BASE, VDM1_MEM_SIZE, VDM1_IO_BASE, VDM1_IO_SIZE}};
+
+UNIT vdm1_unit = {
+ UDATA (&vdm1_svc, 0, 0), 25000
+};
+
+REG vdm1_reg[] = {
+ { HRDATAD (DSTAT, vdm1_dstat, 8, "VDM-1 display parameter register"), },
+ { HRDATAD (DIRTY, vdm1_dirty, 1, "VDM-1 dirty register"), },
+ { HRDATAD (BLINK, vdm1_blink, 1, "VDM-1 blink register"), },
+ { NULL }
+};
+
+DEBTAB vdm1_debug[] = {
+ { "REG", DBG_REG, "Register activity" },
+ { "VIDEO", SIM_VID_DBG_VIDEO, "Video activity" },
+ { 0 }
+};
+
+
+MTAB vdm1_mod[] = {
+ { MTAB_XTD|MTAB_VDV, 0, "IOBASE", "IOBASE",
+ &set_iobase, &show_iobase, NULL, "VDM-1 base I/O address" },
+ { MTAB_XTD|MTAB_VDV, 0, "MEMBASE", "MEMBASE",
+ &set_membase, &show_membase, NULL, "VDM-1 base memory address" },
+ { MTAB_XTD|MTAB_VDV, 0, "CTRL", "CTRL",
+ &vdm1_set_ctrl, &vdm1_show_ctrl, NULL, "VDM-1 control character switches" },
+ { MTAB_XTD|MTAB_VDV, 0, "CURSOR", "CURSOR",
+ &vdm1_set_cursor, &vdm1_show_cursor, NULL, "VDM-1 cursor switches" },
+ { MTAB_XTD|MTAB_VDV, 0, "DISPLAY", "DISPLAY",
+ &vdm1_set_display, &vdm1_show_display, NULL, "VDM-1 display switches" },
+ { 0 }
+};
+DEVICE vdm1_dev = {
+ "VDM1", &vdm1_unit, vdm1_reg, vdm1_mod,
+ 1, 16, 16, 1, 16, 8,
+ NULL, NULL, &vdm1_reset,
+ &vdm1_boot, NULL, NULL,
+ &vdm1_ctx, DEV_DEBUG | DEV_DIS | DEV_DISABLE, 0,
+ vdm1_debug, NULL, NULL, &vdm1_help, NULL, NULL,
+ &vdm1_description
+};
+
+/* VDM1 routines
+
+ vdm1_svc process event
+ vdm1_reset process reset
+*/
+
+t_stat vdm1_svc(UNIT *uptr)
+{
+ SIM_KEY_EVENT kev;
+
+ vdm1_counter++;
+
+ /* Handle blink */
+ if ((vdm1_counter % 10 == 0) && (vdm1_cursor == VDM1_BLINK)) {
+ vdm1_blink = !vdm1_blink;
+ vdm1_dirty = TRUE;
+ }
+
+ if (vdm1_dirty) {
+ vdm1_refresh();
+ vdm1_dirty = TRUE;
+ }
+
+ if (vdm1_kb_callback != NULL) {
+ if (vid_poll_kb(&kev) == SCPE_OK) {
+ (*vdm1_kb_callback)(&kev);
+ }
+ }
+
+ sim_activate_after_abs(uptr, uptr->wait); // 25ms refresh rate
+
+ return SCPE_OK;
+}
+
+t_stat vdm1_reset(DEVICE *dptr)
+{
+ VDM1_CTX *xptr;
+ t_stat r;
+ int i;
+
+ xptr = (VDM1_CTX *) dptr->ctxt;
+
+ if (dptr->flags & DEV_DIS) {
+ sim_map_resource(xptr->pnp.mem_base, xptr->pnp.mem_size, RESOURCE_TYPE_MEMORY, &vdm1_mem, "vdm1", TRUE);
+ sim_map_resource(xptr->pnp.io_base, xptr->pnp.io_size, RESOURCE_TYPE_IO, &vdm1_io, "vdm1", TRUE);
+
+ sim_cancel(&vdm1_unit);
+
+ if (vdm1_active) {
+ vdm1_active = FALSE;
+ return vid_close();
+ }
+
+ return SCPE_OK;
+ }
+
+ sim_map_resource(xptr->pnp.mem_base, xptr->pnp.mem_size, RESOURCE_TYPE_MEMORY, &vdm1_mem, "vdm1", FALSE);
+ sim_map_resource(xptr->pnp.io_base, xptr->pnp.io_size, RESOURCE_TYPE_IO, &vdm1_io, "vdm1", FALSE);
+
+ if (!vdm1_active) {
+ r = vid_open_window(&vdm1_vptr, &vdm1_dev, "Display", VDM1_XSIZE, VDM1_YSIZE, SIM_VID_IGNORE_VBAR | SIM_VID_RESIZABLE); /* video buffer size */
+
+ if (r != SCPE_OK) {
+ return r;
+ }
+
+ vid_set_window_size(vdm1_vptr, 800, 600);
+
+ vdm1_palette[0] = vid_map_rgb_window(vdm1_vptr, 0x00, 0x00, 0x00);
+ vdm1_palette[1] = vid_map_rgb_window(vdm1_vptr, 0x00, 0xFF, 0x30);
+
+ for (i = 0; i < VDM1_PIXELS; i++) {
+ vdm1_surface[i] = vdm1_palette[0];
+ }
+
+ vdm1_active = TRUE;
+ }
+
+ sim_activate_after_abs(&vdm1_unit, 25);
+
+ return SCPE_OK;
+}
+
+static t_stat vdm1_boot(int32 unitno, DEVICE *dptr)
+{
+ exdep_cmd(EX_D, "-m 0 MVI A,0");
+ exdep_cmd(EX_D, "-m 2 OUT 0FEH");
+ exdep_cmd(EX_D, "-m 4 MVI C,0");
+ exdep_cmd(EX_D, "-m 6 MVI B,0");
+ exdep_cmd(EX_D, "-m 8 LXI H,0CC00H");
+ exdep_cmd(EX_D, "-m B DCR B");
+ exdep_cmd(EX_D, "-m C MOV M,B");
+ exdep_cmd(EX_D, "-m D INX H");
+ exdep_cmd(EX_D, "-m E MOV A,H");
+ exdep_cmd(EX_D, "-m F CPI 0D0H");
+ exdep_cmd(EX_D, "-m 11 JNZ 000BH");
+ exdep_cmd(EX_D, "-m 14 DCX H");
+ exdep_cmd(EX_D, "-m 15 MOV A,H");
+ exdep_cmd(EX_D, "-m 16 ORA A");
+ exdep_cmd(EX_D, "-m 17 JNZ 0012H");
+ exdep_cmd(EX_D, "-m 1A INR C");
+ exdep_cmd(EX_D, "-m 1B MOV B,C");
+ exdep_cmd(EX_D, "-m 1C JMP 0008H");
+
+ *((int32 *) sim_PC->loc) = 0x0000;
+
+ return SCPE_OK;
+}
+
+static int32 vdm1_io(const int32 port, const int32 io, const int32 data) {
+ int32 result = 0xff;
+
+ if (io == 1) { /* OUT */
+ if (port == VDM1_DSTAT) {
+ vdm1_dstat = data & 0xff;
+ }
+ }
+
+ return result;
+}
+
+/*
+ * VDM-1 1K Video Memory (16 x 64 characters)
+ */
+static int32 vdm1_mem(int32 addr, int32 rw, int32 data)
+{
+
+ if (rw == 0) {
+ data = vdm1_ram[addr & VDM1_MEM_MASK];
+ }
+ else {
+ vdm1_ram[addr & VDM1_MEM_MASK] = data;
+ vdm1_dirty = TRUE;
+ }
+
+ return data;
+}
+
+t_stat vdm1_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
+{
+ fprintf(st, "\nThe VDM-1 has several switches that control the video display:\n\n");
+
+ fprintf(st, "SET VDM1 CTRL=MODEx\n");
+ fprintf(st, "MODE1 - All control characters suppressed. Only cursor blocks\n");
+ fprintf(st, " are displayed. CR and VT enabled.\n");
+ fprintf(st, "MODE2 - Control characters blanked. CR and VT enabled.\n");
+ fprintf(st, "MODE3 - Control characters displayable. CR and VT enabled.\n");
+ fprintf(st, "MODE4 - Control characters displayable. CR and VT disabled. (default)\n\n");
+
+ fprintf(st, "SET VDM1 CURSOR=NONE,BLINK,NOBLINK\n");
+ fprintf(st, "NONE - All cursors suppressed.\n");
+ fprintf(st, "BLINK - Blinking cursor.\n");
+ fprintf(st, "NOBLINK - Non-blinking cursor. (default)\n\n");
+
+ fprintf(st, "SET VDM1 DISPLAY=NONE,NORMAL,REVERSE\n");
+ fprintf(st, "NONE - No display.\n");
+ fprintf(st, "NORMAL - Normal video. (default)\n");
+ fprintf(st, "REVERSE - Reverse video.\n\n");
+
+ fprintf(st, "VDM-1 test program displays all characters on the screen:\n");
+ fprintf(st, "BOOT VDM1\n\n");
+
+ return SCPE_OK;
+}
+
+const char *vdm1_description (DEVICE *dptr)
+{
+ return "Processor Technology VDM-1 Display";
+}
+
+/*
+ * Draw and refresh the screen in the video window
+ */
+static void vdm1_refresh() {
+ if (vdm1_active) {
+ vdm1_render();
+ vid_draw_window(vdm1_vptr, VDM1_MARGIN, VDM1_MARGIN, VDM1_XSIZE, VDM1_YSIZE, vdm1_surface);
+ vid_refresh_window(vdm1_vptr);
+ }
+}
+
+/*
+ * The VDM-1 display is make up of 16 64-character rows. Each character occupies
+ * 1 byte in memory from CC00-CFFF.
+ */
+static void vdm1_render()
+{
+ uint8 x,y,s,c,c1;
+ int addr = 0;
+ t_bool eol_blank = FALSE;
+ t_bool eos_blank = FALSE;
+
+ addr += (vdm1_dstat & VDM1_DSTAT_CMSK) * VDM1_COLS;
+ s = (vdm1_dstat & VDM1_DSTAT_RMSK) >> 4; /* Shadowing */
+
+ for (y = 0; y < VDM1_LINES; y++) {
+ for (x = 0; x < VDM1_COLS; x++) {
+
+ c = vdm1_ram[addr++];
+ c1 = c & 0x7f;
+
+ /* EOL and EOS blanking */
+ if (c1 == 0x0d && (vdm1_ctrl == VDM1_MODE2 || vdm1_ctrl == VDM1_MODE3)) { // CR
+ eol_blank = TRUE;
+ }
+ else if (c1 == 0x0b && (vdm1_ctrl == VDM1_MODE2 || vdm1_ctrl == VDM1_MODE3)) { // VT
+ eos_blank = TRUE;
+ }
+
+ /* Blanking control */
+ if (vdm1_display == VDM1_NONE || eol_blank || eos_blank || y < s) {
+ c = ' ';
+ }
+
+ /* Control character suppression */
+ if ((c1 < 0x20 || c1 == 0x7f) && (vdm1_ctrl == VDM1_MODE1 || vdm1_ctrl == VDM1_MODE2)) {
+ c = ' ';
+ }
+
+ vdm1_render_char(c, x, y);
+
+ if (addr == VDM1_MEM_SIZE) {
+ addr = 0;
+ }
+ }
+ }
+}
+
+/*
+ * The VDM-1 rendered characters one scan line at a time.
+ * The simulator renders an entire character at a time by
+ * rendering each character in a rectangle area in the
+ * video surface buffer.
+ */
+static void vdm1_render_char(uint8 byte, uint8 x, uint8 y)
+{
+ uint8 rx,ry,c;
+ int start,pixel;
+
+ start = (x * VDM1_CHAR_XSIZE) + (VDM1_XSIZE * VDM1_CHAR_YSIZE * y);
+
+ for (ry = 0; ry < VDM1_CHAR_YSIZE; ry++) {
+
+ pixel = start + (VDM1_XSIZE * ry);
+
+ c = charset[byte & 0x7f][ry];
+
+ if (!vdm1_blink && byte & 0x80) {
+ c = ~(c & 0xff);
+ }
+
+ if (vdm1_display == VDM1_REVERSE) {
+ c = ~(c & 0xff);
+ }
+
+ for (rx = 0; rx < VDM1_CHAR_XSIZE - 1; rx++) {
+ vdm1_surface[pixel++] = vdm1_palette[c & (0x80 >> rx) ? !vdm1_reverse : vdm1_reverse];
+ }
+
+ vdm1_surface[pixel++] = vdm1_palette[(c & 0x80) ? !vdm1_reverse : vdm1_reverse];
+ }
+}
+
+static t_stat vdm1_set_ctrl(UNIT *uptr, int32 val, CONST char *cptr, void *desc)
+{
+ if (!cptr) return SCPE_IERR;
+ if (!strlen(cptr)) return SCPE_ARG;
+
+ /* this assumes that the parameter has already been upcased */
+ if (!strncmp(cptr, "MODE1", strlen(cptr))) {
+ vdm1_ctrl = VDM1_MODE1;
+ } else if (!strncmp(cptr, "MODE2", strlen(cptr))) {
+ vdm1_ctrl = VDM1_MODE2;
+ } else if (!strncmp(cptr, "MODE3", strlen(cptr))) {
+ vdm1_ctrl = VDM1_MODE3;
+ } else if (!strncmp(cptr, "MODE4", strlen(cptr))) {
+ vdm1_ctrl = VDM1_MODE4;
+ } else {
+ return SCPE_ARG;
+ }
+
+ vdm1_dirty = TRUE;
+
+ return SCPE_OK;
+}
+
+static t_stat vdm1_show_ctrl(FILE *st, UNIT *uptr, int32 val, CONST void *desc)
+{
+ if (!st) return SCPE_IERR;
+
+ fprintf(st, "CTRL=");
+
+ switch (vdm1_ctrl) {
+ case VDM1_MODE1:
+ fprintf(st, "MODE1");
+ break;
+
+ case VDM1_MODE2:
+ fprintf(st, "MODE2");
+ break;
+
+ case VDM1_MODE3:
+ fprintf(st, "MODE3");
+ break;
+
+ case VDM1_MODE4:
+ fprintf(st, "MODE4");
+ break;
+
+ default:
+ fprintf(st, "UNKNOWN");
+ break;
+ }
+
+ return SCPE_OK;
+}
+
+static t_stat vdm1_set_cursor(UNIT *uptr, int32 val, CONST char *cptr, void *desc)
+{
+ if (!cptr) return SCPE_IERR;
+ if (!strlen(cptr)) return SCPE_ARG;
+
+ /* this assumes that the parameter has already been upcased */
+ if (!strncmp(cptr, "NONE", strlen(cptr))) {
+ vdm1_cursor = VDM1_NONE;
+ } else if (!strncmp(cptr, "BLINK", strlen(cptr))) {
+ vdm1_cursor = VDM1_BLINK;
+ } else if (!strncmp(cptr, "NOBLINK", strlen(cptr))) {
+ vdm1_cursor = VDM1_NOBLINK;
+ vdm1_blink = FALSE;
+ } else {
+ return SCPE_ARG;
+ }
+
+ vdm1_dirty = TRUE;
+
+ return SCPE_OK;
+}
+
+static t_stat vdm1_show_cursor(FILE *st, UNIT *uptr, int32 val, CONST void *desc)
+{
+ if (!st) return SCPE_IERR;
+
+ fprintf(st, "CURSOR=");
+
+ switch (vdm1_cursor) {
+ case VDM1_NONE:
+ fprintf(st, "NONE");
+ break;
+
+ case VDM1_BLINK:
+ fprintf(st, "BLINK");
+ break;
+
+ case VDM1_NOBLINK:
+ fprintf(st, "NOBLINK");
+ break;
+
+ default:
+ fprintf(st, "UNKNOWN");
+ break;
+ }
+
+ return SCPE_OK;
+}
+
+static t_stat vdm1_set_display(UNIT *uptr, int32 val, CONST char *cptr, void *desc)
+{
+ if (!cptr) return SCPE_IERR;
+ if (!strlen(cptr)) return SCPE_ARG;
+
+ /* this assumes that the parameter has already been upcased */
+ if (!strncmp(cptr, "NONE", strlen(cptr))) {
+ vdm1_display = VDM1_NONE;
+ } else if (!strncmp(cptr, "NORMAL", strlen(cptr))) {
+ vdm1_display = VDM1_NORMAL;
+ } else if (!strncmp(cptr, "REVERSE", strlen(cptr))) {
+ vdm1_display = VDM1_REVERSE;
+ } else {
+ return SCPE_ARG;
+ }
+
+ vdm1_dirty = TRUE;
+
+ return SCPE_OK;
+}
+
+static t_stat vdm1_show_display(FILE *st, UNIT *uptr, int32 val, CONST void *desc)
+{
+ if (!st) return SCPE_IERR;
+
+ fprintf(st, "DISPLAY=");
+
+ switch (vdm1_display) {
+ case VDM1_NONE:
+ fprintf(st, "NONE");
+ break;
+
+ case VDM1_NORMAL:
+ fprintf(st, "NORMAL");
+ break;
+
+ case VDM1_REVERSE:
+ fprintf(st, "REVERSE");
+ break;
+
+ default:
+ fprintf(st, "UNKNOWN");
+ break;
+ }
+
+ return SCPE_OK;
+}
+
diff --git a/AltairZ80/sol20.c b/AltairZ80/sol20.c
new file mode 100644
index 00000000..6992e15a
--- /dev/null
+++ b/AltairZ80/sol20.c
@@ -0,0 +1,2274 @@
+/*** sol20.c: Processor Technology Sol-20
+
+ Created by Patrick Linstruth (patrick@deltecent.com)
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ PETER SCHORN BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ Except as contained in this notice, the name of Patrick Linstruth shall not
+ be used in advertising or otherwise to promote the sale, use or other dealings
+ in this Software without prior written authorization from Patrick Linstruth.
+
+ These functions support the Processor Techology Sol-20
+
+ There are four devices defined, SOL20, SOL20T, SOL20S, and SOL20P. The SOL20
+ device provides personality modules. The SOL20T device supports an emulated
+ tape drive. The SOL20S device supports the serial port. The SOL20P device
+ supports the printer port.
+
+ Devices:
+
+ SOL20K - Keyboard
+ SOL20S - Serial Port
+ SOL20P - Printer Port
+ SOL20T - Tape Port
+
+ The Keyboard, serial and printer ports support TMXR which allow these
+ ports to be attached to real serial ports the sockets. If no TMXR
+ interfaces are attaached, the serial and parallel ports will use
+ the SIMH console for input and output. This allows pasting
+ ENT files into SOLOS using the SIMH console. The keyboard will
+ use the video window and the SIMH console for input.
+
+ The tape device allows attaching files that can be read from and
+ written simulating reading and writing to cassettes.
+
+ The Sol-20 displays its output on the VDM-1 video display.
+ The most commonly used disk controller with the Sol-20 was the North Star
+ hard-sector controller. The first North Star controller sold was SSSD and
+ was typically used to run North Star DOS or CP/M 1.4. The single density
+ format allowed about 88K of storage per diskette. Later, the DSDD North
+ Star controller increased capacity to 350K of storage per diskette.
+
+ Both SSSD (MDSA) and DSDD (MDSAD) are supported by AltairZ80.
+
+ Disk images of North Star DOS and CP/M for both of the North Star
+ controllers, along with utilities for disk image transfer, are available at
+ https://deramp.com/downloads/processor_technology/sol-20/software/
+
+ Example:
+
+ SET SOL20 ENA
+ SET SOL20 ROM=13C
+ SET MDSA ENA
+ ATTACH MDSA0 CPM22b14-48K-SDC-SOL.NSI
+ BOOT SOL20
+
+ At the '>' prompt, enter "EX E800" to boot CP/M
+*/
+
+#include "altairz80_defs.h"
+#include "sim_imd.h"
+#include "sim_tmxr.h"
+#include "sim_video.h"
+
+/********/
+/* SIMH */
+/********/
+
+extern uint32 sim_map_resource(uint32 baseaddr, uint32 size, uint32 resource_type,
+ int32 (*routine)(const int32, const int32, const int32), const char* name, uint8 unmap);
+extern t_stat set_dev_enbdis(DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
+extern t_stat (*vdm1_kb_callback)(SIM_KEY_EVENT *kev);
+extern t_stat set_membase(UNIT *uptr, int32 val, CONST char *cptr, void *desc);
+extern t_stat show_membase(FILE *st, UNIT *uptr, int32 val, CONST void *desc);
+extern t_stat set_cmd(int32 flag, CONST char *cptr);
+
+extern void PutBYTEWrapper(const uint32 Addr, const uint32 Value);
+extern uint32 nmiInterrupt;
+
+/* Debug flags */
+#define VERBOSE_MSG (1 << 0)
+#define ERROR_MSG (1 << 1)
+#define STATUS_MSG (1 << 2)
+
+/* Debug Flags */
+static DEBTAB sol20_dt[] = {
+ { "VERBOSE", VERBOSE_MSG, "Verbose messages" },
+ { "ERROR", ERROR_MSG, "Error messages" },
+ { "STATUS", STATUS_MSG, "Status messages" },
+ { NULL, 0 }
+};
+
+/*****************************/
+/* Local function prototypes */
+/*****************************/
+
+static t_stat sol20_reset(DEVICE *dptr);
+static t_stat sol20_kb_reset(DEVICE *dptr);
+static t_stat sol20_port_reset(DEVICE *dptr);
+static t_stat sol20_svc(UNIT *uptr);
+static t_stat sol20_help(FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr);
+static t_stat sol20_boot(int32 unitno, DEVICE *dptr);
+static t_stat sol20_attach_tape(UNIT *uptr, CONST char *cptr);
+static t_stat sol20_detach_tape(UNIT *uptr);
+static t_stat sol20_attach_mux(UNIT *uptr, CONST char *cptr);
+static t_stat sol20_detach_mux(UNIT *uptr);
+static const char* sol20_description(DEVICE *dptr);
+static t_stat sol20_config_line(DEVICE *dev, TMLN *tmln, int baud);
+static const char* sol20k_description(DEVICE *dptr);
+static const char* sol20t_description(DEVICE *dptr);
+static const char* sol20s_description(DEVICE *dptr);
+static const char* sol20p_description(DEVICE *dptr);
+static t_stat sol20_set_baud(UNIT *uptr, int32 value, const char *cptr, void *desc);
+static t_stat sol20_show_baud(FILE *st, UNIT *uptr, int32 value, const void *desc);
+static t_stat sol20_set_rom(UNIT *uptr, int32 val, CONST char *cptr, void *desc);
+static t_stat sol20_show_rom(FILE *st, UNIT *uptr, int32 val, CONST void *desc);
+static t_stat sol20_show_ports(FILE *st, UNIT *uptr, int32 val, CONST void *desc);
+static t_stat sol20_set_tape(UNIT *uptr, int32 val, CONST char *cptr, void *desc);
+static t_stat sol20_show_tape(FILE *st, UNIT *uptr, int32 val, CONST void *desc);
+static t_stat sol20_rewind(UNIT *uptr);
+static t_stat sol20_erase(UNIT *uptr);
+static int32 sol20io(int32 addr, int32 rw, int32 data);
+static int32 sol20rom(int32 addr, int32 rw, int32 data);
+static uint8 sol20_io_in(uint32 addr);
+static uint8 sol20_io_out(uint32 addr, int32 data);
+static t_stat sol20_kb_callback(SIM_KEY_EVENT *kev);
+static uint8 translate_key(SIM_KEY_EVENT *kev);
+
+/***********/
+/* RAM/ROM */
+/***********/
+
+#define SOL20_ROM_BASE 0xc000
+#define SOL20_ROM_SIZE 2048
+#define SOL20_ROM_MASK (SOL20_ROM_SIZE-1)
+
+/* SOLOS 1.3 ROM */
+static uint8 sol20_rom_13[SOL20_ROM_SIZE] = {
+ 0x00, 0xc3, 0xaf, 0xc1, 0xc3, 0xc9, 0xc1, 0xc3,
+ 0xe0, 0xc5, 0xc3, 0x03, 0xc6, 0xc3, 0x46, 0xc6,
+ 0xc3, 0x83, 0xc6, 0xc3, 0xcb, 0xc6, 0xc3, 0x7f,
+ 0xc7, 0x3a, 0x07, 0xc8, 0xc3, 0x3b, 0xc0, 0x3a,
+ 0x06, 0xc8, 0xe5, 0x21, 0x9a, 0xc2, 0xe6, 0x03,
+ 0x07, 0x85, 0x6f, 0xc3, 0x27, 0xc2, 0xdb, 0xfa,
+ 0x2f, 0xe6, 0x01, 0xc8, 0xdb, 0xfc, 0xc9, 0x00,
+ 0xc3, 0x01, 0xc0, 0xe5, 0x21, 0x92, 0xc2, 0xc3,
+ 0x26, 0xc0, 0xdb, 0xf8, 0xe6, 0x40, 0xc8, 0xdb,
+ 0xf9, 0xc9, 0xdb, 0xf8, 0x17, 0xd2, 0x4a, 0xc0,
+ 0x78, 0xd3, 0xf9, 0xc9, 0xe5, 0xd5, 0xc5, 0x3a,
+ 0x0c, 0xc8, 0xb7, 0xc2, 0x5f, 0xc1, 0x78, 0xe6,
+ 0x7f, 0x47, 0xca, 0x7c, 0xc0, 0x21, 0x73, 0xc2,
+ 0xcd, 0x82, 0xc0, 0xcd, 0x1c, 0xc1, 0x7e, 0xf6,
+ 0x80, 0x77, 0x2a, 0x0a, 0xc8, 0x2c, 0xaf, 0x2b,
+ 0xbc, 0xc2, 0x77, 0xc0, 0xc1, 0xd1, 0xe1, 0xc9,
+ 0x23, 0x23, 0x7e, 0xb7, 0xca, 0x94, 0xc0, 0xb8,
+ 0x23, 0xc2, 0x80, 0xc0, 0xe5, 0xcd, 0x36, 0xc1,
+ 0xe3, 0xc3, 0x27, 0xc2, 0x78, 0xfe, 0x7f, 0xc8,
+ 0xcd, 0x1c, 0xc1, 0x70, 0x3a, 0x08, 0xc8, 0xfe,
+ 0x3f, 0xda, 0xc1, 0xc0, 0x3a, 0x09, 0xc8, 0xfe,
+ 0x0f, 0xc2, 0xc1, 0xc0, 0xaf, 0x32, 0x08, 0xc8,
+ 0x4f, 0xcd, 0x23, 0xc1, 0xaf, 0xcd, 0xfa, 0xc0,
+ 0x3a, 0x0a, 0xc8, 0x3c, 0xe6, 0x0f, 0xc3, 0xee,
+ 0xc0, 0x3a, 0x08, 0xc8, 0x3c, 0xe6, 0x3f, 0x32,
+ 0x08, 0xc8, 0xc0, 0x3a, 0x09, 0xc8, 0x3c, 0xe6,
+ 0x0f, 0x32, 0x09, 0xc8, 0xc9, 0x21, 0x00, 0xcc,
+ 0x36, 0xa0, 0x23, 0x36, 0x20, 0x23, 0x7c, 0xfe,
+ 0xd0, 0xda, 0xdb, 0xc0, 0x37, 0x3e, 0x00, 0x32,
+ 0x09, 0xc8, 0x32, 0x08, 0xc8, 0xd0, 0xd3, 0xfe,
+ 0x32, 0x0a, 0xc8, 0xc9, 0xcd, 0x1c, 0xc1, 0x3a,
+ 0x08, 0xc8, 0xfe, 0x40, 0xd0, 0x36, 0x20, 0x23,
+ 0x3c, 0xc3, 0xfa, 0xc0, 0x3a, 0x09, 0xc8, 0x3d,
+ 0xc3, 0xcf, 0xc0, 0x3a, 0x08, 0xc8, 0x3d, 0xe6,
+ 0x3f, 0x32, 0x08, 0xc8, 0xc9, 0x3a, 0x08, 0xc8,
+ 0x3c, 0xc3, 0x0f, 0xc1, 0x3a, 0x08, 0xc8, 0x4f,
+ 0x3a, 0x09, 0xc8, 0x6f, 0x3a, 0x0a, 0xc8, 0x85,
+ 0x0f, 0x0f, 0x6f, 0xe6, 0x03, 0xc6, 0xcc, 0x67,
+ 0x7d, 0xe6, 0xc0, 0x81, 0x6f, 0xc9, 0xcd, 0x1c,
+ 0xc1, 0x7e, 0xe6, 0x7f, 0x77, 0xc9, 0xcd, 0x0b,
+ 0xc1, 0xcd, 0x1c, 0xc1, 0x36, 0x20, 0xc9, 0xcd,
+ 0xf4, 0xc0, 0xc3, 0x0f, 0xc1, 0x3a, 0x09, 0xc8,
+ 0x3c, 0xe6, 0x0f, 0xc2, 0xd1, 0xc0, 0xc3, 0xb0,
+ 0xc0, 0x3e, 0xff, 0x32, 0x0c, 0xc8, 0xc9, 0xcd,
+ 0x36, 0xc1, 0xcd, 0x68, 0xc1, 0xc3, 0x6b, 0xc0,
+ 0x3a, 0x0c, 0xc8, 0xfe, 0xff, 0xca, 0x90, 0xc1,
+ 0x21, 0x0c, 0xc8, 0x36, 0x00, 0xfe, 0x02, 0xda,
+ 0x88, 0xc1, 0xca, 0x8c, 0xc1, 0xfe, 0x08, 0xca,
+ 0x98, 0xc5, 0xfe, 0x09, 0xda, 0x98, 0xc0, 0xc0,
+ 0x78, 0xc3, 0x0f, 0xc1, 0x78, 0xc3, 0xcf, 0xc0,
+ 0x78, 0xfe, 0x03, 0xca, 0xa6, 0xc1, 0xfe, 0x04,
+ 0xc2, 0xa2, 0xc1, 0x44, 0x4d, 0xe1, 0xd1, 0xc5,
+ 0xe5, 0xaf, 0x32, 0x0c, 0xc8, 0xc9, 0x21, 0x08,
+ 0xc8, 0x46, 0x23, 0x4e, 0xc3, 0x9d, 0xc1, 0xaf,
+ 0x4f, 0x21, 0x00, 0xc8, 0x77, 0x23, 0x0c, 0xc2,
+ 0xb4, 0xc1, 0x31, 0xff, 0xcb, 0xcd, 0xd5, 0xc0,
+ 0xaf, 0xd3, 0xfa, 0x32, 0x07, 0xc8, 0x32, 0x06,
+ 0xc8, 0x31, 0xff, 0xcb, 0x3a, 0x07, 0xc8, 0xf5,
+ 0xaf, 0x32, 0x07, 0xc8, 0xcd, 0xf1, 0xc2, 0xcd,
+ 0xe4, 0xc1, 0xf1, 0x32, 0x07, 0xc8, 0xcd, 0x05,
+ 0xc2, 0xc3, 0xc9, 0xc1, 0xcd, 0x1f, 0xc0, 0xca,
+ 0xe4, 0xc1, 0xe6, 0x7f, 0xca, 0xc0, 0xc1, 0x47,
+ 0xfe, 0x0d, 0xca, 0xf4, 0xc0, 0xfe, 0x0a, 0xc8,
+ 0xfe, 0x7f, 0xc2, 0xff, 0xc1, 0x06, 0x5f, 0xcd,
+ 0x19, 0xc0, 0xc3, 0xe4, 0xc1, 0xcd, 0x36, 0xc1,
+ 0x0e, 0x01, 0xcd, 0x20, 0xc1, 0xeb, 0x21, 0x00,
+ 0xc0, 0xe5, 0xcd, 0x2e, 0xc3, 0xca, 0x80, 0xc4,
+ 0xeb, 0x11, 0x4a, 0xc2, 0xcd, 0x31, 0xc2, 0xcc,
+ 0x2e, 0xc2, 0xca, 0x81, 0xc4, 0x13, 0xeb, 0x7e,
+ 0x23, 0x66, 0x6f, 0xe3, 0x7d, 0xc9, 0x11, 0x3c,
+ 0xc8, 0x1a, 0xb7, 0xc8, 0xe5, 0xbe, 0x13, 0xc2,
+ 0x43, 0xc2, 0x23, 0x1a, 0xbe, 0xc2, 0x43, 0xc2,
+ 0xe1, 0xb7, 0xc9, 0x13, 0x13, 0x13, 0xe1, 0xc3,
+ 0x31, 0xc2, 0x54, 0x45, 0x67, 0xc3, 0x44, 0x55,
+ 0xbf, 0xc3, 0x45, 0x4e, 0x23, 0xc4, 0x45, 0x58,
+ 0x5e, 0xc4, 0x47, 0x45, 0xa7, 0xc4, 0x53, 0x41,
+ 0xe6, 0xc4, 0x58, 0x45, 0xa6, 0xc4, 0x43, 0x41,
+ 0x2b, 0xc5, 0x53, 0x45, 0x7a, 0xc5, 0x43, 0x55,
+ 0xbd, 0xc5, 0x00, 0x0b, 0xd5, 0xc0, 0x17, 0x04,
+ 0xc1, 0x1a, 0xcb, 0xc0, 0x01, 0x0b, 0xc1, 0x13,
+ 0x15, 0xc1, 0x0e, 0xe5, 0xc0, 0x0d, 0x47, 0xc1,
+ 0x0a, 0x4d, 0xc1, 0x5f, 0x3e, 0xc1, 0x1b, 0x59,
+ 0xc1, 0x00, 0x54, 0xc0, 0x4a, 0xc0, 0xe6, 0xc2,
+ 0xd2, 0xc2, 0x2e, 0xc0, 0x42, 0xc0, 0xdd, 0xc2,
+ 0xcb, 0xc2, 0x54, 0x41, 0x8e, 0xc5, 0x53, 0x3d,
+ 0x99, 0xc5, 0x49, 0x3d, 0x9d, 0xc5, 0x4f, 0x3d,
+ 0xa1, 0xc5, 0x4e, 0x3d, 0xb5, 0xc5, 0x43, 0x49,
+ 0xa5, 0xc5, 0x43, 0x4f, 0xa9, 0xc5, 0x58, 0x45,
+ 0xb1, 0xc5, 0x54, 0x59, 0xad, 0xc5, 0x43, 0x52,
+ 0xb9, 0xc5, 0x00, 0xe5, 0x2a, 0x00, 0xc8, 0xc3,
+ 0xd6, 0xc2, 0xe5, 0x2a, 0x02, 0xc8, 0x7d, 0xb4,
+ 0xca, 0xc0, 0xc1, 0xe3, 0xc9, 0xdb, 0xfa, 0x2f,
+ 0xe6, 0x02, 0xc8, 0xdb, 0xfd, 0xc9, 0xdb, 0xfa,
+ 0xe6, 0x04, 0xc2, 0xe6, 0xc2, 0x78, 0xd3, 0xfd,
+ 0xc9, 0xcd, 0xf9, 0xc2, 0x06, 0x3e, 0xc3, 0x19,
+ 0xc0, 0x06, 0x0a, 0xcd, 0x19, 0xc0, 0x06, 0x0d,
+ 0xcd, 0x19, 0xc0, 0x3a, 0x10, 0xc8, 0x4f, 0x0d,
+ 0xf8, 0xaf, 0xcd, 0x1f, 0xc4, 0xc3, 0x07, 0xc3,
+ 0xcd, 0x1b, 0xc3, 0x3e, 0x01, 0xc8, 0xcd, 0x40,
+ 0xc3, 0x7d, 0xc9, 0x0e, 0x0c, 0x1a, 0xfe, 0x20,
+ 0xca, 0x2e, 0xc3, 0x13, 0xfe, 0x3d, 0xca, 0x2e,
+ 0xc3, 0x0d, 0xc2, 0x1d, 0xc3, 0xc9, 0x0e, 0x0a,
+ 0x1a, 0xfe, 0x20, 0xc0, 0x13, 0x0d, 0xc8, 0xc3,
+ 0x30, 0xc3, 0xcd, 0x1b, 0xc3, 0xca, 0x80, 0xc4,
+ 0x21, 0x00, 0x00, 0x1a, 0xfe, 0x20, 0xc8, 0xfe,
+ 0x2f, 0xc8, 0xfe, 0x3a, 0xc8, 0x29, 0x29, 0x29,
+ 0x29, 0xcd, 0x5d, 0xc3, 0xd2, 0x80, 0xc4, 0x85,
+ 0x6f, 0x13, 0xc3, 0x43, 0xc3, 0xd6, 0x30, 0xfe,
+ 0x0a, 0xd8, 0xd6, 0x07, 0xfe, 0x10, 0xc9, 0xcd,
+ 0x10, 0xc3, 0x32, 0x06, 0xc8, 0xcd, 0x10, 0xc3,
+ 0x32, 0x07, 0xc8, 0xcd, 0x2e, 0xc0, 0xca, 0x8b,
+ 0xc3, 0x47, 0xfe, 0x80, 0xca, 0xc0, 0xc1, 0xda,
+ 0x88, 0xc3, 0xcd, 0x54, 0xc0, 0xc3, 0x8b, 0xc3,
+ 0xcd, 0x19, 0xc0, 0xcd, 0x1f, 0xc0, 0xca, 0x73,
+ 0xc3, 0xe6, 0x7f, 0xca, 0x73, 0xc3, 0x47, 0xfe,
+ 0x1b, 0xd2, 0xb9, 0xc3, 0xfe, 0x0d, 0xca, 0xb9,
+ 0xc3, 0xfe, 0x0a, 0xca, 0xb9, 0xc3, 0x3a, 0x0c,
+ 0xc8, 0xb7, 0xc2, 0xb9, 0xc3, 0xc5, 0x06, 0x1b,
+ 0xcd, 0x54, 0xc0, 0x06, 0x07, 0xcd, 0x54, 0xc0,
+ 0xc1, 0xcd, 0x54, 0xc0, 0xc3, 0x73, 0xc3, 0xcd,
+ 0x3a, 0xc3, 0xe5, 0xcd, 0x10, 0xc3, 0xd1, 0xeb,
+ 0xcd, 0xf9, 0xc2, 0xcd, 0xe8, 0xc3, 0xcd, 0x06,
+ 0xc4, 0x0e, 0x10, 0x7e, 0xc5, 0xcd, 0xed, 0xc3,
+ 0x7d, 0x93, 0x7c, 0x9a, 0xd2, 0xc9, 0xc1, 0xc1,
+ 0x23, 0x0d, 0xc2, 0xd3, 0xc3, 0xc3, 0xc8, 0xc3,
+ 0x7c, 0xcd, 0x0b, 0xc4, 0x7d, 0xcd, 0x0b, 0xc4,
+ 0xcd, 0x1f, 0xc0, 0xca, 0x06, 0xc4, 0xe6, 0x7f,
+ 0xca, 0xc9, 0xc1, 0xfe, 0x20, 0xc2, 0x06, 0xc4,
+ 0xcd, 0x1f, 0xc0, 0xca, 0x00, 0xc4, 0x06, 0x20,
+ 0xc3, 0x19, 0xc0, 0x4f, 0x0f, 0x0f, 0x0f, 0x0f,
+ 0xcd, 0x14, 0xc4, 0x79, 0xe6, 0x0f, 0xc6, 0x30,
+ 0xfe, 0x3a, 0xda, 0x1f, 0xc4, 0xc6, 0x07, 0x47,
+ 0xc3, 0x19, 0xc0, 0xcd, 0x3a, 0xc3, 0xe5, 0xaf,
+ 0x32, 0x07, 0xc8, 0xcd, 0xf9, 0xc2, 0x06, 0x3a,
+ 0xcd, 0xff, 0xc1, 0xcd, 0x36, 0xc1, 0x0e, 0x01,
+ 0xcd, 0x20, 0xc1, 0xeb, 0x0e, 0x03, 0xcd, 0x30,
+ 0xc3, 0xca, 0x2b, 0xc4, 0xfe, 0x2f, 0xca, 0xc0,
+ 0xc1, 0xcd, 0x40, 0xc3, 0xfe, 0x3a, 0xca, 0x59,
+ 0xc4, 0x7d, 0xe1, 0x77, 0x23, 0xe5, 0xc3, 0x3c,
+ 0xc4, 0xe3, 0x13, 0xc3, 0x3c, 0xc4, 0xcd, 0x3a,
+ 0xc3, 0xe5, 0x21, 0x00, 0xc0, 0xc9, 0x21, 0x1c,
+ 0xc8, 0xcd, 0x1b, 0xc3, 0x06, 0x06, 0x1a, 0xfe,
+ 0x20, 0xca, 0x86, 0xc4, 0xfe, 0x2f, 0xca, 0x86,
+ 0xc4, 0x77, 0x13, 0x23, 0x05, 0xc2, 0x6e, 0xc4,
+ 0xeb, 0x36, 0x3f, 0xc3, 0xc0, 0xc1, 0x36, 0x00,
+ 0x23, 0x05, 0xc2, 0x86, 0xc4, 0xfe, 0x2f, 0x3e,
+ 0x01, 0xc2, 0x9a, 0xc4, 0x13, 0xcd, 0x2e, 0xc3,
+ 0xd6, 0x30, 0xe6, 0x01, 0x3e, 0x80, 0xc2, 0xa2,
+ 0xc4, 0x1f, 0x32, 0x54, 0xc8, 0xc9, 0x3e, 0xaf,
+ 0xf5, 0x21, 0x2c, 0xc8, 0xcd, 0x69, 0xc4, 0x21,
+ 0x00, 0x00, 0xcd, 0x10, 0xc3, 0xeb, 0x21, 0x2c,
+ 0xc8, 0x7e, 0xb7, 0xc2, 0xc1, 0xc4, 0x21, 0x1c,
+ 0xc8, 0xe5, 0xcd, 0x48, 0xc5, 0xe1, 0xcd, 0xcb,
+ 0xc6, 0xda, 0x14, 0xc5, 0xcd, 0x50, 0xc5, 0xf1,
+ 0xb7, 0xc8, 0x3a, 0x22, 0xc8, 0xb7, 0xfa, 0x14,
+ 0xc5, 0x3a, 0x21, 0xc8, 0xb7, 0xc2, 0x14, 0xc5,
+ 0x2a, 0x27, 0xc8, 0xc3, 0x61, 0xc4, 0xcd, 0x66,
+ 0xc4, 0xcd, 0x3a, 0xc3, 0xe5, 0xcd, 0x3a, 0xc3,
+ 0xe3, 0xe5, 0xcd, 0x10, 0xc3, 0x22, 0x25, 0xc8,
+ 0xe1, 0xd1, 0xe5, 0x7b, 0x95, 0x6f, 0x7a, 0x9c,
+ 0x67, 0x23, 0x22, 0x23, 0xc8, 0xe5, 0xcd, 0x48,
+ 0xc5, 0x21, 0x1c, 0xc8, 0xcd, 0xaf, 0xc7, 0xd1,
+ 0xe1, 0xc3, 0x90, 0xc7, 0xcd, 0xf9, 0xc2, 0x16,
+ 0x06, 0x21, 0x25, 0xc5, 0xcd, 0x6a, 0xc5, 0xcd,
+ 0x50, 0xc5, 0xc3, 0xc0, 0xc1, 0x45, 0x52, 0x52,
+ 0x4f, 0x52, 0x20, 0xcd, 0x66, 0xc4, 0xcd, 0xf9,
+ 0xc2, 0xcd, 0x48, 0xc5, 0x06, 0x01, 0xcd, 0xef,
+ 0xc7, 0xcd, 0x23, 0xc7, 0xda, 0xc0, 0xc1, 0xc2,
+ 0x39, 0xc5, 0xcd, 0x50, 0xc5, 0xc3, 0x39, 0xc5,
+ 0x21, 0x54, 0xc8, 0x3a, 0x0d, 0xc8, 0xb6, 0xc9,
+ 0x16, 0x08, 0x21, 0x1b, 0xc8, 0xcd, 0x6a, 0xc5,
+ 0xcd, 0x06, 0xc4, 0x2a, 0x25, 0xc8, 0xcd, 0xe8,
+ 0xc3, 0x2a, 0x23, 0xc8, 0xcd, 0xe8, 0xc3, 0xc3,
+ 0xf9, 0xc2, 0x7e, 0xb7, 0xc2, 0x71, 0xc5, 0x3e,
+ 0x20, 0xcd, 0x1f, 0xc4, 0x23, 0x15, 0xc2, 0x6a,
+ 0xc5, 0xc9, 0xcd, 0x1b, 0xc3, 0xca, 0x80, 0xc4,
+ 0xd5, 0xcd, 0x3a, 0xc3, 0xe3, 0x11, 0xa2, 0xc2,
+ 0xcd, 0x31, 0xc2, 0xc3, 0x22, 0xc2, 0xb7, 0xca,
+ 0x94, 0xc5, 0x3e, 0x20, 0x32, 0x0d, 0xc8, 0xc9,
+ 0x78, 0x32, 0x0b, 0xc8, 0xc9, 0x32, 0x06, 0xc8,
+ 0xc9, 0x32, 0x07, 0xc8, 0xc9, 0x22, 0x00, 0xc8,
+ 0xc9, 0x22, 0x02, 0xc8, 0xc9, 0x32, 0x22, 0xc8,
+ 0xc9, 0x22, 0x27, 0xc8, 0xc9, 0x32, 0x10, 0xc8,
+ 0xc9, 0x32, 0x11, 0xc8, 0xc9, 0xcd, 0x66, 0xc4,
+ 0x21, 0xc9, 0xc1, 0xcd, 0x10, 0xc3, 0xe5, 0x21,
+ 0x1c, 0xc8, 0xcd, 0x2e, 0xc2, 0xca, 0xd3, 0xc5,
+ 0x1b, 0x36, 0x00, 0x7e, 0x12, 0x13, 0x23, 0x7e,
+ 0x12, 0x13, 0xe1, 0xeb, 0x73, 0x23, 0x72, 0xc9,
+ 0xe5, 0xcd, 0x33, 0xc6, 0xc2, 0xfa, 0xc5, 0x36,
+ 0x01, 0x23, 0x77, 0x23, 0x77, 0x11, 0x63, 0xc8,
+ 0x3a, 0x54, 0xc8, 0x82, 0x57, 0xc1, 0xb7, 0xc3,
+ 0xb6, 0xc6, 0xe1, 0xd1, 0xaf, 0x37, 0xc9, 0x3d,
+ 0x37, 0xd1, 0xc9, 0xcd, 0x33, 0xc6, 0xc8, 0xb7,
+ 0x3c, 0x36, 0x00, 0xc8, 0x23, 0x23, 0x7e, 0x7e,
+ 0xcd, 0xbf, 0xc6, 0xc5, 0x21, 0x07, 0x00, 0x09,
+ 0xb7, 0xca, 0x2b, 0xc6, 0xe5, 0x77, 0x23, 0x36,
+ 0x00, 0x23, 0x73, 0x23, 0x72, 0x60, 0x69, 0xcd,
+ 0x7c, 0xc7, 0xe1, 0xaf, 0x77, 0x23, 0x77, 0xe1,
+ 0xc3, 0x7c, 0xc7, 0x21, 0x55, 0xc8, 0x1f, 0xe6,
+ 0x01, 0x32, 0x54, 0xc8, 0xca, 0x42, 0xc6, 0x21,
+ 0x5c, 0xc8, 0x7e, 0xb7, 0x37, 0xc9, 0xcd, 0x33,
+ 0xc6, 0xc8, 0x3c, 0xfa, 0xfc, 0xc5, 0x36, 0xff,
+ 0x23, 0x7e, 0xe5, 0x23, 0xcd, 0xbf, 0xc6, 0xe1,
+ 0xb7, 0xc2, 0x75, 0xc6, 0xd5, 0xe5, 0x23, 0xcd,
+ 0xa6, 0xc6, 0xcd, 0xc8, 0xc6, 0xda, 0xfa, 0xc5,
+ 0xe1, 0x7b, 0xb2, 0xca, 0xff, 0xc5, 0x73, 0x23,
+ 0x36, 0x00, 0x2b, 0x7b, 0xd1, 0x3d, 0x77, 0x23,
+ 0x7e, 0x34, 0x83, 0x5f, 0xd2, 0x80, 0xc6, 0x14,
+ 0x1a, 0xb7, 0xc9, 0xcd, 0x33, 0xc6, 0xc8, 0x3c,
+ 0xc8, 0x36, 0xfe, 0x23, 0x23, 0x78, 0xf5, 0xe5,
+ 0xcd, 0xbf, 0xc6, 0xe1, 0x7e, 0x83, 0x5f, 0xd2,
+ 0x9b, 0xc6, 0x14, 0xf1, 0x12, 0xb7, 0x34, 0xc0,
+ 0xcd, 0xa6, 0xc6, 0xc3, 0x7c, 0xc7, 0xcd, 0xbf,
+ 0xc6, 0xc5, 0x21, 0x06, 0x00, 0x09, 0x01, 0x00,
+ 0x01, 0xcd, 0xb6, 0xc6, 0xe1, 0xc9, 0x23, 0x71,
+ 0x23, 0x70, 0x23, 0x73, 0x23, 0x72, 0xc9, 0x23,
+ 0x4e, 0x23, 0x46, 0x23, 0x5e, 0x23, 0x56, 0xc9,
+ 0xcd, 0xde, 0xc7, 0xd5, 0x06, 0x03, 0xcd, 0xef,
+ 0xc7, 0xdb, 0xfb, 0xe5, 0xcd, 0x23, 0xc7, 0xe1,
+ 0xda, 0x06, 0xc7, 0xc2, 0xd3, 0xc6, 0xe5, 0x11,
+ 0x1c, 0xc8, 0xcd, 0xd2, 0xc7, 0xe1, 0xc2, 0xd3,
+ 0xc6, 0xd1, 0x7a, 0xb3, 0x2a, 0x23, 0xc8, 0xeb,
+ 0xc2, 0xf6, 0xc6, 0x2a, 0x25, 0xc8, 0xd5, 0xcd,
+ 0x15, 0xc7, 0xca, 0x10, 0xc7, 0xcd, 0x44, 0xc7,
+ 0xda, 0x06, 0xc7, 0xca, 0xf7, 0xc6, 0xaf, 0x37,
+ 0xc3, 0x11, 0xc7, 0x06, 0x01, 0xcd, 0xf1, 0xc7,
+ 0xaf, 0xd3, 0xfa, 0xd1, 0xc9, 0xaf, 0x47, 0xb2,
+ 0xc2, 0x20, 0xc7, 0xb3, 0xc8, 0x43, 0x5a, 0xc9,
+ 0x15, 0xb7, 0xc9, 0x06, 0x0a, 0xcd, 0x5d, 0xc7,
+ 0xd8, 0xdb, 0xfb, 0xb7, 0xc2, 0x23, 0xc7, 0x05,
+ 0xc2, 0x25, 0xc7, 0xcd, 0x6f, 0xc7, 0xd8, 0xfe,
+ 0x01, 0xda, 0x33, 0xc7, 0xc2, 0x23, 0xc7, 0x21,
+ 0x1c, 0xc8, 0x06, 0x10, 0x0e, 0x00, 0xcd, 0x6f,
+ 0xc7, 0xd8, 0x77, 0x23, 0xcd, 0xa8, 0xc7, 0x05,
+ 0xc2, 0x46, 0xc7, 0xcd, 0x6f, 0xc7, 0xa9, 0xc8,
+ 0x3a, 0x11, 0xc8, 0x3c, 0xc9, 0xdb, 0xfa, 0xe6,
+ 0x40, 0xc0, 0xcd, 0x1f, 0xc0, 0xca, 0x5d, 0xc7,
+ 0xe6, 0x7f, 0xc2, 0x5d, 0xc7, 0x37, 0xc9, 0xcd,
+ 0x5d, 0xc7, 0xd8, 0xdb, 0xfa, 0xe6, 0x18, 0xdb,
+ 0xfb, 0xc8, 0x37, 0xc9, 0xcd, 0xde, 0xc7, 0xe5,
+ 0xcd, 0xaf, 0xc7, 0xe1, 0x11, 0x07, 0x00, 0x19,
+ 0x5e, 0x23, 0x56, 0x23, 0x7e, 0x23, 0x66, 0x6f,
+ 0xe5, 0xcd, 0x15, 0xc7, 0xca, 0x0b, 0xc7, 0xcd,
+ 0xc3, 0xc7, 0xc3, 0x91, 0xc7, 0xf5, 0xdb, 0xfa,
+ 0xe6, 0x80, 0xca, 0x9e, 0xc7, 0xf1, 0xd3, 0xfb,
+ 0x91, 0x4f, 0xa9, 0x2f, 0x91, 0x4f, 0xc9, 0xcd,
+ 0xed, 0xc7, 0x16, 0x32, 0xaf, 0xcd, 0x9d, 0xc7,
+ 0x15, 0xc2, 0xb4, 0xc7, 0x3e, 0x01, 0xcd, 0x9d,
+ 0xc7, 0x06, 0x10, 0x0e, 0x00, 0x7e, 0xcd, 0x9d,
+ 0xc7, 0x05, 0x23, 0xc2, 0xc5, 0xc7, 0x79, 0xc3,
+ 0x9d, 0xc7, 0x06, 0x05, 0x1a, 0xbe, 0xc0, 0x05,
+ 0xc8, 0x23, 0x13, 0xc3, 0xd4, 0xc7, 0x3a, 0x54,
+ 0xc8, 0xb7, 0x3a, 0x0d, 0xc8, 0xc2, 0xea, 0xc7,
+ 0xc6, 0x40, 0xc6, 0x40, 0xc9, 0x06, 0x04, 0xd3,
+ 0xfa, 0x11, 0x00, 0x00, 0x1b, 0x7a, 0xb3, 0xc2,
+ 0xf4, 0xc7, 0x05, 0xc2, 0xf1, 0xc7, 0xc9, 0xfa,
+};
+
+/* SOLOS 1.3C ROM for CP/M */
+static uint8 sol20_rom_13c[SOL20_ROM_SIZE] = {
+ 0x00, 0xc3, 0xaf, 0xc1, 0xc3, 0xc9, 0xc1, 0xc3,
+ 0xe0, 0xc5, 0xc3, 0x03, 0xc6, 0xc3, 0x46, 0xc6,
+ 0xc3, 0x83, 0xc6, 0xc3, 0xcb, 0xc6, 0xc3, 0x7f,
+ 0xc7, 0x3a, 0x07, 0xc8, 0xc3, 0x3b, 0xc0, 0x3a,
+ 0x06, 0xc8, 0xe5, 0x21, 0x9a, 0xc2, 0xe6, 0x03,
+ 0x07, 0x85, 0x6f, 0xc3, 0x27, 0xc2, 0xdb, 0xfa,
+ 0x2f, 0xe6, 0x01, 0xc8, 0xdb, 0xfc, 0xc9, 0x00,
+ 0xc3, 0x01, 0xc0, 0xe5, 0x21, 0x92, 0xc2, 0xc3,
+ 0x26, 0xc0, 0xdb, 0xf8, 0xe6, 0x40, 0xc8, 0xdb,
+ 0xf9, 0xc9, 0xdb, 0xf8, 0x17, 0xd2, 0x4a, 0xc0,
+ 0x78, 0xd3, 0xf9, 0xc9, 0xe5, 0xd5, 0xc5, 0x3a,
+ 0x0c, 0xc8, 0xb7, 0xc2, 0x5f, 0xc1, 0x78, 0xe6,
+ 0x7f, 0x47, 0xca, 0x7c, 0xc0, 0x21, 0x73, 0xc2,
+ 0xcd, 0x82, 0xc0, 0xcd, 0x1c, 0xc1, 0x7e, 0xf6,
+ 0x80, 0x77, 0x2a, 0x0a, 0xc8, 0x2c, 0xaf, 0x2b,
+ 0xbc, 0xc2, 0x77, 0xc0, 0xc1, 0xd1, 0xe1, 0xc9,
+ 0x23, 0x23, 0x7e, 0xb7, 0xca, 0x94, 0xc0, 0xb8,
+ 0x23, 0xc2, 0x80, 0xc0, 0xe5, 0xcd, 0x36, 0xc1,
+ 0xe3, 0xc3, 0x27, 0xc2, 0x78, 0xfe, 0x7f, 0xc8,
+ 0xcd, 0x1c, 0xc1, 0x70, 0x3a, 0x08, 0xc8, 0xfe,
+ 0x3f, 0xda, 0xc1, 0xc0, 0x3a, 0x09, 0xc8, 0xfe,
+ 0x0f, 0xc2, 0xc1, 0xc0, 0xaf, 0x32, 0x08, 0xc8,
+ 0x4f, 0xcd, 0x23, 0xc1, 0xaf, 0xcd, 0xfa, 0xc0,
+ 0x3a, 0x0a, 0xc8, 0x3c, 0xe6, 0x0f, 0xc3, 0xee,
+ 0xc0, 0x3a, 0x08, 0xc8, 0x3c, 0xe6, 0x3f, 0x32,
+ 0x08, 0xc8, 0xc0, 0x3a, 0x09, 0xc8, 0x3c, 0xe6,
+ 0x0f, 0x32, 0x09, 0xc8, 0xc9, 0x21, 0x00, 0xcc,
+ 0x36, 0xa0, 0x23, 0x36, 0x20, 0x23, 0x7c, 0xfe,
+ 0xd0, 0xda, 0xdb, 0xc0, 0x37, 0x3e, 0x00, 0x32,
+ 0x09, 0xc8, 0x32, 0x08, 0xc8, 0xd0, 0xd3, 0xfe,
+ 0x32, 0x0a, 0xc8, 0xc9, 0xcd, 0x1c, 0xc1, 0x3a,
+ 0x08, 0xc8, 0xfe, 0x40, 0xd0, 0x36, 0x20, 0x23,
+ 0x3c, 0xc3, 0xfa, 0xc0, 0x3a, 0x09, 0xc8, 0x3d,
+ 0xc3, 0xcf, 0xc0, 0x3a, 0x08, 0xc8, 0x3d, 0xe6,
+ 0x3f, 0x32, 0x08, 0xc8, 0xc9, 0x3a, 0x08, 0xc8,
+ 0x3c, 0xc3, 0x0f, 0xc1, 0x3a, 0x08, 0xc8, 0x4f,
+ 0x3a, 0x09, 0xc8, 0x6f, 0x3a, 0x0a, 0xc8, 0x85,
+ 0x0f, 0x0f, 0x6f, 0xe6, 0x03, 0xc6, 0xcc, 0x67,
+ 0x7d, 0xe6, 0xc0, 0x81, 0x6f, 0xc9, 0xcd, 0x1c,
+ 0xc1, 0x7e, 0xe6, 0x7f, 0x77, 0xc9, 0xcd, 0x0b,
+ 0xc1, 0xcd, 0x1c, 0xc1, 0x36, 0x20, 0xc9, 0xcd,
+ 0xf4, 0xc0, 0xc3, 0x0f, 0xc1, 0x3a, 0x09, 0xc8,
+ 0x3c, 0xe6, 0x0f, 0xc2, 0xd1, 0xc0, 0xc3, 0xb0,
+ 0xc0, 0x3e, 0xff, 0x32, 0x0c, 0xc8, 0xc9, 0xcd,
+ 0x36, 0xc1, 0xcd, 0x68, 0xc1, 0xc3, 0x6b, 0xc0,
+ 0x3a, 0x0c, 0xc8, 0xfe, 0xff, 0xca, 0x90, 0xc1,
+ 0x21, 0x0c, 0xc8, 0x36, 0x00, 0xfe, 0x02, 0xda,
+ 0x88, 0xc1, 0xca, 0x8c, 0xc1, 0xfe, 0x08, 0xca,
+ 0x98, 0xc5, 0xfe, 0x09, 0xda, 0x98, 0xc0, 0xc0,
+ 0x78, 0xc3, 0x0f, 0xc1, 0x78, 0xc3, 0xcf, 0xc0,
+ 0x78, 0xfe, 0x03, 0xca, 0xa6, 0xc1, 0xfe, 0x04,
+ 0xc2, 0xa2, 0xc1, 0x44, 0x4d, 0xe1, 0xd1, 0xc5,
+ 0xe5, 0xaf, 0x32, 0x0c, 0xc8, 0xc9, 0x21, 0x08,
+ 0xc8, 0x46, 0x23, 0x4e, 0xc3, 0x9d, 0xc1, 0xaf,
+ 0x4f, 0x21, 0x00, 0xc8, 0x77, 0x23, 0x0c, 0xc2,
+ 0xb4, 0xc1, 0x31, 0xff, 0xcb, 0xcd, 0xd5, 0xc0,
+ 0xaf, 0xd3, 0xfa, 0x32, 0x07, 0xc8, 0x32, 0x06,
+ 0xc8, 0x31, 0xff, 0xcb, 0x3a, 0x07, 0xc8, 0xf5,
+ 0xaf, 0x32, 0x07, 0xc8, 0xcd, 0xf1, 0xc2, 0xcd,
+ 0xe4, 0xc1, 0xf1, 0x32, 0x07, 0xc8, 0xcd, 0x05,
+ 0xc2, 0xc3, 0xc9, 0xc1, 0xcd, 0x1f, 0xc0, 0xca,
+ 0xe4, 0xc1, 0xfe, 0x8c, 0xca, 0x00, 0xe8, 0xe6,
+ 0x7f, 0xca, 0xc0, 0xc1, 0x47, 0xfe, 0x0d, 0xc8,
+ 0xfe, 0x7f, 0xc2, 0xff, 0xc1, 0x06, 0x5f, 0xcd,
+ 0x19, 0xc0, 0xc3, 0xe4, 0xc1, 0xcd, 0x36, 0xc1,
+ 0x0e, 0x01, 0xcd, 0x20, 0xc1, 0xeb, 0x21, 0x00,
+ 0xc0, 0xe5, 0xcd, 0x2e, 0xc3, 0xca, 0x80, 0xc4,
+ 0xeb, 0x11, 0x4a, 0xc2, 0xcd, 0x31, 0xc2, 0xcc,
+ 0x2e, 0xc2, 0xca, 0x81, 0xc4, 0x13, 0xeb, 0x7e,
+ 0x23, 0x66, 0x6f, 0xe3, 0x7d, 0xc9, 0x11, 0x3c,
+ 0xc8, 0x1a, 0xb7, 0xc8, 0xe5, 0xbe, 0x13, 0xc2,
+ 0x43, 0xc2, 0x23, 0x1a, 0xbe, 0xc2, 0x43, 0xc2,
+ 0xe1, 0xb7, 0xc9, 0x13, 0x13, 0x13, 0xe1, 0xc3,
+ 0x31, 0xc2, 0x54, 0x45, 0x67, 0xc3, 0x44, 0x55,
+ 0xbf, 0xc3, 0x45, 0x4e, 0x23, 0xc4, 0x45, 0x58,
+ 0x5e, 0xc4, 0x47, 0x45, 0xa7, 0xc4, 0x53, 0x41,
+ 0xe6, 0xc4, 0x58, 0x45, 0xa6, 0xc4, 0x43, 0x41,
+ 0x2b, 0xc5, 0x53, 0x45, 0x7a, 0xc5, 0x43, 0x55,
+ 0xbd, 0xc5, 0x00, 0x0b, 0xd5, 0xc0, 0x17, 0x04,
+ 0xc1, 0x1a, 0xcb, 0xc0, 0x01, 0x0b, 0xc1, 0x13,
+ 0x15, 0xc1, 0x0e, 0xe5, 0xc0, 0x0d, 0x47, 0xc1,
+ 0x0a, 0x4d, 0xc1, 0x5f, 0x3e, 0xc1, 0x1b, 0x59,
+ 0xc1, 0x00, 0x54, 0xc0, 0x4a, 0xc0, 0xe6, 0xc2,
+ 0xd2, 0xc2, 0x2e, 0xc0, 0x42, 0xc0, 0xdd, 0xc2,
+ 0xcb, 0xc2, 0x54, 0x41, 0x8e, 0xc5, 0x53, 0x3d,
+ 0x99, 0xc5, 0x49, 0x3d, 0x9d, 0xc5, 0x4f, 0x3d,
+ 0xa1, 0xc5, 0x4e, 0x3d, 0xb5, 0xc5, 0x43, 0x49,
+ 0xa5, 0xc5, 0x43, 0x4f, 0xa9, 0xc5, 0x58, 0x45,
+ 0xb1, 0xc5, 0x54, 0x59, 0xad, 0xc5, 0x43, 0x52,
+ 0xb9, 0xc5, 0x00, 0xe5, 0x2a, 0x00, 0xc8, 0xc3,
+ 0xd6, 0xc2, 0xe5, 0x2a, 0x02, 0xc8, 0x7d, 0xb4,
+ 0xca, 0xc0, 0xc1, 0xe3, 0xc9, 0xdb, 0xfa, 0x2f,
+ 0xe6, 0x02, 0xc8, 0xdb, 0xfd, 0xc9, 0xdb, 0xfa,
+ 0xe6, 0x04, 0xc2, 0xe6, 0xc2, 0x78, 0xd3, 0xfd,
+ 0xc9, 0xcd, 0xf9, 0xc2, 0x06, 0x3e, 0xc3, 0x19,
+ 0xc0, 0x06, 0x0a, 0xcd, 0x19, 0xc0, 0x06, 0x0d,
+ 0xcd, 0x19, 0xc0, 0x3a, 0x10, 0xc8, 0x4f, 0x0d,
+ 0xf8, 0xaf, 0xcd, 0x1f, 0xc4, 0xc3, 0x07, 0xc3,
+ 0xcd, 0x1b, 0xc3, 0x3e, 0x01, 0xc8, 0xcd, 0x40,
+ 0xc3, 0x7d, 0xc9, 0x0e, 0x0c, 0x1a, 0xfe, 0x20,
+ 0xca, 0x2e, 0xc3, 0x13, 0xfe, 0x3d, 0xca, 0x2e,
+ 0xc3, 0x0d, 0xc2, 0x1d, 0xc3, 0xc9, 0x0e, 0x0a,
+ 0x1a, 0xfe, 0x20, 0xc0, 0x13, 0x0d, 0xc8, 0xc3,
+ 0x30, 0xc3, 0xcd, 0x1b, 0xc3, 0xca, 0x80, 0xc4,
+ 0x21, 0x00, 0x00, 0x1a, 0xfe, 0x20, 0xc8, 0xfe,
+ 0x2f, 0xc8, 0xfe, 0x3a, 0xc8, 0x29, 0x29, 0x29,
+ 0x29, 0xcd, 0x5d, 0xc3, 0xd2, 0x80, 0xc4, 0x85,
+ 0x6f, 0x13, 0xc3, 0x43, 0xc3, 0xd6, 0x30, 0xfe,
+ 0x0a, 0xd8, 0xd6, 0x07, 0xfe, 0x10, 0xc9, 0xcd,
+ 0x10, 0xc3, 0x32, 0x06, 0xc8, 0xcd, 0x10, 0xc3,
+ 0x32, 0x07, 0xc8, 0xcd, 0x2e, 0xc0, 0xca, 0x8b,
+ 0xc3, 0x47, 0xfe, 0x80, 0xca, 0xc0, 0xc1, 0xda,
+ 0x88, 0xc3, 0xcd, 0x54, 0xc0, 0xc3, 0x8b, 0xc3,
+ 0xcd, 0x19, 0xc0, 0xcd, 0x1f, 0xc0, 0xca, 0x73,
+ 0xc3, 0xe6, 0x7f, 0xca, 0x73, 0xc3, 0x47, 0xfe,
+ 0x1b, 0xd2, 0xb9, 0xc3, 0xfe, 0x0d, 0xca, 0xb9,
+ 0xc3, 0xfe, 0x0a, 0xca, 0xb9, 0xc3, 0x3a, 0x0c,
+ 0xc8, 0xb7, 0xc2, 0xb9, 0xc3, 0xc5, 0x06, 0x1b,
+ 0xcd, 0x54, 0xc0, 0x06, 0x07, 0xcd, 0x54, 0xc0,
+ 0xc1, 0xcd, 0x54, 0xc0, 0xc3, 0x73, 0xc3, 0xcd,
+ 0x3a, 0xc3, 0xe5, 0xcd, 0x10, 0xc3, 0xd1, 0xeb,
+ 0xcd, 0xf9, 0xc2, 0xcd, 0xe8, 0xc3, 0xcd, 0x06,
+ 0xc4, 0x0e, 0x10, 0x7e, 0xc5, 0xcd, 0xed, 0xc3,
+ 0x7d, 0x93, 0x7c, 0x9a, 0xd2, 0xc9, 0xc1, 0xc1,
+ 0x23, 0x0d, 0xc2, 0xd3, 0xc3, 0xc3, 0xc8, 0xc3,
+ 0x7c, 0xcd, 0x0b, 0xc4, 0x7d, 0xcd, 0x0b, 0xc4,
+ 0xcd, 0x1f, 0xc0, 0xca, 0x06, 0xc4, 0xe6, 0x7f,
+ 0xca, 0xc9, 0xc1, 0xfe, 0x20, 0xc2, 0x06, 0xc4,
+ 0xcd, 0x1f, 0xc0, 0xca, 0x00, 0xc4, 0x06, 0x20,
+ 0xc3, 0x19, 0xc0, 0x4f, 0x0f, 0x0f, 0x0f, 0x0f,
+ 0xcd, 0x14, 0xc4, 0x79, 0xe6, 0x0f, 0xc6, 0x30,
+ 0xfe, 0x3a, 0xda, 0x1f, 0xc4, 0xc6, 0x07, 0x47,
+ 0xc3, 0x19, 0xc0, 0xcd, 0x3a, 0xc3, 0xe5, 0xaf,
+ 0x32, 0x07, 0xc8, 0xcd, 0xf9, 0xc2, 0x06, 0x3a,
+ 0xcd, 0xff, 0xc1, 0xcd, 0x36, 0xc1, 0x0e, 0x01,
+ 0xcd, 0x20, 0xc1, 0xeb, 0x0e, 0x03, 0xcd, 0x30,
+ 0xc3, 0xca, 0x2b, 0xc4, 0xfe, 0x2f, 0xca, 0xc0,
+ 0xc1, 0xcd, 0x40, 0xc3, 0xfe, 0x3a, 0xca, 0x59,
+ 0xc4, 0x7d, 0xe1, 0x77, 0x23, 0xe5, 0xc3, 0x3c,
+ 0xc4, 0xe3, 0x13, 0xc3, 0x3c, 0xc4, 0xcd, 0x3a,
+ 0xc3, 0xe5, 0x21, 0x00, 0xc0, 0xc9, 0x21, 0x1c,
+ 0xc8, 0xcd, 0x1b, 0xc3, 0x06, 0x06, 0x1a, 0xfe,
+ 0x20, 0xca, 0x86, 0xc4, 0xfe, 0x2f, 0xca, 0x86,
+ 0xc4, 0x77, 0x13, 0x23, 0x05, 0xc2, 0x6e, 0xc4,
+ 0xeb, 0x36, 0x3f, 0xc3, 0xc0, 0xc1, 0x36, 0x00,
+ 0x23, 0x05, 0xc2, 0x86, 0xc4, 0xfe, 0x2f, 0x3e,
+ 0x01, 0xc2, 0x9a, 0xc4, 0x13, 0xcd, 0x2e, 0xc3,
+ 0xd6, 0x30, 0xe6, 0x01, 0x3e, 0x80, 0xc2, 0xa2,
+ 0xc4, 0x1f, 0x32, 0x54, 0xc8, 0xc9, 0x3e, 0xaf,
+ 0xf5, 0x21, 0x2c, 0xc8, 0xcd, 0x69, 0xc4, 0x21,
+ 0x00, 0x00, 0xcd, 0x10, 0xc3, 0xeb, 0x21, 0x2c,
+ 0xc8, 0x7e, 0xb7, 0xc2, 0xc1, 0xc4, 0x21, 0x1c,
+ 0xc8, 0xe5, 0xcd, 0x48, 0xc5, 0xe1, 0xcd, 0xcb,
+ 0xc6, 0xda, 0x14, 0xc5, 0xcd, 0x50, 0xc5, 0xf1,
+ 0xb7, 0xc8, 0x3a, 0x22, 0xc8, 0xb7, 0xfa, 0x14,
+ 0xc5, 0x3a, 0x21, 0xc8, 0xb7, 0xc2, 0x14, 0xc5,
+ 0x2a, 0x27, 0xc8, 0xc3, 0x61, 0xc4, 0xcd, 0x66,
+ 0xc4, 0xcd, 0x3a, 0xc3, 0xe5, 0xcd, 0x3a, 0xc3,
+ 0xe3, 0xe5, 0xcd, 0x10, 0xc3, 0x22, 0x25, 0xc8,
+ 0xe1, 0xd1, 0xe5, 0x7b, 0x95, 0x6f, 0x7a, 0x9c,
+ 0x67, 0x23, 0x22, 0x23, 0xc8, 0xe5, 0xcd, 0x48,
+ 0xc5, 0x21, 0x1c, 0xc8, 0xcd, 0xaf, 0xc7, 0xd1,
+ 0xe1, 0xc3, 0x90, 0xc7, 0xcd, 0xf9, 0xc2, 0x16,
+ 0x06, 0x21, 0x25, 0xc5, 0xcd, 0x6a, 0xc5, 0xcd,
+ 0x50, 0xc5, 0xc3, 0xc0, 0xc1, 0x45, 0x52, 0x52,
+ 0x4f, 0x52, 0x20, 0xcd, 0x66, 0xc4, 0xcd, 0xf9,
+ 0xc2, 0xcd, 0x48, 0xc5, 0x06, 0x01, 0xcd, 0xef,
+ 0xc7, 0xcd, 0x23, 0xc7, 0xda, 0xc0, 0xc1, 0xc2,
+ 0x39, 0xc5, 0xcd, 0x50, 0xc5, 0xc3, 0x39, 0xc5,
+ 0x21, 0x54, 0xc8, 0x3a, 0x0d, 0xc8, 0xb6, 0xc9,
+ 0x16, 0x08, 0x21, 0x1b, 0xc8, 0xcd, 0x6a, 0xc5,
+ 0xcd, 0x06, 0xc4, 0x2a, 0x25, 0xc8, 0xcd, 0xe8,
+ 0xc3, 0x2a, 0x23, 0xc8, 0xcd, 0xe8, 0xc3, 0xc3,
+ 0xf9, 0xc2, 0x7e, 0xb7, 0xc2, 0x71, 0xc5, 0x3e,
+ 0x20, 0xcd, 0x1f, 0xc4, 0x23, 0x15, 0xc2, 0x6a,
+ 0xc5, 0xc9, 0xcd, 0x1b, 0xc3, 0xca, 0x80, 0xc4,
+ 0xd5, 0xcd, 0x3a, 0xc3, 0xe3, 0x11, 0xa2, 0xc2,
+ 0xcd, 0x31, 0xc2, 0xc3, 0x22, 0xc2, 0xb7, 0xca,
+ 0x94, 0xc5, 0x3e, 0x20, 0x32, 0x0d, 0xc8, 0xc9,
+ 0x78, 0x32, 0x0b, 0xc8, 0xc9, 0x32, 0x06, 0xc8,
+ 0xc9, 0x32, 0x07, 0xc8, 0xc9, 0x22, 0x00, 0xc8,
+ 0xc9, 0x22, 0x02, 0xc8, 0xc9, 0x32, 0x22, 0xc8,
+ 0xc9, 0x22, 0x27, 0xc8, 0xc9, 0x32, 0x10, 0xc8,
+ 0xc9, 0x32, 0x11, 0xc8, 0xc9, 0xcd, 0x66, 0xc4,
+ 0x21, 0xc9, 0xc1, 0xcd, 0x10, 0xc3, 0xe5, 0x21,
+ 0x1c, 0xc8, 0xcd, 0x2e, 0xc2, 0xca, 0xd3, 0xc5,
+ 0x1b, 0x36, 0x00, 0x7e, 0x12, 0x13, 0x23, 0x7e,
+ 0x12, 0x13, 0xe1, 0xeb, 0x73, 0x23, 0x72, 0xc9,
+ 0xe5, 0xcd, 0x33, 0xc6, 0xc2, 0xfa, 0xc5, 0x36,
+ 0x01, 0x23, 0x77, 0x23, 0x77, 0x11, 0x63, 0xc8,
+ 0x3a, 0x54, 0xc8, 0x82, 0x57, 0xc1, 0xb7, 0xc3,
+ 0xb6, 0xc6, 0xe1, 0xd1, 0xaf, 0x37, 0xc9, 0x3d,
+ 0x37, 0xd1, 0xc9, 0xcd, 0x33, 0xc6, 0xc8, 0xb7,
+ 0x3c, 0x36, 0x00, 0xc8, 0x23, 0x23, 0x7e, 0x7e,
+ 0xcd, 0xbf, 0xc6, 0xc5, 0x21, 0x07, 0x00, 0x09,
+ 0xb7, 0xca, 0x2b, 0xc6, 0xe5, 0x77, 0x23, 0x36,
+ 0x00, 0x23, 0x73, 0x23, 0x72, 0x60, 0x69, 0xcd,
+ 0x7c, 0xc7, 0xe1, 0xaf, 0x77, 0x23, 0x77, 0xe1,
+ 0xc3, 0x7c, 0xc7, 0x21, 0x55, 0xc8, 0x1f, 0xe6,
+ 0x01, 0x32, 0x54, 0xc8, 0xca, 0x42, 0xc6, 0x21,
+ 0x5c, 0xc8, 0x7e, 0xb7, 0x37, 0xc9, 0xcd, 0x33,
+ 0xc6, 0xc8, 0x3c, 0xfa, 0xfc, 0xc5, 0x36, 0xff,
+ 0x23, 0x7e, 0xe5, 0x23, 0xcd, 0xbf, 0xc6, 0xe1,
+ 0xb7, 0xc2, 0x75, 0xc6, 0xd5, 0xe5, 0x23, 0xcd,
+ 0xa6, 0xc6, 0xcd, 0xc8, 0xc6, 0xda, 0xfa, 0xc5,
+ 0xe1, 0x7b, 0xb2, 0xca, 0xff, 0xc5, 0x73, 0x23,
+ 0x36, 0x00, 0x2b, 0x7b, 0xd1, 0x3d, 0x77, 0x23,
+ 0x7e, 0x34, 0x83, 0x5f, 0xd2, 0x80, 0xc6, 0x14,
+ 0x1a, 0xb7, 0xc9, 0xcd, 0x33, 0xc6, 0xc8, 0x3c,
+ 0xc8, 0x36, 0xfe, 0x23, 0x23, 0x78, 0xf5, 0xe5,
+ 0xcd, 0xbf, 0xc6, 0xe1, 0x7e, 0x83, 0x5f, 0xd2,
+ 0x9b, 0xc6, 0x14, 0xf1, 0x12, 0xb7, 0x34, 0xc0,
+ 0xcd, 0xa6, 0xc6, 0xc3, 0x7c, 0xc7, 0xcd, 0xbf,
+ 0xc6, 0xc5, 0x21, 0x06, 0x00, 0x09, 0x01, 0x00,
+ 0x01, 0xcd, 0xb6, 0xc6, 0xe1, 0xc9, 0x23, 0x71,
+ 0x23, 0x70, 0x23, 0x73, 0x23, 0x72, 0xc9, 0x23,
+ 0x4e, 0x23, 0x46, 0x23, 0x5e, 0x23, 0x56, 0xc9,
+ 0xcd, 0xde, 0xc7, 0xd5, 0x06, 0x03, 0xcd, 0xef,
+ 0xc7, 0xdb, 0xfb, 0xe5, 0xcd, 0x23, 0xc7, 0xe1,
+ 0xda, 0x06, 0xc7, 0xc2, 0xd3, 0xc6, 0xe5, 0x11,
+ 0x1c, 0xc8, 0xcd, 0xd2, 0xc7, 0xe1, 0xc2, 0xd3,
+ 0xc6, 0xd1, 0x7a, 0xb3, 0x2a, 0x23, 0xc8, 0xeb,
+ 0xc2, 0xf6, 0xc6, 0x2a, 0x25, 0xc8, 0xd5, 0xcd,
+ 0x15, 0xc7, 0xca, 0x10, 0xc7, 0xcd, 0x44, 0xc7,
+ 0xda, 0x06, 0xc7, 0xca, 0xf7, 0xc6, 0xaf, 0x37,
+ 0xc3, 0x11, 0xc7, 0x06, 0x01, 0xcd, 0xf1, 0xc7,
+ 0xaf, 0xd3, 0xfa, 0xd1, 0xc9, 0xaf, 0x47, 0xb2,
+ 0xc2, 0x20, 0xc7, 0xb3, 0xc8, 0x43, 0x5a, 0xc9,
+ 0x15, 0xb7, 0xc9, 0x06, 0x0a, 0xcd, 0x5d, 0xc7,
+ 0xd8, 0xdb, 0xfb, 0xb7, 0xc2, 0x23, 0xc7, 0x05,
+ 0xc2, 0x25, 0xc7, 0xcd, 0x6f, 0xc7, 0xd8, 0xfe,
+ 0x01, 0xda, 0x33, 0xc7, 0xc2, 0x23, 0xc7, 0x21,
+ 0x1c, 0xc8, 0x06, 0x10, 0x0e, 0x00, 0xcd, 0x6f,
+ 0xc7, 0xd8, 0x77, 0x23, 0xcd, 0xa8, 0xc7, 0x05,
+ 0xc2, 0x46, 0xc7, 0xcd, 0x6f, 0xc7, 0xa9, 0xc8,
+ 0x3a, 0x11, 0xc8, 0x3c, 0xc9, 0xdb, 0xfa, 0xe6,
+ 0x40, 0xc0, 0xcd, 0x1f, 0xc0, 0xca, 0x5d, 0xc7,
+ 0xe6, 0x7f, 0xc2, 0x5d, 0xc7, 0x37, 0xc9, 0xcd,
+ 0x5d, 0xc7, 0xd8, 0xdb, 0xfa, 0xe6, 0x18, 0xdb,
+ 0xfb, 0xc8, 0x37, 0xc9, 0xcd, 0xde, 0xc7, 0xe5,
+ 0xcd, 0xaf, 0xc7, 0xe1, 0x11, 0x07, 0x00, 0x19,
+ 0x5e, 0x23, 0x56, 0x23, 0x7e, 0x23, 0x66, 0x6f,
+ 0xe5, 0xcd, 0x15, 0xc7, 0xca, 0x0b, 0xc7, 0xcd,
+ 0xc3, 0xc7, 0xc3, 0x91, 0xc7, 0xf5, 0xdb, 0xfa,
+ 0xe6, 0x80, 0xca, 0x9e, 0xc7, 0xf1, 0xd3, 0xfb,
+ 0x91, 0x4f, 0xa9, 0x2f, 0x91, 0x4f, 0xc9, 0xcd,
+ 0xed, 0xc7, 0x16, 0x32, 0xaf, 0xcd, 0x9d, 0xc7,
+ 0x15, 0xc2, 0xb4, 0xc7, 0x3e, 0x01, 0xcd, 0x9d,
+ 0xc7, 0x06, 0x10, 0x0e, 0x00, 0x7e, 0xcd, 0x9d,
+ 0xc7, 0x05, 0x23, 0xc2, 0xc5, 0xc7, 0x79, 0xc3,
+ 0x9d, 0xc7, 0x06, 0x05, 0x1a, 0xbe, 0xc0, 0x05,
+ 0xc8, 0x23, 0x13, 0xc3, 0xd4, 0xc7, 0x3a, 0x54,
+ 0xc8, 0xb7, 0x3a, 0x0d, 0xc8, 0xc2, 0xea, 0xc7,
+ 0xc6, 0x40, 0xc6, 0x40, 0xc9, 0x06, 0x04, 0xd3,
+ 0xfa, 0x11, 0x00, 0x00, 0x1b, 0x7a, 0xb3, 0xc2,
+ 0xf4, 0xc7, 0x05, 0xc2, 0xf1, 0xc7, 0xc9, 0x00,
+};
+
+/* SOLOS 4.1 ROM */
+static uint8 sol20_rom_41[SOL20_ROM_SIZE] = {
+ 0x00, 0xc3, 0xaf, 0xc1, 0xc3, 0xc9, 0xc1, 0xc3,
+ 0xe0, 0xc5, 0xc3, 0x03, 0xc6, 0xc3, 0x46, 0xc6,
+ 0xc3, 0x83, 0xc6, 0xc3, 0xcb, 0xc6, 0xc3, 0x7f,
+ 0xc7, 0x3a, 0x07, 0xc8, 0xc3, 0x3b, 0xc0, 0x3a,
+ 0x06, 0xc8, 0xe5, 0x21, 0x9a, 0xc2, 0xe6, 0x03,
+ 0x07, 0x85, 0x6f, 0xc3, 0x27, 0xc2, 0xdb, 0xfa,
+ 0x2f, 0xe6, 0x01, 0xc8, 0xdb, 0xfc, 0xc9, 0x00,
+ 0xc3, 0x01, 0xc0, 0xe5, 0x21, 0x92, 0xc2, 0xc3,
+ 0x26, 0xc0, 0xdb, 0xf8, 0xe6, 0x40, 0xc8, 0xdb,
+ 0xf9, 0xc9, 0xdb, 0xf8, 0x17, 0xd2, 0x4a, 0xc0,
+ 0x78, 0xd3, 0xf9, 0xc9, 0xe5, 0xd5, 0xc5, 0x3a,
+ 0x0c, 0xc8, 0xb7, 0xc2, 0x5f, 0xc1, 0x78, 0xe6,
+ 0x7f, 0x47, 0xca, 0x7c, 0xc0, 0x21, 0x73, 0xc2,
+ 0xcd, 0x82, 0xc0, 0xcd, 0x1c, 0xc1, 0x7e, 0xf6,
+ 0x80, 0x77, 0x2a, 0x0a, 0xc8, 0x2c, 0xaf, 0x2b,
+ 0xbc, 0xc2, 0x77, 0xc0, 0xc1, 0xd1, 0xe1, 0xc9,
+ 0x23, 0x23, 0x7e, 0xb7, 0xca, 0x94, 0xc0, 0xb8,
+ 0x23, 0xc2, 0x80, 0xc0, 0xe5, 0xcd, 0x36, 0xc1,
+ 0xe3, 0xc3, 0x27, 0xc2, 0x78, 0xfe, 0x7f, 0xc8,
+ 0xcd, 0x1c, 0xc1, 0x70, 0x3a, 0x08, 0xc8, 0xfe,
+ 0x3f, 0xda, 0xc1, 0xc0, 0x3a, 0x09, 0xc8, 0xfe,
+ 0x0f, 0xc2, 0xc1, 0xc0, 0xaf, 0x32, 0x08, 0xc8,
+ 0x4f, 0xcd, 0x23, 0xc1, 0xaf, 0xcd, 0xfa, 0xc0,
+ 0x3a, 0x0a, 0xc8, 0x3c, 0xe6, 0x0f, 0xc3, 0xee,
+ 0xc0, 0x3a, 0x08, 0xc8, 0x3c, 0xe6, 0x3f, 0x32,
+ 0x08, 0xc8, 0xc0, 0x3a, 0x09, 0xc8, 0x3c, 0xe6,
+ 0x0f, 0x32, 0x09, 0xc8, 0xc9, 0x21, 0x00, 0xcc,
+ 0x36, 0xa0, 0x23, 0x36, 0x20, 0x23, 0x7c, 0xfe,
+ 0xd0, 0xda, 0xdb, 0xc0, 0x37, 0x3e, 0x00, 0x32,
+ 0x09, 0xc8, 0x32, 0x08, 0xc8, 0xd0, 0xd3, 0xfe,
+ 0x32, 0x0a, 0xc8, 0xc9, 0xcd, 0x1c, 0xc1, 0x3a,
+ 0x08, 0xc8, 0xfe, 0x40, 0xd0, 0x36, 0x20, 0x23,
+ 0x3c, 0xc3, 0xfa, 0xc0, 0x3a, 0x09, 0xc8, 0x3d,
+ 0xc3, 0xcf, 0xc0, 0x3a, 0x08, 0xc8, 0x3d, 0xe6,
+ 0x3f, 0x32, 0x08, 0xc8, 0xc9, 0x3a, 0x08, 0xc8,
+ 0x3c, 0xc3, 0x0f, 0xc1, 0x3a, 0x08, 0xc8, 0x4f,
+ 0x3a, 0x09, 0xc8, 0x6f, 0x3a, 0x0a, 0xc8, 0x85,
+ 0x0f, 0x0f, 0x6f, 0xe6, 0x03, 0xc6, 0xcc, 0x67,
+ 0x7d, 0xe6, 0xc0, 0x81, 0x6f, 0xc9, 0xcd, 0x1c,
+ 0xc1, 0x7e, 0xe6, 0x7f, 0x77, 0xc9, 0xcd, 0x0b,
+ 0xc1, 0xcd, 0x1c, 0xc1, 0x36, 0x20, 0xc9, 0xcd,
+ 0xf4, 0xc0, 0xc3, 0x0f, 0xc1, 0x3a, 0x09, 0xc8,
+ 0x3c, 0xe6, 0x0f, 0xc2, 0xd1, 0xc0, 0xc3, 0xb0,
+ 0xc0, 0x3e, 0xff, 0x32, 0x0c, 0xc8, 0xc9, 0xcd,
+ 0x36, 0xc1, 0xcd, 0x68, 0xc1, 0xc3, 0x6b, 0xc0,
+ 0x3a, 0x0c, 0xc8, 0xfe, 0xff, 0xca, 0x90, 0xc1,
+ 0x21, 0x0c, 0xc8, 0x36, 0x00, 0xfe, 0x02, 0xda,
+ 0x88, 0xc1, 0xca, 0x8c, 0xc1, 0xfe, 0x08, 0xca,
+ 0x98, 0xc5, 0xfe, 0x09, 0xda, 0x98, 0xc0, 0xc0,
+ 0x78, 0xc3, 0x0f, 0xc1, 0x78, 0xc3, 0xcf, 0xc0,
+ 0x78, 0xfe, 0x03, 0xca, 0xa6, 0xc1, 0xfe, 0x04,
+ 0xc2, 0xa2, 0xc1, 0x44, 0x4d, 0xe1, 0xd1, 0xc5,
+ 0xe5, 0xaf, 0x32, 0x0c, 0xc8, 0xc9, 0x21, 0x08,
+ 0xc8, 0x46, 0x23, 0x4e, 0xc3, 0x9d, 0xc1, 0xaf,
+ 0x4f, 0x21, 0x00, 0xc8, 0x77, 0x23, 0x0c, 0xc2,
+ 0xb4, 0xc1, 0x31, 0xff, 0xcb, 0xcd, 0xd5, 0xc0,
+ 0xaf, 0xd3, 0xfa, 0x32, 0x07, 0xc8, 0x32, 0x06,
+ 0xc8, 0x31, 0xff, 0xcb, 0x3a, 0x07, 0xc8, 0xf5,
+ 0xaf, 0x32, 0x07, 0xc8, 0xcd, 0xf1, 0xc2, 0xcd,
+ 0xe4, 0xc1, 0xf1, 0x32, 0x07, 0xc8, 0xcd, 0x05,
+ 0xc2, 0xc3, 0xc9, 0xc1, 0xcd, 0x1f, 0xc0, 0xca,
+ 0xe4, 0xc1, 0xe6, 0x7f, 0xca, 0xc0, 0xc1, 0x47,
+ 0xfe, 0x0d, 0xca, 0xf4, 0xc0, 0xfe, 0x0a, 0xc8,
+ 0xfe, 0x7f, 0xc2, 0xff, 0xc1, 0x06, 0x5f, 0xcd,
+ 0x19, 0xc0, 0xc3, 0xe4, 0xc1, 0xcd, 0x36, 0xc1,
+ 0x0e, 0x01, 0xcd, 0x20, 0xc1, 0xeb, 0x21, 0x00,
+ 0xc0, 0xe5, 0xcd, 0x2e, 0xc3, 0xca, 0x80, 0xc4,
+ 0xeb, 0x11, 0x4a, 0xc2, 0xcd, 0x31, 0xc2, 0xcc,
+ 0x2e, 0xc2, 0xca, 0x81, 0xc4, 0x13, 0xeb, 0x7e,
+ 0x23, 0x66, 0x6f, 0xe3, 0x7d, 0xc9, 0x11, 0x3c,
+ 0xc8, 0x1a, 0xb7, 0xc8, 0xe5, 0xbe, 0x13, 0xc2,
+ 0x43, 0xc2, 0x23, 0x1a, 0xbe, 0xc2, 0x43, 0xc2,
+ 0xe1, 0xb7, 0xc9, 0x13, 0x13, 0x13, 0xe1, 0xc3,
+ 0x31, 0xc2, 0x54, 0x45, 0x67, 0xc3, 0x44, 0x55,
+ 0xbf, 0xc3, 0x45, 0x4e, 0x23, 0xc4, 0x45, 0x58,
+ 0x5e, 0xc4, 0x47, 0x45, 0xa7, 0xc4, 0x53, 0x41,
+ 0xe6, 0xc4, 0x58, 0x45, 0xa6, 0xc4, 0x43, 0x41,
+ 0x2b, 0xc5, 0x53, 0x45, 0x7a, 0xc5, 0x43, 0x55,
+ 0xbd, 0xc5, 0x00, 0x0b, 0xd5, 0xc0, 0x17, 0x04,
+ 0xc1, 0x1a, 0xcb, 0xc0, 0x01, 0x0b, 0xc1, 0x13,
+ 0x15, 0xc1, 0x0e, 0xe5, 0xc0, 0x0d, 0x47, 0xc1,
+ 0x0a, 0x4d, 0xc1, 0x5f, 0x3e, 0xc1, 0x1b, 0x59,
+ 0xc1, 0x00, 0x54, 0xc0, 0x4a, 0xc0, 0xe6, 0xc2,
+ 0xd2, 0xc2, 0x2e, 0xc0, 0x42, 0xc0, 0xdd, 0xc2,
+ 0xcb, 0xc2, 0x54, 0x41, 0x8e, 0xc5, 0x53, 0x3d,
+ 0x99, 0xc5, 0x49, 0x3d, 0x9d, 0xc5, 0x4f, 0x3d,
+ 0xa1, 0xc5, 0x4e, 0x3d, 0xb5, 0xc5, 0x43, 0x49,
+ 0xa5, 0xc5, 0x43, 0x4f, 0xa9, 0xc5, 0x58, 0x45,
+ 0xb1, 0xc5, 0x54, 0x59, 0xad, 0xc5, 0x43, 0x52,
+ 0xb9, 0xc5, 0x00, 0xe5, 0x2a, 0x00, 0xc8, 0xc3,
+ 0xd6, 0xc2, 0xe5, 0x2a, 0x02, 0xc8, 0x7d, 0xb4,
+ 0xca, 0xc0, 0xc1, 0xe3, 0xc9, 0xdb, 0xfa, 0x2f,
+ 0xe6, 0x02, 0xc8, 0xdb, 0xfd, 0xc9, 0xdb, 0xfa,
+ 0xe6, 0x04, 0xc2, 0xe6, 0xc2, 0x78, 0xd3, 0xfd,
+ 0xc9, 0xcd, 0xf9, 0xc2, 0x06, 0x3e, 0xc3, 0x19,
+ 0xc0, 0x06, 0x0a, 0xcd, 0x19, 0xc0, 0x06, 0x0d,
+ 0xcd, 0x19, 0xc0, 0x3a, 0x10, 0xc8, 0x4f, 0x0d,
+ 0xf8, 0xaf, 0xcd, 0x1f, 0xc4, 0xc3, 0x07, 0xc3,
+ 0xcd, 0x1b, 0xc3, 0x3e, 0x01, 0xc8, 0xcd, 0x40,
+ 0xc3, 0x7d, 0xc9, 0x0e, 0x0c, 0x1a, 0xfe, 0x20,
+ 0xca, 0x2e, 0xc3, 0x13, 0xfe, 0x3d, 0xca, 0x2e,
+ 0xc3, 0x0d, 0xc2, 0x1d, 0xc3, 0xc9, 0x0e, 0x0a,
+ 0x1a, 0xfe, 0x20, 0xc0, 0x13, 0x0d, 0xc8, 0xc3,
+ 0x30, 0xc3, 0xcd, 0x1b, 0xc3, 0xca, 0x80, 0xc4,
+ 0x21, 0x00, 0x00, 0x1a, 0xfe, 0x20, 0xc8, 0xfe,
+ 0x2f, 0xc8, 0xfe, 0x3a, 0xc8, 0x29, 0x29, 0x29,
+ 0x29, 0xcd, 0x5d, 0xc3, 0xd2, 0x80, 0xc4, 0x85,
+ 0x6f, 0x13, 0xc3, 0x43, 0xc3, 0xd6, 0x30, 0xfe,
+ 0x0a, 0xd8, 0xd6, 0x07, 0xfe, 0x10, 0xc9, 0xcd,
+ 0x10, 0xc3, 0x32, 0x06, 0xc8, 0xcd, 0x10, 0xc3,
+ 0x32, 0x07, 0xc8, 0xcd, 0x2e, 0xc0, 0xca, 0x8b,
+ 0xc3, 0x47, 0xfe, 0x80, 0xca, 0xc0, 0xc1, 0xda,
+ 0x88, 0xc3, 0xcd, 0x54, 0xc0, 0xc3, 0x8b, 0xc3,
+ 0xcd, 0x19, 0xc0, 0xcd, 0x1f, 0xc0, 0xca, 0x73,
+ 0xc3, 0xe6, 0x7f, 0xca, 0x73, 0xc3, 0x47, 0xfe,
+ 0x1b, 0xd2, 0xb9, 0xc3, 0xfe, 0x0d, 0xca, 0xb9,
+ 0xc3, 0xfe, 0x0a, 0xca, 0xb9, 0xc3, 0x3a, 0x0c,
+ 0xc8, 0xb7, 0xc2, 0xb9, 0xc3, 0xc5, 0x06, 0x1b,
+ 0xcd, 0x54, 0xc0, 0x06, 0x07, 0xcd, 0x54, 0xc0,
+ 0xc1, 0xcd, 0x54, 0xc0, 0xc3, 0x73, 0xc3, 0xcd,
+ 0x3a, 0xc3, 0xe5, 0xcd, 0x10, 0xc3, 0xd1, 0xeb,
+ 0xcd, 0xf9, 0xc2, 0xcd, 0xe8, 0xc3, 0xcd, 0x06,
+ 0xc4, 0x0e, 0x10, 0x7e, 0xc5, 0xcd, 0xed, 0xc3,
+ 0x7d, 0x93, 0x7c, 0x9a, 0xd2, 0xc9, 0xc1, 0xc1,
+ 0x23, 0x0d, 0xc2, 0xd3, 0xc3, 0xc3, 0xc8, 0xc3,
+ 0x7c, 0xcd, 0x0b, 0xc4, 0x7d, 0xcd, 0x0b, 0xc4,
+ 0xcd, 0x1f, 0xc0, 0xca, 0x06, 0xc4, 0xe6, 0x7f,
+ 0xca, 0xc9, 0xc1, 0xfe, 0x20, 0xc2, 0x06, 0xc4,
+ 0xcd, 0x1f, 0xc0, 0xca, 0x00, 0xc4, 0x06, 0x20,
+ 0xc3, 0x19, 0xc0, 0x4f, 0x0f, 0x0f, 0x0f, 0x0f,
+ 0xcd, 0x14, 0xc4, 0x79, 0xe6, 0x0f, 0xc6, 0x30,
+ 0xfe, 0x3a, 0xda, 0x1f, 0xc4, 0xc6, 0x07, 0x47,
+ 0xc3, 0x19, 0xc0, 0xcd, 0x3a, 0xc3, 0xe5, 0xaf,
+ 0x32, 0x07, 0xc8, 0xcd, 0xf9, 0xc2, 0x06, 0x3a,
+ 0xcd, 0xff, 0xc1, 0xcd, 0x36, 0xc1, 0x0e, 0x01,
+ 0xcd, 0x20, 0xc1, 0xeb, 0x0e, 0x03, 0xcd, 0x30,
+ 0xc3, 0xca, 0x2b, 0xc4, 0xfe, 0x2f, 0xca, 0xc0,
+ 0xc1, 0xcd, 0x40, 0xc3, 0xfe, 0x3a, 0xca, 0x59,
+ 0xc4, 0x7d, 0xe1, 0x77, 0x23, 0xe5, 0xc3, 0x3c,
+ 0xc4, 0xe3, 0x13, 0xc3, 0x3c, 0xc4, 0xcd, 0x3a,
+ 0xc3, 0xe5, 0x21, 0x00, 0xc0, 0xc9, 0x21, 0x1c,
+ 0xc8, 0xcd, 0x1b, 0xc3, 0x06, 0x06, 0x1a, 0xfe,
+ 0x20, 0xca, 0x86, 0xc4, 0xfe, 0x2f, 0xca, 0x86,
+ 0xc4, 0x77, 0x13, 0x23, 0x05, 0xc2, 0x6e, 0xc4,
+ 0xeb, 0x36, 0x3f, 0xc3, 0xc0, 0xc1, 0x36, 0x00,
+ 0x23, 0x05, 0xc2, 0x86, 0xc4, 0xfe, 0x2f, 0x3e,
+ 0x01, 0xc2, 0x9a, 0xc4, 0x13, 0xcd, 0x2e, 0xc3,
+ 0xd6, 0x30, 0xe6, 0x01, 0x3e, 0x80, 0xc2, 0xa2,
+ 0xc4, 0x1f, 0x32, 0x54, 0xc8, 0xc9, 0x3e, 0xaf,
+ 0xf5, 0x21, 0x2c, 0xc8, 0xcd, 0x69, 0xc4, 0x21,
+ 0x00, 0x00, 0xcd, 0x10, 0xc3, 0xeb, 0x21, 0x2c,
+ 0xc8, 0x7e, 0xb7, 0xc2, 0xc1, 0xc4, 0x21, 0x1c,
+ 0xc8, 0xe5, 0xcd, 0x48, 0xc5, 0xe1, 0xcd, 0xcb,
+ 0xc6, 0xda, 0x14, 0xc5, 0xcd, 0x50, 0xc5, 0xf1,
+ 0xb7, 0xc8, 0x3a, 0x22, 0xc8, 0xb7, 0xfa, 0x14,
+ 0xc5, 0x3a, 0x21, 0xc8, 0xb7, 0xc2, 0x14, 0xc5,
+ 0x2a, 0x27, 0xc8, 0xc3, 0x61, 0xc4, 0xcd, 0x66,
+ 0xc4, 0xcd, 0x3a, 0xc3, 0xe5, 0xcd, 0x3a, 0xc3,
+ 0xe3, 0xe5, 0xcd, 0x10, 0xc3, 0x22, 0x25, 0xc8,
+ 0xe1, 0xd1, 0xe5, 0x7b, 0x95, 0x6f, 0x7a, 0x9c,
+ 0x67, 0x23, 0x22, 0x23, 0xc8, 0xe5, 0xcd, 0x48,
+ 0xc5, 0x21, 0x1c, 0xc8, 0xcd, 0xaf, 0xc7, 0xd1,
+ 0xe1, 0xc3, 0x90, 0xc7, 0xcd, 0xf9, 0xc2, 0x16,
+ 0x06, 0x21, 0x25, 0xc5, 0xcd, 0x6a, 0xc5, 0xcd,
+ 0x50, 0xc5, 0xc3, 0xc0, 0xc1, 0x45, 0x52, 0x52,
+ 0x4f, 0x52, 0x20, 0xcd, 0x66, 0xc4, 0xcd, 0xf9,
+ 0xc2, 0xcd, 0x48, 0xc5, 0x06, 0x01, 0xcd, 0xef,
+ 0xc7, 0xcd, 0x23, 0xc7, 0xda, 0xc0, 0xc1, 0xc2,
+ 0x39, 0xc5, 0xcd, 0x50, 0xc5, 0xc3, 0x39, 0xc5,
+ 0x21, 0x54, 0xc8, 0x3a, 0x0d, 0xc8, 0xb6, 0xc9,
+ 0x16, 0x08, 0x21, 0x1b, 0xc8, 0xcd, 0x6a, 0xc5,
+ 0xcd, 0x06, 0xc4, 0x2a, 0x25, 0xc8, 0xcd, 0xe8,
+ 0xc3, 0x2a, 0x23, 0xc8, 0xcd, 0xe8, 0xc3, 0xc3,
+ 0xf9, 0xc2, 0x7e, 0xb7, 0xc2, 0x71, 0xc5, 0x3e,
+ 0x20, 0xcd, 0x1f, 0xc4, 0x23, 0x15, 0xc2, 0x6a,
+ 0xc5, 0xc9, 0xcd, 0x1b, 0xc3, 0xca, 0x80, 0xc4,
+ 0xd5, 0xcd, 0x3a, 0xc3, 0xe3, 0x11, 0xa2, 0xc2,
+ 0xcd, 0x31, 0xc2, 0xc3, 0x22, 0xc2, 0xb7, 0xca,
+ 0x94, 0xc5, 0x3e, 0x20, 0x32, 0x0d, 0xc8, 0xc9,
+ 0x78, 0x32, 0x0b, 0xc8, 0xc9, 0x32, 0x06, 0xc8,
+ 0xc9, 0x32, 0x07, 0xc8, 0xc9, 0x22, 0x00, 0xc8,
+ 0xc9, 0x22, 0x02, 0xc8, 0xc9, 0x32, 0x22, 0xc8,
+ 0xc9, 0x22, 0x27, 0xc8, 0xc9, 0x32, 0x10, 0xc8,
+ 0xc9, 0x32, 0x11, 0xc8, 0xc9, 0xcd, 0x66, 0xc4,
+ 0x21, 0xc9, 0xc1, 0xcd, 0x10, 0xc3, 0xe5, 0x21,
+ 0x1c, 0xc8, 0xcd, 0x2e, 0xc2, 0xca, 0xd3, 0xc5,
+ 0x1b, 0x36, 0x00, 0x7e, 0x12, 0x13, 0x23, 0x7e,
+ 0x12, 0x13, 0xe1, 0xeb, 0x73, 0x23, 0x72, 0xc9,
+ 0xe5, 0xcd, 0x33, 0xc6, 0xc2, 0xfa, 0xc5, 0x36,
+ 0x01, 0x23, 0x77, 0x23, 0x77, 0x11, 0x63, 0xc8,
+ 0x3a, 0x54, 0xc8, 0x82, 0x57, 0xc1, 0xb7, 0xc3,
+ 0xb6, 0xc6, 0xe1, 0xd1, 0xaf, 0x37, 0xc9, 0x3d,
+ 0x37, 0xd1, 0xc9, 0xcd, 0x33, 0xc6, 0xc8, 0xb7,
+ 0x3c, 0x36, 0x00, 0xc8, 0x23, 0x23, 0x7e, 0x7e,
+ 0xcd, 0xbf, 0xc6, 0xc5, 0x21, 0x07, 0x00, 0x09,
+ 0xb7, 0xca, 0x2b, 0xc6, 0xe5, 0x77, 0x23, 0x36,
+ 0x00, 0x23, 0x73, 0x23, 0x72, 0x60, 0x69, 0xcd,
+ 0x7c, 0xc7, 0xe1, 0xaf, 0x77, 0x23, 0x77, 0xe1,
+ 0xc3, 0x7c, 0xc7, 0x21, 0x55, 0xc8, 0x1f, 0xe6,
+ 0x01, 0x32, 0x54, 0xc8, 0xca, 0x42, 0xc6, 0x21,
+ 0x5c, 0xc8, 0x7e, 0xb7, 0x37, 0xc9, 0xcd, 0x33,
+ 0xc6, 0xc8, 0x3c, 0xfa, 0xfc, 0xc5, 0x36, 0xff,
+ 0x23, 0x7e, 0xe5, 0x23, 0xcd, 0xbf, 0xc6, 0xe1,
+ 0xb7, 0xc2, 0x75, 0xc6, 0xd5, 0xe5, 0x23, 0xcd,
+ 0xa6, 0xc6, 0xcd, 0xc8, 0xc6, 0xda, 0xfa, 0xc5,
+ 0xe1, 0x7b, 0xb2, 0xca, 0xff, 0xc5, 0x73, 0x23,
+ 0x36, 0x00, 0x2b, 0x7b, 0xd1, 0x3d, 0x77, 0x23,
+ 0x7e, 0x34, 0x83, 0x5f, 0xd2, 0x80, 0xc6, 0x14,
+ 0x1a, 0xb7, 0xc9, 0xcd, 0x33, 0xc6, 0xc8, 0x3c,
+ 0xc8, 0x36, 0xfe, 0x23, 0x23, 0x78, 0xf5, 0xe5,
+ 0xcd, 0xbf, 0xc6, 0xe1, 0x7e, 0x83, 0x5f, 0xd2,
+ 0x9b, 0xc6, 0x14, 0xf1, 0x12, 0xb7, 0x34, 0xc0,
+ 0xcd, 0xa6, 0xc6, 0xc3, 0x7c, 0xc7, 0xcd, 0xbf,
+ 0xc6, 0xc5, 0x21, 0x06, 0x00, 0x09, 0x01, 0x00,
+ 0x01, 0xcd, 0xb6, 0xc6, 0xe1, 0xc9, 0x23, 0x71,
+ 0x23, 0x70, 0x23, 0x73, 0x23, 0x72, 0xc9, 0x23,
+ 0x4e, 0x23, 0x46, 0x23, 0x5e, 0x23, 0x56, 0xc9,
+ 0xcd, 0xde, 0xc7, 0xd5, 0x06, 0x03, 0xcd, 0xef,
+ 0xc7, 0xdb, 0xfb, 0xe5, 0xcd, 0x23, 0xc7, 0xe1,
+ 0xda, 0x06, 0xc7, 0xc2, 0xd3, 0xc6, 0xe5, 0x11,
+ 0x1c, 0xc8, 0xcd, 0xd2, 0xc7, 0xe1, 0xc2, 0xd3,
+ 0xc6, 0xd1, 0x7a, 0xb3, 0x2a, 0x23, 0xc8, 0xeb,
+ 0xc2, 0xf6, 0xc6, 0x2a, 0x25, 0xc8, 0xd5, 0xcd,
+ 0x15, 0xc7, 0xca, 0x10, 0xc7, 0xcd, 0x44, 0xc7,
+ 0xda, 0x06, 0xc7, 0xca, 0xf7, 0xc6, 0xaf, 0x37,
+ 0xc3, 0x11, 0xc7, 0x06, 0x01, 0xcd, 0xf1, 0xc7,
+ 0xaf, 0xd3, 0xfa, 0xd1, 0xc9, 0xaf, 0x47, 0xb2,
+ 0xc2, 0x20, 0xc7, 0xb3, 0xc8, 0x43, 0x5a, 0xc9,
+ 0x15, 0xb7, 0xc9, 0x06, 0x0a, 0xcd, 0x5d, 0xc7,
+ 0xd8, 0xdb, 0xfb, 0xb7, 0xc2, 0x23, 0xc7, 0x05,
+ 0xc2, 0x25, 0xc7, 0xcd, 0x6f, 0xc7, 0xd8, 0xfe,
+ 0x01, 0xda, 0x33, 0xc7, 0xc2, 0x23, 0xc7, 0x21,
+ 0x1c, 0xc8, 0x06, 0x10, 0x0e, 0x00, 0xcd, 0x6f,
+ 0xc7, 0xd8, 0x77, 0x23, 0xcd, 0xa8, 0xc7, 0x05,
+ 0xc2, 0x46, 0xc7, 0xcd, 0x6f, 0xc7, 0xa9, 0xc8,
+ 0x3a, 0x11, 0xc8, 0x3c, 0xc9, 0xdb, 0xfa, 0xe6,
+ 0x40, 0xc0, 0xcd, 0x1f, 0xc0, 0xca, 0x5d, 0xc7,
+ 0xe6, 0x7f, 0xc2, 0x5d, 0xc7, 0x37, 0xc9, 0xcd,
+ 0x5d, 0xc7, 0xd8, 0xdb, 0xfa, 0xe6, 0x18, 0xdb,
+ 0xfb, 0xc8, 0x37, 0xc9, 0xcd, 0xde, 0xc7, 0xe5,
+ 0xcd, 0xaf, 0xc7, 0xe1, 0x11, 0x07, 0x00, 0x19,
+ 0x5e, 0x23, 0x56, 0x23, 0x7e, 0x23, 0x66, 0x6f,
+ 0xe5, 0xcd, 0x15, 0xc7, 0xca, 0x0b, 0xc7, 0xcd,
+ 0xc3, 0xc7, 0xc3, 0x91, 0xc7, 0xf5, 0xdb, 0xfa,
+ 0xe6, 0x80, 0xca, 0x9e, 0xc7, 0xf1, 0xd3, 0xfb,
+ 0x91, 0x4f, 0xa9, 0x2f, 0x91, 0x4f, 0xc9, 0xcd,
+ 0xed, 0xc7, 0x16, 0x32, 0xaf, 0xcd, 0x9d, 0xc7,
+ 0x15, 0xc2, 0xb4, 0xc7, 0x3e, 0x01, 0xcd, 0x9d,
+ 0xc7, 0x06, 0x10, 0x0e, 0x00, 0x7e, 0xcd, 0x9d,
+ 0xc7, 0x05, 0x23, 0xc2, 0xc5, 0xc7, 0x79, 0xc3,
+ 0x9d, 0xc7, 0x06, 0x05, 0x1a, 0xbe, 0xc0, 0x05,
+ 0xc8, 0x23, 0x13, 0xc3, 0xd4, 0xc7, 0x3a, 0x54,
+ 0xc8, 0xb7, 0x3a, 0x0d, 0xc8, 0xc2, 0xea, 0xc7,
+ 0xc6, 0x40, 0xc6, 0x40, 0xc9, 0x06, 0x04, 0xd3,
+ 0xfa, 0x11, 0x00, 0x00, 0x1b, 0x7a, 0xb3, 0xc2,
+ 0xf4, 0xc7, 0x05, 0xc2, 0xf1, 0xc7, 0xc9, 0x00,
+};
+
+static uint8 *sol20_rom = sol20_rom_41; /* Default 4.1 ROM */
+
+/*********************/
+/* SOL20 Definitions */
+/*********************/
+
+/*
+** PORT ASSIGNMENTS
+*/
+#define SOL20_SERST 0xf8 /* SERIAL STATUS PORT */
+#define SOL20_SDATA 0xf9 /* SERIAL DATA */
+#define SOL20_STAPT 0xfa /* STATUS PORT GENERAL */
+#define SOL20_TDATA 0xfb /* TAPE DATA */
+#define SOL20_KDATA 0xfc /* KEYBOARD DATA */
+#define SOL20_PDATA 0xfd /* PARALLEL DATA */
+/*
+** BIT ASSIGNMENT MASKS
+*/
+#define SOL20_SCD 0x01 /* SERIAL CARRIER DETECT */
+#define SOL20_SDSR 0x02 /* SERIAL DATA SET READY */
+#define SOL20_SPE 0x04 /* SERIAL PARITY ERROR */
+#define SOL20_SFE 0x08 /* SERIAL FRAMING ERROR */
+#define SOL20_SOE 0x10 /* SERIAL OVERRUN ERROR */
+#define SOL20_SCTS 0x20 /* SERIAL CLEAR TO SEND */
+#define SOL20_SDR 0x40 /* SERIAL DATA READY */
+#define SOL20_STBE 0x80 /* SERIAL TRANSMITTER BUFFER EMPTY */
+
+#define SOL20_KDR 0x01 /* KEYBOARD DATA READY */
+#define SOL20_PDR 0x02 /* PARALLEL DATA READY */
+#define SOL20_PXDR 0x04 /* PARALLEL DEVICE READY */
+#define SOL20_TFE 0x08 /* TAPE FRAMING ERROR */
+#define SOL20_TOE 0x10 /* TAPE OVERRUN ERROR */
+#define SOL20_TDR 0x40 /* TAPE DATA READY */
+#define SOL20_TTBE 0x80 /* TAPE TRANSMITTER BUFFER EMPTY */
+
+#define SOL20_TAPE1 0x80 /* 1=TURN TAPE ONE ON */
+#define SOL20_TAPE2 0x40 /* 1=TURN TAPE TWO ON */
+
+/****************/
+/* SOL20 Device */
+/****************/
+
+#define SOL20_NAME "Processor Technology Sol-20"
+#define SOL20_SNAME "SOL20"
+
+/*
+** SOL20 Registers and Interface Controls
+*/
+
+typedef struct {
+ uint32 rom_base; /* Memory Base Address */
+ uint32 rom_size; /* Memory Address space requirement */
+ uint32 io_base; /* I/O Base Address */
+ uint32 io_size; /* I/O Address Space requirement */
+} SOL20_CTX;
+
+static SOL20_CTX sol20_ctx = {
+ SOL20_ROM_BASE, SOL20_ROM_SIZE, SOL20_STAPT, 1
+};
+
+static UNIT sol20_unit[] = {
+ { UDATA (NULL, 0, 0) }
+};
+
+static REG sol20_reg[] = {
+ { NULL }
+};
+
+static MTAB sol20_mod[] = {
+ { MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "ROM", "ROM",
+ &set_membase, &show_membase, NULL, "ROM address"},
+ { MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "VER", "VER={13,13C,41}",
+ &sol20_set_rom, &sol20_show_rom, NULL, "ROM version"},
+ { MTAB_XTD|MTAB_VDV, 0, "PORT", "PORT",
+ NULL, sol20_show_ports, NULL, "I/O port address" },
+ { 0 }
+};
+
+DEVICE sol20_dev = {
+ SOL20_SNAME, /* name */
+ sol20_unit, /* unit */
+ sol20_reg, /* registers */
+ sol20_mod, /* modifiers */
+ 1, /* # units */
+ 10, /* address radix */
+ 31, /* address width */
+ 1, /* addr increment */
+ 8, /* data radix */
+ 8, /* data width */
+ NULL, /* examine routine */
+ NULL, /* deposit routine */
+ &sol20_reset, /* reset routine */
+ &sol20_boot, /* boot routine */
+ NULL, /* attach routine */
+ NULL, /* detach routine */
+ &sol20_ctx, /* context */
+ (DEV_DISABLE | DEV_DIS | DEV_DEBUG), /* flags */
+ ERROR_MSG, /* debug control */
+ sol20_dt, /* debug flags */
+ NULL, /* mem size routine */
+ NULL, /* logical name */
+ &sol20_help, /* help */
+ NULL, /* attach help */
+ NULL, /* context for help */
+ &sol20_description /* description */
+};
+
+/****************/
+/* GENERIC PORT */
+/****************/
+
+typedef struct {
+ PNP_INFO pnp; /* Must be first */
+ int32 conn; /* Connected Status */
+ uint16 baud; /* Baud rate */
+ uint8 status; /* Status Byte */
+ uint8 rdr; /* Receive Data Ready */
+ uint8 rxd; /* Receive Data Buffer */
+ uint8 txd; /* Transmit Data Buffer */
+ uint8 tbe; /* Transmit Buffer Empty */
+ TMLN *tmln; /* TMLN pointer */
+ TMXR *tmxr; /* TMXR pointer */
+} SOL20_PORT_CTX;
+
+/**************************/
+/* SOL20K Keyboard Device */
+/**************************/
+
+#define SOL20K_NAME "Sol-20 Keyboard"
+#define SOL20K_SNAME "SOL20K"
+
+static TMLN sol20k_tmln[1] = { /* line descriptors */
+ { 0 }
+};
+
+static TMXR sol20k_tmxr = { /* multiplexer descriptor */
+ 1, /* number of terminal lines */
+ 0, /* listening port (reserved) */
+ 0, /* master socket (reserved) */
+ sol20k_tmln, /* line descriptor array */
+ NULL, /* line connection order */
+ NULL /* multiplexer device (derived internally) */
+};
+
+static SOL20_PORT_CTX sol20k_ctx = {
+ {0, 0, SOL20_KDATA, 1}, 0, 9600, 0,
+ 0, 0, 0, 0, sol20k_tmln, &sol20k_tmxr
+};
+
+static REG sol20k_reg[] = {
+ { NULL }
+};
+
+static UNIT sol20k_unit[] = {
+ { UDATA (&sol20_svc, UNIT_ATTABLE, 0), 500 }
+};
+
+static MTAB sol20k_mod[] = {
+ { MTAB_XTD|MTAB_VDV, 0, "PORT", "PORT",
+ NULL, sol20_show_ports, NULL, "Show serial I/O ports" },
+ { MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "BAUD", "BAUD",
+ &sol20_set_baud, &sol20_show_baud, NULL, "Set baud rate (default=9600)" },
+ { 0 }
+};
+
+DEVICE sol20k_dev = {
+ SOL20K_SNAME, /* name */
+ sol20k_unit, /* unit */
+ sol20k_reg, /* registers */
+ sol20k_mod, /* modifiers */
+ 1, /* # units */
+ 10, /* address radix */
+ 31, /* address width */
+ 1, /* addr increment */
+ 8, /* data radix */
+ 8, /* data width */
+ NULL, /* examine routine */
+ NULL, /* deposit routine */
+ &sol20_kb_reset, /* reset routine */
+ NULL, /* boot routine */
+ &sol20_attach_mux, /* attach routine */
+ &sol20_detach_mux, /* detach routine */
+ &sol20k_ctx, /* context */
+ (DEV_DISABLE | DEV_DIS | DEV_DEBUG | DEV_MUX), /* flags */
+ ERROR_MSG, /* debug control */
+ sol20_dt, /* debug flags */
+ NULL, /* mem size routine */
+ NULL, /* logical name */
+ NULL, /* help */
+ NULL, /* attach help */
+ NULL, /* context for help */
+ &sol20k_description /* description */
+};
+
+/**********************/
+/* SOL20T Tape Device */
+/**********************/
+
+#define SOL20T_NAME "Sol-20 Tape Port"
+#define SOL20T_SNAME "SOL20T"
+
+#define SOL20_TAPE_NORMAL 4000
+#define SOL20_TAPE_FAST 100
+
+static TMLN sol20t_tmln[1] = { /* line descriptors */
+ { 0 }
+};
+
+static TMXR sol20t_tmxr = { /* multiplexer descriptor */
+ 1, /* number of terminal lines */
+ 0, /* listening port (reserved) */
+ 0, /* master socket (reserved) */
+ sol20t_tmln, /* line descriptor array */
+ NULL, /* line connection order */
+ NULL /* multiplexer device (derived internally) */
+};
+
+static SOL20_PORT_CTX sol20t_ctx = {
+ {0, 0, SOL20_TDATA, 1}, 0, 9600, 0,
+ 0, 0, 0, 0, sol20t_tmln, &sol20t_tmxr
+};
+
+static REG sol20t_reg[] = {
+ { HRDATAD (BAUD, sol20t_ctx.baud, 16, "Tape port baud register"), },
+ { HRDATAD (STATUS, sol20t_ctx.baud, 8, "Tape port status register"), },
+ { HRDATAD (TXP, sol20t_ctx.tbe, 8, "Tape port TX buffer empty register"), },
+ { HRDATAD (TXD, sol20t_ctx.txd, 8, "Tape port TX data register"), },
+ { HRDATAD (RXD, sol20t_ctx.rdr, 8, "Tape port RX data ready"), },
+ { HRDATAD (RXD, sol20t_ctx.rxd, 8, "Tape port RX data register"), },
+ { NULL }
+};
+
+static UNIT sol20t_unit[] = {
+ { UDATA (&sol20_svc, UNIT_ATTABLE | UNIT_ROABLE, 0), SOL20_TAPE_NORMAL }
+};
+
+static MTAB sol20t_mod[] = {
+ { MTAB_XTD|MTAB_VDV, 0, "PORT", "PORT",
+ NULL, sol20_show_ports, NULL, "Show serial I/O ports" },
+ { MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "TAPE", "TAPE",
+ &sol20_set_tape, &sol20_show_tape, NULL, "Tape Speed"},
+ { 0 }
+};
+
+DEVICE sol20t_dev = {
+ SOL20T_SNAME, /* name */
+ sol20t_unit, /* unit */
+ sol20t_reg, /* registers */
+ sol20t_mod, /* modifiers */
+ 1, /* # units */
+ 10, /* address radix */
+ 31, /* address width */
+ 1, /* addr increment */
+ 8, /* data radix */
+ 8, /* data width */
+ NULL, /* examine routine */
+ NULL, /* deposit routine */
+ &sol20_port_reset, /* reset routine */
+ NULL, /* boot routine */
+ &sol20_attach_tape, /* attach routine */
+ &sol20_detach_tape, /* detach routine */
+ &sol20t_ctx, /* context */
+ (DEV_DISABLE | DEV_DIS | DEV_DEBUG), /* flags */
+ ERROR_MSG, /* debug control */
+ sol20_dt, /* debug flags */
+ NULL, /* mem size routine */
+ NULL, /* logical name */
+ NULL, /* help */
+ NULL, /* attach help */
+ NULL, /* context for help */
+ &sol20t_description /* description */
+};
+
+/************************/
+/* SOL20S Serial Device */
+/************************/
+
+#define SOL20S_NAME "Sol-20 Serial Port"
+#define SOL20S_SNAME "SOL20S"
+
+static TMLN sol20s_tmln[1] = { /* line descriptors */
+ { 0 }
+};
+
+static TMXR sol20s_tmxr = { /* multiplexer descriptor */
+ 1, /* number of terminal lines */
+ 0, /* listening port (reserved) */
+ 0, /* master socket (reserved) */
+ sol20s_tmln, /* line descriptor array */
+ NULL, /* line connection order */
+ NULL /* multiplexer device (derived internally) */
+};
+
+static SOL20_PORT_CTX sol20s_ctx = {
+ {0, 0, SOL20_SERST, 2}, 0, 9600, 0,
+ 0, 0, 0, 0, sol20s_tmln, &sol20s_tmxr
+};
+
+static REG sol20s_reg[] = {
+ { HRDATAD (BAUD, sol20s_ctx.baud, 16, "Modem port baud register"), },
+ { HRDATAD (TXP, sol20s_ctx.tbe, 8, "Modem port TX buffer empty register"), },
+ { HRDATAD (TXD, sol20s_ctx.txd, 8, "Modem port TX data register"), },
+ { HRDATAD (RXD, sol20s_ctx.rxd, 8, "Modem port RX register"), },
+ { NULL }
+};
+
+static UNIT sol20s_unit[] = {
+ { UDATA (&sol20_svc, UNIT_ATTABLE, 0), 1000 }
+};
+
+static MTAB sol20s_mod[] = {
+ { MTAB_XTD|MTAB_VDV, 0, "PORT", "PORT",
+ NULL, sol20_show_ports, NULL, "Show serial I/O ports" },
+ { MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "BAUD", "BAUD",
+ &sol20_set_baud, &sol20_show_baud, NULL, "Set baud rate (default=9600)" },
+ { 0 }
+};
+
+DEVICE sol20s_dev = {
+ SOL20S_SNAME, /* name */
+ sol20s_unit, /* unit */
+ sol20s_reg, /* registers */
+ sol20s_mod, /* modifiers */
+ 1, /* # units */
+ 10, /* address radix */
+ 31, /* address width */
+ 1, /* addr increment */
+ 8, /* data radix */
+ 8, /* data width */
+ NULL, /* examine routine */
+ NULL, /* deposit routine */
+ &sol20_port_reset, /* reset routine */
+ NULL, /* boot routine */
+ &sol20_attach_mux, /* attach routine */
+ &sol20_detach_mux, /* detach routine */
+ &sol20s_ctx, /* context */
+ (DEV_DISABLE | DEV_DIS | DEV_DEBUG | DEV_MUX), /* flags */
+ ERROR_MSG, /* debug control */
+ sol20_dt, /* debug flags */
+ NULL, /* mem size routine */
+ NULL, /* logical name */
+ NULL, /* help */
+ NULL, /* attach help */
+ NULL, /* context for help */
+ &sol20s_description /* description */
+};
+
+/*************************/
+/* SOL20P Printer Device */
+/*************************/
+
+#define SOL20P_NAME "Sol-20 Printer Port"
+#define SOL20P_SNAME "SOL20P"
+
+static TMLN sol20p_tmln[1] = { /* line descriptors */
+ { 0 }
+};
+
+static TMXR sol20p_tmxr = { /* multiplexer descriptor */
+ 1, /* number of terminal lines */
+ 0, /* listening port (reserved) */
+ 0, /* master socket (reserved) */
+ sol20p_tmln, /* line descriptor array */
+ NULL, /* line connection order */
+ NULL /* multiplexer device (derived internally) */
+};
+
+static SOL20_PORT_CTX sol20p_ctx = {
+ {0, 0, SOL20_PDATA, 1}, 0, 9600, 0,
+ 0, 0, 0, 0, sol20p_tmln, &sol20p_tmxr
+};
+
+static REG sol20p_reg[] = {
+ { HRDATAD (TXP, sol20p_ctx.tbe, 8, "Printer port buffer empty register"), },
+ { HRDATAD (TXD, sol20p_ctx.txd, 8, "Printer port data register"), },
+ { NULL }
+};
+
+static UNIT sol20p_unit[] = {
+ { UDATA (&sol20_svc, UNIT_ATTABLE, 0), 1000 }
+};
+
+static MTAB sol20p_mod[] = {
+ { MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "BAUD", "BAUD",
+ &sol20_set_baud, &sol20_show_baud, NULL, "Set baud rate (default=9600)" },
+ { 0 }
+};
+
+DEVICE sol20p_dev = {
+ SOL20P_SNAME, /* name */
+ sol20p_unit, /* unit */
+ sol20p_reg, /* registers */
+ sol20p_mod, /* modifiers */
+ 1, /* # units */
+ 10, /* address radix */
+ 31, /* address width */
+ 1, /* addr increment */
+ 8, /* data radix */
+ 8, /* data width */
+ NULL, /* examine routine */
+ NULL, /* deposit routine */
+ &sol20_port_reset, /* reset routine */
+ NULL, /* boot routine */
+ &sol20_attach_mux, /* attach routine */
+ &sol20_detach_mux, /* detach routine */
+ &sol20p_ctx, /* context */
+ (DEV_DISABLE | DEV_DIS | DEV_DEBUG | DEV_MUX), /* flags */
+ ERROR_MSG, /* debug control */
+ sol20_dt, /* debug flags */
+ NULL, /* mem size routine */
+ NULL, /* logical name */
+ NULL, /* help */
+ NULL, /* attach help */
+ NULL, /* context for help */
+ &sol20p_description /* description */
+};
+
+static const char* sol20_description(DEVICE *dptr) {
+ return SOL20_NAME;
+}
+
+static const char* sol20k_description(DEVICE *dptr) {
+ return SOL20K_NAME;
+}
+
+static const char* sol20t_description(DEVICE *dptr) {
+ return SOL20T_NAME;
+}
+
+static const char* sol20s_description(DEVICE *dptr) {
+ return SOL20S_NAME;
+}
+
+static const char* sol20p_description(DEVICE *dptr) {
+ return SOL20P_NAME;
+}
+
+/*
+ * Reset function for the main SOL20 device.
+ *
+ * Enables all other Sol-20 devices
+ */
+static t_stat sol20_reset(DEVICE *dptr)
+{
+ static uint8 first = 1;
+#if defined(USE_SIM_VIDEO) && defined(HAVE_LIBSDL)
+ DEVICE *vdm1;
+#endif
+
+ if (dptr->flags & DEV_DIS) { /* Disconnect Resources */
+ sim_map_resource(sol20_ctx.rom_base, sol20_ctx.rom_size, RESOURCE_TYPE_MEMORY, &sol20rom, "sol20rom", TRUE);
+ sim_map_resource(sol20_ctx.io_base, sol20_ctx.io_size, RESOURCE_TYPE_IO, &sol20io, "sol20io", TRUE);
+ }
+ else {
+ /*
+ * If this is the first reset of the SOL20 device,
+ * enable the VDM-1 and SOL20 devices.
+ */
+ if (first--) {
+#if defined(USE_SIM_VIDEO) && defined(HAVE_LIBSDL)
+ if ((vdm1 = find_dev("VDM1")) != NULL) {
+ set_dev_enbdis(vdm1, NULL, 1, NULL);
+ }
+#else
+ sim_messagef(SCPE_NOFNC, "%s device requires VDM1 video support.\n", SOL20_SNAME);
+ return SCPE_NOFNC;
+#endif
+
+ set_dev_enbdis(&sol20k_dev, NULL, 1, NULL);
+ set_dev_enbdis(&sol20t_dev, NULL, 1, NULL);
+ set_dev_enbdis(&sol20s_dev, NULL, 1, NULL);
+ set_dev_enbdis(&sol20p_dev, NULL, 1, NULL);
+ }
+
+ if (sim_map_resource(sol20_ctx.rom_base, sol20_ctx.rom_size, RESOURCE_TYPE_MEMORY, &sol20rom, "sol20rom", FALSE) != 0) {
+ sim_debug(ERROR_MSG, &sol20_dev, "Error mapping MEM resource at 0x%04x\n", sol20_ctx.rom_base);
+ return SCPE_ARG;
+ }
+ /* Connect I/O Ports at base address */
+ if (sim_map_resource(sol20_ctx.io_base, sol20_ctx.io_size, RESOURCE_TYPE_IO, &sol20io, "sol20io", FALSE) != 0) {
+ sim_debug(ERROR_MSG, &sol20_dev, "Error mapping I/O resource at 0x%02x\n", sol20_ctx.io_base);
+ return SCPE_ARG;
+ }
+ }
+
+ sim_debug(STATUS_MSG, &sol20_dev, "reset controller.\n");
+
+ return SCPE_OK;
+}
+
+/*
+ * The BOOT command will enter the SOLOS ROM at 0xC000
+ */
+static t_stat sol20_boot(int32 unitno, DEVICE *dptr)
+{
+ sim_printf("%s: Booting using ROM at 0x%04x\n", SOL20_SNAME, sol20_ctx.rom_base);
+
+ *((int32 *) sim_PC->loc) = sol20_ctx.rom_base;
+
+ return SCPE_OK;
+}
+
+/*
+ * Manage VDM1 keyboard callback
+ */
+static t_stat sol20_kb_reset(DEVICE *dptr) {
+ if (dptr->flags & DEV_DIS) { /* Disconnect VDM1 keyboard callback */
+ vdm1_kb_callback = NULL;
+ }
+ else {
+ vdm1_kb_callback = sol20_kb_callback;
+ }
+
+ return sol20_port_reset(dptr);
+}
+
+static t_stat sol20_port_reset(DEVICE *dptr) {
+ SOL20_PORT_CTX *port;
+ uint32 u;
+
+ port = (SOL20_PORT_CTX *) dptr->ctxt;
+
+ for (u = 0; u < dptr->numunits; u++) {
+ dptr->units[u].dptr = dptr;
+ }
+
+ if (dptr->flags & DEV_DIS) { /* Disconnect I/O Port(s) */
+ sim_map_resource(port->pnp.io_base, port->pnp.io_size, RESOURCE_TYPE_IO, &sol20io, dptr->name, TRUE);
+ for (u = 0; u < dptr->numunits; u++) {
+ sim_cancel(&dptr->units[u]); /* cancel timer */
+ }
+ }
+ else {
+ /* Connect I/O Ports at base address */
+ if (sim_map_resource(port->pnp.io_base, port->pnp.io_size, RESOURCE_TYPE_IO, &sol20io, dptr->name, FALSE) != 0) {
+ sim_debug(ERROR_MSG, dptr, "Error mapping I/O resource at 0x%02x\n", port->pnp.io_base);
+ return SCPE_ARG;
+ }
+
+ port->status = 0x00;
+ port->rdr = FALSE;
+ port->tbe = TRUE;
+
+ for (u = 0; u < dptr->numunits; u++) {
+ sim_activate_after_abs(&dptr->units[u], dptr->units[u].wait); /* activate timer */
+ }
+ }
+
+ return SCPE_OK;
+}
+
+/*
+ * Sol-20 service routine
+ *
+ * The Sol-20 simulator has 4 I/O devices
+ *
+ * SOL20K - Keyboard device that supports TMXR
+ * SOL20S - Serial device that supports TMXR
+ * SOL20P - Parallel device that supports TMXR
+ * SOL20T - Tape device that supports files
+ */
+static t_stat sol20_svc(UNIT *uptr)
+{
+ SOL20_PORT_CTX *port;
+ int32 c = 0;
+ t_stat r = SCPE_OK;
+
+ port = (SOL20_PORT_CTX *) uptr->dptr->ctxt;
+
+ /* Check for new incoming connection */
+ if ((uptr->dptr->flags & DEV_MUX) && (uptr->flags & UNIT_ATT)) {
+ if (tmxr_poll_conn(port->tmxr) >= 0) { /* poll connection */
+
+ port->conn = 1; /* set connected */
+
+ sim_printf("%s: new connection.\n", uptr->dptr->name);
+ }
+ }
+
+ /* TX byte pending? */
+ if (port->tbe == FALSE) {
+ if (uptr->flags & UNIT_ATT) {
+ if (!(uptr->dptr->flags & DEV_MUX)) {
+ r = (sim_fwrite(&port->txd, 1, 1, uptr->fileref) == 1) ? SCPE_OK : SCPE_IOERR;
+ }
+ else {
+ if (port->conn) {
+ if ((r = tmxr_putc_ln(&port->tmln[0], port->txd)) == SCPE_OK) {
+ tmxr_poll_tx(port->tmxr);
+ }
+ else if (r == SCPE_LOST) {
+ port->conn = 0; /* Connection was lost */
+ sim_printf("%s: lost connection.\n", uptr->dptr->name);
+ }
+ }
+ }
+ }
+ else {
+ sim_putchar(port->txd);
+ }
+
+ port->tbe = TRUE;
+ }
+
+ /* Check for Data if RX buffer empty */
+ if (port->rdr == FALSE) {
+ if (uptr->flags & UNIT_ATT) {
+ if (!(uptr->dptr->flags & DEV_MUX)) {
+ if (sim_fread(&c, 1, 1, uptr->fileref) == 1) {
+ c |= SCPE_KFLAG;
+ }
+ }
+ else {
+ tmxr_poll_rx(port->tmxr);
+ c = tmxr_getc_ln(&port->tmln[0]);
+ }
+ }
+ else if (uptr == sol20k_unit) {
+ c = sim_poll_kbd();
+ }
+
+ if (c & (TMXR_VALID | SCPE_KFLAG)) {
+ port->rxd = c & 0xff;
+ port->rdr = TRUE;
+ }
+ }
+
+ sim_activate_after_abs(uptr, uptr->wait); /* reactivate timer */
+
+ return SCPE_OK;
+}
+
+/*
+ * Used to attach (insert) tapes into the SOL20T device
+ */
+static t_stat sol20_attach_tape(UNIT *uptr, CONST char *cptr)
+{
+ t_stat r;
+
+ r = attach_unit(uptr, cptr); /* attach unit */
+ if (r != SCPE_OK) { /* error? */
+ sim_debug(ERROR_MSG, &sol20_dev, "ATTACH error=%d\n", r);
+ return r;
+ }
+
+ sim_printf("%s: Inserted '%s'%s\n", uptr->dptr->name, cptr, uptr->flags & UNIT_RO ? " (Record Protected)" : "");
+
+ return SCPE_OK;
+}
+
+/*
+ * Used to attach (connect) MUX interfaces from the
+ * SOL20K, SOL20S, and SOL20P devices
+ */
+static t_stat sol20_attach_mux(UNIT *uptr, CONST char *cptr)
+{
+ SOL20_PORT_CTX *xptr;
+ t_stat r;
+
+ xptr = (SOL20_PORT_CTX *) uptr->dptr->ctxt;
+
+ if ((r = tmxr_attach(xptr->tmxr, uptr, cptr)) == SCPE_OK) {
+ xptr->tmln[0].rcve = 1;
+ sim_printf("%s: attached '%s' to interface.\n", uptr->dptr->name, cptr);
+ }
+
+ return r;
+}
+
+/*
+ * Used to detach (eject) tapes from the SOL20T device
+ */
+static t_stat sol20_detach_tape(UNIT *uptr)
+{
+ t_stat r;
+
+ r = detach_unit(uptr); /* detach unit */
+
+ if (r != SCPE_OK) {
+ return r;
+ }
+
+ sim_printf("%s: Tape ejected.\n", uptr->dptr->name);
+
+ return SCPE_OK;
+}
+
+/*
+ * Used to detach (disconnect) MUX interfaces from the
+ * SOL20K, SOL20S, and SOL20P devices
+ */
+static t_stat sol20_detach_mux(UNIT *uptr)
+{
+ SOL20_PORT_CTX *xptr;
+ t_stat r;
+
+ xptr = (SOL20_PORT_CTX *) uptr->dptr->ctxt;
+
+ if ((r = tmxr_detach(xptr->tmxr, uptr)) == SCPE_OK) {
+ sim_printf("%s: detached.\n", uptr->dptr->name);
+ }
+
+ return r;
+}
+
+static t_stat sol20_show_ports(FILE *st, UNIT *uptr, int32 val, CONST void *desc) {
+ SOL20_PORT_CTX *port;
+
+ port = (SOL20_PORT_CTX *) uptr->dptr->ctxt;
+
+ fprintf(st, "I/O=0x%02X-0x%02X", port->pnp.io_base, port->pnp.io_base + port->pnp.io_size - 1);
+ return SCPE_OK;
+}
+
+static t_stat sol20_config_line(DEVICE *dev, TMLN *tmln, int baud)
+{
+ char config[20];
+ const char *fmt;
+ t_stat r = SCPE_IERR;
+
+ if (tmln->serport) {
+ fmt = "8N1";
+
+ sprintf(config, "%d-%s", baud, fmt);
+
+ r = tmxr_set_config_line(tmln, config);
+
+ sim_debug(STATUS_MSG, dev, "port configuration set to '%s'.\n", config);
+ }
+
+ return r;
+}
+
+static t_stat sol20_set_baud(UNIT *uptr, int32 value, const char *cptr, void *desc)
+{
+ int32 baud;
+ t_stat r = SCPE_ARG;
+ SOL20_PORT_CTX *port;
+
+ port = (SOL20_PORT_CTX *) uptr->dptr->ctxt;
+
+ if (!(uptr->flags & UNIT_ATT)) {
+ return SCPE_UNATT;
+ }
+
+ if (cptr != NULL) {
+ if (sscanf(cptr, "%d", &baud)) {
+ port->baud = baud;
+ r = sol20_config_line(uptr->dptr, port->tmln, port->baud);
+ }
+ }
+
+ return r;
+}
+
+static t_stat sol20_show_baud(FILE *st, UNIT *uptr, int32 value, const void *desc)
+{
+ SOL20_PORT_CTX *port;
+
+ port = (SOL20_PORT_CTX *) uptr->dptr->ctxt;
+
+ if (uptr->flags & UNIT_ATT) {
+ fprintf(st, "Baud rate: %d", port->baud);
+ }
+
+ return SCPE_OK;
+}
+
+static t_stat sol20_set_rom(UNIT *uptr, int32 val, CONST char *cptr, void *desc)
+{
+ if (!cptr) return SCPE_IERR;
+ if (!strlen(cptr)) return SCPE_ARG;
+
+ /* this assumes that the parameter has already been upcased */
+ if (!strncmp(cptr, "13", strlen(cptr))) {
+ sol20_rom = sol20_rom_13;
+ }
+ else if (!strncmp(cptr, "13C", strlen(cptr))) {
+ sol20_rom = sol20_rom_13c;
+ }
+ else if (!strncmp(cptr, "41", strlen(cptr))) {
+ sol20_rom = sol20_rom_41;
+ }
+ else {
+ return SCPE_ARG;
+ }
+
+ return SCPE_OK;
+}
+
+static t_stat sol20_show_rom(FILE *st, UNIT *uptr, int32 val, CONST void *desc)
+{
+ if (sol20_rom == sol20_rom_13) {
+ fprintf(st, "ROM=v1.3");
+ }
+ else if (sol20_rom == sol20_rom_13c) {
+ fprintf(st, "ROM=v1.3C");
+ }
+ else if (sol20_rom == sol20_rom_41) {
+ fprintf(st, "ROM=v4.1");
+ }
+ else {
+ fprintf(st, "ROM=v?.?");
+ }
+
+ return SCPE_OK;
+}
+
+/*
+ * Sets tape speed to NORMAL or FAST
+ */
+static t_stat sol20_set_tape(UNIT *uptr, int32 val, CONST char *cptr, void *desc)
+{
+ if (!cptr) return SCPE_IERR;
+ if (!strlen(cptr)) return SCPE_ARG;
+
+ /* this assumes that the parameter has already been upcased */
+ if (!strncmp(cptr, "NORMAL", strlen(cptr))) {
+ uptr->wait = SOL20_TAPE_NORMAL;
+ }
+ else if (!strncmp(cptr, "FAST", strlen(cptr))) {
+ uptr->wait = SOL20_TAPE_FAST;
+ }
+ else {
+ return SCPE_ARG;
+ }
+
+ return SCPE_OK;
+}
+
+static t_stat sol20_show_tape(FILE *st, UNIT *uptr, int32 val, CONST void *desc)
+{
+ if (uptr->wait == SOL20_TAPE_NORMAL) {
+ fprintf(st, "TAPE=NORMAL");
+ }
+ else if (uptr->wait == SOL20_TAPE_FAST) {
+ fprintf(st, "TAPE=FAST");
+ }
+
+ return SCPE_OK;
+}
+
+/*
+ * "Rewinds" a tape by seeking to th first byte of
+ * the attached file
+ */
+static t_stat sol20_rewind(UNIT *uptr)
+{
+ if (uptr->flags & UNIT_ATT && uptr->fileref != NULL) {
+ rewind(uptr->fileref);
+ sim_printf("%s: Rewound '%s'\n", uptr->dptr->name, uptr->filename);
+ }
+ else {
+ sim_messagef(SCPE_UNATT, "No tape inserted\n");
+ }
+
+ return SCPE_OK;
+}
+
+/*
+ * "Erases" a tape by truncating the attached file
+ */
+static t_stat sol20_erase(UNIT *uptr)
+{
+ if ((uptr->flags & UNIT_ATT) && (uptr->fileref != NULL)) {
+ sim_set_fsize(uptr->fileref, 0);
+ rewind(uptr->fileref);
+ sim_printf("%s: Erased '%s'\n", uptr->dptr->name, uptr->filename);
+ }
+ else {
+ sim_messagef(SCPE_UNATT, "No tape inserted\n");
+ }
+
+ return SCPE_OK;
+}
+
+/*
+ * Handles memory reads from ROM
+ */
+static int32 sol20rom(int32 addr, int32 rw, int32 data)
+{
+ return(sol20_rom[addr & SOL20_ROM_MASK]);
+}
+
+/*
+ * Handles I/O input and output
+ */
+static int32 sol20io(int32 addr, int32 rw, int32 data)
+{
+ if (rw == 0) {
+ return(sol20_io_in(addr));
+ }
+ else {
+ return(sol20_io_out(addr, data));
+ }
+}
+
+static uint8 sol20_io_in(uint32 addr)
+{
+ uint8 data = 0xff;
+
+ switch(addr & 0xff) {
+ case SOL20_SERST:
+ data = (sol20s_ctx.rdr) ? SOL20_SDR : 0x00;
+ data |= (sol20s_ctx.tbe) ? SOL20_STBE : 0x00;
+ break;
+
+ case SOL20_STAPT:
+ data = (sol20k_ctx.rdr) ? 0x00 : SOL20_KDR; /* Inverted */
+ data |= (sol20t_ctx.rdr) ? SOL20_TDR : 0x00;
+ data |= (sol20t_ctx.tbe) ? SOL20_TTBE : 0x00;
+ data |= (sol20p_ctx.rdr) ? 0x00 : SOL20_PDR; /* Inverted */
+ data |= (sol20p_ctx.tbe) ? SOL20_PXDR : 0x00;
+ break;
+
+ case SOL20_KDATA:
+ data = sol20k_ctx.rxd;
+ sol20k_ctx.rdr = FALSE;
+ break;
+
+ case SOL20_SDATA:
+ data = sol20s_ctx.rxd;
+ sol20s_ctx.rdr = FALSE;
+ break;
+
+ case SOL20_TDATA:
+ data = sol20t_ctx.rxd;
+ sol20t_ctx.rdr = FALSE;
+ break;
+
+ case SOL20_PDATA:
+ data = sol20p_ctx.rxd;
+ sol20p_ctx.rdr = FALSE;
+ break;
+
+ default:
+ sim_printf("Invalid IO Read %02x\n", addr);
+
+ sim_debug(ERROR_MSG, &sol20_dev, "READ Invalid I/O Address %02x (%02x)\n",
+ addr & 0xFF, addr & 0x01);
+ break;
+ }
+
+ return (data);
+}
+
+static uint8 sol20_io_out(uint32 addr, int32 data)
+{
+ switch(addr & 0xff) {
+ case SOL20_SDATA:
+ sol20s_ctx.txd = data;
+ sol20s_ctx.tbe = FALSE;
+ break;
+
+ case SOL20_STAPT:
+ if ((sol20t_ctx.status & SOL20_TAPE1) != (data & SOL20_TAPE1)) {
+ sim_printf("%s: Tape 1 %s\n", SOL20T_SNAME, data & SOL20_TAPE1 ? "ON" : "OFF");
+ }
+ if ((sol20t_ctx.status & SOL20_TAPE2) != (data & SOL20_TAPE2)) {
+ sim_printf("%s: Tape 2 %s\n", SOL20T_SNAME, data & SOL20_TAPE2 ? "ON" : "OFF");
+ }
+ sol20t_ctx.status = data;
+ break;
+
+ case SOL20_TDATA:
+ sol20t_ctx.txd = data;
+ sol20t_ctx.tbe = FALSE;
+ break;
+
+ case SOL20_PDATA:
+ sol20p_ctx.txd = data;
+ sol20p_ctx.tbe = FALSE;
+ break;
+
+ default:
+ sim_debug(ERROR_MSG, &sol20_dev, "WRITE Invalid I/O Address %02x (%02x)\n",
+ addr & 0xFF, addr & 0x01);
+ break;
+ }
+
+ return(0xff);
+}
+
+/*
+ * Callback routine for VDM1 device keyboard events
+ *
+ * The VDM1 device will call this function when it receives
+ * a KEYBOARD event.
+ */
+static t_stat sol20_kb_callback(SIM_KEY_EVENT *kev)
+{
+ uint8 c;
+
+ if ((c = translate_key(kev))) {
+ sol20k_ctx.rxd = c;
+ sol20k_ctx.rdr = TRUE;
+ }
+
+ return SCPE_OK;
+}
+
+#define KEY(NORMAL, SHIFTED) (shifted ? (SHIFTED) : (NORMAL))
+#define CAPS(NORMAL, SHIFTED) (shifted || caps ? (SHIFTED) : (NORMAL))
+#define CTL(NORMAL, SHIFTED, CTLED) \
+ (control ? (CTLED) : CAPS(NORMAL, SHIFTED))
+
+/*
+ * Translate KEYBOARD event keys to Sol-20 ASCII
+ */
+static uint8 translate_key(SIM_KEY_EVENT *kev)
+{
+ static t_bool shifted = FALSE;
+ static t_bool caps = FALSE;
+ static t_bool control = FALSE;
+ static t_bool erase = FALSE;
+
+ if (kev->key != SIM_KEY_F3) { /* Clear erase cassette flag */
+ erase = FALSE;
+ }
+
+ if (kev->state == SIM_KEYPRESS_UP) {
+ switch (kev->key) {
+ case SIM_KEY_SHIFT_L:
+ case SIM_KEY_SHIFT_R:
+ shifted = FALSE;
+ break;
+
+ case SIM_KEY_CTRL_L:
+ case SIM_KEY_CTRL_R:
+ control = FALSE;
+ break;
+ }
+ }
+ else { /* SIM_KEYPRESS_DOWN */
+ switch (kev->key) {
+ case SIM_KEY_SHIFT_L:
+ case SIM_KEY_SHIFT_R:
+ shifted = TRUE;
+ break;
+
+ case SIM_KEY_CAPS_LOCK:
+ caps = !caps;
+ break;
+
+ case SIM_KEY_CTRL_L:
+ case SIM_KEY_CTRL_R:
+ control = TRUE;
+ break;
+
+ case SIM_KEY_0:
+ return KEY ('0', ')');
+
+ case SIM_KEY_1:
+ return KEY ('1', '!');
+
+ case SIM_KEY_2:
+ return KEY ('2', '@');
+
+ case SIM_KEY_3:
+ return KEY ('3', '#');
+
+ case SIM_KEY_4:
+ return KEY ('4', '$');
+
+ case SIM_KEY_5:
+ return KEY ('5', '%');
+
+ case SIM_KEY_6:
+ return KEY ('6', '^');
+
+ case SIM_KEY_7:
+ return KEY ('7', '&');
+
+ case SIM_KEY_8:
+ return KEY ('8', '*');
+
+ case SIM_KEY_9:
+ return KEY ('9', '(');
+
+ case SIM_KEY_A:
+ return CTL ('a', 'A', 0x01);
+
+ case SIM_KEY_B:
+ return CTL ('b', 'B', 0x02);
+
+ case SIM_KEY_C:
+ return CTL ('c', 'C', 0x03);
+
+ case SIM_KEY_D:
+ return CTL ('d', 'D', 0x04);
+
+ case SIM_KEY_E:
+ return CTL ('e', 'E', 0x05);
+
+ case SIM_KEY_F:
+ return CTL ('f', 'F', 0x06);
+
+ case SIM_KEY_G:
+ return CTL ('g', 'G', 0x07);
+
+ case SIM_KEY_H:
+ return CTL ('h', 'H', 0x08);
+
+ case SIM_KEY_I:
+ return CTL ('i', 'I', 0x09);
+
+ case SIM_KEY_J:
+ return CTL ('j', 'J', 0x0a);
+
+ case SIM_KEY_K:
+ return CTL ('k', 'K', 0x0b);
+
+ case SIM_KEY_L:
+ return CTL ('l', 'L', 0x0c);
+
+ case SIM_KEY_M:
+ return CTL ('m', 'M', 0x0d);
+
+ case SIM_KEY_N:
+ return CTL ('n', 'N', 0x0e);
+
+ case SIM_KEY_O:
+ return CTL ('o', 'O', 0x0f);
+
+ case SIM_KEY_P:
+ return CTL ('p', 'P', 0x10);
+
+ case SIM_KEY_Q:
+ return CTL ('q', 'Q', 0x11);
+
+ case SIM_KEY_R:
+ return CTL ('r', 'R', 0x12);
+
+ case SIM_KEY_S:
+ return CTL ('s', 'S', 0x13);
+
+ case SIM_KEY_T:
+ return CTL ('t', 'T', 0x14);
+
+ case SIM_KEY_U:
+ return CTL ('u', 'U', 0x15);
+
+ case SIM_KEY_V:
+ return CTL ('v', 'V', 0x16);
+
+ case SIM_KEY_W:
+ return CTL ('w', 'W', 0x17);
+
+ case SIM_KEY_X:
+ return CTL ('x', 'X', 0x18);
+
+ case SIM_KEY_Y:
+ return CTL ('y', 'Y', 0x19);
+
+ case SIM_KEY_Z:
+ return CTL ('z', 'Z', 0x1a);
+
+ case SIM_KEY_BACKQUOTE:
+ return KEY('`', '~');
+
+ case SIM_KEY_KP_END:
+ return '1';
+
+ case SIM_KEY_KP_DOWN:
+ return '2';
+
+ case SIM_KEY_KP_PAGE_DOWN:
+ return '3';
+
+ case SIM_KEY_KP_LEFT:
+ return '4';
+
+ case SIM_KEY_KP_5:
+ return '5';
+
+ case SIM_KEY_KP_RIGHT:
+ return '6';
+
+ case SIM_KEY_KP_HOME:
+ return '7';
+
+ case SIM_KEY_KP_UP:
+ return '8';
+
+ case SIM_KEY_KP_PAGE_UP:
+ return '9';
+
+ case SIM_KEY_KP_INSERT:
+ return '0';
+
+ case SIM_KEY_MINUS:
+ return KEY ('-', '_');
+
+ case SIM_KEY_EQUALS:
+ return KEY ('=', '+');
+
+ case SIM_KEY_LEFT_BRACKET:
+ return KEY ('[', '{');
+
+ case SIM_KEY_RIGHT_BRACKET:
+ return KEY (']', '}');
+
+ case SIM_KEY_SEMICOLON:
+ return KEY (';', ':');
+
+ case SIM_KEY_SINGLE_QUOTE:
+ return KEY ('\'', '"');
+
+ case SIM_KEY_BACKSLASH:
+ case SIM_KEY_LEFT_BACKSLASH:
+ return KEY ('\\', '|');
+
+ case SIM_KEY_COMMA:
+ return KEY (',', '<');
+
+ case SIM_KEY_PERIOD:
+ return KEY ('.', '>');
+
+ case SIM_KEY_SLASH:
+ return KEY ('/', '?');
+
+ case SIM_KEY_KP_ADD:
+ return '+';
+
+ case SIM_KEY_KP_SUBTRACT:
+ return '-';
+
+ case SIM_KEY_KP_MULTIPLY:
+ return '*';
+
+ case SIM_KEY_KP_DIVIDE:
+ return '/';
+
+ case SIM_KEY_ESC:
+ return 0x1b;
+
+ case SIM_KEY_BACKSPACE:
+ case SIM_KEY_DELETE:
+ return 0x7f;
+
+ case SIM_KEY_TAB:
+ return 0x09;
+
+ case SIM_KEY_ENTER:
+ case SIM_KEY_KP_ENTER:
+ return 0x0d;
+
+ case SIM_KEY_SPACE:
+ return ' ';
+
+ case SIM_KEY_UP:
+ return 0x97;
+
+ case SIM_KEY_DOWN:
+ return 0x9a;
+
+ case SIM_KEY_LEFT:
+ return 0x81;
+
+ case SIM_KEY_RIGHT:
+ return 0x93;
+
+ case SIM_KEY_HOME:
+ return 0x8e;
+
+ case SIM_KEY_F1: /* Rewind Tape */
+ sol20_rewind(sol20t_unit);
+ break;
+
+ case SIM_KEY_F2: /* Eject Tape */
+ sol20_detach_tape(sol20t_unit);
+ break;
+
+ case SIM_KEY_F3: /* Erase Tape */
+ if (sol20t_unit->flags & UNIT_RO) {
+ sim_printf("%s: Cassette is record protected.\n", SOL20T_SNAME);
+ break;
+ }
+
+ if (erase == TRUE) {
+ sol20_erase(sol20t_unit);
+ }
+ else {
+ sim_printf("%s: Press F3 again to erase cassette.\n", SOL20T_SNAME);
+ erase = TRUE;
+ }
+ break;
+
+ case SIM_KEY_F4: /* Tape Speed */
+ sol20t_unit->wait = (sol20t_unit->wait == SOL20_TAPE_NORMAL) ? SOL20_TAPE_FAST : SOL20_TAPE_NORMAL;
+ sim_printf("%s: Tape speed = %s\n", SOL20T_SNAME, (sol20t_unit->wait == SOL20_TAPE_NORMAL) ? "NORMAL" : "FAST");
+ break;
+
+ case SIM_KEY_F5: /* Load Key */
+ return 0x8c;
+
+ case SIM_KEY_F6: /* Mode Select Key */
+ return 0x80;
+
+ case SIM_KEY_F7: /* Clear Key */
+ return 0x8b;
+
+ case SIM_KEY_F8: /* CAPS */
+ caps = !caps;
+ sim_printf("%s: CAPS Lock %s\n", caps ? "ON" : "OFF", SOL20_SNAME);
+ break;
+
+ case SIM_KEY_F10: /* Reboot */
+ PutBYTEWrapper(0x0066, 0xc3); /* JMP */
+ PutBYTEWrapper(0x0067, 0x00); /* JMP */
+ PutBYTEWrapper(0x0068, 0xc0); /* JMP */
+ nmiInterrupt = TRUE;
+ sim_printf("%s: Rebooting...\n", SOL20_SNAME);
+ break;
+
+ default:
+ sim_messagef(SCPE_OK, "Unmapped key = %02X\n", kev->key);
+ break;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Display Sol-20 function key help
+ */
+static t_stat sol20_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
+{
+ fprintf(st, "Sol-20 Function Keys:\n");
+ fprintf(st, "F1: Rewind tape\n");
+ fprintf(st, "F2: Eject tape\n");
+ fprintf(st, "F3: Erase tape\n");
+ fprintf(st, "F4: Tape speed\n");
+ fprintf(st, "F5: Load\n");
+ fprintf(st, "F6: Mode Select\n");
+ fprintf(st, "F7: Clear\n");
+ fprintf(st, "F8: CAPS lock\n");
+ fprintf(st, "F10: Reboot\n");
+
+
+ return SCPE_OK;
+}
+
diff --git a/Visual Studio Projects/AltairZ80.vcproj b/Visual Studio Projects/AltairZ80.vcproj
index 8264a028..05140572 100644
--- a/Visual Studio Projects/AltairZ80.vcproj
+++ b/Visual Studio Projects/AltairZ80.vcproj
@@ -26,7 +26,7 @@
+
+
+
+
diff --git a/makefile b/makefile
index 1cb12457..b282f0a6 100644
--- a/makefile
+++ b/makefile
@@ -164,6 +164,10 @@ ifneq (3,${SIM_MAJOR})
ifneq (,$(or $(findstring pdp6,${MAKECMDGOALS}),$(findstring pdp10-ka,${MAKECMDGOALS}),$(findstring pdp10-ki,${MAKECMDGOALS})))
VIDEO_USEFUL = true
endif
+ # building the AltairZ80 could use video support
+ ifneq (,$(findstring altairz80,${MAKECMDGOALS}))
+ VIDEO_USEFUL = true
+ endif
endif
# building the SEL32 networking can be used
ifneq (,$(findstring sel32,${MAKECMDGOALS}))
@@ -1875,6 +1879,8 @@ ALTAIR_OPT = -I ${ALTAIRD}
ALTAIRZ80D = ${SIMHD}/AltairZ80
ALTAIRZ80 = ${ALTAIRZ80D}/altairz80_cpu.c ${ALTAIRZ80D}/altairz80_cpu_nommu.c \
+ ${ALTAIRZ80D}/sol20.c \
+ ${ALTAIRZ80D}/s100_vdm1.c \
${ALTAIRZ80D}/mmd.c \
${ALTAIRZ80D}/s100_dj2d.c \
${ALTAIRZ80D}/s100_djhdc.c \
@@ -1902,7 +1908,7 @@ ALTAIRZ80 = ${ALTAIRZ80D}/altairz80_cpu.c ${ALTAIRZ80D}/altairz80_cpu_nommu.c \
${ALTAIRZ80D}/m68k/m68kopac.c ${ALTAIRZ80D}/m68k/m68kopdm.c \
${ALTAIRZ80D}/m68k/softfloat/softfloat.c \
${ALTAIRZ80D}/m68k/m68kopnz.c ${ALTAIRZ80D}/m68k/m68kops.c ${ALTAIRZ80D}/m68ksim.c
-ALTAIRZ80_OPT = -I ${ALTAIRZ80D}
+ALTAIRZ80_OPT = -I ${ALTAIRZ80D} -DUSE_SIM_VIDEO ${VIDEO_CCDEFS} $(VIDEO_LDFLAGS)
GRID = ${SIMHD}/GRI
diff --git a/sim_video.c b/sim_video.c
index b27964a3..3f519443 100644
--- a/sim_video.c
+++ b/sim_video.c
@@ -313,17 +313,19 @@ static int SDL_SavePNG_RW(SDL_Surface *surface, SDL_RWops *dst, int freedst)
*/
-#define EVENT_REDRAW 1 /* redraw event for SDL */
-#define EVENT_CLOSE 2 /* close event for SDL */
-#define EVENT_CURSOR 3 /* new cursor for SDL */
-#define EVENT_WARP 4 /* warp mouse position for SDL */
-#define EVENT_DRAW 5 /* draw/blit region for SDL */
-#define EVENT_SHOW 6 /* show SDL capabilities */
-#define EVENT_OPEN 7 /* vid_open request */
-#define EVENT_EXIT 8 /* program exit */
-#define EVENT_SCREENSHOT 9 /* produce screenshot of video window */
-#define EVENT_BEEP 10 /* audio beep */
-#define MAX_EVENTS 20 /* max events in queue */
+#define EVENT_REDRAW 1 /* redraw event for SDL */
+#define EVENT_CLOSE 2 /* close event for SDL */
+#define EVENT_CURSOR 3 /* new cursor for SDL */
+#define EVENT_WARP 4 /* warp mouse position for SDL */
+#define EVENT_DRAW 5 /* draw/blit region for SDL */
+#define EVENT_SHOW 6 /* show SDL capabilities */
+#define EVENT_OPEN 7 /* vid_open request */
+#define EVENT_EXIT 8 /* program exit */
+#define EVENT_SCREENSHOT 9 /* produce screenshot of video window */
+#define EVENT_BEEP 10 /* audio beep */
+#define EVENT_FULLSCREEN 11 /* fullscreen */
+#define EVENT_SIZE 12 /* set window size */
+#define MAX_EVENTS 20 /* max events in queue */
typedef struct {
SIM_KEY_EVENT events[MAX_EVENTS];
@@ -372,6 +374,7 @@ t_bool vid_key_state[SDL_NUM_SCANCODES];
VID_DISPLAY *next;
t_bool vid_blending;
SDL_Rect *vid_dst_last;
+SDL_Rect vid_rect;
uint32 *vid_data_last;
};
@@ -515,7 +518,7 @@ SDL_SetHint (SDL_HINT_RENDER_DRIVER, "software");
SDL_SetHint (SDL_HINT_VIDEO_ALLOW_SCREENSAVER, "1");
#endif
-status = SDL_Init (SDL_INIT_VIDEO);
+status = SDL_Init (SDL_INIT_EVENTS);
if (status) {
fprintf (stderr, "SDL Video subsystem can't initialize: %s\n", SDL_GetError ());
@@ -539,8 +542,10 @@ while (1) {
if (event.type == SDL_USEREVENT) {
if (event.user.code == EVENT_EXIT)
break;
- if (event.user.code == EVENT_OPEN)
+ if (event.user.code == EVENT_OPEN) {
+ SDL_Init (SDL_INIT_VIDEO);
vid_video_events ((VID_DISPLAY *)event.user.data1);
+ }
else {
if (event.user.code == EVENT_SHOW)
vid_show_video_event ();
@@ -1615,6 +1620,26 @@ if (SDL_SemWait (vid_mouse_events.sem) == 0) {
}
}
+void vid_set_window_size (VID_DISPLAY *vptr, int32 w, int32 h)
+{
+SDL_Event user_event;
+
+vptr->vid_rect.h = h;
+vptr->vid_rect.w = w;
+
+user_event.type = SDL_USEREVENT;
+user_event.user.windowID = vptr->vid_windowID;
+user_event.user.code = EVENT_SIZE;
+user_event.user.data1 = NULL;
+user_event.user.data2 = NULL;
+#if defined (SDL_MAIN_AVAILABLE)
+while (SDL_PushEvent (&user_event) < 0)
+ sim_os_ms_sleep (100);
+#else
+ SDL_SetWindowSize(vptr->vid_window, w, h);
+#endif
+}
+
t_bool vid_is_fullscreen_window (VID_DISPLAY *vptr)
{
return SDL_GetWindowFlags (vptr->vid_window) & SDL_WINDOW_FULLSCREEN_DESKTOP;
@@ -1627,10 +1652,22 @@ return vid_is_fullscreen_window (&vid_first);
t_stat vid_set_fullscreen_window (VID_DISPLAY *vptr, t_bool flag)
{
+SDL_Event user_event;
+
+user_event.type = SDL_USEREVENT;
+user_event.user.windowID = vptr->vid_windowID;
+user_event.user.code = EVENT_FULLSCREEN;
+user_event.user.data1 = (flag) ? vptr : NULL;
+user_event.user.data2 = NULL;
+#if defined (SDL_MAIN_AVAILABLE)
+while (SDL_PushEvent (&user_event) < 0)
+ sim_os_ms_sleep (100);
+#else
if (flag)
SDL_SetWindowFullscreen (vptr->vid_window, SDL_WINDOW_FULLSCREEN_DESKTOP);
else
SDL_SetWindowFullscreen (vptr->vid_window, 0);
+#endif
return SCPE_OK;
}
@@ -1659,6 +1696,12 @@ else {
r->x = 0;
r->y = (h - r->h) / 2;
}
+if (vptr->vid_flags & SIM_VID_IGNORE_VBAR) {
+ r->w = w;
+ r->h = h;
+ r->x = 0;
+ r->y = 0;
+ }
}
void vid_update (VID_DISPLAY *vptr)
@@ -1769,6 +1812,11 @@ if (!vptr->vid_texture) {
vptr->vid_format = SDL_AllocFormat (SDL_PIXELFORMAT_ARGB8888);
+if (vptr->vid_flags & SIM_VID_RESIZABLE) {
+ SDL_SetWindowResizable(vptr->vid_window, SDL_TRUE);
+ SDL_RenderSetIntegerScale(vptr->vid_renderer, SDL_TRUE);
+}
+
SDL_StopTextInput ();
vptr->vid_windowID = SDL_GetWindowID (vptr->vid_window);
@@ -2033,22 +2081,27 @@ while (vid_active) {
case SDL_WINDOWEVENT_EXPOSED:
vid_update (vptr);
break;
+ default:
+ sim_debug (SIM_VID_DBG_VIDEO, vptr->vid_dev, "Did not handle window event: %d - %s\n", event.window.event, windoweventtypes[event.window.event]);
+ break;
}
}
break;
case SDL_USEREVENT:
- /* There are 9 user events generated */
- /* EVENT_REDRAW to update the display */
- /* EVENT_DRAW to update a region in the display texture */
- /* EVENT_SHOW to display the current SDL video capabilities */
- /* EVENT_CURSOR to change the current cursor */
- /* EVENT_WARP to warp the cursor position */
- /* EVENT_OPEN to open a new window */
- /* EVENT_CLOSE to wake up this thread and let */
- /* it notice vid_active has changed */
- /* EVENT_SCREENSHOT to take a screenshot */
- /* EVENT_BEEP to emit a beep sound */
+ /* There are 11 user events generated */
+ /* EVENT_REDRAW to update the display */
+ /* EVENT_DRAW to update a region in the display texture */
+ /* EVENT_SHOW to display the current SDL video capabilities */
+ /* EVENT_CURSOR to change the current cursor */
+ /* EVENT_WARP to warp the cursor position */
+ /* EVENT_OPEN to open a new window */
+ /* EVENT_CLOSE to wake up this thread and let */
+ /* it notice vid_active has changed */
+ /* EVENT_SCREENSHOT to take a screenshot */
+ /* EVENT_BEEP to emit a beep sound */
+ /* EVENT_SIZE to change screen size */
+ /* EVENT_FULLSCREEN to change fullscreen */
while (vid_active && event.user.code) {
/* Handle Beep first since it isn't a window oriented event */
if (event.user.code == EVENT_BEEP) {
@@ -2059,7 +2112,7 @@ while (vid_active) {
if (event.user.code != EVENT_OPEN) {
vptr = vid_get_event_window (&event, event.user.windowID);
if (vptr == NULL) {
- sim_debug (SIM_VID_DBG_VIDEO, vptr->vid_dev, "vid_thread() - Ignored event not bound to a window\n");
+ sim_printf ("vid_thread() - Ignored event not bound to a window\n");
event.user.code = 0; /* Mark as done */
break;
}
@@ -2104,6 +2157,17 @@ while (vid_active) {
vid_screenshot_event ();
event.user.code = 0; /* Mark as done */
}
+ if (event.user.code == EVENT_SIZE) {
+ SDL_SetWindowSize (vptr->vid_window, vptr->vid_rect.w, vptr->vid_rect.h);
+ event.user.code = 0; /* Mark as done */
+ }
+ if (event.user.code == EVENT_FULLSCREEN) {
+ if (event.user.data1 != NULL)
+ SDL_SetWindowFullscreen (vptr->vid_window, SDL_WINDOW_FULLSCREEN_DESKTOP);
+ else
+ SDL_SetWindowFullscreen (vptr->vid_window, 0);
+ event.user.code = 0; /* Mark as done */
+ }
if (event.user.code == EVENT_BEEP) {
vid_beep_event ();
event.user.code = 0; /* Mark as done */
@@ -2341,6 +2405,8 @@ for (i = 0; i < SDL_GetNumRenderDrivers(); ++i) {
if (vid_active) {
SDL_RendererInfo info;
+ info.name = "";
+
for (vptr = &vid_first; vptr != NULL; vptr = vptr->next) {
if (vptr->vid_active_window) {
SDL_GetRendererInfo (vptr->vid_renderer, &info);
@@ -2820,6 +2886,11 @@ void vid_set_cursor_position_window (VID_DISPLAY *vptr, int32 x, int32 y)
return;
}
+void vid_set_window_size (VID_DISPLAY *vptr, int32 w, int32 h)
+{
+return;
+}
+
const char *vid_key_name (uint32 key)
{
return "";
diff --git a/sim_video.h b/sim_video.h
index 0d6882f1..c74eb3cb 100644
--- a/sim_video.h
+++ b/sim_video.h
@@ -189,6 +189,8 @@ typedef struct key_event SIM_KEY_EVENT;
t_stat vid_open (DEVICE *dptr, const char *title, uint32 width, uint32 height, int flags);
#define SIM_VID_INPUTCAPTURED 1 /* Mouse and Keyboard input captured (calling */
/* code responsible for cursor display in video) */
+#define SIM_VID_IGNORE_VBAR 2 /* ignore video buffer aspect ratio */
+#define SIM_VID_RESIZABLE 4 /* video screen is resizable */
typedef void (*VID_QUIT_CALLBACK)(void);
t_stat vid_register_quit_callback (VID_QUIT_CALLBACK callback);
typedef void (*VID_GAMEPAD_CALLBACK)(int, int, int);
@@ -214,6 +216,7 @@ t_stat vid_set_fullscreen (t_bool flag);
extern int vid_active;
void vid_set_cursor_position (int32 x, int32 y); /* cursor position (set by calling code) */
+void vid_set_window_size (VID_DISPLAY *vptr, int32 x, int32 y); /* window size (set by calling code) */
t_stat vid_open_window (VID_DISPLAY **vptr, DEVICE *dptr, const char *title, uint32 width, uint32 height, int flags);
t_stat vid_close_window (VID_DISPLAY *vptr);