/*
 * $Id: type340.c,v 1.5 2004/01/24 20:52:16 phil Exp $
 * Simulator Independent DEC Type 340 Graphic Display Processor Simulation
 * Phil Budne <phil@ultimate.com>
 * September 20, 2003
 * from vt11.c
 *
 * Information from DECUS 7-13
 * http://www.spies.com/~aek/pdf/dec/pdp7/7-13_340displayProgMan.pdf
 */

/*
 * Copyright (c) 2003-2004, Philip L. Budne
 *
 * 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 AUTHORS 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 authors.
 */

#include "display.h"			/* XY plot interface */

/*
 * The Type 340 was used on the PDP-{4,6,7,9,10}
 * and used 18-bit words, with bits numbered 0 thru 17
 * (most significant to least)
 */

#define BITMASK(N) (1<<(17-(N)))

/* mask for a field */
#define FIELDMASK(START,END) ((1<<((END)-(START)+1))-1)

/* extract a field */
#define GETFIELD(W,START,END) (((W)>>(17-(END)))&FIELDMASK(START,END))

/* extract a 1-bit field */
#define TESTBIT(W,B) (((W) & BITMASK(B)) != 0)

#ifdef DEBUG_TY340
#define DEBUGF(X) printf X
#else
#define DEBUGF(X)
#endif

typedef long ty340word;

static ty340word DAC;			/* Display Address Counter */
static unsigned char shift;		/* 1 bit */
static enum mode mode;			/* 3 bits */
static int scale;			/* 2 bits */

enum mode { PARAM=0, POINT, SLAVE, CHAR, VECTOR, VCONT, INCR, SUBR };

enum jump_type { DJP=2, DJS=3, DDS=1 };
static ty340word ASR;			/* Address Save Register */
static unsigned char save_ff;		/* "save" flip-flop */

static unsigned char intensity;		/* 3 bits */
static unsigned char lp_ena;		/* 1 bit */

/* kept signed for raster violation checking */
static short xpos, ypos;		/* 10 bits, signed */	    
static unsigned char sequence;		/* 2 bits */

/* XXX make defines public for 340_cycle return */
#define STOPPED 01
#define LPHIT 02
#define VEDGE 04
#define HEDGE 010
static unsigned char status = STOPPED;

/*
 * callbacks into PDP-6/10 simulator
 */
extern ty340word ty340_fetch(ty340word);
extern void ty340_store(ty340word, ty340word);
extern void ty340_stop_int(void);
extern void ty340_lp_int(void);

void
ty340_set_dac(ty340word addr)
{
    DAC = addr;
    mode = 0;
    DEBUGF(("set DAC %06\r\n", DAC));
    status = 0;				/* XXX just clear stopped? */
    /* XXX clear other stuff? save_ff? */
}

void
ty340_reset(void)
{
    /* XXX call display layer? destroy window? */
    xpos = ypos = 0;
    status = STOPPED;
}

static int
point(int x, int y, int seq)
{
    int i;

    /* XXX apply scale? */

    i = DISPLAY_INT_MAX-7+intensity;
    if (i <= 0)
	i = 1;

    if (x < 0 || x > 1023) {
	status |= VEDGE;
	return 0;
    }
    if (y < 0 || y > 1023) {
	status |= HEDGE;
	return 0;
    }

    if (display_point(x, y, i, 0)) {
	if (lp_ena) {
	    /* XXX save location? */
	    status |= LPHIT;
	    sequence = seq;
	}
    }
}

/*
 * two-step algorithm, developed by Xiaolin Wu
 * from http://graphics.lcs.mit.edu/~mcmillan/comp136/Lecture6/Lines.html
 */

/*
 * The two-step algorithm takes the interesting approach of treating
 * line drawing as a automaton, or finite state machine. If one looks
 * at the possible configurations for the next two pixels of a line,
 * it is easy to see that only a finite set of possibilities exist.
 * The two-step algorithm shown here also exploits the symmetry of
 * line-drawing by simultaneously drawn from both ends towards the
 * midpoint.
 */

