/* ka10_iii.c: Triple III display processor.

   Copyright (c) 2019-2020, Richard Cornwell

   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
   RICHARD CORNWELL 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 Richard Cornwell shall not be
   used in advertising or otherwise to promote the sale, use or other dealings
   in this Software without prior written authorization from Richard Cornwell

*/

#include "kx10_defs.h"
#ifndef NUM_DEVS_III
#define NUM_DEVS_III 0
#endif

#if NUM_DEVS_III > 0
#include "display/display.h"
#include "display/iii.h"

#define III_DEVNUM        0430

#define STATUS            u3
#define MAR               u4
#define PIA               u5
#define POS               u6

/* CONO Bits */
#define SET_PIA    000000010    /* Set if this bit is zero */
#define STOP       000000020    /* Stop processor after instruction */
#define CONT       000000040    /* Start execution at address */
#define F          000000100    /* Clear flags */
#define SET_MSK    000360000    /* Set mask */
#define RST_MSK    007400000    /* Reset mask */

/* CONI Bits */
#define PIA_MSK    000000007
#define INST_HLT   000000010    /* 32 - Halt instruction */
#define WRAP_ENB   000000020    /* 31 - Wrap around mask */
#define EDGE_ENB   000000040    /* 30 - Edge interrupt mask */
#define LIGH_ENB   000000100    /* 29 - Light pen enable mask */
#define CLK_STOP   000000200    /* 28 - Clock stop */
                                /* 27 - Not used */
#define CLK_BIT    000001000    /* 26 - Clock */
#define NXM_BIT    000002000    /* 25 - Non-existent memory */
#define IRQ_BIT    000004000    /* 24 - Interrupt pending */
#define DATAO_LK   000010000    /* 23 - PDP10 gave DATAO when running */
#define CONT_BIT   000020000    /* 22 - Control bit */
#define LIGHT_FLG  000040000    /* 21 - Light pen flag */
#define WRAP_FLG   000100000    /* 20 - Wrap around flag */
#define EDGE_FLG   000200000    /* 19 - Edge overflow */
#define HLT_FLG    000400000    /* 18 - Not running */

#define WRAP_MSK   00001
#define EDGE_MSK   00002
#define LIGH_MSK   00004
#define HLT_MSK    00010
#define WRP_FBIT   00020
#define EDG_FBIT   00040
#define LIT_FBIT   00100
#define CTL_FBIT   00200
#define HLT_FBIT   00400
#define NXM_FLG    01000
#define DATA_FLG   02000
#define RUN_FLG    04000

#define TSS_INST   012          /* Test  */
#define LVW_INST   006          /* Long Vector */
#define SVW_INST   002          /* Short vector */
#define JMP_INST   000          /* Jump or Halt */
#define JSR_INST   004          /* JSR(1) or JMS(0), SAVE(3) */
#define RES_INST   014          /* Restore */
#define SEL_INST   010          /* Select instruction */

#define POS_X      01777400000
#define POS_Y      00000377700
#define CBRT       00000000070       /* Current brightness */
#define CSIZE      00000000007       /* Current char size */
#define POS_X_V    17
#define POS_Y_V    6
#define CBRT_V     3
#define CSIZE_V    0

/*
 * Character map.
 * M(x,y) moves pointer to x,y.
 * V(x,y) draws a vector between current pointer and x,y.
 * All characters start at 0,6 and end at 8,6.
 * In the map there are up to 18 points per character. For a character a M(0,0) indicates
 * that drawing is done and a move to 8,6 should be done.
 */
#define M(x,y)   (x << 4)|y|0000
#define V(x,y)   (x << 4)|y|0200

