#define	    ident	"1A01"
/*
** +--------------------------------------------------------------+
** |                  Paul Scherrer Institute                     |
** |                     Computing Section                        |
** |                                                              |
** | This software may be used freely by non-profit organizations.|
** | It may be copied provided that the name of P.S.I. and of the |
** | author is included. Neither P.S.I. nor the author assume any |
** | responsibility for the use of this software outside of P.S.I.|
** +--------------------------------------------------------------+
**
** Module Name  . . . . . . . . : [...SINQHM]VMIO_UTILITY.C
**
** Author   . . . . . . . . . . : D. Maden
** Date of creation . . . . . . : Mar 1997
**
** Updates:
**  1A01  14-Mar-1997 DM	    Initial version.
**---------------------------------------------------------------------------
**  VMIO_UTILITY.C is a set of routines for setting up and using a VMIO10.
**
**  To compile this program for VxWorks on PSS123, use:
**
	    ccvx vmio_utility.c
** where
	    ccvx = ccppc -O0		    \
		    -mcpu=603		    \
		    -I${WIND_BASE}/target/h \
		    -fno-builtin	    \
		    -fno-for-scope	    \
		    -nostdinc		    \
		    -DCPU=PPC603	    \
		    -D_GNU_TOOL		    \
		    -gdwarf -c -Wimplicit

**  and, on the target,
**
**   -> ld < vmio_utility.o
**====================================================================
*/
#include    <vxWorks.h>
#include    <taskLib.h>
#include    <sysLib.h>
#include    <vme.h>
#include    <stdlib.h>
#include    <stdio.h>
#include    <signal.h>
#include    <setjmp.h>

#include    "vmio10_def.h"
/*
**====================	Global Definitions =====================================
*/
#define	    NIL		    0x00

#define	    DFLT_BASE_ADDR  0x1900
/*
**====================	Global Variables =====================================
*/
  char	    *VmioBase;
  char	    Vme_dummy[256];	/* Dummy array - used only when VME access ..
				** .. is disabled. */
  char	    Null = 0x00;
  char	    Bit8 = 0x10;
  int	    My_errno;
  int	    Go_on;
  int	    Signal_has_happened;
  jmp_buf   Trap_env;
/*

**=============================================================================
**  Local routines.
**				    Forward references ...
*/
    void    vmio_byte_send (char bit8, char lobits);
    void    vmio_enable (int ab_enbl, int bc_enbl);
    void    vmio_pol_dir (int a_pol, int a_dir,
			  int b_pol, int b_dir,
			  int c_pol, int c_dir,
			  int d_pol, int d_dir);
    void    vmio_reset ();
    void    vmio_send (char nbytes, char *buff);
    void    vmio_transp_init ();
/*
**-----------------------------------------------------------------*/
  void	Signal_Handler (int sigint) {
/*	==============
*/
    Signal_has_happened = 1;
    printf ("Got into Signal_Handler\n");
    longjmp (Trap_env, 1);
  }
/*
**-----------------------------------------------------------------*/
  void	vmio_byte_send (char bit8, char lobits) {
/*	==============
**			    Send a byte (well, 9 bits really) via the VMIO10.
*/
    char    aux;

    do {				/* Wait for Output Reg. empty */
      VmioBase[VMIO_AB_CNTL] = 0X09;	/* Select Port B status reg .. */
      aux = VmioBase[VMIO_AB_CNTL];	/* .. and read it. */
    } while ((aux & 0x08) == 0);	/* Test its "empty" bit */

    VmioBase[VMIO_PORT_C] = bit8;		/* Send Bit-8 */
    VmioBase[VMIO_PORT_B] = lobits;		/* Output the other bits */
  }
