ftp.nice.ch/pub/next/tools/emulators/vice.0.15.0.NeXT.sd.tgz#/vice-0.15.0/src/pet/pia.c

This is pia.c in view mode; [Download] [Up]

/*
 * pia.c -- PIA chip emulation.
 *
 * Written by
 *  Jouko Valta (jopi@stekt.oulu.fi)
 *  Andre' Fachat (fachat@physik.tu-chemnitz.de)
 *
 * This file is part of VICE, the Versatile Commodore Emulator.
 * See README for copyright notice.
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
 *  02111-1307  USA.
 *
 */

#include "vice.h"

#include <stdio.h>
#include <time.h>

#ifndef PET
#define	PET		/* to get PET definitions in include files as
			   pia.c is non of the files that are different
			   for different platforms - it just exists in
			   xpet only...! */
#endif

#include "types.h"

#include "cmdline.h"
#include "mem.h"
#include "crtc.h"
#include "interrupt.h"
#include "kbd.h"
#include "parallel.h"
#include "pets.h"
#include "pia.h"
#include "resources.h"
#include "vmachine.h"

/* ------------------------------------------------------------------------- */

/* PIA resources.  */

/* Flag: is the diagnostic pin enabled?  */
static int diagnostic_pin_enabled;

static int set_diagnostic_pin_enabled(resource_value_t v)
{
    diagnostic_pin_enabled = (int) v;
    return 0;
}

static resource_t resources[] = {
    { "DiagPin", RES_INTEGER, (resource_value_t) 0,
      (resource_value_t *) &diagnostic_pin_enabled, set_diagnostic_pin_enabled },
    { NULL }
};

int pia_init_resources(void)
{
    return resources_register(resources);
}

/* ------------------------------------------------------------------------- */

static cmdline_option_t cmdline_options[] = {
    { "-diagpin", SET_RESOURCE, 0, NULL, NULL, "DiagPin", (resource_value_t) 1,
      NULL, "Enable userport diagnostic pin" },
    { "+diagpin", SET_RESOURCE, 0, NULL, NULL, "DiagPin", (resource_value_t) 1,
      NULL, "Disable userport diagnostic pin" },
    { NULL }
};

int pia_init_cmdline_options(void)
{
    return cmdline_register_options(cmdline_options);
}

/* ------------------------------------------------------------------------- */

#define P_PORT_A	0
#define P_CTRL_A	1
#define P_PORT_B	2
#define P_CTRL_B	3

typedef struct {
    BYTE  port_a;	/* output register, i.e. what has been written by
			   the CPU. input is assembled at read time */
    BYTE  ddr_a;	/* PIA Port A DDR */
    BYTE  ctrl_a;

    BYTE  port_b;
    BYTE  ddr_b;	/* PIA Port B DDR */
    BYTE  ctrl_b;
} piareg;


/*
 * Local variables
 */

static piareg  pia1, pia2;
static int tape1_sense = 0;
static int is_peek_access = 0;

/* ------------------------------------------------------------------------- */

void mem_set_tape_sense(int v)
{
    tape1_sense = v;
}

void    reset_pia1(void)
{
   /* clear _all_ internal registers */

   pia1.ctrl_a = 0;	/* PIA 1 Port A Control */
   pia1.ctrl_b = 0;	/* PIA 1 Port B Control */
   pia1.ddr_a = 0;	/* PIA 1 Port A DDR */
   pia1.ddr_b = 0;	/* PIA 1 Port B DDR */
   pia1.port_a = 255;	/* PIA 1 Port A input; nothing to read from keyboard */
   pia1.port_b = 255;	/* PIA 1 Port B input; nothing to read from keyboard */

   par_set_eoi(0);	/* CA2 input mode -> pin goes high -> EOI not set */
   crtc_screen_enable(1);

   is_peek_access = 0;

   maincpu_set_irq(I_PIA1, IK_NONE);
}