uint8 map[128][18] = {
   /* Blank */    { 0 },
   /* Down */     { M(0,9), V(3,6), V(3,14), M(3,6), V(6,9) },
   /* Alpha */    { M(6,6), V(3,9), V(1,9), V(0,8), V(0,7), V(1,6), V(3,6), V(6,9) },
   /* Beta */     { V(2,8), V(2,13), V(3,14), V(5,14), V(6,13), V(6,12), V(5,11),
                    V(2,11), M(5,11), V(6,10), V(6,9), V(5,8), V(3,8), V(2,9) },
   /* ^ */        { M(0,8), V(3,11), V(6,8) },
   /* Not */      { M(0,10), V(6,10), V(6,7) },
   /* Epsilon */  { M(3,9), V(2,10), V(1,10), V(0,9), V(0,7), V(1,6), V(2,6), V(3,7),
                    M(2,8), V(0,8) },
   /* Pi */       { M(0,10), V(6,10), M(4,10), V(4,6), M(2,6), V(2,10) },
   /* Lambda */   { V(3,9), M(0,11), V(1,11), V(6,6) },
   /* ??  */      { M(0,11), V(1,12), V(2,12), V(5,9), V(5,7), V(4,6), V(3,6), V(2,7),
                    V(2,8), V(6,12) },
   /* Delta */    { M(2,10), V(1,10), V(0,9), V(0,7), V(1,6), V(3,6), V(4,7), V(4,9),
                    V(3,10), V(2,10), V(2,12), V(4,12) },
   /* Integ */    { M(0,7), V(1,6), V(2,6), V(3,7), V(3,12), V(4,13), V(5,13), V(6,12) },
   /* PlusMinus */{ M(0,9), V(4,9), M(2,11), V(2,7), M(0,7), V(4,7) },
   /* Circross */ { M(0,8), V(0,7), V(1,6), V(3,6), V(4,7), V(4,9), V(3,10), V(1,10),
                    V(0,9), V(0,8), V(4,8), M(2,10), V(2,6) },
   /* Sigma */    { M(0,10), V(1,9), V(2,9), V(4,11), V(5,11), V(6,10), V(5,9), V(4,9),
                    V(2,11), V(1,11), V(0,10) },
   /* Union */    { M(4,8), V(3,9), V(1,9), V(0,8), V(0,7), V(1,6), V(3,6), V(4,7),
                    V(4,10), V(2,12), V(1,12) },
   /* Intersect */{ M(3,11), V(1,11), V(0,10), V(0,8), V(1,7), V(3,7) },
   /* Cap */      { M(0,11), V(2,11), V(3,10), V(3,8), V(2,7), V(0,7) },
   /* Cup */      { M(0,7), V(0,9), V(1,10), V(3,10), V(4,9), V(4,7) },
   /* A */        { M(0,10), V(0,8), V(1,7), V(3,7), V(4,8), V(4,10) },
   /* E */        { M(0,13), V(0,8), V(2,6), V(4,6), V(6,8), V(6,13), M(0,10), V(6,10) },
   /* cx */       { V(6,6), V(6,14), V(0,14), M(2,10), V(6,10) },
                  { V(4,10), M(0,10), V(4,6), M(3,6), V(1,6), V(0,7), V(0,9), V(1,10),
                    V(3,10), V(4,9), V(4,7), V(3,6) },
   /* Dbl arrow */{ M(2,8), V(0,10), V(2,12), M(0,10), V(6,10), M(4,12), V(6,10),
                    V(4,8)},
   /* Under */    { M(0,5), V(6,5) },
                  { M(0,10), V(6,10), M(3,13), V(6,10), V(3,7) },
                  { M(0,12), V(2,14), V(4,12), V(6,14) },
                  { V(6,12), M(0,10), V(6,10), M(0,8), V(6,8) },
                  { V(3,6), M(3,7), V(0,10), V(3,13) },
                  { V(3,6), M(0,7), V(3,10), V(0,13) },
                  { M(0,7), V(6,7), M(6,9), V(0,9), M(0,11), V(6,11) },
                  { M(0,11), V(3,8), V(6,11) },
   /* Blank */    { 0, },
   /* ! */        { M(2,6), V(2,7), M(2,8), V(2,13) },
   /* " */        { M(2,12), V(2,14), M(4,14), V(4,12) },
   /* # */        { M(2,7), V(2,13), M(4,13), V(4,7), M(6,9), V(0,9), M(0,11), V(6,11) },
   /* $ */        { M(0,8), V(2,6), V(4,6), V(6,8), V(4,10), V(2,10), V(0,12), V(2,14),
                    V(4,14), V(6,12), M(4,14), V(4,6), M(2,6), V(2,14) },
   /* % */        { V(6,12), V(1,12), V(0,11), V(0,10), V(1,9), V(2,9), V(3,10), V(3,11),
                    V(2,12), M(4,9), V(3,8), V(3,7), V(4,6), V(5,6), V(6,7), V(6,8),
                    V(5,9), V(4,9) },
   /* & */        { M(6,6), V(1,11), V(1,13), V(2,14), V(3,14), V(4,13), V(0,9), V(0,7),
                    V(1,6), V(3,6), V(5,8) },
   /* ' */        { M(2,12), V(4,14) },
   /* ( */        { M(2,6), V(0,8), V(0,12), V(2,14) },
   /* ) */        { V(2,8), V(2,12), V(0,14) },
   /* * */        { M(1,8), V(5,12), M(3,13), V(3,7), M(5,8), V(1,12), M(0,10),
                    V(6,10) },
   /* + */        { M(2,7), V(2,11), M(0,9), V(4,9) },
   /* , */        { M(0,7), V(1,6), V(1,5), V(0,4) },
   /* - */        { M(0,9), V(4,9) },
   /* . */        { M(2,6), V(3,6), V(3,7), V(2,7), V(2,6) },
   /* / */        { V(6,12) },
   /* 0 */        { M(0,7), V(6,13), M(6,12), V(4,14), V(2,14), V(0,12), V(0,8), V(2,6),
                    V(4,6), V(6,8), V(6,12) },
   /* 1 */        { M(1,12), V(3,14), V(3,6) },
   /* 2 */        { M(0,13), V(1,14), V(4,14), V(6,12), V(6,11), V(5,10), V(2,10),
                    V(0,8), V(0,6), V(6,6) },
   /* 3 */        { M(0,14), V(6,14), V(6,12), V(4,10), V(5,10), V(6,9), V(6,7), V(5,6),
                    V(0,6) },
   /* 4 */        { M(5,6), V(5,14), V(0,9), V(6,9) },
   /* 5 */        { M(0,7), V(1,6), V(4,6), V(6,8), V(6,9), V(5,10), V(1,10), V(0,9),
                    V(0,14), V(6,14) },
   /* 6 */        { M(0,9), V(1,10), V(5,10), V(6,9), V(6,7), V(5,6), V(1,6), V(0,7),
                    V(0,10), V(4,14) },
   /* 7 */        { V(6,12), V(6,14), V(0,14) },
   /* 8 */        { M(1,10), V(0,9), V(0,7), V(1,6), V(5,6), V(6,7), V(6,9), V(5,10),
                    V(6,11), V(6,13), V(5,14), V(1,14), V(0,13), V(0,11), V(1,10),
                    V(5,10) },
   /* 9 */        { M(2,6), V(6,10), V(6,13), V(5,14), V(1,14), V(0,13), V(0,11),
                    V(1,10), V(5,10), V(6,11) },
   /* : */        { M(2,6), V(3,6), V(3,7), V(2,7), V(2,6), M(2,10), V(3,10), V(3,11),
                    V(2,11), V(2,10) },
   /* ; */        { M(2,7), V(3,6), V(3,5), V(2,4), M(2,10), V(3,10), V(3,11), V(2,11),
                    V(2,10) },
   /* < */        { M(3,7), V(0,10), V(3,13) },
   /* = */        { M(0,8), V(6,8), M(6,10), V(0,10) },
   /* > */        { M(0,7), V(3,10), V(0,13) },
   /* ? */        { M(0,13), V(1,14), V(2,13), V(2,12), V(1,11), V(1,8), M(1,7),
                    V(1,6) },
   /* @ */        { M(1,6), V(0,7), V(0,11), V(1,12), V(5,12), V(6,11), V(6,8), V(5,7),
                    V(4,8), V(4,11), M(4,10), V(3,11), V(2,11), V(1,10), V(1,9), V(2,8),
                    V(3,8), V(4,9) },
   /* A */        { V(0,12), V(2,14), V(4,14), V(6,12), V(6,9), V(0,9), V(6,9), V(6,6) },
   /* B */        { V(0,14), V(5,14), V(6,13), V(6,11), V(5,10), V(0,10), V(5,10),
                    V(6,9), V(6,7), V(5,6), V(0,6) },
   /* C */        { M(6,13), V(5,14), V(2,14), V(0,12), V(0,8), V(2,6), V(5,6), V(6,7) },
   /* D */        { V(0,14), V(4,14), V(6,12), V(6,8), V(4,6), V(0,6) },
   /* E */        { M(6,6), V(0,6), V(0,10), V(4,10), V(0,10), V(0,14), V(6,14) },
   /* F */        { V(0,10), V(4,10), V(0,10), V(0,14), V(6,14) },
   /* G */        { M(6,13), V(5,14), V(2,14), V(0,12), V(0,8), V(2,6), V(4,6), V(6,8),
                    V(6,10), V(4,10) },
   /* H */        { V(0,14), V(0,10), V(6,10), V(6,14), V(6,6) },
   /* I */        { M(1,6), V(5,6), V(3,6), V(3,14), V(1,14), V(5,14) },
   /* J */        { M(1,9), V(1,7), V(2,6), V(3,6), V(4,7), V(4,14), V(2,14), V(6,14) },
   /* K */        { V(0,14), V(0,8), V(6,14), V(2,10), V(6,6) },
   /* L */        { M(0,14), V(0,6), V(6,6) },
   /* M */        { V(0,14), V(3,11), V(6,14), V(6,6) },
   /* N */        { V(0,14), V(0,13), V(6,7), V(6,6), V(6,14) },
   /* O */        { M(0,8), V(0,12), V(2,14), V(4,14), V(6,12), V(6,8), V(4,6), V(2,6),
                    V(0,8) },
   /* P */        { V(0,14), V(5,14), V(6,13), V(6,11), V(5,10), V(0,10) },
   /* Q */        { M(0,8), V(0,12), V(2,14), V(4,14), V(6,12), V(6,8), V(4,6), V(2,6),
                    V(0,8), M(3,9), V(6,6) },
   /* R */        { V(0,14), V(5,14), V(6,13), V(6,11), V(5,10), V(0,10), V(2,10),
                    V(6,6) },
   /* S */        { M(0,8), V(2,6), V(4,6), V(6,8), V(4,10), V(2,10), V(0,12), V(2,14),
                    V(4,14), V(6,12) },
   /* T */        { M(3,6), V(3,14), V(0,14), V(6,14) },
   /* U */        { M(0,14), V(0,7), V(1,6), V(5,6), V(6,7), V(6,14) },
   /* V */        { M(0,14), V(0,9), V(3,6), V(6,9), V(6,14) },
   /* W */        { M(0,14), V(0,6), V(3,9), V(6,6), V(6,14) },
   /* X */        { V(0,7), V(6,13), V(6,14), M(0,14), V(0,13), V(6,7), V(6,6) },
   /* Y */        { M(0,14), V(3,11), V(6,14), V(3,11), V(3,6) },
   /* Z */        { M(0,14), V(6,14), V(6,13), V(0,7), V(0,6), V(6,6) },
   /* [ */        { M(3,5), V(0,5), V(0,15), V(3,15) },
   /* \ */        { M(0,12), V(6,6) },
   /* ] */        { M(0,5), V(3,5), V(3,15), V(0,15) },
   /* up arrow */ { M(0,11), V(3,14), V(6,11), M(3,14), V(3,6) },
   /* left arrow*/{ M(3,7), V(0,10), V(3,13), M(0,10), V(6,10) },
   /* ` */        { M(2,14), V(4,12) },
   /* a */        { M(0,9), V(1,10), V(3,10), V(4,9), V(4,6), M(4,8), V(3,9), V(1,9),
                    V(0,8), V(0,7), V(1,6), V(3,6), V(4,7) },
   /* b */        { V(0,13), M(0,9), V(1,10), V(3,10), V(4,9), V(4,7), V(3,6), V(1,6),
                    V(0,7) },
   /* c */        { M(4,9), V(3,10), V(1,10), V(0,9), V(0,7), V(1,6), V(3,6), V(4,7) },
   /* d */        { M(0,7), V(0,9), V(1,10), V(3,10), V(4,9), V(4,7), V(3,6), V(1,6),
                    V(0,7), M(4,6), V(4,13) },
   /* e */        { M(4,7), V(3,6), V(1,6), V(0,7), V(0,9), V(1,10), V(3,10), V(4,9),
                    V(4,8), V(0,8) },
   /* f */        { M(2,6), V(2,12), V(3,13), V(4,13), V(5,12), M(0,11), V(4,11) },
   /* g */        { M(4,9), V(3,10), V(1,10), V(0,9), V(0,7), V(1,6), V(3,6), V(4,7),
                    M(4,10), V(4,5), V(3,4), V(1,4), V(0,5) },
   /* h */        { V(0,13), M(0,9), V(1,10), V(3,10), V(4,9), V(4,6) },
   /* i */        { M(3,12), V(3,11), M(3,10), V(3,7), V(4,6), V(5,6) },
   /* k */        { M(3,12), V(3,11), M(3,10), V(3,5), V(2,4), V(1,3) },
   /* j */        { V(0,13), M(0,8), V(2,10), M(0,8), V(2,6) },
   /* l */        { M(2,6), V(2,13) },
   /* m */        { V(0,10), M(0,9), V(1,10), V(2,10), V(3,9), V(3,6), M(3,9), V(4,10),
                    V(5,10), V(6,9), V(6,6) },
   /* n */        { V(0,10), M(0,9), V(1,10), V(2,10), V(3,9), V(3,6) },
   /* o */        { M(0,7), V(0,9), V(1,10), V(3,10), V(4,9), V(4,7), V(3,6), V(1,6),
                    V(0,7) },
   /* p */        { M(0,4), V(0,10), M(0,9), V(1,10), V(3,10), V(4,9), V(4,7), V(3,6),
                    V(1,6), V(0,7) },
   /* q */        { M(4,9), V(3,10), V(1,10), V(0,9), V(0,7), V(1,6), V(3,6), V(4,7),
                    M(4,10), V(4,4) },
   /* r */        { V(0,10), M(0,9), V(1,10), V(3,10), V(4,9) },
   /* s */        { M(0,7), V(1,6), V(3,6), V(4,7), V(3,8), V(1,8), V(0,9), V(1,10),
                    V(3,10), V(4,9) },
   /* t */        { M(2,13), V(2,7), V(3,6), V(4,6), V(5,7), M(1,11), V(3,11) },
   /* u */        { M(0,10), V(0,7), V(1,6), V(3,6), V(4,7), V(4,10), V(4,6) },
   /* v */        { M(0,9), V(3,6), V(6,9) },
   /* w */        { M(0,10), V(0,6), V(2,8), V(4,6), V(4,10) },
   /* x */        { V(4,10), M(0,10), V(4,6) },
   /* y */        { M(0,9), V(3,6), M(6,9), V(1,4), V(0,4) },
   /* z */        { M(0,10), V(4,10), V(0,6), V(4,6) },
   /* { */        { M(3,15), V(2,14), V(2,12), V(0,10), V(2,8), V(2,6), V(3,5) },
   /* | */        { M(2,4), V(2,14) },
   /* diamon */   { M(3,6), V(0,9), V(3,12), V(6,9), V(3,6) },
   /* } */        { M(0,15), V(1,14), V(1,12), V(3,10), V(1,8), V(1,6), V(0,5) },
   /* \ */        { M(0,12), V(6,6) },
};