/*
**-----------------------------------------------------------------*/
  void	vmio_enable (int ab_enbl, int bc_enbl) {
/*	===========
**			output/input enable for IC6 ,IC7
*/
    VmioBase[VMIO_AB_CNTL] = Z8536_MCCR; /* Select Master Config Control Reg */
    VmioBase[VMIO_AB_CNTL] = ab_enbl;

    VmioBase[VMIO_CD_CNTL] = Z8536_MCCR;
    VmioBase[VMIO_CD_CNTL] = bc_enbl;
  }
/*
**-----------------------------------------------------------------*/
  void	vmio_pol_dir (
/*	============		Set Polarity and Direction of VMIO10 Module
**				A, B, C and D registers.
**				Polarity  bit = 0 for non-inverting.
**				Direction bit = 0 for output.
*/		    int	a_pol,
		    int a_dir,
		    int	b_pol,
		    int b_dir,
		    int	c_pol,
		    int c_dir,
		    int	d_pol,
		    int d_dir) {

    VmioBase[VMIO_AB_CNTL] = Z8536_DPPR_A; /* Port A %10'0010, Data Path Pol */
    VmioBase[VMIO_AB_CNTL] = a_pol;
    VmioBase[VMIO_AB_CNTL] = Z8536_DDR_A;  /* Port A %10'0011, Data Direction */
    VmioBase[VMIO_AB_CNTL] = a_dir;
	
    VmioBase[VMIO_AB_CNTL] = Z8536_DPPR_B; /* Port B %10'1010, Data Path Pol */
    VmioBase[VMIO_AB_CNTL] = b_pol;
    VmioBase[VMIO_AB_CNTL] = Z8536_DDR_B;  /* Port B %10'1011, Data Direction */
    VmioBase[VMIO_AB_CNTL] = b_dir;
	
    VmioBase[VMIO_CD_CNTL] = Z8536_DPPR_A; /* Port C %10'0010, Data Path Pol */
    VmioBase[VMIO_CD_CNTL] = c_pol;
    VmioBase[VMIO_CD_CNTL] = Z8536_DDR_A;  /* Port C %10'0011, Data Direction */
    VmioBase[VMIO_CD_CNTL] = c_dir;

    VmioBase[VMIO_CD_CNTL] = Z8536_DPPR_B; /* Port D %10'1010, Data Path Pol */
    VmioBase[VMIO_CD_CNTL] = d_pol;
    VmioBase[VMIO_CD_CNTL] = Z8536_DDR_B;  /* Port D %10'0011, Data Direction */
    VmioBase[VMIO_CD_CNTL] = d_dir;
  }
/*
**-----------------------------------------------------------------*/
  void	vmio_reset () {
/*	==========
**			    Software reset for VMIO10 module
*/
    char    aux;
		/*
		** Start by forcing the state machine into State 0
		*/
    aux = VmioBase[VMIO_AB_CNTL];    /* Read Cntrl to ensure not State 1 */
    VmioBase[VMIO_AB_CNTL] = NIL;    /* Write zero to Cntrl to ensure not in ..
				     ** .. "Reset State" */
    aux = VmioBase[VMIO_AB_CNTL];    /* Read Cntrl to ensure State 0 */

    VmioBase[VMIO_AB_CNTL] = Z8536_MICR; /* Select the Master Int Ctrl Reg */
    VmioBase[VMIO_AB_CNTL] = 0x01;	 /* Set the reset bit */
    VmioBase[VMIO_AB_CNTL] = NIL;	 /* Then clear it to complete reset */
		/*
		** Repeat for the other Z8536-CIO
		*/
    aux = VmioBase[VMIO_CD_CNTL];
    VmioBase[VMIO_CD_CNTL] = NIL;
    aux = VmioBase[VMIO_CD_CNTL];

    VmioBase[VMIO_CD_CNTL] = Z8536_MICR;
    VmioBase[VMIO_CD_CNTL] = 0x01;
    VmioBase[VMIO_CD_CNTL] = NIL;
  }
