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.