float scale[] = { 1.0F,
    1.0F,  /* 128 chars per line */
    1.3F,  /* 96 chars per line */
    2.0F,  /* 64 chars per line */
    2.5F,  /* 48 chars per line */
    4.0F,  /* 32 chars per line */
    5.3F,  /* 24 chars per line */
    8.0F   /* 16 chars per line */
};


uint64         iii_instr;       /* Currently executing instruction */
int            iii_sel;         /* Select mask */

t_stat iii_devio(uint32 dev, uint64 *data);
t_stat iii_svc(UNIT *uptr);
t_stat iii_reset(DEVICE *dptr);
static void draw_point(int x, int y, int b, UNIT *uptr);
static void draw_line(int x1, int y1, int x2, int y2, int b, UNIT *uptr);
t_stat iii_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr);
const char *iii_description (DEVICE *dptr);

DIB iii_dib = { III_DEVNUM, 1, iii_devio, NULL};

UNIT iii_unit[] = {
    {UDATA (&iii_svc, UNIT_IDLE, 0) },
    { 0 }
    };


MTAB iii_mod[] = {
    { 0 }
    };

DEVICE iii_dev = {
    "III", iii_unit, NULL, iii_mod,
    2, 10, 31, 1, 8, 8,
    NULL, NULL, iii_reset,
    NULL, NULL, NULL, &iii_dib, DEV_DEBUG | DEV_DISABLE | DEV_DIS | DEV_DISPLAY, 0, dev_debug,
    NULL, NULL, &iii_help, NULL, NULL, &iii_description
    };