/*
**-----------------------------------------------------------------*/
  void	vmio_send (
/*	=========			Send bytes to the LWL.
*/		    char    nbytes,
		    char    *buff) {
/*
**		The bytes are buff[0] to buff[nbytes-1]. buff[0] gives the
**		headerbit for buff[1]. The remainder are sent with the 9th
**		bit clear.
*/
    int	    i;
    char    aux;
		/*
		** ---------- loop sending the bytes ---------------
		*/
    VmioBase[VMIO_PORT_C] = 0;			    /* Mode = 0 */

    if (nbytes < 2) return;
    vmio_byte_send (buff[0], buff[1]); /* 2 bytes define the first "LWL-byte" */

    if (nbytes < 3) return;

    for (i = 2; i < nbytes; i++) {     /* The remaining bytes have Bit-8 = 0 */
      vmio_byte_send (NIL, buff[i]);
    }
  }
/*
**-----------------------------------------------------------------*/
  void	vmio_transp_init () {
/*	================
**			Initialise VMIO10 ready for transparent
**			transmission of data.
*/
		/*
		** ---------- initialize i/o ---------------
		*/
    VmioBase[VMIO_AB_CNTL] = 0x28;	/* Port B output port-Mode Spec. Reg */
    VmioBase[VMIO_AB_CNTL] = 0x80;
    	
    VmioBase[VMIO_AB_CNTL] = 0x29;	/* Port B handshake interlock */
    VmioBase[VMIO_AB_CNTL] = 0x00;
  }
/*==============================================================================

**  Main line program
**  ------------------
**============================================================================*/
  int vmio_utility (char *base_addr) {
/*============================================================================*/
    STATUS	    status;
    int		    i;
    char	    aux;
    void	    (* sig_status) (int);
/*============================================================================
**	Perform the initialisation of global variables ...
*/

/*============================================================================
**		Get the VME base address of the Test Generator Module.
**		If the argument "base_addr" is zero, use DFLT_BASE_ADDR.
*/
    if (base_addr == NULL) base_addr = (char *) DFLT_BASE_ADDR;

#ifdef _NO_VME
    printf ("VMIO_UTILITY: Warning, VME access disabled.\n");
    VmioBase = &Vme_dummy[0];
#else
    status = sysBusToLocalAdrs (VME_AM_USR_SHORT_IO, base_addr, &VmioBase);
    if (status != OK) {
      printf ("Error status from sysBusToLocalAdrs\n");
      return ERROR;
    }
#endif
	/*
	** See if the module is present
	*/
    Signal_has_happened = 0;
    sig_status = signal (SIGBUS, Signal_Handler);   /* Catch machine checks */
    if (sig_status == SIG_ERR) {
      printf ("    Problem setting up a signal handler!\n");
      return ERROR;
    }
    i = setjmp (Trap_env);
    if (i == 0) aux = VmioBase[VMIO_AB_CNTL];
    if (Signal_has_happened != 0) {
      printf ("VMIO10 Module not present -- exiting!\n");
      return ERROR;
    }
	/*
	** Reset the VMIO10 Module.
	*/
    vmio_reset ();
	/*
	** Set Ports A, B, C and D to non-inverting and output
	*/
    vmio_pol_dir (NIL, NIL,	/* Port A */
		  NIL, NIL,	/* Port B */
		  NIL, NIL,	/* Port C */
		  NIL, NIL);	/* Port D */
	/*
	** Enable Ports A, B, C and D.
	*/
    vmio_enable (0x84, 0x84);

    Go_on = 0;

    for (;;) {
      for (i=0; i<1000; i++) {}
      if (Go_on != 0) break;
      VmioBase[VMIO_PORT_A] = 0xff;
      VmioBase[VMIO_PORT_A] = 0x00;
      VmioBase[VMIO_PORT_A] = 0xff;
      VmioBase[VMIO_PORT_A] = 0x00;
      VmioBase[VMIO_PORT_A] = 0xff;
      VmioBase[VMIO_PORT_A] = 0x00;
    }
    printf ("Vmio_Utility exiting\n");
    return OK;
  }
/*===================================== End of VMIO_UTILITY.C =============*/