void	reset_pia2(void)
{
   /* clear _all_ internal registers, set input lines */

   pia2.ctrl_a = 0;	/* PIA 2 Port A Control */
   pia2.ctrl_b = 0;	/* PIA 2 Port B Control */
   pia2.ddr_a = 0;	/* PIA 2 Port A DDR */
   pia2.ddr_b = 0;	/* PIA 2 Port B DDR */
			/* PIA 2 Port A input = iec bus */
   pia2.port_a = par_bus;
   pia2.port_b = 255;	/* PIA 2 Port B input; */

   par_set_ndac(0);	/* CA2 input mode */
   par_set_dav(0);	/* CA1 input mode */

   par_set_bus(0xff);	/* all data lines high, because of input mode */

   maincpu_set_irq(I_PIA2, IK_NONE);
}

static void pia1_update_irq(void) {
    if( ((pia1.ctrl_a & 0x81) == 0x81)
	    || ((pia1.ctrl_a & 0x68) == 0x48)
	    || ((pia1.ctrl_b & 0x81) == 0x81)
	    || ((pia1.ctrl_b & 0x68) == 0x48)
	) {
        maincpu_set_irq(I_PIA1, IK_IRQ);
    } else {
        maincpu_set_irq(I_PIA1, IK_NONE);
    }
}

static void pia2_update_irq(void) {
    if( ((pia2.ctrl_a & 0x81) == 0x81)
	    || ((pia2.ctrl_a & 0x68) == 0x48)
	    || ((pia2.ctrl_b & 0x81) == 0x81)
	    || ((pia2.ctrl_b & 0x68) == 0x48)
	) {
        maincpu_set_irq(I_PIA2, IK_IRQ);
    } else {
        maincpu_set_irq(I_PIA2, IK_NONE);
    }
}


/* unfinished control line flag support. Used for PET IRQ input. */
void signal_pia1(int line, int edge) {
    switch(line) {
    case PIA_SIG_CB1:
/*printf("signal_pia1(line=%d, edge=%d, ctrl=%02x)\n",line,edge,pia1.ctrl_b);*/
	/* this currently relies on each edge being called only once,
	 * otherwise multiple IRQs could occur. */
	if( ((pia1.ctrl_b & 0x02) ? PIA_SIG_RISE : PIA_SIG_FALL) == edge) {
	    pia1.ctrl_b |= 0x80;
	    pia1_update_irq();
            /* printf("clk=%d line=%d, edge=%d\n",clk, line, edge); */
	}
	break;
    }
}


/* ------------------------------------------------------------------------- */
/* PIA 1 */

void REGPARM2 store_pia1(ADDRESS addr, BYTE byte)
{

    addr &= 3;

#if 0
    printf("store pia1 [%x] %x\n", (int) addr, (int) byte);
#endif

    switch (addr) {

      case P_PORT_A: /* port A */
	if (pia1.ctrl_a & 4) {
	    pia1.port_a = byte;
		/*(pia1.port_a & ~pia1.ddr_a) | (byte & pia1.ddr_a);*/
	} else
	    pia1.ddr_a = byte;
	break;

      case P_PORT_B: /* port B */
	if (pia1.ctrl_b & 4)
	    pia1.port_b = byte;
		/*(pia1.port_b & ~pia1.ddr_b) | (byte & pia1.ddr_b);*/
	else
	    pia1.ddr_b = byte;
	break;


	/* Control */

      case P_CTRL_A: /* Control A */
	pia1.ctrl_a = (pia1.ctrl_a & 0xc0) | (byte & 0x3f);
	if(pia1.ctrl_a & 0x20) pia1.ctrl_a &= 0xbf;
	pia1_update_irq();

if(pardebug) printf("write pia1.ctrl_a(%x)\n",byte);
	if( (byte & 0x38) == 0x30 ) {
	  par_set_eoi(1);
	  if(pet.pet2k) crtc_screen_enable(0);
	} else {
	  par_set_eoi(0);	/* toggle mode still to be implemented */
	  if(pet.pet2k) crtc_screen_enable(1);
	}
	break;

      case P_CTRL_B: /* Control B */
	pia1.ctrl_b = (pia1.ctrl_b & 0xc0) | (byte & 0x3f);
	if(pia1.ctrl_b & 0x20) pia1.ctrl_b &= 0xbf;
	pia1_update_irq();
/*if(1) printf("write pia1.ctrl_b(%x)\n",byte);*/
	break;


/*
E810	PORT A	7   Diagnostic sense (pin 5 on the user port)
		6   IEEE EOI in
		5   Cassette sense #2
		4   Cassette sense #1
		3-0 Keyboard row select (through 4->10 decoder)
E811	CA2	    output to blank the screen (old PETs only)
		    IEEE EOI out
	CA1	    cassette #1 read line
E812	PORT B	7-0 Contents of keyboard row
		    Usually all or all but one bits set.
E813	CB2	    output to cassette #1 motor: 0=on, 1=off
	CB1	    screen retrace detection in


	 Control

 7    CA1 active transition flag. 1= 0->1, 0= 1->0
 6    CA2 active transition flag. 1= 0->1, 0= 1->0
 5    CA2 direction	      1 = out	     | 0 = in
                    ------------+------------+---------------------
 4    CA2 control   Handshake=0 | Manual=1   | Active: High=1 Low=0
 3    CA2 control   On Read=0	| CA2 High=1 | IRQ on=1, IRQ off=0
		    Pulse  =1	| CA2 Low=0  |

 2    Port A control: DDRA = 0, IORA = 1
 1    CA1 control: Active High = 1, Low = 0
 0    CA1 control: IRQ on=1, off = 0
*/

    }  /* switch */
}