t_stat iii_devio(uint32 dev, uint64 *data) {
     UNIT       *uptr = &iii_unit[0];
     switch(dev & 3) {
     case CONI:
        *data = (((uint64)iii_sel) << 18) | (uint64)(uptr->PIA);
        if ((iii_instr & 037) == 0)
            *data |= INST_HLT;
        *data |= (uptr->STATUS & 07) << 4;
        if (uptr->STATUS & NXM_FLG)
            *data |= NXM_BIT;
        if (uptr->STATUS & DATA_FLG)
            *data |= DATAO_LK;
        if ((uptr->STATUS & RUN_FLG) == 0)
            *data |= HLT_FLG;
        if (uptr->STATUS & CTL_FBIT)
            *data |= CONT_BIT;
        if (uptr->STATUS & WRP_FBIT)
            *data |= WRAP_FLG;
        if (uptr->STATUS & EDG_FBIT)
            *data |= EDGE_FLG;
        if (uptr->STATUS & LIT_FBIT)
            *data |= LIGHT_FLG;
        sim_debug(DEBUG_CONI, &iii_dev, "III %03o CONI %06o %06o\n", dev, (uint32)*data,
               PC);
        break;
     case CONO:
         clr_interrupt(III_DEVNUM);
         if (*data & SET_PIA)
            uptr->PIA = (int)(*data&PIA_MSK);
         if (*data & F)
            uptr->STATUS &= ~(WRP_FBIT|EDG_FBIT|LIT_FBIT|DATA_FLG|NXM_FLG);
         uptr->STATUS &= ~(017 & ((*data >> 14) ^ (*data >> 10)));
         uptr->STATUS ^= (017 & (*data >> 10));
         if (*data & STOP)
             uptr->STATUS &= ~RUN_FLG;
         if (*data & CONT) {
             uptr->STATUS |= RUN_FLG;
             iii_instr = M[uptr->MAR];
             sim_activate(uptr, 10);
         }
         if (((uptr->STATUS >> 3) & (uptr->STATUS & (WRAP_MSK|EDGE_MSK|LIGH_MSK))) != 0)
             set_interrupt(III_DEVNUM, uptr->PIA);
         if (uptr->STATUS & HLT_MSK)
            set_interrupt(III_DEVNUM, uptr->PIA);
         sim_debug(DEBUG_CONO, &iii_dev, "III %03o CONO %06o %06o\n", dev,
                     (uint32)*data, PC);
         break;
     case DATAI:
         sim_debug(DEBUG_DATAIO, &iii_dev, "III %03o DATAI %06o\n", dev, (uint32)*data);
         break;
    case DATAO:
         if (uptr->STATUS & RUN_FLG)
             uptr->STATUS |= DATA_FLG;
         else {
             iii_instr = *data;
             sim_activate(uptr, 10);
         }
         sim_debug(DEBUG_DATAIO, &iii_dev, "III %03o DATAO %06o\n", dev, (uint32)*data);
         break;
    }
    return SCPE_OK;
}