static void
lineTwoStep(int x0, int y0, int x1, int y1)
{
    int dy = y1 - y0;
    int dx = x1 - x0;
    int stepx, stepy;

    if (dy < 0) { dy = -dy;  stepy = -1; } else { stepy = 1; }
    if (dx < 0) { dx = -dx;  stepx = -1; } else { stepx = 1; }

    lpoint(x0,y0);
    if (dx == 0 && dy == 0)		/* following algorithm won't work */
	return;				/* just the one dot */
    lpoint(x1, y1);
    if (dx > dy) {
	int length = (dx - 1) >> 2;
	int extras = (dx - 1) & 3;
	int incr2 = (dy << 2) - (dx << 1);
	if (incr2 < 0) {
	    int c = dy << 1;
	    int incr1 = c << 1;
	    int d =  incr1 - dx;
	    int i;

	    for (i = 0; i < length; i++) {
		x0 += stepx;
		x1 -= stepx;
		if (d < 0) {				/* Pattern: */
		    lpoint(x0, y0);
		    lpoint(x0 += stepx, y0);		/*  x o o   */
		    lpoint(x1, y1);
		    lpoint(x1 -= stepx, y1);
		    d += incr1;
		}
		else {
		    if (d < c) {			  /* Pattern: */
			lpoint(x0, y0);			  /*      o   */
			lpoint(x0 += stepx, y0 += stepy); /*  x o     */
			lpoint(x1, y1);
			lpoint(x1 -= stepx, y1 -= stepy);
		    } else {
			lpoint(x0, y0 += stepy);	/* Pattern: */
			lpoint(x0 += stepx, y0);	/*    o o   */
			lpoint(x1, y1 -= stepy);	/*  x	    */
			lpoint(x1 -= stepx, y1);
		    }
		    d += incr2;
		}
	    }
	    if (extras > 0) {
		if (d < 0) {
		    lpoint(x0 += stepx, y0);
		    if (extras > 1) lpoint(x0 += stepx, y0);
		    if (extras > 2) lpoint(x1 -= stepx, y1);
		} else
                    if (d < c) {
                        lpoint(x0 += stepx, y0);
                        if (extras > 1) lpoint(x0 += stepx, y0 += stepy);
                        if (extras > 2) lpoint(x1 -= stepx, y1);
                    } else {
                        lpoint(x0 += stepx, y0 += stepy);
                        if (extras > 1) lpoint(x0 += stepx, y0);
                        if (extras > 2) lpoint(x1 -= stepx, y1 -= stepy);
                    }
	    }
	} else {
	    int c = (dy - dx) << 1;
	    int incr1 = c << 1;
	    int d =  incr1 + dx;
	    int i;
	    for (i = 0; i < length; i++) {
		x0 += stepx;
		x1 -= stepx;
		if (d > 0) {
		    lpoint(x0, y0 += stepy);		/* Pattern: */
		    lpoint(x0 += stepx, y0 += stepy);	/*      o   */
		    lpoint(x1, y1 -= stepy);		/*    o     */
		    lpoint(x1 -= stepx, y1 -= stepy);	/*  x       */
		    d += incr1;
		} else {
		    if (d < c) {
			lpoint(x0, y0);			  /* Pattern: */
			lpoint(x0 += stepx, y0 += stepy); /*      o   */
			lpoint(x1, y1);			  /*  x o     */
			lpoint(x1 -= stepx, y1 -= stepy);
		    } else {
			lpoint(x0, y0 += stepy);	/* Pattern: */
			lpoint(x0 += stepx, y0);	/*    o o   */
			lpoint(x1, y1 -= stepy);	/*  x       */
			lpoint(x1 -= stepx, y1);
		    }
		    d += incr2;
		}
	    }
	    if (extras > 0) {
		if (d > 0) {
		    lpoint(x0 += stepx, y0 += stepy);
		    if (extras > 1) lpoint(x0 += stepx, y0 += stepy);
		    if (extras > 2) lpoint(x1 -= stepx, y1 -= stepy);
		} else if (d < c) {
		    lpoint(x0 += stepx, y0);
		    if (extras > 1) lpoint(x0 += stepx, y0 += stepy);
		    if (extras > 2) lpoint(x1 -= stepx, y1);
		} else {
		    lpoint(x0 += stepx, y0 += stepy);
		    if (extras > 1) lpoint(x0 += stepx, y0);
		    if (extras > 2) {
			if (d > c)
			    lpoint(x1 -= stepx, y1 -= stepy);
			else
			    lpoint(x1 -= stepx, y1);
		    }
		}
	    }
	}
    } else {
	int length = (dy - 1) >> 2;
	int extras = (dy - 1) & 3;
	int incr2 = (dx << 2) - (dy << 1);
	if (incr2 < 0) {
	    int c = dx << 1;
	    int incr1 = c << 1;
	    int d =  incr1 - dy;
	    int i;
	    for (i = 0; i < length; i++) {
		y0 += stepy;
		y1 -= stepy;
		if (d < 0) {
		    lpoint(x0, y0);
		    lpoint(x0, y0 += stepy);
		    lpoint(x1, y1);
		    lpoint(x1, y1 -= stepy);
		    d += incr1;
		} else {
		    if (d < c) {
			lpoint(x0, y0);
			lpoint(x0 += stepx, y0 += stepy);
			lpoint(x1, y1);
			lpoint(x1 -= stepx, y1 -= stepy);
		    } else {
			lpoint(x0 += stepx, y0);
			lpoint(x0, y0 += stepy);
			lpoint(x1 -= stepx, y1);
			lpoint(x1, y1 -= stepy);
		    }
		    d += incr2;
		}
	    }
	    if (extras > 0) {
		if (d < 0) {
		    lpoint(x0, y0 += stepy);
		    if (extras > 1) lpoint(x0, y0 += stepy);
		    if (extras > 2) lpoint(x1, y1 -= stepy);
		} else
                    if (d < c) {
                        lpoint(x0, y0 += stepy);
                        if (extras > 1) lpoint(x0 += stepx, y0 += stepy);
                        if (extras > 2) lpoint(x1, y1 -= stepy);
                    } else {
                        lpoint(x0 += stepx, y0 += stepy);
                        if (extras > 1) lpoint(x0, y0 += stepy);
                        if (extras > 2) lpoint(x1 -= stepx, y1 -= stepy);
                    }
	    }
	} else {
	    int c = (dx - dy) << 1;
	    int incr1 = c << 1;
	    int d =  incr1 + dy;
	    int i;
	    for (i = 0; i < length; i++) {
		y0 += stepy;
		y1 -= stepy;
		if (d > 0) {
		    lpoint(x0 += stepx, y0);
		    lpoint(x0 += stepx, y0 += stepy);
		    lpoint(x1 -= stepy, y1);
		    lpoint(x1 -= stepx, y1 -= stepy);
		    d += incr1;
		} else {
		    if (d < c) {
			lpoint(x0, y0);
			lpoint(x0 += stepx, y0 += stepy);
			lpoint(x1, y1);
			lpoint(x1 -= stepx, y1 -= stepy);
		    } else {
			lpoint(x0 += stepx, y0);
			lpoint(x0, y0 += stepy);
			lpoint(x1 -= stepx, y1);
			lpoint(x1, y1 -= stepy);
		    }
		    d += incr2;
		}
	    }
	    if (extras > 0) {
		if (d > 0) {
		    lpoint(x0 += stepx, y0 += stepy);
		    if (extras > 1) lpoint(x0 += stepx, y0 += stepy);
		    if (extras > 2) lpoint(x1 -= stepx, y1 -= stepy);
		} else if (d < c) {
		    lpoint(x0, y0 += stepy);
		    if (extras > 1) lpoint(x0 += stepx, y0 += stepy);
		    if (extras > 2) lpoint(x1, y1 -= stepy);
		} else {
		    lpoint(x0 += stepx, y0 += stepy);
		    if (extras > 1) lpoint(x0, y0 += stepy);
		    if (extras > 2) {
			if (d > c)
			    lpoint(x1 -= stepx, y1 -= stepy);
			else
			    lpoint(x1, y1 -= stepy);
		    }
		}
	    }
	}
    }
} /* lineTwoStep */