/* ------------------------------------------------------------------------- */

BYTE REGPARM1 read_pia1(ADDRESS addr)
{
    static BYTE inbyte;

    addr &= 3;

#if 0
    printf("read pia1 [%d]  [%02x %02x] [%02x] [%02x %02x] [%02x]\n",
           addr,
           pia1.port_a, pia1.ddr_a, pia1.ctrl_a,
           pia1.port_b, pia1.ddr_b, pia1.ctrl_b);
#endif

    switch (addr) {

      case P_PORT_A: /* port A */
	if (pia1.ctrl_a & 4) {

	    if(!is_peek_access) {
	        pia1.ctrl_a &= 0x3f;		/* Clear CA1,CA2 IRQ */
	        pia1_update_irq();
	    }

	    inbyte = 0xff
			- (tape1_sense ? 16 : 0)
			- (par_eoi ? 64 : 0)
			- (diagnostic_pin_enabled ? 128 : 0);
	    return ((inbyte & ~pia1.ddr_a) | (pia1.port_a & pia1.ddr_a));
	}
	return (pia1.ddr_a);

/*
E810	PORT A	7   Diagnostic sense (pin 5 on the user port)
		6   IEEE EOI in
		5   Cassette sense #2
		4   Cassette sense #1
		3-0 Keyboard row select (through 4->10 decoder)

E812	PORT B	7-0 Contents of keyboard row
		    Usually all or all but one bits set.
*/
      case P_PORT_B: /* port B */
	if (pia1.ctrl_b & 4) {
	    int     row;
	    BYTE    j = 0xFF;

	    if(!is_peek_access) {
	        pia1.ctrl_b &= 0x3f;		/* Clear CB1,CB2 IRQ */
	        pia1_update_irq();
	    }

	    row = pia1.port_a & 15;

	    if (row < KBD_ROWS)
		j = ~keyarr[row];

#if 0
            printf("read pia1 port B %d\n", j);
            printf("a: %x b:%x  ca: %x cb: %x joy: %x\n",
                   (int) pia1.port_a, (int) j,
                   (int) pia1.ddr_a, (int) pia1.ddr_b, joy[2]);
#endif
#if (defined(DEBUG_PIA) || defined(KBDBUG))
	    if (j < 255)
                printf("%02X %02X %02X %02X %02X  %02X %02X %02X %02X %02X - row %d  %02x\n",
                       keyarr[0], keyarr[1], keyarr[2], keyarr[3], keyarr[4],
                       keyarr[5], keyarr[6], keyarr[7], keyarr[8], keyarr[9],
                       row, j);
#endif

	    return (j);
	}
	return (pia1.ddr_a);


	/* Control */

      case P_CTRL_A: /* Control A */
	return (pia1.ctrl_a);

      case P_CTRL_B: /* Control B */
	return (pia1.ctrl_b);
	break;

    }  /* switch */

    return (0xFF);
}


/* ------------------------------------------------------------------------- */
/* PIA 2 */