t_stat
iii_svc (UNIT *uptr)
{
     uint64    temp;
     int       A;
     int       ox, oy, nx, ny, br, sz;
     int       i, j, ch;
     float     ch_sz;

     iii_cycle(10, 0);

     /* Extract X,Y,Bright and Size */
     sz = (uptr->POS & CSIZE) >> CSIZE_V;
     br = (uptr->POS & CBRT) >> CBRT_V;
     ox = (uptr->POS & POS_X) >> POS_X_V;
     oy = (uptr->POS & POS_Y) >> POS_Y_V;
     nx = ox = (ox ^ 02000) - 02000;
     ny = oy = (oy ^ 02000) - 02000;
     ch_sz = scale[sz];

     sim_debug(DEBUG_DETAIL, &iii_dev, "III: pos %d %d %d %d %o\n", ox, oy, br, sz,
             uptr->STATUS );
     switch(iii_instr & 017) {
     case 000: /* JMP and HLT */
               if (iii_instr & 020) {
                   uptr->MAR = (iii_instr >> 18) & RMASK;
               } else {
                   uptr->STATUS &= ~RUN_FLG;
                   if (uptr->STATUS & HLT_MSK)
                      set_interrupt(III_DEVNUM, uptr->PIA);
                   return SCPE_OK;
               }
               goto skip_up;
     case 001:
     case 003:
     case 005:
     case 007:
     case 011:
     case 013:
     case 015:
     case 017: /* Draw 4 characters */
               for (i = 29; i >= 1; i -= 7) {
                   /* Extract character and compute initial point */
                   int cx, cy;
                   int lx, ly;
                   ch = (iii_instr >> i) & 0177;
                   cx = 0;
                   cy = (int)(6.0 * ch_sz);
                   lx = ox;
                   ly = oy + cy;
                   sim_debug(DEBUG_DETAIL, &iii_dev, "III: ch %d %d %o '%c' %o %o\n",
                             lx, ly, ch, (ch < ' ')? '.' : ch, sz, br);
                   if (ch == '\t' || ch == 0)
                      continue;
                   if (ch == '\r') {
                      ox = -512;
                      continue;
                   }
                   if (ch == '\n') {
                      oy -= (int)(16.0 * ch_sz);
                      continue;
                   }
                   /* Scan map and draw lines as needed */
                   if ((iii_sel & 04000) != 0) {
                       for(j = 0; j < 18; j++) {
                          uint8 v = map[ch][j];
                          if (v == 0)
                             break;
                          cx = (int)((float)((v >> 4) & 07) * ch_sz);
                          cy = (int)((float)(v & 017) * ch_sz);
                          nx = ox + cx;
                          ny = oy + cy;
                          sim_debug(DEBUG_DATA, &iii_dev, "III: map %d %d %d %d %02x\n",
                                  lx, ly, nx, ny, v);
                          if (v & 0200)
                              draw_line(lx, ly, nx, ny, br, uptr);
                          lx = nx;
                          ly = ny;
                       }
                   }
                   ox += (int)(8.0 * ch_sz);
               }
               nx = ox;
               ny = oy;
               break;

     case 002: /* Short Vector */
               if ((iii_sel & 04000) == 0)
                  break;
               /* Do first point */
               nx = (iii_instr >> 26) & 077;
               ny = (iii_instr >> 20) & 077;
               /* Sign extend */
               nx = (nx ^ 040) - 040;
               ny = (ny ^ 040) - 040;
               /* Compute relative position. */
               sim_debug(DEBUG_DETAIL, &iii_dev, "III: short %d %d %o %d\n",
                          nx, ny, sz, br);
               nx += ox;
               ny += oy;
               if (nx < -512 || nx > 512 || ny < -512 || ny > 512)
                   uptr->STATUS |= EDG_FBIT;
               i = (int)((iii_instr >> 18) & 3);
               if ((i & 02) == 0 && (iii_sel & 04000) != 0) { /* Check if visible */
                   if ((i & 01) == 0) { /* Draw a line */
                      draw_line(ox, oy, nx, ny, br, uptr);
                   } else {
                      draw_point(nx, ny, br, uptr);
                   }
               }
               ox = nx;
               oy = ny;
               /* Do second point */
               nx = (iii_instr >> 12) & 0177;
               ny = (iii_instr >> 6) & 0177;
               /* Sign extend */
               nx = (nx ^ 040) - 040;
               ny = (ny ^ 040) - 040;
               sim_debug(DEBUG_DETAIL, &iii_dev, "III: short2 %d %d %o %d\n",
                          nx, ny, sz, br);
               /* Compute relative position. */
               nx += ox;
               ny += oy;
               if (nx < -512 || nx > 512 || ny < -512 || ny > 512)
                   uptr->STATUS |= EDG_FBIT;
               /* Check if visible */
               if ((iii_instr & 040) == 0 && (iii_sel & 04000) != 0) {
                   if ((iii_instr & 020) == 0) { /* Draw a line */
                      draw_line(ox, oy, nx, ny, br, uptr);
                   } else {
                      draw_point(nx, ny, br, uptr);
                   }
               }
               break;

     case 004: /* JSR, JMS, SAVE */
               temp = (((uint64)uptr->MAR) << 18) | 020 /* | CPC */;
               A = (iii_instr >> 18) & RMASK;
               if ((iii_instr & 030) != 030) {
                  M[A] = temp;
                  A++;
               }
               if ((iii_instr & 020) != 020) {
                   temp = uptr->STATUS & 0377;
                   temp |= ((uint64)uptr->POS) << 8;
                   M[A] = temp;
                   A++;
               }
               if ((iii_instr & 030) != 030) {
                  uptr->MAR = A;
               }
               goto skip_up;

     case 006: /* Long Vector */
               /* Update sizes if needed */
               if (((iii_instr >> 8) & CSIZE) != 0)
                  sz = (iii_instr >> 8) & CSIZE;
               if (((iii_instr >> 11) & 7) != 0)
                  br = (iii_instr > 11) & 7;
               nx = (iii_instr >> 25) & 03777;
               ny = (iii_instr >> 14) & 03777;
               nx = (nx ^ 02000) - 02000;
               ny = (ny ^ 02000) - 02000;
               sim_debug(DEBUG_DETAIL, &iii_dev, "III: long %d %d %o %o\n",
                         nx, ny, sz, br);
               if ((iii_instr & 0100) == 0) { /* Relative mode */
                   nx += ox;
                   ny += oy;
                   if (nx < -512 || nx > 512 || ny < -512 || ny > 512)
                       uptr->STATUS |= EDG_FBIT;
               }
               /* Check if visible */
               if ((iii_instr & 040) == 0 && (iii_sel & 04000) != 0) {
                   if ((iii_instr & 020) == 0) /* Draw a line */
                      draw_line(ox, oy, nx, ny, br, uptr);
                   else
                      draw_point(nx, ny, br, uptr);
               }
               break;

     case 010: /* Select instruction */
               i = (iii_instr >> 24) & 07777; /* Set mask */
               j = (iii_instr >> 12) & 07777; /* Reset mask */
               ch = i & j;   /* Compliment mask */
               i &= ~ch;
               j &= ~ch;
               iii_sel = ((iii_sel | i) & ~j) ^ ch;
               goto skip_up;

     case 012: /* Test instruction */
               A = (uptr->STATUS & (int32)(iii_instr >> 12) & 0377) != 0;
               j = (int)((iii_instr >> 20) & 0377);    /* set mask */
               i = (int)((iii_instr >> 28) & 0377);    /* Reset */
               uptr->STATUS &= ~(i ^ j);
               uptr->STATUS ^= j;
               if (A ^ ((iii_instr & 020) != 0))
                   uptr->MAR++;
               goto skip_up;

     case 014: /* Restore */
               A = (iii_instr >> 18) & RMASK;
               temp = M[A];
               if ((iii_instr & 020) != 0) {
                   uptr->STATUS &= ~0377;
                   uptr->STATUS |= temp & 0377;
               }
               if ((iii_instr & 040) != 0) {
                   uptr->POS = (temp >> 8) & (POS_X|POS_Y|CBRT|CSIZE);
               }
               goto skip_up;

     case 016: /* Nop */
               break;
     }
     /* Repack to new position. */
     sim_debug(DEBUG_DATA, &iii_dev, "III: update %d %d %8o ", nx, ny, uptr->POS);
     uptr->POS = (POS_X & ((nx & 03777) << POS_X_V)) |
                 (POS_Y & ((ny & 03777) << POS_Y_V)) |
                 (CBRT & (br << CBRT_V)) |
                 (CSIZE & (sz << CSIZE_V));
     sim_debug(DEBUG_DATA, &iii_dev, "-> %8o\n", uptr->POS);
skip_up:
     if (uptr->STATUS & RUN_FLG) {
         iii_instr = M[uptr->MAR];
         sim_debug(DEBUG_DETAIL, &iii_dev, "III: fetch %06o %012llo\n",
                      uptr->MAR, iii_instr);
         uptr->MAR++;
         uptr->MAR &= RMASK;
         sim_activate(uptr, 50);
     }

     if (((uptr->STATUS >> 3) & (uptr->STATUS & (WRAP_MSK|EDGE_MSK|LIGH_MSK))) != 0)
         set_interrupt(III_DEVNUM, uptr->PIA);

     return SCPE_OK;
}

t_stat iii_reset (DEVICE *dptr)
{
    if (dptr->flags & DEV_DIS) {
        display_close(dptr);
    } else {
        display_reset();
        dptr->units[0].POS = 0;
        iii_init(dptr, 1);
    }
    return SCPE_OK;
}

/* Draw a point at x,y with intensity b. */
/* X and Y runs from -512 to 512. */
static void
draw_point(int x, int y, int b, UNIT *uptr)
{
   if (x < -512 || x > 512 || y < -512 || y > 512)
       uptr->STATUS |= WRP_FBIT;
   iii_point(x, y, b);
}

/* Draw a line between two points */
static void
draw_line(int x1, int y1, int x2, int y2, int b, UNIT *uptr)
{
    if (x1 < -512 || x1 > 512 || y1 < -512 || y1 > 512)
       uptr->STATUS |= WRP_FBIT;
    if (x2 < -512 || x2 > 512 || y2 < -512 || y2 > 512)
       uptr->STATUS |= WRP_FBIT;
    iii_draw_line(x1, y1, x2, y2, b);
}

t_stat iii_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
{
return SCPE_OK;
}

const char *iii_description (DEVICE *dptr)
{
    return "Triple III Display";
}
#endif