static int
vector(int i, int sx, int dx, int sy, int dy)
{
    int x0, y0, x1, y1;

    x0 = xpos;
    y0 = ypos;

    if (sx) {
	x1 = x0 - dx;
	if (x1 < 0)			/* XXX TEMP? */
	    x1 = 0;
    }
    else {
	x1 = x0 + dx;
	if (x1 > 1023)			/* XXX TEMP? */
	    x1 = 1023;
    }

    if (sy) {
	y1 = y0 - dy;
	if (y1 < 0)			/* XXX TEMP? */
	    y1 = 0;
    }
    else {
	y1 = y0 + dy;			/* XXX TEMP? */
	if (y1 > 1023)
	    y1 = 1023;
    }

    DEBUGF(("vector i%d (%d,%d) to (%d,%d)\r\n", i, x0, y0, x1, y1));
    if (i)
	lineTwoStep(x0, y0, x1, y1);

    xpos = x1;
    ypos = y1;
    return 0;
}

/* return true on raster violation */
int
ipoint(int i, int n, unsigned char byte)
{
    if (byte & 010) {			/* left/right */
	if (byte & 04) {
	    if (xpos == 0) {
		status |= VEDGE;
		return 1;
	    }
	    xpos--;
	}
	else {
	    if (xpos == 1023) {
		status |= VEDGE;
		return 1;
	    }
	    xpos++;
	}
    }
    if (byte & 02) {			/* up/down */
	if (byte & 04) {
	    if (ypos == 0) {
		status |= HEDGE;
		return 1;
	    }
	    ypos--;
	}
	else {
	    if (ypos == 1023) {
		status |= HEDGE;
		return 1;
	    }
	    ypos++;
	}
    }
    if (i)
	point(xpos, ypos, n);

    return 0;
}

