From b3a9a0d79c62694eb3ff6467cac8f9b9a456cddd Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Wed, 12 Jun 2013 17:10:23 -0700 Subject: [PATCH] Add sim_video and VAX QVSS (VCB01) Monochrome Video Board from Matt Burke --- PDP11/pdp11_io_lib.c | 4 +- README.md | 6 +- VAX/vax610_defs.h | 28 +- VAX/vax610_sysdev.c | 40 +- VAX/vax610_syslist.c | 10 +- VAX/vax630_defs.h | 29 +- VAX/vax630_sysdev.c | 41 +- VAX/vax630_syslist.c | 10 +- VAX/vax_2681.c | 347 ++++++++ VAX/vax_2681.h | 57 ++ VAX/vax_lk.c | 828 ++++++++++++++++++++ VAX/vax_vc.c | 655 ++++++++++++++++ VAX/vax_vs.c | 210 +++++ Visual Studio Projects/0ReadMe_Projects.txt | 1 + Visual Studio Projects/Pre-Build-Event.cmd | 23 +- Visual Studio Projects/VAX610.vcproj | 48 +- Visual Studio Projects/VAX630.vcproj | 48 +- makefile | 50 +- scp.c | 4 +- sim_video.c | 772 ++++++++++++++++++ sim_video.h | 179 +++++ 21 files changed, 3324 insertions(+), 66 deletions(-) create mode 100644 VAX/vax_2681.c create mode 100644 VAX/vax_2681.h create mode 100644 VAX/vax_lk.c create mode 100644 VAX/vax_vc.c create mode 100644 VAX/vax_vs.c create mode 100644 sim_video.c create mode 100644 sim_video.h diff --git a/PDP11/pdp11_io_lib.c b/PDP11/pdp11_io_lib.c index 0c69b1d6..53068608 100644 --- a/PDP11/pdp11_io_lib.c +++ b/PDP11/pdp11_io_lib.c @@ -497,8 +497,8 @@ AUTO_CON auto_tab[] = {/*c #v am vm fxa fxv */ {017340}, {0214} }, /* TC11 */ { { "TA" }, 1, 1, 0, 0, {017500}, {0260} }, /* TA11 */ - { { NULL }, 1, 2, 64, 8, - {017200} }, /* QVSS - fx CSR */ + { { "QVSS" }, 1, 2, 64, 8, + {017200}, {0100} }, /* QVSS - fx CSR, fx VEC */ { { NULL }, 1, 1, 8, 4 }, /* VS31 */ { { NULL }, 1, 1, 0, 4, {016200} }, /* LNV11 - fx CSR */ diff --git a/README.md b/README.md index 9047c52d..39f17fd0 100644 --- a/README.md +++ b/README.md @@ -8,8 +8,8 @@ VAX/11 730 VAX/11 750 VAX 8600/8650 - MicroVAX I - MicroVAX II + MicroVAX I & VAXStation I + MicroVAX II & VAXStation II rtVAX 1000 (or Industrial VAX 620) #### Howard Harte has implemented a Lincoln Labs TX-0 simulator. @@ -50,6 +50,8 @@ A remote console session will close when an EOF character is entered (i.e. ^D or DHU11 (device VH) on Unibus systems now has 16 ports per multiplexer. MicroVAX 3900 and MicroVAX II have SET CPU AUTOBOOT option MicroVAX 3900 has a SET CPU MODEL=(MicroVAX|VAXServer) command to change between system types + MicroVAX I has a SET CPU MODEL=(MicroVAX|VAXSTATION) command to change between system types + MicroVAX II has a SET CPU MODEL=(MicroVAX|VAXSTATION) command to change between system types #### Terminal Multiplexer additions Added support for TCP connections using IPv4 and/or IPv6. diff --git a/VAX/vax610_defs.h b/VAX/vax610_defs.h index 1b59789a..1dbd6f67 100644 --- a/VAX/vax610_defs.h +++ b/VAX/vax610_defs.h @@ -83,6 +83,20 @@ #define MT_MBRK 60 /* microbreak */ #define MT_MAX 63 /* last valid IPR */ +/* CPU */ + +#define CPU_MODEL_MODIFIERS { MTAB_XTD|MTAB_VDV, 0, "LEDS", NULL, \ + NULL, &cpu_show_leds, NULL, "Display the CPU LED values" }, \ + { MTAB_XTD|MTAB_VDV, 0, "MODEL", "MODEL={MICROVAX|VAXSTATION}", \ + &cpu_set_model, &cpu_show_model, NULL, "Set/Show the simulator CPU Model" } + +/* QVSS memory space */ + +#define QVMAWIDTH 18 /* QVSS mem addr width */ +#define QVMSIZE (1u << QVMAWIDTH) /* QVSS mem length */ +#define QVMAMASK (QVMSIZE - 1) /* QVSS mem addr mask */ +#define QVMBASE 0x3C0000 /* QVSS mem base */ + /* Memory */ #define MAXMEMWIDTH 22 /* max mem, KA610 */ @@ -90,8 +104,9 @@ #define MAXMEMWIDTH_X 22 /* max mem, KA610 */ #define MAXMEMSIZE_X (1 << MAXMEMWIDTH_X) #define INITMEMSIZE (1 << 22) /* initial memory size */ +#define VS_MEMSIZE (((cpu_unit.capac > QVMBASE) ? QVMBASE : cpu_unit.capac)) #define MEMSIZE (cpu_unit.capac) -#define ADDR_IS_MEM(x) (((uint32) (x)) < MEMSIZE) +#define ADDR_IS_MEM(x) (((uint32) (x)) < (sys_model ? VS_MEMSIZE : MEMSIZE)) #undef PAMASK #define PAMASK 0x203FFFFF /* KA610 needs a special mask */ #define MEM_MODIFIERS { UNIT_MSIZE, (1u << 19), NULL, "512K", &cpu_set_size, NULL, NULL, "Set Memory to 512K bytes" },\ @@ -101,10 +116,6 @@ { UNIT_MSIZE, (1u << 22), NULL, "4M", &cpu_set_size, NULL, NULL, "Set Memory to 4M bytes" }, \ { MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "MEMORY", NULL, NULL, &cpu_show_memory, NULL, "Display memory configuration" } extern t_stat cpu_show_memory (FILE* st, UNIT* uptr, int32 val, void* desc); -#define CPU_MODEL_MODIFIERS { MTAB_XTD|MTAB_VDV, 0, "LEDS", NULL, \ - NULL, &cpu_show_leds, NULL, "Display the CPU LED values" }, \ - { MTAB_XTD|MTAB_VDV, 0, "MODEL", NULL, \ - NULL, &cpu_show_model, NULL, "Display the simulator CPU Model" } /* Qbus I/O page */ @@ -159,10 +170,7 @@ extern t_stat cpu_show_memory (FILE* st, UNIT* uptr, int32 val, void* desc); #define DZ_MUXES 4 /* max # of DZV muxes */ #define DZ_LINES 4 /* lines per DZV mux */ #define VH_MUXES 4 /* max # of DHQ muxes */ -#define DLX_LINES 16 /* max # of KL11/DL11's */ -#define DCX_LINES 16 /* max # of DC11's */ #define MT_MAXFR (1 << 16) /* magtape max rec */ -#define AUTO_LNT 34 /* autoconfig ranks */ #define DEV_V_UBUS (DEV_V_UF + 0) /* Unibus */ #define DEV_V_QBUS (DEV_V_UF + 1) /* Qbus */ @@ -309,6 +317,10 @@ typedef struct { #define LOG_CPU_R 0x2 /* REI */ #define LOG_CPU_P 0x4 /* context */ +/* System model */ + +extern int32 sys_model; + /* Function prototypes for virtual memory interface */ int32 Read (uint32 va, int32 lnt, int32 acc); diff --git a/VAX/vax610_sysdev.c b/VAX/vax610_sysdev.c index e1e01057..00c7f31d 100644 --- a/VAX/vax610_sysdev.c +++ b/VAX/vax610_sysdev.c @@ -55,9 +55,10 @@ extern int32 int_req[IPL_HLVL]; extern jmp_buf save_env; extern int32 p1; extern int32 trpirq, mem_err; +extern DEVICE vc_dev, lk_dev, vs_dev; int32 conisp, conpc, conpsl; /* console reg */ -int32 sys_model = 0; +int32 sys_model = 0; /* MicroVAX or VAXstation */ char cpu_boot_cmd[CBUFSIZE] = { 0 }; /* boot command */ static struct boot_dev boot_tab[] = { @@ -74,6 +75,8 @@ t_stat vax610_boot_parse (int32 flag, char *ptr); t_stat cpu_boot (int32 unitno, DEVICE *dptr); extern int32 intexc (int32 vec, int32 cc, int32 ipl, int ei); +extern int32 vc_mem_rd (int32 pa); +extern void vc_mem_wr (int32 pa, int32 val, int32 lnt); extern int32 iccs_rd (void); extern int32 todr_rd (void); extern int32 rxcs_rd (void); @@ -277,7 +280,7 @@ struct reglink { /* register linkage */ }; struct reglink regtable[] = { -/* { QVMBASE, QVMBASE+QVMSIZE, &qv_mem_rd, &qv_mem_wr }, */ + { QVMBASE, QVMBASE+QVMSIZE, &vc_mem_rd, &vc_mem_wr }, { 0, 0, NULL, NULL } }; @@ -411,7 +414,7 @@ if (gbuf[0]) { if (unitno == -1) continue; R[0] = boot_tab[i].code | (('0' + unitno) << 24); - R[1] = 0xC0; + R[1] = (sys_model ? 0x80 : 0xC0); R[2] = 0; R[3] = 0; R[4] = 0; @@ -421,7 +424,7 @@ if (gbuf[0]) { } else { R[0] = 0; - R[1] = 0xC0; + R[1] = (sys_model ? 0x80 : 0xC0); R[2] = 0; R[3] = 0; R[4] = 0; @@ -499,12 +502,39 @@ return "system devices"; t_stat cpu_set_model (UNIT *uptr, int32 val, char *cptr, void *desc) { +#if defined(HAVE_LIBSDL) +char gbuf[CBUFSIZE]; + +if ((cptr == NULL) || (!*cptr)) + return SCPE_ARG; +cptr = get_glyph (cptr, gbuf, 0); +if (MATCH_CMD(gbuf, "MICROVAX") == 0) { + sys_model = 0; + vc_dev.flags = vc_dev.flags | DEV_DIS; /* disable QVSS */ + lk_dev.flags = lk_dev.flags | DEV_DIS; /* disable keyboard */ + vs_dev.flags = vs_dev.flags | DEV_DIS; /* disable mouse */ + strcpy (sim_name, "MicroVAX I (KA610)"); + reset_all (0); /* reset everything */ + } +else if (MATCH_CMD(gbuf, "VAXSTATION") == 0) { + sys_model = 1; + vc_dev.flags = vc_dev.flags & ~DEV_DIS; /* enable QVSS */ + lk_dev.flags = lk_dev.flags & ~DEV_DIS; /* enable keyboard */ + vs_dev.flags = vs_dev.flags & ~DEV_DIS; /* enable mouse */ + strcpy (sim_name, "VAXStation I (KA610)"); + reset_all (0); /* reset everything */ + } +else + return SCPE_ARG; +return SCPE_OK; +#else return SCPE_NOFNC; +#endif } t_stat cpu_print_model (FILE *st) { -fprintf (st, "MicroVAX I"); +fprintf (st, (sys_model ? "VAXstation I" : "MicroVAX I")); return SCPE_OK; } diff --git a/VAX/vax610_syslist.c b/VAX/vax610_syslist.c index c44f2700..2c8c182e 100644 --- a/VAX/vax610_syslist.c +++ b/VAX/vax610_syslist.c @@ -29,7 +29,7 @@ #include "vax_defs.h" -char sim_name[] = "MicroVAX I (KA610)"; +char sim_name[32] = "MicroVAX I (KA610)"; extern DEVICE cpu_dev; extern DEVICE mctl_dev; @@ -47,6 +47,9 @@ extern DEVICE tq_dev; extern DEVICE dz_dev; extern DEVICE xq_dev, xqb_dev; extern DEVICE vh_dev; +extern DEVICE vc_dev; +extern DEVICE lk_dev; +extern DEVICE vs_dev; extern void WriteB (uint32 pa, int32 val); extern UNIT cpu_unit; @@ -64,6 +67,11 @@ DEVICE *sim_devices[] = { &vh_dev, &cr_dev, &lpt_dev, +#if defined(USE_SIM_VIDEO) && defined(HAVE_LIBSDL) + &lk_dev, + &vs_dev, + &vc_dev, +#endif &rl_dev, &rq_dev, &rqb_dev, diff --git a/VAX/vax630_defs.h b/VAX/vax630_defs.h index 00c13b61..ae15dbad 100644 --- a/VAX/vax630_defs.h +++ b/VAX/vax630_defs.h @@ -89,6 +89,17 @@ #define MT_MBRK 60 /* microbreak */ #define MT_MAX 63 /* last valid IPR */ +/* CPU */ + +#define CPU_MODEL_MODIFIERS { MTAB_XTD|MTAB_VDV, 0, "MODEL", "MODEL={MICROVAX|VAXSTATION}", \ + &cpu_set_model, &cpu_show_model, NULL, "Set/Show the simulator CPU Model" }, \ + { MTAB_XTD|MTAB_VDV, 0, "DIAG", "DIAG={FULL|MIN}", \ + &sysd_set_diag, &sysd_show_diag, NULL, "Set/Show boot rom diagnostic mode" }, \ + { MTAB_XTD|MTAB_VDV, 0, "AUTOBOOT", "AUTOBOOT", \ + &sysd_set_halt, &sysd_show_halt, NULL, "Enable autoboot (Disable Halt)" }, \ + { MTAB_XTD|MTAB_VDV|MTAB_NMO, 1, "NOAUTOBOOT", "NOAUTOBOOT", \ + &sysd_set_halt, &sysd_show_halt, NULL, "Disable autoboot (Enable Halt)" } + /* Memory */ #define MAXMEMWIDTH 24 /* max mem, std KA655 */ @@ -107,14 +118,6 @@ { UNIT_MSIZE, (1u << 24), NULL, "16M", &cpu_set_size, NULL, NULL, "Set Memory to 16M bytes" }, \ { MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "MEMORY", NULL, NULL, &cpu_show_memory, NULL, "Display memory configuration" } extern t_stat cpu_show_memory (FILE* st, UNIT* uptr, int32 val, void* desc); -#define CPU_MODEL_MODIFIERS { MTAB_XTD|MTAB_VDV, 0, "MODEL", NULL, \ - NULL, &cpu_show_model, NULL, "Display the simulator CPU Model" }, \ - { MTAB_XTD|MTAB_VDV, 0, "DIAG", "DIAG={FULL|MIN}", \ - &sysd_set_diag, &sysd_show_diag, NULL, "Set/Show boot rom diagnostic mode" }, \ - { MTAB_XTD|MTAB_VDV, 0, "AUTOBOOT", "AUTOBOOT", \ - &sysd_set_halt, &sysd_show_halt, NULL, "Enable autoboot (Disable Halt)" }, \ - { MTAB_XTD|MTAB_VDV|MTAB_NMO, 1, "NOAUTOBOOT", "NOAUTOBOOT", \ - &sysd_set_halt, &sysd_show_halt, NULL, "Disable autoboot (Enable Halt)" } /* Qbus I/O page */ @@ -165,6 +168,13 @@ extern t_stat cpu_show_memory (FILE* st, UNIT* uptr, int32 val, void* desc); #define ADDR_IS_QBM(x) ((((uint32) (x)) >= QBMBASE) && \ (((uint32) (x)) < (QBMBASE + QBMSIZE))) +/* QVSS memory space */ + +#define QVMAWIDTH 18 /* QVSS mem addr width */ +#define QVMSIZE (1u << QVMAWIDTH) /* QVSS mem length */ +#define QVMAMASK (QVMSIZE - 1) /* QVSS mem addr mask */ +#define QVMBASE 0x303C0000 /* QVSS mem base */ + /* Other address spaces */ #define ADDR_IS_CDG(x) (0) @@ -207,10 +217,7 @@ extern t_stat cpu_show_memory (FILE* st, UNIT* uptr, int32 val, void* desc); #define DZ_MUXES 4 /* max # of DZV muxes */ #define DZ_LINES 4 /* lines per DZV mux */ #define VH_MUXES 4 /* max # of DHQ muxes */ -#define DLX_LINES 16 /* max # of KL11/DL11's */ -#define DCX_LINES 16 /* max # of DC11's */ #define MT_MAXFR (1 << 16) /* magtape max rec */ -#define AUTO_LNT 34 /* autoconfig ranks */ #define DEV_V_UBUS (DEV_V_UF + 0) /* Unibus */ #define DEV_V_QBUS (DEV_V_UF + 1) /* Qbus */ diff --git a/VAX/vax630_sysdev.c b/VAX/vax630_sysdev.c index c3440d08..69a5e6a3 100644 --- a/VAX/vax630_sysdev.c +++ b/VAX/vax630_sysdev.c @@ -55,7 +55,7 @@ #define UNIT_NODELAY (1u << UNIT_V_NODELAY) t_stat vax630_boot (int32 flag, char *ptr); -int32 sys_model = 0; +int32 sys_model = 0; /* MicroVAX or VAXstation */ /* Special boot command, overrides regular boot */ @@ -139,6 +139,7 @@ extern UNIT clk_unit; extern jmp_buf save_env; extern int32 p1; extern int32 tmr_poll; +extern DEVICE vc_dev, lk_dev, vs_dev; uint32 *rom = NULL; /* boot ROM */ uint32 *nvr = NULL; /* non-volatile mem */ @@ -182,6 +183,8 @@ extern int32 qbmap_rd (int32 pa); extern void qbmap_wr (int32 pa, int32 val, int32 lnt); extern int32 qbmem_rd (int32 pa); extern void qbmem_wr (int32 pa, int32 val, int32 lnt); +extern int32 vc_mem_rd (int32 pa); +extern void vc_mem_wr (int32 pa, int32 val, int32 lnt); extern int32 wtc_rd (int32 pa); extern void wtc_wr (int32 pa, int32 val, int32 lnt); extern void wtc_set_valid (void); @@ -708,7 +711,7 @@ struct reglink regtable[] = { { ROMBASE, ROMBASE+ROMSIZE+ROMSIZE, &rom_rd, NULL }, { NVRBASE, NVRBASE+NVRSIZE, &nvr_rd, &nvr_wr }, { KABASE, KABASE+KASIZE, &ka_rd, &ka_wr }, -/* { QVMBASE, QVMBASE+QVMSIZE, &qv_mem_rd, &qv_mem_wr }, */ + { QVMBASE, QVMBASE+QVMSIZE, &vc_mem_rd, &vc_mem_wr }, { QBMBASE, QBMBASE+QBMSIZE, &qbmem_rd, &qbmem_wr }, { 0, 0, NULL, NULL } }; @@ -957,12 +960,44 @@ ka_diag_full = 0; return SCPE_OK; } +t_stat cpu_set_model (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +#if defined(HAVE_LIBSDL) +char gbuf[CBUFSIZE]; + +if ((cptr == NULL) || (!*cptr)) + return SCPE_ARG; +cptr = get_glyph (cptr, gbuf, 0); +if (MATCH_CMD(gbuf, "MICROVAX") == 0) { + sys_model = 0; + vc_dev.flags = vc_dev.flags | DEV_DIS; /* disable QVSS */ + lk_dev.flags = lk_dev.flags | DEV_DIS; /* disable keyboard */ + vs_dev.flags = vs_dev.flags | DEV_DIS; /* disable mouse */ + strcpy (sim_name, "MicroVAX II (KA630)"); + reset_all (0); /* reset everything */ + } +else if (MATCH_CMD(gbuf, "VAXSTATION") == 0) { + sys_model = 1; + vc_dev.flags = vc_dev.flags & ~DEV_DIS; /* enable QVSS */ + lk_dev.flags = lk_dev.flags & ~DEV_DIS; /* enable keyboard */ + vs_dev.flags = vs_dev.flags & ~DEV_DIS; /* enable mouse */ + strcpy (sim_name, "VAXStation II (KA630)"); + reset_all (0); /* reset everything */ + } +else + return SCPE_ARG; +return SCPE_OK; +#else +return SCPE_NOFNC; +#endif +} + t_stat cpu_print_model (FILE *st) { #if defined(VAX_620) fprintf (st, "rtVAX 1000"); #else -fprintf (st, "MicroVAX II"); +fprintf (st, (sys_model ? "VAXstation II" : "MicroVAX II")); #endif return SCPE_OK; } diff --git a/VAX/vax630_syslist.c b/VAX/vax630_syslist.c index 425ac3bb..11a25a4f 100644 --- a/VAX/vax630_syslist.c +++ b/VAX/vax630_syslist.c @@ -32,7 +32,7 @@ #if defined(VAX_620) char sim_name[] = "rtVAX1000 (KA620)"; #else -char sim_name[] = "MicroVAX II (KA630)"; +char sim_name[32] = "MicroVAX II (KA630)"; #endif extern DEVICE cpu_dev; @@ -53,6 +53,9 @@ extern DEVICE tq_dev; extern DEVICE dz_dev; extern DEVICE xq_dev, xqb_dev; extern DEVICE vh_dev; +extern DEVICE vc_dev; +extern DEVICE lk_dev; +extern DEVICE vs_dev; extern void WriteB (uint32 pa, int32 val); extern void rom_wr_B (int32 pa, int32 val); @@ -73,6 +76,11 @@ DEVICE *sim_devices[] = { &vh_dev, &cr_dev, &lpt_dev, +#if defined(USE_SIM_VIDEO) && defined(HAVE_LIBSDL) + &lk_dev, + &vs_dev, + &vc_dev, +#endif &rl_dev, &rq_dev, &rqb_dev, diff --git a/VAX/vax_2681.c b/VAX/vax_2681.c new file mode 100644 index 00000000..c5267360 --- /dev/null +++ b/VAX/vax_2681.c @@ -0,0 +1,347 @@ +/* vax_2681.c: 2681 DUART Simulator + + Copyright (c) 2011-2013, Matt Burke + + 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. + + 11-Jun-2013 MB First version +*/ + +#include "vax_2681.h" + +#define CMD_ERX 0x0001 /* Enable receiver */ +#define CMD_DRX 0x0002 /* Disable receiver */ +#define CMD_ETX 0x0004 /* Enable transmitter */ +#define CMD_DTX 0x0008 /* Disable transmitter */ +#define CMD_V_CMD 4 /* Command */ +#define CMD_M_CMD 0x7 + +#define STS_RXR 0x0001 /* Receiver ready */ +#define STS_FFL 0x0002 /* FIFO full */ +#define STS_TXR 0x0004 /* Transmitter ready */ +#define STS_TXE 0x0008 /* Transmitter empty */ +#define STS_OER 0x0010 /* Overrun error */ +#define STS_PER 0x0020 /* Parity error */ +#define STS_FER 0x0040 /* Framing error */ +#define STS_RXB 0x0080 /* Received break */ + +#define ISTS_TAI 0x0001 /* Transmitter ready A */ +#define ISTS_RAI 0x0002 /* Receiver ready A */ +#define ISTS_CBA 0x0004 /* Change in break A */ +#define ISTS_CRI 0x0008 /* Counter ready */ +#define ISTS_TBI 0x0010 /* Transmitter ready B */ +#define ISTS_RBI 0x0020 /* Receiver ready B */ +#define ISTS_CBB 0x0040 /* Change in break B */ +#define ISTS_IPC 0c0080 /* Interrupt port change */ + +#define MODE_V_CHM 6 /* Channel mode */ +#define MODE_M_CHM 0x3 + +#define PORT_A 0 +#define PORT_B 1 + +void ua2681_update_rxi (UART2681 *ctx); +void ua2681_update_txi (UART2681 *ctx); + + +void ua2681_wr (UART2681 *ctx, uint32 rg, uint32 data) +{ +uint32 mp; + +switch (rg) { + + case 0: /* mode 1A,2A */ + mp = ctx->port[PORT_A].mode_ptr; + ctx->port[PORT_A].mode[mp++] = data & 0xFF; + if (mp >= 2) mp = 0; + ctx->port[PORT_A].mode_ptr = mp; + break; + + case 1: /* status/clock A */ + /* Used to set baud rate - NI */ + break; + + case 2: /* command A */ + if (data & CMD_ETX) /* enable transmitter */ + ctx->port[PORT_A].cmd |= CMD_ETX; + else if (data & CMD_DTX) /* disable transmitter */ + ctx->port[PORT_A].cmd &= ~CMD_ETX; + + if (data & CMD_ERX) /* enable receiver */ + ctx->port[PORT_A].cmd |= CMD_ERX; + else if (data & CMD_DRX) /* disable receiver */ + ctx->port[PORT_A].cmd &= ~CMD_ERX; + + switch ((data >> CMD_V_CMD) & CMD_M_CMD) { + case 1: + ctx->port[PORT_A].mode_ptr = 0; + break; + + case 2: + ctx->port[PORT_A].cmd &= ~CMD_ERX; + ctx->port[PORT_A].sts &= ~STS_RXR; + break; + + case 3: + ctx->port[PORT_A].sts &= ~STS_TXR; + break; + + case 4: + ctx->port[PORT_A].sts &= ~(STS_FER | STS_PER | STS_OER); + break; + } + ua2681_update_rxi (ctx); + ua2681_update_txi (ctx); + break; + + case 3: /* tx/rx buf A */ + if (((ctx->port[PORT_A].mode[1] >> MODE_V_CHM) & MODE_M_CHM) == 0x2) { /* Maint */ + ctx->port[PORT_A].buf = data & 0xFF; + ctx->port[PORT_A].sts |= STS_RXR; + ctx->ists |= 0x2; + } + else { + if (ctx->port[PORT_A].put_char != NULL) + ctx->port[PORT_A].put_char (data); + } + ua2681_update_txi (ctx); + break; + + case 5: /* interrupt status/mask */ + ctx->imask = data & 0xFF; + break; + + case 8: /* mode 1B,2B */ + mp = ctx->port[PORT_B].mode_ptr; + ctx->port[PORT_B].mode[mp++] = data & 0xFF; + if (mp >= 2) mp = 0; + ctx->port[PORT_B].mode_ptr = mp; + break; + + case 9: /* status/clock B */ + /* Used to set baud rate - NI */ + break; + + case 10: /* command B */ + if (data & CMD_ETX) /* enable transmitter */ + ctx->port[PORT_B].cmd |= CMD_ETX; + else if (data & CMD_DTX) /* disable transmitter */ + ctx->port[PORT_B].cmd &= ~CMD_ETX; + + if (data & CMD_ERX) /* enable receiver */ + ctx->port[PORT_B].cmd |= CMD_ERX; + else if (data & CMD_DRX) /* disable receiver */ + ctx->port[PORT_B].cmd &= ~CMD_ERX; + + switch ((data >> CMD_V_CMD) & CMD_M_CMD) { + case 1: /* reset mode pointer */ + ctx->port[PORT_B].mode_ptr = 0; + break; + + case 2: + ctx->port[PORT_B].cmd &= ~CMD_ERX; + ctx->port[PORT_B].sts &= ~STS_RXR; + break; + + case 3: + ctx->port[PORT_A].sts &= ~STS_TXR; + break; + + case 4: + ctx->port[PORT_B].sts &= ~(STS_FER | STS_PER | STS_OER); + break; + } + ua2681_update_rxi (ctx); + ua2681_update_txi (ctx); + break; + + case 11: /* tx/rx buf B (mouse) */ + if (((ctx->port[PORT_B].mode[1] >> MODE_V_CHM) & MODE_M_CHM) == 0x2) { /* Maint */ + ctx->port[PORT_B].buf = data & 0xFF; + ctx->port[PORT_B].sts |= STS_RXR; + ctx->ists |= 0x20; + } + else { + if (ctx->port[PORT_B].put_char != NULL) + ctx->port[PORT_B].put_char (data); + } + ua2681_update_txi (ctx); + break; + + default: /* NI */ + break; + } +} + +uint32 ua2681_rd(UART2681 *ctx, uint32 rg) +{ +uint32 data; + +switch (rg) { + + case 0: /* mode 1A,2A */ + data = ctx->port[PORT_A].mode[ctx->port[PORT_A].mode_ptr]; + ctx->port[PORT_A].mode_ptr++; + if (ctx->port[PORT_A].mode_ptr >= 2) ctx->port[PORT_A].mode_ptr = 0; + break; + + case 1: /* status/clock A */ + data = ctx->port[PORT_A].sts; + break; + + case 3: /* tx/rx buf A */ + data = ctx->port[PORT_A].buf; + ctx->port[PORT_A].sts &= ~STS_RXR; + ctx->ists &= ~ISTS_RAI; + ua2681_update_rxi (ctx); + break; + + case 5: /* interrupt status/mask */ + data = ctx->ists; + break; + + case 8: /* mode 1B,2B */ + data = ctx->port[PORT_B].mode[ctx->port[PORT_B].mode_ptr]; + ctx->port[PORT_B].mode_ptr++; + if (ctx->port[PORT_B].mode_ptr >= 2) ctx->port[PORT_B].mode_ptr = 0; + break; + + case 9: /* status/clock B */ + data = ctx->port[PORT_B].sts; + break; + + case 11: /* tx/rx buf B */ + data = ctx->port[PORT_B].buf; + ctx->port[PORT_B].sts &= ~STS_RXR; + ctx->ists &= ~ISTS_RBI; + ua2681_update_rxi (ctx); + break; + + default: /* NI */ + data = 0; + break; + } + +return data; +} + +void ua2681_update_txi (UART2681 *ctx) +{ +if (ctx->port[PORT_A].cmd & CMD_ETX) { /* Transmitter A enabled? */ + ctx->port[PORT_A].sts |= STS_TXR; /* ready */ + ctx->port[PORT_A].sts |= STS_TXE; /* empty */ + ctx->ists |= ISTS_TAI; /* set int */ + } +else { + ctx->port[PORT_A].sts &= ~STS_TXR; /* clear ready */ + ctx->port[PORT_A].sts &= ~STS_TXE; /* clear empty */ + ctx->ists &= ~ISTS_TAI; /* clear int */ + } +if (ctx->port[PORT_B].cmd & CMD_ETX) { /* Transmitter B enabled? */ + ctx->port[PORT_B].sts |= STS_TXR; /* ready */ + ctx->port[PORT_B].sts |= STS_TXE; /* empty */ + ctx->ists |= ISTS_TBI; /* set int */ + } +else { + ctx->port[PORT_B].sts &= ~STS_TXR; /* clear ready */ + ctx->port[PORT_B].sts &= ~STS_TXE; /* clear empty */ + ctx->ists &= ~ISTS_TBI; /* clear int */ + } +if ((ctx->ists & ctx->imask) > 0) /* unmasked ints? */ + ctx->set_int (1); +else ctx->set_int (0); +} + +void ua2681_update_rxi (UART2681 *ctx) +{ +uint8 c; +t_stat r; + +if (ctx->port[PORT_A].cmd & CMD_ERX) { + if (((ctx->port[PORT_A].sts & STS_RXR) == 0) && + (ctx->port[PORT_A].get_char != NULL)) { + r = ctx->port[PORT_A].get_char (&c); + if (r == SCPE_OK) { + ctx->port[PORT_A].buf = c; + ctx->port[PORT_A].sts |= STS_RXR; + ctx->ists |= ISTS_RAI; + } + else { + ctx->port[PORT_A].sts &= ~STS_RXR; + ctx->ists &= ~ISTS_RAI; + } + } + } +else { + ctx->port[PORT_A].sts &= ~STS_RXR; + ctx->ists &= ~ISTS_RAI; + } + +if (ctx->port[PORT_B].cmd & CMD_ERX) { + if (((ctx->port[PORT_B].sts & STS_RXR) == 0) && + (ctx->port[PORT_B].get_char != NULL)) { + r = ctx->port[PORT_B].get_char (&c); + if (r == SCPE_OK) { + ctx->port[PORT_B].buf = c; + ctx->port[PORT_B].sts |= STS_RXR; + ctx->ists |= ISTS_RBI; + } + else { + ctx->port[PORT_B].sts &= ~STS_RXR; + ctx->ists &= ~ISTS_RBI; + } + } + } +else { + ctx->port[PORT_B].sts &= ~STS_RXR; + ctx->ists &= ~ISTS_RBI; + } + +if ((ctx->ists & ctx->imask) > 0) + ctx->set_int (1); +else ctx->set_int (0); +} + +t_stat ua2681_svc (UART2681 *ctx) +{ +ua2681_update_rxi (ctx); +return SCPE_OK; +} + +t_stat ua2681_reset (UART2681 *ctx) +{ +ctx->ists = 0; +ctx->imask = 0; + +ctx->port[PORT_A].sts = 0; +ctx->port[PORT_A].mode[0] = 0; +ctx->port[PORT_A].mode[1] = 0; +ctx->port[PORT_A].mode_ptr = 0; +ctx->port[PORT_A].buf = 0; + +ctx->port[PORT_B].sts = 0; +ctx->port[PORT_B].mode[0] = 0; +ctx->port[PORT_B].mode[1] = 0; +ctx->port[PORT_B].mode_ptr = 0; +ctx->port[PORT_B].buf = 0; +return SCPE_OK; +} diff --git a/VAX/vax_2681.h b/VAX/vax_2681.h new file mode 100644 index 00000000..7351ca9a --- /dev/null +++ b/VAX/vax_2681.h @@ -0,0 +1,57 @@ +/* vax_2681.h: 2681 DUART Simulator + + Copyright (c) 2011-2013, Matt Burke + + 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. + + 11-Jun-2013 MB First version +*/ + +#include "sim_defs.h" + +typedef t_stat (*put_char_t)(uint8); +typedef t_stat (*get_char_t)(uint8*); +typedef void (*set_int_t)(uint32); + +struct uart2681_port_t { + put_char_t put_char; + get_char_t get_char; + uint32 sts; + uint32 cmd; + uint32 mode[2]; + uint32 mode_ptr; + uint32 buf; + }; + +struct uart2681_t { + set_int_t set_int; + struct uart2681_port_t port[2]; + uint32 ists; + uint32 imask; + }; + +typedef struct uart2681_t UART2681; + +void ua2681_wr (UART2681 *ctx, uint32 rg, uint32 data); +uint32 ua2681_rd (UART2681 *ctx, uint32 rg); +t_stat ua2681_svc (UART2681 *ctx); +t_stat ua2681_reset (UART2681 *ctx); diff --git a/VAX/vax_lk.c b/VAX/vax_lk.c new file mode 100644 index 00000000..5afe3242 --- /dev/null +++ b/VAX/vax_lk.c @@ -0,0 +1,828 @@ +/* vax_lk.c: DEC Keyboard (LK201) + + Copyright (c) 2011-2013, Matt Burke + + 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. + + lk LK201 keyboard + + 11-Jun-2013 MB First version +*/ + +#include "vax_defs.h" +#include "sim_video.h" + +/* States */ + +#define LK_IDLE 0 +#define LK_RECV 1 +#define LK_SEND 2 + +/* Key group moding */ + +#define LK_MODE_DOWN 0 +#define LK_MODE_AUTODOWN 1 +#define LK_MODE_NONE 2 +#define LK_MODE_DOWNUP 3 + +/* Scan codes */ + +typedef struct { + int8 group; + int8 code; +} LK_KEYDATA; + +LK_KEYDATA LK_KEY_UNKNOWN = { 0, 0 }; +LK_KEYDATA LK_KEY_TR_0 = { 1, 0xEF }; +LK_KEYDATA LK_KEY_TR_1 = { 1, 0xC0 }; +LK_KEYDATA LK_KEY_TR_2 = { 1, 0xC5 }; +LK_KEYDATA LK_KEY_TR_3 = { 1, 0xCB }; +LK_KEYDATA LK_KEY_TR_4 = { 1, 0xD0 }; +LK_KEYDATA LK_KEY_TR_5 = { 1, 0xD6 }; +LK_KEYDATA LK_KEY_TR_6 = { 1, 0xDB }; +LK_KEYDATA LK_KEY_TR_7 = { 1, 0xE0 }; +LK_KEYDATA LK_KEY_TR_8 = { 1, 0xE5 }; +LK_KEYDATA LK_KEY_TR_9 = { 1, 0xEA }; +LK_KEYDATA LK_KEY_A = { 1, 0xC2 }; +LK_KEYDATA LK_KEY_B = { 1, 0xD9 }; +LK_KEYDATA LK_KEY_C = { 1, 0xCE }; +LK_KEYDATA LK_KEY_D = { 1, 0xCD }; +LK_KEYDATA LK_KEY_E = { 1, 0xCC }; +LK_KEYDATA LK_KEY_F = { 1, 0xD2 }; +LK_KEYDATA LK_KEY_G = { 1, 0xD8 }; +LK_KEYDATA LK_KEY_H = { 1, 0xDD }; +LK_KEYDATA LK_KEY_I = { 1, 0xE6 }; +LK_KEYDATA LK_KEY_J = { 1, 0xE2 }; +LK_KEYDATA LK_KEY_K = { 1, 0xE7 }; +LK_KEYDATA LK_KEY_L = { 1, 0xEC }; +LK_KEYDATA LK_KEY_M = { 1, 0xE3 }; +LK_KEYDATA LK_KEY_N = { 1, 0xDE }; +LK_KEYDATA LK_KEY_O = { 1, 0xEB }; +LK_KEYDATA LK_KEY_P = { 1, 0xF0 }; +LK_KEYDATA LK_KEY_Q = { 1, 0xC1 }; +LK_KEYDATA LK_KEY_R = { 1, 0xD1 }; +LK_KEYDATA LK_KEY_S = { 1, 0xC7 }; +LK_KEYDATA LK_KEY_T = { 1, 0xD7 }; +LK_KEYDATA LK_KEY_U = { 1, 0xE1 }; +LK_KEYDATA LK_KEY_V = { 1, 0xD3 }; +LK_KEYDATA LK_KEY_W = { 1, 0xC6 }; +LK_KEYDATA LK_KEY_X = { 1, 0xC8 }; +LK_KEYDATA LK_KEY_Y = { 1, 0xDC }; +LK_KEYDATA LK_KEY_Z = { 1, 0xC3 }; +LK_KEYDATA LK_KEY_SPACE = { 1, 0xD4 }; +LK_KEYDATA LK_KEY_SEMICOLON = { 1, 0xF2 }; +LK_KEYDATA LK_KEY_PLUS = { 1, 0xF5 }; +LK_KEYDATA LK_KEY_COMMA = { 1, 0xE8 }; +LK_KEYDATA LK_KEY_UBAR = { 1, 0xF9 }; +LK_KEYDATA LK_KEY_PERIOD = { 1, 0xED }; +LK_KEYDATA LK_KEY_QMARK = { 1, 0xF3 }; +LK_KEYDATA LK_KEY_QUOTE = { 1, 0xFB }; +LK_KEYDATA LK_KEY_LBRACE = { 1, 0xFA }; +LK_KEYDATA LK_KEY_RBRACE = { 1, 0xF6 }; +LK_KEYDATA LK_KEY_VBAR = { 1, 0xF7 }; +LK_KEYDATA LK_KEY_TILDE = { 1, 0xBF }; +LK_KEYDATA LK_KEY_KP_0 = { 2, 0x92 }; +LK_KEYDATA LK_KEY_KP_1 = { 2, 0x96 }; +LK_KEYDATA LK_KEY_KP_2 = { 2, 0x97 }; +LK_KEYDATA LK_KEY_KP_3 = { 2, 0x98 }; +LK_KEYDATA LK_KEY_KP_4 = { 2, 0x99 }; +LK_KEYDATA LK_KEY_KP_5 = { 2, 0x9A }; +LK_KEYDATA LK_KEY_KP_6 = { 2, 0x9B }; +LK_KEYDATA LK_KEY_KP_7 = { 2, 0x9D }; +LK_KEYDATA LK_KEY_KP_8 = { 2, 0x9E }; +LK_KEYDATA LK_KEY_KP_9 = { 2, 0x9F }; +LK_KEYDATA LK_KEY_KP_PF1 = { 2, 0xA1 }; +LK_KEYDATA LK_KEY_KP_PF2 = { 2, 0xA2 }; +LK_KEYDATA LK_KEY_KP_PF3 = { 2, 0xA3 }; +LK_KEYDATA LK_KEY_KP_PF4 = { 2, 0xA4 }; +LK_KEYDATA LK_KEY_KP_HYPHEN = { 2, 0xA0 }; +LK_KEYDATA LK_KEY_KP_COMMA = { 2, 0x9C }; +LK_KEYDATA LK_KEY_KP_PERIOD = { 2, 0x94 }; +LK_KEYDATA LK_KEY_KP_ENTER = { 2, 0x95 }; +LK_KEYDATA LK_KEY_DELETE = { 3, 0xBC }; +LK_KEYDATA LK_KEY_TAB = { 3, 0xBE }; +LK_KEYDATA LK_KEY_RETURN = { 4, 0xBD }; +LK_KEYDATA LK_KEY_META = { 5, 0xB1 }; +LK_KEYDATA LK_KEY_LOCK = { 5, 0xB0 }; +LK_KEYDATA LK_KEY_SHIFT = { 6, 0xAE }; +LK_KEYDATA LK_KEY_CTRL = { 6, 0xAF }; +LK_KEYDATA LK_KEY_LEFT = { 7, 0xA7 }; +LK_KEYDATA LK_KEY_RIGHT = { 7, 0xA8 }; +LK_KEYDATA LK_KEY_UP = { 8, 0xAA }; +LK_KEYDATA LK_KEY_DOWN = { 8, 0xA9 }; +LK_KEYDATA LK_KEY_REMOVE = { 9, 0x8C }; +LK_KEYDATA LK_KEY_NEXT_SCREEN= { 9, 0x8F }; +LK_KEYDATA LK_KEY_PREV_SCREEN= { 9, 0x8E }; +LK_KEYDATA LK_KEY_INSERT_HERE= { 9, 0x8B }; +LK_KEYDATA LK_KEY_FIND = { 9, 0x8A }; +LK_KEYDATA LK_KEY_SELECT = { 9, 0x8D }; +LK_KEYDATA LK_KEY_F1 = { 10, 0x56 }; +LK_KEYDATA LK_KEY_F2 = { 10, 0x57 }; +LK_KEYDATA LK_KEY_F3 = { 10, 0x58 }; +LK_KEYDATA LK_KEY_F4 = { 10, 0x59 }; +LK_KEYDATA LK_KEY_F5 = { 10, 0x5A }; +LK_KEYDATA LK_KEY_F6 = { 11, 0x64 }; +LK_KEYDATA LK_KEY_F7 = { 11, 0x65 }; +LK_KEYDATA LK_KEY_F8 = { 11, 0x66 }; +LK_KEYDATA LK_KEY_F9 = { 11, 0x67 }; +LK_KEYDATA LK_KEY_F10 = { 11, 0x68 }; +LK_KEYDATA LK_KEY_F11 = { 12, 0x71 }; +LK_KEYDATA LK_KEY_F12 = { 12, 0x72 }; + +#define LK_BUF_LEN 100 + +#define LK_SEND_CHAR(c) lk_sbuf[lk_stptr++] = c; \ + if (lk_stptr == LK_BUF_LEN) lk_stptr = 0 + +/* Debugging Bitmaps */ + +#define DBG_SERIAL 0x0001 /* serial port data */ +#define DBG_CMD 0x0002 /* commands */ + +t_bool lk_repeat = TRUE; /* autorepeat flag */ +t_bool lk_trpti = FALSE; /* temp repeat inhibit */ +int32 lk_keysdown = 0; /* no of keys held down */ +uint8 lk_sbuf[LK_BUF_LEN]; /* send buffer */ +int32 lk_shptr = 0; /* send buf head ptr */ +int32 lk_stptr = 0; /* send buf tail ptr */ +uint8 lk_rbuf[10]; /* receive buffer */ +int32 lk_rbuf_p = 0; /* receive buffer ptr */ +int32 lk_mode[15]; /* mode of each key group */ + +DEVICE lk_dev; +t_stat lk_wr (uint8 c); +t_stat lk_rd (uint8 *c); +t_stat lk_reset (DEVICE *dptr); +void lk_reset_mode (void); +void lk_cmd (void); +void lk_poll (void); + +/* LK data structures + + lk_dev LK device descriptor + lk_unit LK unit list + lk_reg LK register list + lk_mod LK modifier list + lk_debug LK debug list +*/ + +DEBTAB lk_debug[] = { + {"SERIAL", DBG_SERIAL}, + {"CMD", DBG_CMD}, + {0} + }; + +UNIT lk_unit = { UDATA (NULL, 0, 0) }; + +REG lk_reg[] = { + { NULL } + }; + +MTAB lk_mod[] = { + { 0 } + }; + +DEVICE lk_dev = { + "LK", &lk_unit, lk_reg, lk_mod, + 1, DEV_RDX, 20, 1, DEV_RDX, 8, + NULL, NULL, &lk_reset, + NULL, NULL, NULL, + NULL, DEV_DIS | DEV_DEBUG, 0, + lk_debug + }; + +/* Incoming data on serial line */ + +t_stat lk_wr (uint8 c) +{ +sim_debug (DBG_SERIAL, &lk_dev, "vax -> lk: %02X\n", c); +if (c == 0) + return SCPE_OK; +lk_rbuf[lk_rbuf_p++] = c; +if (lk_rbuf_p == 10) { /* too long? */ + lk_rbuf_p = 0; + LK_SEND_CHAR(0xB6); /* input error */ + return SCPE_OK; + } +if (c & 0x80) /* cmd terminator? */ + lk_cmd(); /* process cmd */ +return SCPE_OK; +} + +/* Outgoing data on serial line */ + +t_stat lk_rd (uint8 *c) +{ +if (lk_shptr == lk_stptr) + lk_poll (); +if (lk_shptr == lk_stptr) { + *c = 0; + return SCPE_EOF; + } +else { + *c = lk_sbuf[lk_shptr++]; + sim_debug (DBG_SERIAL, &lk_dev, "lk -> vax: %02X (%s)\n", *c, + (lk_shptr != lk_stptr) ? "more" : "end"); + if (lk_shptr == LK_BUF_LEN) + lk_shptr = 0; /* ring buffer wrap */ + return SCPE_OK; + } +} + +void lk_cmd () +{ +int32 i, group, mode; + +if (lk_rbuf[0] & 1) { /* peripheral command */ + switch (lk_rbuf[0]) { + + case 0x11: + sim_debug (DBG_CMD, &lk_dev, "LED on\n"); + break; + + case 0x13: + sim_debug (DBG_CMD, &lk_dev, "LED off\n"); + break; + + case 0x89: + sim_debug (DBG_CMD, &lk_dev, "inhibit keyboard transmission\n"); + break; + + case 0x8B: + sim_debug (DBG_CMD, &lk_dev, "resume keyboard transmission\n"); + lk_shptr = lk_stptr = 0; + break; + + case 0x99: + sim_debug (DBG_CMD, &lk_dev, "disable keyclick\n"); + break; + + case 0x1B: + sim_debug (DBG_CMD, &lk_dev, "enable keyclick, volume = \n"); + break; + + case 0xB9: + sim_debug (DBG_CMD, &lk_dev, "disable ctrl keyclick\n"); + break; + + case 0xBB: + sim_debug (DBG_CMD, &lk_dev, "enable ctrl keyclick\n"); + break; + + case 0x9F: + sim_debug (DBG_CMD, &lk_dev, "sound keyclick\n"); + break; + + case 0xA1: + sim_debug (DBG_CMD, &lk_dev, "disable bell\n"); + break; + + case 0x23: + sim_debug (DBG_CMD, &lk_dev, "enable bell, volume = \n"); + break; + + case 0xA7: + sim_debug (DBG_CMD, &lk_dev, "sound bell\n"); + break; + + case 0xC1: + sim_debug (DBG_CMD, &lk_dev, "temporary auto-repeat inhibit\n"); + lk_trpti = TRUE; + break; + + case 0xE3: + sim_debug (DBG_CMD, &lk_dev, "enable auto-repeat across keyboard\n"); + lk_repeat = TRUE; + break; + + case 0xE1: + sim_debug (DBG_CMD, &lk_dev, "disable auto-repeat across keyboard\n"); + lk_repeat = FALSE; + break; + + case 0xD9: + sim_debug (DBG_CMD, &lk_dev, "change all auto-repeat to down only\n"); + for (i = 0; i <= 15; i++) { + if (lk_mode[i] == LK_MODE_AUTODOWN) + lk_mode[i] = LK_MODE_DOWN; + } + break; + + case 0xAB: + sim_debug (DBG_CMD, &lk_dev, "request keyboard ID\n"); + LK_SEND_CHAR (0x01); + LK_SEND_CHAR (0x00); + break; + + case 0xFD: + sim_debug (DBG_CMD, &lk_dev, "jump to power-up\n"); + LK_SEND_CHAR (0x01); + LK_SEND_CHAR (0x00); + LK_SEND_CHAR (0x00); + LK_SEND_CHAR (0x00); + break; + + case 0xCB: + sim_debug (DBG_CMD, &lk_dev, "jump to test mode\n"); + break; + + case 0xD3: + sim_debug (DBG_CMD, &lk_dev, "reinstate defaults\n"); + lk_reset_mode (); + lk_repeat = TRUE; + lk_trpti = FALSE; + LK_SEND_CHAR (0xBA); /* Mode change ACK */ + break; + + default: + printf ("lk: unknown cmd %02X\n", lk_rbuf[0]); + break; + } + } + else { + group = (lk_rbuf[0] >> 3) & 0xF; + if (group < 15) { + sim_debug (DBG_CMD, &lk_dev, "set group %d, ", group); + mode = (lk_rbuf[0] >> 1) & 0x3; + lk_mode[group] = mode; + switch (mode) { + case LK_MODE_DOWN: + sim_debug (DBG_CMD, &lk_dev, "mode = DOWN\n"); + break; + + case LK_MODE_AUTODOWN: + sim_debug (DBG_CMD, &lk_dev, "mode = AUTODOWN\n"); + break; + + case LK_MODE_DOWNUP: + sim_debug (DBG_CMD, &lk_dev, "mode = DOWNUP\n"); + break; + } + LK_SEND_CHAR (0xBA); /* Mode change ACK */ + } + else + sim_debug (DBG_CMD, &lk_dev, "set auto-repeat timing\n"); + } + lk_rbuf_p = 0; +} + +LK_KEYDATA lk_map_key (int key) +{ +LK_KEYDATA lk_key; + +switch (key) { + + case SIM_KEY_F1: + lk_key = LK_KEY_F1; + break; + + case SIM_KEY_F2: + lk_key = LK_KEY_F2; + break; + + case SIM_KEY_F3: + lk_key = LK_KEY_F3; + break; + + case SIM_KEY_F4: + lk_key = LK_KEY_F4; + break; + + case SIM_KEY_F5: + lk_key = LK_KEY_F5; + break; + + case SIM_KEY_F6: + lk_key = LK_KEY_F6; + break; + + case SIM_KEY_F7: + lk_key = LK_KEY_F7; + break; + + case SIM_KEY_F8: + lk_key = LK_KEY_F8; + break; + + case SIM_KEY_F9: + lk_key = LK_KEY_F9; + break; + + case SIM_KEY_F10: + lk_key = LK_KEY_F10; + break; + + case SIM_KEY_F11: + lk_key = LK_KEY_F11; + break; + + case SIM_KEY_F12: + lk_key = LK_KEY_F12; + break; + + case SIM_KEY_0: + lk_key = LK_KEY_TR_0; + break; + + case SIM_KEY_1: + lk_key = LK_KEY_TR_1; + break; + + case SIM_KEY_2: + lk_key = LK_KEY_TR_2; + break; + + case SIM_KEY_3: + lk_key = LK_KEY_TR_3; + break; + + case SIM_KEY_4: + lk_key = LK_KEY_TR_4; + break; + + case SIM_KEY_5: + lk_key = LK_KEY_TR_5; + break; + + case SIM_KEY_6: + lk_key = LK_KEY_TR_6; + break; + + case SIM_KEY_7: + lk_key = LK_KEY_TR_7; + break; + + case SIM_KEY_8: + lk_key = LK_KEY_TR_8; + break; + + case SIM_KEY_9: + lk_key = LK_KEY_TR_9; + break; + + case SIM_KEY_A: + lk_key = LK_KEY_A; + break; + + case SIM_KEY_B: + lk_key = LK_KEY_B; + break; + + case SIM_KEY_C: + lk_key = LK_KEY_C; + break; + + case SIM_KEY_D: + lk_key = LK_KEY_D; + break; + + case SIM_KEY_E: + lk_key = LK_KEY_E; + break; + + case SIM_KEY_F: + lk_key = LK_KEY_F; + break; + + case SIM_KEY_G: + lk_key = LK_KEY_G; + break; + + case SIM_KEY_H: + lk_key = LK_KEY_H; + break; + + case SIM_KEY_I: + lk_key = LK_KEY_I; + break; + + case SIM_KEY_J: + lk_key = LK_KEY_J; + break; + + case SIM_KEY_K: + lk_key = LK_KEY_K; + break; + + case SIM_KEY_L: + lk_key = LK_KEY_L; + break; + + case SIM_KEY_M: + lk_key = LK_KEY_M; + break; + + case SIM_KEY_N: + lk_key = LK_KEY_N; + break; + + case SIM_KEY_O: + lk_key = LK_KEY_O; + break; + + case SIM_KEY_P: + lk_key = LK_KEY_P; + break; + + case SIM_KEY_Q: + lk_key = LK_KEY_Q; + break; + + case SIM_KEY_R: + lk_key = LK_KEY_R; + break; + + case SIM_KEY_S: + lk_key = LK_KEY_S; + break; + + case SIM_KEY_T: + lk_key = LK_KEY_T; + break; + + case SIM_KEY_U: + lk_key = LK_KEY_U; + break; + + case SIM_KEY_V: + lk_key = LK_KEY_V; + break; + + case SIM_KEY_W: + lk_key = LK_KEY_W; + break; + + case SIM_KEY_X: + lk_key = LK_KEY_X; + break; + + case SIM_KEY_Y: + lk_key = LK_KEY_Y; + break; + + case SIM_KEY_Z: + lk_key = LK_KEY_Z; + break; + + case SIM_KEY_BACKQUOTE: + lk_key = LK_KEY_TILDE; + break; + + case SIM_KEY_MINUS: + lk_key = LK_KEY_UBAR; + break; + + case SIM_KEY_EQUALS: + lk_key = LK_KEY_PLUS; + break; + + case SIM_KEY_LEFT_BRACKET: + lk_key = LK_KEY_LBRACE; + break; + + case SIM_KEY_RIGHT_BRACKET: + lk_key = LK_KEY_RBRACE; + break; + + case SIM_KEY_SEMICOLON: + lk_key = LK_KEY_SEMICOLON; + break; + + case SIM_KEY_SINGLE_QUOTE: + lk_key = LK_KEY_QUOTE; + break; + + case SIM_KEY_BACKSLASH: + lk_key = LK_KEY_VBAR; + break; + + case SIM_KEY_LEFT_BACKSLASH: + case SIM_KEY_COMMA: + lk_key = LK_KEY_COMMA; + break; + + case SIM_KEY_PERIOD: + lk_key = LK_KEY_PERIOD; + break; + + case SIM_KEY_SLASH: + lk_key = LK_KEY_QMARK; + break; + + /* case SIM_KEY_PRINT: */ + /* case SIM_KEY_PAUSE: */ + /* case SIM_KEY_ESC: */ + + case SIM_KEY_BACKSPACE: + lk_key = LK_KEY_DELETE; + break; + + case SIM_KEY_TAB: + lk_key = LK_KEY_TAB; + break; + + case SIM_KEY_ENTER: + lk_key = LK_KEY_RETURN; + break; + + case SIM_KEY_SPACE: + lk_key = LK_KEY_SPACE; + break; + + case SIM_KEY_INSERT: + lk_key = LK_KEY_FIND; + break; + + case SIM_KEY_DELETE: + lk_key = LK_KEY_SELECT; + break; + + case SIM_KEY_HOME: + lk_key = LK_KEY_INSERT_HERE; + break; + + case SIM_KEY_END: + lk_key = LK_KEY_PREV_SCREEN; + break; + + case SIM_KEY_PAGE_UP: + lk_key = LK_KEY_REMOVE; + break; + + case SIM_KEY_PAGE_DOWN: + lk_key = LK_KEY_NEXT_SCREEN; + break; + + case SIM_KEY_UP: + lk_key = LK_KEY_UP; + break; + + case SIM_KEY_DOWN: + lk_key = LK_KEY_DOWN; + break; + + case SIM_KEY_LEFT: + lk_key = LK_KEY_LEFT; + break; + + case SIM_KEY_RIGHT: + lk_key = LK_KEY_RIGHT; + break; + + case SIM_KEY_CAPS_LOCK: + lk_key = LK_KEY_LOCK; + break; + + case SIM_KEY_NUM_LOCK: + lk_key = LK_KEY_KP_PF1; + break; + + case SIM_KEY_SCRL_LOCK: + + case SIM_KEY_ALT_L: + case SIM_KEY_ALT_R: + lk_key = LK_KEY_META; + break; + + case SIM_KEY_CTRL_L: + case SIM_KEY_CTRL_R: + lk_key = LK_KEY_CTRL; + break; + + case SIM_KEY_SHIFT_L: + case SIM_KEY_SHIFT_R: + lk_key = LK_KEY_SHIFT; + break; + + case SIM_KEY_WIN_L: + case SIM_KEY_WIN_R: + case SIM_KEY_MENU: + lk_key = LK_KEY_UNKNOWN; + break; + + case SIM_KEY_KP_ADD: + case SIM_KEY_KP_SUBTRACT: + case SIM_KEY_KP_END: + case SIM_KEY_KP_DOWN: + case SIM_KEY_KP_PAGE_DOWN: + case SIM_KEY_KP_LEFT: + case SIM_KEY_KP_RIGHT: + case SIM_KEY_KP_HOME: + case SIM_KEY_KP_UP: + case SIM_KEY_KP_PAGE_UP: + case SIM_KEY_KP_INSERT: + case SIM_KEY_KP_DELETE: + case SIM_KEY_KP_5: + case SIM_KEY_KP_ENTER: + case SIM_KEY_KP_MULTIPLY: + case SIM_KEY_KP_DIVIDE: + + case SIM_KEY_UNKNOWN: + lk_key = LK_KEY_UNKNOWN; + break; + + default: + lk_key = LK_KEY_UNKNOWN; + break; + } +return lk_key; +} + +void lk_reset_mode (void) +{ +lk_mode[1] = LK_MODE_AUTODOWN; /* 1 = 48 graphic keys, spacebar */ +lk_mode[2] = LK_MODE_AUTODOWN; /* 2 = numeric keypad */ +lk_mode[3] = LK_MODE_AUTODOWN; /* 3 = delete character */ +lk_mode[4] = LK_MODE_DOWN; /* 4 = return, tab */ +lk_mode[5] = LK_MODE_DOWN; /* 5 = lock, compose */ +lk_mode[6] = LK_MODE_DOWNUP; /* 6 = shift, ctrl */ +lk_mode[7] = LK_MODE_AUTODOWN; /* 7 = horizontal cursors */ +lk_mode[8] = LK_MODE_AUTODOWN; /* 8 = vertical cursors */ +lk_mode[9] = LK_MODE_DOWNUP; /* 9 = six basic editing keys */ +lk_mode[10] = LK_MODE_AUTODOWN; /* 10 = function keys: f1 - f5 */ +lk_mode[11] = LK_MODE_AUTODOWN; /* 11 = function keys: f6 - f10 */ +lk_mode[12] = LK_MODE_AUTODOWN; /* 12 = function keys: f11 - f14 */ +lk_mode[13] = LK_MODE_AUTODOWN; /* 13 = function keys: help, do */ +lk_mode[14] = LK_MODE_AUTODOWN; /* 14 = function keys: f17 - f20 */ +} + +t_stat lk_reset (DEVICE *dptr) +{ +lk_rbuf_p = 0; +lk_keysdown = 0; +lk_repeat = TRUE; +lk_trpti = FALSE; +lk_shptr = 0; +lk_stptr = 0; +lk_reset_mode (); +return SCPE_OK; +} + +void lk_poll (void) +{ +SIM_KEY_EVENT ev; +LK_KEYDATA lk_key; +int32 mode; + +if (vid_poll_kb (&ev) != SCPE_OK) + return; + +lk_key = lk_map_key (ev.key); +mode = lk_mode[lk_key.group]; + +if (lk_trpti && (ev.state != SIM_KEYPRESS_REPEAT)) + lk_trpti = FALSE; + +switch (mode) { + + case LK_MODE_DOWN: + if (ev.state == SIM_KEYPRESS_DOWN) { + LK_SEND_CHAR (lk_key.code); + } + break; + + case LK_MODE_AUTODOWN: + if (ev.state == SIM_KEYPRESS_DOWN) { + LK_SEND_CHAR (lk_key.code); + } + else if ((ev.state == SIM_KEYPRESS_REPEAT) && lk_repeat && !lk_trpti) { + LK_SEND_CHAR (0xB4); + } + break; + + case LK_MODE_DOWNUP: + if (ev.state == SIM_KEYPRESS_DOWN) { + lk_keysdown++; + LK_SEND_CHAR (lk_key.code); + } + else { + lk_keysdown--; + if (lk_keysdown > 0) { + LK_SEND_CHAR (lk_key.code); + } + else { + LK_SEND_CHAR (0xB3); /* LK_ALLUP */ + } + } + break; + } +} diff --git a/VAX/vax_vc.c b/VAX/vax_vc.c new file mode 100644 index 00000000..a496bdb4 --- /dev/null +++ b/VAX/vax_vc.c @@ -0,0 +1,655 @@ +/* vax_vc.c: QVSS video simulator (VCB01) + + Copyright (c) 2011-2013, Matt Burke + + 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. + + vc Qbus video subsystem + + 11-Jun-2013 MB First version +*/ + +#include "vax_defs.h" +#include "sim_video.h" +#include "vax_2681.h" + +#define CSR_MOD 0x0001 /* Monitor size */ +#define CSR_VID 0x0004 /* Video output en */ +#define CSR_FNC 0x0008 /* Cursor function */ +#define CSR_VRB 0x0010 /* Video readback en */ +#define CSR_TST 0x0020 /* Test bit */ +#define CSR_CUR 0x0080 /* Cursor active */ +#define CSR_V_MS 6 /* Mouse buttons */ +#define CSR_M_MS 0x7 +#define CSR_V_MA 11 /* Memory base addr */ +#define CSR_M_MA 0xF +#define CSR_RW (CSR_IE|CSR_TST|CSR_VRB|CSR_FNC|CSR_VID) + +#define CRTCP_REG 0x001F /* CRTC internal register address */ +#define CRTCP_VB 0x0020 /* Vertical blank */ +#define CRTCP_LPF 0x0040 /* Light pen register full */ +#define CRTCP_US 0x0080 /* Update strobe */ +#define CRTCP_RW CRTCP_REG + +#define CRTC_HTOT 0 /* Horizontal total */ +#define CRTC_HDSP 1 /* Horizontal displayed */ +#define CRTC_HPOS 2 /* HSYNC position */ +#define CRTC_HVWD 3 /* HSYNC/VSYNC widths */ +#define CRTC_VTOT 4 /* Vertical total */ +#define CRTC_VTOA 5 /* Vertical total adjust */ +#define CRTC_VDSP 6 /* Vertical displayed */ +#define CRTC_VPOS 7 /* VSYNC position */ +#define CRTC_MODE 8 /* Mode */ +#define CRTC_MSCN 9 /* Maximum scan line */ +#define CRTC_CSCS 10 /* Cursor scan start */ +#define CRTC_CSCE 11 /* Cursor scan end */ +#define CRTC_SAH 12 /* Start address high */ +#define CRTC_SAL 13 /* Start address low */ +#define CRTC_CAH 14 /* Cursor address high */ +#define CRTC_CAL 15 /* Cursor address low */ +#define CRTC_LPPL 16 /* Light pen position low */ +#define CRTC_LPPH 17 /* Light pen position high */ +#define CRTC_SIZE 18 /* Number of registers */ + +#define IRQ_DUART 0 /* UART chip */ +#define IRQ_VSYNC 1 /* VSYNC */ +#define IRQ_MOUSE 2 /* Mouse movement */ +#define IRQ_CSTRT 3 /* Cursor start */ +#define IRQ_MBA 4 /* Mouse button A */ +#define IRQ_MBB 5 /* Mouse button B */ +#define IRQ_MBC 6 /* Mouse button C */ +#define IRQ_SPARE 7 /* (spare) */ + +#define VC_XSIZE 1024 +#define VC_YSIZE 864 + +#define VCMAP_VLD 0x80000000 /* valid */ +#define VCMAP_LN 0x00000FFF /* buffer line */ + +#define VC_OFF(x,y) ((x >> 5) | (y << 5)) /* index into framebuffer */ +#define CUR_X (vc_curx & 0x3FF) /* cursor X */ +#define CUR_Y ((vc_crtc[CRTC_CAH] * \ + (vc_crtc[CRTC_MSCN] + 1)) + \ + vc_crtc[CRTC_CSCS]) /* cursor Y */ +#define CUR_V ((vc_crtc[CRTC_CSCS] & 0x20) == 0) /* cursor visible */ +#define CUR_F (vc_csr & CSR_FNC) /* cursor function */ + +#define IOLN_QVSS 0100 + +extern int32 int_req[IPL_HLVL]; +extern int32 tmxr_poll; /* calibrated delay */ + +extern t_stat lk_wr (uint8 c); +extern t_stat lk_rd (uint8 *c); +extern t_stat vs_wr (uint8 c); +extern t_stat vs_rd (uint8 *c); + +struct vc_int_t { + uint32 ptr; + uint32 vec[8]; /* Interrupt vectors */ + uint32 irr; /* Interrupt request */ + uint32 imr; /* Interrupt mask */ + uint32 isr; /* Interrupt status */ + uint32 acr; /* Auto-clear mask */ + uint32 mode; + }; + +struct vc_int_t vc_intc; /* Interrupt controller */ + +uint32 vc_csr = 0; /* Control/status */ +uint32 vc_curx = 0; /* Cursor X-position */ +uint32 vc_cur_x = 0; /* Last cursor X-position */ +uint32 vc_cur_y = 0; /* Last cursor Y-position */ +uint32 vc_cur_f = 0; /* Last cursor function */ +t_bool vc_cur_v = FALSE; /* Last cursor visible */ +uint32 vc_mpos = 0; /* Mouse position */ +uint32 vc_crtc[CRTC_SIZE]; /* CRTC registers */ +uint32 vc_crtc_p = 0; /* CRTC pointer */ +uint32 vc_icdr = 0; /* Interrupt controller data */ +uint32 vc_icsr = 0; /* Interrupt controller status */ +uint32 vc_map[1024]; /* Scanline map */ +uint32 vc_buf[(1u << 16)]; /* Video memory */ +uint8 vc_cur[256]; /* Cursor image */ + +DEVICE vc_dev; +t_stat vc_rd (int32 *data, int32 PA, int32 access); +t_stat vc_wr (int32 data, int32 PA, int32 access); +t_stat vc_svc (UNIT *uptr); +t_stat vc_reset (DEVICE *dptr); +t_stat vc_set_enable (UNIT *uptr, int32 val, char *cptr, void *desc); +void vc_powerdown (void); +void vc_setint (int32 src); +int32 vc_inta (void); +void vc_clrint (int32 src); +void vc_uart_int (uint32 set); +t_stat vc_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr); +char *vc_description (DEVICE *dptr); + + +/* QVSS data structures + + vc_dev QVSS device descriptor + vc_unit QVSS unit list + vc_reg QVSS register list + vc_mod QVSS modifier list +*/ + +DIB vc_dib = { + IOBA_AUTO, IOLN_QVSS, &vc_rd, &vc_wr, + 1, IVCL (QVSS), 0, { &vc_inta } + }; + +UNIT vc_unit = { UDATA (&vc_svc, UNIT_IDLE, 0) }; + +REG vc_reg[] = { + { HRDATA (CSR, vc_csr, 16) }, + { HRDATA (CURX, vc_curx, 9) }, + { HRDATA (MPOS, vc_mpos, 16) }, + { HRDATA (ICDR, vc_icdr, 16) }, + { HRDATA (ICSR, vc_icsr, 16) }, + { HRDATA (IRR, vc_intc.irr, 8) }, + { HRDATA (IMR, vc_intc.imr, 8) }, + { HRDATA (ISR, vc_intc.isr, 8) }, + { HRDATA (ACR, vc_intc.acr, 8) }, + { HRDATA (MODE, vc_intc.mode, 8) }, + { HRDATA (IPTR, vc_intc.ptr, 8), REG_HRO }, + { BRDATA (VEC, vc_intc.vec, 16, 32, 8) }, + { BRDATA (CRTC, vc_crtc, 16, 8, CRTC_SIZE) }, + { HRDATA (CRTCP, vc_crtc_p, 8) }, + { BRDATA (MAP, vc_map, 16, 16, 1024) }, + { NULL } + }; + +MTAB vc_mod[] = { + { MTAB_XTD|MTAB_VDV, 1, NULL, "ENABLE", + &vc_set_enable, NULL, NULL, "Enable VCB01 (QVSS)" }, + { MTAB_XTD|MTAB_VDV, 0, NULL, "DISABLE", + &vc_set_enable, NULL, NULL, "Disable VCB01 (QVSS)" }, + { MTAB_XTD|MTAB_VDV|MTAB_VALR, 004, "ADDRESS", "ADDRESS", + &set_addr, &show_addr, NULL, "Bus address" }, + { MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "VECTOR", "VECTOR", + &set_vec, &show_vec, NULL, "Interrupt vector" }, + { 0 } + }; + +DEVICE vc_dev = { + "QVSS", &vc_unit, vc_reg, vc_mod, + 1, DEV_RDX, 20, 1, DEV_RDX, 8, + NULL, NULL, &vc_reset, + NULL, NULL, NULL, + &vc_dib, DEV_DIS | DEV_QBUS, 0, + NULL, NULL, NULL, &vc_help, NULL, NULL, + &vc_description + }; + +UART2681 vc_uart = { + &vc_uart_int, + { { &lk_wr, &lk_rd }, { &vs_wr, &vs_rd } } + }; + + +t_stat vc_rd (int32 *data, int32 PA, int32 access) +{ +uint32 rg = (PA >> 1) & 0x1F; +uint32 crtc_rg, i; + +*data = 0; +switch ((PA >> 1) & 0x1F) { /* decode PA<1> */ + + case 0: /* CSR */ + *data = vc_csr; + break; + + case 1: /* Cursor X */ + *data = 0; + break; + + case 2: /* Mouse position */ + *data = vc_mpos; + break; + + case 4: /* CRTC addr ptr */ + *data = vc_crtc_p; + break; + + case 5: /* CRTC data */ + crtc_rg = vc_crtc_p & CRTCP_REG; + *data = vc_crtc[crtc_rg]; + if ((crtc_rg == CRTC_LPPL) || (crtc_rg == CRTC_LPPH)) + vc_crtc_p &= ~CRTCP_LPF; /* Clear light pen full */ + break; + + case 6: /* ICDR */ + switch ((vc_intc.mode >> 5) & 0x3) { + + case 0: /* ISR */ + *data = vc_intc.isr; + break; + + case 1: /* IMR */ + *data = vc_intc.imr; + break; + + case 2: /* IRR */ + *data = vc_intc.irr; + break; + + case 3: /* ACR */ + *data = vc_intc.acr; + break; + } + break; + + case 7: /* ICSR */ + *data = vc_icsr | 0x40; /* Chip enabled */ + *data |= (vc_intc.mode & 0x1) ? 0x20 : 0; /* Priority mode */ + *data |= (vc_intc.mode & 0x4) ? 0x10 : 0; /* Interrupt mode */ + *data |= (vc_intc.mode & 0x80) ? 0x8 : 0; /* Master mask */ + if (vc_icsr & 0x80) { /* Group int pending */ + for (i = 0; i < 8; i++) { + if (vc_intc.isr & (1u << i)) { + *data |= i; + break; + } + } + } + break; + + case 16: /* UART mode 1A,2A */ + case 17: /* UART status/clock A */ + case 18: /* UART command A */ + case 19: /* UART tx/rx buf A */ + case 21: /* UART interrupt status/mask */ + case 24: /* UART mode 1B,2B */ + case 25: /* UART status/clock B */ + case 26: /* UART command B */ + case 27: /* UART tx/rx buf B */ + *data = ua2681_rd (&vc_uart, (rg - 16)); + break; + + default: /* Spares */ + break; + } /* end switch PA */ + +return SCPE_OK; +} + +t_stat vc_wr (int32 data, int32 PA, int32 access) +{ +uint32 rg = (PA >> 1) & 0x1F; +uint32 crtc_rg; + +switch ((PA >> 1) & 0x1F) { /* decode PA<1> */ + + case 0: /* CSR */ + vc_csr = (vc_csr & ~CSR_RW) | (data & CSR_RW); + break; + + case 1: /* Cursor X */ + vc_curx = data; + break; + + case 2: /* Mouse position */ + break; + + case 4: /* CRTC addr ptr */ + vc_crtc_p = (vc_crtc_p & ~CRTCP_RW) | (data & CRTCP_RW); + break; + + case 5: /* CRTC data */ + crtc_rg = vc_crtc_p & CRTCP_REG; + vc_crtc[crtc_rg] = data & BMASK; + break; + + case 6: /* ICDR */ + if (vc_intc.ptr == 8) /* IMR */ + vc_intc.imr = data & 0xFFFF; + else if (vc_intc.ptr == 9) /* ACR */ + vc_intc.acr = data & 0xFFFF; + else + vc_intc.vec[vc_intc.ptr] = data & 0xFFFF; /* Vector */ + break; + + case 7: /* ICSR */ + switch ((data >> 4) & 0xF) { + + case 0: /* Reset */ + vc_intc.imr = 0xFF; + vc_intc.irr = 0; + vc_intc.isr = 0; + vc_intc.acr = 0; + break; + + case 2: /* Clear IRR & IMR */ + if (data & 0x8) { /* one bit */ + vc_intc.irr &= ~(1u << (data & 0x7)); + vc_intc.imr &= ~(1u << (data & 0x7)); + } + else { /* all bits */ + vc_intc.irr = 0; + vc_intc.imr = 0; + } + break; + + case 3: /* Set IMR */ + if (data & 0x8) /* one bit */ + vc_intc.imr |= (1u << (data & 0x7)); + else /* all bits */ + vc_intc.imr = 0xFF; + break; + + case 4: /* Clear IRR */ + if (data & 0x8) /* one bit */ + vc_intc.irr &= ~(1u << (data & 0x7)); + else /* all bits */ + vc_intc.irr = 0; + break; + + case 6: /* Clear highest priority ISR */ + break; + + case 7: /* Clear ISR */ + if (data & 0x8) /* one bit */ + vc_intc.isr &= ~(1u << (data & 0x7)); + else /* all bits */ + vc_intc.isr = 0; + break; + + case 8: /* Load mode bits */ + case 9: + vc_intc.mode &= ~0x1F | (data & 0x1F); + break; + + case 10: /* Control mode bits */ + vc_intc.mode &= ~0x60 | ((data << 3) & 0x60); /* mode<06:05> = data<03:02> */ + if (((data & 0x3) == 0x1) || ((data & 0x3) == 2)) + vc_intc.mode &= ~0x80 | ((data << 7) & 0x80); + break; + + case 11: /* Preselect IMR */ + vc_intc.ptr = 8; + break; + + case 12: /* Preselect ACR */ + vc_intc.ptr = 9; + break; + + case 14: /* Preselect response mem */ + vc_intc.ptr = (data & 0x7); + break; + } + break; + + case 16: /* UART mode 1A,2A */ + case 17: /* UART status/clock A */ + case 18: /* UART command A */ + case 19: /* UART tx/rx buf A (keyboard) */ + case 21: /* UART interrupt status/mask */ + case 24: /* UART mode 1B,2B */ + case 25: /* UART status/clock B */ + case 26: /* UART command B */ + case 27: /* UART tx/rx buf B (mouse) */ + ua2681_wr (&vc_uart, (rg - 16), data); + break; + + default: /* Spares */ + break; + } + +return SCPE_OK; +} + +int32 vc_mem_rd (int32 pa) +{ +uint32 rg = (pa >> 2) & 0xFFFF; +return vc_buf[rg]; +} + +void vc_mem_wr (int32 pa, int32 val, int32 lnt) +{ +uint32 rg = (pa >> 2) & 0xFFFF; +int32 nval, i; +int32 sc; +uint32 scrln, bufln; +uint32 idx; + +if (lnt < L_LONG) { + int32 mask = (lnt == L_WORD)? 0xFFFF: 0xFF; + int32 t = vc_buf[rg]; + sc = (pa & 3) << 3; + nval = ((val & mask) << sc) | (t & ~(mask << sc)); + } +else nval = val; + +if (rg >= 0xFFF8) { /* cursor image */ + idx = (pa << 3) & 0xFF; /* get byte index */ + for (i = 0; i < (lnt << 3); i++) + vc_cur[idx++] = (val >> i) & 1; /* 1bpp to 8bpp */ + } +else if (rg >= 0xFE00) { /* scanline map */ + if (vc_buf[rg] != nval) { + scrln = (pa >> 1) & 0x3FF; /* screen line */ + sc = (scrln & 1) ? 16 : 0; /* odd line? (upper word) */ + bufln = (nval >> sc) & 0x7FF; /* buffer line */ + vc_map[scrln] = bufln; /* update map */ + + if (lnt > L_WORD) { /* remapping 2 lines? */ + scrln++; /* next screen line */ + bufln = (val >> 16) & 0x7FF; /* buffer line */ + vc_map[scrln] = bufln; /* update map */ + } + } + } +bufln = rg / 32; +for (scrln = 0; scrln < 1024; scrln++) { + if ((vc_map[scrln] & 0x7FF) == bufln) { + vc_map[scrln] = vc_map[scrln] & ~VCMAP_VLD; /* invalidate map */ + } + } +vc_buf[rg] = nval; +} + +SIM_INLINE void vc_invalidate (uint32 y1, uint32 y2) +{ +uint32 ln; +for (ln = y1; ln < y2; ln++) + vc_map[ln] = vc_map[ln] & ~VCMAP_VLD; /* invalidate map entry */ +} + +void vc_checkint (void) +{ +uint32 i; +uint32 msk = (vc_intc.irr & ~vc_intc.imr); /* unmasked interrutps */ +vc_icsr &= ~0x87; /* clear GRI & vector */ + +if ((vc_intc.mode & 0x80) && ~(vc_intc.mode & 0x4)) { /* group int MM & not polled */ + for (i = 0; i < 8; i++) { + if (msk & (1u << i)) { + vc_icsr |= (0x80 | i); + } + } + if (vc_icsr & 0x80) + SET_INT (QVSS); + else + CLR_INT (QVSS); + } +else CLR_INT (QVSS); +} + +void vc_clrint (int32 src) +{ +uint32 msk = (1u << src); +vc_intc.irr &= ~msk; +vc_intc.isr &= ~msk; +vc_checkint (); +} + +void vc_setint (int32 src) +{ +uint32 msk = (1u << src); +vc_intc.irr |= msk; +vc_checkint (); +} + +void vc_uart_int (uint32 set) +{ +if (set) + vc_setint (IRQ_DUART); +else + vc_clrint (IRQ_DUART); +} + +int32 vc_inta (void) +{ +uint32 i; +uint32 msk = (vc_intc.irr & ~vc_intc.imr); /* unmasked interrutps */ + +for (i = 0; i < 8; i++) { + if (msk & (1u << i)) { + vc_intc.irr &= ~(1u << i); + if (vc_intc.acr & (1u << i)) + vc_intc.isr &= ~(1u << i); + else vc_intc.isr |= (1u << i); + vc_checkint(); + return (vc_intc.vec[i] + VEC_Q); + } + } +return 0; /* no intr req */ +} + +t_stat vc_svc (UNIT *uptr) +{ +t_bool updated = FALSE; /* flag for refresh */ +uint8 line[1024]; +uint32 ln, col, off; +uint8 *cur; + +vc_crtc_p = vc_crtc_p ^ CRTCP_VB; /* Toggle VBI */ +vc_crtc_p = vc_crtc_p | CRTCP_LPF; /* Light pen full */ + +if (vc_cur_v != CUR_V) { /* visibility changed? */ + if (CUR_V) /* visible? */ + vc_invalidate (CUR_Y, (CUR_Y + 16)); /* invalidate new pos */ + else + vc_invalidate (vc_cur_y, (vc_cur_y + 16)); /* invalidate old pos */ + } +else if (vc_cur_y != CUR_Y) { /* moved (Y)? */ + vc_invalidate (CUR_Y, (CUR_Y + 16)); /* invalidate new pos */ + vc_invalidate (vc_cur_y, (vc_cur_y + 16)); /* invalidate old pos */ + } +else if ((vc_cur_x != CUR_X) || (vc_cur_f != CUR_F)) { /* moved (X) or mask changed? */ + vc_invalidate (CUR_Y, (CUR_Y + 16)); /* invalidate new pos */ + } + +vc_cur_x = CUR_X; /* store cursor data */ +vc_cur_y = CUR_Y; +vc_cur_v = CUR_V; +vc_cur_f = CUR_F; + +for (ln = 0; ln < VC_YSIZE; ln++) { + if ((vc_map[ln] & VCMAP_VLD) == 0) { /* line invalid? */ + off = vc_map[ln] * 32; /* get video buf offet */ + for (col = 0; col < 1024; col++) + line[col] = (vc_buf[off + (col >> 5)] >> col) & 1; /* 1bpp to 8bpp */ + if (CUR_V) { /* cursor visible? */ + if ((ln >= CUR_Y) && (ln < (CUR_Y + 16))) { /* cursor on this line? */ + cur = &vc_cur[((ln - CUR_Y) << 4)]; /* get image base */ + for (col = 0; col < 16; col++) { + if (CUR_F) /* mask function */ + line[CUR_X + col] = line[CUR_X + col] | cur[col]; + else + line[CUR_X + col] = line[CUR_X + col] & ~cur[col]; + line [CUR_X + col] = line[CUR_X + col] & 1; + } + } + } + vid_draw (0, ln, 1024, 1, &line[0]); /* update line */ + updated = TRUE; + vc_map[ln] = vc_map[ln] | VCMAP_VLD; /* set valid */ + } + } + +if (updated) /* video updated? */ + vid_refresh (); /* put to screen */ + +ua2681_svc (&vc_uart); /* service DUART */ +vc_setint (IRQ_VSYNC); /* VSYNC int */ +sim_activate (uptr, tmxr_poll); /* reactivate */ +return SCPE_OK; +} + +t_stat vc_reset (DEVICE *dptr) +{ +uint32 i; +t_stat r; + +CLR_INT (QVSS); /* clear int req */ +sim_cancel (&vc_unit); /* stop poll */ +ua2681_reset (&vc_uart); /* reset DUART */ + +vc_intc.ptr = 0; /* interrupt controller */ +vc_intc.irr = 0; +vc_intc.imr = 0xFF; +vc_intc.isr = 0; +vc_intc.acr = 0; +vc_intc.mode = 0x80; +vc_icsr = 0; + +vc_csr = (0xF << CSR_V_MA) | CSR_MOD; +vc_curx = 0; +vc_mpos = 0; + +for (i = 0; i < CRTC_SIZE; i++) + vc_crtc[i] = 0; +vc_crtc[CRTC_CSCS] = 0x20; /* hide cursor */ +vc_crtc_p = (CRTCP_LPF | CRTCP_VB); + +if (dptr->flags & DEV_DIS) + return vid_close (); + +r = vid_open (VC_XSIZE, VC_YSIZE); /* display size */ +if (r != SCPE_OK) + return r; +sim_activate_abs (&vc_unit, tmxr_poll); +return auto_config (NULL, 0); /* run autoconfig */ +} + +t_stat vc_set_enable (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +return cpu_set_model (NULL, 0, (val ? "VAXSTATION" : "MICROVAX"), NULL); +} + +t_stat vc_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr) +{ +fprintf (st, "VCB01 Monochrome Video Subsystem (%s)\n\n", dptr->name); +fprintf (st, "Use the Control-Right-Shift key combination to regain focus from the simulated\n"); +fprintf (st, "video display\n"); +fprint_set_help (st, dptr); +fprint_show_help (st, dptr); +fprint_reg_help (st, dptr); +return SCPE_OK; +} + +char *vc_description (DEVICE *dptr) +{ +return "VCB01 Monochrome Graphics Adapter"; +} diff --git a/VAX/vax_vs.c b/VAX/vax_vs.c new file mode 100644 index 00000000..479079fd --- /dev/null +++ b/VAX/vax_vs.c @@ -0,0 +1,210 @@ +/* vax_vs.c: DEC Mouse/Tablet (VSXXX) + + Copyright (c) 2011-2013, Matt Burke + + 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. + + vs VSXXX-nn pointing device + + 11-Jun-2013 MB First version +*/ + +#include "vax_defs.h" +#include "sim_video.h" + +#define VSXXX_IDLE 0 +#define VSXXX_RECV 1 +#define VSXXX_SEND 2 +#define VSXXX_TEST 3 + +#define VSXXX_PROMPT 0 +#define VSXXX_INC 1 + +/* Debugging Bitmaps */ + +#define DBG_SERIAL 0x0001 /* serial port data */ +#define DBG_CMD 0x0002 /* commands */ + +int32 vs_state = VSXXX_IDLE; +int32 vs_mode = VSXXX_PROMPT; +int32 vs_bptr = 0; +int32 vs_datalen = 0; +int32 vs_x = 0; /* X-axis motion */ +int32 vs_y = 0; /* Y-axis motion */ +t_bool vs_l = 0; +t_bool vs_m = 0; +t_bool vs_r = 0; +uint8 vs_buf[10]; + +DEVICE vs_dev; +t_stat vs_wr (uint8 c); +t_stat vs_rd (uint8 *c); +t_stat vs_reset (DEVICE *dptr); +void vs_cmd (int32 c); +void vs_sendupd (void); +void vs_poll (void); + + +/* VS data structures + + vs_dev VS device descriptor + vs_unit VS unit list + vs_reg VS register list + vs_mod VS modifier list + vs_debug VS debug list +*/ + +DEBTAB vs_debug[] = { + {"SERIAL", DBG_SERIAL}, + {"CMD", DBG_CMD}, + {0} + }; + +UNIT vs_unit = { UDATA (NULL, 0, 0) }; + +REG vs_reg[] = { + { NULL } + }; + +MTAB vs_mod[] = { + { 0 } + }; + +DEVICE vs_dev = { + "VS", &vs_unit, vs_reg, vs_mod, + 1, DEV_RDX, 20, 1, DEV_RDX, 8, + NULL, NULL, &vs_reset, + NULL, NULL, NULL, + NULL, DEV_DIS | DEV_DEBUG, 0, + vs_debug + }; + + +t_stat vs_wr (uint8 c) +{ +if (vs_state != VSXXX_TEST) { + vs_bptr = 0; + vs_state = VSXXX_IDLE; + vs_datalen = 0; + vs_cmd (c); + } +return SCPE_OK; +} + +t_stat vs_rd (uint8 *c) +{ +if (vs_state == VSXXX_IDLE) + vs_poll (); +switch (vs_state) { + + case VSXXX_IDLE: + *c = 0; + return SCPE_EOF; + + case VSXXX_SEND: + case VSXXX_TEST: + *c = vs_buf[vs_bptr++]; + sim_debug (DBG_SERIAL, &vs_dev, "mouse -> vax: %02X\n", *c); + if (vs_bptr == vs_datalen) { + vs_state = VSXXX_IDLE; + } + return SCPE_OK; + } +return SCPE_EOF; +} + +void vs_cmd (int32 c) +{ +sim_debug (DBG_SERIAL, &vs_dev, "vax -> mouse: %c\n", c); +switch (c) { + + case 0x52: /* R */ + sim_debug (DBG_CMD, &vs_dev, "set mode incremental\n", c); + vs_mode = VSXXX_INC; + break; + + case 0x44: /* D */ + sim_debug (DBG_CMD, &vs_dev, "set mode prompt\n", c); + vs_mode = VSXXX_PROMPT; + break; + + case 0x50: /* P */ + sim_debug (DBG_CMD, &vs_dev, "poll\n", c); + vs_mode = VSXXX_PROMPT; + vs_sendupd (); + break; + + case 0x54: /* T */ + sim_debug (DBG_CMD, &vs_dev, "test\n", c); + vs_reset (&vs_dev); + vs_state = VSXXX_TEST; + vs_buf[0] = 0xA0; /* send ID */ + vs_buf[1] = 0x12; + vs_buf[2] = 0x00; + vs_buf[3] = 0x00; + vs_bptr = 0; + vs_state = VSXXX_SEND; + vs_datalen = 4; + break; + } +} + +t_stat vs_reset (DEVICE *dptr) +{ +vs_bptr = 0; +vs_state = VSXXX_IDLE; +vs_datalen = 0; +vs_mode = VSXXX_PROMPT; +return SCPE_OK; +} + +void vs_sendupd (void) +{ +vs_buf[0] = 0x80; +vs_buf[0] |= (((vs_x >= 0) ? 1 : 0) << 4); /* sign bits */ +vs_buf[0] |= (((vs_y >= 0) ? 1 : 0) << 3); +vs_buf[0] |= (((vs_l) ? 1 : 0) << 2); /* button states */ +vs_buf[0] |= (((vs_m) ? 1 : 0) << 1); +vs_buf[0] |= ((vs_r) ? 1 : 0); +vs_buf[1] = (abs(vs_x)) & 0x7F; /* motion */ +vs_buf[2] = (abs(vs_y)) & 0x7F; +vs_bptr = 0; +vs_state = VSXXX_SEND; +vs_datalen = 3; +} + +void vs_poll (void) +{ +SIM_MOUSE_EVENT ev; + +if (vid_poll_mouse (&ev) != SCPE_OK) + return; +if (vs_state == VSXXX_IDLE) { + vs_x = ev.x_rel; + vs_y = ev.y_rel; + vs_l = ev.b1_state; + vs_m = ev.b2_state; + vs_r = ev.b3_state; + if (vs_mode == VSXXX_INC) + vs_sendupd (); + } +} diff --git a/Visual Studio Projects/0ReadMe_Projects.txt b/Visual Studio Projects/0ReadMe_Projects.txt index 24445549..9d0446e0 100644 --- a/Visual Studio Projects/0ReadMe_Projects.txt +++ b/Visual Studio Projects/0ReadMe_Projects.txt @@ -18,6 +18,7 @@ For Example, the directory structure should look like: .../simh/simhv38-2-rc1/BIN/Nt/Win32-Release/vax.exe .../simh/windows-build/pthreads/pthread.h .../simh/windows-build/winpcap/WpdPack/Include/pcap.h + .../simh/windows-build/libSDL/SDL-1.2.15/include/SDL.h The contents of the windows-build directory can be downloaded from: diff --git a/Visual Studio Projects/Pre-Build-Event.cmd b/Visual Studio Projects/Pre-Build-Event.cmd index e582f3ba..7d6de24b 100644 --- a/Visual Studio Projects/Pre-Build-Event.cmd +++ b/Visual Studio Projects/Pre-Build-Event.cmd @@ -12,7 +12,10 @@ rem ROM images are consistent with the ROM images from which they rem are derived. rem BUILD To validate that the required dependent libraries and include rem files are available in the directory ..\..\windows-build\ -rem These libraries currently include winpcap and pthreads. +rem These libraries currently include winpcap and pthreads and +rem optionally SDL. +rem LIBSDL To validate that the required dependent SDL libraries and include +rem files are available in the directory ..\..\windows-build\ rem rem In addition to the optional activities mentioned above, other activities rem are also performed. These include: @@ -30,6 +33,7 @@ if "%1" == "" goto _done_args set _arg= if /I "%1" == "ROM" set _arg=ROM if /I "%1" == "BUILD" set _arg=BUILD +if /I "%1" == "LIBSDL" set _arg=LIBSDL if "%_arg%" == "" echo *** warning *** unknown parameter %0 if not "%_arg%" == "" set _X_%_arg%=%_arg% shift @@ -56,15 +60,26 @@ popd :_check_build if "%_X_BUILD%" == "" goto _done_build if exist ../../windows-build-windows-build move ../../windows-build-windows-build ../../windows-build >NUL -if not exist ../../windows-build/winpcap/Wpdpack/Include/pcap.h goto _notice -if not exist ../../windows-build/pthreads/pthread.h goto _notice +if not exist ../../windows-build/winpcap/Wpdpack/Include/pcap.h goto _notice1 +if not exist ../../windows-build/pthreads/pthread.h goto _notice1 +if "%_X_LIBSDL%" == "" goto _done_build +if not exist ../../windows-build/libSDL/SDL-1.2.15/include/SDL.h goto _notice2 goto _done_build -:_notice +:_notice1 echo **************************************************** echo **************************************************** echo ** The required build support is not available. ** echo **************************************************** echo **************************************************** +goto _ProjectInfo +:_notice2 +echo **************************************************** +echo **************************************************** +echo ** The required build support is out of date. ** +echo **************************************************** +echo **************************************************** +goto _ProjectInfo +:_ProjectInfo type 0ReadMe_Projects.txt exit 1 :_done_build diff --git a/Visual Studio Projects/VAX610.vcproj b/Visual Studio Projects/VAX610.vcproj index 20b904b4..5f21fef8 100644 --- a/Visual Studio Projects/VAX610.vcproj +++ b/Visual Studio Projects/VAX610.vcproj @@ -27,7 +27,7 @@ + + @@ -324,6 +328,10 @@ RelativePath="..\VAX\vax610_syslist.c" > + + @@ -344,6 +352,10 @@ RelativePath="..\VAX\vax_fpa.c" > + + @@ -360,6 +372,14 @@ RelativePath="..\VAX\vax_syscm.c" > + + + + + + + + diff --git a/Visual Studio Projects/VAX630.vcproj b/Visual Studio Projects/VAX630.vcproj index 9de1010e..361d0915 100644 --- a/Visual Studio Projects/VAX630.vcproj +++ b/Visual Studio Projects/VAX630.vcproj @@ -27,7 +27,7 @@ + + @@ -320,6 +324,10 @@ RelativePath="..\VAX\vax630_syslist.c" > + + @@ -340,6 +348,10 @@ RelativePath="..\VAX\vax_fpa.c" > + + @@ -356,6 +368,14 @@ RelativePath="..\VAX\vax_syscm.c" > + + + + @@ -437,10 +457,18 @@ RelativePath="..\sim_tmxr.h" > + + + + diff --git a/makefile b/makefile index b7d0e7a9..de222b42 100644 --- a/makefile +++ b/makefile @@ -54,13 +54,18 @@ BUILD_SINGLE := $(MAKECMDGOALS) $(BLANK_SUFFIX) ifneq (,$(or $(findstring pdp11,$(MAKECMDGOALS)),$(findstring vax,$(MAKECMDGOALS)),$(findstring all,$(MAKECMDGOALS)))) NETWORK_USEFUL = true + ifneq (,$(or $(findstring microvax1,$(MAKECMDGOALS)),$(findstring microvax2,$(MAKECMDGOALS)))) + VIDEO_USEFUL = true + endif ifneq (,$(findstring all,$(MAKECMDGOALS))$(word 2,$(MAKECMDGOALS))) BUILD_MULTIPLE = s + VIDEO_USEFUL = true endif else ifeq ($(MAKECMDGOALS),) # default target is all NETWORK_USEFUL = true + VIDEO_USEFUL = true BUILD_MULTIPLE = s BUILD_SINGLE := all $(BUILD_SINGLE) endif @@ -308,6 +313,13 @@ ifeq ($(WIN32),) #*nix Environments (&& cygwin) OS_CCDEFS += -DHAVE_FNMATCH endif endif + ifneq (,$(call find_include,SDL/SDL)) + ifneq (,$(call find_lib,SDL)) + OS_CCDEFS += -DHAVE_LIBSDL -I$(dir $(call find_include,SDL/SDL)) + OS_LDFLAGS += -lSDL + $(info using libSDL: $(call find_lib,SDL) $(call find_include,SDL/SDL)) + endif + endif ifneq (,$(NETWORK_USEFUL)) ifneq (,$(call find_include,pcap)) ifneq (,$(call find_lib,$(PCAPLIB))) @@ -495,8 +507,27 @@ else NETWORK_FEATURES = - dynamic networking support using libpcap components found in the MinGW directories endif endif - OS_CCDEFS = -fms-extensions $(PTHREADS_CCDEFS) - OS_LDFLAGS = -lm -lwsock32 -lwinmm $(PTHREADS_LDFLAGS) + ifneq (,$(VIDEO_USEFUL)) + ifeq (libSDL,$(shell if exist ..\windows-build\libSDL\SDL-1.2.15\include\SDL.h echo libSDL)) + OS_CCDEFS += -DHAVE_LIBSDL -I..\windows-build\libSDL\SDL-1.2.15\include + OS_LDFLAGS += -lSDL -lSDLmain -L..\windows-build\libSDL\SDL-1.2.15\lib + else + $(info ***********************************************************************) + $(info ***********************************************************************) + $(info ** This build could produce simulators with video capabilities. **) + $(info ** However, the required files to achieve this can't be found on **) + $(info ** this system. Download the file: **) + $(info ** https://github.com/simh/windows-build/archive/windows-build.zip **) + $(info ** Refer to the file: **) + $(info ** "Visual Studio Projects\0ReadMe_Projects.txt" for where to place **) + $(info ** the 'windows-build' folder extracted from that zip file. **) + $(info ***********************************************************************) + $(info ***********************************************************************) + $(info .) + endif + endif + OS_CCDEFS += -fms-extensions $(PTHREADS_CCDEFS) + OS_LDFLAGS += -lm -lwsock32 -lwinmm $(PTHREADS_LDFLAGS) EXE = .exe ifneq (binexists,$(shell if exist BIN echo binexists)) MKDIRBIN = if not exist BIN mkdir BIN @@ -613,7 +644,8 @@ LDFLAGS := $(OS_LDFLAGS) $(NETWORK_LDFLAGS) $(LDFLAGS_O) # BIN = BIN/ SIM = scp.c sim_console.c sim_fio.c sim_timer.c sim_sock.c \ - sim_tmxr.c sim_ether.c sim_tape.c sim_disk.c sim_serial.c + sim_tmxr.c sim_ether.c sim_tape.c sim_disk.c sim_serial.c \ + sim_video.c # @@ -684,25 +716,27 @@ VAX_OPT = -DVM_VAX -DUSE_INT64 -DUSE_ADDR64 -I ${VAXD} -I ${PDP11D} ${NETWORK_OP VAX610 = ${VAXD}/vax_cpu.c ${VAXD}/vax_cpu1.c ${VAXD}/vax_fpa.c \ ${VAXD}/vax_cis.c ${VAXD}/vax_octa.c ${VAXD}/vax_cmode.c \ ${VAXD}/vax_mmu.c ${VAXD}/vax_sys.c ${VAXD}/vax_syscm.c \ - ${VAXD}/vax610_stddev.c ${VAXD}/vax610_sysdev.c \ - ${VAXD}/vax610_io.c ${VAXD}/vax610_syslist.c ${VAXD}/vax610_mem.c \ + ${VAXD}/vax610_stddev.c ${VAXD}/vax610_sysdev.c ${VAXD}/vax610_io.c \ + ${VAXD}/vax610_syslist.c ${VAXD}/vax610_mem.c ${VAXD}/vax_vc.c \ + ${VAXD}/vax_lk.c ${VAXD}/vax_vs.c ${VAXD}/vax_2681.c \ ${PDP11D}/pdp11_rl.c ${PDP11D}/pdp11_rq.c ${PDP11D}/pdp11_ts.c \ ${PDP11D}/pdp11_dz.c ${PDP11D}/pdp11_lp.c ${PDP11D}/pdp11_tq.c \ ${PDP11D}/pdp11_xq.c ${PDP11D}/pdp11_vh.c ${PDP11D}/pdp11_cr.c \ ${PDP11D}/pdp11_io_lib.c -VAX610_OPT = -DVM_VAX -DVAX_610 -DUSE_INT64 -DUSE_ADDR64 -I ${VAXD} -I ${PDP11D} ${NETWORK_OPT} +VAX610_OPT = -DVM_VAX -DVAX_610 -DUSE_INT64 -DUSE_ADDR64 -DUSE_SIM_VIDEO -I ${VAXD} -I ${PDP11D} ${NETWORK_OPT} VAX630 = ${VAXD}/vax_cpu.c ${VAXD}/vax_cpu1.c ${VAXD}/vax_fpa.c \ ${VAXD}/vax_cis.c ${VAXD}/vax_octa.c ${VAXD}/vax_cmode.c \ ${VAXD}/vax_mmu.c ${VAXD}/vax_sys.c ${VAXD}/vax_syscm.c \ ${VAXD}/vax_watch.c ${VAXD}/vax630_stddev.c ${VAXD}/vax630_sysdev.c \ - ${VAXD}/vax630_io.c ${VAXD}/vax630_syslist.c \ + ${VAXD}/vax630_io.c ${VAXD}/vax630_syslist.c ${VAXD}/vax_vc.c \ + ${VAXD}/vax_lk.c ${VAXD}/vax_vs.c ${VAXD}/vax_2681.c \ ${PDP11D}/pdp11_rl.c ${PDP11D}/pdp11_rq.c ${PDP11D}/pdp11_ts.c \ ${PDP11D}/pdp11_dz.c ${PDP11D}/pdp11_lp.c ${PDP11D}/pdp11_tq.c \ ${PDP11D}/pdp11_xq.c ${PDP11D}/pdp11_vh.c ${PDP11D}/pdp11_cr.c \ ${PDP11D}/pdp11_io_lib.c VAX620_OPT = -DVM_VAX -DVAX_620 -DUSE_INT64 -DUSE_ADDR64 -I ${VAXD} -I ${PDP11D} ${NETWORK_OPT} -VAX630_OPT = -DVM_VAX -DVAX_630 -DUSE_INT64 -DUSE_ADDR64 -I ${VAXD} -I ${PDP11D} ${NETWORK_OPT} +VAX630_OPT = -DVM_VAX -DVAX_630 -DUSE_INT64 -DUSE_ADDR64 -DUSE_SIM_VIDEO -I ${VAXD} -I ${PDP11D} ${NETWORK_OPT} VAX730 = ${VAXD}/vax_cpu.c ${VAXD}/vax_cpu1.c ${VAXD}/vax_fpa.c \ diff --git a/scp.c b/scp.c index 57252fbc..c4c92134 100644 --- a/scp.c +++ b/scp.c @@ -221,6 +221,7 @@ #include "sim_tape.h" #include "sim_ether.h" #include "sim_serial.h" +#include "sim_video.h" #include "sim_sock.h" #include #include @@ -2811,6 +2812,7 @@ if (flag) { fprintf (st, "\n\t\tMemory Access: %s Endian", sim_end ? "Little" : "Big"); fprintf (st, "\n\t\tMemory Pointer Size: %d bits", (int)sizeof(dptr)*8); fprintf (st, "\n\t\t%s", sim_toffset_64 ? "Large File (>2GB) support" : "No Large File support"); + fprintf (st, "\n\t\tSDL Video support: %s", vid_version()); fprintf (st, "\n\t\tOS clock tick size: %dms", os_tick_size); #if defined(__VMS) if (1) { @@ -6138,7 +6140,7 @@ return SCPE_OK; sim_activate add entry to event queue sim_activate_abs add entry to event queue even if event already scheduled - sim_activate_notbefure add entry to event queue even if event already scheduled + sim_activate_notbefore add entry to event queue even if event already scheduled but not before the specified time sim_activate_after add entry to event queue after a specified amount of wall time sim_cancel remove entry from event queue diff --git a/sim_video.c b/sim_video.c new file mode 100644 index 00000000..febe306d --- /dev/null +++ b/sim_video.c @@ -0,0 +1,772 @@ +/* sim_video.c: Bitmap video output + + Copyright (c) 2011-2013, Matt Burke + + 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. + + 11-Jun-2013 MB First version +*/ + +#include "sim_video.h" + +#if HAVE_LIBSDL +#include +#include + +extern int32 sim_is_running; + +#define EVENT_REDRAW 1 /* redraw event for SDL */ +#define EVENT_CLOSE 2 /* close event for SDL */ +#define MAX_EVENTS 20 /* max events in queue */ + +typedef struct { + SIM_KEY_EVENT events[MAX_EVENTS]; + SDL_sem *sem; + int32 head; + int32 tail; + int32 count; + } KEY_EVENT_QUEUE; + +typedef struct { + SIM_MOUSE_EVENT events[MAX_EVENTS]; + SDL_sem *sem; + int32 head; + int32 tail; + int32 count; + t_bool b1_state; + t_bool b2_state; + t_bool b3_state; + } MOUSE_EVENT_QUEUE; + +int vid_thread (void* arg); + +t_bool vid_active; +t_bool vid_key_state[SDLK_LAST]; +t_bool vid_mouse_captured; +int32 vid_width; +int32 vid_height; +SDL_Surface *vid_image; /* video buffer */ +SDL_Surface *vid_window; /* window handle */ +SDL_Thread *vid_thread_id; /* event thread handle */ +SDL_Color vid_palette[256]; +KEY_EVENT_QUEUE vid_key_events; /* keyboard events */ +MOUSE_EVENT_QUEUE vid_mouse_events; /* mouse events */ + +t_stat vid_open (uint32 width, uint32 height) +{ +if (!vid_active) { + vid_active = TRUE; + vid_width = width; + vid_height = height; + vid_mouse_captured = FALSE; + + vid_key_events.head = 0; + vid_key_events.tail = 0; + vid_key_events.count = 0; + vid_key_events.sem = SDL_CreateSemaphore (1); + vid_mouse_events.head = 0; + vid_mouse_events.tail = 0; + vid_mouse_events.count = 0; + vid_mouse_events.sem = SDL_CreateSemaphore (1); + + vid_thread_id = SDL_CreateThread (vid_thread, NULL); + if (vid_thread_id == NULL) { + vid_active = FALSE; + return SCPE_OPENERR; + } + + vid_image = SDL_CreateRGBSurface (SDL_SWSURFACE, width, height, 8, 0, 0, 0, 0); + + vid_palette[0].r = 0; + vid_palette[0].g = 0; + vid_palette[0].b = 0; + vid_palette[1].r = 255; + vid_palette[1].g = 255; + vid_palette[1].b = 255; + SDL_SetColors (vid_image, vid_palette, 0, 2); + + memset (&vid_key_state, 0, sizeof(vid_key_state)); + } +return SCPE_OK; +} + +t_stat vid_close (void) +{ +SDL_Event user_event; + +if (vid_active) { + vid_active = FALSE; + user_event.type = SDL_USEREVENT; + user_event.user.code = EVENT_CLOSE; + user_event.user.data1 = NULL; + user_event.user.data2 = NULL; + + SDL_PushEvent (&user_event); + } +return SCPE_OK; +} + +t_stat vid_poll_kb (SIM_KEY_EVENT *ev) +{ +if (SDL_SemTryWait (vid_key_events.sem) == 0) { /* get lock */ + if (vid_key_events.count > 0) { /* events in queue? */ + *ev = vid_key_events.events[vid_key_events.head++]; + vid_key_events.count--; + if (vid_key_events.head == MAX_EVENTS) + vid_key_events.head = 0; + SDL_SemPost (vid_key_events.sem); + return SCPE_OK; + } + SDL_SemPost (vid_key_events.sem); + } +return SCPE_EOF; +} + +t_stat vid_poll_mouse (SIM_MOUSE_EVENT *ev) +{ +if (SDL_SemTryWait (vid_mouse_events.sem) == 0) { + if (vid_mouse_events.count > 0) { + *ev = vid_mouse_events.events[vid_mouse_events.head++]; + vid_mouse_events.count--; + if (vid_mouse_events.head == MAX_EVENTS) + vid_mouse_events.head = 0; + SDL_SemPost (vid_mouse_events.sem); + return SCPE_OK; + } + SDL_SemPost (vid_mouse_events.sem); + } +return SCPE_EOF; +} + +void vid_draw (int32 x, int32 y, int32 w, int32 h, uint8 *buf) +{ +int32 i, j; +uint8* pix; + +pix = (uint8 *)vid_image->pixels; +pix = pix + (y * vid_width) + x; + +for (i = y; i < (y + h); i++) { + for (j = x; j < (x + w); j++) { + *pix++ = *buf++; + } + pix = pix + vid_width; + } +} + +void vid_refresh (void) +{ +SDL_Event user_event; + +user_event.type = SDL_USEREVENT; +user_event.user.code = EVENT_REDRAW; +user_event.user.data1 = NULL; +user_event.user.data2 = NULL; + +SDL_PushEvent (&user_event); +} + +int vid_map_key (int key) +{ +switch (key) { + + case SDLK_BACKSPACE: + return SIM_KEY_BACKSPACE; + + case SDLK_TAB: + return SIM_KEY_TAB; + + case SDLK_RETURN: + return SIM_KEY_ENTER; + + case SDLK_PAUSE: + return SIM_KEY_PAUSE; + + case SDLK_ESCAPE: + return SIM_KEY_ESC; + + case SDLK_SPACE: + return SIM_KEY_SPACE; + + case SDLK_QUOTE: + return SIM_KEY_SINGLE_QUOTE; + + case SDLK_COMMA: + return SIM_KEY_COMMA; + + case SDLK_MINUS: + return SIM_KEY_MINUS; + + case SDLK_PERIOD: + return SIM_KEY_PERIOD; + + case SDLK_SLASH: + return SIM_KEY_SLASH; + + case SDLK_0: + return SIM_KEY_0; + + case SDLK_1: + return SIM_KEY_1; + + case SDLK_2: + return SIM_KEY_2; + + case SDLK_3: + return SIM_KEY_3; + + case SDLK_4: + return SIM_KEY_4; + + case SDLK_5: + return SIM_KEY_5; + + case SDLK_6: + return SIM_KEY_6; + + case SDLK_7: + return SIM_KEY_7; + + case SDLK_8: + return SIM_KEY_8; + + case SDLK_9: + return SIM_KEY_9; + + case SDLK_SEMICOLON: + return SIM_KEY_SEMICOLON; + + case SDLK_EQUALS: + return SIM_KEY_EQUALS; + + case SDLK_LEFTBRACKET: + return SIM_KEY_LEFT_BRACKET; + + case SDLK_BACKSLASH: + return SIM_KEY_BACKSLASH; + + case SDLK_RIGHTBRACKET: + return SIM_KEY_RIGHT_BRACKET; + + case SDLK_BACKQUOTE: + return SIM_KEY_BACKQUOTE; + + case SDLK_a: + return SIM_KEY_A; + + case SDLK_b: + return SIM_KEY_B; + + case SDLK_c: + return SIM_KEY_C; + + case SDLK_d: + return SIM_KEY_D; + + case SDLK_e: + return SIM_KEY_E; + + case SDLK_f: + return SIM_KEY_F; + + case SDLK_g: + return SIM_KEY_G; + + case SDLK_h: + return SIM_KEY_H; + + case SDLK_i: + return SIM_KEY_I; + + case SDLK_j: + return SIM_KEY_J; + + case SDLK_k: + return SIM_KEY_K; + + case SDLK_l: + return SIM_KEY_L; + + case SDLK_m: + return SIM_KEY_M; + + case SDLK_n: + return SIM_KEY_N; + + case SDLK_o: + return SIM_KEY_O; + + case SDLK_p: + return SIM_KEY_P; + + case SDLK_q: + return SIM_KEY_Q; + + case SDLK_r: + return SIM_KEY_R; + + case SDLK_s: + return SIM_KEY_S; + + case SDLK_t: + return SIM_KEY_T; + + case SDLK_u: + return SIM_KEY_U; + + case SDLK_v: + return SIM_KEY_V; + + case SDLK_w: + return SIM_KEY_W; + + case SDLK_x: + return SIM_KEY_X; + + case SDLK_y: + return SIM_KEY_Y; + + case SDLK_z: + return SIM_KEY_Z; + + case SDLK_DELETE: + return SIM_KEY_DELETE; + + case SDLK_KP0: + return SIM_KEY_KP_INSERT; + + case SDLK_KP1: + return SIM_KEY_KP_END; + + case SDLK_KP2: + return SIM_KEY_KP_DOWN; + + case SDLK_KP3: + return SIM_KEY_KP_PAGE_DOWN; + + case SDLK_KP4: + return SIM_KEY_KP_LEFT; + + case SDLK_KP5: + return SIM_KEY_KP_5; + + case SDLK_KP6: + return SIM_KEY_KP_RIGHT; + + case SDLK_KP7: + return SIM_KEY_KP_HOME; + + case SDLK_KP8: + return SIM_KEY_KP_UP; + + case SDLK_KP9: + return SIM_KEY_KP_PAGE_UP; + + case SDLK_KP_PERIOD: + return SIM_KEY_KP_DELETE; + + case SDLK_KP_DIVIDE: + return SIM_KEY_KP_DIVIDE; + + case SDLK_KP_MULTIPLY: + return SIM_KEY_KP_MULTIPLY; + + case SDLK_KP_MINUS: + return SIM_KEY_KP_SUBTRACT; + + case SDLK_KP_PLUS: + return SIM_KEY_KP_ADD; + + case SDLK_KP_ENTER: + return SIM_KEY_KP_ENTER; + + case SDLK_UP: + return SIM_KEY_UP; + + case SDLK_DOWN: + return SIM_KEY_DOWN; + + case SDLK_RIGHT: + return SIM_KEY_RIGHT; + + case SDLK_LEFT: + return SIM_KEY_LEFT; + + case SDLK_INSERT: + return SIM_KEY_INSERT; + + case SDLK_HOME: + return SIM_KEY_HOME; + + case SDLK_END: + return SIM_KEY_END; + + case SDLK_PAGEUP: + return SIM_KEY_PAGE_UP; + + case SDLK_PAGEDOWN: + return SIM_KEY_PAGE_DOWN; + + case SDLK_F1: + return SIM_KEY_F1; + + case SDLK_F2: + return SIM_KEY_F2; + + case SDLK_F3: + return SIM_KEY_F3; + + case SDLK_F4: + return SIM_KEY_F4; + + case SDLK_F5: + return SIM_KEY_F5; + + case SDLK_F6: + return SIM_KEY_F6; + + case SDLK_F7: + return SIM_KEY_F7; + + case SDLK_F8: + return SIM_KEY_F8; + + case SDLK_F9: + return SIM_KEY_F9; + + case SDLK_F10: + return SIM_KEY_F10; + + case SDLK_F11: + return SIM_KEY_F11; + + case SDLK_F12: + return SIM_KEY_F12; + + case SDLK_NUMLOCK: + return SIM_KEY_NUM_LOCK; + + case SDLK_CAPSLOCK: + return SIM_KEY_CAPS_LOCK; + + case SDLK_SCROLLOCK: + return SIM_KEY_SCRL_LOCK; + + case SDLK_RSHIFT: + return SIM_KEY_SHIFT_R; + + case SDLK_LSHIFT: + return SIM_KEY_SHIFT_L; + + case SDLK_RCTRL: + return SIM_KEY_CTRL_R; + + case SDLK_LCTRL: + return SIM_KEY_CTRL_L; + + case SDLK_RALT: + return SIM_KEY_ALT_R; + + case SDLK_LALT: + return SIM_KEY_ALT_L; + + case SDLK_RMETA: + return SIM_KEY_ALT_R; + + case SDLK_LMETA: + return SIM_KEY_WIN_L; + + case SDLK_LSUPER: + return SIM_KEY_WIN_L; + + case SDLK_RSUPER: + return SIM_KEY_WIN_R; + + case SDLK_PRINT: + return SIM_KEY_PRINT; + + case SDLK_BREAK: + return SIM_KEY_PAUSE; + + case SDLK_MENU: + return SIM_KEY_MENU; + + default: + return SIM_KEY_UNKNOWN; + } +} + +void vid_key (SDL_KeyboardEvent *event) +{ +SIM_KEY_EVENT ev; + +if (vid_mouse_captured) { + static Uint8 *KeyStates = NULL; + static int numkeys; + + if (!KeyStates) + KeyStates = SDL_GetKeyState(&numkeys); + if ((event->state == SDL_PRESSED) && KeyStates[SDLK_RSHIFT] && (KeyStates[SDLK_LCTRL] || KeyStates[SDLK_RCTRL])) { + SDL_WM_GrabInput (SDL_GRAB_OFF); /* relese cursor */ + SDL_ShowCursor (SDL_ENABLE); /* show cursor */ + vid_mouse_captured = FALSE; + return; + } + } +if (!sim_is_running) + return; +if (SDL_SemWait (vid_key_events.sem) == 0) { + if (vid_key_events.count < MAX_EVENTS) { + if (event->state == SDL_PRESSED) { + if (!vid_key_state[event->keysym.sym]) { /* Key was not down before */ + vid_key_state[event->keysym.sym] = TRUE; + ev.key = vid_map_key (event->keysym.sym); + ev.state = SIM_KEYPRESS_DOWN; + } + else { + ev.key = vid_map_key (event->keysym.sym); + ev.state = SIM_KEYPRESS_REPEAT; + } + } + else { + vid_key_state[event->keysym.sym] = FALSE; + ev.key = vid_map_key (event->keysym.sym); + ev.state = SIM_KEYPRESS_UP; + } + vid_key_events.events[vid_key_events.tail++] = ev; + vid_key_events.count++; + if (vid_key_events.tail == MAX_EVENTS) + vid_key_events.tail = 0; + } + SDL_SemPost (vid_key_events.sem); + } +} + +void vid_mouse_move (SDL_MouseMotionEvent *event) +{ +SDL_Event dummy_event; +int32 cx; +int32 cy; +SIM_MOUSE_EVENT ev; + +if (!vid_mouse_captured) + return; + +if ((event->x == 0) || + (event->y == 0) || + (event->x == (vid_width - 1)) || + (event->y == (vid_height - 1))) { /* reached edge of window? */ + cx = vid_width / 2; + cy = vid_height / 2; + SDL_WarpMouse (cx, cy); /* back to centre */ + SDL_PumpEvents (); + while (SDL_PeepEvents (&dummy_event, 1, SDL_GETEVENT, SDL_MOUSEMOTIONMASK)) {}; + } +if (!sim_is_running) + return; +if (SDL_SemWait (vid_mouse_events.sem) == 0) { + if (vid_mouse_events.count < MAX_EVENTS) { + ev.x_rel = event->xrel; + ev.y_rel = (-event->yrel); + ev.b1_state = (event->state & SDL_BUTTON(SDL_BUTTON_LEFT)) ? TRUE : FALSE; + ev.b2_state = (event->state & SDL_BUTTON(SDL_BUTTON_MIDDLE)) ? TRUE : FALSE; + ev.b3_state = (event->state & SDL_BUTTON(SDL_BUTTON_RIGHT)) ? TRUE : FALSE; + vid_mouse_events.b1_state = ev.b1_state; + vid_mouse_events.b2_state = ev.b2_state; + vid_mouse_events.b3_state = ev.b3_state; + vid_mouse_events.events[vid_mouse_events.tail++] = ev; + vid_mouse_events.count++; + if (vid_mouse_events.tail == MAX_EVENTS) + vid_mouse_events.tail = 0; + } + SDL_SemPost (vid_mouse_events.sem); + } +} + +void vid_mouse_button (SDL_MouseButtonEvent *event) +{ +SDL_Event dummy_event; +int32 cx; +int32 cy; +SIM_MOUSE_EVENT ev; +t_bool state; + +if (!vid_mouse_captured) { + if ((event->state == SDL_PRESSED) && + (event->button == SDL_BUTTON_LEFT)) { /* left click and cursor not captured? */ + SDL_WM_GrabInput (SDL_GRAB_ON); /* lock cursor to window */ + SDL_ShowCursor (SDL_DISABLE); /* hide cursor */ + cx = vid_width / 2; + cy = vid_height / 2; + SDL_WarpMouse (cx, cy); /* move cursor to centre of window */ + SDL_PumpEvents (); + while (SDL_PeepEvents (&dummy_event, 1, SDL_GETEVENT, SDL_MOUSEMOTIONMASK)) {}; + vid_mouse_captured = TRUE; + } + return; + } +if (!sim_is_running) + return; +if (SDL_SemWait (vid_mouse_events.sem) == 0) { + if (vid_mouse_events.count < MAX_EVENTS) { + state = (event->state == SDL_PRESSED) ? TRUE : FALSE; + ev.x_rel = 0; + ev.y_rel = 0; + switch (event->button) { + case SDL_BUTTON_LEFT: + vid_mouse_events.b1_state = state; + break; + case SDL_BUTTON_MIDDLE: + vid_mouse_events.b2_state = state; + break; + case SDL_BUTTON_RIGHT: + vid_mouse_events.b3_state = state; + break; + } + ev.b1_state = vid_mouse_events.b1_state; + ev.b2_state = vid_mouse_events.b2_state; + ev.b3_state = vid_mouse_events.b3_state; + vid_mouse_events.events[vid_mouse_events.tail++] = ev; + vid_mouse_events.count++; + if (vid_mouse_events.tail == MAX_EVENTS) + vid_mouse_events.tail = 0; + } + SDL_SemPost (vid_mouse_events.sem); + } +} + +void vid_update (void) +{ +SDL_Rect vid_dst; + +vid_dst.x = 0; +vid_dst.y = 0; +vid_dst.w = vid_width; +vid_dst.h = vid_height; + +SDL_BlitSurface (vid_image, NULL, vid_window, &vid_dst); +SDL_UpdateRects (vid_window, 1, &vid_dst); +} + +int vid_thread (void* arg) +{ +int vid_bpp = 8; +int vid_flags = 0; +SDL_Event event; + +if (SDL_Init (SDL_INIT_VIDEO|SDL_INIT_NOPARACHUTE) < 0) { + return SCPE_OPENERR; + } + +vid_window = SDL_SetVideoMode (vid_width, vid_height, vid_bpp, vid_flags); + +if (vid_window == NULL) { + return SCPE_OPENERR; + } + +if (SDL_EnableKeyRepeat (SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL) < 0) { + return SCPE_OPENERR; + } + +SDL_WM_SetCaption (&sim_name[0], &sim_name[0]); + +while (vid_active) { + if (SDL_WaitEvent (&event)) { + switch (event.type) { + + case SDL_KEYDOWN: + case SDL_KEYUP: + vid_key ((SDL_KeyboardEvent*)&event); + break; + + case SDL_MOUSEBUTTONDOWN: + case SDL_MOUSEBUTTONUP: + vid_mouse_button ((SDL_MouseButtonEvent*)&event); + break; + + case SDL_MOUSEMOTION: + vid_mouse_move ((SDL_MouseMotionEvent*)&event); + break; + + case SDL_USEREVENT: + if (event.user.code == EVENT_REDRAW) + vid_update (); + break; + + default: + break; + } + } + } +SDL_Quit (); +return 0; +} + +const char *vid_version(void) +{ +static char SDLVersion[80]; +const SDL_version *ver = SDL_Linked_Version(); + +sprintf(SDLVersion, "SDL Version %d.%d.%d", ver->major, ver->minor, ver->patch); +return (const char *)SDLVersion; +} + +#else + +/* Non-implemented versions */ + +t_stat vid_open (uint32 width, uint32 height) +{ +return SCPE_NOFNC; +} + +t_stat vid_close (void) +{ +return SCPE_OK; +} + +t_stat vid_poll_kb (SIM_KEY_EVENT *ev) +{ +return SCPE_EOF; +} + +t_stat vid_poll_mouse (SIM_MOUSE_EVENT *ev) +{ +return SCPE_EOF; +} + +void vid_draw (int32 x, int32 y, int32 w, int32 h, uint8 *buf) +{ +return; +} + +void vid_refresh (void) +{ +return; +} + +const char *vid_version (void) +{ +return "No Video Support"; +} + +#endif diff --git a/sim_video.h b/sim_video.h new file mode 100644 index 00000000..87e66fbf --- /dev/null +++ b/sim_video.h @@ -0,0 +1,179 @@ +/* sim_video.c: Bitmap video output + + Copyright (c) 2011-2013, Matt Burke + + 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. + + 11-Jun-2013 MB First version +*/ + +#ifndef _SIM_VIDEO_H_ +#define _SIM_VIDEO_H_ 0 + +#include "sim_defs.h" + +#define SIM_KEYPRESS_DOWN 0 /* key states */ +#define SIM_KEYPRESS_UP 1 +#define SIM_KEYPRESS_REPEAT 2 + + +#define SIM_KEY_F1 0 /* key syms */ +#define SIM_KEY_F2 1 +#define SIM_KEY_F3 2 +#define SIM_KEY_F4 3 +#define SIM_KEY_F5 4 +#define SIM_KEY_F6 5 +#define SIM_KEY_F7 6 +#define SIM_KEY_F8 7 +#define SIM_KEY_F9 8 +#define SIM_KEY_F10 9 +#define SIM_KEY_F11 10 +#define SIM_KEY_F12 11 + +#define SIM_KEY_0 12 +#define SIM_KEY_1 13 +#define SIM_KEY_2 14 +#define SIM_KEY_3 15 +#define SIM_KEY_4 16 +#define SIM_KEY_5 17 +#define SIM_KEY_6 18 +#define SIM_KEY_7 19 +#define SIM_KEY_8 20 +#define SIM_KEY_9 21 + +#define SIM_KEY_A 22 +#define SIM_KEY_B 23 +#define SIM_KEY_C 24 +#define SIM_KEY_D 25 +#define SIM_KEY_E 26 +#define SIM_KEY_F 27 +#define SIM_KEY_G 28 +#define SIM_KEY_H 29 +#define SIM_KEY_I 30 +#define SIM_KEY_J 31 +#define SIM_KEY_K 32 +#define SIM_KEY_L 33 +#define SIM_KEY_M 34 +#define SIM_KEY_N 35 +#define SIM_KEY_O 36 +#define SIM_KEY_P 37 +#define SIM_KEY_Q 38 +#define SIM_KEY_R 39 +#define SIM_KEY_S 40 +#define SIM_KEY_T 41 +#define SIM_KEY_U 42 +#define SIM_KEY_V 43 +#define SIM_KEY_W 44 +#define SIM_KEY_X 45 +#define SIM_KEY_Y 46 +#define SIM_KEY_Z 47 + +#define SIM_KEY_BACKQUOTE 48 +#define SIM_KEY_MINUS 49 +#define SIM_KEY_EQUALS 50 +#define SIM_KEY_LEFT_BRACKET 51 +#define SIM_KEY_RIGHT_BRACKET 52 +#define SIM_KEY_SEMICOLON 53 +#define SIM_KEY_SINGLE_QUOTE 54 +#define SIM_KEY_BACKSLASH 55 +#define SIM_KEY_LEFT_BACKSLASH 56 +#define SIM_KEY_COMMA 57 +#define SIM_KEY_PERIOD 58 +#define SIM_KEY_SLASH 59 + +#define SIM_KEY_PRINT 60 +#define SIM_KEY_SCRL_LOCK 61 +#define SIM_KEY_PAUSE 62 + +#define SIM_KEY_ESC 63 +#define SIM_KEY_BACKSPACE 64 +#define SIM_KEY_TAB 65 +#define SIM_KEY_ENTER 66 +#define SIM_KEY_SPACE 67 +#define SIM_KEY_INSERT 68 +#define SIM_KEY_DELETE 69 +#define SIM_KEY_HOME 70 +#define SIM_KEY_END 71 +#define SIM_KEY_PAGE_UP 72 +#define SIM_KEY_PAGE_DOWN 73 +#define SIM_KEY_UP 74 +#define SIM_KEY_DOWN 75 +#define SIM_KEY_LEFT 76 +#define SIM_KEY_RIGHT 77 + +#define SIM_KEY_CAPS_LOCK 78 +#define SIM_KEY_NUM_LOCK 79 + +#define SIM_KEY_ALT_L 80 +#define SIM_KEY_ALT_R 81 +#define SIM_KEY_CTRL_L 82 +#define SIM_KEY_CTRL_R 83 +#define SIM_KEY_SHIFT_L 84 +#define SIM_KEY_SHIFT_R 85 +#define SIM_KEY_WIN_L 86 +#define SIM_KEY_WIN_R 87 +#define SIM_KEY_MENU 88 + +#define SIM_KEY_KP_ADD 89 +#define SIM_KEY_KP_SUBTRACT 90 +#define SIM_KEY_KP_END 91 +#define SIM_KEY_KP_DOWN 92 +#define SIM_KEY_KP_PAGE_DOWN 93 +#define SIM_KEY_KP_LEFT 94 +#define SIM_KEY_KP_RIGHT 95 +#define SIM_KEY_KP_HOME 96 +#define SIM_KEY_KP_UP 97 +#define SIM_KEY_KP_PAGE_UP 98 +#define SIM_KEY_KP_INSERT 99 +#define SIM_KEY_KP_DELETE 100 +#define SIM_KEY_KP_5 101 +#define SIM_KEY_KP_ENTER 102 +#define SIM_KEY_KP_MULTIPLY 103 +#define SIM_KEY_KP_DIVIDE 104 + +#define SIM_KEY_UNKNOWN 200 + +struct mouse_event { + uint32 x_rel; /* X axis relative motion */ + uint32 y_rel; /* Y axis relative motion */ + t_bool b1_state; /* state of button 1 */ + t_bool b2_state; /* state of button 2 */ + t_bool b3_state; /* state of button 3 */ + }; + +struct key_event { + uint32 key; /* key sym */ + uint32 state; /* key state change */ + }; + +typedef struct mouse_event SIM_MOUSE_EVENT; +typedef struct key_event SIM_KEY_EVENT; + +t_stat vid_open (uint32 width, uint32 height); +t_stat vid_close (void); +t_stat vid_poll_kb (SIM_KEY_EVENT *ev); +t_stat vid_poll_mouse (SIM_MOUSE_EVENT *ev); +void vid_draw (int32 x, int32 y, int32 w, int32 h, uint8 *buf); +void vid_refresh (void); +const char *vid_version (void); + +#endif