void REGPARM2 store_pia2(ADDRESS addr, BYTE byte)
{
    addr &= 3;

#if 0
    printf("store pia2 [%x] %x\n", (int) addr, (int) byte);
#endif

/*
E820	PORT A	    Input buffer for IEEE data lines
E821	CA2	    IEEE NDAC out
	CA1	    IEEE ATN in
E822	PORT B	    Output buffer for IEEE data lines
E823	CB2	    IEEE DAV out
	CB1	    IEEE SRQ in
*/

    switch (addr) {

      case P_PORT_A: /* port A */
	if (pia2.ctrl_a & 4) {
	    pia2.port_a = byte;
		/*(pia2.port_a & ~pia2.ddr_a) | (byte & pia2.ddr_a);*/
	} else
	    pia2.ddr_a = byte;
	break;

      case P_PORT_B: /* port B */
	if (pia2.ctrl_b & 4) {
if(pardebug) printf("write pia2.port_b(%x)\n",byte);
	    par_set_bus(byte^255); /* ignoring ddr_b, hmm... */
	    pia2.port_b = byte;
		/*(pia2.port_b & ~pia2.ddr_b) | (byte & pia2.ddr_b);*/
	} else
	    pia2.ddr_b = byte;
	break;


	/* Control */

      case P_CTRL_A: /* Control A */
	pia2.ctrl_a = (pia2.ctrl_a & 0xc0) | (byte & 0x3f);
	if(pia2.ctrl_a & 0x20) pia2.ctrl_a &= 0xbf;
	pia2_update_irq();

if(pardebug) printf("write pia2.ctrl_a(%x)\n",byte);
	if( (byte & 0x38) == 0x30 ) par_set_ndac(1);
	else par_set_ndac(0);
	break;

      case P_CTRL_B: /* Control B */
	pia2.ctrl_b = (pia2.ctrl_b & 0xc0) | (byte & 0x3f);
	if(pia2.ctrl_b & 0x20) pia2.ctrl_b &= 0xbf;
	pia2_update_irq();

if(pardebug) printf("write pia2.ctrl_b(%x)\n",byte);
	if( (byte & 0x38) == 0x30 ) par_set_dav(1);
	else par_set_dav(0);
	break;

    }  /* switch */
}


/* ------------------------------------------------------------------------- */

BYTE REGPARM1 read_pia2(ADDRESS addr)
{
    addr &= 3;

#if 0
    printf("read pia2 [%d]\n", addr);
#endif

    switch (addr) {

      case P_PORT_A: /* port A */
	if (pia2.ctrl_a & 4) {

	    if(!is_peek_access) {
	        pia2.ctrl_a &= 0x3f;		/* Clear CA1,CA2 IRQ */
	        pia2_update_irq();
	    }

	    if (pardebug)
		printf("read pia2 port A %x, par_bus=%x, gives %x\n",
			pia2.port_a, par_bus,
			(par_bus & ~pia2.ddr_a) |(pia2.port_a & pia2.ddr_a));

	    return (par_bus & ~pia2.ddr_a) |(pia2.port_a & pia2.ddr_a);
	}
	return (pia2.ddr_a);

      case P_PORT_B: /* port B */
	if (pia2.ctrl_b & 4) {

	    if(!is_peek_access) {
	        pia2.ctrl_b &= 0x3f;		/* Clear CB1,CB2 IRQ */
	        pia2_update_irq();
	    }

	    if (pardebug)
		printf("read pia2 port B %x, par_bus=%x, gives %x\n",
			pia2.port_b, par_bus,
			(~(par_bus|pia2.ddr_b)) |(pia2.port_b & pia2.ddr_b));

	    return (~pia2.ddr_b) |(pia2.port_b & pia2.ddr_b);
	}
	else
	    return (pia2.ddr_b);


	/* Control */

      case P_CTRL_A: /* Control A */
	return (pia2.ctrl_a);

      case P_CTRL_B: /* Control B */
	return (pia2.ctrl_b);
	break;

    }  /* switch */

    return (0xFF);
}


BYTE REGPARM1 peek_pia1(ADDRESS addr)
{
    BYTE t;
    is_peek_access = 1;
    t = read_pia1(addr);
    is_peek_access = 0;
    return t;
}

BYTE REGPARM1 peek_pia2(ADDRESS addr)
{
    BYTE t;
    is_peek_access = 1;
    t = read_pia2(addr);
    is_peek_access = 0;
    return t;
}



These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.