/* 
 * 342 character generator - first 64 characters (from manual)
 */
static const unsigned char chars[64][5] = {
    { 0070, 0124, 0154, 0124, 0070 },	/* 00 */
    { 0174, 0240, 0240, 0240, 0174 },	/* 01 A */
    { 0376, 0222, 0222, 0222, 0154 },	/* 02 B */
    { 0174, 0202, 0202, 0202, 0104 },	/* 03 C */
    { 0376, 0202, 0202, 0202, 0174 },	/* 04 D */
    { 0376, 0222, 0222, 0222, 0222 },	/* 05 E */
    { 0376, 0220, 0220, 0220, 0220 },	/* 06 F */
    { 0174, 0202, 0222, 0222, 0134 },	/* 07 G */
    { 0376, 0020, 0020, 0020, 0376 },	/* 10 H */
    { 0000, 0202, 0376, 0202, 0000 },	/* 11 I */
    { 0004, 0002, 0002, 0002, 0374 },	/* 12 J */
    { 0376, 0020, 0050, 0104, 0202 },	/* 13 K */
    { 0376, 0002, 0002, 0002, 0002 },	/* 14 K */
    { 0374, 0100, 0040, 0100, 0374 },	/* 15 M */
    { 0376, 0100, 0040, 0020, 0376 },	/* 16 N */
    { 0174, 0202, 0202, 0202, 0174 },	/* 17 O */
    { 0376, 0220, 0220, 0220, 0140 },	/* 20 P */
    { 0174, 0202, 0212, 0206, 0176 },	/* 21 Q */
    { 0376, 0220, 0230, 0224, 0142 },	/* 22 R */
    { 0144, 0222, 0222, 0222, 0114 },	/* 23 S */
    { 0200, 0200, 0376, 0200, 0200 },	/* 24 T */
    { 0374, 0002, 0002, 0002, 0374 },	/* 25 U */
    { 0370, 0004, 0002, 0004, 0370 },	/* 26 V */
    { 0376, 0004, 0010, 0004, 0376 },	/* 27 W */
    { 0202, 0104, 0070, 0104, 0202 },	/* 30 X */
    { 0200, 0100, 0076, 0100, 0200 },	/* 31 Y */
    { 0226, 0232, 0222, 0262, 0322 },	/* 32 Z */
    { 0000, 0000, 0000, 0000, 0000 },	/* 33 LF */
    { 0000, 0000, 0000, 0000, 0000 },	/* 34 CR */
    { 0000, 0000, 0000, 0000, 0000 },	/* 35 HORIZ */
    { 0000, 0000, 0000, 0000, 0000 },	/* 36 VERT */
    { 0000, 0000, 0000, 0000, 0000 },	/* 37 ESC */
    { 0000, 0000, 0000, 0000, 0000 },	/* 40 space */
    { 0000, 0000, 0372, 0000, 0000 },	/* 41 ! */
    { 0000, 0340, 0000, 0340, 0000 },	/* 42 " */
    { 0050, 0376, 0050, 0376, 0050 },	/* 43 # */
    { 0144, 0222, 0376, 0222, 0114 },	/* 44 $ */
    { 0306, 0310, 0220, 0246, 0306 },	/* 45 % */
    { 0154, 0222, 0156, 0004, 0012 },	/* 46 & */
    { 0000, 0000, 0300, 0340, 0000 },	/* 47 ' */
    { 0070, 0104, 0202, 0000, 0000 },	/* 50 ( */
    { 0000, 0000, 0202, 0104, 0070 },	/* 51 ) */
    { 0124, 0070, 0174, 0070, 0124 },	/* 52 * */
    { 0020, 0020, 0174, 0020, 0020 },	/* 53 + */
    { 0000, 0014, 0016, 0000, 0000 },	/* 54 , */
    { 0020, 0020, 0020, 0020, 0020 },	/* 55 - */
    { 0000, 0006, 0006, 0000, 0000 },	/* 56 . */
    { 0004, 0010, 0020, 0040, 0100 },	/* 57 / */
    { 0174, 0212, 0222, 0242, 0174 },	/* 60 0 */
    { 0000, 0102, 0376, 0002, 0000 },	/* 61 1 */
    { 0116, 0222, 0222, 0222, 0142 },	/* 62 2 */
    { 0104, 0202, 0222, 0222, 0154 },	/* 63 3 */
    { 0020, 0060, 0120, 0376, 0020 },	/* 64 4 */
    { 0344, 0222, 0222, 0222, 0214 },	/* 65 5 */
    { 0174, 0222, 0222, 0222, 0114 },	/* 66 6 */
    { 0306, 0210, 0220, 0240, 0300 },	/* 67 7 */
    { 0154, 0222, 0222, 0222, 0154 },	/* 70 8 */
    { 0144, 0222, 0222, 0222, 0174 },	/* 71 9 */
    { 0000, 0066, 0066, 0000, 0000 },	/* 72 : */
    { 0000, 0154, 0156, 0000, 0000 },	/* 73 ; */
    { 0020, 0050, 0104, 0202, 0000 },	/* 74 < */
    { 0050, 0050, 0050, 0050, 0050 },	/* 75 = */
    { 0000, 0202, 0104, 0050, 0020 },	/* 76 > */
    { 0100, 0200, 0236, 0220, 0140 }	/* 77 ? */
};

