mirror of
https://github.com/simh/simh.git
synced 2026-01-25 19:56:25 +00:00
Altair8800: New DAZZLER, PMMI devices and other features
Adds Cromemco DAZZLER video device Adds PMMI MM-103 modem device Adds SET RAM PROT/UNPROT=pages Adds Martin Eberhard's CDBL ROM Corrects file format for cromemco and pmmi header files.
This commit is contained in:
@@ -74,6 +74,8 @@ DEVICE *sim_devices[] = {
|
||||
&m2sio0_dev,
|
||||
&m2sio1_dev,
|
||||
&acr_dev,
|
||||
&daz_dev,
|
||||
&pmmi_dev,
|
||||
&sio_dev,
|
||||
&sbc200_dev,
|
||||
&tarbell_dev,
|
||||
|
||||
@@ -48,6 +48,8 @@ extern DEVICE mdsk_dev;
|
||||
extern DEVICE m2sio0_dev;
|
||||
extern DEVICE m2sio1_dev;
|
||||
extern DEVICE acr_dev;
|
||||
extern DEVICE daz_dev;
|
||||
extern DEVICE pmmi_dev;
|
||||
extern DEVICE sio_dev;
|
||||
extern DEVICE sbc200_dev;
|
||||
extern DEVICE tarbell_dev;
|
||||
|
||||
615
Altair8800/cromemco_dazzler.c
Normal file
615
Altair8800/cromemco_dazzler.c
Normal file
@@ -0,0 +1,615 @@
|
||||
/* cromemco_dazzler.c: Cromemco DAZZLER and JS-1 Joystick
|
||||
|
||||
Copyright (c) 2026 Patrick A. 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
|
||||
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.
|
||||
|
||||
History:
|
||||
18-Jan-2026 Initial version
|
||||
|
||||
==================================================================
|
||||
|
||||
This device simulates the Cromemco Dazzler and D+7A with JS-1 Joystick
|
||||
Console.
|
||||
|
||||
*/
|
||||
|
||||
#include "sim_defs.h"
|
||||
#include "sim_video.h"
|
||||
#include "altair8800_defs.h"
|
||||
#include "s100_bus.h"
|
||||
#include "s100_cpu.h"
|
||||
#include "cromemco_dazzler.h"
|
||||
|
||||
/*
|
||||
** Public VID_DISPLAY for other devices that may want
|
||||
** to access the video display directly, such as joystick
|
||||
** events.
|
||||
*/
|
||||
VID_DISPLAY *daz_vptr = NULL;
|
||||
|
||||
static t_bool daz_0e = 0x00;
|
||||
static t_bool daz_0f = 0x80;
|
||||
static uint32 daz_addr = 0x0000;
|
||||
static t_bool daz_frame = 0x3f;
|
||||
static uint8 daz_resolution = 32;
|
||||
static uint16 daz_pages = 1;
|
||||
static uint16 daz_window_width = 640;
|
||||
static uint16 daz_window_height = 640;
|
||||
static uint16 daz_screen_width = 32;
|
||||
static uint16 daz_screen_height = 32;
|
||||
static uint16 daz_screen_pixels = 32 * 32;
|
||||
static uint8 daz_color = 0;
|
||||
static uint32 daz_surface[DAZ_PIXELS];
|
||||
static uint32 daz_cpalette[16];
|
||||
static uint32 daz_gpalette[16];
|
||||
|
||||
#define DAZ_SHOW_VIDEO(b) (b & DAZ_ON) ? "ON" : "OFF"
|
||||
#define DAZ_SHOW_RES(b) (b & DAZ_RESX4) ? "X4" : "NORMAL"
|
||||
#define DAZ_SHOW_MEMSIZE(b) (b & DAZ_2K) ? "2K" : "512"
|
||||
#define DAZ_SHOW_COLOR(b) (b & DAZ_COLOR) ? "COLOR" : "B/W"
|
||||
|
||||
extern t_stat exdep_cmd(int32 flag, CONST char *cptr);
|
||||
|
||||
static const char *daz_description(DEVICE *dptr);
|
||||
static t_stat daz_svc(UNIT *uptr);
|
||||
static t_stat daz_reset(DEVICE *dptr);
|
||||
static t_stat daz_boot(int32 unitno, DEVICE *dptr);
|
||||
static void daz_set_0f(uint8 val);
|
||||
static t_stat daz_set_video(UNIT *uptr, int32 val, CONST char *cptr, void *desc);
|
||||
static t_stat daz_show_video(FILE *st, UNIT *uptr, int32 val, CONST void *desc);
|
||||
static t_stat daz_set_resolution(UNIT *uptr, int32 val, CONST char *cptr, void *desc);
|
||||
static t_stat daz_show_resolution(FILE *st, UNIT *uptr, int32 val, CONST void *desc);
|
||||
static t_stat daz_set_memsize(UNIT *uptr, int32 val, CONST char *cptr, void *desc);
|
||||
static t_stat daz_show_memsize(FILE *st, UNIT *uptr, int32 val, CONST void *desc);
|
||||
static t_stat daz_set_color(UNIT *uptr, int32 val, CONST char *cptr, void *desc);
|
||||
static t_stat daz_show_color(FILE *st, UNIT *uptr, int32 val, CONST void *desc);
|
||||
static int32 daz_io(const int32 port, const int32 io, const int32 data);
|
||||
static t_stat daz_open_video(void);
|
||||
static t_stat daz_close_video(void);
|
||||
static void daz_resize_video(void);
|
||||
static void daz_refresh(void);
|
||||
static void daz_render_normal(void);
|
||||
static void daz_render_x4(void);
|
||||
static int32 daz_quad_surfacex(int q);
|
||||
static int32 daz_quad_surfacey(int q);
|
||||
static t_stat daz_show_help(FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr);
|
||||
|
||||
/* Debug flags */
|
||||
#define VERBOSE_MSG (1 << 0)
|
||||
|
||||
/*
|
||||
DAZZLER data structures
|
||||
|
||||
daz_dev DAZ device descriptor
|
||||
daz_unit DAZ unit descriptor
|
||||
daz_reg DAZ register list
|
||||
*/
|
||||
|
||||
static RES daz_res = { DAZ_IO_BASE, DAZ_IO_SIZE, 0 ,0, NULL };
|
||||
|
||||
static UNIT daz_unit = {
|
||||
UDATA (&daz_svc, 0, 0), 33000 /* 30 fps */
|
||||
};
|
||||
|
||||
static REG daz_reg[] = {
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
static DEBTAB daz_debug[] = {
|
||||
{ "VERBOSE", VERBOSE_MSG, "Verbose messages" },
|
||||
{ "JOYSTICK", SIM_VID_DBG_JOYSTICK, "Joystick messages" },
|
||||
{ "VIDEO", SIM_VID_DBG_VIDEO, "Video messages" },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
static MTAB daz_mod[] = {
|
||||
{ MTAB_XTD|MTAB_VDV, 0, "VIDEO", "VIDEO",
|
||||
&daz_set_video, &daz_show_video, NULL, "DAZZLER Video [ ON | OFF ]" },
|
||||
{ MTAB_XTD|MTAB_VDV, 0, "IOBASE", "IOBASE",
|
||||
&set_iobase, &show_iobase, NULL, "DAZZLER Base I/O Address" },
|
||||
{ MTAB_XTD|MTAB_VDV, 0, "MEMSIZE", "MEMSIZE",
|
||||
&daz_set_memsize, &daz_show_memsize, NULL, "DAZZLER Memory Size [ 512 | 2K ]" },
|
||||
{ MTAB_XTD|MTAB_VDV, 0, "RESOLUTION", "RESOLUTION",
|
||||
&daz_set_resolution, &daz_show_resolution, NULL, "DAZZLER Resolution [ NORMAL | HIGH ]" },
|
||||
{ MTAB_XTD|MTAB_VDV, 0, "COLOR", "COLOR",
|
||||
&daz_set_color, &daz_show_color, NULL, "DAZZLER Color [ BW | COLOR ]" },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
DEVICE daz_dev = {
|
||||
"DAZZLER", &daz_unit, daz_reg, daz_mod,
|
||||
1, ADDRRADIX, ADDRWIDTH, 1, DATARADIX, DATAWIDTH,
|
||||
NULL, NULL, &daz_reset,
|
||||
&daz_boot, NULL, NULL,
|
||||
&daz_res, DEV_DEBUG | DEV_DIS | DEV_DISABLE, 0,
|
||||
daz_debug, NULL, NULL, &daz_show_help, NULL, NULL,
|
||||
&daz_description
|
||||
};
|
||||
|
||||
/*
|
||||
DAZZLER routines
|
||||
|
||||
daz_description
|
||||
daz_svc
|
||||
daz_reset
|
||||
*/
|
||||
static const char *daz_description (DEVICE *dptr)
|
||||
{
|
||||
return "Cromemco Dazzler";
|
||||
}
|
||||
|
||||
static t_stat daz_svc(UNIT *uptr)
|
||||
{
|
||||
daz_refresh();
|
||||
|
||||
sim_activate_after_abs(uptr, uptr->wait);
|
||||
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
static t_stat daz_reset(DEVICE *dptr)
|
||||
{
|
||||
t_stat r = SCPE_OK;
|
||||
|
||||
if (dptr->flags & DEV_DIS) {
|
||||
s100_bus_remio(daz_res.io_base, daz_res.io_size, &daz_io);
|
||||
|
||||
sim_cancel(&daz_unit);
|
||||
|
||||
if (daz_vptr != NULL) {
|
||||
return daz_close_video();
|
||||
}
|
||||
} else {
|
||||
s100_bus_addio(daz_res.io_base, daz_res.io_size, &daz_io, "DAZZLER");
|
||||
|
||||
if (daz_vptr == NULL) {
|
||||
daz_open_video();
|
||||
} else {
|
||||
sim_activate_after_abs(&daz_unit, daz_unit.wait);
|
||||
}
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static t_stat daz_boot(int32 unitno, DEVICE *dptr)
|
||||
{
|
||||
ChipType chiptype = cpu_get_chiptype();
|
||||
|
||||
if (chiptype == CHIP_TYPE_8080) {
|
||||
exdep_cmd(EX_D, "-m 100 MVI A,01H");
|
||||
exdep_cmd(EX_D, "-m 102 ORI 80H");
|
||||
exdep_cmd(EX_D, "-m 104 OUT 0EH");
|
||||
exdep_cmd(EX_D, "-m 106 MVI A,10H");
|
||||
exdep_cmd(EX_D, "-m 108 OUT 0FH");
|
||||
exdep_cmd(EX_D, "-m 10A LXI H,200H");
|
||||
exdep_cmd(EX_D, "-m 10D MVI C,32");
|
||||
exdep_cmd(EX_D, "-m 10F MVI B,16");
|
||||
exdep_cmd(EX_D, "-m 111 XRA A");
|
||||
exdep_cmd(EX_D, "-m 112 MOV M,A");
|
||||
exdep_cmd(EX_D, "-m 113 ADI 11H");
|
||||
exdep_cmd(EX_D, "-m 115 INX H");
|
||||
exdep_cmd(EX_D, "-m 116 DCR B");
|
||||
exdep_cmd(EX_D, "-m 117 JNZ 112H");
|
||||
exdep_cmd(EX_D, "-m 11A DCR C");
|
||||
exdep_cmd(EX_D, "-m 11B JNZ 10FH");
|
||||
exdep_cmd(EX_D, "-m 11E JMP 11EH");
|
||||
} else if (chiptype == CHIP_TYPE_Z80) {
|
||||
exdep_cmd(EX_D, "-m 100 LD A,01H");
|
||||
exdep_cmd(EX_D, "-m 102 OR 80H");
|
||||
exdep_cmd(EX_D, "-m 104 OUT (0EH),A");
|
||||
exdep_cmd(EX_D, "-m 106 LD A,10H");
|
||||
exdep_cmd(EX_D, "-m 108 OUT (0FH),A");
|
||||
exdep_cmd(EX_D, "-m 10A LD HL,200H");
|
||||
exdep_cmd(EX_D, "-m 10D LD C,32");
|
||||
exdep_cmd(EX_D, "-m 10F LD B,16");
|
||||
exdep_cmd(EX_D, "-m 111 XOR A");
|
||||
exdep_cmd(EX_D, "-m 112 LD (HL),A");
|
||||
exdep_cmd(EX_D, "-m 113 ADD A,11H");
|
||||
exdep_cmd(EX_D, "-m 115 INC HL");
|
||||
exdep_cmd(EX_D, "-m 116 DEC B");
|
||||
exdep_cmd(EX_D, "-m 117 JP NZ,112H");
|
||||
exdep_cmd(EX_D, "-m 11A DEC C");
|
||||
exdep_cmd(EX_D, "-m 11B JP NZ,10FH");
|
||||
exdep_cmd(EX_D, "-m 11E JP 11EH");
|
||||
}
|
||||
|
||||
*((int32 *) sim_PC->loc) = 0x0100;
|
||||
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
static int32 daz_io(const int32 port, const int32 io, const int32 data)
|
||||
{
|
||||
int32 p = port - daz_res.io_base;
|
||||
|
||||
if (io == 0) { /* IN */
|
||||
switch (p) {
|
||||
case 0x00: /* 0E */
|
||||
daz_frame = 0x7f;
|
||||
if ((sim_os_msec() % 30) > 25) {
|
||||
daz_frame &= ~DAZ_EOF;
|
||||
} else {
|
||||
daz_frame |= (sim_os_msec() & 1) ? 0x00 : DAZ_EVEN;
|
||||
}
|
||||
|
||||
return daz_frame;
|
||||
|
||||
case 0x01: /* 0F */
|
||||
sim_debug(VERBOSE_MSG, &daz_dev, "Unspecified IN 0x%02X\n", port);
|
||||
break;
|
||||
}
|
||||
} else { /* OUT */
|
||||
switch (p) {
|
||||
case 0x00: /* 0E */
|
||||
daz_0e = data;
|
||||
daz_addr = (data & 0x7f) << 9;
|
||||
|
||||
sim_debug(VERBOSE_MSG, &daz_dev, "New video address 0x%04X Video is %s\n", daz_addr, daz_0e & DAZ_ON ? "ON" : "OFF");
|
||||
break;
|
||||
|
||||
case 0x01: /* 0F */
|
||||
daz_set_0f(data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
static t_stat daz_open_video(void)
|
||||
{
|
||||
t_stat r = SCPE_OK;
|
||||
int i;
|
||||
|
||||
if (daz_vptr == NULL) {
|
||||
sim_debug(VERBOSE_MSG, &daz_dev, "Opening new video window w:%d h:%d\n", daz_window_width, daz_window_height);
|
||||
|
||||
r = vid_open_window(&daz_vptr, &daz_dev, "Display", daz_window_width, daz_window_height, SIM_VID_IGNORE_VBAR | SIM_VID_RESIZABLE); /* video buffer size */
|
||||
|
||||
if (r != SCPE_OK) {
|
||||
sim_printf("Could not open video window r=%X\n", r);
|
||||
return r;
|
||||
}
|
||||
|
||||
daz_resize_video();
|
||||
|
||||
daz_cpalette[0] = vid_map_rgb_window(daz_vptr, 0x00, 0x00, 0x00);
|
||||
daz_cpalette[1] = vid_map_rgb_window(daz_vptr, 0x80, 0x00, 0x00);
|
||||
daz_cpalette[2] = vid_map_rgb_window(daz_vptr, 0x00, 0x80, 0x00);
|
||||
daz_cpalette[3] = vid_map_rgb_window(daz_vptr, 0x80, 0x80, 0x00);
|
||||
daz_cpalette[4] = vid_map_rgb_window(daz_vptr, 0x00, 0x00, 0x80);
|
||||
daz_cpalette[5] = vid_map_rgb_window(daz_vptr, 0x80, 0x00, 0x80);
|
||||
daz_cpalette[6] = vid_map_rgb_window(daz_vptr, 0x00, 0x80, 0x80);
|
||||
daz_cpalette[7] = vid_map_rgb_window(daz_vptr, 0x80, 0x80, 0x80);
|
||||
daz_cpalette[8] = vid_map_rgb_window(daz_vptr, 0x00, 0x00, 0x00);
|
||||
daz_cpalette[9] = vid_map_rgb_window(daz_vptr, 0xff, 0x00, 0x00);
|
||||
daz_cpalette[10] = vid_map_rgb_window(daz_vptr, 0x00, 0xff, 0x00);
|
||||
daz_cpalette[11] = vid_map_rgb_window(daz_vptr, 0xff, 0xff, 0x00);
|
||||
daz_cpalette[12] = vid_map_rgb_window(daz_vptr, 0x00, 0x00, 0xff);
|
||||
daz_cpalette[13] = vid_map_rgb_window(daz_vptr, 0xff, 0x00, 0xff);
|
||||
daz_cpalette[14] = vid_map_rgb_window(daz_vptr, 0x00, 0xff, 0xff);
|
||||
daz_cpalette[15] = vid_map_rgb_window(daz_vptr, 0xff, 0xff, 0xff);
|
||||
daz_gpalette[0] = vid_map_rgb_window(daz_vptr, 0x00, 0x00, 0x00);
|
||||
daz_gpalette[1] = vid_map_rgb_window(daz_vptr, 0x10, 0x10, 0x10);
|
||||
daz_gpalette[2] = vid_map_rgb_window(daz_vptr, 0x20, 0x20, 0x20);
|
||||
daz_gpalette[3] = vid_map_rgb_window(daz_vptr, 0x30, 0x30, 0x30);
|
||||
daz_gpalette[4] = vid_map_rgb_window(daz_vptr, 0x40, 0x40, 0x40);
|
||||
daz_gpalette[5] = vid_map_rgb_window(daz_vptr, 0x50, 0x50, 0x50);
|
||||
daz_gpalette[6] = vid_map_rgb_window(daz_vptr, 0x60, 0x60, 0x60);
|
||||
daz_gpalette[7] = vid_map_rgb_window(daz_vptr, 0x70, 0x70, 0x70);
|
||||
daz_gpalette[8] = vid_map_rgb_window(daz_vptr, 0x80, 0x80, 0x80);
|
||||
daz_gpalette[9] = vid_map_rgb_window(daz_vptr, 0x90, 0x90, 0x90);
|
||||
daz_gpalette[10] = vid_map_rgb_window(daz_vptr, 0xa0, 0xa0, 0xa0);
|
||||
daz_gpalette[11] = vid_map_rgb_window(daz_vptr, 0xb0, 0xb0, 0xb0);
|
||||
daz_gpalette[12] = vid_map_rgb_window(daz_vptr, 0xc0, 0xc0, 0xc0);
|
||||
daz_gpalette[13] = vid_map_rgb_window(daz_vptr, 0xd0, 0xd0, 0xd0);
|
||||
daz_gpalette[14] = vid_map_rgb_window(daz_vptr, 0xe0, 0xe0, 0xe0);
|
||||
daz_gpalette[15] = vid_map_rgb_window(daz_vptr, 0xff, 0xff, 0xff);
|
||||
|
||||
for (i = 0; i < daz_screen_pixels; i++) {
|
||||
daz_surface[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
sim_activate_after_abs(&daz_unit, daz_unit.wait);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static t_stat daz_close_video(void)
|
||||
{
|
||||
t_stat r;
|
||||
|
||||
sim_debug(VERBOSE_MSG, &daz_dev, "Closing video window\n");
|
||||
|
||||
if ((r = vid_close_window(daz_vptr)) == SCPE_OK) {
|
||||
sim_cancel(&daz_unit);
|
||||
|
||||
daz_vptr = NULL;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static void daz_resize_video(void)
|
||||
{
|
||||
if (daz_vptr != NULL) {
|
||||
vid_render_set_logical_size(daz_vptr, daz_screen_width, daz_screen_height);
|
||||
if (!sim_is_running) {
|
||||
daz_refresh();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Draw and refresh the screen in the video window
|
||||
*/
|
||||
static void daz_refresh(void) {
|
||||
if (daz_vptr != NULL) {
|
||||
if (daz_0f & DAZ_RESX4) {
|
||||
daz_render_x4();
|
||||
} else {
|
||||
daz_render_normal();
|
||||
}
|
||||
vid_draw_window(daz_vptr, 0, 0, daz_screen_width, daz_screen_height, daz_surface);
|
||||
vid_refresh_window(daz_vptr);
|
||||
}
|
||||
}
|
||||
|
||||
static void daz_render_normal(void)
|
||||
{
|
||||
int q, x, y;
|
||||
int32 maddr = daz_addr;
|
||||
int32 saddr = 0;
|
||||
|
||||
for (q = 0; q < daz_pages; q++) {
|
||||
for (y = daz_quad_surfacey(q); y < daz_quad_surfacey(q) + 32; y++) {
|
||||
for (x = daz_quad_surfacex(q); x < daz_quad_surfacex(q) + 32; x+= 2) {
|
||||
saddr = (y * daz_resolution) + x;
|
||||
if (!(daz_0e & DAZ_ON)) {
|
||||
daz_surface[saddr] = 0x00;
|
||||
daz_surface[saddr+1] = 0x00;
|
||||
} else if (daz_0f & DAZ_COLOR) {
|
||||
daz_surface[saddr] = daz_cpalette[s100_bus_memr(maddr) & 0x0f];
|
||||
daz_surface[saddr+1] = daz_cpalette[(s100_bus_memr(maddr) & 0xf0) >> 4];
|
||||
} else {
|
||||
daz_surface[saddr] = daz_gpalette[s100_bus_memr(maddr) & 0x0f];
|
||||
daz_surface[saddr+1] = daz_gpalette[(s100_bus_memr(maddr) & 0xf0) >> 4];
|
||||
}
|
||||
maddr++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void daz_render_x4(void)
|
||||
{
|
||||
int b, q, x, y;
|
||||
int32 maddr = daz_addr;
|
||||
int32 saddr = 0;
|
||||
int32 soffset[] = {0, 1, daz_resolution, daz_resolution + 1, 2, 3, daz_resolution + 2, daz_resolution + 3};
|
||||
uint32 color;
|
||||
|
||||
if (daz_0f & DAZ_COLOR) {
|
||||
color = daz_cpalette[daz_color];
|
||||
} else {
|
||||
color = daz_gpalette[daz_color];
|
||||
}
|
||||
|
||||
for (q = 0; q < daz_pages; q++) {
|
||||
for (y = daz_quad_surfacey(q); y < daz_quad_surfacey(q) + 64; y+=2) {
|
||||
for (x = daz_quad_surfacex(q); x < daz_quad_surfacex(q) + 64; x += 4) {
|
||||
saddr = (y * daz_resolution) + x;
|
||||
for (b = 0; b < 8; b++) {
|
||||
if (daz_0e & DAZ_ON) {
|
||||
daz_surface[saddr + soffset[b]] = (s100_bus_memr(maddr) & (1 << b)) ? color : 0;
|
||||
} else {
|
||||
daz_surface[saddr + soffset[b]] = 0x00;
|
||||
}
|
||||
}
|
||||
maddr++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int32 daz_quad_surfacex(int q)
|
||||
{
|
||||
if (q == 1 || q == 3) {
|
||||
return daz_resolution / ((daz_0f & DAZ_RESX4) ? 2 : 2);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32 daz_quad_surfacey(int q)
|
||||
{
|
||||
if (q == 2 || q == 3) {
|
||||
return daz_resolution / ((daz_0f & DAZ_RESX4) ? 2 : 2);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void daz_set_0f(uint8 val) {
|
||||
uint8 old = daz_0f;
|
||||
|
||||
/* Update daz_0f register */
|
||||
daz_0f = val;
|
||||
daz_color = daz_0f & 0x0f;
|
||||
|
||||
/* Did resolution change? */
|
||||
if ((daz_0f & (DAZ_RESX4 | DAZ_2K)) != (old & (DAZ_RESX4 | DAZ_2K))) {
|
||||
daz_resolution = 32;
|
||||
daz_pages = 1;
|
||||
if (daz_0f & DAZ_RESX4) {
|
||||
daz_resolution *= 2;
|
||||
}
|
||||
if (daz_0f & DAZ_2K) {
|
||||
daz_pages = 4;
|
||||
daz_resolution *= 2;
|
||||
}
|
||||
|
||||
sim_debug(VERBOSE_MSG, &daz_dev, "Setting resolution to %02X %dx%d (%d pages) %s %s\n",
|
||||
daz_0f, daz_resolution, daz_resolution, daz_pages, DAZ_SHOW_RES(daz_0f), DAZ_SHOW_MEMSIZE(daz_0f));
|
||||
|
||||
daz_screen_width = daz_resolution;
|
||||
daz_screen_height = daz_resolution;
|
||||
daz_screen_pixels = daz_screen_width * daz_screen_height;
|
||||
|
||||
daz_resize_video();
|
||||
}
|
||||
|
||||
if (!sim_is_running) {
|
||||
daz_refresh();
|
||||
}
|
||||
}
|
||||
|
||||
static t_stat daz_set_video(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, "OFF", strlen(cptr))) {
|
||||
daz_0e &= ~DAZ_ON;
|
||||
} else if (!strncmp(cptr, "ON", strlen(cptr))) {
|
||||
daz_0e |= DAZ_ON;
|
||||
} else {
|
||||
return SCPE_ARG;
|
||||
}
|
||||
|
||||
if (!sim_is_running) {
|
||||
daz_refresh();
|
||||
}
|
||||
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
static t_stat daz_show_video(FILE *st, UNIT *uptr, int32 val, CONST void *desc) {
|
||||
if (!st) return SCPE_IERR;
|
||||
|
||||
fprintf(st, "VIDEO=%s", DAZ_SHOW_VIDEO(daz_0e));
|
||||
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
static t_stat daz_set_resolution(UNIT *uptr, int32 val, CONST char *cptr, void *desc)
|
||||
{
|
||||
uint8 old = daz_0f;
|
||||
|
||||
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))) {
|
||||
old &= ~DAZ_RESX4;
|
||||
} else if (!strncmp(cptr, "HIGH", strlen(cptr))) {
|
||||
old |= DAZ_RESX4;
|
||||
} else {
|
||||
return SCPE_ARG;
|
||||
}
|
||||
|
||||
daz_set_0f(old);
|
||||
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
static t_stat daz_show_resolution(FILE *st, UNIT *uptr, int32 val, CONST void *desc) {
|
||||
if (!st) return SCPE_IERR;
|
||||
|
||||
fprintf(st, "RES=%s", DAZ_SHOW_RES(daz_0f));
|
||||
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
static t_stat daz_set_memsize(UNIT *uptr, int32 val, CONST char *cptr, void *desc)
|
||||
{
|
||||
uint8 old = daz_0f;
|
||||
|
||||
if (!cptr) return SCPE_IERR;
|
||||
if (!strlen(cptr)) return SCPE_ARG;
|
||||
|
||||
/* this assumes that the parameter has already been upcased */
|
||||
if (!strncmp(cptr, "512", strlen(cptr))) {
|
||||
old &= ~DAZ_2K;
|
||||
} else if (!strncmp(cptr, "2K", strlen(cptr))) {
|
||||
old |= DAZ_2K;
|
||||
} else {
|
||||
return SCPE_ARG;
|
||||
}
|
||||
|
||||
daz_set_0f(old);
|
||||
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
static t_stat daz_show_memsize(FILE *st, UNIT *uptr, int32 val, CONST void *desc) {
|
||||
if (!st) return SCPE_IERR;
|
||||
|
||||
fprintf(st, "MEMSIZE=%s @ %04X", DAZ_SHOW_MEMSIZE(daz_0f), daz_addr);
|
||||
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
static t_stat daz_set_color(UNIT *uptr, int32 val, CONST char *cptr, void *desc)
|
||||
{
|
||||
uint8 old = daz_0f;
|
||||
|
||||
if (!cptr) return SCPE_IERR;
|
||||
if (!strlen(cptr)) return SCPE_ARG;
|
||||
|
||||
/* this assumes that the parameter has already been upcased */
|
||||
if (!strncmp(cptr, "BW", strlen(cptr))) {
|
||||
old &= ~DAZ_COLOR;
|
||||
} else if (!strncmp(cptr, "COLOR", strlen(cptr))) {
|
||||
old |= DAZ_COLOR;
|
||||
} else {
|
||||
return SCPE_ARG;
|
||||
}
|
||||
|
||||
daz_set_0f(old);
|
||||
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
static t_stat daz_show_color(FILE *st, UNIT *uptr, int32 val, CONST void *desc) {
|
||||
if (!st) return SCPE_IERR;
|
||||
|
||||
fprintf(st, "%s", DAZ_SHOW_COLOR(daz_0f));
|
||||
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
static t_stat daz_show_help(FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
|
||||
{
|
||||
fprintf (st, "\nCROMEMCO DAZZLER (%s)\n", dptr->name);
|
||||
|
||||
fprint_set_help (st, dptr);
|
||||
fprint_show_help (st, dptr);
|
||||
fprint_reg_help (st, dptr);
|
||||
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
56
Altair8800/cromemco_dazzler.h
Normal file
56
Altair8800/cromemco_dazzler.h
Normal file
@@ -0,0 +1,56 @@
|
||||
/* cromemco_dazzler.h
|
||||
|
||||
Copyright (c) 2026 Patrick A. 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
|
||||
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.
|
||||
|
||||
History:
|
||||
01/18/26 Initial version
|
||||
|
||||
*/
|
||||
|
||||
#ifndef _CROMEMCO_DAZZLER_H
|
||||
#define _CROMEMCO_DAZZLER_H
|
||||
|
||||
|
||||
#define DAZ_PIXELS (128 * 128) /* total number of pixels */
|
||||
|
||||
#define DAZ_IO_BASE 0x0e
|
||||
#define DAZ_IO_SIZE 2
|
||||
#define DAZ_MEM_SIZE 2048
|
||||
#define DAZ_MEM_MASK (2048 - 1)
|
||||
|
||||
#define DAZ_ON 0x80 /* On/Off */
|
||||
#define DAZ_RESX4 0x40 /* Resolution X 4 */
|
||||
#define DAZ_2K 0x20 /* Picture in 2K bytes of memory */
|
||||
#define DAZ_COLOR 0x10 /* Picture in 2K bytes of memory */
|
||||
#define DAZ_HIGH 0x08 /* High intensity color */
|
||||
#define DAZ_BLUE 0x04 /* Blue */
|
||||
#define DAZ_GREEN 0x02 /* Green */
|
||||
#define DAZ_RED 0x01 /* Red */
|
||||
#define DAZ_EOF 0x40 /* End of Frame */
|
||||
#define DAZ_EVEN 0x80 /* Even Line */
|
||||
|
||||
extern VID_DISPLAY *daz_vptr;
|
||||
|
||||
#endif
|
||||
|
||||
705
Altair8800/pmmi_mm103.c
Normal file
705
Altair8800/pmmi_mm103.c
Normal file
@@ -0,0 +1,705 @@
|
||||
/* pmmi_mm103: PMMI MM-103 MODEM
|
||||
|
||||
Copyright (c) 2026 Patrick A. 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
|
||||
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.
|
||||
|
||||
History:
|
||||
18-Jan-2026 Initial version
|
||||
|
||||
==================================================================
|
||||
|
||||
This device emulates a PMMI Communications MM-103 Modem & Communications
|
||||
adapter.
|
||||
|
||||
The MM-103 uses 4 input and 4 output addresses. This driver defaults to
|
||||
E0-E3 hex.
|
||||
|
||||
The MM-103 uses the Motorola MC6860L digital modem chip. This device does
|
||||
not have the ability to emulate the modulation and demodulation functions
|
||||
or the ability to connect to a phone line. All modem features, such as
|
||||
switch hook, dial tone detection, and dialing, are emulated in such a way
|
||||
that most software written for the MM-103 should function in some useful
|
||||
fashion.
|
||||
|
||||
To provide any useful functionality, this device needs to be attached to
|
||||
a socket or serial port. Enter "HELP PMMI" at the "simh>" prompt for
|
||||
additional information.
|
||||
*/
|
||||
|
||||
#include "sim_defs.h"
|
||||
#include "sim_tmxr.h"
|
||||
#include "altair8800_defs.h"
|
||||
#include "s100_bus.h"
|
||||
#include "pmmi_mm103.h"
|
||||
|
||||
#define DEVICE_DESC "PMMI MM-103 MODEM"
|
||||
#define DEVICE_NAME "PMMI"
|
||||
|
||||
static int32 poc = TRUE; /* Power On Clear */
|
||||
|
||||
/* Debug flags */
|
||||
#define STATUS_MSG (1 << 0)
|
||||
#define ERROR_MSG (1 << 1)
|
||||
#define VERBOSE_MSG (1 << 2)
|
||||
|
||||
typedef struct {
|
||||
int32 conn; /* Connected Status */
|
||||
int32 baud; /* Baud rate */
|
||||
int32 dtr; /* DTR Status */
|
||||
int32 txp; /* Transmit Pending */
|
||||
int32 stb; /* Status Buffer */
|
||||
int32 ireg0; /* In Register 0 */
|
||||
int32 ireg1; /* In Register 1 */
|
||||
int32 ireg2; /* In Register 2 */
|
||||
int32 ireg3; /* In Register 3 */
|
||||
int32 oreg0; /* Out Register 0 */
|
||||
int32 oreg1; /* Out Register 1 */
|
||||
int32 oreg2; /* Out Register 2 */
|
||||
int32 oreg3; /* Out Register 3 */
|
||||
int32 intmsk; /* Interrupt Mask */
|
||||
uint32 ptimer; /* Next Pulse Timer */
|
||||
uint32 dtimer; /* Next DT Timer */
|
||||
uint32 flags; /* Original Flags */
|
||||
} PMMI_CTX;
|
||||
|
||||
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 uint32 sim_map_resource(uint32 baseaddr, uint32 size, uint32 resource_type,
|
||||
int32 (*routine)(const int32, const int32, const int32), const char* name, uint8 unmap);
|
||||
|
||||
|
||||
static const char* pmmi_description(DEVICE *dptr);
|
||||
static t_stat pmmi_svc(UNIT *uptr);
|
||||
static t_stat pmmi_reset(DEVICE *dptr);
|
||||
static t_stat pmmi_attach(UNIT *uptr, CONST char *cptr);
|
||||
static t_stat pmmi_detach(UNIT *uptr);
|
||||
static t_stat pmmi_set_baud(UNIT *uptr, int32 value, const char *cptr, void *desc);
|
||||
static t_stat pmmi_show_baud(FILE *st, UNIT *uptr, int32 value, const void *desc);
|
||||
static t_stat pmmi_config_line(UNIT *uptr);
|
||||
static int32 pmmi_io(int32 addr, int32 io, int32 data);
|
||||
static int32 pmmi_reg0(int32 io, int32 data);
|
||||
static int32 pmmi_reg1(int32 io, int32 data);
|
||||
static int32 pmmi_reg2(int32 io, int32 data);
|
||||
static int32 pmmi_reg3(int32 io, int32 data);
|
||||
static t_stat pmmi_set_console(UNIT *uptr, int32 value, const char *cptr, void *desc);
|
||||
static t_stat pmmi_show_help(FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr);
|
||||
|
||||
/* Debug Flags */
|
||||
static DEBTAB pmmi_dt[] = {
|
||||
{ "STATUS", STATUS_MSG, "Status messages" },
|
||||
{ "ERROR", ERROR_MSG, "Error messages" },
|
||||
{ "VERBOSE", VERBOSE_MSG, "Verbose messages" },
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
/* Terminal multiplexer library descriptors */
|
||||
|
||||
static TMLN pmmi_tmln[] = { /* line descriptors */
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
|
||||
static TMXR pmmi_tmxr = { /* multiplexer descriptor */
|
||||
1, /* number of terminal lines */
|
||||
0, /* listening port (reserved) */
|
||||
0, /* master socket (reserved) */
|
||||
pmmi_tmln, /* line descriptor array */
|
||||
NULL, /* line connection order */
|
||||
NULL /* multiplexer device (derived internally) */
|
||||
};
|
||||
|
||||
static RES pmmi_res = { PMMI_IOBASE, PMMI_IOSIZE, 0, 0, &pmmi_tmxr };
|
||||
|
||||
static MTAB pmmi_mod[] = {
|
||||
{ MTAB_XTD|MTAB_VDV, 0, "IOBASE", "IOBASE",
|
||||
&set_iobase, &show_iobase, NULL, "Sets MITS 2SIO base I/O address" },
|
||||
{ UNIT_PMMI_RTS, UNIT_PMMI_RTS, "RTS", "RTS", NULL, NULL, NULL,
|
||||
"RTS follows DTR (default)" },
|
||||
{ UNIT_PMMI_RTS, 0, "NORTS", "NORTS", NULL, NULL, NULL,
|
||||
"RTS does not follow DTR" },
|
||||
{ MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "BAUD", "BAUD", &pmmi_set_baud, &pmmi_show_baud,
|
||||
NULL, "Set baud rate (default=300)" },
|
||||
|
||||
{ MTAB_XTD | MTAB_VUN, UNIT_PMMI_CONSOLE, NULL, "CONSOLE", &pmmi_set_console, NULL, NULL, "Set as CONSOLE" },
|
||||
{ MTAB_XTD | MTAB_VUN, 0, NULL, "NOCONSOLE", &pmmi_set_console, NULL, NULL, "Remove as CONSOLE" },
|
||||
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
static PMMI_CTX pmmi_ctx = { 0, PMMI_BAUD, 1 };
|
||||
|
||||
static UNIT pmmi_unit[] = {
|
||||
{ UDATA (&pmmi_svc, UNIT_ATTABLE | UNIT_DISABLE | UNIT_PMMI_RTS, 0), PMMI_WAIT },
|
||||
};
|
||||
|
||||
static REG pmmi_reg[] = {
|
||||
{ HRDATAD (IREG0, pmmi_ctx.ireg0, 8, "PMMI input register 0"), },
|
||||
{ HRDATAD (IREG1, pmmi_ctx.ireg1, 8, "PMMI input register 1"), },
|
||||
{ HRDATAD (IREG2, pmmi_ctx.ireg2, 8, "PMMI input register 2"), },
|
||||
{ HRDATAD (IREG3, pmmi_ctx.ireg3, 8, "PMMI input register 3"), },
|
||||
{ HRDATAD (OREG0, pmmi_ctx.oreg0, 8, "PMMI output register 0"), },
|
||||
{ HRDATAD (OREG1, pmmi_ctx.oreg1, 8, "PMMI output register 1"), },
|
||||
{ HRDATAD (OREG2, pmmi_ctx.oreg2, 8, "PMMI output register 2"), },
|
||||
{ HRDATAD (OREG3, pmmi_ctx.oreg3, 8, "PMMI output register 3"), },
|
||||
{ HRDATAD (TXP, pmmi_ctx.txp, 8, "PMMI tx data pending"), },
|
||||
{ FLDATAD (CON, pmmi_ctx.conn, 0, "PMMI connection status"), },
|
||||
{ DRDATAD (BAUD, pmmi_ctx.baud, 8, "PMMI calculated baud rate"), },
|
||||
{ HRDATAD (INTMSK, pmmi_ctx.intmsk, 8, "PMMI interrupt mask"), },
|
||||
{ FLDATAD (TBMT, pmmi_ctx.ireg0, 0, "PMMI TBMT status"), },
|
||||
{ FLDATAD (DAV, pmmi_ctx.ireg0, 1, "PMMI DAV status"), },
|
||||
{ FLDATAD (OR, pmmi_ctx.ireg0, 4, "PMMI OVRN status"), },
|
||||
{ FLDATAD (DT, pmmi_ctx.ireg2, 0, "PMMI dial tone status (active low)"), },
|
||||
{ FLDATAD (RNG, pmmi_ctx.ireg2, 1, "PMMI ringing status (active low)"), },
|
||||
{ FLDATAD (CTS, pmmi_ctx.ireg2, 2, "PMMI CTS status (active low)"), },
|
||||
{ FLDATAD (AP, pmmi_ctx.ireg2, 0, "PMMI answer phone status (active low)"), },
|
||||
{ FLDATAD (PULSE, pmmi_ctx.ireg2, 7, "PMMI timer pulse"), },
|
||||
{ DRDATAD (TIMER, pmmi_ctx.ptimer, 32, "PMMI timer pulse ms"), },
|
||||
{ DRDATAD (WAIT, pmmi_unit[0].wait, 32, "PMMI wait cycles"), },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
DEVICE pmmi_dev = {
|
||||
DEVICE_NAME, /* name */
|
||||
pmmi_unit, /* unit */
|
||||
pmmi_reg, /* registers */
|
||||
pmmi_mod, /* modifiers */
|
||||
1, /* # units */
|
||||
ADDRRADIX, /* address radix */
|
||||
ADDRWIDTH, /* address width */
|
||||
1, /* address increment */
|
||||
DATARADIX, /* data radix */
|
||||
DATAWIDTH, /* data width */
|
||||
NULL, /* examine routine */
|
||||
NULL, /* deposit routine */
|
||||
&pmmi_reset, /* reset routine */
|
||||
NULL, /* boot routine */
|
||||
&pmmi_attach, /* attach routine */
|
||||
&pmmi_detach, /* detach routine */
|
||||
&pmmi_res, /* context */
|
||||
(DEV_DISABLE | DEV_DIS | DEV_DEBUG | DEV_MUX), /* flags */
|
||||
0, /* debug control */
|
||||
pmmi_dt, /* debug flags */
|
||||
NULL, /* mem size routine */
|
||||
NULL, /* logical name */
|
||||
&pmmi_show_help, /* help */
|
||||
NULL, /* attach help */
|
||||
NULL, /* context for help */
|
||||
&pmmi_description /* description */
|
||||
};
|
||||
|
||||
static const char* pmmi_description(DEVICE *dptr)
|
||||
{
|
||||
return DEVICE_DESC;
|
||||
}
|
||||
|
||||
static t_stat pmmi_reset(DEVICE *dptr)
|
||||
{
|
||||
if (dptr->flags & DEV_DIS) { /* Disable Device */
|
||||
s100_bus_remio(pmmi_res.io_base, pmmi_res.io_size, &pmmi_io);
|
||||
|
||||
poc = TRUE;
|
||||
}
|
||||
else {
|
||||
if (poc) {
|
||||
s100_bus_addio(pmmi_res.io_base, pmmi_res.io_size, &pmmi_io, DEVICE_NAME);
|
||||
|
||||
poc = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Set DEVICE for this UNIT */
|
||||
dptr->units[0].dptr = dptr;
|
||||
|
||||
/* Enable TMXR modem control passthrough */
|
||||
tmxr_set_modem_control_passthru(pmmi_res.tmxr);
|
||||
|
||||
/* Reset status registers */
|
||||
pmmi_ctx.ireg0 = 0;
|
||||
pmmi_ctx.ireg1 = 0;
|
||||
pmmi_ctx.ireg2 = PMMI_RNG | PMMI_CTS | PMMI_DT | PMMI_AP;
|
||||
pmmi_ctx.ireg3 = 0;
|
||||
pmmi_ctx.oreg0 = 0;
|
||||
pmmi_ctx.oreg1 = 0;
|
||||
pmmi_ctx.oreg2 = 0;
|
||||
pmmi_ctx.oreg3 = 0;
|
||||
pmmi_ctx.txp = 0;
|
||||
pmmi_ctx.intmsk = 0;
|
||||
pmmi_ctx.ptimer = sim_os_msec() + 40;
|
||||
pmmi_ctx.dtimer = 0;
|
||||
|
||||
if (!(dptr->flags & DEV_DIS)) {
|
||||
sim_activate(&dptr->units[0], dptr->units[0].wait);
|
||||
} else {
|
||||
sim_cancel(&dptr->units[0]);
|
||||
}
|
||||
|
||||
sim_debug(STATUS_MSG, dptr, "reset adapter.\n");
|
||||
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
static t_stat pmmi_svc(UNIT *uptr)
|
||||
{
|
||||
int32 c,s,ireg2;
|
||||
t_stat r = SCPE_OK;
|
||||
uint32 ms;
|
||||
|
||||
/* Check for new incoming connection */
|
||||
if (uptr->flags & UNIT_ATT) {
|
||||
if (tmxr_poll_conn(pmmi_res.tmxr) >= 0) { /* poll connection */
|
||||
|
||||
/* Clear DTR and RTS if serial port */
|
||||
if (pmmi_res.tmxr->ldsc->serport) {
|
||||
s = TMXR_MDM_DTR | ((pmmi_dev.units[0].flags & UNIT_PMMI_RTS) ? TMXR_MDM_RTS : 0);
|
||||
tmxr_set_get_modem_bits(pmmi_res.tmxr->ldsc, 0, s, NULL);
|
||||
}
|
||||
|
||||
pmmi_res.tmxr->ldsc->rcve = 1; /* Enable receiver */
|
||||
pmmi_ctx.conn = 1; /* set connected */
|
||||
|
||||
sim_debug(STATUS_MSG, uptr->dptr, "new connection.\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* Update incoming modem status bits */
|
||||
if (uptr->flags & UNIT_ATT) {
|
||||
tmxr_set_get_modem_bits(pmmi_res.tmxr->ldsc, 0, 0, &s);
|
||||
|
||||
ireg2 = pmmi_ctx.ireg2;
|
||||
pmmi_ctx.ireg2 &= ~PMMI_CTS;
|
||||
pmmi_ctx.ireg2 |= (s & TMXR_MDM_CTS) ? 0 : PMMI_CTS; /* Active Low */
|
||||
|
||||
/* CTS status changed */
|
||||
if ((ireg2 ^ pmmi_ctx.ireg2) & PMMI_CTS) {
|
||||
if (pmmi_ctx.ireg2 & PMMI_CTS) { /* If no CTS, set AP bit */
|
||||
pmmi_ctx.ireg2 |= PMMI_AP; /* Answer Phone Bit (active low) */
|
||||
}
|
||||
sim_debug(STATUS_MSG, uptr->dptr, "CTS state changed to %s.\n", (pmmi_ctx.ireg2 & PMMI_CTS) ? "LOW" : "HIGH");
|
||||
}
|
||||
|
||||
pmmi_ctx.ireg2 &= ~PMMI_RNG;
|
||||
pmmi_ctx.ireg2 |= (s & TMXR_MDM_RNG) ? 0 : PMMI_RNG; /* Active Low */
|
||||
|
||||
/* RNG status changed */
|
||||
if ((ireg2 ^ pmmi_ctx.ireg2) & PMMI_RNG) {
|
||||
/* Answer Phone Bit on RI */
|
||||
if (!(pmmi_ctx.ireg2 & PMMI_RNG)) {
|
||||
pmmi_ctx.ireg2 &= ~PMMI_AP; /* Answer Phone Bit (active low) */
|
||||
}
|
||||
|
||||
sim_debug(STATUS_MSG, uptr->dptr, "RNG state changed to %s.\n", (pmmi_ctx.ireg2 & PMMI_RNG) ? "LOW" : "HIGH");
|
||||
}
|
||||
|
||||
/* Enable receiver if CTS is active low */
|
||||
pmmi_res.tmxr->ldsc->rcve = !(pmmi_ctx.ireg2 & PMMI_CTS);
|
||||
|
||||
/* If socket, connection status follows CTS */
|
||||
if (!pmmi_res.tmxr->ldsc->serport) {
|
||||
pmmi_ctx.conn = !(pmmi_ctx.ireg2 & PMMI_CTS);
|
||||
}
|
||||
}
|
||||
|
||||
/* TX data */
|
||||
if (pmmi_ctx.txp) {
|
||||
if (uptr->flags & UNIT_ATT) {
|
||||
/*
|
||||
** If CTS active low, send byte
|
||||
** otherwise, toss character
|
||||
*/
|
||||
if (!(pmmi_ctx.ireg2 & PMMI_CTS)) {
|
||||
r = tmxr_putc_ln(pmmi_res.tmxr->ldsc, pmmi_ctx.oreg1);
|
||||
}
|
||||
pmmi_ctx.txp = 0; /* Reset TX Pending */
|
||||
} else {
|
||||
r = sim_putchar(pmmi_ctx.oreg1);
|
||||
pmmi_ctx.txp = 0; /* Reset TX Pending */
|
||||
}
|
||||
|
||||
if (r == SCPE_LOST) {
|
||||
pmmi_ctx.conn = 0; /* Connection was lost */
|
||||
sim_debug(STATUS_MSG, uptr->dptr, "lost connection.\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* Update TBMT if not set and no character pending */
|
||||
if (!pmmi_ctx.txp && !(pmmi_ctx.ireg0 & PMMI_TBMT)) {
|
||||
if (uptr->flags & UNIT_ATT) {
|
||||
tmxr_poll_tx(pmmi_res.tmxr);
|
||||
pmmi_ctx.ireg0 |= (tmxr_txdone_ln(pmmi_res.tmxr->ldsc) && pmmi_ctx.conn) ? (PMMI_TBMT | PMMI_TEOC) : 0;
|
||||
} else {
|
||||
pmmi_ctx.ireg0 |= (PMMI_TBMT | PMMI_TEOC);
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for Data if RX buffer empty */
|
||||
if (!(pmmi_ctx.ireg0 & PMMI_DAV)) {
|
||||
if (uptr->flags & UNIT_ATT) {
|
||||
tmxr_poll_rx(pmmi_res.tmxr);
|
||||
|
||||
c = tmxr_getc_ln(pmmi_res.tmxr->ldsc);
|
||||
} else {
|
||||
c = s100_bus_poll_kbd(uptr);
|
||||
}
|
||||
|
||||
if (c & (TMXR_VALID | SCPE_KFLAG)) {
|
||||
pmmi_ctx.ireg1 = c & 0xff;
|
||||
pmmi_ctx.ireg0 |= PMMI_DAV;
|
||||
pmmi_ctx.ireg0 &= ~(PMMI_FE | PMMI_OR | PMMI_RPE);
|
||||
}
|
||||
}
|
||||
|
||||
/* Timer Pulses */
|
||||
ms = sim_os_msec();
|
||||
|
||||
if (ms > pmmi_ctx.ptimer) {
|
||||
if (pmmi_ctx.oreg2) {
|
||||
if (pmmi_ctx.ireg2 & PMMI_TMR) {
|
||||
pmmi_ctx.ireg2 &= ~PMMI_TMR;
|
||||
pmmi_ctx.ptimer = sim_os_msec() + 600 / (PMMI_CLOCK / pmmi_ctx.oreg2); /* 60% off */
|
||||
} else {
|
||||
pmmi_ctx.ireg2 |= PMMI_TMR;
|
||||
pmmi_ctx.ptimer = sim_os_msec() + 400 / (PMMI_CLOCK / pmmi_ctx.oreg2); /* 40% on */
|
||||
}
|
||||
} else {
|
||||
pmmi_ctx.ptimer = sim_os_msec() + 100; /* default to 100ms if timer rate is 0 */
|
||||
}
|
||||
}
|
||||
|
||||
/* Emulate dial tone */
|
||||
if ((ms > pmmi_ctx.dtimer) && (pmmi_ctx.oreg0 & PMMI_SH) && (pmmi_ctx.ireg2 & PMMI_DT)) {
|
||||
pmmi_ctx.ireg2 &= ~PMMI_DT;
|
||||
sim_debug(STATUS_MSG, uptr->dptr, "dial tone active.\n");
|
||||
}
|
||||
|
||||
/* Don't let TMXR clobber our wait time */
|
||||
uptr->wait = PMMI_WAIT;
|
||||
|
||||
sim_activate_abs(uptr, uptr->wait);
|
||||
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
|
||||
/* Attach routine */
|
||||
static t_stat pmmi_attach(UNIT *uptr, CONST char *cptr)
|
||||
{
|
||||
t_stat r;
|
||||
|
||||
sim_debug(VERBOSE_MSG, uptr->dptr, "attach (%s).\n", cptr);
|
||||
|
||||
if ((r = tmxr_attach(pmmi_res.tmxr, uptr, cptr)) == SCPE_OK) {
|
||||
|
||||
pmmi_ctx.flags = uptr->flags; /* Save Flags */
|
||||
|
||||
if (!pmmi_res.tmxr->ldsc->serport) {
|
||||
uptr->flags |= UNIT_PMMI_RTS; /* Force following DTR on sockets */
|
||||
}
|
||||
|
||||
pmmi_res.tmxr->ldsc->rcve = 1;
|
||||
|
||||
sim_activate(uptr, uptr->wait);
|
||||
|
||||
sim_debug(VERBOSE_MSG, uptr->dptr, "activated service.\n");
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Detach routine */
|
||||
static t_stat pmmi_detach(UNIT *uptr)
|
||||
{
|
||||
sim_debug(VERBOSE_MSG, uptr->dptr, "detach.\n");
|
||||
|
||||
if (uptr->flags & UNIT_ATT) {
|
||||
uptr->flags = pmmi_ctx.flags; /* Restore Flags */
|
||||
|
||||
sim_cancel(uptr);
|
||||
|
||||
return (tmxr_detach(pmmi_res.tmxr, uptr));
|
||||
}
|
||||
|
||||
return SCPE_UNATT;
|
||||
}
|
||||
|
||||
static t_stat pmmi_set_baud(UNIT *uptr, int32 value, const char *cptr, void *desc)
|
||||
{
|
||||
int32 baud;
|
||||
t_stat r = SCPE_ARG;
|
||||
|
||||
if (!(uptr->flags & UNIT_ATT)) {
|
||||
return SCPE_UNATT;
|
||||
}
|
||||
|
||||
if (cptr != NULL) {
|
||||
if (sscanf(cptr, "%d", &baud)) {
|
||||
if (baud >= 61 && baud <=600) {
|
||||
pmmi_ctx.baud = baud;
|
||||
r = pmmi_config_line(uptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static t_stat pmmi_show_baud(FILE *st, UNIT *uptr, int32 value, const void *desc)
|
||||
{
|
||||
if (uptr->flags & UNIT_ATT) {
|
||||
fprintf(st, "Baud rate: %d", pmmi_ctx.baud);
|
||||
}
|
||||
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
static t_stat pmmi_config_line(UNIT *uptr)
|
||||
{
|
||||
char config[20];
|
||||
char b,p,s;
|
||||
t_stat r = SCPE_IERR;
|
||||
|
||||
switch (pmmi_ctx.oreg0 & PMMI_BMSK) {
|
||||
case PMMI_5BIT:
|
||||
b = '5';
|
||||
break;
|
||||
|
||||
case PMMI_6BIT:
|
||||
b = '6';
|
||||
break;
|
||||
|
||||
case PMMI_7BIT:
|
||||
b = '7';
|
||||
break;
|
||||
|
||||
case PMMI_8BIT:
|
||||
default:
|
||||
b = '8';
|
||||
break;
|
||||
}
|
||||
|
||||
switch (pmmi_ctx.oreg0 & PMMI_PMSK) {
|
||||
case PMMI_OPAR:
|
||||
p = 'O';
|
||||
break;
|
||||
|
||||
case PMMI_EPAR:
|
||||
p = 'E';
|
||||
break;
|
||||
|
||||
case PMMI_NPAR:
|
||||
default:
|
||||
p = 'N';
|
||||
break;
|
||||
}
|
||||
|
||||
switch (pmmi_ctx.oreg0 & PMMI_SMSK) {
|
||||
case PMMI_2SB:
|
||||
s = '2';
|
||||
break;
|
||||
|
||||
case PMMI_1SB:
|
||||
default:
|
||||
s = '1';
|
||||
break;
|
||||
}
|
||||
|
||||
sprintf(config, "%d-%c%c%c", pmmi_ctx.baud, b,p,s);
|
||||
|
||||
sim_debug(STATUS_MSG, uptr->dptr, "setting port configuration to '%s'.\n", config);
|
||||
|
||||
r = tmxr_set_config_line(pmmi_res.tmxr->ldsc, config);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int32 pmmi_io(int32 addr, int32 io, int32 data)
|
||||
{
|
||||
int32 r = 0;
|
||||
|
||||
addr &= 0xff;
|
||||
data &= 0xff;
|
||||
|
||||
if (io == S100_IO_WRITE) {
|
||||
sim_debug(VERBOSE_MSG, &pmmi_dev, "OUT %02X,%02X\n", addr , data);
|
||||
} else {
|
||||
sim_debug(VERBOSE_MSG, &pmmi_dev, "IN %02X\n", addr);
|
||||
}
|
||||
|
||||
switch (addr & 0x03) {
|
||||
case PMMI_REG0:
|
||||
r = pmmi_reg0(io, data);
|
||||
break;
|
||||
|
||||
case PMMI_REG1:
|
||||
r = pmmi_reg1(io, data);
|
||||
break;
|
||||
|
||||
case PMMI_REG2:
|
||||
r = pmmi_reg2(io, data);
|
||||
break;
|
||||
|
||||
case PMMI_REG3:
|
||||
r = pmmi_reg3(io, data);
|
||||
break;
|
||||
}
|
||||
|
||||
return(r);
|
||||
}
|
||||
|
||||
static int32 pmmi_reg0(int32 io, int32 data)
|
||||
{
|
||||
int32 r;
|
||||
|
||||
if (io == S100_IO_READ) {
|
||||
r = pmmi_ctx.ireg0;
|
||||
} else { pmmi_ctx.oreg0 = data; /* Set UART configuration */
|
||||
pmmi_config_line(&pmmi_dev.units[0]);
|
||||
|
||||
if (data & PMMI_SH) { /* If off-hook, clear dial tone bit (active low) */
|
||||
pmmi_ctx.dtimer = sim_os_msec() + 500; /* Dial tone in 500ms */
|
||||
if (pmmi_ctx.oreg0 & PMMI_SH) {
|
||||
pmmi_ctx.ireg2 &= ~PMMI_AP; /* Answer Phone Bit (active low) */
|
||||
}
|
||||
} else if (!(pmmi_ctx.ireg2 & PMMI_DT)) {
|
||||
pmmi_ctx.dtimer = 0;
|
||||
pmmi_ctx.ireg2 |= PMMI_DT;
|
||||
sim_debug(STATUS_MSG, &pmmi_dev, "dial tone inactive.\n");
|
||||
}
|
||||
|
||||
if (data & PMMI_RI) { /* Go off-hook in answer mode */
|
||||
pmmi_ctx.ireg2 &= ~PMMI_AP; /* Answer Phone Bit (active low) */
|
||||
}
|
||||
|
||||
r = 0x00;
|
||||
}
|
||||
|
||||
return(r);
|
||||
}
|
||||
|
||||
static int32 pmmi_reg1(int32 io, int32 data)
|
||||
{
|
||||
int32 r;
|
||||
|
||||
if (io == S100_IO_READ) {
|
||||
r = pmmi_ctx.ireg1;
|
||||
pmmi_ctx.ireg0 &= ~(PMMI_DAV | PMMI_FE | PMMI_OR | PMMI_RPE);
|
||||
} else {
|
||||
pmmi_ctx.oreg1 = data;
|
||||
pmmi_ctx.ireg0 &= ~(PMMI_TBMT | PMMI_TEOC);
|
||||
pmmi_ctx.txp = 1;
|
||||
|
||||
r = 0x00;
|
||||
}
|
||||
|
||||
return(r);
|
||||
}
|
||||
|
||||
static int32 pmmi_reg2(int32 io, int32 data)
|
||||
{
|
||||
int32 r;
|
||||
|
||||
if (io == S100_IO_READ) {
|
||||
r = pmmi_ctx.ireg2;
|
||||
} else {
|
||||
pmmi_ctx.oreg2 = data;
|
||||
|
||||
/*
|
||||
** The actual baud rate is determined by the following:
|
||||
** Rate = 250,000/(Reg X 16) where Reg = the binary
|
||||
** value loaded into the rate generator.
|
||||
*/
|
||||
if (data) {
|
||||
pmmi_ctx.baud = 250000/(data * 16);
|
||||
|
||||
pmmi_config_line(&pmmi_dev.units[0]);
|
||||
}
|
||||
|
||||
r = 0x00;
|
||||
}
|
||||
|
||||
return(r);
|
||||
}
|
||||
|
||||
static int32 pmmi_reg3(int32 io, int32 data)
|
||||
{
|
||||
int32 s;
|
||||
|
||||
if (io == S100_IO_READ) {
|
||||
pmmi_ctx.intmsk = pmmi_ctx.oreg2; /* Load int mask from rate generator */
|
||||
} else {
|
||||
pmmi_ctx.oreg3 = data;
|
||||
/* Set/Clear DTR */
|
||||
s = TMXR_MDM_DTR | ((pmmi_dev.units[0].flags & UNIT_PMMI_RTS) ? TMXR_MDM_RTS : 0);
|
||||
if (data & PMMI_DTR) {
|
||||
sim_debug(STATUS_MSG, &pmmi_dev, "setting DTR HIGH.\n");
|
||||
tmxr_set_get_modem_bits(pmmi_res.tmxr->ldsc, s, 0, NULL);
|
||||
if (pmmi_ctx.oreg0 & PMMI_SH) {
|
||||
pmmi_ctx.ireg2 &= ~PMMI_AP; /* Answer Phone Bit (active low) */
|
||||
}
|
||||
} else {
|
||||
sim_debug(STATUS_MSG, &pmmi_dev, "setting DTR LOW.\n");
|
||||
tmxr_set_get_modem_bits(pmmi_res.tmxr->ldsc, 0, s, NULL);
|
||||
pmmi_ctx.ireg2 |= PMMI_AP;
|
||||
}
|
||||
}
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
static t_stat pmmi_set_console(UNIT *uptr, int32 value, const char *cptr, void *desc)
|
||||
{
|
||||
if (value == UNIT_PMMI_CONSOLE) {
|
||||
s100_bus_console(uptr);
|
||||
}
|
||||
else {
|
||||
s100_bus_noconsole(uptr);
|
||||
}
|
||||
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
static t_stat pmmi_show_help(FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
|
||||
{
|
||||
fprintf (st, "\nPMMI MM-103 (%s)\n", dptr->name);
|
||||
|
||||
fprint_set_help (st, dptr);
|
||||
fprint_show_help (st, dptr);
|
||||
fprint_reg_help (st, dptr);
|
||||
fprintf(st, "\n\n");
|
||||
tmxr_attach_help(st, dptr, uptr, flag, cptr);
|
||||
|
||||
fprintf(st, "----- NOTES -----\n\n");
|
||||
fprintf(st, "Only one device may poll the host keyboard for CONSOLE input.\n");
|
||||
fprintf(st, "Use SET %s CONSOLE to select this UNIT as the CONSOLE device.\n", sim_dname(dptr));
|
||||
fprintf(st, "\nUse SHOW BUS CONSOLE to display the current CONSOLE device.\n\n");
|
||||
|
||||
fprintf(st, "This device may be attached to a serial port on the host computer\n");
|
||||
fprintf(st, "with the ATTACH command:\n\n");
|
||||
fprintf(st, " sim> ATTACH %s CONNECT=/dev/tty.usbserial-AB0NW409\n\n", sim_dname(dptr));
|
||||
|
||||
fprintf(st, "This device may also be attached to a TCP/IP port on the host computer\n");
|
||||
fprintf(st, "with the ATTACH command. The following will listen for a connection\n");
|
||||
fprintf(st, "on port 8800:\n\n");
|
||||
fprintf(st, " sim> ATTACH %s 8800\n", sim_dname(dptr));
|
||||
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
93
Altair8800/pmmi_mm103.h
Normal file
93
Altair8800/pmmi_mm103.h
Normal file
@@ -0,0 +1,93 @@
|
||||
/* pmmi_mm103.h
|
||||
|
||||
Copyright (c) 2026 Patrick A. 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
|
||||
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.
|
||||
|
||||
History:
|
||||
01/18/26 Initial version
|
||||
|
||||
*/
|
||||
|
||||
#ifndef _PMMI_MM103_H
|
||||
#define _PMMI_MM103_H
|
||||
|
||||
|
||||
#define UNIT_V_PMMI_VERBOSE (UNIT_V_UF + 0) /* Verbose messages */
|
||||
#define UNIT_PMMI_VERBOSE (1 << UNIT_V_PMMI_VERBOSE)
|
||||
#define UNIT_V_PMMI_CONSOLE (UNIT_V_UF + 1) /* Use this device for console */
|
||||
#define UNIT_PMMI_CONSOLE (1 << UNIT_V_PMMI_CONSOLE)
|
||||
#define UNIT_V_PMMI_RTS (UNIT_V_UF + 2) /* RTS follows DTR */
|
||||
#define UNIT_PMMI_RTS (1 << UNIT_V_PMMI_RTS)
|
||||
|
||||
#define PMMI_WAIT 500 /* Service Wait Interval */
|
||||
|
||||
#define PMMI_IOBASE 0xC0
|
||||
#define PMMI_IOSIZE 4
|
||||
|
||||
#define PMMI_REG0 0 /* Relative Address 0 */
|
||||
#define PMMI_REG1 1 /* Relative Address 1 */
|
||||
#define PMMI_REG2 2 /* Relative Address 2 */
|
||||
#define PMMI_REG3 3 /* Relative Address 3 */
|
||||
|
||||
#define PMMI_TBMT 0x01 /* Transmit Data Register Empty */
|
||||
#define PMMI_DAV 0x02 /* Receive Data Register Full */
|
||||
#define PMMI_TEOC 0x04 /* Transmit Serializer Empty */
|
||||
#define PMMI_RPE 0x08 /* Parity Error */
|
||||
#define PMMI_OR 0x10 /* Overrun */
|
||||
#define PMMI_FE 0x20 /* Framing Error */
|
||||
|
||||
#define PMMI_DT 0x01 /* Dial Tone */
|
||||
#define PMMI_RNG 0x02 /* Ringing */
|
||||
#define PMMI_CTS 0x04 /* Clear to Send */
|
||||
#define PMMI_RXBRK 0x08 /* RX Break */
|
||||
#define PMMI_AP 0x10 /* Answer Phone */
|
||||
#define PMMI_FO 0x20 /* Digital Carrier Signal */
|
||||
#define PMMI_MODE 0x40 /* Mode */
|
||||
#define PMMI_TMR 0x80 /* Timer Pulses */
|
||||
|
||||
#define PMMI_ST 0x10 /* Self Test */
|
||||
#define PMMI_DTR 0x40 /* DTR */
|
||||
|
||||
#define PMMI_SH 0x01 /* Switch Hook */
|
||||
#define PMMI_RI 0x02 /* Ring Indicator */
|
||||
#define PMMI_5BIT 0x00 /* 5 Data Bits */
|
||||
#define PMMI_6BIT 0x04 /* 6 Data Bits */
|
||||
#define PMMI_7BIT 0x08 /* 7 Data Bits */
|
||||
#define PMMI_8BIT 0x0C /* 8 Data Bits */
|
||||
#define PMMI_BMSK 0x0C /* Data Bits Bit Mask */
|
||||
|
||||
#define PMMI_OPAR 0x00 /* Odd Parity */
|
||||
#define PMMI_NPAR 0x10 /* No Parity */
|
||||
#define PMMI_EPAR 0x20 /* Odd Parity */
|
||||
#define PMMI_PMSK 0x30 /* Parity Bit Mask */
|
||||
|
||||
#define PMMI_1SB 0x00 /* 1 Stop Bit */
|
||||
#define PMMI_15SB 0x40 /* 1.5 Stop Bits */
|
||||
#define PMMI_2SB 0x40 /* 2 Stop Bits */
|
||||
#define PMMI_SMSK 0x40 /* Stop Bits Bit Mask */
|
||||
|
||||
#define PMMI_CLOCK 2500 /* Rate Generator / 100 */
|
||||
#define PMMI_BAUD 300 /* Default baud rate */
|
||||
|
||||
#endif
|
||||
|
||||
@@ -45,8 +45,6 @@ static t_stat bus_hexsave_command (int32 flag, const char *cptr);
|
||||
static t_stat hexload (const char *filename, t_addr bias);
|
||||
static t_stat hexsave (FILE *outFile, t_addr start, t_addr end);
|
||||
|
||||
static ChipType chiptype = CHIP_TYPE_Z80;
|
||||
|
||||
static MDEV mdev_table[MAXPAGE]; /* Active memory table */
|
||||
static MDEV mdev_dflt; /* Default memory table */
|
||||
|
||||
@@ -413,18 +411,6 @@ void s100_bus_memw(t_addr addr, int32 data)
|
||||
mdev_table[page].routine(addr, S100_IO_WRITE, data);
|
||||
}
|
||||
|
||||
ChipType s100_bus_set_chiptype(ChipType new)
|
||||
{
|
||||
chiptype = new;
|
||||
|
||||
return chiptype;
|
||||
}
|
||||
|
||||
ChipType s100_bus_get_chiptype(void)
|
||||
{
|
||||
return chiptype;
|
||||
}
|
||||
|
||||
uint32 s100_bus_set_addr(uint32 new)
|
||||
{
|
||||
bus_addr = new;
|
||||
|
||||
@@ -159,6 +159,11 @@ void cpu_set_chiptype(ChipType new_type)
|
||||
cpu_reset(&cpu_dev);
|
||||
}
|
||||
|
||||
ChipType cpu_get_chiptype()
|
||||
{
|
||||
return cpu_type;
|
||||
}
|
||||
|
||||
char * cpu_get_chipname(ChipType type)
|
||||
{
|
||||
return cpu_chipname[type];
|
||||
|
||||
@@ -56,6 +56,7 @@ typedef struct {
|
||||
} CPU;
|
||||
|
||||
extern void cpu_set_chiptype(ChipType type);
|
||||
extern ChipType cpu_get_chiptype(void);
|
||||
extern char * cpu_get_chipname(ChipType type);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -41,6 +41,7 @@ static t_stat ram_default_dis (UNIT *uptr, int32 value, const char *cptr,
|
||||
static t_stat ram_set_memsize (int32 value);
|
||||
static t_stat ram_clear_command (UNIT *uptr, int32 value, const char *cptr, void *desc);
|
||||
static t_stat ram_enable_command (UNIT *uptr, int32 value, const char *cptr, void *desc);
|
||||
static t_stat ram_prot_command (UNIT *uptr, int32 value, const char *cptr, void *desc);
|
||||
static t_stat ram_randomize_command (UNIT *uptr, int32 value, const char *cptr, void *desc);
|
||||
static t_stat ram_size_command (UNIT *uptr, int32 value, const char *cptr, void *desc);
|
||||
static void ram_clear (void);
|
||||
@@ -54,7 +55,7 @@ static uint32 GetBYTE(register uint32 Addr);
|
||||
static int32 poc = TRUE; /* Power On Clear */
|
||||
|
||||
static int32 M[MAXBANKSIZE]; /* RAM */
|
||||
static int32 P[MAXBANKSIZE >> LOG2PAGESIZE]; /* Active pages */
|
||||
static int32 P[MAXBANKSIZE >> LOG2PAGESIZE]; /* Protected pages */
|
||||
static int32 memsize = MAXBANKSIZE;
|
||||
|
||||
static const char* ram_description(DEVICE *dptr) {
|
||||
@@ -86,6 +87,10 @@ static MTAB ram_mod[] = {
|
||||
NULL, NULL, "Enable RAM page(s)" },
|
||||
{ MTAB_XTD | MTAB_VDV | MTAB_VALR, 0, NULL, "REMRAM={PAGE | START-END | ALL}", &ram_enable_command,
|
||||
NULL, NULL, "Disable RAM page(s)" },
|
||||
{ MTAB_XTD | MTAB_VDV | MTAB_VALR, TRUE, NULL, "PROT={PAGE | START-END | ALL}", &ram_prot_command,
|
||||
NULL, NULL, "Protect RAM page(s)" },
|
||||
{ MTAB_XTD | MTAB_VDV | MTAB_VALR, FALSE, NULL, "UNPROT={PAGE | START-END | ALL}", &ram_prot_command,
|
||||
NULL, NULL, "Unprotect RAM page(s)" },
|
||||
{ MTAB_VDV, 0, NULL, "CLEAR", &ram_clear_command,
|
||||
NULL, NULL, "Sets RAM to 0x00" },
|
||||
{ MTAB_VDV, 0, NULL, "RANDOM", &ram_randomize_command,
|
||||
@@ -93,8 +98,12 @@ static MTAB ram_mod[] = {
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
/* Debug Flags */
|
||||
#define VERBOSE_MSG (1 << 0)
|
||||
|
||||
/* Debug Flags */
|
||||
static DEBTAB ram_dt[] = {
|
||||
{ "VERBOSE", VERBOSE_MSG, "Verbose messages" },
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
@@ -116,7 +125,7 @@ DEVICE ram_dev = {
|
||||
NULL, /* attach routine */
|
||||
NULL, /* detach routine */
|
||||
NULL, /* context */
|
||||
(DEV_DISABLE), /* flags */
|
||||
(DEV_DISABLE | DEV_DEBUG), /* flags */
|
||||
0, /* debug control */
|
||||
ram_dt, /* debug flags */
|
||||
NULL, /* mem size routine */
|
||||
@@ -129,6 +138,8 @@ DEVICE ram_dev = {
|
||||
|
||||
static t_stat ram_reset(DEVICE *dptr)
|
||||
{
|
||||
t_addr addr;
|
||||
|
||||
if (dptr->flags & DEV_DIS) { /* Disable Device */
|
||||
s100_bus_remmem(0x0000, MAXBANKSIZE, &ram_memio);
|
||||
ram_default_dis(NULL, 0, NULL, NULL);
|
||||
@@ -143,6 +154,14 @@ static t_stat ram_reset(DEVICE *dptr)
|
||||
ram_default_ena(NULL, 0, NULL, NULL);
|
||||
}
|
||||
|
||||
for (addr = 0; addr < MAXADDR; addr++) {
|
||||
M[addr] = 0x00;
|
||||
|
||||
if ((addr & 0xff) == 0x00) {
|
||||
P[addr >> LOG2PAGESIZE] = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
poc = FALSE;
|
||||
}
|
||||
}
|
||||
@@ -175,12 +194,17 @@ static int32 ram_memio(const int32 addr, const int32 rw, const int32 data)
|
||||
return 0x0ff;
|
||||
}
|
||||
|
||||
static void PutBYTE(register uint32 Addr, const register uint32 Value)
|
||||
static void PutBYTE(uint32 Addr, const register uint32 Value)
|
||||
{
|
||||
M[Addr & ADDRMASK] = Value & DATAMASK;
|
||||
if (!P[(Addr & ADDRMASK) >> LOG2PAGESIZE]) {
|
||||
M[Addr & ADDRMASK] = Value & DATAMASK;
|
||||
}
|
||||
else {
|
||||
sim_debug(VERBOSE_MSG, &ram_dev, "RAM: Page %02X is protected\n", Addr >> LOG2PAGESIZE);
|
||||
}
|
||||
}
|
||||
|
||||
static uint32 GetBYTE(register uint32 Addr)
|
||||
static uint32 GetBYTE(uint32 Addr)
|
||||
{
|
||||
return M[Addr & ADDRMASK] & DATAMASK; /* RAM */
|
||||
}
|
||||
@@ -200,9 +224,8 @@ static t_stat ram_default_dis(UNIT *uptr, int32 value, const char *cptr, void *d
|
||||
}
|
||||
|
||||
/* set memory to 'size' kilo byte */
|
||||
static t_stat ram_set_memsize(int32 size) {
|
||||
int32 page;
|
||||
|
||||
static t_stat ram_set_memsize(int32 size)
|
||||
{
|
||||
size <<= KBLOG2;
|
||||
|
||||
if (size < KB) {
|
||||
@@ -218,11 +241,6 @@ static t_stat ram_set_memsize(int32 size) {
|
||||
s100_bus_remmem(0x0000, MAXBANKSIZE, &ram_memio); /* Remove all pages */
|
||||
s100_bus_addmem(0x0000, memsize, &ram_memio, "RAM"); /* Add memsize pages */
|
||||
|
||||
/* Keep track of active pages for SHOW */
|
||||
for (page = 0; page < (MAXBANKSIZE >> LOG2PAGESIZE); page++) {
|
||||
P[page] = (page << LOG2PAGESIZE) <= memsize;
|
||||
}
|
||||
|
||||
ram_unit.capac = memsize;
|
||||
|
||||
return SCPE_OK;
|
||||
@@ -246,7 +264,8 @@ static void ram_randomize()
|
||||
}
|
||||
}
|
||||
|
||||
static t_stat ram_size_command(UNIT *uptr, int32 value, const char *cptr, void *desc) {
|
||||
static t_stat ram_size_command(UNIT *uptr, int32 value, const char *cptr, void *desc)
|
||||
{
|
||||
int32 size, result;
|
||||
|
||||
if (cptr == NULL) {
|
||||
@@ -263,12 +282,13 @@ static t_stat ram_size_command(UNIT *uptr, int32 value, const char *cptr, void *
|
||||
return SCPE_ARG | SCPE_NOMESSAGE;
|
||||
}
|
||||
|
||||
static t_stat ram_enable_command(UNIT *uptr, int32 value, const char *cptr, void *desc) {
|
||||
static t_stat ram_enable_command(UNIT *uptr, int32 value, const char *cptr, void *desc)
|
||||
{
|
||||
int32 size;
|
||||
t_addr start, end;
|
||||
|
||||
if (cptr == NULL) {
|
||||
sim_printf("Memory page(s) must be provided as SET RAM ENABLE=E0-EF\n");
|
||||
sim_printf("Memory page(s) must be provided as SET RAM %s=E0-EF\n", value ? "ADDRAM" : "REMRAM");
|
||||
return SCPE_ARG | SCPE_NOMESSAGE;
|
||||
}
|
||||
|
||||
@@ -298,6 +318,35 @@ static t_stat ram_enable_command(UNIT *uptr, int32 value, const char *cptr, void
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
static t_stat ram_prot_command(UNIT *uptr, int32 value, const char *cptr, void *desc)
|
||||
{
|
||||
t_addr start, end;
|
||||
uint16 page;
|
||||
|
||||
if (cptr == NULL) {
|
||||
sim_printf("Memory page(s) must be provided as SET RAM %s=E0-EF\n", value ? "PROT" : "UNPROT");
|
||||
return SCPE_ARG | SCPE_NOMESSAGE;
|
||||
}
|
||||
|
||||
if (get_range(NULL, cptr, &start, &end, 16, PAGEMASK, 0) == NULL) {
|
||||
return SCPE_ARG;
|
||||
}
|
||||
|
||||
if (start > MAXPAGE) {
|
||||
start = start >> LOG2PAGESIZE;
|
||||
}
|
||||
if (end > MAXPAGE) {
|
||||
end = end >> LOG2PAGESIZE;
|
||||
}
|
||||
|
||||
/* Protect or Unprotect Pages */
|
||||
for (page = start; page <= end; page++) {
|
||||
P[page] = value;
|
||||
}
|
||||
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
static t_stat ram_clear_command(UNIT *uptr, int32 value, const char *cptr, void *desc)
|
||||
{
|
||||
ram_clear();
|
||||
|
||||
@@ -55,11 +55,12 @@ static t_stat rom_show_help(FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, cons
|
||||
static int32 M[MAXBANKSIZE];
|
||||
|
||||
static ROM rom_table[] = {
|
||||
{ UNIT_ROM_ALTMON, rom_altmon, ROM_ALTMON_BASEADDR, ROM_ALTMON_SIZE, ROM_ALTMON_NAME, ROM_ALTMON_DESC },
|
||||
{ UNIT_ROM_DBL, rom_mits_dbl, ROM_MITS_DBL_BASEADDR, ROM_MITS_DBL_SIZE, ROM_MITS_DBL_NAME, ROM_MITS_DBL_DESC },
|
||||
{ UNIT_ROM_HDSK, rom_mits_hdsk, ROM_MITS_HDSK_BASEADDR, ROM_MITS_HDSK_SIZE, ROM_MITS_HDSK_NAME, ROM_MITS_HDSK_DESC },
|
||||
{ UNIT_ROM_TURMON, rom_mits_turmon, ROM_MITS_TURMON_BASEADDR, ROM_MITS_TURMON_SIZE, ROM_MITS_TURMON_NAME, ROM_MITS_TURMON_DESC },
|
||||
{ UNIT_ROM_AZ80DBL, rom_az80_dbl, ROM_AZ80_DBL_BASEADDR, ROM_AZ80_DBL_SIZE, ROM_AZ80_DBL_NAME, ROM_AZ80_DBL_DESC },
|
||||
{ UNIT_ROM_ALTMON, rom_altmon, ROM_ALTMON_BASEADDR, ROM_ALTMON_SIZE, ROM_ALTMON_NAME, ROM_ALTMON_DESC },
|
||||
{ UNIT_ROM_DBL, rom_mits_dbl, ROM_MITS_DBL_BASEADDR, ROM_MITS_DBL_SIZE, ROM_MITS_DBL_NAME, ROM_MITS_DBL_DESC },
|
||||
{ UNIT_ROM_HDSK, rom_mits_hdsk, ROM_MITS_HDSK_BASEADDR, ROM_MITS_HDSK_SIZE, ROM_MITS_HDSK_NAME, ROM_MITS_HDSK_DESC },
|
||||
{ UNIT_ROM_TURMON, rom_mits_turmon, ROM_MITS_TURMON_BASEADDR, ROM_MITS_TURMON_SIZE, ROM_MITS_TURMON_NAME, ROM_MITS_TURMON_DESC },
|
||||
{ UNIT_ROM_CDBL, rom_me_cdbl, ROM_ME_CDBL_BASEADDR, ROM_ME_CDBL_SIZE, ROM_ME_CDBL_NAME, ROM_ME_CDBL_DESC },
|
||||
{ UNIT_ROM_AZ80DBL, rom_az80_dbl, ROM_AZ80_DBL_BASEADDR, ROM_AZ80_DBL_SIZE, ROM_AZ80_DBL_NAME, ROM_AZ80_DBL_DESC },
|
||||
|
||||
{ 0, NULL, 0x0000, 0, "", "" }
|
||||
};
|
||||
@@ -108,6 +109,11 @@ static MTAB rom_mod[] = {
|
||||
{ UNIT_ROM_TURMON, 0, "NO" ROM_MITS_TURMON_NAME, "NO" ROM_MITS_TURMON_NAME, &rom_dis_turmon, NULL,
|
||||
NULL, "Disable " ROM_MITS_TURMON_DESC },
|
||||
|
||||
{ UNIT_ROM_CDBL, UNIT_ROM_CDBL, ROM_ME_CDBL_NAME, ROM_ME_CDBL_NAME, &rom_ena, NULL,
|
||||
NULL, "Enable " ROM_ME_CDBL_DESC },
|
||||
{ UNIT_ROM_CDBL, 0, "NO" ROM_ME_CDBL_NAME, "NO" ROM_ME_CDBL_NAME, &rom_dis_turmon, NULL,
|
||||
NULL, "Disable " ROM_ME_CDBL_DESC },
|
||||
|
||||
{ MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "LIST", NULL, NULL, &rom_show_list, NULL, "Show available ROMs" },
|
||||
|
||||
{ 0 }
|
||||
|
||||
@@ -43,7 +43,9 @@
|
||||
#define UNIT_ROM_ALTMON (1 << UNIT_ROM_V_ALTMON )
|
||||
#define UNIT_ROM_V_TURMON (UNIT_V_UF+4) /* Enable/Disable Turnkey Monitor */
|
||||
#define UNIT_ROM_TURMON (1 << UNIT_ROM_V_TURMON )
|
||||
#define UNIT_ROM_V_AZ80DBL (UNIT_V_UF+5) /* Enable/Disable AltairZ80 Disk Boot Loader */
|
||||
#define UNIT_ROM_V_CDBL (UNIT_V_UF+5) /* Enable/Disable Combined Disk Boot Loader */
|
||||
#define UNIT_ROM_CDBL (1 << UNIT_ROM_V_CDBL)
|
||||
#define UNIT_ROM_V_AZ80DBL (UNIT_V_UF+6) /* Enable/Disable AltairZ80 Disk Boot Loader */
|
||||
#define UNIT_ROM_AZ80DBL (1 << UNIT_ROM_V_AZ80DBL)
|
||||
|
||||
typedef struct {
|
||||
|
||||
@@ -330,6 +330,53 @@ static int32 rom_altmon[ROM_ALTMON_SIZE] = {
|
||||
0x9c, 0x23, 0xc0, 0x13, 0xc9, 0xff, 0xff, 0xff
|
||||
};
|
||||
|
||||
/*
|
||||
* Martin Eberhard Combined Disk Boot Loader
|
||||
* https://deramp.com/downloads/altair/software/roms/custom_roms/M%20Eberhard%20Improved%20ROMs/CDBL.ASM
|
||||
*/
|
||||
#define ROM_ME_CDBL_BASEADDR 0xff00
|
||||
#define ROM_ME_CDBL_SIZE 0x0100
|
||||
#define ROM_ME_CDBL_NAME "CDBL"
|
||||
#define ROM_ME_CDBL_DESC "Combined Disk Boot Loader"
|
||||
|
||||
static int32 rom_me_cdbl[ROM_ME_CDBL_SIZE] = {
|
||||
0xf3, 0x11, 0xf5, 0xff, 0x21, 0xe1, 0x4c, 0x1b,
|
||||
0x2b, 0x1a, 0x77, 0x7d, 0xb7, 0xc2, 0x07, 0xff,
|
||||
0x01, 0x82, 0x06, 0xe9, 0xd3, 0x22, 0x2f, 0xd3,
|
||||
0x23, 0x3e, 0x2c, 0xd3, 0x22, 0xaf, 0xd3, 0x08,
|
||||
0xdb, 0x08, 0xe6, 0x08, 0xc2, 0x09, 0x4c, 0x3e,
|
||||
0x04, 0xd3, 0x09, 0x3e, 0x01, 0xd3, 0x09, 0x0b,
|
||||
0x78, 0xb1, 0xc2, 0x1b, 0x4c, 0x0c, 0xdb, 0x08,
|
||||
0x0f, 0x0f, 0xda, 0x22, 0x4c, 0xe6, 0x10, 0x3e,
|
||||
0x02, 0xc2, 0x19, 0x4c, 0xdb, 0x09, 0xe6, 0x3f,
|
||||
0xfe, 0x1e, 0xc2, 0x30, 0x4c, 0xdb, 0x09, 0x0f,
|
||||
0xd2, 0x39, 0x4c, 0xdb, 0x09, 0x0f, 0xda, 0x3f,
|
||||
0x4c, 0xe6, 0x1f, 0xc6, 0x10, 0x4f, 0x65, 0x3e,
|
||||
0x03, 0xd3, 0x10, 0x3e, 0x11, 0xd3, 0x10, 0x3e,
|
||||
0x10, 0x31, 0x7b, 0x4d, 0xf5, 0xdb, 0x09, 0xe6,
|
||||
0x3f, 0x0f, 0xb8, 0xc2, 0x59, 0x4c, 0x11, 0x7b,
|
||||
0x4d, 0x7c, 0xaa, 0xe6, 0xfe, 0x3e, 0x4f, 0xca,
|
||||
0xc5, 0x4c, 0xe5, 0xc5, 0x01, 0x80, 0x00, 0xdb,
|
||||
0x08, 0x07, 0xda, 0x73, 0x4c, 0xdb, 0x0a, 0x12,
|
||||
0x1c, 0xc2, 0x73, 0x4c, 0x1e, 0x7e, 0x1a, 0x77,
|
||||
0xbe, 0xc2, 0xc3, 0x4c, 0x80, 0x47, 0x13, 0x23,
|
||||
0x0d, 0xc2, 0x82, 0x4c, 0xeb, 0x4e, 0x0c, 0x23,
|
||||
0xae, 0xb1, 0xc1, 0xc2, 0xb6, 0x4c, 0x2a, 0x7c,
|
||||
0x4d, 0xeb, 0x7d, 0x93, 0x7c, 0x9a, 0xd2, 0xc7,
|
||||
0x4c, 0x11, 0x53, 0x4c, 0xd5, 0x04, 0x04, 0x78,
|
||||
0xb9, 0xd8, 0x06, 0x01, 0xc8, 0x78, 0xd3, 0x09,
|
||||
0x05, 0xc9, 0x3e, 0x04, 0xd3, 0x09, 0xe1, 0xf1,
|
||||
0x3d, 0xc2, 0x55, 0x4c, 0x3e, 0x43, 0x11, 0x3e,
|
||||
0x4d, 0x47, 0x37, 0x3e, 0x80, 0xd3, 0x08, 0xd2,
|
||||
0x00, 0x00, 0xfb, 0x22, 0x01, 0x00, 0x78, 0x32,
|
||||
0x00, 0x00, 0xd3, 0x01, 0xd3, 0x11, 0xd3, 0x05,
|
||||
0xd3, 0x23, 0xc3, 0xd6, 0x4c, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
|
||||
};
|
||||
|
||||
/*
|
||||
* AltairZ80 Disk Boot Loader
|
||||
*/
|
||||
#define ROM_AZ80_DBL_BASEADDR 0xff00
|
||||
#define ROM_AZ80_DBL_SIZE 0x0100
|
||||
#define ROM_AZ80_DBL_NAME "AZ80DBL"
|
||||
|
||||
@@ -203,6 +203,10 @@
|
||||
RelativePath="..\Altair8800\altair8800_sys.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\Altair8800\cromemco_dazzler.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\Altair8800\mits_2sio.c"
|
||||
>
|
||||
@@ -215,6 +219,10 @@
|
||||
RelativePath="..\Altair8800\mits_dsk.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\Altair8800\pmmi_mm103.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\Altair8800\s100_bram.c"
|
||||
>
|
||||
@@ -336,6 +344,10 @@
|
||||
RelativePath="..\Altair8800\altair8800_sys.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\Altair8800\cromemco_dazzler.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\Altair8800\mits_2sio.h"
|
||||
>
|
||||
@@ -348,6 +360,10 @@
|
||||
RelativePath="..\Altair8800\mits_dsk.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\Altair8800\pmmi_mm103.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\Altair8800\s100_bram.h"
|
||||
>
|
||||
|
||||
2
makefile
2
makefile
@@ -2242,9 +2242,11 @@ ALTAIR8800 = \
|
||||
${ALTAIR8800D}/s100_ram.c \
|
||||
${ALTAIR8800D}/s100_rom.c \
|
||||
${ALTAIR8800D}/s100_z80.c \
|
||||
${ALTAIR8800D}/cromemco_dazzler.c \
|
||||
${ALTAIR8800D}/mits_2sio.c \
|
||||
${ALTAIR8800D}/mits_acr.c \
|
||||
${ALTAIR8800D}/mits_dsk.c \
|
||||
${ALTAIR8800D}/pmmi_mm103.c \
|
||||
${ALTAIR8800D}/sds_sbc200.c \
|
||||
${ALTAIR8800D}/sds_vfii.c \
|
||||
${ALTAIR8800D}/tarbell_fdc.c \
|
||||
|
||||
Reference in New Issue
Block a user