/*
 * type 342 Character/Symbol generator for type 340 display
 * return true if ESCaped
 */
static int
character(int n, char c)
{
    int x, y;

    switch (c) {
    case 033:				/* LF */
	if (ypos < 12) {
	    status |= HEDGE;
	    ypos = 0;
	}
	else
	    ypos -= 12;			/* XXX scale? */

	return 0;
    case 034:				/* CR */
	xpos = 0;
	return 0;
    case 035:				/* shift in */
	shift = 1;
	return 0;
    case 036:				/* shift out */
	shift = 0;
	return 0;
    case 037:				/* escape */
	sequence = n;
	return 1;
    }
    /* XXX plot character from character set selected by "shift"
     * (offset index by 64?)
     */
    for (x = 0; x < 5; x++) {
	for (y = 0; y < 7; y++) {
	    if (chars[c][x] & (1<<y)) {
		/* XXX check for raster violation? */
		point(xpos+x, ypos+y, n); /* XXX scale? */
	    }
	}
    }
    xpos += 7;				/* XXX scale? */
    if (xpos > 1023) {
	xpos = 1023;
	status |= VEDGE;
    }
    return 0;
}

int
ty340_cycle(int us, int slowdown)
{
    ty340word inst, addr;
    int i, escape, stopped;

    if (status & STOPPED)
	return 0;			/* XXX age display? */

    inst = ty340_fetch(DAC);
    DEBUGF(("%06o: %06o\r\n", DAC, inst));
    DAC++;

    escape = 0;
    switch (mode) {
    case PARAM:
	mode = GETFIELD(inst, 2, 4);

	if (TESTBIT(inst, 5)) {		/* load l.p. enable */
	    lp_ena = TESTBIT(inst,6);
	    DEBUGF(("lp_ena %d\r\n", lp_ena));
	}

	if (TESTBIT(inst, 7)) {
	    status |= STOPPED;
	    if (TESTBIT(inst, 8))
		ty340_stop_int();	/* set stop_int_end? */
	}

	if (TESTBIT(inst, 11))
	    scale = GETFIELD(inst, 12, 13);

	if (TESTBIT(inst, 14))
	    intensity = GETFIELD(inst, 15, 17);

	break;

    case POINT:
	mode = GETFIELD(inst, 2, 4);

	if (TESTBIT(inst, 5))		/* load l.p. enable */
	    lp_ena = TESTBIT(inst,6);

	if (TESTBIT(inst, 1))
	    ypos = GETFIELD(inst, 8, 17);
	else
	    xpos = GETFIELD(inst, 8, 17);

	if (TESTBIT(inst, 7))
	    point(xpos, ypos, 0);
	break;

    case SLAVE:
	mode = GETFIELD(inst, 2, 4);
	break;

    case CHAR:
	escape = (character(0, GETFIELD(inst, 0, 5)) ||
		  character(1, GETFIELD(inst, 6, 11)) ||
		  character(2, GETFIELD(inst, 12, 17)));
	break;

    case VECTOR:
	escape = TESTBIT(inst, 0);
	if (vector(TESTBIT(inst, 1),
		   TESTBIT(inst, 2), GETFIELD(inst, 3, 9),
		   TESTBIT(inst, 10), GETFIELD(inst, 11, 17))) {
	    /* XXX interrupt? */
	}
	break;
    case VCONT:
	escape = TESTBIT(inst, 0);
	if (vector(TESTBIT(inst, 1),
		   TESTBIT(inst, 2), GETFIELD(inst, 3, 9),
		   TESTBIT(inst, 10), GETFIELD(inst, 11, 17))) {
	    /* XXX set escape? */
	    mode = PARAM;		/* raster violation */
	}
	break;

    case INCR:
	escape = TESTBIT(inst, 0);	/* escape bit */
	i = TESTBIT(inst, 1);

	if (ipoint(i, 0, GETFIELD(inst, 2, 5)) ||
	    ipoint(i, 1, GETFIELD(inst, 6, 9)) ||
	    ipoint(i, 2, GETFIELD(inst, 10, 13)) ||
	    ipoint(i, 3, GETFIELD(inst, 14, 17)))
	    /* XXX set escape? */
	    mode = PARAM;		/* raster violation */
	break;

    case SUBR:
	/* type 347 Display Subroutine Option? */

	mode = GETFIELD(inst, 2, 4);
	/* XXX take high bits of current DAC? */
	addr = GETFIELD(inst, 5, 17);

	switch (GETFIELD(inst, 0, 1)) {
	case DJS:			/* display jump and save */
	    ASR = DAC;
	    save_ff = 1;		/* set "save" flip-flop */
	    /* FALL */
	case DJP:			/* display jump */
	    DAC = addr;
	    break;
	case DDS:			/* display deposit save register */
	    ty340_deposit(addr, (DJP<<16) | ASR);
	    save_ff = 0;		/* ?? */
	    break;
	default:
	    /* XXX ??? */
	    break;
	}
	break;
    }

    if (escape) {
	mode = PARAM;
	if (save_ff) {
	    /* return from subroutine */
	    DAC = ASR;
	    save_ff = 0;
	}
    }
    return status;
} /* ty340_cycle */
